Kokil Thapa - Professional Web Developer in Nepal
Freelancer Web Developer in Nepal with 15+ Years of Experience

Kokil Thapa is an experienced full-stack web developer focused on building fast, secure, and scalable web applications. He helps businesses and individuals create SEO-friendly, user-focused digital platforms designed for long-term growth.

Compliance as Code Explained

By Kokil Thapa | Last reviewed: September 2026

Manual compliance checklists fail the moment your team ships faster than your auditor can review spreadsheets. Compliance as Code Explained is the practice of encoding regulatory, security, and operational rules as version-controlled artifacts that run automatically in pipelines—much like infrastructure as code defines servers. On production Laravel and WordPress systems I maintain, compliance drift often appears first in deployment config, not in application logic. This guide maps the concept, the tooling stack, and the patterns that actually hold up under audit.

What Is Compliance as Code and How Does It Differ from Policy as Code?

Compliance as code is the umbrella. Policy as code is one implementation layer inside it. Think of compliance as the outcome auditors care about. Policy as code is how you express individual rules.

A SOC 2 control might require encrypted database connections. You encode that rule in Rego for Open Policy Agent (OPA). The pipeline evaluates every Terraform plan against it. A failed check blocks the merge. That is compliance as code in action.

Compliance as Code StackGit RepoRules + app codeCI PipelineTests + scansPolicy EngineOPA / SentinelEvidenceAudit logsCompliance Domains Encoded as CodeSecurityPrivacyOperationsFinance / VATData residency
Compliance as Code Explained: version-controlled rules flow through CI into policy engines and produce machine-readable audit evidence.

The distinction matters when you scope a project. Policy as code handles individual allow/deny decisions. Compliance as code adds traceability, evidence collection, control mapping, and remediation workflows on top.

Core artifact types

  • Policy definitions — Rego, Sentinel HCL, or YAML rules that express must-pass conditions.
  • Compliance tests — Automated checks tied to specific control IDs (CC6.1, GDPR Art. 32, etc.).
  • Evidence collectors — Scripts or pipeline jobs that export logs, scan results, and config snapshots.
  • Control matrices — YAML or JSON files mapping framework requirements to automated checks.

On a legal-tech portal I built, document retention rules lived in application code. The auditor wanted proof those rules were enforced consistently. Moving retention logic into tested, versioned policy files closed that gap faster than any policy PDF.

Why Should Teams Adopt Compliance as Code Instead of Manual Audits?

Manual audits snapshot a point in time. Production changes every day. Compliance as code gives you continuous assurance between audit cycles.

DimensionManual complianceCompliance as code
TimingQuarterly or annual reviewEvery commit and deploy
EvidenceScreenshots, spreadsheetsMachine-readable JSON, SARIF, signed artifacts
Drift detectionFound late, often by auditorBlocked at merge or deploy gate
Cost at scaleLinear with systems and headcountFixed pipeline cost, marginal per service
Developer frictionLast-minute fire drillsFast feedback in familiar CI tools
Audit prep timeWeeks of evidence gatheringExport from evidence store in hours

Startups chasing SOC 2 compliance feel this pain early. Enterprise clients ask for evidence before contract signature. Manual collection does not scale when you deploy ten times a week.

For Nepal-based SaaS companies, data residency requirements add another layer. Encoding region constraints in Terraform policy prevents accidental provisioning in the wrong AWS region. That single automated check beats a quarterly spreadsheet review.

How Do You Implement Compliance as Code in a CI/CD Pipeline?

Start small. Pick one high-risk control. Automate it. Expand from there. A common mistake is trying to map an entire SOC 2 framework before a single pipeline gate works.

CI/CD Compliance GatesCommitPush to GitSAST ScanSonarQubeIaC PolicyOPA / SentinelDeployIf all passEvidenceS3 / GCSFailure Paths Block MergeFail: open S3 bucketFail: no TLS 1.2+Fail: secrets in codeDeveloper gets fix-it-now feedback in MR
Compliance as Code Explained in CI: each gate maps to a control, blocks bad merges, and stores pass/fail evidence automatically.

Step 1: Map controls to automatable checks

Export your framework control list. SOC 2, ISO 27001, GDPR, PCI DSS, or Nepal-specific rules from eCommerce legal compliance guides. Mark each control as automated, partially automated, or manual-only.

Most security and change-management controls automate well. Physical security and HR background checks stay manual. Be honest about the split. Auditors respect accurate control matrices over inflated automation claims.

Step 2: Write the first policy file

Here is a minimal OPA Rego policy that denies public S3 buckets. Save it as policies/s3_public_access.rego:

package terraform.s3

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket"
  resource.change.after.acl == "public-read"
  msg := sprintf("S3 bucket %s must not be public", [resource.address])
}

deny[msg] {
  resource := input.resource_changes[_]
  resource.type == "aws_s3_bucket_public_access_block"
  not resource.change.after.block_public_acls
  msg := "Public access block must enable block_public_acls"
}

Run it with Conftest against a Terraform plan JSON file. The official Open Policy Agent documentation covers Rego syntax and testing patterns in detail.

Step 3: Wire the check into GitLab CI or GitHub Actions

A GitLab CI job for a Laravel 13 project on PHP 8.3 might look like this:

compliance:terraform-policy:
  stage: test
  image: openpolicyagent/conftest:latest
  script:
    - terraform init -backend=false
    - terraform plan -out=plan.tfplan
    - terraform show -json plan.tfplan > plan.json
    - conftest test plan.json -p policies/ --output json > policy-results.json
  artifacts:
    paths:
      - policy-results.json
    expire_in: 1 year
  rules:
    - if: $CI_PIPELINE_SOURCE == "merge_request_event"

Store artifacts for at least one audit cycle. Many teams keep twelve months. Align retention with your framework requirements and contract terms.

Step 4: Add application-level compliance tests

Infrastructure policy is not enough. Application code carries privacy and access-control obligations too. On Laravel apps I maintain, I add PHPUnit tests that verify authorization policies and data export endpoints.

public function test_user_cannot_download_another_users_document(): void
{
    $owner = User::factory()->create();
    $intruder = User::factory()->create();
    $document = Document::factory()->for($owner)->create();

    $response = $this->actingAs($intruder)
        ->get(route('documents.download', $document));

    $response->assertForbidden();
}

Tag these tests with a @group compliance annotation. Run them in a dedicated CI job. Export JUnit XML as evidence. This pairs well with code coverage gates in CI when you tie coverage thresholds to security-critical modules.

Step 5: Collect and index evidence

Each passing pipeline run produces artifacts. Scan reports, policy results, test output, dependency audit logs. Push them to an immutable store. S3 with Object Lock, GCS with retention policies, or a dedicated compliance platform.

Structure evidence by control ID. A JSON index file makes auditor queries fast:

{
  "control_id": "CC6.1",
  "framework": "SOC2",
  "automated_check": "terraform-s3-public-access-policy",
  "last_pass": "2026-09-08T14:22:00Z",
  "pipeline_url": "https://gitlab.example.com/project/-/pipelines/12345",
  "artifact_path": "s3://compliance-evidence/2026/09/CC6.1-12345.json"
}

The approach mirrors what I describe in automating SOC 2 compliance evidence in CI. The difference at scale is consistent naming and retention from day one.

Which Tools and Frameworks Support Compliance as Code?

No single tool covers every compliance domain. Mature teams assemble a stack. Each layer handles a different artifact type.

Compliance as Code Tool LayersPolicy EnginesOPA + ConftestTerraform, K8s, JSONHashiCorp SentinelTerraform Cloud / EnterpriseBenchmark ScannersOpenSCAPCIS, STIG, NIST profilesInSpec / Chef ComplianceServer and OS hardeningApp Security ScannersSonarQube / SemgrepSAST, secrets detectionComposer audit / npm auditEvidence PlatformsVanta / Drata / SecureframeSOC 2 evidence aggregationCustom S3 + indexer
Tool layers for Compliance as Code Explained: policy engines, benchmark scanners, app security tools, and evidence stores work together.
  1. Open Policy Agent (OPA) — General-purpose policy engine. Works with Terraform, Kubernetes, API gateways, and custom JSON inputs. See also policy as code with OPA and Conftest.
  2. HashiCorp Sentinel — Embedded in Terraform Cloud. Good if you already use HashiCorp stack. Covered in Sentinel policy as code for Terraform.
  3. OpenSCAP — Runs CIS and STIG benchmarks against Linux servers. Useful for Linux system administration hardening on Ubuntu 22/24 hosts.
  4. InSpec — Ruby-based compliance language for server and container configuration testing.
  5. SAST and dependency scanners — SonarQube, Semgrep, composer audit, npm audit for supply-chain controls.
  6. Evidence platforms — Vanta, Drata, Secureframe for SOC 2. Or roll your own with S3 and a searchable index.

