stacktrace-cli 0.1.0__tar.gz → 0.2.1__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.
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/CLAUDE.md +27 -6
- stacktrace_cli-0.2.1/PKG-INFO +154 -0
- stacktrace_cli-0.2.1/README.md +129 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0006-trust-boundary-and-detection-upload.md +1 -1
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0008-console-in-separate-demo-package.md +2 -2
- stacktrace_cli-0.2.1/docs/adrs/0026-the-console-becomes-a-product-surface.md +108 -0
- stacktrace_cli-0.2.1/docs/adrs/0027-a-finding-may-name-what-it-could-not-place.md +112 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/INDEX.md +3 -1
- stacktrace_cli-0.2.1/docs/cutover-openaca-remote.md +87 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/007-detection-upload.md +11 -6
- stacktrace_cli-0.2.1/docs/plans/008-monitor.md +630 -0
- stacktrace_cli-0.2.1/docs/releases/v0.2.0.md +121 -0
- stacktrace_cli-0.2.1/docs/releases/v0.2.1.md +49 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/detection-upload.md +23 -1
- stacktrace_cli-0.2.1/docs/specs/monitor.md +459 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/pyproject.toml +8 -4
- stacktrace_cli-0.2.1/src/stacktrace_cli/__init__.py +3 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/analysis.py +375 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/cli.py +174 -18
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/acquire.py +5 -9
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/composition.py +59 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/join.py +48 -2
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/orchestrate.py +37 -3
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/record.py +8 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/deterministic.py +95 -47
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/finding.py +111 -2
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/render.py +62 -2
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/run.py +385 -17
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/__init__.py +12 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/escalate.py +172 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/render.py +252 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/server.py +477 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/app.js +1045 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/OFL.txt +210 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-mono-400-latin.woff2 +0 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-mono-500-latin.woff2 +0 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/fonts/dm-sans-latin.woff2 +0 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/index.html +104 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/site/styles.css +628 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/state.py +102 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/verdicts.py +52 -0
- stacktrace_cli-0.2.1/src/stacktrace_cli/monitor/watch.py +349 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/detect_payload.py +99 -27
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/redact.py +13 -2
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/sync_detect.py +79 -42
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/upload_contract.py +21 -0
- stacktrace_cli-0.2.1/tests/monitor/feed_harness.mjs +803 -0
- stacktrace_cli-0.2.1/tests/monitor/test_escalation_gates.py +398 -0
- stacktrace_cli-0.2.1/tests/monitor/test_feed_model.py +484 -0
- stacktrace_cli-0.2.1/tests/monitor/test_render.py +344 -0
- stacktrace_cli-0.2.1/tests/monitor/test_server.py +413 -0
- stacktrace_cli-0.2.1/tests/monitor/test_site_assets.py +204 -0
- stacktrace_cli-0.2.1/tests/monitor/test_state.py +111 -0
- stacktrace_cli-0.2.1/tests/monitor/test_verdicts.py +137 -0
- stacktrace_cli-0.2.1/tests/monitor/test_watch.py +607 -0
- stacktrace_cli-0.2.1/tests/remote/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_contract_is_exhaustive.py +79 -2
- stacktrace_cli-0.2.1/tests/remote/test_detect_payload_reaches_the_cloud_model.py +286 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_redaction.py +49 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_sync_detect.py +2 -2
- stacktrace_cli-0.2.1/tests/test_agent_instance_id.py +207 -0
- stacktrace_cli-0.2.1/tests/test_analysis.py +362 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_cli.py +38 -0
- stacktrace_cli-0.2.1/tests/test_detection_components.py +194 -0
- stacktrace_cli-0.2.1/tests/test_detection_subject.py +671 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_render.py +93 -1
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_run.py +43 -0
- stacktrace_cli-0.2.1/tests/test_monitor_cli.py +85 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_untrusted_content_never_travels.py +216 -6
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/uv.lock +1 -1
- stacktrace_cli-0.1.0/PKG-INFO +0 -228
- stacktrace_cli-0.1.0/README.md +0 -207
- stacktrace_cli-0.1.0/src/stacktrace_cli/__init__.py +0 -3
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.agents/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.claude/settings.json +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.claude/skills/release-stacktrace/SKILL.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.codex/hooks.json +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/autofix.yml +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/ci.yml +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/claude.yml +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.github/workflows/publish-pypi.yml +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/.gitignore +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/AGENTS.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0001-session-telemetry-as-input.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0002-session-collection-in-openaidr.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0003-runtime-edges.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0004-three-stage-detector.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0005-detection-family-and-report-assembly.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0007-proprietary-package-on-open-dependencies.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0010-detection-severity-and-confidence-ladders.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0011-verdict-cache.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0012-observation-evidence-kinds-and-transport.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0013-rule-catalogue-triage-and-per-rule-context.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0014-declared-project-mapping.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0015-narrow-the-security-catalogue.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0016-stall-grouping-is-session-wide.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0017-a-declined-repeat-is-a-stall.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0018-remote-sync-config-and-facade-consumption.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0019-delegated-commands-are-openaca-objects.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0020-openaca-consumption-boundary.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0021-two-command-kinds.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0022-detection-scope-is-a-catalogue-column.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0023-sync-detect-collects-and-does-not-escalate.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0024-the-upload-carries-observations.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/0025-a-denied-call-is-activity-never-an-invocation.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/HOOK-PROMPT.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/adrs/TEMPLATE.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/002-session-input.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/003-correlation.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/004-detector.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/005-remote-sync.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/plans/006-cli-composition.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/releases/v0.0.1.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/releases/v0.1.0.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/aidr.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/cli-composition.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/correlation.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/detector.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/remote-sync.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/docs/specs/session-input.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/scripts/git-hooks/pre-push +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/scripts/install-hooks.sh +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/__main__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/observed.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/project_map.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/correlate/render.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/analyzer.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/cache.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/markers.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/priors.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/exclusions.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/framing.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-deceptive-completion.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-injected-instruction-followed.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/prompts/v1/stacktrace-intent-drift.md +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/reasoning.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/rules.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/secrets.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/detector/verdict.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/cli.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/client.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/config.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/payload.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/policy.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/spool.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/remote/sync.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/access.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/outcome.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/protocols.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/src/stacktrace_cli/sessions/render.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/agent_bom_fixture.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/detector_session_fixture.py +0 -0
- {stacktrace_cli-0.1.0/tests/remote → stacktrace_cli-0.2.1/tests/monitor}/__init__.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/helpers.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_cli.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_client.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_config.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_activity.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_cli.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_client.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_gate_matches_the_cloud.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_layers_compose.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_spool.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_upload_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_detect_wire_payload.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_facade_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_payload.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_policy.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_redact_payload.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_seam.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_spool.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_sync.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/remote/test_upload_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_acquire.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_bom_shape.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_call_status_conventions.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_composition.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlate_orchestrate.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlate_render.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_correlated_session.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_analyzer_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_analyzer_live.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_cache.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_deterministic.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_end_to_end.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_finding.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_liveness.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_markers.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_priors.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_reasoning.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_secrets.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_detector_verdict.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_fingerprint_covers_what_the_analyzer_reads.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_help_sections.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_join.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_observed.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_openaca_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_openaidr_contract.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_option_arity_matches_the_binary.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_project_map.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_readme_examples_are_real_output.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_release_readiness.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_seam_boundary.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_access.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_end_to_end.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_protocol_typing.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_protocols.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_sessions_render.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_shell_separators_match_the_shell.py +0 -0
- {stacktrace_cli-0.1.0 → stacktrace_cli-0.2.1}/tests/test_verification_subcommands_match_the_binary.py +0 -0
|
@@ -11,8 +11,8 @@ and by CI pipelines that invoke `stacktrace`, and it builds on the open-source
|
|
|
11
11
|
It is also the **design home for Stacktrace Detect** — the AIDR product this CLI
|
|
12
12
|
grows into. The specs in `docs/specs/` and the decisions in `docs/adrs/` describe
|
|
13
13
|
the whole system: session input, correlation against the composition graph, the
|
|
14
|
-
three-stage detector, and the combined report. The code here
|
|
15
|
-
|
|
14
|
+
three-stage detector, and the combined report. The code here implements them
|
|
15
|
+
incrementally.
|
|
16
16
|
|
|
17
17
|
## Common commands
|
|
18
18
|
|
|
@@ -52,11 +52,13 @@ the single source of truth for the version string reported by `--version`.
|
|
|
52
52
|
|
|
53
53
|
Build backend is hatchling with a src layout; the wheel's contents are declared
|
|
54
54
|
explicitly by `[tool.hatch.build.targets.wheel] packages = ["src/stacktrace_cli"]`.
|
|
55
|
-
|
|
56
|
-
|
|
55
|
+
Runtime dependencies are `openaca` for the Agent Composition Analysis
|
|
56
|
+
primitives this CLI drives, `openaidr` for session collection, and `httpx` for
|
|
57
|
+
the remote channel. Each is pinned exactly before a release; see
|
|
58
|
+
`docs/cutover-openaca-remote.md`.
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
+
`sessions`, `detect`, `monitor` and `remote` are native; `bom`, `policy` and
|
|
61
|
+
`scan` are OpenACA's own command objects.
|
|
60
62
|
|
|
61
63
|
**The design that functionality implements is in this repo.** Read
|
|
62
64
|
`docs/specs/aidr.md` first — it is the umbrella: components, contracts, the two
|
|
@@ -121,6 +123,25 @@ nothing about detection.
|
|
|
121
123
|
a review names a site, fix the invariant and extend the exhaustive test — a
|
|
122
124
|
second finding of the same class means the first fix was at the wrong level.
|
|
123
125
|
|
|
126
|
+
## Adding a command
|
|
127
|
+
|
|
128
|
+
A command is a **pass-through** or it is **native**, never both — and a
|
|
129
|
+
pass-through never gains a flag of its own. See
|
|
130
|
+
[ADR-0021](docs/adrs/0021-two-command-kinds.md) for why.
|
|
131
|
+
|
|
132
|
+
- **Pass-through** — add one string to `PASSTHROUGH` in
|
|
133
|
+
`src/stacktrace_cli/cli.py`, having decided it belongs. The loop registers
|
|
134
|
+
OpenACA's own command object under that name; there is nothing else to
|
|
135
|
+
write and nothing to keep in step with OpenACA.
|
|
136
|
+
- **Native** — write a Click command or group and `add_command` it, the way
|
|
137
|
+
`remote` is. If it needs OpenACA it calls `openaca.core`
|
|
138
|
+
([ADR-0020](docs/adrs/0020-openaca-consumption-boundary.md)), and whatever
|
|
139
|
+
it names there is added to the contract test in `tests/remote/`, because it
|
|
140
|
+
now holds duplicated knowledge of an interface.
|
|
141
|
+
|
|
142
|
+
The section a command lands under in `--help` follows from which kind it is;
|
|
143
|
+
there is no second list to update.
|
|
144
|
+
|
|
124
145
|
---
|
|
125
146
|
|
|
126
147
|
## Behavioral guidelines
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: stacktrace-cli
|
|
3
|
+
Version: 0.2.1
|
|
4
|
+
Summary: CLI for Stacktrace — Detection and Response platform for AI Agents.
|
|
5
|
+
Project-URL: Homepage, https://stacktrace.ai
|
|
6
|
+
Author-email: "Stacktrace AI, Inc" <founders@stacktrace.ai>
|
|
7
|
+
License-Expression: LicenseRef-Proprietary
|
|
8
|
+
Keywords: agent-security,ai-security,openaca,stacktrace
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Environment :: Console
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: Other/Proprietary License
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Topic :: Security
|
|
19
|
+
Requires-Python: >=3.11
|
|
20
|
+
Requires-Dist: click>=8.1
|
|
21
|
+
Requires-Dist: httpx<1.0.dev0,>=0.28.1
|
|
22
|
+
Requires-Dist: openaca==0.6.0
|
|
23
|
+
Requires-Dist: openaidr==0.1.0
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# stacktrace-cli
|
|
27
|
+
|
|
28
|
+
Detection and response for AI coding agents, from the command line.
|
|
29
|
+
|
|
30
|
+
Coding agents read files, run shell commands and call MCP servers on their own
|
|
31
|
+
initiative, and they write a transcript of every bit of it to disk.
|
|
32
|
+
`stacktrace` reads those transcripts, correlates what ran against the
|
|
33
|
+
components the agent is built from, and reports the security and reliability
|
|
34
|
+
findings in it — locally, on the machine the agent worked on.
|
|
35
|
+
|
|
36
|
+
The PyPI distribution is `stacktrace-cli`; the command it installs is
|
|
37
|
+
`stacktrace`. The two names differ because the bare `stacktrace` name on PyPI
|
|
38
|
+
belongs to an unrelated project.
|
|
39
|
+
|
|
40
|
+
## Installation
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
uv tool install stacktrace-cli # isolated; recommended
|
|
44
|
+
# or
|
|
45
|
+
pip install stacktrace-cli
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
Requires Python 3.11 or newer.
|
|
49
|
+
|
|
50
|
+
```console
|
|
51
|
+
$ stacktrace --version
|
|
52
|
+
stacktrace 0.2.1 (openaca 0.6.0)
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Quick start
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
stacktrace sessions # what the agents on this machine did
|
|
59
|
+
stacktrace detect # what is wrong with it
|
|
60
|
+
stacktrace monitor # the same, live in a browser
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Commands
|
|
64
|
+
|
|
65
|
+
| Command | |
|
|
66
|
+
|---|---|
|
|
67
|
+
| `sessions` | Print what the agents on this machine actually did. |
|
|
68
|
+
| `detect` | Find security and reliability findings in what agents did. |
|
|
69
|
+
| `monitor` | Watch this machine's agents in a browser, live. |
|
|
70
|
+
| `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
|
|
71
|
+
| `scan` | Scan a repository or endpoint for agent-composition findings. |
|
|
72
|
+
| `bom` | Generate an Agent BOM for a repository or endpoint. |
|
|
73
|
+
| `policy` | Validate and compile restrictive endpoint policies. |
|
|
74
|
+
|
|
75
|
+
The last three are composition analysis, supplied by
|
|
76
|
+
[`openaca`](https://pypi.org/project/openaca/) and available under either
|
|
77
|
+
name.
|
|
78
|
+
|
|
79
|
+
## What it looks like
|
|
80
|
+
|
|
81
|
+
```console
|
|
82
|
+
$ stacktrace sessions --since 2d --include-content
|
|
83
|
+
claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
|
|
84
|
+
assistant: Reading the changelog before drafting the release notes.
|
|
85
|
+
ok 28c Read
|
|
86
|
+
result: ## 0.4.0 - correlate, detect
|
|
87
|
+
assistant: Filing the release-notes follow-up.
|
|
88
|
+
- github/create_issue
|
|
89
|
+
|
|
90
|
+
Summary — 1 sessions, 2 turns, 2 tool calls
|
|
91
|
+
|
|
92
|
+
agent kinds
|
|
93
|
+
1 claude-code
|
|
94
|
+
|
|
95
|
+
tools called (2 distinct)
|
|
96
|
+
1 Read
|
|
97
|
+
1 github/create_issue
|
|
98
|
+
|
|
99
|
+
MCP servers reached (1 distinct)
|
|
100
|
+
1 github
|
|
101
|
+
|
|
102
|
+
0 subagent turns · 0 results abridged upstream · 1 ok
|
|
103
|
+
|
|
104
|
+
1 of 2 calls returned with no outcome the collector could establish; the agent's parser supplies no success signal.
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
A blank status column is the collector's `unknown`, not a pending call: the
|
|
108
|
+
client recorded no outcome that could be established, and the closing line
|
|
109
|
+
counts those rather than filling one in.
|
|
110
|
+
|
|
111
|
+
## What `detect` finds
|
|
112
|
+
|
|
113
|
+
Four kinds of finding, under two families that carry separate severity
|
|
114
|
+
ladders — a stalled loop and a leaked credential do not belong on one scale.
|
|
115
|
+
|
|
116
|
+
**Security** — a credential reaching an outbound call; an injected instruction
|
|
117
|
+
the agent then followed; a vulnerable component actually reached, with the
|
|
118
|
+
vulnerability behind it.
|
|
119
|
+
|
|
120
|
+
**Reliability** — a loop that stalled; a call that hung.
|
|
121
|
+
|
|
122
|
+
Findings are correlated against an Agent BOM before they are judged, so a
|
|
123
|
+
vulnerable component is reported when something actually used it rather than
|
|
124
|
+
because it is installed.
|
|
125
|
+
|
|
126
|
+
## What leaves your machine
|
|
127
|
+
|
|
128
|
+
Two of `detect`'s three stages run entirely locally and need no model or
|
|
129
|
+
credential. The third sends flagged sessions to the agent's *own* CLI — the
|
|
130
|
+
provider that produced the transcript, never a different one — capped by
|
|
131
|
+
`--budget`; `--no-escalate` turns it off and leaves the two local stages.
|
|
132
|
+
|
|
133
|
+
`sessions` omits prompts, tool arguments and results unless you pass
|
|
134
|
+
`--include-content`. `monitor` binds to loopback only, refuses a non-loopback
|
|
135
|
+
address rather than warning about it, and escalates nothing unless `--escalate`
|
|
136
|
+
is given.
|
|
137
|
+
|
|
138
|
+
## Status
|
|
139
|
+
|
|
140
|
+
Beta, and under active development.
|
|
141
|
+
|
|
142
|
+
`sessions`, `detect` and `monitor` work end to end today. Session collection
|
|
143
|
+
currently reads Claude Code transcripts; further agent kinds are in progress
|
|
144
|
+
upstream in [OpenAIDR](https://github.com/open-agent-security/openaidr).
|
|
145
|
+
|
|
146
|
+
## Built on
|
|
147
|
+
|
|
148
|
+
Two Apache-2.0 packages, neither of which depends on this one:
|
|
149
|
+
[`openaca`](https://pypi.org/project/openaca/) for agent composition analysis,
|
|
150
|
+
and [`openaidr`](https://pypi.org/project/openaidr/) for session collection.
|
|
151
|
+
|
|
152
|
+
## Licence
|
|
153
|
+
|
|
154
|
+
Proprietary. © Stacktrace AI, Inc. — [stacktrace.ai](https://stacktrace.ai)
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# stacktrace-cli
|
|
2
|
+
|
|
3
|
+
Detection and response for AI coding agents, from the command line.
|
|
4
|
+
|
|
5
|
+
Coding agents read files, run shell commands and call MCP servers on their own
|
|
6
|
+
initiative, and they write a transcript of every bit of it to disk.
|
|
7
|
+
`stacktrace` reads those transcripts, correlates what ran against the
|
|
8
|
+
components the agent is built from, and reports the security and reliability
|
|
9
|
+
findings in it — locally, on the machine the agent worked on.
|
|
10
|
+
|
|
11
|
+
The PyPI distribution is `stacktrace-cli`; the command it installs is
|
|
12
|
+
`stacktrace`. The two names differ because the bare `stacktrace` name on PyPI
|
|
13
|
+
belongs to an unrelated project.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv tool install stacktrace-cli # isolated; recommended
|
|
19
|
+
# or
|
|
20
|
+
pip install stacktrace-cli
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Requires Python 3.11 or newer.
|
|
24
|
+
|
|
25
|
+
```console
|
|
26
|
+
$ stacktrace --version
|
|
27
|
+
stacktrace 0.2.1 (openaca 0.6.0)
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Quick start
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
stacktrace sessions # what the agents on this machine did
|
|
34
|
+
stacktrace detect # what is wrong with it
|
|
35
|
+
stacktrace monitor # the same, live in a browser
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
| Command | |
|
|
41
|
+
|---|---|
|
|
42
|
+
| `sessions` | Print what the agents on this machine actually did. |
|
|
43
|
+
| `detect` | Find security and reliability findings in what agents did. |
|
|
44
|
+
| `monitor` | Watch this machine's agents in a browser, live. |
|
|
45
|
+
| `remote` | Configure remote endpoint services and upload to Stacktrace Cloud. |
|
|
46
|
+
| `scan` | Scan a repository or endpoint for agent-composition findings. |
|
|
47
|
+
| `bom` | Generate an Agent BOM for a repository or endpoint. |
|
|
48
|
+
| `policy` | Validate and compile restrictive endpoint policies. |
|
|
49
|
+
|
|
50
|
+
The last three are composition analysis, supplied by
|
|
51
|
+
[`openaca`](https://pypi.org/project/openaca/) and available under either
|
|
52
|
+
name.
|
|
53
|
+
|
|
54
|
+
## What it looks like
|
|
55
|
+
|
|
56
|
+
```console
|
|
57
|
+
$ stacktrace sessions --since 2d --include-content
|
|
58
|
+
claude-code:s1 [claude-code] 2026-08-27T09:00:00+00:00 2 turns 2 calls
|
|
59
|
+
assistant: Reading the changelog before drafting the release notes.
|
|
60
|
+
ok 28c Read
|
|
61
|
+
result: ## 0.4.0 - correlate, detect
|
|
62
|
+
assistant: Filing the release-notes follow-up.
|
|
63
|
+
- github/create_issue
|
|
64
|
+
|
|
65
|
+
Summary — 1 sessions, 2 turns, 2 tool calls
|
|
66
|
+
|
|
67
|
+
agent kinds
|
|
68
|
+
1 claude-code
|
|
69
|
+
|
|
70
|
+
tools called (2 distinct)
|
|
71
|
+
1 Read
|
|
72
|
+
1 github/create_issue
|
|
73
|
+
|
|
74
|
+
MCP servers reached (1 distinct)
|
|
75
|
+
1 github
|
|
76
|
+
|
|
77
|
+
0 subagent turns · 0 results abridged upstream · 1 ok
|
|
78
|
+
|
|
79
|
+
1 of 2 calls returned with no outcome the collector could establish; the agent's parser supplies no success signal.
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
A blank status column is the collector's `unknown`, not a pending call: the
|
|
83
|
+
client recorded no outcome that could be established, and the closing line
|
|
84
|
+
counts those rather than filling one in.
|
|
85
|
+
|
|
86
|
+
## What `detect` finds
|
|
87
|
+
|
|
88
|
+
Four kinds of finding, under two families that carry separate severity
|
|
89
|
+
ladders — a stalled loop and a leaked credential do not belong on one scale.
|
|
90
|
+
|
|
91
|
+
**Security** — a credential reaching an outbound call; an injected instruction
|
|
92
|
+
the agent then followed; a vulnerable component actually reached, with the
|
|
93
|
+
vulnerability behind it.
|
|
94
|
+
|
|
95
|
+
**Reliability** — a loop that stalled; a call that hung.
|
|
96
|
+
|
|
97
|
+
Findings are correlated against an Agent BOM before they are judged, so a
|
|
98
|
+
vulnerable component is reported when something actually used it rather than
|
|
99
|
+
because it is installed.
|
|
100
|
+
|
|
101
|
+
## What leaves your machine
|
|
102
|
+
|
|
103
|
+
Two of `detect`'s three stages run entirely locally and need no model or
|
|
104
|
+
credential. The third sends flagged sessions to the agent's *own* CLI — the
|
|
105
|
+
provider that produced the transcript, never a different one — capped by
|
|
106
|
+
`--budget`; `--no-escalate` turns it off and leaves the two local stages.
|
|
107
|
+
|
|
108
|
+
`sessions` omits prompts, tool arguments and results unless you pass
|
|
109
|
+
`--include-content`. `monitor` binds to loopback only, refuses a non-loopback
|
|
110
|
+
address rather than warning about it, and escalates nothing unless `--escalate`
|
|
111
|
+
is given.
|
|
112
|
+
|
|
113
|
+
## Status
|
|
114
|
+
|
|
115
|
+
Beta, and under active development.
|
|
116
|
+
|
|
117
|
+
`sessions`, `detect` and `monitor` work end to end today. Session collection
|
|
118
|
+
currently reads Claude Code transcripts; further agent kinds are in progress
|
|
119
|
+
upstream in [OpenAIDR](https://github.com/open-agent-security/openaidr).
|
|
120
|
+
|
|
121
|
+
## Built on
|
|
122
|
+
|
|
123
|
+
Two Apache-2.0 packages, neither of which depends on this one:
|
|
124
|
+
[`openaca`](https://pypi.org/project/openaca/) for agent composition analysis,
|
|
125
|
+
and [`openaidr`](https://pypi.org/project/openaidr/) for session collection.
|
|
126
|
+
|
|
127
|
+
## Licence
|
|
128
|
+
|
|
129
|
+
Proprietary. © Stacktrace AI, Inc. — [stacktrace.ai](https://stacktrace.ai)
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0026
|
|
3
|
+
title: The console becomes a product surface, served by the engine
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2026-09-06
|
|
6
|
+
supersedes: 0008
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: null
|
|
9
|
+
amended-by: null
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Context
|
|
13
|
+
|
|
14
|
+
ADR-0008 kept the trace console out of the engine and gave three reasons. Two
|
|
15
|
+
were about *kind*: a served page with taste-driven layout is different software
|
|
16
|
+
from a library, and their release cadences and review standards differ. One was
|
|
17
|
+
about *order*: making the console the product surface "before the engine's
|
|
18
|
+
claims are validated inverts the order — the engine comes first, and nothing yet
|
|
19
|
+
measures its central claim."
|
|
20
|
+
|
|
21
|
+
That last reason names its own expiry, and it has arrived. 0.1.0 ships
|
|
22
|
+
`sessions`, `detect` over nine rules and three stages, and both upload paths;
|
|
23
|
+
the detector's claims are measured by its own corpus and by the hosted side
|
|
24
|
+
receiving them. The engine came first, and did.
|
|
25
|
+
|
|
26
|
+
What forces the decision now is a product one rather than a technical one: the
|
|
27
|
+
data is only useful if a person can follow it, and a sequence reads better as a
|
|
28
|
+
timeline than as a findings list — 0008's own opening sentence. A developer who
|
|
29
|
+
has to run `detect`, read JSON, and re-run it to see what changed is being asked
|
|
30
|
+
to be the renderer. `stacktrace monitor` is that renderer, and it has to ship
|
|
31
|
+
where the data is.
|
|
32
|
+
|
|
33
|
+
## Decision
|
|
34
|
+
|
|
35
|
+
The engine serves a local console. `stacktrace monitor` starts an HTTP server
|
|
36
|
+
bound to loopback, opens a browser, and renders live sessions and detections
|
|
37
|
+
from in-process calls into the same surfaces `detect` uses.
|
|
38
|
+
|
|
39
|
+
The three clauses of 0008 that this reverses, stated plainly:
|
|
40
|
+
|
|
41
|
+
1. **The engine gains a serving surface and a browser-facing asset.** `site/`
|
|
42
|
+
ships as package data in the wheel.
|
|
43
|
+
2. **The console performs no analysis of its own.** *This one survives.* Monitor
|
|
44
|
+
calls `collect_sessions`, `acquire_correlated_view` and `run_detector`; it
|
|
45
|
+
adds no rule, no grade and no heuristic, and it never writes the verdict
|
|
46
|
+
cache. A finding on the page is a finding `detect` would print.
|
|
47
|
+
3. **The tenets govern the console now**, because it is a product surface rather
|
|
48
|
+
than a demonstration. Trust, quality, cost and security apply — which is why
|
|
49
|
+
the page computes only the two free stages by default, and why the one action
|
|
50
|
+
it offers is gated four ways.
|
|
51
|
+
|
|
52
|
+
## Alternatives considered
|
|
53
|
+
|
|
54
|
+
- **Keep 0008 and ship the console as a separate optional distribution**
|
|
55
|
+
(`stacktrace-console`, or an extra) — rejected. It preserves the letter of
|
|
56
|
+
0008 at the cost of the thing 0008 was protecting: a second distribution has
|
|
57
|
+
its own version, its own install step and its own drift against three read
|
|
58
|
+
contracts, and every user who wants to *see* their data pays an install to do
|
|
59
|
+
it. The cadence argument that justified separation for a demo does not survive
|
|
60
|
+
the surface becoming the product.
|
|
61
|
+
|
|
62
|
+
- **Amend 0008 to carve out one read-only local surface** — rejected as
|
|
63
|
+
dishonest bookkeeping. The carve-out is the whole of clause 1; an amendment
|
|
64
|
+
that removes a decision's first clause is a supersession wearing a smaller
|
|
65
|
+
word.
|
|
66
|
+
|
|
67
|
+
- **Leave rendering to the hosted console** — rejected. The hosted side is
|
|
68
|
+
agent-scoped and receives only what ADR-0006 authorizes: no prompt, no
|
|
69
|
+
argument, no result, no matched value. The local console is precisely where a
|
|
70
|
+
responder may see the matched string, which ADR-0006 calls out as deliberate
|
|
71
|
+
asymmetry. A fleet view cannot replace a machine view; it is a different
|
|
72
|
+
question.
|
|
73
|
+
|
|
74
|
+
- **Ship the console but compute nothing** (render the last `detect` run's
|
|
75
|
+
cache) — rejected. "Live sessions, stale findings" is the failure mode a
|
|
76
|
+
reader cannot see: the page looks current, and a leak that happened after the
|
|
77
|
+
last run is absent from it.
|
|
78
|
+
|
|
79
|
+
## Consequences
|
|
80
|
+
|
|
81
|
+
**What this enables.** A developer watches an alias resolve into a real
|
|
82
|
+
component while a session is still running — 0008's own description of the
|
|
83
|
+
demonstration, now available without a demo. The three published read contracts
|
|
84
|
+
gain their first in-repo consumer, so a change to span identity breaks a test
|
|
85
|
+
here rather than silently landing enrichments on the wrong rows elsewhere.
|
|
86
|
+
|
|
87
|
+
**What it costs, and 0008 was right about both.**
|
|
88
|
+
|
|
89
|
+
- **Every consumer of the wheel carries a UI they did not ask for.** `site/` is
|
|
90
|
+
three files and no JavaScript dependency, so the cost is bytes rather than a
|
|
91
|
+
dependency tree — but a library consumer still ships them.
|
|
92
|
+
- **Visual iteration now happens inside the engine's release process.** A
|
|
93
|
+
layout change rides a release built for a detection engine. The mitigation is
|
|
94
|
+
that the console's own priorities stay 0008's — latency, then fidelity — and
|
|
95
|
+
that no page change can alter a finding, because monitor computes none.
|
|
96
|
+
|
|
97
|
+
**What to watch for.** A rule that fires only in the console, or a grade the
|
|
98
|
+
page adjusts for legibility. Either would make clause 2 false, and clause 2 is
|
|
99
|
+
the one keeping this from being a fork of the detector.
|
|
100
|
+
|
|
101
|
+
## When to revisit
|
|
102
|
+
|
|
103
|
+
Revisit if the console acquires a reason to compute something the detector does
|
|
104
|
+
not — that is the point at which it stops being a renderer and needs its own
|
|
105
|
+
decision. Revisit if the wheel's browser-facing assets grow beyond static files,
|
|
106
|
+
because a build step is the cadence problem 0008 warned about actually arriving.
|
|
107
|
+
Do not revisit on the grounds that a library consumer carries the UI: that cost
|
|
108
|
+
is accepted here explicitly, not overlooked.
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
id: 0027
|
|
3
|
+
title: A finding may name the component it could not place
|
|
4
|
+
status: accepted
|
|
5
|
+
date: 2026-09-07
|
|
6
|
+
supersedes: null
|
|
7
|
+
superseded-by: null
|
|
8
|
+
amends: 0006
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Context
|
|
12
|
+
|
|
13
|
+
ADR-0006 constraint 3 keeps session content off the wire *by construction*: a
|
|
14
|
+
detection carries a rule id and non-content descriptors, "never an excerpt of
|
|
15
|
+
an argument, result or prompt", and the family is uploadable whole so no
|
|
16
|
+
projection exists to be got wrong. That constraint has held every finding this
|
|
17
|
+
product has shipped and is not in question here.
|
|
18
|
+
|
|
19
|
+
One case has now met the condition ADR-0006 wrote for its own revision:
|
|
20
|
+
|
|
21
|
+
> Revisit if a detection type proves genuinely unactionable without an evidence
|
|
22
|
+
> excerpt — that would be a real argument against constraint 3, and the answer
|
|
23
|
+
> is more likely a better non-content descriptor than an excerpt.
|
|
24
|
+
|
|
25
|
+
A finding's **subject** is what the finding is about. Where correlation places
|
|
26
|
+
the call, the subject is a BOM component and constraint 3 was never in play.
|
|
27
|
+
Where correlation cannot place it, the only name that exists is the one the
|
|
28
|
+
session used — `call.mcp_server` for a server, `arguments["skill"]` for a
|
|
29
|
+
skill — and the second of those is, read literally, an excerpt of an argument.
|
|
30
|
+
|
|
31
|
+
Removing it leaves the highest-severity finding this detector produces reading:
|
|
32
|
+
|
|
33
|
+
high stacktrace-credential-egress
|
|
34
|
+
Credential-shaped material reached an outbound call
|
|
35
|
+
on a mcp_server (not in inventory)
|
|
36
|
+
|
|
37
|
+
A responder cannot act on that. They cannot rotate the right credential, revoke
|
|
38
|
+
the right access, or find the thing, because the document does not say what the
|
|
39
|
+
thing was. The unplaced case is also the one where naming matters *most*: a
|
|
40
|
+
credential reaching a component no Agent BOM declares is the least expected and
|
|
41
|
+
least explicable event this product reports.
|
|
42
|
+
|
|
43
|
+
Empirically it is not rare. On the machine this was written against, 156 calls
|
|
44
|
+
across 15 distinct names were unplaced, including the one `high`
|
|
45
|
+
credential-egress finding in the window.
|
|
46
|
+
|
|
47
|
+
## Decision
|
|
48
|
+
|
|
49
|
+
**A detection may carry the name the session addressed a component by, when
|
|
50
|
+
correlation could not place it.** This narrows ADR-0006 constraint 3; every
|
|
51
|
+
other clause of 0006 stays in force, and constraint 3 continues to forbid
|
|
52
|
+
excerpts of prompts, results and arguments in every other position.
|
|
53
|
+
|
|
54
|
+
Four bounds make it a descriptor rather than an opening.
|
|
55
|
+
|
|
56
|
+
1. **One field, one purpose.** The name appears only as
|
|
57
|
+
`Participant.name` on a finding's subject or a named party to it. No rule
|
|
58
|
+
may interpolate it into prose; `Evidence.detail` remains closed to it, which
|
|
59
|
+
is the drift ADR-0006 names as *"reached by writing a helpful sentence"*.
|
|
60
|
+
|
|
61
|
+
2. **It is never an identity.** `Participant.identity` stays null for an
|
|
62
|
+
unplaced party, so the name can resolve no lookup, join to no inventory and
|
|
63
|
+
render as no link. A consumer must mark it as unverified. Two machines can
|
|
64
|
+
call unrelated servers `support`; this ADR does not make that name mean
|
|
65
|
+
anything beyond the session that said it.
|
|
66
|
+
|
|
67
|
+
3. **Bounded and validated at the boundary.** Length-capped on the wire, and
|
|
68
|
+
walked by the same disclosure gate every other leaf passes, so a name
|
|
69
|
+
carrying a path or a credential shape is refused rather than trimmed.
|
|
70
|
+
|
|
71
|
+
4. **The local surfaces are unchanged and remain the fuller answer.** `monitor`
|
|
72
|
+
and `stacktrace detect` read the session directly and may always say more
|
|
73
|
+
than the upload does. This ADR is only about what leaves the machine.
|
|
74
|
+
|
|
75
|
+
## Consequences
|
|
76
|
+
|
|
77
|
+
The `credential-egress` above reads `on support (not in inventory)`, in Fleet
|
|
78
|
+
as well as locally, and a responder has somewhere to start.
|
|
79
|
+
|
|
80
|
+
The residual exposure is a short, model-influenceable string reaching a hosted
|
|
81
|
+
service. It is real and it is accepted here rather than argued away: an
|
|
82
|
+
attacker who can choose the `skill` argument already drives the agent's tool
|
|
83
|
+
calls, and has channels with far more bandwidth than a capped name field in a
|
|
84
|
+
detection upload. What this ADR must not become is precedent — the argument
|
|
85
|
+
above is about *the subject of a finding being unnameable otherwise*, and does
|
|
86
|
+
not extend to any other field.
|
|
87
|
+
|
|
88
|
+
`tests/test_untrusted_content_never_travels.py` keeps every other canary,
|
|
89
|
+
including the ones for prompts, results, arguments and the tool name an MCP
|
|
90
|
+
server chose. It gains the case this ADR permits, so the exemption is stated
|
|
91
|
+
where the invariant is enforced rather than only here.
|
|
92
|
+
|
|
93
|
+
## Alternatives rejected
|
|
94
|
+
|
|
95
|
+
- **Drop the name, keep the type** (`a skill (not in inventory)`). This was
|
|
96
|
+
implemented and is what prompted the ADR. It is compliant and unactionable,
|
|
97
|
+
which makes it the wrong trade for a product whose output is meant to be
|
|
98
|
+
acted on. A rule that produces findings nobody can use protects nothing.
|
|
99
|
+
|
|
100
|
+
- **Carry the server alias, drop the skill argument.** Defensible on the letter
|
|
101
|
+
of constraint 3 — a server alias is not an argument excerpt — and rejected as
|
|
102
|
+
a distinction a reader cannot see. It would make one finding nameable and its
|
|
103
|
+
neighbour not, for a reason invisible on the page, and leaves the same
|
|
104
|
+
residual exposure for the case it permits.
|
|
105
|
+
|
|
106
|
+
- **Send a hash of the name.** Rejected. It is stable across machines, which is
|
|
107
|
+
the one property the name must not have, and it is unreadable, which is the
|
|
108
|
+
one property a responder needs.
|
|
109
|
+
|
|
110
|
+
- **Amend nothing and surface the name only in `monitor`.** Rejected as the
|
|
111
|
+
status quo restated: triage happens in Fleet, and a console on one laptop
|
|
112
|
+
does not answer for a fleet.
|
|
@@ -41,7 +41,7 @@ supersedes anything yet.
|
|
|
41
41
|
- [0005](0005-detection-family-and-report-assembly.md) — **Detections are their own finding family, assembled here.** Why a detection is not an observation, and why `stacktrace` merges the four families rather than OpenACA emitting a fourth. `stacktrace-*` identifiers. Read before adding a finding family, touching output assembly, or contributing anything upstream.
|
|
42
42
|
- [0006](0006-trust-boundary-and-detection-upload.md) — **Sessions never leave the machine; detections upload agent-keyed.** No upload path for anything session-derived; findings carry descriptors, never excerpts; place identity stays in the envelope. Read before adding a detection field, touching redaction, or describing AIDR as fully local or anonymous.
|
|
43
43
|
- [0007](0007-proprietary-package-on-open-dependencies.md) — **Proprietary package on open dependencies.** Why this is not inside OpenACA or OpenAIDR, and why the dependency arrow never reverses. Read before moving code between repos.
|
|
44
|
-
- [0008](0008-console-in-separate-demo-package.md) — **Trace console ships as a separate demo package.** Read before adding a served UI, transport, or web asset to this repo.
|
|
44
|
+
- [0008](0008-console-in-separate-demo-package.md) — **Trace console ships as a separate demo package.** Read before adding a served UI, transport, or web asset to this repo. **Superseded by [0026](0026-the-console-becomes-a-product-surface.md).**
|
|
45
45
|
- [0010](0010-detection-severity-and-confidence-ladders.md) — **Detections define their own severity and confidence ladders.** Amends ADR-0005: `openaca.core` exports no ladder to reuse, and CVSS labels grade advisories a detection does not have. Read before changing a finding's grade, or before assuming the four families share one scale.
|
|
46
46
|
- [0011](0011-verdict-cache.md) — **A bounded local verdict cache, and what it may hold.** Amends ADR-0006: a reasoning verdict is an expensive pure function of a session, so it may persist — carrying rule ids, grades, spans and analyzer identity, and never conversation. Read before persisting anything session-derived, or before letting an upload path read local state.
|
|
47
47
|
- [0012](0012-observation-evidence-kinds-and-transport.md) — **Observation is graded by what could misread it; an MCP transport is positive-only evidence.** Severity and confidence are orthogonal and neither is read off the other; a precondition sets a finding's grade, corroboration takes the best; `stdio` is never evidence of local execution. Read before changing a rule's confidence, adding an evidence kind, or treating an absent transport as local.
|
|
@@ -57,4 +57,6 @@ supersedes anything yet.
|
|
|
57
57
|
- [0022](0022-detection-scope-is-a-catalogue-column.md) — **Detection scope is a per-rule catalogue column, set by cardinality.** Fleet identifies a detection by rule plus anchor, so scope decides what counts as the same finding seen again; `advisory-reach` and `progress-stall` both read as session-shaped and fire more than once per session, and session scope would merge those firings into one row permanently. Deriving scope from `bool(evidence)` is rejected — every rule always cites something. Read before adding a rule, or before changing how one groups its findings.
|
|
58
58
|
- [0023](0023-sync-detect-collects-and-does-not-escalate.md) — **`sync detect` re-collects in-process, and defaults `--escalate` off.** The inverse of `stacktrace detect`, because a scheduled unattended run spending provider quota and crossing a content boundary on a timer is a recurring charge nobody approved per-run; consuming `detect --format json` was rejected as a projection of a projection. Read before changing a sync default, or before aligning the two commands' flags.
|
|
59
59
|
- [0024](0024-the-upload-carries-observations.md) — **The upload carries observations; the Cloud derives catalogue text and coverage.** `title`, `remediation`, `family`, `verdict.stage` and `coverage` are all dropped — the first four are catalogue facts the Cloud seeds, and coverage is summed from `activity[]`. Not a privacy projection (ADR-0006 settled that) but a non-duplication one. Read before adding a field to the upload payload, or before "fixing" a bare `rule_id` in the console.
|
|
60
|
+
- [0026](0026-the-console-becomes-a-product-surface.md) — **The console becomes a product surface, served by the engine.** Supersedes ADR-0008 on its own stated condition: the engine came first, 0.1.0 shipped, and the data is only useful if a person can follow it. `stacktrace monitor` serves a loopback page from in-process calls, so the wheel now carries a `site/` asset — the cost 0008 refused, accepted here explicitly. What survives from 0008 is the clause that matters: the console renders and never computes, so a finding on the page is one `detect` would print. Read before adding anything to the console that the detector does not produce.
|
|
60
61
|
- [0025](0025-a-denied-call-is-activity-never-an-invocation.md) — **A denied call is activity, and never an invocation.** ADR-0017 makes a declined repeat a stall while `outcome.py` keeps a denied call out of every count, so a denied-only session produced a finding with no activity and the Cloud rejected the whole run; a separate `denied` counter resolves it without either rule bending, and coverage keeps summing `invocations` alone. Read before changing what `activity[]` counts, or before folding `denied` into a coverage-like ratio.
|
|
62
|
+
- [0027](0027-a-finding-may-name-what-it-could-not-place.md) — **A finding may name the component it could not place.** Narrows ADR-0006 constraint 3 for one field: an unplaced subject carries the name the session addressed it by, never as an identity. Read before removing a name from a finding on trust-boundary grounds, or before widening this to a second field.
|