fix: [nomad-step-2] S2.5 — bin/disinto init --import-env / --import-sops / --age-key wire-up (#883) #907
3 changed files with 67 additions and 4 deletions
38
bin/disinto
38
bin/disinto
|
|
@ -684,13 +684,21 @@ _disinto_init_nomad() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Step 2/3/4 scripts must exist as soon as any --import-* flag is set,
|
# --empty short-circuits after cluster-up: no policies, no auth, no
|
||||||
# since we unconditionally invoke policies+auth and optionally import.
|
# import, no deploy. It's the "cluster-only escape hatch" for debugging
|
||||||
|
# (docs/nomad-migration.md). Caller-side validation already rejects
|
||||||
|
# --empty combined with --with or any --import-* flag, so reaching
|
||||||
|
# this branch with those set is a bug in the caller.
|
||||||
|
#
|
||||||
|
# On the default (non-empty) path, vault-apply-policies.sh and
|
||||||
|
# vault-nomad-auth.sh are invoked unconditionally — they are idempotent
|
||||||
|
# and cheap to re-run, and subsequent --with deployments depend on
|
||||||
|
# them. vault-import.sh is invoked only when an --import-* flag is set.
|
||||||
local import_any=false
|
local import_any=false
|
||||||
if [ -n "$import_env" ] || [ -n "$import_sops" ]; then
|
if [ -n "$import_env" ] || [ -n "$import_sops" ]; then
|
||||||
import_any=true
|
import_any=true
|
||||||
fi
|
fi
|
||||||
if [ "$import_any" = true ]; then
|
if [ "$empty" != "true" ]; then
|
||||||
if [ ! -x "$vault_policies_sh" ]; then
|
if [ ! -x "$vault_policies_sh" ]; then
|
||||||
echo "Error: ${vault_policies_sh} not found or not executable" >&2
|
echo "Error: ${vault_policies_sh} not found or not executable" >&2
|
||||||
exit 1
|
exit 1
|
||||||
|
|
@ -699,7 +707,7 @@ _disinto_init_nomad() {
|
||||||
echo "Error: ${vault_auth_sh} not found or not executable" >&2
|
echo "Error: ${vault_auth_sh} not found or not executable" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
if [ ! -x "$vault_import_sh" ]; then
|
if [ "$import_any" = true ] && [ ! -x "$vault_import_sh" ]; then
|
||||||
echo "Error: ${vault_import_sh} not found or not executable" >&2
|
echo "Error: ${vault_import_sh} not found or not executable" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -722,6 +730,13 @@ _disinto_init_nomad() {
|
||||||
"${cmd[@]}" || true
|
"${cmd[@]}" || true
|
||||||
echo ""
|
echo ""
|
||||||
|
|
||||||
|
# --empty skips policies/auth/import/deploy — cluster-up only, no
|
||||||
|
# workloads. The operator-visible dry-run plan must match the real
|
||||||
|
# run, so short-circuit here too.
|
||||||
|
if [ "$empty" = "true" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Vault policies + auth are invoked on every nomad real-run path
|
# Vault policies + auth are invoked on every nomad real-run path
|
||||||
# regardless of --import-* flags (they're idempotent; S2.1 + S2.3).
|
# regardless of --import-* flags (they're idempotent; S2.1 + S2.3).
|
||||||
# Mirror that ordering in the dry-run plan so the operator sees the
|
# Mirror that ordering in the dry-run plan so the operator sees the
|
||||||
|
|
@ -793,6 +808,12 @@ _disinto_init_nomad() {
|
||||||
sudo -n -- "${cluster_cmd[@]}" || exit $?
|
sudo -n -- "${cluster_cmd[@]}" || exit $?
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --empty short-circuits here: cluster-up only, no policies/auth/import
|
||||||
|
# and no deploy. Matches the dry-run plan above and the docs/runbook.
|
||||||
|
if [ "$empty" = "true" ]; then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
# Apply Vault policies (S2.1) — idempotent, safe to re-run.
|
# Apply Vault policies (S2.1) — idempotent, safe to re-run.
|
||||||
echo ""
|
echo ""
|
||||||
echo "── Applying Vault policies ────────────────────────────"
|
echo "── Applying Vault policies ────────────────────────────"
|
||||||
|
|
@ -1005,6 +1026,15 @@ disinto_init() {
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# --empty is the cluster-only escape hatch — it skips policies, auth,
|
||||||
|
# import, and deploy. Pairing it with --import-* silently does nothing,
|
||||||
|
# which is a worse failure mode than a clear error. Reject explicitly.
|
||||||
|
if [ "$empty" = true ] \
|
||||||
|
&& { [ -n "$import_env" ] || [ -n "$import_sops" ] || [ -n "$age_key" ]; }; then
|
||||||
|
echo "Error: --empty and --import-env/--import-sops/--age-key are mutually exclusive" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# Dispatch on backend — the nomad path runs lib/init/nomad/cluster-up.sh
|
# Dispatch on backend — the nomad path runs lib/init/nomad/cluster-up.sh
|
||||||
# (S0.4). The default and --empty variants are identical today; Step 1
|
# (S0.4). The default and --empty variants are identical today; Step 1
|
||||||
# will branch on $empty to add job deployment to the default path.
|
# will branch on $empty to add job deployment to the default path.
|
||||||
|
|
|
||||||
|
|
@ -60,6 +60,9 @@ This runs, in order:
|
||||||
- `--age-key` without `--import-sops` → error.
|
- `--age-key` without `--import-sops` → error.
|
||||||
- `--import-env` alone (no sops) → OK (imports just the plaintext `.env`).
|
- `--import-env` alone (no sops) → OK (imports just the plaintext `.env`).
|
||||||
- `--backend=docker` with any `--import-*` flag → error.
|
- `--backend=docker` with any `--import-*` flag → error.
|
||||||
|
- `--empty` with any `--import-*` flag → error (mutually exclusive: `--empty`
|
||||||
|
skips the import step, so pairing them silently discards the import
|
||||||
|
intent).
|
||||||
|
|
||||||
## Idempotency
|
## Idempotency
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -280,3 +280,33 @@ setup_file() {
|
||||||
[ "$status" -eq 0 ]
|
[ "$status" -eq 0 ]
|
||||||
[[ "$output" == *"env file: /tmp/.env"* ]]
|
[[ "$output" == *"env file: /tmp/.env"* ]]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# --empty short-circuits after cluster-up: no policies, no auth, no
|
||||||
|
# import, no deploy. The dry-run plan must match that — cluster-up plan
|
||||||
|
# appears, but none of the S2.x section banners do.
|
||||||
|
@test "disinto init --backend=nomad --empty --dry-run skips policies/auth/import sections" {
|
||||||
|
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --empty --dry-run
|
||||||
|
[ "$status" -eq 0 ]
|
||||||
|
# Cluster-up still runs (it's what --empty brings up).
|
||||||
|
[[ "$output" == *"Cluster-up dry-run"* ]]
|
||||||
|
# Policies + auth + import must NOT appear under --empty.
|
||||||
|
[[ "$output" != *"Vault policies dry-run"* ]]
|
||||||
|
[[ "$output" != *"Vault auth dry-run"* ]]
|
||||||
|
[[ "$output" != *"Vault import dry-run"* ]]
|
||||||
|
[[ "$output" != *"no --import-env/--import-sops"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
# --empty + any --import-* flag silently does nothing (import is skipped),
|
||||||
|
# so the CLI rejects the combination up front rather than letting it
|
||||||
|
# look like the import "succeeded".
|
||||||
|
@test "disinto init --backend=nomad --empty --import-env errors" {
|
||||||
|
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --empty --import-env /tmp/.env --dry-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"--empty and --import-env/--import-sops/--age-key are mutually exclusive"* ]]
|
||||||
|
}
|
||||||
|
|
||||||
|
@test "disinto init --backend=nomad --empty --import-sops --age-key errors" {
|
||||||
|
run "$DISINTO_BIN" init placeholder/repo --backend=nomad --empty --import-sops /tmp/.env.vault.enc --age-key /tmp/keys.txt --dry-run
|
||||||
|
[ "$status" -ne 0 ]
|
||||||
|
[[ "$output" == *"--empty and --import-env/--import-sops/--age-key are mutually exclusive"* ]]
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue