--- title: "I Automated My SOC2 Audit Prep in an Afternoon (And You Can Too)" published: false tags: [security, python, devops, compliance] --- # I Automated My SOC2 Audit Prep in an Afternoon (And You Can Too) Let me paint you a picture. It's 11 PM. Your audit is in three weeks. You're cross-referencing a spreadsheet with 847 rows against cloud console screenshots you took last Tuesday, hoping nothing changed since then. Your coffee is cold. Your eyes hurt. Your auditor just emailed asking for "just a few more controls." I've been there. Most of us have. This tutorial is about escaping that reality using **ComplianceWeave** — a continuous compliance monitoring tool that covers SOC2, GDPR, HIPAA, and ISO 27001. By the end, you'll have a Python script that scans your infrastructure, pulls audit-ready reports, and even kicks off remediation — all without touching a single spreadsheet. Let's build something useful. --- ## Prerequisites - Python 3.9+ - A ComplianceWeave account and API key - `requests` and `python-dotenv` installed (`pip install requests python-dotenv`) - An infrastructure worth auditing (relatable) Store your API key safely: Enter fullscreen mode Exit fullscreen mode bash .env COMPLIANCEWEAVE_API_KEY=your_api_key_here COMPLIANCEWEAVE_BASE_URL=https://api.complianceweave.io/v1 --- ## Step 1: Build Your Client Foundation Before touching any endpoints, let's write a reusable client. Future-you will appreciate this when you're wiring this into a CI/CD pipeline at 9 AM instead of a spreadsheet at 11 PM. Enter fullscreen mode Exit fullscreen mode python compliance_client.py import os import time import requests from dotenv import load_dotenv load_dotenv() 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 before your auditor does." ) 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, timeout=30, **kwargs) response.raise_for_status() return response.json() except requests.exceptions.Timeout: raise RuntimeError(f"Request to {endpoint} timed out. Your infrastructure might be large — try again.") except requests.exceptions.HTTPError as e: status = e.response.status_code if status == 401: raise PermissionError("Invalid API key. Rotate it in your ComplianceWeave dashboard.") elif status == 429: # Respect rate limits — be a good API citizen retry_after = int(e.response.headers.get("Retry-After", 60)) print(f"Rate limited. Waiting {retry_after}s...") time.sleep(retry_after) return self._request(method, endpoint, **kwargs) else: raise RuntimeError(f"API error {status}: {e.response.text}") except requests.exceptions.ConnectionError: raise RuntimeError("Can't reach ComplianceWeave API. Check your network or their status page.") Enter fullscreen mode Exit fullscreen mode This client handles the three failure modes that will actually bite you: timeouts on large infrastructure scans, expired API keys, and rate limits during bulk operations. --- ## Step 2: Trigger Your First Compliance Scan Here's where the magic starts. `POST /compliance/scan` kicks off a scan against your chosen frameworks. We'll target SOC2 and GDPR — the two that tend to generate the most auditor paperwork. Enter fullscreen mode Exit fullscreen mode python In compliance_client.py, add this method to ComplianceWeaveClient: def trigger_scan(self, frameworks: list[str], scope: dict = None) -> dict: """ Trigger a compliance scan. frameworks: List from ["SOC2", "GDPR", "HIPAA", "ISO27001"] scope: Optional dict to target specific resources """ valid_frameworks = {"SOC2", "GDPR", "HIPAA", "ISO27001"} invalid = set(frameworks) - valid_frameworks if invalid: raise ValueError(f"Unknown frameworks: {invalid}. Valid options: {valid_frameworks}") payload = { "frameworks": frameworks, "scope": scope or {"include": "all"} } print(f"🔍 Starting scan for: {', '.join(frameworks)}") result = self._request("POST", "/compliance/scan", json=payload) scan_id = result.get("scan_id") print(f"✅ Scan initiated. ID: {scan_id}") print(f" Estimated completion: {result.get('estimated_duration', 'unknown')}") return result Enter fullscreen mode Exit fullscreen mode --- Run it --- if name == "main": client = ComplianceWeaveClient() scan = client.trigger_scan( frameworks=["SOC2", "GDPR"], scope={"regions": ["us-east-1", "eu-west-1"]} ) print(f"\nScan response: {scan}") Enter fullscreen mode Exit fullscreen mode **Expected output:** Enter fullscreen mode Exit fullscreen mode json 🔍 Starting scan for: SOC2, GDPR ✅ Scan initiated. ID: scan_a3f92b1c Estimated completion: 8-12 minutes Scan response: { "scan_id": "scan_a3f92b1c", "status": "running", "frameworks": ["SOC2", "GDPR"], "estimated_duration": "8-12 minutes", "created_at": "2024-11-14T14:23:01Z" } --- ## Step 3: Fetch Your Audit-Ready Reports Once the scan completes, `GET /compliance/reports` hands you structured evidence. Let's add polling logic — because nobody wants to manually refresh an endpoint. Enter fullscreen mode Exit fullscreen mode python Add to ComplianceWeaveClient: def get_reports(self, scan_id: str, poll: bool = True, poll_interval: int = 30) -> dict: """ Retrieve compliance reports. Optionally polls until scan completes. """ endpoint = f"/compliance/reports?scan_id={scan_id}" if not poll: return self._request("GET", endpoint) print(f"⏳ Waiting for scan {scan_id} to complete...") attempts = 0 max_attempts = 40 # ~20 minutes max wait while attempts dict: """ Attempt automated remediation. Always dry_run=True first. Always. """ if not finding_ids: print("No findings to remediate.") return {} payload = { "finding_ids": finding_ids, "dry_run": dry_run } mode = "DRY RUN" if dry_run else "LIVE" print(f"🔧 Running remediation [{mode}] on {len(finding_ids)} findings...") result = self._request("POST", "/compliance/remediate", json=payload) for action in result.get("actions", []): status_icon = "✅" if action["status"] == "success" else "❌" print(f" {status_icon} {action['finding_id']}: {action['action_taken']}") if action.get("requires_manual_review"): print(f" ⚠️ Manual review required: {action['reason']}") return result Enter fullscreen mode Exit fullscreen mode --- Full workflow --- if name == "main": client = ComplianceWeaveClient() # 1. Scan scan = client.trigger_scan(frameworks=["SOC2", "GDPR"]) # 2. Get report report = client.get_reports(scan["scan_id"]) # 3. Find auto-remediable issues (low severity only — don't auto-fix critical) auto_fix_candidates = [ f["finding_id"] for f in report.get("findings", []) if f.get("auto_remediable") and f.get("severity") in ("low", "medium") ] # 4. Dry run first, then flip to dry_run=False when you're confident if auto_fix_candidates: client.remediate(auto_fix_candidates, dry_run=True) Enter fullscreen mode Exit fullscreen mode **Expected output:** Enter fullscreen mode Exit fullscreen mode plaintext 🔧 Running remediation [DRY RUN] on 11 findings... ✅ find_b291: Would enable CloudTrail logging in us-east-1 ✅ find_c847: Would apply required data classification tags to S3 buckets ❌ find_d103: Cannot auto-remediate — requires IAM policy approval ⚠️ Manual review required: Privilege escalation risk --- ## Putting It All Together Here's your complete audit automation script — the one you'll actually commit to your repo: Enter fullscreen mode Exit fullscreen mode python audit_runner.py from compliance_client import ComplianceWeaveClient import json from datetime import datetime def run_audit(frameworks=None, output_file=None): frameworks = frameworks or ["SOC2", "GDPR", "HIPAA", "ISO27001"] client = ComplianceWeaveClient() scan = client.trigger_scan(frameworks=frameworks) report = client.get_reports(scan["scan_id"]) # Save full report for your auditor if output_file: with open(output_file, "w") as f: json.dump(report, f, indent=2) print(f"\n📁 Full report saved to {output_file}") # Auto-remediate safe findings candidates = [ f["finding_id"] for f in report.get("findings", []) if f.get("auto_remediable") and f.get("severity") == "low" ] if candidates: client.remediate(candidates, dry_run=False) return report Enter fullscreen mode Exit fullscreen mode if name == "main": timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") run_audit(output_file=f"audit_report_{timestamp}.json") Schedule this with cron or a GitHub Actions workflow, and you've just transformed compliance from a quarterly panic into background infrastructure. --- ## What You Built In ~150 lines of Python, you now have: - **Continuous scanning** across four major compliance frameworks - **Structured, auditor-ready reports** pulled programmatically - **Automated remediation** for safe, low-risk findings - **Proper error handling** for the production realities of timeouts, rate limits, and auth failures The next time an auditor emails asking for evidence, you send them a JSON file and a timestamp. That's the goal. ComplianceWeave's API is designed to slot into existing workflows — CI/CD pipelines, scheduled jobs, Slack alerting, whatever fits your stack. The hard part isn't the code. It was always the manual evidence collection. Now that's handled. Go get some sleep. Enter fullscreen mode Exit fullscreen mode
How to Automate SOC2 and GDPR Compliance Scans with ComplianceWeave
Full Article
Original Source
Read the full article at Dev →KhanList aggregates and links to publicly available news content. We do not host full articles from third-party sources. Always verify important information with original sources.