← all branches

feat/sec-base

blocked
2ad7120 · incrementalPR #267reviewed 2026-07-08 17:33 UTC7H · 14M · 11L · 1I
The branch
Purpose
Land the ISO 27001 + SOC 2 compliance baseline: CI dependency/code scanning, CDK CloudTrail/GuardDuty stacks reconciled to live reality, GitHub org security settings enabled, and a comprehensive compliance knowledge base (SSOT rule, 18+ policy skeletons, auditor documents, evidence machinery).
Goal
Pass ISO 27001 Stage 1 (target M7) + SOC 2 Type I (target M6) with a 'pass-with-findings' trajectory; complete the observation window for Type II (~M11) and ISO Stage 2 (~M9).
Sub-goals
  • SG-1: Dependency & code scanning — dependabot.yml + codeql.yml + advisory audit job (done)
  • SG-2: CDK security baseline reconcile — AuditTrailStack + GuardDutyBaseline match live reality (done)
  • SG-3: GitHub org security settings enabled (done)
  • SG-4: Compliance knowledge base — 48 docs/policies under docs/compliance/ (done)
  • SG-mock-audit: Independent mock Stage 1 audit run (48/100 initial), full remediation pass (72/100 re-grade), residuals RG-1/RG-2 closed
The changes (whole branch)
What
Mock Stage 1 audit remediation: 4 new ISMS documents (audit-remediation-tracker, competence-and-communication, context-and-interested-parties, document-control-procedure), 10 updated policies/SoA/objectives/system-description to remove false-present-tense claims, add 5.2c/5.2d commitments, [operating]/[designed] tags on SOC 2 controls, CSOCs/CUECs/incident-disclosure sections, and SoA tally/exclusion corrections (7.13 reclassified, 5.15/5.23/8.25 downgraded to ◐). Score improved 48→72/100.
Why
The initial mock audit returned NOT READY (48/100) with 7 majors and 8 minors. All doc-fixable findings were closed in one pass; remaining 4 open items are founder actions (risk workshop, sign-off session, management review, vendor attestation collection) and one code fix (BAT-256).
Areas
docs/compliance/ (root docs)+12980docs/compliance/policies/+3570.claude/rules/+700.github/+1220infra/cdk/src/stacks/+416.branch/+61164
Blast
48 files changed, +1909/−170. Pure documentation + CI config — no runtime code, no database migrations, no API surface changes. CDK stacks authored but not deployed. Risk is compliance program correctness, not operational stability.
compliance iso27001 soc2 docs-only
ci· CI check API not accessible from self-hosted runner tokencoderabbit· No .coderabbit.yaml in repo

Findings · 35

correctness6

high

SOC 2 description implies subprocessor list is already published

docs/compliance/soc2-system-description.md:27

Confidentiality commitment at line 27 states 'subprocessor list published' in present tense. vendor-register.md action ③ marks publication as outstanding. Same false-present-tense class as MAJ-7/RG-2 — not caught in the remediation pass. Change to 'subprocessor list (to be published — vendor register action ③)'.

medium

SoA physical-exclusion justification still says provider reports 'on file'

docs/compliance/statement-of-applicability.md:73

7.1 justification and its 'Same' siblings for all 9 N-A controls read 'reports on file'. Provider attestations are not yet collected (MIN-8 open, vendor register action ① outstanding). RG-2 was fixed in scope-statement.md but this SoA instance was missed.

medium

Certification timeline in O-9 contradicts compliance.md SSOT

docs/compliance/security-objectives.md:23

O-9 says 'SOC 2 Type II ~M12 · ISO 27001 certificate ~M10'. compliance.md says 'Type II ~M11; ISO Stage 2 M9'. Both dates differ; auditors will flag the inconsistency. Align security-objectives.md to compliance.md.

medium

Policies lack version/date required by the newly-adopted document-control procedure

docs/compliance/policies/information-security-policy.md:6

document-control-procedure.md defines 'v0.x = draft' with version date = commit date. All 18 policy skeletons use bare 'DRAFT — not approved' with no version number or date, immediately contradicting the procedure they are governed by. The new context-and-interested-parties.md and competence-and-communication.md were correctly versioned — the convention should be back-applied to policies.

low

MAJ-1 tracker note oversimplifies the two-tier approval model

docs/compliance/audit-remediation-tracker.md:13

Tracker says 'owner merge to main = approval' without noting the exception: the master Information Security Policy and risk acceptances require explicit Alvaro sign-off (per document-control-procedure.md, 'A merge SHA is insufficient'). A founder reading only the tracker may incorrectly believe their merge suffices for the master policy.

low

Tracker '5/7 majors closed' count is inconsistent with MAJ-7 being 'doc-closed' not 'closed'

