Build and deployment
Branches and stacks
| Branch | Stack | Account |
|---|---|---|
|
|
staging, 605668041275 |
|
|
production, 625663093496 |
A push to either branch deploys its stack. Pull requests to them run CI only. Changes to
new-rules-P312 go through reviewed pull requests.
Build
sam build uses BuildMethod: makefile: for each function it calls the Makefile target
build-<LogicalId> with ARTIFACTS_DIR set. build-ApiFunction and build-WorkerFunction run the same
recipe:
-
Export the runtime dependencies from
uv.lock(uv export --frozen --no-dev). -
Install them into the artifact for
x86_64-manylinux2014and Python 3.12 (uv pip install --python-platform … --target), so a build on macOS still produces Linux wheels. -
Fail if a macOS binary (
darwin.so,*.dylib) ended up in the artifact. -
Copy
src/into the artifact, so handlers arehandlers.<module>.lambda_handler.
samconfig.toml builds in source (build_in_source = true), cached and in parallel. Each artifact is about
51 MB unzipped.
Deploy
make deploy ENV=dev|prod runs sam build and sam deploy --config-env <env>. The same command runs in CI
and, for emergencies, from a laptop:
make deploy ENV=dev AWS_PROFILE=dev
GitHub Actions
flowchart LR
PR["Pull request to develop_new_rules or new-rules-P312"] --> CI
PUSHDEV["Push to develop_new_rules"] --> DEPLOY["deploy.yml"]
PUSHPROD["Merge to new-rules-P312"] --> DEPLOY
DEPLOY --> CI["ci.yml: lock check, lint, typecheck, check-names, test-cov, sam-validate"]
CI -->|develop_new_rules| DEV["_deploy.yml env=dev"]
CI -->|new-rules-P312| PROD["_deploy.yml env=prod"]
DEV --> DEVSTACK[("eventlogger-rules-dev")]
PROD --> PRODSTACK[("eventlogger-rules-prod")]
| File | Role |
|---|---|
|
Runs on pull requests, on demand and as a reusable workflow: |
|
Runs on pushes to the two branches and on demand: calls CI, then |
|
Reusable deploy job: checks the AWS account ID, runs |
|
Shared setup: Python from |
Deploy jobs run in the GitHub environment of the same name. concurrency: deploy-<env> allows one deploy per
environment at a time and never cancels a running one. All actions are pinned by commit SHA and workflows
only get contents: read.
Secrets
| Secret | Use |
|---|---|
|
Read access to |
|
Deploys to 605668041275 |
|
Deploys to 625663093496 |
These are organisation secrets. The deploy keys need to create and update CloudFormation stacks, IAM roles
(CAPABILITY_IAM), Lambda functions and event source mappings, API Gateway, EventBridge rules, SNS
subscriptions and the SAM managed S3 bucket. They also need lambda:AddPermission and
lambda:RemovePermission on pyb-api-gateway-authorizer:live, because the stack grants RulesApi the right
to invoke that shared authorizer.
Follow-up: OIDC deploy roles
The deploy job still uses long-lived organisation access keys. Replace them with short-lived credentials from GitHub’s OIDC provider:
-
In each account, create the IAM OIDC provider
token.actions.githubusercontent.comwith audiencests.amazonaws.com, if it doesn’t exist yet. -
Create a deploy role per account, for example
github-eventlogger-rules-deploy, that trusts only this repository’s environment. Because the deploy job declaresenvironment:, the token’ssubclaim is environment-based:{ "Effect": "Allow", "Principal": {"Federated": "arn:aws:iam::625663093496:oidc-provider/token.actions.githubusercontent.com"}, "Action": "sts:AssumeRoleWithWebIdentity", "Condition": { "StringEquals": { "token.actions.githubusercontent.com:aud": "sts.amazonaws.com", "token.actions.githubusercontent.com:sub": "repo:Payability/EventLoggerApp:environment:prod" } } }Use
environment:devand the 605668041275 provider for the dev role. Limit its permissions to theeventlogger-rules-*stacks, their roles and functions,RulesApiand the SAM managed bucket. -
In
_deploy.yml, addpermissions: id-token: writeto the deploy job and replace the access key inputs ofconfigure-aws-credentialswithrole-to-assume: arn:aws:iam::<account>:role/github-eventlogger-rules-deploy. -
Remove the
AWS_*secrets fromdeploy.ymland_deploy.yml.
Legacy CodeBuild project
The production account still has the CodeBuild project EventLoggerApp from the Zappa era. Its webhook
builds every push with the pushed commit’s buildspec.yml, which the new branches don’t have. Exclude them
before the first push: see the cutover runbook.