VaultGRC EngineeringCompliance as code: turning controls into automated checks auditors accept
GRC Engineering · Guide

Compliance as code: turning controls into automated checks auditors accept

Compliance as code: turning controls into automated checks auditors accept

Harry WestFounder & CEO21 October 202611 min read
Inside This Article
What is compliance as code?What does a compliance as code check need to contain?How do auditors decide whether automated evidence counts?Why is the compliance check a control in its own right?How should you handle exceptions and false positives?Which controls should you codify first, and which stay manual?What format should compliance as code evidence take?What does compliance as code look like for one control?What are the common mistakes with compliance as code?Frequently asked questions
Book a discovery call

Key takeaways

Compliance as code expresses control requirements as automated, version-controlled checks that test systems on a schedule and record each result as evidence. Unlike policy as code, it detects and proves rather than blocks. Auditors rely on a check only when it maps to a control, its logic is reviewed and change-controlled, and its results are complete and retained for the whole period.

Information produced by the entity
ISA (UK) 500 paragraph 9 requires auditors to evaluate whether information produced by the entity is reliable enough, including evidence about its accuracy and completeness.
Period of reliance
ISA (UK) 330 paragraph 11 requires auditors to test controls for the particular time, or throughout the period, for which they intend to rely on them.
Automated control consistency
ISA (UK) 330 paragraph A29 notes an automated control can be expected to function consistently unless the IT application is changed, so changes to the check matter.
OSCAL assessment results
NIST's OSCAL assessment results model records observations with their evidence, findings that can show control objective status, and timestamps, and supports continuous assessment.

Your engineers wrote a script that checks every cloud account for multi-factor authentication each night. It works. Then the auditor asks three questions: which control does it test, who approved its logic, and can you prove it ran on every day of the report period? Nobody has a clean answer, and the enterprise renewal is waiting on the SOC 2 report. That gap, between a script that works and evidence an auditor accepts, is what compliance as code has to close.

This guide is for heads of compliance, GRC leads and CTOs at UK B2B tech firms who already run automated checks and now have to defend them. It shows how compliance as code turns a control into a check an auditor can rely on: the anatomy of a check, how auditors test system-generated evidence, what to codify first, and a worked example.

What is compliance as code?

Compliance as code is the practice of expressing control requirements as automated, version-controlled checks that test your systems on a schedule and record each result as evidence. Policy as code blocks bad changes before they happen; compliance as code detects drift and proves the control held. The checks only count when each is mapped, reviewed and complete.

The two ideas share tooling, which is why they get confused. A policy engine in a deployment pipeline stops a change that breaks a rule. A compliance check looks at the live estate, compares it with the control requirement and writes down what it found.

Most firms need both. This page covers the detective side and the evidence it produces.

The term also gets used for writing policies in Markdown and storing them in Git. That is good document control, and it is not what an auditor means by a coded check.

What does a compliance as code check need to contain?

A compliance as code check needs eight parts: the control objective, the framework reference by ID, the data source, the test logic, the pass and fail criteria, the frequency, a named owner and the evidence record it writes. Missing any one of them leaves a question the auditor will ask, and the script cannot answer.

We recommend writing these parts down as a short specification that sits beside the code, in the same repository:

PartWhat it recordsExample for MFA enforcement
Control objectiveThe outcome the control exists to achieve, in plain EnglishOnly authenticated staff with a second factor can sign in to production consoles
Framework referenceThe requirement IDs the check supportsISO 27001 Annex A 8.5; SOC 2 CC6
Data sourceThe system the check reads, and howThe identity provider's user directory, read through its administration interface with a read-only account
Test logicWhat the check compares, in a sentence a non-engineer can followEvery active user in the production access group has a registered second factor and is covered by an enforcement rule
Pass and fail criteriaThe exact condition for each resultPass: zero users without enforced MFA. Fail: one or more, listed by user ID
FrequencyHow often it runs, and the triggerDaily at 02:00, and after any change to the access group
OwnerThe named person who acts on a failHead of IT operations
Evidence outputWhat is written, where, and for how longA dated, signed result record with the population count, kept in write-once storage for the report period plus one year

