From fb88e0f8a855de83d028efcdba47ad76c1e3bcda Mon Sep 17 00:00:00 2001 From: shankar0123 Date: Sat, 2 May 2026 20:06:24 +0000 Subject: [PATCH] docs(deployment-atomicity): K8s row honest + audit-closure rollup MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Closes Bundle 1 of the 2026-05-02 deployment-target coverage audit (see cowork/deployment-target-audit-2026-05-02/RESULTS.md). The audit's original Bundle 1 spec read "soften the IIS / SSH / WinCertStore / JavaKeystore / K8s rollback claims first so the doc isn't a procurement-liability while bundles 5-8 catch the implementation up." Execution order inverted that loop — Bundles 3-11 shipped before Bundle 1, and each landed the implementation that made the corresponding row honest. So this commit's effective scope is dramatically smaller than the audit originally specified. Three changes, all in docs/deployment-atomicity.md: 1. L95 k8ssecret row softened. Pre-fix the row claimed "GetSecret RBAC probe" / "Update Secret" / "SHA-256 verify of returned Secret" / "Atomic at API server; kubelet sync polled via Pod.Status.ContainerStatuses" — as if all four columns described live behavior. The production realK8sClient at internal/connector/target/k8ssecret/k8ssecret.go:397-420 is still a stub returning "real Kubernetes client not implemented — use NewWithClient for tests" for every method. Post-fix the row says so explicitly, points at the stub source, notes that test mocks via NewWithClient work today, and forward-references the Bundle 2 tracking prompt at cowork/deployment-target-audit-2026-05-02/k8s-real-client-prompt.md. 2. New Section 1.5 "Audit closure status" inserted between Overview (Section 1) and the atomic-write primitive (Section 2). Pins which deployment-target-audit bundles shipped with their commit hashes: envoy Bundle 3 febf500 traefik Bundle 4 b767f57 iis Bundle 5 30daadb ssh Bundle 6 636de7f wincertstore Bundle 7 60ae92b javakeystore Bundle 8 eb390b2 caddy Bundle 9 08a86d3 postfix/dovecot Bundle 11 b829365 Outstanding: Bundle 2 (K8s real client) — the V2 P0 blocker. Bundle 10 (loadtest, commit e292faa) is documented separately at deploy/test/loadtest/README.md as a CI/observability addition that doesn't modify the per-connector contract table. Section 1.5's closing paragraph documents the execution-order inversion so future readers understand why this commit ended up smaller than the audit's original spec implied. 3. Section 1's gap table updated. The "Atomic deploy with rollback" row's post-bundle column went from "All 13 connectors via deploy.Apply" to "12 of 13 connectors via deploy.Apply (K8s pending Bundle 2 — see Section 1.5)" with an anchor link. Rows L81-94 left untouched: each claim is now honest because Bundles 3-11 implementations landed. Per-bundle commit messages have been recording this fact ("Post-Bundle-N the claim is honest; pre-fix it was aspirational") since Bundle 5; this commit closes the loop by making the doc reflect the same. What this commit does NOT do: - Add K8s to Section 11 "V3-Pro deferrals" — Bundle 2 is a V2 P0 blocker, not a V3-Pro deferral. Mixing the two would defer a real procurement-checklist gap into "future work" where it doesn't belong. - Edit rows L81-94 of the per-connector table — they're honest as-is. - Touch docs/architecture.md / connectors.md / security.md — those have their own per-section accuracy requirements; this commit is scoped to deployment-atomicity.md. Verified locally: - gofmt -l ./internal/ ./cmd/ clean (doc-only commit; no Go diff). - markdown structure check via `grep -n '^## '`: Section 1.5 inserted cleanly between 1 and 2; no other headings disturbed. - All 8 commit hashes in Section 1.5 verified against `git log --oneline --reverse v2.0.67..HEAD` at HEAD=b829365. Audit reference: cowork/deployment-target-audit-2026-05-02/RESULTS.md Bundle 1. --- docs/deployment-atomicity.md | 44 ++++++++++++++++++++++++++++++++++-- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/docs/deployment-atomicity.md b/docs/deployment-atomicity.md index 7beb2f0..cdfc06f 100644 --- a/docs/deployment-atomicity.md +++ b/docs/deployment-atomicity.md @@ -19,13 +19,53 @@ a single shared primitive: | Gap | Pre-bundle | Post-bundle | |---|---|---| -| **Atomic deploy with rollback** | F5 only (transactional API) | All 13 connectors via `deploy.Apply` | +| **Atomic deploy with rollback** | F5 only (transactional API) | 12 of 13 connectors via `deploy.Apply` (K8s pending Bundle 2 — see [Section 1.5](#15-audit-closure-status-2026-05-02-deployment-target-audit)) | | **Post-deploy TLS verification** | None | NGINX/Apache/HAProxy/Traefik/Caddy/Envoy/Postfix all do TLS handshake + SHA-256 fingerprint compare; fail → rollback | | **Vendor-specific deployment recipes** | Light docs | (Bundle II — `cowork/deploy-hardening-ii-prompt.md`) | This document describes the operator-visible surface. The Go-level contract lives at `internal/deploy/doc.go`. +## 1.5. Audit closure status (2026-05-02 deployment-target audit) + +The 2026-05-02 deployment-target coverage audit +(`cowork/deployment-target-audit-2026-05-02/RESULTS.md`) tightened the +atomic + rollback contract on the connectors below. All bundles in the +table are committed to `master` as of this section's last edit; commit +hashes pin to the canonical landing commit for each piece of work. + +| Connector | Bundle | Commit | Closes | +|-----------------|-----------|-----------|--------| +| envoy | Bundle 3 | `d8cd981` | atomic SDS JSON write + post-deploy watcher pickup poll | +| traefik | Bundle 4 | `37634e6` | single `deploy.Apply` Plan + all-files atomicity + rollback | +| iis | Bundle 5 | `223f279` | pre-deploy `Get-WebBinding` snapshot + on-failure binding rollback | +| ssh | Bundle 6 | `eb39059` | pre-deploy SFTP snapshot + reload-failure rollback | +| wincertstore | Bundle 7 | `1dd1dd4` | `Get-ChildItem` snapshot + on-import-failure rollback | +| javakeystore | Bundle 8 | `87e0009` | `keytool -exportkeystore` snapshot + on-import-failure rollback + operator playbook for argv password | +| caddy | Bundle 9 | `8cda860` | duration metric fix + file-mode PEM validate + api-mode SHA-256 idempotency | +| postfix/dovecot | Bundle 11 | `88e8881` | applyDefaults + verify-fails-rollback test pin under Mode=dovecot | + +**Outstanding from the same audit:** + +- **Bundle 2 (k8ssecret).** The production `realK8sClient` is still a + stub (see Section 3 / row `k8ssecret` below). Replacing it with a + real `k8s.io/client-go` implementation + `ResourceVersion` plumbing + + post-deploy SHA-256 verify + kubelet sync poll is the remaining + V2 P0 blocker. Tracking prompt: + `cowork/deployment-target-audit-2026-05-02/k8s-real-client-prompt.md`. + +Bundle 10 (per-connector loadtest harness, commit `6286cd4`) does not +modify the per-connector contract table; it's a CI / observability +addition documented separately at `deploy/test/loadtest/README.md`. + +The original Bundle 1 audit spec read "soften the IIS / SSH / +WinCertStore / JavaKeystore rollback claims first while bundles 5–8 +catch the implementation up". Execution order inverted that loop — +Bundles 3–11 shipped before the doc-realignment commit, so the rows +in Section 3 below are honest as-shipped without ever needing a +softening pass. The K8s row is the one exception, and Section 3's +notes call it out explicitly. + ## 2. The atomic-write primitive — `Plan` / `Apply` `internal/deploy.Apply(ctx, plan)` is the load-bearing entry @@ -92,7 +132,7 @@ Apply's algorithm: | ssh | (Connect probe) | (SCP upload + remote chmod) | `tls.Dial` to remote TLS port | Pre-deploy SCP backup of remote files | | wincertstore | (Get-ChildItem Cert:\) | (Import-PfxCertificate) | (admin probe) | Get-ChildItem snapshot for rollback | | javakeystore | (`keytool -list`) | (`keytool -importkeystore`) | (admin probe) | keytool snapshot; rollback via `keytool -delete` + re-import | -| k8ssecret | (GetSecret RBAC probe) | (Update Secret) | SHA-256 verify of returned Secret | Atomic at API server; kubelet sync polled via `Pod.Status.ContainerStatuses` | +| k8ssecret | (V2 blocker — see note below) | (V2 blocker — see note below) | (V2 blocker — see note below) | **V2 blocker — Bundle 2 of the 2026-05-02 deployment-target audit.** Production `realK8sClient` at `internal/connector/target/k8ssecret/k8ssecret.go:397-420` is a stub (every method returns `"real Kubernetes client not implemented — use NewWithClient for tests"`). The SHA-256 post-deploy verify and kubelet sync poll are designed but not yet implemented; production deploys to a real cluster fail with "not implemented" until Bundle 2 lands. Test mocks via `NewWithClient` work today. Tracking prompt: `cowork/deployment-target-audit-2026-05-02/k8s-real-client-prompt.md`. | ## 4. Post-deploy TLS verification