test: container lab for the two-tier apply

A disposable ubuntu container, a fake private tier and a fake bootstrap
endpoint, so the whole documented path — chezmoi init --apply, dotup pick,
dotup private, cmp apply, dotsecrets — can run end to end without touching a
real machine or a real credential. The fake tier mirrors the real one's
structure (seven secrets and one alias) because dotsecrets is copied verbatim
and the "8 exports, not 7" assertion depends on that cardinality; its ids are
sequential and obviously synthetic.

check-verbatim.sh keeps the fake tier's copies of shipped files honest, and
snapshot.sh records file modes so a 644 where a 600 belongs is a diff.
This commit is contained in:
bcherb2
2026-08-21 22:34:53 -04:00
parent d1e3f8bce2
commit a001406a33
22 changed files with 2809 additions and 0 deletions
@@ -0,0 +1,71 @@
{{- $name := get . "gitName" -}}
{{- $email := get . "gitEmail" -}}
{{- $signing := get . "gitSigningKey" -}}
{{- $wan := get . "giteaWanSsh" -}}
{{- $lan := get . "giteaLanSsh" -}}
; ~/.config/git/config.local -- PRIVATE tier.
;
; The other half of the seam. ~/.gitconfig comes from the public repo, carries
; no [user], and ends with `[include] path = ~/.config/git/config.local`. Git
; treats a missing include as a no-op, so a public-only machine reads the
; public half and stops -- and `git commit` correctly refuses to guess who you
; are.
;
; Everything here is identity, not configuration: it is the answer to "whose
; machine is this", which is exactly the question the public tier must not be
; able to answer.
;
; Values come from the [data] prompts in .chezmoi.toml.tmpl, asked once at
; `chezmoi init`. Re-answer them with `cmp init` (see README).
{{ if and $name $email -}}
[user]
name = {{ $name }}
email = {{ $email }}
{{- if $signing }}
signingkey = {{ $signing }}
[commit]
gpgsign = true
[tag]
gpgsign = true
{{- end }}
{{- else -}}
; NO IDENTITY CONFIGURED.
;
; gitName and/or gitEmail are empty in the chezmoi config, which means either
; you pressed enter through the prompts or something overwrote
; ~/.config/chezmoi/chezmoi.toml after this tier was initialised. Re-run:
;
; chezmoi init -S ~/.local/share/dotfiles-private
;
; Until then git will refuse to commit, which is the correct complaint.
{{- end }}
; Every remote in every repo you own is ssh. This rewrite is what lets a
; copy-pasted https:// GitHub URL clone over the key you actually have, which
; matters most on a machine built ten minutes ago. It lived in the old
; dot_gitconfig; phase 3 removed it from the public tier because it names an
; authentication method tied to your keys, not a neutral default.
[url "git@github.com:"]
insteadOf = https://github.com/
{{ if $wan -}}
; Gitea clone/push shortcuts: git clone gitea:ben/repo.git
[url "{{ $wan }}"]
insteadOf = gitea:
{{ end -}}
{{ if $lan -}}
[url "{{ $lan }}"]
insteadOf = gitea-lan:
{{ end }}
{{- if and $wan $lan }}
[alias]
; Configure `origin` to push to BOTH gitea servers at once. Run once inside
; a repo whose origin points at either gitea host:
;
; git dual-gitea
;
; After this, `git push` writes to WAN + LAN simultaneously. Fetch/pull
; continues to use origin's existing fetch URL.
dual-gitea = "!f() { url=$(git remote get-url origin) || { echo 'no origin remote' >&2; return 1; }; p=${url#gitea:}; p=${p#gitea-lan:}; p=${p#{{ $wan }}}; p=${p#{{ $lan }}}; if [ \"$p\" = \"$url\" ]; then echo \"origin is not a gitea remote: $url\" >&2; return 1; fi; git config --unset-all remote.origin.pushurl 2>/dev/null; git remote set-url --add --push origin \"gitea:$p\"; git remote set-url --add --push origin \"gitea-lan:$p\"; echo 'Dual-push configured on origin:'; git remote -v; }; f"
{{- end }}
@@ -0,0 +1,61 @@
{{- $wanWeb := get . "giteaWanWeb" -}}
{{- $lanWeb := get . "giteaLanWeb" -}}
# ~/.config/zsh/local.zsh -- PRIVATE tier. Mode 600.
#
# Sourced by the public ~/.zshrc, guarded, near the end:
#
# [[ -r ${XDG_CONFIG_HOME:-$HOME/.config}/zsh/local.zsh ]] && source ...
#
# Absent on a public-only machine, where the guard makes it a silent no-op.
# `_mac` and `_open` from .zshrc are still in scope by the time this runs, so
# an alias moved here needs no rewriting.
#
# What belongs here: anything that names a host you own. Nothing that is a
# secret -- those come from ~/.config/zsh/secrets.zsh, written by `dotsecrets`
# and carried in no repository at all.
#
# Mode 600 rather than 644, for the same reason .zshrc and .zshenv are: this is
# code your login shell executes, and a group-writable copy of it is arbitrary
# code execution for anyone in your primary group.
# --------------------------------------------------------------- gitea ---
# The web UI. The WAN host is a real name behind TLS; the LAN one is a bare
# address on a port, reachable only from the house, which is precisely why it
# cannot live in the public tier.
{{ if $wanWeb }}alias gitea='_open {{ $wanWeb }}'{{ end }}
{{ if $lanWeb }}alias gitea-lan='_open {{ $lanWeb }}'{{ end }}
# The clone/push shortcuts are git-side, not shell-side: `gitea:` and
# `gitea-lan:` are url.insteadOf rewrites in ~/.config/git/config.local, so
# `git clone gitea:ben/repo.git` works from any shell, not just this one.
# ------------------------------------------------------------- chezmoi ---
# Two instances, one home directory. The public tier lays the base; the private
# tier overlays identity on top. Both are ordinary chezmoi invocations with a
# different --source, so every subcommand you know still works:
#
# cm status / cm diff / cm re-add ~/.zshrc public
# cmp status / cmp diff / cmp apply private
#
# Each tier has its own source AND its own config file:
#
# public `chezmoi init --apply <url>`, no flags -> ~/.local/share/chezmoi
# ~/.config/chezmoi/chezmoi.toml
# private dotup, --source ... -c .../private.toml -> ~/.local/share/dotfiles-private
# ~/.config/chezmoi/private.toml
#
# The -c is not cosmetic. Both tiers used to render their .chezmoi.toml.tmpl to
# the same default path, so re-running the PUBLIC installer overwrote the config
# holding this tier's seven promptStringOnce answers -- name, email, signing key,
# the gitea addresses -- and they were gone. Silently: the templates degrade
# politely when their data is missing, so the first symptom was `git commit` not
# knowing who you are, days later and unconnected to the install that caused it.
#
# -S and -c must stay in step with dotup's PRIV_SRC and PRIV_CFG. If you move one,
# move the other, or cmp reads a config that describes a different source tree.
alias cm='chezmoi'
alias cmp='chezmoi -S ${XDG_DATA_HOME:-$HOME/.local/share}/dotfiles-private -c ${XDG_CONFIG_HOME:-$HOME/.config}/chezmoi/private.toml'
# Refresh ~/.config/zsh/secrets.zsh from Bitwarden Secrets Manager on demand.
# `cmp apply` does the same thing via run_after_50-secrets.sh.
# dotsecrets