fix: install bws, isolate the private config, keep credentials out of logs

Three defects the private tier could not survive a fresh machine with.

bws was never installed. The private/bws-secrets row promised seven API
keys and shipped no way to fetch them: dotsecrets shells out to `bws
secret get`, and nothing put that binary on the box. Added as a tarball
channel with checksum verification, musl rather than gnu so it does not
pin a glibc newer than an older LTS carries, plus core/unzip as a real
@needs dependency since the release is a .zip and 24.04 minimal has no
unzip. The releases API needs filtering by tag prefix: sdk-sm is a
monorepo and `latest` usually points at a python SDK, not bws.

Both tiers rendered their config to ~/.config/chezmoi/chezmoi.toml, so
re-running the public installer overwrote the private config and took its
seven promptStringOnce answers with it. Silently -- the templates degrade
politely when data is missing, so the symptom was `git commit` not knowing
who you are, days later. The private tier now renders to private.toml and
the cmp alias carries the matching -c.

`run` echoes its argv to stderr, and the private init argv ends in
https://user:TOKEN@host -- into scrollback, any `dotup 2>log`, and any
agent transcript. Traced through redact_url instead, in both the live and
dry-run branches. The clone is also chmod -R go-rwx afterwards: it lands
at the caller umask, and .git/config stores that same credential URL.

Tests: 90 passing, 9 new covering all three.
This commit is contained in:
bcherb2
2026-08-17 11:15:48 -04:00
parent e1332c67d8
commit 90bca39396
3 changed files with 130 additions and 3 deletions
+32
View File
@@ -102,6 +102,38 @@ is "@spec lines are not packages" "0" \
"$(sh $D render | cut -f2 | grep -c 'spec' || true)"
reset; sh $D toggle p:core/uv >/dev/null
is "dropping uv drops specify-cli" "off" "$(on agents/specify-cli)"
# bws-secrets promised seven API keys and installed nothing to fetch them with.
# The binary ships as a .zip and 24.04 minimal has no unzip, so the dependency
# is real rather than decorative.
reset; sh $D toggle p:private/bws-secrets >/dev/null
is "ticking bws-secrets pulls in unzip" "on" "$(on core/unzip)"
is "bws-secrets has an install channel" "-tarball" \
"$(awk -F'\t' '$1=="private" && $2=="bws-secrets" {print $4}' "$M")"
printf '\n\033[1mcredentials never reach a log\033[0m\n'
# `run` echoes its whole argv to stderr. The private init's argv ends in
# https://user:TOKEN@host, so it must not go through `run`.
is "private init does not use run()" "0" \
"$(grep -c 'run chezmoi init' $D)"
# Two, not one: the dry-run branch traces it too, and a dry run that printed a
# live token would be the worse leak of the pair.
is "both traced URLs are redacted" "2" \
"$(grep -c 'redact_url "\$p_repo"' $D)"
# Exercise the real implementation lifted straight out of dotup. A copy of the
# sed expression here would keep passing after someone edited the original.
rd() { eval "$(sed -n '/^redact_url()/p' $D)"; redact_url "$1"; }
is "redact_url strips userinfo" "https://<redacted>@git.example.com/x.git" \
"$(rd 'https://ben:deadbeefcafe@git.example.com/x.git')"
is "...and leaves a credential-free URL alone" "https://git.example.com/x.git" \
"$(rd 'https://git.example.com/x.git')"
# Two tiers, two configs. Sharing one meant the public installer silently ate
# the private tier's seven promptStringOnce answers.
is "private init carries its own -c" "1" \
"$(grep -c '\-c "\$PRIV_CFG"' $D)"
is "PRIV_CFG is not the default config path" "0" \
"$(grep -c 'PRIV_CFG=.*chezmoi/chezmoi.toml' $D)"
is "the private source is locked down after clone" "1" \
"$(grep -c 'chmod -R go-rwx "\$PRIV_SRC"' $D)"
printf '\n\033[1mrisk model — the invariants that matter\033[0m\n'
reset