From 60caad8c8bf74d952892d420e0497a092d781126 Mon Sep 17 00:00:00 2001 From: JF Date: Mon, 6 Apr 2026 20:24:47 -0400 Subject: [PATCH] security: supply chain hardening for OpenSSF Best Practices badge - SHA-pin all GitHub Actions across ci.yml, release.yml (29 action refs) - Add top-level permissions to all workflows (contents:read / {} + job-level) - Upgrade pnpm/action-setup from v2 (mutable branch) to v4 (immutable tag) - Pin CI tool versions: debugpy==1.8.14, dlv@v1.24.2, pip==25.0.1, build/twine/tomlkit - Add pnpm audit step to CI pipeline - Add Dependabot for github-actions, npm, pip ecosystems - Add CodeQL SAST workflow for TypeScript/JavaScript - Add OpenSSF Scorecard workflow with SARIF upload - Add OpenSSF Scorecard badge to README - Add 80% statement coverage threshold to vitest config - Create SECURITY.md with vulnerability disclosure policy - Create CODE_OF_CONDUCT.md (Contributor Covenant v2.1) - Create ARCHITECTURE.md with monorepo overview and data flow - Create SUPPLY-CHAIN-SECURITY.md with governance model and controls - Update CONTRIBUTING.md to link to CODE_OF_CONDUCT.md Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/dependabot.yml | 28 +++++++ .github/workflows/ci.yml | 63 +++++++++------- .github/workflows/codeql.yml | 41 ++++++++++ .github/workflows/release.yml | 60 ++++++++------- .github/workflows/scorecard.yml | 45 +++++++++++ .github/workflows/validate-secrets.yml | 3 + ARCHITECTURE.md | 72 ++++++++++++++++++ CODE_OF_CONDUCT.md | 83 ++++++++++++++++++++ CONTRIBUTING.md | 2 +- README.md | 1 + SECURITY.md | 62 +++++++++++++++ SUPPLY-CHAIN-SECURITY.md | 100 +++++++++++++++++++++++++ vitest.config.ts | 5 +- 13 files changed, 509 insertions(+), 56 deletions(-) create mode 100644 .github/dependabot.yml create mode 100644 .github/workflows/codeql.yml create mode 100644 .github/workflows/scorecard.yml create mode 100644 ARCHITECTURE.md create mode 100644 CODE_OF_CONDUCT.md create mode 100644 SECURITY.md create mode 100644 SUPPLY-CHAIN-SECURITY.md diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..117b5b08 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,28 @@ +version: 2 +updates: + - package-ecosystem: github-actions + directory: / + schedule: + interval: weekly + day: monday + commit-message: + prefix: "ci" + + - package-ecosystem: npm + directory: / + schedule: + interval: weekly + day: monday + commit-message: + prefix: "deps" + groups: + minor-and-patch: + update-types: ["minor", "patch"] + + - package-ecosystem: pip + directory: /mcp_debugger_launcher + schedule: + interval: weekly + day: monday + commit-message: + prefix: "deps" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ff8acad7..d2318519 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -6,6 +6,9 @@ on: pull_request: branches: [ main ] +permissions: + contents: read + jobs: build-and-test: name: Build and Test @@ -19,39 +22,39 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: ${{ matrix.node-version }} cache: 'pnpm' - name: Setup Python ${{ matrix.python-version }} - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: ${{ matrix.python-version }} - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install debugpy + python -m pip install "pip==25.0.1" + python -m pip install "debugpy==1.8.14" - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 with: go-version: '1.21' - name: Install Delve debugger - run: go install github.com/go-delve/delve/cmd/dlv@latest + run: go install github.com/go-delve/delve/cmd/dlv@v1.24.2 - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' @@ -61,6 +64,10 @@ jobs: env: SKIP_ADAPTER_VENDOR: 'true' + - name: Audit dependencies + run: pnpm audit --prod --audit-level=high + continue-on-error: true + - name: Vendor adapter binaries run: pnpm run vendor:adapters continue-on-error: true @@ -81,7 +88,7 @@ jobs: - name: Upload Windows test diagnostics if: failure() && matrix.os == 'windows-latest' - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: windows-test-diagnostics path: | @@ -92,14 +99,14 @@ jobs: if-no-files-found: warn - name: Upload coverage reports - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 if: matrix.os == 'ubuntu-latest' with: name: coverage-report path: coverage/ - name: Upload coverage to Codecov - uses: codecov/codecov-action@v4 + uses: codecov/codecov-action@b9fd7d16f6d7d1b5d2bec1a2887e65ceed900238 # v4 if: matrix.os == 'ubuntu-latest' with: token: ${{ secrets.CODECOV_TOKEN }} @@ -113,31 +120,31 @@ jobs: runs-on: windows-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: 22.x cache: 'pnpm' - name: Setup Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: '3.11' - name: Install Python dependencies run: | - python -m pip install --upgrade pip - python -m pip install debugpy + python -m pip install "pip==25.0.1" + python -m pip install "debugpy==1.8.14" - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' @@ -157,7 +164,7 @@ jobs: - name: Upload targeted test diagnostics if: failure() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 with: name: windows-python-integration-logs path: | @@ -172,21 +179,21 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '22.x' cache: 'pnpm' - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' @@ -209,21 +216,21 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '22.x' cache: 'pnpm' - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..b8e7c820 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,41 @@ +name: CodeQL + +on: + push: + branches: [ main ] + pull_request: + branches: [ main ] + schedule: + - cron: '0 6 * * 1' # Monday 6:00 UTC + +permissions: + security-events: write + contents: read + actions: read + +jobs: + analyze: + name: Analyze + runs-on: ubuntu-latest + + strategy: + fail-fast: false + matrix: + language: [ javascript-typescript ] + + steps: + - name: Checkout repository + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + + - name: Initialize CodeQL + uses: github/codeql-action/init@5c8a8a642e79153f5d047b10ec1cba1d1cc65699 # v3 + with: + languages: ${{ matrix.language }} + + - name: Autobuild + uses: github/codeql-action/autobuild@5c8a8a642e79153f5d047b10ec1cba1d1cc65699 # v3 + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@5c8a8a642e79153f5d047b10ec1cba1d1cc65699 # v3 + with: + category: /language:${{ matrix.language }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 90d46024..783de8d8 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -11,49 +11,53 @@ on: required: true default: 'refs/tags/v0.20.0' +permissions: {} + jobs: build-and-test: name: Build and Test runs-on: ubuntu-latest - + permissions: + contents: read + steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 ref: ${{ github.event.inputs.ref || github.ref }} - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '22.x' cache: 'pnpm' - name: Setup Python 3.11 - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: '3.11' - name: Install Python dependencies run: | - python -m pip install --upgrade pip - pip install debugpy + python -m pip install "pip==25.0.1" + pip install "debugpy==1.8.14" - name: Setup Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5 with: go-version: '1.21' - name: Install Delve debugger - run: go install github.com/go-delve/delve/cmd/dlv@latest + run: go install github.com/go-delve/delve/cmd/dlv@v1.24.2 - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' @@ -83,19 +87,21 @@ jobs: name: Build and Push Docker Image needs: build-and-test runs-on: ubuntu-latest - + permissions: + contents: read + steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 ref: ${{ github.event.inputs.ref || github.ref }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3 - name: Log in to Docker Hub - uses: docker/login-action@v3 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -120,7 +126,7 @@ jobs: - name: Extract metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5 with: images: debugmcp/mcp-debugger tags: | @@ -130,7 +136,7 @@ jobs: type=raw,value=latest,enable=${{ env.PUBLISH_LATEST == 'true' }} - name: Build and push Docker image - uses: docker/build-push-action@v5 + uses: docker/build-push-action@ca052bb54ab0790a636c9b5f226502c73d547a25 # v5 with: context: . platforms: linux/amd64,linux/arm64 @@ -144,23 +150,25 @@ jobs: name: Publish Python Launcher to PyPI needs: build-and-test runs-on: ubuntu-latest - + permissions: + contents: read + steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 ref: ${{ github.event.inputs.ref || github.ref }} - name: Set up Python - uses: actions/setup-python@v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5 with: python-version: '3.11' - name: Install Python build dependencies run: | - python -m pip install --upgrade pip - pip install build twine tomlkit + python -m pip install "pip==25.0.1" + pip install "build==1.2.2" "twine==6.1.0" "tomlkit==0.13.2" - name: Resolve release ref run: | @@ -219,25 +227,25 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 ref: ${{ github.event.inputs.ref || github.ref }} - name: Setup pnpm - uses: pnpm/action-setup@v2 + uses: pnpm/action-setup@b906affcce14559ad1aafd4ab0e942779e9f58b1 # v4 with: version: 10 - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4 with: node-version: '22.x' registry-url: 'https://registry.npmjs.org' cache: 'pnpm' - name: Setup Java 21 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4 with: distribution: 'temurin' java-version: '21' @@ -331,7 +339,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 with: fetch-depth: 0 ref: ${{ github.event.inputs.ref || github.ref }} diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 00000000..3195a38d --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,45 @@ +name: OpenSSF Scorecard + +on: + push: + branches: [ main ] + schedule: + - cron: '0 6 * * 1' # Monday 6:00 UTC + workflow_dispatch: + +permissions: {} + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + security-events: write + id-token: write + contents: read + actions: read + + steps: + - name: Checkout code + uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4 + with: + persist-credentials: false + + - name: Run analysis + uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0 + with: + results_file: results.sarif + results_format: sarif + publish_results: true + + - name: Upload artifact + uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4 + with: + name: SARIF file + path: results.sarif + retention-days: 5 + + - name: Upload to code-scanning + uses: github/codeql-action/upload-sarif@5c8a8a642e79153f5d047b10ec1cba1d1cc65699 # v3 + with: + sarif_file: results.sarif diff --git a/.github/workflows/validate-secrets.yml b/.github/workflows/validate-secrets.yml index 7e101c3d..e9fb5748 100644 --- a/.github/workflows/validate-secrets.yml +++ b/.github/workflows/validate-secrets.yml @@ -3,6 +3,9 @@ name: Validate Release Secrets on: workflow_dispatch: +permissions: + contents: read + jobs: validate-npm: name: "npm: token" diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md new file mode 100644 index 00000000..0e6d4ff3 --- /dev/null +++ b/ARCHITECTURE.md @@ -0,0 +1,72 @@ +# Architecture + +mcp-debugger is a Model Context Protocol (MCP) server that bridges MCP clients (like Claude) with language-specific debug adapters via the Debug Adapter Protocol (DAP). It enables AI agents to perform step-through debugging of multiple programming languages. + +## Monorepo Structure + +The project uses pnpm workspaces with 9 packages: + +``` +packages/ + shared/ Core interfaces and types (IDebugAdapter, IAdapterFactory) + adapter-python/ Python debugging via debugpy + adapter-javascript/ JavaScript/Node.js debugging via js-debug + adapter-rust/ Rust debugging via CodeLLDB + adapter-go/ Go debugging via Delve + adapter-java/ Java debugging via JDI bridge + adapter-dotnet/ .NET/C# debugging via netcoredbg + adapter-mock/ Mock adapter for testing + mcp-debugger/ Self-contained CLI bundle (npx distribution) +``` + +Build order: `shared` -> adapters -> `mcp-debugger` CLI bundle. + +## Data Flow + +``` +MCP Client (Claude, etc.) + | MCP Protocol (JSON-RPC over STDIO or SSE) + v +MCP Server (src/server.ts) + | Tool routing, input validation, path resolution + v +SessionManager (src/session/) + | Session lifecycle, breakpoint management, state machine + v +ProxyManager (src/proxy/proxy-manager.ts) + | IPC messages to spawned child process + v +ProxyWorker (src/proxy/dap-proxy-worker.ts) + | DAP Protocol, adapter policy selection + v +Language Adapter (@debugmcp/adapter-*) + | Spawns and controls debug runtime + v +Target Process (user's script or binary) +``` + +Each debug session runs in a **separate process** for isolation. The ProxyManager spawns a child process containing the ProxyWorker, which communicates with the debug adapter over DAP. + +## Key Components + +- **MCP Server** (`src/server.ts`): Registers 21 MCP tools, handles STDIO and SSE transports, dynamically discovers available language adapters +- **SessionManager** (`src/session/`): 4-class inheritance hierarchy managing session lifecycle (`CREATED` -> `INITIALIZING` -> `READY` -> `RUNNING` <-> `PAUSED` -> `STOPPED`) +- **Adapter Registry** (`src/adapters/`): Dynamic loading of adapters on-demand via ES module imports +- **Adapter Policies** (`src/proxy/`): Language-specific DAP behavior via the policy pattern (e.g., `PythonAdapterPolicy`, `JsDebugAdapterPolicy`) +- **Dependency Injection** (`src/container/`): Constructor injection for all major components + +## Adapter Plugin Pattern + +Each language adapter implements two interfaces from `@debugmcp/shared`: + +- **`IAdapterFactory`**: Creates adapter instances, reports supported languages and capabilities +- **`IDebugAdapter`**: Manages debug adapter lifecycle (initialize, launch/attach, shutdown) + +Adapters are loaded dynamically by the `AdapterLoader`, which searches for `@debugmcp/adapter-{language}` packages at runtime. This allows adapters to be developed and deployed independently. + +## Detailed Documentation + +- [Adapter architecture and API reference](docs/architecture/README.md) +- [System overview with Mermaid diagrams](docs/architecture/system-overview.md) +- [Adapter development guide](docs/architecture/adapter-development-guide.md) +- [Testing architecture](docs/architecture/testing-architecture.md) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 00000000..fa66f721 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,83 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our community include: + +* Demonstrating empathy and kindness toward other people +* Being respectful of differing opinions, viewpoints, and experiences +* Giving and gracefully accepting constructive feedback +* Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience +* Focusing on what is best not just for us as individuals, but for the overall community + +Examples of unacceptable behavior include: + +* The use of sexualized language or imagery, and sexual attention or advances of any kind +* Trolling, insulting or derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or email address, without their explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at **debug@sycamore.llc**. All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of actions. + +**Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.1, available at [https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at [https://www.contributor-covenant.org/faq][FAQ]. Translations are available at [https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b094bee1..0c763498 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -16,7 +16,7 @@ Thank you for your interest in contributing to mcp-debugger! We welcome contribu ## 📜 Code of Conduct -This project adheres to a Code of Conduct that all contributors are expected to follow. Please be respectful and professional in all interactions. +This project adheres to the [Contributor Covenant Code of Conduct](CODE_OF_CONDUCT.md). All contributors are expected to follow it. Please be respectful and professional in all interactions. ## 🚀 Getting Started diff --git a/README.md b/README.md index 3f979e80..d959a47b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,7 @@ [![npm version](https://img.shields.io/npm/v/@debugmcp/mcp-debugger.svg)](https://www.npmjs.com/package/@debugmcp/mcp-debugger) [![Docker Pulls](https://img.shields.io/docker/pulls/debugmcp/mcp-debugger.svg)](https://hub.docker.com/r/debugmcp/mcp-debugger) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](./LICENSE) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/debugmcp/mcp-debugger/badge)](https://scorecard.dev/viewer/?uri=github.com/debugmcp/mcp-debugger) ## 🎯 Overview diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 00000000..907aa520 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,62 @@ +# Security Policy + +## Supported Versions + +| Version | Supported | +| ------- | ------------------ | +| 0.20.x | :white_check_mark: | +| < 0.20 | :x: | + +## Reporting a Vulnerability + +**Do NOT file a public GitHub issue for security vulnerabilities.** + +### Preferred: GitHub Security Advisories + +Report vulnerabilities through [GitHub Security Advisories](https://github.com/debugmcp/mcp-debugger/security/advisories/new). This provides a private channel for discussion and coordinated disclosure. + +### Alternative: Email + +Send details to **debug@sycamore.llc** with subject line `[SECURITY] mcp-debugger: `. + +### What to Include + +- Description of the vulnerability +- Steps to reproduce +- Affected versions +- Impact assessment (if known) + +### Response Timeline + +- **Acknowledgment**: Within 48 hours +- **Initial assessment**: Within 1 week +- **Resolution target**: Within 90 days + +We will coordinate disclosure timing with the reporter. Credit is given to responsible reporters unless anonymity is requested. + +## Scope + +The following components are in scope for security reports: + +- **MCP server** (`src/`) — protocol handling, tool routing, input validation +- **Language adapters** (`packages/adapter-*`) — debug adapter lifecycle, process spawning +- **CLI bundle** (`packages/mcp-debugger`) — command-line entry points +- **Docker image** (`Dockerfile`) — container security, base image vulnerabilities +- **CI/CD pipelines** (`.github/workflows/`) — supply chain integrity +- **Published packages** — npm (`@debugmcp/*`), PyPI (`debug-mcp-server-launcher`), Docker Hub (`debugmcp/mcp-debugger`) + +### Out of Scope + +- Vulnerabilities in upstream debug adapters (debugpy, js-debug, CodeLLDB, Delve, netcoredbg) — report these to their respective maintainers +- Denial of service via intentionally malformed DAP messages in a local-only deployment +- Issues requiring physical access to the host machine + +## Security Design + +mcp-debugger follows these security principles: + +- **Process isolation**: Each debug session runs in a separate process +- **No credential storage**: The server does not store or manage user credentials +- **Input validation**: File paths and DAP messages are validated at system boundaries +- **Least privilege**: CI workflows use minimal GitHub token permissions +- **Supply chain hardening**: GitHub Actions are SHA-pinned, dependencies are audited, npm packages are published with sigstore provenance diff --git a/SUPPLY-CHAIN-SECURITY.md b/SUPPLY-CHAIN-SECURITY.md new file mode 100644 index 00000000..b860f380 --- /dev/null +++ b/SUPPLY-CHAIN-SECURITY.md @@ -0,0 +1,100 @@ +# Supply Chain Security + +This document describes the supply chain security controls for mcp-debugger. It covers how code changes are vetted, how packages are published, and how access is governed. + +## Governance Model + +mcp-debugger uses an **agent-first development model** where AI coding agents handle implementation while CI serves as the primary quality gate. Manual merge and release decisions remain with the project maintainers. + +- Agents create pull requests but cannot merge independently +- All PRs must pass CI status checks before merging +- Branch protection rules enforce these constraints server-side + +## Supply Chain Controls + +### GitHub Actions Pinning + +All GitHub Actions in CI and release workflows are pinned to immutable commit SHAs rather than mutable version tags. This prevents tag mutation attacks where a compromised action could be injected via a tag update. + +Format: `actions/checkout@ # v4` + +Dependabot automatically proposes SHA updates for GitHub Actions on a weekly schedule. + +### Dependency Management + +- **Lock file integrity**: `pnpm-lock.yaml` records SHA-512 hashes for every dependency. The lock file is committed and verified on every CI run. +- **Dependabot**: Configured for npm, pip, and GitHub Actions ecosystems with weekly update schedules. +- **Dependency audit**: `pnpm audit` runs in CI to flag known vulnerabilities in production dependencies. + +### Static Analysis + +- **CodeQL**: GitHub's CodeQL runs SAST on every push to main and on pull requests, analyzing TypeScript/JavaScript for security vulnerabilities. +- **OpenSSF Scorecard**: Automated security health assessment runs weekly, with results published to the OpenSSF dashboard and GitHub Security tab. + +### Publishing Security + +#### npm (`@debugmcp/*` packages) + +- **OIDC trusted publishing**: npm packages are published using GitHub's OIDC token provider, eliminating long-lived npm tokens from CI. +- **Sigstore provenance**: All npm packages are published with `--provenance`, generating sigstore attestations that link each package version to its source commit and build workflow. +- **Verification**: `npm audit signatures @debugmcp/mcp-debugger` verifies provenance attestations. + +#### PyPI (`debug-mcp-server-launcher`) + +- Currently uses token-based authentication via repository secret. +- Migration to OIDC trusted publishing (via `pypa/gh-action-pypi-publish`) is planned to eliminate the long-lived PyPI token. + +#### Docker Hub (`debugmcp/mcp-debugger`) + +- Multi-platform images (linux/amd64, linux/arm64) built in CI. +- Published only after all tests pass. +- Credential-based authentication via repository secrets. + +### CI Tool Pinning + +All tools installed during CI are pinned to specific versions to ensure reproducible builds: +- Python packages (debugpy, build tools) pinned with `==` version specifiers +- Go tools (Delve) pinned to specific release tags +- Node.js, Python, Go, and Java runtime versions are fixed in workflow matrices + +## Branch Protection + +The `main` branch is protected with the following rules: + +- Required status checks must pass before merging (CI jobs: Build and Test, Lint Code, Container Tests, Test Summary) +- Force pushes are blocked +- Branch deletion is blocked +- All changes must go through pull requests + +## Process Isolation + +Each debug session runs in a separate child process. The MCP server itself never executes user code directly -- it delegates to language-specific debug adapters (debugpy, js-debug, CodeLLDB, Delve, JDI, netcoredbg) which spawn and control the target process. + +## Input Validation + +- File paths are validated at the MCP server boundary via `SimpleFileChecker` before being passed to session management +- DAP messages are validated at the proxy layer +- The server does not store or manage user credentials + +## Access Continuity + +The project has multiple contributors to avoid single points of failure: + +| System | Access Holders | +|--------|---------------| +| npm (`@debugmcp` scope) | Project maintainers with OIDC (no personal tokens needed) | +| Docker Hub (`debugmcp/mcp-debugger`) | Project maintainers via repository secrets | +| GitHub (admin) | Organization owners of `debugmcp` | +| PyPI (`debug-mcp-server-launcher`) | Project maintainers via repository secret (OIDC planned) | + +If the primary maintainer becomes unavailable, organization-level access on GitHub ensures continuity. npm OIDC publishing is tied to the GitHub repository, not individual accounts. + +## Incident Response + +See [SECURITY.md](SECURITY.md) for vulnerability reporting process and response timelines. + +## References + +- [OpenSSF Scorecard](https://scorecard.dev/viewer/?uri=github.com/debugmcp/mcp-debugger) +- [npm provenance documentation](https://docs.npmjs.com/generating-provenance-statements) +- [Sigstore](https://www.sigstore.dev/) diff --git a/vitest.config.ts b/vitest.config.ts index fe4d2e56..e0b0d9eb 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -124,7 +124,10 @@ export default defineConfig({ 'packages/shared/src/index.ts', 'packages/shared/src/models/index.ts' ], - include: ['src/**/*.{ts,js}', 'packages/**/src/**/*.{ts,js}'] + include: ['src/**/*.{ts,js}', 'packages/**/src/**/*.{ts,js}'], + thresholds: { + statements: 80 + } }, testTimeout: 30000, maxWorkers: 1, // Required for process spawning tests