Skip to content

docs: add READMEs, CLAUDE.md, and markdown linting - #7

Merged
gangster merged 3 commits into
mainfrom
docs/readmes-and-linting
May 19, 2026
Merged

docs: add READMEs, CLAUDE.md, and markdown linting#7
gangster merged 3 commits into
mainfrom
docs/readmes-and-linting

Conversation

@gangster

Copy link
Copy Markdown
Collaborator

Summary

  • Add CLAUDE.md with project overview, deployment ordering, commands, testing conventions, and architecture decisions
  • Add module READMEs for eks, eks-node-group, ssm-bastion, github_oidc (following MODULE-README-TEMPLATE with terraform-docs auto-generated sections)
  • Add AWS live unit READMEs for networking, eks, cilium, node-groups, ssm-bastion (following TERRAGRUNT-README-TEMPLATE)
  • Update cilium module README for multi-cloud support (was Azure-only)
  • Update Azure cilium live unit READMEs for cloud_provider variable
  • Add markdown linting: .markdownlint.yml config, .markdownlintignore, CI job (lints changed files only), pre-commit hook
  • Add terraform-docs freshness check to CI and pre-commit hook

Test plan

  • CI passes (markdown-lint, terraform-docs, existing checks)
  • markdownlint-cli2 CLAUDE.md infra/modules/aws/*/README.md infra/modules/cilium/README.md infra/live/aws/platform/us-east-1/platform/*/README.md returns 0 errors
  • Module READMEs contain <!-- BEGIN_TF_DOCS --> markers with auto-generated content
  • Terragrunt READMEs follow the standard template structure

🤖 Generated with Claude Code

gangster and others added 3 commits May 19, 2026 15:48
- Add CLAUDE.md with project overview, deployment ordering, key
  commands, testing conventions, and architecture decisions
- Add module READMEs: eks, eks-node-group, ssm-bastion, github_oidc
  (following MODULE-README-TEMPLATE with terraform-docs markers)
- Add live unit READMEs: networking, eks, cilium, node-groups,
  ssm-bastion (following TERRAGRUNT-README-TEMPLATE)
- Update cilium module README for multi-cloud (was Azure-only)
- Update Azure cilium live READMEs for cloud_provider variable
- Add markdownlint config (.markdownlint.yml, .markdownlintignore)
- Add markdown-lint and terraform-docs CI jobs to ci.yml
- Add markdownlint and terraform-docs checks to pre-commit hook

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The terraform-docs/gh-actions action fails on modules without
BEGIN_TF_DOCS markers. Replace with a custom script that only checks
modules that have opted in.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Pre-commit hook still runs terraform-docs locally. CI job can be
re-enabled once all module READMEs have been migrated to use markers.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@gangster
gangster merged commit 8b4e304 into main May 19, 2026
5 checks passed
@gangster
gangster deleted the docs/readmes-and-linting branch May 19, 2026 22:59
gangster added a commit that referenced this pull request Jun 1, 2026
…ocs) (#159)

* docs(arch): audit aws-organizations.md for accuracy

- 4 accounts not 2 (add Test in Platform OU, Prod in Workloads/Prod); OU tree + module-processing trace updated
- AWS provider 6.47.0 (was 5.91.0)
- enforce-encryption: add missing DenyUnencryptedEbsOnLaunch + DenyUnencryptedS3Uploads statements
- protect-data-and-network: add DenyTeamTagTampering (ABAC tag integrity, #62)
- exempt roles: document all three (OrganizationAccountAccessRole, PlatformDeployer, github-actions-terratest), not just one
- fix 'Three statements' count in CANNOT-bypass table; reconcile HIPAA ~90 services

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): rewrite config-hierarchy.md AWS-first and accurate

The doc predated the AWS-first pivot — it described a 7-layer hierarchy with Azure/GCP
as deployed clouds. Reframed to current reality:
- 6-layer hierarchy (root/common/env/region+network/workload/unit); _versions.hcl and
  _base.hcl documented as supporting files, not layers (matches CLAUDE.md + ADR-001)
- AWS-only: no live/azure or live/gcp trees exist; removed fabricated Azure aks_core /
  dev-eastus examples, _envcommon, and module-count tables; Azure/GCP now a concise
  'planned, same pattern' section
- cloud detection defaults to 'aws' (not 'azure'); only provider_aws generated
- AWS provider 6.47.0 (was 5.91.0)
- env layer is env.hcl; envs are mgmt/platform/preprod/prod/test (not ops/dev)
- environment_account_map sourced from secrets.hcl; state bucket/role from secrets
- 2 safety assertions (env-path + account), not 3 (dropped nonexistent 'Azure workload-path')
- _versions.hcl has ~37 module sources + ~10 helm pins (not '4 modules / empty helm map')

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): cosign-image-signing §10b — SLSA L3 cutover done on preprod

Provenance is now signed solely by the isolated trusted-ci reusable workflow and
verify-attestations is in Enforce on preprod (Build L3 achieved); was described as
'today hand-authored / dual-provenance first / swaps later'. Platform replication (P4) pending.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): preprod-tenant-model — fix ADR-027 link, add Pod Identity egress policy

- fix broken link (027-hybrid-tenant-isolation -> -model); add ADR-041 to related
- add the 5th tenant policy allow-pod-identity-egress (CiliumNetworkPolicy, host egress
  to the Pod Identity agent 169.254.170.23:80, ADR-041) to the resource table + network
  topology; correct count to 'two CiliumNetworkPolicies'

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): platform-capability-coverage — observability now live, security depth shipped

- Observability #7: ❌ Missing -> 🟡 Partial (metrics+Mimir+dashboards+SNS alerting live on
  hub ADR-043/044, Falco runtime detection ADR-045); remaining = logs/traces/cost + spoke fan-in.
  Reordered into the 🟡 group.
- Reframe strategic gaps: DX/self-service is now the dominant gap; security-depth items
  (SBOM, SLSA L3, Falco, Semgrep SAST) have largely shipped.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): kyverno-policy-catalog — add attestation verification, fix per-team count rationale

- add the deployed verify-attestations-team-<team> policy (CycloneDX SBOM + SLSA provenance,
  trusted-ci for L3-adopted teams; Enforce on preprod 2026-05-30, ADR-042) — was missing
- fix the '+2 per-team policies' explanation: four policy families are per-tenant
  (restrict-images, restrict-route-hostnames, verify-images, verify-attestations); counts are
  an indicative snapshot, read live via kubectl get cpol

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): observability-current-state — P2 Step 3 / PR #147 now merged (was 'finalizing')

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(arch): supply-chain-overview — fix app-beta -> app-bravo (team naming)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(compliance): scp-control-mapping — add missing SCP statements + all 3 exempt roles

- enforce-encryption: add DenyUnencryptedEbsOnLaunch + DenyUnencryptedS3Uploads to the
  control-mapping table and description (audit completeness)
- protect-data-and-network: add DenyTeamTagTampering (ABAC tag integrity)
- exempt-role governance: list all three (OrganizationAccountAccessRole, PlatformDeployer,
  github-actions-terratest) + note the no-exemption statements — important for auditors
- bump Last reviewed to 2026-06-01

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): modify-scps — fix exempt_roles examples to keep all 3 live roles

Both exempt_roles examples showed only OrganizationAccountAccessRole + a break-glass role;
copying them would drop PlatformDeployer (breaks IaC apply) and github-actions-terratest
(breaks CI). Show the real three + append pattern with DO-NOT-REMOVE warnings. Also clarify the
DenyUnencryptedS3Uploads 'add a statement' example already ships; bump review date.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): incident-scp-blocking — exempt_roles append pattern + new SCP error rows

