Chapter 26Lesson 05~330 minutes

Checkpoint Lab — SBOMs, Dependency Lists, Vulnerability Management, Remediation, and Security Dashboards

Trace one synthetic dependency from SBOM inventory through finding, remediation branch, rescanning evidence, disposition, sanitization, and verified cleanup.

CheckpointSBOMRemediationDispositionCleanup

Learning objectives

  • Trace one synthetic vulnerable dependency through SBOM, finding, remediation MR, rescanning evidence and final disposition.
  • Predict component/pipeline state changes before executing the lab.
  • Distinguish Resolved, Dismissed and No longer detected using explicit evidence.
  • Diagnose one missing or malformed evidence path without hiding the original cause.
  • Retain only sanitized audit evidence and verify cleanup.
Availability baseline — verified 2026-08-22 against GitLab 19.3. A plain CycloneDX JSON file is an open, portable evidence format and can be generated, validated, hashed, stored as an ordinary CI artifact, and reviewed on GitLab Free. GitLab’s artifacts:reports:cyclonedx ingestion, Dependency List, Dependency Scanning, Vulnerability Report/details, Security Dashboards, Security Inventory, vulnerability exports/APIs, and hosted vulnerability-management lifecycle are currently Ultimate across GitLab.com, Self-Managed, and Dedicated. Therefore every mandatory lab in this chapter has a Free-compatible fixture path; Ultimate steps are clearly optional/read-only. GitLab 19.3 is the current monthly release, published 2026-08-20.

1. Checkpoint scenario and success criteria

You are the maintainer of disposable project gitlab-ch26-checkpoint. Version 1.2.0 of fictional component widget-parser appears in a CycloneDX SBOM and a synthetic finding. Your task is to change it to fictional fixed version 1.2.1, prove the identity change, simulate rescanning, distinguish lifecycle outcomes, and clean the training project without retaining sensitive or unnecessary artifacts.

Preflight: mandatory path is GitLab Free + Git + Python 3. No real CVE, secret, exploit, package download, privileged runner, container registry, cloud account, Kubernetes cluster or paid security feature is required. If an Ultimate disposable project is available, hosted Dependency List/Vulnerability Report/API checks are optional.

2. Write predictions before action

Record at least these predictions in checkpoint.md:

  1. Before remediation, SBOM and finding both identify pkg:npm/widget-parser@1.2.0.
  2. A remediation branch pipeline can prove 1.2.1, but default-branch hosted state should not be treated as remediated until the change is merged and the default branch is rescanned.
  3. A missing finding after a malformed/missing scan is not equivalent to No longer detected from a valid scan.
  4. Dismissed is a risk decision; Resolved is a verified remediation state; No longer detected is scanner activity evidence.

3. Setup the evidence fixture

