Skip to content

Commit ec01f9b

Browse files
authored
Add CI workflows for testing and version checks, enhance README and T… (#17)
* Add CI workflows for testing and version checks, enhance README and TESTING documentation * Bump version to 0.1.3 in README.md and sync-ssh-keys.sh * Add shellcheck directive to ignore dynamic source path warning in test config loading * Enhance test workflow with improved configuration validation and error handling * Fix permission issues in configuration validation and invalid method handling tests * Update GitHub user keys in tests and adjust permission checks for integration tests * Fix arithmetic operations for set -e compatibility - Replace ((var++)) with var=1 to prevent script exit under set -e - Fix script exit code issue in integration tests - Add proper temp file cleanup - Ensure summary message is displayed correctly * Revert users.conf to original example configuration - Remove integration test user configuration - Restore original example comments and configuration - Prepare for production use
1 parent ae45e1a commit ec01f9b

File tree

9 files changed

+821
-36
lines changed

9 files changed

+821
-36
lines changed

.github/workflows/check-version.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ on:
77
paths:
88
- 'sync-ssh-keys.sh'
99
- 'users.conf'
10+
- '.github/workflows/check-version.yml'
1011

1112
jobs:
1213
check-version:

.github/workflows/ci.yml

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
name: CI
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
push:
8+
branches:
9+
- main
10+
11+
jobs:
12+
# Run all individual checks in parallel
13+
lint:
14+
uses: ./.github/workflows/lint.yml
15+
16+
version-check:
17+
uses: ./.github/workflows/check-version.yml
18+
if: github.event_name == 'pull_request'
19+
20+
test:
21+
uses: ./.github/workflows/test.yml
22+
23+
# Final status check
24+
ci-success:
25+
runs-on: ubuntu-latest
26+
needs: [lint, test]
27+
if: always()
28+
steps:
29+
- name: Check all jobs status
30+
run: |
31+
if [[ "${{ needs.lint.result }}" != "success" ]]; then
32+
echo "Lint job failed"
33+
exit 1
34+
fi
35+
36+
if [[ "${{ needs.test.result }}" != "success" ]]; then
37+
echo "Test job failed"
38+
exit 1
39+
fi
40+
41+
if [[ "${{ github.event_name }}" == "pull_request" && "${{ needs.version-check.result }}" != "success" ]]; then
42+
echo "Version check job failed"
43+
exit 1
44+
fi
45+
46+
echo "All CI checks passed!"

.github/workflows/lint.yml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,14 @@ on:
66
- main
77
paths:
88
- 'sync-ssh-keys.sh'
9+
- 'users.conf'
10+
- '.github/workflows/lint.yml'
11+
push:
12+
branches:
13+
- main
14+
paths:
15+
- 'sync-ssh-keys.sh'
16+
- 'users.conf'
917
- '.github/workflows/lint.yml'
1018

1119
jobs:

.github/workflows/test.yml

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
name: Test SSH Key Sync
2+
# This workflow performs comprehensive testing of the SSH key sync script
3+
# It includes unit tests, configuration validation, and integration tests
4+
# Unit tests avoid executing the main script to prevent unintended side effects
5+
6+
on:
7+
pull_request:
8+
branches:
9+
- main
10+
paths:
11+
- 'sync-ssh-keys.sh'
12+
- 'users.conf'
13+
- '.github/workflows/test.yml'
14+
push:
15+
branches:
16+
- main
17+
paths:
18+
- 'sync-ssh-keys.sh'
19+
- 'users.conf'
20+
- '.github/workflows/test.yml'
21+
22+
jobs:
23+
test:
24+
runs-on: ubuntu-latest
25+
steps:
26+
- name: Checkout code
27+
uses: actions/checkout@v4
28+
29+
- name: Install required packages
30+
run: |
31+
sudo apt-get update
32+
sudo apt-get install -y diffutils
33+
34+
- name: Make script executable
35+
run: chmod +x sync-ssh-keys.sh
36+
37+
- name: Create test users
38+
run: |
39+
sudo useradd -m testuser1 || true
40+
sudo useradd -m testuser2 || true
41+
sudo useradd -m testuser3 || true
42+
43+
- name: Setup test environment
44+
run: |
45+
# Create a temporary test configuration
46+
cat > test-users.conf << 'EOF'
47+
#!/bin/bash
48+
# Test configuration for GitHub Actions
49+
50+
# No GitHub token needed for public key tests
51+
CONF_GITHUB_TOKEN=""
52+
53+
# Test user key mapping with public GitHub users
54+
declare -A USER_KEYS=(
55+
# Test with a known GitHub user that has public keys
56+
["testuser1"]="ghuser:locus313"
57+
# Test with raw public key (using GitHub's public key endpoint)
58+
["testuser2"]="raw:https://github.com/locus313.keys"
59+
)
60+
EOF
61+
62+
- name: Test configuration validation
63+
run: |
64+
# Test with missing config file
65+
mv users.conf users.conf.backup
66+
if sudo ./sync-ssh-keys.sh 2>&1 | grep -q "Failed to load configuration file 'users.conf'"; then
67+
echo "✓ Configuration file validation works"
68+
else
69+
echo "✗ Configuration file validation failed"
70+
mv users.conf.backup users.conf
71+
exit 1
72+
fi
73+
mv users.conf.backup users.conf
74+
75+
- name: Test configuration loading
76+
run: |
77+
# Use test configuration
78+
cp test-users.conf users.conf
79+
80+
# Test that configuration can be sourced and validated
81+
bash -c 'source users.conf && declare -p USER_KEYS >/dev/null'
82+
echo "✓ Configuration loading test completed"
83+
84+
- name: Test invalid method handling
85+
run: |
86+
# Create config with invalid method
87+
cat > test-invalid.conf << 'EOF'
88+
#!/bin/bash
89+
declare -A USER_KEYS=(
90+
["testuser1"]="invalid:test"
91+
)
92+
EOF
93+
94+
cp test-invalid.conf users.conf
95+
96+
# Should fail with unsupported method error
97+
# Run with sudo to avoid permission issues that would mask the method error
98+
if sudo ./sync-ssh-keys.sh 2>&1 | grep -q "Unsupported method 'invalid'"; then
99+
echo "✓ Invalid method handling works"
100+
else
101+
echo "✗ Invalid method handling failed"
102+
echo "Actual output:"
103+
sudo ./sync-ssh-keys.sh 2>&1 | head -10
104+
exit 1
105+
fi
106+
107+
- name: Test script syntax and functions
108+
run: |
109+
# Test script syntax
110+
bash -n sync-ssh-keys.sh
111+
echo "✓ Script syntax is valid"
112+
113+
# Test that required functions are defined (without executing main)
114+
if grep -q "^log_message()" sync-ssh-keys.sh && \
115+
grep -q "^fetch_key_file()" sync-ssh-keys.sh && \
116+
grep -q "^validate_method()" sync-ssh-keys.sh && \
117+
grep -q "^load_configuration()" sync-ssh-keys.sh; then
118+
echo "✓ Required functions are present"
119+
else
120+
echo "✗ Required functions are missing"
121+
exit 1
122+
fi
123+
124+
- name: Test with empty user array
125+
run: |
126+
# Create config with empty user array
127+
cat > test-empty.conf << 'EOF'
128+
#!/bin/bash
129+
declare -A USER_KEYS=()
130+
EOF
131+
132+
cp test-empty.conf users.conf
133+
134+
# Should exit cleanly with warning (no sudo needed since no user access)
135+
if ./sync-ssh-keys.sh 2>&1 | grep -q "No users defined in USER_KEYS array"; then
136+
echo "✓ Empty user array handling works"
137+
else
138+
echo "✗ Empty user array handling failed"
139+
exit 1
140+
fi
141+
142+
- name: Test GitHub user key fetching (mock)
143+
run: |
144+
# Test the curl command format for GitHub user keys
145+
curl -fsSL "https://github.com/locus313.keys" | head -2
146+
echo "✓ GitHub user key endpoint is accessible"
147+
148+
- name: Test script version extraction
149+
run: |
150+
# Verify version can be extracted
151+
VERSION=$(awk -F'"' '/SCRIPT_VERSION/ {print $2; exit}' sync-ssh-keys.sh)
152+
if [[ -n "$VERSION" ]]; then
153+
echo "✓ Script version found: $VERSION"
154+
else
155+
echo "✗ Script version not found"
156+
exit 1
157+
fi
158+
159+
- name: Test self-update function (dry run)
160+
run: |
161+
# Test that self-update function exists and can be parsed
162+
grep -q "self_update()" sync-ssh-keys.sh
163+
grep -q "get_latest_release_url" sync-ssh-keys.sh
164+
grep -q "download_latest_script" sync-ssh-keys.sh
165+
echo "✓ Self-update functions are present"
166+
167+
- name: Test error handling
168+
run: |
169+
# Create config that will trigger various error conditions
170+
cat > test-errors.conf << 'EOF'
171+
#!/bin/bash
172+
declare -A USER_KEYS=(
173+
["nonexistentuser"]="ghuser:nonexistentuser12345"
174+
["testuser1"]="raw:https://invalid-url-that-does-not-exist.example.com/keys"
175+
)
176+
EOF
177+
178+
# Test that config is syntactically valid
179+
bash -n test-errors.conf
180+
echo "✓ Error handling configuration is valid"
181+
182+
- name: Test log message formatting
183+
run: |
184+
# Test log functions exist and have correct format
185+
if grep -q "log_message()" sync-ssh-keys.sh && \
186+
grep -q "log_error()" sync-ssh-keys.sh && \
187+
grep -q "log_warning()" sync-ssh-keys.sh && \
188+
grep -q "log_info()" sync-ssh-keys.sh; then
189+
echo "✓ Log functions are present"
190+
else
191+
echo "✗ Log functions are missing"
192+
exit 1
193+
fi
194+
195+
- name: Cleanup test environment
196+
run: |
197+
# Restore original configuration
198+
git checkout users.conf 2>/dev/null || true
199+
200+
# Remove test files
201+
rm -f test-*.conf
202+
203+
# Remove test users (if they exist)
204+
sudo userdel -f testuser1 2>/dev/null || true
205+
sudo userdel -f testuser2 2>/dev/null || true
206+
sudo userdel -f testuser3 2>/dev/null || true
207+
208+
echo "✓ Cleanup completed"
209+
210+
integration-test:
211+
runs-on: ubuntu-latest
212+
needs: test
213+
if: github.event_name == 'pull_request'
214+
steps:
215+
- name: Checkout code
216+
uses: actions/checkout@v4
217+
218+
- name: Install required packages
219+
run: |
220+
sudo apt-get update
221+
sudo apt-get install -y diffutils
222+
223+
- name: Make script executable
224+
run: chmod +x sync-ssh-keys.sh
225+
226+
- name: Create integration test user
227+
run: |
228+
sudo useradd -m integrationuser
229+
230+
- name: Setup integration test configuration
231+
run: |
232+
cat > users.conf << 'EOF'
233+
#!/bin/bash
234+
# Integration test configuration
235+
declare -A USER_KEYS=(
236+
# Use a real GitHub user with known public keys for integration testing
237+
["integrationuser"]="ghuser:locus313"
238+
)
239+
EOF
240+
241+
- name: Run integration test
242+
run: |
243+
# Run the script with sudo and verify it completes successfully
244+
sudo ./sync-ssh-keys.sh
245+
246+
# Verify the authorized_keys file was created
247+
if sudo test -f /home/integrationuser/.ssh/authorized_keys; then
248+
echo "✓ authorized_keys file created successfully"
249+
echo "File contents:"
250+
sudo head -2 /home/integrationuser/.ssh/authorized_keys
251+
echo "File permissions:"
252+
sudo ls -la /home/integrationuser/.ssh/authorized_keys
253+
else
254+
echo "✗ authorized_keys file was not created"
255+
echo "Directory contents:"
256+
sudo ls -la /home/integrationuser/ || true
257+
sudo ls -la /home/integrationuser/.ssh/ || true
258+
exit 1
259+
fi
260+
261+
- name: Verify file permissions
262+
run: |
263+
# Check SSH directory permissions
264+
PERMS=$(sudo stat -c "%a" /home/integrationuser/.ssh)
265+
if [[ "$PERMS" == "700" ]]; then
266+
echo "✓ SSH directory permissions are correct (700)"
267+
else
268+
echo "✗ SSH directory permissions are incorrect: $PERMS"
269+
exit 1
270+
fi
271+
272+
# Check authorized_keys file permissions
273+
PERMS=$(sudo stat -c "%a" /home/integrationuser/.ssh/authorized_keys)
274+
if [[ "$PERMS" == "600" ]]; then
275+
echo "✓ authorized_keys file permissions are correct (600)"
276+
else
277+
echo "✗ authorized_keys file permissions are incorrect: $PERMS"
278+
exit 1
279+
fi
280+
281+
- name: Cleanup integration test
282+
run: |
283+
sudo userdel -rf integrationuser 2>/dev/null || true
284+
git checkout users.conf

0 commit comments

Comments
 (0)