From dcdf791c3c211ddf7ae4227651d5c7de69206ee4 Mon Sep 17 00:00:00 2001 From: Silo Server Migration Date: Sun, 24 May 2026 19:58:22 -0400 Subject: [PATCH] chore: add local path leak pre-commit guard --- .githooks/pre-commit | 4 ++ AGENTS.md | 2 + Makefile | 10 ++++- scripts/check-local-path-leaks.sh | 64 +++++++++++++++++++++++++++++++ 4 files changed, 79 insertions(+), 1 deletion(-) create mode 100755 .githooks/pre-commit create mode 100755 scripts/check-local-path-leaks.sh diff --git a/.githooks/pre-commit b/.githooks/pre-commit new file mode 100755 index 00000000..ee5b75b9 --- /dev/null +++ b/.githooks/pre-commit @@ -0,0 +1,4 @@ +#!/usr/bin/env sh +set -eu + +scripts/check-local-path-leaks.sh --cached diff --git a/AGENTS.md b/AGENTS.md index 7c863965..b604f99f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,6 +3,8 @@ ## Project Structure & Module Organization `cmd/silo` contains the main server entrypoint. Backend code lives in `internal/`, organized by domain (`api`, `catalog`, `metadata`, `playback`, `scanner`, `jellycompat`, etc.); keep new code in the package that owns the behavior instead of creating catch-all helpers. Database changes belong in `migrations/` as paired numbered `.up.sql` and `.down.sql` files. The React frontend lives in `web/src/`, with feature code split across `components/`, `pages/`, `hooks/`, `player/`, and `lib/`. Reference material belongs in `docs/architecture/` or `docs/superpowers/{specs,plans}/`; ad hoc SQL helpers live in `scripts/`. +When creating or editing `docs/superpowers/specs/` or `docs/superpowers/plans/`, never include local absolute filesystem paths or transient worktree IDs. Use repository-relative paths and wording like "Commands assume the repository root is the cwd." + This repository is a VERY EARLY WIP. Proposing sweeping changes that improve long-term maintainability is encouraged. diff --git a/Makefile b/Makefile index 4deea2ce..9edb443f 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: frontend build dev-frontend dev-backend dev-proxy dev-transcode lint clean jellyfin-web-bundle migrate-continuum-check +.PHONY: frontend build dev-frontend dev-backend dev-proxy dev-transcode lint clean jellyfin-web-bundle migrate-continuum-check verify-local-paths install-hooks GIT_COMMON_DIR := $(strip $(shell git rev-parse --git-common-dir 2>/dev/null)) MAIN_CHECKOUT_ROOT := $(if $(GIT_COMMON_DIR),$(abspath $(GIT_COMMON_DIR)/..)) @@ -43,6 +43,14 @@ lint: golangci-lint run cd web && pnpm run lint +# Check committed content for local machine path leaks. +verify-local-paths: + scripts/check-local-path-leaks.sh + +# Install repo-local git hooks for this checkout/worktree. +install-hooks: + git config core.hooksPath .githooks + # Fetch and build the pinned Jellyfin Web bundle jellyfin-web-bundle: JELLYFIN_WEB_OUTPUT_DIR=$(JELLYFIN_WEB_OUTPUT_DIR) scripts/fetch-jellyfin-web.sh diff --git a/scripts/check-local-path-leaks.sh b/scripts/check-local-path-leaks.sh new file mode 100755 index 00000000..af860c68 --- /dev/null +++ b/scripts/check-local-path-leaks.sh @@ -0,0 +1,64 @@ +#!/usr/bin/env bash +set -euo pipefail + +usage() { + printf 'usage: %s [--cached]\n' "${0##*/}" >&2 +} + +cached=0 +case "${1:-}" in + "") + ;; + --cached) + cached=1 + ;; + -h|--help) + usage + exit 0 + ;; + *) + usage + exit 2 + ;; +esac + +repo_root=$(git rev-parse --show-toplevel) +cd "$repo_root" + +failed=0 +t3_worktree_dir='\.t3'/'worktrees' +t3_worktree_id_prefix='t3''code-' + +check_pattern() { + local label=$1 + local pattern=$2 + shift 2 + + local matches + if [[ "$cached" -eq 1 ]]; then + matches=$(git grep --cached -n -I -E "$pattern" -- "$@" 2>/dev/null) || return 0 + else + matches=$(git grep -n -I -E "$pattern" -- "$@" 2>/dev/null) || return 0 + fi + + if [[ -n "$matches" ]]; then + printf '%s\n' "local path leak check failed: $label" >&2 + printf '%s\n\n' "$matches" >&2 + failed=1 + fi +} + +check_pattern \ + "T3 worktree path or generated worktree id" \ + "(${t3_worktree_dir}|/Users/[^[:space:]]*/${t3_worktree_dir}/|${t3_worktree_id_prefix}[0-9a-f]{8})" \ + . + +check_pattern \ + "absolute /Users path in generated superpowers docs" \ + '/Users/[^[:space:]]+' \ + docs/superpowers/specs docs/superpowers/plans + +if [[ "$failed" -ne 0 ]]; then + printf '%s\n' "Remove local machine paths from committed content. Use repository-relative paths instead." >&2 + exit 1 +fi