fix: migrate copy-forward is manifest-free, no dead-end on legacy projects (EGB-710)

This commit is contained in:
Brian Majewski 2026-06-08 06:58:22 -07:00
parent 679ddbc1b7
commit c121982dcd
2 changed files with 37 additions and 27 deletions

41
secrets
View file

@ -2138,47 +2138,40 @@ _migrate_project() {
info "Store is already format v2 — nothing to migrate."
return 0
fi
local manifest="$PWD/$SECRETS_JSON_NAME"
if [ ! -e "$manifest" ]; then
die "No $SECRETS_JSON_NAME in $PWD.
'secrets migrate' copy-forwards a project's v1 blobs to their v2 names and
reads the project manifest to do so. cd into a project that has a manifest,
then run 'secrets migrate'. (Store-wide 'secrets migrate --finalize' comes
after every project is migrated.)"
fi
_check_manifest_file "$manifest"
local project; project=$(derive_project_name "")
local pdir="$SECRETS_DIR/$project"
local moved=0 already=0 would=0 etype epath slug old new
while IFS=$'\t' read -r etype epath _; do
[ -n "$etype" ] || continue
# Only `properties` blobs change name in v2; dotenv and `file` are already
# in their v2 shape and never move.
[ "$etype" = "gradle-properties" ] || continue
slug=$(_secrets_files_slug "$epath")
old="$pdir/external/$slug.gradle-properties.age"
new="$pdir/external/$slug.properties.age"
[ -f "$old" ] || continue # nothing pushed yet (or already dropped)
if [ -f "$new" ]; then # idempotent: twin already exists
# Source of truth for the copy-forward is the STORE, not a project manifest.
# Every v1 properties blob is a `*.gradle-properties.age` file whose v2 twin
# is the same name with the `.properties.age` suffix (the only on-disk change
# v2 makes). Enumerating the store — exactly as `_migrate_finalize` does —
# means migrate twins precisely the blobs finalize will demand twins for, with
# no manifest dependency. This is why a legacy `.secrets-files`-only project
# (no `.secrets.json` yet) migrates cleanly instead of dead-ending, and why a
# store blob the manifest no longer declares still gets a twin.
local moved=0 already=0 would=0 f new
while IFS= read -r f; do
[ -f "$f" ] || continue
new="${f%.gradle-properties.age}.properties.age"
if [ -f "$new" ]; then
already=$((already + 1))
continue
fi
if [ "$dry_run" = true ]; then
echo "would migrate: $project/external/$slug.gradle-properties.age -> $slug.properties.age"
echo "would migrate: ${f#"$SECRETS_DIR"/} -> $(basename "$new")"
would=$((would + 1))
else
cp "$old" "$new"
cp "$f" "$new"
moved=$((moved + 1))
fi
done < <(_json_external_entries "$manifest")
done < <(find "$pdir/external" -type f -name '*.gradle-properties.age' 2>/dev/null)
if [ "$dry_run" = true ]; then
echo "migrate --dry-run: $would blob(s) would be copy-forwarded for '$project' (writes nothing); $already already present. v1 blobs are kept until 'secrets migrate --finalize'."
return 0
fi
if [ "$moved" -eq 0 ] && [ "$already" -eq 0 ]; then
info "Nothing to migrate for '$project' (no v1 properties blobs)."
info "Nothing to migrate for '$project' — no v1 properties blobs in the store (already v2-shaped). If you expected one, run 'secrets push' first, then re-run 'secrets migrate'."
return 0
fi
ensure_store_protections