For multi-cloud setups, read multi-cloud governance and policy as code. The same OPA policies can evaluate AWS, Azure, and GCP resource plans with minor input adapters.

The NIST Cybersecurity Framework gives a useful taxonomy for organizing controls. Map your automated checks to Identify, Protect, Detect, Respond, and Recover categories. Auditors recognize the structure even when your tooling is custom.

What Does Compliance as Code Look Like on a Real Production System?

Abstract patterns become clearer with a concrete walkthrough. Consider a Laravel 12 booking platform on AWS with MySQL 8.4, Redis 8.10, and GitLab CI.

Legal-Tech Portal: Compliance ChecksLaravel App — Client Documents + PaymentsSimilar to portals like Mijar Law AssociatesRBAC TestsSpatie PermissionRetention JobScheduled purgeTLS PolicyALB config scanBackupsDaily cronCommon Gotcha: Policy Passes, App FailsIaC allows HTTPS but Laravel debug mode left on in .envFix: add env validation step in Deployer 7 hook
Compliance as Code Explained on a legal-tech portal: infrastructure, application, and runtime checks must all run—see our Mijar Law Associates portfolio entry.

Projects like Mijar Law Associates and Notary Nepal handle sensitive client documents. Compliance as code for these systems spans three layers.

Infrastructure layer. Terraform policies enforce encrypted RDS instances, private subnets, and no public security group rules. OpenSCAP scans the Ubuntu EC2 host against CIS Level 1.

Application layer. PHPUnit tests verify RBAC with Spatie Laravel Permission. Feature tests confirm audit log entries on document download. A scheduled job test proves retention purge runs and respects configurable periods.

Runtime layer. A Deployer 7 post-deploy hook validates APP_DEBUG=false and APP_ENV=production in the live .env. This catches the gotcha shown above. Infrastructure can be perfect while application config drifts.

For WordPress 7.1 and WooCommerce 11.1 shops, compliance as code looks different. Plugin vulnerability scans, file integrity checks, and GDPR cookie consent tests replace Terraform policy. See WordPress GDPR compliance checklist for the control list.

Nepal-specific finance controls add another dimension. A SaaS billing in NPR must produce VAT-compliant invoices. Business rules belong in code with tests. Cross-check calculations with the Nepal salary calculator pattern—deterministic logic, versioned, testable. Read Nepal VAT and tax compliance for SaaS businesses for the regulatory context.

Encoding a retention policy in Laravel

// app/Console/Commands/PurgeExpiredDocuments.php
public function handle(): int
{
    $retentionDays = (int) config('compliance.document_retention_days', 2555);

    $expired = Document::query()
        ->where('created_at', '<', now()->subDays($retentionDays))
        ->whereNull('legal_hold_at')
        ->get();

    foreach ($expired as $document) {
        $document->delete(); // triggers media library cleanup
        activity()->performedOn($document)->log('retention_purge');
    }

    return self::SUCCESS;
}

Pair this with a test and a CI job. Export the activity log query result as quarterly evidence. The auditor sees automated purges happened on schedule.

How Do You Avoid Common Compliance as Code Mistakes?

Teams new to this approach repeat the same failures. Most are process problems, not tool problems.

  • Automating low-value controls first. Start with high-risk items: public exposure, unencrypted data, missing auth checks. Leave office-visitor-log automation for later.
  • Treating a passing scan as full compliance. Automated checks cover a subset of controls. Document which remain manual. Auditors will ask.
  • No evidence retention policy. Pipeline artifacts expire in thirty days by default. Extend retention before your first audit.
  • Policy files outside code review. Compliance rules must go through the same MR process as application code. No side-channel edits in the production console.
  • Ignoring developer ergonomics. Cryptic Rego errors frustrate teams. Write clear denial messages. Add conftest verify locally. Use the JSON formatter to debug plan output and the regex tester for log parsing rules.
  • Skipping runtime validation. IaC policy at plan time does not catch manual console changes or bad .env values. Add periodic drift detection with terraform plan -detailed-exitcode or scheduled OpenSCAP runs.

I've seen GitLab CI pipelines pass every policy check while cron jobs pointed at stale release paths after a Deployer symlink swap. Compliance as code must include operational checks, not just pre-merge gates. That lesson applies across the sister sites I maintain on shared EC2 infrastructure.

