Drata SOC 2 Remediation Board — Ordermatic (corrected)
| Status | Verified board — supersedes the assumptions in the handoff spec |
| As of | 2026-06-26 · 35 FAILED / 17 PASSED (52 monitoring tests) |
| Method | Multi-agent verification against the live repo + GitHub API + Drata API (not the spec’s assumptions) |
| Companion | soc2-readiness.md (CC1–CC9 strategy), branch-protection-proposal.md, out-of-scope-tests.md |
1. Executive summary
Section titled “1. Executive summary”The headline correction: several failing tests the spec marked “already shipped, just needs Drata to rescan” are not actually deployed. The clearest case is Wave 0 — PR #1926 merged the Cloud Armor / load-balancer Terraform but it was never terraform apply-ed, so the WAF/LB does not exist in ordermatic-prod and live traffic still flows through the Cloud Run domain-mapping (ghs.googlehosted.com), not an LB. No rescan can pass it. That “merged ≠ applied” trap recurs across the monitoring, HA, and firewall rows: writing Terraform is not the fix; applying it is.
Two structural truths shape the infra tests:
- The primary application database is Neon (external), the queue layer is Temporal + Redis, and object storage is Cloudflare R2 — none are GCP resources, so Drata’s read-only GCP connector (
dratareadonly@ordermatic-prod) literally cannot see them. Tests like DB CPU/IO/storage and queue-age need a non-GCP control or an N/A justification, not a GCP alert policy. - The branch protection the deploy pipeline assumes does not exist.
mainhas no protection (GET branches/main/protection→ 404); the one repo ruleset (6222454, “Pull-Requests Only”, active) has an emptyinclude[]so it targets no branch and requires 0 approvals; GitHub org-wide 2FA is OFF. The controls are claimed in DRAFT policy but not enforced in the platform.
The 35 tests sort into: (a) already satisfied in code (Public SSH Denied, unique VCS accounts); (b) agent-preps / human-applies (monitoring alerts, branch protection, WAF/LB apply); (c) human-only console or decision work (Workspace/GCP MFA, bucket versioning, queue-age control, background-check vendor); (d) people/Wave-3 artifacts already drafted in PR #1932 that flip on Drata publish + sign-off; (e) 3 proposed N/A.
2. The 35 failing tests
Section titled “2. The 35 failing tests”Owner key: 🤖 agent · 🤝 agent-preps / human-applies · 👤 human · 🚫 propose N/A.
| # | Test | Verified reality | Concrete next action | Owner | Conf |
|---|---|---|---|---|---|
| 1 | Web Application Firewall in Place | Cloud Armor TF (#1926) merged, never applied; no securityPolicy in ordermatic-prod; ingress is Cloud Run ghs, not an LB |
Run the gated cutover gcp-edge-lb-cutover.md (apply LB+Armor → flip DNS → enforce), then rescan |
🤝 | high |
| 2 | Load Balancer Used | Same as #1 — no global forwarding rule / backend service exists yet | Same cutover; LB + WAF land together | 🤝 | high |
| 3 | Infrastructure Instance CPU Monitored | Zero google_monitoring_alert_policy in repo; Better Stack has only an error-rate alert + uptime (invisible to Drata’s GCP connector) |
Add google_monitoring_alert_policy on compute…/instance/cpu/utilization (>0.85/5m) + notification channel; apply |
🤝 | high |
| 4 | Database CPU Monitored | No alert; only GCP DB is Cloud SQL erp-prod-ln (Dagster/Temporal). App DB = Neon (external, invisible to GCP connector) |
Alert on cloudsql…/cpu/utilization for erp-prod-ln; separately decide Neon control or N/A |
🤝 | high |
| 5 | Database Read I/O Monitored | No alert; same Neon-is-external gap | Alert on cloudsql…/disk/read_ops_count; flag Neon |
🤝 | high |
| 6 | Database Free Storage Space Monitored | No alert; Cloud SQL + postgres-VM disk metrics unalerted | Alert on cloudsql…/disk/utilization (>0.85); flag Neon |
🤝 | high |
| 7 | Messaging Queue Message Age Monitored | No GCP-native queue exists (no Pub/Sub / Cloud Tasks); async = Temporal + Redis — no metric for Drata to read | Decision: Temporal schedule-to-start custom metric, Redis depth alert, or N/A with durability justification | 👤 | med |
| 8 | Cloud Storage Buckets Versioned | Zero google_storage_bucket in TF; object storage is R2/S3; real GCS buckets were gcloud-created |
Identify flagged buckets; gsutil versioning set on each (or import to TF). Not a rescan |
👤 | high |
| 9 | Public SSH Denied | Satisfied in code — only SSH rule restricts tcp:22 to IAP range 35.235.240.0/20; no 0.0.0.0/0 |
Read-only gcloud compute firewall-rules list to confirm no legacy default-allow-ssh; likely green on rescan |
👤 | high |
| 10 | Zone Redundancy | Cloud Run regional (multi-zone); app DB = Neon/external; Cloud SQL is hardcoded ZONAL |
Decide: Neon → N/A w/ external evidence, or flip Cloud SQL availability_type → REGIONAL (cost + restart, sign-off) |
🤝 | high |
| 11 | Formal Code Review Process | False — main unprotected (404); ruleset 6222454 active but empty include[] (targets nothing, 0 approvals); staging requires 0 reviews |
branch-protection-proposal.md §3a (staging: 1 review + checks) + a ruleset that actually targets main |
🤝 | high |
| 12 | Only Authorized Employees Change Code | Partial — private repo, 2 collaborators; no branch-level push restriction (either could push main) |
Restrict-push on main (Model A: promotion bot + admin); audit the 2 collaborators |
🤝 | med |
| 13 | Production Code Changes Restricted | False at SCM — main has no protection/required-check/force-push block; auto-deploy-main.yml’s “protection allows the token” comment references protection that doesn’t exist |
Proposal §3b ruleset on main (block force-push/deletion, linear history, required promotion-guard) + restrict-push; test FF promotion before relying — revert on break ([[prod-promotion-deploy-trigger-gap]]) |
🤝 | high |
| 14 | MFA on Version Control System | GitHub org 2FA = OFF (two_factor_requirement_enabled:false, team plan supports it); 2 human members |
Confirm both members have personal 2FA → flip Org → Authentication security → require 2FA → rescan | 🤝 | high |
| 15 | MFA on Identity Provider | IdP = Google Workspace; 2-Step enforcement is console-only, not verifiable from repo | admin.google.com → Security → 2-Step → enforce for all OUs; attach evidence | 👤 | high |
| 16 | MFA on Cloud Infrastructure | GCP human logins ride Workspace identities; console-only | Verify in Google Admin / GCP org policy; fixing #15 likely satisfies this | 👤 | high |
| 17 | Employees have Unique Infrastructure Accounts | GCP owner = individual david@; full uniqueness across GCP/Neon/Infisical/1P is console-only |
Agent pre-builds checklist from org-chart; human attests per system in the quarterly access review | 🤝 | med |
| 18 | Employees have Unique Version Control Accounts | Passes for accounts that exist — GitHub org = 2 human members, both User (dboone31=David, fromerom-braintly=Fabio); no shared logins |
Map the 2 in Drata personnel; likely green on rescan | 🤝 | high |
| 19 | Job Descriptions | Drafted in #1932 | Publish to Drata + owner sign-off | 🤝 | high |
| 20 | Engineering Job Description | Drafted (eng JD) in #1932 | Publish + sign-off | 🤝 | high |
| 21 | Performance Evaluation Process | Drafted in #1932 | Publish + sign-off | 🤝 | high |
| 22 | New Hire Contracts | Security terms drafted in #1932 (needs legal) | Finalize w/ counsel; publish + sign-off | 🤝 | high |
| 23 | MSAs Offered to Customers | MSA security clause drafted in #1932 (needs legal) | Finalize w/ counsel; publish + sign-off | 🤝 | high |
| 24 | Maintains Organization Chart | Drafted in #1932; roster reconciled 2026-06-26 | Publish + sign-off | 🤝 | high |
| 25 | Security Awareness Training Completed | In scope; 8 humans | Assign Drata training; all 8 complete | 👤 | high |
| 26 | Employee Background Checks | In scope; blocked on vendor | Approve Drata’s broker (Certn/KarmaCheck); run | 👤 | high |
| 27 | Contractor Background Checks | Same — blocked on vendor | Approve vendor; run for the 2 contractors | 👤 | high |
| 28 | Malware Detection Software Installed | Flips on Drata Agent install | Install Drata Agent on the 8 laptops | 👤 | high |
| 29 | Security Patches Auto-Applied | Flips on Drata Agent install | Install Drata Agent | 👤 | high |
| 30 | Screen Lock Required | Flips on Drata Agent install | Install Drata Agent | 👤 | high |
| 31 | Hard-Disk Encryption Enabled | Flips on Drata Agent install | Install Drata Agent | 👤 | high |
| 32 | Password Manager Records | Flips on Drata Agent install | Install Drata Agent | 👤 | high |
| 33 | Independent Board of Directors | Founder-led governance; no independent board | Mark N/A w/ justification (out-of-scope-tests.md) |
🚫 | high |
| 34 | Infrastructure Accounts Properly Removed | Offboarding test; no terminations yet | Mark N/A until first termination | 🚫 | high |
| 35 | Terminated Version Control Accounts Removed | Same — no terminations yet | Mark N/A until first termination | 🚫 | high |
3. Spec corrections (where the handoff was wrong, verified)
Section titled “3. Spec corrections (where the handoff was wrong, verified)”- Wave 0 is not a rescan. WAF/LB Terraform was merged but never applied; the resources don’t exist in
ordermatic-prod. (#1926 precedent — generalizes to every TF row.) - “Create an alert policy” understates the monitoring blocker. The repo has zero monitoring alert policies, and the app DB (Neon), queue (Temporal/Redis), and object store (R2) are not GCP resources — Drata’s GCP connector can’t see them. Several of these need a non-GCP control or N/A, not a GCP alert.
- The branch protection the deploy workflow relies on is fictional.
auto-deploy-main.ymlsays “main’s branch protection allows this workflow’s token to push; humans cannot” — butmainprotection is 404.mainis wide open. - The one ruleset is inert, not protective. Ruleset
6222454(“Pull-Requests Only”, active) has an emptyinclude[]→ targets no branch, 0 approvals. - Org 2FA was assumed enforced; it’s OFF.
two_factor_requirement_enabled:false— a config gap, not a plan limit. - Bucket versioning is not a code/rescan fix — there are zero
google_storage_bucketresources to detect or toggle. - Zone Redundancy / Cloud SQL HA assumed a GCP-managed app DB — the app DB is Neon (external), and the Cloud SQL that exists is
ZONAL. - “Public SSH Denied” is already satisfied in code — just verify no legacy rule survives outside TF.
4. Fastest path to green (ordered by tests-cleared-per-action)
Section titled “4. Fastest path to green (ordered by tests-cleared-per-action)”- Drata Agent on the 8 laptops → clears 5 (Wave 2: #28–32). Highest leverage on the board.
- Publish the 6 people artifacts (#1932) to Drata + sign-off → clears 6 (#19–24).
- Flip GitHub org-wide 2FA (after both members enable personal 2FA) → clears #14; cheap, console-only.
- Mark the 3 N/A (#33–35) with justification → clears 3, zero eng work.
- Apply GitHub branch protection (proposal §3a/§3b: real
stagingreview gate + a ruleset that actually targetsmainwith FF-bot bypass) → clears 3 (#11–13). Test FF promotion before relying; revert on break. - Confirm Workspace 2SV enforcement (admin console + evidence) → clears 2 (#15–16, GCP rides Workspace).
- Apply the WAF/LB cutover (Wave 0) → clears 2 (#1–2); high audit weight.
- Build + apply the GCP monitoring module (4 alert policies + channel) → clears the GCP-visible DB/instance tests (#3–6); separately raise the Neon-gap + queue-age (#7) decisions.
- Verify-only quick wins: confirm no legacy
default-allow-ssh(#9, likely already green) + map the 2 GitHub accounts in Drata (#18, already green). - Approve a background-check vendor → unblocks 2 (#26–27); assign training (#25) in parallel.
Longer poles needing a human decision: bucket versioning (#8 — identify + gsutil per bucket), Zone Redundancy scope (#10 — Neon N/A vs. Cloud SQL → REGIONAL with cost sign-off), and the queue-age control (#7).
5. The recurring caveat: merged ≠ applied
Section titled “5. The recurring caveat: merged ≠ applied”For every 🤝 infra row (WAF/LB, monitoring alerts, Cloud SQL HA), the agent can write and PR the Terraform, but a human must terraform apply (gcloud/IAM/TF applies are classifier-gated). Drata only sees the resource once it exists in ordermatic-prod. Don’t trigger a Drata rescan until the apply has landed — there’s nothing to find otherwise.
6. Refinements (laziest path / reuse what exists)
Section titled “6. Refinements (laziest path / reuse what exists)”- WAF (#1–2): try the Cloudflare WAF before the GCP Cloud Armor LB. The zone is already on Cloudflare (DNS-only today). Enabling Cloudflare proxy + managed WAF is one toggle vs. the multi-phase GCP Cloud Armor LB cutover (#1926: NEG, cert, anycast IP, DNS flip, ingress lockdown). Build the GCP LB only if Drata won’t credit the Cloudflare WAF — confirm Drata’s detection path first.
- N/A (#33–35): use the Drata UI, not the API. The Public API only offers
enabled=false(disable), which is not a formal “Not Applicable.” In the Drata UI, mark each test Not Applicable with the rationale fromout-of-scope-tests.md. Re-enable the two offboarding tests at the first termination. - CC6/CC7 evidence: attach the existing CASA assessment; don’t re-document. Tenant isolation, encryption (AES-256-GCM/PBKDF2), TLS, and the supply-chain gate are already assessed in
casa-self-assessment.md. Map CASA → the SOC 2 controls as evidence (readiness-doc Step 3) rather than generating new technical-control evidence.