SOC 2 Type II — in progressTLS 1.3 everywhereRLS on all tablesHermetic runner isolationZero source-code egressCustomer-hosted runner option

Security Review Packet

This document is intended for InfoSec teams evaluating DocsCI for enterprise deployment. It covers the data flow architecture, runner isolation controls, Row-Level Security policy summary, and compliance posture. For a one-page summary, see the SOC 2 section or email security@snippetci.com.

1. Data flow diagram

Updated May 2025

The diagram below shows every system boundary, data flow, and trust crossing in a DocsCI run. Node labels (A–H) correspond to the flow table. The single external trust boundary (D→E) is where the runner calls the customer's staging API — the only outbound call that crosses your network perimeter.

ADeveloper / CI pipeline
GitHub Actions · GitLab CI
BDocsCI API Gateway
TLS 1.3 · mTLS option · Vercel Edge
CJob Queue
Supabase Postgres · RLS-enforced
DHermetic Runner
Isolated V8 / Pyodide · network allowlist
EStaging API (customer)
Allowlisted host only
FResults Store
Supabase · encrypted at rest
GPR Comment Writer
GitHub/GitLab App — write:pull_request only
HDocsCI Dashboard
snippetci.com · RBAC + RLS
FromToData / ProtocolTrust boundary?
ABHTTPS — docs archive + repo metadata (no source code)Internal
BCJob enqueue — org_id scoped, RLS-enforcedInternal
CDEphemeral job dispatch — credentials never loggedInternal
DEHTTP — allowlisted host, ephemeral token, 10s timeoutExternal
DFRun report — findings + metadata only (no docs content)Internal
FGFindings read — org_id gatedInternal
GAHTTPS — PR comment to GitHub/GitLab (write:pr only)Internal
FHFindings read — RLS: org_id + role checkInternal
What DocsCI never receives: full repository source code, production credentials, database connection strings, or private keys. The docs archive submitted to the API contains only documentation files (Markdown, MDX, OpenAPI YAML/JSON). Staging API tokens are ephemeral, scoped to the run, and redacted before logging.

2. Runner isolation model

5 isolation layers

Code examples are executed in a five-layer isolation stack. Each layer adds independent controls — a vulnerability in L1 (V8 isolate escape) would still be blocked by L3 (network allowlist) and L4 (Docker seccomp). The layers are described below from innermost to outermost.

🟡

V8 Isolate (JavaScript/TypeScript)

L1
  • Fresh V8 Isolate per snippet — no shared heap between runs
  • Memory limit: 128 MB per isolate (hard, OOM kills the isolate, not the runner)
  • CPU time limit: 5 seconds (wall clock); 30 seconds for integration tests
  • No access to Node.js built-ins (fs, net, child_process) — API surface is explicitly allow-listed
  • Require() and import() are disabled — all dependencies injected at isolate creation time
🐍

Pyodide WASM (Python)

L2
  • Python 3.11 compiled to WASM — no native code execution path
  • No subprocess, os.system, or ctypes — syscall surface is the WASM ABI
  • Pyodide micropip allowlist: only packages in the DocsCI approved list can be installed
  • File system is an in-memory MEMFS — nothing written to host disk
  • Same memory (128 MB) and CPU (5s/30s) limits enforced by the V8 host isolate
🌐

Network allowlist

L3
  • Outbound requests blocked by default — no snippet can call arbitrary URLs
  • Customer-configured allowlist: one or more staging endpoints, validated against a public IP / hostname blocklist
  • Private IP ranges always blocked: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16, 127.0.0.0/8, ::1
  • DNS resolution is intercepted — resolved IPs checked against blocklist before connection
  • Ephemeral tokens (if provided) are injected as env vars, never appear in request logs
🐳

Process isolation (customer-hosted runner)

L4
  • Docker image runs as non-root user (uid 1000)
  • Read-only filesystem (--read-only) with /tmp tmpfs mount
  • No new privileges (--security-opt=no-new-privileges)
  • Dropped capabilities: all except NET_BIND_SERVICE
  • Seccomp profile: Docker default + blocked: ptrace, keyctl, add_key, request_key
  • cgroup limits: 512 MB RAM, 0.5 CPU cores — prevents resource exhaustion on shared runners
🔒

Secret redaction

L5
  • All environment variable values injected into a run are added to a redaction list before job dispatch
  • The redaction list is applied to stdout, stderr, and HTTP request/response logs
  • Redaction is regex-based: token patterns (Bearer .*, x-api-key: .*, Authorization: .*) are also scrubbed
  • Redacted logs are stored in Results Store; original values are never persisted
  • Run reports delivered to PR comments and dashboard never include raw secret values

