Skip to content

Findings-catalogue fixes, part 4 (low/info items and design notes) - #8

Merged
Harshith029 merged 7 commits into
mainfrom
catalogue-part4
Oct 19, 2026
Merged

Harshith029 merged 7 commits into
mainfrom
catalogue-part4

Conversation

@Harshith029

Copy link
Copy Markdown
Owner

The remaining low-severity and informational findings from the catalogue. Every behaviour change has a test that fails on the code before it, checked by running it against the old code.

Fixes

  • Cosmos persistence:
    • Couldn't start: both builders used the async Azure clients, which need aiohttp, so setting AZURE_COSMOS_ENDPOINT failed at startup. Fixed with a new extra, sentinel-prox[cosmos]; without it the error now says which extra to install.
    • Duplicate builder: the unused copy was removed.
    • Writes were not atomic (COSMOS-2): they read and then upserted, so a concurrent writer could silently replace a span. They now use create_item.
  • Authorization (AUTHZ-16): a rule with no condition now denies; the old assert crashed outside the fail-closed path. Asserts on the authorization and gateway paths are explicit checks.
  • Gateway (GW-18): the read of the SDK's private session index is now in one place, an error is logged if it's missing, and a test pins the attribute. Losing it silently would lock every tenant at its session cap.
  • SQLite (STORE-2): timestamps live in an indexed column, with in-place migration, so listing and retention no longer parse every span's JSON while holding the lock.
  • Replay (REPLAY-1): duplicate span ids are reported as duplicates, not cycles.
  • Restore (CM-10): startup restore no longer loads every span of every trace for a guess that never matched.
  • Demo baseline (DEMO-04): uses the protected run's driver and web mode; it was always the script.
  • Dashboard (DEMO-09, DEMO-26): the kill chain and verdict come from the run's data, and the trust gauge uses the configured threshold. Checked in a browser.
  • Classifier (CLS-2): labels any server's tools by the verbs in their names.
  • Event fan-out (CM-18): each event is serialized once, however many subscribers stream it.
  • Test fake (TCD-22): the fake Cosmos container refuses queries it can't answer and gains create_item.
  • Dead code (DCC-23, GW-20): removed build_web_server and _expected_token.

Docs

Corrected:

  • what "durably emitted" means for each store (DUR-1);
  • which events cost trust (TRUST-5);
  • that the evasion page is staged against the local shield (DEMO-06);
  • which keys sentinel.yaml accepts (DCC-10);
  • several stale test docstrings (TCD-21, TCD-25, PP-15);
  • the positioning claim of equivalence with CaMeL (TCD-27);
  • where external /mcp runs appear on the dashboard (DEMO-16).

New docs/design-notes.md records every finding deliberately kept as it is, with the reason, plus the one still open: GW-12, a server-side browser session store.

Testing

Windows, Python 3.11:

  • Full suite twice: 687 passed, 12 skipped, 1 xfailed.
  • All 12 real-MCP diagnostics pass, one per process.
  • ruff and mypy --strict: clean.

🤖 Generated with Claude Code

Harshith029 and others added 7 commits October 19, 2026 01:30
…onest replay, indexed timestamps

Findings-catalogue items, each with a test that fails before the change:

- COSMOS-2: CosmosForensicStore read, then upserted, so two writers of one
  span id could both see it absent and the second replaced the first. It
  now uses create_item (atomic) and compares only on a conflict; a retried
  create meets its own identical copy and stays idempotent.
- AUTHZ-16: the engine asserted rule.condition outside its fail-closed try,
  so a broken rule crashed the call instead of denying it, and -O dropped
  the check. The authorization and gateway asserts are explicit checks.
- REPLAY-1: with one parent per span, the walk can only re-enter a span
  through a duplicate, yet that was reported as a cycle. Duplicates are now
  reported as duplicates; real cycles still show as unreachable spans.
- STORE-2: listing and retention ran json_extract over every span under
  the store lock. Spans carry an indexed ts column; old databases migrate.