Engage your auditor early. Show them a sample evidence export and control matrix before the formal audit. Adjust naming and retention based on their feedback. This saves rework and builds trust.

For teams without in-house DevOps capacity, testing and optimization services or enterprise application development can bootstrap the first control set. The goal is a maintainable baseline your team owns afterward.

Key Takeaways

  • Compliance as code encodes audit requirements as version-controlled, executable rules—not static PDF checklists.
  • Start with one high-risk control, automate it in CI, store the evidence, then expand the control matrix incrementally.
  • Combine infrastructure policy (OPA/Sentinel), application tests (PHPUnit/feature tests), and runtime validation (deploy hooks, OpenSCAP).
  • Map every automated check to a framework control ID and retain artifacts for at least one full audit cycle.
  • Legal-tech, eCommerce, and SaaS systems in Nepal need both global frameworks (SOC 2, GDPR) and local rules (VAT, data residency).
  • Treat compliance policies like production code: code review, tests, clear error messages, and no manual console exceptions.

People Also Ask

Is compliance as code only for large enterprises?

No. Startups benefit most because they build automation habits before complexity grows. A five-person team with GitLab CI and ten OPA policies can produce cleaner SOC 2 evidence than a fifty-person team relying on quarterly manual reviews.

Can compliance as code replace an external auditor?

It cannot. Auditors still evaluate control design and operating effectiveness. Compliance as code reduces evidence-gathering time and proves continuous operation. It makes audits faster and cheaper, not unnecessary.

How does compliance as code relate to Infrastructure as Code?

Infrastructure as Code defines what your servers and networks should look like. Compliance as Code validates that those definitions—and the resulting deployments—meet regulatory and security requirements. IaC is the input; compliance checks are the guardrails.

What frameworks work best with compliance as code?

SOC 2, ISO 27001, CIS Benchmarks, and PCI DSS map well because their controls are specific and testable. GDPR and Nepal VAT rules work for application-level and business-logic checks. Physical and HR controls remain manual by nature.

Build Compliance Into Your Pipeline From Day One

Compliance as Code Explained is not a enterprise-only buzzword. It is how small teams stay audit-ready while shipping weekly on Laravel 13, WordPress 7.1, or custom platforms. Encode your highest-risk controls first. Wire them into CI. Store the evidence. Expand the matrix as your product and client requirements grow.

If you need help mapping controls to a concrete pipeline for a legal portal, eCommerce store, or SaaS product, review the Court Marriage In Nepal and Nepal Divorce Services portfolio entries for examples of compliance-sensitive workflows. For hands-on implementation, explore custom software development or reach out via contact us to discuss your control matrix and CI setup.

Frequently Asked Questions

Compliance as Code Explained means writing audit and regulatory requirements as executable, version-controlled rules—policies, tests, and evidence collectors—that run in CI/CD and block non-compliant changes before they reach production. Instead of quarterly spreadsheet reviews, every merge and deploy is checked automatically, and pass/fail results are stored as machine-readable evidence auditors can query later.

Compliance as code is the umbrella outcome auditors care about. Policy as code is one implementation layer inside it—individual allow/deny rules, such as a Rego policy denying public S3 buckets evaluated against a Terraform plan. Compliance as code adds traceability, evidence collection, control mapping to framework IDs like CC6.1 or GDPR Art. 32, and remediation workflows on top of those individual policy decisions.

Manual audits snapshot one point in time while production changes daily. Compliance as code gives continuous assurance between audit cycles. Evidence becomes machine-readable JSON and SARIF instead of screenshots. Drift is blocked at merge or deploy gates rather than found late by an auditor. At scale, pipeline cost stays fixed while manual compliance cost grows linearly with systems and headcount—painful for startups deploying ten times weekly.

No. Startups benefit most because they build automation habits before compliance debt accumulates. Enterprise clients often request SOC 2 evidence before contract signature. Manual collection cannot keep pace with frequent deploys. Nepal-based SaaS companies face added data residency requirements—encoding region constraints in Terraform policy prevents accidental provisioning in the wrong AWS region better than quarterly spreadsheet reviews.

Four artifact types form the foundation. Policy definitions express must-pass conditions in Rego, Sentinel HCL, or YAML. Compliance tests tie automated checks to specific control IDs. Evidence collectors export logs, scan results, and config snapshots from pipeline runs. Control matrices are YAML or JSON files mapping framework requirements to those automated checks, giving auditors a clear map of what is covered versus manual-only.

Start small with one high-risk control, not an entire SOC 2 framework. Map controls as automated, partially automated, or manual-only. Write your first policy file, wire it into GitLab CI or GitHub Actions, add application-level PHPUnit tests tagged @group compliance, then collect artifacts into an immutable evidence store indexed by control ID. Store pipeline artifacts for at least one full audit cycle—many teams keep twelve months aligned with framework requirements.

A Rego policy saved as policies/s3_public_access.rego can deny Terraform plans that create public-read S3 buckets or omit block_public_acls on public access blocks. Run it with Conftest against terraform show -json plan output. Failed checks block the merge request. Clear denial messages in the policy help developers fix issues without deciphering cryptic Rego errors—run conftest verify locally before pushing.

No single tool covers every domain; mature teams assemble a stack. OPA and Conftest handle general policy evaluation on Terraform and Kubernetes. HashiCorp Sentinel embeds in Terraform Cloud. OpenSCAP runs CIS and STIG benchmarks on Ubuntu 22/24 hosts. InSpec tests server configuration. SAST and dependency scanners like SonarQube, Semgrep, composer audit, and npm audit cover supply-chain controls. Evidence platforms include Vanta, Drata, Secureframe, or a roll-your-own S3 store with a searchable index.

On a Laravel 12 booking platform with MySQL 8.4, Redis 8.10, and GitLab CI, checks span three layers. Infrastructure: Terraform policies enforce encrypted RDS, private subnets, and no public security groups; OpenSCAP scans the Ubuntu EC2 host. Application: PHPUnit verifies RBAC via Spatie Laravel Permission and audit logs on document download. Runtime: a Deployer 7 post-deploy hook validates APP_DEBUG=false and APP_ENV=production in the live .env.

WordPress 7.1 and WooCommerce 11.1 shops need a different stack than Terraform-centric setups. Replace infrastructure policy with plugin vulnerability scans, file integrity checks, and GDPR cookie consent tests. The control list aligns with a WordPress GDPR compliance checklist. eCommerce legal obligations—retention, consent, export—still belong in tested, versioned code rather than ad hoc admin configuration changes outside review.

Infrastructure policy alone misses privacy and access-control obligations in application code. Add PHPUnit feature tests verifying authorization policies— for example, confirming one user cannot download another user's document. Tag tests with @group compliance, run them in a dedicated CI job, and export JUnit XML as evidence. Pair with code coverage gates on security-critical modules. On legal-tech portals, retention purge commands should have tests proving scheduled jobs respect configurable periods and legal holds.

Each passing pipeline run produces scan reports, policy results, test output, and dependency audit logs. Push artifacts to an immutable store—S3 with Object Lock, GCS with retention policies, or a dedicated compliance platform. Structure evidence by control ID in a JSON index linking framework, automated check name, last pass timestamp, pipeline URL, and artifact path. Default thirty-day artifact expiry is too short; extend retention before your first audit.

Automating low-value controls first instead of high-risk items like public exposure or missing auth checks. Treating a passing scan as full compliance without documenting manual-only controls. Letting pipeline artifacts expire in thirty days. Editing policy files outside code review via production console exceptions. Skipping runtime validation—I have seen GitLab CI pass every policy check while cron jobs pointed at stale release paths after a Deployer symlink swap. Engage auditors early with sample evidence exports.

Yes. Nepal-based SaaS and eCommerce systems need both global frameworks like SOC 2 and GDPR and local rules. Data residency constraints belong in Terraform policy. VAT-compliant NPR invoicing requires business rules in code with deterministic, versioned, testable calculations—not spreadsheet logic. Document retention, consent, and export obligations on legal-tech portals should mirror the same pattern: encoded rules, PHPUnit tests, and quarterly evidence exports from activity logs proving purges ran on schedule.

Pick one high-risk control and automate it before mapping an entire framework. External help can bootstrap the first control set and wire GitLab CI jobs for Terraform policy and PHPUnit compliance tests, but the goal is a maintainable baseline your team owns afterward. Show auditors a sample evidence export and control matrix early, adjust naming and retention from their feedback, then expand incrementally—accurate partial automation beats inflated claims about full framework coverage.

Share this article

0 Comments

Leave a comment

Your email is not published. Comments appear once they have been read. Sign in to have your details filled in.

Quick Contact Options
Choose how you want to connect me: