Chapter 15 — Application and software supply chain security: guided lab
Lesson map
Lesson 15 published. Map, example, EX043.
flowchart TD
N0["Learning outcomes"]
N1["15.1 The audit"]
N2["Lab — dependency audit"]
N3["15.2 Lab result"]
N4["15.3 Turning results into tasks"]
N5["15.4 Checking matches"]
N6["15.5 Prioritisation"]
N7["Recording the audit"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX043"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["15.1 The audit"]
N2["Lab — dependency audit"]
N3["15.2 Lab result"]
N4["15.3 Turning results into tasks"]
N5["15.4 Checking matches"]
N6["15.5 Prioritisation"]
N7["Recording the audit"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX043"]
[Learning outcomes]
|
v
[15.1 The audit]
|
v
[Lab — dependency audit]
|
v
[15.2 Lab result]
|
v
[15.3 Turning results into tasks]
|
v
[15.4 Checking matches]
|
v
[15.5 Prioritisation]
|
v
[Recording the audit]
|
v
[Worked example] --> [Exercise EX043]
Learning outcomes
You will (1) run a dependency audit across clients; (2) read advisory matches; (3) total by severity; (4) turn results into tasks.
15.1 The audit
The audit compares each client's installed library versions with a synthetic advisory list, each advisory naming a library, affected versions and severity. Each advisory row gives the lowest affected version and the fixed version, the same form used in the inventory lab. Because the advisory list is synthetic, the lab shows the method without depending on any real feed. The audit is the step that turns the inventory into action. The inventory says which version each project runs; the audit says which of those versions an advisory names. Running it nightly means a newly published advisory is matched against every client by the next morning instead of after days of searching.
Lab — dependency audit
"""Audit all client projects against a synthetic advisory list and summarise by severity."""
projects = {"greenleaf-booking": {"upload-kit": "3.1.0", "forms": "2.2.0"}, "harbour-cafe": {"forms": "2.4.1"},
"kiteschool-site": {"upload-kit": "3.4.2"}, "museum-tickets": {"upload-kit": "2.9.8", "forms": "2.4.1"}}
adv = [("ADV-7", "upload-kit", "2.0.0", "3.2.0", "high"), ("ADV-8", "forms", "2.0.0", "2.3.0", "medium")]
def v(s): return tuple(map(int, s.split(".")))
count = {}
for p, deps in sorted(projects.items()):
for aid, pkg, lo, fix, sev in adv:
if pkg in deps and v(lo) <= v(deps[pkg]) < v(fix):
print(f"{p:18} {aid} {pkg} {deps[pkg]} -> {fix} ({sev})"); count[sev] = count.get(sev, 0) + 1
print("totals:", count)
Run with python3 lab_audit.py. Verified output:
greenleaf-booking ADV-7 upload-kit 3.1.0 -> 3.2.0 (high)
greenleaf-booking ADV-8 forms 2.2.0 -> 2.3.0 (medium)
museum-tickets ADV-7 upload-kit 2.9.8 -> 3.2.0 (high)
totals: {'high': 2, 'medium': 1}
15.2 Lab result
Greenleaf matches ADV-7 (high) and ADV-8 (medium); museum-tickets matches ADV-7. Totals: high 2, medium 1. The output lists project, library, version and advisory, which is exactly what a developer needs to start. museum-tickets also uses forms 2.4.1, which is above ADV-8's fixed version 2.3.0, so it does not match. harbour-cafe uses the same forms version and is likewise clear. kiteschool-site runs upload-kit 3.4.2, above ADV-7's fix. Each output line gives the fixed version after the arrow, so the developer knows the target without opening the advisory. The totals line tells Aiko how much high-severity work is open at a glance.
15.3 Turning results into tasks
Each match becomes a task with the owner from the inventory and a due date from the severity: high within 7 days, medium within 30. For the lab results, both ADV-7 matches would be due within 7 days and Greenleaf's ADV-8 match within 30. The owner named in the inventory receives the task, so nobody has to decide who should act. Due dates come from the severity in the advisory, adjusted only when context shows the affected feature is unused. Any such adjustment is written on the task with the reason.
15.4 Checking matches
Diego confirms each match by reading the advisory, since version ranges can be written ambiguously. Checking also confirms that the affected feature is actually used. Of the 11 matches in the full audit, one turned out false because the advisory's range excluded the installed patch version. Diego records the reason so the same wording does not mislead the next run. Ambiguity is common at range boundaries, for example whether a range ending at a version includes that version itself. Reading the advisory text settles it before work starts, so developers are not asked to fix projects that were never affected.
15.5 Prioritisation
Where many matches arrive at once, Brightwave may consider exploit likelihood scores such as EPSS (Jacobs et al., 2021) alongside severity and client context. Brightwave has not adopted such scores yet, because its match counts are small enough to handle by severity and context. Diego notes EPSS as an option if a single advisory ever matches many projects at once. Severity remains the starting point; any other score would only change the order within a severity group. Client context, such as Greenleaf's medical notes, still decides which project goes first.
Recording the audit
Each audit run is saved with its date, the advisory list version used and the matches found. When a client asks whether they were affected by an advisory, Brightwave can answer from the record rather than from memory. The record also shows how long each match stayed open, which feeds the remediation-time measure from chapter 9. Diego notices that matches in projects with an active owner close in about four days, while those in projects with no recent work take nearly three weeks, and he raises this with Aiko as a staffing issue.
Worked example
Running the audit across all 23 client projects returns 11 matches. Diego confirms 10; one is a false match because the advisory's range excludes the installed patch version. Corrected matches become tasks, and all highs are fixed within six days.
Synthetic case. Advisories and matches are synthetic.
Errors and limits
Audits only find known advisories; they say nothing about unknown flaws.
Exercises
- EX043 — Lab totals. What totals did the lab give? Rubric: 3 = high 2, medium 1; 2 = partial; 1 = vague; 0 = none.
- EX044 — Due dates. What due dates apply? Rubric: 3 = high 7 days; medium 30; 2 = partial; 1 = vague; 0 = none.
- EX045 — False match. Why was one match false? Rubric: 3 = range excluded installed version; 2 = partial; 1 = vague; 0 = none.
Synthesis
Audit, confirm, assign and fix by severity.
Continue studying — chapter 15 of 30
← Chapter 14 (draft) · Course chapter index · Chapter 16 (draft) →