Skip to content

Commit 468a774

Browse files
committed
docs: Phase 6 — CONTRIBUTING.md, pre-commit config, SECURITY.md, updated README
- Add CONTRIBUTING.md: full contributor guide with bash 3.2 compat table, usage() pattern, test path depth rules, stubbing guidelines, PR checklist - Add .pre-commit-config.yaml: ShellCheck hook via koalaman/shellcheck-precommit - Add SECURITY.md: vulnerability reporting, secrets hygiene, contributor best practices - README: update badges (CI, ShellCheck, 265 tests, 44 scripts), add 10 new Phase 5 scripts to Backup, DevOps, Monitoring, Container/Kubernetes, Utilities tables, fix Prerequisites to reflect bash 3.2+ compatibility
1 parent 2e7b390 commit 468a774

4 files changed

Lines changed: 403 additions & 5 deletions

File tree

.pre-commit-config.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
repos:
2+
- repo: https://github.com/koalaman/shellcheck-precommit
3+
rev: v0.10.0
4+
hooks:
5+
- id: shellcheck
6+
name: ShellCheck
7+
args: [--severity=warning]
8+
types: [shell]

CONTRIBUTING.md

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
# Contributing to bash-scripts
2+
3+
Thank you for your interest in contributing! This guide covers everything you need to add scripts, fix bugs, or improve the test suite.
4+
5+
---
6+
7+
## Quick Start
8+
9+
```bash
10+
# Clone the repo
11+
git clone https://github.com/wesleyscholl/bash-scripts.git
12+
cd bash-scripts
13+
14+
# Install BATS test framework (submodules are already committed)
15+
# Run the full test suite
16+
bats $(find tests -name '*.bats' -not -path '*/test_helper/*' | sort)
17+
```
18+
19+
---
20+
21+
## Repository Layout
22+
23+
```
24+
bash-scripts/
25+
├── scripts/
26+
│ ├── lib/
27+
│ │ └── utils.sh # Shared helpers — log_info, log_error, check_dependency
28+
│ ├── backup/ # Backup & data-protection scripts
29+
│ ├── ci-cd/ # CI/CD pipeline scripts
30+
│ ├── devops/ # Docker, Git, infrastructure scripts
31+
│ ├── kubernetes/ # kubectl / k8s scripts
32+
│ ├── monitoring/ # Alerting and observability scripts
33+
│ ├── notifications/ # Slack, email, and log aggregation
34+
│ ├── system/ # OS-level health and resource scripts
35+
│ └── utils/ # General-purpose utilities
36+
└── tests/
37+
├── test_helper/ # BATS support libraries (bats-support, bats-assert)
38+
├── utils.bats # Tests for lib/utils.sh
39+
└── <category>/ # One .bats file per script, mirroring scripts/
40+
```
41+
42+
---
43+
44+
## Adding a New Script
45+
46+
### 1. Choose the right category directory
47+
48+
| Category | Use for |
49+
|---|---|
50+
| `backup/` | Data backup, dump, rotation |
51+
| `ci-cd/` | Build pipelines, deployment automation |
52+
| `devops/` | Docker, Git, infrastructure provisioning |
53+
| `kubernetes/` | kubectl operations, pod management |
54+
| `monitoring/` | Alerting, health checks, cost monitoring |
55+
| `notifications/` | Slack, email, log aggregation |
56+
| `system/` | OS resources, process management |
57+
| `utils/` | General-purpose helpers, secret management |
58+
59+
### 2. Use the standard script template
60+
61+
Every script **must** follow this structure:
62+
63+
```bash
64+
#!/bin/bash
65+
# script-name.sh — One-line description
66+
set -euo pipefail
67+
68+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
69+
# shellcheck source=../lib/utils.sh
70+
source "${SCRIPT_DIR}/../lib/utils.sh"
71+
72+
# --- default values ---
73+
MY_FLAG=""
74+
DRY_RUN=false
75+
76+
usage() {
77+
cat <<EOF
78+
Usage: $(basename "$0") [options]
79+
80+
Short description of what this script does.
81+
82+
Options:
83+
--my-flag VALUE Description (env: MY_ENV_VAR)
84+
--dry-run Show what would happen, make no changes
85+
-h, --help Show this help message
86+
87+
Examples:
88+
$(basename "$0") --my-flag value
89+
$(basename "$0") --dry-run
90+
EOF
91+
}
92+
93+
while [[ $# -gt 0 ]]; do
94+
case "$1" in
95+
--my-flag) MY_FLAG="$2"; shift 2 ;;
96+
--dry-run) DRY_RUN=true; shift ;;
97+
-h|--help) usage; exit 0 ;;
98+
*) log_error "Unknown option: $1"; usage; exit 1 ;;
99+
esac
100+
done
101+
102+
# --- validate required args ---
103+
if [[ -z "$MY_FLAG" ]]; then
104+
log_error "--my-flag is required."
105+
usage
106+
exit 1
107+
fi
108+
109+
# --- main logic ---
110+
if [[ "$DRY_RUN" == "true" ]]; then
111+
log_info "[dry-run] Would do X with ${MY_FLAG}."
112+
exit 0
113+
fi
114+
115+
# do the real work here
116+
117+
exit 0
118+
```
119+
120+
### 3. Key rules
121+
122+
- `set -euo pipefail` — mandatory on every script.
123+
- **Never put `exit` inside `usage()`**. Call `usage; exit 0` or `usage; exit 1` at the call sites.
124+
- Exit codes: `0` = success, `1` = bad user input / missing argument, `2` = runtime / system error.
125+
- Accept `--dry-run` on any script that modifies state.
126+
- Accept `--help` / `-h` that prints a usage example.
127+
- For `--quiet` support, redirect `log_info` calls behind a flag check where appropriate.
128+
- Source `utils.sh` using `"${SCRIPT_DIR}/../lib/utils.sh"` (scripts live one level below `scripts/`).
129+
- Make executable: `chmod +x scripts/<category>/your-script.sh`.
130+
131+
### 4. Bash 3.2 compatibility (macOS default shell)
132+
133+
macOS ships with bash 3.2. Avoid:
134+
135+
| Dangerous | Safe alternative |
136+
|---|---|
137+
| `mapfile` / `readarray` | `while IFS= read -r line; do arr+=("$line"); done < <(cmd)` |
138+
| Empty array under `set -u`: `"${arr[@]}"` | Always pre-populate arrays, or check `"${#arr[@]}" -gt 0` first |
139+
| `[[ str =~ regex ]]` with complex regex | Use `grep -qE` or `awk` |
140+
141+
---
142+
143+
## Adding Tests
144+
145+
Every new script **requires** a corresponding BATS test file.
146+
147+
### Test file location & naming
148+
149+
```
150+
scripts/monitoring/my-alert.sh → tests/monitoring/my-alert.bats
151+
```
152+
153+
### Standard test file structure
154+
155+
```bash
156+
#!/usr/bin/env bats
157+
load "${BATS_TEST_DIRNAME}/../test_helper/bats-support/load"
158+
load "${BATS_TEST_DIRNAME}/../test_helper/bats-assert/load"
159+
160+
setup() {
161+
export SCRIPT_PATH="${BATS_TEST_DIRNAME}/../../scripts/<category>/my-script.sh"
162+
export BINSTUB="${BATS_TEST_TMPDIR}/bin"
163+
mkdir -p "$BINSTUB"
164+
165+
# Create stubs for external commands (kubectl, aws, docker, etc.)
166+
cat > "${BINSTUB}/mycmd" <<'STUB'
167+
#!/bin/bash
168+
echo "stub output"
169+
exit 0
170+
STUB
171+
chmod +x "${BINSTUB}/mycmd"
172+
173+
export PATH="${BINSTUB}:${PATH}"
174+
}
175+
176+
# Required tests — every script needs these four:
177+
@test "script exists and is executable" {
178+
[ -f "$SCRIPT_PATH" ]
179+
[ -x "$SCRIPT_PATH" ]
180+
}
181+
182+
@test "--help exits 0 and prints usage" {
183+
run "$SCRIPT_PATH" --help
184+
assert_success
185+
assert_output --partial "Usage:"
186+
}
187+
188+
@test "exits 1 without required argument" {
189+
run "$SCRIPT_PATH"
190+
assert_failure
191+
}
192+
193+
@test "set -euo pipefail is present" {
194+
grep -q 'set -euo pipefail' "$SCRIPT_PATH"
195+
}
196+
197+
# Add behavioural tests below:
198+
@test "dry-run exits 0 and prints dry-run message" {
199+
run "$SCRIPT_PATH" --required-arg value --dry-run
200+
assert_success
201+
assert_output --partial "dry-run"
202+
}
203+
```
204+
205+
### Path depth rules
206+
207+
```
208+
tests/utils.bats → test_helper at tests/test_helper/
209+
scripts at scripts/
210+
211+
tests/subdir/foo.bats → test_helper at ${BATS_TEST_DIRNAME}/../test_helper/ (one level up)
212+
scripts at ${BATS_TEST_DIRNAME}/../../scripts/ (two levels up)
213+
```
214+
215+
### Stubbing external commands
216+
217+
- Create executable stubs in `${BATS_TEST_TMPDIR}/bin/` and prepend to `$PATH`.
218+
- Stubs should return appropriate exit codes and predictable output.
219+
- Never require live external services (AWS, GCP, Kubernetes) in tests.
220+
- Use `teardown()` if you create files outside `BATS_TEST_TMPDIR`.
221+
222+
---
223+
224+
## Running Tests
225+
226+
```bash
227+
# Full suite
228+
find tests -name '*.bats' -not -path '*/test_helper/*' | sort | xargs bats
229+
230+
# Single file
231+
bats tests/monitoring/aws-cost-alert.bats
232+
233+
# Single category
234+
bats tests/kubernetes/
235+
236+
# Verbose (shows test names as they run)
237+
find tests -name '*.bats' -not -path '*/test_helper/*' | sort | xargs bats --tap
238+
```
239+
240+
---
241+
242+
## Linting
243+
244+
All scripts are linted with [ShellCheck](https://www.shellcheck.net/). Install it and run:
245+
246+
```bash
247+
shellcheck scripts/**/*.sh scripts/lib/utils.sh
248+
```
249+
250+
The CI pipeline runs ShellCheck on every pull request and fails on any warning.
251+
252+
---
253+
254+
## Commit Message Format
255+
256+
This repo follows [Conventional Commits](https://www.conventionalcommits.org/):
257+
258+
```
259+
type(scope): short description
260+
261+
Body (optional) — explain why, not what.
262+
```
263+
264+
| Type | Use for |
265+
|---|---|
266+
| `feat` | New script or feature |
267+
| `fix` | Bug fix in a script or test |
268+
| `test` | New or updated BATS tests only |
269+
| `docs` | Documentation only |
270+
| `refactor` | Code change with no behaviour change |
271+
| `chore` | CI, tooling, dependency updates |
272+
273+
**Scope** = the script name or category (e.g. `feat(db-backup)`, `fix(monitoring)`, `test(kubernetes)`).
274+
275+
---
276+
277+
## Pull Request Checklist
278+
279+
Before opening a PR, verify:
280+
281+
- [ ] New script follows the standard template (see above).
282+
- [ ] `set -euo pipefail` present.
283+
- [ ] `--help` works and includes an example.
284+
- [ ] `--dry-run` implemented for any state-modifying script.
285+
- [ ] Script is executable (`chmod +x`).
286+
- [ ] Corresponding `.bats` test file exists in the matching `tests/<category>/` directory.
287+
- [ ] All four required tests are present (exists, --help, missing-arg, set -euo).
288+
- [ ] Full suite passes locally: `find tests -name '*.bats' -not -path '*/test_helper/*' | sort | xargs bats`.
289+
- [ ] `shellcheck` produces zero warnings on the new/modified script.
290+
- [ ] Commit message follows Conventional Commits format.

README.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44

55
A comprehensive collection of production-ready Bash scripts for DevOps engineers, system administrators, and automation enthusiasts. These scripts handle everything from system monitoring and backups to Kubernetes management and CI/CD integrations.
66

7+
[![CI](https://github.com/wesleyscholl/bash-scripts/actions/workflows/ci.yml/badge.svg)](https://github.com/wesleyscholl/bash-scripts/actions/workflows/ci.yml)
8+
[![ShellCheck](https://img.shields.io/badge/ShellCheck-passing-brightgreen.svg)](https://www.shellcheck.net/)
9+
[![Tests](https://img.shields.io/badge/Tests-265%20passing-brightgreen.svg)](tests/)
10+
[![Scripts](https://img.shields.io/badge/Scripts-44%20production--ready-blue.svg)](scripts/)
711
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
812
[![Shell](https://img.shields.io/badge/Shell-Bash-green.svg)](https://www.gnu.org/software/bash/)
9-
[![Test Coverage](https://img.shields.io/badge/Test%20Coverage-100%25-brightgreen.svg)](tests/)
10-
[![Tests](https://img.shields.io/badge/Tests-443%20total%2C%20434%20passing-success.svg)](tests/)
1113

1214
<img width="600" alt="bash" src="https://github.com/user-attachments/assets/2bd21a84-eac3-4309-9404-3b21bf31ac26" />
1315

@@ -54,8 +56,11 @@ This repository contains battle-tested Bash scripts designed to automate common
5456
| `argo-cd-sync.sh` | Synchronizes ArgoCD applications |
5557
| `auto-deployment.sh` | Automates application deployment workflows |
5658
| `sonarqube-slack-notify.sh` | Sends SonarQube analysis results to Slack |
59+
| `terraform-plan-notify.sh` | Runs `terraform plan` and posts the summary to Slack |
5760
| `create-confluence-page.sh` | Creates and updates Confluence documentation pages |
5861
| `git-repo-stats.sh` | Generates comprehensive Git repository statistics |
62+
| `git-cleanup-merged.sh` | Deletes merged local (and optionally remote) branches |
63+
| `docker-image-prune.sh` | Prunes dangling or unused Docker images by age/label |
5964

6065
### Monitoring & Alerting
6166

@@ -67,8 +72,10 @@ This repository contains battle-tested Bash scripts designed to automate common
6772
| `splunk-search.sh` | Performs automated Splunk log searches |
6873
| `check-ssl-expiry.sh` | Monitors SSL certificate expiration dates |
6974
| `docker-log-monitor.sh` | Monitors and analyzes Docker container logs |
70-
| `log-monitor.sh` | Monitors log files for keywords with real-time alerts and email notifications |
71-
| `system-resource-reporter.sh` | Generates comprehensive system resource reports in multiple formats |
75+
| `log-monitor.sh` | Monitors log files for keywords with real-time alerts |
76+
| `system-resource-reporter.sh` | Generates comprehensive system resource reports |
77+
| `aws-cost-alert.sh` | Queries AWS Cost Explorer and alerts via Slack when spend exceeds a threshold |
78+
| `cert-auto-renew.sh` | Runs `certbot renew` and reloads the web server only when a cert is renewed |
7279

7380
### Backup & Recovery
7481

@@ -80,6 +87,7 @@ This repository contains battle-tested Bash scripts designed to automate common
8087
| `rotate-old-files.sh` | Implements file rotation policies |
8188
| `log-rotation.sh` | Manages log file rotation and archival |
8289
| `log-file-cleanup.sh` | Cleans up old log files based on retention policies |
90+
| `db-backup.sh` | Dumps MySQL or PostgreSQL databases with gzip compression and retention rotation |
8391

8492
### Container & Kubernetes
8593

@@ -89,16 +97,20 @@ This repository contains battle-tested Bash scripts designed to automate common
8997
| `scale-deployment.sh` | Scales Kubernetes deployments automatically |
9098
| `restart-containers.sh` | Restarts Docker containers based on criteria |
9199
| `gc-cleanup.sh` | Performs garbage collection and cleanup tasks |
100+
| `k8s-pod-logs-export.sh` | Exports logs from all pods in a namespace to individual timestamped files |
101+
| `service-discovery.sh` | Lists all services in a k8s namespace with type, cluster IP, ports, and optional endpoints |
92102

93103
### Utilities
94104

95105
| Script | Description |
96106
|--------|-------------|
97107
| `random-password-generator.sh` | Generates secure random passwords |
108+
| `log-aggregator.sh` | Tails multiple log files into one aggregated output with timestamps and source labels |
109+
| `secret-rotation.sh` | Rotates a secret in AWS Secrets Manager or HashiCorp Vault |
98110

99111
## 🔧 Prerequisites
100112

101-
- Bash 4.0 or higher
113+
- Bash 3.2+ (macOS-compatible; scripts are compatible with bash 3.2 and higher)
102114
- Standard Unix utilities (grep, awk, sed, etc.)
103115
- **Testing Framework**: BATS (Bash Automated Testing System) for running tests
104116
- Specific tools required by individual scripts:

0 commit comments

Comments
 (0)