Run three proposals through an intake path and reconcile it with the log
Task
Apply the whole of objective 4.1 to your lab: build a single front door for new AI use, tier three proposals through it, keep the result in a register with conditions and review dates, handle a material change, and then test the path the way the lesson says to test it, by comparing what the register approves with who the gateway log shows actually using the system.
Steps
- Write
lab/intake.md, the one front door: at least five questions, each on a line startingQ1:,Q2:and so on, covering what data and its highest classification, which model, who uses the output, whether it acts or decides about people, and whether it faces customers. - Create
lab/ai-use-register.csvwith headerid,use_case,owner,users,max_data_class,faces_customers,decides_about_people,tier,status,approved_on,review_by,conditions.usersis semicolon-separated;max_data_classis one of your documents' labels; yes/no columns holdyesorno;statusisproposed,approved,rejectedorretired; dates are YYYY-MM-DD. - Tier with one rule and apply it mechanically:
highif the use decides about people or reaches restricted data; otherwisemediumif it faces customers or reaches confidential data; otherwiselow. Run three proposals: UC-01, your own user asking the retrieval app about non-restricted documents; UC-02, the invented usercustomer-demoasking product FAQ questions; UC-03, using the app to shortlist job applicants against the salary bands indocs/restricted/. Approve the first two with conditions and a review date; record UC-03 as rejected or proposed for full review, with the reason inconditions. - Write
lab/integration-map.csvwith headerai_activity,existing_process,owning_function,line, one row each for enterprise risk management, third-party risk, data governance and privacy, change management, security architecture review, incident response and internal audit.lineis 1, 2 or 3 from the three lines model; the CoE must not appear at line 3. - Make one material change for real: swap in a different small model, or add a new document source to the index (created as
secai-docs, the documents' owner since lesson 17, with the sameclassification,owneranddepartmentfront matter as the rest). Add a new register row for the changed use and mark the row it supersedesretired. - Send a few requests to the gateway (
POST $GW/ask, HTTPS on127.0.0.1:8088since lesson 13, JSON body withuserandquestion) as UC-01's user and ascustomer-demo, then two asintern-unregistered, a user in no register row. That is planted shadow use. - Run the verify block. Any user in the log other than the planted one is real unregistered use from earlier labs, such as a test identity from the injection labs: register it as its own use and re-run until only the planted user remains.
Verify
cd ~/secai-lab
grep -c '^Q[0-9]*:' lab/intake.md
python - <<'EOF'
import csv, json, datetime
rows = list(csv.DictReader(open("lab/ai-use-register.csv", encoding="utf-8")))
today = datetime.date.today().isoformat()
def tier(r):
if r["decides_about_people"] == "yes" or r["max_data_class"] == "restricted":
return "high"
if r["faces_customers"] == "yes" or r["max_data_class"] == "confidential":
return "medium"
return "low"
appr = [r for r in rows if r["status"] == "approved"]
print(len(rows), "register rows,", len(appr), "approved,",
sum(r["status"] == "retired" for r in rows), "retired")
print("tier disagrees with the rule:", [r["id"] for r in rows if r["tier"] != tier(r)])
print("approved with no conditions or review date:",
[r["id"] for r in appr if not r["conditions"] or not r["review_by"]])
print("approved past their review date:", [r["id"] for r in appr if r["review_by"] < today])
print("high tier approved:", [r["id"] for r in appr if r["tier"] == "high"])
covered = {u.strip() for r in appr for u in r["users"].split(";")}
seen = {json.loads(l)["user"] for l in open("logs/gateway.jsonl", encoding="utf-8") if l.strip()}
print("users in the log with no approved use:", sorted(seen - covered))
im = list(csv.DictReader(open("lab/integration-map.csv", encoding="utf-8")))
print(len({r["existing_process"] for r in im}), "existing processes mapped")
print("CoE at line 3:", sum("coe" in r["owning_function"].lower() and r["line"] == "3" for r in im))
EOF
Five or more intake questions; at least four register rows with one retired; every tier list, condition list, review list and high-tier list empty; exactly one unapproved user, intern-unregistered; seven or more existing processes; and zero CoE rows at line 3. If the user list is empty, the check has missed your planted traffic: look at how your gateway records user.
Notes
The reconciliation in the last step is the lesson's test of an approval path made literal: the path is judged by the use it did not see. In a real organisation the log would be a web proxy or OAuth consent list rather than your gateway, which lesson 31's applied lab practises. Revert to the snapshot afterwards only if you want the old model back; the register should then gain a row recording that change too.
This is an independent study companion for CompTIA SecAI+ CY0-001 and is not produced by or endorsed by CompTIA.