Skip to content

Commit 222cfdd

Browse files
ci: harden publishing and tool installation
1 parent d71b595 commit 222cfdd

5 files changed

Lines changed: 85 additions & 80 deletions

File tree

.github/scripts/workflow-policy.test.mjs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,13 @@ const CI_WORKFLOW_URL = new URL("ci.yml", WORKFLOWS_URL);
99
const COVERAGE_WORKFLOW_URL = new URL("coverage.yml", WORKFLOWS_URL);
1010
const RELEASE_WORKFLOW_URL = new URL("release.yml", WORKFLOWS_URL);
1111
const FALLOW_CONFIG_URL = new URL(".fallowrc.json", ROOT_URL);
12+
const WASM_PACK_INSTALL_ACTION = "taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595";
13+
const WASM_PACK_WORKFLOWS = new Map([
14+
["bench.yml", " if: matrix.kind == 'node'\n"],
15+
["ci.yml", ""],
16+
["coverage.yml", ""],
17+
["release.yml", ""],
18+
]);
1219

1320
const trackedPackageLocks = async () => {
1421
const tracked = execFileSync("git", ["ls-files", "--", ":(glob)**/package-lock.json"], {
@@ -104,6 +111,52 @@ describe("Checkout credential policy", () => {
104111
}
105112
}
106113
});
114+
115+
it("uses a step-scoped token and explicit authenticated remote for badge pushes", async () => {
116+
const workflow = await readFile(COVERAGE_WORKFLOW_URL, "utf8");
117+
const job = workflowJob(workflow, "coverage");
118+
const badgeStep = job.slice(job.indexOf(" - name: Update coverage badges"));
119+
120+
assert.match(badgeStep, /^ env:\n GH_TOKEN: \$\{\{ github\.token \}\}$/m);
121+
assert.doesNotMatch(job, /^ env:\n(?: .*\n)* GH_TOKEN:/m);
122+
assert.doesNotMatch(badgeStep, /git push origin badges/);
123+
const authenticatedPushes = badgeStep.match(
124+
/git push "https:\/\/x-access-token:\$\{GH_TOKEN\}@github\.com\/\$\{GITHUB_REPOSITORY\}\.git" badges/g,
125+
);
126+
assert.equal(authenticatedPushes?.length, 2);
127+
});
128+
});
129+
130+
describe("Pinned wasm-pack installation policy", () => {
131+
it("uses only the pinned install action for wasm-pack in every workflow", async () => {
132+
for (const entry of await workflowFiles()) {
133+
const workflow = await readFile(new URL(entry.name, WORKFLOWS_URL), "utf8");
134+
135+
assert.doesNotMatch(workflow, /rustwasm\.github\.io\/wasm-pack/, entry.name);
136+
assert.doesNotMatch(workflow, /curl[^\n|]*\|\s*sh/, entry.name);
137+
138+
const condition = WASM_PACK_WORKFLOWS.get(entry.name);
139+
if (condition !== undefined) {
140+
const install = [
141+
" - name: Install wasm-pack",
142+
condition.trimEnd(),
143+
` uses: ${WASM_PACK_INSTALL_ACTION} # v2.81.11`,
144+
" with:",
145+
" tool: wasm-pack@0.13.1",
146+
]
147+
.filter(Boolean)
148+
.join("\n");
149+
assert.ok(workflow.includes(install), `${entry.name}: missing pinned wasm-pack installer`);
150+
}
151+
152+
if (/\bwasm-pack (?:build|test)\b/.test(workflow)) {
153+
assert.ok(
154+
WASM_PACK_WORKFLOWS.has(entry.name),
155+
`${entry.name}: wasm-pack use is missing from the pinned installer policy`,
156+
);
157+
}
158+
}
159+
});
107160
});
108161

109162
describe("Rust feature coverage", () => {
@@ -145,6 +198,17 @@ describe("Release supply-chain policy", () => {
145198
assert.doesNotMatch(workflow, /\bnpm install\b/);
146199
});
147200

201+
it("requires provenance for every npm publish attempt", async () => {
202+
const workflow = await readFile(RELEASE_WORKFLOW_URL, "utf8");
203+
const publishes = workflow.split("\n").filter((line) => /\bnpm publish\b/.test(line));
204+
205+
assert.ok(publishes.length > 0, "release workflow must publish npm packages");
206+
for (const publish of publishes) {
207+
assert.match(publish, /--provenance\b/, publish.trim());
208+
}
209+
assert.doesNotMatch(workflow, /retrying without provenance/i);
210+
});
211+
148212
it("uses ordered frozen tooling for both NAPI package builds", async () => {
149213
const workflow = await readFile(RELEASE_WORKFLOW_URL, "utf8");
150214
const buildJob = workflowJob(workflow, "build-napi");

.github/workflows/bench.yml

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -100,22 +100,9 @@ jobs:
100100

101101
- name: Install wasm-pack
102102
if: matrix.kind == 'node'
103-
shell: bash
104-
run: |
105-
set -euo pipefail
106-
107-
install_script='https://rustwasm.github.io/wasm-pack/installer/init.sh'
108-
109-
for attempt in 1 2 3; do
110-
if curl "$install_script" -sSf | sh; then
111-
exit 0
112-
fi
113-
114-
echo "wasm-pack installer attempt $attempt failed; retrying..." >&2
115-
sleep 5
116-
done
117-
118-
cargo install wasm-pack --locked --version 0.13.1
103+
uses: taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595 # v2.81.11
104+
with:
105+
tool: wasm-pack@0.13.1
119106

120107
- name: Build JS benchmark packages
121108
if: matrix.kind == 'node'

.github/workflows/ci.yml

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -218,22 +218,9 @@ jobs:
218218
- name: Install JS dependencies
219219
run: corepack pnpm install --ignore-scripts --frozen-lockfile
220220
- name: Install wasm-pack
221-
shell: bash
222-
run: |
223-
set -euo pipefail
224-
225-
install_script='https://rustwasm.github.io/wasm-pack/installer/init.sh'
226-
227-
for attempt in 1 2 3; do
228-
if curl "$install_script" -sSf | sh; then
229-
exit 0
230-
fi
231-
232-
echo "wasm-pack installer attempt $attempt failed; retrying..." >&2
233-
sleep 5
234-
done
235-
236-
cargo install wasm-pack --locked --version 0.13.1
221+
uses: taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595 # v2.81.11
222+
with:
223+
tool: wasm-pack@0.13.1
237224
- name: Build N-API packages
238225
run: |
239226
corepack pnpm --filter @srcmap/codec build

.github/workflows/coverage.yml

Lines changed: 7 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -44,22 +44,9 @@ jobs:
4444
run: corepack pnpm install --ignore-scripts --frozen-lockfile
4545

4646
- name: Install wasm-pack
47-
shell: bash
48-
run: |
49-
set -euo pipefail
50-
51-
install_script='https://rustwasm.github.io/wasm-pack/installer/init.sh'
52-
53-
for attempt in 1 2 3; do
54-
if curl "$install_script" -sSf | sh; then
55-
exit 0
56-
fi
57-
58-
echo "wasm-pack installer attempt $attempt failed; retrying..." >&2
59-
sleep 5
60-
done
61-
62-
cargo install wasm-pack --locked --version 0.13.1
47+
uses: taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595 # v2.81.11
48+
with:
49+
tool: wasm-pack@0.13.1
6350

6451
# Rust coverage (lcov)
6552
- name: Rust coverage
@@ -123,6 +110,8 @@ jobs:
123110
124111
# Update badges branch
125112
- name: Update coverage badges
113+
env:
114+
GH_TOKEN: ${{ github.token }}
126115
run: |
127116
git config user.name "github-actions[bot]"
128117
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
@@ -134,7 +123,7 @@ jobs:
134123
echo "{}" > rust-coverage.json
135124
git add coverage.json rust-coverage.json
136125
git commit -m "chore: init badges branch"
137-
git push origin badges
126+
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" badges
138127
git checkout main
139128
fi
140129
@@ -148,7 +137,7 @@ jobs:
148137
149138
git add coverage.json rust-coverage.json
150139
git diff --cached --quiet || git commit -m "chore: update coverage badges to ${COVERAGE}%"
151-
git push origin badges
140+
git push "https://x-access-token:${GH_TOKEN}@github.com/${GITHUB_REPOSITORY}.git" badges
152141
153142
cd "$GITHUB_WORKSPACE"
154143
git worktree remove /tmp/srcmap-badges

.github/workflows/release.yml

Lines changed: 8 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -202,22 +202,9 @@ jobs:
202202
- uses: Swatinem/rust-cache@e18b497796c12c097a38f9edb9d0641fb99eee32 # v2
203203

204204
- name: Install wasm-pack
205-
shell: bash
206-
run: |
207-
set -euo pipefail
208-
209-
install_script='https://rustwasm.github.io/wasm-pack/installer/init.sh'
210-
211-
for attempt in 1 2 3; do
212-
if curl "$install_script" -sSf | sh; then
213-
exit 0
214-
fi
215-
216-
echo "wasm-pack installer attempt $attempt failed; retrying..." >&2
217-
sleep 5
218-
done
219-
220-
cargo install wasm-pack --locked --version 0.13.1
205+
uses: taiki-e/install-action@15449e3094499af05d8d964a1c884208e4b8b595 # v2.81.11
206+
with:
207+
tool: wasm-pack@0.13.1
221208

222209
- name: Build sourcemap-wasm (nodejs)
223210
run: wasm-pack build --target nodejs --out-dir pkg --release
@@ -358,10 +345,7 @@ jobs:
358345
exit 0
359346
fi
360347
361-
if ! npm publish --access public --provenance --ignore-scripts; then
362-
echo "Provenance publish failed for ${name}@${version}, retrying without provenance..."
363-
npm publish --access public --ignore-scripts
364-
fi
348+
npm publish --access public --provenance --ignore-scripts
365349
EOF
366350
chmod +x /tmp/publish-if-needed.sh
367351
@@ -449,11 +433,8 @@ jobs:
449433
fi
450434
451435
if ! npm publish "$dir" --access public --provenance; then
452-
echo "Provenance publish failed for ${name}@${version}, retrying without provenance..."
453-
if ! npm publish "$dir" --access public; then
454-
echo "::error::Failed to publish ${name}@${version}"
455-
failed=1
456-
fi
436+
echo "::error::Failed to publish ${name}@${version} with provenance"
437+
failed=1
457438
fi
458439
done
459440
@@ -480,11 +461,8 @@ jobs:
480461
fi
481462
482463
if ! npm publish "$dir" --access public --provenance; then
483-
echo "Provenance publish failed for ${name}@${version}, retrying without provenance..."
484-
if ! npm publish "$dir" --access public; then
485-
echo "::error::Failed to publish ${name}@${version}"
486-
failed=1
487-
fi
464+
echo "::error::Failed to publish ${name}@${version} with provenance"
465+
failed=1
488466
fi
489467
done
490468

0 commit comments

Comments
 (0)