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

# Chapter 11: Credential Isolation

> Credential isolation is the guarantee that a connector, the code that actually calls an

## What it is

Credential isolation is the guarantee that a connector, the code that actually calls an
external service like HubSpot, GitHub, or Paytm, never holds a long-lived, reusable
credential. Instead it receives a single-use, time-bounded session credential, minted fresh
for one specific execution, resolved to the real secret only at the last possible moment, and
destroyed immediately after use, whether that use succeeded or failed.

## Why it was built

A connector is the part of this system closest to the outside world, and therefore the part
most exposed to a bug, a dependency vulnerability, or a compromised third-party API response.
If a connector held the platform's real HubSpot API key or GitHub App private key directly, a
single flaw in connector code could leak that credential, and the leak would be reusable by
whoever obtained it, for as long as the credential remained valid. Credential isolation
removes that exposure at the architecture level: even a fully compromised connector can only
ever hand an attacker a credential that is already spent, or one that is about to expire in
seconds and is bound to an authorization that has already been consumed.

## How it works

The mechanism lives in `packages/execution-control/src/`, specifically two classes:

**`SessionCredentialVault`** (`SessionCredentialVault.ts:18-25`) exposes three operations:
`issue()`, `consume()`, and `revoke()`. Its in-memory implementation,
`InMemorySessionCredentialVault`, wraps an underlying `CredentialVault` (the thing that
actually holds the real, long-lived secret) and never itself stores the secret value. The
class's own doc comment states this precisely: "issue() only confirms the underlying
credential exists, it never resolves or stores the secret" (`SessionCredentialVault.ts:44-46`).

* `issue(connectorId, authorizationId)` calls `credentials.getCredential(connectorId)` once,
  purely to confirm a credential exists for that connector, then discards the resolved value
  immediately. It returns a `SessionCredential` object (`SessionCredentialVault.ts:10-16`)
  containing only an id, timestamps, and the connector/authorization it's scoped to, never the
  secret itself.
* `consume(sessionCredentialId)` is the only method that ever calls back into the underlying
  vault for the real value, and it does so fresh, at the moment of use. Before it does, it
  checks the session record for three failure conditions, each throwing if true: already
  revoked, already used, or expired (`SessionCredentialVault.ts:97-111`). It then marks the
  session `used = true` and returns the real credential exactly once. A second call to
  `consume()` on the same session id always throws.
* `revoke(sessionCredentialId)` marks a session dead, unconditionally.

**`SessionCredentialSecureConnector`** (`SessionCredentialSecureConnector.ts`) is what actually
wraps a real connector's `execute()` call with this lifecycle. Its own `execute()` method
(`SessionCredentialSecureConnector.ts:74-131`) does exactly this, in order:

1. Asserts the connector's policy allows this specific request (`policy.assertAllowed(...)`).
2. Calls `sessionCredentials.issue(...)`, obtaining a session credential id.
3. Inside a `try`/`finally`: calls `sessionCredentials.consume(...)` to resolve the real
   credential just before use, passes it straight into the wrapped executor's `execute()`
   call, and in the `finally` block, unconditionally calls `sessionCredentials.revoke(...)` ,
   this runs whether the executor succeeded, threw, or the policy check itself threw after
   issuance.
4. Records exactly one audit event, `execution.completed` or `execution.rejected`, naming the
   connector, the session credential's id (never its value), the authorization it executed
   under, and the capability invoked. The credential's id is auditable; the credential's value
   never appears anywhere in the audit trail.

Because `consume()` throws on a second call, and `revoke()` runs unconditionally on every exit
path via `finally`, a session credential can be used at most once, ever, no matter how the
execution ends.

One subtlety worth being precise about, from the class's own doc comment
(`SessionCredentialSecureConnector.ts:20-32`): this connector is also constructed with a
`gatewayAuthentication` value proving it was configured with material signed by the Gateway's
key at registration time. That value is frozen once, at construction, and reused for every
execution this connector instance will ever handle, it is not, and cannot be, a
per-request proof by itself. The actual per-request replay protection comes from a different
layer, `ConnectorPolicy`'s single-use `GatewaySession` check, enforced one level up, before a
`GatewaySession` is even created. The two guarantees (registration-time authenticity, and
per-request single-use) are deliberately separate mechanisms, not the same check reused twice.

## How it enables things, with a concrete example

`packages/api/tests/integration/credential-isolation.integration.test.ts` proves this
guarantee at the HTTP boundary, not just at the library level. Its own doc comment
(`credential-isolation.integration.test.ts:10-19`) explains the split precisely:
`packages/execution-control/tests/unit/session-credential-secure-connector.test.ts` already
proves "a session credential is issued and destroyed exactly once per execution" by calling
`SessionCredentialSecureConnector.execute()` directly; this integration test proves the exact
same guarantee holds through a real `POST /execute` HTTP request against the real Express app,
through the real `ExecutionGateway` / `SessionCredentialExecutionControl` /
`ExecutionControlService` / `SessionCredentialSecureConnector` chain. It builds its own
"inspectable" execution system (`packages/api/tests/bootstrap/createInspectableExecutionSystem.ts`)
specifically to get a direct reference to the audit sink and the session credential vault,
which the production bootstrap chain does not expose by design. The test asserts that after a
successful `/execute` call, exactly one `execution.completed` audit event carries a
`credentialId`, confirming a session credential really was issued and consumed, not skipped.

`packages/api/tests/integration/execution-failure.integration.test.ts` is the companion case:
it proves the same revoke-on-every-exit-path guarantee when the underlying connector executor
throws, not just on the success path.

## How to validate this yourself

* `packages/execution-control/src/SessionCredentialVault.ts` and
  `SessionCredentialSecureConnector.ts`, the actual mechanism.
* `packages/execution-control/src/types.ts`, `CredentialVault`, `ExecutionCredential`,
  `SecureConnector`, `ConnectorPolicy` interface shapes.
* `packages/execution-control/tests/unit/session-credential-vault.test.ts`,
  `session-credential-secure-connector.test.ts`, `session-credential-execution-control.test.ts`
  , the library-level proofs, one per class.
* `packages/api/tests/integration/credential-isolation.integration.test.ts` and
  `execution-failure.integration.test.ts`, the HTTP-boundary proofs.
* `packages/api/tests/bootstrap/createInspectableExecutionSystem.ts`, how a test gets a
  direct handle on the audit sink and vault that production code never exposes.

## Integration requirements

None from an operator's perspective, this is an internal architectural guarantee, not a
configurable feature. A new connector wired into this system automatically gets session
credential isolation by virtue of being registered behind `SessionCredentialSecureConnector`;
there is no opt-out path documented in the source, and none should be added without a strong,
explicit reason.
