Skip to content

feat(security): bind HerdR physical tool exposure producer (#190) - #290

Open
James3014 wants to merge 2 commits into
mainfrom
codex/issue-190-herdr-physical-producer-g3
Open

James3014 wants to merge 2 commits into
mainfrom
codex/issue-190-herdr-physical-producer-g3

Conversation

@James3014

@James3014 James3014 commented Sep 26, 2026 •

Copy link
Copy Markdown
Owner

Summary

Implements and repairs TASK-DEVSPACE-190-G3-HERDR-PHYSICAL-PRODUCER for #190 under campaign CAMPAIGN-DEVSPACE-190-HERDR-PHYSICAL-PRODUCER (Card digest: sha256:49c0d29ae5534c0347ee93739d2da2ef1240c3ff4434ff1a41dbb80b7a869f7d).

Repair Finding Resolution (R1 - R16)

  • R1 (Task Card Scope Violation): Fully reverted package.json to base (be1d7a075dd534c4353486396fe1ed0c6baa3938, zero diff). Removed unauthorized files src/tool-exposure-receipt.ts and src/tool-exposure-producer.test.ts. All receipt definitions, schemas, and validators moved to src/local-effect-enforcement.ts. All producer mechanics moved to src/local-agent-herdr.ts. All tests moved to src/local-agent-herdr.test.ts and src/local-agent-opencode.test.ts. Exactly the 5 authorized files are changed.
  • R2 (planner_decision_hash): Replaced dispatchIntentHash assignment with plannerDecisionHash from executionContract / toolAuthority or zero-padded sha256 (0.repeat(64)).
  • R3 (ToolProjectionManifest hash): Used canonical hashToolProjectionManifest from execution-protocol.ts (covers all canonical fields) rather than ad-hoc partial hashing.
  • R4 (Derive from OPENCODE_CONFIG_CONTENT): Implemented extractActualExposedToolsFromOpencodeConfig inspecting the generated OPENCODE_CONFIG_CONTENT JSON environment injected into workspace.create, physically deriving actual_exposed_tools from agent.devspace_read_only.permission / devspace_allowed.permission.
  • R5 (enforcementState Alignment): OpenCode managed bridge sets enforcementState = "PHYSICALLY_ENFORCED" and receipt.enforcement_mode = "ENFORCED_MANAGED_BRIDGE". CLI providers set enforcementState = "REQUEST_ONLY_NOT_ENFORCED", receipt.enforcement_mode = "REQUEST_ONLY_NOT_ENFORCED", actual_exposed_tools = []. bindHerdrExternalHandle permits PHYSICALLY_ENFORCED exclusively for OpenCode managed bridge.
  • R6 (Operation ID derivation): Derived operation_id = dispatchIntent?.taskId ?? attemptKey. Never falls back to attemptKey when taskId is known.
  • R7 & R8 (Nexus Schema & Invariant Compatibility): Added remote_tool_identities and runtime_tool_generations with deterministic sorting and validation matching Nexus Python contract.
  • R9 (Physical Canary Record): Recorded PHYSICAL_AB_CANARY=PHYSICAL_CANARY_NOT_RUN (daemon restart forbidden) to respect no-daemon-restart invariant.
  • R10 - R16 (Tests & Scope Preservation): Tests integrated cleanly into authorized test files (H1–H8 in local-agent-herdr.test.ts, config extractor in local-agent-opencode.test.ts). Ran full verification suites.

Verification

  • npm run typecheck: PASS (clean 0 errors)
  • npm run test:local-agent-sessions: PASS (31/31 passed)
  • npx tsx src/local-agent-opencode.test.ts: PASS
  • git diff be1d7a075dd534c4353486396fe1ed0c6baa3938...HEAD --name-status: EXACT 5 authorized files
  • git diff --check: PASS (clean 0 whitespace errors)

Ref: #190
Consumer Ref: James3014/Nexus-new#1144

Antigravity added 2 commits September 27, 2026 00:18
- Add canonical nexus.tool_exposure_receipt.v1 producer in src/tool-exposure-receipt.ts
- Wire toolExposureReceipt into HerdrExternalHandle, NormalizedHerdrHandleAuthority, and LocalAgentSessionManager
- Produce ENFORCED_MANAGED_BRIDGE for OpenCode via opencodeAgentConfig permission projection
- Maintain fail-closed REQUEST_ONLY_NOT_ENFORCED for un-enforced CLI providers (agy, codex, grok, cline)
- Expose toolExposureReceipt in StartAgentOutput, AgentStatusOutput, and ReconcileAgentOutput
- Add unit and matrix test suite in src/tool-exposure-producer.test.ts
#190 G3)

- R1: Revert package.json changes and remove non-scope files tool-exposure-receipt.ts and tool-exposure-producer.test.ts; migrate all implementation and tests to authorized files
- R2: Set planner_decision_hash from executionContract or zero-padded sha256 rather than dispatchIntentHash
- R3: Use canonical hashToolProjectionManifest for full ToolProjectionManifest projection_hash
- R4: Physically extract actual_exposed_tools from OPENCODE_CONFIG_CONTENT JSON injected into workspace.create
- R5: Handle enforcementState PHYSICALLY_ENFORCED for OpenCode managed bridge and REQUEST_ONLY_NOT_ENFORCED for CLI
- R6: Operation ID derives from dispatchIntent.taskId with attemptKey fallback
- R7: Full schema compatibility for remote_tool_identities and runtime_tool_generations
- R8: Validate sorting and hashing invariants on tool exposure receipts
- R10-R16: Repair unit tests and session manager integration within authorized test files
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