putitoutthere 0.2.10 → 0.2.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -0
- package/MIGRATIONS.md +60 -0
- package/README.md +35 -10
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -12,6 +12,7 @@ are prefixed `**BREAKING**` and link to the matching section in
|
|
|
12
12
|
|
|
13
13
|
### Added
|
|
14
14
|
|
|
15
|
+
- **Reusable workflow accepts a caller-provided `CARGO_REGISTRY_TOKEN` via `secrets:`.** OIDC trusted publishers remain the default and recommended path, but Trusted Publishing on crates.io binds to an *already-published* crate — so the first publish of a brand-new crate has no OIDC path available, and consumers were forced to either fork the workflow or run `cargo publish` outside it. The `workflow_call` surface now declares an optional `CARGO_REGISTRY_TOKEN` secret; when set, the `rust-lang/crates-io-auth-action` OIDC exchange is skipped and the caller-provided token is exported to `$GITHUB_ENV` for the engine's crates handler to read. Callers without a token keep the OIDC path unchanged. The "Auth: OIDC trusted publishers ... Long-lived registry tokens are explicitly NOT supported" framing in `release.yml`'s header has been softened to match. See [README → Trusted publishers → crates.io](./README.md#cratesio) and [MIGRATIONS.md](./MIGRATIONS.md#crates-token-fallback). #283.
|
|
15
16
|
- **Preflight check: every cascaded `kind = "npm"` package must declare a non-empty `repository` field in `package.json`.** `putitoutthere` invokes `npm publish --provenance` on the OIDC trusted-publisher path, and the npm CLI hard-requires this field so the registry can verify the artifact was built from the repo the trusted publisher declares. A missing or empty field previously surfaced as a confusing tail-end npm error after the runner had spun up, OIDC had been negotiated, and the artifact had been built — wasting a full release run on a precondition checkable in milliseconds. The new `requireProvenanceMetadata` runs alongside `requireAuth` in `src/publish.ts`, before any side effects, and reports every failing package in one error rather than failing on the first. Surfaces a new stable error code, `PIOT_NPM_MISSING_REPOSITORY`. Both the canonical object form (`{ type, url, directory? }`) and the legacy single-string form are accepted; only an empty `url` (or no `url` at all) fails. The npm handler's inline backstop is also tightened to match the same predicate (previously `!pkg.repository` slipped `{}`, `{ type: 'git' }`, and whitespace strings through). Documented in [README → `kind = "npm"`](./README.md#kind--npm). See [MIGRATIONS.md](./MIGRATIONS.md#npm-package-json-must-declare-repository). #280.
|
|
16
17
|
- **Reusable workflow `.github/workflows/build.yml` (`workflow_call`).** PR-time build verification: runs the same plan + build matrix that `release.yml` runs, calling a shared internal `_matrix.yml` reusable workflow so action pins, per-target build steps, and runner selection cannot drift between the two paths. `build.yml` declares only `permissions: contents: read` and contains no publish job, no `id-token: write`, no OIDC trusted-publisher exchange, and no registry auth — the bytes required to publish do not exist on this code path. Two optional inputs forwarded to `_matrix.yml`: `node_version` (default `24`), `python_version` (default `3.12`). Concurrency is keyed on `github.ref` with `cancel-in-progress: true` so PR pushes supersede stale runs (release.yml's repository-keyed group with `cancel-in-progress: false` is unchanged). An `actionlint`-job grep assertion rejects any future patch that adds `id-token: write` to `build.yml` or `_matrix.yml`. See [README → Build check](./README.md#1b-optional-drop-in-githubworkflowsbuild-checkyml) and [MIGRATIONS.md](./MIGRATIONS.md#new-buildyml-reusable-workflow-for-pr-time-build-verification).
|
|
17
18
|
- **`PIOT_PUBLISH_EMPTY_PLAN` error code.** Surfaced when `publish` is invoked with an empty matrix. Joins `PIOT_AUTH_NO_TOKEN` in the stable error-code vocabulary; foreign agents debugging a failed publish can fingerprint on the code without parsing prose.
|
package/MIGRATIONS.md
CHANGED
|
@@ -21,6 +21,66 @@ Each section covers five things, in order:
|
|
|
21
21
|
|
|
22
22
|
## Unreleased
|
|
23
23
|
|
|
24
|
+
### Crates token fallback
|
|
25
|
+
|
|
26
|
+
**Summary.** The reusable workflow now accepts an optional
|
|
27
|
+
`CARGO_REGISTRY_TOKEN` via `secrets:`. Trusted Publishing on
|
|
28
|
+
crates.io binds to an *already-published* crate, so the very
|
|
29
|
+
first publish of a brand-new crate has no OIDC path available;
|
|
30
|
+
without this fallback consumers had to either fork the workflow
|
|
31
|
+
or publish once outside it. OIDC trusted publishers remain the
|
|
32
|
+
default and recommended path — when the secret is unset,
|
|
33
|
+
behavior is byte-for-byte unchanged. When the secret is set,
|
|
34
|
+
the `rust-lang/crates-io-auth-action` OIDC exchange is skipped
|
|
35
|
+
and the caller-provided token is exported to `$GITHUB_ENV` as
|
|
36
|
+
`CARGO_REGISTRY_TOKEN` for the engine's crates handler to read.
|
|
37
|
+
The header comment in `.github/workflows/release.yml` has been
|
|
38
|
+
softened to match: previously *"Long-lived registry tokens are
|
|
39
|
+
explicitly NOT supported via this workflow"*; now OIDC is
|
|
40
|
+
described as the default with the token fallback called out for
|
|
41
|
+
first-publish bootstrap. #283.
|
|
42
|
+
|
|
43
|
+
**Required changes.** None for consumers already on the OIDC
|
|
44
|
+
path. To bootstrap a brand-new crate or to use the workflow on
|
|
45
|
+
an account where Trusted Publishing isn't available, wire the
|
|
46
|
+
secret in the caller's `release.yml`:
|
|
47
|
+
|
|
48
|
+
| Before | After |
|
|
49
|
+
| -------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
50
|
+
| `uses: thekevinscott/putitoutthere/.github/workflows/release.yml@v0` | `uses: thekevinscott/putitoutthere/.github/workflows/release.yml@v0`<br>`secrets:`<br>` CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}` |
|
|
51
|
+
|
|
52
|
+
The repo-level secret holding the crates.io API token can be
|
|
53
|
+
named anything; the *workflow* secret it gets passed as must
|
|
54
|
+
be `CARGO_REGISTRY_TOKEN` exactly — the reusable workflow keys
|
|
55
|
+
on that name. Drop the `secrets:` block from the caller's
|
|
56
|
+
`release.yml` once Trusted Publishing is registered against
|
|
57
|
+
the now-existing crate; subsequent publishes are zero-secret.
|
|
58
|
+
|
|
59
|
+
**Deprecations removed.** None.
|
|
60
|
+
|
|
61
|
+
**Behavior changes without code changes.** None when the secret
|
|
62
|
+
is unset (OIDC path unchanged). When the secret is set, the
|
|
63
|
+
publish job's "Authenticate with crates.io (OIDC)" step is
|
|
64
|
+
conditionally skipped and a new "Export CARGO_REGISTRY_TOKEN
|
|
65
|
+
(caller-provided)" step writes the secret to `$GITHUB_ENV`
|
|
66
|
+
gated on the same condition. The gate reads the secret through a
|
|
67
|
+
job-level `CALLER_CARGO_REGISTRY_TOKEN` env var because GitHub
|
|
68
|
+
Actions does not allow the `secrets` context inside step-level
|
|
69
|
+
`if:` conditions ([context availability](https://docs.github.com/en/actions/learn-github-actions/contexts#context-availability));
|
|
70
|
+
this is an internal mechanism — consumers don't see or set
|
|
71
|
+
`CALLER_CARGO_REGISTRY_TOKEN` themselves.
|
|
72
|
+
|
|
73
|
+
**Verification.** Wire `CARGO_REGISTRY_TOKEN` to a valid
|
|
74
|
+
crates.io API token in the caller repo and trigger a release.
|
|
75
|
+
The publish-job logs should show "Authenticate with crates.io
|
|
76
|
+
(OIDC)" as `skipped`, "Export CARGO_REGISTRY_TOKEN (OIDC)" as
|
|
77
|
+
`skipped`, and "Export CARGO_REGISTRY_TOKEN (caller-provided)"
|
|
78
|
+
as `success`. The crate publishes; the only difference visible
|
|
79
|
+
in the registry is the publish was authorised against the
|
|
80
|
+
caller-provided token rather than an OIDC-minted ephemeral one.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
24
84
|
### npm package.json must declare `repository`
|
|
25
85
|
|
|
26
86
|
**Summary.** Every cascaded `kind = "npm"` package's `package.json`
|
package/README.md
CHANGED
|
@@ -301,23 +301,48 @@ releases without fighting registry-immutable-publish semantics.
|
|
|
301
301
|
|
|
302
302
|
## Trusted publishers
|
|
303
303
|
|
|
304
|
-
OIDC trusted publishers
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
304
|
+
OIDC trusted publishers are the default and recommended auth path.
|
|
305
|
+
The reusable workflow also accepts a long-lived `CARGO_REGISTRY_TOKEN`
|
|
306
|
+
via `secrets:` for cases where Trusted Publishing isn't reachable —
|
|
307
|
+
most commonly the very first publish of a brand-new crate, since
|
|
308
|
+
Trusted Publishing on crates.io binds to an *already-published* crate
|
|
309
|
+
and there's no pending-publisher equivalent. When set, the OIDC
|
|
310
|
+
exchange is skipped and the caller-provided token is used instead.
|
|
311
|
+
Drop the secret once Trusted Publishing is registered against the
|
|
312
|
+
existing crate.
|
|
313
|
+
|
|
314
|
+
For all three registries the OIDC fields are the same: **your**
|
|
315
|
+
repository owner/name, **your** workflow filename (`release.yml`),
|
|
316
|
+
and optionally a GitHub environment name. Note: you register against
|
|
317
|
+
your *own* repository, not against `thekevinscott/putitoutthere` —
|
|
318
|
+
see "How auth flows" below for the why.
|
|
312
319
|
|
|
313
320
|
### crates.io
|
|
314
321
|
|
|
315
|
-
1.
|
|
316
|
-
|
|
322
|
+
1. **First publish (brand-new crate).** Trusted Publishing binds to
|
|
323
|
+
an existing crate, so the first `cargo publish` has no OIDC path.
|
|
324
|
+
Either run `cargo publish` once locally with your account's API
|
|
325
|
+
token, or pass `CARGO_REGISTRY_TOKEN` to the reusable workflow via
|
|
326
|
+
`secrets:` to bootstrap through this workflow:
|
|
327
|
+
|
|
328
|
+
```yaml
|
|
329
|
+
jobs:
|
|
330
|
+
release:
|
|
331
|
+
uses: thekevinscott/putitoutthere/.github/workflows/release.yml@v0
|
|
332
|
+
secrets:
|
|
333
|
+
CARGO_REGISTRY_TOKEN: ${{ secrets.CARGO_REGISTRY_TOKEN }}
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
When `CARGO_REGISTRY_TOKEN` is set, the OIDC step
|
|
337
|
+
(`rust-lang/crates-io-auth-action`) is skipped and the caller-
|
|
338
|
+
provided token is exported to the publish step's environment.
|
|
317
339
|
2. Go to `https://crates.io/crates/<crate>/settings` → **Trusted Publishing**
|
|
318
340
|
→ **Add**.
|
|
319
341
|
3. Fill in: your repo owner, your repo name, workflow filename
|
|
320
342
|
(`release.yml`), environment (optional).
|
|
343
|
+
4. Drop the `CARGO_REGISTRY_TOKEN` secret from the workflow once
|
|
344
|
+
Trusted Publishing is registered; subsequent publishes are
|
|
345
|
+
zero-secret on the OIDC path.
|
|
321
346
|
|
|
322
347
|
### PyPI
|
|
323
348
|
|