forked from MudwoodLabs/pyrxd
-
Notifications
You must be signed in to change notification settings - Fork 0
159 lines (146 loc) · 6.51 KB
/
Copy pathdocs.yml
File metadata and controls
159 lines (146 loc) · 6.51 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
name: Docs
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
# Single in-flight deploy at a time, but don't cancel a running one.
concurrency:
group: pages
cancel-in-progress: false
permissions:
contents: read
jobs:
build:
name: Build Sphinx HTML
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
- uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
with:
python-version: "3.12"
cache: pip
- name: Install build dependencies
# Scorecard flags these as "pipCommand not pinned by hash"
# (PinnedDependenciesID). Accepted residual risk:
# * `pip install --upgrade pip` is the canonical bootstrap; pinning
# pip itself would force regular catch-up bumps with no real
# security gain (this step runs in an ephemeral runner, no
# persistent attack surface).
# * `pip install -r docs/requirements.txt` is version-pinned in
# that file (sphinx>=7,<9 etc.). Hash-pinning would require
# `pip-compile --generate-hashes` and a regenerated
# requirements file on every Sphinx bump — high friction, low
# win for a docs-only build.
# * `pip install -e .` is an editable dev install; there's no
# wheel to hash since the source is the local checkout.
# Bandit / OSV / CodeQL still scan the actual code paths.
run: |
python -m pip install --upgrade pip
pip install -r docs/requirements.txt
pip install -e .
- name: Build + vendor wheels for the inspect page
# The browser-hosted inspect page (docs/inspect/) loads pyrxd
# at runtime from a wheel served alongside the page, plus
# cbor2 (the only runtime dep the inspect path actually
# needs). Both wheels are SHA-256 pinned via manifest.json
# and verified in JS before installation — see
# docs/inspect_static/inspect/inspect.js.
#
# cbor2 is vendored from PyPI at this fixed version (5.4.6 —
# the last release with a pure-Python wheel; later versions
# are C-only and not micropip-installable under WASM). The
# SHA-256 here is the upstream PyPI hash for that file. Bump
# only deliberately and update the SHA at the same time.
#
# The wheels + manifest.json are placed into
# docs/inspect_static/inspect/wheels/, which sphinx-build
# ships verbatim via html_extra_path. Tested smoke-load
# happens in tests/web/test_facade_smoke.py before this step
# in CI.
run: |
set -euo pipefail
mkdir -p docs/inspect_static/inspect/wheels
cd docs/inspect_static/inspect/wheels
# 1. Build the pyrxd wheel from the current source.
pip wheel --wheel-dir . --no-deps ../../../..
wheel=$(ls pyrxd-*.whl | head -1)
if [ -z "$wheel" ]; then
echo "::error::pip wheel produced no pyrxd wheel"
exit 1
fi
# 2. Vendor the cbor2 wheel from PyPI. Pin the upstream
# SHA-256 here and verify; if PyPI ever serves different
# bytes (compromise, yank-and-reupload), this step fails
# closed before the wrong wheel reaches the deploy.
cbor2_url="https://files.pythonhosted.org/packages/d5/e1/af78b099196feaab7c0252108abc4f5cfd36d255ac47c4b4a695ff838bf9/cbor2-5.4.6-py3-none-any.whl"
cbor2_expected_sha="181ac494091d1f9c5bb373cd85514ce1eb967a8cf3ec298e8dfa8878aa823956"
curl -sSL -o cbor2-5.4.6-py3-none-any.whl "$cbor2_url"
cbor2_actual_sha=$(sha256sum cbor2-5.4.6-py3-none-any.whl | awk '{print $1}')
if [ "$cbor2_actual_sha" != "$cbor2_expected_sha" ]; then
echo "::error::cbor2 wheel SHA-256 mismatch: expected $cbor2_expected_sha, got $cbor2_actual_sha"
exit 1
fi
# 3. Compute SHA-256 of every artifact the page will fetch
# + verify, and write the manifest. The page-side JS
# refuses to install anything whose SHA doesn't match.
#
# The manifest is assembled via Python's ``json.dumps`` (not
# a shell heredoc) so any unexpected character in ``$wheel``
# — should ``pip wheel`` ever produce a filename with an
# embedded quote or backslash — is escaped properly rather
# than slipping into the JSON as a parser confusion. Audit
# finding NEW-3. The Python source lives in a tempfile so
# YAML doesn't try to parse the colons in the dict literal.
wheel_sha=$(sha256sum "$wheel" | awk '{print $1}')
glue_sha=$(sha256sum ../glue.py | awk '{print $1}')
git_sha="${GITHUB_SHA:-unknown}"
export WHEEL="$wheel"
export WHEEL_SHA="$wheel_sha"
export CBOR2_SHA="$cbor2_expected_sha"
export GLUE_SHA="$glue_sha"
export GIT_SHA="$git_sha"
script=$(mktemp)
cat > "$script" <<'PY'
import json, os
manifest = {
"wheel": os.environ["WHEEL"],
"wheel_sha256": os.environ["WHEEL_SHA"],
"cbor2_wheel": "cbor2-5.4.6-py3-none-any.whl",
"cbor2_sha256": os.environ["CBOR2_SHA"],
"glue_sha256": os.environ["GLUE_SHA"],
"git_sha": os.environ["GIT_SHA"][:7],
"git_sha_full": os.environ["GIT_SHA"],
}
with open("manifest.json", "w") as f:
json.dump(manifest, f, indent=2)
PY
python3 "$script"
rm -f "$script"
echo "Wheels:"
ls -la
echo "Manifest:"
cat manifest.json
- name: Build HTML
run: sphinx-build -b html docs docs/_build/html
- name: Upload artifact
uses: actions/upload-pages-artifact@fc324d3547104276b827a68afc52ff2a11cc49c9 # v5.0.0
with:
path: docs/_build/html
deploy:
name: Deploy to GitHub Pages
# Only deploy on pushes to main (and manual dispatch). PRs get the build
# check above for free, but they don't publish.
if: github.event_name != 'pull_request'
needs: build
runs-on: ubuntu-latest
permissions:
pages: write
id-token: write
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
steps:
- id: deployment
uses: actions/deploy-pages@cd2ce8fcbc39b97be8ca5fce6e763baed58fa128 # v5.0.0