Skip to content

English · Español

Lab 00 — Hardening pass on security/THREATS.md

🇪🇸 Recorre security/THREATS.md línea por línea. Para cada hilo abierto: cerrarlo, aceptarlo con razón explícita, o reposicionarlo como off-ramp. Cero ambigüedad.

Objective

Walk every open thread in security/THREATS.md end-to-end. For each: implement the mitigation (Close), write a rationale (Accept), or move it to the off-ramp list (Punt). At the end, THREATS.md contains zero items in the OPEN state.

Setup

  • security/THREATS.md from earlier phases.
  • READING_LIST.md (will be created in lab 02 — this lab adds entries before lab 02 writes the rest).
  • The CI: pip-audit, bandit, mypy --strict, pytest. Run them all green before starting.

Tasks

  1. Snapshot the current state.
uv run python scripts/count_threats.py

Print: - Total threats listed. - Number in OPEN state. - Number in MITIGATED. - Number with no explicit state (a bug — flag and add an explicit state).

  1. Triage each open threat. For each open thread, in order, decide one of three:
  2. Close. Implement the mitigation now. Add a test that verifies it. Update the status to MITIGATED by <test_name> with a link.
  3. Accept with rationale. Write the rationale per theory/03-residual-risk-and-offramps.md. Must include: (a) why the threat doesn't apply now, (b) mitigations in force, © trigger for reassessment, (d) review date.
  4. Punt to off-ramp. Move to READING_LIST.md under the "off-ramps" section. Mark in THREATS.md as [PUNTED: see READING_LIST.md #N].

  5. Re-run CI and the security tools:

uv run bandit -r src/
uv run pip-audit
uv run pytest tests/security/
uv run mypy --strict src/

All four must pass. If bandit or pip-audit flags new issues, decide: close or accept (with rationale). Repeat until clean.

  1. Verify the snapshot:
uv run python scripts/count_threats.py

Expected: - OPEN: 0 - MITIGATED or ACCEPTED: > 0 - All threats have an explicit state.

  1. Write a one-page hardening summary at security/HARDENING_PHASE_40.md:
  2. How many threats started open vs ended open.
  3. How many were closed; key closure tests.
  4. How many were accepted; the highest-risk accepted threat (one sentence).
  5. How many were punted; pointer to the off-ramp section.

Deliverables

  • Updated security/THREATS.md with zero OPEN threats.
  • security/HARDENING_PHASE_40.md (one page).
  • Tests added for any newly-closed threat in tests/security/.
  • Off-ramp entries added to READING_LIST.md.

Acceptance

  • python scripts/count_threats.py reports 0 open threats.
  • Every threat has either: a MITIGATED by <test> link, an ACCEPTED with rationale + review date, or a PUNTED to READING_LIST.md #N reference.
  • bandit, pip-audit, mypy --strict, and pytest all pass.
  • The hardening summary is honest about which threats were accepted, not just which were closed.

Pitfalls

  • Closing a threat without a test. If there's no test, you closed nothing — you wrote a comment. Every closed threat must have a test that would fail if the threat were re-introduced.
  • Accepting without a trigger. "Accepted forever" is not acceptance, it's avoidance. Force yourself to write the reassessment trigger.
  • Punting too aggressively. If you punt more than ~30% of open threats, you're using the off-ramp as a dumping ground. Re-examine: are any of them quick closures you skipped?
  • Treating bandit and pip-audit warnings as "not real." Some are noise (false positives on patterns). For each warning, either add a # nosec comment with a one-sentence rationale or fix it. Silent suppression is forbidden.

Stretch

  • Add a CI step that runs count_threats.py and fails if any thread is in the OPEN state. Prevents future open-thread accumulation.
  • Add a 6-month review reminder — a markdown table at the top of THREATS.md with every "accepted" entry's next review date, sortable.

Next: 01-write-the-postmortem.md