agent-capmap 0.1.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.
Files changed (181) hide show
  1. agent_capmap-0.1.0/.env.example +9 -0
  2. agent_capmap-0.1.0/.gitattributes +1 -0
  3. agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +52 -0
  4. agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/classification.yml +52 -0
  5. agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/client_support.yml +34 -0
  6. agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
  7. agent_capmap-0.1.0/.github/dependabot.yml +22 -0
  8. agent_capmap-0.1.0/.github/pull_request_template.md +19 -0
  9. agent_capmap-0.1.0/.github/workflows/action-selftest.yml +69 -0
  10. agent_capmap-0.1.0/.github/workflows/ci.yml +110 -0
  11. agent_capmap-0.1.0/.github/workflows/codeql.yml +40 -0
  12. agent_capmap-0.1.0/.github/workflows/release.yml +109 -0
  13. agent_capmap-0.1.0/.gitignore +31 -0
  14. agent_capmap-0.1.0/.gitleaks.toml +15 -0
  15. agent_capmap-0.1.0/.gitleaksignore +7 -0
  16. agent_capmap-0.1.0/.pre-commit-config.yaml +27 -0
  17. agent_capmap-0.1.0/AGENTS.md +177 -0
  18. agent_capmap-0.1.0/CHANGELOG.md +168 -0
  19. agent_capmap-0.1.0/CLAUDE.md +1 -0
  20. agent_capmap-0.1.0/CODE_OF_CONDUCT.md +83 -0
  21. agent_capmap-0.1.0/CONTRIBUTING.md +173 -0
  22. agent_capmap-0.1.0/LICENSE +21 -0
  23. agent_capmap-0.1.0/PKG-INFO +295 -0
  24. agent_capmap-0.1.0/README.md +252 -0
  25. agent_capmap-0.1.0/SECURITY.md +59 -0
  26. agent_capmap-0.1.0/action.yml +137 -0
  27. agent_capmap-0.1.0/docs/blog-outline.md +73 -0
  28. agent_capmap-0.1.0/docs/examples/agentcapmap.yml +89 -0
  29. agent_capmap-0.1.0/docs/github-action.md +61 -0
  30. agent_capmap-0.1.0/docs/poc-checklist.md +111 -0
  31. agent_capmap-0.1.0/docs/taxonomy.md +159 -0
  32. agent_capmap-0.1.0/docs/threat-model.md +180 -0
  33. agent_capmap-0.1.0/docs/vs-mcp-scan.md +73 -0
  34. agent_capmap-0.1.0/eval/README.md +121 -0
  35. agent_capmap-0.1.0/eval/agents.json +103 -0
  36. agent_capmap-0.1.0/eval/apply_labels.py +82 -0
  37. agent_capmap-0.1.0/eval/capture.py +221 -0
  38. agent_capmap-0.1.0/eval/catalog.json +82 -0
  39. agent_capmap-0.1.0/eval/labeled_servers/aws-api.json +117 -0
  40. agent_capmap-0.1.0/eval/labeled_servers/aws-iam.json +3175 -0
  41. agent_capmap-0.1.0/eval/labeled_servers/azure.json +2990 -0
  42. agent_capmap-0.1.0/eval/labeled_servers/brave-search.json +105 -0
  43. agent_capmap-0.1.0/eval/labeled_servers/commands.json +77 -0
  44. agent_capmap-0.1.0/eval/labeled_servers/context7.json +110 -0
  45. agent_capmap-0.1.0/eval/labeled_servers/deepwiki.json +137 -0
  46. agent_capmap-0.1.0/eval/labeled_servers/desktop-commander.json +1142 -0
  47. agent_capmap-0.1.0/eval/labeled_servers/exa.json +119 -0
  48. agent_capmap-0.1.0/eval/labeled_servers/fetch.json +85 -0
  49. agent_capmap-0.1.0/eval/labeled_servers/filesystem.json +547 -0
  50. agent_capmap-0.1.0/eval/labeled_servers/firecrawl.json +3060 -0
  51. agent_capmap-0.1.0/eval/labeled_servers/git.json +546 -0
  52. agent_capmap-0.1.0/eval/labeled_servers/github.json +1502 -0
  53. agent_capmap-0.1.0/eval/labeled_servers/gitlab.json +239 -0
  54. agent_capmap-0.1.0/eval/labeled_servers/heroku.json +1411 -0
  55. agent_capmap-0.1.0/eval/labeled_servers/memory.json +426 -0
  56. agent_capmap-0.1.0/eval/labeled_servers/notion.json +6736 -0
  57. agent_capmap-0.1.0/eval/labeled_servers/obsidian.json +606 -0
  58. agent_capmap-0.1.0/eval/labeled_servers/playwright.json +1171 -0
  59. agent_capmap-0.1.0/eval/labeled_servers/postgres.json +54 -0
  60. agent_capmap-0.1.0/eval/labeled_servers/qdrant.json +106 -0
  61. agent_capmap-0.1.0/eval/labeled_servers/sentry.json +662 -0
  62. agent_capmap-0.1.0/eval/labeled_servers/sequential-thinking.json +109 -0
  63. agent_capmap-0.1.0/eval/labeled_servers/slack.json +325 -0
  64. agent_capmap-0.1.0/eval/labeled_servers/supabase.json +1147 -0
  65. agent_capmap-0.1.0/eval/labeled_servers/tavily.json +434 -0
  66. agent_capmap-0.1.0/eval/labeled_servers/time.json +96 -0
  67. agent_capmap-0.1.0/eval/run_eval.py +298 -0
  68. agent_capmap-0.1.0/examples/README.md +31 -0
  69. agent_capmap-0.1.0/examples/demo/inventory.json +860 -0
  70. agent_capmap-0.1.0/examples/live-trifecta/mcp.json +12 -0
  71. agent_capmap-0.1.0/examples/live-trifecta/sandbox/README.md +2 -0
  72. agent_capmap-0.1.0/fixtures/README.md +27 -0
  73. agent_capmap-0.1.0/fixtures/clean/expected.json +25 -0
  74. agent_capmap-0.1.0/fixtures/clean/mcp.json +12 -0
  75. agent_capmap-0.1.0/fixtures/clean/tools.json +34 -0
  76. agent_capmap-0.1.0/fixtures/exec-injection/expected.json +128 -0
  77. agent_capmap-0.1.0/fixtures/exec-injection/mcp.json +12 -0
  78. agent_capmap-0.1.0/fixtures/exec-injection/tools.json +40 -0
  79. agent_capmap-0.1.0/fixtures/no-approval-destructive/expected.json +59 -0
  80. agent_capmap-0.1.0/fixtures/no-approval-destructive/mcp.json +9 -0
  81. agent_capmap-0.1.0/fixtures/no-approval-destructive/tools.json +20 -0
  82. agent_capmap-0.1.0/fixtures/overscoped-token/expected.json +106 -0
  83. agent_capmap-0.1.0/fixtures/overscoped-token/mcp.json +14 -0
  84. agent_capmap-0.1.0/fixtures/overscoped-token/tools.json +25 -0
  85. agent_capmap-0.1.0/fixtures/poisoned-description/expected.json +57 -0
  86. agent_capmap-0.1.0/fixtures/poisoned-description/mcp.json +8 -0
  87. agent_capmap-0.1.0/fixtures/poisoned-description/tools.json +23 -0
  88. agent_capmap-0.1.0/fixtures/rug-pull/baseline.json +11 -0
  89. agent_capmap-0.1.0/fixtures/rug-pull/expected.json +105 -0
  90. agent_capmap-0.1.0/fixtures/rug-pull/mcp.json +8 -0
  91. agent_capmap-0.1.0/fixtures/rug-pull/tools.json +32 -0
  92. agent_capmap-0.1.0/fixtures/shadowing/expected.json +77 -0
  93. agent_capmap-0.1.0/fixtures/shadowing/mcp.json +12 -0
  94. agent_capmap-0.1.0/fixtures/shadowing/tools.json +24 -0
  95. agent_capmap-0.1.0/fixtures/trifecta/expected.json +87 -0
  96. agent_capmap-0.1.0/fixtures/trifecta/mcp.json +22 -0
  97. agent_capmap-0.1.0/fixtures/trifecta/tools.json +33 -0
  98. agent_capmap-0.1.0/policies/default.yaml +113 -0
  99. agent_capmap-0.1.0/pyproject.toml +95 -0
  100. agent_capmap-0.1.0/requirements/build.in +4 -0
  101. agent_capmap-0.1.0/requirements/build.lock +30 -0
  102. agent_capmap-0.1.0/requirements/dev.lock +1687 -0
  103. agent_capmap-0.1.0/requirements/runtime.lock +562 -0
  104. agent_capmap-0.1.0/schemas/policy.schema.json +172 -0
  105. agent_capmap-0.1.0/schemas/tool-tags.schema.json +57 -0
  106. agent_capmap-0.1.0/scripts/build_reference_labels.py +87 -0
  107. agent_capmap-0.1.0/scripts/check.py +81 -0
  108. agent_capmap-0.1.0/src/agentcapmap/__init__.py +3 -0
  109. agent_capmap-0.1.0/src/agentcapmap/__main__.py +5 -0
  110. agent_capmap-0.1.0/src/agentcapmap/baseline.py +125 -0
  111. agent_capmap-0.1.0/src/agentcapmap/classify/__init__.py +221 -0
  112. agent_capmap-0.1.0/src/agentcapmap/classify/cache.py +74 -0
  113. agent_capmap-0.1.0/src/agentcapmap/classify/prompt.py +160 -0
  114. agent_capmap-0.1.0/src/agentcapmap/classify/provider.py +122 -0
  115. agent_capmap-0.1.0/src/agentcapmap/classify/reference.py +115 -0
  116. agent_capmap-0.1.0/src/agentcapmap/classify/reference_labels.json +6135 -0
  117. agent_capmap-0.1.0/src/agentcapmap/cli.py +392 -0
  118. agent_capmap-0.1.0/src/agentcapmap/diff.py +103 -0
  119. agent_capmap-0.1.0/src/agentcapmap/discovery/__init__.py +209 -0
  120. agent_capmap-0.1.0/src/agentcapmap/discovery/_common.py +297 -0
  121. agent_capmap-0.1.0/src/agentcapmap/discovery/claude_code.py +258 -0
  122. agent_capmap-0.1.0/src/agentcapmap/discovery/claude_desktop.py +28 -0
  123. agent_capmap-0.1.0/src/agentcapmap/discovery/cursor.py +33 -0
  124. agent_capmap-0.1.0/src/agentcapmap/discovery/mcp_json.py +29 -0
  125. agent_capmap-0.1.0/src/agentcapmap/discovery/vscode.py +65 -0
  126. agent_capmap-0.1.0/src/agentcapmap/enumerate/__init__.py +278 -0
  127. agent_capmap-0.1.0/src/agentcapmap/enumerate/hashing.py +37 -0
  128. agent_capmap-0.1.0/src/agentcapmap/enumerate/http.py +313 -0
  129. agent_capmap-0.1.0/src/agentcapmap/enumerate/netguard.py +60 -0
  130. agent_capmap-0.1.0/src/agentcapmap/enumerate/stdio.py +273 -0
  131. agent_capmap-0.1.0/src/agentcapmap/enumerate/transport.py +86 -0
  132. agent_capmap-0.1.0/src/agentcapmap/evaluation.py +498 -0
  133. agent_capmap-0.1.0/src/agentcapmap/findings.py +129 -0
  134. agent_capmap-0.1.0/src/agentcapmap/graph/__init__.py +264 -0
  135. agent_capmap-0.1.0/src/agentcapmap/graph/server_attrs.py +164 -0
  136. agent_capmap-0.1.0/src/agentcapmap/limits.py +35 -0
  137. agent_capmap-0.1.0/src/agentcapmap/models.py +186 -0
  138. agent_capmap-0.1.0/src/agentcapmap/policy/__init__.py +24 -0
  139. agent_capmap-0.1.0/src/agentcapmap/policy/engine.py +229 -0
  140. agent_capmap-0.1.0/src/agentcapmap/policy/loader.py +223 -0
  141. agent_capmap-0.1.0/src/agentcapmap/py.typed +0 -0
  142. agent_capmap-0.1.0/src/agentcapmap/redact.py +268 -0
  143. agent_capmap-0.1.0/src/agentcapmap/report/__init__.py +36 -0
  144. agent_capmap-0.1.0/src/agentcapmap/report/_text.py +62 -0
  145. agent_capmap-0.1.0/src/agentcapmap/report/markdown.py +152 -0
  146. agent_capmap-0.1.0/src/agentcapmap/report/sarif.py +209 -0
  147. agent_capmap-0.1.0/src/agentcapmap/taxonomy.py +56 -0
  148. agent_capmap-0.1.0/tests/__init__.py +0 -0
  149. agent_capmap-0.1.0/tests/conftest.py +74 -0
  150. agent_capmap-0.1.0/tests/fake_llm.py +74 -0
  151. agent_capmap-0.1.0/tests/fake_secrets.py +34 -0
  152. agent_capmap-0.1.0/tests/fixtures/configs/claude_code/.mcp.json +31 -0
  153. agent_capmap-0.1.0/tests/fixtures/configs/claude_desktop/claude_desktop_config.json +24 -0
  154. agent_capmap-0.1.0/tests/fixtures/configs/cursor/.cursor/mcp.json +24 -0
  155. agent_capmap-0.1.0/tests/fixtures/configs/generic/mcp.json +11 -0
  156. agent_capmap-0.1.0/tests/fixtures/configs/vscode/.vscode/mcp.json +32 -0
  157. agent_capmap-0.1.0/tests/fixtures/configs/vscode/.vscode/settings.json +28 -0
  158. agent_capmap-0.1.0/tests/fixtures/sarif/SOURCE.md +11 -0
  159. agent_capmap-0.1.0/tests/fixtures/sarif/sarif-schema-2.1.0.json +3389 -0
  160. agent_capmap-0.1.0/tests/mock_mcp_server.py +287 -0
  161. agent_capmap-0.1.0/tests/scenarios.py +96 -0
  162. agent_capmap-0.1.0/tests/test_baseline.py +74 -0
  163. agent_capmap-0.1.0/tests/test_classify.py +318 -0
  164. agent_capmap-0.1.0/tests/test_claude_code.py +222 -0
  165. agent_capmap-0.1.0/tests/test_cli.py +231 -0
  166. agent_capmap-0.1.0/tests/test_diff.py +94 -0
  167. agent_capmap-0.1.0/tests/test_discovery.py +204 -0
  168. agent_capmap-0.1.0/tests/test_enumerate_http.py +83 -0
  169. agent_capmap-0.1.0/tests/test_enumerate_stdio.py +203 -0
  170. agent_capmap-0.1.0/tests/test_evaluation.py +292 -0
  171. agent_capmap-0.1.0/tests/test_fixtures.py +182 -0
  172. agent_capmap-0.1.0/tests/test_hardening.py +231 -0
  173. agent_capmap-0.1.0/tests/test_hashing.py +45 -0
  174. agent_capmap-0.1.0/tests/test_jsonc.py +34 -0
  175. agent_capmap-0.1.0/tests/test_netguard.py +69 -0
  176. agent_capmap-0.1.0/tests/test_policy.py +323 -0
  177. agent_capmap-0.1.0/tests/test_provider.py +105 -0
  178. agent_capmap-0.1.0/tests/test_redact.py +109 -0
  179. agent_capmap-0.1.0/tests/test_reference.py +207 -0
  180. agent_capmap-0.1.0/tests/test_report.py +264 -0
  181. agent_capmap-0.1.0/tests/test_server_attrs.py +88 -0
@@ -0,0 +1,9 @@
1
+ # Copy to .env (git-ignored) or export these in your shell. Never commit real values.
2
+
3
+ # Required only for `--classify` without `--offline`.
4
+ ANTHROPIC_API_KEY=<YOUR_API_KEY>
5
+
6
+ # Optional overrides.
7
+ # AGENTCAPMAP_MODEL=claude-opus-5-5
8
+ # AGENTCAPMAP_EFFORT=medium
9
+ # AGENTCAPMAP_CACHE_DIR=<PATH_TO_CACHE_DIR>
@@ -0,0 +1 @@
1
+ * text=auto eol=lf
@@ -0,0 +1,52 @@
1
+ name: Bug report
2
+ description: agent-capmap crashed, misread a config, or produced wrong output.
3
+ labels: [bug]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ **Before pasting anything, remove secrets.** agent-capmap redacts secrets in its own
9
+ output, but raw config files (`mcp.json`, `~/.claude.json`, `settings.json`) contain
10
+ API keys and tokens. Replace them with `<REDACTED>`. Security vulnerabilities go to
11
+ [private reporting](https://github.com/NKwolv/agent-capmap/security/advisories/new),
12
+ not here.
13
+ - type: input
14
+ id: version
15
+ attributes:
16
+ label: Version
17
+ description: Output of `agentcapmap --version`.
18
+ validations:
19
+ required: true
20
+ - type: input
21
+ id: environment
22
+ attributes:
23
+ label: OS and Python version
24
+ placeholder: Windows 11, Python 3.12
25
+ validations:
26
+ required: true
27
+ - type: textarea
28
+ id: command
29
+ attributes:
30
+ label: Command you ran
31
+ render: shell
32
+ validations:
33
+ required: true
34
+ - type: textarea
35
+ id: expected
36
+ attributes:
37
+ label: What you expected
38
+ validations:
39
+ required: true
40
+ - type: textarea
41
+ id: actual
42
+ attributes:
43
+ label: What happened
44
+ description: Error message or the relevant part of the output (secrets removed).
45
+ render: text
46
+ validations:
47
+ required: true
48
+ - type: textarea
49
+ id: config
50
+ attributes:
51
+ label: Minimal config that reproduces it (optional, secrets removed)
52
+ render: json
@@ -0,0 +1,52 @@
1
+ name: Wrong classification or finding
2
+ description: A tool got the wrong capability tags, or a rule fired (or failed to fire) wrongly.
3
+ labels: [classification]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ These reports improve the taxonomy, the classifier prompt and the evaluation set.
9
+ Tool definitions from public MCP servers are fine to paste; **remove secrets** and
10
+ anything internal from private servers. See
11
+ [docs/taxonomy.md](https://github.com/NKwolv/agent-capmap/blob/main/docs/taxonomy.md)
12
+ for what each tag means.
13
+ - type: dropdown
14
+ id: kind
15
+ attributes:
16
+ label: Kind of problem
17
+ options:
18
+ - Wrong tag on a tool
19
+ - False positive (a finding that should not fire)
20
+ - False negative (a risk that was missed)
21
+ - Suspicious-description flag wrong
22
+ validations:
23
+ required: true
24
+ - type: input
25
+ id: server
26
+ attributes:
27
+ label: MCP server and version
28
+ placeholder: "@modelcontextprotocol/server-filesystem 2026.1.14"
29
+ validations:
30
+ required: true
31
+ - type: textarea
32
+ id: tool
33
+ attributes:
34
+ label: Tool definition
35
+ description: The tool's name, description and input schema, as returned by tools/list.
36
+ render: json
37
+ validations:
38
+ required: true
39
+ - type: textarea
40
+ id: got
41
+ attributes:
42
+ label: What agent-capmap reported
43
+ description: The tags (with evidence) or the finding, and the model used if you classified with an LLM.
44
+ render: json
45
+ validations:
46
+ required: true
47
+ - type: textarea
48
+ id: expected
49
+ attributes:
50
+ label: What you expected, and why
51
+ validations:
52
+ required: true
@@ -0,0 +1,34 @@
1
+ name: Support another AI client or config format
2
+ description: Ask agent-capmap to read the MCP configuration of a client it does not support yet.
3
+ labels: [enhancement, discovery]
4
+ body:
5
+ - type: markdown
6
+ attributes:
7
+ value: |
8
+ Supported today: Claude Desktop, Cursor, VS Code, Claude Code and generic `mcp.json`.
9
+ Adding a client is a good first contribution; see "Adding a client config format" in
10
+ [CONTRIBUTING.md](https://github.com/NKwolv/agent-capmap/blob/main/CONTRIBUTING.md).
11
+ - type: input
12
+ id: client
13
+ attributes:
14
+ label: Client name and version
15
+ placeholder: Windsurf 1.12
16
+ validations:
17
+ required: true
18
+ - type: textarea
19
+ id: locations
20
+ attributes:
21
+ label: Where it stores MCP configuration
22
+ description: File paths per OS, and a link to the client's documentation if there is one.
23
+ validations:
24
+ required: true
25
+ - type: textarea
26
+ id: example
27
+ attributes:
28
+ label: Example config (secrets removed)
29
+ render: json
30
+ - type: textarea
31
+ id: approvals
32
+ attributes:
33
+ label: Approval / auto-approve settings (optional)
34
+ description: Does the client record which tools run without asking? Where?
@@ -0,0 +1,8 @@
1
+ blank_issues_enabled: false
2
+ contact_links:
3
+ - name: Report a security vulnerability
4
+ url: https://github.com/NKwolv/agent-capmap/security/advisories/new
5
+ about: Please report vulnerabilities privately, never in a public issue. See SECURITY.md.
6
+ - name: Ask a question
7
+ url: https://github.com/NKwolv/agent-capmap#readme
8
+ about: Check the README and docs/ first; if they do not answer it, open a bug report.
@@ -0,0 +1,22 @@
1
+ version: 2
2
+ updates:
3
+ # pyproject.toml ranges and the hash-pinned lockfiles in requirements/.
4
+ - package-ecosystem: pip
5
+ directories: ["/", "/requirements"]
6
+ schedule:
7
+ interval: weekly
8
+ # Let new releases age before proposing them (supply-chain safety).
9
+ cooldown:
10
+ default-days: 14
11
+ groups:
12
+ python-dependencies:
13
+ patterns: ["*"]
14
+ - package-ecosystem: github-actions
15
+ directory: /
16
+ schedule:
17
+ interval: weekly
18
+ cooldown:
19
+ default-days: 14
20
+ groups:
21
+ github-actions:
22
+ patterns: ["*"]
@@ -0,0 +1,19 @@
1
+ ## What and why
2
+
3
+ <!-- What does this change, and why is it needed? Link the issue if there is one. -->
4
+
5
+ ## Checklist
6
+
7
+ - [ ] All checks from [CONTRIBUTING.md](../CONTRIBUTING.md) pass locally (ruff, mypy,
8
+ pytest, bandit, pip-audit, zizmor, gitleaks).
9
+ - [ ] Tests added or updated, including negative cases for anything security-relevant.
10
+ - [ ] No secrets, personal paths or real credentials in code, fixtures or output.
11
+ - [ ] Untrusted input (configs, server responses, LLM output) is size-bounded and
12
+ validated; nothing from it reaches a shell, `eval` or a file path unchecked.
13
+ - [ ] New dependencies are justified, verified on PyPI and added to the lockfiles.
14
+ - [ ] Docs and CHANGELOG updated if behavior changed.
15
+
16
+ ## Security notes
17
+
18
+ <!-- Trust boundaries touched, assumptions made, anything that needs a maintainer
19
+ decision. Write "None" if the change has no security impact. -->
@@ -0,0 +1,69 @@
1
+ name: Action self-test
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # Read-only: the self-test runs the local action and checks its outputs; it uploads
9
+ # nothing (code scanning upload is exercised by users' workflows, see docs/examples).
10
+ permissions:
11
+ contents: read
12
+
13
+ concurrency:
14
+ group: ${{ github.workflow }}-${{ github.ref }}
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ selftest:
19
+ name: Run the action on the scenario fixtures
20
+ runs-on: ${{ matrix.os }}
21
+ strategy:
22
+ fail-fast: false
23
+ matrix:
24
+ os: [ubuntu-latest, windows-latest]
25
+ steps:
26
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
27
+ with:
28
+ persist-credentials: false
29
+ - id: capmap
30
+ # The self-test must run the action from this checkout (the commit under test).
31
+ # The $/ self-repository form is not documented for a root-level action.yml.
32
+ uses: ./ # zizmor: ignore[self-repository]
33
+ with:
34
+ path: fixtures
35
+ fail-on: none
36
+ sarif-file: selftest.sarif
37
+ - name: Check outputs and SARIF
38
+ shell: bash
39
+ env:
40
+ FINDINGS: ${{ steps.capmap.outputs.findings }}
41
+ SARIF: ${{ steps.capmap.outputs.sarif-file }}
42
+ run: |
43
+ set -euo pipefail
44
+ # Without enumeration only config-level rules can fire: CAP-007 on the
45
+ # unpinned server in fixtures/overscoped-token.
46
+ test "$FINDINGS" = "1"
47
+ python - "$SARIF" <<'EOF'
48
+ import json, sys
49
+ sarif = json.load(open(sys.argv[1], encoding="utf-8"))
50
+ assert sarif["version"] == "2.1.0"
51
+ (result,) = sarif["runs"][0]["results"]
52
+ assert result["ruleId"] == "CAP-007", result["ruleId"]
53
+ uri = result["locations"][0]["physicalLocation"]["artifactLocation"]["uri"]
54
+ assert uri == "fixtures/overscoped-token/mcp.json", uri
55
+ print("SARIF ok:", result["ruleId"], uri)
56
+ EOF
57
+ - name: Gate fails at medium
58
+ id: gate
59
+ continue-on-error: true
60
+ uses: ./ # zizmor: ignore[self-repository]
61
+ with:
62
+ path: fixtures
63
+ fail-on: medium
64
+ sarif-file: gate.sarif
65
+ - name: Check the gate failed
66
+ shell: bash
67
+ env:
68
+ OUTCOME: ${{ steps.gate.outcome }}
69
+ run: test "$OUTCOME" = "failure"
@@ -0,0 +1,110 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ # Read-only token: CI only checks out code and runs local tools.
9
+ permissions:
10
+ contents: read
11
+
12
+ concurrency:
13
+ group: ${{ github.workflow }}-${{ github.ref }}
14
+ cancel-in-progress: true
15
+
16
+ jobs:
17
+ test:
18
+ name: Test (${{ matrix.os }}, Python ${{ matrix.python-version }})
19
+ runs-on: ${{ matrix.os }}
20
+ strategy:
21
+ fail-fast: false
22
+ matrix:
23
+ os: [ubuntu-latest, windows-latest]
24
+ python-version: ["3.11", "3.12", "3.13"]
25
+ steps:
26
+ # Actions are pinned to full commit SHAs; Dependabot keeps them current.
27
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
28
+ with:
29
+ persist-credentials: false
30
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
31
+ with:
32
+ python-version: ${{ matrix.python-version }}
33
+ - name: Install (hash-pinned lockfile, no unpinned build dependencies)
34
+ run: |
35
+ python -m pip install --require-hashes -r requirements/dev.lock
36
+ python -m pip install --no-deps --no-build-isolation -e .
37
+ - name: Ruff (lint, incl. security rules)
38
+ run: ruff check . && ruff format --check .
39
+ - name: Mypy
40
+ run: mypy
41
+ - name: Pytest
42
+ run: pytest
43
+
44
+ security:
45
+ name: Security scans (SAST + SCA)
46
+ runs-on: ubuntu-latest
47
+ steps:
48
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
49
+ with:
50
+ persist-credentials: false
51
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
52
+ with:
53
+ python-version: "3.12"
54
+ - name: Install
55
+ run: |
56
+ python -m pip install --require-hashes -r requirements/dev.lock
57
+ python -m pip install --no-deps --no-build-isolation -e .
58
+ - name: SAST (bandit)
59
+ run: bandit -c pyproject.toml -r src
60
+ - name: SCA (pip-audit on every locked dependency)
61
+ run: pip-audit --strict --require-hashes -r requirements/dev.lock
62
+ - name: Workflow security (zizmor)
63
+ run: zizmor --offline --persona auditor action.yml .github/workflows/
64
+
65
+ secrets:
66
+ name: Secret scanning (gitleaks, full history)
67
+ runs-on: ubuntu-latest
68
+ steps:
69
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
70
+ with:
71
+ fetch-depth: 0
72
+ persist-credentials: false
73
+ - name: gitleaks
74
+ # Official image pinned by digest (v8.30.1), no network. Runs as the runner user
75
+ # so git's ownership check passes; --redact keeps any finding out of the log.
76
+ run: >
77
+ docker run --rm --network none --user "$(id -u):$(id -g)"
78
+ -v "${GITHUB_WORKSPACE}:/repo"
79
+ ghcr.io/gitleaks/gitleaks@sha256:c00b6bd0aeb3071cbcb79009cb16a60dd9e0a7c60e2be9ab65d25e6bc8abbb7f
80
+ git /repo --config /repo/.gitleaks.toml --redact --no-banner --exit-code 1
81
+
82
+ sbom:
83
+ name: SBOM (CycloneDX)
84
+ runs-on: ubuntu-latest
85
+ steps:
86
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
87
+ with:
88
+ persist-credentials: false
89
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
90
+ with:
91
+ python-version: "3.12"
92
+ - name: Install tooling
93
+ run: python -m pip install --require-hashes -r requirements/dev.lock
94
+ - name: Build wheel and a clean runtime environment
95
+ # The SBOM describes exactly what a user installs: the runtime lockfile plus
96
+ # this package, in an environment with no installer tooling.
97
+ run: |
98
+ python -m pip wheel --no-deps --no-build-isolation -w dist .
99
+ python -m venv --without-pip runtime-env
100
+ python -m pip --python runtime-env/bin/python install --require-hashes -r requirements/runtime.lock
101
+ python -m pip --python runtime-env/bin/python install --no-deps --no-index dist/*.whl
102
+ - name: Generate SBOM
103
+ run: >
104
+ cyclonedx-py environment --pyproject pyproject.toml --mc-type application
105
+ --output-format JSON --output-reproducible -o sbom.cdx.json runtime-env/bin/python
106
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
107
+ with:
108
+ name: sbom
109
+ path: sbom.cdx.json
110
+ if-no-files-found: error
@@ -0,0 +1,40 @@
1
+ name: CodeQL
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+ workflow_dispatch:
8
+ schedule:
9
+ - cron: "17 3 * * 1"
10
+
11
+ # Default to read-only; the analyze job widens only what CodeQL needs.
12
+ permissions:
13
+ contents: read
14
+
15
+ concurrency:
16
+ group: ${{ github.workflow }}-${{ github.ref }}
17
+ cancel-in-progress: true
18
+
19
+ jobs:
20
+ analyze:
21
+ name: CodeQL (${{ matrix.language }})
22
+ runs-on: ubuntu-latest
23
+ permissions:
24
+ contents: read # check out the code
25
+ security-events: write # upload CodeQL results to code scanning
26
+ strategy:
27
+ fail-fast: false
28
+ matrix:
29
+ language: [python, actions]
30
+ steps:
31
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
32
+ with:
33
+ persist-credentials: false
34
+ - uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
35
+ with:
36
+ languages: ${{ matrix.language }}
37
+ queries: security-and-quality
38
+ - uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
39
+ with:
40
+ category: /language:${{ matrix.language }}
@@ -0,0 +1,109 @@
1
+ name: Release
2
+
3
+ # Publishes a version to PyPI and GitHub Releases when a tag like v0.1.0 is pushed.
4
+ # PyPI uses trusted publishing (OIDC): no API token is stored in this repository.
5
+ on:
6
+ push:
7
+ tags: ["v*"]
8
+
9
+ # Every job declares the minimum it needs.
10
+ permissions: {}
11
+
12
+ # One release at a time, and never cancel one halfway through publishing.
13
+ concurrency:
14
+ group: release
15
+ cancel-in-progress: false
16
+
17
+ jobs:
18
+ verify:
19
+ name: Verify (tests and SCA)
20
+ runs-on: ubuntu-latest
21
+ permissions:
22
+ contents: read
23
+ steps:
24
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
25
+ with:
26
+ persist-credentials: false
27
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
28
+ with:
29
+ python-version: "3.12"
30
+ - name: Check the tag matches the package version
31
+ env:
32
+ TAG: ${{ github.ref_name }}
33
+ run: |
34
+ version=$(python -c "import tomllib; print(tomllib.load(open('pyproject.toml', 'rb'))['project']['version'])")
35
+ if [ "$TAG" != "v$version" ]; then
36
+ echo "::error::Tag $TAG does not match version $version in pyproject.toml"
37
+ exit 1
38
+ fi
39
+ - name: Install (hash-pinned lockfile)
40
+ run: |
41
+ python -m pip install --require-hashes -r requirements/dev.lock
42
+ python -m pip install --no-deps --no-build-isolation -e .
43
+ - name: Tests
44
+ run: pytest
45
+ - name: SCA (pip-audit on every locked dependency)
46
+ run: |
47
+ pip-audit --strict --require-hashes -r requirements/runtime.lock
48
+ pip-audit --strict --require-hashes -r requirements/build.lock
49
+
50
+ build:
51
+ name: Build distributions
52
+ needs: verify
53
+ runs-on: ubuntu-latest
54
+ permissions:
55
+ contents: read
56
+ steps:
57
+ - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
58
+ with:
59
+ persist-credentials: false
60
+ - uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
61
+ with:
62
+ python-version: "3.12"
63
+ - name: Build sdist and wheel (hash-pinned build backend)
64
+ run: |
65
+ python -m pip install --require-hashes -r requirements/build.lock
66
+ python -m hatchling build -t sdist -t wheel
67
+ - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
68
+ with:
69
+ name: dist
70
+ path: dist/
71
+ if-no-files-found: error
72
+
73
+ pypi:
74
+ name: Publish to PyPI
75
+ needs: build
76
+ runs-on: ubuntu-latest
77
+ # Configure this environment on GitHub with a required reviewer so every release
78
+ # needs a manual approval; PyPI's trusted publisher is bound to it.
79
+ environment:
80
+ name: pypi
81
+ url: https://pypi.org/project/agent-capmap/
82
+ permissions:
83
+ id-token: write # OIDC token for trusted publishing and attestations
84
+ steps:
85
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
86
+ with:
87
+ name: dist
88
+ path: dist/
89
+ - uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2
90
+
91
+ github-release:
92
+ name: GitHub release
93
+ needs: pypi
94
+ runs-on: ubuntu-latest
95
+ permissions:
96
+ contents: write # create the release and upload the distributions
97
+ steps:
98
+ - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
99
+ with:
100
+ name: dist
101
+ path: dist/
102
+ - name: Create release
103
+ env:
104
+ GH_TOKEN: ${{ github.token }}
105
+ TAG: ${{ github.ref_name }}
106
+ run: >
107
+ gh release create "$TAG" dist/* --repo "$GITHUB_REPOSITORY" --verify-tag
108
+ --title "$TAG"
109
+ --notes "See [CHANGELOG.md](https://github.com/$GITHUB_REPOSITORY/blob/$TAG/CHANGELOG.md). Install: \`pipx install agent-capmap==${TAG#v}\`"
@@ -0,0 +1,31 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *.egg-info/
4
+ .venv/
5
+ venv/
6
+ build/
7
+ dist/
8
+ .mypy_cache/
9
+ .pytest_cache/
10
+ .ruff_cache/
11
+ .coverage
12
+ htmlcov/
13
+
14
+ # Secrets and credentials: never commit (AGENTS.md section 1)
15
+ .env
16
+ .env.*
17
+ !.env.example
18
+ *.pem
19
+ *.key
20
+ *.p12
21
+ *.pfx
22
+ credentials*
23
+ *.tfstate
24
+ *.tfstate.*
25
+ kubeconfig
26
+ .secrets/
27
+
28
+ # Local classifier cache and scan output (may contain tool descriptions)
29
+ .agentcapmap/
30
+ /inventory*.json
31
+ /sbom*.json
@@ -0,0 +1,15 @@
1
+ title = "agent-capmap secret scanning"
2
+
3
+ # Start from gitleaks' maintained default rule set.
4
+ [extend]
5
+ useDefault = true
6
+
7
+ # Test fixtures deliberately contain credential-shaped values so redaction can be
8
+ # tested, and every one of them contains "fake" (see tests/fake_secrets.py).
9
+ #
10
+ # This allowlist matches on the secret value only. Do NOT add `paths` here: in gitleaks
11
+ # 8.30 a path entry skips matching files entirely, even with condition = "AND", which
12
+ # would hide a real secret placed in tests/ (verified by a negative test).
13
+ [[allowlists]]
14
+ description = "Deliberately fake credentials (value contains 'fake')"
15
+ regexes = ['''(?i)fake''']
@@ -0,0 +1,7 @@
1
+ # Exact gitleaks findings reviewed and accepted. Each entry is one finding in one commit;
2
+ # anything new is still reported.
3
+ #
4
+ # Phase 1 commit: deliberately fake test values that did not yet contain "fake".
5
+ # Since replaced (tests/fake_secrets.py PATH_SECRET, tests/test_redact.py JWT sample).
6
+ bc368719f073b650f42dd721394bfa5db74c4f75:tests/test_redact.py:jwt:39
7
+ bc368719f073b650f42dd721394bfa5db74c4f75:tests/fake_secrets.py:generic-api-key:13
@@ -0,0 +1,27 @@
1
+ # All hooks run the tool versions pinned in requirements/dev.lock (installed in your
2
+ # venv), so pre-commit never fetches unpinned third-party hook code.
3
+ repos:
4
+ - repo: local
5
+ hooks:
6
+ - id: ruff
7
+ name: ruff (lint, incl. security rules)
8
+ entry: ruff check --fix
9
+ language: system
10
+ types: [python]
11
+ - id: ruff-format
12
+ name: ruff format
13
+ entry: ruff format
14
+ language: system
15
+ types: [python]
16
+ - id: mypy
17
+ name: mypy
18
+ entry: mypy
19
+ language: system
20
+ types: [python]
21
+ pass_filenames: false
22
+ - id: bandit
23
+ name: bandit (SAST)
24
+ entry: bandit -q -c pyproject.toml -r src
25
+ language: system
26
+ types: [python]
27
+ pass_filenames: false