Course outline

Git and GitHub / Intermediate: collaborative change management / Lesson 12

Testing and collaborative GitHub workflows

Keep automated evidence attached to the candidate revision and protect the boundary between contributed code and privileged automation.

About 4 min readContent reviewed
On this page

Lesson goals

  • Explain local checks, hosted status, and protected integration.
  • Review workflow permissions and untrusted contribution risks.

Test the snapshot that will be reviewed

Tests run on a particular checkout and environment. A passing result from an earlier commit does not automatically cover later changes, and working-tree tests can include unstaged fixes absent from the commit. Record candidate identity, tool versions, and relevant environment assumptions. Hosted pull-request workflows may test the head or a generated integration ref depending on event and configuration, so know what the check actually evaluated. A status name alone is weak evidence. Keep the final reviewed diff and required checks aligned with the candidate being integrated rather than treating green history as a permanent property of a branch name.

Use a small local contract check

A repository can contain a focused test that protects a behavior rather than depending entirely on hosted automation. The example below checks a synthetic title-normalization rule using Python’s standard library. It does not access a network or modify Git history. In a real project, the function should be imported from application code rather than duplicated inside the test. The local demonstration makes expected behavior explicit, while a workflow supplies the repeatable execution environment. Tests should catch plausible regressions and complement review instead of asserting incidental formatting or private implementation details.

python A self-contained synthetic local test
import unittest

def normalized_title(value):
    result = value.strip()
    if not result:
        raise ValueError("EMPTY_TITLE")
    return result

class TitleTests(unittest.TestCase):
    def test_spaces_are_rejected(self):
        with self.assertRaisesRegex(ValueError, "EMPTY_TITLE"):
            normalized_title("   ")
    def test_title_is_trimmed(self):
        self.assertEqual(normalized_title("  Notes  "), "Notes")

if __name__ == "__main__":
    unittest.main()

Uses Python 3 standard-library unittest and can be validated in a temporary directory. The expected result is two passing tests. No test result is treated as proof of the entire application or of GitHub branch policy.

Read workflow configuration as executable policy

GitHub Actions YAML defines events, jobs, permissions, and commands. The fragment below illustrates read-only token permissions and a local test command after trusted checkout and runtime setup. It is incomplete and cannot run as an independent workflow. Pin compatible actions and dependencies according to project policy rather than inventing a supposedly immutable version. Workflow syntax and available controls evolve, so use official documentation for the repository’s platform. Required-check selection, skipped jobs, and path filters need review because missing evidence must not be mistaken for a completed passing test.

yaml GitHub Actions job fragment for an already prepared checkout
permissions:
  contents: read

jobs:
  test:
    runs-on: ubuntu-24.04
    timeout-minutes: 10
    steps:
      - name: Run prepared local tests
        run: python -m unittest discover -s tests

Trusted checkout and a compatible Python runtime are prerequisites omitted from this fragment. The runner label is an image family, not an immutable environment. No workflow file is installed or triggered by the course, and no credential is needed for the synthetic test.

Protect privileged capabilities from untrusted changes

A contributed branch can modify tests, scripts, dependencies, and workflow content. Executing it with publication credentials or a privileged runner creates a trust boundary regardless of the job’s friendly name. Understand event semantics, especially workflows with elevated context, and never combine privileged execution with untrusted checkout casually. Limit token authority, keep secrets out of logs and artifacts, and use approved short-lived identity where needed for separate authorized tasks. A passing test suite does not prove the workflow itself was trustworthy; policy ownership and trusted evaluation need their own controls.

Keep review, tests, and integration connected

Small coherent changes help reviewers understand intent and make failures easier to attribute. Respond to review with explicit explanations and new evidence when behavior changes. If the base advances, verify the integration candidate under the project’s merge or queue policy. Required approvals and checks can protect shared branches, but they do not replace authorization for deployment or other external actions. Preserve diagnostic evidence with bounded retention and synthetic data. After merging, confirm the destination state and communicate material limitations through the normal project record, without assuming any automated green status closes every operational responsibility.

Common errors and fixes

Tests passed only with unstaged code

Why it happens
The tested tree differed from the candidate commit.
How to fix it
Test an isolated checkout of the actual snapshot.
Prevent it next time
Bind test evidence to commit identity.

An untrusted change receives release credentials

Why it happens
Validation and privileged automation share a trust context.
How to fix it
Separate capabilities and review event/checkout behavior.
Prevent it next time
Use least privilege and trusted policy ownership.

A required suite never runs

Why it happens
Filters or conditions omit its evidence path.
How to fix it
Inspect expected checks and classify missing evidence explicitly.
Prevent it next time
Test workflow selection on representative changes.

Check your understanding

1. A workflow tests a generated merge ref. Why should the review record say so?

Show worked solution

The result describes that integration snapshot, which can differ from the topic tip. Recording identity clarifies what behavior was validated and whether later base or head changes require another run.

2. A test job needs no external service. Which token scope should be considered first?

Show worked solution

Start from minimal permissions, commonly read-only repository contents when checkout needs it, and grant only capabilities actually required. Remove unrelated secrets and privileged runner access. The job name does not justify broad authority.

Key takeaways

  • Test evidence belongs to a specific snapshot and environment.
  • Workflow configuration is executable policy.
  • Untrusted validation and privileged actions need distinct boundaries.

Official references