@objctp/opencode-shell-routines 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +114 -0
  3. package/agents/shell-architect.md +88 -0
  4. package/agents/shell-expert.md +60 -0
  5. package/commands/shell-audit.md +47 -0
  6. package/commands/shell-batch-exec.md +48 -0
  7. package/commands/shell-new.md +57 -0
  8. package/commands/shell-routines-setup.md +66 -0
  9. package/commands/shell-test-run.md +46 -0
  10. package/opencode.json +19 -0
  11. package/package.json +34 -0
  12. package/plugins/shell-hooks.ts +150 -0
  13. package/scripts/lib-batch.sh +297 -0
  14. package/scripts/lib-common.sh +332 -0
  15. package/skills/shell-batch-operations/SKILL.md +97 -0
  16. package/skills/shell-batch-operations/assets/batch-template.sh +124 -0
  17. package/skills/shell-batch-operations/examples/data-pipeline.sh +157 -0
  18. package/skills/shell-batch-operations/examples/file-batch.sh +140 -0
  19. package/skills/shell-batch-operations/references/decision-tree.md +53 -0
  20. package/skills/shell-best-practices/SKILL.md +313 -0
  21. package/skills/shell-best-practices/assets/library.sh +142 -0
  22. package/skills/shell-best-practices/assets/minimal.sh +54 -0
  23. package/skills/shell-best-practices/assets/posix.sh +180 -0
  24. package/skills/shell-best-practices/assets/standard.sh +203 -0
  25. package/skills/shell-best-practices/references/patterns.md +386 -0
  26. package/skills/shell-best-practices/references/security.md +195 -0
  27. package/skills/shell-debugging/SKILL.md +115 -0
  28. package/skills/shell-debugging/examples/debug-session.md +165 -0
  29. package/skills/shell-debugging/references/debugging-guide.md +336 -0
  30. package/skills/shell-profiling/SKILL.md +154 -0
  31. package/skills/shell-profiling/examples/profile-session.md +225 -0
  32. package/skills/shell-profiling/references/optimisation-patterns.md +373 -0
  33. package/skills/shell-profiling/references/profiling-tools.md +318 -0
  34. package/skills/shell-profiling/scripts/bench.sh +82 -0
  35. package/skills/shell-profiling/scripts/trace-aggregate.sh +34 -0
  36. package/skills/shell-review/SKILL.md +61 -0
  37. package/skills/shell-review/examples/sample-review.md +42 -0
  38. package/skills/shell-review/references/guidelines.md +48 -0
  39. package/skills/shell-review/references/review-template.md +56 -0
  40. package/skills/shell-security/SKILL.md +128 -0
  41. package/skills/shell-security/examples/dangerous-command-review.md +231 -0
  42. package/skills/shell-security/examples/secure-script-example.sh +317 -0
  43. package/skills/shell-security/references/dangerous-commands.md +561 -0
  44. package/skills/shell-security/references/security-patterns.md +30 -0
  45. package/skills/shell-security/references/sensitive-files.md +525 -0
  46. package/skills/shell-security/scripts/security-audit.sh +208 -0
  47. package/skills/shell-test/SKILL.md +237 -0
  48. package/skills/shell-test/examples/test-example.md +74 -0
  49. package/skills/shell-test/references/advanced-patterns.md +52 -0
  50. package/skills/shell-test/references/assertions.md +184 -0
  51. package/skills/shell-test/references/test-template.md +60 -0
  52. package/skills/shell-test/scripts/public-coverage.sh +93 -0