docs/compliance/audit-remediation-tracker.md:42

Counting Closed rows: MAJ-2/3/4/5 = 4 fully closed; MAJ-7 = doc-closed; MAJ-1/6 = open. Summary should read '4/7 fully closed + 1 doc-closed (MAJ-7, code residual BAT-256), 2 founder-action open' rather than '5/7 fully closed, MAJ-7 doc-closed' which conflates the two categories.

security8

high

AUP FDE/MFA self-attestation has no defined artifact — will fail Type II sampling

docs/compliance/policies/acceptable-use-policy.md:15

The transition language converts hard controls to honor-system attestations. No artifact is defined: no form, no checklist row, no re-attestation trigger on device change, no retention location. A Type II sampler will ask for evidence the self-attestation happened per person; without an artifact, 'self-attestation' is indistinguishable from 'no control'. Specify: what the artifact is, who holds it, where retained.

high

CFE credential manual-deletion interim has no defined SLA or exercise record (RG-3 unexercised)

docs/compliance/policies/data-retention-disposal-policy.md:19

Manual deletion of CFE Secrets Manager secrets on offboarding: (1) not in the HR policy offboarding checklist (hr-security-policy.md lists Google/GitHub/AWS/Vercel/Supabase/Tinybird/Stripe/Notion/Linear — CFE secrets absent); (2) no interim deletion SLA defined (the 'days' SLA only applies post-BAT-256); (3) never been exercised (RG-3 open). Crown-jewel data class + LFPDPPP personal-data obligations make this a live privacy liability, not just a compliance gap.

medium

Document-control allows policy self-approval without second reviewer

docs/compliance/document-control-procedure.md:33

Operational policies can be approved by 'merge to main by the approving owner'. If Alex is sole tech-lead in CODEOWNERS, he can author + merge his own access-control, IR, and data-retention policies. ISO 7.5 expects the producer not to be the sole approver. Recommend: require a named second reviewer (Diego or Alvaro) when author and approving owner are the same person.

medium

IR plan SEV1 24h notification window may breach LFPDPPP 'without delay' obligation

docs/compliance/policies/incident-response-plan.md:13

SEV1 says 'customer/regulator notification decision ≤ 24h'. LFPDPPP Article 36 requires notification 'without delay' once a breach is confirmed — it does not offer a 24h safe harbor for the decision itself. CFE credentials may qualify as personal data under LFPDPPP. The ir-tabletop scenario confirms this gap is known. Add a specific LFPDPPP timing commitment alongside the 24h target.

medium

SOC 2 system description embeds all four AWS account IDs in a customer-distributable document

docs/compliance/soc2-system-description.md:33

Prod (353625676934), staging (966363209222), dev (706877673155), management (397762539248) are in plain text. This file is designed for external distribution to customers and prospects. Account IDs enable targeted reconnaissance (confused-deputy attacks, S3 resource enumeration). Replace with environment labels and move the account→environment mapping to an internal-only doc not included in the customer PDF extract.

medium

Access [operating] overstates OIDC posture: OIDC roles hold AdministratorAccess (BAT-259 open)

docs/compliance/soc2-system-description.md:85

The [operating] bucket claims 'OIDC (no static AWS keys)' as an operating control. compliance.md SSOT confirms GitHub OIDC deployer roles attach AdministratorAccess (open finding, BAT-259). An AdministratorAccess OIDC role is an operating security gap, not an operating control. Either note the residual inline or move OIDC least-privilege claim to [designed, implementing] until BAT-259 is closed.

low

CUECs missing customer obligation to report external CFE account compromise

docs/compliance/soc2-system-description.md:110

CUECs cover Batu API key rotation but not the customer's duty to notify Batu if their CFE portal account is externally compromised or if CFE credentials change outside of Batu. The F-4 auth-cache issue (25-min stale session) makes this a real attack vector. Add: 'Notifying Batu promptly if their CFE Mi Espacio account is compromised externally or if CFE portal credentials are changed outside of Batu, so cached sessions can be invalidated.'

low

Notion token incident disclosure lacks scope-analysis before claiming no customer-data impact

docs/compliance/soc2-system-description.md:119

Assessment rationale ('not affecting customer data') is not documented. Evidence needed: what databases/pages the token accessed, whether customer PII was in those pages, basis for 'no external access' claim (Notion audit log check). CA-001 records only revocation. If the token had access to customer-related Notion pages, the assessment may be incorrect. The SOC 2 description should cite the scope analysis, not just the remediation action.

conventions7

medium

Version format inconsistency: 'DRAFT 0.1' vs canonical 'DRAFT v0.1' in SoA

docs/compliance/statement-of-applicability.md:6

