Files
tommylauren da311bfc54 chore(protect-mcp): pin protect-mcp@0.5.5 and @veritasacta/verify@0.3.0
Closes the version-pinning suggestion from @wshobson on #494. The
tamper-detection test in plugins/protect-mcp/test/run-tests.sh
previously called `npx protect-mcp@latest` and `npx @veritasacta/verify`
with no version constraint, meaning an upstream npm publish could
flip the test green or red without any repo-side signal. Pinning
eliminates that.

Changes
───────
- plugins/protect-mcp/hooks/hooks.json: 2 x
    protect-mcp@latest -> protect-mcp@0.5.5
  (PreToolUse evaluate + PostToolUse sign)

- plugins/protect-mcp/test/run-tests.sh:
    6 x protect-mcp@latest -> protect-mcp@0.5.5
    3 x @veritasacta/verify    -> @veritasacta/verify@0.3.0
  (the four PreToolUse test invocations, keygen, sign, plus the two
  verify calls in tests 7 and 8)

- Header comment at the top of run-tests.sh now mentions the pinned
  @veritasacta/verify version for clarity.

What is NOT pinned
──────────────────
README.md and SKILL.md references remain as `npx protect-mcp@latest`
and `npx @veritasacta/verify`. Those are documentation of the pattern
a user should use in their own project, and "latest" is the right
advice for that audience. The test infrastructure is the only
executed path where pinning matters for reproducibility.

How to bump
───────────
When you want to update (e.g., protect-mcp publishes 0.6.0 with a
breaking change to --input handling), update both files together:

  perl -i -pe 's/protect-mcp\@0\.5\.5/protect-mcp\@0.6.0/g' \
    plugins/protect-mcp/hooks/hooks.json \
    plugins/protect-mcp/test/run-tests.sh

Then re-run ./plugins/protect-mcp/test/run-tests.sh to confirm the
tamper-detection guard still passes before merging.

This PR does NOT touch review-agent-governance or signed-audit-trails
because those plugins are still in review (#495, #496). Once they
land, a follow-up PR will pin them too.

Tests
─────
- python3 -m json.tool hooks.json passes
- bash -n run-tests.sh passes
- No other files touched; no marketplace.json changes (avoids conflict
  with #495 and #496)
2026-04-17 20:54:55 -04:00
..

protect-mcp test fixtures

Round-trip tests for the protect-mcp plugin's PreToolUse and PostToolUse hooks. Exercises the full evaluate → sign → verify loop against deterministic fixtures, including the tamper-detection path.

Layout

test/
├── fixtures/
│   ├── test-policy.cedar                  # Cedar policy used by all tests
│   ├── pretool-allow-read.json            # Read should be permitted
│   ├── pretool-allow-bash-safe.json       # Bash "git status" should be permitted
│   ├── pretool-deny-bash-destructive.json # Bash "rm -rf /" should be denied
│   ├── pretool-deny-write.json            # Write should be denied
│   └── posttool-signing-input.json        # Input for receipt signing
├── expected/
│   └── receipt-schema.json                # Expected receipt shape (JSON Schema)
├── run-tests.sh                           # Full round-trip (requires node / npx)
└── verify-fixtures.sh                     # Static validation (python3 only)

Running

Full round-trip (local development)

./run-tests.sh

Requires node (>= 18), npx, and python3. Fetches protect-mcp and @veritasacta/verify from npm on first run. Runs eight tests:

# Scenario Expected exit
1 PreToolUse on Read 0 (permit)
2 PreToolUse on Bash git status 0 (permit)
3 PreToolUse on Bash rm -rf / 2 (forbid)
4 PreToolUse on Write 2 (forbid)
5 PostToolUse signing produces a receipt file 0 (success)
6 Produced receipt conforms to the schema 0 (valid)
7 @veritasacta/verify accepts the receipt 0 (valid)
8 Tampered receipt is rejected 1 (tampered)

Test 8 is the critical regression guard: flipping the decision field in a signed receipt must invalidate the Ed25519 signature, so @veritasacta/verify must exit 1 rather than 0.

Static validation (CI-safe)

./verify-fixtures.sh

Only requires python3. Validates that every fixture is well-formed JSON and has the expected structure. No network calls, no npm fetches. Safe to run in sandboxed or offline CI.

What the tests prove

  • Policy evaluation: Cedar permit and forbid rules produce the expected exit codes (0 / 2).
  • Receipt schema: signed receipts include every required field from draft-farley-acta-signed-receipts.
  • Signature integrity: @veritasacta/verify validates authentic receipts and rejects tampered ones, with the documented exit codes.
  • End-to-end integration: the plugin's two hooks compose into a working allow/deny + sign + verify pipeline.

Extending

To add a new test case:

  1. Drop a pretool-*.json or posttool-*.json fixture into fixtures/
  2. Add a matching rule to fixtures/test-policy.cedar if the test needs one
  3. Add an assertion block to run-tests.sh mirroring the existing ones

Follow the naming convention pretool-<allow|deny>-<scenario>.json so the intent is obvious from ls fixtures/.

Exit codes

Script Exit Meaning
run-tests.sh 0 All tests passed
run-tests.sh 1 One or more tests failed
run-tests.sh 77 Required tool missing (skipped in CI)
verify-fixtures.sh 0 All fixtures valid
verify-fixtures.sh 1 Fixture malformed
verify-fixtures.sh 77 python3 missing (skipped)

77 is the autotools convention for "skip this test" and is interpreted as a skip by most CI frameworks.