mcp-warden-cli 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mcp_warden_cli-1.0.0/.github/ISSUE_TEMPLATE/bug_report.yml +75 -0
- mcp_warden_cli-1.0.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- mcp_warden_cli-1.0.0/.github/ISSUE_TEMPLATE/feature_request.yml +52 -0
- mcp_warden_cli-1.0.0/.github/PULL_REQUEST_TEMPLATE.md +39 -0
- mcp_warden_cli-1.0.0/.github/dependabot.yml +24 -0
- mcp_warden_cli-1.0.0/.github/workflows/action-test.yml +147 -0
- mcp_warden_cli-1.0.0/.github/workflows/deps-locked.yml +88 -0
- mcp_warden_cli-1.0.0/.github/workflows/docs.yml +81 -0
- mcp_warden_cli-1.0.0/.github/workflows/examples.yml +95 -0
- mcp_warden_cli-1.0.0/.github/workflows/integrity-gate.yml +230 -0
- mcp_warden_cli-1.0.0/.github/workflows/release.yml +188 -0
- mcp_warden_cli-1.0.0/.github/workflows/sigstore-fixture.yml +76 -0
- mcp_warden_cli-1.0.0/.gitignore +25 -0
- mcp_warden_cli-1.0.0/.gitleaks.toml +20 -0
- mcp_warden_cli-1.0.0/.hypothesis/.gitignore +9 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/0ac87047b2101d00 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/0f78f4c5dfc3ec68 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1123ff8c7df61a75 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/166123028c09ce5a +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/19963d50c188fc89 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1bc4420e557a4a6c +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1d320fe167a83e7e +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1d37c2b81416c9cc +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1d92178d356cd006 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/1eb1d2091c42d146 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/22c9161fb29ccd1d +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/2861c475f8f6640d +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/2c648f5ece25bf1b +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/2fb82bfa0bdf25f4 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/31b7090f6083b3de +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/38879f4735819604 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/3a5c232418138d5e +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/4c60a6d5813c6026 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/54fa25d1048e526f +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/56c2321fd144ff81 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/5abdd8a8fa0f26a8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/5d68adf45561bab8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/5e6c439c06f8166c +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/63088e1987514d1f +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/67da63c67def28cd +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/6985dbd48e79fe50 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/6e92e55af0b43dac +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/6f8e50d9bba46424 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/752d20f4d08bbab8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/77188865a8b89606 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/7c0227c1543cf1a7 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/7c609014e505cdb7 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/7dae633ad6beb312 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/818b5634372ffcc0 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/822d60e72b73ac67 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/86dc3a317f141aa1 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/88a6443235d3c4c3 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/8c3092a523c48b3d +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/8dbbda4799fecb3b +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/9504269672cd5922 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/96702b7d6cc0aac4 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/9c31cd3a5545e4b8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/9e3dbdc584aee45b +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/a1b74dede9492584 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/a2d7b9dcf7c963e8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/a46cdf2d81318187 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ab70b0843c8efda8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ac3a6c5416518fdc +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ae9bcc4de55ea6df +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/b2b4900e07439276 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/b63b352e6de46daa +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/bfd5fd085ec158e1 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/c348f06ef4dc9bbf +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/c7eb1b39a3fecbe8 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/c7ff6b7c362ffdaa +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/c8c7f4b8a3ba3756 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/cba21f149513281d +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ce757813990c427f +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/cf4860dbd577fa02 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/d2d2e0b391659f5e +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/d7dd46e3ab67e9f2 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/d8a6e73ca1695f6c +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/e4dc134db43a698a +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/e91e67a53a5aa4c6 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ea25419afd56349e +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/f6adf5c5dc4d4d5f +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/fce0200863b3c581 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/constants/ffa00c565d1a3509 +4 -0
- mcp_warden_cli-1.0.0/.hypothesis/unicode_data/15.1.0/charmap.json.gz +0 -0
- mcp_warden_cli-1.0.0/.hypothesis/unicode_data/15.1.0/codec-utf-8.json.gz +0 -0
- mcp_warden_cli-1.0.0/.pre-commit-hooks.yaml +27 -0
- mcp_warden_cli-1.0.0/CHANGELOG.md +128 -0
- mcp_warden_cli-1.0.0/CODEOWNERS +12 -0
- mcp_warden_cli-1.0.0/CODE_OF_CONDUCT.md +133 -0
- mcp_warden_cli-1.0.0/CONTRIBUTING.md +222 -0
- mcp_warden_cli-1.0.0/DOCUMENTATION_INDEX.md +184 -0
- mcp_warden_cli-1.0.0/LICENSE +21 -0
- mcp_warden_cli-1.0.0/Makefile +23 -0
- mcp_warden_cli-1.0.0/PKG-INFO +517 -0
- mcp_warden_cli-1.0.0/README.md +493 -0
- mcp_warden_cli-1.0.0/RELEASING.md +178 -0
- mcp_warden_cli-1.0.0/SECURITY.md +139 -0
- mcp_warden_cli-1.0.0/SYSTEM_CONTEXT_DIAGRAM.md +195 -0
- mcp_warden_cli-1.0.0/action/build-requirements.lock +22 -0
- mcp_warden_cli-1.0.0/action/requirements.lock +664 -0
- mcp_warden_cli-1.0.0/action.yml +263 -0
- mcp_warden_cli-1.0.0/docs/CHECKS.md +294 -0
- mcp_warden_cli-1.0.0/docs/GUARD_PROXY.md +499 -0
- mcp_warden_cli-1.0.0/docs/GUARD_PROXY_V3.md +499 -0
- mcp_warden_cli-1.0.0/docs/POLICY_MODEL.md +262 -0
- mcp_warden_cli-1.0.0/docs/RESULT_INSPECTION.md +404 -0
- mcp_warden_cli-1.0.0/docs/SIGNING.md +272 -0
- mcp_warden_cli-1.0.0/docs/SPEC.md +499 -0
- mcp_warden_cli-1.0.0/docs/THREAT_MODEL.md +321 -0
- mcp_warden_cli-1.0.0/docs/THREAT_MODEL_V2.md +257 -0
- mcp_warden_cli-1.0.0/docs/WARDEN_LOCK_EXAMPLE.md +58 -0
- mcp_warden_cli-1.0.0/docs/WARDEN_LOCK_SCHEMA.md +501 -0
- mcp_warden_cli-1.0.0/docs-site/checklist.md +91 -0
- mcp_warden_cli-1.0.0/docs-site/comparison.md +101 -0
- mcp_warden_cli-1.0.0/docs-site/index.md +34 -0
- mcp_warden_cli-1.0.0/docs-site/lock-format.md +63 -0
- mcp_warden_cli-1.0.0/docs-site/pin-in-ci.md +137 -0
- mcp_warden_cli-1.0.0/docs-site/quickstart.md +98 -0
- mcp_warden_cli-1.0.0/docs-site/rug-pull.md +67 -0
- mcp_warden_cli-1.0.0/docs-site/tool-poisoning.md +74 -0
- mcp_warden_cli-1.0.0/examples/README.md +55 -0
- mcp_warden_cli-1.0.0/examples/github-actions/matrix-multiple-servers.yml +45 -0
- mcp_warden_cli-1.0.0/examples/github-actions/pin-on-merge-check-on-pr.yml +57 -0
- mcp_warden_cli-1.0.0/examples/github-actions/private-repo-no-sarif.yml +38 -0
- mcp_warden_cli-1.0.0/examples/github-actions/sarif-upload.yml +38 -0
- mcp_warden_cli-1.0.0/examples/gitlab-ci/.gitlab-ci.yml +33 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-everything/README.md +43 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-everything/warden.lock +581 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-memory/README.md +47 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-memory/warden.lock +555 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-sequential-thinking/README.md +39 -0
- mcp_warden_cli-1.0.0/examples/pinned-servers/server-sequential-thinking/warden.lock +173 -0
- mcp_warden_cli-1.0.0/examples/pre-commit/.pre-commit-config.yaml +29 -0
- mcp_warden_cli-1.0.0/mkdocs.yml +73 -0
- mcp_warden_cli-1.0.0/pyproject.toml +54 -0
- mcp_warden_cli-1.0.0/requirements-dev.lock +694 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/__init__.py +25 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/capture.py +197 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/check_core.py +98 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/checks.py +163 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/checks_secret.py +129 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/checks_supply.py +146 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/cli.py +367 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/cli_diff.py +245 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/cli_guard.py +301 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/cli_lock.py +124 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/cli_sign.py +304 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/drift.py +272 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/emit_res.py +102 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/emitters.py +169 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/framing.py +338 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard.py +397 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_banner.py +211 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_io.py +70 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_lifecycle.py +320 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_list_gate.py +95 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_loop.py +332 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_result.py +249 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/guard_strict.py +159 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/hashing.py +102 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/inspector.py +169 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/lockfile.py +299 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/models.py +300 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/net_rules.py +80 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/policy_eval.py +264 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/policy_model.py +261 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/precommit.py +259 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/provenance.py +199 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/redact.py +52 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/res_catalog.py +198 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/res_net.py +227 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/res_rules.py +176 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/result_inspection.py +201 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/schema_diff.py +548 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/signing.py +291 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/tokenizer.py +199 -0
- mcp_warden_cli-1.0.0/src/mcp_warden/wire_block.py +258 -0
- mcp_warden_cli-1.0.0/tests/__init__.py +0 -0
- mcp_warden_cli-1.0.0/tests/fixtures/clean.warden.lock +141 -0
- mcp_warden_cli-1.0.0/tests/fixtures/clean_listchange.warden.lock +35 -0
- mcp_warden_cli-1.0.0/tests/fixtures/clean_server.py +76 -0
- mcp_warden_cli-1.0.0/tests/fixtures/crash_server.py +66 -0
- mcp_warden_cli-1.0.0/tests/fixtures/fault_guard_launcher.py +91 -0
- mcp_warden_cli-1.0.0/tests/fixtures/listchange_server.py +111 -0
- mcp_warden_cli-1.0.0/tests/fixtures/mutated_server.py +96 -0
- mcp_warden_cli-1.0.0/tests/fixtures/overcap_server.py +178 -0
- mcp_warden_cli-1.0.0/tests/fixtures/poison_server.py +70 -0
- mcp_warden_cli-1.0.0/tests/fuzz/__init__.py +8 -0
- mcp_warden_cli-1.0.0/tests/fuzz/conftest.py +74 -0
- mcp_warden_cli-1.0.0/tests/fuzz/test_fuzz_ansi.py +188 -0
- mcp_warden_cli-1.0.0/tests/fuzz/test_fuzz_domain.py +186 -0
- mcp_warden_cli-1.0.0/tests/fuzz/test_fuzz_framing.py +393 -0
- mcp_warden_cli-1.0.0/tests/fuzz/test_fuzz_redact.py +153 -0
- mcp_warden_cli-1.0.0/tests/test_action_yml.py +138 -0
- mcp_warden_cli-1.0.0/tests/test_checks.py +180 -0
- mcp_warden_cli-1.0.0/tests/test_cli_version.py +61 -0
- mcp_warden_cli-1.0.0/tests/test_diff.py +249 -0
- mcp_warden_cli-1.0.0/tests/test_drift.py +254 -0
- mcp_warden_cli-1.0.0/tests/test_e2e_pin_check.py +121 -0
- mcp_warden_cli-1.0.0/tests/test_emitters.py +144 -0
- mcp_warden_cli-1.0.0/tests/test_framing.py +152 -0
- mcp_warden_cli-1.0.0/tests/test_guard_banner.py +337 -0
- mcp_warden_cli-1.0.0/tests/test_guard_platform.py +203 -0
- mcp_warden_cli-1.0.0/tests/test_guard_posture.py +155 -0
- mcp_warden_cli-1.0.0/tests/test_guard_proxy.py +228 -0
- mcp_warden_cli-1.0.0/tests/test_guard_strict.py +976 -0
- mcp_warden_cli-1.0.0/tests/test_guard_v3.py +430 -0
- mcp_warden_cli-1.0.0/tests/test_hashing.py +82 -0
- mcp_warden_cli-1.0.0/tests/test_inspect_parity.py +105 -0
- mcp_warden_cli-1.0.0/tests/test_inspection_policy.py +154 -0
- mcp_warden_cli-1.0.0/tests/test_lockfile.py +173 -0
- mcp_warden_cli-1.0.0/tests/test_policy.py +299 -0
- mcp_warden_cli-1.0.0/tests/test_precommit.py +386 -0
- mcp_warden_cli-1.0.0/tests/test_provenance.py +250 -0
- mcp_warden_cli-1.0.0/tests/test_result_inspection.py +243 -0
- mcp_warden_cli-1.0.0/tests/test_schema_diff.py +262 -0
- mcp_warden_cli-1.0.0/tests/test_schema_diff_refs.py +428 -0
- mcp_warden_cli-1.0.0/tests/test_signing.py +613 -0
- mcp_warden_cli-1.0.0/tests/test_spec_consistency.py +142 -0
- mcp_warden_cli-1.0.0/tests/test_tokenizer.py +61 -0
- mcp_warden_cli-1.0.0/tests/test_wire_block.py +61 -0
- mcp_warden_cli-1.0.0/tests/test_workflow_pins.py +111 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
name: 🐛 Bug report
|
|
2
|
+
description: Report a defect in mcp-warden (NOT a security vulnerability)
|
|
3
|
+
labels: ["bug", "triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
⚠️ **Do not report security vulnerabilities here.** If this is a way to
|
|
9
|
+
bypass a control mcp-warden claims to enforce (drift slips through, a real
|
|
10
|
+
secret is emitted unredacted, a poisoned result evades the block tier),
|
|
11
|
+
report it privately per [SECURITY.md](https://github.com/ernestprovo23/mcp-warden/blob/main/SECURITY.md).
|
|
12
|
+
- type: checkboxes
|
|
13
|
+
id: prechecks
|
|
14
|
+
attributes:
|
|
15
|
+
label: Pre-flight
|
|
16
|
+
options:
|
|
17
|
+
- label: This is a functional bug, not a security vulnerability.
|
|
18
|
+
required: true
|
|
19
|
+
- label: I searched existing issues and this is not a duplicate.
|
|
20
|
+
required: true
|
|
21
|
+
- label: I can reproduce this on the latest release or `main`.
|
|
22
|
+
required: true
|
|
23
|
+
- type: input
|
|
24
|
+
id: version
|
|
25
|
+
attributes:
|
|
26
|
+
label: mcp-warden version
|
|
27
|
+
description: Output of `mcp-warden --version`, or the commit SHA.
|
|
28
|
+
placeholder: "1.0.0"
|
|
29
|
+
validations:
|
|
30
|
+
required: true
|
|
31
|
+
- type: dropdown
|
|
32
|
+
id: command
|
|
33
|
+
attributes:
|
|
34
|
+
label: Which command?
|
|
35
|
+
options:
|
|
36
|
+
- pin
|
|
37
|
+
- check
|
|
38
|
+
- policy
|
|
39
|
+
- guard
|
|
40
|
+
- inspect
|
|
41
|
+
- other / not sure
|
|
42
|
+
validations:
|
|
43
|
+
required: true
|
|
44
|
+
- type: textarea
|
|
45
|
+
id: repro
|
|
46
|
+
attributes:
|
|
47
|
+
label: Reproduction
|
|
48
|
+
description: >
|
|
49
|
+
Exact command(s) and flags, plus a minimal MCP server fixture, `warden.lock`,
|
|
50
|
+
policy file, or `trace.jsonl` that reproduces it. **Strip or fake any real
|
|
51
|
+
secrets first.**
|
|
52
|
+
render: shell
|
|
53
|
+
validations:
|
|
54
|
+
required: true
|
|
55
|
+
- type: textarea
|
|
56
|
+
id: expected
|
|
57
|
+
attributes:
|
|
58
|
+
label: Expected behavior
|
|
59
|
+
validations:
|
|
60
|
+
required: true
|
|
61
|
+
- type: textarea
|
|
62
|
+
id: actual
|
|
63
|
+
attributes:
|
|
64
|
+
label: Actual behavior
|
|
65
|
+
description: Include the full output / exit code. Redact anything sensitive.
|
|
66
|
+
validations:
|
|
67
|
+
required: true
|
|
68
|
+
- type: textarea
|
|
69
|
+
id: env
|
|
70
|
+
attributes:
|
|
71
|
+
label: Environment
|
|
72
|
+
description: OS, Python version, how you installed (uv / pip), and how you run tests.
|
|
73
|
+
placeholder: "macOS 14 / Python 3.11.8 / uv / .venv"
|
|
74
|
+
validations:
|
|
75
|
+
required: false
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
blank_issues_enabled: false
|
|
2
|
+
contact_links:
|
|
3
|
+
- name: 🔒 Report a security vulnerability
|
|
4
|
+
url: https://github.com/ernestprovo23/mcp-warden/security/advisories/new
|
|
5
|
+
about: "Security issues must be reported privately — do NOT open a public issue. See SECURITY.md."
|
|
6
|
+
- name: 📖 Documentation & threat model
|
|
7
|
+
url: https://github.com/ernestprovo23/mcp-warden/tree/main/docs
|
|
8
|
+
about: "Read the design specs and threat model before filing — some behaviors are explicitly out of scope."
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
name: 💡 Feature / new check request
|
|
2
|
+
description: Propose a feature, or a new WRD-* / WRD-RES-* detection rule
|
|
3
|
+
labels: ["enhancement", "triage"]
|
|
4
|
+
body:
|
|
5
|
+
- type: markdown
|
|
6
|
+
attributes:
|
|
7
|
+
value: |
|
|
8
|
+
New checks are very welcome. mcp-warden blocks **only on deterministic
|
|
9
|
+
signals** (~0 false positives); heuristic/fuzzy detectors are accepted only
|
|
10
|
+
in the monitor (log-only) tier. Frame your proposal around a concrete threat.
|
|
11
|
+
- type: textarea
|
|
12
|
+
id: threat
|
|
13
|
+
attributes:
|
|
14
|
+
label: Threat / problem
|
|
15
|
+
description: What attack or failure does this address? Where does it appear (MCP surface, tool-result shape, CLI workflow)?
|
|
16
|
+
validations:
|
|
17
|
+
required: true
|
|
18
|
+
- type: dropdown
|
|
19
|
+
id: kind
|
|
20
|
+
attributes:
|
|
21
|
+
label: What are you proposing?
|
|
22
|
+
options:
|
|
23
|
+
- New static check (WRD-* — pin/check time)
|
|
24
|
+
- New result-inspection rule (WRD-RES-* — guard/inspect time)
|
|
25
|
+
- CLI / workflow feature
|
|
26
|
+
- Other
|
|
27
|
+
validations:
|
|
28
|
+
required: true
|
|
29
|
+
- type: dropdown
|
|
30
|
+
id: tier
|
|
31
|
+
attributes:
|
|
32
|
+
label: For a new check — deterministic or fuzzy?
|
|
33
|
+
description: Deterministic = can block (near-zero false positives). Fuzzy = monitor/log-only.
|
|
34
|
+
options:
|
|
35
|
+
- Deterministic (block-capable)
|
|
36
|
+
- Fuzzy (monitor / log-only)
|
|
37
|
+
- N/A — not a check
|
|
38
|
+
validations:
|
|
39
|
+
required: false
|
|
40
|
+
- type: textarea
|
|
41
|
+
id: detection
|
|
42
|
+
attributes:
|
|
43
|
+
label: Proposed detection / behavior
|
|
44
|
+
description: How would it match deterministically? What severity? Any false-positive risk and how you'd anchor against it?
|
|
45
|
+
validations:
|
|
46
|
+
required: true
|
|
47
|
+
- type: textarea
|
|
48
|
+
id: alternatives
|
|
49
|
+
attributes:
|
|
50
|
+
label: Alternatives considered
|
|
51
|
+
validations:
|
|
52
|
+
required: false
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
Thanks for contributing to mcp-warden. mcp-warden is a security tool, so PRs are
|
|
3
|
+
held to a determinism + specs-in-sync bar. See CONTRIBUTING.md.
|
|
4
|
+
Do NOT use a PR to report a security vulnerability — follow SECURITY.md.
|
|
5
|
+
-->
|
|
6
|
+
|
|
7
|
+
## What & why
|
|
8
|
+
|
|
9
|
+
<!-- What does this change do, and what problem does it solve? Link any issue. -->
|
|
10
|
+
|
|
11
|
+
Closes #
|
|
12
|
+
|
|
13
|
+
## Type of change
|
|
14
|
+
|
|
15
|
+
- [ ] Bug fix (non-breaking)
|
|
16
|
+
- [ ] New feature / check (non-breaking)
|
|
17
|
+
- [ ] Breaking change (alters a hash, canonical form, rule verdict, or CLI contract)
|
|
18
|
+
- [ ] Docs / specs only
|
|
19
|
+
- [ ] CI / tooling
|
|
20
|
+
|
|
21
|
+
## Checklist
|
|
22
|
+
|
|
23
|
+
- [ ] **Tests pass** via the repo venv: `.venv/bin/python -m pytest -q` is green.
|
|
24
|
+
- [ ] **Specs updated.** Any behavior change (hashing, canonicalization, the
|
|
25
|
+
`WRD-*` / `WRD-RES-*` catalogs, drift semantics, block posture, policy,
|
|
26
|
+
reserved error codes) updates the matching `docs/` spec in this same PR.
|
|
27
|
+
- [ ] **Determinism preserved.** No unintended change to a digest, canonical form,
|
|
28
|
+
or rule verdict on an unchanged surface. If a hash change is intentional, it
|
|
29
|
+
is documented and the version is bumped.
|
|
30
|
+
- [ ] **`guard` / `inspect` parity** holds for any result-rule change
|
|
31
|
+
(`tests/test_inspect_parity.py`).
|
|
32
|
+
- [ ] **No secrets.** No real credentials anywhere; test fixtures use obviously-fake
|
|
33
|
+
placeholders (already allowlisted in `.gitleaks.toml`).
|
|
34
|
+
- [ ] **Docs in sync.** README / CLI reference / `DOCUMENTATION_INDEX.md` updated if
|
|
35
|
+
user-facing behavior or flags changed.
|
|
36
|
+
|
|
37
|
+
## Notes for reviewers
|
|
38
|
+
|
|
39
|
+
<!-- Anything you want a reviewer to look at first; fixture/spec diffs welcome. -->
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
version: 2
|
|
2
|
+
updates:
|
|
3
|
+
# Python dependencies declared in pyproject.toml.
|
|
4
|
+
- package-ecosystem: "pip"
|
|
5
|
+
directory: "/"
|
|
6
|
+
schedule:
|
|
7
|
+
interval: "weekly"
|
|
8
|
+
open-pull-requests-limit: 5
|
|
9
|
+
labels:
|
|
10
|
+
- "dependencies"
|
|
11
|
+
commit-message:
|
|
12
|
+
prefix: "deps"
|
|
13
|
+
|
|
14
|
+
# GitHub Actions used by the CI workflows.
|
|
15
|
+
- package-ecosystem: "github-actions"
|
|
16
|
+
directory: "/"
|
|
17
|
+
schedule:
|
|
18
|
+
interval: "weekly"
|
|
19
|
+
open-pull-requests-limit: 5
|
|
20
|
+
labels:
|
|
21
|
+
- "dependencies"
|
|
22
|
+
- "ci"
|
|
23
|
+
commit-message:
|
|
24
|
+
prefix: "ci"
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
name: Action self-test
|
|
2
|
+
|
|
3
|
+
# Validates the composite mcp-warden-action against the fixture MCP servers
|
|
4
|
+
# on all three supported runner OSes. Also runs a dedicated ubuntu job that
|
|
5
|
+
# exercises the real SARIF upload path (requires security-events: write).
|
|
6
|
+
#
|
|
7
|
+
# Runs on every push/PR that touches the action itself or its fixtures.
|
|
8
|
+
|
|
9
|
+
on:
|
|
10
|
+
push:
|
|
11
|
+
branches: [main]
|
|
12
|
+
paths:
|
|
13
|
+
- "action.yml"
|
|
14
|
+
- "action/**"
|
|
15
|
+
- "tests/fixtures/**"
|
|
16
|
+
- ".github/workflows/action-test.yml"
|
|
17
|
+
pull_request:
|
|
18
|
+
branches: [main]
|
|
19
|
+
paths:
|
|
20
|
+
- "action.yml"
|
|
21
|
+
- "action/**"
|
|
22
|
+
- "tests/fixtures/**"
|
|
23
|
+
- ".github/workflows/action-test.yml"
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
# --------------------------------------------------------------------------
|
|
27
|
+
# Matrix job: pass path + blocking proof on ubuntu / macos / windows.
|
|
28
|
+
# upload-sarif: false — the matrix legs do not have security-events: write.
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
action-matrix:
|
|
31
|
+
name: "Action test (${{ matrix.os }})"
|
|
32
|
+
runs-on: ${{ matrix.os }}
|
|
33
|
+
strategy:
|
|
34
|
+
fail-fast: false
|
|
35
|
+
matrix:
|
|
36
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
37
|
+
|
|
38
|
+
steps:
|
|
39
|
+
- name: Checkout
|
|
40
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
41
|
+
|
|
42
|
+
# -----------------------------------------------------------------------
|
|
43
|
+
# Pass path: clean server vs committed lock — gate must exit 0.
|
|
44
|
+
# -----------------------------------------------------------------------
|
|
45
|
+
- name: "Pass path — clean server must exit 0"
|
|
46
|
+
id: pass-path
|
|
47
|
+
uses: ./
|
|
48
|
+
with:
|
|
49
|
+
server-cmd: "python tests/fixtures/clean_server.py"
|
|
50
|
+
lock: "tests/fixtures/clean.warden.lock"
|
|
51
|
+
sarif: "clean-check.sarif"
|
|
52
|
+
upload-sarif: "false"
|
|
53
|
+
|
|
54
|
+
- name: "Assert pass-path exit code is 0"
|
|
55
|
+
shell: bash
|
|
56
|
+
run: |
|
|
57
|
+
code="${{ steps.pass-path.outputs.exit-code }}"
|
|
58
|
+
if [ "$code" != "0" ]; then
|
|
59
|
+
echo "ERROR: pass path exit code was $code (expected 0)" >&2
|
|
60
|
+
exit 1
|
|
61
|
+
fi
|
|
62
|
+
echo "Pass path exited 0 — OK"
|
|
63
|
+
|
|
64
|
+
# -----------------------------------------------------------------------
|
|
65
|
+
# Blocking proof: mutated server vs same lock — gate must exit 1.
|
|
66
|
+
# continue-on-error: true so the job does not fail on the expected non-0.
|
|
67
|
+
# We then assert that the step outcome was 'failure' and exit-code == '1'.
|
|
68
|
+
# -----------------------------------------------------------------------
|
|
69
|
+
- name: "Blocking proof — mutated server must exit 1"
|
|
70
|
+
id: blocking-proof
|
|
71
|
+
uses: ./
|
|
72
|
+
continue-on-error: true
|
|
73
|
+
with:
|
|
74
|
+
server-cmd: "python tests/fixtures/mutated_server.py"
|
|
75
|
+
lock: "tests/fixtures/clean.warden.lock"
|
|
76
|
+
sarif: "mutated-check.sarif"
|
|
77
|
+
upload-sarif: "false"
|
|
78
|
+
|
|
79
|
+
- name: "Assert blocking-proof step failed with exit-code 1"
|
|
80
|
+
shell: bash
|
|
81
|
+
run: |
|
|
82
|
+
outcome="${{ steps.blocking-proof.outcome }}"
|
|
83
|
+
code="${{ steps.blocking-proof.outputs.exit-code }}"
|
|
84
|
+
if [ "$outcome" != "failure" ]; then
|
|
85
|
+
echo "ERROR: blocking-proof step outcome was '$outcome' (expected 'failure')" >&2
|
|
86
|
+
exit 1
|
|
87
|
+
fi
|
|
88
|
+
if [ "$code" != "1" ]; then
|
|
89
|
+
echo "ERROR: blocking-proof exit-code was '$code' (expected '1')" >&2
|
|
90
|
+
exit 1
|
|
91
|
+
fi
|
|
92
|
+
echo "Blocking proof step outcome=failure, exit-code=1 — gate is working correctly"
|
|
93
|
+
|
|
94
|
+
# --------------------------------------------------------------------------
|
|
95
|
+
# Dedicated upload job: ubuntu only, with security-events: write.
|
|
96
|
+
# Exercises the real SARIF upload path end-to-end against the clean fixture.
|
|
97
|
+
# --------------------------------------------------------------------------
|
|
98
|
+
action-upload-sarif:
|
|
99
|
+
name: "Action test (SARIF upload, ubuntu)"
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
permissions:
|
|
102
|
+
contents: read
|
|
103
|
+
security-events: write
|
|
104
|
+
|
|
105
|
+
steps:
|
|
106
|
+
- name: Checkout
|
|
107
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
108
|
+
|
|
109
|
+
- name: "Clean server — upload-sarif true (real upload path)"
|
|
110
|
+
id: upload-test
|
|
111
|
+
uses: ./
|
|
112
|
+
with:
|
|
113
|
+
server-cmd: "python tests/fixtures/clean_server.py"
|
|
114
|
+
lock: "tests/fixtures/clean.warden.lock"
|
|
115
|
+
sarif: "upload-test.sarif"
|
|
116
|
+
upload-sarif: "true"
|
|
117
|
+
category: "mcp-warden-action-test"
|
|
118
|
+
|
|
119
|
+
- name: "Assert upload-test exit code is 0"
|
|
120
|
+
shell: bash
|
|
121
|
+
run: |
|
|
122
|
+
code="${{ steps.upload-test.outputs.exit-code }}"
|
|
123
|
+
if [ "$code" != "0" ]; then
|
|
124
|
+
echo "ERROR: upload-test exit code was $code (expected 0)" >&2
|
|
125
|
+
exit 1
|
|
126
|
+
fi
|
|
127
|
+
echo "SARIF upload path exited 0 — OK"
|
|
128
|
+
|
|
129
|
+
- name: "Assert SARIF upload step succeeded"
|
|
130
|
+
shell: bash
|
|
131
|
+
env:
|
|
132
|
+
UPLOAD_OUTCOME: ${{ steps.upload-test.outputs['sarif-upload'] }}
|
|
133
|
+
run: |
|
|
134
|
+
# The composite action's sarif-upload step id is internal; we verify
|
|
135
|
+
# upload success by confirming the overall action step exited 0 (already
|
|
136
|
+
# asserted above) and that the SARIF file was produced and is non-empty.
|
|
137
|
+
sarif_path="${{ steps.upload-test.outputs.sarif }}"
|
|
138
|
+
if [ -z "$sarif_path" ] || [ ! -f "$sarif_path" ]; then
|
|
139
|
+
echo "ERROR: SARIF file not found at path '$sarif_path' — upload cannot have succeeded" >&2
|
|
140
|
+
exit 1
|
|
141
|
+
fi
|
|
142
|
+
sarif_size=$(wc -c < "$sarif_path")
|
|
143
|
+
if [ "$sarif_size" -eq 0 ]; then
|
|
144
|
+
echo "ERROR: SARIF file is empty — upload would have been rejected" >&2
|
|
145
|
+
exit 1
|
|
146
|
+
fi
|
|
147
|
+
echo "SARIF file present at $sarif_path (${sarif_size} bytes) and action exited 0 — upload confirmed OK"
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: deps-locked
|
|
2
|
+
|
|
3
|
+
# Proves mcp-warden "heals itself": its OWN dev/CI dependency closure installs
|
|
4
|
+
# reproducibly from a fully hash-pinned lockfile (requirements-dev.lock). A
|
|
5
|
+
# supply-chain integrity gate that ships unpinned transitive deps is
|
|
6
|
+
# indefensible — this job is the standing evidence that we don't (issue #14,
|
|
7
|
+
# conclave v1 must-do #4).
|
|
8
|
+
#
|
|
9
|
+
# What it asserts, in a CLEAN environment, on every push/PR:
|
|
10
|
+
# 1. `pip install --require-hashes` accepts the committed lockfile end-to-end.
|
|
11
|
+
# --require-hashes makes pip REFUSE any artifact whose sha256 is not pinned,
|
|
12
|
+
# so a drifted or tampered transitive dep fails the job here.
|
|
13
|
+
# 2. The lockfile is still in sync with pyproject.toml — we regenerate it with
|
|
14
|
+
# the documented `uv pip compile` command and fail if the committed file
|
|
15
|
+
# differs (catches "bumped pyproject, forgot to regenerate the lock").
|
|
16
|
+
# 3. The package + its runtime/dev closure import from the locked set.
|
|
17
|
+
|
|
18
|
+
on:
|
|
19
|
+
push:
|
|
20
|
+
branches: [main]
|
|
21
|
+
pull_request:
|
|
22
|
+
branches: [main]
|
|
23
|
+
|
|
24
|
+
permissions:
|
|
25
|
+
contents: read
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
deps-locked:
|
|
29
|
+
name: Hash-locked dev/CI install
|
|
30
|
+
runs-on: ubuntu-latest
|
|
31
|
+
|
|
32
|
+
steps:
|
|
33
|
+
# Pinned to the same full-SHA actions the rest of CI uses (test_workflow_pins.py
|
|
34
|
+
# enforces 40-char SHA + version comment on every `uses:`). Bump majors
|
|
35
|
+
# deliberately, never float tags — this is the supply-chain tool's own CI.
|
|
36
|
+
- name: Checkout
|
|
37
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
38
|
+
|
|
39
|
+
- name: Set up Python 3.11
|
|
40
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
41
|
+
with:
|
|
42
|
+
python-version: "3.11"
|
|
43
|
+
|
|
44
|
+
# --------------------------------------------------------------------
|
|
45
|
+
# 1. Hash-verified install in a clean venv.
|
|
46
|
+
# --require-hashes makes pip reject ANY package whose artifact hash is
|
|
47
|
+
# not pinned in requirements-dev.lock, so transitive drift fails closed.
|
|
48
|
+
# --------------------------------------------------------------------
|
|
49
|
+
- name: Install dev/CI closure with --require-hashes
|
|
50
|
+
run: |
|
|
51
|
+
python -m venv /tmp/locked
|
|
52
|
+
/tmp/locked/bin/python -m pip install --upgrade pip
|
|
53
|
+
/tmp/locked/bin/python -m pip install --require-hashes -r requirements-dev.lock
|
|
54
|
+
|
|
55
|
+
# --------------------------------------------------------------------
|
|
56
|
+
# 2. Lockfile-in-sync check.
|
|
57
|
+
# Regenerate with the SAME documented command and fail if the committed
|
|
58
|
+
# lock drifted from pyproject.toml. Keeps the lock from silently rotting.
|
|
59
|
+
# --------------------------------------------------------------------
|
|
60
|
+
- name: Install uv (pinned)
|
|
61
|
+
run: python -m pip install "uv==0.6.16"
|
|
62
|
+
|
|
63
|
+
- name: Verify lockfile is in sync with pyproject.toml
|
|
64
|
+
run: |
|
|
65
|
+
uv pip compile --universal --generate-hashes --python-version 3.11 \
|
|
66
|
+
--extra dev pyproject.toml -o /tmp/requirements-dev.regenerated.lock
|
|
67
|
+
# Compare only the dependency body. The autogenerated header comment
|
|
68
|
+
# embeds the `-o` output path, which differs by construction (the CI
|
|
69
|
+
# run writes to /tmp), so we strip leading `#` comment lines before
|
|
70
|
+
# diffing. Pins, markers, and hashes are all in the body and are
|
|
71
|
+
# compared exactly.
|
|
72
|
+
if ! diff -u \
|
|
73
|
+
<(grep -v '^#' requirements-dev.lock) \
|
|
74
|
+
<(grep -v '^#' /tmp/requirements-dev.regenerated.lock); then
|
|
75
|
+
echo "::error::requirements-dev.lock is out of sync with pyproject.toml."
|
|
76
|
+
echo "Regenerate it (see SECURITY.md / CONTRIBUTING.md) and commit the result:"
|
|
77
|
+
echo " uv pip compile --universal --generate-hashes --python-version 3.11 --extra dev pyproject.toml -o requirements-dev.lock"
|
|
78
|
+
exit 1
|
|
79
|
+
fi
|
|
80
|
+
echo "requirements-dev.lock is in sync with pyproject.toml."
|
|
81
|
+
|
|
82
|
+
# --------------------------------------------------------------------
|
|
83
|
+
# 3. The locked closure actually works — import the package + key deps.
|
|
84
|
+
# --------------------------------------------------------------------
|
|
85
|
+
- name: Import package + locked closure
|
|
86
|
+
run: |
|
|
87
|
+
/tmp/locked/bin/python -m pip install --no-deps -e .
|
|
88
|
+
/tmp/locked/bin/python -c "import mcp_warden; from mcp_warden import cli; import mcp, rfc8785, pydantic, typer, rich, yaml, anyio, pytest, hypothesis; print('OK: mcp_warden + hash-locked dev/CI closure import clean')"
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
name: Docs
|
|
2
|
+
|
|
3
|
+
# Builds the mkdocs-material documentation site.
|
|
4
|
+
# - On every PR: `mkdocs build --strict` is the gate (no broken internal
|
|
5
|
+
# links, no warnings). It does NOT deploy.
|
|
6
|
+
# - On push to main: build, then deploy to GitHub Pages.
|
|
7
|
+
#
|
|
8
|
+
# All third-party actions are pinned to a full 40-char commit SHA with a version
|
|
9
|
+
# comment (enforced by tests/test_workflow_pins.py).
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
push:
|
|
13
|
+
branches: [main]
|
|
14
|
+
pull_request:
|
|
15
|
+
branches: [main]
|
|
16
|
+
|
|
17
|
+
# Least-privilege by default; the deploy job widens scope locally.
|
|
18
|
+
permissions:
|
|
19
|
+
contents: read
|
|
20
|
+
|
|
21
|
+
concurrency:
|
|
22
|
+
group: docs-${{ github.ref }}
|
|
23
|
+
cancel-in-progress: false
|
|
24
|
+
|
|
25
|
+
jobs:
|
|
26
|
+
# --------------------------------------------------------------------------
|
|
27
|
+
# Job 1: strict build — the PR gate. Runs on PRs and on main.
|
|
28
|
+
# Fails the build on any broken internal link or mkdocs warning.
|
|
29
|
+
# --------------------------------------------------------------------------
|
|
30
|
+
build:
|
|
31
|
+
name: mkdocs build --strict
|
|
32
|
+
runs-on: ubuntu-latest
|
|
33
|
+
steps:
|
|
34
|
+
- name: Checkout
|
|
35
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
36
|
+
|
|
37
|
+
- name: Set up Python 3.11
|
|
38
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
39
|
+
with:
|
|
40
|
+
python-version: "3.11"
|
|
41
|
+
|
|
42
|
+
- name: Install mkdocs-material
|
|
43
|
+
run: pip install "mkdocs-material==9.7.6"
|
|
44
|
+
|
|
45
|
+
- name: Build site (strict)
|
|
46
|
+
run: mkdocs build --strict --site-dir site
|
|
47
|
+
|
|
48
|
+
- name: Upload Pages artifact
|
|
49
|
+
# Only needed on main, where the deploy job consumes it. Harmless on PRs
|
|
50
|
+
# (artifact is just not deployed), and keeps the build job self-contained.
|
|
51
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
52
|
+
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5
|
|
53
|
+
with:
|
|
54
|
+
path: site
|
|
55
|
+
|
|
56
|
+
# --------------------------------------------------------------------------
|
|
57
|
+
# Job 2: deploy to GitHub Pages — only on push to main.
|
|
58
|
+
#
|
|
59
|
+
# NOTE: this requires GitHub Pages to be enabled for the repo with the
|
|
60
|
+
# "GitHub Actions" source (Settings -> Pages). Until that one-time enable is
|
|
61
|
+
# done, this job will fail on main but the PR gate (job 1) is unaffected.
|
|
62
|
+
# --------------------------------------------------------------------------
|
|
63
|
+
deploy:
|
|
64
|
+
name: Deploy to GitHub Pages
|
|
65
|
+
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
|
|
66
|
+
needs: build
|
|
67
|
+
runs-on: ubuntu-latest
|
|
68
|
+
permissions:
|
|
69
|
+
contents: read
|
|
70
|
+
pages: write
|
|
71
|
+
id-token: write
|
|
72
|
+
environment:
|
|
73
|
+
name: github-pages
|
|
74
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
75
|
+
steps:
|
|
76
|
+
- name: Configure Pages
|
|
77
|
+
uses: actions/configure-pages@45bfe0192ca1faeb007ade9deae92b16b8254a0d # v6
|
|
78
|
+
|
|
79
|
+
- name: Deploy
|
|
80
|
+
id: deployment
|
|
81
|
+
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
name: Examples
|
|
2
|
+
|
|
3
|
+
# Keeps examples/ honest:
|
|
4
|
+
# 1. lint — YAML-lint every example workflow so a broken copy-paste template
|
|
5
|
+
# can never merge.
|
|
6
|
+
# 2. check — re-run `mcp-warden check` against each committed lock under
|
|
7
|
+
# examples/pinned-servers/ so the example locks stay green (a drifted
|
|
8
|
+
# upstream server or a stale lock fails this job).
|
|
9
|
+
#
|
|
10
|
+
# All third-party actions are pinned to a full 40-char commit SHA with a version
|
|
11
|
+
# comment (enforced by tests/test_workflow_pins.py).
|
|
12
|
+
|
|
13
|
+
on:
|
|
14
|
+
push:
|
|
15
|
+
branches: [main]
|
|
16
|
+
pull_request:
|
|
17
|
+
branches: [main]
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
# --------------------------------------------------------------------------
|
|
21
|
+
# Job 1: YAML-lint the example workflows.
|
|
22
|
+
# --------------------------------------------------------------------------
|
|
23
|
+
lint:
|
|
24
|
+
name: YAML lint example workflows
|
|
25
|
+
runs-on: ubuntu-latest
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout
|
|
28
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
29
|
+
|
|
30
|
+
- name: Set up Python 3.11
|
|
31
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
32
|
+
with:
|
|
33
|
+
python-version: "3.11"
|
|
34
|
+
|
|
35
|
+
- name: Install yamllint
|
|
36
|
+
run: pip install "yamllint==1.35.1"
|
|
37
|
+
|
|
38
|
+
# Lint the example workflow / CI / config YAML. The relaxed ruleset focuses
|
|
39
|
+
# on syntactic validity and basic hygiene rather than strict formatting,
|
|
40
|
+
# since these are copy-paste templates authored for readability.
|
|
41
|
+
- name: Lint example YAML
|
|
42
|
+
run: |
|
|
43
|
+
yamllint -d relaxed \
|
|
44
|
+
examples/github-actions \
|
|
45
|
+
examples/gitlab-ci \
|
|
46
|
+
examples/pre-commit
|
|
47
|
+
|
|
48
|
+
# --------------------------------------------------------------------------
|
|
49
|
+
# Job 2: re-check the committed example locks.
|
|
50
|
+
#
|
|
51
|
+
# Launches each real, openly-available server via its PINNED ref and verifies
|
|
52
|
+
# the committed warden.lock still matches the live surface. No paid creds, no
|
|
53
|
+
# secrets — every server is public.
|
|
54
|
+
# --------------------------------------------------------------------------
|
|
55
|
+
check-locks:
|
|
56
|
+
name: Re-check committed example locks
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- name: Checkout
|
|
60
|
+
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
|
|
61
|
+
|
|
62
|
+
- name: Set up Python 3.11
|
|
63
|
+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
|
|
64
|
+
with:
|
|
65
|
+
python-version: "3.11"
|
|
66
|
+
|
|
67
|
+
# Node provides npx for the @modelcontextprotocol/* servers.
|
|
68
|
+
- name: Set up Node 22
|
|
69
|
+
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
|
|
70
|
+
with:
|
|
71
|
+
node-version: "22"
|
|
72
|
+
|
|
73
|
+
- name: Install mcp-warden
|
|
74
|
+
run: pip install -e .
|
|
75
|
+
|
|
76
|
+
- name: "check: server-everything (npx, pinned @2026.1.26)"
|
|
77
|
+
run: |
|
|
78
|
+
mcp-warden check \
|
|
79
|
+
--lock examples/pinned-servers/server-everything/warden.lock \
|
|
80
|
+
--timeout 120 \
|
|
81
|
+
-- npx -y @modelcontextprotocol/server-everything@2026.1.26
|
|
82
|
+
|
|
83
|
+
- name: "check: server-memory (npx, pinned @2026.1.26)"
|
|
84
|
+
run: |
|
|
85
|
+
mcp-warden check \
|
|
86
|
+
--lock examples/pinned-servers/server-memory/warden.lock \
|
|
87
|
+
--timeout 120 \
|
|
88
|
+
-- npx -y @modelcontextprotocol/server-memory@2026.1.26
|
|
89
|
+
|
|
90
|
+
- name: "check: server-sequential-thinking (npx, pinned @2025.12.18)"
|
|
91
|
+
run: |
|
|
92
|
+
mcp-warden check \
|
|
93
|
+
--lock examples/pinned-servers/server-sequential-thinking/warden.lock \
|
|
94
|
+
--timeout 120 \
|
|
95
|
+
-- npx -y @modelcontextprotocol/server-sequential-thinking@2025.12.18
|