> ## Documentation Index
> Fetch the complete documentation index at: https://docs.commons.diy/llms.txt
> Use this file to discover all available pages before exploring further.

# CREDENTIAL INTEGRATION PLAN

# Native credential execution in Spaces

Status: implementation and rollout runbook, September 8, 2026. The roles,
access, and activity improvements shipped in PR #367. The operator has approved
one Spaces deployment with Infisical remaining the secret store. Production
cutover is explicit; existing external deployments retain compatibility until
`CREDENTIAL_EXECUTION_MODE=native` is enabled.

## Target

```text theme={null}
Human session / agent Commons identity
                 |
                 v
Spaces server: roles, assignments, connection policy, approvals
                 |
                 v
Internal executor: validate request, check live authority, consume once
                 |
                 +----> Infisical: retrieve the exact permitted secret
                 |
                 +----> Approved provider: inject credential for this call
                 |
                 v
Spaces database: redacted execution history and replay protection
```

The operator runs the existing Spaces service and database. Infisical stores
and versions secrets. Agents continue using Commons APIs/MCP, receiving bounded
provider responses rather than secret values. Credential pages and activity
remain in Spaces. No standalone gateway, Infisical proxy container, or gateway
audit database is required in the final deployment.

## Reuse and changes

| Area                  | Retain                                                                                        | Change                                                                                  |
| --------------------- | --------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
| Identity and access   | Human sessions, per-Space roles, agent assignments and grants, last-Owner guard               | Keep the existing authority functions as the single policy source                       |
| Credential storage    | Infisical paths, IDs, values, rotation history; existing write adapter                        | Add a narrowly scoped read adapter for internal execution                               |
| Execution             | Destination/method/path/header limits, DNS/SSRF checks, response/time limits, live revocation | Extract gateway core from its HTTP server; call it inside Spaces                        |
| Tickets and approvals | Request binding, expiry, atomic one-use consumption, exact approval fingerprints              | Store consumption with Spaces persistence; retain compatibility routes during migration |
| Activity              | Agent/task/run attribution, redaction, filtered history                                       | Write directly to Spaces tables and remove the audit-reader HTTP hop                    |
| Operations            | Readiness and synthetic conformance checks                                                    | One service readiness surface, one release, fewer inter-service keys and URLs           |

Implementation: `packages/credential-gateway/src/core.ts` is a transport-free
library shared by both modes. `packages/api/src/credential-execution.ts` binds
it to live Spaces authorization, exact database credential references, the
Infisical reader, and the existing Spaces database. No gateway process is
started in native mode. The writer remains in `infisical-writer.ts`.

