feat/sec-base
needs attentionviewing older commit697438c · fullPR #267reviewed 2026-07-07 20:12 UTC3H · 7M · 6L · 2I- Purpose
- Land the repo-implementable security baseline for the ISO 27001:2022 + SOC 2 Type II program — the first concrete engineering step toward certification.
- Goal
- Dependency/code scanning in CI, CloudTrail/GuardDuty CDK stacks reconciled with live management-account reality, GitHub org security settings enabled, and compliance knowledge base (rule doc + 18 draft policy skeletons) committed.
- Sub-goals
- SG-1: Dependabot + CodeQL + advisory pnpm audit CI job
- SG-2: AuditTrailStack reconciled to live batu-org-trail; GuardDutyBaselineStack documents live detector + org enrollment runbook
- SG-3: GitHub org security features enabled via gh api (Dependabot, secret scanning, push protection, code security)
- SG-4: .claude/rules/compliance.md program SSOT + 18 docs/compliance/policies/ skeletons
- SG-N: Framework learnings recorded (no CLAUDE.md changes required)
- What
- New: .github/dependabot.yml (npm + GH Actions weekly grouped), .github/workflows/codeql.yml (JS/TS CodeQL, non-blocking), advisory security-audit job in pr-checks.yml, .claude/rules/compliance.md (compliance program SSOT with verified live findings), 19 docs/compliance/policies/ files (README + 18 policy skeletons). Modified: AuditTrailStack (isMultiRegionTrail true + enableFileValidation true + deploy-deferred header), GuardDutyBaselineStack (deploy-deferred header + org enrollment runbook in comments).
- Why
- ISO 27001:2022 + SOC 2 Type II combined certification program started 2026-07-06. This branch lands all repo-side controls that can be implemented before the compliance platform is chosen and before management-account deploys (cdk import path). Dependency scanning and policy skeletons establish the evidence baseline; CDK reconciliation prevents a future deploy from creating duplicate AWS resources.
- Areas
- .github/+122−0infra/cdk/src/stacks/+41−6.claude/rules/+63−0docs/compliance/policies/+348−0
- Blast
- 27 files, +574/-6 across 4 areas. No runtime domain logic changed — all changes are CI config, CDK authored-but-deferred infrastructure, and documentation. No database migrations. No API surface changes.
Findings · 19
correctness3
PIPESTATUS[0] unreachable under bash pipefail — step summary left with unclosed code block
.github/workflows/pr-checks.yml:166
GHA runs bash with -eo pipefail. When pnpm audit exits non-zero, the pipe `pnpm audit 2>&1 | tee -a "$GITHUB_STEP_SUMMARY"` fails and bash -e exits before reaching `STATUS=${PIPESTATUS[0]}`, leaving the step summary with an unclosed ``` block. The closing block and `exit "$STATUS"` are never reached. Fix: append `|| true` to the tee pipe (matching the Squawk pattern in the same file) — continue-on-error: true makes exit $STATUS redundant anyway.
GuardDuty CfnDetector missing FindingPublishingFrequency — may show drift on cdk import
infra/cdk/src/stacks/security/guardduty-baseline.stack.ts:47
The live detector may have a non-default FindingPublishingFrequency. The CfnDetector only sets `enable: true`. If the live value differs from the CDK default (SIX_HOURS), `cdk import` will show a diff and CloudFormation may attempt to change it. Document the live value and add it to CfnDetector before import.
Dependabot npm major updates compete with the 5-PR open-pull-requests-limit
.github/dependabot.yml:16
The 5-PR limit applies to all npm Dependabot PRs including ungrouped majors. With 110 current vulnerabilities (8 critical/45 high), many major-version updates may queue simultaneously and silently stop opening once the limit is hit. Security updates bypass the limit, but version-update PRs do not. Consider raising the limit or adding an explicit major group.
security5
CodeQL concurrency group cancels scheduled weekly scan on main pushes
.github/workflows/codeql.yml:19
concurrency group `${{ github.workflow }}-${{ github.ref }}` is identical for push-to-main and the schedule trigger (both resolve to refs/heads/main). With cancel-in-progress: true, a merge to main will cancel an in-progress scheduled scan. The scheduled weekly run is the backstop for vulnerabilities introduced without a PR — silently losing it undermines the SOC 2 CC7.1 evidence chain. Fix: use `${{ github.workflow }}-${{ github.event_name }}-${{ github.ref }}`.
GuardDuty detector ID (management account) hardcoded in source — increase blast radius of any IAM leak
infra/cdk/src/stacks/security/guardduty-baseline.stack.ts:9
The live detector ID `64cb231701e12bdefd8a41a985267fd9` is hardcoded in a JSDoc comment alongside the account ID already present in infrastructure.md. Combined, these let an attacker with read-level AWS access enumerate GuardDuty configuration or attempt suppression rules. Store as a CDK context variable (`-c guarddutyDetectorId=...`) seeded from SSM; use a placeholder in the runbook comment.
CloudTrail log bucket uses SSE-S3 — no CMK, no key-usage audit trail
infra/cdk/src/stacks/audit/audit-trail.stack.ts:51
BucketEncryption.S3_MANAGED means the CloudTrail log bucket's encryption key cannot itself be audited via CloudTrail — a circular gap. The cryptography-key-management-policy.md calls for auditable key usage. Since the stack is deploy-deferred and `cdk import` is the path, author with BucketEncryption.KMS_MANAGED now so the IaC reflects the target posture.
CloudTrail bucket versioned but no noncurrent-version expiry rule
infra/cdk/src/stacks/audit/audit-trail.stack.ts:56
The bucket has versioning enabled and a current-version expiry of 365 days, but no noncurrentVersionExpiration. Older superseded log object versions accumulate indefinitely. Add noncurrentVersionExpiration: Duration.days(365) to stay within the stated retention window.
Supabase CLI fetched without checksum verification in database-checks job
.github/workflows/pr-checks.yml
The database-checks job (pre-existing) fetches the latest Supabase CLI release dynamically via curl without verifying a checksum. The runner has POSTGRES_URL access. Pin to a specific version and verify the SHA256 from the GitHub release checksum file. This is a supply-chain risk, not introduced by this branch but noted given the security-baseline context.
conventions3
compliance.md open items: items 2-8 packed onto same lines — renders as 3 items not 8
.claude/rules/compliance.md:58
Lines 58 and 60 concatenate multiple numbered list items onto the same physical line (e.g. '…custom evidence. 2. Combined-audit quotes…' and '…contacto@`. 4. CFE-credential… 5. Verify… 6. GHAS… 7. Linear… 8. Revive…'). Markdown renderers display these as 3 items. This is the compliance program SSOT — an auditor reviewing it will miss five action items. Each item needs its own line.
pr-checks.yml SLA comment points to compliance.md — SLA is actually in vulnerability-patch-management-policy.md
.github/workflows/pr-checks.yml:172
The step summary comment says 'see .claude/rules/compliance.md' for the patch SLA, but compliance.md has no SLA numbers. The Critical 7d / High 30d / Medium 90d schedule is in docs/compliance/policies/vulnerability-patch-management-policy.md. Update the pointer so the CI breadcrumb leads to the right document.
risk-management-methodology.md missing Batu-specific notes section
docs/compliance/policies/risk-management-methodology.md
All other 17 policy files include a '## Batu-specific notes' section. The risk management methodology ends after '## Seed risks' without one, breaking structural consistency across the 18-policy set. Add a section covering where the risk register lives, who signs risk acceptances, and how it links to the SoA.
tests1
No CDK assertion tests for security control properties — future hardening item
infra/cdk/package.json
No CDK unit/snapshot test suite exists project-wide (pre-existing). For the new security-baseline stacks, CDK assertions (aws-cdk-lib/assertions) that verify isMultiRegionTrail=true and enableFileValidation=true would make compliance properties regression-proof. Not a blocker for this PR — cdk synth is the established project convention.
improvement7
No secret-scanning CI step — GHAS push protection dormant until billing approved
.github/workflows/pr-checks.yml
GHAS billing sign-off is pending (open item 6). Until approved, GitHub push protection is disabled on this private repo. There is no fallback gitleaks/trufflehog step in CI scanning PR diffs for CFE credentials or AWS keys. Add a gitleaks step with continue-on-error: true as an interim control — it's free, runs without GHAS, and produces audit evidence (CC6.1/A.8.12).
Missing Privacy / LFPDPPP policy — legal obligation for Mexican SaaS
docs/compliance/policies/
Two existing policies reference LFPDPPP (data-retention-disposal-policy.md, incident-response-plan.md) but there is no privacy-policy.md covering: ARCO rights procedure, legal basis for processing, 5-day breach notification to INAI, Aviso de Privacidad publication, and cross-border transfer rules. ISO 27001 A.5.34 and SOC 2 C1.1 require an explicit privacy commitment. This is a legal obligation, not just an audit nice-to-have — the 19th policy should be added before the observation window opens.
CI OIDC AdministratorAccess finding has no tracked resolution — no Linear issue, no target date
infra/cdk/src/stacks/cicd/github-oidc-roles.stack.ts:55
The finding is documented in compliance.md (CC6.3/A.8.2) but has no Linear issue, no TODO comment pointing to one, and no milestone. An auditor at Type I (~M6) will flag this as a failure. A scope-down to CDK-specific IAM actions is non-trivial but must be scheduled before M4. Add a // TODO(SEC): tracked in Linear <issue> comment and create the issue.
IR plan skeleton has no RTO/RPO numbers — Type I assessors require defined targets
docs/compliance/policies/incident-response-plan.md
The plan mentions 'define response times per SEV' without defining them, and has no RTO/RPO values. An auditor at Type I will flag the absence of defined targets. Add conservative straw-men (e.g. Platform RTO < 8h, RPO < 1h based on Supabase PITR; document as unvalidated until restore test) — having a number that gets revised is better than having none.
security-audit produces no machine-readable artifact — no vulnerability trending for SOC 2 evidence
.github/workflows/pr-checks.yml
The job writes human-readable text to the step summary. For the Type II observation window, auditors want evidence of SLA tracking per CVE. Add `pnpm audit --json > audit-report.json` + `actions/upload-artifact` to produce a structured record. A separate scheduled weekly audit job that trends the burn-down of the 110-vulnerability baseline would close the CC7.1 gap.
GitHub Actions not SHA-pinned in new workflows — supply-chain risk for security-critical checks
.github/workflows/codeql.yml
codeql.yml uses `github/codeql-action/init@v3` (security-events: write) and pr-checks.yml deploys with floating tags. Pinning to immutable SHAs (e.g. actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683) is the SLSA L2 / OpenSSF Scorecard expectation for compliance repos. Dependabot github-actions ecosystem updates SHAs automatically, so operational cost is low once pinned. The new codeql.yml should model the target practice since it's the security scan itself.
Statement of Applicability (SoA) not tracked as a repo artifact — ISO Stage 1 mandatory
.claude/rules/compliance.md
ISO 27001:2022 Clause 6.1.3 mandates an SoA documenting applicable/excluded Annex A controls with justifications. The spike/iso27001-readiness branch had a SoA skeleton (unmerged prior art, referenced in compliance.md). Both risk-management-methodology.md and physical-security-policy.md reference the SoA without pointing to a file. Add docs/compliance/soa.md (adapted from the spike) and list it in compliance.md open items — Stage 1 is ~M7.
History · 6 commits
- 2ad7120blockedincremental7H · 14M · 11L2026-07-08 17:33
- 26393f2needs attentionincremental5H · 19M · 11L2026-07-08 04:57
- 9b22f9fneeds attentionincremental6H · 12M · 9L2026-07-08 03:15
- 697438cneeds attentionfull3H · 7M · 6L2026-07-07 20:12current
- aaec085needs attentionincremental7H · 11M · 9L2026-07-07 17:59
- 6a3693cneeds attentionfull11H · 13M · 6L2026-07-07 17:41