-
Notifications
You must be signed in to change notification settings - Fork 30
Expand file tree
/
Copy pathvalidate-all.sh
More file actions
executable file
·195 lines (171 loc) · 6.31 KB
/
validate-all.sh
File metadata and controls
executable file
·195 lines (171 loc) · 6.31 KB
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
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#!/bin/bash
# =============================================================================
# validate-all.sh - Run every risk-map validator with --force
# =============================================================================
# Replacement for the prior `pre-commit.sh --force` workflow. Runs each
# validator against the full tree (regardless of git staging) and, by
# default, does not regenerate graphs, tables, or SVGs. Use this while
# iterating on content to catch issues before you stage for commit.
#
# Usage:
# ./scripts/tools/validate-all.sh # run all validators
# ./scripts/tools/validate-all.sh --quiet # suppress per-validator banners
# ./scripts/tools/validate-all.sh --check-generation # also verify generated tables
# ./scripts/tools/validate-all.sh --help # show this help
#
# --check-generation regenerates tables into a temporary directory and compares
# them with risk-map/tables. It does not write tracked files or change the git
# index. The temporary directory is cleaned up on success, failure, INT, and TERM.
#
# Exit codes:
# 0 All validators passed
# 1 One or more validators failed (see output for details)
# 2 Bad arguments
# =============================================================================
# set -u catches unset variables; we deliberately do not set -e because each
# validator must run even if a prior one fails (failures are counted, not
# fatal). Any new statement added to check_generated_tables that can return
# non-zero must therefore be explicitly checked (e.g. wrapped in `if !`).
set -u
QUIET=false
CHECK_GENERATION=false
while [[ $# -gt 0 ]]; do
case "$1" in
--quiet|-q)
QUIET=true
shift
;;
--check-generation)
CHECK_GENERATION=true
shift
;;
--help|-h)
sed -n '2,23p' "$0"
exit 0
;;
*)
echo "Unknown argument: $1" >&2
echo "See --help for usage." >&2
exit 2
;;
esac
done
# Resolve repo root from this script's location so the command works from
# any cwd. This script lives at scripts/tools/validate-all.sh so the repo
# root is two parents up.
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd -P)"
REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd -P)"
cd "$REPO_ROOT"
# ANSI colors (match install-deps.sh / verify-deps.sh conventions)
if [[ -t 1 ]]; then
GREEN='\033[0;32m'
RED='\033[0;31m'
YELLOW='\033[0;33m'
RESET='\033[0m'
else
GREEN=''; RED=''; YELLOW=''; RESET=''
fi
banner() {
if [[ "$QUIET" != "true" ]]; then
echo -e "${YELLOW}─── $1 ───${RESET}"
fi
}
pass_msg() { echo -e "${GREEN}[PASS]${RESET} $1"; }
fail_msg() { echo -e "${RED}[FAIL]${RESET} $1"; }
FAILURES=0
GEN_TMPDIR=""
cleanup_generation_tmp() {
if [[ -n "${GEN_TMPDIR:-}" && -d "$GEN_TMPDIR" ]]; then
rm -rf "$GEN_TMPDIR"
fi
}
handle_generation_signal() {
# exit 130 re-fires the EXIT trap, which runs cleanup_generation_tmp a
# second time; the `-d "$GEN_TMPDIR"` guard in that function makes the
# second call a no-op, so net behavior is one cleanup.
cleanup_generation_tmp
trap - INT TERM
exit 130
}
check_generated_tables() {
# Without this guard an empty GEN_TMPDIR turns "$GEN_TMPDIR/tables"
# into "/tables", writing outside the repo.
if ! GEN_TMPDIR="$(mktemp -d)"; then
fail_msg "Could not create temporary directory for generation check"
return 1
fi
# check_generated_tables owns the EXIT trap for the remainder of the
# script. The function is the last validator invoked, so this is safe;
# any future code added after the CHECK_GENERATION block needs to either
# chain into this trap or move it out of the function.
trap cleanup_generation_tmp EXIT
trap handle_generation_signal INT TERM
local generated_table_dir="$GEN_TMPDIR/tables"
local drift_report="$GEN_TMPDIR/table-drift.txt"
mkdir -p "$generated_table_dir"
if ! python3 scripts/hooks/yaml_to_markdown.py --all --all-formats --output-dir "$generated_table_dir" --quiet; then
fail_msg "Markdown table generation check failed"
return 1
fi
if ! diff -r -q risk-map/tables "$generated_table_dir" > "$drift_report"; then
fail_msg "Generated markdown tables are out of sync"
echo "Table drift detected:" >&2
cat "$drift_report" >&2
return 1
fi
pass_msg "Generated markdown tables match risk-map/tables"
return 0
}
# Each validator accepts --force to run against the full tree. Output is
# routed straight to the user's terminal so error messages retain their
# original formatting. The order below matches the framework config's
# validator ordering for consistency with commit-time feedback.
banner "Schema meta-validation"
if check-jsonschema --check-metaschema risk-map/schemas/*.schema.json; then
pass_msg "Schema files are structurally valid JSON Schema"
else
fail_msg "One or more schema files are invalid JSON Schema"
FAILURES=$((FAILURES + 1))
fi
banner "Component edge validation"
if python3 scripts/hooks/validate_riskmap.py --force; then
pass_msg "Component edges"
else
fail_msg "Component edge validation reported errors"
FAILURES=$((FAILURES + 1))
fi
banner "Control-to-risk reference validation"
if python3 scripts/hooks/validate_control_risk_references.py --force; then
pass_msg "Control-to-risk references"
else
fail_msg "Control-to-risk reference validation reported errors"
FAILURES=$((FAILURES + 1))
fi
banner "Framework reference validation"
if python3 scripts/hooks/validate_framework_references.py --force; then
pass_msg "Framework references"
else
fail_msg "Framework reference validation reported errors"
FAILURES=$((FAILURES + 1))
fi
banner "Issue template validation"
if python3 scripts/hooks/validate_issue_templates.py --force; then
pass_msg "Issue templates"
else
fail_msg "Issue template validation reported errors"
FAILURES=$((FAILURES + 1))
fi
if [[ "$CHECK_GENERATION" == "true" ]]; then
banner "Generated table parity"
if ! check_generated_tables; then
FAILURES=$((FAILURES + 1))
fi
fi
echo
if [[ "$FAILURES" -eq 0 ]]; then
pass_msg "All validators passed"
exit 0
else
fail_msg "$FAILURES validator(s) reported errors"
exit 1
fi