heygrc
Field notesthe heygrc team

The one-line PR that quietly broke ISO 27001 A.8.15

Compliance does not fail in the audit. It fails in a five-line pull request that looked like a cleanup.

The audit is where you find out. The pull request is where it happened. Somewhere between those two moments, often months apart, a control that an auditor will sample stopped operating, and nobody noticed, because the change that broke it did not look like a compliance change. It looked like a cleanup.

Here is the shape of it. The control is ISO 27001:2022 A.8.15, logging. The change is one deleted line.

The change

A pull request tidies up a function that updates a user's role. There is a log call in the middle that the author reads as noise, it fires on every role change and clutters the output, so it goes. The function still works. The tests still pass. The diff is one line shorter and, if anything, cleaner.

access/roles.ts+0 -1
async function updateRole(actor, target, role) {  await db.roles.set(target, role)-  await audit.log("role.update", { actor, target, role })  return ok()}
heygrcISO 27001:2022 A.8.15

That line was the audit record for a change to access rights. A.8.15 (logging) expects security-relevant events, including changes to privileges, to be recorded and retained, and A.8.16 (monitoring) depends on that record existing. Deleting it removes the only evidence that a role ever changed.

Why nobody caught it

A reviewer looking at this diff sees a removed log line. To catch the problem, they would have to know that this particular log is the evidence for a control, that the control is A.8.15, and that A.8.15 is in scope for their certification. That is three pieces of framework knowledge a code reviewer is not carrying in their head while they approve a routine refactor.

This is the gap. The checkpoint is in the right place, code review already looks at every change, on purpose, before it ships. What is missing is the framework awareness to recognise that an ordinary-looking line is load-bearing for an audit.

What it costs later

Caught here, this is a one-line revert and a thirty-second conversation. The author still has the whole change in their head. Caught in the audit, it is an exception: the control did not operate across the window, and now someone has to reconstruct when the logging stopped, what depended on it, and how to restore it safely, on a deadline, possibly after the author has left.

The cost of a compliance gap is set by one thing: how long it sat there before anyone noticed. The pull request is the cheapest possible place to notice.

The point

Compliance fails in a five-line PR, not in the audit. The audit is a lagging indicator of a decision someone made in a diff weeks earlier. heygrc is built to read that diff against the frameworks you have to meet and name the control a change touches, A.8.15, on the pull request, while the fix is still cheap. heygrc is in early access.

iso-27001loggingcode-reviewshift-left