Skip to content
Back to skills

Bash Scripting

BSecurity

Shell conventions for this repo's operator scripts and role-deployed shell templates, with real exemplar scripts for secrets, locking, and checksums. Use when writing or reviewing scripts/*.sh, an ansible/roles/*/templates/*.sh.j2 script, or a non-trivial Makefile shell recipe. Not for scripts/*.py.

  • 5 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 12, 2026
devopspythonshellbashterraform

Works with

  • cli

Security analysis

B75/100
  • criticalSends environment variables or credentials to an external URL

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

Scanned November 9, 2026

npx -y skills add po4yka/ripdpi-vpn-deploy --skill bash-scripting --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Bash Scripting?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Bash Scripting
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/po4yka-bash-scripting/badge)](https://www.skillsdirectory.com/skills/po4yka-bash-scripting)

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

Download with Pro
SKILL.md
---
name: bash-scripting
description: Shell conventions for this repo's operator scripts and role-deployed shell templates, with real exemplar scripts for secrets, locking, and checksums. Use when writing or reviewing scripts/*.sh, an ansible/roles/*/templates/*.sh.j2 script, or a non-trivial Makefile shell recipe. Not for scripts/*.py.
---

# Shell scripts (vpn-deploy)

Operators run these scripts on both macOS and Linux workstations, and several handle decrypted secrets. `scripts/CLAUDE.md` holds the per-script pitfalls; this skill covers the conventions that apply to every shell file.

## Conventions

- `#!/usr/bin/env bash` and `set -euo pipefail`. `scripts/restore.sh` is deliberately POSIX `#!/bin/sh` with `set -eu` and says why in its header; follow that pattern only when bash is genuinely unavailable.
- Resolve the repo root the way existing scripts do: `REPO_ROOT="$(cd "$(dirname "$0")/.." && pwd)"`. Most scripts take their inputs from environment variables set by the Makefile (`PROVIDER`, `ENV`, `HOSTS`, `SOPS_FILE`, ...) rather than flags.
- Quote every expansion, never `eval` operator input, and use `printf '%q'` when forwarding values into a nested shell.
- `shellcheck -s bash -S warning` must pass (`make shellcheck`, pre-commit, and CI run it on `scripts/*.sh` and `terraform/exception/cascade-ingress/*.sh`). A `# shellcheck disable=` needs a one-line justification above it. Role `*.sh.j2` templates are Jinja and are not shellchecked, so review them by hand.
- Plain `exit 1` is the norm. Use distinct exit codes only when a caller branches on them, and document them in the script header.
- Stay portable: `command -v`, not `which`; explicit `mktemp` templates (macOS `mktemp -t` ignores `TMPDIR`); `sha256sum` with a `shasum -a 256` fallback; `flock` with a `lockf` fallback.

## Secrets and side effects

- Never re-implement decryption. Pipe `sops --decrypt --output-type json ... | python3 ...` when the plaintext is consumed once (`new-client.sh`, `issue-sub-token.sh`). When a file is unavoidable, follow `decrypt-secrets.sh`: runtime dir `${VPN_RUNTIME_DIR:-${XDG_RUNTIME_DIR:-${TMPDIR:-/tmp}/vpn-provision-$(id -u)}}`, `mktemp` inside it, `chmod 0600` at once, `trap 'rm -f "$tmp"' EXIT`, then an atomic `mv`.
- No `set -x` in scripts that can see secrets; gate debug output behind an explicit opt-in.
- Downloads are pinned and checksum-verified before execution (`install-vpnd.sh`); never pipe a remote installer into a shell.
- Lock the resource being protected, not a synthetic name: `new-client.sh` opens `${SOPS_FILE}.new-client.lock` on FD 9 and takes `flock -n 9` or `lockf -s -t 0 9`. Shared SOPS writers must use that same lock file.
- Destructive scripts append to the audit log with `audit-log.sh append-best-effort` so a logging failure never fails the operation.
- Trap `EXIT` for cleanup; `ERR` alone misses signal-driven exits.

## Tests

bats suites live in `tests/bats/` (run with `bats tests/bats/`; part of `make ci-fast`). Add one when a script gains non-trivial argument validation or a dry-run mode; see `fleet_rotate_dryrun.bats` and `blue_green_dryrun.bats` for the stub-binary pattern in `tests/stubs/bin/`.

Attribution

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

View all in devops →

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.