Skip to content

Refactor TUI to two-tier menu with ownership guard#1

Merged
hyperpolymath merged 1 commit intomainfrom
claude/safety-checks-script-org-OtyYv
Apr 16, 2026
Merged

Refactor TUI to two-tier menu with ownership guard#1
hyperpolymath merged 1 commit intomainfrom
claude/safety-checks-script-org-OtyYv

Conversation

@hyperpolymath
Copy link
Copy Markdown
Owner

Summary

Restructure the Script Manager TUI from a flat 23-item menu into a two-tier hierarchical menu organized by category (A–F), and introduce an ownership allowlist guard to prevent operations on repositories outside a configured set of allowed owners.

Key Changes

TUI Restructuring

  • Two-tier menu architecture: Top level shows 6 categories (Audits & Reports, Repository Maintenance, GitHub Operations, Estate-Wide Deployment, External Tools, Coming Soon); each category opens a sub-menu of numbered items
  • Single source of truth: New categories/0 function defines all menu items, their actions, and help text in one place
  • Improved navigation: Users select category letter, then item number; "b" returns to main menu, "0" exits
  • Enhanced help system: Help now displays all categories and items with one-line descriptions; added ownership safety documentation

Ownership Guard (New Module)

  • New ScriptManager.OwnershipGuard module: Mirrors bash scripts/lib/ownership_guard.sh for consistent behavior across Elixir and shell scripts
  • Allowlist sources (in priority order):
    1. GIT_SCRIPTS_ALLOWED_OWNERS environment variable (space/comma-separated)
    2. config/owners.config file (bash array syntax)
    3. Default: ["hyperpolymath"]
  • Public API:
    • allowed_owners/0 — return configured allowlist (lowercase)
    • owner_allowed?/1 — check if owner is in allowlist
    • repo_owner/1 — extract GitHub owner from local repo's origin remote
    • repo_allowed?/1 — check if a local repo's owner is allowed
    • filter_allowed/1 and filter_allowed_verbose/1 — filter repo lists
    • assert_owner_allowed!/1 — hard guard that exits with code 78 if owner not allowed
  • Host-agnostic URL parsing: Handles SSH-style (git@host:path) and URL-style (proto://host/path) remotes; works with GitHub, GitLab, Bitbucket, Gitea, and self-hosted servers

Integration with Existing Modules

  • ScriptManager.PRProcessor: Added assert_owner_allowed! check before mass PR operations
  • ScriptManager.GitSyncer: Filter repos through ownership guard before concurrent sync
  • ScriptManager.EstateDeployer: Guard estate-wide deployments
  • ScriptManager.DependencyFixer: Check enclosing repo owner before applying patches
  • ScriptManager.RepoCleanup: Added warning about external script execution

Bash Script Updates

  • scripts/lib/ownership_guard.sh (new): Portable bash implementation with same API as Elixir module
  • scripts/audit_script.sh: Source ownership guard; filter repos and add owner column to output
  • scripts/update_repos.sh: Source ownership guard; skip repos with foreign owners before pushing
  • scripts/md_to_adoc_converter.sh: Source ownership guard; only convert files in allowed repos
  • scripts/standardize_readmes.sh: Source ownership guard; filter repos before standardization
  • scripts/branch-protection-apply.sh: Source ownership guard; refuse to apply rules to foreign repos
  • scripts/project-tabs-audit.sh: Source ownership guard; audit only allowed repos
  • scripts/wiki-audit.sh: Source ownership guard; audit only allowed repos

Configuration

  • New config/owners.config: Template file with documented array syntax and environment variable override mechanism

UX Improvements

  • System status display: Now shows ownership allowlist
  • Startup banner: Displays allowlist on TUI launch
  • Error recovery: Improved error handling and recovery messages
  • Timing: All operations now report elapsed time
  • Confirmation prompts: Critical operations (branch protection, repo cleanup) require explicit confirmation

Implementation Details

  • Menu definition is data-driven: Each item specifies action shape (:fun, :fun_confirm,

https://claude.ai/code/session_014ME3ph3UecQQAPQDKY2HPf

Adds an ownership safety guard so scripts NEVER touch repositories outside
a configured allowlist of owners (defaults to ["hyperpolymath"]; edit
config/owners.config or set GIT_SCRIPTS_ALLOWED_OWNERS to add personal /
family / additional org accounts). The guard is enforced in two parallel
implementations that share the same config:

  - scripts/lib/ownership_guard.sh — sourced by every shell script that
    targets a single org or pushes to remotes; provides
    owner_allowed/repo_allowed/assert_owner_allowed and a host-agnostic
    owner extractor (works for GitHub, GitLab, Bitbucket, Gitea,
    self-hosted, SSH-style, etc.).
  - lib/script_manager/ownership_guard.ex — the Elixir equivalent;
    exposes allowed_owners/0, owner_allowed?/1, repo_allowed?/1,
    filter_allowed/1, filter_allowed_verbose/1 and assert_owner_allowed!/1.

Wired into all the scripts/modules that can mutate or affect repos:
  shell: branch-protection-apply, wiki-audit, project-tabs-audit,
         audit_script (per-repo filter + uses derived owner for the
         Dependabot URL), update_repos (per-repo filter before push),
         standardize_readmes & md_to_adoc_converter (per-repo filter).
  elixir: PRProcessor.process_all/add_standard_comment (asserts org),
          GitSyncer.run (filters discovered repos before push),
          EstateDeployer.deploy_by_paths (filters before writing files),
          DependencyFixer.fix_lithoglyph/fix_rgtv (refuses to patch when
          enclosing repo is foreign-owned),
          RepoCleanup (warns the external cleanup scripts are NOT bound
          by the allowlist).

Also rewrites the TUI menu as two tiers with clearer item names:
  [A] Audits & Reports         — wiki, project metadata, contractiles,
                                 secrets/Dependabot, health dashboard,
                                 local-vs-remote sync verification
  [B] Repository Maintenance   — update repos, global git sync,
                                 standardise READMEs, MD→AsciiDoc,
                                 clean unicode, cleanup ops, dep fixes
  [C] GitHub Operations        — branch protection rulesets, mass PR
                                 processor, gh CLI helper
  [D] Estate-Wide Deployment   — deploy estate standards, link
                                 toolchains, find media repos
  [E] External Tools           — launch NQC, launch Invariant Path
  [F] Coming Soon              — dependency updater, release manager
The startup banner shows the active owner allowlist and the help and
system-status screens both surface it so it's obvious at a glance.

Note: rebuild the escript with `mix escript.build` to pick up the
Elixir-side changes; the bash-side guard is active immediately.

https://claude.ai/code/session_014ME3ph3UecQQAPQDKY2HPf
@hyperpolymath hyperpolymath merged commit b4eb072 into main Apr 16, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants