heygrc
Guide

Compliance checks for AI-generated code

An AI agent can write code that is correct, safe, and appropriately licensed, and still move a control you are audited on. Bug, vulnerability, and license scanners are not built to read that. Here is what a compliance check for AI-generated code actually reads, with a worked example.

the heygrc team

On a team that leans on coding agents, those agents open a large share of the pull requests that ship, and they are often good at the visible task: the feature works, the tests pass, the dependencies are current. What an agent may have no reason to weigh is whether a change moved a control your company is audited on, because that obligation lives in your frameworks and your context, not in the diff it was asked to produce. That gap is what a compliance check for AI-generated code is for.

The existing roundups of AI code-compliance tools mostly mean one of three things: static analysis for bugs, dependency and license scanning, or secret detection. Those are real and worth running. None of them is built to read a change against SOC 2, ISO 27001, or the GDPR at the level of a specific control, which is a different question asked of the same pull request.

What compliance means here, at the control level

Compliance for AI-generated code is not a license-header check or a vulnerability score. It is the question of whether a change touched a control you are obligated to keep: a logical-access boundary, an audit-log record, an encryption floor, a retention limit. Those obligations are named in the frameworks your company selected, at a grain you can verify, for example ISO 27001:2022 A.8.15 for logging or GDPR Art. 5(1)(c) for data minimisation.

The reason this is a separate reading is that a control-relevant change is usually correct code. It typically compiles, it is safe, it is properly licensed, and it does what the agent was asked to do. The problem is not a defect in the change; it is that the change quietly moved something an auditor may later examine. A check that only looks for defects is not built to flag that.

A worked example: an agent enriches a profile with more data than it needs

Suppose an agent is asked to add a loyalty-tier badge to the account page. To compute the tier it adds a user_profile cache and populates it from the identity service. The straightforward way to do that, and a way an agent optimising for the task might pick, is to copy the whole identity record into the new store: date of birth, national ID, home address, and phone, alongside the tier and display name the badge actually uses.

The migration is clean and the feature works on the first try. But the new store now holds four categories of personal data the loyalty badge has no purpose for. That is data minimisation, GDPR Art. 5(1)(c): personal data must be adequate, relevant, and limited to what is necessary for the purpose. The fix is one line of intent, populate the cache with the tier and display name only, and it is cheapest to make in the pull request that introduced the store, while the author still has the context. Left in, it becomes a new store containing personal data unnecessary for its stated purpose, discovered months later.

Why bug, vulnerability, and license scanners are not built to catch this

The change above is not the kind of thing those scanners are built to catch: the code is correct, so a bug scanner passes it; no new dependency arrived, so a license scanner passes it; and a vulnerability scanner is not built to read a widened personal-data footprint as a finding. So the scanners built to find those things are working as designed when they pass it, because a control-relevant change that is otherwise clean is not what they are built to read. This is not a knock on them; catching bugs, vulnerabilities, and license drift is genuinely valuable, and an agent's output needs all of it.

It does mean a compliance reading is a distinct layer, not a stronger version of the same scan. It reads the diff against the frameworks you are bound to and names the control the change touched, which is information the other tools are not built to produce. The sensible posture is to run both: the code-quality and security scanners for defects, and a compliance check for control drift, on the same pull request.

The shift that makes this urgent

Two things change when agents write a large share of the code. Volume: an agent opens more pull requests than a careful human compliance reading can keep up with, so the reading either becomes the bottleneck or gets skipped. Failure shape: an agent optimises for the visible task, so control code that reads as friction, a log line, a permission check, a retention limit, is exactly the kind of thing a diff can trim or widen without noticing.

Regardless of who wrote a change, the auditor still assesses whether the control operated, so AI-written code is held to the same bar as human code. What has to change is that the compliance reading now has to run at machine speed to keep pace, which means automating the first pass and reserving human judgment for the flagged cases.

How to add the check

A compliance check for AI-generated code runs on the pull request the way your other checks do: it triggers when a PR is opened or updated, reads the diff against the frameworks you have selected and your company context, and posts the controls a change touches with the clause attached, as a comment plus a neutral status. When an agent opens the PR, the check meets the code where the agent already put it, with no extra step for the human who has to sign off.

heygrc is built to be that check as a GitHub App: install it, configure your frameworks and context once (a single REST call your coding agent can make for you), and it reviews each pull request for compliance impact and cites the control at the diff. It posts a neutral Checks status plus inline comments, so it informs rather than blocks unless you choose to require it. Use it alongside your bug and security scanners, not instead of them.