@@ -0,0 +1,128 @@
1
+ ---
2
+ name: shell-security
3
+ description: Audit a bash script for security risks the linters miss: destructive commands, system-file writes, hardcoded credentials, insecure permissions, and dynamic execution (eval/source). Run the bundled detector, classify each finding by severity, and offer safer fixes on approval. Use when checking a script's safety ("audit for vulnerabilities", "is this safe?", "secure this script"). For quoting and general standards use shell-best-practices; for overall quality review use shell-review.
4
+ allowed-tools: Read, Grep, Bash, Write, Edit
5
+ argument-hint: [script-path]
6
+ ---
7
+
8
+ # Shell Security Skill
9
+
10
+ Analyse bash scripts for security vulnerabilities, warn about risks, and automatically fix issues with safer alternatives upon approval.
11
+
12
+ ## Target
13
+
14
+ **Target script:** `$ARGUMENTS`
15
+
16
+ If `$ARGUMENTS` is not provided, prompt the user to specify which script to audit. If `$ARGUMENTS` is a directory, scan each `.sh` file in that directory.
17
+
18
+ ## How It Works
19
+
20
+ 1. **Read the script** -- Understand purpose and context
21
+ 2. **Run `scripts/security-audit.sh "$TARGET"`** -- Do not replicate its grep patterns manually; always use the script
22
+ 3. **Interpret results** -- Consult all `references/` files (`dangerous-commands.md`, `security-patterns.md`, `sensitive-files.md`) and `examples/` (`secure-script-example.sh` for safer patterns, `dangerous-command-review.md` for output format) for context; categorise as Fatal/Severe/Moderate. For dynamic execution findings (`eval`/`source` with variables), classify each as **by design** (developer tool inherently executes code), **needs review** (handles untrusted input), or **safe** (variable is internally generated). Report "by design" findings as informational, not actionable issues. See the Assessment guide in `references/dangerous-commands.md` under the Dynamic Execution section.
23
+ 4. **Warn with context** -- Explain risk, provide line number, suggest safer alternative
24
+ 5. **Offer to fix** -- For fixable issues, offer to apply safer alternatives
25
+ 6. **Confirm before modifying** -- Always ask for approval before applying any fix
26
+
27
+ **Done when** every detector category has run via `scripts/security-audit.sh`; each finding has a line, severity (Fatal/Severe/Moderate), and safer alternative; every dynamic-execution finding is classified (by design / needs review / safe); and no fix is applied without explicit approval.
28
+
29
+ ## Scope
30
+
31
+ This skill covers **destructive commands, credentials, sensitive files, insecure permissions, and dynamic execution patterns**. For quoting and general best practices, use shell-best-practices instead. For overall quality review, use shell-review instead.
32
+
33
+ ## What It Checks (Unique Coverage)
34
+
35
+ | Category | Examples | Already Covered By |
36
+ | --------------------------- | ---------------------------------------------------- | ------------------ |
37
+ | **Destructive commands** | `rm -rf /`, `dd`, fork bombs, `chmod 777` | UNIQUE |
38
+ | **System file risks** | Editing `/etc/passwd`, `/etc/sudoers`, `/etc/shadow` | UNIQUE |
39
+ | **Credential exposure** | Hardcoded API keys, secrets in code | UNIQUE |
40
+ | **Sensitive file patterns** | `.env`, `.pem`, `.key`, credentials files | UNIQUE |
41
+ | **Dynamic execution** | `eval` with variables, dynamic `source`, indirect commands | UNIQUE |
42
+
43
+ **NOT covered here** (use existing tools):
44
+ | Issue | Use Instead |
45
+ |-------|-------------|
46
+ | Unquoted variables | ShellCheck, shell-best-practices |
47
+ | Pipe to `sh`/`bash` | shell-best-practices |
48
+ | Temp file issues | shell-best-practices |
49
+ | Syntax errors | bash -n hook |
50
+ | Formatting | shfmt hook |
51
+
52
+ ## Auto-Fix Behaviour
53
+
54
+ **Auto-fixable issues** (applied upon approval):
55
+
56
+ - Add `--preserve-root` to rm commands
57
+ - Replace hardcoded credentials with environment variables
58
+ - Add confirmation prompts to dangerous commands
59
+ - Replace `chmod 777` with specific permissions
60
+ - Add guards before system file operations
61
+
62
+ **Requires manual review**:
63
+
64
+ - Fork bomb patterns (need architecture review)
65
+ - Destructive commands with variable paths
66
+ - System file modifications (needs intent clarification)
67
+
68
+ **Always confirm before modifying** -- even for auto-fixable issues, the workflow is:
69
+
70
+ 1. Show the dangerous code
71
+ 2. Explain the risk
72
+ 3. Show the safer alternative
73
+ 4. Prompt the user for approval before applying the fix
74
+
75
+ ## Integration
76
+
77
+ **How shell-security fits with existing tooling:**
78
+
79
+ ```
80
+ ┌─────────────────────────────────────────────────────────────────────┐
81
+ │ EXISTING TOOLING (runs first) │
82
+ ├─────────────────────────────────────────────────────────────────────┤
83
+ │ Hooks (PostToolUse): ShellCheck │ shfmt │ bash -n │
84
+ │ LSP: bash-language-server (real-time) │
85
+ │ Skills: shell-best-practices (eval, quoting, temp) │
86
+ └─────────────────────────────────────────────────────────────────────┘
87
+
88
+
89
+ ┌─────────────────────────────────────────────────────────────────────┐
90
+ │ shell-security (UNIQUE coverage only) │
91
+ ├─────────────────────────────────────────────────────────────────────┤
92
+ │ Focus: Destructive commands │ System files │ Credentials │ 777 │
93
+ │ Action: Warn + Auto-fix (with permission) │
94
+ └─────────────────────────────────────────────────────────────────────┘
95
+
96
+
97
+ ┌─────────────────────────────────────────────────────────────────────┐
98
+ │ shell-review (final output) │
99
+ ├─────────────────────────────────────────────────────────────────────┤
100
+ │ Consolidates: ShellCheck + shell-security + other findings │
101
+ │ Output: Structured review with severity categories │
102
+ └─────────────────────────────────────────────────────────────────────┘
103
+ ```
104
+
105
+ **Key point**: shell-security does NOT duplicate what ShellCheck/shell-best-practices already catch. It focuses on:
106
+
107
+ - **Destructive command severity** ([FATAL]/[SEVERE]/[MODERATE]) with security context
108
+ - **System file awareness** (knows `/etc/passwd` is sensitive)
109
+ - **Credential detection** (recognises API keys, secrets)
110
+ - **Dynamic execution detection** (flags eval/source with variable arguments)
111
+ - **Auto-fix capability** (can apply safer alternatives)
112
+
113
+ ## References
114
+
115
+ - `references/dangerous-commands.md` -- Catalogue of destructive commands with risk levels and safer alternatives
116
+ - `references/security-patterns.md` -- Conceptual map of detection categories and auto-fix status
117
+ - `references/sensitive-files.md` -- Files that require careful handling
118
+
119
+ Always read all references and examples before producing audit results.
120
+
121
+ ## Examples
122
+
123
+ - `examples/dangerous-command-review.md` -- Sample review output with remediation
124
+ - `examples/secure-script-example.sh` -- Secure coding reference
125
+
126
+ ## Scripts
127
+
128
+ - `scripts/security-audit.sh` -- Reusable audit script that runs all detection grep patterns against a target file or directory.
@@ -0,0 +1,231 @@
1
+ # Dangerous Command Review Example
2
+
3
+ This example demonstrates how the `shell-security` skill reviews a script containing dangerous commands and offers fixes.
4
+
5
+ ## Input Script
6
+
7
+ ```bash
8
+ #!/usr/bin/env bash
9
+ # deploy.sh - Deploy application to production
10
+
11
+ set -e
12
+
13
+ # Configuration
14
+ TARGET_DIR="/var/www/app"
15
+ BACKUP_DIR="/var/backups/app"
16
+ API_KEY="sk-1234567890abcdefghijklmnop"
17
+ DB_PASSWORD="SuperSecretPass123"
18
+
19
+ # Clean previous deployment
20
+ rm -rf /var/www/app_old
21
+ rm -rf $TARGET_DIR
22
+
23
+ # Create backup
24
+ tar -czf "$BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz" "$TARGET_DIR"
25
+
26
+ # Extract new files
27
+ tar -xzf deploy.tar.gz -C "$TARGET_DIR"
28
+
29
+ # Set permissions
30
+ chmod -R 777 "$TARGET_DIR"
31
+
32
+ # Update database
33
+ mysql -u root -p"$DB_PASSWORD" -e "UPDATE users SET active=1"
34
+
35
+ # Clean up temporary files
36
+ find / -name "*.tmp" -exec rm {} \;
37
+
38
+ # Restart service
39
+ systemctl restart app-service
40
+ ```
41
+
42
+ ## Review Output
43
+
44
+ ```
45
+ Scanning deploy.sh for security issues (unique coverage)...
46
+
47
+ Found 6 issues:
48
+
49
+ 1. ◆ Line 13: rm -rf targeting system directory
50
+ What: rm -rf /var/www/app_old
51
+ Risk: Deletes directory without validation, could delete wrong path
52
+ Fix: Add validation and --preserve-root flag
53
+ [Apply fix] [Show diff] [Skip]
54
+
55
+ Proposed fix:
56
+ ```bash
57
+ [[ -d "/var/www/app_old" ]] || { echo "Directory not found" >&2; exit 1; }
58
+ rm -rf --preserve-root /var/www/app_old
59
+ ```
60
+
61
+ 2. ● Line 14: Unquoted variable in rm command
62
+ What: rm -rf $TARGET_DIR
63
+ Risk: If TARGET_DIR is empty, may delete unexpected files
64
+ Fix: Quote variable and add --preserve-root
65
+ [Apply fix] [Show diff] [Skip]
66
+
67
+ Proposed fix:
68
+ ```bash
69
+ rm -rf --preserve-root "$TARGET_DIR"
70
+ ```
71
+
72
+ 3. ● Line 9: Hardcoded API key
73
+ What: API_KEY="sk-1234567890abcdefghijklmnop"
74
+ Risk: Credential exposed in version control
75
+ Fix: Use environment variable
76
+ [Apply fix] [Show diff] [Skip]
77
+
78
+ Proposed fix:
79
+ ```bash
80
+ API_KEY="${API_KEY:?API_KEY environment variable not set}"
81
+ ```
82
+
83
+ 4. ● Line 10: Hardcoded database password
84
+ What: DB_PASSWORD="SuperSecretPass123"
85
+ Risk: Credential exposed in version control
86
+ Fix: Use environment variable or credential store
87
+ [Apply fix] [Show diff] [Skip]
88
+
89
+ Proposed fix:
90
+ ```bash
91
+ # Use MySQL config file instead
92
+ db_password="${DB_PASSWORD:?DB_PASSWORD not set}"
93
+ mysql -u root -p"$db_password" -e "..."
94
+ # OR: use ~/.my.cnf for credentials
95
+ ```
96
+
97
+ 5. ● Line 23: chmod 777 on application directory
98
+ What: chmod -R 777 "$TARGET_DIR"
99
+ Risk: Makes directory world-writable, security vulnerability
100
+ Fix: Use specific permissions (755 for dirs, 644 for files)
101
+ [Apply fix] [Show diff] [Skip]
102
+
103
+ Proposed fix:
104
+ ```bash
105
+ find "$TARGET_DIR" -type d -exec chmod 755 {} \;
106
+ find "$TARGET_DIR" -type f -exec chmod 644 {} \;
107
+ ```
108
+
109
+ 6. ▲ Line 29: find from root directory
110
+ What: find / -name "*.tmp" -exec rm {} \;
111
+ Risk: Searches entire filesystem, slow and risky
112
+ Fix: Limit search scope to specific directories
113
+ [Apply fix] [Show diff] [Skip]
114
+
115
+ Proposed fix:
116
+ ```bash
117
+ find "$TARGET_DIR" -name "*.tmp" -delete
118
+ find /tmp -maxdepth 1 -name "*.tmp" -delete
119
+ ```
120
+
121
+ ---
122
+ Severity Summary:
123
+ ◆ Fatal: 1
124
+ ● Severe: 4
125
+ ▲ Moderate: 1
126
+
127
+ Note: ShellCheck will catch other issues (unquoted variables on line 26, etc.)
128
+ Run shellcheck deploy.sh for additional linting.
129
+ ```
130
+
131
+ ## Remediation Workflow
132
+
133
+ When the user selects `[Apply fix]` for all issues:
134
+
135
+ ```
136
+ ✔ Applying fixes...
137
+
138
+ 1. ✔ Added validation to rm -rf /var/www/app_old
139
+ 2. ✔ Added quotes and --preserve-root to rm -rf $TARGET_DIR
140
+ 3. ✔ Replaced hardcoded API_KEY with environment variable
141
+ 4. ✔ Replaced hardcoded DB_PASSWORD with environment variable
142
+ 5. ✔ Replaced chmod 777 with specific permissions
143
+ 6. ✔ Limited find scope to TARGET_DIR
144
+
145
+ All fixes applied. Review the changes:
146
+ git diff deploy.sh
147
+ ```
148
+
149
+ ## Fixed Script
150
+
151
+ ```bash
152
+ #!/usr/bin/env bash
153
+ # deploy.sh - Deploy application to production
154
+
155
+ set -euo pipefail
156
+
157
+ # Configuration - use environment variables for secrets
158
+ : "${TARGET_DIR:=/var/www/app}"
159
+ : "${BACKUP_DIR:=/var/backups/app}"
160
+ : "${API_KEY:?API_KEY environment variable not set}"
161
+ : "${DB_PASSWORD:?DB_PASSWORD environment variable not set}"
162
+
163
+ # Validate directories exist
164
+ for dir in "$TARGET_DIR" "$BACKUP_DIR"; do
165
+ [[ -d "$dir" ]] || { echo "Error: Directory not found: $dir" >&2; exit 1; }
166
+ done
167
+
168
+ # Clean previous deployment (with validation)
169
+ if [[ -d "/var/www/app_old" ]]; then
170
+ rm -rf --preserve-root /var/www/app_old
171
+ fi
172
+
173
+ # Create backup
174
+ tar -czf "$BACKUP_DIR/backup-$(date +%Y%m%d).tar.gz" "$TARGET_DIR"
175
+
176
+ # Extract new files
177
+ tar -xzf deploy.tar.gz -C "$TARGET_DIR"
178
+
179
+ # Set permissions (specific, not 777)
180
+ find "$TARGET_DIR" -type d -exec chmod 755 {} \;
181
+ find "$TARGET_DIR" -type f -exec chmod 644 {} \;
182
+
183
+ # Update database (credentials from environment)
184
+ mysql -u root -p"$DB_PASSWORD" -e "UPDATE users SET active=1"
185
+
186
+ # Clean up temporary files (limited scope)
187
+ find "$TARGET_DIR" -name "*.tmp" -delete
188
+ find /tmp -maxdepth 1 -name "*.tmp" -delete
189
+
190
+ # Restart service
191
+ systemctl restart app-service
192
+ ```
193
+
194
+ ## Additional ShellCheck Findings
195
+
196
+ After shell-security fixes, ShellCheck may report:
197
+
198
+ ```
199
+ Line 35: mysql -u root -p"$DB_PASSWORD" -e "..."
200
+ ^-- SC2154: DB_PASSWORD is referenced but not assigned.
201
+ (This is expected - we require it as environment variable)
202
+
203
+ Line 35: mysql -u root -p"$DB_PASSWORD" -e "..."
204
+ ^-- SC2016: Expressions don't expand in single quotes.
205
+ (Use double quotes for variable expansion in command)
206
+ ```
207
+
208
+ ## Warning Format Template
209
+
210
+ When the skill detects issues, it uses this format:
211
+
212
+ > Symbols are coloured in `security-audit.sh` output: ◆ purple (Fatal), ● red (Severe), ▲ yellow (Moderate), ✔ light green (OK).
213
+
214
+ ```markdown
215
+ ◆/●/▲ **[Severity] [Issue type detected]**
216
+
217
+ **What was detected:**
218
+ Line N: `code_snippet`
219
+
220
+ **Why this matters:**
221
+ - Risk explanation
222
+ - Impact assessment
223
+ - Common scenarios that cause problems
224
+
225
+ **Safer alternative:**
226
+ ```bash
227
+ # Fixed code with explanation
228
+ ```
229
+
230
+ Shall I apply this fix? (This will [describe what the fix does])
231
+ ```
@@ -0,0 +1,317 @@
1
+ #!/usr/bin/env bash
2
+ # secure-script-example.sh
3
+ # Demonstrates secure alternatives to common dangerous patterns
4
+
5
+ set -euo pipefail
6
+
7
+ ###
8
+ ### :::: Configuration :::: ###########
9
+ ###
10
+
11
+ # Require environment variables for secrets
12
+ : "${DATABASE_URL:?DATABASE_URL environment variable not set}"
13
+ : "${API_KEY:?API_KEY environment variable not set}"
14
+ : "${APP_HOME:?APP_HOME environment variable not set}"
15
+
16
+ # Directory paths with validation
17
+ BACKUP_DIR="${APP_HOME}/backups"
18
+ TEMP_DIR="${APP_HOME}/tmp"
19
+ LOG_DIR="${APP_HOME}/logs"
20
+
21
+ ###
22
+ ### :::: Initialization :::: ##########
23
+ ###
24
+
25
+ # Create directories with secure permissions
26
+ function init_directories() {
27
+ local dir
28
+ for dir in "$BACKUP_DIR" "$TEMP_DIR" "$LOG_DIR"; do
29
+ if [[ ! -d "$dir" ]]; then
30
+ mkdir -p "$dir"
31
+ chmod 700 "$dir"
32
+ fi
33
+ done
34
+ }
35
+
36
+ ###
37
+ ### :::: Safe File Operations :::: ####
38
+ ###
39
+
40
+ # Safe file deletion with validation
41
+ function safe_delete() {
42
+ local target="$1"
43
+ local force="${2:-false}"
44
+
45
+ # Validate target exists
46
+ if [[ ! -e "$target" ]]; then
47
+ echo "Warning: Target does not exist: $target" >&2
48
+ return 1
49
+ fi
50
+
51
+ # Validate target is within allowed directory
52
+ local real_target
53
+ real_target=$(realpath "$target")
54
+ if [[ ! "$real_target" =~ ^"$APP_HOME" ]]; then
55
+ echo "Error: Refusing to delete outside APP_HOME: $target" >&2
56
+ return 1
57
+ fi
58
+
59
+ # Confirm deletion unless forced
60
+ if [[ "$force" != "true" ]]; then
61
+ echo "Delete: $target"
62
+ read -r -p "Confirm? [y/N] " response
63
+ [[ "$response" =~ ^[Yy]$ ]] || return 1
64
+ fi
65
+
66
+ # Delete with safety flags
67
+ rm -rf --preserve-root -- "$target"
68
+ }
69
+
70
+ # Safe temporary file creation
71
+ function safe_tempfile() {
72
+ local prefix="${1:-script}"
73
+ local tmpfile
74
+
75
+ tmpfile=$(mktemp "${TEMP_DIR}/${prefix}.XXXXXX") || return 1
76
+ chmod 600 "$tmpfile"
77
+ echo "$tmpfile"
78
+ }
79
+
80
+ # Safe file writing with backup
81
+ function safe_write() {
82
+ local file="$1"
83
+ local content="$2"
84
+
85
+ # Validate file path
86
+ if [[ ! "$file" =~ ^"$APP_HOME" ]] && [[ ! "$file" =~ ^"$TEMP_DIR" ]]; then
87
+ echo "Error: Refusing to write outside APP_HOME: $file" >&2
88
+ return 1
89
+ fi
90
+
91
+ # Create backup if file exists
92
+ if [[ -f "$file" ]]; then
93
+ local backup
94
+ backup="${file}.bak.$(date +%Y%m%d_%H%M%S)"
95
+ cp "$file" "$backup"
96
+ echo "Backup created: $backup"
97
+ fi
98
+
99
+ # Write content
100
+ printf '%s\n' "$content" >"$file"
101
+ chmod 600 "$file"
102
+ }
103
+
104
+ ###
105
+ ### :::: Secure Permissions :::: ######
106
+ ###
107
+
108
+ # Set specific permissions instead of 777
109
+ function set_permissions() {
110
+ local target="$1"
111
+
112
+ # Directories: 755 (rwxr-xr-x)
113
+ find "$target" -type d -exec chmod 755 {} \;
114
+
115
+ # Files: 644 (rw-r--r--)
116
+ find "$target" -type f -exec chmod 644 {} \;
117
+
118
+ # Executable scripts: 755
119
+ find "$target" -type f -name "*.sh" -exec chmod 755 {} \;
120
+
121
+ # Sensitive files: 600
122
+ find "$target" -type f \( -name "*.key" -o -name "*.pem" -o -name ".env" \) -exec chmod 600 {} \;
123
+ }
124
+
125
+ ###
126
+ ### :::: Secure Database Operations :::: #####
127
+ ###
128
+
129
+ # Use MySQL with config file instead of command-line password
130
+ function mysql_query() {
131
+ local query="$1"
132
+
133
+ # Create temporary MySQL config
134
+ local my_cnf
135
+ my_cnf=$(safe_tempfile mysql) || return 1
136
+
137
+ # Write credentials to temp config (will be deleted)
138
+ cat >"$my_cnf" <<EOF
139
+ [client]
140
+ user="${DB_USER:-root}"
141
+ password="${DB_PASSWORD}"
142
+ host="${DB_HOST:-localhost}"
143
+ EOF
144
+
145
+ # Execute query with config file
146
+ mysql --defaults-file="$my_cnf" -e "$query"
147
+ local status=$?
148
+
149
+ # Securely delete config
150
+ shred -u "$my_cnf"
151
+
152
+ return "$status"
153
+ }
154
+
155
+ ###
156
+ ### :::: Safe Cleanup :::: ############
157
+ ###
158
+
159
+ # Clean temporary files within scope only
160
+ function cleanup_temp_files() {
161
+ local days="${1:-7}"
162
+
163
+ # Only clean within TEMP_DIR
164
+ find "$TEMP_DIR" -type f -mtime +"$days" -delete
165
+
166
+ # Clean old backups (keep last 10)
167
+ find "$BACKUP_DIR" -maxdepth 1 -name 'backup-*.tar.gz' -printf '%T@ %p\0' |
168
+ sort -zrn |
169
+ tail -zn +11 |
170
+ cut -zd ' ' -f2- |
171
+ xargs -r0 rm --
172
+ }
173
+
174
+ ###
175
+ ### :::: Signal Handling :::: #########
176
+ ###
177
+
178
+ # Secure trap handler (use function, not eval)
179
+ function cleanup_handler() {
180
+ local exit_code=$?
181
+
182
+ echo "Cleaning up..." >&2
183
+
184
+ # Remove temp files
185
+ [[ -d "${TEMP_DIR:-}" ]] && rm -rf -- "${TEMP_DIR:?}"/*
186
+
187
+ # Log exit
188
+ [[ -d "${LOG_DIR:-}" ]] && echo "Script exited with code: $exit_code" >>"$LOG_DIR/exit.log"
189
+
190
+ exit "$exit_code"
191
+ }
192
+
193
+ # Register cleanup handler (function reference, not string)
194
+ trap cleanup_handler EXIT
195
+
196
+ ###
197
+ ### :::: Input Validation :::: ########
198
+ ###
199
+
200
+ # Validate directory path
201
+ function validate_directory() {
202
+ local dir="$1"
203
+ local create="${2:-false}"
204
+
205
+ # Check if absolute path
206
+ [[ "$dir" = /* ]] || {
207
+ echo "Error: Path must be absolute: $dir" >&2
208
+ return 1
209
+ }
210
+
211
+ # Check if within allowed paths
212
+ if [[ ! "$dir" =~ ^"$APP_HOME" ]] && [[ ! "$dir" =~ ^/tmp ]]; then
213
+ echo "Error: Path outside allowed directories: $dir" >&2
214
+ return 1
215
+ fi
216
+
217
+ # Create if requested
218
+ if [[ "$create" == "true" ]] && [[ ! -d "$dir" ]]; then
219
+ mkdir -p "$dir"
220
+ chmod 755 "$dir"
221
+ fi
222
+
223
+ return 0
224
+ }
225
+
226
+ # Validate filename (prevent path traversal)
227
+ function validate_filename() {
228
+ local filename="$1"
229
+
230
+ # Reject path traversal attempts
231
+ if [[ "$filename" =~ \.\. ]]; then
232
+ echo "Error: Path traversal detected: $filename" >&2
233
+ return 1
234
+ fi
235
+
236
+ # Reject absolute paths (should be relative)
237
+ if [[ "$filename" = /* ]]; then
238
+ echo "Error: Absolute path not allowed: $filename" >&2
239
+ return 1
240
+ fi
241
+
242
+ # Reject special characters
243
+ if [[ "$filename" =~ [[:space:]] ]]; then
244
+ echo "Error: Spaces not allowed in filename: $filename" >&2
245
+ return 1
246
+ fi
247
+
248
+ return 0
249
+ }
250
+
251
+ ###
252
+ ### :::: Safe Command Execution :::: ##
253
+ ###
254
+
255
+ # Execute command with timeout and resource limits
256
+ function safe_execute() {
257
+ local timeout="${1:-300}" # 5 minutes default
258
+ shift
259
+ local cmd=("$@")
260
+
261
+ # Set resource limits
262
+ ulimit -t "$timeout" # CPU time
263
+ ulimit -v 4194304 # Max 4GB virtual memory
264
+ ulimit -u 100 # Max 100 processes
265
+
266
+ # Execute with timeout
267
+ timeout "$timeout" "${cmd[@]}"
268
+ }
269
+
270
+ ###
271
+ ### :::: Example Usage :::: ###########
272
+ ###
273
+
274
+ function main() {
275
+ # Initialize
276
+ init_directories
277
+
278
+ # Example: Safe file operations
279
+ local tempfile
280
+ tempfile=$(safe_tempfile data)
281
+ echo "Processing data in $tempfile"
282
+
283
+ # Example: Safe deletion
284
+ # safe_delete "$APP_HOME/old_data" false # Ask for confirmation
285
+ # safe_delete "$APP_HOME/cache" true # Force deletion
286
+
287
+ # Example: Set secure permissions
288
+ # set_permissions "$APP_HOME/public"
289
+
290
+ # Example: Cleanup
291
+ cleanup_temp_files 30
292
+
293
+ echo "Operations completed successfully"
294
+ }
295
+
296
+ # Run main if executed directly
297
+ if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then
298
+ main "$@"
299
+ fi
300
+
301
+ ###
302
+ ### :::: Security Checklist :::: ###########
303
+ ###
304
+
305
+ # ✔ set -euo pipefail for error handling
306
+ # ✔ Environment variables for secrets (no hardcoding)
307
+ # ✔ Path validation before operations
308
+ # ✔ realpath for canonical paths
309
+ # ✔ --preserve-root for rm
310
+ # ✔ mktemp for temporary files
311
+ # ✔ Specific permissions (no 777)
312
+ # ✔ Function references in trap (not eval)
313
+ # ✔ Input validation (path traversal prevention)
314
+ # ✔ Resource limits for commands
315
+ # ✔ Secure credential handling (MySQL config file)
316
+ # ✔ Cleanup handlers for temp files
317
+ # ✔ Confirmation prompts for destructive operations