Module 7: Gitops Beyond Terraform

6. CI/CD for application code vs. infrastructure

Description

This module's lessons 2 through 5 compared tools and mechanisms, always within the infrastructure world you already know. This lesson draws this entire module's most important boundary, deliberately short and direct: what changes when the "code" a CI/CD pipeline processes isn't declarative HCL, but an application's source code —an API, a frontend, a script—. It's not a long lesson because it doesn't need to be: the difference boils down to a few concrete concepts, and lesson 7 makes it tangible with a real pipeline, run with act.

Connection to the module

This lesson is the module's exact hinge: it closes the purely conceptual part (lessons 2 through 5) and sets the stage for the only hands-on lesson (7). Everything you read here you're going to see really run in the next lesson — a minimal pipeline with exactly the characteristic application CI/CD steps this lesson names: checkout, lint, test.


The table that summarizes the whole module

Infrastructure CI/CD (this guide, Modules 2-6)Application code CI/CD
What the pipeline processesDeclarative HCL (.tf)Executable source code (.py, .js, .go...)
Characteristic "verification" stepterraform fmt, terraform validateLinter (ruff, eslint), type checker
Characteristic "test" stepterraform plan (calculates what would change, doesn't run business logic)Unit/integration tests (pytest, jest) — run real business logic
Does an "artifact" exist to compile/package?No — the HCL applies directly, it doesn't compile to an intermediate binaryYes — a package, a binary, or typically a container image
What the "deploy" step doesterraform apply — moves a declared resource's state to the next oneReplacing a running application's replicas, with a strategy (Module 7, lesson 5: rolling/blue-green/canary)
What credentials it needsCloud provider credentials (AWS, via OIDC — Module 4)Database credentials, third-party APIs, and also the cloud provider's if deploying there
Is "success" easily reversible?Yes — git revert + the same pipeline (Module 6)Depends on the deployment strategy (Module 7, lesson 5)

Notice the "artifact" row — it's probably the table's deepest structural difference. andes-cargo-infra/ never produced anything you could "store in a registry and version as a unit" — the HCL gets read and applied directly against the cloud provider on every run. A typical application pipeline, instead, has an explicit build step (compile, package, build a container image) that has no equivalent in this guide's pipeline, precisely because Terraform doesn't "compile" in the same sense.


Why plan isn't the same as a test

It's worth being precise on a point that invites confusion: terraform plan looks like a test —it runs before applying, and if something's wrong, it shows it—, but it doesn't fulfill the same function as a unit test. plan calculates the difference between the declared state and the real state, and shows it to you for human review — it doesn't run any business logic or verify an expected behavior against an expected result. An application unit test, instead, does exactly that: it runs a real function with known inputs and asserts that the output is the expected one. terraform validate (Module 3) is the closest thing to a test you ran in this guide, and even that doesn't run logic — it only confirms the HCL's syntax and internal references are valid.

This distinction explains why this guide's pipeline never had a step literally called "test": there's no application's own business logic to test. Andes Cargo never wrote a function that calculates something and needs to be verified against known cases — it declared resources, and the only possible "test" on a declaration is "is the resulting plan the one I expected?", a question a human answers by reading the plan, not one an automated assert can answer on its own without duplicating the plan itself.


Common mistakes

Thinking terraform validate is "Terraform's equivalent" of a unit test (conceptual, this lesson's most common confusion). What happens: someone, seeing both run in CI before applying/deploying, assumes they fulfill the same role. Why it happens: both show up at the same point in the pipeline (early verification, before the expensive part). How to spot it: if you describe terraform validate as "this guide's tests." How to fix it: validate confirms syntax and references — it never runs business logic or compares an output against an expected result, because declarative HCL doesn't have "business logic" in the sense an application function does.

Assuming any application pipeline needs a "build" step (generalization-based, corrected in lesson 7). What happens: someone expects lesson 7's minimal pipeline to have a compilation or packaging step. Why it happens: this lesson's table presents it as a typical structural difference. How to spot it: if you're surprised lesson 7's pipeline doesn't have a "build" step. How to fix it: the table's row says "typically" — an interpreted Python script, like lesson 7's, doesn't need to compile to a binary before running; the build step is characteristic of compiled languages or applications packaged as a container image, not a universal rule for all application CI/CD.


Exercises

Exercise 1 — Fill in the table from memory. Without looking at this lesson, write the table's four rows (verification step, test step, artifact, deployment) for both types of CI/CD.

See solution

Infrastructure: verification = fmt/validate; test = plan (calculates difference, doesn't run logic); artifact = none, applies directly; deployment = apply, moves a resource's state to the next one. Application: verification = linter/type checker; test = unit/integration tests that run real logic with assert; artifact = package/binary/container image; deployment = replacing running replicas, with a strategy (rolling/blue-green/canary).

Exercise 2 — Explain why plan isn't a test. In one or two sentences, explain to a colleague why terraform plan, even though it runs before applying and shows if something's wrong, doesn't fulfill the same function as an application unit test.

See solution

plan calculates and shows the difference between the declared state and the real one, for a human to review — it doesn't run any logic of its own or compare a calculated result against an expected one with an assert. A unit test does do that: it runs real code with known inputs and automatically asserts the output is correct, with no need for human review to know whether it passed or failed.

Exercise 3 — Locate the boundary's two guides. Which two ecosystem guides cover, in depth, this lesson's table's "application" side?

See solution

cicd-python-backend-guide (CI/CD pipelines for a Python backend application: lint, tests, build, deploy of a real artifact) and testing-in-cicd-guide (automated testing strategies — unit, integration, end-to-end — integrated into a CI pipeline). This guide names the contrast; those two build it.


Summary and next step

In this lesson you systematized, in a single table, the complete boundary between infrastructure CI/CD (what you built in Modules 2 through 6) and application code CI/CD: what gets verified, what gets tested, whether an artifact exists, and what "deploying" means in each case. You precisely confirmed why terraform plan/validate aren't equivalent to an application unit test — the absence of the declarative HCL's own business logic.

Before moving on you should be able to: fill in the contrast table from memory; explain why this guide never needed a "test" step in the application sense; and name the two ecosystem guides that cover application CI/CD in depth.

Lesson 7 makes everything in this lesson tangible: you're going to really run, with act, a minimal three-step pipeline —checkout, lint, test— on a trivial Python script, and you're going to see the difference from ci.yml with your own eyes.

Resources

  1. GitHub Docs — GitHub Actions — official documentation for the tool that runs both kinds of pipeline (infrastructure and application), with no technical distinction between them.
  2. terraform-and-iac-guide, Module 1, lesson 3 — the definition of "declarative" that explains why HCL has no business logic of its own to test.
  3. cicd-python-backend-guide (NIEVA) — this lesson's table's complete "application" side, built in depth.
  4. testing-in-cicd-guide (NIEVA) — automated testing strategies in CI, this lesson's table's "test" step, covered thoroughly.