-
Notifications
You must be signed in to change notification settings - Fork 4
Expand file tree
/
Copy pathtest.sh
More file actions
executable file
·431 lines (360 loc) · 15 KB
/
Copy pathtest.sh
File metadata and controls
executable file
·431 lines (360 loc) · 15 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
#!/bin/bash
# Test script for gopass-secret-service
# Runs tests in an isolated D-Bus session with isolated gopass/GPG
# Note: We don't use set -e because we want to continue on test failures
BINARY="./gopass-secret"
TIMEOUT=5
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
# Create temporary directory for all test data (bus socket, pid files, logs, gopass, etc.)
TEST_TMPDIR=$(mktemp -d -t gopass-secret-service-test.XXXXXX)
PID_FILE="$TEST_TMPDIR/service.pid"
LOG_FILE="$TEST_TMPDIR/service.log"
ORIGINAL_HOME="$HOME"
ORIGINAL_GNUPGHOME="${GNUPGHOME:-}"
cleanup() {
echo -e "${YELLOW}Cleaning up...${NC}"
# Stop the service
if [ -f "$PID_FILE" ]; then
PID=$(cat "$PID_FILE")
if kill -0 "$PID" 2>/dev/null; then
echo "Sending SIGTERM to service PID $PID..."
kill -TERM "$PID" 2>/dev/null || true
# Wait for graceful shutdown
for i in $(seq 1 $TIMEOUT); do
if ! kill -0 "$PID" 2>/dev/null; then
echo -e "${GREEN}Service terminated gracefully${NC}"
break
fi
sleep 1
done
# Force kill if still running
if kill -0 "$PID" 2>/dev/null; then
echo -e "${YELLOW}Service still running, sending SIGKILL...${NC}"
kill -9 "$PID" 2>/dev/null || true
fi
fi
fi
# Stop the private D-Bus daemon
if [ -n "$DBUS_DAEMON_PID" ] && kill -0 "$DBUS_DAEMON_PID" 2>/dev/null; then
echo "Stopping D-Bus daemon (PID $DBUS_DAEMON_PID)..."
kill -TERM "$DBUS_DAEMON_PID" 2>/dev/null || true
fi
# Restore original environment
export HOME="$ORIGINAL_HOME"
if [ -n "$ORIGINAL_GNUPGHOME" ]; then
export GNUPGHOME="$ORIGINAL_GNUPGHOME"
else
unset GNUPGHOME
fi
# Clean up temporary directory
if [ -n "$TEST_TMPDIR" ] && [ -d "$TEST_TMPDIR" ]; then
echo "Removing temporary test directory..."
rm -rf "$TEST_TMPDIR"
fi
echo "Cleanup complete"
}
start_dbus() {
echo "Starting private D-Bus daemon..."
DBUS_SOCK="$TEST_TMPDIR/bus.sock"
DBUS_ADDR="unix:path=$DBUS_SOCK"
dbus-daemon --session --nofork --address="$DBUS_ADDR" &
DBUS_DAEMON_PID=$!
# Wait for socket to appear
for i in $(seq 1 50); do
if [ -S "$DBUS_SOCK" ]; then
break
fi
sleep 0.1
done
if [ ! -S "$DBUS_SOCK" ]; then
echo -e "${RED}D-Bus daemon failed to create socket${NC}"
exit 1
fi
export DBUS_SESSION_BUS_ADDRESS="$DBUS_ADDR"
echo "D-Bus daemon started (PID: $DBUS_DAEMON_PID)"
echo "D-Bus address: $DBUS_SESSION_BUS_ADDRESS"
# Verify D-Bus is working
if ! dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.ListNames >/dev/null 2>&1; then
echo -e "${RED}D-Bus daemon started but not responding${NC}"
exit 1
fi
}
setup_isolated_environment() {
echo "Setting up isolated test environment..."
echo "Test directory: $TEST_TMPDIR"
# Set up isolated HOME (all data stays within TEST_TMPDIR)
export HOME="$TEST_TMPDIR/home"
mkdir -p "$HOME"
# Set up isolated GNUPGHOME
export GNUPGHOME="$TEST_TMPDIR/gnupg"
mkdir -p "$GNUPGHOME"
chmod 700 "$GNUPGHOME"
# Set up isolated XDG directories to prevent any access to user's data
export XDG_CONFIG_HOME="$TEST_TMPDIR/config"
export XDG_DATA_HOME="$TEST_TMPDIR/data"
export XDG_CACHE_HOME="$TEST_TMPDIR/cache"
mkdir -p "$XDG_CONFIG_HOME" "$XDG_DATA_HOME" "$XDG_CACHE_HOME"
# Configure gpg-agent for non-interactive use
cat > "$GNUPGHOME/gpg-agent.conf" <<EOF
allow-loopback-pinentry
pinentry-program /usr/bin/pinentry-tty
EOF
# Create a test GPG key (no passphrase for testing)
echo "Creating test GPG key..."
gpg --batch --gen-key <<EOF
%no-protection
Key-Type: RSA
Key-Length: 2048
Name-Real: Test User
Name-Email: test@gopass-secret-service.local
Expire-Date: 0
%commit
EOF
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to create test GPG key${NC}"
exit 1
fi
# Configure git (in isolated home, not global)
git config --global user.email "test@gopass-secret-service.local"
git config --global user.name "Test User"
# Check if gopass is available
if ! command -v gopass &> /dev/null; then
echo -e "${RED}gopass not found in PATH${NC}"
exit 1
fi
# Initialize gopass store within the temp directory
echo "Initializing test gopass store..."
GOPASS_STORE="$TEST_TMPDIR/gopass-store"
mkdir -p "$GOPASS_STORE"
gopass init --path "$GOPASS_STORE" test@gopass-secret-service.local
if [ $? -ne 0 ]; then
echo -e "${RED}Failed to initialize gopass store${NC}"
exit 1
fi
echo -e "${GREEN}Isolated environment ready${NC}"
}
# Set trap for cleanup on exit
trap cleanup EXIT
# Start private D-Bus daemon
start_dbus
# Set up isolated gopass/GPG environment
setup_isolated_environment
# Check if binary exists
if [ ! -x "$BINARY" ]; then
echo -e "${RED}Binary not found: $BINARY${NC}"
echo "Building..."
go build -o "$BINARY" ./cmd/gopass-secret
fi
# Start the service
echo "Starting gopass-secret service..."
$BINARY service -d > "$LOG_FILE" 2>&1 &
echo $! > "$PID_FILE"
PID=$(cat "$PID_FILE")
echo "Started with PID: $PID"
# Wait for service to be ready
echo "Waiting for service to be ready..."
for i in $(seq 1 10); do
if dbus-send --session --print-reply --dest=org.freedesktop.DBus /org/freedesktop/DBus org.freedesktop.DBus.GetNameOwner string:org.freedesktop.secrets >/dev/null 2>&1; then
echo -e "${GREEN}D-Bus name acquired!${NC}"
break
fi
# Check if process is still running
if ! kill -0 "$PID" 2>/dev/null; then
echo -e "${RED}Service exited unexpectedly!${NC}"
echo "Log output:"
cat "$LOG_FILE"
exit 1
fi
sleep 1
done
# Wait for full initialization (check for "Service started successfully" in log)
echo "Waiting for initialization..."
for i in $(seq 1 15); do
if grep -q "Service started successfully" "$LOG_FILE" 2>/dev/null; then
echo -e "${GREEN}Service ready!${NC}"
break
fi
if ! kill -0 "$PID" 2>/dev/null; then
echo -e "${RED}Service exited during initialization!${NC}"
cat "$LOG_FILE"
exit 1
fi
sleep 1
done
if ! grep -q "Service started successfully" "$LOG_FILE" 2>/dev/null; then
echo -e "${YELLOW}Warning: Service may not be fully initialized${NC}"
fi
# Verify service is responding
if ! dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.DBus.Introspectable.Introspect >/dev/null 2>&1; then
echo -e "${RED}Service is not responding to D-Bus calls${NC}"
cat "$LOG_FILE"
exit 1
fi
echo ""
echo "=== Running Tests ==="
echo ""
TESTS_PASSED=0
TESTS_FAILED=0
run_test() {
local name="$1"
local cmd="$2"
echo -n "Test: $name... "
if eval "$cmd" >/dev/null 2>&1; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
return 0
else
echo -e "${RED}FAILED${NC}"
TESTS_FAILED=$((TESTS_FAILED + 1))
return 0 # Return 0 to not exit with set -e
fi
}
# Test 1: Check Collections property
run_test "Get Collections property" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.DBus.Properties.Get string:'org.freedesktop.Secret.Service' string:'Collections'"
# Test 2: Check ReadAlias for default
run_test "ReadAlias default" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service.ReadAlias string:default"
# Test 3: Check default collection exists at alias path
run_test "Default collection via alias path" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets/aliases/default org.freedesktop.DBus.Properties.Get string:'org.freedesktop.Secret.Collection' string:'Label'"
# Test 4: Check default collection exists at regular path
run_test "Default collection via regular path" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets/collection/default org.freedesktop.DBus.Properties.Get string:'org.freedesktop.Secret.Collection' string:'Label'"
# Test 5: Try Python secretstorage (if available)
if python3 -c "import secretstorage" 2>/dev/null; then
run_test "Python secretstorage get_default_collection" \
"python3 -c \"import secretstorage; conn = secretstorage.dbus_init(); coll = secretstorage.get_default_collection(conn); print(coll.get_label())\""
else
echo "Skipping Python tests (secretstorage not installed)"
fi
# Test 6: Store a secret with secret-tool
echo -n "Test: Store secret with secret-tool... "
if echo "test-secret-value-$$" | timeout 10 secret-tool store --label="Test Secret $$" test-attr test-value-$$ 2>&1; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
# Test 7: Lookup the secret
echo -n "Test: Lookup secret with secret-tool... "
RETRIEVED=$(timeout 10 secret-tool lookup test-attr test-value-$$ 2>&1)
if [ "$RETRIEVED" = "test-secret-value-$$" ]; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
else
echo -e "${RED}FAILED${NC} (got: '$RETRIEVED')"
TESTS_FAILED=$((TESTS_FAILED + 1))
fi
# Test 8: Duplicate prevention - store same attributes again
echo -n "Test: Duplicate prevention (same attrs)... "
echo "new-secret-value-$$" | timeout 10 secret-tool store --label="Test Secret 2 $$" test-attr test-value-$$ 2>&1
# Count items with these attributes - should be exactly 1
SEARCH_RESULT=$(timeout 10 secret-tool search test-attr test-value-$$ 2>&1)
ITEM_COUNT=$(echo "$SEARCH_RESULT" | grep -c "^label = " || echo "0")
if [ "$ITEM_COUNT" = "1" ]; then
echo -e "${GREEN}PASSED${NC} (1 item, no duplicate)"
TESTS_PASSED=$((TESTS_PASSED + 1))
else
echo -e "${RED}FAILED${NC} (found $ITEM_COUNT items, expected 1)"
TESTS_FAILED=$((TESTS_FAILED + 1))
fi
# Test 9: Clear the secret
run_test "Clear secret with secret-tool" \
"timeout 10 secret-tool clear test-attr test-value-$$"
# Test 10: Verify deleted item is not accessible
echo -n "Test: Deleted item not accessible... "
LOOKUP_AFTER_DELETE=$(timeout 10 secret-tool lookup test-attr test-value-$$ 2>&1)
if [ -z "$LOOKUP_AFTER_DELETE" ]; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
else
echo -e "${RED}FAILED${NC} (item still accessible after delete)"
TESTS_FAILED=$((TESTS_FAILED + 1))
fi
else
echo -e "${RED}FAILED${NC}"
TESTS_FAILED=$((TESTS_FAILED + 1))
# Show debug info
echo "Service log:"
tail -20 "$LOG_FILE"
fi
echo ""
echo "--- Session collection ---"
echo ""
# The session collection is only exposed when the kernel keyring backend is
# available (rootless containers in restrictive user namespaces, kernels
# built without CONFIG_KEYS, etc. won't have it). Detect by asking the daemon
# to resolve the alias: "/" means no such alias, which means the keyring
# backend wasn't initialised. Skip session tests in that case rather than
# failing — non-keyring environments are out-of-contract for this feature.
SESSION_ALIAS_RESULT=$(dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service.ReadAlias string:session 2>/dev/null | grep "object path" | awk '{print $NF}' | tr -d '"')
if [ "$SESSION_ALIAS_RESULT" = "/" ] || [ -z "$SESSION_ALIAS_RESULT" ]; then
echo -e "${YELLOW}Skipping session tests: kernel keyring unavailable (alias resolves to '$SESSION_ALIAS_RESULT')${NC}"
SKIP_SESSION=1
else
SKIP_SESSION=0
fi
if [ "$SKIP_SESSION" = "0" ]; then
# Test: ReadAlias session resolves to a path (we don't pin the target collection
# name here — that's an implementation detail — only that the alias exists).
run_test "ReadAlias session" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets org.freedesktop.Secret.Service.ReadAlias string:session"
# Test: session collection is reachable via the alias path.
run_test "Session collection via alias path" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets/aliases/session org.freedesktop.DBus.Properties.Get string:'org.freedesktop.Secret.Collection' string:'Label'"
# Test: session collection is reachable via its canonical path.
run_test "Session collection via regular path" \
"dbus-send --session --print-reply --dest=org.freedesktop.secrets /org/freedesktop/secrets/collection/session org.freedesktop.DBus.Properties.Get string:'org.freedesktop.Secret.Collection' string:'Label'"
# Tests: store/lookup through the session collection AND confirm no gopass
# commit happens — the whole point of the session backend.
SESS_TAG="session-$$"
COMMITS_BEFORE=$(git -C "$GOPASS_STORE" rev-list --count HEAD 2>/dev/null || echo 0)
echo -n "Test: Store secret in session collection... "
if echo "session-payload-$$" | timeout 10 secret-tool store --label="Session $$" --collection session test-session "$SESS_TAG" 2>&1; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
echo -n "Test: Lookup session secret... "
RETRIEVED=$(timeout 10 secret-tool lookup test-session "$SESS_TAG" 2>&1)
if [ "$RETRIEVED" = "session-payload-$$" ]; then
echo -e "${GREEN}PASSED${NC}"
TESTS_PASSED=$((TESTS_PASSED + 1))
else
echo -e "${RED}FAILED${NC} (got: '$RETRIEVED')"
TESTS_FAILED=$((TESTS_FAILED + 1))
fi
# The contract: writes against the session collection don't reach gopass.
# If this assertion fails, attribute-based routing has broken or the
# session collection regressed to gopass storage.
echo -n "Test: Session write did not commit to gopass... "
COMMITS_AFTER=$(git -C "$GOPASS_STORE" rev-list --count HEAD 2>/dev/null || echo 0)
if [ "$COMMITS_BEFORE" = "$COMMITS_AFTER" ]; then
echo -e "${GREEN}PASSED${NC} ($COMMITS_BEFORE commits before/after)"
TESTS_PASSED=$((TESTS_PASSED + 1))
else
echo -e "${RED}FAILED${NC} (commits: $COMMITS_BEFORE -> $COMMITS_AFTER)"
TESTS_FAILED=$((TESTS_FAILED + 1))
fi
# Confirm we can also delete the session item via the same secret-tool
# path. (clear is best-effort cleanup; don't gate the suite on it.)
timeout 10 secret-tool clear test-session "$SESS_TAG" >/dev/null 2>&1 || true
else
echo -e "${RED}FAILED${NC}"
TESTS_FAILED=$((TESTS_FAILED + 1))
echo "Service log tail:"
tail -20 "$LOG_FILE"
fi
fi # SKIP_SESSION
echo ""
echo "=== Test Results ==="
echo -e "Passed: ${GREEN}$TESTS_PASSED${NC}"
echo -e "Failed: ${RED}$TESTS_FAILED${NC}"
echo ""
if [ $TESTS_FAILED -gt 0 ]; then
echo "Some tests failed. Service log:"
cat "$LOG_FILE"
exit 1
fi
echo -e "${GREEN}All tests passed!${NC}"
exit 0