Skip to content

Conversation

@alexei-led
Copy link
Owner

Implement OS-level process isolation for running AWS CLI commands
to provide defense-in-depth security against command injection.

Key features:

  • Linux support: Landlock LSM (kernel 5.13+) with bubblewrap fallback
  • macOS support: Seatbelt (sandbox-exec) via subprocess
  • Two AWS credential passing modes: environment variables and ~/.aws access
  • Configurable via AWS_MCP_SANDBOX and AWS_MCP_SANDBOX_CREDENTIALS env vars

The sandbox restricts filesystem access while allowing:

  • Read access to system binaries and libraries
  • Read access to AWS configuration (~/.aws) if configured
  • Write access to /tmp and current working directory
  • Network access for AWS API calls

This complements the existing command validation security layer.

claude and others added 14 commits November 27, 2025 06:30
Implement OS-level process isolation for running AWS CLI commands
to provide defense-in-depth security against command injection.

Key features:
- Linux support: Landlock LSM (kernel 5.13+) with bubblewrap fallback
- macOS support: Seatbelt (sandbox-exec) via subprocess
- Two AWS credential passing modes: environment variables and ~/.aws access
- Configurable via AWS_MCP_SANDBOX and AWS_MCP_SANDBOX_CREDENTIALS env vars

The sandbox restricts filesystem access while allowing:
- Read access to system binaries and libraries
- Read access to AWS configuration (~/.aws) if configured
- Write access to /tmp and current working directory
- Network access for AWS API calls

This complements the existing command validation security layer.
- Remove unused execute_piped_command() from tools.py and its tests
- Move duplicated _build_env() method to SandboxBackend base class
- Update module docstring in tools.py to reflect current purpose
- Remove unused imports from test files
- Use modern Python 3.13 type hints (list[str] instead of List[str])
- Add sandbox environment variables to README configuration table
- Add Sandbox Execution section with backend support details
- Update architecture diagrams to show Security → Sandbox flow
- Update spec.md tool names (aws_cli_help, aws_cli_pipeline)
- Add Security Validator and Sandbox to component architecture
- Update directory structure with sandbox.py and security.py
- Add Docker vs Sandbox comparison in Why Docker section
- Streamline Example Interactions to show tool usage patterns
- Add sandbox disable option to CLAUDE.md for development
- Add value proposition explaining CLI wrapper vs API wrapper approach
- Reorganize README: move detailed content to dedicated docs
- Create docs/SECURITY.md (architecture), docs/DEVELOPMENT.md
- Create CONTRIBUTING.md, SECURITY.md (vulnerability reporting)
- Fix tool names in INSTRUCTIONS (describe_command -> aws_cli_help)
- Improve tool descriptions for AI-friendliness with examples
- Add AWS_ENV_VARS and AWS_SECRET_ENV_VARS constants
- Filter out secret-bearing AWS vars when pass_aws_env is disabled
- Add tests for env var filtering behavior
Convert subprocess.TimeoutExpired to asyncio.TimeoutError in
execute_sandboxed_async to match the documented contract and ensure
execute_aws_command catches timeouts correctly instead of falling
through to generic exception handling.

Also remove unsupported version/capabilities args from FastMCP init.
- Remove fake tests in test_main.py that tested mocks instead of code
- Add platform-specific skip markers for Linux/macOS sandbox backends
- Add timeout handling tests for sync and async sandbox execution
- Add version parsing edge case tests for Landlock and Seatbelt
- Add Seatbelt profile tests for AWS config disabled
- Add backend selection tests for unsupported platforms
- Coverage improved from 79% to 85% for sandbox.py
Previously, when Landlock failed to apply in the preexec_fn, it would
log a warning and continue execution without sandboxing - even when
sandbox_mode="required". This could give users false confidence that
sandboxing was active when it wasn't.

Now the behavior respects the configured mode:
- required: raises RuntimeError if Landlock fails (fail-safe)
- auto: logs warning with mode info and continues (graceful fallback)
- disabled: no change

