-
Notifications
You must be signed in to change notification settings - Fork 0
138 lines (127 loc) · 5.48 KB
/
Copy pathwire-shape-contract.yml
File metadata and controls
138 lines (127 loc) · 5.48 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
name: Wire-Shape Contract
# QF-14 Java arm: blocks drift between Java @JsonProperty-annotated
# classes and the OpenAPI specs that are the authoritative wire
# contract. Runs on every PR and push to main. Drift NOT covered by
# the baseline fails the check.
#
# Specs are fetched from the getaxonflow/axonflow community mirror at
# the SHA recorded in tests/fixtures/wire-shape-baseline.json so the
# gate is deterministic. A 'spec-pin-bump' label is required on PRs
# that change the SHA, preserving review integrity (a PR that both
# moved the SHA and the Java classes could otherwise silence drift).
#
# To regenerate the baseline:
# python3 scripts/wire_shape/refresh.py <specs_dir>
on:
pull_request:
branches: [main]
paths:
- 'src/main/java/**/*.java'
- 'tests/fixtures/wire-shape-baseline.json'
- 'scripts/wire_shape/**'
- '.github/workflows/wire-shape-contract.yml'
push:
branches: [main]
paths:
- 'src/main/java/**/*.java'
- 'tests/fixtures/wire-shape-baseline.json'
- 'scripts/wire_shape/**'
- '.github/workflows/wire-shape-contract.yml'
permissions:
contents: read
concurrency:
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
jobs:
wire-shape:
name: Validate Wire Shape
runs-on: ubuntu-latest
env:
AXONFLOW_TELEMETRY: 'off'
steps:
- name: Checkout SDK (full history for SHA-bump guard)
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Read pinned OpenAPI specs SHA from baseline
id: specs_sha
run: |
python3 - <<'PY' >> "$GITHUB_OUTPUT"
import json
import sys
path = "tests/fixtures/wire-shape-baseline.json"
data = json.load(open(path))
sha = (data.get("openapi_specs_sha", "") or "").strip()
if not sha:
print(
f"::error::{path} is missing openapi_specs_sha. "
"Regenerate via scripts/wire_shape/refresh.py.",
file=sys.stderr,
)
sys.exit(1)
print(f"sha={sha}")
PY
- name: Guard against unauthorized OpenAPI specs SHA bump
if: github.event_name == 'pull_request'
env:
PR_LABELS: ${{ toJSON(github.event.pull_request.labels.*.name) }}
BASE_REF: ${{ github.base_ref }}
PR_SHA: ${{ steps.specs_sha.outputs.sha }}
run: |
set -e
BASE_FILE=$(mktemp)
if git show "origin/${BASE_REF}:tests/fixtures/wire-shape-baseline.json" > "$BASE_FILE" 2>/dev/null; then
# File exists on the base branch. It MUST parse — a malformed
# baseline file would otherwise let `BASE_SHA` come back empty
# and route this PR through the "first pin introduction"
# bypass below, silently authorizing a SHA bump.
BASE_SHA=$(python3 -c "import json, sys; print(json.load(open(sys.argv[1])).get('openapi_specs_sha','') or '')" "$BASE_FILE")
else
# File genuinely absent on the base branch (first-time
# introduction). Distinguishing this from "file present but
# unparseable" is what guards the bypass.
BASE_SHA=""
fi
rm -f "$BASE_FILE"
if [ -z "$BASE_SHA" ]; then
if git cat-file -e "origin/${BASE_REF}:tests/fixtures/wire-shape-baseline.json" 2>/dev/null; then
echo "::error::tests/fixtures/wire-shape-baseline.json on origin/${BASE_REF} parsed with empty openapi_specs_sha."
echo "::error::This is unrecoverable from inside the gate. Re-run scripts/wire_shape/refresh.py on main."
exit 1
fi
echo "::notice::Base branch has no wire-shape-baseline.json yet; treating this PR as first pin introduction."
exit 0
fi
if [ "$BASE_SHA" = "$PR_SHA" ]; then
echo "openapi_specs_sha unchanged (${PR_SHA})."
exit 0
fi
echo "SHA change detected: ${BASE_SHA} -> ${PR_SHA}"
HAS_LABEL=$(printf '%s' "$PR_LABELS" | python3 -c "import json, sys; print('spec-pin-bump' in json.load(sys.stdin))")
if [ "$HAS_LABEL" = "True" ]; then
echo "::notice::'spec-pin-bump' label present — SHA bump authorized."
exit 0
fi
echo "::error::openapi_specs_sha changed from ${BASE_SHA} to ${PR_SHA}."
echo "::error::The wire-shape contract's spec revision is pinned to preserve"
echo "::error::review integrity: a SHA change in the same PR as SDK changes"
echo "::error::can silence drift by retargeting the contract to a friendlier"
echo "::error::revision. Either split into a dedicated SHA-bump PR, or"
echo "::error::apply the 'spec-pin-bump' label to this PR."
exit 1
- name: Checkout OpenAPI specs (pinned to baseline SHA)
uses: actions/checkout@v4
with:
repository: getaxonflow/axonflow
ref: ${{ steps.specs_sha.outputs.sha }}
path: axonflow-community
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install PyYAML
run: pip install 'pyyaml>=6,<7'
- name: Run wire-shape contract validator
env:
AXONFLOW_OPENAPI_SPECS_DIR: ${{ github.workspace }}/axonflow-community/docs/api
run: python3 scripts/wire_shape/validate.py