Skip to content

Commit 24ce044

Browse files
hyperpolymathclaude
andcommitted
refactor(scripts): shared common.sh library + grouped subgroups + new health/sync tools
Adds scripts/lib/common.sh — every script now sources it for safe-by-default strict mode + ERR/EXIT traps, structured timestamped logging, dry-run plumbing (GS_DRY_RUN, gs::do, gs::sh), bounded parallelism, single-instance locks, snapshot/rollback on destructive edits, GH CLI auth + rate-limit + retry wrappers, repo-iteration helpers, and structured A2ML reporting. Honours NO_COLOR and non-TTY. Groups scripts/ into purposeful subgroups via symlinks (real files stay at scripts/ root because the Elixir TUI hardcodes those names): audit/ contractiles, wiki, project-tabs, sync-status, secrets-and-deps fix/ unwrap, innerhtml, branch-protection, all (composite) sync/ update-repos, standardize-readmes, mirror-check health/ gh-doctor, estate-report lib/ common.sh (new), ownership_guard.sh (existing) Heavy refactors that now ride the lib end-to-end: - audit_contractiles.sh — 6 canonical verbs (post-2026-04-18 lust deprecation), K9 SVC vs contractile-drift detection, A2ML report. - branch-protection-apply.sh — gh preflight, retry-on-flake, in-place ruleset updates (no duplicates), per-repo failure isolation. - fix-unwrap-to-match.sh — defaults to REPORT-ONLY per the unwrap-to-expect anti-pattern memo; --apply-expect opts in with snapshot+rollback. - update_repos.sh — fetch + safe-rebase + force-with-lease push, ff-only abort safety, per-repo failure capture, lock-protected. - fix-innerhtml.sh — text-only innerHTML rewrite + SECURITY-comment annotations; idempotent; snapshot+rollback. - audit_script.sh — gitleaks + Dependabot, graceful degrade if gitleaks absent. - verify.sh — read-only HEAD-vs-origin Markdown table. New tools: - health/gh-doctor.sh — gh auth/scope/rate-limit/jq/git-credentials check. - health/estate-report.sh — runs every read-only audit + aggregates Markdown. - sync/mirror-check.sh — verifies the GitHub-only push policy; honours the 007 and bitfuckit estate-wide exceptions. - fix/all.sh — runs every fixer in sequence (replaces fix-security-issues.sh). Reconciled / dropped: - ci-integration-example.sh -> moved to docs/ci-integration-example.adoc (it was prose, not a script). - md_to_adoc_converter.sh, fix-security-issues.sh, USE-GH-CLI.sh become deprecation stubs forwarding to standardize_readmes.sh, fix/all.sh, and health/gh-doctor.sh respectively, so the Elixir TUI's hardcoded names still resolve. scripts/README.adoc documents the layout, common flags (-n/--dry-run, -y/--yes, -j/--jobs N, -v/-q, -h/--help) and common env (GS_REPOS_DIR, GS_REPO_LIST, GS_BACKUP_DIR, GS_REPORT_DIR, NO_COLOR), with a template for new scripts. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent c155498 commit 24ce044

30 files changed

Lines changed: 2109 additions & 821 deletions

