insolvia-deploy
How Insolvia ships — and the rule that deploys happen in CI, never from your CLI. Use this whenever a task is about deploying, shipping, releasing, or "applying" infrastructure/services to staging or
Files1
View on GitHubSKILL.md.claude/skills/insolvia-deploy/SKILL.md
GitHubDeploying Insolvia
Deploys run in GitHub Actions, triggered by git — not from anyone's CLI. The only credential that touches staging/prod AWS is the CI OIDC deploy role.
The pipeline
One workflow, release.yml, owns the whole path to production:
- Merge to
main. The staging stage runs automatically: staging infra applies, then the changed services deploy (path-filtered against the last commit staging released green, so a leg an earlier run lost is retried), in dependency order. - Staging goes green → the run parks at the
promotejob, waiting on theinsolvia-productionenvironment's required reviewer. - Approve it in the GitHub UI (the run's page, "Review deployments" — one click, once). The production stage then ships the same commit: prod infra applies, then every service promotes.
So the deploy procedure is: open a PR, get it merged, approve the pending
release run when you want prod to have it. There is no script and no
dispatch in the normal path. Not approving is fine — each new green staging
run cancels older pending ones, so the offer is always the newest validated
commit, and an unapproved run ending cancelled is normal, not a failure.
| Target | Trigger |
|---|---|
| staging (infra + api, admin, mcp, filing, marketing, app) | automatic on merge to main — the staging stage of release.yml |
| prod (infra + all services) | approving the promote gate of a green release.yml run |
| shared infra + the mailer | not from this repo — they release from insolvia-services' own release.yml. A new service's ECR repository is added and released there before the PR here that deploys it, because the env root's data "aws_ecr_repository" hard-fails until it exists |
| one prod service, out of band | dispatch its *-prod.yml (emergency path: staging-green check + its own approval) |
| prod infra, out of band | dispatch infra-prod.yml — mode: plan (default, read-only → job summary) or mode: apply |
What the production stage actually does
It promotes, it does not rebuild — and it promotes everything at the approved commit, not just what that push changed. You can merge five PRs and approve only the fifth run; nothing is left behind. Details worth knowing before you debug one:
- The container repositories are shared across environments, so the image
staging validated is already in the repository prod pulls from; each leg
resolves the commit's
sha-<commit>tag to an immutable digest and deploys that. Therecordjob guarantees the tag exists for every service at every staging-green commit (unchanged services get the digest staging is currently serving). The app is the one exception and rebuilds from the verified commit, because it bakes its environment in at build time. - Prod infra applies as the first leg of the approved release — same
shape as staging, behind the approval.
infra-prod.ymlstays dispatchable for a read-only plan or an out-of-band apply. - A hand-dispatched prod deploy refuses a commit staging never validated.
That is
.github/actions/verified-commitreading theinsolvia/staging-releasecommit status therecordjob stamps; the fix is normally "let staging release it first", notforce: true.
Rolling back the API or marketing does not need the pipeline at all — they
serve through a live Lambda alias, so
aws lambda update-alias --function-name <fn> --name live --function-version <previous>
reverts in seconds. That is a read of the alias plus one write; it is the one
production mutation that is faster by hand than through CI, and the job summary
of every deploy prints the exact command with the previous version filled in.
For a full re-promotion of an older commit, re-run its (green) release.yml
run and approve the gate again, or dispatch the individual *-prod.yml
workflows with sha=<commit>.
The rule
Do not deploy or apply against staging or prod from the CLI. Specifically, never run against staging/prod:
terraform applyininfra/envs/stagingorinfra/envs/proddocker pushto a service ECR repo, oraws lambda update-function-codeaws s3 syncof client assets or a CloudFront invalidation for a live env
If you want to see a prod plan, that is infra-prod.yml with mode: plan
(the only way to plan against real prod state — shared-infra-plan.yml validates
offline with no credentials).
The only local applies that are legitimate
- Your own per-machine dev env —
scripts/dev-aws-*againstinfra/envs/dev(that's your dev database; see theinsolvia-scriptsskill). - The
ci-trustanchor — insolvia-services'scripts/apply-ci-trust.sh, run from that checkout, human-gated because CI cannot apply its own permissions (seeinsolvia-deploy-role-permissions).
Everything else is a merge, an approval, or a dispatch — never a hand-run apply.