Skip to content

github-guard: bake WASM into gateway image, align test/release workflows, and rename user-facing flags to "guards"#1693

Merged
lpcox merged 14 commits intomainfrom
lpcox/github-guard
Mar 9, 2026
Merged

github-guard: bake WASM into gateway image, align test/release workflows, and rename user-facing flags to "guards"#1693
lpcox merged 14 commits intomainfrom
lpcox/github-guard

Conversation

@lpcox
Copy link
Collaborator

@lpcox lpcox commented Mar 9, 2026

  • Add guards/github-guard Rust WASM module implementing information flow control for GitHub MCP servers

    • Three WASM entrypoints: label_agent (session init from allow-only policy), label_resource (pre-execution labeling + operation type), label_response (post-execution fine-grained labeling)
    • Enforces repo-scoped access control via allow-only guard policies: repos (all, public, or glob patterns like owner/repo, owner/*, owner/prefix*) and min-integrity (none, reader, writer, merged)
    • Rust source in rust-guard/ compiled to github-guard-rust.wasm via build.sh targeting wasm32-wasip1
    • Integration test script (run_integration_tests.sh) and Copilot interactive test script (run_copilot_test.sh) with eight guard modes: yolo, all, public-only, owner-only, repo-only, prefix-only, multi-only, lockdown
    • Comprehensive docs: overview, labeling spec, secrecy/integrity specs, implementation summary, testing guide, agentic workflow policy schema
  • Bake WASM guard into Docker image at build time

    • Dockerfile: COPYs guards/github-guard/github-guard-rust.wasm/guards/github/00-github-guard.wasm in the runtime stage
    • Guard is available at container startup with no host-side volume mounts required
    • Follows gateway guard discovery path structure: /guards/{serverID}/*.wasm
  • Auto-detect baked guards in run_containerized.sh entrypoint

    • When MCP_GATEWAY_WASM_GUARDS_DIR is not explicitly set and /guards exists in the container, auto-sets MCP_GATEWAY_WASM_GUARDS_DIR=/guards
    • Explicit opt-out: set MCP_GATEWAY_WASM_GUARDS_DIR="" (empty string) to disable auto-detection (e.g. yolo/lockdown modes)
    • Extra Docker CMD args forwarded via exec "$CMD" "${FLAGS[@]}" "$@" so callers can append gateway flags without word-splitting issues
  • Simplify test scripts to use baked-guard discovery

    • run_copilot_test.sh: removed host-side WASM copy, volume mounts, and duplicate CLI flags that conflicted with entrypoint env vars; fixed routed-mode URL (/mcp/{server})
    • run_integration_tests.sh: removed explicit WASM volume mount and guard config block; relies on env var discovery
    • Local WASM file existence pre-checks removed from both scripts
  • Incremental build-gateway via Makefile stamp/dependency tracking

    • guards/github-guard/Makefile: .build-gateway-stamp file skips Docker rebuild when no relevant sources changed
    • Declared source dependencies: all Go files, go.mod/go.sum, Dockerfile, run_containerized.sh, run.sh, and all Rust guard sources (including nested src/labels/*.rs, Cargo.toml, Cargo.lock)
    • build-gateway depends on build (WASM output) so the Docker COPY always succeeds
  • Update release workflow to build Rust WASM guard before Docker publish

    • Both release.md (source spec) and release.lock.yml (generated): Rust toolchain setup uses dtolnay/rust-toolchain pinned to commit SHA f6f14b6a0eef8949dcd51cb07cdbcdaadbca9e1c # stable — no first-party Rust setup action exists in github/gh-aw/githubnext
    • Ensures github-guard-rust.wasm exists at release time for the COPY instruction in Dockerfile
  • Rename all user-facing gateway items from "difc" to "guards"

    • CLI flags: --enable-difc--enable-guards, --difc-mode--guards-mode, --difc-sink-server-ids--guards-sink-server-ids
    • Environment variables: MCP_GATEWAY_ENABLE_DIFCMCP_GATEWAY_ENABLE_GUARDS, MCP_GATEWAY_DIFC_MODEMCP_GATEWAY_GUARDS_MODE, MCP_GATEWAY_DIFC_SINK_SERVER_IDSMCP_GATEWAY_GUARDS_SINK_SERVER_IDS
    • Config file keys (TOML/JSON): enable_difcenable_guards, difc_modeguards_mode
    • Updated throughout: README.md, AGENTS.md, DIFC_RULES.md, OVERVIEW.md, config.example.toml, test scripts, and test files
    • Internal WASM protocol field difc_mode (in LabelAgentResult JSON returned by label_agent) is intentionally unchanged — it is a guard ↔ gateway protocol field, not a user-configured item
  • Fix capture_integrity_corpus.sh: add mkdir -p before writing corpus file so the script doesn't fail with set -e when guards/github-guard/src/testdata/integrity/ doesn't exist yet

  • Fix case-insensitive workflow path detection in check_file_secrecy: use path_lower (not original path) for the .github/workflows/ prefix check so workflow secrecy detection is consistent with all other path checks in the function


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

lpcox and others added 7 commits March 8, 2026 17:21
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Change default GATEWAY_IMAGE from ghcr.io/lpcox/github-guard:latest
  to local/gh-aw-mcpg (built from repo root Dockerfile)
- Add build-gateway target to guards/github-guard/Makefile
- Wire build-gateway as dependency for test-integration and test-copilot
- Remove references to missing directories (guard-sdk, noop-guard,
  agentdojo-guards) from Makefile
- Add smoke test fallback when Go integration test harness is absent
- Forward extra Docker CMD args in run_containerized.sh entrypoint

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…args

The run_copilot_test.sh was passing --listen, --config-stdin, --log-dir
as Docker CMD args, duplicating what the run_containerized.sh entrypoint
already builds from env vars. This caused flag conflicts.

Changes:
- Default to routed mode (matching /mcp/{server} URL pattern in MCP config)
- Remove duplicate CLI args; let entrypoint handle standard flags via env vars
- Only pass extra flags (--enable-difc, --enable-config-extensions) as CMD args
- Pass GATEWAY_CLI_ARGS to docker run so non-yolo flags reach the gateway

Tested: make test-copilot-yolo runs clean with no guard errors.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The WASM guard is now copied into the image at build time at
/guards/github/00-github-guard.wasm, matching the gateway's
guard discovery path structure.

Changes:
- Dockerfile: COPY WASM into /guards/github/ in runtime stage
- run_containerized.sh: auto-detect baked-in guards when
  MCP_GATEWAY_WASM_GUARDS_DIR is not explicitly set
- run_copilot_test.sh: remove host-side WASM copy and volume mount;
  set env var to /guards for guarded modes, empty for yolo/lockdown
- run_integration_tests.sh: remove WASM volume mount and explicit
  guard config block; use env var discovery instead
- Makefile: build-gateway now depends on build target to ensure
  WASM exists before Docker image is built

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The WASM guard is baked into the Docker image now, so the scripts
no longer need to check for or build the local .wasm file.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Make build-gateway incremental using a stamp file and explicit dependencies.
The image now rebuilds only when gateway Go code, Docker/entrypoint scripts,
or rust guard sources change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add Rust toolchain setup and wasm32-wasip1 target in the release docker job,
then build guards/github-guard/github-guard-rust.wasm before the Docker
multi-arch build so the baked-in guard COPY in Dockerfile always succeeds.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings March 9, 2026 03:42
@lpcox
Copy link
Collaborator Author

lpcox commented Mar 9, 2026

@copilot create a more comprehensive summary for the pr

Copy link
Contributor

Copilot AI commented Mar 9, 2026

@copilot create a more comprehensive summary for the pr

Updated the PR description with a full breakdown of all 7 commits, organized by feature area:

  • guards/github-guard Rust WASM module: covers the three WASM entrypoints (label_agent, label_resource, label_response), guard policy fields (repos, min-integrity), all eight Copilot test modes, and the accompanying docs
  • Baked WASM in Docker image: explains the COPY path (/guards/github/00-github-guard.wasm) and why it eliminates host-side volume mounts
  • Auto-detection in run_containerized.sh: documents the opt-in/opt-out behavior (MCP_GATEWAY_WASM_GUARDS_DIR="" to disable) and the CMD arg forwarding fix
  • Simplified test scripts: covers what was removed from run_copilot_test.sh and run_integration_tests.sh and why
  • Incremental build-gateway: explains the stamp file approach and declared source dependencies
  • Release workflow: documents the Rust toolchain + WASM build steps added before the multi-arch Docker push

Copilot finished work on behalf of lpcox March 9, 2026 03:45
@lpcox
Copy link
Collaborator Author

lpcox commented Mar 9, 2026

@copilot i'd like to change all user-facing gateway items like command line flags, environment variables, and documentation to use the term "guards" instead of "difc" for example, the flag "--enable-difc" should be "--enable-guards"

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR makes the GitHub Guard WASM artifact a first-class part of the MCP Gateway container story by baking the guard into the gateway image, teaching startup scripts/tests to discover baked guards automatically, and aligning the release workflow to build the Rust WASM before publishing Docker images.

Changes:

  • Bake guards/github-guard/github-guard-rust.wasm into the gateway image under /guards/github/00-github-guard.wasm and auto-detect /guards at runtime.
  • Add/refresh GitHub Guard integration + corpus-capture scripts and expand Rust guard labeling modules/docs.
  • Make gateway image builds incremental via a stamp-based Makefile and update release workflows to build the guard prior to Docker publish.

Reviewed changes

Copilot reviewed 44 out of 45 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
run_containerized.sh Auto-detect baked guards under /guards and append container CMD args when launching awmg.
guards/github-guard/scripts/run_integration_tests.sh New integration test runner that starts the gateway container and runs a Go harness or smoke tests.
guards/github-guard/scripts/capture_integrity_corpus.sh New helper to capture/refresh an integrity corpus fixture using gh api + jq.
guards/github-guard/rust-guard/src/tools.rs Tool classification helpers/constants for read/write/read-write detection.
guards/github-guard/rust-guard/src/permissions.rs Permission parsing helpers and related unit tests.
guards/github-guard/rust-guard/src/labels/tool_rules.rs Tool-specific secrecy/integrity labeling rules and sensitive-path handling.
guards/github-guard/rust-guard/src/labels/response_paths.rs Path-based (JSON Pointer) response labeling implementation.
guards/github-guard/rust-guard/src/labels/response_items.rs Legacy item-cloning response labeling implementation.
guards/github-guard/rust-guard/src/labels/constants.rs Centralized label constants, field names, and size/limit constants.
guards/github-guard/rust-guard/src/labels/README.md Documentation for the refactored labels module structure and design decisions.
guards/github-guard/rust-guard/build.sh Rust WASM build script (wasm32-wasip1) and artifact copy-out.
guards/github-guard/rust-guard/README.md Rust guard overview, build instructions, and architecture notes.
guards/github-guard/rust-guard/Cargo.toml Rust crate manifest for the WASM guard.
guards/github-guard/rust-guard/Cargo.lock Rust dependency lockfile for the guard.
guards/github-guard/rust-guard/.gitignore Ignore Rust build artifacts and local wasm outputs under rust-guard/.
guards/github-guard/rust-guard/.cargo/config.toml WASM runner config for local execution via wasmtime.
guards/github-guard/docs/agentic-workflow-policy.schema.json JSON Schema for allow-only frontmatter policy.
guards/github-guard/docs/TEST_SUMMARY.md Summary of test coverage and how to run tests.
guards/github-guard/docs/TESTING.md Comprehensive testing guide and modes.
guards/github-guard/docs/SECURITY_SUMMARY.md Security posture summary and recommendations.
guards/github-guard/docs/SECRECY_TAG_SPEC.md Secrecy tag spec and derivation rules.
guards/github-guard/docs/QUICKSTART.md Quickstart for building guard + local gateway image and running tests.
guards/github-guard/docs/OVERVIEW.md End-to-end system overview and operating modes.
guards/github-guard/docs/LABEL_AGENT_IMPLEMENTATION_PLAN.md Plan/spec for label_agent interface and policy mapping.
guards/github-guard/docs/LABELING.md DIFC labeling spec for GitHub objects and tools.
guards/github-guard/docs/INTEGRITY_TAG_SPEC.md Integrity tag spec (hard cutover) and derivation rules.
guards/github-guard/docs/IMPLEMENTATION_SUMMARY.md Implementation summary for guard architecture and labeling.
guards/github-guard/docs/IMPLEMENTATION.md Full implementation doc for guard behavior and structure.
guards/github-guard/docs/GATEWAY_FIX.md Gateway/guard interface notes and proposed fixes for label_response wrapping.
guards/github-guard/docs/GATEWAY_ALLOWONLY_INTEGRATION_SPEC.md Integration spec for AllowOnly policies and gateway changes.
guards/github-guard/docs/CROSS_REPO_RELEASE.md Documentation for cross-repo release workflow and publishing flow.
guards/github-guard/docs/AGENTIC_WORKFLOW_POLICY_FRONTMATTER.md Proposed policy shape and strict schema (frontmatter).
guards/github-guard/README.md Top-level GitHub Guard documentation and operating modes.
guards/github-guard/Makefile Build/test automation + incremental gateway image build using a stamp file.
guards/github-guard/LICENSE MIT license for the guard subtree.
guards/github-guard/.gitignore Ignore the stamp file used by incremental gateway builds.
Dockerfile Copy baked guard into /guards/github/00-github-guard.wasm in the runtime image.
.github/workflows/release.md Build the Rust WASM guard before Docker build/publish in the release workflow.
.github/workflows/release.lock.yml Lockfile workflow updated to install Rust target and build the baked guard pre-publish.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +279 to +282
- name: Set up Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: wasm32-wasip1
Copy link

Copilot AI Mar 9, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new Set up Rust step uses the third-party GitHub Action dtolnay/rust-toolchain@stable, which is pinned only to the mutable stable ref in a release pipeline. If that action or its tag is compromised, an attacker could run arbitrary code in this job, exfiltrate GITHUB_TOKEN, or tamper with built images and release artifacts. To reduce this supply-chain risk, pin the action to a specific commit SHA (or switch to an officially maintained setup action pinned to a stable major tag) so the exact code being executed in the release job is immutable and auditable.

Copilot uses AI. Check for mistakes.
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot open a new pull request to apply changes based on this feedback But also check if there is a first-party action for rust setup from github githubnext or gh-aw

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Checked github/gh-aw, githubnext, and github-actions — no first-party Rust setup action exists in any of those orgs. The github/gh-aw/actions/setup action is for gh-aw CLI setup only.

Pinned dtolnay/rust-toolchain@stabledtolnay/rust-toolchain@f6f14b6a0eef8949dcd51cb07cdbcdaadbca9e1c # stable in release.md (commit f4e7147), matching the SHA already present in the generated release.lock.yml. Both files are now consistent.

lpcox and others added 4 commits March 8, 2026 20:50
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
…g keys, and docs

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Mar 9, 2026

@copilot i'd like to change all user-facing gateway items like command line flags, environment variables, and documentation to use the term "guards" instead of "difc" for example, the flag "--enable-d...

Done in commit 570d0d4. All user-facing items have been renamed from difc to guards:

CLI flags: --enable-difc--enable-guards, --difc-mode--guards-mode, --difc-sink-server-ids--guards-sink-server-ids

Env vars: MCP_GATEWAY_ENABLE_DIFCMCP_GATEWAY_ENABLE_GUARDS, MCP_GATEWAY_DIFC_MODEMCP_GATEWAY_GUARDS_MODE, MCP_GATEWAY_DIFC_SINK_SERVER_IDSMCP_GATEWAY_GUARDS_SINK_SERVER_IDS

Config file keys (TOML/JSON): enable_difcenable_guards, difc_modeguards_mode

Docs/scripts: README.md, AGENTS.md, DIFC_RULES.md, OVERVIEW.md, config.example.toml, run_copilot_test.sh, run_integration_tests.sh, and the test files updated throughout.

The internal WASM protocol field difc_mode (in the JSON returned by label_agent) is intentionally left as-is — it's part of the guard ↔ gateway protocol, not a user-configured item.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • example.com
    • Triggering command: /tmp/go-build2074544038/b332/launcher.test /tmp/go-build2074544038/b332/launcher.test -test.testlogfile=/tmp/go-build2074544038/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo1.25.7 (dns block)
    • Triggering command: /tmp/go-build127011177/b336/launcher.test /tmp/go-build127011177/b336/launcher.test -test.testlogfile=/tmp/go-build127011177/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/b3/b33e11975f6834abc27239b3540c3eece53e80c4b3cdb208b7fa291822ecdbde-d se 4544038/b065/vet.cfg g_.a --gdwarf-5 --64 -o ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile -I 4544038/b226/_pkg_.a -fPIC x_amd64/vet -pthread b/gh-aw-mcpg/int-atomic -fmessage-length-bool x_amd64/vet (dns block)
  • invalid-host-that-does-not-exist-12345.com
    • Triggering command: /tmp/go-build2074544038/b314/config.test /tmp/go-build2074544038/b314/config.test -test.testlogfile=/tmp/go-build2074544038/b314/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-p l2B4YBBT9 cal/bin/bash (dns block)
    • Triggering command: /tmp/go-build127011177/b318/config.test /tmp/go-build127011177/b318/config.test -test.testlogfile=/tmp/go-build127011177/b318/testlog.txt -test.paniconexit0 -test.timeout=10m0s s-th�� /testutil/mcptest/config.go /testutil/mcptest/driver.go .cfg . --gdwarf2 (dns block)
  • nonexistent.local
    • Triggering command: /tmp/go-build2074544038/b332/launcher.test /tmp/go-build2074544038/b332/launcher.test -test.testlogfile=/tmp/go-build2074544038/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo1.25.7 (dns block)
    • Triggering command: /tmp/go-build127011177/b336/launcher.test /tmp/go-build127011177/b336/launcher.test -test.testlogfile=/tmp/go-build127011177/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/b3/b33e11975f6834abc27239b3540c3eece53e80c4b3cdb208b7fa291822ecdbde-d se 4544038/b065/vet.cfg g_.a --gdwarf-5 --64 -o ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile -I 4544038/b226/_pkg_.a -fPIC x_amd64/vet -pthread b/gh-aw-mcpg/int-atomic -fmessage-length-bool x_amd64/vet (dns block)
  • slow.example.com
    • Triggering command: /tmp/go-build2074544038/b332/launcher.test /tmp/go-build2074544038/b332/launcher.test -test.testlogfile=/tmp/go-build2074544038/b332/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/cgo1.25.7 (dns block)
    • Triggering command: /tmp/go-build127011177/b336/launcher.test /tmp/go-build127011177/b336/launcher.test -test.testlogfile=/tmp/go-build127011177/b336/testlog.txt -test.paniconexit0 -test.timeout=10m0s /home/REDACTED/.cache/go-build/b3/b33e11975f6834abc27239b3540c3eece53e80c4b3cdb208b7fa291822ecdbde-d se 4544038/b065/vet.cfg g_.a --gdwarf-5 --64 -o ache/go/1.25.7/x64/pkg/tool/linux_amd64/compile -I 4544038/b226/_pkg_.a -fPIC x_amd64/vet -pthread b/gh-aw-mcpg/int-atomic -fmessage-length-bool x_amd64/vet (dns block)
  • this-host-does-not-exist-12345.com
    • Triggering command: /tmp/go-build2074544038/b341/mcp.test /tmp/go-build2074544038/b341/mcp.test -test.testlogfile=/tmp/go-build2074544038/b341/testlog.txt -test.paniconexit0 -test.timeout=10m0s -test.v=true 64/src/runtime/c-p ODE/GATEWAY_GUARgo/parser x_amd64/asm rds mode:/g ard/scripts/run_-unsafeptr=false (dns block)
    • Triggering command: /tmp/go-build127011177/b345/mcp.test /tmp/go-build127011177/b345/mcp.test -test.testlogfile=/tmp/go-build127011177/b345/testlog.txt -test.paniconexit0 -test.timeout=10m0s (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title github-guard: bake WASM into gateway image and align test/release workflows github-guard: bake WASM into gateway image, align test/release workflows, and rename user-facing flags to "guards" Mar 9, 2026
Copilot finished work on behalf of lpcox March 9, 2026 04:00
…pus.sh

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copy link
Contributor

Copilot AI commented Mar 9, 2026

@copilot create a more comprehensive summary for the pr

Updated the PR description with a full breakdown organized by feature area — covering the Rust WASM module and its three entrypoints, baked-guard Docker integration, auto-detection in the entrypoint script, simplified test scripts, incremental Makefile stamp tracking, pinned release workflow actions, the difc→guards rename, and the two script/Rust bug fixes.

@copilot i'd like to change all user-facing gateway items like command line flags, environment variables, and documentation to use the term "guards" instead of "difc" for example, the flag "--enable-d...

Done — all user-facing items renamed from difc to guards: CLI flags (--enable-guards, --guards-mode, --guards-sink-server-ids), env vars (MCP_GATEWAY_ENABLE_GUARDS, MCP_GATEWAY_GUARDS_MODE, MCP_GATEWAY_GUARDS_SINK_SERVER_IDS), config keys (enable_guards, guards_mode), and docs/scripts throughout. The internal WASM protocol field difc_mode is left unchanged as it's part of the guard ↔ gateway protocol, not user-configured.

Co-authored-by: lpcox <15877973+lpcox@users.noreply.github.com>
Copilot finished work on behalf of lpcox March 9, 2026 15:25
@lpcox lpcox merged commit 62d05f5 into main Mar 9, 2026
13 of 14 checks passed
@lpcox lpcox deleted the lpcox/github-guard branch March 9, 2026 15:29
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