← CI/CD: build, validate, and deliver
11 / 12 · 70 MIN

Loaded target and process state

Confirm the implementation actually exercised and distinguish search, module cache, disk state and declared identity.

From declared file to called code

The previous lesson showed a report with the correct digest but tests that did not execute the candidate. This lab now calls functions from actual Python modules created by the script itself. Three directories exist: A represents an earlier implementation, B a defective candidate and C the correction. All expose the same module name and label 1.0. In claimed-B-loaded-A, the report computes B digest while search loads A. All four tests pass, but the gate identifies target-mismatch. The useful conclusion is that A was successfully exercised by that set, not that B is approved. Preserve that distinction in handover language and the promotion decision.

Explicit search and inherited environment

In a fresh process, the script puts A before B in sys.path and observes the resolved origin. In a second process pair, PYTHONPATH points to A while code appends B to the end of the search. The normal process finds A; the process using -I ignores the variable and finds B through the explicitly added location. The exercise installs no packages and changes no user configuration. Record origin using __file__, inspect file bytes and connect those observations to outcomes. For a real service, add relevant dependencies, configuration and runtime. Do not confuse a visible path with complete proof of the execution chain.

What is already loaded

Another experiment retains the same process. It first imports A, then changes the search directory to B and imports the same name again. The object remains the same and behavior remains A behavior. Calling importlib.invalidate_caches does not change that outcome: invalidating finder caches does not remove or replace the existing sys.modules entry. In the lab, a fresh interpreter with explicit search simplifies comparison of B. This does not mean any production service can safely be restarted without planning. If a product supports reloading, existing references, dependencies and state need consideration. Such a reload strategy was neither implemented nor validated in this exercise.

Current disk and earlier memory

In the controlled-replacement group, the process imports B and records an initial observation. The script then replaces the file with C bytes without reloading the module. A later disk read already matches C, but calling the function still returns B value. This limits a common claim: hashing a path after tests does not independently reconstruct bytes loaded earlier. The exercise is sequential and uses owned files; it does not simulate a concurrent attack. In a real context, protect the source and execution path and preserve timing context. Do not claim immutability, signing or attestation that these local controls do not provide.

Delivery decision and limits

In a fictional APS case, the supplier presents green results with label 1.0. RUN observes origin A while the delivery order identifies B. The manager coordinates search correction, requests a new run and retains earlier results with their correct scope. The aim is to connect the technical fix to evidence that B is now exercised. Editing a report field or presenting more tests against A is insufficient. Mode -I helps limit inherited Python configuration but is not an operating-system sandbox. The lab executes only owned code and does not demonstrate hostile-code confinement, credential protection or network isolation. Keep those boundaries visible when adapting the exercise to an actual pipeline.

Diagnostic workshop

For a twenty-minute workshop, distribute three reports: B declared with A loaded, changed search with the same object, and disk C with B behavior. Development explains loading; QA bounds what each test established; RUN requests data needed to decide. Each group writes observation, likely cause, next experiment and owner. The response must avoid claiming that a file change already updated a process. This workshop was prepared but not performed by human participants. In summary, distinguish declared identity, observed origin, process state and functional outcome. Connect this lesson with artifacts, configuration management, troubleshooting and release management without treating local diagnosis as production acceptance.

python3 content/labs/cicd-target/run.py --output /tmp/dr-cicd-target-first.json
# Choose a new output path; recorded runtime: CPython 3.13.1.
# claimed-B-loaded-A: four tests pass; gateReasons=[target-mismatch]
# module-cache-survives-path-and-finder-change: sameObject=true
# pythonpath-and-isolated-process: normal loads A; isolated loads B
# disk-change-does-not-replace-loaded-module: disk C, behavior B
# Original owned source modules only; no package installation or hosted CI.
IN PRACTICE

The report declares candidate B, but search finds installation A, which passes all four tests. Label 1.0 exists on both.

Common pitfalls

Assuming the declared digest controls import, confusing invalidate_caches with reload or treating -I as operating-system security isolation.

Related topics: Artifact identity · Test evidence · Release management

Take this idea with you

The report should describe the observed target. A search or disk change does not by itself establish that the process now executes new code.

Create account

Reference: The import system · CI/CD practices 2026-09; scoped GitHub Actions GitLab Jenkins and Azure DevOps Services documentation