Skip to content

feat(security): validate offline MCP catalog approval pins - #2408

Merged
groupthinking merged 4 commits into
mainfrom
security/mcp-catalog-approval-2407
Oct 12, 2026
Merged

groupthinking merged 4 commits into
mainfrom
security/mcp-catalog-approval-2407

Conversation

@groupthinking

@groupthinking groupthinking commented Oct 12, 2026 •

Copy link
Copy Markdown
Owner

Closes #2407

Bounded follow-up to #2349 / GRV-780; the parent remains open.

Recorded MCP catalogs previously had an identity-bound hash but no approval comparator. Add a fixture-only CLI that exits zero only when a complete capture exactly matches a separately reviewed approved pin. Split schema/description digests explain drift; the full catalog/tool hashes still block every contract change, including metadata and annotations. Diagnostics emit hashes/codes only. No RugSnare dependency or copied code, server execution, credential lookup, active configuration change or deployment.

The reviewed pin is a trusted file, not a signature. Caller-supplied identity still needs independent provenance/configuration binding. Real capture, launcher containment, credential migration and active runtime/CI enforcement remain in the parent; inventory catalog values are not fabricated.

Local validation on current main 33a3a47e314dbc5d1aff2f5e8a7ccc8f7a684a78 plus exact update head e7e06c0e28182f6eede0ecc11b87345990f4cc4b: 12 stdlib offline security tests passed with sockets/DNS/subprocess creation forbidden; 36 workflow-gate tests passed; the extracted GitHub Script body compiled; git diff --check passed. All six PR paths classify needs_preview=false.

Fresh exact-head GitHub result: 28 successful checks and two expected skips, with zero failures and zero pending checks. The required E2E job passed through its explicit not-applicable path: deployment classification and the N/A receipt passed; preview lookup, dependency installation, live E2E execution, result parsing/commenting and the live green-signal step were skipped. Copilot reports zero open findings and GitHub reports zero review threads. This is check evidence, not production-deployment evidence.

Risk: medium, security validation logic; fail-closed on malformed, unapproved, or incompletely listed data. Rollback: revert this patch. Production evidence is not applicable to an offline validator. Exact-head gates passed; squash merge remains separately gated. Parent #2349 remains open.

Copilot AI balanced review requested due to automatic review settings October 12, 2026 12:50
@vercel

vercel Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
v0-uvai Ready Ready Preview, v0 Oct 12, 2026 4:31pm UTC

@github-actions github-actions Bot added ci/cd documentation Improvements or additions to documentation python labels Oct 12, 2026
@coderabbitai

coderabbitai Bot commented Oct 12, 2026 •

Copy link
Copy Markdown
Contributor

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Repository: groupthinking/EventRelay/.coderabbit.yaml
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 98b32735-4c0b-42ce-9e1a-3f98c5273a1c

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Repository reconciliation: this PR does not reference exactly one canonical issue.

Please add a Closes #<issue> reference in the PR description so it can be tracked against the delivery plan.

See governance: #898

Copy link
Copy Markdown
Owner Author

Exact-head execution receipt: fetched and checked out 431486879bb6c9ac2c63eb72559ff4f1ab6e1d76, then ran python -m unittest discover -s tests/security -p test_mcp_catalog_approval.py -v: 11 tests, OK, exit 0. git diff --check: exit 0. Sockets, DNS and subprocess creation are prohibited by the fixture guard. Existing pytest inventory regressions cannot run locally: No module named pytest; they are wired into the CI Python matrix.

Merge HOLD: current-head workflows and independent review are pending. Ruleset 24057160 requires Closing keyword to open issue; classic branch-protection read returned HTTP 403 Resource not accessible by integration. Do not infer that inaccessible requirements are absent. No parent closure or production deployment is claimed.

@github-actions

Copy link
Copy Markdown
Contributor

✅ E2E Test Results: ALL TESTS PASSED

