Skills DirectorySkills Directory
SkillsLearnSecurityCategoriesDocsBlogPro
Sign InSubmit Skill
Skills Directory

Security-tested agent skills for Claude, coding agents, and AI workflows.

Directory

  • Browse Skills
  • All Skills A–Z
  • Claude Skills
  • Claude Code Skills
  • Agent Skills
  • Categories
  • Authors
  • Submit a Skill

Learn

  • Learn Hub
  • Install Claude Skills
  • Write SKILL.md
  • Skills vs MCP
  • Directories Compared

Security

  • Security
  • Methodology
  • Secure Claude Skills
  • Security Badges
  • Chrome Extension
  • Skill Manager

Company

  • About
  • Community
  • Blog
  • API Docs
  • Advertise

2026 Skills Directory. All rights reserved.

ProTermsPrivacyRefunds
Back to skills

Linux Safe Script Execution

DSecurity

Performs pre-flight validation and interaction mapping for Linux automation scripts to identify availability risks before execution.

4 stars
0 votes
0 copies
1 views
Added 9/4/2026
devopspythonrustgoshellbashnodedockerterraformtestingci/cd

Security Analysis

D48/100
criticalPipes output to a shell interpreter
highPerforms destructive filesystem operations
criticalDownloads and executes remote scripts — classic supply chain attack

Pro shows the line behind each finding and how to fix it

Scanned 9/4/2026

$npx -y skills add paulpas/agent-skill-router --skill linux-safe-script-execution --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Linux Safe Script Execution?

Add the live security badge to your README — it updates automatically with every re-scan.

