Skip to content

feat(policy): enforce synchronous prompt policy barrier - #469

Draft
tumberger wants to merge 1 commit into
jens/eng-624-c3-session-policy-managerfrom
jens/eng-624-c4-sync-prompt-enforcement
Draft

tumberger wants to merge 1 commit into
jens/eng-624-c3-session-policy-managerfrom
jens/eng-624-c4-sync-prompt-enforcement

Conversation

@tumberger

@tumberger tumberger commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor

ENG-624 CLI stack 4/6; stacked on #468.

Wires the synchronous prompt barrier into the persistent daemon and existing Cedar provider. PreToolUse selects one complete session PolicySet and performs one local Cedar authorization call.

Runtime enablement comes from endpoint configuration. The client needs no prompt-policy trust-key bootstrap or extra cryptographic setup.

tumberger commented Aug 14, 2026 •

Copy link
Copy Markdown
Contributor Author

Comment on lines +133 to +134
expiresAt, _ := time.Parse(time.RFC3339Nano, bundle.ExpiresAt)
state.snapshot = Snapshot{Required: true, Ready: true, PromptSequence: sequence, Deployment: &deployment, ExpiresAt: expiresAt}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Silently ignoring time parsing error will cause all prompt policies to be treated as expired. If bundle.ExpiresAt is malformed or in an unexpected format, time.Parse will fail and return the zero time value. At line 150, the check time.Now().Before(selected.ExpiresAt) will always be false (since current time is after zero time), causing valid policies to be rejected with "required prompt policy is not ready" errors.

expiresAt, err := time.Parse(time.RFC3339Nano, bundle.ExpiresAt)
if err != nil {
    state.snapshot = Snapshot{
        Required: true, Ready: false, PromptSequence: sequence,
        Failure: fmt.Errorf("invalid expiry time: %w", err),
    }
    return state.snapshot, state.snapshot.Failure
}
Suggested change
expiresAt, _ := time.Parse(time.RFC3339Nano, bundle.ExpiresAt)
state.snapshot = Snapshot{Required: true, Ready: true, PromptSequence: sequence, Deployment: &deployment, ExpiresAt: expiresAt}
expiresAt, err := time.Parse(time.RFC3339Nano, bundle.ExpiresAt)
if err != nil {
state.snapshot = Snapshot{Required: true, Ready: false, PromptSequence: sequence, Failure: fmt.Errorf("invalid expiry time: %w", err)}
return state.snapshot, state.snapshot.Failure
}
state.snapshot = Snapshot{Required: true, Ready: true, PromptSequence: sequence, Deployment: &deployment, ExpiresAt: expiresAt}

Spotted by Graphite

Fix in Graphite


Is this helpful? React 👍 or 👎 to let us know.

@greptile-apps

greptile-apps Bot commented Aug 15, 2026 •

Copy link
Copy Markdown

Greptile Summary

This PR adds an opt-in synchronous prompt-policy barrier to the managed daemon and selects verified, session-specific Cedar policy sets for subsequent tool calls.

  • Adds prompt submission activation and session cleanup around the existing policy-provider chain.
  • Extends Cedar snapshot selection with session-aware policy lookup and expiry handling.
  • Configures prompt-policy trust keys, client, and manager during managed-daemon startup.
  • Propagates prompt data and the manager through runtime host and Guard server wiring.

Confidence Score: 4/5

The prompt-policy barrier should be fixed before merging because a routine Cedar refresh outage can reject every new user prompt despite a valid authoritative cached deployment.

Prompt activation consults only the active Cedar deployment, while the cache and existing enforcement path intentionally continue using LastKnownGood after the active snapshot ages out.

Files Needing Attention: internal/sessionpolicy/manager.go

Important Files Changed

Filename Overview
internal/sessionpolicy/manager.go Adds expiring, session-specific Cedar snapshot selection, but prompt activation incorrectly rejects a valid last-known-good parent after cache expiry.
internal/guard/app/server/prompt_policy.go Adds the synchronous prompt activation barrier and session cleanup around the existing provider chain.
internal/guard/app/server/cedar.go Selects session-specific snapshots for PreToolUse while retaining legacy organization-only providers.
internal/managedobserve/daemon.go Opt-in trust-key configuration constructs and wires the prompt-policy client and session manager.
internal/runtimehost/host.go Propagates the optional session manager into Guard server construction.
internal/guard/app/server/runtime.go Preserves prompt text when converting between hook and risk events.

Sequence Diagram

sequenceDiagram
  participant Agent
  participant Daemon
  participant Manager as Session Policy Manager
  participant API as Prompt Policy API
  participant Cedar
  Agent->>Daemon: UserPromptSubmit
  Daemon->>Manager: BeginPrompt(session, prompt)
  Manager->>API: Derive policy from parent deployment
  API-->>Manager: Signed complete PolicySet
  Manager-->>Daemon: Atomically activate session policy
  Daemon-->>Agent: Allow or activation deny
  Agent->>Daemon: PreToolUse
  Daemon->>Manager: CurrentFor(session)
  Manager-->>Cedar: Selected session PolicySet
  Cedar-->>Agent: Authorization decision
Loading

Comments Outside Diff (1)

  1. internal/sessionpolicy/manager.go, line 99-103 (link)

    P1 Last-known-good parent is ignored

    When a successful Cedar snapshot ages past the cache maximum age during a refresh outage, Deployment is cleared while LastKnownGood remains authoritative, but BeginPrompt checks only Deployment. This rejects every new prompt with “prompt policy parent is not ready” even though Cedar can still enforce the valid cached deployment.

    Knowledge Base Used: Guard runtime decision engine

Reviews (1): Last reviewed commit: "feat(policy): enforce synchronous prompt..." | Re-trigger Greptile

@tumberger
tumberger force-pushed the jens/eng-624-c3-session-policy-manager branch from f12befe to 8867b94 Compare August 15, 2026 13:31
@tumberger
tumberger force-pushed the jens/eng-624-c4-sync-prompt-enforcement branch from e5ce4dc to c27d9dd Compare August 15, 2026 13:31
@tumberger
tumberger marked this pull request as draft August 15, 2026 13:34
@tumberger
tumberger force-pushed the jens/eng-624-c4-sync-prompt-enforcement branch from c27d9dd to fa4e627 Compare August 26, 2026 09:00
@tumberger
tumberger force-pushed the jens/eng-624-c3-session-policy-manager branch from 8867b94 to 03a75ff Compare August 26, 2026 09:00
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