Metric Value
Status 🟢 GREEN
Total Tests
Passed 16
Failed
Deployment https://v0-uvai-hd6fcest8-garv1.vercel.app
Test Output
very request without persisting it�[32m 1�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mhomepage returns 200 with HTML�[32m 286�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mfeatures page contains template/workflow markup�[33m 308�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mfeatures page surfaces at least 5 workflow/template indicators�[32m 249�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mVideo Pack Pipeline�[2m > �[22mPOST /api/video/pack accepts a YouTube URL without hanging�[33m 2246�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mVideo Pack Pipeline�[2m > �[22mGET /api/video/pack resolves to a ready pack with evidence lineage�[33m 787�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22mmissing URL returns 400, not a hang�[32m 174�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22minvalid URL returns 400 quickly, not a hang�[32m 190�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22mPOST /api/video/pack with no body returns 400�[32m 185�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mDashboard�[2m > �[22m/dashboard returns 200�[32m 242�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mDashboard�[2m > �[22m/dashboard contains agent or pipeline visualization markup�[32m 188�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mAPI Health�[2m > �[22mGET /api returns a response (not 404)�[33m 340�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mAPI Health�[2m > �[22mretired /api/pipeline routes are gone (no pipeline served)�[32m 103�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mStatic Assets�[2m > �[22mhomepage has proper meta tags�[32m 192�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mStatic Assets�[2m > �[22m/features page returns 200�[32m 197�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m1 passed�[39m�[22m�[90m (1)�[39m
�[2m      Tests �[22m �[1m�[32m16 passed�[39m�[22m�[90m (16)�[39m
�[2m   Start at �[22m 12:51:44
�[2m   Duration �[22m 7.54s�[2m (transform 42ms, setup 0ms, import 54ms, tests 7.37s, environment 0ms)�[22m


Copy link
Copy Markdown
Owner Author

CI evidence update for unchanged head 431486879bb6c9ac2c63eb72559ff4f1ab6e1d76: Python 3.11 job ran the combined inventory/approval suite: 37 passed, 20 subtests passed in 0.08s. Dependency-free offline job also passed all 11 tests (checkout merge ref cd9e546f8119b22c76763defe0cd977a20a70bc5).

Latest merge HOLD: Python 3.10/3.12, build, Trivy and independent reviews still pending; classic branch-protection requirements remain unreadable (403). PR is unmerged, mergeable but unstable. Parent #2349 freshly verified open. Do not interpret a skipped automated review or a successful scanner job alone as security approval.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🔵 Needs a closer look

Security-sensitive trusted-pin logic warrants final human review and completion of the pending exact-head gates.

0 open findings

What changed in this PR

Adds an offline, fail-closed validator for comparing recorded MCP tool catalogs against reviewed approval pins.

Changes:

  • Adds identity-bound catalog comparison and drift diagnostics.
  • Adds hermetic tests covering malformed input and contract drift.
  • Adds CI enforcement and documents the trusted-pin boundary.
File Description
scripts/​security/​audit_local_mcp_configs.py Implements catalog records and approval comparison.
scripts/​security/​validate_mcp_catalog.py Provides the offline validation CLI.
tests/​security/​test_mcp_catalog_approval.py Tests matching, drift, redaction, and malformed inputs.
artifacts/​security/​local-mcp-catalog-approval.md Documents approval semantics and limitations.
artifacts/​security/​local-mcp-audit-stage-one.md References the new comparison stage.
.github/​workflows/​ci.yml Runs catalog regressions in CI.

🧠 Review effort: Balanced


💡 Configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

@groupthinking
groupthinking force-pushed the security/mcp-catalog-approval-2407 branch from 0c6026c to 4314868 Compare October 12, 2026 14:57
@github-actions

Copy link
Copy Markdown
Contributor

✅ E2E Test Results: ALL TESTS PASSED

Metric Value
Status 🟢 GREEN
Total Tests
Passed 16
Failed
Deployment https://v0-uvai-hd6fcest8-garv1.vercel.app
Test Output
y request without persisting it�[32m 1�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mhomepage returns 200 with HTML�[33m 376�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mfeatures page contains template/workflow markup�[33m 301�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mTemplate Gallery�[2m > �[22mfeatures page surfaces at least 5 workflow/template indicators�[32m 251�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mVideo Pack Pipeline�[2m > �[22mPOST /api/video/pack accepts a YouTube URL without hanging�[33m 2611�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mVideo Pack Pipeline�[2m > �[22mGET /api/video/pack resolves to a ready pack with evidence lineage�[33m 813�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22mmissing URL returns 400, not a hang�[32m 197�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22minvalid URL returns 400 quickly, not a hang�[32m 217�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mError Handling�[2m > �[22mPOST /api/video/pack with no body returns 400�[32m 191�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mDashboard�[2m > �[22m/dashboard returns 200�[32m 284�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mDashboard�[2m > �[22m/dashboard contains agent or pipeline visualization markup�[32m 232�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mAPI Health�[2m > �[22mGET /api returns a response (not 404)�[33m 1391�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mAPI Health�[2m > �[22mretired /api/pipeline routes are gone (no pipeline served)�[32m 108�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mStatic Assets�[2m > �[22mhomepage has proper meta tags�[32m 269�[2mms�[22m�[39m
 �[32m✓�[39m tests/e2e/pipeline.test.ts�[2m > �[22mEventRelay E2E — Live Deployment�[2m > �[22mStatic Assets�[2m > �[22m/features page returns 200�[32m 243�[2mms�[22m�[39m

�[2m Test Files �[22m �[1m�[32m1 passed�[39m�[22m�[90m (1)�[39m
�[2m      Tests �[22m �[1m�[32m16 passed�[39m�[22m�[90m (16)�[39m
�[2m   Start at �[22m 14:58:07
�[2m   Duration �[22m 10.36s�[2m (transform 45ms, setup 0ms, import 57ms, tests 10.19s, environment 0ms)�[22m


Add test to verify significance of schema array order.
@groupthinking
groupthinking merged commit a40dbb3 into main Oct 12, 2026
34 checks passed
@groupthinking
groupthinking deleted the security/mcp-catalog-approval-2407 branch October 12, 2026 15:55
@linear-code

linear-code Bot commented Oct 12, 2026

Copy link
Copy Markdown
Contributor

GRV-813

This branch was successfully deployed

1 active deployment
Preview — e7e06c0e Deployed Oct 12, 2026 by vercel[bot]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ci/cd documentation Improvements or additions to documentation python

Projects

None yet

Development

Successfully merging this pull request may close these issues.

security: validate recorded MCP catalogs against reviewed approvals

2 participants