Skip to content

feat: scanner dispatch extensions + monitoring — phases 3-6 (Ossprey, CLI monitoring, full-chain validation) - #100

Merged
neomatrix369 merged 5 commits into
neomatrix369:mainfrom
devanshkaria88:frontline-hack-phases-3-6
Aug 22, 2026
Merged

feat: scanner dispatch extensions + monitoring — phases 3-6 (Ossprey, CLI monitoring, full-chain validation)#100
neomatrix369 merged 5 commits into
neomatrix369:mainfrom
devanshkaria88:frontline-hack-phases-3-6

Conversation

@devanshkaria88

@devanshkaria88 devanshkaria88 commented Aug 21, 2026

Copy link
Copy Markdown
Contributor

Summary

Continuation of the phased Claude Code integration (Phases 1–2 merged in #83). Fresh branch off post-#98 main; one commit per phase, all phases complete:

  • Phase 3 — Ossprey malware-scanner adapter (c703f66): registered after DepShield in SCANNER_GROUPS; credential-gated (skipped_missing_credential is the default runtime path while access provisioning stays OPEN — slice 35 BLOCKED); exit-code disambiguation so a scan failure can never masquerade as a malware finding (red only on a positive OSSBOM/verdict signal, else unreachable); honestly RESEARCH-labeled per ADR-0005; trust-strip gate deliberately preserved (no Ossprey mention in the five gated docs until provisioning + live verification exist).
  • Phase 4 — tripwire status observability (91fecdf, slice 37): read-only hooks + scan/dispatch health; fleet-wide stranded-run detection via head-count (immune to the recent-page and PostgREST 1000-row caps); §3 two-switch disagreement warning + missing-config tamper callout; enforcement preservation proven by test (select-family calls only, zero fs writes); invalid input exits nonzero with actionable guidance; degrades to local-only output without Supabase creds.
  • Phases 5–6 — full-chain validation harness + FE/BE note (63af5cf, slices 38–39): scripts/full-chain-validation.sh staged checklist with a single accountable exit code, LIVE /tw-self-check as a named never-mocked stage, explicit ossprey: SKIPPED(access), honest BLOCKED(.env) for live stages until Supabase/Modal creds exist; slice 39 stays deferred per its own spec, delivered as docs/research/fe-be-target-architecture.md.

Every phase was adversarially reviewed before its commit (Phase 3: 45 dedicated tests incl. disambiguation both ways; Phase 4: 1 major + 4 minors confirmed by repro and fixed with regression tests).

Test Results

As of 63af5cf (on post-#98 main):

  • Sandbox: 232 passed, coverage 97.03% (≥95 gate) · Guard: 111 passed · CLI: 138 passed + eslint clean
  • xenon split ceilings met (scanners.py D/C/B; scan_app.py C/–/A); ruff/mypy/bandit clean
  • Trust-strip: rg -i 'ossprey|overmind' empty across all five gated files
  • Full-chain harness degraded-mode run verified on the dev machine (honest BLOCKED stages; evidence JSON emitted); live PASS awaits deployed Supabase/Modal credentials

Checklist

  • ./scripts/quality-gates.sh passes locally
  • New tests added or updated (or change is docs-only)
  • Docs updated where applicable
  • No secrets or credentials committed

🤖 Generated with Claude Code

…SEARCH-labeled (Phase 3)

Second dispatch extension per ADR-0005/ADR-0017, registered after DepShield
in SCANNER_GROUPS (applies_to both):
- run_ossprey: `ossprey scan <workdir> -o <ossbom.json>` subprocess adapter.
  Credential gate FIRST — skipped_missing_credential is the default runtime
  path today (OSSPREY_API_KEY / API_KEY absent; Ossprey access provisioning
  is OPEN, slice 35 BLOCKED). Adapter activates when a key lands.
- Exit-code disambiguation (vendor contract: 0 = clean/skipped, 1 = malware
  OR scan failure): exit 0 is authoritative-clean; nonzero emits red
  'malware' findings ONLY on a positive signal (malicious OSSBOM component,
  or an unambiguous verdict line with negation guard) — a scan failure
  degrades to unreachable, never a phantom red that would block a clean
  artifact. OSSBOM parsing tolerates list and {components|packages:[...]}
  shapes with defensive access.
- RESEARCH evidence label per the module's discipline: OSSBOM schema and
  verdict wording are vendor-doc-sourced, NOT live-probed — needs
  reconciliation against the pinned ossprey-cli before VERIFIED.
- Trust-strip gate deliberately preserved: no Ossprey mention in README/
  QUICKSTART/CONTRIBUTING/STATUS/ARCHITECTURE (no user-usable capability
  yet — "badges only when functionality exists"). Documented instead in
  scanner-output-adapters.md §8, DECISIONS rows, ADR-0017 addendum,
  OPTIONAL_SCANNER_KEYS + env-vars (key marked access-OPEN).
- Modal image: guarded best-effort release-binary install (absent binary
  degrades to unreachable, acceptable while provisioning is OPEN).

Rebased onto post-merge main (PR neomatrix369#83 + slices 40-43). Gates: 232 sandbox
tests @ 97.03% coverage, 111 guard, 129 cli; ruff/mypy/bandit clean; xenon
split ceilings met; trust-strip rg clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 21, 2026

Copy link
Copy Markdown

code-review-graph review

Overall risk: 0.40 (MEDIUM) — 101 changed function(s)/class(es), 3 affected flow(s), 48 test gap(s)

Risk-scored changes

Risk Level Symbol Location Tested
0.40 medium cli/src/statusCommand.js::unwrap cli/src/statusCommand.js:95 no
0.40 medium cli/src/statusCommand.js::twoSwitchDisagreement cli/src/statusCommand.js:234 no
0.40 medium cli/src/statusCommand.js::runStatus cli/src/statusCommand.js:353 no
0.40 medium sandbox/scanners.py::_ossprey_component_is_malicious sandbox/scanners.py:940 yes
0.40 medium sandbox/scanners.py::_ossprey_malware_verdict_line sandbox/scanners.py:996 yes
0.40 medium scripts/full-chain-validation.sh::record scripts/full-chain-validation.sh:30 no
0.35 low cli/src/statusCommand.js::parseLimit cli/src/statusCommand.js:32 no
0.35 low cli/src/statusCommand.js::isPlainObject cli/src/statusCommand.js:42 no
0.35 low cli/src/statusCommand.js::isTripwireHookCommand cli/src/statusCommand.js:47 no
0.35 low cli/src/statusCommand.js::readHookRegistration cli/src/statusCommand.js:54 no

Affected execution flows

  • scan_item — criticality 0.35, 14 node(s) across 2 file(s)
  • _on_scanner_done — criticality 0.25, 5 node(s) across 1 file(s)
  • main — criticality 0.22, 4 node(s) across 1 file(s)

Test gaps

  • cli/src/statusCommand.js::parseLimit (cli/src/statusCommand.js:32)
  • cli/src/statusCommand.js::isPlainObject (cli/src/statusCommand.js:42)
  • cli/src/statusCommand.js::isTripwireHookCommand (cli/src/statusCommand.js:47)
  • cli/src/statusCommand.js::readHookRegistration (cli/src/statusCommand.js:54)
  • cli/src/statusCommand.js::entry (cli/src/statusCommand.js:60)
  • ...and 43 more without direct tests

Token savings: this graph-backed report used ~58,734 fewer tokens (~80%) than reading every changed file in full (estimated, chars/4 approximation).


Powered by code-review-graph — local-first analysis; no code leaves the CI runner.

devanshkaria88 and others added 4 commits August 21, 2026 14:54
…ility (Phase 4, slice 37)

CLI monitoring per slice-37's spec (operator observability, extending the
existing CLI — not a second truth store):
- `tripwire status [--json] [--limit <n>]`: hooks state (~/.tripwire/config.json
  enable/validity, PreToolUse registration in ~/.claude/settings.json, Supabase
  monitoring_enabled/threshold, §3 two-switch disagreement warning, and a
  tamper callout when the hook is registered but config.json is missing —
  that state DENIES all matched tools); items heatmap distribution via
  per-status head-counts (immune to PostgREST's 1000-row cap); recent
  scan-run health with fleet-wide stranded-running detection (dedicated
  head-count query, not page-local — a strand older than the newest --limit
  runs is exactly the busy-system case) naming the reconcile remedy;
  per-scanner latest status with unreachable/skipped tallies.
- GWT 2 (enforcement unchanged) proven by test: recorded Supabase calls are
  select-family only (zero insert/update/upsert/delete/rpc), zero fs writes.
- GWT 3: invalid --limit exits nonzero with an actionable example; missing
  Supabase env degrades to local-hooks-only output (exit 0) instead of
  hard-failing observability.
- Docs: user-guide monitoring section + troubleshooting, DECISIONS rows
  (surface choice; Bash-interception explicitly not slice-37 scope — the
  upstream handler already gates skills-path Bash), slice-37 Before-Check
  name-sketch ticked (gate status left PLANNED for maintainer rituals),
  CHANGELOG entry.

Adversarial verify confirmed 1 major (stranded pagination blind spot) +
4 minors (row-cap counts, missing-config understatement, prototype-key
drop, user-scope-only registration claim) — all fixed with regression
tests. Gates: 138 cli tests pass, eslint clean.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ecture note (Phases 5-6, slices 38-39)

Phase 5 (slice 38): scripts/full-chain-validation.sh — staged checklist with
a single accountable result (exit 0 only when every required stage passes):
preflight, credentials, hooks-installed, demo-artifacts, scan-dispatch,
verify-status, depshield-dispatch, ossprey-dispatch, cli-monitoring, and a
LIVE /tw-self-check stage invoked via `claude -p` (never mocked, output
captured into evidence) per the slice-38 GWTs and the original SEQUENCE-13
expectation. `ossprey-dispatch: SKIPPED(access)` is explicit while slice 35
remains BLOCKED. Stages needing Supabase/Modal creds report BLOCKED(.env)
honestly; degraded-mode run verified on this machine (evidence JSON written
to .test-results/full-chain-evidence.json; gate evidence stays a maintainer
ritual — the script never fabricates it).

Phase 6 (slice 39): deferred by default per the slice's own spec (Could,
hackathon-too-large). Deliverable is docs/research/fe-be-target-architecture.md:
current three-plane boundary map, the two pressures worth solving on pull-in
(single-implementation six-state machine; anon read path to retire the
client-side service-role key), and pinned non-goals.

DECISIONS rows recorded for both; slice files left at maintainer-owned
gate states.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…chain harness, escaped pipes in a DECISIONS table row

- scripts/full-chain-validation.sh: interpolate $CONFIG_JSON instead of a
  quoted tilde path (SC2088); move `|| true` outside the command
  substitutions so the A && B || C pattern disappears (SC2015)
- docs/plan/DECISIONS.md: escape regex pipes in the slice-37 HOOK_MATCHER
  code span — raw pipes split the markdown table cells (MD056/MD038)

Verified locally via `uvx pre-commit run --all-files`: shellcheck,
markdownlint, actionlint, gitleaks, ruff(+format), mypy, bandit, xenon,
vulture, pylint, pytest-testmon, CLI node tests + ESLint all pass. The
eslint-dashboard hook fails only locally (dashboard node_modules not
installed on this machine); untouched by this branch and green on main CI.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@neomatrix369
neomatrix369 marked this pull request as ready for review August 21, 2026 23:51
@neomatrix369
neomatrix369 self-requested a review as a code owner August 21, 2026 23:51
@neomatrix369

Copy link
Copy Markdown
Owner

Review follow-up — critical/high fixes (branch fix/pr-100-review)

Consolidated implementation of the nw-reviewer critical/high findings from the PR #100 review report.

Fixed in this branch

ID Issue Fix
H1 Broad stdout negation regex (\bnot\b, \bclean\b) could suppress real malware lines Narrowed to clean-summary patterns only (no/not/zero/none/0 malicious, clean scan/result); regression test for "not a false positive" wording
H2 claude -p in full-chain harness had no wall-clock cap run_with_timeout (120s; timeout / gtimeout / Python fallback); exit 124 → BLOCKED(timeout)
H4 Generic API_KEY could activate or confuse Ossprey gate Adapter accepts OSSPREY_API_KEY only; docs + harness aligned
C1 DepShield + Ossprey timeouts exceeded SCAN_TIMEOUT envelope OSSPREY_TIMEOUT 200→100; CI gate scripts/check-scanner-timeout-budget.sh; budget table in docs/ARCHITECTURE.md
H3 Unverified Ossprey binary tag Pinned v0.12.0 (verified linux-amd64 asset); image build emits WARNING when binary missing
H5 RESEARCH adapter activation gate Live CLI reconcile After-Checks added to slice 35/36 stubs

Still intentional (not changed)

  • Ossprey remains in SCANNER_GROUPS (credential-gated; DECISIONS rows stand)
  • Trust-strip on five gated docs remains clean
  • Adapter stays RESEARCH until slice 35/36 live reconcile passes

Verification

  • sandbox/tests/test_scanners_ossprey.py: 47 passed
  • scripts/check-scanner-timeout-budget.sh: OK (120+100 ≤ 240)

Maintainers: cherry-pick or merge fix/pr-100-review onto frontline-hack-phases-3-6 before marking PR ready.

@neomatrix369
neomatrix369 merged commit 27bcf32 into neomatrix369:main Aug 22, 2026
15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants