8.8 KiB
Redis Lab Strict Kubeconfig Renderer Implementation Plan
For agentic workers: REQUIRED SUB-SKILL: Use
superpowers:subagent-driven-developmentto implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.
Goal: Complete parent Task 11.1A by replacing mutation-by-mutation kubeconfig filtering with a pinned-K3s, strict block-grammar validator/renderer and passing an independent safety review.
Architecture: Freeze the already-reviewed lifecycle/ownership state machine as Task 11.1A-1.
Move kubeconfig validation/rendering into one tracked AWK program, Task 11.1A-2. The program accepts
only the exact single-cluster/context/user block grammar emitted by the pinned K3s slice, transforms
only lab identity fields, and rejects every non-allowlisted structure before any lab kubectl
command.
Tech Stack: Bash 5 strict mode, POSIX-compatible AWK features already used by the repository, the fake-command shell contract, Gradle 9, Java 21.
Global Constraints
- Do not create a VM, run real Multipass/k3s/kubectl, inspect host inventory, or access the network.
- Do not modify Task 11.1A-1 ownership, state, signal, lock, cleanup or fingerprint behavior.
- Do not add
yq, PyYAML, Ruby, Java YAML runtime, or another downloadable parser dependency. - The only accepted source grammar is the pinned K3s admin kubeconfig block-style shape defined in deep design §37.13.4.1.
preferences: {}is the only permitted flow collection.- Validation failure removes the destination, emits only
redis-lab: lab kubeconfig invalid, and occurs before labkubectl. - Preserve prior
CREATED|RECONCILEstate and delete only exact marker-proven current-run VMs. - Tests must show RED against the current implementation before production changes.
- Human-only Git policy applies: do not stage, commit, amend or push.
Task 1: Extract a strict generated-kubeconfig renderer
Files:
- Create:
infra/redis-lab/lib/render-kubeconfig.awk - Modify:
infra/redis-lab/bin/redis-lab - Modify:
infra/redis-lab/test/redis-lab-contract.sh
Interfaces:
-
Consumes:
awk -v address=<validated IPv4> -v target=ca-redis-lab -f <renderer> <source>. -
Produces: rendered kubeconfig on stdout and exit
0, or no accepted output and non-zero exit. -
Integration:
render_lab_kubeconfig <source> <destination> <server-address>performs atomic temporary render, mode0600, destination replacement only after renderer success. -
Step 1: Add realistic positive and sibling-flow RED fixtures
Change the fake
validkubeconfig to this complete credential-data shape, using canary values rather than real certificate material:apiVersion: v1 clusters: - cluster: certificate-authority-data: preserve-default-ca-canary server: https://127.0.0.1:6443 name: default contexts: - context: cluster: default namespace: team-default user: default name: default current-context: default kind: Config preferences: {} users: - name: default user: client-certificate-data: preserve-default-client-cert-canary client-key-data: preserve-default-client-key-canaryAdd separate public
upvariants containing, after their canonical item:cluster : {server: https://foreign.invalid:6443}and:
context : {cluster: foreign, user: foreign}Each variant must assert failure, zero lab
kubectl, three exact marker-proven deletes, removed rendered kubeconfig, and no forbidden fake invocation. -
Step 2: Run the direct contract and verify RED
Run:
bash -n infra/redis-lab/bin/redis-lab infra/redis-lab/test/redis-lab-contract.sh bash infra/redis-lab/test/redis-lab-contract.shExpected: syntax succeeds and the first new sibling-flow case fails because the current renderer unexpectedly accepts it.
-
Step 3: Implement the strict AWK state machine
render-kubeconfig.awkmust use an explicitstatetransition for every accepted line. It must not print from a catch-all rule. The accepted transition sequence is:apiVersion -> clusters -> cluster-item -> ca-data -> server -> cluster-name -> contexts -> context-item -> context-cluster -> optional-namespace -> context-user -> context-name -> current-context -> kind -> preferences -> users -> user-name -> user-body -> client-cert -> client-key -> EOFExact identity transitions print these replacements:
print " server: https://" address ":6443" print " name: " target print " cluster: " target print " user: " target print "current-context: " target print "- name: " targetCA/client credential and namespace transitions print
$0unchanged. Any unmatched line setsinvalid=1;ENDexits non-zero unless the final state isclient-key, every required transition occurred once, the input had no tab/CR/YAML marker, and no trailing line exists. -
Step 4: Integrate the renderer fail-closed
Add:
KUBECONFIG_RENDERER="${REPOSITORY_ROOT}/infra/redis-lab/lib/render-kubeconfig.awk"validate_static_contractmust require a readable regular non-symlink renderer at that exact canonical path. Replace the inline AWK body with:local render_next="${destination_file}.next" rm -f -- "${render_next}" if ! awk -v address="${server_address}" -v target="${CONTEXT_NAME}" \ -f "${KUBECONFIG_RENDERER}" "${source_file}" >"${render_next}"; then rm -f -- "${render_next}" "${destination_file}" fail 'lab kubeconfig invalid' return 1 fi chmod 0600 -- "${render_next}" mv -f -- "${render_next}" "${destination_file}"Add the
.nextdestination to symlink-child validation. Propagaterm,chmodandmvfailures with the same sanitized error and without retaining a partially accepted destination. -
Step 5: Run focused GREEN
Run the direct contract again. Expected:
redis-lab-contract: PASS, exit0.
Task 2: Complete the mutation matrix and parent acceptance
Files:
- Modify:
infra/redis-lab/test/redis-lab-contract.sh - Modify:
infra/redis-lab/README.md - Modify:
docs/superpowers/plans/2026-07-29-redis-production-capability-completion.md - Modify:
.superpowers/sdd/2026-07-29-redis-production-capability-completion/progress.md - Create:
.superpowers/sdd/2026-07-29-redis-production-capability-completion/task-11-1a-2-brief.md - Create:
.superpowers/sdd/2026-07-29-redis-production-capability-completion/task-11-1a-2-report.md
Interfaces:
-
Consumes: Task 1 strict renderer and existing lifecycle fake runtime.
-
Produces: parent Task 11.1A review package with no open Critical/Important finding.
-
Step 1: Add one mutation per grammar boundary
Add table-driven fixture variants for missing, duplicate, reordered and unknown keys; whitespace before colon; quoted/tagged/explicit keys; anchor/alias/merge; unexpected
{}/[]; tab, CRLF,---/..., and trailing content. Every case must assert failure before labkubectl, exact current-run cleanup and removed render output. -
Step 2: Prove scalar preservation and exact transformation
The positive case must assert:
server: https://192.0.2.10:6443 name/current-context: ca-redis-lab namespace: team-default preserve-default-ca-canary preserve-default-client-cert-canary preserve-default-client-key-canaryIt must also assert that no
name: default,cluster: default,user: default,current-context: defaultor loopback server remains. -
Step 3: Re-run the full fake-only verification
Run:
bash -n infra/redis-lab/bin/redis-lab infra/redis-lab/test/redis-lab-contract.sh bash infra/redis-lab/test/redis-lab-contract.sh cd src ./gradlew :adapter:outbound:cache-redis:redisLabContractTest --console=plain ./gradlew :adapter:outbound:cache-redis:test --console=plain ./gradlew :adapter:outbound:cache-redis:check --dry-run --console=plainExpected: direct
PASS; both Gradle executionsBUILD SUCCESSFUL; dry-run includesredisLabContractTest. -
Step 4: Run an independent scoped review
Reviewer acceptance:
- strict renderer has no catch-all pass-through;
- the valid pinned fixture reaches EOF exactly once;
- every non-allowlisted structural line fails;
- destination publication is atomic/fail-closed;
- Task 11.1A-1 lifecycle code is unchanged except the renderer call and static path checks;
- Critical
0, Important0, both spec and quality PASS.
-
Step 5: Close the parent task
Only after Step 4 passes, replace the ledger
BLOCKEDstate with an additive resolution line:Task 11.1A-2: complete (human-only commit policy; strict renderer review clean) Task 11.1A: complete (11.1A-1 lifecycle + 11.1A-2 renderer; fake-only evidence)Do not claim live readiness, R2 or VM/k3s qualification.