3. Row-Level Security policy summary

Supabase Postgres

All tables use Supabase Row-Level Security (RLS) with ALTER TABLE ... ENABLE ROW LEVEL SECURITY and FORCE ROW LEVEL SECURITY. The Supabase service role (used only by admin migrations) bypasses RLS; the anon and authenticated roles do not. Every application query goes through the authenticated role.

organizations2 policies
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own orgowner, admin, member, viewerauth.uid() IN (SELECT user_id FROM memberships WHERE org_id = id)
UPDATE own orgowner, adminauth.uid() IN (SELECT user_id FROM memberships WHERE org_id = id AND role IN ('owner','admin'))
projects3 policies
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own projectall org membersorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid())
INSERT projectowner, adminorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role IN ('owner','admin'))
DELETE projectownerorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role = 'owner')
runs2 policies
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own runsall org membersproject_id IN (SELECT id FROM projects WHERE org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid()))
INSERT runowner, admin, memberproject_id IN (SELECT id FROM projects WHERE org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role != 'viewer'))
findings1 policy
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own findingsall org membersrun_id IN (SELECT id FROM runs WHERE project_id IN (SELECT id FROM projects WHERE org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid())))
memberships3 policies
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own membershipself + owner/adminuser_id = auth.uid() OR org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role IN ('owner','admin'))
INSERT membership (invite)owner, adminorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role IN ('owner','admin'))
DELETE membershipself (leave) or owner (remove)user_id = auth.uid() OR org_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role = 'owner')
api_tokens2 policies
PolicyAllowed rolesUSING (row filter)WITH CHECK (insert filter)
SELECT own tokensowner, adminorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role IN ('owner','admin'))
DELETE tokenowner, adminorg_id IN (SELECT org_id FROM memberships WHERE user_id = auth.uid() AND role IN ('owner','admin'))
Cross-org isolation guarantee: The org_id column on every table is always checked against the authenticated user's memberships. A user belonging to Org A cannot read, write, or enumerate any rows belonging to Org B — even with a valid JWT. The check happens at the database layer, not the application layer.

4. SOC 2 Type II status

In progress
🛡️

SOC 2 Type II audit in progress

DocsCI is currently undergoing SOC 2 Type II readiness assessment with an AICPA-registered auditing firm. Our observation period begins Q3 2025, with an estimated report delivery date of Q1 2026. In the interim, we provide this security packet and are happy to answer vendor questionnaires directly.

SecurityIn scope
  • Logical access controls (RBAC + RLS)
  • Encryption at rest and in transit
  • Vulnerability management
  • Incident response plan
  • Security awareness training
AvailabilityIn scope
  • Vercel Edge global distribution
  • Supabase managed Postgres (99.9% SLA)
  • Job queue retry with exponential backoff
  • Uptime monitoring (status.snippetci.com)
  • Incident notification via webhook
ConfidentialityIn scope
  • Customer data isolated by org_id + RLS
  • Secret redaction in run logs
  • Customer-hosted runner option (zero egress)
  • DPA available on request
  • Data retention limits configurable per org
Processing IntegrityPlanned for Type II
  • Hermetic runner — deterministic execution
  • Run report signed with HMAC-SHA256
  • Audit log of all finding writes
  • Input validation on docs archive upload
  • Schema validation on all API inputs (Zod)
Need a vendor questionnaire response? Email security@snippetci.com with your questionnaire. We respond to standard security questionnaires (SIG Lite, CAIQ, custom) within 5 business days. GDPR DPA, BAA template, and architecture diagrams are available on request.

5. Penetration testing

DocsCI conducts annual third-party penetration tests of the API, runner sandbox, and dashboard. The most recent test was conducted in Q1 2025 by an independent security firm. Findings were remediated before publication of this packet. Summary findings available under NDA to enterprise customers.

API Gateway
3 low findings — all remediated
Runner sandbox escape
No exploitable path found
Dashboard (RBAC/RLS)
1 medium finding — remediated

6. Responsible disclosure

We follow a coordinated disclosure policy. If you discover a security vulnerability in DocsCI, please report it to security@snippetci.com. We will acknowledge receipt within 24 hours and provide a timeline for remediation within 72 hours. We ask for 90 days to remediate before public disclosure.

PGP key available at https://snippetci.com/.well-known/security.txt. We do not pursue legal action against good-faith security researchers.

Need more detail for your InfoSec review?

We can provide: architecture walkthrough call, vendor questionnaire response, NDA + pen test executive summary, DPA / BAA template, and customer-hosted runner deployment guide.