-
Notifications
You must be signed in to change notification settings - Fork 1
193 lines (174 loc) · 7.84 KB
/
Copy pathdeploy.yml
File metadata and controls
193 lines (174 loc) · 7.84 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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
name: Deploy to GitHub Pages
# Publication gate (ADR-2003 closeout, 2026-09-05).
#
# The previous version built the site and uploaded it. Nothing between those two
# steps could reject a defective candidate: a build that produced a page with
# missing media, broken internal links, absent meta tags or a stale diagram
# baseline was published exactly as readily as a correct one, and the repo's
# verify sequence (`npm run verify`, the dream-cycle evaluators, the diagram
# guard, the drift counter) ran only in other workflows or by hand.
#
# The build job now runs those gates BEFORE `upload-pages-artifact`, so a
# candidate that fails any of them never reaches the deploy job. The gates are
# split into two classes:
#
# BLOCKING asset inventory, build sentinel, internal-link integrity, meta
# tags, structured data, diagram baseline. All are self-contained:
# they need only this checkout, so they are enforceable here and a
# failure is a genuine defect in the candidate.
#
# REPORTED the self-description drift counter, which reads its truth from a
# pinned agentbox checkout. Where that sibling checkout is
# unavailable (no credentials on this runner) the axis cannot be
# evaluated, so the counter runs in reported mode and does not block
# — the partial-source failure mode of ADR-005 §Decision 2. When the
# checkout succeeds it blocks, because then it is measuring
# something real.
#
# The build receipt (website/build-receipt.json) records the published artefact
# revision, the dist tree digest, per-asset hashes, and each gate's verdict, and
# is uploaded alongside the site so a published page can be traced to the
# revision and the checks that admitted it.
on:
push:
branches: [main]
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: pages
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
- name: Install Node
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
node-version: '22'
# Pinned to the same revision as scripts/drift-counter/allowlist.json
# .source_pin.revision. Optional: without credentials this step fails and
# the drift counter degrades to reported mode rather than blocking.
- name: Check out agentbox (drift-counter count sources, pinned)
id: agentbox
continue-on-error: true
uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
with:
repository: DreamLab-AI/agentbox
ref: b859b37d2ffb74c08cfbb9aa9ad7e1cc61d6b188
path: _agentbox
# ── build ───────────────────────────────────────────────────────────
# build.sh itself fails on any missing REQUIRED asset declared in
# website/assets.manifest.json.
- name: Build website
run: |
cd website
chmod +x build.sh
./build.sh
# ── BLOCKING gate 1: asset inventory, stamped with the published revision
- name: Gate — asset inventory and build receipt
run: |
node scripts/website-assets.mjs verify \
--published-revision "${GITHUB_SHA}"
# ── BLOCKING gate 2: the build output exists and is a site
- name: Gate — build output
run: |
set -euo pipefail
OUT="$(bash scripts/dream-build-check.sh)"
echo "$OUT"
grep -q '^BUILD-OK$' <<< "$OUT" || { echo "::error::build output check failed"; exit 1; }
# ── BLOCKING gate 3: every internal link and asset reference resolves
- name: Gate — internal link integrity
run: |
set -euo pipefail
OUT="$(bash scripts/dream-link-check.sh)"
echo "$OUT"
grep -q '^LINK-INTEGRITY-OK$' <<< "$OUT" \
|| { echo "::error::internal links or assets are missing from dist/"; exit 1; }
# ── BLOCKING gate 4: required meta tags are present
- name: Gate — meta tags
run: |
set -euo pipefail
OUT="$(bash scripts/dream-meta-tags-scan.sh)"
echo "$OUT"
grep -q '^META-SCAN-OK$' <<< "$OUT" \
|| { echo "::error::required meta tags missing from the built page"; exit 1; }
# ── BLOCKING gate 5: structured data parses
- name: Gate — structured data
run: |
set -euo pipefail
OUT="$(bash scripts/dream-structured-data-scan.sh)"
echo "$OUT"
grep -q '^SD-SCAN-OK$' <<< "$OUT" \
|| { echo "::error::structured data on the built page does not parse"; exit 1; }
# ── BLOCKING gate 6: committed diagram baseline still has visible text
# The browser-free authoritative guard from the RES-b render gate; the
# re-render half needs Chrome and stays in diagram-render.yml.
- name: Gate — diagram baseline (text visibility)
run: node scripts/check-diagram-text.js presentation/report/diagrams/rendered
# ── REPORTED (or blocking, when the sibling checkout landed) ─────────
- name: Gate — self-description drift counter
id: drift
env:
DRIFT_AGENTBOX_DIR: ${{ github.workspace }}/_agentbox
run: |
set -uo pipefail
if [[ "${{ steps.agentbox.outcome }}" != "success" ]]; then
echo "::warning::agentbox checkout unavailable — drift counter runs in REPORTED mode and does not block."
node scripts/drift-counter/drift-counter.mjs || true
echo "verdict=reported" >> "$GITHUB_OUTPUT"
exit 0
fi
node scripts/drift-counter/drift-counter.mjs
echo "verdict=enforced-pass" >> "$GITHUB_OUTPUT"
# ── record the gate verdicts in the receipt ──────────────────────────
- name: Record gate verdicts in the build receipt
run: |
set -euo pipefail
node -e '
const fs = require("node:fs");
const p = "website/build-receipt.json";
const r = JSON.parse(fs.readFileSync(p, "utf8"));
r.gates = {
asset_inventory: "blocking-pass",
build_output: "blocking-pass",
link_integrity: "blocking-pass",
meta_tags: "blocking-pass",
structured_data: "blocking-pass",
diagram_baseline: "blocking-pass",
drift_counter: process.env.DRIFT_VERDICT || "reported",
};
r.published = {
target: "github-pages",
revision: process.env.GITHUB_SHA,
workflow_run: process.env.GITHUB_RUN_ID,
ref: process.env.GITHUB_REF,
};
fs.writeFileSync(p, JSON.stringify(r, null, 2) + "\n");
console.log(JSON.stringify(r.gates, null, 2));
'
env:
DRIFT_VERDICT: ${{ steps.drift.outputs.verdict }}
- name: Upload build receipt
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02
with:
name: website-build-receipt
path: website/build-receipt.json
# Only reached when every blocking gate passed.
- name: Upload artifact
uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
with:
path: website/dist
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e