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.
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.
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.
2. Write predictions before action
Record at least these predictions in checkpoint.md:
-
Before remediation, SBOM and finding both identify
pkg:npm/widget-parser@1.2.0. - 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.
- A missing finding after a malformed/missing scan is not equivalent to No longer detected from a valid scan.
- 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?
No longer detected. After verifying the component/build identity and remediation, an authorized user or policy can mark the vulnerability Resolved.
A malformed report produces no findings. What is the correct disposition?
Unknown/invalid scan evidence. Repair the report or scanner; do not resolve or dismiss based on absence.
What is the key difference between Dismissed and Resolved?
Dismissed is an intentional decision not to remediate a finding; Resolved represents verified remediation/fix. Neither is the same as a scanner simply omitting a finding.
Why must the after-SBOM be tied to the merged/default-branch pipeline?
A branch-only SBOM proves a candidate change, not the state that the tracked/default branch or release actually built.
An API script based on GET /projects/:id/vulnerabilities starts breaking after an upgrade. What design issue should you revisit?
GitLab documents current project vulnerability REST APIs as unstable/deprecating; use current GraphQL/documented interfaces and version-aware integration tests.
What does this chapter add to a production GitLab operating model?
An auditable lifecycle connecting component inventory, findings, ownership/triage, remediation change, rescanning, disposition and dashboard/API scope.
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.
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.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this
address.