Skip to content

Commit 94a493a

Browse files
committed
use trusted publishing workflow
adapted from bytecodealliance/wit-bindgen#1350
1 parent 2173d9d commit 94a493a

2 files changed

Lines changed: 74 additions & 47 deletions

File tree

.github/workflows/publish.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,13 @@ on:
99

1010
permissions:
1111
contents: write
12+
id-token: write
1213

1314
jobs:
1415
create_tag:
1516
name: Publish artifacts of build
1617
runs-on: ubuntu-latest
18+
environment: release
1719
if: |
1820
github.repository_owner == 'bytecodealliance'
1921
&& github.event_name == 'push'
@@ -62,10 +64,14 @@ jobs:
6264
with:
6365
tag_name: v${{ steps.tag.outputs.version }}
6466

67+
- uses: rust-lang/crates-io-auth-action@v1
68+
id: auth
69+
if: steps.tag.outputs.push_tag == 'yes'
70+
6571
- run: |
6672
rm -rf main.log
6773
rustc ci/publish.rs
6874
./publish publish
6975
env:
70-
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
76+
CARGO_REGISTRY_TOKEN: ${{ steps.auth.outputs.token }}
7177
if: steps.tag.outputs.push_tag == 'yes'

ci/publish.rs

Lines changed: 67 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::collections::HashMap;
1111
use std::env;
1212
use std::fs;
1313
use std::path::{Path, PathBuf};
14-
use std::process::{Command, Stdio};
14+
use std::process::{Command, Output, Stdio};
1515
use std::thread;
1616
use std::time::Duration;
1717

@@ -296,14 +296,8 @@ fn publish(krate: &Crate) -> bool {
296296

297297
// First make sure the crate isn't already published at this version. This
298298
// script may be re-run and there's no need to re-attempt previous work.
299-
let output = Command::new("curl")
300-
.arg(&format!("https://crates.io/api/v1/crates/{}", krate.name))
301-
.output()
302-
.expect("failed to invoke `curl`");
303-
if output.status.success()
304-
&& String::from_utf8_lossy(&output.stdout)
305-
.contains(&format!("\"newest_version\":\"{}\"", krate.version))
306-
{
299+
let output = curl(&format!("https://crates.io/api/v1/crates/{}", krate.name));
300+
if output.is_none() {
307301
println!(
308302
"skip publish {} because {} is latest version",
309303
krate.name, krate.version,
@@ -322,43 +316,6 @@ fn publish(krate: &Crate) -> bool {
322316
return false;
323317
}
324318

325-
// After we've published then make sure that the `wasmtime-publish` group is
326-
// added to this crate for future publications. If it's already present
327-
// though we can skip the `cargo owner` modification.
328-
let output = Command::new("curl")
329-
.arg(&format!(
330-
"https://crates.io/api/v1/crates/{}/owners",
331-
krate.name
332-
))
333-
.output()
334-
.expect("failed to invoke `curl`");
335-
if output.status.success()
336-
&& String::from_utf8_lossy(&output.stdout).contains("wasmtime-publish")
337-
{
338-
println!(
339-
"wasmtime-publish already listed as an owner of {}",
340-
krate.name
341-
);
342-
return true;
343-
}
344-
345-
// Note that the status is ignored here. This fails most of the time because
346-
// the owner is already set and present, so we only want to add this to
347-
// crates which haven't previously been published.
348-
let status = Command::new("cargo")
349-
.arg("owner")
350-
.arg("-a")
351-
.arg("github:bytecodealliance:wasmtime-publish")
352-
.arg(&krate.name)
353-
.status()
354-
.expect("failed to run cargo");
355-
if !status.success() {
356-
panic!(
357-
"FAIL: failed to add wasmtime-publish as owner `{}`: {}",
358-
krate.name, status
359-
);
360-
}
361-
362319
true
363320
}
364321

@@ -384,6 +341,7 @@ fn verify(crates: &[Crate]) {
384341
if !krate.publish {
385342
continue;
386343
}
344+
verify_crates_io(&krate);
387345
verify_and_vendor(&krate);
388346
}
389347

@@ -415,4 +373,67 @@ fn verify(crates: &[Crate]) {
415373
)
416374
.unwrap();
417375
}
376+
377+
fn verify_crates_io(krate: &Crate) {
378+
let name = &krate.name;
379+
let Some(owners) = curl(&format!("https://crates.io/api/v1/crates/{name}/owners")) else {
380+
panic!(
381+
"
382+
failed to get owners for {name}
383+
384+
If this crate does not exist on crates.io yet please ping wstd maintainers
385+
to add the crate on crates.io as a small shim. When doing so please remind them
386+
that the trusted publishing workflow must be configured as well.
387+
",
388+
name = name,
389+
);
390+
};
391+
392+
// This is the id of the `wasmtime-publish` user on crates.io
393+
if !owners.contains("\"id\":73222,") {
394+
panic!(
395+
"
396+
crate {name} is not owned by wasmtime-publish, please run:
397+
398+
cargo owner -a wasmtime-publish {name}
399+
",
400+
name = name,
401+
);
402+
}
403+
404+
if owners.split("\"id\"").count() != 2 {
405+
panic!(
406+
"
407+
crate {name} is not exclusively owned by wasmtime-publish
408+
409+
Please contact wasm-tools maintainers to ensure that `wasmtime-publish` is the
410+
only listed owner of the crate.
411+
",
412+
name = name,
413+
);
414+
}
415+
}
416+
}
417+
418+
fn curl(url: &str) -> Option<String> {
419+
let output = cmd_output(
420+
Command::new("curl")
421+
.arg("--user-agent")
422+
.arg("bytecodealliance/wit-bindgen auto-publish script")
423+
.arg(url),
424+
);
425+
if !output.status.success() {
426+
println!("failed to curl: {}", output.status);
427+
println!("stderr: {}", String::from_utf8_lossy(&output.stderr));
428+
return None;
429+
}
430+
Some(String::from_utf8_lossy(&output.stdout).into())
431+
}
432+
433+
fn cmd_output(cmd: &mut Command) -> Output {
434+
eprintln!("Running: `{:?}`", cmd);
435+
match cmd.output() {
436+
Ok(o) => o,
437+
Err(e) => panic!("Failed to run `{:?}`: {}", cmd, e),
438+
}
418439
}

0 commit comments

Comments
 (0)