- TCD-22: the fake Cosmos container ignored the SQL; it now refuses any
  query but the one it answers, and has create_item.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…o wasted restore

Findings-catalogue items, each with a test that fails before the change:

- DOC-1 (and a real defect behind it): both Cosmos builders used the async
  Azure clients, which need aiohttp, and SENTINEL does not install it. So
  setting AZURE_COSMOS_ENDPOINT failed at startup with a bare import error;
  Cosmos persistence could not run. New extra sentinel-prox[cosmos]; without
  it the error names the extra. The unused duplicate create_cosmos_store
  (whose docstring promised wiring "in a later phase") is removed.
- GW-18: releasing ended sessions reads the SDK's private
  _server_instances. Losing it meant no releases at all, so every tenant
  would hit its session cap for good, silently. Now one accessor, an error
  logged once if it is missing, and a test pinning the SDK attribute.
- CM-10: restore guessed each trace's scenario from its user input, which
  is redacted before storage, so the guess never matched, and it loaded
  every span of every trace at startup to make it. Removed; the scenario
  comes from the ownership row.
- DCC-23 / GW-20: removed build_web_server and _expected_token (unused);
  corrected a comment that still said trust is keyed by agent alone.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…d gauge from data

Findings-catalogue items; checked in a browser where noted:

- DEMO-04: the before/after baseline always ran the scripted transcript,
  so with a live model the dashboard compared a model against a script. It
  now uses the run's driver choice and web mode; the direct client gained
  list_tools so a live-model driver can run there. Test fails before.
- DEMO-09: the kill chain named web_fetch and block-untrusted-origin, and
  the verdict claimed "the exfiltration would have succeeded", whatever
  the run did. Both come from the recorded steps now. In a browser, the
  privilege scenario shows no untrusted input, a clean lineage, and
  delete_record refused by rule never; the hero names web_fetch.
- DEMO-26: the trust gauge hard-coded a threshold of 40. The configured
  value is in /capabilities (and the trust endpoint) and the dashboard
  reads it.
- DEMO-16: the examples said an external /mcp run appears in the live view;
  it is listed in the history tab.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CLS-2: the rule-based labels matched only the demo's tool names, so blocks
on an operator's own tools were mostly "unclassified". After the existing
demo rules, a tool whose name contains a destructive or privileged verb
(delete, drop, refund, transfer, exec...) is privilege_escalation, and an
outbound one (send, post, upload, webhook...) blocked by authorization or on
a tainted lineage is exfiltration. camelCase, snake, kebab and dotted names
are split into words. Test fails before the change for four of five cases.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
CM-18: fan-out wakes every subscriber, and each one serialized every event
itself (model_dump + json.dumps per subscriber per event). BroadcastEvent
now caches its JSON text, so the cost is one serialization per event. Test
counts model_dump calls across five subscribers: five before, one after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- DUR-1: "durably emitted" now says what each store guarantees.
- TRUST-5: trust/config.yaml says which events cost trust and which do not.
- DEMO-06: the evasion page is written against the local shield's patterns.
- DCC-10 (rest): README and cli docstring list the keys sentinel.yaml takes.
- TCD-21: a phase-6 test called zero auth "the default posture".
- TCD-25: the non-bypassability test covers the proxy's own path only.
- TCD-27: the positioning doc claimed "the same class of guarantee" as CaMeL.
- PP-15: the union-vs-walk test says what it does and does not prove.
- AUTHZ-13: the AST docstring lists boolean literals.
- docs/design-notes.md: each finding deliberately left as it is, with why.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ll open

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Harshith029
Harshith029 merged commit f98be0e into main Oct 19, 2026
7 checks passed
@Harshith029
Harshith029 deleted the catalogue-part4 branch October 19, 2026 17:57
@Harshith029 Harshith029 mentioned this pull request Oct 19, 2026
1 task done
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.

1 participant