The specification is what the auditor reads first. The code is what they test against it.

A check with no control objective is not a control. It is a script with an opinion.

How do auditors decide whether automated evidence counts?

Auditors treat a check's output as information produced by the entity, so they test whether it is complete and accurate before relying on it. They then test the check's design and whether it operated across the whole period. A check that passes all three tests covers the whole population, where a screenshot sample covers a handful of items.

The UK auditing standards, written for financial statement audits, set out the logic plainly. ISA (UK) 500, paragraph 9, requires the auditor to evaluate whether information produced by the entity is sufficiently reliable, including evidence about its accuracy and completeness. Paragraph A61 adds that the auditor may get that evidence by testing the controls over how the information is prepared and maintained.

For a coded check, that means three things the auditor will look for:

  1. Completeness of the population. The check read every account, user or resource in scope, not only the ones it could reach. A count of what was tested, reconciled to an independent list, answers this.
  2. Accuracy of the logic. The test does what its specification says. The auditor may re-run it, read the code or test it against a known failure.
  3. Integrity of the output. The result record could not have been edited after it was written.

Design and operation are separate tests. ISA (UK) 330, paragraph 11, requires the auditor to test controls throughout the period they intend to rely on them. The same idea sits behind a SOC 2 Type 2 report, which covers how controls operated over a period rather than at one date. ISA (UK) 402 defines a type 2 service organisation report in the same terms.

Automation helps here. ISA (UK) 330 paragraph A29 notes that an automated control can be expected to function consistently unless the application is changed. The auditor may then test that it continues to work, including the general IT controls around it. That shifts the weight onto the next question: who can change the check?

Why is the compliance check a control in its own right?

The compliance check is a control in its own right because the evidence it produces is only as trustworthy as the process that changes it. If anyone can edit the logic, switch it off or delete a failed result without review, the auditor cannot rely on the output, however good the code looks.

ISA (UK) 330 paragraph A36 says an auditor may check whether an automated control has changed by inspecting logs that show what was changed. Your repository history is that log, if you run it properly.

We recommend treating the check repository like production code under ISO 27001 Annex A 8.32 change management:

  • Peer review. Every change to test logic or pass criteria goes through a reviewed pull request, approved by someone other than the author.
  • Restricted access. Few people can merge, and the people whose systems are being tested cannot change the checks that test them.
  • Traceable releases. Each result record names the version of the check that produced it.
  • Protected history. Results and run logs are kept in storage that the check's own operators cannot overwrite.

The same discipline covers the SOC 2 change management criteria in the CC8 series. One change process can serve both frameworks.

A coded control that anyone can quietly edit gives no more assurance than a spreadsheet.

How should you handle exceptions and false positives?

Handle exceptions and false positives through a recorded process, not by editing the check. A genuine exception needs an owner, a reason, a compensating control and an expiry date. A false positive is a defect in the check, so the fix goes through the same reviewed change as any other logic change, with the fail result kept.

Most coded checks will flag something you decide to accept: a service account that cannot hold a second factor, or a legacy system with a retirement date. We recommend an exception register that records:

  • the check and the resource it excepts;
  • why the exception exists, and who approved it;
  • the compensating control, such as network restriction or extra logging;
  • the expiry date, after which the check fails again.

The check should read the register and report excepted items as a separate result, not as passes. The auditor then sees every exception, who approved it and whether it lapsed.

False positives are different. If the check fails something that meets the control, correct the logic, and keep the original fail alongside a note that links to the fix.

An exception with no expiry date is a policy change that nobody approved.

Which controls should you codify first, and which stay manual?

Codify the controls that test system state first: configuration, access, encryption, logging and patching. Their requirements are objective, their data sits in systems you can query, and they change often enough for a point-in-time sample to miss drift. Controls that rest on human judgement stay manual, with automation supporting the record.

