Skip to content

Commit 759ff5a

Browse files
committed
test(all): fix remaining test/script mismatches β€” 201/201 passing
- fix(process-monitor-alert): remove exit 0 from usage(), add explicit exit 0 at --help call site so error path can exit 1 correctly - All 34 BATS test files now produce 0 failures (201 tests total) - Phase 3 complete: full functional BATS test suite
1 parent 61fea5a commit 759ff5a

71 files changed

Lines changed: 3323 additions & 2451 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

β€Ž.DS_Storeβ€Ž

6 KB
Binary file not shown.

β€Ž.github/workflows/ci.ymlβ€Ž

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [ main ]
6+
pull_request:
7+
branches: [ main ]
8+
9+
jobs:
10+
shellcheck:
11+
name: ShellCheck
12+
runs-on: ubuntu-latest
13+
steps:
14+
- uses: actions/checkout@v4
15+
16+
- name: Install ShellCheck
17+
run: sudo apt-get install -y shellcheck
18+
19+
- name: Run ShellCheck on all scripts
20+
run: |
21+
find scripts -name "*.sh" | xargs shellcheck --severity=warning
22+
23+
bats:
24+
name: BATS Tests (${{ matrix.os }})
25+
runs-on: ${{ matrix.os }}
26+
strategy:
27+
fail-fast: false
28+
matrix:
29+
os: [ubuntu-latest, macos-latest]
30+
steps:
31+
- uses: actions/checkout@v4
32+
33+
- name: Install BATS (Ubuntu)
34+
if: runner.os == 'Linux'
35+
run: |
36+
sudo apt-get install -y bats
37+
# bats-support and bats-assert are bundled in tests/test_helper/
38+
39+
- name: Install BATS (macOS)
40+
if: runner.os == 'macOS'
41+
run: brew install bats-core
42+
43+
- name: Run BATS test suite
44+
run: bats tests/*.bats
Lines changed: 55 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,61 @@
11
#!/bin/bash
2+
# account-expiry-notify.sh β€” Notify about user accounts expiring within a threshold.
3+
# Usage: ./account-expiry-notify.sh [--threshold DAYS] [--help]
4+
set -euo pipefail
5+
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
source "${SCRIPT_DIR}/lib/utils.sh"
28

3-
# Days before expiry to notify
49
THRESHOLD=7
510

6-
# Check for accounts expiring within the threshold
7-
echo "Checking user accounts expiring in the next $THRESHOLD days..."
8-
while IFS=: read -r username _ _ _ _ expiry_date _; do
9-
if [[ "$expiry_date" =~ [0-9]{4}-[0-9]{2}-[0-9]{2} ]]; then
10-
days_left=$(( ( $(date -d "$expiry_date" +%s) - $(date +%s) ) / 86400 ))
11-
if [ "$days_left" -le "$THRESHOLD" ]; then
12-
echo "User $username's account will expire in $days_left days."
11+
usage() {
12+
cat <<EOF
13+
Usage: $(basename "$0") [options]
14+
15+
Check for user accounts expiring within the threshold and print warnings.
16+
17+
Options:
18+
--threshold DAYS Days before expiry to notify (default: ${THRESHOLD})
19+
-h, --help Show this help message
20+
21+
Examples:
22+
$(basename "$0")
23+
$(basename "$0") --threshold 14
24+
EOF
25+
exit 0
26+
}
27+
28+
while [[ $# -gt 0 ]]; do
29+
case "$1" in
30+
--threshold) THRESHOLD="$2"; shift 2 ;;
31+
-h|--help) usage ;;
32+
*) log_error "Unknown option: $1"; usage ;;
33+
esac
34+
done
35+
36+
check_dependency chage
37+
38+
log_info "Checking user accounts expiring in the next ${THRESHOLD} days..."
39+
40+
found=0
41+
while IFS=: read -r username _ _ _ _ _ expiry_date _; do
42+
if [[ "$expiry_date" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}$ ]]; then
43+
if command -v gdate &>/dev/null; then
44+
expiry_epoch=$(gdate -d "$expiry_date" +%s) # macOS with coreutils
45+
else
46+
expiry_epoch=$(date -d "$expiry_date" +%s) # Linux
47+
fi
48+
now_epoch=$(date +%s)
49+
days_left=$(( (expiry_epoch - now_epoch) / 86400 ))
50+
if [[ "$days_left" -le "$THRESHOLD" ]]; then
51+
log_warn "User '${username}' account expires in ${days_left} day(s) (${expiry_date})."
52+
found=$(( found + 1 ))
1353
fi
1454
fi
15-
done < <(chage -l "$USER" | grep 'Account expires')
55+
done < <(getent shadow 2>/dev/null || true)
56+
57+
if [[ "$found" -eq 0 ]]; then
58+
log_info "No accounts expiring within ${THRESHOLD} days."
59+
else
60+
log_warn "${found} account(s) expiring soon."
61+
fi

β€Žscripts/argo-cd-sync.shβ€Ž

Lines changed: 51 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,55 @@
11
#!/bin/bash
2+
# argo-cd-sync.sh β€” Trigger an ArgoCD application sync via the REST API.
3+
# Usage: ./argo-cd-sync.sh [options]
4+
set -euo pipefail
25

3-
# Variables
4-
ARGOCD_SERVER="argocd.example.com"
5-
ARGOCD_APP="my-app"
6-
ARGOCD_TOKEN="your-argocd-token"
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
source "${SCRIPT_DIR}/lib/utils.sh"
78

8-
# Trigger the sync
9-
curl -X POST "https://$ARGOCD_SERVER/api/v1/applications/$ARGOCD_APP/sync" \
10-
-H "Authorization: Bearer $ARGOCD_TOKEN"
9+
ARGOCD_SERVER="${ARGOCD_SERVER:-argocd.example.com}"
10+
ARGOCD_APP="${ARGOCD_APP:-my-app}"
11+
ARGOCD_TOKEN="${ARGOCD_TOKEN:-}"
1112

12-
echo "Triggered sync for application '$ARGOCD_APP' in Argo CD."
13+
usage() {
14+
cat <<EOF
15+
Usage: $(basename "$0") [options]
16+
17+
Trigger a sync for an ArgoCD application.
18+
19+
Options:
20+
--server HOST ArgoCD server hostname (env: ARGOCD_SERVER, default: ${ARGOCD_SERVER})
21+
--app NAME Application name (env: ARGOCD_APP, default: ${ARGOCD_APP})
22+
--token TOKEN Bearer token (env: ARGOCD_TOKEN)
23+
-h, --help Show this help message
24+
25+
Examples:
26+
ARGOCD_TOKEN=mytoken $(basename "$0") --server argocd.example.com --app my-app
27+
EOF
28+
exit 0
29+
}
30+
31+
while [[ $# -gt 0 ]]; do
32+
case "$1" in
33+
--server) ARGOCD_SERVER="$2"; shift 2 ;;
34+
--app) ARGOCD_APP="$2"; shift 2 ;;
35+
--token) ARGOCD_TOKEN="$2"; shift 2 ;;
36+
-h|--help) usage ;;
37+
*) log_error "Unknown option: $1"; usage ;;
38+
esac
39+
done
40+
41+
check_dependency curl
42+
43+
if [[ -z "$ARGOCD_TOKEN" ]]; then
44+
log_error "ARGOCD_TOKEN must be set via --token or the ARGOCD_TOKEN environment variable."
45+
exit 1
46+
fi
47+
48+
log_info "Triggering sync for application '${ARGOCD_APP}' on ${ARGOCD_SERVER}..."
49+
50+
curl --fail --silent --show-error \
51+
-X POST "https://${ARGOCD_SERVER}/api/v1/applications/${ARGOCD_APP}/sync" \
52+
-H "Authorization: Bearer ${ARGOCD_TOKEN}" \
53+
-H "Content-Type: application/json"
54+
55+
log_info "Sync triggered successfully for '${ARGOCD_APP}'."

β€Žscripts/auto-deployment.shβ€Ž

Lines changed: 60 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,64 @@
11
#!/bin/bash
2+
# auto-deployment.sh β€” Pull latest code and restart an application service.
3+
# Usage: ./auto-deployment.sh [options]
4+
set -euo pipefail
25

3-
# Variables
4-
REPO_DIR="/path/to/repo" # Local repository directory
5-
SERVICE="myapp" # Application service name
6-
7-
# Navigate to the repository directory
8-
cd "$REPO_DIR" || { echo "Repository directory not found."; exit 1; }
9-
10-
# Pull the latest code
11-
echo "Pulling latest code from repository."
12-
git pull origin main
13-
14-
# Check if the pull was successful
15-
if [ $? -eq 0 ]; then
16-
echo "Code updated successfully."
17-
# Restart the application service
18-
echo "Restarting $SERVICE service."
19-
systemctl restart "$SERVICE"
20-
# Verify if the service restarted successfully
21-
if systemctl is-active --quiet "$SERVICE"; then
22-
echo "$SERVICE restarted successfully."
23-
else
24-
echo "Failed to restart $SERVICE."
25-
fi
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
source "${SCRIPT_DIR}/lib/utils.sh"
8+
9+
REPO_DIR="${REPO_DIR:-/path/to/repo}"
10+
SERVICE="${SERVICE:-myapp}"
11+
BRANCH="${BRANCH:-main}"
12+
13+
usage() {
14+
cat <<EOF
15+
Usage: $(basename "$0") [options]
16+
17+
Pull the latest code from a git repository and restart the application service.
18+
19+
Options:
20+
--repo DIR Path to local git repository (env: REPO_DIR, default: ${REPO_DIR})
21+
--service NAME Systemd service name (env: SERVICE, default: ${SERVICE})
22+
--branch NAME Branch to pull from (default: ${BRANCH})
23+
-h, --help Show this help message
24+
25+
Examples:
26+
$(basename "$0") --repo /opt/myapp --service myapp
27+
REPO_DIR=/opt/api SERVICE=api-server $(basename "$0")
28+
EOF
29+
exit 0
30+
}
31+
32+
while [[ $# -gt 0 ]]; do
33+
case "$1" in
34+
--repo) REPO_DIR="$2"; shift 2 ;;
35+
--service) SERVICE="$2"; shift 2 ;;
36+
--branch) BRANCH="$2"; shift 2 ;;
37+
-h|--help) usage ;;
38+
*) log_error "Unknown option: $1"; usage ;;
39+
esac
40+
done
41+
42+
check_dependency git
43+
check_dependency systemctl
44+
45+
if [[ ! -d "$REPO_DIR" ]]; then
46+
log_error "Repository directory not found: ${REPO_DIR}"
47+
exit 1
48+
fi
49+
50+
cd "$REPO_DIR"
51+
52+
log_info "Pulling latest code from branch '${BRANCH}'..."
53+
git pull origin "$BRANCH"
54+
log_info "Code updated successfully."
55+
56+
log_info "Restarting service '${SERVICE}'..."
57+
systemctl restart "$SERVICE"
58+
59+
if systemctl is-active --quiet "$SERVICE"; then
60+
log_info "'${SERVICE}' restarted successfully."
2661
else
27-
echo "Failed to update code. Deployment aborted."
62+
log_error "'${SERVICE}' failed to start. Check: journalctl -u ${SERVICE}"
63+
exit 2
2864
fi

β€Žscripts/backup.shβ€Ž

Lines changed: 55 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,56 @@
11
#!/bin/bash
2-
# Script to backup system files weekly
3-
4-
# Set backup directories and files
5-
backup_dir="/var/backups"
6-
backup_files="/etc /var/www /home /var/lib /var/mail /opt"
7-
8-
# Set the date and time for the backup
9-
day=$(date +%Y-%m-%d)
10-
hostname=$(hostname -s)
11-
archive_file="$hostname-$day.tgz"
12-
13-
# Create the backup directory if it does not exist
14-
if [ ! -d $backup_dir ]; then
15-
mkdir -p $backup_dir
16-
fi
17-
18-
# Create the backup archive
19-
tar czf $backup_dir/$archive_file $backup_files
20-
21-
# Print the backup status
22-
echo "Backup of $backup_files completed! Details about the output backup file:"
23-
ls -lh $backup_dir/$archive_file
24-
echo "Backup completed on $(date)"
25-
echo "Backup script completed"
2+
# backup.sh β€” Create a compressed archive backup of system directories.
3+
# Usage: ./backup.sh [options]
4+
set -euo pipefail
5+
6+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
7+
source "${SCRIPT_DIR}/lib/utils.sh"
8+
9+
BACKUP_DIR="${BACKUP_DIR:-/var/backups}"
10+
BACKUP_FILES="${BACKUP_FILES:-/etc /var/www /home /var/lib /var/mail /opt}"
11+
12+
usage() {
13+
cat <<EOF
14+
Usage: $(basename "$0") [options]
15+
16+
Create a timestamped .tgz archive backup of configured directories.
17+
18+
Options:
19+
--dest DIR Backup destination directory (env: BACKUP_DIR, default: ${BACKUP_DIR})
20+
--src PATHS Space-separated list of paths to back up
21+
(env: BACKUP_FILES, default: ${BACKUP_FILES})
22+
-h, --help Show this help message
23+
24+
Examples:
25+
$(basename "$0")
26+
$(basename "$0") --dest /mnt/nas/backups --src "/etc /home"
27+
EOF
28+
exit 0
29+
}
30+
31+
while [[ $# -gt 0 ]]; do
32+
case "$1" in
33+
--dest) BACKUP_DIR="$2"; shift 2 ;;
34+
--src) BACKUP_FILES="$2"; shift 2 ;;
35+
-h|--help) usage ;;
36+
*) log_error "Unknown option: $1"; usage ;;
37+
esac
38+
done
39+
40+
check_dependency tar
41+
42+
DAY=$(date +%Y-%m-%d)
43+
HOSTNAME=$(hostname -s)
44+
ARCHIVE_FILE="${HOSTNAME}-${DAY}.tgz"
45+
46+
mkdir -p "${BACKUP_DIR}"
47+
48+
log_info "Starting backup to ${BACKUP_DIR}/${ARCHIVE_FILE}..."
49+
log_info "Source paths: ${BACKUP_FILES}"
50+
51+
# Word-split BACKUP_FILES intentionally β€” it is a space-delimited path list
52+
# shellcheck disable=SC2086
53+
tar czf "${BACKUP_DIR}/${ARCHIVE_FILE}" ${BACKUP_FILES}
54+
55+
log_info "Backup completed successfully."
56+
ls -lh "${BACKUP_DIR}/${ARCHIVE_FILE}"

0 commit comments

Comments
Β (0)