Chapter 35Lesson 05~340 minutes

Checkpoint Lab — GitHub Actions Importer, CI Migration, Compatibility, and Modernization

Migrate a synthetic CI pipeline with one unsupported construct, prove behavioral parity, document deltas, and produce a guarded cutover and rollback plan.

CheckpointDual runParityCutoverRollback

Learning objectives

  • Migrate a synthetic pipeline with one unsupported feature.
  • Fail closed until unsupported behavior is mapped.
  • Prove same-revision artifact and quality-gate parity.
  • Write guarded cutover and rollback criteria.
  • Bridge migration evidence into the Chapter 36 capstone.

1. Checkpoint: migrate, compare, cut over safely

You own a synthetic legacy pipeline with build, test and manual deploy stages. One source feature—legacy-quality-gate-plugin—is intentionally unsupported. Your task is to produce a candidate Actions workflow, preserve the unsupported item, implement a documented replacement, run parity checks on the same revision, and write a cutover/rollback record. The mandatory path is local and free.

2. Preflight, assumptions and predictions

  • Python 3.11+ and Git installed.
  • No production repository or source CI server is required.
  • All deployment state is a local JSON file under the lab directory.
  • No credential value appears in source or target files.
  • If live Importer is used optionally, run audit or dry-run first and record actual version output.

Predict before execution: (1) source and target build artifacts should have the same digest for the same commit; (2) the first target candidate should be denied cutover because the unsupported quality gate is unresolved; (3) after the replacement check is added, target CI can become eligible while legacy deployment remains disabled during proof.

3. Create the migration inventory and source pipeline

{
  "source_platform": "SyntheticCI 2.4",
  "pipeline": "release-main",
  "trigger": "push main",
  "agent": {"os":"linux","tools":["python3"],"private_network":false},
  "secrets": ["DEPLOY_TOKEN"],
  "artifact": "dist/app.txt",
  "deployment": {"manual_approval":true,"target":"local:target-state.json"},
  "unsupported": ["legacy-quality-gate-plugin"]
}

Hash the inventory and source configuration. Their digests identify the migration input set. Any later edit creates a new migration revision and must not be silently mixed with earlier parity evidence.

4. Candidate Actions workflow with the unsupported item preserved

name: migration-checkpoint
on:
  workflow_dispatch:
permissions: {}
jobs:
  build-test:
    runs-on: ubuntu-24.04
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
      - run: python3 scripts/build_and_test.py
      - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: migration-${{ github.sha }}
          path: dist/app.txt
  quality-gate:
    needs: build-test
    runs-on: ubuntu-24.04
    steps:
      # TODO(actions-importer): replace legacy-quality-gate-plugin.
      - run: exit 1
  deploy:
    needs: quality-gate
    environment: migration-lab
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-24.04
    permissions: {}
    steps:
      - run: echo "synthetic deploy only after mapped gate"

The intentionally failing quality-gate job is safer than silently dropping the unsupported source behavior. It makes the missing contract fail closed until engineering resolves it.

5. Replace the unsupported gate with observable local behavior

from pathlib import Path
artifact=Path('dist/app.txt')
assert artifact.exists(), 'artifact missing'
text=artifact.read_text()
assert 'BLOCKED' not in text, 'quality policy violation'
print('quality gate: PASS')

Document this as an intentional implementation delta: the legacy plugin is not “converted”; its required outcome is reimplemented as a deterministic local policy check. In a real migration, acceptance criteria would be agreed with the source-system owner.

6. Execute parity test and preserve one failing comparison

import hashlib, json, pathlib
s=pathlib.Path('source-out/app.txt'); t=pathlib.Path('target-out/app.txt')
def h(p): return hashlib.sha256(p.read_bytes()).hexdigest()
report={'source_sha':h(s),'target_sha':h(t),'artifact_equal':h(s)==h(t),'quality_gate':'mapped','cutover_eligible':h(s)==h(t)}
pathlib.Path('evidence/parity.json').write_text(json.dumps(report,indent=2))
print(json.dumps(report,indent=2))

Before the replacement check exists, record cutover_eligible=false. Do not overwrite that first-failure evidence after repair. The second report should cite the same source revision and explicitly name the repaired semantic gap.

7. Write the guarded cutover and rollback plan

Phase Legacy CI Actions Deployment authority Exit criterion
Inventory active candidate only legacy only source contract hashed
Dual-run validation build/test active build/test active legacy only same-SHA parity sample passes
Cutover build may remain read-only authoritative Actions only old deploy credential/trigger disabled and denial verified
Rollback window read-only standby authoritative unless rollback trigger exactly one system rollback criteria and artifact target known
Retirement disabled/archived authoritative Actions only evidence retained; legacy credential revoked

Rollback means restoring the previous known deploy authority and artifact, not enabling both systems. State the exact rollback trigger, responsible operator and verification steps.

8. Required evidence packet

  • Source platform/version and pipeline/config digest.
  • Source revision SHA used by both implementations.
  • Generated workflow and preserved Importer TODO/unsupported inventory.
  • Runner/tool assumptions and explicit permissions.
  • Source and target run IDs or local simulation identifiers.
  • Artifact SHA-256 comparison and quality-gate result.
  • Secret mapping document containing names/scopes only, never values.
  • Cutover record proving one deploy authority and legacy disablement.
  • Rollback target and acceptance criteria.
  • Assumptions/limitations note, including whether live Importer was used.

9. Verification and cleanup

test -f evidence/parity.json
python3 - <<'PY'
import json
r=json.load(open('evidence/parity.json'))
assert r['artifact_equal'] is True
assert r['quality_gate']=='mapped'
assert r['cutover_eligible'] is True
print('checkpoint parity verified')
PY

If you used only the local path, no cloud or enterprise cleanup is necessary. If you used live source/GitHub credentials, remove temporary tokens, close or delete the disposable migration PR/repository if authorized, and verify that no source deployment permission was broadened.

10. What Chapter 35 adds—and the bridge to Chapter 36

This chapter adds migration discipline to the production operating model: syntax conversion is subordinate to invariant preservation, same-revision evidence, explicit runner/secret/artifact mappings, one deployment authority and reversible cutover. Chapter 36 combines these controls into the capstone: a secure reusable enterprise CI/CD platform with versioned contracts, governed runners, provenance, deployment controls, observability and recovery.

Next lesson

Capstone: Build a Secure Reusable Enterprise CI/CD Platform: Core Concepts and Mental Model

Continue with the next lesson to build on the current concepts, evidence, security boundaries, and operational practices.

Knowledge check

Why should an unsupported migration feature fail closed in the checkpoint?

Which two items must match before artifact parity is meaningful?

What belongs in a secret-mapping evidence file?

During dual-run validation, which system should deploy?

What makes rollback safe?

Official references and version notes

Keep the academy open

Support free, practical DevOps education.

Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.