Control typeExamplesApproach
System state, objectiveMFA enforcement, encryption at rest, logging enabled, public storage blockedCodify first: full population, frequent runs
Process with a system trailLeaver access removed within the agreed time, changes approved before deploymentCodify the comparison between two records
Periodic human activityAccess reviews, backup restore testsAutomate the reminder and the record; a person does the review
JudgementRisk acceptance, management review, supplier due diligenceStay manual; keep the decision and its reasoning

Judgement controls stay manual because the auditor is testing the quality of a decision, not the state of a system. A script can prove a management review meeting was held. It cannot prove the meeting weighed the right risks.

Your own reviews of whether you meet your policies, under ISO 27001 Annex A 5.36, sit across both groups. Coded results feed the review, and a person signs it.

What format should compliance as code evidence take?

Compliance as code evidence should be a structured, dated record that names the control, the check version, the population tested, the result and any exceptions, kept unaltered for the whole report period. NIST's OSCAL is the open standard for that record, so your results can move between tools and assessors without rework.

OSCAL, the Open Security Controls Assessment Language, is a NIST-led initiative with machine-readable formats in XML, JSON and YAML. It is organised in three layers:

  • Control layer: catalogues of controls and profiles that select and tailor them.
  • Implementation layer: system security plans and component definitions that say how a system meets the controls.
  • Assessment layer: assessment plans, assessment results, and plans of action and milestones.

The OSCAL assessment results model is the one that matters for coded checks. It holds observations with their evidence, findings that can show each control objective's status, and a log of assessment actions with start and end timestamps. NIST says it also supports reporting continuous assessment information.

You do not have to adopt OSCAL on day one. We recommend at least matching its shape: one record per run, with the control reference, the timestamps, the observation and the finding. Converting later is then a mapping exercise.

Retention follows the audit, not the tool. We recommend keeping every result record and run log for the full report period, plus enough time for the auditor to finish, and a gap in that run history needs an explanation on file. The idea of ongoing control monitoring is set out in NIST SP 800-137, NIST's guide to information security continuous monitoring.

What does compliance as code look like for one control?

Compliance as code for one control runs from the requirement to the check to a stored evidence record. Taking MFA enforcement as the example: the requirement comes from ISO 27001 Annex A 8.5 and the SOC 2 CC6 series, the check tests every in-scope user daily, and each run writes a record the auditor can sample.

Step 1: the requirement. Your access control policy says all staff signing in to production systems use multi-factor authentication. That supports ISO 27001 Annex A 8.5 secure authentication and the logical access criteria in the CC6 series of the SOC 2 Trust Services Criteria.

Step 2: the specification. The eight parts from the table above, written down and approved by the control owner before any code is written.

Step 3: the check. A small job reads the identity provider, lists every active user in the production access group, and confirms each one has a registered second factor and an enforcement rule. It counts the population, reads the exception register and writes the result.

Step 4: the evidence record. Each run stores one record:

FieldIllustrative value
ControlProduction MFA enforcement (ISO 27001 A.8.5; SOC 2 CC6)
Check versionRepository tag v1.4, approved in a reviewed pull request
Run start and end2026-09-14 02:00:03 to 02:00:41 UTC
Population87 active users in the production access group; directory export count 87
ResultPass: 86 enforced, 1 excepted
ExceptionBreak-glass account, approved by the CTO, expires 2026-12-31, compensated by an alert on any sign-in
IntegrityWritten to write-once storage; record hash logged

These values are illustrative, not drawn from a real system.

Step 5: what the auditor tests. They reconcile the population count to the directory, read the specification against the code, re-run the check or test it with a known failing account, and sample records across the period. Then they check the repository history for changes to the logic.

What are the common mistakes with compliance as code?