Security grade badge for Linux Safe Script Execution
[![Security: D — Skills Directory](https://www.skillsdirectory.com/api/skills/paulpas-linux-safe-script-execution/badge)](https://www.skillsdirectory.com/skills/paulpas-linux-safe-script-execution)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
Files
SKILL.md
---
name: linux-safe-script-execution
description: Performs pre-flight validation and interaction mapping for Linux automation scripts to identify availability risks before execution.
license: MIT
compatibility: opencode
archetypes:
  - tactical
  - diagnostic
anti_triggers:
  - brainstorming
  - vague ideation
  - long-form architecture
response_profile:
  verbosity: low
  directive_strength: high
  abstraction_level: operational
metadata:
  version: "1.0.0"
  domain: linux
  triggers: script safety, pre-flight checks, availability risk, script interaction, automation safety, service disruption, Linux operational safety
  role: implementation
  scope: implementation
  output-format: code
  content-types: [code, guidance, do-dont, examples]
---

# Safe Script Execution for Linux Infrastructure Automation

Infrastructure engineer performing pre-flight validation and interaction mapping for Linux automation scripts to identify availability risks, resource conflicts, and service disruption points before execution.

## TL;DR Checklist

- [ ] Verify script has `set -euo pipefail` and explicit error handling on every command
- [ ] Map all file-system paths the script touches and confirm no data-loss operations without backup
- [ ] Check every `systemctl` call — would restarting this service cause downtime for dependent services?
- [ ] Verify no `rm -rf`, `dd`, `truncate`, or filesystem resize operations without explicit user confirmation
- [ ] Confirm all network ports the script opens are within the approved range and documented
- [ ] Check resource consumption estimates against host capacity (disk space, memory, CPU)
- [ ] Validate that the script runs under a dedicated service account, not root, unless explicitly required

---

## When to Use

Use this skill when:

- **Deploying automation scripts on production hosts** — Any script that modifies system state, restarts services, or changes configurations
- **Reviewing third-party or vendor scripts** — Evaluating scripts from external sources before running them on your infrastructure
- **Implementing CI/CD pipeline steps that touch production systems** — Ensuring automated deployment steps don't disrupt running services
- **Auditing existing runbooks and playbooks** — Identifying risky operations in documented procedures
- **Preparing to run migration or upgrade scripts** — Systems undergoing version changes where downtime or data loss is unacceptable
- **Validating infrastructure-as-code changes before apply** — Terraform, Ansible, or Salt states that modify live systems

---

## When NOT to Use

Avoid this skill for:

- **Local development or sandbox environments** — Where no availability risk exists, standard testing is sufficient
- **Read-only inspection commands** — `systemctl status`, `journalctl`, `df`, `free` do not modify system state
- **One-time setup on disposable infrastructure** — Where the entire VM/container is ephemeral and can be discarded
- **Network packet capture or passive monitoring** — Tools like `tcpdump` or `ss` that observe without modifying

Use `linux-service-integrity-operations` when the script is ready to execute and you need safe restart patterns and health monitoring during the change.

---

## Core Workflow

### 1. Parse Script for Dangerous Operations

Identify all operations that modify system state. Build an inventory of every file, service, and network endpoint the script touches.

```bash
#!/usr/bin/env bash
# preflight_audit.sh — Analyze a deployment script for availability risks
# Usage: ./preflight_audit.sh <script.sh>
set -euo pipefail

readonly DANGEROUS_PATTERNS=(
    'systemctl\s+(restart|stop|reload|kill)'
    'rm\s+(-rf|--no-preserve-root)'
    'dd\s+of='
    'truncate\s+-s\s+0'
    'mkfs\.'
    'lvremove|lvreduce|vgremove'
    'iptables|nftables\s+-F'
    'modprobe|insmod|rmmod'
    'fallocate|truncate\s+-s'
    'curl|wget.*\|.*bash|sh\s*-'
    'chattr\s+-i'
    'umount'
    'swapoff'
)

readonly DANGEROUS_PATTERNS_NAMES=(
    'service_restart' 'destructive_rm' 'disk_write' 'file_truncate'
    'filesystem_create' 'lv_destruction' 'firewall_flush' 'kernel_module'
    'disk_allocation' 'pipe_risk' 'attr_remove' 'unmount' 'swap_disable'
)

audit_script() {
    local script_file="$1"
    local risk_level="LOW"
    local findings=()
    local service_ops=()
    local file_ops=()
    local resource_risks=()

    if [[ ! -f "$script_file" ]]; then
        echo "ERROR: Script not found: $script_file" >&2
        return 1
    fi

    echo "=== Pre-flight Audit: $(basename "$script_file") ==="
    echo "File: $script_file"
    echo "Size: $(wc -c < "$script_file") bytes"
    echo ""

    # Check for safety patterns
    if ! grep -q 'set -euo pipefail' "$script_file"; then
        findings+=("CRITICAL: Missing 'set -euo pipefail' — unhandled errors will cascade")
        risk_level="CRITICAL"
    fi

    if ! grep -qE '^\s*(set|trap)' "$script_file"; then
        findings+=("WARNING: No error trapping or set flags — failures may go undetected")
    fi

    # Check dangerous operations
    for i in "${!DANGEROUS_PATTERNS[@]}"; do
        if grep -qE "${DANGEROUS_PATTERNS[$i]}" "$script_file"; then
            local matches
            matches=$(grep -cE "${DANGEROUS_PATTERNS[$i]}" "$script_file")
            findings+=("HIGH: ${DANGEROUS_PATTERNS_NAMES[$i]} detected — ${matches} occurrence(s)")
            risk_level="HIGH"
        fi
    done

    # Check for hard-coded credentials
    if grep -qiE '(password|secret|key|token)\s*=\s*["\x27]' "$script_file"; then
        findings+=("CRITICAL: Hard-coded credentials detected in script")
        risk_level="CRITICAL"
    fi

    # Map systemctl operations
    while IFS= read -r line; do
        service_ops+=("$line")
    done < <(grep -nE 'systemctl\s+(restart|stop|reload|kill|disable|enable)' "$script_file" 2>/dev/null || true)

    if [[ ${#service_ops[@]} -gt 0 ]]; then
        echo ""
        echo "=== Service Impact Analysis ==="
        for op in "${service_ops[@]}"; do
            local svc_name
            svc_name=$(echo "$op" | grep -oE '[a-zA-Z0-9_-]+\.service' || echo "unknown service")
            echo "  [${op}] → Service: $svc_name"
        done
    fi

    echo ""
    echo "=== Risk Assessment ==="
    echo "Overall risk: $risk_level"
    echo "Findings: ${#findings[@]}"
    for finding in "${findings[@]}"; do
        echo "  • $finding"
    done

    echo ""
    echo "=== Recommendations ==="
    if [[ "$risk_level" == "CRITICAL" ]]; then
        echo "  • DO NOT run this script in production without remediation"
        echo "  • Address all CRITICAL findings before proceeding"
        echo "  • Obtain approval from on-call engineer"
    elif [[ "$risk_level" == "HIGH" ]]; then
        echo "  • Review all HIGH findings before execution"
        echo "  • Schedule during maintenance window"
        echo "  • Ensure rollback procedure is ready"
    else
        echo "  • Standard change process applies"
        echo "  • Ensure monitoring is active during execution"
    fi
}

audit_script "${1:?Usage: $0 <script.sh>}"
```

**Checkpoint:** All dangerous operations are identified and catalogued. No CRITICAL findings remain unresolved.

### 2. Map Service Dependencies

Determine what other services depend on any service this script will restart or modify. Use `systemctl list-dependencies` to map the full dependency tree.

```bash
#!/usr/bin/env bash
# service_dependency_map.sh — Map full dependency impact before restarting a service
# Usage: ./service_dependency_map.sh <service.service>
set -euo pipefail

map_dependencies() {
    local target_service="$1"

    if ! systemctl list-unit-files "${target_service}" &>/dev/null; then
        echo "ERROR: Service '${target_service}' not found" >&2
        return 1
    fi

    echo "=== Dependency Impact Analysis: ${target_service} ==="
    echo ""

    # Upstream dependencies — what must be running for this service to work
    echo "--- Upstream Dependencies (Required Before Restart) ---"
    systemctl list-dependencies --reverse "${target_service}" --no-pager 2>/dev/null | \
        sed 's/├── /  /; s/└── /  /; s/│   /  /' | \
        grep -v 'list-dependencies' || echo "  (none)"
    echo ""

    # Downstream dependents — what breaks if this service restarts
    echo "--- Downstream Dependents (At Risk During Restart) ---"
    systemctl list-dependencies "${target_service}" --no-pager 2>/dev/null | \
        sed 's/├── /  /; s/└── /  /; s/│   /  /' | \
        grep -v 'list-dependencies' || echo "  (none)"
    echo ""

    # Check for network ports that would be briefly unavailable
    echo "--- Network Port Impact ---"
    local socket_unit
    socket_unit=$(systemctl cat "${target_service}" 2>/dev/null | grep -E '^ListenStream|^ListenDatagram' || true)
    if [[ -n "$socket_unit" ]]; then
        echo "  Socket activations detected:"
        echo "$socket_unit" | while IFS= read -r line; do
            echo "    $line"
        done
    fi

    # Check if this is a core infrastructure service
    local critical_services=(
        "systemd-journald" "systemd-logind" "dbus" "NetworkManager"
        "sshd" "cron" "systemd-timesyncd" "containerd" "docker"
        "polkit" "udev" "runit"
    )

    for crit in "${critical_services[@]}"; do
        if [[ "$target_service" == "${crit}.service" || "$target_service" == "${crit}.timer" ]]; then
            echo ""
            echo "  ⚠ CRITICAL: '${target_service}' is a core infrastructure service"
            echo "  ⚠ Restart may cause brief system-wide instability"
            echo "  ⚠ Use 'systemctl reload' instead of 'restart' where possible"
            echo "  ⚠ Ensure remote access is available via console/serial before proceeding"
            break
        fi
    done

    # Check for OnFailure handlers
    local failure_handler
    failure_handler=$(systemctl cat "${target_service}" 2>/dev/null | grep '^OnFailure=' || true)
    if [[ -n "$failure_handler" ]]; then
        echo ""
        echo "--- Cascade Failure Risk ---"
        echo "  OnFailure handler: $failure_handler"
        echo "  If this service fails to restart, $failure_handler will be triggered"
    fi
}

map_dependencies "${1:?Usage: $0 <service.service>}"
```

**Checkpoint:** Full dependency tree is mapped. No core infrastructure services are targeted for restart without console access.

### 3. Verify Resource Headroom

Confirm the host has sufficient disk space, memory, and CPU headroom for the script's expected workload.

```bash
#!/usr/bin/env bash
# resource_headroom.sh — Verify host has sufficient resources before running a script
# Usage: ./resource_headroom.sh <script.sh>
set -euo pipefail

check_resource_headroom() {
    local script_file="$1"

    echo "=== Resource Headroom Check ==="
    echo ""

    # Disk space analysis
    echo "--- Disk Space ---"
    local disk_usage
    disk_usage=$(df -h / | awk 'NR==2 {print $5}' | tr -d '%')
    local disk_free
    disk_free=$(df -h / | awk 'NR==2 {print $4}')

    if [[ "$disk_usage" -gt 90 ]]; then
        echo "  ⚠ CRITICAL: Root filesystem at ${disk_usage}% — script may fail"
        echo "  ⚠ Free space: $disk_free"
    elif [[ "$disk_usage" -gt 80 ]]; then
        echo "  WARNING: Root filesystem at ${disk_usage}% — tight on space"
        echo "  Free space: $disk_free"
    else
        echo "  OK: Root filesystem at ${disk_usage}% — sufficient space"
        echo "  Free space: $disk_free"
    fi

    # Check if script creates/extends any files
    local estimated_disk
    estimated_disk=$(grep -oE '(truncate\s+-s\s+(\d+[kmgKMG])?)|(dd\s+.*count=\d+)|(mkfs|fdisk)' "$script_file" 2>/dev/null || true)
    if [[ -n "$estimated_disk" ]]; then
        echo "  ⚠ Script contains disk-extending operations"
        echo "  Operations: $estimated_disk"
    fi
    echo ""

    # Memory analysis
    echo "--- Memory ---"
    local mem_total
    mem_total=$(grep MemTotal /proc/meminfo | awk '{print int($2/1024)}')
    local mem_available
    mem_available=$(grep MemAvailable /proc/meminfo | awk '{print int($2/1024)}')
    local mem_used_pct
    mem_used_pct=$(awk "BEGIN {printf \"%d\", (1 - $mem_available / $mem_total) * 100}")

    if [[ "$mem_used_pct" -gt 90 ]]; then
        echo "  ⚠ CRITICAL: Memory at ${mem_used_pct}% — ($mem_available MB available of ${mem_total} MB)"
    elif [[ "$mem_used_pct" -gt 80 ]]; then
        echo "  WARNING: Memory at ${mem_used_pct}% — ($mem_available MB available of ${mem_total} MB)"
    else
        echo "  OK: Memory at ${mem_used_pct}% — ($mem_available MB available of ${mem_total} MB)"
    fi
    echo ""

    # CPU load check
    echo "--- CPU Load ---"
    local load_avg
    load_avg=$(cat /proc/loadavg | awk '{print $1}')
    local cpu_count
    cpu_count=$(nproc)
    local load_ratio
    load_ratio=$(awk "BEGIN {printf \"%.2f\", $load_avg / $cpu_count}")

    if awk "BEGIN {exit !($load_ratio > 2.0)}"; then
        echo "  ⚠ WARNING: Load ratio ${load_ratio}x CPU count — consider delaying execution"
    else
        echo "  OK: Load ratio ${load_ratio}x CPU count (${load_avg} on ${cpu_count} CPUs)"
    fi
    echo ""

    # File descriptor check
    echo "--- File Descriptors ---"
    local fd_limit
    fd_limit=$(ulimit -n)
    local fd_used
    fd_used=$(ls /proc/$$/fd 2>/dev/null | wc -l)

    if [[ "$fd_limit" -lt 1024 ]]; then
        echo "  WARNING: File descriptor limit is low ($fd_limit)"
    else
        echo "  OK: FD limit $fd_limit, currently used $fd_used"
    fi
}

check_resource_headroom "${1:?Usage: $0 <script.sh>}"
```

**Checkpoint:** All resource metrics are within acceptable thresholds. No CRITICAL findings.

### 4. Generate Risk Assessment Report

Produce a structured summary of all findings, risk level, and required approvals before execution.

```python
from dataclasses import dataclass, field
from enum import Enum
from typing import Optional
from datetime import datetime


class RiskLevel(Enum):
    SAFE = "SAFE"
    LOW = "LOW"
    MEDIUM = "MEDIUM"
    HIGH = "HIGH"
    CRITICAL = "CRITICAL"


@dataclass
class ScriptFinding:
    """A single finding from pre-flight script analysis."""
    severity: str  # CRITICAL, HIGH, WARNING, INFO
    category: str  # error_handling, dangerous_op, service_impact, etc.
    message: str
    line_number: Optional[int] = None
    remediation: str = ""


@dataclass
class RiskAssessment:
    """Structured pre-flight risk assessment for a Linux automation script."""
    script_path: str
    risk_level: RiskLevel
    findings: list = field(default_factory=list)
    service_impacts: list = field(default_factory=list)
    resource_risks: list = field(default_factory=list)
    requires_approval: bool = False
    recommended_window: str = ""

    def add_finding(self, severity: str, category: str, message: str,
                    line_number: Optional[int] = None, remediation: str = ""):
        self.findings.append(ScriptFinding(severity, category, message, line_number, remediation))
        if severity == "CRITICAL":
            self.risk_level = RiskLevel.CRITICAL
            self.requires_approval = True
        elif severity == "HIGH" and self.risk_level not in (RiskLevel.CRITICAL,):
            self.risk_level = RiskLevel.HIGH
            self.requires_approval = True

    def to_report(self) -> str:
        """Generate a human-readable risk assessment report."""
        lines = [
            f"=== Pre-Flight Risk Assessment ===",
            f"Script: {self.script_path}",
            f"Risk Level: {self.risk_level.value}",
            f"Timestamp: {datetime.now().isoformat()}",
            f"Requires Approval: {'YES' if self.requires_approval else 'No'}",
            f"",
            f"--- Findings ({len(self.findings)}) ---",
        ]

        for f in self.findings:
            prefix = "🔴" if f.severity == "CRITICAL" else "🟡" if f.severity == "HIGH" else "🔵" if f.severity == "WARNING" else "ℹ️"
            line = f"  {prefix} [{f.severity}] {f.category}: {f.message}"
            if f.line_number:
                line += f" (line {f.line_number})"
            if f.remediation:
                line += f"\n     → {f.remediation}"
            lines.append(line)

        if self.service_impacts:
            lines.append("")
            lines.append("--- Service Impact ---")
            for imp in self.service_impacts:
                lines.append(f"  • {imp}")

        lines.append("")
        lines.append("--- Execution Recommendation ---")
        if self.risk_level == RiskLevel.CRITICAL:
            lines.append("  DO NOT EXECUTE without remediation and approval.")
        elif self.risk_level == RiskLevel.HIGH:
            lines.append("  Schedule during maintenance window. Ensure rollback is ready.")
        elif self.risk_level == RiskLevel.MEDIUM:
            lines.append("  Standard change process applies. Monitor closely.")
        else:
            lines.append("  Low risk. Standard execution procedure applies.")

        return "\n".join(lines)


def assess_script_risk(
    script_path: str,
    dangerous_ops: Optional[list[str]] = None
) -> RiskAssessment:
    """Perform a pre-flight risk assessment on a shell script.

    Analyzes the script for error handling, dangerous operations,
    service dependencies, and resource consumption risks.

    Args:
        script_path: Path to the shell script to analyze
        dangerous_ops: Optional list of additional dangerous patterns to check

    Returns:
        RiskAssessment with all findings and risk level

    Raises:
        FileNotFoundError: If script_path does not exist
        PermissionError: If script_path is not readable
    """
    import os
    import re

    if not os.path.isfile(script_path):
        raise FileNotFoundError(f"Script not found: {script_path}")
    if not os.access(script_path, os.R_OK):
        raise PermissionError(f"Script not readable: {script_path}")

    assessment = RiskAssessment(script_path=script_path)
    content = open(script_path).read()
    lines = content.splitlines()

    default_dangerous = [
        ("systemctl\\s+(restart|stop|reload|kill)", "service_restart"),
        ("rm\\s+(-rf|--no-preserve-root)", "destructive_rm"),
        ("(dd\\s+of=|truncate\\s+-s\\s+0)", "disk_write"),
        ("(iptables|nftables)\\s+-F", "firewall_flush"),
        ("(modprobe|insmod|rmmod)", "kernel_module"),
        ("curl.*\\|.*bash", "pipe_risk"),
    ]

    patterns = dangerous_ops or default_dangerous

    for i, line in enumerate(lines, start=1):
        for pattern, category in patterns:
            if re.search(pattern, line):
                assessment.add_finding(
                    severity="HIGH" if "restart" in category else "CRITICAL",
                    category=category,
                    message=f"Dangerous operation in line {i}: {line.strip()}",
                    line_number=i,
                    remediation=f"Add --dry-run support and rollback before this operation"
                )

        # Check for credential patterns
        if re.search(r'(password|secret|token)\s*=\s*["\'][^\s"\']', line, re.IGNORECASE):
            assessment.add_finding(
                severity="CRITICAL",
                category="credential_exposure",
                message=f"Hard-coded credential detected",
                line_number=i,
                remediation="Move to environment variable or secrets manager"
            )

    # Check error handling
    if "set -euo pipefail" not in content:
        assessment.add_finding(
            severity="CRITICAL",
            category="error_handling",
            message="Missing 'set -euo pipefail' — unhandled errors will cascade",
            remediation="Add 'set -euo pipefail' as the second line of the script"
        )

    if "trap" not in content and "set -E" not in content:
        assessment.add_finding(
            severity="WARNING",
            category="error_handling",
            message="No error trapping configured",
            remediation="Add 'trap cleanup EXIT ERR INT TERM' handler"
        )

    return assessment
```

**Checkpoint:** Risk assessment report is generated. All CRITICAL findings have remediation steps. Approval decision is documented.

---

## Implementation Patterns

### Pattern 1: Safe File Operation Wrapper

**BAD — Unsafe file operations with no validation**

```bash
#!/bin/bash
# ❌ BAD: No error handling, no backup, no validation
deploy_config() {
    cp /tmp/new-config.conf /etc/myapp/config.conf
    systemctl restart myapp
    echo "Deployed successfully"
}

# Problems:
# - If cp fails, the old config is replaced with nothing (data loss)
# - If restart fails, service is down with no recovery
# - No backup of original config
# - No post-deploy health check
```

**GOOD — Safe file operations with validation and rollback**

```bash
#!/usr/bin/env bash
# ✅ GOOD: Safe deploy with backup, validation, and rollback
set -euo pipefail

readonly APP_NAME="myapp"
readonly APP_DIR="/etc/${APP_NAME}"
readonly BACKUP_DIR="${APP_DIR}/.backups"
readonly CONFIG_FILE="${APP_DIR}/config.conf"

deploy_config() {
    local source_file="${1:?Usage: deploy_config <new-config.conf>}"
    local deploy_timestamp
    deploy_timestamp="$(date +%Y%m%dT%H%M%S)"

    # Validate source exists and is readable
    [[ -f "$source_file" ]] && [[ -r "$source_file" ]] || {
        echo "ERROR: Source config not found or not readable: $source_file" >&2
        return 1
    }

    # Validate destination directory exists
    [[ -d "$APP_DIR" ]] || {
        echo "ERROR: Application directory does not exist: $APP_DIR" >&2
        return 1
    }

    # Backup current config
    mkdir -p "$BACKUP_DIR"
    local backup_file="${BACKUP_DIR}/config.conf.${deploy_timestamp}"
    cp -a "$CONFIG_FILE" "$backup_file"
    echo "Backed up config to $backup_file"

    # Validate new config syntax before deploying
    if command -v "${APP_NAME}-ctl" &>/dev/null; then
        if ! "${APP_NAME}-ctl" validate-config "$source_file" 2>/dev/null; then
            echo "ERROR: New config failed syntax validation" >&2
            echo "Restoring backup..."
            cp -a "$backup_file" "$CONFIG_FILE"
            return 1
        fi
    fi

    # Deploy with correct ownership
    cp "$source_file" "${CONFIG_FILE}"
    chown root:root "$CONFIG_FILE"
    chmod 644 "$CONFIG_FILE"

    # Reload service (prefer reload over restart to minimize disruption)
    if systemctl reload "${APP_NAME}" &>/dev/null; then
        echo "Service reloaded successfully"
    elif systemctl restart "${APP_NAME}" &>/dev/null; then
        echo "Service restarted (reload unavailable)"
    else
        echo "ERROR: Failed to reload/restart ${APP_NAME}" >&2
        echo "Restoring backup..."
        cp -a "$backup_file" "$CONFIG_FILE"
        echo "Config restored. Contact operations team."
        return 1
    fi

    # Health check after deploy
    sleep 2
    if systemctl is-active --quiet "${APP_NAME}"; then
        echo "Post-deploy health check passed"
        return 0
    else
        echo "ERROR: Health check failed after deploy" >&2
        echo "Restoring backup and stopping service..."
        cp -a "$backup_file" "$CONFIG_FILE"
        systemctl restart "${APP_NAME}"
        return 1
    fi
}

deploy_config "${1:?Usage: $0 <new-config.conf>}"
```

### Pattern 2: Pre-flight Script Executor with Dry-Run

**Bash — Safe execution framework with dry-run and rollback support**

```bash
#!/usr/bin/env bash
# safe_script_executor.sh — Execute scripts with pre-flight validation and rollback
# Usage: ./safe_script_executor.sh [--dry-run] [--timeout 300] <script.sh>
set -euo pipefail

DRY_RUN=false
TIMEOUT=300
SCRIPT_PATH=""

# Parse arguments
while [[ $# -gt 0 ]]; do
    case "$1" in
        --dry-run) DRY_RUN=true; shift ;;
        --timeout) TIMEOUT="$2"; shift 2 ;;
        *) SCRIPT_PATH="$1"; shift ;;
    esac
done

if [[ -z "$SCRIPT_PATH" ]]; then
    echo "Usage: $0 [--dry-run] [--timeout N] <script.sh>" >&2
    exit 1
fi

# Create a rollback snapshot if this is a live run
ROLLBACK_SNAPSHOT=""
create_rollback_snapshot() {
    ROLLBACK_SNAPSHOT=$(mktemp -d "/tmp/safe-exec-rollback.XXXXXX")

    # Snapshot mounted filesystems (only those we can safely snapshot)
    for mount_point in /etc /var/lib /opt; do
        if [[ -d "$mount_point" ]]; then
            echo "  Snapshotting: $mount_point"
            rsync -a --delete "$mount_point/" "${ROLLBACK_SNAPSHOT}${mount_point}/" 2>/dev/null || true
        fi
    done

    # Snapshot systemd service states
    systemctl list-unit-files --state=enabled --no-pager 2>/dev/null | \
        awk 'NR>1 {print $1}' > "${ROLLBACK_SNAPSHOT}/enabled-services.txt"

    echo "Rollback snapshot created: $ROLLBACK_SNAPSHOT"
}

rollback() {
    if [[ -z "$ROLLBACK_SNAPSHOT" ]]; then
        echo "WARNING: No rollback snapshot available" >&2
        return 1
    fi

    echo "=== Executing Rollback ==="

    # Restore configuration directories
    for target in /etc /var/lib /opt; do
        if [[ -d "${ROLLBACK_SNAPSHOT}${target}" ]]; then
            echo "  Restoring: $target"
            rsync -a "${ROLLBACK_SNAPSHOT}${target}/" "$target/" 2>/dev/null || true
        fi
    done

    echo "Rollback complete. Snapshot available at: $ROLLBACK_SNAPSHOT"
    echo "Review differences with: diff -r $target ${ROLLBACK_SNAPSHOT}${target}"
}

trap rollback ERR

# Pre-flight checks
echo "=== Pre-flight Checks ==="
echo "Script: $SCRIPT_PATH"
echo "Dry-run: $DRY_RUN"
echo "Timeout: ${TIMEOUT}s"
echo ""

# Check script exists and is readable
if [[ ! -f "$SCRIPT_PATH" ]]; then
    echo "ERROR: Script not found: $SCRIPT_PATH" >&2
    exit 1
fi
if [[ ! -r "$SCRIPT_PATH" ]]; then
    echo "ERROR: Script not readable: $SCRIPT_PATH" >&2
    exit 1
fi

# Run the preflight audit if available
if command -v ./preflight_audit.sh &>/dev/null; then
    echo "Running preflight audit..."
    ./preflight_audit.sh "$SCRIPT_PATH" || echo "WARNING: Preflight audit had findings — review above"
    echo ""
fi

# Create rollback snapshot for live runs
if [[ "$DRY_RUN" != "true" ]]; then
    create_rollback_snapshot
    echo ""
    echo "WARNING: This is a LIVE run. A rollback snapshot has been created."
    echo "Press Ctrl+C within 5 seconds to cancel..."
    sleep 5
else
    echo "DRY RUN mode — no changes will be made. No rollback needed."
    echo ""
fi

# Execute the script with timeout
echo "=== Executing Script ==="
if [[ "$DRY_RUN" == "true" ]]; then
    bash -n "$SCRIPT_PATH" && echo "Syntax check passed" || {
        echo "ERROR: Script has syntax errors" >&2
        exit 1
    }
    echo "DRY RUN: Would execute: bash \"$SCRIPT_PATH\""
else
    bash "$SCRIPT_PATH" &
    SCRIPT_PID=$!

    # Monitor with timeout
    (
        sleep "$TIMEOUT"
        if kill -0 "$SCRIPT_PID" 2>/dev/null; then
            echo "ERROR: Script exceeded ${TIMEOUT}s timeout — killing" >&2
            kill -TERM "$SCRIPT_PID" 2>/dev/null || true
            sleep 5
            kill -9 "$SCRIPT_PID" 2>/dev/null || true
            exit 1
        fi
    ) &
    MONITOR_PID=$!

    wait "$SCRIPT_PID"
    EXEC_EXIT=$?

    # Kill the monitor
    kill "$MONITOR_PID" 2>/dev/null || true
    wait "$MONITOR_PID" 2>/dev/null || true

    if [[ $EXEC_EXIT -ne 0 ]]; then
        echo "ERROR: Script exited with code $EXEC_EXIT" >&2
        echo "Rollback has been triggered automatically."
        exit 1
    fi

    echo "Script completed successfully"
fi

# Cleanup rollback on success
if [[ -n "$ROLLBACK_SNAPSHOT" && $EXEC_EXIT -eq 0 ]]; then
    rm -rf "$ROLLBACK_SNAPSHOT"
    echo "Rollback snapshot cleaned up (deployment succeeded)"
fi

echo "=== Execution Complete ==="
```

---

## Constraints

### MUST DO

- **MUST** require `set -euo pipefail` in all scripts before approving execution — scripts without it are unconditionally rejected
- **MUST** map every service restart to its full dependency tree using `systemctl list-dependencies` before approving
- **MUST** create a rollback snapshot or backup before any operation that modifies filesystem state on a running production host
- **MUST** verify disk space and memory headroom before executing scripts that modify data or launch new processes
- **MUST** use `systemctl reload` instead of `systemctl restart` wherever the service supports graceful reload
- **MUST** run a post-execution health check after every service restart — never assume the service started correctly
- **MUST** validate new configuration files with the application's native validation command before deploying them
- **MUST** implement a timeout wrapper around every script execution to prevent hung processes from blocking the host

### MUST NOT DO

- **MUST NOT** run `rm -rf` or any destructive file operation on a production host without an explicit `--yes` flag and manual confirmation
- **MUST NOT** restart `systemd-journald`, `dbus`, or `udev` on a running system — these can cause cascading failures
- **MUST NOT** flush firewall rules (`iptables -F` or `nft flush ruleset`) without immediately restoring the allow rules
- **MUST NOT** run scripts as root when a dedicated service account can perform the task
- **MUST NOT** pipe remote data directly into a shell (`curl URL | bash`) — download, verify checksum, then execute
- **MUST NOT** skip the pre-flight audit step regardless of script size or perceived trust level
- **MUST NOT** hard-code credentials in scripts — use environment variables, systemd `EnvironmentFile`, or a secrets manager

---

## Output Template

When applying this skill, produce:

1. **Risk Assessment Summary** — Risk level (SAFE/LOW/MEDIUM/HIGH/CRITICAL), total findings count, and whether approval is required
2. **Dangerous Operations Inventory** — Every file-system, service, and network operation the script performs, with line numbers and severity
3. **Service Dependency Map** — For every service the script restarts: upstream dependencies and downstream dependents
4. **Resource Headroom Report** — Current disk, memory, and CPU metrics with pass/fail against safety thresholds
5. **Execution Decision** — Clear recommendation: approved, approved-with-caveats, or blocked, with justification
6. **Rollback Plan** — Specific rollback steps and snapshot location if execution fails or causes unexpected disruption

---

## Related Skills

| Skill | Purpose |
|-------|---------|
| `linux-service-integrity-operations` | Execute changes without service interruption — use after pre-flight validation passes |
| `linux-security` | Validate that the script doesn't introduce security regressions (permissions, MAC policies) |
| `linux-services` | Understand systemd unit file structure and dependency ordering for accurate impact analysis |
| `networking` | Check network port allocations and firewall implications of the script's operations |

---

## Live References

> Authoritative documentation links for this skill's domain. The model follows markdown links at load time to resolve external references and inline content.

- [Bash Reference Manual — Error Handling](https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html)
- [systemctl Documentation](https://www.freedesktop.org/software/systemd/man/latest/systemctl.html)
- [Systemd Service Manager — Security](https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html)
- [Linux Foundation — Safe Scripting Practices](https://www.linuxfoundation.org/research/scripting)
- [GNU coreutils — Safe File Operations](https://www.gnu.org/software/coreutils/manual/html_node/file-operation-options.html)
- [rsync Documentation](https://rsync.samba.org/documentation.html)
- [procps-ng — Linux Memory and Resource Info](https://wiki.ubuntu.com/Kernel/Reference/uptime)

Attribution

paulpaspaulpas
View sourceSee grades on GitHubMore from paulpas →
SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments (0)

No comments yet. Be the first to comment!

SSkills DirectorySkills Directory

Ship a skill? Prove it's safe.

Free 120-pattern security scan, letter grade, and an embeddable README badge.

Submit a skill

Related Skills

Terraform Module Library

Build reusable Terraform modules for AWS, Azure, and GCP infrastructure following infrastructure-as-code best practices. Use when creating infrastructure modules, standardizing cloud provisioning, or implementing reusable IaC components.

401991 votes

sematext-otel

Wire a service's OpenTelemetry output to Sematext Cloud. Walks through region, App-type, instrumentation flow (managed OTLP endpoint vs Sematext Agent), and signal selection (traces/metrics/logs), then produces the exact env-var block and points at a runnable reference example in this repo. Invoke when instrumenting a new app for Sematext.

01 votes

Deployment Patterns

Deployment workflows, CI/CD pipeline patterns, Docker containerization, health checks, rollback strategies, and production readiness checklists for web applications. Use when setting up deployment infrastructure or planning releases.

2699140 votes

Babysit

Watch a pull request or review cycle until it is ready to merge. Use when asked to babysit, monitor, or keep checking PR comments, reviews, and CI until all actionable issues are resolved.

971540 votes

V7 Roster

Interact with the Paperclip control plane API for task coordination and governance. Use when checking assignments, updating issue status, posting comments, delegating work, managing routines, or calling Paperclip API endpoints.

953190 votes
View all in devops →