Module 2: Anatomy Of A Github Actions Workflow

1. Introduction: reading and writing a workflow with judgment

Description

In Module 1 you installed act, ran a "hello world" end to end, and left andes-cargo-infra/ ready — Git repository initialized, .actrc pinned, .github/workflows/ created, LocalStack running on your host. All of that worked, but you ran lesson 7's YAML by copying it, with nobody yet explaining, field by field, what each line does. This module closes that gap: you're going to dissect a GitHub Actions workflow's complete syntax —on, jobs, steps, runs-on, uses, with, env— on a real file you're going to run with your own hands, you're going to learn to trigger any event without needing a GitHub account (act -e), and you're going to learn to pass secrets to that simulation safely. You leave this module with the first workflow that actually touches Andes Cargo: hello-andes-cargo.yml, running inside andes-cargo-infra/.

Connection to the module

Lessons 2 through 5 are the dissection: a workflow block's complete anatomy (lesson 2), what event triggers it and when (lesson 3), the schedule trigger with cron syntax (lesson 4), and what a reusable Action is, with the supply-chain risk named (lesson 5). Lessons 6 and 7 are pure hands-on: you write an event by hand and pass it to act with -e (lesson 6), and you pass it secrets without ever committing them (lesson 7). Lesson 8 —this module's project— brings it all together: Andes Cargo's first real workflow, run with act push, with a step that confirms the job's container can reach the LocalStack running on your host.


What you take from Module 1 (and what's missing)

By the end of Module 1 you knew, in practice, that a workflow has a .yml file, that act -l lists it, and that act push runs it. What you still didn't know —and is exactly what this module solves—:

  • What each field means in a workflow: why on goes first, what jobs groups, why steps is an ordered list, what runs-on decides, and the exact difference between a step that runs a command (run) and one that reuses someone else's code (uses).
  • What events exist, beyond Module 1's push: pull_request, workflow_dispatch, and why an event's branches:/paths: filter matters for a real pipeline like apply.yml.
  • How to simulate any event without depending on having a GitHub account or a remote repository — you're going to write a Pull Request's payload by hand.
  • How to pass secrets to a local run without ever writing them in the YAML or in a commit.

This module's map: the 8 lessons

#LessonWhat you practice
1Introduction (this one)The module's map, what's missing from Module 1, what you'll be able to read/write by the end
2A workflow block's complete anatomyon/jobs/steps/runs-on/uses/with/env, dissected on a real workflow
3Triggers: push, pull_request, workflow_dispatchWhat triggers a workflow and when; branches:/paths: filters
4The schedule trigger and cron syntaxcron: syntax; the drift-detection case arriving in Module 5
5Reusable Actions: uses, with, and the supply chainactions/checkout@v4, hashicorp/setup-terraform@v3; tag vs. SHA
6Hands-on: simulating events with act -eExecuted: pr-event.json written by hand, act pull_request -e
7Hands-on: passing secrets to actExecuted: .secrets (gitignored), act --secret-file, -s
8Project: Andes Cargo's first real workflowExecuted: hello-andes-cargo.yml, act push, LocalStack from the runner

The module's analogy: reading a contract, not just signing it

In Module 1 you ran a workflow like someone who signs a contract without reading it, trusting that the example worked because the lesson said so. This module teaches you to read the whole contract before signing it — and, later, to draft your own. A GitHub Actions workflow has the same predictable structure as any well-written contract: first it states under what conditions it applies (on — the equivalent of "this contract takes effect when X happens"), then it groups the obligations by block (jobs — "these are the buyer's clauses, these are the seller's"), and within each block, an ordered sequence of concrete steps (steps — "first the deposit gets paid, then the deed gets signed, never the other way around"). uses is the clause that says "apply such-and-such notary's standard procedure, don't reinvent it every time" — reusing work that's already done and tested, instead of writing every check from scratch.

You're going to learn to read that whole contract in this module, on a real file, executing it as you read it — not in the abstract.


What does NOT change in this module

You still don't spend a cent, and you still don't touch Andes Cargo's business infrastructure. No workflow in this module runs terraform plan or terraform apply against the four real resources —that only starts in Module 3—. Module 2's project, hello-andes-cargo.yml, does the minimum necessary to prove the path to LocalStack works (awslocal sts get-caller-identity, a read-only command, creating or modifying nothing), not to deploy anything yet. Same account 000000000000, same region us-east-1, same andes-cargo-infra/ inherited without a single new line of HCL.

Before and after this module

   BEFORE (end of Module 1)                     AFTER (end of Module 2)

   "I copied the lesson's YAML                  "I know what each field
    and `act push` worked."                       means: on, jobs, steps,
                                                    runs-on, uses, with, env."

   "I only know how to trigger `push`,           "I can simulate any
    and only because the workflow                 event —including a Pull
    listened for push."                           Request— by writing its
                                                    payload by hand."

   "I don't know how I'd pass                    "I know how to pass
    credentials to a workflow without              secrets without ever
    writing them in the file."                     writing them in the
                                                    YAML or in a commit."

Common mistakes

Thinking a workflow is just "a list of terminal commands" (conceptual, this module's central confusion). What happens: someone looks at a workflow and reads it as if steps were simply a bash script with nice names, treating on, jobs, runs-on as "metadata that doesn't matter." Why it happens: steps are, superficially, the closest thing to what you already know from a terminal. How to spot it: if, when copying someone else's workflow, you only look at the run: section and jump straight to what it does, without checking what event triggers it or what image it runs on. How to fix it: on decides whether the job runs at all; runs-on decides where; only after that does what runs matter. A perfect step in a job that never triggers does nothing — this module's lesson 2 spends equal time on every field, not just steps.

Assuming act -e is exclusive to Pull Requests (scope-based, previewed from lesson 6). What happens: someone understands act -e file.json only as "the way to simulate a PR," without realizing it works for any event that needs a richer payload than the one act generates by default —a push with a specific commit message, a workflow_dispatch with concrete inputs. How to fix it: lesson 6 shows it with pull_request because it's this guide's most common case, but the mechanism (-e path/to/event.json) is generic for any GitHub Actions event.


Exercises

Exercise 1 — Sort the fields by their function. Without looking at lesson 2 yet, try to match each field with its function: on, jobs, steps, runs-on, uses, with, env. Functions: (a) environment variables available to the commands; (b) what event triggers the workflow; (c) input parameters for a reused Action; (d) the image/system a job runs on; (e) the ordered sequence of actions within a job; (f) reference to reusable code from another person or repository; (g) the grouping of work, each one potentially in parallel.

See solution

on → (b). jobs → (g). steps → (e). runs-on → (d). uses → (f). with → (c). env → (a). If you matched most of them without looking, you already have the right intuition before entering lesson 2 — which is going to confirm every one of them with a real workflow running.

Exercise 2 — Explain the contract analogy in your own words. Without using the word "contract," explain to a colleague in two sentences why on conceptually goes "before" jobs, and why jobs goes "before" steps.

See solution

A complete answer sounds, roughly, like this: "on decides whether the workflow runs at all for this event —without that, nothing that follows matters. jobs groups the work into units that can run in parallel or depend on each other, and each job needs its own sequence of steps because the steps are instructions, one after another, within that specific unit of work." The hierarchy isn't arbitrary: each level scopes the next one.

Exercise 3 — Anticipate the module's project. Without having seen hello-andes-cargo.yml yet (it arrives in lesson 8), predict: what type of command would you expect that workflow to run to "confirm the job's container can reach LocalStack," without creating or modifying any resource?

See solution

A read-only command, which creates or modifies nothing — the answer lesson 8 gives is awslocal sts get-caller-identity, the same command you used in Module 1 to confirm your identity inside the LocalStack lab. It's the right choice precisely because it commits to nothing: if it fails, you know it's a network problem between the job's container and the host, not an error in a half-finished apply.


Summary and next step

In this lesson you saw the complete map of this module's 8 lessons, and the difference between "running a workflow because the lesson says so" and "reading a workflow with judgment." The contract analogy —conditions first (on), grouped obligations next (jobs), ordered steps at the end (steps)— is the idea you're going to reuse in every lesson of this module.

Before moving on you should be able to: name this module's 8 lessons and what each one contributes; match a workflow's seven main fields with their function; and explain why on decides whether the rest of the file even matters.

Lesson 2 opens the dissection with a real workflow's complete anatomy —not an isolated fragment— run with act as we read it.

Resources

  1. GitHub Docs — Workflow syntax for GitHub Actions — the complete syntax reference this module is going to dissect.
  2. nektosact.com — User Guideact -e, act --secret-file, and -s, used in lessons 6 and 7.
  3. terraform-and-iac-guide, Module 2 (NIEVA) — the same pedagogical progression (syntax anatomy before real project) applied to HCL instead of YAML.