Chapter 8 — Programming II
Lesson map
Lesson 08 published. Map, example, EX022.
flowchart TD
N0["Learning outcomes"]
N1["8.1 Design"]
N2["8.2 Parsing"]
N3["8.3 Errors"]
N4["8.4 Tests"]
N5["8.5 Reports"]
N6["8.6 Review"]
N7["8.7 Version control"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7
N7 --> EX["Worked example"]
EX --> Q["Exercise EX022"]
Logical drawing
flowchart LR
N0["Learning outcomes"]
N1["8.1 Design"]
N2["8.2 Parsing"]
N3["8.3 Errors"]
N4["8.4 Tests"]
N5["8.5 Reports"]
N6["8.6 Review"]
N7["8.7 Version control"]
N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> N7 --> Q["EX022"]
[Learning outcomes]
|
v
[8.1 Design]
|
v
[8.2 Parsing]
|
v
[8.3 Errors]
|
v
[8.4 Tests]
|
v
[8.5 Reports]
|
v
[8.6 Review]
|
v
[8.7 Version control]
|
v
[Worked example] --> [Exercise EX022]
Learning outcomes
You will (1) build a larger configuration checker with modules and tests; (2) parse JSON exports; (3) handle errors; (4) produce reports for different readers.
8.1 Design
Samuel's checker has three parts: loaders for each export type, a set of check functions and a report writer. Adding a new check means adding one function and its tests.
The separation paid off when Kubernetes exports arrived in a different shape from the cloud console's: only a new loader was needed, and the existing checks ran on its output unchanged. Each part can be tested on its own, so a bug in the report writer cannot hide a wrong result in a check. Samuel keeps each part in its own file, with a short description at the top saying what it expects and returns.
8.2 Parsing
Exports from the cloud console and Kubernetes are JSON. Each loader validates required fields and reports malformed records with their position.
A malformed record might be an export bug or a resource with unusual settings, and either deserves attention. Reporting its position, such as record 17 in the registry export, lets Samuel or Tom find it quickly. The loader still processes the rest of the file, so one bad record does not stop the whole weekly run, and the final report lists how many records were rejected and why.
8.3 Errors
A check that cannot run reports "unable to check" rather than silently passing.
This rule follows from the earlier lesson about missing settings. If a check cannot read a repository's anonymous-pull field, silently passing would report the repository as safe when nothing is known. "Unable to check" puts the gap in front of the team, who can then find out why the field is missing. In the first weekly run, three such results pointed to an export that had been cut short.
8.4 Tests
Each check has tests with synthetic records: one compliant, one non-compliant, one with missing fields. Tests run automatically on every change.
The missing-fields test is the one that matters most for security, since it checks that the program reports a gap rather than guessing. Running tests on every change means a quick edit cannot break a check without someone noticing. When the case-sensitivity bug was fixed, the new mixed-case test ran alongside the old ones and confirmed that nothing else had changed.
8.5 Reports
A detailed report for the cloud team lists every finding; a summary for managers counts findings by severity and account.
The two audiences need different things. The cloud team needs every finding with the resource name and the fix; managers need to know whether things are getting better and where the risk is concentrated. Producing both from the same results keeps them consistent: a manager's count of high-severity findings always matches the number of high-severity lines in the detailed report.
8.6 Review
Tom's team reviews the code before it runs against real exports, checking that it only reads files.
Confirming that the checker only reads files matters because it runs with access to sensitive exports. A checker that wrote or deleted anything could damage the very evidence it examines. Reviewers also look at what the reports contain, making sure no secret values from the exports are printed in plain text, only the fact that a secret was found. The review is recorded in the repository alongside the change.
8.7 Version control
The checker lives in a repository with a changelog, so results can be linked to the code version.
If a weekly report suddenly shows ten new findings, the changelog helps decide whether StudyHub changed or the checker did. A finding that appears the same week as a new check is probably old and only newly visible. Each report header names the code version, so this question can be answered from the report itself without asking Samuel. Old versions stay available, so a past report can be reproduced exactly.
Running regularly
The checker runs weekly against fresh exports, and its reports are saved with the export date and code version. Comparing weekly reports shows whether findings are being fixed or new ones appearing. Samuel adds a short section at the top of each report listing what changed since the previous week, which is what the cloud team reads first. Over the term, weekly reports show findings falling from 41 to 9, with the remaining ones assigned to owners and dates.
Sharing
The checker is shared with other university teams.
Worked example
During review, a team member notices that the checker treats repository names case-sensitively while the registry does not. A test with mixed-case names is added and the comparison fixed.
Synthetic case. Code and data are synthetic.
Errors and limits
Checkers need the same care as production code.
Exercises
- EX022 — Three parts. Name the checker's parts. Rubric: 3 = loaders, checks, report writer; 2 = two; 1 = one; 0 = none.
- EX023 — Unable to check. Why report "unable to check"? Rubric: 3 = avoid silent passing; 2 = partial; 1 = vague; 0 = none.
- EX024 — Case bug. What bug did review find? Rubric: 3 = case-sensitive names; 2 = partial; 1 = vague; 0 = none.
Synthesis
Structured, reviewed checkers scale to many resources.
Continue studying — chapter 08 of 40
← Chapter 07 (draft) · Course chapter index · Chapter 09 (draft) →