git init gitlab-ch26-checkpoint
cd gitlab-ch26-checkpoint
git switch -c main
mkdir -p evidence
printf 'widget-parser=1.2.0\n' > deps.lock
# Add the synthetic CycloneDX and finding JSON shown in Lesson 2.
python -m json.tool evidence/sbom-before.cdx.json >/dev/null
python -m json.tool evidence/finding-before.json >/dev/null
sha256sum evidence/* > evidence/SHA256SUMS.before
git add . && git commit -m "ch26: add synthetic vulnerable dependency evidence"
git rev-parse HEAD

Verify independently: the SBOM purl, finding purl/version and deps.lock must all agree. If they do not, stop—the lab has already reproduced the identity mismatch from Lesson 4.

4. Add a tiny evidence pipeline

stages: [verify]
verify_security_evidence:
  stage: verify
  image: python:3.13-alpine
  script:
    - python -m json.tool evidence/sbom-before.cdx.json >/dev/null
    - python -m json.tool evidence/finding-before.json >/dev/null
    - sha256sum evidence/sbom-before.cdx.json evidence/finding-before.json
  artifacts:
    when: always
    paths: [evidence/]
    expire_in: 7 days

Run it only on the disposable project. Record pipeline ID, job ID, commit SHA and artifact hash. No hosted security UI is required to pass the checkpoint.

5. Remediation branch and MR

git switch -c remediate/widget-parser-1.2.1
printf 'widget-parser=1.2.1\n' > deps.lock
# Create evidence/sbom-after.cdx.json with purl pkg:npm/widget-parser@1.2.1.
# Create evidence/rescan-after.json with synthetic=true and findings=[] plus scan_valid=true.
python -m json.tool evidence/sbom-after.cdx.json >/dev/null
python -m json.tool evidence/rescan-after.json >/dev/null
sha256sum evidence/sbom-after.cdx.json evidence/rescan-after.json > evidence/SHA256SUMS.after
git add . && git commit -m "ch26: remediate synthetic widget-parser finding"
git rev-parse HEAD

Open an MR. Before merging, verify the predicted branch identity. After merging, verify the default branch contains the same remediation commit or merge result and run the valid evidence pipeline again.

6. Inject one broken scan and diagnose it

Now create a temporary branch where rescan-after.json is invalid JSON or the pipeline deliberately omits it. The result should be a failed validation or missing artifact, not a “clean scan.”

git switch -c diagnose/missing-report
printf '{"scan_valid":' > evidence/rescan-after.json
python -m json.tool evidence/rescan-after.json
# Expected: non-zero exit with JSON parse error. Preserve the error.
# Repair by restoring valid JSON; do not replace the failed run with a fabricated clean result.

Interpretation: a missing/malformed report means unknown scan result. It cannot justify Resolved or Dismissed.

7. Classify the final disposition

Use this decision table after a valid default-branch rescan:

Observed evidence Correct interpretation
1.2.1 SBOM + valid rescan with no synthetic finding No longer detected evidence; verify remediation, then mark Resolved on Ultimate if authorized.
1.2.0 still present + valid finding + business accepts risk Remain vulnerable; optional Ultimate status may be Dismissed with a reason/comment and external owner/review metadata.
No report / malformed report Unknown. Repair scanner/report first; never call it resolved.
1.2.1 SBOM + finding still references 1.2.0 Evidence mismatch/stale finding; reconcile pipeline and finding identity.

8. Optional Ultimate verification

On an Ultimate disposable project, inspect Secure → Dependency list and Secure → Vulnerability report after a valid default-branch pipeline. Confirm current role requirements before changing status. If using automation, prefer documented GraphQL for longer-lived vulnerability lifecycle integrations because current REST project-vulnerability APIs are unstable/deprecating. Vulnerability exports are authenticated Ultimate resources and are author-scoped.

9. Produce a sanitized evidence packet

Keep a small text/JSON packet containing:

  • project path and GitLab version/offering;
  • before/after commit SHA and pipeline/job IDs;
  • before/after purl/version;
  • SBOM/report SHA-256 hashes;
  • MR ID/URL and test outcome;
  • final disposition and rationale;
  • scanner/report coverage statement;
  • no tokens, cookies, complete environment dumps, or private application data.

10. Cleanup and verify

git switch main
git branch -D diagnose/missing-report
git branch -D remediate/widget-parser-1.2.1
# If branches were pushed, remove only disposable remote branches after evidence is saved.
# Delete the disposable project only after verifying no downstream references depend on it.
# Verify locally:
git branch --list
find evidence -maxdepth 1 -type f -print

If you intentionally delete the disposable project, verify it is gone through the UI/API rather than assuming the delete click succeeded. Retain only sanitized evidence outside the project according to your training/audit policy.

11. Verification checklist

  • Before and after component purls differ only by intended version.
  • Both SBOM files parse and have recorded hashes.
  • The valid rescan is distinguishable from the malformed/missing-report run.
  • The remediation MR/commit is linked to the after evidence.
  • No real secret or real vulnerable package was introduced.
  • Final disposition explicitly distinguishes Resolved, Dismissed and No longer detected.
  • Temporary branches/project resources are cleaned up and cleanup is independently verified.

Knowledge check

A valid rescan after the merge no longer reports the finding. What is the immediate evidence state?

A malformed report produces no findings. What is the correct disposition?

What is the key difference between Dismissed and Resolved?

Why must the after-SBOM be tied to the merged/default-branch pipeline?

An API script based on GET /projects/:id/vulnerabilities starts breaking after an upgrade. What design issue should you revisit?

What does this chapter add to a production GitLab operating model?

12. Chapter close and bridge to Chapter 27

Chapter 26 converts security evidence into an accountable operating loop. You can now tell the difference between inventory, detection, lifecycle state and proof of remediation—and you can identify when dashboards lie by omission. Chapter 27 builds on this foundation by asking a different question: how should organizations enforce scanner execution, pipeline rules, approval policies and compliance controls consistently across projects?

Primary sources and version notes

These lessons were finalized against current official GitLab documentation on 2026-08-22. Re-check tier, feature-flag, API, and Self-Managed-version behavior before using the same workflow later.

Next chapter

Security Policies, Scan Execution, Pipeline Execution, Approval Policies, and Compliance Controls

Carry the evidence model forward into organization-level enforcement and policy design.

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.