document-control-procedure.md defines 'v0.x = draft'. The SoA uses 'DRAFT 0.1' (no 'v' prefix). soc2-system-description.md has the same deviation. context-and-interested-parties.md and competence-and-communication.md correctly use 'DRAFT v0.1'. The procedure controls itself — deviations in documents introduced this branch are immediate self-contradictions.

medium

soc2-system-description.md uses 'DRAFT 0.1' and is missing Owner field

docs/compliance/soc2-system-description.md:7

Uses 'DRAFT 0.1' not 'DRAFT v0.1', and has no Owner header row. Every other ISMS document (audit-rfq.md, cfe-credential-data-flow.md, context-and-interested-parties.md, etc.) includes an Owner row. The SOC 2 system description is a managed document requiring an accountable owner.

low

scope-statement.md Status field missing the date component

docs/compliance/scope-statement.md:6

document-control-procedure.md requires 'version date = commit date'. scope-statement.md Status reads 'DRAFT v0.1 — for founder review' with no date, while all other new documents in this branch include the date (e.g. 'DRAFT v0.1 · 2026-07-08').

low

security-objectives.md uses separate Version row instead of inline Status pattern

docs/compliance/security-objectives.md:8

Uses a split '| Version | 0.1 · date |' row while canonical pattern (and document-control-procedure.md) puts version inline in Status: 'DRAFT v0.1 · 2026-07-08'. Also the version token is '0.1' not 'v0.1'.

low

SoA physical-exclusion justification retains 'reports on file' (same false-claim class as RG-2)

docs/compliance/statement-of-applicability.md:73

RG-2 was closed by rewording scope-statement.md. The SoA's N-A justification for 7.1 (and 'Same' siblings) still says 'inherited from cloud providers (reports on file)'. Provider reports are not yet collected (MIN-8 open). Parenthetical should read 'reports to be collected into the vendor register'.

low

audit-remediation-tracker.md missing Owner field

docs/compliance/audit-remediation-tracker.md

Every ISMS document includes an Owner row. The remediation tracker has Source/Purpose/Status but no Owner. Alex (ISMS owner) is the logical choice.

info

All 18 policy skeletons use bare 'DRAFT — not approved' without version/date

docs/compliance/policies/information-security-policy.md:6

Systemic across all policies (consistent pattern). The document-control-procedure.md now in place requires version+date stamps. No fix needed before merge; the next editorial pass on policies should add 'DRAFT v0.1 · <commit-date>' to each Status field for consistency.

tests7

high

SEV1 ≤1h acknowledge commitment is unverifiable — no on-call mechanism defined

docs/compliance/policies/incident-response-plan.md:13

No alerting channel is named, no PagerDuty/SNS/phone escalation path exists in any doc, no IC rotation or backup defined for when Alex is unreachable. logging-monitoring-policy.md only says GuardDuty findings route to 'an alerting channel' without specifying it. Auditors will ask 'how do you know within 60 minutes at 2am?' — current docs cannot answer.

medium

O-2 interim measurement 'Vercel deployment/health metrics' has no operational definition

docs/compliance/security-objectives.md:16

No dashboard URL, no query, no sampling cadence. An auditor cannot reproduce the 99.5% availability figure from this description. Define concretely: which Vercel page, which date range, which export method, whose responsibility, what cadence.

medium

SOC 2 system description says observation-window prerequisites are 'scheduled' but no concrete dates exist

docs/compliance/soc2-system-description.md:90

control-calendar.md lists the IR tabletop as 'Before the Type II window opens' with no actual meeting date. backup-policy.md specifies quarterly restore tests but records no first scheduled instance. 'Scheduled' implies a date exists; if it doesn't, this is a false-precision claim of the MAJ-7/RG-2 class.

medium

Corrective-action register has 4 open CAs with 'TBD' due dates — Clause 10.1 nonconformity

docs/compliance/corrective-action-register.md

CA-002 (CFE deletion, High), CA-003 (auth-cache, Medium), CA-004 (AdministratorAccess, High), CA-005 (mgmt account workloads, Medium) all show 'Due: TBD'. ISO 10.1 requires specific target completion dates. Stage 1 auditors routinely flag TBD due dates on open CAs as evidence the corrective-action process is not operating. CA-002 and CA-004 (both High) need concrete dates.

medium

Document-drift detection relies on undocumented recurring standup with no calendar evidence

docs/compliance/control-calendar.md:45

control-calendar.md says 'calendar reminders + the fortnightly compliance standup are the mechanism' for document freshness until BAT-232 ships. No evidence the standup exists as a recurring calendar event; no defined owner for reminder creation; no pointer in document-control-procedure.md. 'We had reminders' is not a verifiable control.

low

O-8 restore-test cadence conflicts: quarterly (O-8 + backup-policy) vs annual (BC/DR policy)

