All lessons › Function F — AI Governance for Agentic Systems › Building the Governance Framework — Risk and Control
F1.7

Continuous control verification

F1
▶
Lightboard recording

Not recorded yet. The lesson below is complete and runnable today — the video is added later without touching this page.

Video placeholderpublishes automatically from recordings/F1.7.mp4
Risk

Automating judgment instead of evidence collection.

Control

Agent-assisted evidence collection, drift detection, exception tracking.

The lab

Automate one evidence package on a schedule.

◉Use case relevance

A control that is verified annually is a control you know about once a year. Continuous verification is the only version of assurance that keeps up with a system whose behaviour changes between tests.

At CyberTravels. collect() raises without a named human. Collection is automatable and judgement is not, and the failure this prevents is specific: a model asked whether a control is adequate answers yes, and the answer is filed as evidence. The verdict field comes back empty on purpose.

◴What this lesson is — Day 0, Day 1, Day 2

What continuous control verification can automate, which is gathering the artefact, and what it cannot, which is the adequacy judgement and the name that goes on it.

Day 0 — why

Point-in-time assurance describes a system that no longer exists by the time anyone reads it.

Day 1 — how

Re-run the evidence collection inside a freshness window derived from how fast the thing actually changes.

Day 2 — measure

Controls currently evidenced — passing and in window — rather than controls that once passed. The number drops, and it is the first honest one.

Measure this

what to measuredenominator or target
controls currently evidenced — passing and in windowshare of controls; it drops against "controls that once passed", and that is the first honest number

▦The framework, and how it works

   annual                          continuous
   +-------------+                 +-------------------------+
   | one sample  |                 | probe on every change   |
   | one date    |      vs         | sample continuously     |
   | one signature|                | escalate on failure     |
   +-------------+                 +-------------------------+

   assurance that keeps up with a system that changes weekly

Continuous control verification is the operating model that follows from F1.1.

The number that matters is not how much passed once. It is how much is currently evidenced — controls whose most recent test is passing and within its freshness window.

Three states, and the third is the one classical GRC tooling cannot express:

  • PASS — tested, passing, in window.
  • FAIL — tested, failing. Honest and actionable.
  • STALE — tested, was passing, out of window. Not a pass.

Plus the absence state: no evidence at all, which is different from failing and is often the largest category in a first assessment.

Anchor → F1.1. This is the machinery that re-measures. F1.1 argues that a control tested six months ago is unevidenced rather than passing; continuous verification is what shortens that window, and the freshness window per control is itself an indicator.

2 · Demo — the posture, computed honestly

3 · Where it breaks — what a point-in-time report would have said

4 · The control — automate one test and watch the posture hold

5 · Collecting the runtime evidence, as a skill

Automating a control means something has to go and look. For the network and logging controls that underwrite every default-deny claim CyberTravels makes, that is a posture collector: egress rules, private endpoints, route tables, key policies, and whether the audit trail is not merely enabled but delivering. It collects; it does not conclude. This is the file in this repository:

▶Real time execution as skill

The skill — skills/attestation/aws-runtime-posture-collector/SKILL.md

name: aws-runtime-posture-collector
description: >-
  Snapshot a deployment's cloud network, crypto and logging posture as
  evidence for default-deny and egress controls. Use to evidence network
  isolation, to check whether private endpoints and endpoint policies are in
  place, or to record the runtime configuration an attestation depends on.
allowed-tools: Bash, Read

Aws Runtime Posture Collector

Controls: Controls 1 and 2 — runtime posture

What this collects

Configuration state, at a point in time, for the network and crypto boundary around one deployment. It is evidence for other skills' verdicts rather than a verdict in itself.

When to use this

When an attestation needs to say something about the network, and therefore after the deployment is running. The claims it supports — default-deny egress, private endpoints, log retention — are runtime facts that no static analysis can reach, and re-collecting is what makes the attestation re-issuable when the posture drifts.

Procedure

  1. Security groups and network ACLs. Enumerate egress rules. Any rule permitting 0.0.0.0/0 outbound is an egress-open finding regardless of what an application-layer policy says.
  2. Private endpoints. Record whether a private endpoint exists for each model and gateway service in use, and read the endpoint policy — an unscoped endpoint policy is an endpoint that permits any principal.
  3. Route tables. Identify NAT and internet gateways on the deployment's subnets. A private endpoint does not help if a default route to an internet gateway remains.
  4. Key policies. Record key policies and condition keys that scope use to a specific service. Unconditioned key access is a finding.
  5. Logging. Confirm the audit trail and log destinations are enabled and delivering, and record the retention.

Example

Input — the fixture committed at the top of scripts/aws_runtime_posture_collector.py. Edit it and re-run: the buckets, counts and verdicts below are derived from it, not hard-coded.

Output — the opening lines of a real run:

control  state           age (days)
------------------------------------
AC-1     PASS                   2.0
AC-2     PASS                   9.0
SB-1     STALE                 31.0
SB-2     STALE                120.0
EV-1     PASS                   5.0
EV-2     PASS                  12.0

The run continues past this. test_skills.py executes the script on every build, with no model configured — so what CI proves is that it runs and refuses legibly, not that it prints these lines. The output above is a recorded run against a real model, and nothing re-diffs it: a model's answer is not reproducible, and this repository does not claim otherwise anywhere it can be checked.

Output contract

{
  "deployment_id": "str",
  "collected_at": "str",
  "network": {
    "egress_open_findings": [{"sg": "str", "rule": "str"}],
    "private_endpoints": [{"service": "str", "present": true, "policy_scoped": true}],
    "internet_route_present": false
  },
  "crypto": {"keys": [{"id": "str", "conditioned": true}]},
  "logging": {"audit_trail_enabled": true, "log_destinations": ["str"], "retention_days": 0},
  "verdict": "PASS|PARTIAL|FAIL"
}

Failure modes

  • Reading configuration and calling it enforcement. This skill records what is configured. Whether traffic actually obeys it is the egress verifier's job.
  • Ignoring the route table because a private endpoint exists.
  • Recording that logging is enabled without checking that it is delivering.

Three ways to do this lesson. Pick one. They run the same procedure against the same code — what changes is who drives it, and how much you see.

1In your AI agent — you are taught

The agent reads the lesson, explains the idea, fetches the code, runs the check and answers your questions as you go. This is the one to take if you are here to learn.

Install it, once. From the folder you cloned. --all does every agent it finds on your machine:

python3 scripts/install_skills.py --all --lessons F1.7

Then restart your agent and open it in that folder. On Windows, if python3 says Python was not found, use python instead.

Then pick f1-7-continuous-control-verification:

agentinstall just for this agentstart it
Claude Codepython3 scripts/install_skills.py --tool claude --lessons F1.7type /f1-7-continuous-control-verification
GitHub Copilot (VS Code)python3 scripts/install_skills.py --tool copilot --lessons F1.7type /f1-7-continuous-control-verification in Chat
Cursorpython3 scripts/install_skills.py --tool cursor --lessons F1.7type / in Agent chat and search for it
Codexpython3 scripts/install_skills.py --tool agents --lessons F1.7type $f1-7-continuous-control-verification, or run /skills

2As one Python command — you just run it

No agent, no conversation. The same lesson executes and prints the same readback. Take this one if you have no assistant, if you are reviewing rather than learning, or if you want the result without the teaching around it.

python3 scripts/lesson.py F1.7

3Read the code, and the difference — nothing runs

Neither of the above, and no model needed. The first command writes CyberTravels exactly as it stood at the end of this lesson; the second prints the diff — the lines this lesson added or changed, and nothing from any later one.

python3 scripts/checkpoint.py --at F1.7 --out work/cybertravels
python3 scripts/checkpoint.py --at F1.7 --diff

On Windows, type python wherever these say python3 — and use \ instead of / in the paths. Everything else is identical. A0.0 step 2 explains why.

Ways 1 and 2 need a model; way 3 does not. A signed-in Claude Code CLI needs no API key, and any OpenAI-compatible endpoint works too. With neither, the audit exits 2 and says so rather than inventing an answer. A0.0 sets this up.

Ways 1 and 2 both end with the same readback: What I did, What changed, The number and Read this next. A step that was skipped or refused is reported as exactly that, never as a pass.

If you did the last lesson’s challenge, expect this to stop. Most challenges ask you to edit the code, and ways 1 and 2 will not overwrite your edits: you get stopped, not a failure, with two options — --out for a fresh folder that keeps your work, or --force to discard it and start this lesson clean.

✓What you just proved

The skill loads and reports its shape, and the line to take from it is the boundary it draws: configuration is not enforcement. A private endpoint next to a route table with a NAT gateway is a recorded fact and an open path at the same time, and logging that is switched on but not delivering evidences nothing at all.

✎Your turn

Automate the control with the shortest freshness window first — it is the one costing the most manual effort and going stale most often. One automated test converts an annual assertion into a live control.

Tools used

OPAOSCALGLM-4.6Claude Haiku 4.5

Skill source: skills/attestation/aws-runtime-posture-collector

← PreviousF1.6 · Operating vs outcome guardrails