OpenClaw EnterpriseDOCSGitHub

Protected credential request flow

Overview

The supervisor holds an Agent's GitHub identity reply until OpenClaw Control Plane (OCC) permits release. See the legacy supervisor cutoff and threat model.

Entry Points

Flow

Follow the metadata GET

For an admitted github-app-metadata route to repository 12345, acme/widgets, at https://api.github.com:

  1. Match. The supervisor binds the bodyless GET /repos/acme/widgets reply to its exchange. The adapter checks method, URL, headers and body against the route.
  2. Resolve. OCC authorizes the Agent and registered grant. The Token Service starts or joins issuance; OCC rechecks authority and token version before returning the header.
  3. Permit. OCC rechecks the same-stream binding. Sending must start by the permit deadline.
  4. Release. The adapter requires complete 200 JSON, at most 64 KiB, matching the admitted ID and name (ASCII case may differ). The caller receives 200, Content-Type: application/json, Cache-Control: no-store and only this body.
json
{ "id": 12345, "full_name": "acme/widgets" }

ID 67890 under the same name is withheld after GitHub receives the request. The credential-free profile applies the same filters, records no_material_required and sends no credential header. GitHub metadata adapter

graph TD
  A["<b>Resolve token</b><br/>Match route and access"] -->|Denied| X["Refuse before send"]
  A -->|Header ready| B["<b>Authorize send</b><br/>Recheck grant and version"]
  B -->|Denied| X
  B -->|Permit| C["<b>Send GET</b><br/>Hold GitHub's reply"]
  C --> D{"Valid identity<br/>and live caller?"}
  D -->|Yes| G["Release ID and name"]
  D -->|No| H["Withhold reply"]

Execution Trace

1. Admit source and install the revision plan

Bundled OpenShell rejects new static OpenAI use via InstalledDriver.assertNewStaticProviderUse: source refusal precedes material reads; deployment refusal precedes counterpart probes. Retained revisions keep their provider, authorization, withdrawal and cleanup under the current Sandbox contract.

OCC checks source and Secret permissions; existing sources need opt-in. Version 3 binds Sandbox and Proxy to one registered Driver. The plan records its digest, execution, source generation, grant, and routes; empty routes deny all. admitProxyPlan derives routes from saved Harness settings and source consent. checkEgressUseIn rechecks before delivery and send authorization. Console apps/controller/src/console/agents/detail.mts:requestedHarnessOverrides captures the controls at submission. OCC owns normalized input before awaiting admission, which resolves settings and checks both caller and Agent grants.

For credential-free metadata, packages/occ/src/index.ts:admitProxyPlan rejects a Driver grant that differs from the source. Equivalent grants have the same digest across property orders. Unprotected revisions remain v2. Only the bundled Driver recognizes historical protected plans by original capability IDs for stored release or custody settlement.

Compute rechecks admission with the worker before launch. PostgreSQL rejects unknown decisions and mixed v2/v3 fields. Older workers refuse v3. Upgrade all writers before admitting it.

For each route, apps/controller/src/drivers/compute/kubernetes/index.ts:preparedEgressReady selects the issuer, projects the admitted source and checks readiness. Compute has observation methods, without token-read or lifecycle authority. Missing or mismatched owners refuse release; cold sources remain pending.

Deploy returns 409 for missing Git delivery profiles (REPOSITORY_GIT_PROFILE_UNSUPPORTED), bundled git-write (REPOSITORY_GIT_SENDER_UNQUALIFIED), unadmitted bindings, Agents without Git on a Git-only Proxy, and Installation limits. Preparation repeats both Git refusals. Protected repository Git uses a separate worker binding and requires proof of the recipient before release.

Compute passes Credential Proxy wiring to Sandbox. Protected sources require admission, API-key login and an exact source-key match. Only Gateway-owned sources receive their exact Gateway attachment and authentication environment. apps/controller/src/drivers/egress-proxy/openshell.ts:openShellEgressConfiguration emits /** on inference routes so any verified executable in the admitted execution can reach the model endpoint through credential middleware. The egress Driver compares the full prepared policy against the plan, including the explicit matcher.

Authenticated V1 evidence binds both policies to the Sandbox, instance, policy version, configuration and environment revisions, and capabilities. The gateway compares unknown fields. Installation and revalidation accept only the exact name-only rule exception. Missing, legacy, widened or changed evidence refuses. The local comparison fingerprint covers both policies and hashes.

Compute sets OPENCLAW_EGRESS_ENROLLMENT_REVISION_ID from protected Harness admission. The helper matches the manifest before opening the authenticated listener. The provider receives only the verifier; Compute withholds the private status revision, port, container name and Pod UID.

The Harness waits before its first model probe. Compute awaits installation commit, rechecks evidence and calls the Sandbox Driver. The Driver verifies the Sandbox and service and reads the execution/plan challenge. Compute signs the fresh process nonce and current installation with its control-plane key. The listener closes before Codex starts. Restart invalidates the old release. After 180 seconds startup fails closed and remains held. Reconciliation can repeat readiness checks without resolving material or retrying business requests. Active revisions require queued work; default Kubernetes has no periodic maintenance for Harness-only restarts.

During held Git enrollment, openshell-git-runtime.ts:observeHeldPreview logs curl and response failures. An unconfirmed one-shot probe blocks the route with bootstrap_failed before credential delivery or release.

openshell-git-installation.ts:observeOpenShellGitInstallation completes a model OBSERVE per active environment for observed Git routes, including rotations. ObservedHookPreview.completedModelReceipt caches completion per environment revision. Stale or incomplete model receipts keep the route pending without changing the original launch witness or startup acknowledgment.

2. Capture identity, operation and first authority decision

Each TLS HttpInstallationExchange.Exchange authenticates a bearer, then challenges its supervisor with 32 random bytes. Up to 1,024 openings, 256 per Sandbox, wait for acceptance, closure or a 30-second deadline. The owner rechecks the bearer, gateway-signed exchange_key and supervisor Ed25519 signature over openshell-exchange-v1, zero byte, challenge and binary opening. Request JSON cannot supply a key; bearer-only calls refuse. Online authorization (apps/controller/src/drivers/egress-proxy/openshell-online-authority.ts:createAuthority) has the same capacity limits.

Before awaiting work, the adapter copies the request and binds a private capability to the stream. Credential Proxy bounds body size, reserves capacity and copies headers, body and authenticated peer. Send and response require the same sender, Sandbox, instance, exchange, installation and optional peer key. Any key change refuses. Peer expiry must remain valid at resolution, send and response lookup. Bearers and handles cannot transfer custody. Closure cancels the stream; cancellation or expiry releases material. Pending policy or receipt work retains its slot. No pipelining.

packages/occ/src/credential-proxy.ts:resolve assigns the verified Sandbox's share, loads its persisted installation and pins eligible providers before classification. Ambiguity refuses. OCC rechecks pins around provider calls and at material access, send and response release; changes restored between checks escape detection. Only one exact route match reserves a UUIDv7 ID before capture or policy I/O. Creation fixes its 30-second replay horizon; capacity is bounded. Unsupported or ambiguous operations refuse before reservation. createCredentialProxy audits only when exactly one refused route reports, exactly once with a valid rule. It records execution and exact request ID before capture or credential access. Persistence failure refuses as authority-unavailable.

Enrollment must start at the authenticated supervisor hello. The supplier must keep its private key outside the Agent and pin its actual reply sink before queueing. This path remains unqualified. Required capability openshell.supervisor-middleware.installation-exchange.v1 cannot be substituted by an old executable-restricted grant.

Each check requires a fresh platform transaction; enclosing transactions refuse to prevent IAM snapshot reuse. It verifies current Namespace/Agent state, admitted revision, installation, source generation, withdrawal and exact Agent source permission. credentialNamespace supplies Compute's runtime placement to the Driver; IAM and audit retain logical Namespace identity. The Driver requeries policy-status evidence against the stored fence. Replacement, missing evidence or changed configuration refuses even if the saved installation was valid. Denials record phase and internal request attribution without material.

3. Resolve versioned material and authorize its sole send

The Secret Driver verifies ownership and reads authoritative UID/resourceVersion. Static and prepared GitHub reads share one { signal, deadlineAt } lifetime through namespace verification, GET and retries. Child scopes inherit cancellation and the earliest deadline. Each HTTP dispatch checks expiry independently of timers. Invalid deadlines fail closed; per-attempt timeouts cannot extend the lifetime. GitHub acquisition validation, transport and metadata injection share a wire check: 1–16,384 bytes of nonspace printable ASCII, not authentication.

apps/controller/src/drivers/repo/github/access/prepared-lifecycle.ts:resolve checks source registration and token lifetime, reading ciphertext only for the selected issuer, attempt and version. Decryption rechecks deadline and cancellation. Without a timely eligible token, OCC withholds the header. Background cleanup can access retired material.

Before send, packages/occ/src/state/prepared-github-state.ts:postgresPreparedGitHubProof queries current material metadata in the active platform transaction, without another checkout. Lifecycle issuer/trust identity, shared metadata predicates and exact evidence fence stale selections. The port exposes neither ciphertext nor caller-supplied SQL. Statement and lock timeouts respect tighter caller limits. Successful SQL restores the original settings in the same unit before rechecking cancellation and absolute expiry; SQL errors leave rollback to the transaction owner. OCC checks withdrawal, rejection and binding in that unit.

Same-stream authorization echoes the original deadline, evidence and injection digest. The registry reserves the handle; packages/occ/src/egress-send-receipts.ts:EgressSendReceipts.begin commits possible dispatch before permission. The key includes authenticated sender Ref, instance, stable request/use ID and attempt ID; the binding includes exact store-qualified material and original deadline. Existing attempts, failed writes or unknown commits refuse permission, even after authority restart.

The sender and OCC bind the same Sandbox, instance, configuration, peer key, policy hash, authority scope and plan to the exchange. The Git recipient has its own delivery evidence.

After reservation, OCC’s authorizeSend port verifies the current runtime before opening the send transaction. The selected IAMDriver.authorize method makes the fresh decision for the exact service principal, operate action and Credential Source. For native IAM, the Namespace lock orders that decision and receipt commit against supported Namespace binding changes. An external IAM decision occurs before the transaction and cannot share that ordering. OCC rechecks the selected route, installation, material and rejection fence, then mints the permit and calls EgressSendReceipts.authorizeIn in the same transaction. The receipt binds the execution, installation fence, exchange, response custody, request and injection digests, authorization time and send-start deadline. The deadline is at most one second away and cannot outlive the request, material or identity.

Before returning permission, the registry rechecks cancellation, ownership and the persisted deadline. A lost acknowledgment, handle or deadline yields no permit. Restart cannot reauthorize the attempt. Revocation may race an authorized send; an origin write with a lost reply remains a possible effect and must not be retried.

4. Protect response and finish

packages/occ/src/credential-proxy.ts:protectResponse binds the complete response to its peer, request and exchange, removes unlisted headers and withholds bytes until approval. The request deadline bounds the first byte. On progress, renewResponse checks policy at most once every 15 seconds, including during outages. Unavailability preserves the deadline; denial cuts the stream. Recovery can renew before expiry. A shorter authenticated peer lifetime caps leases and held responses despite later progress. Limits: five minutes idle, fifteen minutes total, 4 MiB and 16,384 events.

openai-responses.ts:isResponsesEvent validates Responses envelopes, including response-only null local-tool metadata and the optional effective image policy. Invalid or unknown fields withhold all bytes. Protection scans SDK snapshots, joined assistant text and completed/streamed Codex Plans; ambiguous order or indexes refuse. Function arguments parse once as bounded JSON. The supported profile preserves safe bytes. The origin already received the credential.

Only this exchange can claim the response. EgressSendReceipts.observe atomically records the decision and any exact rejection fence without bodies, headers, credentials or handles. Failure withholds bytes; success still requires checking cancellation and deadline.

Structured OpenAI invalid_api_key can establish rejection; a bare 401 cannot. At its next scheduled check, the prepared owner excludes a positively rejected version. Concurrent owners coalesce replacement; uncertain issuance blocks it; late feedback cannot invalidate its successor. GitHub metadata has no positive rejection classifier.

Erase material after response handling or at deadline. Only a refusal before permission can settle as undispatched. After possible permission, inspect the exact attempt without retrying; returning bytes does not prove delivery.

5. Configure the regular Harness caller

apps/controller/src/drivers/compute/plugin-runtime.ts:codexToml selects HTTP Responses with local tools. It disables provider tools, WebSockets, and retries. Startup probes also disable retries.

apps/controller/src/drivers/egress-proxy/openai-provider.ts:createOpenAiStaticProvider applies the request policy through openai-responses.ts:responsesRequestFailure before Secret resolution. The grant selects model and destination. Resumed reasoning input can carry content: null.

6. Reduce the live credential policy

OCC commits withdrawal before provider action. Under the Agent lock, packages/occ/src/credential-policy-reduction.ts:reduceCredentialPolicy records the source or repository compare-and-reduce request in credential_delivery_reductions. Concurrent reductions wait; recovery observes without another capability probe or mutation. The store separately constrains policy and material reduction receipts.

Only exact-dispatch Git uses reduction v2. Online and observed-hook Git retain v5/v6. Ordinary v3 uses reduction v1 only when the Driver explicitly declares it; v2 alone does not authorize v1 or multiple static sources.

Policy requires the exact observed operation, stable recipient and retained plan; the original receipt stays unchanged. Missing identity, stale operations or invalid configuration/policy evidence keeps withdrawal pending. A confirmed replacement recipient can require retirement. Remaining grants stay unchanged; the last route leaves deny-all. Settlement and stale installation cannot restore withdrawn routes. Reference-peer proof does not qualify released Sandboxes or continued model execution.

7. Retain installation custody

packages/occ/src/state/credential-deliveries.ts:CredentialDeliveries requires independent confirmation for registered recipients; snapshots require their reserving worker, including bootstrap. Neither grants request authority.

apps/controller/src/drivers/egress-proxy/openshell-git-runtime.ts:reconcile cancels definitely unsent writes. Uncertain writes remain blocked. release drops closed routes after Sandbox deletion, preserving refusal. prepare requires a held launch or explicit installation preview and closes another worker's persisted route before credential access. verifyExecution refuses historical installation-wide renewal. retireExpiredRepositoryAccess settles the original fenced detach.

Before transport startup, openshell-repository-git-evidence.ts:openShellGitRecipientEvidence checks discovered sessions. Issuance requires selected online delivery or explicit observed-hook preview. Historical v4 and installation-wide v5 cannot issue. See restart behavior.

Deletion retains custody but stops use. apps/controller/src/drivers/egress-proxy/openshell-git-route-store.ts:confirmDetached verifies the original fence, recipient, material, policy and request without reapplying.

Debugging and Verification

Follow the testing guide to qualify model execution, response custody and NetworkPolicy; observe origin and caller separately. openclaw.egress.authorize rows describe attempts. Pre-reservation refusals can reuse requestId; correlate actor, source, revision and time. Responses classificationRule maps to apps/controller/src/drivers/egress-proxy/openai-responses.ts:responsesRequestFailure after route and model eligibility checks. Numbers identify root slots; audit rule 1 hides unknown names. Values are excluded; absent rules identify no slot. Caller refusals stay generic.

Manual Notes

None.

Search documentation