◇ OpenCyber Academy
Engineering · Chapter 9 · English

Chapter 9 — Programming II

Open, free learning for anyone who wants to protect people and technology. No account is required to read this text or its worked answers.

Chapter 9 — Programming II

Lesson map

Lesson 09 published. Map, example, EX025.

flowchart TD
  N0["Learning outcomes"]
  N1["9.1 Larger programs"]
  N2["9.2 Parsing exports"]
  N3["Lab — Role summary"]
  N4["9.3 Reading the role summary"]
  N5["9.4 Reproducibility"]
  N6["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6
  N6 --> EX["Worked example"]
  EX --> Q["Exercise EX025"]

Logical drawing

flowchart LR
  N0["Learning outcomes"]
  N1["9.1 Larger programs"]
  N2["9.2 Parsing exports"]
  N3["Lab — Role summary"]
  N4["9.3 Reading the role summary"]
  N5["9.4 Reproducibility"]
  N6["Synthesis"]
  N0 --> N1 --> N2 --> N3 --> N4 --> N5 --> N6 --> Q["EX025"]
[Learning outcomes]
    |
    v
[9.1 Larger programs]
    |
    v
[9.2 Parsing exports]
    |
    v
[Lab — Role summary]
    |
    v
[9.3 Reading the role summary]
    |
    v
[9.4 Reproducibility]
    |
    v
[Synthesis]
    |
    v
[Worked example] --> [Exercise EX025]

Learning outcomes

You will (1) build larger, structured programs; (2) parse identity exports; (3) handle errors and keep results reproducible.

9.1 Larger programs

As Sana's checks grow, she splits code into modules: readers for each export format, a common account model, comparison logic and report writers. Each module is small enough to understand. Functions have clear names and short docstrings, and there are no global variables that would make one part depend invisibly on another. This structure lets a colleague review the code and lets Sana add a new application's export by writing one reader, without touching the comparison logic that has already been tested.

9.2 Parsing exports

Application exports arrive in different formats: comma-separated files, directory listings and JSON from cloud services. A parser turns each into a common structure: username, display name, status, last sign-in and roles. Sana writes parsers against synthetic samples first, and each parser reports lines it cannot understand rather than silently skipping them. A silently skipped line could hide exactly the stale administrator account the check exists to find, so visible errors are a safety feature, not an inconvenience. Each parser has its own tests using small synthetic files.

Lab — Role summary

"""Summarise synthetic role assignments: members per role and risky permission combinations (stdlib only)."""
from collections import defaultdict
roles = {"clerk": {"view", "payments-raise"}, "clerk-plus": {"view", "payments-raise", "export"}, "approver": {"view", "payments-approve"},
         "manager": {"view", "payments-approve", "reports"}, "manager-temp": {"view", "payments-approve", "reports", "export"},
         "auditor": {"view", "reports"}, "helpdesk": {"view", "reset"}}
assign = {"u01": ["clerk"], "u02": ["clerk"], "u03": ["clerk"], "u04": ["clerk-plus"], "u05": ["approver"], "u06": ["approver"],
          "u07": ["manager"], "u08": ["manager"], "u09": ["manager-temp"], "u10": ["auditor"], "u11": ["helpdesk"], "u12": ["clerk", "approver"]}
members = defaultdict(int)
for u, rs in assign.items():
    for r in rs: members[r] += 1
print(f"accounts={len(assign)} roles={len(roles)}")
for r in roles: print(f"  {r:13} members={members[r]}")
print("single-member roles:", sorted(r for r in roles if members[r] == 1))
for u, rs in sorted(assign.items()):
    p = set().union(*(roles[r] for r in rs))
    if {"payments-raise", "payments-approve"} <= p: print("raise+approve:", u, rs)

Run with python3 lab_roles.py. Verified output:

accounts=12 roles=7
  clerk         members=4
  clerk-plus    members=1
  approver      members=3
  manager       members=2
  manager-temp  members=1
  auditor       members=1
  helpdesk      members=1
single-member roles: ['auditor', 'clerk-plus', 'helpdesk', 'manager-temp']
raise+approve: u12 ['clerk', 'approver']

9.3 Reading the role summary

The synthetic export lists twelve accounts across seven roles. Four roles have only one member each, and two of those differ from a larger role by a single permission. This is the early stage of role explosion described in chapter 2. The script also shows one account holding both payments-raise and payments-approve through different roles. Sana records these as findings for the role design work later in the project, noting that the data is synthetic and the real export must be checked with each application owner.

9.4 Reproducibility

A result is reproducible when someone else can run the same program on the same input and get the same output. Sana records the script version, the export file and its date, and avoids hidden dependencies such as the current date unless it is passed in explicitly. Reports include these details in a header. When an auditor later asks how a finding was produced, Sana can show exactly which script and data created it, which turns analysis into evidence the council can rely on.

Worked example

The role summary finds seven roles for twelve accounts, four single-member roles and one account combining raise and approve permissions.

Synthetic case. Exports, roles and accounts are synthetic.

Errors and limits

Parsers that silently skip unreadable lines can hide the very accounts a check is meant to find.

Exercises

Synthesis

Modular, error-reporting, reproducible programs make identity analysis dependable across many applications.

Continue studying — chapter 09 of 50

← Chapter 08 (draft) · Course chapter index · Chapter 10 (draft) →