bigpowers 2.73.6 → 2.73.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.pi/package.json +1 -1
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/scripts/audit-compliance.sh +22 -292
- package/scripts/lib/audit-compliance-judge.sh +51 -0
- package/scripts/lib/audit-compliance-report.sh +75 -0
- package/scripts/lib/audit-compliance-runner.sh +121 -0
- package/scripts/lib/migrate-version-common.sh +113 -0
- package/scripts/lib/migrate-version-execute.sh +81 -0
- package/scripts/lib/migrate-version-plan.sh +119 -0
- package/scripts/lib/migrate-version-post.sh +170 -0
- package/scripts/lib/migrate-version-run.sh +53 -0
- package/scripts/lib/migrate-version-transforms.sh +231 -0
- package/scripts/migrate-version.sh +7 -679
package/.pi/package.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [2.73.8](https://github.com/danielvm-git/bigpowers/compare/v2.73.7...v2.73.8) (2026-07-07)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **audit-code:** split audit-compliance.sh into lib modules under 300-line cap ([#63](https://github.com/danielvm-git/bigpowers/issues/63)) ([7d5ea6e](https://github.com/danielvm-git/bigpowers/commit/7d5ea6e0f0c992f26b493b3843ede886770eed6f))
|
|
7
|
+
|
|
8
|
+
## [2.73.7](https://github.com/danielvm-git/bigpowers/compare/v2.73.6...v2.73.7) (2026-07-07)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **migrate-spec:** split migrate-version.sh into lib modules under 300-line cap ([#62](https://github.com/danielvm-git/bigpowers/issues/62)) ([11842f2](https://github.com/danielvm-git/bigpowers/commit/11842f297c58d88df24f451316153242e3f4c63a))
|
|
14
|
+
|
|
1
15
|
## [2.73.6](https://github.com/danielvm-git/bigpowers/compare/v2.73.5...v2.73.6) (2026-07-06)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
# audit-compliance.sh — Agentic Gherkin Compliance Harness (LLM-Judge Upgrade)
|
|
3
|
-
|
|
3
|
+
|
|
4
|
+
_LIB="$(dirname "${BASH_SOURCE[0]}")/lib"
|
|
5
|
+
source "$_LIB/audit-compliance-runner.sh"
|
|
6
|
+
source "$_LIB/audit-compliance-report.sh"
|
|
7
|
+
|
|
8
|
+
audit_show_help() {
|
|
4
9
|
cat <<EOF
|
|
5
10
|
Usage: bash scripts/audit-compliance.sh [feature-file|directory] [options]
|
|
6
11
|
|
|
@@ -15,320 +20,45 @@ If a directory is provided, all .feature files in that directory will be process
|
|
|
15
20
|
EOF
|
|
16
21
|
}
|
|
17
22
|
|
|
18
|
-
# --- Arguments Parsing ---
|
|
19
23
|
DRY_RUN=false
|
|
20
24
|
SCENARIO_FILTER=""
|
|
21
25
|
JUDGE="binary"
|
|
22
26
|
MODEL=""
|
|
23
27
|
INPUTS=()
|
|
28
|
+
TOTAL_GLOBAL_PASS=0
|
|
29
|
+
TOTAL_GLOBAL_FAIL=0
|
|
30
|
+
TOTAL_GLOBAL_WAIVED=0
|
|
31
|
+
TOTAL_GLOBAL_EXPIRED=0
|
|
32
|
+
SCORE=0
|
|
24
33
|
|
|
25
34
|
while [[ $# -gt 0 ]]; do
|
|
26
35
|
case "$1" in
|
|
27
|
-
--help)
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
--
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
;;
|
|
35
|
-
--scenario)
|
|
36
|
-
SCENARIO_FILTER="$2"
|
|
37
|
-
shift 2
|
|
38
|
-
;;
|
|
39
|
-
--judge)
|
|
40
|
-
JUDGE="$2"
|
|
41
|
-
shift 2
|
|
42
|
-
;;
|
|
43
|
-
--model)
|
|
44
|
-
MODEL="$2"
|
|
45
|
-
shift 2
|
|
46
|
-
;;
|
|
47
|
-
-*)
|
|
48
|
-
echo "Unknown option: $1"
|
|
49
|
-
show_help
|
|
50
|
-
exit 1
|
|
51
|
-
;;
|
|
52
|
-
*)
|
|
53
|
-
INPUTS+=("$1")
|
|
54
|
-
shift
|
|
55
|
-
;;
|
|
36
|
+
--help) audit_show_help; exit 0 ;;
|
|
37
|
+
--dry-run) DRY_RUN=true; shift ;;
|
|
38
|
+
--scenario) SCENARIO_FILTER="$2"; shift 2 ;;
|
|
39
|
+
--judge) JUDGE="$2"; shift 2 ;;
|
|
40
|
+
--model) MODEL="$2"; shift 2 ;;
|
|
41
|
+
-*) echo "Unknown option: $1"; audit_show_help; exit 1 ;;
|
|
42
|
+
*) INPUTS+=("$1"); shift ;;
|
|
56
43
|
esac
|
|
57
44
|
done
|
|
58
45
|
|
|
59
46
|
if [[ ${#INPUTS[@]} -eq 0 ]]; then
|
|
60
47
|
echo "Error: No feature file or directory specified."
|
|
61
|
-
|
|
48
|
+
audit_show_help
|
|
62
49
|
exit 1
|
|
63
50
|
fi
|
|
64
51
|
|
|
65
|
-
# --- Global Stats ---
|
|
66
|
-
TOTAL_GLOBAL_PASS=0
|
|
67
|
-
TOTAL_GLOBAL_FAIL=0
|
|
68
|
-
TOTAL_GLOBAL_WAIVED=0
|
|
69
|
-
TOTAL_GLOBAL_EXPIRED=0
|
|
70
|
-
|
|
71
|
-
# --- Waiver Subsystem ---
|
|
72
|
-
# Sourced from scripts/lib/waiver-utils.sh — provides has_waiver().
|
|
73
|
-
WAIVER_FILE="specs/verifications/waivers.yaml"
|
|
74
|
-
true && source "$(dirname "${BASH_SOURCE[0]}")/lib/waiver-utils.sh"
|
|
75
|
-
|
|
76
|
-
# --- Judging Logic ---
|
|
77
|
-
|
|
78
|
-
judge_with_gemini() {
|
|
79
|
-
local step="$1"
|
|
80
|
-
local feature_name="$2"
|
|
81
|
-
local scenario_name="$3"
|
|
82
|
-
local evidence="$4"
|
|
83
|
-
local report_file="$5"
|
|
84
|
-
|
|
85
|
-
echo " [JUDGE] Sending evidence to Gemini CLI..."
|
|
86
|
-
|
|
87
|
-
local prompt="You are the Master Test Architect judging a compliance audit.
|
|
88
|
-
Benchmark Feature: $feature_name
|
|
89
|
-
Scenario: $scenario_name
|
|
90
|
-
Compliance Step: $step
|
|
91
|
-
|
|
92
|
-
Evidence gathered from the codebase:
|
|
93
|
-
---
|
|
94
|
-
$evidence
|
|
95
|
-
---
|
|
96
|
-
|
|
97
|
-
Based on the benchmark principles, does this evidence demonstrate compliance?
|
|
98
|
-
Respond strictly in the following format:
|
|
99
|
-
VERDICT: [PASS/FAIL]
|
|
100
|
-
RATIONALE: [One sentence explanation]"
|
|
101
|
-
|
|
102
|
-
local model_output
|
|
103
|
-
local gemini_cmd="gemini --approval-mode plan"
|
|
104
|
-
if [[ -n "$MODEL" ]]; then
|
|
105
|
-
gemini_cmd="$gemini_cmd -m $MODEL"
|
|
106
|
-
fi
|
|
107
|
-
|
|
108
|
-
model_output=$($gemini_cmd -p "$prompt" 2>&1)
|
|
109
|
-
local exit_code=$?
|
|
110
|
-
|
|
111
|
-
if [[ $exit_code -eq 0 ]]; then
|
|
112
|
-
local verdict
|
|
113
|
-
verdict=$(echo "$model_output" | grep "VERDICT:" | cut -d' ' -f2)
|
|
114
|
-
local rationale
|
|
115
|
-
rationale=$(echo "$model_output" | grep "RATIONALE:" | cut -d' ' -f2-)
|
|
116
|
-
|
|
117
|
-
if [[ "$verdict" == "PASS" ]]; then
|
|
118
|
-
echo " Result: PASS"
|
|
119
|
-
echo "- [x] $step (PASS) - $rationale" >> "$report_file"
|
|
120
|
-
return 0
|
|
121
|
-
else
|
|
122
|
-
echo " Result: FAIL"
|
|
123
|
-
echo "- [ ] $step (FAIL) - $rationale" >> "$report_file"
|
|
124
|
-
return 1
|
|
125
|
-
fi
|
|
126
|
-
else
|
|
127
|
-
echo " Result: ERROR (Gemini CLI failed)"
|
|
128
|
-
echo "- [ ] $step (ERROR) - Gemini CLI exit code $exit_code. Output: $model_output" >> "$report_file"
|
|
129
|
-
return 1
|
|
130
|
-
fi
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
# --- Core Execution ---
|
|
136
|
-
|
|
137
|
-
process_step() {
|
|
138
|
-
local step="$1"
|
|
139
|
-
local feature_name="$2"
|
|
140
|
-
local scenario_name="$3"
|
|
141
|
-
local report_file="$4"
|
|
142
|
-
echo " [STEP] $step"
|
|
143
|
-
|
|
144
|
-
if [[ "$DRY_RUN" == "true" ]]; then
|
|
145
|
-
return 0
|
|
146
|
-
fi
|
|
147
|
-
|
|
148
|
-
local sanitized_step
|
|
149
|
-
sanitized_step=$(echo "$step" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
|
150
|
-
local step_script="specs/verifications/steps/${sanitized_step}.sh"
|
|
151
|
-
|
|
152
|
-
if [[ -f "$step_script" ]]; then
|
|
153
|
-
echo " [EXEC] Gathering evidence: $step_script"
|
|
154
|
-
local evidence
|
|
155
|
-
evidence=$(bash "$step_script" 2>&1)
|
|
156
|
-
local exit_code=$?
|
|
157
|
-
|
|
158
|
-
if [[ "$JUDGE" == "gemini" ]]; then
|
|
159
|
-
judge_with_gemini "$step" "$feature_name" "$scenario_name" "$evidence" "$report_file"
|
|
160
|
-
# Gemini path: rely on judge return code (no waiver check for LLM path)
|
|
161
|
-
else
|
|
162
|
-
# Binary path: check waivers before counting as FAIL
|
|
163
|
-
if [[ $exit_code -eq 0 ]]; then
|
|
164
|
-
echo " Result: PASS"
|
|
165
|
-
echo "- [x] $step (PASS)" >> "$report_file"
|
|
166
|
-
return 0
|
|
167
|
-
fi
|
|
168
|
-
|
|
169
|
-
# Step failed — check if it has a valid waiver
|
|
170
|
-
has_waiver "$sanitized_step"
|
|
171
|
-
local waiver_code=$?
|
|
172
|
-
|
|
173
|
-
if [[ $waiver_code -eq 0 ]]; then
|
|
174
|
-
# Valid waiver — exclude from denominator
|
|
175
|
-
echo " Result: WAIVED (documented exception)"
|
|
176
|
-
echo "- [~] $step (WAIVED)" >> "$report_file"
|
|
177
|
-
((TOTAL_GLOBAL_WAIVED++))
|
|
178
|
-
return 3 # Special code: waived (not PASS, not FAIL)
|
|
179
|
-
elif [[ $waiver_code -eq 2 ]]; then
|
|
180
|
-
# Expired waiver — re-enter denominator as FAIL
|
|
181
|
-
echo " Result: FAIL (EXPIRED WAIVER)"
|
|
182
|
-
echo "- [ ] $step (FAIL) - EXPIRED WAIVER: review_date has passed" >> "$report_file"
|
|
183
|
-
((TOTAL_GLOBAL_EXPIRED++))
|
|
184
|
-
((TOTAL_GLOBAL_FAIL++))
|
|
185
|
-
return 1
|
|
186
|
-
else
|
|
187
|
-
# No waiver — genuine FAIL
|
|
188
|
-
echo " Result: FAIL"
|
|
189
|
-
echo "- [ ] $step (FAIL) - $evidence" >> "$report_file"
|
|
190
|
-
((TOTAL_GLOBAL_FAIL++))
|
|
191
|
-
return 1
|
|
192
|
-
fi
|
|
193
|
-
fi
|
|
194
|
-
else
|
|
195
|
-
echo " Result: FAIL (Missing evidence: $step_script)"
|
|
196
|
-
echo "- [ ] $step (FAIL) - No verification script found at $step_script" >> "$report_file"
|
|
197
|
-
((TOTAL_GLOBAL_FAIL++))
|
|
198
|
-
return 1
|
|
199
|
-
fi
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
run_audit_file() {
|
|
203
|
-
local FEATURE_FILE="$1"
|
|
204
|
-
echo "------------------------------------------------------------"
|
|
205
|
-
echo "FEATURE: $FEATURE_FILE"
|
|
206
|
-
|
|
207
|
-
local REPORT_FILE="specs/verifications/reports/audit-$(basename "$FEATURE_FILE" .feature)-$(date +%Y%m%d-%H%M%S).md"
|
|
208
|
-
mkdir -p specs/verifications/reports
|
|
209
|
-
|
|
210
|
-
echo "# Audit Report: $FEATURE_FILE" > "$REPORT_FILE"
|
|
211
|
-
echo "Date: $(date)" >> "$REPORT_FILE"
|
|
212
|
-
echo "Mode: Autonomous Verification (Judge: $JUDGE)" >> "$REPORT_FILE"
|
|
213
|
-
echo "" >> "$REPORT_FILE"
|
|
214
|
-
|
|
215
|
-
local TOTAL_PASS=0
|
|
216
|
-
local TOTAL_FAIL=0
|
|
217
|
-
local CURRENT_FEATURE=""
|
|
218
|
-
local CURRENT_SCENARIO=""
|
|
219
|
-
local IN_SCENARIO=false
|
|
220
|
-
|
|
221
|
-
while IFS= read -r line; do
|
|
222
|
-
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
223
|
-
|
|
224
|
-
if [[ "$line" =~ ^Feature: ]]; then
|
|
225
|
-
CURRENT_FEATURE="${line#Feature: }"
|
|
226
|
-
echo "FEATURE: $CURRENT_FEATURE"
|
|
227
|
-
echo "## Feature: $CURRENT_FEATURE" >> "$REPORT_FILE"
|
|
228
|
-
elif [[ "$line" =~ ^Scenario: ]]; then
|
|
229
|
-
CURRENT_SCENARIO="${line#Scenario: }"
|
|
230
|
-
if [[ -n "$SCENARIO_FILTER" && "$CURRENT_SCENARIO" != "$SCENARIO_FILTER" ]]; then
|
|
231
|
-
IN_SCENARIO=false
|
|
232
|
-
continue
|
|
233
|
-
fi
|
|
234
|
-
IN_SCENARIO=true
|
|
235
|
-
echo " SCENARIO: $CURRENT_SCENARIO"
|
|
236
|
-
echo "### Scenario: $CURRENT_SCENARIO" >> "$REPORT_FILE"
|
|
237
|
-
elif [[ "$line" =~ ^(Given|When|Then|And|But)\ ]]; then
|
|
238
|
-
if [[ "$IN_SCENARIO" == "true" ]]; then
|
|
239
|
-
local step_result
|
|
240
|
-
process_step "$line" "$CURRENT_FEATURE" "$CURRENT_SCENARIO" "$REPORT_FILE"
|
|
241
|
-
step_result=$?
|
|
242
|
-
if [[ $step_result -eq 3 ]]; then
|
|
243
|
-
# Waived — excluded from both pass and fail counts
|
|
244
|
-
:
|
|
245
|
-
elif [[ $step_result -eq 0 ]]; then
|
|
246
|
-
((TOTAL_PASS++))
|
|
247
|
-
((TOTAL_GLOBAL_PASS++))
|
|
248
|
-
else
|
|
249
|
-
((TOTAL_FAIL++))
|
|
250
|
-
fi
|
|
251
|
-
fi
|
|
252
|
-
fi
|
|
253
|
-
done < "$FEATURE_FILE"
|
|
254
|
-
|
|
255
|
-
echo ""
|
|
256
|
-
echo "File Summary: PASS: $TOTAL_PASS, FAIL: $TOTAL_FAIL"
|
|
257
|
-
echo "Report saved to: $REPORT_FILE"
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
# --- Main Execution ---
|
|
261
52
|
for input in "${INPUTS[@]}"; do
|
|
262
53
|
if [[ -d "$input" ]]; then
|
|
263
54
|
for f in "$input"/*.feature; do
|
|
264
|
-
|
|
265
|
-
run_audit_file "$f"
|
|
266
|
-
fi
|
|
55
|
+
[[ -f "$f" ]] && audit_run_file "$f"
|
|
267
56
|
done
|
|
268
57
|
elif [[ -f "$input" ]]; then
|
|
269
|
-
|
|
58
|
+
audit_run_file "$input"
|
|
270
59
|
else
|
|
271
60
|
echo "Warning: Input not found: $input"
|
|
272
61
|
fi
|
|
273
62
|
done
|
|
274
63
|
|
|
275
|
-
|
|
276
|
-
echo "Global Audit Summary:"
|
|
277
|
-
TOTAL_GLOBAL_ALL=$((TOTAL_GLOBAL_PASS + TOTAL_GLOBAL_FAIL))
|
|
278
|
-
echo " TOTAL PASS: $TOTAL_GLOBAL_PASS"
|
|
279
|
-
echo " TOTAL FAIL: $TOTAL_GLOBAL_FAIL"
|
|
280
|
-
echo " TOTAL WAIVED: $TOTAL_GLOBAL_WAIVED (excluded from denominator)"
|
|
281
|
-
if [[ $TOTAL_GLOBAL_EXPIRED -gt 0 ]]; then
|
|
282
|
-
echo " EXPIRED WAIVERS: $TOTAL_GLOBAL_EXPIRED (counted as FAIL)"
|
|
283
|
-
fi
|
|
284
|
-
if [[ $TOTAL_GLOBAL_ALL -gt 0 ]]; then
|
|
285
|
-
SCORE=$(awk "BEGIN { printf \"%d\", $TOTAL_GLOBAL_PASS * 100 / $TOTAL_GLOBAL_ALL }")
|
|
286
|
-
else
|
|
287
|
-
SCORE=0
|
|
288
|
-
fi
|
|
289
|
-
|
|
290
|
-
# ── OKF verification-report (e45s02) ────────────────────────────────────
|
|
291
|
-
OKF_DIR="specs/verifications/reports"
|
|
292
|
-
mkdir -p "$OKF_DIR"
|
|
293
|
-
OKF_FILE="$OKF_DIR/audit-$(date +%Y-%m-%d).okf.md"
|
|
294
|
-
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
295
|
-
GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
296
|
-
GATE=$(if [[ $SCORE -ge 94 ]]; then echo "pass"; else echo "fail"; fi)
|
|
297
|
-
|
|
298
|
-
cat > "$OKF_FILE" << OKF_EOF
|
|
299
|
-
---
|
|
300
|
-
okf_kind: verification-report
|
|
301
|
-
okf_version: "0.1"
|
|
302
|
-
score: ${SCORE}
|
|
303
|
-
gate_status: "${GATE}"
|
|
304
|
-
threshold: 94
|
|
305
|
-
total_pass: ${TOTAL_GLOBAL_PASS}
|
|
306
|
-
total_fail: ${TOTAL_GLOBAL_FAIL}
|
|
307
|
-
total_waived: ${TOTAL_GLOBAL_WAIVED}
|
|
308
|
-
generated_by: scripts/audit-compliance.sh
|
|
309
|
-
generated_at: "${TIMESTAMP}"
|
|
310
|
-
git_commit: "${GIT_COMMIT}"
|
|
311
|
-
---
|
|
312
|
-
|
|
313
|
-
# Compliance Audit — $(date +%Y-%m-%d)
|
|
314
|
-
|
|
315
|
-
**Score:** ${SCORE}% (${TOTAL_GLOBAL_PASS}/${TOTAL_GLOBAL_ALL} passed, ${TOTAL_GLOBAL_WAIVED} waived)
|
|
316
|
-
**Gate:** ${GATE} | **Threshold:** 94%
|
|
317
|
-
|
|
318
|
-
See \`specs/verifications/reports/audit-*.md\` for detailed step-by-step reports.
|
|
319
|
-
OKF_EOF
|
|
320
|
-
|
|
321
|
-
echo "OKF report: $OKF_FILE"
|
|
322
|
-
|
|
323
|
-
if [[ $TOTAL_GLOBAL_WAIVED -gt 0 ]]; then
|
|
324
|
-
echo " SCORE: ${SCORE}% (of ${TOTAL_GLOBAL_ALL} unwaived checks, threshold 94%)"
|
|
325
|
-
else
|
|
326
|
-
echo " SCORE: ${SCORE}% (threshold 94%)"
|
|
327
|
-
fi
|
|
328
|
-
if [[ $SCORE -ge 94 ]]; then
|
|
329
|
-
echo " GATE: PASS"
|
|
330
|
-
exit 0
|
|
331
|
-
else
|
|
332
|
-
echo " GATE: FAIL (below 94%)"
|
|
333
|
-
exit 1
|
|
334
|
-
fi
|
|
64
|
+
audit_print_summary_and_exit
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e45s02
|
|
3
|
+
# Gemini LLM judge for audit-compliance.sh
|
|
4
|
+
|
|
5
|
+
if [ -n "${AUDIT_COMPLIANCE_JUDGE_LOADED:-}" ]; then return 0; fi
|
|
6
|
+
AUDIT_COMPLIANCE_JUDGE_LOADED=1
|
|
7
|
+
|
|
8
|
+
audit_judge_with_gemini() {
|
|
9
|
+
local step="$1" feature_name="$2" scenario_name="$3" evidence="$4" report_file="$5"
|
|
10
|
+
local prompt model_output gemini_cmd exit_code verdict rationale
|
|
11
|
+
|
|
12
|
+
echo " [JUDGE] Sending evidence to Gemini CLI..."
|
|
13
|
+
|
|
14
|
+
prompt="You are the Master Test Architect judging a compliance audit.
|
|
15
|
+
Benchmark Feature: $feature_name
|
|
16
|
+
Scenario: $scenario_name
|
|
17
|
+
Compliance Step: $step
|
|
18
|
+
|
|
19
|
+
Evidence gathered from the codebase:
|
|
20
|
+
---
|
|
21
|
+
$evidence
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
Based on the benchmark principles, does this evidence demonstrate compliance?
|
|
25
|
+
Respond strictly in the following format:
|
|
26
|
+
VERDICT: [PASS/FAIL]
|
|
27
|
+
RATIONALE: [One sentence explanation]"
|
|
28
|
+
|
|
29
|
+
gemini_cmd="gemini --approval-mode plan"
|
|
30
|
+
[[ -n "$MODEL" ]] && gemini_cmd="$gemini_cmd -m $MODEL"
|
|
31
|
+
|
|
32
|
+
model_output=$($gemini_cmd -p "$prompt" 2>&1)
|
|
33
|
+
exit_code=$?
|
|
34
|
+
|
|
35
|
+
if [[ $exit_code -eq 0 ]]; then
|
|
36
|
+
verdict=$(echo "$model_output" | grep "VERDICT:" | cut -d' ' -f2)
|
|
37
|
+
rationale=$(echo "$model_output" | grep "RATIONALE:" | cut -d' ' -f2-)
|
|
38
|
+
if [[ "$verdict" == "PASS" ]]; then
|
|
39
|
+
echo " Result: PASS"
|
|
40
|
+
echo "- [x] $step (PASS) - $rationale" >> "$report_file"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
echo " Result: FAIL"
|
|
44
|
+
echo "- [ ] $step (FAIL) - $rationale" >> "$report_file"
|
|
45
|
+
return 1
|
|
46
|
+
fi
|
|
47
|
+
|
|
48
|
+
echo " Result: ERROR (Gemini CLI failed)"
|
|
49
|
+
echo "- [ ] $step (ERROR) - Gemini CLI exit code $exit_code. Output: $model_output" >> "$report_file"
|
|
50
|
+
return 1
|
|
51
|
+
}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e45s02
|
|
3
|
+
# OKF report and gate verdict for audit-compliance.sh
|
|
4
|
+
|
|
5
|
+
if [ -n "${AUDIT_COMPLIANCE_REPORT_LOADED:-}" ]; then return 0; fi
|
|
6
|
+
AUDIT_COMPLIANCE_REPORT_LOADED=1
|
|
7
|
+
|
|
8
|
+
audit_write_okf_report() {
|
|
9
|
+
local OKF_DIR OKF_FILE TIMESTAMP GIT_COMMIT GATE TOTAL_GLOBAL_ALL
|
|
10
|
+
|
|
11
|
+
TOTAL_GLOBAL_ALL=$((TOTAL_GLOBAL_PASS + TOTAL_GLOBAL_FAIL))
|
|
12
|
+
if [[ $TOTAL_GLOBAL_ALL -gt 0 ]]; then
|
|
13
|
+
SCORE=$(awk "BEGIN { printf \"%d\", $TOTAL_GLOBAL_PASS * 100 / $TOTAL_GLOBAL_ALL }")
|
|
14
|
+
else
|
|
15
|
+
SCORE=0
|
|
16
|
+
fi
|
|
17
|
+
|
|
18
|
+
OKF_DIR="specs/verifications/reports"
|
|
19
|
+
mkdir -p "$OKF_DIR"
|
|
20
|
+
OKF_FILE="$OKF_DIR/audit-$(date +%Y-%m-%d).okf.md"
|
|
21
|
+
TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
|
22
|
+
GIT_COMMIT=$(git rev-parse HEAD 2>/dev/null || echo "unknown")
|
|
23
|
+
GATE=$(if [[ $SCORE -ge 94 ]]; then echo "pass"; else echo "fail"; fi)
|
|
24
|
+
|
|
25
|
+
cat > "$OKF_FILE" << OKF_EOF
|
|
26
|
+
---
|
|
27
|
+
okf_kind: verification-report
|
|
28
|
+
okf_version: "0.1"
|
|
29
|
+
score: ${SCORE}
|
|
30
|
+
gate_status: "${GATE}"
|
|
31
|
+
threshold: 94
|
|
32
|
+
total_pass: ${TOTAL_GLOBAL_PASS}
|
|
33
|
+
total_fail: ${TOTAL_GLOBAL_FAIL}
|
|
34
|
+
total_waived: ${TOTAL_GLOBAL_WAIVED}
|
|
35
|
+
generated_by: scripts/audit-compliance.sh
|
|
36
|
+
generated_at: "${TIMESTAMP}"
|
|
37
|
+
git_commit: "${GIT_COMMIT}"
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
# Compliance Audit — $(date +%Y-%m-%d)
|
|
41
|
+
|
|
42
|
+
**Score:** ${SCORE}% (${TOTAL_GLOBAL_PASS}/${TOTAL_GLOBAL_ALL} passed, ${TOTAL_GLOBAL_WAIVED} waived)
|
|
43
|
+
**Gate:** ${GATE} | **Threshold:** 94%
|
|
44
|
+
|
|
45
|
+
See \`specs/verifications/reports/audit-*.md\` for detailed step-by-step reports.
|
|
46
|
+
OKF_EOF
|
|
47
|
+
|
|
48
|
+
echo "OKF report: $OKF_FILE"
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
audit_print_summary_and_exit() {
|
|
52
|
+
local TOTAL_GLOBAL_ALL=$((TOTAL_GLOBAL_PASS + TOTAL_GLOBAL_FAIL))
|
|
53
|
+
|
|
54
|
+
echo "============================================================"
|
|
55
|
+
echo "Global Audit Summary:"
|
|
56
|
+
echo " TOTAL PASS: $TOTAL_GLOBAL_PASS"
|
|
57
|
+
echo " TOTAL FAIL: $TOTAL_GLOBAL_FAIL"
|
|
58
|
+
echo " TOTAL WAIVED: $TOTAL_GLOBAL_WAIVED (excluded from denominator)"
|
|
59
|
+
[[ $TOTAL_GLOBAL_EXPIRED -gt 0 ]] && echo " EXPIRED WAIVERS: $TOTAL_GLOBAL_EXPIRED (counted as FAIL)"
|
|
60
|
+
|
|
61
|
+
audit_write_okf_report
|
|
62
|
+
|
|
63
|
+
if [[ $TOTAL_GLOBAL_WAIVED -gt 0 ]]; then
|
|
64
|
+
echo " SCORE: ${SCORE}% (of ${TOTAL_GLOBAL_ALL} unwaived checks, threshold 94%)"
|
|
65
|
+
else
|
|
66
|
+
echo " SCORE: ${SCORE}% (threshold 94%)"
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
if [[ $SCORE -ge 94 ]]; then
|
|
70
|
+
echo " GATE: PASS"
|
|
71
|
+
exit 0
|
|
72
|
+
fi
|
|
73
|
+
echo " GATE: FAIL (below 94%)"
|
|
74
|
+
exit 1
|
|
75
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# story: e45s02
|
|
3
|
+
# Feature-file runner for audit-compliance.sh
|
|
4
|
+
|
|
5
|
+
if [ -n "${AUDIT_COMPLIANCE_RUNNER_LOADED:-}" ]; then return 0; fi
|
|
6
|
+
AUDIT_COMPLIANCE_RUNNER_LOADED=1
|
|
7
|
+
|
|
8
|
+
source "$(dirname "${BASH_SOURCE[0]}")/audit-compliance-judge.sh"
|
|
9
|
+
WAIVER_FILE="specs/verifications/waivers.yaml"
|
|
10
|
+
true && source "$(dirname "${BASH_SOURCE[0]}")/waiver-utils.sh"
|
|
11
|
+
|
|
12
|
+
audit_process_step() {
|
|
13
|
+
local step="$1" feature_name="$2" scenario_name="$3" report_file="$4"
|
|
14
|
+
local sanitized_step step_script evidence exit_code waiver_code
|
|
15
|
+
|
|
16
|
+
echo " [STEP] $step"
|
|
17
|
+
[[ "$DRY_RUN" == "true" ]] && return 0
|
|
18
|
+
|
|
19
|
+
sanitized_step=$(echo "$step" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//')
|
|
20
|
+
step_script="specs/verifications/steps/${sanitized_step}.sh"
|
|
21
|
+
|
|
22
|
+
if [[ ! -f "$step_script" ]]; then
|
|
23
|
+
echo " Result: FAIL (Missing evidence: $step_script)"
|
|
24
|
+
echo "- [ ] $step (FAIL) - No verification script found at $step_script" >> "$report_file"
|
|
25
|
+
((TOTAL_GLOBAL_FAIL++))
|
|
26
|
+
return 1
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
echo " [EXEC] Gathering evidence: $step_script"
|
|
30
|
+
evidence=$(bash "$step_script" 2>&1)
|
|
31
|
+
exit_code=$?
|
|
32
|
+
|
|
33
|
+
if [[ "$JUDGE" == "gemini" ]]; then
|
|
34
|
+
audit_judge_with_gemini "$step" "$feature_name" "$scenario_name" "$evidence" "$report_file"
|
|
35
|
+
return $?
|
|
36
|
+
fi
|
|
37
|
+
|
|
38
|
+
if [[ $exit_code -eq 0 ]]; then
|
|
39
|
+
echo " Result: PASS"
|
|
40
|
+
echo "- [x] $step (PASS)" >> "$report_file"
|
|
41
|
+
return 0
|
|
42
|
+
fi
|
|
43
|
+
|
|
44
|
+
has_waiver "$sanitized_step"
|
|
45
|
+
waiver_code=$?
|
|
46
|
+
|
|
47
|
+
if [[ $waiver_code -eq 0 ]]; then
|
|
48
|
+
echo " Result: WAIVED (documented exception)"
|
|
49
|
+
echo "- [~] $step (WAIVED)" >> "$report_file"
|
|
50
|
+
((TOTAL_GLOBAL_WAIVED++))
|
|
51
|
+
return 3
|
|
52
|
+
fi
|
|
53
|
+
if [[ $waiver_code -eq 2 ]]; then
|
|
54
|
+
echo " Result: FAIL (EXPIRED WAIVER)"
|
|
55
|
+
echo "- [ ] $step (FAIL) - EXPIRED WAIVER: review_date has passed" >> "$report_file"
|
|
56
|
+
((TOTAL_GLOBAL_EXPIRED++))
|
|
57
|
+
((TOTAL_GLOBAL_FAIL++))
|
|
58
|
+
return 1
|
|
59
|
+
fi
|
|
60
|
+
|
|
61
|
+
echo " Result: FAIL"
|
|
62
|
+
echo "- [ ] $step (FAIL) - $evidence" >> "$report_file"
|
|
63
|
+
((TOTAL_GLOBAL_FAIL++))
|
|
64
|
+
return 1
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
audit_run_file() {
|
|
68
|
+
local FEATURE_FILE="$1" REPORT_FILE line TOTAL_PASS TOTAL_FAIL step_result
|
|
69
|
+
local CURRENT_FEATURE="" CURRENT_SCENARIO="" IN_SCENARIO=false
|
|
70
|
+
|
|
71
|
+
echo "------------------------------------------------------------"
|
|
72
|
+
echo "FEATURE: $FEATURE_FILE"
|
|
73
|
+
|
|
74
|
+
REPORT_FILE="specs/verifications/reports/audit-$(basename "$FEATURE_FILE" .feature)-$(date +%Y%m%d-%H%M%S).md"
|
|
75
|
+
mkdir -p specs/verifications/reports
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
echo "# Audit Report: $FEATURE_FILE"
|
|
79
|
+
echo "Date: $(date)"
|
|
80
|
+
echo "Mode: Autonomous Verification (Judge: $JUDGE)"
|
|
81
|
+
echo ""
|
|
82
|
+
} > "$REPORT_FILE"
|
|
83
|
+
|
|
84
|
+
TOTAL_PASS=0
|
|
85
|
+
TOTAL_FAIL=0
|
|
86
|
+
|
|
87
|
+
while IFS= read -r line; do
|
|
88
|
+
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
89
|
+
|
|
90
|
+
if [[ "$line" =~ ^Feature: ]]; then
|
|
91
|
+
CURRENT_FEATURE="${line#Feature: }"
|
|
92
|
+
echo "FEATURE: $CURRENT_FEATURE"
|
|
93
|
+
echo "## Feature: $CURRENT_FEATURE" >> "$REPORT_FILE"
|
|
94
|
+
elif [[ "$line" =~ ^Scenario: ]]; then
|
|
95
|
+
CURRENT_SCENARIO="${line#Scenario: }"
|
|
96
|
+
if [[ -n "$SCENARIO_FILTER" && "$CURRENT_SCENARIO" != "$SCENARIO_FILTER" ]]; then
|
|
97
|
+
IN_SCENARIO=false
|
|
98
|
+
continue
|
|
99
|
+
fi
|
|
100
|
+
IN_SCENARIO=true
|
|
101
|
+
echo " SCENARIO: $CURRENT_SCENARIO"
|
|
102
|
+
echo "### Scenario: $CURRENT_SCENARIO" >> "$REPORT_FILE"
|
|
103
|
+
elif [[ "$line" =~ ^(Given|When|Then|And|But)\ ]]; then
|
|
104
|
+
[[ "$IN_SCENARIO" != "true" ]] && continue
|
|
105
|
+
audit_process_step "$line" "$CURRENT_FEATURE" "$CURRENT_SCENARIO" "$REPORT_FILE"
|
|
106
|
+
step_result=$?
|
|
107
|
+
if [[ $step_result -eq 3 ]]; then
|
|
108
|
+
:
|
|
109
|
+
elif [[ $step_result -eq 0 ]]; then
|
|
110
|
+
((TOTAL_PASS++))
|
|
111
|
+
((TOTAL_GLOBAL_PASS++))
|
|
112
|
+
else
|
|
113
|
+
((TOTAL_FAIL++))
|
|
114
|
+
fi
|
|
115
|
+
fi
|
|
116
|
+
done < "$FEATURE_FILE"
|
|
117
|
+
|
|
118
|
+
echo ""
|
|
119
|
+
echo "File Summary: PASS: $TOTAL_PASS, FAIL: $TOTAL_FAIL"
|
|
120
|
+
echo "Report saved to: $REPORT_FILE"
|
|
121
|
+
}
|