> Archived: historical audit/plan/report material. Use `docs/current-source-of-truth.md` for the active architecture baseline and `docs/archive/README.md` for archive guidance.

# Channel Secret Hardening and Disable Policy

Date: 2026-03-02

## 1. Goal

Reduce channel security risk by:

1. Removing plaintext channel secrets from setup persistence.
2. Applying a capability + secret policy gate before channel registration.
3. Disabling risky channel instances instead of allowing partial startup with unsafe config.

## 2. What Changed

1. `POST /v1/setup/channels` no longer stores plaintext secrets in `friday_setup_state.channels_json`.
2. Secret fields are encrypted into `secrets` table (`scope = "channel"`), and channel config stores `secret://channel/<refKey>`.
3. Hub startup resolves channel secrets from:
   - `$ENV_VAR` references
   - `secret://channel/...` references
4. In default `strict` mode, plaintext secret values are blocked and that channel instance is disabled.

## 3. Secret Reference Format

1. Channel secret scope: `channel`
2. Persisted reference format: `secret://channel/<url-encoded-refKey>`
3. Ref key format generated by setup route: `channel:<kind>:<slot>:<field>`

## 4. Channel Secret Policy

Environment variable: `FRIDAY_CHANNEL_SECRET_POLICY`

1. `strict` (default):
   - Plaintext secret values are rejected at runtime for channel registration.
   - Missing env refs or missing secret refs disable the channel instance.
2. `compat`:
   - Plaintext values are accepted with warning logs.
   - Missing required secret values still disable the channel instance.

## 5. Capability Matrix Baseline

Defined in code at `src/channels/friday-channel-security.ts` as `FRIDAY_CHANNEL_CAPABILITY_MATRIX`.

Current policy gate requires:

1. `supportsInbound = true`
2. `supportsOutbound = true`

If either is false (or missing profile), channel registration is disabled by policy.

## 6. Dynamic Secret Requirements

Also defined in `src/channels/friday-channel-security.ts` via `getFridayChannelSecretFieldDescriptors(...)`.

Examples:

1. `discord`: `token` required.
2. `slack`:
   - always `botToken` required;
   - `mode=http` requires `signingSecret`.
3. `whatsapp`:
   - `provider=cloud-api` requires `accessToken`.
4. `line`: `channelAccessToken` + `channelSecret` required.

## 7. Verification Coverage

1. Unit: `test/unit/channels/friday-channel-security.test.ts`
2. Hub integration: `test/integration/hub/friday-hub-bootstrap-integration.test.ts`
3. Setup E2E persistence: `test/e2e/setup-wizard.e2e.test.ts` (A8)
