(Renumbered from 0044 → 0046 to avoid collision with PR #996's ADR-0044 which claimed the slot first.)
Status: Accepted
Date: 2026-05-03 UTC
Deciders: software-architect
Scope: Secret store selection for the FreeScout API token used by Raptor's support portal endpoints
Design doc: docs/architecture/support-raxx-app.md
Refs: Epic #651 · ADR-0002 (no stored credentials)
Raptor's /api/v1/support/* endpoints proxy FreeScout using a FreeScout API token. This token is a server-side secret: it must never touch the browser bundle, CF Pages env vars accessible to client code, or any observable response. It must be rotatable without a code redeploy.
The constraint document asks us to choose between AWS SSM Parameter Store and Infisical and justify the decision. The project memory file feedback_aws_workloads_use_ssm_not_vault.md indicates SSM is preferred for AWS-hosted workloads. Raptor runs on Heroku, not AWS.
Use Infisical for the FreeScout API token and webhook secret.
The two secrets are:
- /raxx/prod/freescout-api-token → Heroku config var FREESCOUT_API_TOKEN
- /raxx/prod/freescout-support-webhook-secret → Heroku config var FREESCOUT_SUPPORT_WEBHOOK_SECRET
Both are surfaced to Raptor as Heroku config vars at dyno boot. Infisical's Heroku integration (or CI-driven Heroku config:set) syncs them. Rotation: update the value in Infisical, re-sync to Heroku config, Heroku restarts the dyno. No code redeploy required.
/raxx/prod/ is consistent with existing secrets (/raxx/prod/session-jwt-secret, etc.).feedback_vault_folder_must_exist.md, Infisical returns 404 if /raxx/prod/ does not exist as a folder. Operator must verify the path exists before the S1 sub-card sets the secret.feedback_heroku_config_set_echoes_secrets.md, any heroku config:set command must append >/dev/null 2>&1 to suppress stdout. This is a CI/deploy script concern, not a Raptor concern — documented in the S9 operational sub-card.feedback_aws_workloads_use_ssm_not_vault.md would apply and the secret path would change. Infisical can co-exist with SSM; this is not a locked-in decision.Rejected for Heroku-hosted Raptor. SSM requires either (a) AWS SDK in Raptor with an IAM user and access keys — adding two new secrets to manage a secret, or (b) a Lambda/ECS sidecar to sync SSM → Heroku env vars. Either path adds more complexity than Infisical's existing Heroku integration provides. The feedback_aws_workloads_use_ssm_not_vault.md preference applies to AWS-native workloads; Raptor is not one.
Rejected. A secret set only in Heroku config has no audit trail, no rotation automation, and no DPA-ready access log. Per platform invariant, secrets must be in a managed secret store with rotation and audit capability.
Rejected outright. The FreeScout API token in CF Pages env vars could be read by any CF Pages build step or — worse — accidentally bundled into the static output. The architecture invariant is absolute: the FreeScout API token is a server-side secret only. It lives in Raptor (Heroku), never in CF Pages.