Learn by Directing AI
Unit 3

Secrets in the Pipeline

Step 1: The secrets problem

The pipeline needs credentials. The test step needs a database URL to run integration tests. The deploy step needs a deployment token. The application needs a session secret.

These values cannot be in the YAML file. The workflow file lives in the repository. Anyone with repository access can read it. And the git history is permanent -- a secret committed once is compromised forever, even if you delete it in a later commit.

GitHub Secrets solves this. You store sensitive values in the repository's settings. The pipeline injects them as environment variables at runtime. The values never appear in the repository, the workflow file, or the git history.

Step 2: Configure GitHub Secrets

Go to your repository on GitHub. Navigate to Settings, then Secrets and variables, then Actions.

Add three repository secrets:

  • DATABASE_URL -- your PostgreSQL connection string
  • SESSION_SECRET -- the session signing key from your .env file
  • DEPLOY_TOKEN -- a deployment token (you can use a placeholder for now if you don't have a deploy target)

Each secret is stored encrypted. GitHub masks them in log output -- if a step accidentally prints a secret value, GitHub replaces it with *** in the logs. But masking is a safety net, not a strategy. The pipeline should never attempt to print secrets in the first place.

Step 3: Update the pipeline to use secrets

Tell Claude to update the CI/CD workflow to inject the GitHub Secrets as environment variables:

Update .github/workflows/ci.yml to:
1. Add environment variables from GitHub Secrets for the test and deploy jobs
2. Use ${{ secrets.DATABASE_URL }} for the database connection in the test job
3. Use ${{ secrets.SESSION_SECRET }} for the session configuration
4. Use ${{ secrets.DEPLOY_TOKEN }} for the deployment step
5. Make sure no step echoes, prints, or logs any environment variable

Step 4: Review AI's secret handling

Open the updated workflow file. AI commonly generates pipeline steps that expose secrets in ways that aren't obvious:

  • echo "Deploying with token $DEPLOY_TOKEN" -- prints the token to logs
  • env or printenv in a debug step -- dumps all environment variables
  • npm run build -- --verbose with a build tool that logs configuration including database URLs

Check every step. No command should output the value of any environment variable. The GitHub masking catches most leaks, but preventing them is better than relying on the safety net.

Step 5: Add the migration check

Aminata asked whether the pipeline could catch database-breaking changes. Last season, a developer renamed a column and half the reports stopped working.

A migration check step runs after the test step and before deployment. It verifies that any Prisma schema changes produce valid migrations and that the migrations apply cleanly against the current database schema.

Tell Claude to add a migration check step to the pipeline:

Add a database migration check step to the CI/CD pipeline. It should:
1. Run after the test step and before the build step
2. Run prisma migrate diff to check for schema changes
3. If there are schema changes, run prisma migrate deploy --dry-run to verify they apply cleanly
4. Fail the pipeline if the migration would break the existing schema

Step 6: Verify the migration check

Push the updated pipeline. Then test it: modify the Prisma schema in a way that would break existing queries -- rename a column that API routes depend on. Push and watch the pipeline. The migration check should catch the breaking change before it reaches production.

After verifying, revert the schema change.

✓ Check

Check: Check the pipeline logs. No secret values should appear in any log output. Pipeline logs should contain masked values (***) for all secrets. No database URLs, API keys, or session secrets in plain text.