DEV Community

Ahmed Moussa
Ahmed Moussa

Posted on

How to Automate SOC2 and GDPR Compliance Scans with ComplianceWeave

---
title: "I Automated My SOC2 Audit Prep in an Afternoon (And You Can Too)"
published: false
tags: [security, devops, python, compliance]
---

Picture this: it's 11 PM, three weeks before your SOC2 audit, and you're manually screenshotting AWS console pages into a Google Doc labeled `evidence_FINAL_v3_USE_THIS_ONE.docx`.

We've all been there. Or we've *heard* the war stories.

This tutorial is the exit ramp from that highway to misery. We're going to wire up **ComplianceWeave** to your infrastructure and have it do the evidence-hunting while you do literally anything else.

By the end, you'll have a Python script that scans your environment, surfaces gaps, triggers remediation, and hands you a polished audit report — automatically.

Let's build it.

---

## What We're Working With

ComplianceWeave exposes three endpoints that, chained together, form a complete compliance automation loop:

| Endpoint | What it does |
|---|---|
| `POST /compliance/scan` | Kicks off an infrastructure scan against your chosen frameworks |
| `GET /compliance/reports` | Fetches generated audit-ready reports |
| `POST /compliance/remediate` | Auto-remediates fixable violations |

We'll use all three. In order. Like sensible engineers.

---

## Prerequisites

Enter fullscreen mode Exit fullscreen mode


bash
pip install requests python-dotenv rich


We're using `rich` for readable terminal output because staring at raw JSON at 11 PM is a form of self-harm.

Create a `.env` file:

Enter fullscreen mode Exit fullscreen mode


bash
COMPLIANCEWEAVE_API_KEY=your_api_key_here
COMPLIANCEWEAVE_BASE_URL=https://api.complianceweave.io/v1


---

## Step 1: Set Up Your Client

First, let's build a small, reusable client so we're not copy-pasting headers into every request.

Enter fullscreen mode Exit fullscreen mode


python

compliance_client.py

import os
import time
import requests
from dotenv import load_dotenv
from rich.console import Console
from rich.panel import Panel

load_dotenv()
console = Console()

class ComplianceWeaveClient:
def init(self):
self.api_key = os.getenv("COMPLIANCEWEAVE_API_KEY")
self.base_url = os.getenv("COMPLIANCEWEAVE_BASE_URL")

    if not self.api_key:
        raise EnvironmentError(
            "COMPLIANCEWEAVE_API_KEY not set. "
            "Check your .env file."
        )

    self.session = requests.Session()
    self.session.headers.update({
        "Authorization": f"Bearer {self.api_key}",
        "Content-Type": "application/json",
        "Accept": "application/json",
    })

def _request(self, method, endpoint, **kwargs):
    url = f"{self.base_url}{endpoint}"
    try:
        response = self.session.request(method, url, **kwargs)
        response.raise_for_status()
        return response.json()
    except requests.exceptions.HTTPError as e:
        console.print(f"[bold red]HTTP Error:[/bold red] {e.response.status_code} — {e.response.text}")
        raise
    except requests.exceptions.ConnectionError:
        console.print("[bold red]Connection failed.[/bold red] Is the API URL correct?")
        raise
    except requests.exceptions.Timeout:
        console.print("[bold red]Request timed out.[/bold red] Try again or check your network.")
        raise
Enter fullscreen mode Exit fullscreen mode

**Why a session object?** It reuses the TCP connection across requests, which matters when you're hitting the API repeatedly during a scan-poll loop. Small wins add up.

---

## Step 2: Trigger a Compliance Scan

Now let's initiate a scan. ComplianceWeave lets you specify which frameworks to check — we'll target SOC2 and GDPR simultaneously.

Enter fullscreen mode Exit fullscreen mode


python

scan.py

from compliance_client import ComplianceWeaveClient, console
from rich.progress import Progress, SpinnerColumn, TextColumn
import time

def run_scan(client, frameworks=None, environment="production"):
if frameworks is None:
frameworks = ["SOC2", "GDPR"]

console.print(Panel(
    f"Starting scan for: [bold cyan]{', '.join(frameworks)}[/bold cyan]\n"
    f"Environment: [bold]{environment}[/bold]",
    title="🔍 ComplianceWeave Scan"
))

payload = {
    "frameworks": frameworks,
    "environment": environment,
    "options": {
        "deep_scan": True,         # Check resource-level configs, not just account-level
        "include_remediation": True # Flag auto-fixable issues
    }
}

response = client._request("POST", "/compliance/scan", json=payload)
scan_id = response.get("scan_id")

if not scan_id:
    raise ValueError("No scan_id returned. Something went wrong on the API side.")

console.print(f"[green]✓ Scan initiated.[/green] ID: [bold]{scan_id}[/bold]")

# Poll until the scan completes
with Progress(
    SpinnerColumn(),
    TextColumn("[progress.description]{task.description}"),
    transient=True,
) as progress:
    task = progress.add_task("Scanning infrastructure...", total=None)

    while True:
        status_response = client._request("GET", f"/compliance/scan/{scan_id}")
        status = status_response.get("status")

        if status == "completed":
            progress.stop()
            break
        elif status == "failed":
            raise RuntimeError(f"Scan failed: {status_response.get('error', 'Unknown error')}")

        time.sleep(10)  # Don't hammer the API

console.print(f"[green]✓ Scan complete.[/green]")
return status_response
Enter fullscreen mode Exit fullscreen mode

**Expected output:**

Enter fullscreen mode Exit fullscreen mode


plaintext
╭──────────────── 🔍 ComplianceWeave Scan ────────────────╮
│ Starting scan for: SOC2, GDPR │
│ Environment: production │
╰─────────────────────────────────────────────────────────╯
✓ Scan initiated. ID: scan_a3f92b1c
⠸ Scanning infrastructure...
✓ Scan complete.


The polling loop is intentional. Scans against real infrastructure take time — fighting that with impatient code just gets you incomplete results.

---

## Step 3: Auto-Remediate What You Can

Before pulling the report, let's fix the low-hanging fruit. ComplianceWeave flags issues it can remediate automatically (think: misconfigured S3 bucket ACLs, overly permissive security groups, missing encryption settings).

Enter fullscreen mode Exit fullscreen mode


python

remediate.py

from compliance_client import ComplianceWeaveClient, console
from rich.table import Table

def remediate_violations(client, scan_results):
violations = scan_results.get("violations", [])
auto_fixable = [v for v in violations if v.get("auto_remediable") is True]

if not auto_fixable:
    console.print("[yellow]No auto-remediable violations found.[/yellow] Manual review required for all issues.")
    return []

table = Table(title="Auto-Remediating Violations")
table.add_column("Resource", style="cyan")
table.add_column("Issue", style="yellow")
table.add_column("Framework", style="magenta")

for v in auto_fixable:
    table.add_row(v["resource_id"], v["description"], v["framework"])

console.print(table)

violation_ids = [v["violation_id"] for v in auto_fixable]

payload = {
    "violation_ids": violation_ids,
    "dry_run": False  # Set True to preview changes without applying
}

result = client._request("POST", "/compliance/remediate", json=payload)

fixed = result.get("remediated", [])
failed = result.get("failed", [])

console.print(f"[green]✓ Fixed {len(fixed)} violation(s).[/green]")
if failed:
    console.print(f"[red]✗ {len(failed)} remediation(s) failed.[/red] Check the report for details.")

return fixed
Enter fullscreen mode Exit fullscreen mode

> **Best practice:** Always run with `dry_run: True` first in a staging environment. Automated remediation is powerful. So is accidentally locking yourself out of a resource.

---

## Step 4: Pull Your Audit-Ready Report

The scan is done, violations are patched. Time to collect your evidence.

Enter fullscreen mode Exit fullscreen mode


python

report.py

from compliance_client import ComplianceWeaveClient, console
import json
from datetime import datetime

def fetch_report(client, scan_id, output_format="pdf"):
console.print(f"\n[bold]Fetching report for scan:[/bold] {scan_id}")

params = {
    "scan_id": scan_id,
    "format": output_format,   # "pdf", "json", or "csv"
    "include_evidence": True,  # Attach raw evidence artifacts
    "frameworks": ["SOC2", "GDPR"]
}

report = client._request("GET", "/compliance/reports", params=params)

# Save the report locally
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
filename = f"compliance_report_{timestamp}.json"

with open(filename, "w") as f:
    json.dump(report, f, indent=2)

# Print a human-readable summary
summary = report.get("summary", {})
console.print(f"\n[bold green]Report Summary[/bold green]")
console.print(f"  Overall Score:     {summary.get('compliance_score', 'N/A')}%")
console.print(f"  Controls Passed:   {summary.get('controls_passed', 0)}")
console.print(f"  Controls Failed:   {summary.get('controls_failed', 0)}")
console.print(f"  Report saved to:   [cyan]{filename}[/cyan]")

return report, filename
Enter fullscreen mode Exit fullscreen mode

**Expected output:**

Enter fullscreen mode Exit fullscreen mode


plaintext
Fetching report for scan: scan_a3f92b1c

Report Summary
Overall Score: 91%
Controls Passed: 147
Controls Failed: 13
Report saved to: compliance_report_20240315_143022.json


---

## Step 5: Wire It All Together

Enter fullscreen mode Exit fullscreen mode


python

main.py

from compliance_client import ComplianceWeaveClient, console
from scan import run_scan
from remediate import remediate_violations
from report import fetch_report

def main():
client = ComplianceWeaveClient()

# 1. Scan
scan_results = run_scan(
    client,
    frameworks=["SOC2", "GDPR", "HIPAA"],
    environment="production"
)

# 2. Remediate what we can
remediate_violations(client, scan_results)

# 3. Re-scan to capture remediation (optional but recommended for auditors)
final_results = run_scan(client, frameworks=["SOC2", "GDPR", "HIPAA"])

# 4. Generate the report
report, filename = fetch_report(
    client,
    scan_id=final_results["scan_id"]
)

console.print(f"\n[bold green]✓ Done.[/bold green] Hand [cyan]{filename}[/cyan] to your auditor.")
Enter fullscreen mode Exit fullscreen mode

if name == "main":
main()


---

## What You Actually Built

In ~150 lines of Python, you now have:

- **Automated evidence collection** across SOC2, GDPR, HIPAA, and ISO 27001
- **Intelligent remediation** that fixes what it safely can
- **Audit-ready reports** generated without a single screenshot

The real win isn't the code — it's the meeting you won't have to schedule to explain why the evidence doc is named `FINAL_v3_USE_THIS_ONE`.

Schedule this as a weekly cron job. Let ComplianceWeave run continuously. Show up to your audit with a folder of timestamped reports instead of a folder of regrets.

Your future self, three weeks before the next audit, will thank you.

---

*Questions? Drop them in the comments. I check. Eventually.*
Enter fullscreen mode Exit fullscreen mode

Top comments (0)