Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions scripts/check-trusted-base.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,11 +91,50 @@ emit_marker() {
printf '%s\t%s\t%s\t%s\n' "$1" "$2" "$3" "$4" >> "$markers_tsv"
}

# Coq comments nest and may span lines. A line-oriented grep sees prose inside
# `(* ... *)` as code whenever the interior line does not begin with a comment
# delimiter. Strip nested block comments and strings while preserving line
# count before looking for proof escape hatches. Coq permits multiline strings
# and escapes a quote as `""`, so string state spans lines and takes precedence
# over comment delimiters. An unterminated string emits a synthetic marker so
# malformed input fails closed instead of hiding the remainder of the file.
strip_coq_noncode() {
awk '
{
line = $0; out = ""; i = 1; n = length(line)
while (i <= n) {
c = substr(line, i, 1); pair = substr(line, i, 2)
if (instr) {
if (pair == "\"\"") { i += 2; continue }
if (c == "\"") { instr = 0; i++; continue }
i++; continue
}
if (c == "\"") { instr = 1; i++; continue }
if (depth > 0) {
if (pair == "(*") { depth++; i += 2; continue }
if (pair == "*)") { depth--; i += 2; continue }
i++; continue
}
if (pair == "(*") { depth++; i += 2; continue }
out = out c; i++
}
print out
}
END {
if (instr) print "Axiom __unterminated_coq_string"
}
' "$1"
}
Comment thread
hyperpolymath marked this conversation as resolved.

# Coq Axiom / Admitted
echo "$proof_files" | grep -E '\.v$' | while read -r f; do
[ -z "$f" ] && continue
grep -nE '^[[:space:]]*(Axiom|Admitted|admit\.)' "$f" 2>/dev/null | while IFS=: read -r ln rest; do
emit_marker "$f" "$ln" "coq-axiom-or-admit" "$(echo "$rest" | head -c 80)"
strip_coq_noncode "$f" 2>/dev/null | grep -nE '^[[:space:]]*(Axiom|Admitted|admit\.)' | while IFS=: read -r ln rest; do
orig="$(sed -n "${ln}p" "$f" 2>/dev/null)"
# The language-aware pass already removed comments. Do not feed the
# original line through the generic prefix heuristic: `(* note *) Admitted.`
# is executable debt even though its original text begins with a comment.
printf '%s\t%s\t%s\t%s\n' "$f" "$ln" "coq-axiom-or-admit" "$(echo "$orig" | head -c 80)" >> "$markers_tsv"
done
done

Expand Down
87 changes: 87 additions & 0 deletions scripts/tests/check-trusted-base-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,78 @@
EOF
}

setup_coq_multiline_comments_only() {

Check warning on line 188 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNkFW3Z_PDv27CRSIQ&open=AaBNkFW3Z_PDv27CRSIQ&pullRequest=694
mkdir -p formal
cat > formal/Commentary.v <<'EOF'
(** A documentation block may discuss old proof state.
Admitted markers in prior revisions are not executable here.
(* Nested comments may also mention:
admit.
*)
Axiom references in prose are not declarations. *)
Theorem closed : True.
Proof. exact I. Qed.
EOF
}

setup_coq_comment_then_real_admitted() {

Check warning on line 202 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNkFW3Z_PDv27CRSIR&open=AaBNkFW3Z_PDv27CRSIR&pullRequest=694
mkdir -p formal docs
cat > formal/ActualDebt.v <<'EOF'
(* Admitted. inside a comment must not count. *)
Theorem open_obligation : True.
Admitted.
EOF
cat > docs/proof-debt.md <<'EOF'
# Proof Debt
(Intentionally empty: the real marker must fail this positive control.)
EOF
}

setup_coq_string_delimiters_then_real_marker() {

Check warning on line 215 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNlWjgVskNNOoG0bzV&open=AaBNlWjgVskNNOoG0bzV&pullRequest=694
mkdir -p formal docs
cat > formal/StringDelimiter.v <<'EOF'
From Coq Require Import Strings.String.
Definition opening_delimiter : string := "(* not a comment".
Definition escaped_quote : string := "text "" (* still a string".
Definition multiline_delimiters : string := "first line
(* neither opens a comment
nor does this close one *)
last line".
(* A quoted delimiter inside a real comment must not change its depth:
"(*"
*)
Axiom string_delimiters_do_not_hide_this : True.
EOF
cat > docs/proof-debt.md <<'EOF'
# Proof Debt
(Intentionally empty: a string delimiter must not hide the real axiom.)
EOF
}

setup_coq_unterminated_string() {

Check warning on line 236 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNmFNQGqlOf_YDhAxV&open=AaBNmFNQGqlOf_YDhAxV&pullRequest=694
mkdir -p formal docs
cat > formal/UnterminatedString.v <<'EOF'
From Coq Require Import Strings.String.
Definition malformed : string := "this never closes
Admitted.
EOF
cat > docs/proof-debt.md <<'EOF'
# Proof Debt
(Intentionally empty: malformed input must fail closed.)
EOF
}

setup_coq_leading_comment_then_real_marker() {

Check warning on line 249 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add an explicit return statement at the end of the function.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNlWjgVskNNOoG0bzW&open=AaBNlWjgVskNNOoG0bzW&pullRequest=694
mkdir -p formal docs
cat > formal/LeadingComment.v <<'EOF'
(* explanatory prefix *) Admitted.
EOF
cat > docs/proof-debt.md <<'EOF'
# Proof Debt
(Intentionally empty: a leading comment must not hide the real marker.)
EOF
}

# Existing behaviour must still work.
run_case "marker with no docs and no ignore fails (early exit)" \
1 "No docs/proof-debt.md (or equivalent) found" setup_marker_no_docs
Expand All @@ -211,6 +283,21 @@
run_case "mixed: one marker exempted, one documented in proof-debt" \
0 "1 marker(s) exempted via .trusted-base-ignore" setup_mixed_exempt_and_documented

run_case "Coq nested multiline comment prose is not executable debt" \
0 "No soundness-relevant escape hatches detected" setup_coq_multiline_comments_only

run_case "real Coq Admitted after a comment still fails" \
1 "1/1 escape hatch(es) are undocumented" setup_coq_comment_then_real_admitted

run_case "Coq comment delimiters inside strings cannot hide a later axiom" \
1 "1/1 escape hatch(es) are undocumented" setup_coq_string_delimiters_then_real_marker

run_case "real Coq marker after a same-line leading comment still fails" \
1 "1/1 escape hatch(es) are undocumented" setup_coq_leading_comment_then_real_marker

run_case "unterminated Coq string fails closed instead of hiding the file" \
1 "1/1 escape hatch(es) are undocumented" setup_coq_unterminated_string

Check warning on line 299 in scripts/tests/check-trusted-base-test.sh

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define a constant instead of using the literal '1/1 escape hatch(es) are undocumented' 6 times.

See more on https://sonarcloud.io/project/issues?id=hyperpolymath_standards&issues=AaBNmFNQGqlOf_YDhAxW&open=AaBNmFNQGqlOf_YDhAxW&pullRequest=694

echo
echo "PASS=$PASS FAIL=$FAIL"
if [[ "$FAIL" -gt 0 ]]; then
Expand Down
Loading