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.
- agent_capmap-0.1.0/.env.example +9 -0
- agent_capmap-0.1.0/.gitattributes +1 -0
- agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +52 -0
- agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/classification.yml +52 -0
- agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/client_support.yml +34 -0
- agent_capmap-0.1.0/.github/ISSUE_TEMPLATE/config.yml +8 -0
- agent_capmap-0.1.0/.github/dependabot.yml +22 -0
- agent_capmap-0.1.0/.github/pull_request_template.md +19 -0
- agent_capmap-0.1.0/.github/workflows/action-selftest.yml +69 -0
- agent_capmap-0.1.0/.github/workflows/ci.yml +110 -0
- agent_capmap-0.1.0/.github/workflows/codeql.yml +40 -0
- agent_capmap-0.1.0/.github/workflows/release.yml +109 -0
- agent_capmap-0.1.0/.gitignore +31 -0
- agent_capmap-0.1.0/.gitleaks.toml +15 -0
- agent_capmap-0.1.0/.gitleaksignore +7 -0
- agent_capmap-0.1.0/.pre-commit-config.yaml +27 -0
- agent_capmap-0.1.0/AGENTS.md +177 -0
- agent_capmap-0.1.0/CHANGELOG.md +168 -0
- agent_capmap-0.1.0/CLAUDE.md +1 -0
- agent_capmap-0.1.0/CODE_OF_CONDUCT.md +83 -0
- agent_capmap-0.1.0/CONTRIBUTING.md +173 -0
- agent_capmap-0.1.0/LICENSE +21 -0
- agent_capmap-0.1.0/PKG-INFO +295 -0
- agent_capmap-0.1.0/README.md +252 -0
- agent_capmap-0.1.0/SECURITY.md +59 -0
- agent_capmap-0.1.0/action.yml +137 -0
- agent_capmap-0.1.0/docs/blog-outline.md +73 -0
- agent_capmap-0.1.0/docs/examples/agentcapmap.yml +89 -0
- agent_capmap-0.1.0/docs/github-action.md +61 -0
- agent_capmap-0.1.0/docs/poc-checklist.md +111 -0
- agent_capmap-0.1.0/docs/taxonomy.md +159 -0
- agent_capmap-0.1.0/docs/threat-model.md +180 -0
- agent_capmap-0.1.0/docs/vs-mcp-scan.md +73 -0
- agent_capmap-0.1.0/eval/README.md +121 -0
- agent_capmap-0.1.0/eval/agents.json +103 -0
- agent_capmap-0.1.0/eval/apply_labels.py +82 -0
- agent_capmap-0.1.0/eval/capture.py +221 -0
- agent_capmap-0.1.0/eval/catalog.json +82 -0
- agent_capmap-0.1.0/eval/labeled_servers/aws-api.json +117 -0
- agent_capmap-0.1.0/eval/labeled_servers/aws-iam.json +3175 -0
- agent_capmap-0.1.0/eval/labeled_servers/azure.json +2990 -0
- agent_capmap-0.1.0/eval/labeled_servers/brave-search.json +105 -0
- agent_capmap-0.1.0/eval/labeled_servers/commands.json +77 -0
- agent_capmap-0.1.0/eval/labeled_servers/context7.json +110 -0
- agent_capmap-0.1.0/eval/labeled_servers/deepwiki.json +137 -0
- agent_capmap-0.1.0/eval/labeled_servers/desktop-commander.json +1142 -0
- agent_capmap-0.1.0/eval/labeled_servers/exa.json +119 -0
- agent_capmap-0.1.0/eval/labeled_servers/fetch.json +85 -0
- agent_capmap-0.1.0/eval/labeled_servers/filesystem.json +547 -0
- agent_capmap-0.1.0/eval/labeled_servers/firecrawl.json +3060 -0
- agent_capmap-0.1.0/eval/labeled_servers/git.json +546 -0
- agent_capmap-0.1.0/eval/labeled_servers/github.json +1502 -0
- agent_capmap-0.1.0/eval/labeled_servers/gitlab.json +239 -0
- agent_capmap-0.1.0/eval/labeled_servers/heroku.json +1411 -0
- agent_capmap-0.1.0/eval/labeled_servers/memory.json +426 -0
- agent_capmap-0.1.0/eval/labeled_servers/notion.json +6736 -0
- agent_capmap-0.1.0/eval/labeled_servers/obsidian.json +606 -0
- agent_capmap-0.1.0/eval/labeled_servers/playwright.json +1171 -0
- agent_capmap-0.1.0/eval/labeled_servers/postgres.json +54 -0
- agent_capmap-0.1.0/eval/labeled_servers/qdrant.json +106 -0
- agent_capmap-0.1.0/eval/labeled_servers/sentry.json +662 -0
- agent_capmap-0.1.0/eval/labeled_servers/sequential-thinking.json +109 -0
- agent_capmap-0.1.0/eval/labeled_servers/slack.json +325 -0
- agent_capmap-0.1.0/eval/labeled_servers/supabase.json +1147 -0
- agent_capmap-0.1.0/eval/labeled_servers/tavily.json +434 -0
- agent_capmap-0.1.0/eval/labeled_servers/time.json +96 -0
- agent_capmap-0.1.0/eval/run_eval.py +298 -0
- agent_capmap-0.1.0/examples/README.md +31 -0
- agent_capmap-0.1.0/examples/demo/inventory.json +860 -0
- agent_capmap-0.1.0/examples/live-trifecta/mcp.json +12 -0
- agent_capmap-0.1.0/examples/live-trifecta/sandbox/README.md +2 -0
- agent_capmap-0.1.0/fixtures/README.md +27 -0
- agent_capmap-0.1.0/fixtures/clean/expected.json +25 -0
- agent_capmap-0.1.0/fixtures/clean/mcp.json +12 -0
- agent_capmap-0.1.0/fixtures/clean/tools.json +34 -0
- agent_capmap-0.1.0/fixtures/exec-injection/expected.json +128 -0
- agent_capmap-0.1.0/fixtures/exec-injection/mcp.json +12 -0
- agent_capmap-0.1.0/fixtures/exec-injection/tools.json +40 -0
- agent_capmap-0.1.0/fixtures/no-approval-destructive/expected.json +59 -0
- agent_capmap-0.1.0/fixtures/no-approval-destructive/mcp.json +9 -0
- agent_capmap-0.1.0/fixtures/no-approval-destructive/tools.json +20 -0
- agent_capmap-0.1.0/fixtures/overscoped-token/expected.json +106 -0
- agent_capmap-0.1.0/fixtures/overscoped-token/mcp.json +14 -0
- agent_capmap-0.1.0/fixtures/overscoped-token/tools.json +25 -0
- agent_capmap-0.1.0/fixtures/poisoned-description/expected.json +57 -0
- agent_capmap-0.1.0/fixtures/poisoned-description/mcp.json +8 -0
- agent_capmap-0.1.0/fixtures/poisoned-description/tools.json +23 -0
- agent_capmap-0.1.0/fixtures/rug-pull/baseline.json +11 -0
- agent_capmap-0.1.0/fixtures/rug-pull/expected.json +105 -0
- agent_capmap-0.1.0/fixtures/rug-pull/mcp.json +8 -0
- agent_capmap-0.1.0/fixtures/rug-pull/tools.json +32 -0
- agent_capmap-0.1.0/fixtures/shadowing/expected.json +77 -0
- agent_capmap-0.1.0/fixtures/shadowing/mcp.json +12 -0
- agent_capmap-0.1.0/fixtures/shadowing/tools.json +24 -0
- agent_capmap-0.1.0/fixtures/trifecta/expected.json +87 -0
- agent_capmap-0.1.0/fixtures/trifecta/mcp.json +22 -0
- agent_capmap-0.1.0/fixtures/trifecta/tools.json +33 -0
- agent_capmap-0.1.0/policies/default.yaml +113 -0
- agent_capmap-0.1.0/pyproject.toml +95 -0
- agent_capmap-0.1.0/requirements/build.in +4 -0
- agent_capmap-0.1.0/requirements/build.lock +30 -0
- agent_capmap-0.1.0/requirements/dev.lock +1687 -0
- agent_capmap-0.1.0/requirements/runtime.lock +562 -0
- agent_capmap-0.1.0/schemas/policy.schema.json +172 -0
- agent_capmap-0.1.0/schemas/tool-tags.schema.json +57 -0
- agent_capmap-0.1.0/scripts/build_reference_labels.py +87 -0
- agent_capmap-0.1.0/scripts/check.py +81 -0
- agent_capmap-0.1.0/src/agentcapmap/__init__.py +3 -0
- agent_capmap-0.1.0/src/agentcapmap/__main__.py +5 -0
- agent_capmap-0.1.0/src/agentcapmap/baseline.py +125 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/__init__.py +221 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/cache.py +74 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/prompt.py +160 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/provider.py +122 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/reference.py +115 -0
- agent_capmap-0.1.0/src/agentcapmap/classify/reference_labels.json +6135 -0
- agent_capmap-0.1.0/src/agentcapmap/cli.py +392 -0
- agent_capmap-0.1.0/src/agentcapmap/diff.py +103 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/__init__.py +209 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/_common.py +297 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/claude_code.py +258 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/claude_desktop.py +28 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/cursor.py +33 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/mcp_json.py +29 -0
- agent_capmap-0.1.0/src/agentcapmap/discovery/vscode.py +65 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/__init__.py +278 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/hashing.py +37 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/http.py +313 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/netguard.py +60 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/stdio.py +273 -0
- agent_capmap-0.1.0/src/agentcapmap/enumerate/transport.py +86 -0
- agent_capmap-0.1.0/src/agentcapmap/evaluation.py +498 -0
- agent_capmap-0.1.0/src/agentcapmap/findings.py +129 -0
- agent_capmap-0.1.0/src/agentcapmap/graph/__init__.py +264 -0
- agent_capmap-0.1.0/src/agentcapmap/graph/server_attrs.py +164 -0
- agent_capmap-0.1.0/src/agentcapmap/limits.py +35 -0
- agent_capmap-0.1.0/src/agentcapmap/models.py +186 -0
- agent_capmap-0.1.0/src/agentcapmap/policy/__init__.py +24 -0
- agent_capmap-0.1.0/src/agentcapmap/policy/engine.py +229 -0
- agent_capmap-0.1.0/src/agentcapmap/policy/loader.py +223 -0
- agent_capmap-0.1.0/src/agentcapmap/py.typed +0 -0
- agent_capmap-0.1.0/src/agentcapmap/redact.py +268 -0
- agent_capmap-0.1.0/src/agentcapmap/report/__init__.py +36 -0
- agent_capmap-0.1.0/src/agentcapmap/report/_text.py +62 -0
- agent_capmap-0.1.0/src/agentcapmap/report/markdown.py +152 -0
- agent_capmap-0.1.0/src/agentcapmap/report/sarif.py +209 -0
- agent_capmap-0.1.0/src/agentcapmap/taxonomy.py +56 -0
- agent_capmap-0.1.0/tests/__init__.py +0 -0
- agent_capmap-0.1.0/tests/conftest.py +74 -0
- agent_capmap-0.1.0/tests/fake_llm.py +74 -0
- agent_capmap-0.1.0/tests/fake_secrets.py +34 -0
- agent_capmap-0.1.0/tests/fixtures/configs/claude_code/.mcp.json +31 -0
- agent_capmap-0.1.0/tests/fixtures/configs/claude_desktop/claude_desktop_config.json +24 -0
- agent_capmap-0.1.0/tests/fixtures/configs/cursor/.cursor/mcp.json +24 -0
- agent_capmap-0.1.0/tests/fixtures/configs/generic/mcp.json +11 -0
- agent_capmap-0.1.0/tests/fixtures/configs/vscode/.vscode/mcp.json +32 -0
- agent_capmap-0.1.0/tests/fixtures/configs/vscode/.vscode/settings.json +28 -0
- agent_capmap-0.1.0/tests/fixtures/sarif/SOURCE.md +11 -0
- agent_capmap-0.1.0/tests/fixtures/sarif/sarif-schema-2.1.0.json +3389 -0
- agent_capmap-0.1.0/tests/mock_mcp_server.py +287 -0
- agent_capmap-0.1.0/tests/scenarios.py +96 -0
- agent_capmap-0.1.0/tests/test_baseline.py +74 -0
- agent_capmap-0.1.0/tests/test_classify.py +318 -0
- agent_capmap-0.1.0/tests/test_claude_code.py +222 -0
- agent_capmap-0.1.0/tests/test_cli.py +231 -0
- agent_capmap-0.1.0/tests/test_diff.py +94 -0
- agent_capmap-0.1.0/tests/test_discovery.py +204 -0
- agent_capmap-0.1.0/tests/test_enumerate_http.py +83 -0
- agent_capmap-0.1.0/tests/test_enumerate_stdio.py +203 -0
- agent_capmap-0.1.0/tests/test_evaluation.py +292 -0
- agent_capmap-0.1.0/tests/test_fixtures.py +182 -0
- agent_capmap-0.1.0/tests/test_hardening.py +231 -0
- agent_capmap-0.1.0/tests/test_hashing.py +45 -0
- agent_capmap-0.1.0/tests/test_jsonc.py +34 -0
- agent_capmap-0.1.0/tests/test_netguard.py +69 -0
- agent_capmap-0.1.0/tests/test_policy.py +323 -0
- agent_capmap-0.1.0/tests/test_provider.py +105 -0
- agent_capmap-0.1.0/tests/test_redact.py +109 -0
- agent_capmap-0.1.0/tests/test_reference.py +207 -0
- agent_capmap-0.1.0/tests/test_report.py +264 -0
- 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
|