Capture the org conventions rolled out in the INFRA-47 hygiene pass: - github-standards.md: static-only README badges (dynamic shields break on private repos; CI badge is member-only) and a lowercase-hyphenated repo topic vocabulary, both part of new-repo provisioning. - cicd.md: the central inline-config reusable PR labeler — pull_request trigger, the three required caller permissions, no per-repo labeler.yml.
3.8 KiB
CI/CD Pipelines
Requirement
Every deployable repo must have a CI/CD pipeline. No manual deploys to production. If it deploys to AWS, it needs a pipeline.
Platform
GitHub Actions is the standard CI/CD platform. All pipelines use reusable workflows from the Sea-Haven-Industries/.github org repo (.github/workflows/).
Workflow Structure
Every repo gets two thin workflow files in .github/workflows/:
| File | Trigger | Purpose |
|---|---|---|
ci.yaml |
pull_request on main |
Lint, typecheck, test, synth/validate |
deploy.yaml |
push on main |
Deploy to AWS |
CDK Stacks (TypeScript)
# .github/workflows/ci.yaml
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
uses: Sea-Haven-Industries/.github/.github/workflows/ci-typescript-cdk.yaml@main
with:
node-version: "24"
# .github/workflows/deploy.yaml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
uses: Sea-Haven-Industries/.github/.github/workflows/cd-cdk.yaml@main
with:
node-version: "24"
secrets:
deploy-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
SAM Stacks (Python)
# .github/workflows/ci.yaml
name: CI
on:
pull_request:
branches: [main]
jobs:
ci:
uses: Sea-Haven-Industries/.github/.github/workflows/ci-python-sam.yaml@main
# .github/workflows/deploy.yaml
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
uses: Sea-Haven-Industries/.github/.github/workflows/cd-sam.yaml@main
with:
stack-name: "your-stack-name"
secrets:
cfn-role-arn: ${{ secrets.AWS_DEPLOY_ROLE_ARN }}
Authentication
Deploy workflows authenticate to AWS via OIDC (no long-lived credentials). Each repo needs:
- An IAM role named
githubdeploy-<repo-name>with:- OIDC trust policy for
token.actions.githubusercontent.com - Subject condition:
repo:Sea-Haven-Industries/<repo>:ref:refs/heads/main - Inline policy allowing
sts:AssumeRoleon CDK/SAM bootstrap roles
- OIDC trust policy for
- A repo secret
AWS_DEPLOY_ROLE_ARNcontaining the role ARN
Node.js Version
Always pass node-version: "24" to reusable workflows. Local dev uses Node 24 / npm 11 which generates lockfileVersion 3. The workflow defaults match this, but be explicit to avoid drift.
Naming
- All workflow files: kebab-case
- Reusable workflow references:
@mainbranch
When to Add a Pipeline
- When creating a new deployable project — the pipeline is part of the initial setup, not a follow-up
- When working on an existing project that lacks one — flag it and add it as part of the current work
A project is not production-ready without CI/CD.
PR Auto-Labeling
Pull requests are auto-labeled org-wide by a reusable workflow in .github. The label rules live once, centrally, inside the reusable workflow itself (written to the runner at execution time), so each repo needs only a short caller and no per-repo labeler.yml:
# .github/workflows/labeler.yml — the per-repo caller
name: Labeler
on:
pull_request:
branches: [main]
permissions:
contents: read
pull-requests: write
issues: write
jobs:
label:
uses: Sea-Haven-Industries/.github/.github/workflows/callable-labeler.yaml@main
- The trigger is plain
pull_request, notpull_request_target: private repos take no fork PRs, so the lower-privilege event is sufficient and avoids the pwn-request surface. Becausepull_requestruns the workflow from the merge commit, the Labeler check appears on the PR that first adds the caller — an absent or failed check means a missing permission, not expected behaviour. - The caller MUST grant all three permissions. Reusable-workflow permissions can only be downgraded from the caller, so omitting
issues: write(needed to create labels that don't exist yet) or any other grant causes a silentstartup_failure. - Adding the caller is part of new-repo provisioning.