- Step 3a exempt_roles: keep all 3 live roles (don't drop PlatformDeployer/terratest)
- SCP-to-error table: add DenyUnencryptedEbsOnLaunch, DenyUnencryptedS3Uploads, DenyTeamTagTampering
- bump review date

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs: review troubleshooting/aws-organizations + align HIPAA service count to ~117

- troubleshooting/aws-organizations.md: reviewed (OU hierarchy + procedures accurate); HIPAA
  count 120+ -> ~117; bump review date; make lint-clean (MD040 add 'text' to bare error-output
  fences, MD036 convert bold 'Error: ...' sub-headings to #### headings — pre-existing, now in
  CI scope since the file is touched)
- correct HIPAA count to ~117 in aws-organizations.md (was my earlier ~90 guess) and
  scp-control-mapping.md (was 120+) — now consistent with scps.tf

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(terraform): variable_validation_standards — AWS-first reframe

Principles are cloud-agnostic and correct; the concrete examples were all Azure (in an AWS-only
repo). Add an AWS-context note, replace the Azure-region example with the AWS allowed-regions
pattern (us-east-1/us-west-2, matching deny-regions SCP), and azurerm_example -> aws_acm_certificate.
Remaining Azure-named examples kept as pattern illustrations (noted as transferable to AWS).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): secrets-management — clarify tenant secrets vs Pod Identity

ClusterSecretStore name (aws-secrets-manager) verified correct. Sharpen the App-Team-Secret note:
per-namespace ESO SecretStores are still the target model (ADR-024 pending), but tenant AWS resource
access is already live via EKS Pod Identity (ADR-041), not ESO; ClusterSecretStore now on platform+preprod.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): tenant-onboarding — add hostnames (required), Pod Identity, cosign

- teams.hcl example was missing hostnames: a team onboarded without it has ALL HTTPRoutes denied by
  Kyverno (ADR-029). Add hostnames to the example + a prominent warning; add optional aws/Pod-Identity block
- note to apply pod-identity + s3-shared units when an aws block is declared (ADR-041)
- point to app-supply-chain-onboarding for cosign signing (images must be signed to pass admission)
- verification: add allow-pod-identity-egress to expected CiliumNetworkPolicies

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): kyverno-break-glass — note separate verify_attestations_failure_action knob

Attestation verification (SBOM + SLSA provenance, incl. trusted-ci L3) has its own failure-action,
independent of validation and image-signature verification — can be flipped to Audit for break-glass
without weakening the signature gate (ADR-042).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): upgrade-procedures — add observability/Mimir/Falco/vCluster to version table

All existing pins verified correct. Add the components that shipped this week: kube-prometheus-stack
86.1.0 + Mimir 6.0.6 (platform-only), Falco 9.0.0 (preprod-only), vCluster 0.34.1 (deferred). Note
their single-cluster placement skips the preprod-first sequencing.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): tailscale-vpn — note preprod subnet router (10.101)

Doc covered only the platform cluster; preprod also runs a tailscale unit advertising 10.101.0.0/16
(split DNS -> 10.101.0.2), which is what provides operator kubectl access to the now-private preprod
API. Namespace tailscale-system verified correct; bump review date.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(user-guide): AWS-current — platctl, 4 accounts, IAM roles, ops->platform

- bootstrap/teardown use platctl (ADR-038); scripts/bootstrap-platform.sh is gone. ~30 units, not 16
- greenfield expected: 4 member accounts (platform/test/preprod/prod), not 2
- IAM roles table: PlatformAdmin (Platform+PreProd), PlatformDeployer (+Test), DeveloperAccess-<team> on
  PreProd per-team (was wrongly 'Platform') — matches ADR-007/039/040
- fix stale ops/ path in dependency example -> platform/

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(onboarding): AWS-first/current — structure, 6-layer, platctl, 4 accounts

- repo structure tree: root.hcl (not terragrunt.hcl); AWS-only modules/live (removed nonexistent
  naming/azure/gcp modules + azure/gcp live + charts/ + planning/); add cmd/platctl; env.hcl
- config hierarchy: seven-layer -> six-layer, drop _envcommon, env.hcl, note _versions/_base as supporting
- greenfield: 4 accounts (platform/test/preprod/prod); platctl bootstrap/teardown (ADR-038, ~30 units)
  replaces the removed scripts/bootstrap-platform.sh

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(interview-prep): reframe multi-cloud overclaims as AWS-first

azure/gcp modules are planned (not present); the tenant model is designed for AKS/GKE but only
AWS/EKS is deployed. Rest of the doc (IaC structure, state, SCPs) is accurate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(index): README — AWS-first framing, six-layer, add key architecture docs

- multi-cloud (AWS,Azure,GCP) -> multi-cloud-by-design, AWS-first today
- Config Hierarchy: seven-layer -> six-layer; link the config-hierarchy.md doc (not _base.hcl)
- add cosign, kyverno-policy-catalog, aws-organizations, platform-capability-coverage to How It Works
- repo layout: aws/+shared modules (azure/gcp planned), live/aws only, add cmd/platctl

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(runbook): deploy-app-preprod — per-team ECR role, drop :latest, note signing

CI examples used the removed shared github-actions-ecr-push role (now per-team, ADR-036/#60),
pushed :latest (denied by Kyverno disallow-latest-tag), and omitted cosign signing (required by
verify-images Enforce). Fix both build-push.yml and preview.yml: per-team role, immutable SHA tag
only, and a pointer to app-supply-chain-onboarding for signing/SBOM/provenance.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(plans): update status — observability P1/P2 live, SLSA L3 done on preprod

- 102-observability-stack: 'implementation not started' -> P1+P2 (Mimir) DONE and live (ADR-043/044,
  PR #147); points to observability-current-state as-built
- 131-slsa-build-l3: 'P2-P4 not started' -> P1-P3 DONE on preprod (Build L3 achieved), P4 remaining
- slsa-l3-provenance-cutover-HANDOFF: marked COMPLETE/superseded by ADR-042 (retained for history)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gangster added a commit that referenced this pull request Jun 4, 2026
#209)

After a long node-group-at-zero downtime, the Tailscale subnet-router
pod's stored node key goes invalid; it restarts in NeedsLogin and asks
the operator to reissue an auth key, but the operator reports
ConnectorReady=True and never mints one into the secret's empty
reissue_authkey field -> 10-min timeout -> CrashLoop -> the cluster's
whole route is unadvertised and the cluster is unreachable over
Tailscale (kubectl resolves but times out -- distinct from the
split-DNS conflict #1). Fix: delete the wedged state secret + pod so
the operator re-provisions a fresh auth key and the pod re-registers.

Observed on preprod during the 2026-06-04 scale-up incident (#206).

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
gangster added a commit that referenced this pull request Jul 12, 2026
…(real alpha/bravo names) (#1387)

* docs(observability): accuracy + teachability sweep of the deep dives; adopt real alpha/bravo names

Pressure-tested all five observability deep dives against primary-source code
(not other docs — the tenant-proxy incident showed the as-built doc and skill
were themselves stale). Fixes the accuracy failures, which clustered in the
low-attention spots (headers, gotchas, code-block field names, hard counts,
"live output" blocks), and applies the bounded teachability edits.

CRITICAL accuracy:
- stack-and-storage: header, a datasource bullet, and Gotcha #7 still described
  the RETIRED fail-closed tenant-proxies as live (Gotcha #7 asserted a false
  security guarantee). Rewritten to the soft read model (folder perms + #1157
  dashboards; proxy retired #1269, read_proxy_url=""; network default-deny is
  the real data-plane boundary). Also corrected the federated datasource header
  platform|preprod -> platform|preprod|alpha|bravo (verified vs the module).
- correlation + reference + orientation + correlation-walk.svg: `tracesToProfilesV2`
  is the broken field Grafana silently ignores (#1269) — the real field is
  `tracesToProfiles` (no V2; logs has a V2, profiles does not). Fixed everywhere
  it appeared, incl. the shipped diagram label. Loki derived-field url escape
  fixed to the required `$$${__value.raw}` (three $).

MAJOR accuracy:
- slos: alert count "42 across 12 groups" -> the real "61 across 20"; freeze-gate
  reframed (one-shot pre-flight: freezes if the service is ALREADY burning >=2x,
  never blocks a first deploy).
- collection: hub/spoke table cell for the OTel operator/CRD on the spoke was
  wrong (shown absent) — it's live with 5 CRs; exclusion mechanism corrected to
  the `exclude_instrument` annotation predicate (namespace stays in the glob).

Naming: the deep dives now use the REAL running apps (alpha/bravo) instead of
generic acme/globex — which also makes the "live kubectl output" blocks genuinely
verifiable (real teams are alpha/bravo/platform). Orientation + the 9 diagrams
keep acme/globex for now (that retrofit is a separate follow-up).

Teachability (bounded): two-SLO-systems compare table; a stitched end-to-end
triage walk; front-loaded takeaways; de-duplicated the repeated hub-first point;
glossed cortex-tenant / exemplar / Downward API / serviceMonitorSelectorNil...;
worked example of one opted-in pod; burn-rate multiplier->error-ratio; PagerDuty
status de-dated in the reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(observability): retrofit orientation + diagrams to real alpha/bravo names

Extends the real-name adoption from the deep dives to the orientation prose
and the three shipped diagrams that carried generic team names
(correlation-walk, hub-and-spoke, isolation-model): acme->alpha, globex->bravo,
acme-shop->alpha-shop, acme-checkout->alpha-checkout, globex-widgets->bravo-dispatch.
Team + product names only; the friendly service names (shop-web/checkout) stay so
the orientation and its diagrams remain internally consistent. SVG label swaps are
<=+1 char, verified in dark mode (no overflow/gluing). The whole observability
section now uses the real running apps.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(observability): fix reference alert count ~40 -> ~60 (missed in the sweep)

The reference's alerting line still said ~40 curated rules; the real count is
61 across 20 groups (curated.yaml) — matching the deep-dive fix. A textbook
instance of the very trap being captured: a stale count survived in a reference.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(observability): place the 5 Tier-1 deep-dive diagrams

The deep dives had zero diagrams (all 9 visuals were in the orientation) —
the biggest gap flagged in the pressure-test. Places one signature diagram
per deep dive at its section anchor, each going mechanism-deep where the
orientation's overview diagrams don't:

- pipeline-swimlanes  → collection §End-to-end flow (kernel→collector→store, all signals)
- correlation-web     → correlation §end of Part 1 (the replace(uid,…) convention across tenants)
- two-slo-pipelines   → slos §Two generators (Sloth vs auto-derived, one burn-rate shape)
- isolation-status    → stack-storage §Honest status (hard write / soft read / retired proxy)
- eval-feedback-loop  → agent-obs §The three slices (the human-verdict calibration loop)

Baked light+dark via theme-svg.mjs; all verified in dark mode (no word-glue on
the multi-line SVGs, house colour grammar, real alpha/bravo names). isolation-status
doubles as a visual lock on the corrected read-isolation story.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(observability): place the 10 Tier-2/3 deep-dive diagrams

Completes the deep-dive diagram program — two per doc, going a level deeper
than the Tier-1 signature diagrams:

collection:  beyla-vs-sdk-fragmentation (L0/L1 traceparent split + the fix),
             three-alloys (one binary, three topologies)
correlation: loop-vs-oneway (SDK closes the loop, Beyla-only doesn't),
             fragile-seam (service.name agreement, not declaration)
slos:        alert-routing-tree (severity plumbing before ownership),
             opencost-vs-cur (speedometer vs odometer, the sum() trap)
stack:       storage-shape (disposable hot buffer, durable S3 tail),
             network-perimeter (tenancy is a network boundary, not a header)
agent:       triage-span-tree (replaces the bare mermaid with an annotated
             span tree), content-capture-tiers (metadata always / content
             gated / regulated never)

All baked light+dark via theme-svg.mjs; every one verified in dark-mode Chrome
(no word-glue on the multi-line SVGs, house colour grammar, real alpha/bravo
names). The agent-obs mermaid block is removed.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* docs(observability): re-render eval-feedback-loop as a closed ring

The first render was a numbered vertical flow with a 'back to 1' note — it read
as a checklist, not a loop. Re-rendered as a true closed ring: 5 nodes clockwise
(agent disposition → Slack proposal → human verdict → counter → accept-rate) with
curved arrows completing the cycle, 'is the agent calibrated?' in the center, and
the same-machine / confidently-wrong / cold-agent callouts outside the ring.
Placement unchanged. Verified in dark mode (no arrow/label overlap).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant