Skip to content

Commit e2db891

Browse files
authored
Refactor fetch_key_file to include retry logic and improve error handling (#9)
* Refactor fetch_key_file to include retry logic and improve error handling * Enhance fetch_key_file with retry logic and update documentation to reflect changes * Bump script version to 0.0.8
1 parent 9456987 commit e2db891

File tree

3 files changed

+62
-28
lines changed

3 files changed

+62
-28
lines changed

.github/copilot-instructions.md

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This document provides comprehensive guidance for AI coding agents and contribut
1313
- Support for multiple fetch methods (`raw`, `api`, `ghuser`).
1414
- Logging and error handling.
1515
- Configuration loading from `users.conf`.
16-
- A helper function `fetch_key_file` to handle key retrieval logic.
16+
- A helper function `fetch_key_file` to handle key retrieval logic with retries for failed operations.
1717

1818
### Configuration
1919
- **`users.conf`**: Defines users and their key sources. Example structure:
@@ -97,3 +97,8 @@ This document provides comprehensive guidance for AI coding agents and contribut
9797
- **`raw`**: Fetches keys from a public URL.
9898
- **`api`**: Fetches keys from a private GitHub repository using the GitHub API.
9999
- **`ghuser`**: Fetches public keys from a GitHub user's profile.
100+
101+
### Enhanced Error Handling
102+
- The `fetch_key_file` function includes a retry mechanism for failed fetch operations.
103+
- By default, it retries up to 3 times with a 2-second delay between attempts.
104+
- Logs detailed error messages for each failed attempt and skips the user if all retries fail.

README.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ This Bash script pulls `authorized_keys` files from remote URLs and updates SSH
1212
- ✅ GitHub user public keys (method: `ghuser`)
1313
- Safe: Only updates keys if they’ve changed
1414
- Logs activity per user
15+
- Retries failed fetch operations up to 3 times with a delay
1516

1617
## ⚙️ Configuration
1718

@@ -41,10 +42,11 @@ declare -A USER_KEYS=(
4142
## Usage
4243

4344
1. Edit the `users.conf` file to define users and their key URLs or GitHub usernames.
44-
2. If using the `api` method, either export your GitHub token or set `CONF_GITHUB_TOKEN` in `users.conf`:
45+
2. If using the `api` method, either export your GitHub token:
4546
```bash
4647
export GITHUB_TOKEN=your_token_here
4748
```
49+
or set `CONF_GITHUB_TOKEN` in `users.conf`.
4850
3. Make sure the script is executable:
4951
```bash
5052
chmod +x sync-ssh-keys.sh
@@ -58,5 +60,18 @@ declare -A USER_KEYS=(
5860

5961
- The script sources `users.conf` for configuration.
6062
- Uses a helper function `fetch_key_file` to fetch keys using the appropriate method.
63+
- Includes a retry mechanism for failed fetch operations (3 attempts with a 2-second delay).
6164
- Only updates a user's `authorized_keys` if the remote file has changed.
6265
- Logs all actions with timestamps.
66+
67+
## Examples
68+
69+
### Adding a New User
70+
1. Add the user to `users.conf`:
71+
```bash
72+
["newuser"]="ghuser:newuser-github-username"
73+
```
74+
2. Run the script to sync keys:
75+
```bash
76+
./sync-ssh-keys.sh
77+
```

sync-ssh-keys.sh

Lines changed: 40 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
set -euo pipefail
33

44
# shellcheck disable=SC2034 # planned to be used in a future release
5-
SCRIPT_VERSION="0.0.7"
5+
SCRIPT_VERSION="0.0.8"
66

77
# === Load user configuration ===
88
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
@@ -30,24 +30,30 @@ fetch_key_file() {
3030
local METHOD="$1"
3131
local TARGET="$2"
3232
local OUTFILE="$3"
33+
local RETRIES=3
34+
local RETRY_DELAY=2
3335

34-
if [[ "$METHOD" == "raw" ]]; then
35-
curl -fsSL "$TARGET" -o "$OUTFILE"
36-
return $?
37-
elif [[ "$METHOD" == "api" ]]; then
38-
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required for API access}"
39-
curl -fsSL -H "Authorization: token $GITHUB_TOKEN" \
40-
-H "Accept: application/vnd.github.v3.raw" \
41-
"$TARGET" -o "$OUTFILE"
42-
return $?
43-
elif [[ "$METHOD" == "ghuser" ]]; then
44-
# TARGET is the GitHub username
45-
curl -fsSL "https://github.com/${TARGET}.keys" -o "$OUTFILE"
46-
return $?
47-
else
48-
log_message "Error: Unsupported method '$METHOD' encountered for URL '$TARGET'. Halting execution."
49-
exit 2
50-
fi
36+
for ((i=1; i<=RETRIES; i++)); do
37+
if [[ "$METHOD" == "raw" ]]; then
38+
curl -fsSL "$TARGET" -o "$OUTFILE" && return 0
39+
elif [[ "$METHOD" == "api" ]]; then
40+
: "${GITHUB_TOKEN:?GITHUB_TOKEN is required for API access}"
41+
curl -fsSL -H "Authorization: token $GITHUB_TOKEN" \
42+
-H "Accept: application/vnd.github.v3.raw" \
43+
"$TARGET" -o "$OUTFILE" && return 0
44+
elif [[ "$METHOD" == "ghuser" ]]; then
45+
curl -fsSL "https://github.com/${TARGET}.keys" -o "$OUTFILE" && return 0
46+
else
47+
log_message "Error: Unsupported method '$METHOD' encountered for URL '$TARGET'. Halting execution."
48+
exit 2
49+
fi
50+
51+
log_message "Attempt $i/$RETRIES failed for method '$METHOD' and URL '$TARGET'. Retrying in $RETRY_DELAY seconds..."
52+
sleep "$RETRY_DELAY"
53+
done
54+
55+
log_message "Error: All $RETRIES attempts failed for method '$METHOD' and URL '$TARGET'. Skipping."
56+
return 1
5157
}
5258

5359
TMP_FILES=()
@@ -58,16 +64,19 @@ for USER in "${!USER_KEYS[@]}"; do
5864
ENTRY="${USER_KEYS[$USER]}"
5965
METHOD="${ENTRY%%:*}"
6066
URL="${ENTRY#*:}"
67+
6168
# Ensure user exists
6269
if ! id "$USER" &>/dev/null; then
6370
log_message "User '$USER' does not exist. Skipping."
6471
continue
6572
fi
73+
6674
USER_HOME=$(getent passwd "$USER" | cut -d: -f6)
6775
if [ -z "$USER_HOME" ]; then
6876
log_message "Failed to determine home directory for user '$USER'. Skipping."
6977
continue
7078
fi
79+
7180
AUTH_KEYS="$USER_HOME/.ssh/authorized_keys"
7281
SSH_DIR="$(dirname "$AUTH_KEYS")"
7382

@@ -76,21 +85,26 @@ for USER in "${!USER_KEYS[@]}"; do
7685
mkdir -p "$SSH_DIR"
7786
chown "$USER:$USER" "$SSH_DIR"
7887
chmod 700 "$SSH_DIR"
79-
log_message "Created .ssh directory for user '$USER'"
88+
log_message "Created .ssh directory for user '$USER' at $SSH_DIR."
8089
fi
8190

8291
log_message "Fetching key file for $USER from $URL (method: $METHOD)"
8392
if ! fetch_key_file "$METHOD" "$URL" "$TMP_FILE"; then
84-
log_message "Failed to fetch key file for user '$USER' from $URL. Skipping."
93+
log_message "Failed to fetch key file for user '$USER' from $URL after multiple attempts. Skipping."
8594
continue
8695
fi
8796

88-
if [ ! -f "$AUTH_KEYS" ] || ! cmp -s "$TMP_FILE" "$AUTH_KEYS"; then
89-
cp "$TMP_FILE" "$AUTH_KEYS"
90-
chown "$USER:$USER" "$AUTH_KEYS"
91-
chmod 600 "$AUTH_KEYS"
92-
log_message "Updated authorized_keys for user '$USER'"
97+
if [ ! -f "$AUTH_KEYS" ]; then
98+
log_message "No existing authorized_keys file for user '$USER'. Creating a new one."
99+
elif ! cmp -s "$TMP_FILE" "$AUTH_KEYS"; then
100+
log_message "Changes detected in authorized_keys for user '$USER'. Updating the file."
93101
else
94-
log_message "No changes for user '$USER'"
102+
log_message "No changes detected in authorized_keys for user '$USER'."
103+
continue
95104
fi
105+
106+
cp "$TMP_FILE" "$AUTH_KEYS"
107+
chown "$USER:$USER" "$AUTH_KEYS"
108+
chmod 600 "$AUTH_KEYS"
109+
log_message "Updated authorized_keys for user '$USER' at $AUTH_KEYS."
96110
done

0 commit comments

Comments
 (0)