Integrations
Settings, then Integrations is where the five external-service credentials live. None of them is required to boot. Each gates one optional feature, and the platform degrades cleanly when one is absent rather than failing.
Evidence object storage is not one of them. It is configured per organisation rather than once
for the whole platform, so the table behind this screen — which is keyed by credential name alone
and global to the process — cannot express it. Its credentials live in their own table and are
managed through the /api/organizations/{org_id}/evidence-storage endpoints. An organisation
administrator configures it on their own Settings, then Evidence storage card — see
Evidence Storage Settings.
The screen is open to platform administrators only.
What each credential unlocks
Section titled “What each credential unlocks”| Credential | What it enables |
|---|---|
| Resend API key | Transactional email: invitations, notifications |
| Anthropic API key | AI document generation and evidence assessment |
| OIDC client secret | Single sign-on with an external identity provider |
| Have I Been Pwned API key | Vendor breach research |
| NVD API key | A higher NVD rate limit for vendor CVE research |
Each row shows whether the item is configured, what the feature does, and where the value came from. The setup-health panel lists configured against unconfigured items and what each unlocks, which is also the configuration-baseline artifact an assessor tends to ask for.
Write-only, always
Section titled “Write-only, always”A stored value is never rendered back — not in the UI, not in any API response, not in an error body. Configured rows show a masked placeholder and a Replace action. There is no reveal.
Values are encrypted with SCF_SECRET_KEY before they reach the database, so a pg_dump taken
without the secrets directory yields nothing usable. That matters because the dump is the artifact
that leaves the building: the database itself is loopback-only and its volume sits on an encrypted
disk, but neither protects a backup in transit.
If SCF_SECRET_KEY is not configured, the screen shows a banner explaining it and in-app writes are
refused with a 409. Values already supplied through a file or the environment keep working
regardless — they are not encrypted by the platform because the platform never stored them.
Operator-managed against in-app
Section titled “Operator-managed against in-app”The resolution order for a tier-3 credential is database, then file, then environment. A value you set in the app lands in the database and wins.
When the same credential is already supplied as a file in the secrets directory or as an
environment variable, the row is marked Managed by operator and Replace is disabled. An API
write against such a row is refused with a 409. This is deliberate: silently shadowing a value
the operator manages in Vault or a systemd unit would make the running configuration disagree with
the deployment that describes it.
To move such a credential into the app, remove it from the file or the environment first, restart, then set it in the UI.
Audit trail
Section titled “Audit trail”Every set, replace and clear is written to the platform audit log with the actor and a timestamp,
and the recent entries appear on the Integrations screen itself. The audit table has no value
column — by construction it cannot leak a credential. The actor is the user’s email address, or
api_key:master when the request authenticated with the master API key.
From the command line
Section titled “From the command line”docker compose exec backend python -m cli.admin secrets-statusPrints the same health view. It never prints a value.
