Skip to content

Deploying the Project


Lint and test are green. Nothing that produces is visible to anyone outside your own Actions tab until the pipeline ships it somewhere. This chapter is about setting that up — the AWS side and the workflow that uses it — with the mechanics pointed out and the actual assembly left to you.

Choose Your Target

stalefinder produces a report and has nothing that needs to stay running between scans — that points at S3: scan on a schedule, upload the result, done. If you picked speedtest-cli, the same shape fits — a scheduled run producing a number worth recording. If you picked something genuinely long-running instead, ECR + ECS is the better fit, using the same push-then-update-service pattern from the ECS deployment chapter earlier in this course.

The rest of this chapter assumes the S3 path. Decide on a bucket name and a prefix under it for your reports before going further — you’ll need both in more than one place below.

Set Up the AWS Side

Confirm the OIDC provider exists. If you completed the OIDC setup chapter earlier in this course, your AWS account already has an identity provider trusted for token.actions.githubusercontent.com — an account only needs one, shared across every repository and role that uses it. Check before assuming:

aws iam list-open-id-connect-providers

Only create a new one if nothing shows up for that provider URL — refer back to the OIDC setup chapter for the exact command if you need it.

Create an IAM role scoped to this repository. This part is new even if the provider isn’t — a fresh project needs its own role. Write a trust policy for it and work through these requirements rather than reusing one from an earlier chapter wholesale, since the values need to match this specific repository:

  • The principal trusting this role is your account’s GitHub OIDC provider, referenced by its ARN.
  • The action is the standard OIDC assume-role action you used in the security section’s walkthrough.
  • The aud condition should match sts.amazonaws.com, exactly as it did there.
  • The sub condition is what actually restricts who can assume this role — scope it to this repository and branch specifically, not to your whole GitHub org. Go back to the OIDC walkthrough chapter if you don’t remember the exact claim format; get this one right, since it’s the entire access-control boundary for the role.

Once the trust policy is written, create the role and attach a permissions policy that grants exactly one thing: write access to your reports prefix in your bucket. Nothing broader — no full-bucket access, no unrelated S3 permissions left over from copying a template. If the bucket doesn’t exist yet, create it before attaching the policy.

Store the resulting role ARN as a repository secret. That’s the only cloud credential this pipeline will hold.

Plan the Deploy Workflow

This is a second, independent workflow file from ci.yml — the plan from the Designing the Pipeline chapter called for the scheduled scan to be separate from the push/PR-triggered CI run, and nothing since then has changed that.

Work through this checklist:

  • Triggered on a schedule (cron), with workflow_dispatch also enabled so you can trigger it manually while testing — you don’t want to wait for a cron to fire just to find out a step is broken

  • Declares permissions: id-token: write and contents: read at the workflow or job level — without the first one, nothing that follows can request the token OIDC depends on

  • Checks out the repository and sets up Python, same as your CI workflow

  • Installs the project and runs your CLI wrapper, capturing its output to a file

  • Uses the same AWS-credentials-via-OIDC action from the OIDC walkthrough chapter, pointed at the role ARN you stored as a secret

  • Uploads the captured report to your bucket and prefix, with a filename that won’t collide with the previous run — a timestamp in the key is a simple way to guarantee that

Tip

The credentials that the OIDC step produces aren’t something you reference explicitly in later steps — they land as environment variables that the AWS CLI picks up automatically. If your upload step is failing with a credentials error, check the permissions: block and the order of your steps before assuming the role or policy is wrong.

Test with a manual workflow_dispatch run before trusting the schedule. Once it succeeds, confirm the object actually landed:

aws s3 ls "s3://<your-bucket>/<your-prefix>/"

Add the Status Badge

Near the top of your README.md, add a badge pointing at your CI workflow file:

[![CI](https://github.com/<org>/<repo>/actions/workflows/ci.yml/badge.svg)](https://github.com/<org>/<repo>/actions/workflows/ci.yml)

GitHub renders that SVG from the most recent run on your default branch — nothing to regenerate, it updates on its own the next time the workflow runs. If it’s not green, that’s your pipeline telling you something the rest of this checklist didn’t catch.

Cleanup

Once you’ve confirmed the badge is green and a report has landed in S3, tear down what you don’t intend to keep running:

# Remove test reports
aws s3 rm "s3://<your-bucket>/<your-prefix>/" --recursive

# Remove the role and its policy
aws iam delete-role-policy --role-name <your-role-name> --policy-name <your-policy-name>
aws iam delete-role --role-name <your-role-name>

Leave the OIDC provider itself alone unless you created it fresh for this chapter and nothing else in your account depends on it — it’s shared infrastructure, not something scoped to one project.

If you’d rather keep the scheduled scan running as an actual working tool instead of a one-off exercise, skip the role deletion and just clear out the test reports.

Last updated on