A few months ago, I thought CI/CD simply meant writing a GitHub Actions YAML file that runs pytest.
If tests pass, the result is 'green'; if they fail, it's 'red'pretty straightforward, right?
However, while progressing through my QA automation roadmap (projects P141–P170), my mentor introduced me to a concept that completely shifted my perspective on testing: the 'Trust Boundary'.
When a test fails in CI, developers need evidence (such as screenshots, traces, or logs) to debug the issue. But how can they be certain that the evidence stored hasn't been corrupted? How do they know the pipeline is making the correct decision?
Here is how I built a secure CI pipeline to address this challenge.
- Preserving Evidence of Failure (The
if: always()Strategy) Typically, if a GitHub Actions job fails, subsequent steps do not execute. This means that if your Playwright test crashes, the step to upload artifacts won't run-causing the failure screenshot to be lost forever as soon as the virtual machine shuts down. To solve this, I used theif: always()condition for the upload step: -name: Upload Failure Evidence uses: actions/upload-artifact@v4 if: always() with: name: test-evidence path: artifacts/ This ensures that even if the test crashes, the evidence is safely uploaded to GitHub's cloud storage. - Independent Auditor/Verifier (Decoupled from the Test Job)
If the test job itself generates the evidence and also verifies it, the situation becomes akin to grading one's own homework. Even if a bug corrupts the file, the test job might still report a successful verification (
verification = true) based on incorrect data. To resolve this, I split my pipeline into separate jobs: Test Job: Runs Pytest, generates evidence, calculates the SHA-256 hash, and uploads it to the cloud. Verify Job: Downloads the artifact, recalculates the hash from the raw bytes, and compares the two. This establishes a 'trust boundary.' Here, the Verify job acts as an independent auditor. If anyone (or a system bug) alters or tampers with the evidence while it is stored in the cloud, the hashes will no longer match, and the auditor will mark the pipeline as 'failed.' - The Final Quality Gate
Finally, I added a third job: 'The Gate.'
This job depends on the 'Verify' job (though the
if: always()condition was not used). Its sole purpose is to display the final decision: ================================= FINAL EVIDENCE GATE ================================= Test execution: PASS Artifact upload: PASS SHA-256 verification: PASS FINAL GATE: PASS If verification fails, the 'Gate' step is skipped, and the overall workflow is marked as 'Red' (failed). What's next?"Praman"(Proof) By completing this stage of CI/CD, I realized that QA isn't just about finding bugs; it is about building an engineering framework based on trust and evidence. Stemming from this insight, I’ve named my future architecture'Praman'-a word that translates to 'Proof' or 'Evidence'. The next steps in my roadmap involve transforming this pipeline into a modular, "drop-in" Python QA engine that freelance clients can easily integrate into their own repositories. It will be a tool designed to execute tests, gather irrefutable evidence, and (eventually) leverage AI to analyze the root causes of failures. If you are building CI/CD pipelines, I highly recommend exploring independent artifact verification. It elevates your pipeline from a mere "script runner" into a professional-grade engineering system. What aspects of CI/CD are you currently learning? Let’s connect!
Top comments (0)