docs/compliance/policies/business-continuity-dr-policy.md:13

Security objective O-8 and backup-policy.md both specify quarterly restore tests. business-continuity-dr-policy.md line 13 says 'Annual DR exercise'. control-calendar.md correctly lists quarterly. BC/DR policy is the outlier; an auditor sampling at the lower-frequency anchor will observe fewer tests than expected.

low

CFE credential manual interim deletion never exercised — no test record exists

docs/compliance/policies/data-retention-disposal-policy.md:21

The policy describes the obligation but there is no runbook for the interim manual deletion path and no evidence of a test run. RG-3 explicitly notes 'designed but never exercised'. Type I auditor would expect either an exercise record or a step-by-step runbook for the interim procedure.

improvement7

high

Open CAs CA-002..CA-005 have no due dates — fix before Stage 1

docs/compliance/corrective-action-register.md

All four open corrective actions carry 'Due: TBD'. Each needs a concrete date: CA-002 tied to BAT-256 milestone, CA-004 tied to BAT-259, CA-005 to BAT-260. Cheap fix; an auditor sampling Clause 10 compliance at Stage 1 will cite TBD dates as the corrective-action process not operating.

high

RG-3 (CFE offboarding dry-run) has no owner, date, or artifact spec

docs/compliance/audit-remediation-tracker.md

RG-3 is the only residual that produces an auditor-inspectable artifact (dated offboarding checklist). Currently: no owner, no date, no artifact definition. HR policy promises the dry-run before the observation window. Name Diego as owner, set target date (before M6 window open), specify artifact: 'completed offboarding checklist with Secrets Manager deletion confirmation, logged in CA-002'.

high

No legal register exists; 5.31 is ▢ 'with counsel' — Stage 1 auditors probe this

docs/compliance/statement-of-applicability.md

Context-and-interested-parties.md lists INAI/LFPDPPP as a primary interested-party whose requirements the ISMS must address. 5.31 is ▢ with 'Register: LFPDPPP, fiscal retention, customer contracts — with counsel'. No legal register exists in docs/compliance/. A one-page legal register listing LFPDPPP, Código Fiscal, and applicable NOM obligations + status closes this gap before Stage 1. Much of the content is already known without external counsel.

medium

Controls 5.5/5.6 reference IR plan contacts that don't exist in the IR plan

docs/compliance/statement-of-applicability.md

SoA 5.5 says 'Name contacts (LFPDPPP authority INAI, CERT-MX) in the IR plan' and 5.6 says 'List AWS/GitHub security bulletins in IR plan'. Neither section exists in incident-response-plan.md. Both are cheap to add (a list of 5 contacts + a list of 5 advisory subscriptions) and close two ▢ controls without founder action.

medium

Competence evidence for ISMS owner is aspirational — 'CTO experience' is not an auditable record

docs/compliance/competence-and-communication.md

ISO 7.2 requires documented evidence of competence. 'CTO experience; leads the program; (optional) ISO Lead Implementer course' is not a document. Name the fallback evidence: 'documented engagement in ISMS design decisions evidenced by commit history and management-review minutes'. IR tabletop participation record should be listed as 'pending — scheduled for [date]' rather than implicitly current.

medium

document-control-procedure does not specify external-document expiry tracking — attestations will silently age out

docs/compliance/document-control-procedure.md

vendor-register.md lacks obtained-date and expiry columns. SOC 2 reports expire after 12 months; during the Type II observation window, an attestation collected in M3 expires in M15 — but without expiry tracking it will appear current. Add an 'obtained / expires' column to the vendor register and an explicit attestation-expiry spot-check to the control calendar.

low

Break-glass procedure for key-person concentration (R-9) referenced but not written

docs/compliance/risk-register.md

R-9 mitigation cites 'documented deputies, break-glass procedure, password-manager shared vaults'. access-control-policy.md mentions 'break-glass path' but no runbook exists. A one-page doc (which vault, who has deputy credentials, post-use review) provides evidence for R-9, A.5.2, A.5.3, and BC/DR simultaneously — and is the answer to 'what if Alex is unavailable during a SEV1?'

History · 6 commits

  1. 2ad7120blockedincremental7H · 14M · 11L2026-07-08 17:33current
  2. 26393f2needs attentionincremental5H · 19M · 11L2026-07-08 04:57
  3. 9b22f9fneeds attentionincremental6H · 12M · 9L2026-07-08 03:15
  4. 697438cneeds attentionfull3H · 7M · 6L2026-07-07 20:12
  5. aaec085needs attentionincremental7H · 11M · 9L2026-07-07 17:59
  6. 6a3693cneeds attentionfull11H · 13M · 6L2026-07-07 17:41