summaryrefslogtreecommitdiff
path: root/tests/check.sh
blob: 99add68561d486d8788fc52054afcb8550046965 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
#!/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