Skip to content

PROD-318 feat(interceptor): behavioral CONSTRAIN interception - #23

Open
salamisandwich77 wants to merge 15 commits into
feat/PROD-250-sandbox-sdk-integrationfrom
feat/PROD-318-behavioral-constrain
Open

PROD-318 feat(interceptor): behavioral CONSTRAIN interception#23
salamisandwich77 wants to merge 15 commits into
feat/PROD-250-sandbox-sdk-integrationfrom
feat/PROD-318-behavioral-constrain

Conversation

@salamisandwich77

@salamisandwich77 salamisandwich77 commented Aug 17, 2026

Copy link
Copy Markdown

Behavioral CONSTRAIN enforces true interception.

  • Started-span CONSTRAIN aborts the host action (zero host requests) + dispatches the named profile into the sandbox
  • Fail-close on both paths: sandbox failure fails the activity (retryable), span evidence finalizes first
  • Deterministic dispatch identity (workflow/run/activity/attempt/profile) — retries dedupe, one execution per id
  • ActivityCompleted CONSTRAIN = no-op; sandbox span parented to the trigger span

Tests: 701 passed.

The global config stores the raw Ed25519 key object; the dispatcher's
GovernanceClientConfig requires agent_did + sign_headers. The plugin
now wraps it in AipEd25519RequestSigner before resolving the sandbox
config — previously any run with an agent identity crashed at plugin
construction with GovernanceProtocolError.
Legacy OTel governance hooks parsed CONSTRAIN as a non-blocking verdict and returned without invoking the Temporal framework adapter. Forward started-stage sync and async constraints through the registered adapter so behavioral profile dispatches are retained and attached to activity results.
@salamisandwich77 salamisandwich77 changed the title PROD-318 fix(interceptor): ActivityCompleted CONSTRAIN is a no-op PROD-318 feat(interceptor): behavioral CONSTRAIN interception Aug 19, 2026
@salamisandwich77
salamisandwich77 changed the base branch from main to feat/PROD-250-sandbox-sdk-integration August 26, 2026 07:54
@salamisandwich77
salamisandwich77 marked this pull request as ready for review August 26, 2026 07:55
The terminal record never carried the proxy's per-destination decisions, so
the guarded-command span showed outcome fields but no destination. finalize
now reads execution.egress_decisions off the dispatch result, the record
carries them, and _record_span emits openbox.sandbox.egress.count plus
decision, host, and port per entry, matching the attributes the console tree
already knows how to render.
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