feat: external entries via .secrets.json + legacy absorb + properties rail (EGB-677 stage 1)
- .secrets.json external[] drives push/pull: type 'properties' (alias of gradle-properties; blob suffix stays legacy-compatible in stage 1) and type 'file'; same charset rails as the legacy parser - push absorbs uncovered .secrets-files entries into the manifest (idempotent, gradle-properties → properties) with a delete hint - pull: manifest wins entirely; a coexisting .secrets-files warns as superseded instead of being silently ignored - basename rail generalized: properties targets must end '.properties' (was exact 'gradle.properties') — rc files/gitconfig still blocked; EGB-531 wrong-basename test updated for the sanctioned change
This commit is contained in:
parent
884da0965c
commit
d7e1400487
3 changed files with 322 additions and 32 deletions
|
|
@ -244,3 +244,138 @@ load test_helper
|
|||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"project-relative"* ]] || false
|
||||
}
|
||||
|
||||
# ─── C: legacy absorb + external entries via .secrets.json ─────────────
|
||||
|
||||
# Local fixtures (mirror secrets.bats EGB-531/652 helpers)
|
||||
m_gradle_src() { mkdir -p "$HOME/.gradle"; printf '%s' "$1" > "$HOME/.gradle/gradle.properties"; }
|
||||
m_file_src() { mkdir -p "$HOME/keystores"; printf 'KS\x00\x01\x02\xffDATA\n' > "$HOME/keystores/upload.keystore"; }
|
||||
|
||||
@test "push absorbs .secrets-files into .secrets.json (properties + file)" {
|
||||
init_with_remote
|
||||
m_gradle_src $'beaconClerkPkTest=pk_test_abc\n'
|
||||
m_file_src
|
||||
local dir="$WORK_DIR/absorbproj"; mkdir -p "$dir"
|
||||
echo "K=v" > "$dir/.env"
|
||||
printf 'gradle-properties ~/.gradle/gradle.properties beaconClerkPkTest\nfile ~/keystores/upload.keystore\n' > "$dir/.secrets-files"
|
||||
cd "$dir"
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Absorbed"* ]] || false
|
||||
run jq -r '.external | length' .secrets.json
|
||||
[ "$output" = "2" ]
|
||||
run jq -r '.external[] | select(.path == "~/.gradle/gradle.properties") | .type' .secrets.json
|
||||
[ "$output" = "properties" ]
|
||||
run jq -r '.external[] | select(.type == "file") | .path' .secrets.json
|
||||
[ "$output" = "~/keystores/upload.keystore" ]
|
||||
# stage 1: blob naming stays legacy-compatible
|
||||
run bash -c "ls $SECRETS_DIR/absorbproj/external/*.gradle-properties.age"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "absorb is idempotent — second push adds no duplicate externals" {
|
||||
init_with_remote
|
||||
m_gradle_src $'beaconClerkPkTest=pk_test_abc\n'
|
||||
local dir="$WORK_DIR/absorb2"; mkdir -p "$dir"
|
||||
echo "K=v" > "$dir/.env"
|
||||
printf 'gradle-properties ~/.gradle/gradle.properties beaconClerkPkTest\n' > "$dir/.secrets-files"
|
||||
cd "$dir"
|
||||
"$SECRETS_BIN" push >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
run jq -r '.external | length' .secrets.json
|
||||
[ "$output" = "1" ]
|
||||
}
|
||||
|
||||
@test "external properties entry in .secrets.json drives push without .secrets-files" {
|
||||
init_with_remote
|
||||
m_gradle_src $'beaconClerkPkTest=pk_test_abc\n'
|
||||
local dir="$WORK_DIR/jsonextproj"; mkdir -p "$dir"
|
||||
printf '{"version":2,"external":[{"type":"properties","path":"~/.gradle/gradle.properties","keys":["beaconClerkPkTest"]}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
run "$SECRETS_BIN" push jsonextproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
run bash -c "ls $SECRETS_DIR/jsonextproj/external/*.gradle-properties.age"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
||||
@test "pull merges properties keys sourced from .secrets.json" {
|
||||
init_with_remote
|
||||
m_gradle_src $'beaconClerkPkTest=pk_test_abc\nunrelated=keep\n'
|
||||
local dir="$WORK_DIR/jsonpull"; mkdir -p "$dir"
|
||||
printf '{"version":2,"external":[{"type":"properties","path":"~/.gradle/gradle.properties","keys":["beaconClerkPkTest"]}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
"$SECRETS_BIN" push jsonpull >/dev/null 2>&1
|
||||
m_gradle_src $'beaconClerkPkTest=STALE\nunrelated=keep\n'
|
||||
run "$SECRETS_BIN" pull jsonpull
|
||||
[ "$status" -eq 0 ]
|
||||
run grep -c 'beaconClerkPkTest=pk_test_abc' "$HOME/.gradle/gradle.properties"
|
||||
[ "$output" = "1" ]
|
||||
run grep -c 'unrelated=keep' "$HOME/.gradle/gradle.properties"
|
||||
[ "$output" = "1" ]
|
||||
}
|
||||
|
||||
@test "properties rail generalized: any *.properties basename is accepted" {
|
||||
init_with_remote
|
||||
mkdir -p "$HOME/.config"
|
||||
printf 'apiKey=abc123\n' > "$HOME/.config/app.properties"
|
||||
local dir="$WORK_DIR/genprops"; mkdir -p "$dir"
|
||||
printf '{"version":2,"external":[{"type":"properties","path":"~/.config/app.properties","keys":["apiKey"]}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
run "$SECRETS_BIN" push genprops
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
}
|
||||
|
||||
@test "properties rail still blocks a non-.properties target" {
|
||||
init_with_remote
|
||||
printf 'PATH=/evil\n' > "$HOME/.bashrc"
|
||||
local dir="$WORK_DIR/evilprops"; mkdir -p "$dir"
|
||||
printf '{"version":2,"external":[{"type":"properties","path":"~/.bashrc","keys":["PATH"]}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
run "$SECRETS_BIN" push evilprops
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *".properties"* ]] || false
|
||||
}
|
||||
|
||||
@test "file entry via .secrets.json round-trips binary with mode 600" {
|
||||
init_with_remote
|
||||
m_file_src
|
||||
local dir="$WORK_DIR/jsonfile"; mkdir -p "$dir"
|
||||
printf '{"version":2,"external":[{"type":"file","path":"~/keystores/upload.keystore"}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
"$SECRETS_BIN" push jsonfile >/dev/null 2>&1
|
||||
cp "$HOME/keystores/upload.keystore" "$TEST_TMPDIR/orig.keystore"
|
||||
rm "$HOME/keystores/upload.keystore"
|
||||
run "$SECRETS_BIN" pull jsonfile
|
||||
[ "$status" -eq 0 ]
|
||||
cmp -s "$HOME/keystores/upload.keystore" "$TEST_TMPDIR/orig.keystore"
|
||||
local mode
|
||||
mode=$(stat -f '%Lp' "$HOME/keystores/upload.keystore" 2>/dev/null || stat -c '%a' "$HOME/keystores/upload.keystore")
|
||||
[ "$mode" = "600" ]
|
||||
}
|
||||
|
||||
@test "json file entry with keys is rejected with a warning" {
|
||||
init_with_remote
|
||||
m_file_src
|
||||
local dir="$WORK_DIR/badfile"; mkdir -p "$dir"
|
||||
echo "K=v" > "$dir/.env"
|
||||
printf '{"version":2,"external":[{"type":"file","path":"~/keystores/upload.keystore","keys":["nope"]}]}\n' > "$dir/.secrets.json"
|
||||
cd "$dir"
|
||||
run "$SECRETS_BIN" push badfile
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"no keys"* ]] || false
|
||||
run bash -c "ls $SECRETS_DIR/badfile/external/*.file.age 2>/dev/null"
|
||||
[ "$status" -ne 0 ]
|
||||
}
|
||||
|
||||
@test "pull warns that .secrets-files is superseded when .secrets.json exists" {
|
||||
init_with_remote
|
||||
create_project_dir superproj
|
||||
"$SECRETS_BIN" push superproj >/dev/null 2>&1
|
||||
printf 'gradle-properties ~/.gradle/gradle.properties beaconClerkPkTest\n' > .secrets-files
|
||||
run "$SECRETS_BIN" pull superproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"superseded"* ]] || false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue