-
-
Notifications
You must be signed in to change notification settings - Fork 0
139 lines (133 loc) · 5.4 KB
/
Copy pathcoq-proof-gate.yml
File metadata and controls
139 lines (133 loc) · 5.4 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
# SPDX-License-Identifier: MPL-2.0
# This workflow is managed by gh actions-lock.
# This workflow is managed by gh actions-lock.
# Coq/Rocq proof gate for the `formal/` mechanised-metatheory track (issue #513).
#
# This gate is deliberately FAIL-CLOSED. It does NOT probe for the prover and
# skip when absent — the container guarantees `coqc` exists, so a missing
# prover is an infrastructure failure, not a silent pass.
#
# `formal/justfile` remains the single source of truth for the proof list and
# its dependency order; this workflow parses that list rather than duplicating
# it, and fails if any `formal/*.v` on disk is not named there.
name: Coq Proof Gate
on:
pull_request:
paths:
- 'formal/**'
- '.github/workflows/coq-proof-gate.yml'
push:
branches: [main]
paths:
- 'formal/**'
- '.github/workflows/coq-proof-gate.yml'
workflow_dispatch:
permissions: read-all
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
jobs:
coq-proofs:
runs-on: ubuntu-latest
timeout-minutes: 30
# The image ships bash 5.2, but GitHub fell back to `sh -e {0}` (dash) on
# the first run, which rejects `set -o pipefail` and the bash-only string
# operations below. Declare the shell explicitly rather than depending on
# the runner's detection.
defaults:
run:
shell: bash
container:
# coqorg/coq:8.20 — pinned by digest. `formal/README.adoc` documents 8.18;
# the corpus was verified to check clean on 8.20.1 (deprecation warnings
# for `app_length` only, no errors).
image: coqorg/coq@sha256:e50d77c4c5a9aa0d76ae1b343d79c5f922da3a75054b79c5dc635895438e4674
options: --user root
steps:
- uses: actions/checkout@v7.0.1
# The coqorg images install Coq into an opam switch owned by the `coq`
# user and put it on PATH via an ENTRYPOINT wrapper. GitHub Actions
# overrides the entrypoint for job containers, so that wrapper never
# runs and `coqc` is not on PATH — the switch has to be added by hand.
# Globbed rather than hard-coded so an image bump does not silently
# break the gate; fails loudly if the switch cannot be located.
- name: Put the image's opam switch on PATH
run: |
set -euo pipefail
sw="$(ls -d /home/coq/.opam/*/bin 2>/dev/null | head -1 || true)"
if [ -z "$sw" ] || [ ! -x "$sw/coqc" ]; then
echo "::error::could not locate coqc in the image's opam switch"
exit 1
fi
echo "$sw" >> "$GITHUB_PATH"
echo "added $sw to PATH"
# The coqorg images install Coq into an opam switch owned by the `coq`
# user and put it on PATH via an ENTRYPOINT wrapper. GitHub Actions
# overrides the entrypoint for job containers, so that wrapper never
# runs and `coqc` is not on PATH — the switch has to be added by hand.
# Globbed rather than hard-coded so an image bump does not silently
# break the gate; fails loudly if the switch cannot be located.
- name: Put the image's opam switch on PATH
run: |
set -euo pipefail
sw="$(ls -d /home/coq/.opam/*/bin 2>/dev/null | head -1 || true)"
if [ -z "$sw" ] || [ ! -x "$sw/coqc" ]; then
echo "::error::could not locate coqc in the image's opam switch"
exit 1
fi
echo "$sw" >> "$GITHUB_PATH"
echo "added $sw to PATH"
- name: Record prover version
run: coqc --version
- name: Extract the ordered proof list from formal/justfile
id: list
run: |
set -euo pipefail
cd formal
list="$(sed -n '/for f in /,/; do/p' justfile \
| tr '\n' ' ' \
| sed 's/.*for f in //; s/; do.*//; s/\\//g' \
| tr -s ' ')"
if [ -z "${list// /}" ]; then
echo "::error::could not parse the proof list out of formal/justfile"
exit 1
fi
echo "count=$(printf '%s' "$list" | wc -w)"
echo "list=$list" >> "$GITHUB_OUTPUT"
- name: Guard — every formal/*.v must be wired into the gate
env:
LIST: ${{ steps.list.outputs.list }}
run: |
set -euo pipefail
cd formal
missing=0
for f in *.v; do
b="${f%.v}"
case " $LIST " in
*" $b "*) ;;
*) echo "::error file=formal/$f::proof file is not listed in formal/justfile — it would never be checked"; missing=1 ;;
esac
done
[ "$missing" -eq 0 ] || exit 1
echo "all on-disk proofs are wired into the gate"
- name: Type-check every proof and reject any axiom / Admitted
env:
LIST: ${{ steps.list.outputs.list }}
run: |
set -euo pipefail
cd formal
all=""
for f in $LIST; do
echo "== coqc $f.v =="
o="$(coqc -Q . ASFormal "$f.v")"
printf '%s\n' "$o"
all+="$o"$'\n'
done
# `Print Assumptions` emits "Axioms:" when a theorem depends on an
# axiom or an `Admitted` proof; "Closed under the global context"
# is the clean result.
if printf '%s' "$all" | grep -q "Axioms:"; then
echo "::error::a proof depends on an axiom / Admitted"
exit 1
fi
echo "OK: all proofs mechanised; no axioms."