Skip to content

INT-O1: enforce review validation and trusted provenance at entrypoints#146

Merged
skylarbpayne merged 3 commits into
mainfrom
remediation/int-o1
Jul 14, 2026
Merged

INT-O1: enforce review validation and trusted provenance at entrypoints#146
skylarbpayne merged 3 commits into
mainfrom
remediation/int-o1

Conversation

@skylarbpayne

@skylarbpayne skylarbpayne commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • Applies the merged HW-07 revision-action validator at the Hermes plugin tool and dashboard HTTP entrypoints.
  • Strips client-controlled by, actor, source, principal, and provenance fields before persistence; receipts project truthful provenance without changing existing ApprovalDecision.to_dict() result shapes.
  • Marks local dashboard actions as unattributed_local_operator and adds the browser-side nonblank request_changes guard.

Entrypoint matrix

Surface Validation Provenance result Spoof handling
workflow_review_respond tool HW-07 v1 validation for revision schemas legacy/unverified adapter label only; never authenticated client identity/provenance keys stripped
POST /review-requests/response and /operator-steps/response HW-07 v1 validation with structured 400 errors unattributed_local_operator with server-generated local-dashboard event browser identity/provenance keys stripped
Dashboard review action blocks blank request_changes before submit; backend remains authoritative server-owned local-dashboard event only no browser actor field is accepted
Approval decision receipts existing serialized decision shape preserved provenance exposed separately on adapter receipts no client label upgrades identity

Verification

  • Focused six-file contract suite on Python 3.9 and 3.11: 156 passed each.
  • Full Python 3.11.14: 656 passed, 2 skipped.
  • Full Python 3.9.6: 657 passed, 1 skipped.
  • Existing serialized-shape regressions: 3 targeted tests passed, then both full suites passed.
  • Normalized replay regressions went red on the old head, then green on both tool and dashboard routes after recovering the durable operator request schema.
  • Real SQLite replay probe: first response and whitespace-equivalent replay both succeeded; a different normalized payload with the same client key failed closed; each route retained exactly 1 signal and 1 step completion.
  • Real spoof probe through both tool and HTTP handlers:
    • tool forged by=skylar plus authenticated-principal payload -> kind=legacy_unverified, principal=null; durable payload only {action, feedback}.
    • HTTP forged by=skylar plus authenticated-principal payload -> kind=unattributed_local_operator, principal=null; source is server-owned local-dashboard.
  • git diff --check passed.
  • Exact allowlist check passed: 7 of 8 permitted paths changed; no forbidden path changed.

Ancestry and collision receipts

  • Base / HW-08: b1fbe15f6a8de092ebb7fbd7da6e2fa0bc670b5b
  • FND-OP consumed ancestor: 2727a46b1a799a4a2125d3b85e292db514f1fb98
  • HW-07 consumed ancestor: 4674210f67d6d8ab4cf86abeb9ae330124c75294
  • Exact head: 0afe40754c64b14239f3c29448e1d3d355494f05
  • Excluded PR feat: support custom select values in review queue #131 head fc9eb5ae0797c5cbdfcf51d6b9be551e6ba85331 is not an ancestor and was not consumed or modified.

Changed paths

  • src/hermes_workflows/hermes_plugin_approvals.py
  • src/hermes_workflows/approvals.py
  • plugins/hermes-workflows-approvals/dashboard/plugin_api.py
  • plugins/hermes-workflows-approvals/dashboard/dist/index.js
  • tests/test_approval_provenance.py
  • tests/test_hermes_plugin_approvals.py
  • tests/test_dashboard_plugin.py

Gate

Do not merge. This repair invalidates SR1/QR1; fresh separate Palmer INT-O1 SR2, then QR2, remain mandatory.

GitHub checks at 0afe40754c64b14239f3c29448e1d3d355494f05

  • build: passed (16s)
  • pytest (3.11): passed (1m2s)
  • pytest (3.9): passed (1m40s)
  • deploy: skipped as expected for this PR

@skylarbpayne

Copy link
Copy Markdown
Owner Author

INT-O1 Repair 3 — fresh transport ID normalized replay

Exact repair head: a2005f55abec05a3f18ed87522fbe43620f770aa (from 0afe40754c64b14239f3c29448e1d3d355494f05).

Repair-only paths:

  • src/hermes_workflows/hermes_plugin_approvals.py
  • plugins/hermes-workflows-approvals/dashboard/plugin_api.py
  • tests/test_hermes_plugin_approvals.py
  • tests/test_dashboard_plugin.py

Evidence:

  • TDD red at old head behavior: the tool and dashboard fresh-key A/B normalized replay regressions both failed with idempotency key was reused with a different decision/response (2 failed).
  • Green regression: 2 passed.
  • Python 3.9 focused: 156 passed in 2.51s; full: 657 passed, 1 skipped in 37.65s.
  • Python 3.11 focused: 156 passed in 2.11s; full: 656 passed, 2 skipped in 31.64s.
  • Independent temporary-SQLite probes, both routes: key A succeeded; whitespace-equivalent key B returned the existing result; different content with key C failed closed; exactly 1 SignalReceived and 1 operator StepCompleted remained.
  • Probe provenance: tool stayed legacy_unverified, dashboard stayed unattributed_local_operator, both principals remained null, forged authority fields were absent from the persisted payload, and the first durable transport source (tool-A / dashboard-A) remained unchanged.
  • Invalid Unicode-whitespace revision probes: 0 signals and 0 step completions on both routes (dashboard HTTP 400; tool structured failure).
  • Browser bundle inspection: the shipped submission path still creates a fresh crypto.randomUUID() request ID and sends it as idempotency_key; server enforcement is the trust boundary.
  • git diff --check clean. Repair diff is exactly the four allowed paths above; cumulative PR diff remains inside the INT-O1 closed allowlist.

No live profile install, registry/database mutation, service restart/reconfiguration, deploy/cutover, user-data mutation, external send, cron change, or Motion/Wonderly edit was performed. Do not merge; fresh SR3 and separate QR3 remain controller-owned.

@skylarbpayne
skylarbpayne merged commit 98370d2 into main Jul 14, 2026
4 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.

1 participant