All lessons › Function C — Application Security with an AI SDLC › The AI SDLC — an Agentic AppSec Pipeline, Before and After Deploy
C2.0

The AI SDLC — what runs before a deploy, and what runs after

C2

This starts chapter C2. Its course guide is C2 in the Function C course guide →

▶
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/C2.0.mp4
Risk

A security pipeline built as if it were exempt from the risks it exists to find.

Control

Build the pipeline and the harness as one system, and hold both to the same evidence standard.

The lab

Run a real LLM loop against a CyberTravels finding, then add the verifier and watch the same loop refuse what it just accepted.

◉Use case relevance

Half of what is sold as AI security tooling cannot run before a deploy, and half of it tells you nothing after one. Buy across that line without noticing it and you own two tools that agree with each other and a gap between them where the incidents happen.

At CyberTravels. You add cybertravels/appsec/, and it ships inside the tree it scans. That is the lesson's argument rather than a filing decision: a pipeline in its own repository drifts from the code it reviews, and one that exempts itself from its own stages is the expensive kind. The stage table names what each stage may claim — claim_for(10) says reachable, claim_for(12) says exploited, and a report that blurs them is one nobody can act on.

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

The pipeline as one system, split by what each half can honestly assert: before a deploy there is source and no running thing, so every finding is a hypothesis; after it there is a disposable replica, so a finding can be demonstrated. Including where the pipeline lives, and why exempting it from its own stages is the expensive choice.

Day 0 — why

A security pipeline built as if it were exempt from the risks it exists to find is the one nobody audits.

Day 1 — how

Learn the line first — what can run before a deploy and what only works after one — then build the pipeline and its harness as one system.

Day 2 — measure

Every stage after this reports its own number. This lesson's output is the order they run in, which is what makes those numbers comparable.

Measure this

what to measuredenominator or target
nothing is computed herethe output is the order the stages run in, which is what makes their numbers comparable
Who this function is for. Application security. AppSec engineers, product security engineers, secure code reviewers and penetration testers — the people who already run a security gate on every release, and now have to keep up with code an agent wrote.

▦The framework, and how it works

   ONE LINE, AND EVERY TOOL SITS ON ONE SIDE OF IT

              PRE-DEPLOYMENT          |        POST-DEPLOYMENT
      artefacts sitting still         |      a system that is running
                                      |
   source, manifest, IaC plan,        |   real traffic, the identity the
   tool schema, SBOM                  |   workload actually got, what left
                                      |
   cheap . repeatable . CAN BLOCK     |   sees what really happened . CANNOT
   THE MERGE                          |   block the merge that caused it
                                      |
   SAST  SCA/SBOM  IaC policy         |   DAST  egress enforcement  drift
   threat model  tool-schema review   |   detection  canaries  attestation
                                      |
   blind to: the identity it gets     |   blind to: the commit, until after
                                      |
      C2.2 - C2.7                     |      C2.8 - C2.18, and Function E

   the gap is not a tool you are missing. it is the line itself:
   nothing on the left can see a runtime fact, and nothing on the
   right can stop the change that created one

CyberTravels ships faster than Alex can read. The Coding Agent opens pull requests that touch a hundred files, and the review that used to be a careful hour is now a scroll. Function C is what he builds instead of scrolling.

It is one pipeline, built in order, and the first thing to get straight is where each piece of it can run at all — because half of what is sold as AI security tooling cannot run before a deploy, and half of it tells you nothing after one.

The line

Pre-deployment works on artefacts sitting still. Source, a manifest, an IaC plan, a tool schema, an SBOM. Nothing is running, so the analysis is cheap, repeatable and — the property that matters most — it can block a merge. It is also structurally blind to every fact that does not exist until deployment: the identity the workload actually got, the route it can actually reach, the traffic it actually saw.

Post-deployment works on a system that is running. It sees what really happened, which is the only way to learn some things at all. And it cannot block the change that caused it. By the time it has an opinion, the merge is in.

