Skip to content

Migrate CI/CD from CodePipeline to GitHub Actions#193

Open
layertwo wants to merge 1 commit intomainlinefrom
migrate-to-github-actions
Open

Migrate CI/CD from CodePipeline to GitHub Actions#193
layertwo wants to merge 1 commit intomainlinefrom
migrate-to-github-actions

Conversation

@layertwo
Copy link
Owner

Summary

  • Replace AWS CDK Pipelines (CodePipeline V2) with a GitHub Actions deploy workflow
  • Rewrite lib/app.ts to instantiate stacks directly with explicit stackName properties matching existing CloudFormation stack names (Beta-ServiceStack, Beta-MonitoringStack, Prod-ServiceStack, Prod-MonitoringStack) for zero-diff takeover
  • Switch Smithy CLI download from aarch64 to x86_64 for GitHub Actions runners
  • Three-job workflow: build (Smithy + CDK synth) → deploy beta → deploy prod (with environment approval gate)
  • Concurrency group queues deployments instead of cancelling in-flight ones

Pre-merge checklist

  • IAM role for GitHub Actions OIDC created and ARN stored as CDK_DEPLOY_ROLE_ARN secret
  • GitHub environments beta and prod created (prod with required reviewers)
  • Run cdk diff against all 4 stacks to verify zero resource changes
  • Disable CodePipeline source stage transition before merging

Post-merge

  • Verify GitHub Actions build + beta + prod deploy succeeds
  • Delete the Pipeline CloudFormation stack
  • Delete lib/stacks/pipeline.ts

Test plan

  • npm run build compiles cleanly
  • cdk list outputs the 4 expected stack names
  • cdk diff shows zero changes for all deployed stacks
  • GitHub Actions workflow triggers on push to mainline
  • Beta stacks deploy and reach UPDATE_COMPLETE
  • Prod approval gate works, prod stacks deploy successfully

Replace AWS CDK Pipelines (CodePipeline V2) with a GitHub Actions
workflow for building and deploying. Stacks are now instantiated
directly in app.ts with explicit stackName properties matching the
existing CloudFormation stack names, enabling zero-diff takeover.

- Rewrite lib/app.ts to instantiate ServiceStack and MonitoringStack
  directly for Beta and Prod stages
- Change Smithy CLI download URL from aarch64 to x86_64 for GitHub
  Actions runners
- Add .github/workflows/deploy.yml with build → beta → prod pipeline,
  concurrency queuing, and workflow_dispatch stage selector
@claude
Copy link

claude bot commented Feb 12, 2026

Claude finished @layertwo's task in 2m 12s —— View job


Code Review Complete

I've completed a comprehensive security and quality review of this PR that migrates from AWS CodePipeline to GitHub Actions.


Review Checklist

Core Quality

  • Code follows conventions - TypeScript/YAML structure is clean
  • No commented-out code - Clean migration
  • Proper error handling - CDK will handle deployment errors
  • DRY principle applied - Good use of loop for stages

Security

  • No hardcoded secrets - Uses GitHub secrets correctly
  • Input validation - Limited user inputs, workflow_dispatch is validated
  • Command injection - No dynamic command construction
  • Secure error handling - CDK provides safe error output

OWASP Top 10

  • SQL Injection - Not applicable (infrastructure code)
  • XSS - Not applicable
  • Broken Authentication - OIDC properly configured
  • Sensitive Data Exposure - Secrets properly managed
  • XXE - Not applicable
  • Broken Access Control - AWS IAM role controls access
  • Security Misconfiguration - Some concerns (see findings)
  • CSRF - Not applicable
  • Known Vulnerabilities - Using latest action versions
  • Logging & Monitoring - CDK provides deployment logs

Documentation

  • README/AGENTS.md - Not required for this change
  • Complex logic commented - Could use improvement (see findings)

Issues Summary

MEDIUM Severity (2 issues)

  1. Unverified External Download (.github/workflows/deploy.yml:40)

    • Smithy CLI downloaded without checksum verification
    • Risk: Potential supply chain attack vector
    • Fix: Add SHA256 verification after download
  2. Broken Deployment Logic (.github/workflows/deploy.yml:104)

    • workflow_dispatch with stage: prod will fail
    • Issue: deploy-prod requires deploy-beta but beta will be skipped
    • Fix: Remove deploy-beta from needs or adjust conditions

LOW Severity (4 issues)

  1. No Rollback Strategy (.github/workflows/deploy.yml:94)

    • Deployments use --require-approval never without rollback
    • Recommendation: Add --progress events flag for visibility
  2. Unused Export (lib/config.ts:14)

    • SMITHY_DOWNLOAD_URL defined but not used
    • Recommendation: Remove or use in workflow
  3. Missing Documentation (lib/app.ts:18)

    • Redundant stackName property needs explanation
    • Recommendation: Add comment about migration intent
  4. Artifact Retention (.github/workflows/deploy.yml:56)

    • No retention policy for build artifacts
    • Recommendation: Set retention-days: 1
  5. Concurrency Visibility (.github/workflows/deploy.yml:17)

    • No timeout or visibility for queued deployments
    • Recommendation: Add timeout-minutes at job level

Security Rating: ✅ ACCEPTABLE

No critical or high-severity security issues found. The MEDIUM issues are related to operational safety rather than direct security vulnerabilities. The migration follows GitHub Actions security best practices with OIDC authentication and proper secret management.

Recommendation

This PR is approved for merge after addressing:

  1. MUST FIX: Deployment logic issue (workflow_dispatch prod deployment)
  2. SHOULD FIX: Add checksum verification for Smithy CLI download
  3. NICE TO HAVE: Other LOW severity improvements

