Prepare positive and negative examples
The laboratory uses actionlint 1.7.11, built with Go 1.27.1 for Darwin arm64, to analyze eight original workflows. Three are accepted and five rejected according to recorded expectations. Retain version, binary hash, and file hashes so the comparison can be repeated. ShellCheck and pyflakes are explicitly disabled; the result excludes those analyses. No workflow was sent to GitHub, no hosted runner was started, and no tokens were requested. Before execution, classify each file and state why. Then compare the diagnostic with your prediction. An expected rejection is a successful test of the control, not a laboratory failure.
Correct the graph without losing intent
The missing-job example declares that inspect needs compile, but only build and inspect exist. Correct the reference to the producer actually required. Do not solve the error by deleting needs without checking whether the consumer could start before data exists. In the cycle example, build and inspect wait for one another. More runners do not remove the circular dependency. Decompose responsibilities and identify an executable order. During real review, also draw mandatory checks. If publication and testing depend only on the same build, they may not be connected to each other. A graph accepted by the checker does not establish that publication waits for every result required by the service.
Treat outputs as a contract
In unknown-output, the producer publishes release_id and the consumer requests relese_id. The diagnostic exposes the typo, but review should go beyond spelling: the value must be produced, published by the job, and consumed in the correct context. The needs context refers to jobs on which the consumer directly depends; do not assume every indirect ancestor automatically becomes available. If adding a direct dependency, retain the mandatory test as well. An empty output should not be replaced with an arbitrary label simply to proceed. In a fictional financial service, candidate identity links test results to delivered content and to history needed for recovery.
Review permissions against a concrete need
The invalid-permission example uses contents: deploy, which is not a valid value for that scope. Correcting syntax to write-all would be too broad for a job that only needs reading. Declare the appropriate requirement and review effective configuration. In unsafe-event-input, a pull request title enters run code directly. The accepted variant passes it through an environment variable and prints it with quoting. The comparison teaches separation of data from code, not certification of the entire workflow’s security. Review must still cover who can change the definition, what code executes, and which privileges are available in each context.
Recognize green without checks
The valid-without-tests file is intentionally incomplete: its only command prints a positive message. actionlint accepts it because that message is syntactically valid. No functional test ran. Use this example to request the right evidence in a delivery meeting: test command, selected cases, results, evaluated candidate, and the rule preventing promotion when a requirement fails. A zero-test count also deserves investigation, even if the process exits zero. Do not turn the observation into a rule rejecting every printf; displaying data is legitimate. The problem is assigning result presentation the role of executing or deciding the check.
Deliver a review the team can use
Finish the workshop by reviewing a fictional design with build, tests, and publication. Identify each value’s producer, dependencies, and the condition authorizing progression. For every gap, record a proposed change and the evidence that will confirm correction. Distinguish what the linter checked from what requires platform execution. Pull request approval also does not automatically replace checks on an Azure DevOps resource; each mechanism has its own scope. The workshop product is a reasoned review and verification list, not production authorization. The guide can be used in a team session, but that human session has not yet been executed.
python3 content/labs/cicd-evidence/run.py --actionlint /path/to/actionlint
# Requires actionlint 1.7.11; Bash path defaults to /bin/bash
# Eight original workflow fixtures: 3 accepted, 5 rejected
# ShellCheck and pyflakes integrations are disabled explicitly
# This command does not execute a hosted GitHub workflow.A fictional team separates build, testing, and publication. An output typo and incomplete needs leave the candidate without valid identity.
Common pitfalls
Deleting dependencies to silence errors, creating empty jobs to satisfy names, or treating a success message as an executed test.
Related topics: GitHub Actions · Release Management · Git
A workflow can be valid while still omitting the required checks. Confirm the graph, data contract, and decision that uses the results.
Reference: actionlint v1.7.11 checks · CI/CD practices 2026-09; scoped GitHub Actions GitLab Jenkins and Azure DevOps Services documentation