Commit ef96befe authored by otica-integrator's avatar otica-integrator
Browse files

Merge branch 'agent/issue-5' into 'main'

fix(skill): scope TrimSpace advice to Make-included vault reads

Closes #5

See merge request !5
parents 5e9c1cc7 3aaee668
Loading
Loading
Loading
Loading
+22 −1
Original line number Diff line number Diff line
@@ -266,11 +266,12 @@ kc-render: envvars

**Two gotchas when converting `envvars.sec` from `#!vault2text` to `#!gomplate`:**

1. **`| strings.TrimSpace` every vault read.** Vault often stores files with trailing newlines. Without trim, the `\n` lands in the value and Make dies with `missing separator`:
1. **`| strings.TrimSpace` vault reads that get `-include`d into Make.** Vault often stores values with a trailing newline. When such a value lands in `envvars.sec` / `env.mk` and is `-include`d, that `\n` breaks Make with `missing separator`, so trim it:
   ```diff
   - export PROXMOX_USERNAME={{ tmpl.Exec "vault-kv" .Env.PROXMOX_USER_PATH }}
   + export PROXMOX_USERNAME={{ tmpl.Exec "vault-kv" .Env.PROXMOX_USER_PATH | strings.TrimSpace }}
   ```
   **Only trim Make-included scalars — never Secret `data:` payloads.** For PEM keys and certs, openssl and most tools emit a trailing newline and many consumers rely on it; for binary blobs like keytabs (stored `format:base64`) any trim mangles the bytes. Either way `TrimSpace` silently corrupts the secret and breaks byte-for-byte parity with what Vault stored (what `vault2kube` produced) — render `data:` payloads verbatim.

2. **Do NOT wrap vault values in shell quotes.** Make's `-include` doesn't strip quotes — `export FOO='bar'` makes the Make variable `FOO` literally `'bar'`. Use unquoted values (Make's RHS is whitespace-permissive for most values).

@@ -293,6 +294,8 @@ deploy: kc-config kc-apply-sec kc-apply

Vault binary-blob note: Vault stores binary keytabs as `{format: base64, value: <base64>}`. gomplate's `vault-kv` driver returns the raw bytes (auto-decoded), so `| base64.Encode` re-encodes back to the same base64 string the Secret needs — byte-identical to what `vault2kube` produced.

**Render payloads verbatim — never `| strings.TrimSpace` before `base64.Encode`.** PEM keys and certs are commonly stored with a significant trailing newline; trimming it drops a byte from the decoded payload, so the rendered Secret no longer matches the original and a workload may fail later when it loads a key/cert missing its final `\n`. This mirrors the `vault-read.sh` verbatim-output fix.

### Validate

```bash
@@ -308,6 +311,24 @@ make kc-diff # no output (exit 0) = render matches what's deployed

**Never `cat .deploy_sec/secret.yml`** — it contains real base64-encoded keytabs / PEMs. Use `make kc-diff` instead (shows structural delta, no secret bytes when secret is unchanged).

**When a plain-string payload's trailing newline is significant** (PEM keys, certs — values stored *without* `format:base64`), don't assume `TrimSpace` is safe — confirm the migrated render is byte-identical to the legacy `vault2kube` output. Compare the rendered, decoded length against the value stored in Vault without revealing the bytes, e.g.:
```bash
# stored length in Vault vs. rendered length — must match. Read the stored value
# straight from Vault (independent of vault-read.sh's trailing-newline behavior)
# with jq -j, which adds no newline of its own. Both sides count the same bytes
# only for plain-string values — see the keytab note below for format:base64 blobs.
# Run each pipeline as ONE unit: the jq stage alone prints the raw secret to
# stdout — only the trailing `| wc -c` keeps it off your terminal. Assumes the KV
# field is named `value` (the vault-kv driver's convention); under another key jq
# emits the literal `null` (4 bytes) and the counts silently won't match.
vault kv get -format=json "${SEC_PATH}/my-key" | jq -j '.data.value//.data.data.value' | wc -c
make kc-render-sec && grep 'my-key:' .deploy_sec/secret.yml | awk '{print $2}' | base64 -d | wc -c
```

A mismatch of exactly 1 byte is the classic dropped-trailing-newline symptom.

> **Not for `format:base64` blobs (binary keytabs).** Vault stores those as a base64 *string*, so the first command counts the base64 length while the second counts the decoded bytes — the two `wc -c` counts legitimately differ even on a perfect render. A binary keytab carries no significant trailing newline anyway; verify its integrity with `make kc-diff` instead.

## 9. Universal gotchas

**OTICA `render.sh` `/*` first-line glob bug.** If a `.tf` file starts with `/*`, bash globs it to root dirs. Workaround: prepend a `#` comment on line 1.