OpenClaw EnterpriseDOCSGitHub

Repository credential configuration flow

Overview

The repository credential composition loader validates operator-selected configuration, prepared registry policy, and TLS files before returning a frozen configuration owner. In Kubernetes projection mode, the sidecar derives the broker origin from its trusted deployment argument before protected loading. The standalone --check-config entry point still requires an explicit origin, reports a nonsecret summary, and closes that owner. This flow stops before provider requests or listener startup.

Entry Points

Flow

graph TD
  Input["<b>Operator configuration</b><br/>Absolute protected path"] --> Ancestors["<b>Validate ancestors</b><br/>Root to immediate parent"]
  Projection["<b>Kubernetes inputs</b><br/>Selected generations"] --> Snapshot["<b>Check and copy inputs</b><br/>Private regular files"]
  Expected["<b>Deployment origin</b><br/>Trusted sidecar argument"] --> Snapshot
  Snapshot -->|invalid projection or identity| Reject
  Snapshot -->|protected snapshot| Ancestors
  Ancestors -->|unsafe owner, mode or symlink| Reject["<b>Reject configuration</b><br/>No provider call"]
  Ancestors -->|trusted path| File["<b>Open protected file</b><br/>Bound size and identity"]
  File -->|changed or invalid| Reject
  File -->|valid JSON| Backend["<b>Validate backend and registry</b><br/>Require compatible policy"]
  Backend -->|incompatible policy| Reject
  Backend -->|compatible| Material["<b>Load selected authority and TLS</b><br/>Repeat protected reads"]
  Material -->|invalid material| Reject
  Material -->|validated| Owner["<b>Construct selected owner</b><br/>Freeze configuration"]
  Owner -->|configuration check| Summary["<b>Return safe summary</b><br/>Close owned material"]
  Owner -->|service startup| Service["<b>Service composition</b><br/>Own material lifetime"]
  classDef input fill:#F1EEF5,stroke:#A091AD,color:#3A3243,stroke-width:1px
  classDef operation fill:#EBF3F0,stroke:#7F9D93,color:#2B4038,stroke-width:1px
  classDef blocked fill:#F7F1E5,stroke:#B3A078,color:#514532,stroke-width:1px
  class Input,Projection,Expected input
  class Snapshot,Ancestors,File,Backend,Material,Owner,Summary,Service operation
  class Reject blocked

Execution Trace

1. Render the Kubernetes broker origin before preparing TLS

scripts/render-repository-credentials-origin.ts:renderedBroker

The operator renders the Helm chart after selecting repositoryCredentials values and before issuing the broker certificate. The helper reads the rendered worker sidecar's --public-origin argument and returns that origin, hostname, Service name, release, namespace, and Backend ID. Certificate issuance uses that hostname as its DNS SAN, so the chart-rendered origin remains the input for TLS material, startup, and later Agent session material. The helper does not derive a second hostname policy; Helm validation owns the supported Service settings.

The chart escapes each literal dollar in the Backend ID for Kubernetes argument expansion. The origin helper removes that single escape layer when reporting the logical ID. Projected service configuration and registry values retain the original ID, which must match the broker process argument exactly. This keeps valid IDs such as github-$$ and github-$(BACKEND) literal without depending on the Pod environment.

Helm always renders an explicit worker Deployment strategy. Disabled installs use the Kubernetes default RollingUpdate values, maxSurge: "25%" and maxUnavailable: "25%". Broker-enabled installs render strategy.type: Recreate and omit rollingUpdate, allowing server-side apply to remove the previous RollingUpdate fields before Kubernetes validates the Recreate strategy. Older disabled releases that did not explicitly own the RollingUpdate fields must first refresh with the current disabled chart and no active Agent sessions, then opt in to repository credentials. Existing broker-enabled installs already use Recreate.

2. Snapshot Kubernetes inputs when selected

apps/controller/src/composition/repository-credentials/projected-inputs.ts:prepareProjectedInputs and apps/controller/src/composition/repository-credentials/protected-file.ts:readProtectedFile

Kubernetes startup reads config.json, TLS files and registry from the currently selected projected-volume generation. The projection layer fills an absent gateway.publicOrigin from the trusted --public-origin deployment argument. If operators provide gateway.publicOrigin, it must match that argument exactly. The same projection check verifies that the serving certificate covers the derived full Service FQDN before copying any projected input into the private runtime directory.

The protected loader requires a normalized absolute path and validates its directory ancestors in root-to-leaf order. Each accepted prefix therefore protects the next path component against replacement by another local user. Ancestors must be directories owned by root or the service user. Group/other writes fail except for a root-owned sticky ancestor above the immediate parent. The immediate parent remains unwritable by those users.

The loader opens the final basename without following symlinks. It checks the file owner, mode, link count, type, and size. It reads at most one byte beyond the checked file size. It then compares the open file with the named inode and its original metadata. Invalid or replaced files fail before their contents become configuration. The reader retains ownership of its candidate buffer until descriptor closure and transfer succeed. It clears scratch bytes and any candidate that cannot be transferred, including on a close failure. Success transfers an independent buffer to its caller; failure returns no filesystem details. Configuration maps that failure to invalid-configuration and clears successfully returned bytes.

3. Validate configuration and construct material owners

apps/controller/src/composition/repository-credentials/config.ts:loadConfiguration

Composition rejects github-app and github-app-registry before opening any App key. The fixed error tells operators to stop admissions and drain accepted work on its original owner before switching. The replacement process cannot continue an old owner's uncertain issuance or replay its PR creation.

Production native startup requires github-prepared-git-registry. Pure registry validation checks the Backend identity; the prepared factory requires one exact ref and an approved transport. Installation-wide access requires the protected Credential Proxy and fails native startup. Composition validates the private worker socket path and trusted upstream origins, then loads TLS. It constructs warm-registry-factory.ts:createPreparedGitHubRegistryFactory, which consumes READY material and has no App key or issuer capability. The worker Token Service retains issuance and cleanup ownership.

github-token is the explicit development alternative. It requires --development-authority, an eight-hour session cap, and the configured push input bound. The same protected reader loads its token; composition removes one trailing newline and constructs GitHubStaticTokenOwner. Failure clears owned buffers. The returned configuration owns its TLS and selected factory.

4. Close validation material or hand it to service startup

apps/controller/src/composition/repository-credentials/check-config.ts:checkConfiguration

The check returns the gateway origin, configured profiles, maximum session duration, authority and, for the token kind, its token class. Its finally block closes the material owner, and the CLI prints only the safe summary. It creates no session, listener, or provider request. The Kubernetes check similarly closes the loaded owner before reporting success; it also rejects a shutdown grace beyond the Pod's allowed service cleanup window. Normal startup instead passes the owner to apps/controller/src/composition/repository-credentials/service.ts:runService, which retains it until startup failure or process shutdown. The service flow owns that lifetime.

Debugging and Verification

Follow the build and configuration commands in the operator guide. Success prints JSON with valid: true; failure prints invalid-configuration. Inspect every ancestor when safe-looking files still fail validation. A shared writable deployment directory can permit substitution of an otherwise private configuration tree.

Run the configuration and emitted-package cases in the testing guide. They exercise generated TLS files and the actual loader. They establish startup validation, not live GitHub behavior or platform integration.

Search documentation