Also adds sandbox_mode parameter to all backend execute() methods
to enable this context-aware enforcement.
Update SECURITY.md to document that required mode provides fail-safe
behavior: commands fail if sandbox cannot apply at execution time,
not just if the backend is unavailable at startup.
Previously, execute_piped_sandboxed_async passed the same timeout to
each pipeline stage, so N commands could take N×timeout seconds. This
violated the documented contract ("timeout in seconds for the entire
pipeline").

Now tracks elapsed time with time.monotonic() and calculates remaining
time for each stage. Pipeline aborts immediately when total timeout is
exceeded.

Adds test verifying 3×0.15s sleeps timeout before 0.5s with 0.3s limit.
The region auto-injection only checked for exact "--region" match,
so --region=eu-west-1 was not detected as having a region. This caused
the default region to be appended, silently overriding user's intent
since AWS CLI honors the last --region argument.

Now checks if any arg starts with "--region" to handle both:
- --region eu-west-1 (space-separated)
- --region=eu-west-1 (equals syntax)

Fixed in both execute_aws_command and execute_pipe_command.
Major version bumps:
- fastmcp: 0.4.1 → 2.13.0 (major API changes)
- mcp: 1.0.0 → 1.22.0
- boto3: 1.34.0 → 1.41.0
- pytest: 7.0.0 → 9.0.0
- pytest-cov: 4.0.0 → 7.0.0
- pytest-asyncio: 0.23.0 → 1.3.0
- ruff: 0.2.0 → 0.14.0
- moto: 4.0.0 → 5.1.0
- setuptools_scm: 7.0.0 → 9.0.0

All tests pass with new dependencies.
@codecov
Copy link

codecov bot commented Nov 28, 2025

Codecov Report

❌ Patch coverage is 86.60714% with 60 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.78%. Comparing base (df44aab) to head (90a699c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
src/aws_mcp_server/sandbox.py 84.52% 50 Missing ⚠️
src/aws_mcp_server/cli_executor.py 79.54% 9 Missing ⚠️
src/aws_mcp_server/prompts.py 98.38% 1 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@            Coverage Diff             @@
##             main      #21      +/-   ##
==========================================
- Coverage   95.06%   90.78%   -4.28%     
==========================================
  Files           8        9       +1     
  Lines         669      977     +308     
==========================================
+ Hits          636      887     +251     
- Misses         33       90      +57     
Files with missing lines Coverage Δ
src/aws_mcp_server/config.py 100.00% <100.00%> (ø)
src/aws_mcp_server/resources.py 90.47% <100.00%> (+0.97%) ⬆️
src/aws_mcp_server/server.py 100.00% <100.00%> (ø)
src/aws_mcp_server/tools.py 100.00% <100.00%> (+1.72%) ⬆️
src/aws_mcp_server/prompts.py 98.79% <98.38%> (-1.21%) ⬇️
src/aws_mcp_server/cli_executor.py 89.92% <79.54%> (-6.48%) ⬇️
src/aws_mcp_server/sandbox.py 84.52% <84.52%> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

- Use uv pip sync with lock file instead of installing from pyproject.toml
- Ensures consistent dependency versions (especially ruff) across CI runs
- Fix shellcheck warnings for unquoted GITHUB_PATH/GITHUB_OUTPUT
… paths

- Make sandbox_available() catch SandboxError and return False instead of
  propagating, preventing uncaught exceptions when AWS_MCP_SANDBOX=required
  but no backend is available
- Move log statements inside try blocks in execute_aws_command and
  execute_pipe_command to ensure sandbox errors are properly caught
- Add get_aws_credential_paths() helper to discover credential paths from
  AWS_SHARED_CREDENTIALS_FILE, AWS_CONFIG_FILE, and AWS_WEB_IDENTITY_TOKEN_FILE
- Update Landlock, Bubblewrap, and Seatbelt backends to whitelist custom
  credential paths, fixing "Unable to locate credentials" errors when using
  non-default credential locations
- Add tests for sandbox_available() returning False on SandboxError
- Add tests for get_aws_credential_paths() helper covering default ~/.aws,
  custom credentials file, custom config file, web identity token file,
  non-existent paths, and deduplication
The test_build_profile test was failing in CI because ~/.aws doesn't exist.
Mock the helper function to ensure consistent test behavior.
- get_aws_profiles() now reads from AWS_CONFIG_FILE and
  AWS_SHARED_CREDENTIALS_FILE environment variables
- Documents custom credential path support in sandbox
- Ensures consistency: sandbox whitelists custom paths and
  resources can discover profiles from them
- Replace verbose 25-line prompts with ~10-line focused templates
- Add concrete AWS CLI examples for each prompt type
- Extract common examples into module-level dictionaries
- Each prompt now leads with example and specifies output format
- Follows best practice: "concrete examples > verbose instructions"
- Replace pip/curl install with astral-sh/setup-uv@v7 action
- Enable uv cache for faster builds
- Read Python version from pyproject.toml (uv python install)
- Update actions: checkout@v6, codecov-action@v5, build-push-action@v6
- Remove unnecessary matrix strategy and comments
- Consistent patterns across ci.yml and release.yml
- Add comprehensive USAGE.md with integration examples
- Simplify README with essential quickstart info
- Move detailed content to dedicated doc files
- Update CONTRIBUTING with cleaner setup reference
- Refresh SECURITY and VERSION docs
Ubuntu's externally managed Python rejects --system installs.
Switch to uv sync which creates a venv automatically and use
uv run to execute commands in the virtual environment.
The old uv.lock was pip-compile format (requirements.txt style).
uv sync requires TOML format lock file. Regenerated with uv lock.
Also update Makefile to use uv sync commands.
@alexei-led alexei-led merged commit 128a801 into main Nov 29, 2025
4 checks passed
@alexei-led alexei-led deleted the claude/sandbox-aws-cli-01EnE7BVjBvQKnDDwzBKM1Y7 branch November 29, 2025 10:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants