215 lines
6.3 KiB
Bash
215 lines
6.3 KiB
Bash
#!/usr/bin/env bats
|
|
# tests/lib-hvault.bats — Unit tests for lib/hvault.sh
|
|
#
|
|
# Runs against a dev-mode Vault server (single binary, no LXC needed).
|
|
# CI launches vault server -dev inline before running these tests.
|
|
|
|
VAULT_BIN="${VAULT_BIN:-vault}"
|
|
|
|
setup_file() {
|
|
export TEST_DIR
|
|
TEST_DIR="$(cd "$(dirname "$BATS_TEST_FILENAME")/.." && pwd)"
|
|
|
|
# Start dev-mode vault on a random port
|
|
export VAULT_DEV_PORT
|
|
VAULT_DEV_PORT="$(shuf -i 18200-18299 -n 1)"
|
|
export VAULT_ADDR="http://127.0.0.1:${VAULT_DEV_PORT}"
|
|
|
|
"$VAULT_BIN" server -dev \
|
|
-dev-listen-address="127.0.0.1:${VAULT_DEV_PORT}" \
|
|
-dev-root-token-id="test-root-token" \
|
|
-dev-no-store-token \
|
|
&>"${BATS_FILE_TMPDIR}/vault.log" &
|
|
export VAULT_PID=$!
|
|
|
|
export VAULT_TOKEN="test-root-token"
|
|
|
|
# Wait for vault to be ready (up to 10s)
|
|
local i=0
|
|
while ! curl -sf "${VAULT_ADDR}/v1/sys/health" >/dev/null 2>&1; do
|
|
sleep 0.5
|
|
i=$((i + 1))
|
|
if [ "$i" -ge 20 ]; then
|
|
echo "Vault failed to start. Log:" >&2
|
|
cat "${BATS_FILE_TMPDIR}/vault.log" >&2
|
|
return 1
|
|
fi
|
|
done
|
|
}
|
|
|
|
teardown_file() {
|
|
if [ -n "${VAULT_PID:-}" ]; then
|
|
kill "$VAULT_PID" 2>/dev/null || true
|
|
wait "$VAULT_PID" 2>/dev/null || true
|
|
fi
|
|
}
|
|
|
|
setup() {
|
|
# Source the module under test
|
|
source "${TEST_DIR}/lib/hvault.sh"
|
|
export VAULT_ADDR VAULT_TOKEN
|
|
}
|
|
|
|
# ── hvault_kv_put + hvault_kv_get ────────────────────────────────────────────
|
|
|
|
@test "hvault_kv_put writes and hvault_kv_get reads a secret" {
|
|
run hvault_kv_put "test/myapp" "username=admin" "password=s3cret"
|
|
[ "$status" -eq 0 ]
|
|
|
|
run hvault_kv_get "test/myapp"
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.username == "admin"'
|
|
echo "$output" | jq -e '.password == "s3cret"'
|
|
}
|
|
|
|
@test "hvault_kv_get extracts a single key" {
|
|
hvault_kv_put "test/single" "foo=bar" "baz=qux"
|
|
|
|
run hvault_kv_get "test/single" "foo"
|
|
[ "$status" -eq 0 ]
|
|
[ "$output" = "bar" ]
|
|
}
|
|
|
|
@test "hvault_kv_get fails for missing key" {
|
|
hvault_kv_put "test/keymiss" "exists=yes"
|
|
|
|
run hvault_kv_get "test/keymiss" "nope"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_kv_get fails for missing path" {
|
|
run hvault_kv_get "test/does-not-exist-$(date +%s)"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_kv_put fails without KEY=VAL" {
|
|
run hvault_kv_put "test/bad"
|
|
[ "$status" -ne 0 ]
|
|
echo "$output" | grep -q '"error":true' || echo "$stderr" | grep -q '"error":true'
|
|
}
|
|
|
|
@test "hvault_kv_put rejects malformed pair (no =)" {
|
|
run hvault_kv_put "test/bad2" "noequals"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_kv_get fails without PATH" {
|
|
run hvault_kv_get
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# ── hvault_kv_list ───────────────────────────────────────────────────────────
|
|
|
|
@test "hvault_kv_list lists keys at a path" {
|
|
hvault_kv_put "test/listdir/a" "k=1"
|
|
hvault_kv_put "test/listdir/b" "k=2"
|
|
|
|
run hvault_kv_list "test/listdir"
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '. | length >= 2'
|
|
echo "$output" | jq -e 'index("a")'
|
|
echo "$output" | jq -e 'index("b")'
|
|
}
|
|
|
|
@test "hvault_kv_list fails on nonexistent path" {
|
|
run hvault_kv_list "test/no-such-path-$(date +%s)"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_kv_list fails without PATH" {
|
|
run hvault_kv_list
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# ── hvault_policy_apply ──────────────────────────────────────────────────────
|
|
|
|
@test "hvault_policy_apply creates a policy" {
|
|
local pfile="${BATS_TEST_TMPDIR}/test-policy.hcl"
|
|
cat > "$pfile" <<'HCL'
|
|
path "secret/data/test/*" {
|
|
capabilities = ["read"]
|
|
}
|
|
HCL
|
|
|
|
run hvault_policy_apply "test-reader" "$pfile"
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Verify the policy exists via Vault API
|
|
run curl -sf -H "X-Vault-Token: ${VAULT_TOKEN}" \
|
|
"${VAULT_ADDR}/v1/sys/policies/acl/test-reader"
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.data.policy' | grep -q "secret/data/test"
|
|
}
|
|
|
|
@test "hvault_policy_apply is idempotent" {
|
|
local pfile="${BATS_TEST_TMPDIR}/idem-policy.hcl"
|
|
printf 'path "secret/*" { capabilities = ["list"] }\n' > "$pfile"
|
|
|
|
run hvault_policy_apply "idem-policy" "$pfile"
|
|
[ "$status" -eq 0 ]
|
|
|
|
# Apply again — should succeed
|
|
run hvault_policy_apply "idem-policy" "$pfile"
|
|
[ "$status" -eq 0 ]
|
|
}
|
|
|
|
@test "hvault_policy_apply fails with missing file" {
|
|
run hvault_policy_apply "bad-policy" "/nonexistent/policy.hcl"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_policy_apply fails without args" {
|
|
run hvault_policy_apply
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# ── hvault_token_lookup ──────────────────────────────────────────────────────
|
|
|
|
@test "hvault_token_lookup returns token info" {
|
|
run hvault_token_lookup
|
|
[ "$status" -eq 0 ]
|
|
echo "$output" | jq -e '.policies'
|
|
echo "$output" | jq -e '.accessor'
|
|
echo "$output" | jq -e 'has("ttl")'
|
|
}
|
|
|
|
@test "hvault_token_lookup fails without VAULT_TOKEN" {
|
|
unset VAULT_TOKEN
|
|
run hvault_token_lookup
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_token_lookup fails without VAULT_ADDR" {
|
|
unset VAULT_ADDR
|
|
run hvault_token_lookup
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# ── hvault_jwt_login ─────────────────────────────────────────────────────────
|
|
|
|
@test "hvault_jwt_login fails without VAULT_ADDR" {
|
|
unset VAULT_ADDR
|
|
run hvault_jwt_login "myrole" "fakejwt"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_jwt_login fails without args" {
|
|
run hvault_jwt_login
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
@test "hvault_jwt_login returns error for unconfigured jwt auth" {
|
|
# JWT auth backend is not enabled in dev mode by default — expect failure
|
|
run hvault_jwt_login "myrole" "eyJhbGciOiJSUzI1NiJ9.fake.sig"
|
|
[ "$status" -ne 0 ]
|
|
}
|
|
|
|
# ── Env / prereq errors ─────────────────────────────────────────────────────
|
|
|
|
@test "all functions fail with structured JSON error when VAULT_ADDR unset" {
|
|
unset VAULT_ADDR
|
|
for fn in hvault_kv_get hvault_kv_put hvault_kv_list hvault_policy_apply hvault_token_lookup; do
|
|
run $fn "dummy" "dummy"
|
|
[ "$status" -ne 0 ]
|
|
done
|
|
}
|