That is the whole of the distinction, and it decides more than people expect. A risk covered only on the left is one you can prevent and cannot detect. A risk covered only on the right is one you can detect and cannot prevent. Both of them appear on a tooling inventory as the same word — covered — and only one of them is what the person reading the inventory believed they had bought.

Why the chapter is ordered this way

Stages 1 to 10 are pre-deployment: ingest the estate, derive a threat model, audit the code, scan the supply chain, filter to what is reachable. They are cheap and they can gate. Stages 11 to 15 need something running: a replica to attack, an exploit to execute, a patch to prove, a report to sign. They are the expensive half, and they exist because the cheap half produces hypotheses rather than facts.

Nothing in this chapter fixes the middle. The gap between the two sides is not a tool you are missing — it is the line itself, and the honest move is to know which side each of your controls is on before somebody asks you whether a risk is covered.

2 · What Alex is actually up against

before the Coding Agentafter
pull requests per week640
files touched per PR3up to 120
reviewers11
Nothing about the review capacity changed. That is the whole problem, and it is the reason every stage after this one is automated rather than scheduled.

3 · Every technique, on one side or the other

techniquepre-deploypost-deploywhat only the other side sees
SAST / code analysisyesnowhether the vulnerable path is reached with real traffic
Dependency and SBOM scanningyespartlywhat actually loaded, versus what the manifest pinned
IaC and policy-as-codeyesnothe identity and network the workload really got
Threat modellingyesre-run on driftentry points added by a config change, not a commit
Tool-schema and MCP surface reviewyesyesa description edited by a server after review
DAST / attack simulationagainst a replicayesresponses only a live system produces
Guardrails and egress enforcementconfig onlyyesthe request that was actually attempted
Runtime posture and driftnoyesa guardrail switched off after the demo — B3.9
Detection and canariesnoyessomebody using a credential nothing legitimate touches
Attestationsigns the claimre-checks itwhether the deployment still matches what was signed
Read the last column rather than the ticks. It is the sentence that says what each technique is structurally unable to see, and it is the one that decides whether two tools are coverage or two invoices.

4 · The placement, as a skill

The table above is a reference. This is the same question asked of CyberTravels' own inventory, which is the version that produces an answer somebody has to do something about.

It counts three things separately: how many of the techniques can actually block a merge, which risks are covered only on the side that can prevent them, and which only on the side that can merely observe. All three read as “covered” on a tooling inventory.

5 · What the counts are for

Three numbers come out of that run and each one has a different owner.

Gate-capable. Four of ten. Everything else produces a ticket, and a ticket is a request rather than a control. If your security posture depends on tickets being worked, it depends on next quarter's headcount.

Post-only risks. These are the ones that get signed off in a review, because a control exists, it runs, and it reports. It reports afterwards. The sign-off is not wrong about the control; it is wrong about what the control does.

Uncovered. One, and it is the subject of C2.7: an artefact in the build with no manifest entry has no identifier, so the SCA pass on the left never had anything to look up and the report was clean about it. That is a gap nothing on either side is currently pointed at.

▶Real time execution as skill

The skill — skills/appsec/sdlc-control-placement/SKILL.md

name: sdlc-control-placement
description: >-
  Place each security technique on the pre-deployment / post-deployment line and
  report which risks are covered only on the side that cannot act on them. Use
  when reviewing AppSec tooling coverage, when choosing where a new control
  belongs, or when a risk is described as covered and the incident happened
  anyway.
allowed-tools: Read, Grep, Glob

Which side of the deploy is each control on, and what does that cost?

Every security technique works on one of two things: artefacts sitting still — source, a manifest, an IaC plan, a tool schema — or a system that is running. That is not a taxonomy for its own sake. It decides two properties that nothing else changes:

  • pre-deployment is cheap, repeatable and can block a merge, and it is blind to every fact that only exists at runtime — the identity the workload actually got, the traffic it actually saw;
  • post-deployment sees what really happened and cannot block the change that caused it. It can only tell you afterwards.

A risk covered only on the left is a risk you can prevent and cannot detect. A risk covered only on the right is one you can detect and cannot prevent. Both appear as "covered" on a tooling inventory, and only one of them is what the person reading the inventory thought they were buying.

When to use this

Before buying anything, when a tooling inventory is presented as coverage, and after any incident where the answer to "did we have a control for that" was yes. Also when placing a new control: the same technique run at build time and at runtime answers different questions, and choosing is a design decision rather than a scheduling one.

Procedure

1 — List the techniques you actually run, not the ones on the architecture diagram. A tool that is deployed and muted is not a control.

2 — Place each one. Pre, post, or genuinely both. "Both" is rarer than it looks: a technique that runs at build time and again at runtime counts as both only if the runtime pass can see something the build pass could not.

3 — For each one, name what the other side sees that it cannot. This is the sentence that turns a list into an argument. If you cannot write it, the placement is wrong or the technique is not doing what you think.

4 — Map risks to sides, not to tools. For each risk class, which sides cover it. Then count the two failure shapes: preventable but invisible (pre only) and visible but unpreventable (post only).

5 — Report the uncovered and the one-sided separately. A risk with nothing on either side is a gap everybody understands. A risk covered only on the side that cannot act is the one that gets signed off, and it is the one this procedure exists to surface.

Example

Input — the fixture committed at the top of scripts/sdlc_control_placement.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:

techniques, placed
   technique                     side   gate  blind to
   SAST / code analysis          pre    yes   whether the vulnerable path is reached with real traffic
   SCA and SBOM scanning         pre    yes   what actually loaded, versus what the manifest pinned
   IaC and policy-as-code        pre    yes   the identity and network the workload really got
   threat modelling              pre    -     entry points added by a config change, not a commit
   tool-schema / MCP review      both   yes   a description edited by the server after review
   DAST / attack simulation      post   -     the commit that introduced it

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

{
  "techniques": [{"name": "str", "side": "pre|post|both", "blind_to": "str"}],
  "risks": [{"risk": "str", "sides": ["pre|post"], "shape": "covered|pre-only|post-only|uncovered"}],
  "counts": {"pre_only": 0, "post_only": 0, "uncovered": 0},
  "gate_capable": 0
}

gate_capable counts the techniques that can actually block a merge. It is usually much smaller than the tooling budget suggests, and it is the number that decides how much of your security posture is advisory.

Failure modes

  • Counting a muted tool as coverage. It runs, it reports, nobody reads it.
  • Marking everything "both". The word stops meaning anything and the one-sided risks disappear into it.
  • Assuming pre-deployment sees the deployment. It sees the plan. The identity the workload got, the route it can reach and the guardrail that was switched off after the demo are all facts that do not exist yet.
  • Reading post-deployment coverage as prevention. Detection tells you it happened. Nothing on that side of the line stops the merge.

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 C2.0

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

Then pick c2-0-the-ai-sdlc:

agentinstall just for this agentstart it
Claude Codepython3 scripts/install_skills.py --tool claude --lessons C2.0type /c2-0-the-ai-sdlc
GitHub Copilot (VS Code)python3 scripts/install_skills.py --tool copilot --lessons C2.0type /c2-0-the-ai-sdlc in Chat
Cursorpython3 scripts/install_skills.py --tool cursor --lessons C2.0type / in Agent chat and search for it
Codexpython3 scripts/install_skills.py --tool agents --lessons C2.0type $c2-0-the-ai-sdlc, 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 C2.0

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 C2.0 --out work/cybertravels
python3 scripts/checkpoint.py --at C2.0 --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

Four of ten techniques can block a merge; the other six produce tickets. Two risks are covered only before the deploy — preventable, and invisible once shipped — and three only after it, where detection is the whole of the control and the merge that caused it already went through. One is covered by nothing on either side, and that one is the undeclared vendored binary C2.7 goes after.

✎Your turn

Write your own inventory into the same two columns, then delete every row that is deployed and muted. What is left is your coverage. The row that will start an argument is the one somebody believes is preventative and is in the right-hand column.

Tools used

Claude Haiku 4.5

Skill source: skills/appsec/sdlc-control-placement

← PreviousB3.11 · Securing the developers' coding agents