The architecture change from CodePipeline to GitHub Actions is sound and follows infrastructure-as-code best practices.



- name: Install Smithy CLI
run: |
curl -L https://github.com/smithy-lang/smithy/releases/download/1.67.0/smithy-cli-linux-x86_64.zip -o smithy-cli.zip
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM - Security: Unverified External Download

The Smithy CLI is downloaded from GitHub without checksum verification. An attacker could potentially serve a malicious binary if the GitHub release is compromised or through a MITM attack.

Recommendation: Add SHA256 checksum verification after download:

- name: Install Smithy CLI
  run: |
    curl -L https://github.com/smithy-lang/smithy/releases/download/1.67.0/smithy-cli-linux-x86_64.zip -o smithy-cli.zip
    echo "EXPECTED_SHA256_HERE  smithy-cli.zip" | sha256sum -c -
    unzip -qo smithy-cli.zip -d smithy-install
    sudo smithy-install/smithy-cli-linux-x86_64/install

You can obtain the checksum from the GitHub release page or by running sha256sum on a trusted download.

aws-region: ${{ env.AWS_REGION }}

- name: Deploy Beta-ServiceStack
run: npx cdk deploy Beta-ServiceStack --app build/cdk.out --require-approval never
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW - Deployment Safety: No Rollback Strategy

The deployment steps use --require-approval never which bypasses CDK's safety checks. If a deployment fails midway, there's no automated rollback mechanism.

Recommendation: Consider:

  1. Adding --rollback flag support (available in newer CDK versions)
  2. Adding a post-deployment verification step
  3. Using --progress events for better visibility into deployment progress

Example:

- name: Deploy Beta-ServiceStack
  run: npx cdk deploy Beta-ServiceStack --app build/cdk.out --require-approval never --progress events

github.event_name == 'push' ||
github.event.inputs.stage == 'all' ||
github.event.inputs.stage == 'prod'
needs: [build, deploy-beta]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

MEDIUM - Deployment Logic: Missing Beta Deployment Condition for workflow_dispatch

When using workflow_dispatch with stage: prod, the prod deployment will fail because it has needs: [build, deploy-beta], but deploy-beta will be skipped (its if condition won't match).

Current behavior:

  • Manual trigger with stage: prod → beta skipped → prod fails (missing dependency)

Recommendation: Update the dependency logic:

deploy-prod:
  if: >-
    github.event_name == 'push' ||
    github.event.inputs.stage == 'all' ||
    github.event.inputs.stage == 'prod'
  needs: build
  # Remove deploy-beta from needs, or make it conditional

Or change line 104 to: needs: [build] and add explicit stack ordering within the job if beta must deploy first.

// renovate: datasource=github-releases depName=smithy-lang/smithy
export const SMITHY_LANG_VER = "1.67.0";
export const SMITHY_DOWNLOAD_URL = `https://github.com/smithy-lang/smithy/releases/download/${SMITHY_LANG_VER}/smithy-cli-linux-aarch64.zip`;
export const SMITHY_DOWNLOAD_URL = `https://github.com/smithy-lang/smithy/releases/download/${SMITHY_LANG_VER}/smithy-cli-linux-x86_64.zip`;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW - Code Quality: Unused Export

The SMITHY_DOWNLOAD_URL constant is defined but not used anywhere in the codebase. The workflow file hardcodes the URL directly (line 40 of deploy.yml).

Recommendation: Either:

  1. Use this constant in the workflow by exporting it as an environment variable
  2. Remove this unused export to keep the code clean

If keeping it for documentation purposes, add a comment explaining why it's not used in the workflow.

for (const {stageType, prefix} of stages) {
const env = {account: ACCOUNT_ID, region: REGION};

const serviceStack = new ServiceStack(app, `${prefix}-ServiceStack`, {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW - Code Quality: Redundant stackName Property

The stackName property is redundant since it's identical to the construct ID (second parameter). CDK will use the construct ID as the stack name by default.

Current code:

new ServiceStack(app, `${prefix}-ServiceStack`, {
    stackName: `${prefix}-ServiceStack`,  // Redundant
    env,
    stageType,
});

Recommendation: While explicit is fine for documentation and ensuring exact CloudFormation stack names match, consider adding a comment explaining this is intentional for the zero-diff takeover migration from CodePipeline:

// Explicit stackName ensures exact CloudFormation stack name match during migration
const serviceStack = new ServiceStack(app, `${prefix}-ServiceStack`, {
    stackName: `${prefix}-ServiceStack`,
    env,
    stageType,
});

- name: CDK synth
run: npx cdk synth --all --output build/cdk.out

- uses: actions/upload-artifact@v4
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW - Security: Artifact Retention

The uploaded artifact doesn't specify a retention period. GitHub defaults to 90 days, which may be longer than necessary for build artifacts that are only needed for the duration of the deployment.

Recommendation: Add explicit retention to reduce storage costs and limit exposure window:

- uses: actions/upload-artifact@v4
  with:
    name: cdk-out
    path: build/cdk.out
    retention-days: 1  # Only needed for this workflow run

- beta
- prod

concurrency:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LOW - Operational Insight: Limited Concurrency Control Visibility

The cancel-in-progress: false queues deployments, which is good for safety, but there's no visibility into queued deployments or timeout configuration.

Recommendation: Consider adding:

  1. A timeout at the workflow level to prevent indefinite queuing
  2. A notification or comment when a deployment is queued

Example:

concurrency:
  group: deploy-${{ github.ref }}
  cancel-in-progress: false

jobs:
  build:
    timeout-minutes: 30  # Prevent indefinite runs
    runs-on: ubuntu-latest

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant