Skip to content

Commit 89e0958

Browse files
authored
chore: prepare 0.1.0-alpha.2 OIDC release (#21)
Remove the one-time alpha.1 bootstrap and prepare the OIDC-only alpha.2 candidate.
1 parent a35d6f6 commit 89e0958

12 files changed

Lines changed: 76 additions & 404 deletions

.github/workflows/publish.yml

Lines changed: 1 addition & 283 deletions
Original file line numberDiff line numberDiff line change
@@ -4,12 +4,6 @@ on:
44
release:
55
types:
66
- published
7-
workflow_dispatch:
8-
inputs:
9-
source_run_id:
10-
description: Failed v0.1.0-alpha.1 Publish run containing the verified artifact
11-
required: true
12-
type: string
137

148
permissions:
159
contents: read
@@ -189,7 +183,7 @@ jobs:
189183
run: npm run test:live
190184

191185
publish:
192-
name: Publish with npm Trusted Publishing or alpha.1 bootstrap
186+
name: Publish with npm Trusted Publishing
193187
needs:
194188
- live-smoke
195189
- verify
@@ -223,9 +217,7 @@ jobs:
223217
path: release-artifacts
224218
- name: Publish the exact artifact with provenance
225219
env:
226-
ALPHA1_BOOTSTRAP_ENABLED: ${{ vars.NPM_ALPHA1_BOOTSTRAP_ENABLED }}
227220
DIST_TAG: ${{ needs.verify.outputs.dist-tag }}
228-
NODE_AUTH_TOKEN: ${{ vars.NPM_ALPHA1_BOOTSTRAP_ENABLED == 'true' && needs.verify.outputs.version == '0.1.0-alpha.1' && secrets.NPM_ALPHA1_BOOTSTRAP_TOKEN || '' }}
229221
VERSION: ${{ needs.verify.outputs.version }}
230222
run: bash scripts/publish-artifact.sh
231223
- name: Verify the public registry artifact
@@ -350,277 +342,3 @@ jobs:
350342
process.exitCode = 1;
351343
});
352344
EOF
353-
354-
recover-verify:
355-
name: Verify the failed alpha.1 publication source
356-
if: github.event_name == 'workflow_dispatch'
357-
runs-on: ubuntu-latest
358-
timeout-minutes: 10
359-
outputs:
360-
dist-tag: next
361-
release-commit: ${{ steps.trust.outputs.release-commit }}
362-
source-run-id: ${{ steps.trust.outputs.source-run-id }}
363-
version: 0.1.0-alpha.1
364-
permissions:
365-
actions: read
366-
contents: read
367-
steps:
368-
- name: Check out the recovery implementation
369-
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
370-
with:
371-
fetch-depth: 0
372-
persist-credentials: false
373-
- name: Reject an untrusted recovery source
374-
id: trust
375-
env:
376-
EXPECTED_REPOSITORY: cometapi-dev/cometapi-node
377-
EXPECTED_TAG: v0.1.0-alpha.1
378-
GH_TOKEN: ${{ github.token }}
379-
SOURCE_RUN_ID: ${{ inputs.source_run_id }}
380-
shell: bash
381-
run: |
382-
set -euo pipefail
383-
if [[ "$GITHUB_REPOSITORY" != "$EXPECTED_REPOSITORY" || \
384-
"$GITHUB_REF" != "refs/heads/main" ]]; then
385-
echo "Recovery is restricted to the canonical repository's main branch." >&2
386-
exit 1
387-
fi
388-
if [[ ! "$SOURCE_RUN_ID" =~ ^[1-9][0-9]*$ ]]; then
389-
echo "source_run_id must be a positive integer." >&2
390-
exit 1
391-
fi
392-
393-
git fetch --no-tags origin \
394-
"+refs/tags/${EXPECTED_TAG}:refs/tags/${EXPECTED_TAG}" \
395-
"+refs/heads/main:refs/remotes/origin/main"
396-
release_commit="$(git rev-parse --verify "refs/tags/${EXPECTED_TAG}^{commit}")"
397-
if ! git merge-base --is-ancestor "$release_commit" refs/remotes/origin/main; then
398-
echo "The immutable release tag is not reachable from origin/main." >&2
399-
exit 1
400-
fi
401-
402-
release_json="$(gh api \
403-
"repos/${GITHUB_REPOSITORY}/releases/tags/${EXPECTED_TAG}")"
404-
run_json="$(gh api \
405-
"repos/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}")"
406-
jobs_json="$(gh api \
407-
"repos/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}/jobs?per_page=100")"
408-
artifacts_json="$(gh api \
409-
"repos/${GITHUB_REPOSITORY}/actions/runs/${SOURCE_RUN_ID}/artifacts?per_page=100")"
410-
411-
RELEASE_JSON="$release_json" RUN_JSON="$run_json" \
412-
JOBS_JSON="$jobs_json" ARTIFACTS_JSON="$artifacts_json" \
413-
RELEASE_COMMIT="$release_commit" EXPECTED_TAG="$EXPECTED_TAG" node <<'EOF'
414-
const release = JSON.parse(process.env.RELEASE_JSON);
415-
const run = JSON.parse(process.env.RUN_JSON);
416-
const jobs = JSON.parse(process.env.JOBS_JSON).jobs;
417-
const artifacts = JSON.parse(process.env.ARTIFACTS_JSON).artifacts;
418-
const expectedCommit = process.env.RELEASE_COMMIT;
419-
const expectedTag = process.env.EXPECTED_TAG;
420-
421-
const reject = (message) => {
422-
throw new Error(message);
423-
};
424-
if (
425-
release.tag_name !== expectedTag ||
426-
release.draft !== false ||
427-
release.prerelease !== true ||
428-
release.immutable !== true
429-
) {
430-
reject("Recovery requires the published immutable alpha.1 prerelease.");
431-
}
432-
if (
433-
run.event !== "release" ||
434-
run.path !== ".github/workflows/publish.yml" ||
435-
run.head_branch !== expectedTag ||
436-
run.head_sha !== expectedCommit ||
437-
run.status !== "completed" ||
438-
run.conclusion !== "failure"
439-
) {
440-
reject("The source run does not match the failed alpha.1 release workflow.");
441-
}
442-
const conclusions = new Map(jobs.map((job) => [job.name, job.conclusion]));
443-
if (
444-
conclusions.get("Verify the immutable release artifact") !== "success" ||
445-
conclusions.get("Verify the release tag against CometAPI") !== "success" ||
446-
conclusions.get(
447-
"Publish with npm Trusted Publishing or alpha.1 bootstrap",
448-
) !== "failure"
449-
) {
450-
reject("The source run does not have the required verify/live success boundary.");
451-
}
452-
const candidates = artifacts.filter(
453-
(artifact) =>
454-
artifact.name === "npm-package-0.1.0-alpha.1" &&
455-
artifact.expired === false,
456-
);
457-
if (candidates.length !== 1 || !candidates[0].digest) {
458-
reject("The source run must contain one unexpired verified alpha.1 artifact.");
459-
}
460-
EOF
461-
462-
echo "release-commit=${release_commit}" >> "$GITHUB_OUTPUT"
463-
echo "source-run-id=${SOURCE_RUN_ID}" >> "$GITHUB_OUTPUT"
464-
465-
recover-publish:
466-
name: Recover the verified alpha.1 npm publication
467-
needs:
468-
- recover-verify
469-
runs-on: ubuntu-latest
470-
timeout-minutes: 15
471-
environment:
472-
name: npm
473-
url: https://www.npmjs.com/package/cometapi/v/0.1.0-alpha.1
474-
permissions:
475-
actions: read
476-
contents: read
477-
id-token: write
478-
steps:
479-
- name: Check out the reviewed recovery implementation
480-
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3
481-
with:
482-
persist-credentials: false
483-
- name: Set up Node.js 24
484-
uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38 # v6.5.0
485-
with:
486-
node-version: 24.x
487-
registry-url: https://registry.npmjs.org
488-
- name: Use a Trusted Publishing-capable npm CLI
489-
run: npm install --global npm@11.12.1
490-
- name: Download the original verified release artifact
491-
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4.3.0
492-
with:
493-
github-token: ${{ github.token }}
494-
name: npm-package-0.1.0-alpha.1
495-
path: release-artifacts
496-
repository: cometapi-dev/cometapi-node
497-
run-id: ${{ needs.recover-verify.outputs.source-run-id }}
498-
- name: Publish the exact recovered artifact with provenance
499-
env:
500-
ALPHA1_BOOTSTRAP_ENABLED: ${{ vars.NPM_ALPHA1_BOOTSTRAP_ENABLED }}
501-
DIST_TAG: ${{ needs.recover-verify.outputs.dist-tag }}
502-
NODE_AUTH_TOKEN: ${{ secrets.NPM_ALPHA1_BOOTSTRAP_TOKEN }}
503-
VERSION: ${{ needs.recover-verify.outputs.version }}
504-
run: bash scripts/publish-artifact.sh
505-
- name: Verify the recovered public registry artifact
506-
env:
507-
DIST_TAG: ${{ needs.recover-verify.outputs.dist-tag }}
508-
VERSION: ${{ needs.recover-verify.outputs.version }}
509-
shell: bash
510-
run: |
511-
set -euo pipefail
512-
mapfile -t tarballs < <(find "$GITHUB_WORKSPACE/release-artifacts" -maxdepth 1 -type f -name '*.tgz' -print)
513-
if [[ "${#tarballs[@]}" -ne 1 ]]; then
514-
echo "Expected exactly one downloaded artifact for registry verification." >&2
515-
exit 1
516-
fi
517-
local_integrity="$(node -e 'const {createHash}=require("node:crypto");const {readFileSync}=require("node:fs");process.stdout.write("sha512-"+createHash("sha512").update(readFileSync(process.argv[1])).digest("base64"))' "${tarballs[0]}")"
518-
registry_ready="false"
519-
for attempt in {1..12}; do
520-
resolved="$(npm view "cometapi@${VERSION}" version 2>/dev/null || true)"
521-
tagged="$(npm view "cometapi@${DIST_TAG}" version 2>/dev/null || true)"
522-
registry_dist="$(npm view "cometapi@${VERSION}" dist --json 2>/dev/null || true)"
523-
if [[ "$resolved" == "$VERSION" && "$tagged" == "$VERSION" && -n "$registry_dist" ]] && \
524-
REGISTRY_DIST="$registry_dist" LOCAL_INTEGRITY="$local_integrity" node <<'EOF'
525-
let ready = false;
526-
try {
527-
const dist = JSON.parse(process.env.REGISTRY_DIST);
528-
ready =
529-
dist.integrity === process.env.LOCAL_INTEGRITY &&
530-
Boolean(dist.attestations?.url) &&
531-
dist.attestations?.provenance?.predicateType ===
532-
"https://slsa.dev/provenance/v1";
533-
} catch {}
534-
process.exitCode = ready ? 0 : 1;
535-
EOF
536-
then
537-
registry_ready="true"
538-
break
539-
fi
540-
if [[ "$attempt" -lt 12 ]]; then
541-
sleep 10
542-
fi
543-
done
544-
if [[ "$registry_ready" != "true" ]]; then
545-
echo "Registry state did not converge for cometapi@${VERSION}, ${DIST_TAG}, integrity, and provenance." >&2
546-
exit 1
547-
fi
548-
549-
verify_dir="$(mktemp -d)"
550-
cd "$verify_dir"
551-
npm init --yes >/dev/null
552-
npm install --ignore-scripts --no-audit --no-fund \
553-
"openai@6.47.0" "cometapi@${VERSION}"
554-
signatures_verified="false"
555-
for attempt in {1..3}; do
556-
if npm audit signatures; then
557-
signatures_verified="true"
558-
break
559-
fi
560-
if [[ "$attempt" -lt 3 ]]; then
561-
sleep 10
562-
fi
563-
done
564-
if [[ "$signatures_verified" != "true" ]]; then
565-
echo "Registry signature and provenance verification did not converge." >&2
566-
exit 1
567-
fi
568-
npm ls openai --all
569-
if [[ -d node_modules/cometapi/node_modules/openai ]]; then
570-
echo "The registry fixture contains a nested OpenAI installation." >&2
571-
exit 1
572-
fi
573-
574-
node --input-type=module <<'EOF'
575-
import assert from "node:assert/strict";
576-
import { CometAPI } from "cometapi";
577-
578-
const client = new CometAPI({
579-
apiKey: "mock-registry-key",
580-
maxRetries: 0,
581-
fetch: async () =>
582-
new Response(JSON.stringify({ object: "list", data: [] }), {
583-
status: 200,
584-
headers: { "content-type": "application/json" },
585-
}),
586-
});
587-
const models = await client.models.list();
588-
assert.deepEqual(models.data, []);
589-
EOF
590-
591-
node <<'EOF'
592-
const assert = require("node:assert/strict");
593-
const { CometAPI } = require("cometapi");
594-
const { APIError } = require("openai");
595-
596-
const client = new CometAPI({
597-
apiKey: "mock-registry-key",
598-
maxRetries: 0,
599-
fetch: async () =>
600-
new Response(
601-
JSON.stringify({
602-
error: {
603-
message: "mock registry failure",
604-
type: "invalid_request_error",
605-
},
606-
}),
607-
{
608-
status: 400,
609-
headers: { "content-type": "application/json" },
610-
},
611-
),
612-
});
613-
614-
(async () => {
615-
let caught;
616-
try {
617-
await client.models.list();
618-
} catch (error) {
619-
caught = error;
620-
}
621-
assert.ok(caught instanceof APIError);
622-
})().catch((error) => {
623-
console.error(error);
624-
process.exitCode = 1;
625-
});
626-
EOF

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "0.1.0-alpha.1"
2+
".": "0.1.0-alpha.2"
33
}

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,15 @@ follows Keep a Changelog, and versions follow Semantic Versioning.
55

66
## [Unreleased]
77

8+
## [0.1.0-alpha.2] - 2026-07-27
9+
10+
### Changed
11+
12+
- Removed the one-time alpha.1 token bootstrap and manual recovery workflow
13+
after configuring npm Trusted Publishing.
14+
- Required the release workflow to publish through OIDC without registry token
15+
credentials while preserving exact-artifact and provenance verification.
16+
817
## [0.1.0-alpha.1] - 2026-07-27
918

1019
### Added

README.md

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ the official OpenAI JavaScript request, response, stream, and error types while
55
defaulting the client to CometAPI.
66

77
> **Registry Alpha pre-release:** the SDK is under active 0.1 development.
8-
> `0.1.0-alpha.1` is approved for npm publication under the `next` dist-tag,
8+
> `0.1.0-alpha.2` is approved for npm publication under the `next` dist-tag,
99
> and its API may change before `0.1.0`.
1010
1111
## Supported 0.1 surface
@@ -52,8 +52,8 @@ For source-checkout testing, retain and verify one exact tarball:
5252
```bash
5353
mkdir -p .artifacts
5454
npm pack --pack-destination .artifacts
55-
npm run test:package -- --tarball .artifacts/cometapi-0.1.0-alpha.1.tgz
56-
npm run test:fixtures -- --tarball .artifacts/cometapi-0.1.0-alpha.1.tgz
55+
npm run test:package -- --tarball .artifacts/cometapi-0.1.0-alpha.2.tgz
56+
npm run test:fixtures -- --tarball .artifacts/cometapi-0.1.0-alpha.2.tgz
5757
```
5858

5959
Install that path in a separate consumer when needed. Do not treat a locally
@@ -210,10 +210,10 @@ parent.
210210
211211
The repository has completed Public Preview. Blocking CI, protected repository
212212
rules, security reporting, protected environments, and the authorized live
213-
smoke have passed. Registry Alpha `0.1.0-alpha.1` is approved for npm
214-
publication; mocked responses, packed artifacts, GitHub Actions, trusted live
215-
tests, and npm publication remain separate evidence layers and must not be
216-
represented as another.
213+
smoke have passed. Registry Alpha `0.1.0-alpha.1` is available from npm, and
214+
`0.1.0-alpha.2` is approved for OIDC publication. Mocked responses, packed
215+
artifacts, GitHub Actions, trusted live tests, and npm publication remain
216+
separate evidence layers and must not be represented as another.
217217
218218
See:
219219

0 commit comments

Comments
 (0)