Skip to content

feat(policy): support signed frozen policy bundles #1842

@zredlined

Description

@zredlined

Problem Statement

Enterprise deployments need a low-friction way for security or platform teams to define the maximum capabilities an OpenShell-managed runtime may have. Those teams may author, approve, sign, and distribute policy outside OpenShell, while OpenShell admits the approved artifact, stores the exact runtime-facing copy in the gateway database, enforces it with existing policy primitives, and audits which signed policy bundle governed the runtime.

Today OpenShell already stores policy revisions, composes effective policy with provider profiles, supports global policy, and supports agent-driven policy updates. What is missing is a signed governance artifact that says: this policy/profile set is trusted, this is the maximum allowed envelope, and this runtime must not be widened locally beyond it.

This should be general enough for any enterprise policy source and simple enough to demonstrate with a GitHub-hosted policy artifact and GitHub-native attestation or signing.

Proposed Design

Add a signed frozen policy bundle admission path.

The bundle should contain or reference OpenShell-native artifacts such as sandbox/global policy and provider-profile policy inputs. It should carry stable identity, version, digest, issuer/source metadata, and signature or attestation metadata. OpenShell verifies the bundle against configured trust material, imports the exact admitted policy/profile bodies into the gateway database, and uses those admitted bodies for runtime composition and enforcement.

Operational model: external systems can author, sign, approve, and distribute the bundle. OpenShell verifies and admits the bundle once, then enforces from the admitted gateway copy.

When a bundle is marked frozen, OpenShell should reject local changes that would alter or widen the governed envelope, including direct policy updates, agent-driven policy approvals, provider/profile changes, or other mutation paths that affect effective runtime capability. Narrower restrictions may be allowed only if the bundle's mutation mode permits them.

Audit logs and policy status should include enough provenance to answer: which bundle/version/digest was admitted, who/what signed it, which sandbox loaded it, which policy hash was enforced, and whether a denied mutation exceeded a frozen bundle.

MVP Check Strategy

This issue should not block on the maximal-policy prover work.

The minimal acceptable MVP check is exact frozen-policy enforcement: after OpenShell verifies and admits a signed bundle, the admitted policy/profile bodies can become the governing effective policy for the target sandbox or sandbox set, and local attempts to mutate or widen that governed policy are rejected.

If the maximal-policy prover path from #1840 is available, the preferred implementation is to treat the signed bundle as the maximum envelope and use the prover/Z3 to admit narrower sandbox policies or agent-requested policy updates that are provably subsets of that signed maximum.

The bundle shape, stored provenance, and audit fields should support both paths so the simple exact-policy demo can evolve into prover-backed subset enforcement without changing the signed artifact model.

MVP Demo

Use a minimal GitHub example:

  1. Publish a GitHub-focused OpenShell policy/provider-profile bundle from a GitHub repo or release.
  2. Sign or attest the bundle with a simple verifier path.
  3. Import the bundle into the OpenShell gateway and store the admitted copy.
  4. Create a sandbox governed by the frozen bundle. For the minimal path, this may use the signed policy as the sandbox's governing effective policy. For the prover path, this may use the signed policy as the maximum envelope for a narrower requested policy.
  5. Show an allowed GitHub action succeeding.
  6. Show a disallowed GitHub write or policy-widening request being rejected by frozen-policy enforcement or by the prover-backed maximum-envelope check.
  7. Show logs/status containing bundle id, version/digest, policy hash, and frozen-denial provenance.

Definition of Done

  • Define a minimal signed bundle shape and trusted issuer/key configuration.
  • Verify bundle signature or attestation before admission.
  • Store admitted policy/profile bodies in the OpenShell gateway database.
  • Bind admitted bundles to policy hashes, versions, and sandbox/runtime metadata.
  • Implement a non-blocking MVP check strategy: exact signed-policy enforcement is sufficient for the first demo; prover-backed subset enforcement is preferred if available.
  • Enforce frozen mutation semantics on policy update and agent-driven approval paths.
  • Reject provider/profile changes that would widen effective runtime capability beyond a frozen bundle.
  • Emit OCSF/shorthand audit context for bundle admission, sandbox load, frozen mutation denial, and policy hash/version.
  • Add focused tests for valid admission, invalid signature rejection, frozen mutation rejection, and audit provenance.
  • Provide a minimal GitHub-based demo path.
  • Document the admission, storage, enforcement, and audit model.

Open Questions

  • Should the first demo use GitHub artifact attestations, a signed release asset, or a simple JWKS/JWT-style detached signature?
  • For the first implementation, should engineering use exact signed-policy enforcement, prover-backed subset enforcement, or stage them in that order?
  • Should frozen bundles forbid all local mutation, or allow narrower runtime-specific restrictions once subset checks are available?
  • Which existing artifact should carry the first bundle reference: global policy, sandbox create, provider-profile import, or a new small bundle record?

Related: #1840

MVP Scope

  • Use existing OpenShell policy and provider-profile primitives for enforcement.
  • Store admitted runtime policy/profile bodies in the gateway database.
  • Verify signed artifacts at admission time.
  • Record signing/provenance metadata for audit and policy status.
  • Keep hardware/runtime attestation out of the first version.
  • Treat the full external policy subsystem contract as follow-on work.
  • Treat full MCP/tool-call policy support as follow-on work; future tool constraints can use the same bundle once that policy surface exists.

Alternatives Considered

Use only global policy

Global policy is useful for deployment-wide controls, but it does not capture signed provenance, provider-profile inputs, per-profile frozen mutation semantics, or reusable enterprise-scoped policy bundles.

Start with a large custom integration

The MVP should stay vendor-neutral and low friction. A GitHub-hosted signed or attested bundle is enough to prove admission, frozen enforcement, and audit without committing to one enterprise policy backend.

Agent Investigation

  • Existing gateway policy revision storage and provider-profile import/composition provide much of the persistence and effective-policy machinery.
  • Existing policy advisor and update paths show the mutation surfaces that must respect frozen bundles.
  • Existing OCSF/shorthand policy logs provide a natural place to add bundle provenance.
  • The gap is first-class signed bundle admission plus frozen maximum-envelope enforcement.

Checklist

  • I've reviewed existing issues and the architecture docs
  • This is a design proposal, not a "please build this" request

Metadata

Metadata

Assignees

Labels

area:gatewayGateway server and control-plane workarea:policyPolicy engine and policy lifecycle worktopic:securitySecurity issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions