Skip to content

Enterprise permission modes with managed maximum policies #2109

Description

@zredlined

Problem Statement

Enterprise deployments need a simple way to govern how much autonomy an
OpenShell sandbox can have without forcing every workflow to start from an empty
policy. Security should be able to define a managed maximum policy and the
permission modes users may choose. Users should still be able to start a sandbox
with a useful base policy for their project or task, as long as that starting
policy is inside the managed maximum.

OpenShell already has sandbox policy hot reload, provider profile policy
composition, the policy.local proposal flow, and prover spike work for
maximum-policy containment. The missing product behavior is a managed
maximum-policy admission gate:

candidate_effective_policy <= managed_maximum_policy

The current global policy mechanism is not enough because it replaces sandbox
policy and rejects sandbox-local evolution. Enterprise permission modes need the
opposite shape: a hard ceiling plus local policy evolution below that ceiling.

Proposed Design

Add a gateway-owned managed maximum policy/profile with minimal metadata:

policy_id
version
max_policy
allowed_modes
default_mode
audit_label

The maximum policy is ordinary OpenShell policy YAML. It is the organization
ceiling, not the sandbox's necessarily active starting policy.

Sandbox creation accepts the normal user-supplied starting inputs:

base_policy
mode
providers

When a managed maximum policy is active, gateway admission must prove:

base_policy + provider_layers <= managed_maximum_policy
mode in allowed_modes

Sandbox creation must also evaluate whether the starting authority is
auto-eligible:

base_policy + provider_layers <= auto_eligible_maximum_policy

If the base policy or provider layers include review-required authority, the
gateway must not silently start the sandbox with that authority. For MVP, reject
the create request in any governed mode with structured guidance that identifies
the review-required capability. A later flow can add create-time approval, but
this ticket should not let base policy bypass review. The managed maximum policy
is the only source of approval semantics: startup access is evaluated the same
way as later policy expansions, not through a separate approved-template or hash
system.

If both checks pass, the sandbox starts with the base policy. The base
policy may include common agent bootstrap endpoints, package registries,
source-control reads, internal artifact hosts, or any other project-specific
access the user wants to begin with.

During the session, the effective policy can evolve through direct policy
updates, policy advisor proposals, approval flows, and provider attachment, but
the invariant remains:

effective_policy = base_policy + provider_layers + session_expansions
effective_policy <= managed_maximum_policy

Permission Mode Semantics

ask

The sandbox starts from the base policy. New in-maximum authority
requires approval before it is added. Outside-maximum authority is rejected.

auto

The sandbox starts from the base policy. New in-maximum authority can
be applied automatically when it is eligible for auto-approval. Review-required
authority still asks. Unsupported authority is rejected with admin-required
guidance. Outside-maximum authority is rejected.

Auto-approval eligibility is derived from the managed maximum policy. A maximum
policy allow surface is auto-eligible unless it is marked review-required. An
organization that wants agents to evolve without human or reviewer approval
inside a surface should:

allowed_modes includes auto
the sandbox runs in mode auto
the managed maximum policy allows that surface
the matching maximum-policy surface is not review-required
the prover can model that surface

For example, if the managed maximum permits broad L4, REST, GraphQL, or MCP
authority without review requirements, an auto session may add narrower local
policy for those endpoints/tools without prompting. If a matching maximum-policy
capability is marked review-required, auto mode still asks before granting it.

When no managed maximum policy is configured, OpenShell keeps its existing
unmanaged behavior. That is not a new permission mode in this issue.

Decision Contract

Every authority-changing request resolves to exactly one decision:

apply
ask
reject

Decision order:

if no managed maximum policy:
    use existing unmanaged behavior

if mode is not allowed:
    reject

if candidate effective policy exceeds managed maximum:
    reject

if create request starts with review-required authority:
    reject

if candidate uses a policy surface the prover cannot model:
    reject with admin-required guidance; never auto-apply

if mode == ask:
    ask

if mode == auto and requested delta exceeds auto-eligible maximum view:
    ask

if mode == auto:
    apply

For this MVP, auto is auto-approval of proposed grants. It does not require
OpenShell to automatically allow a runtime request just because the maximum
policy would permit it. The existing denial, proposal, /wait, hot-reload, and
retry loop remains the agent-facing workflow.

Prover Requirements

This feature should use maximum-policy containment checks, not only the current
proposal risk-finding queries. The core checks are:

candidate_effective_policy <= managed_maximum_policy
requested_delta <= auto_eligible_maximum_policy

The auto_eligible_maximum_policy is compiled from the same managed maximum
policy by excluding review-required capabilities. This keeps the user-facing
policy surface singular: one maximum policy, with optional review requirements.
The auto-eligible check applies to the newly requested authority, not the entire
effective policy, so previously approved review-required grants do not block
unrelated future auto-approved grants.

Existing prover/risk outputs such as link-local reach, credentialed L4 bypass,
credential reach expansion, capability expansion, and narrowness-budget findings
may remain useful reviewer context. They are not the admission contract for this
ticket.

Required modeled MVP surfaces:

  • L4 host/port/binary reach.
  • REST method/path reach.
  • GraphQL operation and field reach.
  • MCP server/tool reach.
  • Explicit deny precedence for those surfaces.
  • Review-required annotations for those surfaces.

Unsupported surfaces must fail closed with admin-required guidance until the
prover can model them. They must not apply through ordinary user approval or
automatic approval.

Example Managed Maximum Policies

Add a small set of example enterprise maximum policies as fixtures and docs.
These should be intentionally simple and runnable through the containment tests.

Fully Autonomous Inside Approved Developer Services

This example allows an auto session to evolve local policy without prompts for
approved developer infrastructure. The organization gets a hard ceiling, but no
human/reviewer approval is required inside that ceiling.

metadata:
  policy_id: eng-dev-autonomous
  version: 1
  allowed_modes: [ask, auto]
  default_mode: auto

network_policies:
  github_api:
    endpoints:
      - host: api.github.com
        port: 443
        protocol: rest
        rules:
          - allow:
              method: GET
              path: /repos/acme/**
          - allow:
              method: POST
              path: /repos/acme/**
    binaries:
      - path: /usr/bin/gh
      - path: /usr/bin/curl

  package_registries:
    endpoints:
      - host: registry.npmjs.org
        port: 443
      - host: pypi.org
        port: 443
      - host: files.pythonhosted.org
        port: 443
    binaries:
      - path: /usr/bin/npm
      - path: /usr/bin/python3
      - path: /usr/bin/pip

Auto For Reads, Review For Writes

This example lets the agent discover and add read access automatically, while
write operations route to approval even in auto mode.

metadata:
  policy_id: github-pr-reviewed
  version: 1
  allowed_modes: [ask, auto]
  default_mode: auto

network_policies:
  github_api:
    endpoints:
      - host: api.github.com
        port: 443
        protocol: rest
        rules:
          - allow:
              method: GET
              path: /repos/acme/**
          - allow:
              method: POST
              path: /repos/acme/*/pulls
            review:
              required: true
              reason: Opening a pull request changes repository state.
          - deny:
              method: DELETE
              path: /repos/**
    binaries:
      - path: /usr/bin/gh
      - path: /usr/bin/curl

  github_graphql:
    endpoints:
      - host: api.github.com
        port: 443
        protocol: graphql
        rules:
          - allow:
              operation: query
              fields: [repository, viewer]
          - allow:
              operation: mutation
              fields: [createPullRequest]
            review:
              required: true
              reason: Opening a pull request changes repository state.
          - deny:
              operation: mutation
              fields: [deleteRepository]
    binaries:
      - path: /usr/bin/gh
      - path: /usr/bin/curl

MCP Tools With Review For Destructive Actions

This example shows the same model for MCP: tool reads can auto-apply, while
state-changing tools require review.

metadata:
  policy_id: github-mcp-reviewed
  version: 1
  allowed_modes: [ask, auto]
  default_mode: auto

mcp_policies:
  github:
    server: github
    tools:
      - name: get_issue
      - name: list_pull_requests
      - name: create_pull_request
        review:
          required: true
          reason: Creating a pull request changes repository state.
      - name: delete_repository
        deny: true

Use these examples as initial docs and containment fixtures. Update the field
names to match the implemented schema for review annotations, explicit denies,
GraphQL, and MCP.

MVP Scope

  • Configure one managed maximum policy at gateway scope.
  • Enforce sandbox-create admission for base policy, mode, and providers.
  • Enforce the same maximum-policy containment gate on direct policy updates.
  • Enforce the same gate on agent-authored and mechanistic proposal approval.
  • Enforce the same gate on provider attachment when provider-derived policy
    layers or credentials would change effective authority.
  • Support governed modes ask and auto.
  • Model containment and auto-eligibility for L4, REST, GraphQL, and MCP
    authority.
  • Surface provider/credential impact in approval and rejection output.
  • Include example managed maximum policies for common enterprise modes.
  • Return clear organization-policy rejection guidance when a request exceeds
    the maximum.
  • Include maximum policy id/version, mode, decision, candidate policy hash, and
    applied policy hash in audit output.

Non-Goals

  • Signed policy bundle distribution or artifact attestation.
  • Team/tenant-specific maximum policy selection.
  • A managed catalog of base policy templates.
  • Prompting on every runtime use of an already-granted capability.
  • A first-class enterprise bypass mode.
  • Query-parameter, CIDR, endpoint path scoping, or other containment surfaces
    outside the L4/REST/GraphQL/MCP MVP set unless needed for the first golden
    path.
  • Replacing raw OpenShell policy YAML with a new policy language.

Existing Work To Build On

Acceptance Criteria

  • A managed maximum policy can be configured at gateway scope.
  • Sandbox creation rejects a base policy that exceeds the managed maximum.
  • Sandbox creation rejects a permission mode not listed in allowed_modes.
  • Sandbox creation accepts a useful user-provided base policy when it is
    contained by the managed maximum.
  • Sandbox creation rejects base policy or provider layers that include
    review-required authority instead of granting that authority without
    approval.
  • Direct policy updates are rejected when the resulting effective policy
    would exceed the managed maximum.
  • Agent-authored proposal approval and automatic proposal approval are
    rejected when the resulting effective policy would exceed the managed
    maximum.
  • Provider attachment is rejected when provider-derived policy or credential
    reach would exceed the managed maximum.
  • ask mode asks for every in-maximum expansion.
  • auto mode applies eligible in-maximum expansions without user approval.
  • auto mode asks when the matching maximum-policy capability is
    review-required.
  • Maximum-policy containment supports L4, REST, GraphQL, and MCP surfaces.
  • Auto-eligible containment excludes review-required capabilities for L4,
    REST, GraphQL, and MCP surfaces.
  • Explicit denies are enforced before allows for modeled maximum-policy
    surfaces.
  • Unsupported containment surfaces reject with admin-required guidance and
    are never auto-applied.
  • Approval and rejection output for provider/credential-affecting changes
    includes provider identity, credential key or target host scope, affected
    binary/tool, authority being added, managed maximum policy id/version, and
    decision reason.
  • Example managed maximum policies cover fully autonomous in-boundary work,
    auto-read/review-write GitHub REST and GraphQL work, and MCP tool review.
  • Outside-maximum denials return structured guidance suitable for
    policy.local and the agent redraft loop.
  • Audit logs include maximum policy id/version, mode, decision,
    source, candidate policy hash, and applied policy hash.
  • Tests cover sandbox create, policy update, proposal approval,
    auto-approval, provider attachment, and unsupported-surface fail-closed
    behavior.

Alternatives Considered

Put base policy templates inside the managed profile

This couples org guardrails to workflow catalogs. For the MVP, users can supply
the base policy at sandbox creation, and the gateway only needs to prove that it
is inside the managed maximum and does not include review-required authority.
Named templates are out of scope and must not become a second approval source;
any future convenience layer still needs to use the same maximum-policy and
create-time review semantics.

Use only global policy

Global policy is an override: it applies one payload for all sandboxes and
blocks sandbox-local policy mutation. Managed maximum policy needs to admit
narrower base policies and session-local evolution below the maximum.

Add enterprise bypass mode now

A bypass mode is easy to confuse with turning enforcement off. The safer MVP is
ask and auto inside the managed maximum. Unmanaged or full-access local
development behavior can remain outside this issue.

Agent Investigation

Metadata

Metadata

Assignees

Type

No type

Fields

No fields configured for issues without a type.

Projects

Status
Todo

Relationships

None yet

Development

No branches or pull requests

Issue actions