Module 8: Capstone The Andes Cargo Pipeline

8. Final project: the Andes Cargo pipeline as a deliverable

Description

This is the project that closes the complete guide. There's no new technical piece to build —lessons 3 and 4 already proved, with act's literal output, that the entire pipeline works under pressure— and lessons 5, 6, and 7 already precisely traced every honesty boundary. What this project does is what no earlier module had room to do in full: present the entire repository as a portfolio piece, with a pipeline README.md that documents the end-to-end flow, a guided audit of the complete structure, and the exact criteria a technical interviewer —or you yourself, explaining this work six months from now— would use to judge whether it's real or decorative.

Connection to the module

Every closing project in this guide, since Module 1, ended with a guided confirmation of that module's work. This is the same exercise, applied one last time to all eight complete modules: three production workflows, a real guardrail, and a walkthrough tested twice under pressure. With this, cicd-and-gitops-on-aws-guide is complete.


Step 1 — Structure audit: the complete pipeline layer

cd andes-cargo-infra
find . -maxdepth 3 -not -path '*/.terraform*' -not -path './.git/*' -not -path './.git' | sort

What to expect (literal, executed to write this lesson):

.
./.actrc
./.github
./.github/act-events
./.github/act-events/pr-event-52.json
./.github/act-events/pr-event-revert.json
./.github/act-events/pr-event.json
./.github/guardrail-fixtures
./.github/guardrail-fixtures/shipments-already-applied.state.json
./.github/workflows
./.github/workflows/apply.yml
./.github/workflows/ci.yml
./.github/workflows/drift.yml
./.github/workflows/guardrail-demo.yml
./.gitignore
./.secrets
./dynamodb.tf
./iam.tf
./lambda
./lambda.tf
./lambda/function.zip
./lambda/handler.py
./locals.tf
./modules
./modules/iam-role
./modules/s3-bucket
./outputs.tf
./providers.tf
./s3.tf
./terraform.tfvars
./variables.tf
./versions.tf

Split this list into two layers, and confirm you can explain each one without hesitation: the business layerversions.tf through lambda.tf, plus modules/— is, line by line, the same project terraform-and-iac-guide left finished in its capstone; this guide never rewrote a single line of business HCL, except for the guardrail's documented exception. The pipeline layer —everything inside .github/, plus .actrc and .secrets— is this guide's genuinely new part, built module by module, from Module 1's single-line .actrc to Module 6's ci.yml guardrail.

Confirm the business project is still valid, with no trace of this guide's work:

terraform fmt -check -recursive
terraform validate

What to expect (literal):

Success! The configuration is valid.

Step 2 — The pipeline README.md: the portfolio deliverable

Create this file at andes-cargo-infra/'s root — the document anyone opening this repository would read first:

# andes-cargo-infra — CI/CD pipeline

Andes Cargo's infrastructure (manifest bucket, shipments table, IAM roles, processing
function) declared in Terraform, with a GitHub Actions pipeline that automates its
review and application. Run end-to-end with `act` (v0.2.89) against LocalStack —
$0, reproducible, no AWS or GitHub account needed to develop it.

## The pipeline

| Workflow | Trigger | What it does |
|---|---|---|
| `ci.yml` | `pull_request` against `main` | `fmt``validate``plan` → guardrail → summary → uploads the plan as an artifact |
| `apply.yml` | `push` to `main` | Downloads the exact plan that was reviewed, applies it with `-auto-approve` |
| `drift.yml` | `schedule` (daily, 06:00 UTC) or `workflow_dispatch` | Read-only `plan -detailed-exitcode`, reports if anything changed outside Terraform |

## The guardrail

`ci.yml` includes a step that fails the job if the `plan` tries to destroy the
`Shipments` table — a `grep` over `terraform show -json`, added in the guide's Module 6
that built this pipeline. `guardrail-demo.yml` tests that same guardrail against a
seeded `state` *fixture*, with no need for real applied infrastructure.

## How to run it locally