scripts/README.adoc

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
= scripts/
2+
:toc: preamble
3+
4+
Estate-wide bash automation. Every script is built on
5+
`lib/common.sh`, which provides safe-by-default strict mode, structured
6+
logging, dry-run support, bounded parallelism, single-instance locking,
7+
signal-safe cleanup, GH CLI rate-limit + retry, snapshot-based rollback,
8+
and repo-iteration helpers.
9+
10+
== Layout
11+
12+
The directory tree is *grouped by purpose* via symlinks. The actual
13+
scripts continue to live at `scripts/` root (the Elixir TUI hardcodes
14+
those paths).
15+
16+
[cols="1,3", options="header"]
17+
|===
18+
| Group | Purpose
19+
20+
| `lib/` | Shared library (`common.sh`); source it from every script.
21+
| `audit/` | Read-only inspection: contractiles, wiki, About metadata, sync, secrets+deps.
22+
| `fix/` | Mutating remediations: unwrap, innerHTML, branch protection, composite `all.sh`.
23+
| `sync/` | Estate-wide sync: update-repos, README standardisation, mirror-policy verification.
24+
| `health/` | Diagnostics: `gh-doctor`, `estate-report` aggregator.
25+
|===
26+
27+
== Common flags
28+
29+
Every script that uses `lib/common.sh` understands:
30+
31+
[cols="1,3", options="header"]
32+
|===
33+
| Flag | Effect
34+
35+
| `-n` / `--dry-run` | Read-only; destructive ops are logged, not executed.
36+
| `-y` / `--yes` | Skip confirmation prompts (CI mode).
37+
| `-j` / `--jobs N` | Bounded parallelism (default 4).
38+
| `-v` / `--verbose` | Debug-level logging.
39+
| `-q` / `--quiet` | Warnings/errors only.
40+
| `-h` / `--help` | Per-script help text.
41+
|===
42+
43+
== Common environment
44+
45+
[cols="1,3", options="header"]
46+
|===
47+
| Var | Default
48+
49+
| `GS_REPOS_DIR` | `/var/mnt/eclipse/repos`
50+
| `GS_LOG_LEVEL` | `info`
51+
| `GS_DRY_RUN` | `0`
52+
| `GS_PARALLEL` | `4`
53+
| `GS_BACKUP_DIR` | `~/.cache/git-scripts/backups`
54+
| `GS_REPORT_DIR` | `~/.cache/git-scripts/reports`
55+
| `GS_LOCK_DIR` | `${TMPDIR}/git-scripts.locks`
56+
| `GS_REPO_LIST` | (optional) one-repo-per-line filter list
57+
| `NO_COLOR` | non-empty disables ANSI colours
58+
|===
59+
60+
== audit/
61+
62+
[cols="1,3", options="header"]
63+
|===
64+
| Script | Reports
65+
66+
| `audit/contractiles.sh` | 6 canonical verbs (`intend trust must bust adjust dust`), K9 SVC location, accessibility hooks/docs. Drift vs missing vs ok.
67+
| `audit/wiki.sh` | Wiki enabled/disabled + page count + page list.
68+
| `audit/project-tabs.sh` | GitHub repo About: description, homepage, mandatory topics.
69+
| `audit/sync-status.sh` | Local HEAD vs origin/<branch> table. Read-only (no fetch).
70+
| `audit/secrets-and-deps.sh`| gitleaks scan + open-Dependabot-alert count.
71+
|===
72+
73+
== fix/
74+
75+
[cols="1,3", options="header"]
76+
|===
77+
| Script | Effect
78+
79+
| `fix/unwrap.sh` | Reports bare `.unwrap()` in non-test Rust. Rewrite is opt-in via `--apply-expect` (anti-pattern; see memory).
80+
| `fix/innerhtml.sh` | Annotates / rewrites XSS-prone DOM writes. Snapshot+rollback per file.
81+
| `fix/branch-protection.sh` | Applies the canonical 'Base' ruleset to every non-archived repo. Updates pre-existing rulesets in place.
82+
| `fix/all.sh` | Runs every fixer in sequence against one repo. Replaces legacy `fix-security-issues.sh`.
83+
|===
84+
85+
== sync/
86+
87+
[cols="1,3", options="header"]
88+
|===
89+
| Script | Effect
90+
91+
| `sync/update-repos.sh` | Fetch + safe-rebase + force-with-lease push across the configured set. ff-only safety; per-repo failure capture.
92+
| `sync/standardize-readmes.sh`| README.md -> README.adoc via pandoc; snapshots saved.
93+
| `sync/mirror-check.sh` | Verifies the GitHub-only-push policy. Flags non-github origins, multi-forge drift, suspicious `pushurl` redirects. Honours estate-wide exceptions (`007`, `bitfuckit`).
94+
|===
95+
96+
== health/
97+
98+
[cols="1,3", options="header"]
99+
|===
100+
| Script | Effect
101+
102+
| `health/gh-doctor.sh` | Validates gh installed, authenticated, scoped (`repo`, `workflow`, `read:org`), rate-limit headroom, jq present, git credential helper sane. Replaces legacy `USE-GH-CLI.sh`.
103+
| `health/estate-report.sh`| Runs every read-only audit and aggregates into a single Markdown report.
104+
|===
105+
106+
== Removed / deprecated
107+
108+
* `ci-integration-example.sh` -> moved to `docs/ci-integration-example.adoc` (it was prose, not a script).
109+
* `md_to_adoc_converter.sh` -> deprecation stub forwarding to `standardize_readmes.sh` (original sed regexes were broken).
110+
* `fix-security-issues.sh` -> deprecation stub forwarding to `fix/all.sh`.
111+
* `USE-GH-CLI.sh` -> deprecation stub forwarding to `health/gh-doctor.sh`.
112+
113+
The deprecation stubs still resolve, so the Elixir TUI's hardcoded names
114+
keep working — they just print a notice and exec the replacement.
115+
116+
== Writing a new script
117+
118+
[source,bash]
119+
----
120+
#!/usr/bin/env bash
121+
# SPDX-License-Identifier: PMPL-1.0-or-later
122+
set -uo pipefail
123+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
124+
. "${SCRIPT_DIR}/lib/common.sh" # or ../lib/common.sh from a subgroup
125+
126+
GS_SCRIPT_NAME="my-thing"
127+
GS_HELP_TEXT="Usage: my-thing.sh [--dry-run] [--help]"
128+
gs::strict
129+
gs::install_trap
130+
gs::install_trap_summary
131+
gs::lock my-thing # single-instance protection
132+
gs::need gh jq # fail fast on missing tools
133+
gs::gh_check # auth + rate-limit headroom
134+
135+
while (( $# > 0 )); do
136+
case "$1" in
137+
-n|--dry-run) GS_DRY_RUN=1 ;;
138+
-h|--help) printf '%s\n' "${GS_HELP_TEXT}"; exit 0 ;;
139+
*) gs::die "unknown flag: $1" ;;
140+
esac
141+
shift
142+
done
143+
144+
while IFS= read -r repo; do
145+
gs::info "scanning $(basename "${repo}")..."
146+
gs::do touch "${repo}/.scanned" # honours --dry-run
147+
done < <(gs::repos)
148+
----

scripts/USE-GH-CLI.sh

Lines changed: 11 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,42 +1,12 @@
11
#!/usr/bin/env bash
2-
# Use GitHub CLI to address PR issues
3-
4-
echo "🔧 USING GITHUB CLI"
5-
echo "=================="
6-
echo ""
7-
8-
# Check gh is available
9-
if ! command -v gh &> /dev/null; then
10-
echo "❌ GitHub CLI not found"
11-
exit 1
12-
fi
13-
14-
# Authenticate
15-
if ! gh auth status &> /dev/null; then
16-
echo "🔑 Authenticating..."
17-
gh auth login
18-
fi
19-
20-
echo "✅ GitHub CLI ready"
21-
echo ""
22-
23-
# Function to address a PR
24-
target_pr() {
25-
local repo="$1"
26-
local pr_num="$2"
27-
local action="$3"
28-
29-
echo "Processing $repo #$pr_num: $action"
30-
31-
# Example: gh pr comment $pr_num -b "message"
32-
# Add your specific actions here
33-
}
34-
35-
echo "📋 Available commands:"
36-
echo "gh pr list --state open"
37-
echo "gh pr view <number>"
38-
echo "gh pr comment <number> -b 'message'"
39-
echo ""
40-
41-
echo "Run manual commands like:"
42-
echo "gh pr comment 3 -b 'Thanks for the review! Fixing now.'"
2+
# SPDX-License-Identifier: PMPL-1.0-or-later
3+
#
4+
# DEPRECATED — replaced by health/gh-doctor.sh.
5+
#
6+
# This file used to be a printed tutorial. It has been replaced with a real
7+
# diagnostic. Stub kept so the Elixir TUI's hardcoded reference
8+
# (lib/script_manager/gh_cli.ex) still resolves.
9+
10+
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
11+
echo "[deprecated] USE-GH-CLI.sh -> health/gh-doctor.sh" >&2
12+
exec "${SCRIPT_DIR}/health/gh-doctor.sh" "$@"

scripts/audit/contractiles.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../audit_contractiles.sh

scripts/audit/project-tabs.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../project-tabs-audit.sh

scripts/audit/secrets-and-deps.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../audit_script.sh

scripts/audit/sync-status.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../verify.sh

scripts/audit/wiki.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../wiki-audit.sh

0 commit comments

Comments
 (0)