Build a pipeline that stops a bad change
Task
Build a CI pipeline that lints, tests, scans and only then deploys, and prove the property that justifies it: a change that fails any stage cannot reach the deploy step. Add a secret scanner and confirm it blocks a committed credential.
Steps
- Write a pipeline definition with ordered stages: lint, test, scan, deploy. Each stage fails the pipeline on a non-zero exit. The Verify drives it through
./run-pipeline.sh <branch>: with a plain shell pipeline, that script checks out the branch, runs the stages in order underset -e, and prints<stage>: okas each one passes; with a real runner, make it trigger the pipeline for that branch and print the job log. Create the three branches the Verify names as you go:good(step 3),badtest(step 4) andsecret(step 5). - Add real checks:
shellcheck/ansible-lintin lint, a unit test in test,gitleaksand a container scan in scan. - Commit a good change and watch every stage pass and the deploy run.
- Commit a change that fails the test. Confirm the pipeline STOPS at test and the deploy stage never runs. This is the whole value.
- Commit a change introducing a hardcoded secret. Confirm
gitleaksfails the scan stage and blocks the deploy -- and contrast a pre-commit hook, which would have stopped it reaching the history at all. - Restrict deploy to the main branch with an
only/ifcondition, and confirm a feature branch runs the checks but not the deploy. - Inject a secret into the pipeline the right way -- a masked, protected variable -- and confirm it does not appear in the job log.
Verify
cd ~/lab-ci
# good change: deploy stage recorded
./run-pipeline.sh good 2>&1 | grep -qi 'deploy: ok' && echo "good change deploys"
# failing test: pipeline stops before deploy
./run-pipeline.sh badtest 2>&1 | tee out.txt; grep -qi 'deploy: ok' out.txt && echo "DEPLOYED despite failure -- wrong" || echo "stopped before deploy"
# committed secret: scan blocks it, and nothing deploys
./run-pipeline.sh secret 2>&1 | tee out2.txt; grep -qi 'leaks found' out2.txt && ! grep -qi 'deploy: ok' out2.txt && echo "scan blocked the secret"
Each check reads a stage's ok line, not the word "deploy" or "gitleaks": those appear in any run that lists its stages or names its tools, whether the stage passed or not.
The failing-test run NOT reaching deploy is the property the whole pipeline exists for: broken change in, no deployment out. The secret scanner catching a credential in CI is useful; a pre-commit hook catching it before the commit is better, because a key that reached CI is already in the history.
Notes
Shift-left is the theme: a defect caught by a pre-commit hook costs seconds, in CI a pipeline run, in staging a deployment, in production an outage. The pipeline is the backstop; the hook is the earlier and cheaper catch, and a secret that reaches either the history or CI must be rotated regardless.
This is an independent study companion for CompTIA Linux+ and is not produced by or endorsed by CompTIA.