test: make [[ ]] assertions effective under bash 3.2 (EGB-677 precursor)
bats on macOS runs under system bash 3.2, where a failing [[ ]] compound command mid-test does NOT trip the ERR trap — every mid-test [[ "$output" == *...* ]] assertion in the suite was decorative. Append '|| false' to all 123 standalone [[ ]] assertion lines so failures become plain-command failures, which bats catches. Full suite still green (133/133) — no latent false positives were hiding.
This commit is contained in:
parent
a3c71f293b
commit
6dbc4e0d01
1 changed files with 123 additions and 123 deletions
|
|
@ -27,7 +27,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Already initialized"* ]]
|
||||
[[ "$output" == *"Already initialized"* ]] || false
|
||||
|
||||
# Key must not be overwritten
|
||||
local key_after
|
||||
|
|
@ -51,7 +51,7 @@ load test_helper
|
|||
|
||||
run env PATH="$fake_path" "$SECRETS_BIN" init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"age"* ]]
|
||||
[[ "$output" == *"age"* ]] || false
|
||||
}
|
||||
|
||||
# ─── push ──────────────────────────────────────────────────────────────
|
||||
|
|
@ -73,7 +73,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" push testproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"No secret files"* ]]
|
||||
[[ "$output" == *"No secret files"* ]] || false
|
||||
}
|
||||
|
||||
@test "push errors with missing key" {
|
||||
|
|
@ -83,7 +83,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" push testproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Key file"* ]]
|
||||
[[ "$output" == *"Key file"* ]] || false
|
||||
}
|
||||
|
||||
@test "push derives project name from dirname" {
|
||||
|
|
@ -140,7 +140,7 @@ load test_helper
|
|||
|
||||
run git commit -m "should fail"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Plaintext"* ]]
|
||||
[[ "$output" == *"Plaintext"* ]] || false
|
||||
}
|
||||
|
||||
# ─── pull ──────────────────────────────────────────────────────────────
|
||||
|
|
@ -168,7 +168,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" pull nonexistent
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"not found"* ]]
|
||||
[[ "$output" == *"not found"* ]] || false
|
||||
}
|
||||
|
||||
@test "pull errors with missing key" {
|
||||
|
|
@ -183,7 +183,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" pull testproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Key file"* ]]
|
||||
[[ "$output" == *"Key file"* ]] || false
|
||||
}
|
||||
|
||||
@test "pull overwrites existing files" {
|
||||
|
|
@ -217,7 +217,7 @@ load test_helper
|
|||
run "$SECRETS_BIN" pull testproj
|
||||
[ "$status" -eq 0 ]
|
||||
[ -x "$SECRETS_DIR/.git/hooks/pre-commit" ]
|
||||
[[ "$output" == *"Reinstalled"* ]]
|
||||
[[ "$output" == *"Reinstalled"* ]] || false
|
||||
}
|
||||
|
||||
# ─── list ──────────────────────────────────────────────────────────────
|
||||
|
|
@ -231,8 +231,8 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"projA"* ]]
|
||||
[[ "$output" == *"projB"* ]]
|
||||
[[ "$output" == *"projA"* ]] || false
|
||||
[[ "$output" == *"projB"* ]] || false
|
||||
}
|
||||
|
||||
@test "list shows empty message" {
|
||||
|
|
@ -240,7 +240,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"No projects"* ]]
|
||||
[[ "$output" == *"No projects"* ]] || false
|
||||
}
|
||||
|
||||
# ─── rm ────────────────────────────────────────────────────────────────
|
||||
|
|
@ -261,7 +261,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" rm nonexistent
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"not found"* ]]
|
||||
[[ "$output" == *"not found"* ]] || false
|
||||
}
|
||||
|
||||
# ─── pre-commit hook ──────────────────────────────────────────────────
|
||||
|
|
@ -275,7 +275,7 @@ load test_helper
|
|||
|
||||
run git commit -m "should fail"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Plaintext"* ]]
|
||||
[[ "$output" == *"Plaintext"* ]] || false
|
||||
}
|
||||
|
||||
@test "pre-commit allows .age files" {
|
||||
|
|
@ -304,7 +304,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" clear
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Cleared 3"* ]]
|
||||
[[ "$output" == *"Cleared 3"* ]] || false
|
||||
|
||||
# Files should be gone
|
||||
[ ! -f "$WORK_DIR/testproj/.env" ]
|
||||
|
|
@ -318,7 +318,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" clear
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"No secret files"* ]]
|
||||
[[ "$output" == *"No secret files"* ]] || false
|
||||
}
|
||||
|
||||
@test "clear does not remove non-secret files" {
|
||||
|
|
@ -347,7 +347,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" clear --workspaces
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Cleared"* ]]
|
||||
[[ "$output" == *"Cleared"* ]] || false
|
||||
|
||||
# All should be gone
|
||||
[ ! -f "$mono/.env" ]
|
||||
|
|
@ -368,7 +368,7 @@ load test_helper
|
|||
# Run a command that reads the secret
|
||||
run "$SECRETS_BIN" run cat .env
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]] || false
|
||||
|
||||
# After run completes, plaintext files should be cleared
|
||||
[ ! -f "$WORK_DIR/testproj/.env" ]
|
||||
|
|
@ -395,7 +395,7 @@ load test_helper
|
|||
@test "run errors with no command" {
|
||||
run "$SECRETS_BIN" run
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Usage"* ]]
|
||||
[[ "$output" == *"Usage"* ]] || false
|
||||
}
|
||||
|
||||
@test "run passes arguments through to command" {
|
||||
|
|
@ -407,7 +407,7 @@ load test_helper
|
|||
# Run with multiple args
|
||||
run "$SECRETS_BIN" run ls -la .env
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *".env"* ]]
|
||||
[[ "$output" == *".env"* ]] || false
|
||||
}
|
||||
|
||||
@test "run supports -- separator" {
|
||||
|
|
@ -418,7 +418,7 @@ load test_helper
|
|||
|
||||
run "$SECRETS_BIN" run -- cat .env
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]] || false
|
||||
}
|
||||
|
||||
# ─── workspaces ────────────────────────────────────────────────────────
|
||||
|
|
@ -491,7 +491,7 @@ PKGJSON
|
|||
|
||||
run "$SECRETS_BIN" push --workspaces
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"No package.json"* ]]
|
||||
[[ "$output" == *"No package.json"* ]] || false
|
||||
}
|
||||
|
||||
@test "push --workspaces errors without workspaces field" {
|
||||
|
|
@ -502,7 +502,7 @@ PKGJSON
|
|||
|
||||
run "$SECRETS_BIN" push --workspaces
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"No workspaces"* ]]
|
||||
[[ "$output" == *"No workspaces"* ]] || false
|
||||
}
|
||||
|
||||
@test "push --workspaces errors when no env files anywhere" {
|
||||
|
|
@ -517,7 +517,7 @@ EOF
|
|||
|
||||
run "$SECRETS_BIN" push --workspaces
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"No secret files"* ]]
|
||||
[[ "$output" == *"No secret files"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-281: multi-store resolution ──────────────────────────────────
|
||||
|
|
@ -529,8 +529,8 @@ EOF
|
|||
cd subdir
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]] || false
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "which uses .secrets-store file in cwd" {
|
||||
|
|
@ -539,10 +539,10 @@ EOF
|
|||
create_bound_project_dir myapp "~/.secrets-work"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]] || false
|
||||
# Source line must include both the rule name AND the resolved file path,
|
||||
# not the empty parens (".secrets-store file ()") that v0.1.0.0 shipped.
|
||||
[[ "$output" == *".secrets-store file ("*"$WORK_DIR/myapp/.secrets-store)"* ]]
|
||||
[[ "$output" == *".secrets-store file ("*"$WORK_DIR/myapp/.secrets-store)"* ]] || false
|
||||
}
|
||||
|
||||
@test "--store flag overrides .secrets-store file and SECRETS_DIR env" {
|
||||
|
|
@ -550,8 +550,8 @@ EOF
|
|||
create_bound_project_dir myapp "~/.secrets-from-file"
|
||||
run "$SECRETS_BIN" --store "$HOME/.secrets-from-flag" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-from-flag"* ]]
|
||||
[[ "$output" == *"--store flag"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-from-flag"* ]] || false
|
||||
[[ "$output" == *"--store flag"* ]] || false
|
||||
}
|
||||
|
||||
@test "which walks up to find .secrets-store in ancestor" {
|
||||
|
|
@ -562,7 +562,7 @@ EOF
|
|||
cd "$WORK_DIR/repo/sub/deep"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]] || false
|
||||
}
|
||||
|
||||
@test "which walk-up stops at HOME boundary, does not read \$HOME/.secrets-store" {
|
||||
|
|
@ -572,9 +572,9 @@ EOF
|
|||
cd "$WORK_DIR/repo"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *"should-not-be-used"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" != *"should-not-be-used"* ]] || false
|
||||
[[ "$output" == *"$HOME/.secrets"* ]] || false
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "which from outside HOME falls through to default" {
|
||||
|
|
@ -582,8 +582,8 @@ EOF
|
|||
cd /tmp
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]] || false
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "empty .secrets-store falls through to next rule" {
|
||||
|
|
@ -593,7 +593,7 @@ EOF
|
|||
: > .secrets-store
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "comment-only .secrets-store falls through" {
|
||||
|
|
@ -603,7 +603,7 @@ EOF
|
|||
printf '# this is a comment\n \n# another\n' > .secrets-store
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "bare name 'work' resolves to ~/.secrets-work" {
|
||||
|
|
@ -614,7 +614,7 @@ EOF
|
|||
cd "$WORK_DIR/repo"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]] || false
|
||||
}
|
||||
|
||||
@test "~/-prefix in .secrets-store expands to HOME" {
|
||||
|
|
@ -625,7 +625,7 @@ EOF
|
|||
cd "$WORK_DIR/repo"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-x"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-x"* ]] || false
|
||||
}
|
||||
|
||||
@test ".secrets-store with command injection content does not execute" {
|
||||
|
|
@ -671,7 +671,7 @@ EOF
|
|||
|
||||
run "$SECRETS_BIN" --store "$SECRETS_DIR" run -- cat .env
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]]
|
||||
[[ "$output" == *"SECRET_KEY=abc123"* ]] || false
|
||||
}
|
||||
|
||||
@test "uninitialized store referenced by .secrets-store gives directed error" {
|
||||
|
|
@ -683,8 +683,8 @@ EOF
|
|||
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone"* ]]
|
||||
[[ "$output" == *"--store"* ]]
|
||||
[[ "$output" == *"git clone"* ]] || false
|
||||
[[ "$output" == *"--store"* ]] || false
|
||||
}
|
||||
|
||||
@test "push -w ignores per-workspace .secrets-store, uses monorepo root binding" {
|
||||
|
|
@ -727,7 +727,7 @@ PKG
|
|||
create_project_dir myapp
|
||||
run "$SECRETS_BIN" --store "$HOME/.secrets-work" push myapp
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Store: $HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"Store: $HOME/.secrets-work"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-281: gap-filler tests (auto-decided during /ship coverage audit) ─
|
||||
|
|
@ -735,7 +735,7 @@ PKG
|
|||
@test "--store with missing argument errors out" {
|
||||
run "$SECRETS_BIN" --store
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"--store requires"* ]]
|
||||
[[ "$output" == *"--store requires"* ]] || false
|
||||
}
|
||||
|
||||
@test "--store=value (equals form) is accepted" {
|
||||
|
|
@ -744,7 +744,7 @@ PKG
|
|||
cd "$HOME"
|
||||
run "$SECRETS_BIN" --store="$HOME/.secrets-equals" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-equals"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-equals"* ]] || false
|
||||
}
|
||||
|
||||
@test "where and status are aliases of which" {
|
||||
|
|
@ -754,11 +754,11 @@ PKG
|
|||
cd subdir
|
||||
run "$SECRETS_BIN" where
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"source:"* ]]
|
||||
[[ "$output" == *"source:"* ]] || false
|
||||
|
||||
run "$SECRETS_BIN" status
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"source:"* ]]
|
||||
[[ "$output" == *"source:"* ]] || false
|
||||
}
|
||||
|
||||
@test "--store default sugar resolves to ~/.secrets" {
|
||||
|
|
@ -766,7 +766,7 @@ PKG
|
|||
cd "$HOME"
|
||||
run "$SECRETS_BIN" --store default which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]] || false
|
||||
}
|
||||
|
||||
@test "missing key.txt in non-default store gives directed error" {
|
||||
|
|
@ -783,8 +783,8 @@ PKG
|
|||
|
||||
run "$SECRETS_BIN" push myapp
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"key.txt"* ]]
|
||||
[[ "$output" == *"teammate"* ]]
|
||||
[[ "$output" == *"key.txt"* ]] || false
|
||||
[[ "$output" == *"teammate"* ]] || false
|
||||
}
|
||||
|
||||
@test "CRLF line endings in .secrets-store are tolerated" {
|
||||
|
|
@ -795,7 +795,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-crlf"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-crlf"* ]] || false
|
||||
}
|
||||
|
||||
@test "list hints at 'secrets which' when non-default store is active" {
|
||||
|
|
@ -805,7 +805,7 @@ PKG
|
|||
|
||||
run "$SECRETS_BIN" --store "$HOME/.secrets-x" list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"secrets which"* ]]
|
||||
[[ "$output" == *"secrets which"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-281: adversarial-review regression tests (F1-F5) ─────────────
|
||||
|
|
@ -825,7 +825,7 @@ PKG
|
|||
# Run a command, then verify .env is cleared by the EXIT trap
|
||||
run "$SECRETS_BIN" run -- cat .env
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"should-not-leak"* ]]
|
||||
[[ "$output" == *"should-not-leak"* ]] || false
|
||||
# CRITICAL: the trap must have cleaned up — .env must NOT exist on disk.
|
||||
# If F1 regressed (string-interpolated trap), the file would still be here.
|
||||
[ ! -f "$QUOTED_DIR/.env" ]
|
||||
|
|
@ -842,27 +842,27 @@ PKG
|
|||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
# The symlink should be ignored, falling through to default
|
||||
[[ "$output" != *"/etc/passwd"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets"* ]]
|
||||
[[ "$output" == *"source: default"* ]]
|
||||
[[ "$output" != *"/etc/passwd"* ]] || false
|
||||
[[ "$output" == *"$HOME/.secrets"* ]] || false
|
||||
[[ "$output" == *"source: default"* ]] || false
|
||||
}
|
||||
|
||||
@test "F3: --store rejects flag-shaped value" {
|
||||
run "$SECRETS_BIN" --store --workspaces which
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"looks like a flag"* ]]
|
||||
[[ "$output" == *"looks like a flag"* ]] || false
|
||||
}
|
||||
|
||||
@test "F3: --store rejects literal --" {
|
||||
run "$SECRETS_BIN" --store -- which
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"looks like a flag"* ]]
|
||||
[[ "$output" == *"looks like a flag"* ]] || false
|
||||
}
|
||||
|
||||
@test "F4: --store= empty value is rejected" {
|
||||
run "$SECRETS_BIN" --store= which
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"requires a value"* ]]
|
||||
[[ "$output" == *"requires a value"* ]] || false
|
||||
}
|
||||
|
||||
@test "F5: HOME unset gives directed error" {
|
||||
|
|
@ -872,7 +872,7 @@ PKG
|
|||
run "$SECRETS_BIN" which
|
||||
export HOME="$SAVED_HOME" # restore before assertions in case bats relies on it
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"HOME"* ]]
|
||||
[[ "$output" == *"HOME"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-282: optional remote URL in .secrets-store ──────────────────
|
||||
|
|
@ -886,7 +886,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: .secrets-store with URL parses both tokens" {
|
||||
|
|
@ -898,9 +898,9 @@ PKG
|
|||
# that includes the actual URL (not the placeholder).
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone git@github.com:acme/work-secrets.git $HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"git clone git@github.com:acme/work-secrets.git $HOME/.secrets-work"* ]] || false
|
||||
# Placeholder must NOT appear when a real URL was supplied
|
||||
[[ "$output" != *"<their-store-remote>"* ]]
|
||||
[[ "$output" != *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: missing-store error still works without URL (placeholder)" {
|
||||
|
|
@ -911,7 +911,7 @@ PKG
|
|||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
# No URL given — placeholder is the right behavior.
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: https URL is preserved literally" {
|
||||
|
|
@ -921,7 +921,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"https://github.com/acme/work-secrets.git"* ]]
|
||||
[[ "$output" == *"https://github.com/acme/work-secrets.git"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: ~/-prefixed path with URL works" {
|
||||
|
|
@ -931,7 +931,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone git@github.com:acme/x.git $HOME/.secrets-x"* ]]
|
||||
[[ "$output" == *"git clone git@github.com:acme/x.git $HOME/.secrets-x"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: comments before URL line are still skipped" {
|
||||
|
|
@ -941,7 +941,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone git@github.com:acme/work-secrets.git"* ]]
|
||||
[[ "$output" == *"git clone git@github.com:acme/work-secrets.git"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-282 adversarial regressions: URL injection prevention ────────
|
||||
|
|
@ -958,11 +958,11 @@ PKG
|
|||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
# Must use the placeholder, NOT the attacker URL
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" != *"rm -rf"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
[[ "$output" != *"rm -rf"* ]] || false
|
||||
# And must have warned the user that something was dropped
|
||||
[[ "$output" == *"WARNING"* ]]
|
||||
[[ "$output" == *"unsafe"* ]]
|
||||
[[ "$output" == *"WARNING"* ]] || false
|
||||
[[ "$output" == *"unsafe"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282 SECURITY: URL with backticks is dropped" {
|
||||
|
|
@ -972,7 +972,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282 SECURITY: URL with command substitution \$() is dropped" {
|
||||
|
|
@ -982,7 +982,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282 SECURITY: URL with ANSI escape is dropped (terminal-spoof prevention)" {
|
||||
|
|
@ -993,7 +993,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282 SECURITY: multi-token URL ('work url1 url2') is dropped" {
|
||||
|
|
@ -1005,7 +1005,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282 SECURITY: glob char in URL is dropped (no expansion either way)" {
|
||||
|
|
@ -1018,7 +1018,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"<their-store-remote>"* ]]
|
||||
[[ "$output" == *"<their-store-remote>"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: spec parsing is glob-safe (work * does NOT expand)" {
|
||||
|
|
@ -1032,7 +1032,7 @@ PKG
|
|||
[ "$status" -eq 0 ]
|
||||
# Spec is the literal "work" (resolves to ~/.secrets-work). The "*" gets
|
||||
# rejected as unsafe URL and dropped. Resolution works; no globbing.
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]]
|
||||
[[ "$output" == *"$HOME/.secrets-work"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-282: URL with - + _ : / @ . is preserved (positive test)" {
|
||||
|
|
@ -1043,7 +1043,7 @@ PKG
|
|||
cd "$WORK_DIR/proj"
|
||||
run "$SECRETS_BIN" pull
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git+ssh://user@host:2222/path/to-repo_v2.git"* ]]
|
||||
[[ "$output" == *"git+ssh://user@host:2222/path/to-repo_v2.git"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-531: gradle.properties external file support ──────────────────
|
||||
|
|
@ -1069,9 +1069,9 @@ gradle_project() {
|
|||
gradle_project gproj
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"gradle-properties"* ]]
|
||||
[[ "$output" == *"~/.gradle/gradle.properties"* ]]
|
||||
[[ "$output" == *"beaconClerkPkTest"* ]]
|
||||
[[ "$output" == *"gradle-properties"* ]] || false
|
||||
[[ "$output" == *"~/.gradle/gradle.properties"* ]] || false
|
||||
[[ "$output" == *"beaconClerkPkTest"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: push extracts managed keys into external/ blob (no .env needed)" {
|
||||
|
|
@ -1080,7 +1080,7 @@ gradle_project() {
|
|||
gradle_project gproj
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Extracted 2 key"* ]]
|
||||
[[ "$output" == *"Extracted 2 key"* ]] || false
|
||||
run bash -c "ls $SECRETS_DIR/gproj/external/*.gradle-properties.age"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
|
@ -1091,7 +1091,7 @@ gradle_project() {
|
|||
gradle_project gproj
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"not found"* ]]
|
||||
[[ "$output" == *"not found"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: pull merges managed keys, preserves unrelated entries" {
|
||||
|
|
@ -1103,7 +1103,7 @@ gradle_project() {
|
|||
gradle_src $'unrelated.key=keepme\norg.gradle.jvmargs=-Xmx2g\n'
|
||||
run "$SECRETS_BIN" pull gproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Merged 2 key"* ]]
|
||||
[[ "$output" == *"Merged 2 key"* ]] || false
|
||||
grep -q 'beaconClerkPkTest=pk_test_abc' "$HOME/.gradle/gradle.properties"
|
||||
grep -q 'beaconClerkPkLive=pk_live_xyz' "$HOME/.gradle/gradle.properties"
|
||||
grep -q 'unrelated.key=keepme' "$HOME/.gradle/gradle.properties"
|
||||
|
|
@ -1225,7 +1225,7 @@ gradle_project() {
|
|||
printf 'gradle-properties ~/.gradle/custom.properties beaconClerkPkTest\n' > .secrets-files
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"gradle.properties"* ]]
|
||||
[[ "$output" == *"gradle.properties"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: target outside HOME is refused" {
|
||||
|
|
@ -1239,7 +1239,7 @@ gradle_project() {
|
|||
run "$SECRETS_BIN" push gproj
|
||||
rm -rf "$outside"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"HOME"* ]]
|
||||
[[ "$output" == *"HOME"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: symlinked target is refused" {
|
||||
|
|
@ -1250,7 +1250,7 @@ gradle_project() {
|
|||
gradle_project gproj beaconClerkPkTest
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"symlink"* ]]
|
||||
[[ "$output" == *"symlink"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: unknown type in manifest warns and skips" {
|
||||
|
|
@ -1259,7 +1259,7 @@ gradle_project() {
|
|||
printf 'gradle-props ~/.gradle/gradle.properties beaconClerkPkTest\n' > .secrets-files
|
||||
echo "X=1" > .env
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[[ "$output" == *"unknown type"* ]]
|
||||
[[ "$output" == *"unknown type"* ]] || false
|
||||
[ ! -d "$SECRETS_DIR/gproj/external" ]
|
||||
}
|
||||
|
||||
|
|
@ -1269,7 +1269,7 @@ gradle_project() {
|
|||
printf 'gradle-properties\n' > .secrets-files
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"WARNING"* ]]
|
||||
[[ "$output" == *"WARNING"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: manifest path with command-substitution chars is rejected" {
|
||||
|
|
@ -1280,7 +1280,7 @@ gradle_project() {
|
|||
printf 'gradle-properties ~/.gradle/gradle.properties$(touch %s) beaconClerkPkTest\n' "$pwn" > .secrets-files
|
||||
run "$SECRETS_BIN" which
|
||||
[ ! -f "$pwn" ]
|
||||
[[ "$output" == *"WARNING"* ]]
|
||||
[[ "$output" == *"WARNING"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: symlinked .secrets-files is ignored" {
|
||||
|
|
@ -1290,7 +1290,7 @@ gradle_project() {
|
|||
ln -s "$HOME/realmanifest" .secrets-files
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *"beaconClerkPkTest"* ]]
|
||||
[[ "$output" != *"beaconClerkPkTest"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: rekey re-encrypts the external blob (still decryptable after)" {
|
||||
|
|
@ -1329,7 +1329,7 @@ gradle_project() {
|
|||
"$SECRETS_BIN" push gproj >/dev/null 2>&1
|
||||
run "$SECRETS_BIN" list
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"external"* ]]
|
||||
[[ "$output" == *"external"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: no .secrets-files behaves exactly as before (backward compat)" {
|
||||
|
|
@ -1347,7 +1347,7 @@ gradle_project() {
|
|||
git add -f gradle.properties
|
||||
run git commit -m "should fail"
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"Plaintext"* ]]
|
||||
[[ "$output" == *"Plaintext"* ]] || false
|
||||
}
|
||||
|
||||
# ── EGB-531: coverage for warning/error branches, workspaces, multi-entry ──
|
||||
|
|
@ -1395,9 +1395,9 @@ gradle_project() {
|
|||
gradle_project gproj
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"beaconClerkPkLive"* ]]
|
||||
[[ "$output" == *"not found"* ]]
|
||||
[[ "$output" == *"Extracted 1 key"* ]]
|
||||
[[ "$output" == *"beaconClerkPkLive"* ]] || false
|
||||
[[ "$output" == *"not found"* ]] || false
|
||||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: pull warns when manifest entry has no blob in store" {
|
||||
|
|
@ -1408,7 +1408,7 @@ gradle_project() {
|
|||
cd "$WORK_DIR/gproj"
|
||||
run "$SECRETS_BIN" pull gproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"no encrypted data exists"* ]]
|
||||
[[ "$output" == *"no encrypted data exists"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: multi-entry manifest syncs each target" {
|
||||
|
|
@ -1436,8 +1436,8 @@ gradle_project() {
|
|||
printf 'gradle-properties ~/.gradle/gradle.properties bad=key\n' > .secrets-files
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"WARNING"* ]]
|
||||
[[ "$output" != *"bad=key"* ]]
|
||||
[[ "$output" == *"WARNING"* ]] || false
|
||||
[[ "$output" != *"bad=key"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: symlinked parent dir of target is refused" {
|
||||
|
|
@ -1448,7 +1448,7 @@ gradle_project() {
|
|||
gradle_project gproj beaconClerkPkTest
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"symlink"* ]]
|
||||
[[ "$output" == *"symlink"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: push skips a multi-line (continuation) managed value with a warning" {
|
||||
|
|
@ -1459,8 +1459,8 @@ gradle_project() {
|
|||
gradle_project gproj
|
||||
run "$SECRETS_BIN" push gproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"multi-line"* ]]
|
||||
[[ "$output" == *"Extracted 1 key"* ]]
|
||||
[[ "$output" == *"multi-line"* ]] || false
|
||||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-531: push skips comment and continuation lines in source" {
|
||||
|
|
@ -1491,7 +1491,7 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone"* ]]
|
||||
[[ "$output" == *"git clone"* ]] || false
|
||||
# Must not leave a half-initialized store behind
|
||||
[ ! -d "$SECRETS_DIR/.git" ]
|
||||
# Key untouched
|
||||
|
|
@ -1505,12 +1505,12 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Restored store .gitignore"* ]]
|
||||
[[ "$output" == *"Restored store .gitignore"* ]] || false
|
||||
[ -f "$SECRETS_DIR/.gitignore" ]
|
||||
grep -q "key.txt" "$SECRETS_DIR/.gitignore"
|
||||
# key.txt must never be tracked (push does `git add -A` in the store)
|
||||
run git -C "$SECRETS_DIR" ls-files
|
||||
[[ "$output" != *"key.txt"* ]]
|
||||
[[ "$output" != *"key.txt"* ]] || false
|
||||
}
|
||||
|
||||
@test "pull restores missing store .gitignore" {
|
||||
|
|
@ -1535,7 +1535,7 @@ gradle_project() {
|
|||
[ "$status" -eq 0 ]
|
||||
[ -f "$SECRETS_DIR/.gitignore" ]
|
||||
run git -C "$SECRETS_DIR" ls-files
|
||||
[[ "$output" != *"key.txt"* ]]
|
||||
[[ "$output" != *"key.txt"* ]] || false
|
||||
}
|
||||
|
||||
@test "rekey re-encrypts dotenv blobs (round-trip survives key rotation)" {
|
||||
|
|
@ -1563,7 +1563,7 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Reinstalled pre-commit hook"* ]]
|
||||
[[ "$output" == *"Reinstalled pre-commit hook"* ]] || false
|
||||
[ -x "$SECRETS_DIR/.git/hooks/pre-commit" ]
|
||||
}
|
||||
|
||||
|
|
@ -1584,8 +1584,8 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" != *"Restored store .gitignore"* ]]
|
||||
[[ "$output" != *"Reinstalled pre-commit hook"* ]]
|
||||
[[ "$output" != *"Restored store .gitignore"* ]] || false
|
||||
[[ "$output" != *"Reinstalled pre-commit hook"* ]] || false
|
||||
}
|
||||
|
||||
@test "restored store .gitignore carries the full block/allow globs" {
|
||||
|
|
@ -1617,7 +1617,7 @@ gradle_project() {
|
|||
[ "$status" -eq 0 ]
|
||||
[ -f "$SECRETS_DIR/.gitignore" ]
|
||||
run git -C "$SECRETS_DIR" ls-files
|
||||
[[ "$output" != *"key.txt"* ]]
|
||||
[[ "$output" != *"key.txt"* ]] || false
|
||||
}
|
||||
|
||||
@test "push untracks a previously committed key.txt with a warning" {
|
||||
|
|
@ -1629,9 +1629,9 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" push
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"key.txt was tracked"* ]]
|
||||
[[ "$output" == *"key.txt was tracked"* ]] || false
|
||||
run git -C "$SECRETS_DIR" ls-files
|
||||
[[ "$output" != *"key.txt"* ]]
|
||||
[[ "$output" != *"key.txt"* ]] || false
|
||||
}
|
||||
|
||||
@test "push rewrites a store .gitignore that is missing the key.txt line" {
|
||||
|
|
@ -1643,7 +1643,7 @@ gradle_project() {
|
|||
[ "$status" -eq 0 ]
|
||||
grep -qx 'key.txt' "$SECRETS_DIR/.gitignore"
|
||||
run git -C "$SECRETS_DIR" ls-files
|
||||
[[ "$output" != *"key.txt"* ]]
|
||||
[[ "$output" != *"key.txt"* ]] || false
|
||||
}
|
||||
|
||||
@test "init guard renders the real clone URL when .secrets-store carries a remote" {
|
||||
|
|
@ -1655,7 +1655,7 @@ gradle_project() {
|
|||
|
||||
run "$SECRETS_BIN" init
|
||||
[ "$status" -eq 1 ]
|
||||
[[ "$output" == *"git clone git@example.com:me/secrets-work.git"* ]]
|
||||
[[ "$output" == *"git clone git@example.com:me/secrets-work.git"* ]] || false
|
||||
}
|
||||
|
||||
# ─── EGB-652: `file` external type (whole-file sync, e.g. Android keystore) ──
|
||||
|
|
@ -1680,8 +1680,8 @@ file_project() {
|
|||
file_project fproj
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"file"* ]]
|
||||
[[ "$output" == *"~/keystores/upload.keystore"* ]]
|
||||
[[ "$output" == *"file"* ]] || false
|
||||
[[ "$output" == *"~/keystores/upload.keystore"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-652: push encrypts a file-type entry into external/ blob" {
|
||||
|
|
@ -1690,7 +1690,7 @@ file_project() {
|
|||
file_project fproj
|
||||
run "$SECRETS_BIN" push fproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Encrypted file"* ]]
|
||||
[[ "$output" == *"Encrypted file"* ]] || false
|
||||
run bash -c "ls $SECRETS_DIR/fproj/external/*.file.age"
|
||||
[ "$status" -eq 0 ]
|
||||
}
|
||||
|
|
@ -1704,7 +1704,7 @@ file_project() {
|
|||
rm -rf "$HOME/keystores"
|
||||
run "$SECRETS_BIN" pull fproj
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Restored file"* ]]
|
||||
[[ "$output" == *"Restored file"* ]] || false
|
||||
cmp "$HOME/keystores/upload.keystore" "$TEST_TMPDIR/reference"
|
||||
mode=$(stat -f '%Lp' "$HOME/keystores/upload.keystore" 2>/dev/null || stat -c '%a' "$HOME/keystores/upload.keystore")
|
||||
[ "$mode" = "600" ]
|
||||
|
|
@ -1730,10 +1730,10 @@ file_project() {
|
|||
cd "$dir"
|
||||
run "$SECRETS_BIN" which
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"take no keys"* ]]
|
||||
[[ "$output" == *"take no keys"* ]] || false
|
||||
# The rejected entry must not be listed as parsed (header only prints
|
||||
# when at least one entry parses).
|
||||
[[ "$output" != *"external files ("* ]]
|
||||
[[ "$output" != *"external files ("* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-652: file target outside HOME is refused on push" {
|
||||
|
|
@ -1743,7 +1743,7 @@ file_project() {
|
|||
cd "$dir"
|
||||
run "$SECRETS_BIN" push fout
|
||||
[ "$status" -ne 0 ]
|
||||
[[ "$output" == *"inside \$HOME"* ]] || [[ "$output" == *"Refusing"* ]]
|
||||
[[ "$output" == *"inside \$HOME"* ]] || [[ "$output" == *"Refusing"* ]] || false
|
||||
}
|
||||
|
||||
@test "EGB-652: gradle-properties entries still work alongside a file entry" {
|
||||
|
|
@ -1755,6 +1755,6 @@ file_project() {
|
|||
cd "$dir"
|
||||
run "$SECRETS_BIN" push fmix
|
||||
[ "$status" -eq 0 ]
|
||||
[[ "$output" == *"Extracted 1 key"* ]]
|
||||
[[ "$output" == *"Encrypted file"* ]]
|
||||
[[ "$output" == *"Extracted 1 key"* ]] || false
|
||||
[[ "$output" == *"Encrypted file"* ]] || false
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue