feat: secrets list --json machine-readable output (EGB-699)
Add a --json flag to `secrets list` that emits a structured object for
tooling/CI instead of the human table — feeds the EGB-671 install scripts,
which need to enumerate a cloned store programmatically.
Contract: {"store", "projects":[{"name","entries":[...]}]}, each entry
self-describing via a type discriminator — {type:dotenv,path} or
{type:external,subtype:properties|file,path}. cmd_list_json mirrors the same
recursive store walk as the human list (nested <project>/<relpath>.age +
external/<slug>.age); jq assembles the JSON so paths escape correctly and
stdout stays pure JSON (the non-default-store hint is suppressed; jq is a
hard dep only in --json mode).
Tests: 7 new bats cases (dotenv, nested relpath, external properties + file
subtypes, empty store, pure-stdout-under-notice, store path). Full suite
261 pass / 0 fail.
VERSION 0.7.1.0 -> 0.7.2.0; CHANGELOG/README/CLAUDE.md updated.
This commit is contained in:
parent
b8fe20f9bf
commit
446256caf1
6 changed files with 172 additions and 4 deletions
|
|
@ -1763,3 +1763,84 @@ file_project() {
|
|||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
[[ "$output" == *"Encrypted file"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-699: `list --json` machine-readable output ──────────────────────
|
||||
|
||||
@test "EGB-699: list --json emits valid JSON with project and dotenv entry" {
|
||||
init_with_remote
|
||||
create_project_dir jproj
|
||||
"$SECRETS_BIN" push jproj >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
# entire stdout parses as JSON
|
||||
echo "$output" | jq -e . >/dev/null
|
||||
# project is present
|
||||
echo "$output" | jq -e '.projects[] | select(.name == "jproj")' >/dev/null
|
||||
# .env shows up as a dotenv entry
|
||||
echo "$output" | jq -e '.projects[] | select(.name == "jproj")
|
||||
| .entries[] | select(.type == "dotenv" and .path == ".env")' >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json includes a nested dotenv relpath" {
|
||||
init_with_remote
|
||||
create_project_dir nestjson
|
||||
mkdir -p packages/web
|
||||
echo "N=nested" > packages/web/.env.development
|
||||
"$SECRETS_BIN" add packages/web/.env.development >/dev/null
|
||||
"$SECRETS_BIN" push >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | jq -e '.projects[] | select(.name == "nestjson")
|
||||
| .entries[] | select(.type == "dotenv" and .path == "packages/web/.env.development")' >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json marks an external properties entry with subtype" {
|
||||
init_with_remote
|
||||
gradle_src $'beaconClerkPkTest=pk_test_abc\n'
|
||||
gradle_project gjson beaconClerkPkTest
|
||||
"$SECRETS_BIN" push gjson >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | jq -e '.projects[] | select(.name == "gjson")
|
||||
| .entries[] | select(.type == "external" and .subtype == "properties")' >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json marks an external file entry with subtype" {
|
||||
init_with_remote
|
||||
file_src
|
||||
local dir="$WORK_DIR/fjson"; mkdir -p "$dir"
|
||||
printf 'file ~/keystores/upload.keystore\n' > "$dir/.secrets-files"
|
||||
cd "$dir"
|
||||
"$SECRETS_BIN" push fjson >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | jq -e '.projects[] | select(.name == "fjson")
|
||||
| .entries[] | select(.type == "external" and .subtype == "file")' >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json on an empty store emits an empty projects array" {
|
||||
"$SECRETS_BIN" init >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | jq -e '.projects == []' >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json keeps stdout pure JSON (notices go to stderr)" {
|
||||
# The non-default-store hint normally prints to stdout in human mode; under
|
||||
# --json it must not, or it would corrupt the document. Capture stdout only.
|
||||
init_with_remote
|
||||
create_project_dir purejson
|
||||
"$SECRETS_BIN" push purejson >/dev/null 2>&1
|
||||
local json
|
||||
json=$("$SECRETS_BIN" list --json 2>/dev/null)
|
||||
echo "$json" | jq -e . >/dev/null
|
||||
}
|
||||
|
||||
@test "EGB-699: list --json reports the active store path" {
|
||||
init_with_remote
|
||||
create_project_dir storejson
|
||||
"$SECRETS_BIN" push storejson >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list --json
|
||||
[ "$status" -eq 0 ]
|
||||
echo "$output" | jq -e --arg s "$SECRETS_DIR" '.store == $s' >/dev/null
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue