Skip to content

feat(proxy): optional evidence payload on POST /audit (#11)#72

Merged
olivrg merged 2 commits into
mainfrom
feat/audit-evidence-payload
Jun 19, 2026
Merged

feat(proxy): optional evidence payload on POST /audit (#11)#72
olivrg merged 2 commits into
mainfrom
feat/audit-evidence-payload

Conversation

@olivrg

@olivrg olivrg commented Jun 19, 2026

Copy link
Copy Markdown
Contributor

Description

Adds an optional evidence array to POST /audit so a hook-based adapter (OpenClaw, #11) can populate
evidence-grounding facts on its single adapter-scoped token, instead of the SDK-scoped POST /evidence. This is the one remaining Helio-core change the adapter depends on.

  • governance-service: AuditInput gains evidence; on a successful, first-finalize audit it writes each entry via EvidenceStore, bound to the pending evaluation's own session_id/tool_name (the adapter never supplies them — it cannot target another session). Every per-entry failure is soft (reported, never request-fatal) and the audit still finalizes 201: caps are enforced here as soft-drops — too_many (>16) / too_large (>64 KiB) — alongside the store's key_not_in_policy_allowlist / closed and no_session / evidence_unavailable. Notably closed is not the 503 the standalone /evidence route returns — losing the audit row for a call that already ran would be worse than a dropped evidence entry.
  • governance-api: evidence added to the auditBody schema (no route-level .max(), so caps stay soft-drops) and folded into auditPayloadHash, order-independent (sorted by the full canonical tuple) — an identical retry replays cleanly while divergent evidence is a 409 evaluation_conflict.

Success-only, first-finalize-only (idempotent replays never re-write). The /audit endpoint stays adapter-token-scoped; non-evidence audits are byte-identical and the MCP path is untouched.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Refactor (no functional changes)
  • Documentation
  • CI / build / tooling

Packages Affected

  • packages/proxy
  • packages/dashboard
  • packages/python-sdk
  • Root config / monorepo tooling
  • docs/
  • examples/

Checklist

  • I have read CONTRIBUTING.md
  • My code follows the existing style (ESLint + Prettier pass)
  • TypeScript strict mode — no any types or @ts-ignore without justification
  • I have added or updated tests for my changes
  • All CI checks pass (pnpm secrets:scan, pnpm docs:check:ci, pnpm audit --audit-level=high, pnpm build, pnpm lint, pnpm format:check, pnpm typecheck, pnpm test)
  • I have updated documentation if this changes user-facing behavior
  • Commit messages follow Conventional Commits (e.g. feat:, fix:, docs:)

How to Test

  1. Run a proxy with an evidence.requires rule for a key, then POST /evaluatePOST /audit with status: "success" and evidence: [{ evidence_key, evidence_data }]; confirm the response returns evidence: [{ evidence_key, stored: true }] and a later evidence-grounded /evaluate sees the stored fact.
  2. Submit a disallowed key, an oversized (>64 KiB) entry, and a >16-entry array; confirm each soft-drops with the matching reason (key_not_in_policy_allowlist / too_large / too_many) while the audit still returns 201.
  3. Close the evidence store mid-flight and POST /audit with evidence; confirm 201 with reason: "closed" (never 503). Replay the same evaluation_id with divergent evidence → 409 evaluation_conflict; replay with identical evidence in any order → 200 already_finalized.
  4. pnpm --filter @gethelio/proxy test — full suite (1592 tests) passes, including the new audit evidence cases in governance-service and the route-level evidence cases in governance-api.

Part of #11.

Additional Context

olivrg added 2 commits June 19, 2026 12:04
Lets a hook-based adapter populate evidence-grounding facts on its single
adapter-scoped token, instead of the SDK-scoped POST /evidence — the
remaining core change for the OpenClaw adapter (#11).

- governance-service: add `evidence` to AuditInput and write it via
  EvidenceStore on a successful, first-finalize audit, bound to the pending
  evaluation's own session_id/tool_name (the adapter never supplies them).
  Every per-entry failure is soft (reported, never request-fatal): caps are
  enforced here as soft-drops — `too_many` (>16) / `too_large` (>64 KiB) — and
  the store's `key_not_in_policy_allowlist` / `closed`, plus `no_session` /
  `evidence_unavailable`, all still finalize 201. Critically, `closed` is NOT
  the 503 the standalone /evidence route returns — losing the audit row for a
  call that already ran would be worse than a dropped evidence entry.
- governance-api: add `evidence` to the auditBody schema (no route-level
  `.max()`, so caps stay soft-drops) and fold it into auditPayloadHash,
  order-independent (sorted by the full canonical tuple) so an identical retry
  replays cleanly while divergent evidence is a 409 conflict.

Success-only, first-finalize-only (idempotent replays never re-write).
Tests cover every soft-drop reason, the closed!=503 asymmetry over HTTP, the
gross-body 413, and order-independent idempotency.
- Add a "Populating evidence" section: array shape, success-only,
  first-finalize-only, per-entry soft-fail outcomes (and their reasons), and
  order-independent idempotency.
- Rewrite the Authentication note that claimed "an adapter cannot write
  evidence" — it now describes the narrow, scoped capability the adapter gains
  via /audit (bound to its own session/tool, allowlist-enforced), without the
  SDK-scoped /evidence route.
- Fix the summary-table /install-scan line that still read "observational" to
  reflect the deny_install enforcement shipped in #13.
@olivrg olivrg force-pushed the feat/audit-evidence-payload branch from 1b78acb to cd11a52 Compare June 19, 2026 11:04
@olivrg olivrg merged commit 507b036 into main Jun 19, 2026
3 checks passed
@olivrg olivrg deleted the feat/audit-evidence-payload branch June 19, 2026 11:22
olivrg added a commit that referenced this pull request Jun 19, 2026
The /audit evidence field (#72) and the hono/undici security patch (#73),
released together as v0.6.0.
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