#!/usr/bin/env bash # リポジトリの整合性チェック。push 前に実行する: bash tests/check.sh set -uo pipefail cd "$(dirname "$0")/.." FAIL=0 ok() { echo " ok: $*"; } ng() { echo " NG: $*"; FAIL=1; } echo "=== シェルスクリプト構文 ===" while IFS= read -r f; do if bash -n "$f" 2>/dev/null; then ok "$f" else ng "$f" bash -n "$f" || true fi done < <(find . -name '*.sh' -not -path './.git/*' | sort) while IFS= read -r f; do if bash -n "$f" 2>/dev/null; then ok "$f" else ng "$f" bash -n "$f" || true fi done < <(find git/hooks -type f -name 'post-receive' | sort) echo "" echo "=== Python 構文 ===" for f in hetzner-admin/app.py mail/dns/setup-route53.py; do if python3 -m py_compile "$f" 2>/dev/null; then ok "$f" else ng "$f" python3 -m py_compile "$f" || true fi done echo "" echo "=== repos.txt と git/hooks/ の整合性 ===" mapfile -t repos < <(grep -vE '^\s*(#|$)' git/repos.txt | cut -d: -f1) for repo in "${repos[@]}"; do if [[ -f "git/hooks/$repo/post-receive" ]]; then ok "repos.txt: $repo → hooks あり" else ng "repos.txt: $repo のフックがない (git/hooks/$repo/post-receive)" fi done for dir in git/hooks/*/; do name="$(basename "$dir")" if printf '%s\n' "${repos[@]}" | grep -qx "$name"; then ok "hooks: $name → repos.txt に定義あり" else ng "hooks: $name が repos.txt に定義されていない" fi done echo "" echo "=== sessions.txt のリポジトリが repos.txt に存在するか ===" while IFS=: read -r user repo; do [[ "$user" =~ ^#.*$ || -z "$user" ]] && continue if printf '%s\n' "${repos[@]}" | grep -qx "$repo"; then ok "sessions.txt: $user:$repo" else ng "sessions.txt: $repo が repos.txt に定義されていない" fi done < claude/sessions.txt echo "" echo "=== hetzner-admin: app.py の COMMANDS が run-command.sh で許可されているか ===" while IFS= read -r cmd; do if grep -qF "\"$cmd\")" hetzner-admin/run-command.sh; then ok "$cmd" else ng "run-command.sh のホワイトリストにない: $cmd" fi done < <(python3 - <<'EOF' import ast tree = ast.parse(open("hetzner-admin/app.py").read()) for node in ast.walk(tree): if isinstance(node, ast.Assign) and getattr(node.targets[0], "id", "") == "COMMANDS": for elt in node.value.elts: print(elt.elts[1].value) EOF ) echo "" echo "=== 秘密ファイルがコミットされていないか ===" for name in users.conf id_rsa id_rsa.pub .env; do regex="(^|/)$(printf '%s' "$name" | sed 's/\./\\./g')\$" if git ls-files | grep -qE "$regex"; then ng "コミットされている: $(git ls-files | grep -E "$regex")" else ok "$name は未コミット" fi done echo "" echo "=== Caddyfile 検証(docker が使える場合のみ) ===" if docker info >/dev/null 2>&1 && docker image inspect caddy-caddy:latest >/dev/null 2>&1; then if docker run --rm -v "$PWD/caddy:/etc/caddy:ro" caddy-caddy:latest \ caddy validate --config /etc/caddy/Caddyfile --adapter caddyfile >/dev/null 2>&1; then ok "Caddyfile valid" else ng "Caddyfile が無効" fi else echo " skip: docker にアクセスできない(root で実行すると検証される)" fi echo "" if [[ "$FAIL" -eq 0 ]]; then echo "All checks passed." else echo "FAILED: 上記の NG を修正してください。" exit 1 fi