The common mistakes with compliance as code are checks with no control mapping, scripts that change without review, gaps in the run history and dashboards that nobody signs off. Each one leaves the auditor with output they cannot rely on, so the team falls back to screenshots in the middle of fieldwork.

  • No control mapping. A check that tests something useful but maps to no control objective produces data, not evidence.
  • Unreviewed scripts. One engineer wrote it, nobody else has read it, and the logic changed twice during the period.
  • Gaps in the run history. The job failed silently for three weeks and nobody noticed. Under ISA (UK) 330 paragraph 11, a period you cannot evidence is a period the auditor cannot rely on.
  • Population not reconciled. The check passed every account it could reach, and nobody asked how many it could not.
  • Dashboards nobody signs off. A live dashboard shows the state today. The auditor needs the record for each day, and evidence that someone acted on the fails.

A green dashboard with gaps in its history proves only that it was green when someone looked.

Frequently asked questions

No. Compliance as code changes what the auditor tests, not whether they test. Instead of sampling screenshots, they test the check's design, the completeness of its population and the integrity of its records. The audit can be faster, but the auditor still forms an independent view of the evidence.

No. A version-controlled repository, a scheduler, read-only access to the systems in scope and write-once storage for results are enough for a first set of checks. The discipline around review, exceptions and retention matters more than the tooling, and it carries over if you adopt a platform later.

We recommend starting with five to ten system-state controls that your auditor currently samples by screenshot, such as MFA, encryption at rest and logging. Run them for a full quarter before the report period starts, so the run history, the exception register and the review process are proven before they count.

Yes. Map each check to every requirement it supports, by ID, in its specification. One MFA check can support ISO 27001 Annex A 8.5 and the SOC 2 CC6 series. Each auditor still decides whether the evidence meets their own criteria, so keep the mapping precise.

Profile image for Harry West, Founder and CEO of GRCMANA
Author

Harry West

Harry is the founder of GRCMANA, he helps regulated service providers close the enterprise trust gap — turning GRC, cyber resilience and AI governance from paperwork exercises into shippable systems.

Domain engine

GRC Engineering reference directory.

Every guide in this domain, grouped by level — fundamentals, intermediate and advanced. Open any entry for its core practices, implementation steps and the evidence it produces.

01Fundamentals2 guides
How to choose GRC tools: a vendor-neutral selection guide→Compliance automation: what to automate first, and what never to→
02Intermediate6 guides
GRC metrics: the KPIs that show your compliance programme is working, and how to collect them automatically→Security metrics: the 10 measures a B2B tech firm should report to its board, customers and investors→Automated evidence collection: build an audit evidence catalogue that collects itself→Security questionnaires: how to answer once and reuse everywhere→Trust centre: what to publish and how to run one→Control testing: design vs operating effectiveness, and how to automate it→
03Advanced4 guides
Unified control library: how to build one common control framework for every standard→Compliance as code: turning controls into automated checks auditors accept→Policy as code: which security controls to encode first→Continuous control monitoring: how to test controls automatically between audits→
GRC Engineering Accelerator

Ready to stop rebuilding evidence for every audit?

Work with a Trust Architect to automate evidence collection and continuous control monitoring, so your next audit and your next security questionnaire draw on the same live controls.

Book a call →
GRCMANA
  • About
  • Insights
  • Contact
Ask the Trust ArchitectBook a Call →
  • About
  • Insights
  • The Vault
    Compliance VaultCyber Essentials→ISO 27001→SOC 2→ISO 42001→
    Domain VaultGRC Fundamentals→Risk Management→AI Governance→GRC Engineering→
    Other ResourcesFree Tools→Templates→Newsletter→
  • Contact
Book a Call →Ask the Trust ArchitectFixed fee. ISO 27001 in as few as six weeks.
GRCMANA

Helping high-growth B2B tech startups close the Enterprise Trust Gap through security, governance, and AI resilience.

ISO 27001ISO 42001ISO 9001Cyber EssentialsEU AI Act ReadyNIST AI RMF

The Vault

GRC EngineeringAI GovernanceISO 27001ISO 42001All Vault Resources

Resources

BlogFree ToolsTemplatesNewsletter

Company

About GRCMANAContactPrivacy PolicyTerms & ConditionsCookie Policy
© 2025 GRCMANA · All rights reservedRegistered in England & Wales under company registration 16810805. VAT Registration 506308024