-
Notifications
You must be signed in to change notification settings - Fork 0
136 lines (124 loc) · 5.13 KB
/
Copy pathwire-shape-contract.yml
File metadata and controls
136 lines (124 loc) · 5.13 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
name: Wire-Shape Contract
# QF-15 TypeScript arm: blocks drift between exported TS interfaces
# 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 TS types could otherwise silence drift).
#
# To regenerate the baseline:
# node scripts/wire-shape/refresh.js <specs_dir>
on:
pull_request:
branches: [main]
paths:
- 'src/**/*.ts'
- 'tests/fixtures/wire-shape-baseline.json'
- 'scripts/wire-shape/**'
- '.github/workflows/wire-shape-contract.yml'
- 'package.json'
- 'package-lock.json'
push:
branches: [main]
paths:
- 'src/**/*.ts'
- 'tests/fixtures/wire-shape-baseline.json'
- 'scripts/wire-shape/**'
- '.github/workflows/wire-shape-contract.yml'
- 'package.json'
- 'package-lock.json'
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
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.js.",
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_SHA=$(
git show "origin/${BASE_REF}:tests/fixtures/wire-shape-baseline.json" 2>/dev/null \
| python3 -c "import json, sys; print(json.load(sys.stdin).get('openapi_specs_sha','') or '')" \
|| true
)
if [ -z "$BASE_SHA" ]; then
echo "::notice::Base branch has no openapi_specs_sha 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 Node.js
uses: actions/setup-node@v4
with:
node-version: '20.x'
cache: 'npm'
- name: Install dependencies
run: npm ci
- name: Run wire-shape contract validator
env:
AXONFLOW_OPENAPI_SPECS_DIR: ${{ github.workspace }}/axonflow-community/docs/api
run: node scripts/wire-shape/validate.js
- name: Run transformer-coverage gate (type-vs-implementation)
# Catches the class of bug where a typed wire field exists on
# the interface but the runtime transformer's return literal
# doesn't populate it (cancelPlan.success, mapBudgetResponse
# missing tenant_id/org_id, listUsageRecords missing 8 wire
# fields — every gap caught by the post-merge audit on PR
# #185 would have been blocked by this gate at PR time).
run: node scripts/transformer-coverage/check.js --baseline .lint_baselines/transformer_coverage.json