# 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) ```yaml # .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) ```yaml # .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: 1. An IAM role named `githubdeploy-` with: - OIDC trust policy for `token.actions.githubusercontent.com` - Subject condition: `repo:Sea-Haven-Industries/:ref:refs/heads/main` - Inline policy allowing `sts:AssumeRole` on CDK/SAM bootstrap roles 2. A repo secret `AWS_DEPLOY_ROLE_ARN` containing 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: `@main` branch ## 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`**: ```yaml # .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`, not `pull_request_target`: private repos take no fork PRs, so the lower-privilege event is sufficient and avoids the pwn-request surface. Because `pull_request` runs 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 silent `startup_failure`. - Adding the caller is part of new-repo provisioning.