Infisical supports a machine identity exchanging its client credentials for a
short-lived API token, then retrieving an individual secret by name. Reuse the
deployment's configured Infisical region/domain; don't hardcode a new region.
See [Universal Auth](https://infisical.com/docs/documentation/platform/identities/universal-auth)
and [secret retrieval](https://infisical.com/docs/api-reference/endpoints/secrets/read).

## Security tradeoff

The legacy gateway uses a proxy identity without value-read permission; the
separate Infisical proxy handles injection. Removing both processes means the
Spaces executor will hold retrieved values transiently. Infisical still handles
storage, but compromise of the Spaces process can then reach the configured
read scope. An internal module is not a process isolation boundary.

Use a separate runtime read identity limited to the required environment and
paths; retain the write identity's existing scope. Do not grant broad vault
read/list/admin rights. The operator approved this tradeoff on September 8, 2026. Reuse the scoped
proxy reader identity during cutover; keep reader and writer identities separate. Never return values through metadata/reveal APIs, place them in agent
environments, persist them in Spaces, or log request headers/bodies. Drop secret
references promptly; JavaScript cannot guarantee memory zeroization.

Keep outbound requests bounded and redirects disabled. Authentication injection
must happen only after server-derived destination and live access checks. Block
request overrides of destination, secret reference, and protected headers. Guard
provider responses against credential reflection and keep error messages
allowlisted. Vault and authorization outages fail closed. Do not retry an
ambiguous provider mutation automatically.

## Configuration

Native execution is the default on a fresh host. A pre-existing
`CREDENTIAL_GATEWAY_URL` preserves external mode until the operator explicitly
sets `CREDENTIAL_EXECUTION_MODE=native`. Unknown modes fail closed.

Configure the Spaces API environment:

* `CREDENTIAL_EXECUTION_SIGNING_KEY`: a new random signing secret, at least 32
  characters. Use a different key from the retired gateway so old tickets
  cannot cross into the new replay store.
* `COMMONS_CREDENTIAL_DESTINATIONS_JSON`: the existing destination allowlist
  (HTTPS origins, methods, path prefixes, allowed caller/response headers,
  timeout, and response size). Provider authentication headers must not be
  allowed as caller headers.
* `COMMONS_CREDENTIAL_BINDINGS_JSON`: exact Space/connection/destination bindings
  to credential IDs already in Spaces. Header names are lowercase; the prefix
  is literal, including any trailing space. For example:

```json theme={null}
[
  {
    "space": "team-science",
    "connectionId": "team-science-publisher",
    "destinationId": "railway-team-science",
    "credentials": [
      { "credentialId": "railway-deploy", "header": "project-access-token", "prefix": "" }
    ]
  }
]
```

* `INFISICAL_READER_CLIENT_ID` / `INFISICAL_READER_CLIENT_SECRET`: the dedicated
  runtime reader identity, limited to the referenced environment and paths.
* Existing `INFISICAL_DOMAIN`, `INFISICAL_PROJECT_ID`, `INFISICAL_ENVIRONMENT`,
  writer identity, connection policies, and credential definitions remain.

Bindings select database credential IDs. Callers cannot submit vault paths,
secret names, injection headers, or a different destination. Every credential
on a connection must be active and bound; rotation reads its current value for
the next call. Secret imports and reference expansion are disabled.

`POST /v0/spaces/:space/credential-calls` and MCP `call_external_service` retain
their contracts. Low-level ticket clients use the returned `gateway_url`,
which now points to `POST /v0/credential-execution/call` on the Spaces host.
The legacy field name is retained for client compatibility. Tickets are bound
to the complete request and consumed atomically before external execution.
There is no automatic retry or fallback between execution modes.

Readiness is included in `/healthz` as `credentials: {mode, configured, ready}`.
A configured native executor with invalid configuration or unavailable
persistence makes readiness fail. An unconfigured fresh host can still run
Spaces. Readiness does not fetch vault values; each execution fails closed on
vault or authorization failure. The credential page derives its **Spaces
service on Railway** link from Railway's own service environment metadata.

## History and cutover

`credential_execution_events` and `credential_execution_ticket_uses` live in
the existing Spaces database. Execution events omit request paths, headers,
bodies, secret values, and provider-controlled request IDs. History imports
retain the old sanitized records, timestamps, source sequence and digest.
The authorized UI projection omits sensitive internals in either mode and
sorts by occurrence time, so importing older records does not hide new calls.

1. Deploy this code in existing external mode. Build the API, then run the
   operator-only migration command inside the Spaces deployment with its
   `DATABASE_URL`, old `CREDENTIAL_GATEWAY_URL` and read-only
   `CREDENTIAL_GATEWAY_AUDIT_READER_KEY`:

   ```sh theme={null}
   CREDENTIAL_HISTORY_SOURCE=railway-gateway-0ef2a619 node packages/api/dist/migrate-credential-history.js
   ```

   The importer validates ordered pages, runs each page transactionally, and
   deduplicates by `(source, source_sequence)`. A changed digest for an existing
   source sequence fails the import. It prints counts only and is safe to retry.
2. Set the native variables, preserving all existing connection allowlists,
   credentials and grants, then redeploy Spaces. Verify native readiness,
   allowed read-only fixture calls, request substitution denial and replay
   rejection. Verify per-Space and per-agent history remains available.
3. Drain legacy tickets for their configured maximum TTL plus request timeout.
   Run the history import again and verify a repeated import adds zero rows.
   Compare source counts and original timestamps before retiring the source.
4. Remove the gateway and proxy deployments and stop the old audit database
   runtime. Preserve the old database volume for rollback/retention. Remove
   obsolete `CREDENTIAL_GATEWAY_*` variables from Spaces and redeploy with only
   the native configuration.

Rollback before retirement may explicitly restore external mode and its old
configuration. Do not reuse signing keys across the two stores or reissue an
ambiguous provider write. After retirement, recover the old database/runtime
before selecting external mode. Infisical values and versions are unchanged.

## Verification

Tests cover native API issuance/execution, concurrent replay, exact approvals,
live grant/membership/task/credential checks, cross-Space isolation, exact
Infisical path/name retrieval, vault failure, protected headers, DNS/SSRF,
redirect refusal, compressed response limits, total timeout, secret reflection,
durable activity and idempotent history import. The same core also runs the
standalone gateway suite. Local-calendar timestamps cover Today, Yesterday,
weekday/month/day, relative age, year boundaries and daylight-saving changes.