\`\`\`bash
brew install act
docker run --rm -d --name localstack_main -p 127.0.0.1:4566:4566 \
  -e LOCALSTACK_AUTH_TOKEN=${LOCALSTACK_AUTH_TOKEN:?} localstack/localstack

act pull_request -e .github/act-events/pr-event.json -j terraform-checks --secret-file .secrets
act push -W .github/workflows/apply.yml
act workflow_dispatch -j check-drift -W .github/workflows/drift.yml
\`\`\`

## What this pipeline does NOT build (on purpose)

- **Real federated OIDC** against an AWS account — shown in complete YAML, not
  executed (`act` doesn't issue OIDC tokens). Dummy `test`/`test` credentials via
  `.secrets`, acceptable only because the destination is LocalStack.
- **Human approval of *Environments*** and **branch protection** — real
  `github.com` configuration, with no associated YAML `act` can execute.
- **SAST/DAST, SBOM, image signing, policies as a system** (`conftest`/OPA/Sentinel at
  scale) — outside this learning project's scope.

Complete design and execution-honesty documentation for every piece:
`cicd-and-gitops-on-aws-guide` (NIEVA).

Commit the document:

git add README.md
git commit -m "Add README.md: pipeline documentation for andes-cargo-infra"

Step 3 — How to defend this project in an interview

A technical interviewer reviewing this repository —or you yourself, explaining it six months later— doesn't need you to recite YAML from memory. They need you to be able to answer, without hesitation, four kinds of questions, each with its specific evidence somewhere in this guide:

  1. "Why two separate workflows, ci.yml and apply.yml, instead of one with a condition?" — the answer lives in Module 3, lesson 2: separating plan (on every PR) from apply (only on push to main) is the standard pattern cited from HashiCorp's official tutorial, and it avoids the family of vulnerabilities where a pull_request from an untrusted branch ends up, by a configuration mistake, with write permissions.

  2. "How do you guarantee what gets applied is exactly what got reviewed, not a recalculation?" — the answer lives in Module 5, lesson 3, and you confirmed it three times with your own eyes in this module: upload-artifact/download-artifact move the same binary file between jobs, verified by identical SHA256 at every point —the same hash showed up in ci.yml on upload, and twice in apply.yml on download, in this module's lesson 3—.

  3. "What happens if someone attempts a dangerous change, by mistake or on purpose?" — the answer lives in Module 6 and got demonstrated under pressure in this module's lesson 4: a real grep over the JSON plan stops the job before any artifact exists that apply.yml could apply. Plan: 10 to add, 1 to destroyJob failed, unambiguous.

  4. "What's this pipeline missing for real production?" — the complete answer lives in this module's lessons 5, 6, and 7: real PR comments and human approval (require github.com), end-to-end OIDC and SAST/DAST/SBOM (cloud-security-and-guardrails-guide), and the rest of the operational lifecycle —EKS with pull-based GitOps, SRE, FinOps— each with its own dedicated guide, not a vague admission that "work remains."

If you can answer all four with this guide's specific evidence —not a generic claim about CI/CD best practices—, this project is ready to defend.


Step 4 — Final confirmation: the complete pipeline, listed

act -l

What to expect (literal, executed to write this lesson):

Stage  Job ID                   Job name                 Workflow name    Workflow file       Events
0      fetch-reviewed-plan      fetch-reviewed-plan      apply            apply.yml           push
0      terraform-checks         terraform-checks         ci               ci.yml              pull_request
0      check-drift              check-drift              drift-detection  drift.yml           schedule,workflow_dispatch
0      destroy-shipments-check  destroy-shipments-check  guardrail-demo   guardrail-demo.yml  workflow_dispatch
1      terraform-apply          terraform-apply          apply            apply.yml           push
git log --oneline | wc -l
git log --oneline | head -5

What to expect (representative for the hashes and the exact count —depends on how many times you ran each module's project throughout this guide—, literal for the most recent messages' structure):

<N>
<hash> Add README.md: pipeline documentation for andes-cargo-infra
<hash> Add CostCenter tag to the shipment-docs bucket
<hash> Add doc/adr/0001-choosing-cicd-tooling.md: ADR for GitHub Actions over Jenkins/GitLab CI
<hash> ci.yml: add a guardrail step that blocks any plan destroying the Shipments table; add guardrail-demo.yml to test it against a seeded fixture
<hash> Add pr-event-revert.json to simulate the revert PR with act

Five jobs listed, the same cumulative history since Module 1 — no workflow got lost, no commit got rewritten. This is the final confirmation that the repository is exactly in the state this module's eight lessons, and the seven before it, built with real evidence.


Common mistakes

Considering the project "done" without writing Step 2's README.md (scope-based). What happens: someone completes lessons 3 and 4, sees the pipeline working, and assumes that's enough portfolio evidence. How to fix it: a repository with no document explaining the complete flow forces anyone reviewing it to reconstruct the logic by reading YAML with no context — the README.md is what turns "a bunch of files that work" into "a project that explains itself." It's the same discipline Module 4 already applied with SECRETS-AND-ENVIRONMENTS.md.

Presenting this project without mentioning its explicit limits (honesty-based, revisit lessons 5-7). What happens: someone, showing this work in an interview, presents it as "production-ready" without naming any of lessons 5, 6, and 7's pieces. How to fix it: an experienced interviewer values someone who knows their own work's exact limits more than someone who presents a learning project as if it were a complete production system — this module's lessons 5-7 are, literally, the script for that part of the conversation.

Deleting .secrets or .gitignore while preparing the repository to show it (security-based). What happens: someone, preparing this project to share it, deletes files that seem like "internal configuration" without checking which ones matter. How to fix it: .gitignore proves you understand what should never be versioned; .secrets, gitignored since Module 2, should never have been in Git's history in the first place —confirm it with git log --all --full-history -- .secrets, which should return empty, exactly as Module 4 confirmed—. If you're going to share this repository publicly, verify that command before publishing it, not after.


Exercises

Exercise 1 — Answer Step 3's four interview questions without looking at the lesson. From memory, write a complete answer to each of this lesson's four interview questions, citing the specific evidence from which module/lesson backs it up.

See solution

The four answers' complete structure is in Step 3 — this exercise's goal is having been able to reconstruct them without looking, citing from memory the specific evidence: Module 3's HashiCorp pattern (question 1), Module 5's and this module's lesson 3's SHA256 verification (question 2), this module's lesson 4's Plan: 10 to add, 1 to destroyJob failed (question 3), and lessons 5-7's three boundary pieces (question 4). If you cited specific evidence —numbers, filenames, lesson names— instead of generic claims, you have the complete defense internalized.

Exercise 2 — Explain this guide's complete thesis in under thirty spoken seconds. An interviewer gives you thirty seconds to explain what you built in this guide and why it matters. Write that answer.

See solution

A complete answer, fitted to thirty spoken seconds, sounds, roughly, like this: "I took AWS infrastructure already declared in Terraform and built the CI/CD pipeline that governs it: every Pull Request calculates a plan someone reviews, every merge to main applies it automatically with the exact same file that got reviewed —verified by SHA256—, a scheduled check detects changes made outside the pipeline, and a guardrail automatically blocks any attempt to destroy the project's most critical resource. I tested the complete pipeline twice: with a real change that goes through end-to-end without me ever touching terraform apply, and with a destruction attempt the pipeline stops before applying. The point isn't that a pipeline is faster than applying by hand — it's that it leaves an auditable record of who approved what, and makes some dangerous decisions technically impossible, without depending on anyone's judgment in the moment."

Exercise 3 — Apply Module 7's map metaphor to this entire guide. Close the loop opened in Module 7, lesson 1, exercise 3: compare the sentence you wrote back then about your own map's edge with what you know now, closing Module 8.

See solution

There's no single correct answer — it's the same honest self-assessment you already practiced, now with this guide's complete map available. A reasonable updated version: "I know how to build and test, end-to-end, a complete infrastructure CI/CD pipeline —automatic review, automatic application only after review, a real guardrail protecting a critical resource, tested under pressure with an accepted change and a rejected one—. I know how to precisely name what it's missing for real production: end-to-end OIDC, SAST/DAST, real human approval, and the rest of the operational lifecycle —Kubernetes, SRE, FinOps—, each with its own dedicated guide I'd know where to start with." If your version combines something you built with something you can name precisely but haven't built yet, you have exactly the skill this entire guide practiced from start to finish.


Summary and next step

In this final project you audited andes-cargo-infra/'s complete structure —twelve pipeline-layer files and directories, without touching a single line of the inherited business layer—, wrote the README.md that documents the complete flow as a portfolio piece, and prepared the defense for four interview questions with this guide's specific evidence. You confirmed, with act -l and git log, that the complete repository is exactly where this module's eight lessons, and the seven earlier modules, left it.

Before closing this guide you should be able to: answer Step 3's four interview questions with specific, not generic, evidence; explain the guide's complete thesis in under thirty spoken seconds; and name, without hesitation, both what you built and what you know exists but haven't built yet.

With this, cicd-and-gitops-on-aws-guide is complete: eight modules, a real infrastructure CI/CD pipeline —tested, not just described—, a guardrail protecting Andes Cargo's most critical resource, and complete honesty about where this work ends. The path continues, depending on what your own project needs, in any of the sister guides this module's lessons 5, 6, and 7 traced: cloud-security-and-guardrails-guide, kubernetes-and-eks-in-production-guide, sre-and-incident-response-guide, or finops-and-cost-guardrails-guide.

Resources

  1. nektosact.com — User Guide — complete act reference, the tool that held up every lesson's real execution in this guide.
  2. GitHub Docs — GitHub Actions — official documentation for the complete engine behind Andes Cargo's three production workflows.
  3. HashiCorp Developer — Automate Terraform with GitHub Actions — the central pattern this entire guide implemented and tested end-to-end.
  4. terraform-and-iac-guide (NIEVA) — the original andes-cargo-infra/ project, automated by this guide without rewriting a single line of business logic, except for Module 6's guardrail.