Bundle refresh
Adding or removing a client shouldn’t mean rebuilding infrastructure. Bundle refresh is the runtime counterpart of Add a client without redeploying: a running adapter picks up new signed trust material and signed policy without an image rebuild, upstream change, or adapter code change.
Keep the two paths separate
Section titled “Keep the two paths separate”flowchart LR
subgraph Deploy["Deployment path"]
D["adapter Deployment / Service / NetworkPolicy"]
end
subgraph Refresh["Bundle refresh path"]
R["signed trust + policy bundle objects"]
end
D -->|"owns runtime resources"| K["adapter"]
R -->|"owns trust/policy material + refresh signal"| K
The deployment path owns runtime resources. The refresh path owns bundle material and the refresh signal that makes the adapter read new mounted files. Keeping them separate avoids accidental infrastructure changes during a trust update.
What a refresh should do
Section titled “What a refresh should do”- Validate trust material and policy bundle shape.
- Verify signatures with the configured bundle-signing public key.
- Review the diff for route, issuer, key, source, freshness, and signer-class changes.
- Preserve unrelated issuer/key/source entries unless an explicit removal is intended.
- Update only the mounted bundle objects.
- Trigger an adapter refresh or rollout so the projected files are read again.
It should not change the adapter image, containers, volumes, replicas, Service, upstream, networking, broker configuration, or cloud infrastructure.
Add a client
Section titled “Add a client”trustplane bundle merge-source appends a client public key to trust material and a matching
source rule to the selected route:
trustplane bundle merge-source \ --trust-material trust-material.json \ --policy-bundle trustplane.bundle.json \ --out-trust-material trust-material.merged.json \ --out-policy-bundle trustplane.bundle.merged.json \ --source-type oidc_jwks \ --issuer https://issuer.example.com/external-jwks \ --trust-domain example.external \ --kid example-client-2 \ --public-key "$CLIENT_PUBLIC_KEY_B64URL" \ --route-id example.orders.read \ --subject-exact external:jwks:example-client-2 \ --required-key-binding softwareThen sign the merged outputs before using them with adapter signature enforcement:
trustplane bundle sign \ --trust-material trust-material.merged.json \ --out trust-material.merged.signed.json \ --signer-issuer local://bundle-signer \ --kid bundle-signing-key-1 \ --private-key "$BUNDLE_SIGNING_PRIVATE_KEY_B64URL"
trustplane bundle sign \ --policy-bundle trustplane.bundle.merged.json \ --out trustplane.bundle.merged.signed.json \ --signer-issuer local://bundle-signer \ --kid bundle-signing-key-1 \ --private-key "$BUNDLE_SIGNING_PRIVATE_KEY_B64URL"Remove or revoke a local source
Section titled “Remove or revoke a local source”trustplane bundle remove-source removes a trusted key and matching route source selector while
preserving unrelated trust material and route policy. Because removal is destructive, it requires
explicit confirmation:
trustplane bundle remove-source \ --trust-material trust-material.json \ --policy-bundle trustplane.bundle.json \ --out-trust-material trust-material.removed.json \ --out-policy-bundle trustplane.bundle.removed.json \ --issuer https://issuer.example.com/external-jwks \ --trust-domain example.external \ --kid example-client-2 \ --route-id example.orders.read \ --subject-exact external:jwks:example-client-2 \ --confirm-remove \ --revoke--revoke appends local revocation metadata for the removed key/source. Denial takes effect when
you refresh the adapter with the replacement signed bundle. This does not add a hosted revocation
workflow, database, approval system, or managed distribution service.
Verify the refresh
Section titled “Verify the refresh”| Step | Expected |
|---|---|
| Unknown client key before publish | deny |
| Publish reviewed, signed trust material and policy | new client accepted, no image rebuild |
| Signed business request after publish | allow |
| Duplicate replay | deny (jti_replay) |
| Tampered path | deny (request_binding_mismatch) |
| Wrong audience | deny |
| Wrong route | deny |
| Removed source after refresh | deny |
Mind freshness during refresh
Section titled “Mind freshness during refresh”realtimeroutes require a current bundle view and fail closed when the mounted file view is stale or unknown.boundedroutes allow a known bundle age up tomax_staleness_seconds, then fail closed.offline-okroutes explicitly allow stale/offline bundle use for lower-risk cases.
Next steps
Section titled “Next steps”- Example deployment — the full deployment flow this refresh path plugs into.
- Capability map — which example proves each capability.