Dashboard › publish › Distillation
332588dc-085d-4cf0-bd84-85b0f5b37052["lore_tm_v1_kN4TjT2gVEy21tfiQ08MHB0XJYV0skiISeid7x2jRno","lore_tm_v1_T2XS-i8R_o9YUaRdcG1Z-Ir960BPZ8p6y6bp-gLvypM","lore_tm_v1_LgBt_z_1iFnypsDwS9EDLrI72GaHDRNUhmdJsseZrCs","lore_tm_v1_E8hPy8DHawGXvjRqCbyIn3ams--cvglWYNohdDzGl-s","lore_tm_v1_qJHXBAlhd71doikniQ4INKgzMcDL9PX7OUo08kb5xHs","lore_tm_v1_hWD9edrj3U1jbAYe5IJRVyKjyGnbjK5qKlhkAp3r9VA","lore_tm_v1_W3Ru_UchcsCVegHKgFcGEn1YaeZC9-AzvoLJ3NKe7Ew","lore_tm_v1_b6pcUCQ2715GQZbEIGLWd6X8AfOUDqEYaCpi35gR3hg","lore_tm_v1_gd81wt1Ic-5Sm-3254P0CUGjG3KxUkbjZzqUx9C0odk","lore_tm_v1_XneQkMlOnMiDUTiDRzPyMhW4-q-nMzDW-VFSSHkl-GM"]
Date: Sep 8, 2026
ci-ready..github/workflows/publish.yml triggers on issue labeled events, uses concurrency group ${{ github.event.issue.title }} with cancel-in-progress: false, and grants contents: read, issues: write, and packages: write..github/workflows/publish.yml:26-168 waiting-for-ci runs in production only when accepted is added to an open issue whose title starts publish: . It checks out publish code at actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803 with persist-credentials: false; gets internal-app and release-bot app tokens; runs node src/publish/authorize-approval.js; records its output approval attestation as a github-actions[bot] comment; then runs node src/publish/validate-approval-attestation.js..github/workflows/publish.yml:93-111 rejects any failed authorization, missing authorized == 'true', failed approval-attestation comment, or failed attestation validation by removing accepted, commenting Approval is invalid or could not be verified. Re-add the accepted label to retry after resolving the issue., and exiting 1..github/workflows/publish.yml:113-142 resets an approved issue to clean CI-pending state by removing ci-failed and ci-ready and adding ci-pending; removing ci-ready is intentional so the poller’s later add generates a fresh labeled event for publish.yml. It comments either Retrying — CI was previously failed. Checking CI status now. or Approved. Checking CI status on the release branch. Publishing will start automatically when CI passes..github/workflows/publish.yml:144-168 best-effort enables the cron poller by setting repository variable CI_POLLER_HAS_PENDING to true using a dedicated CI_POLLER_APP_CLIENT_ID app token, then immediately dispatches event_type=ci-poller with the internal app token because GITHUB_TOKEN workflow-dispatch events are suppressed..github/workflows/publish.yml:170-220 publish runs in production only on an open issue’s ci-ready label event when labels include accepted and ci-ready, and exclude ci-pending and ci-failed; it has timeout-minutes: 90. Before publishing it validates approval with REQUIRE_CI_READY_ATTESTATION: "true" and removes accepted, comments the invalid-approval retry message, and exits if validation fails..github/workflows/publish.yml:222-282 sets up Node 24, caches Yarn using .__publish__/yarn.lock, runs yarn install --cwd ".__publish__", parses inputs via node .__publish__/src/publish/inputs.js, posts workflow details, and conditionally takes Craft configuration from protected merge-target branches: sentry-migr8/tmp-merge-target; sentry-javascript/v10, v9, v8, v7, or master; sentry-python/alpha; and sentry-wizard/1.x. It checks out the target repository into __repo__ at fetch depth 0 with a Release Bot app token..github/workflows/publish.yml:284-326 constructs Craft’s already-published state JSON from CRAFT_PUBLISH_TARGETS_JSON and writes it outside target-repo contents to $GITHUB_WORKSPACE/.craft-state/craft/publish-state-${owner_sanitised}-${repo_sanitised}-${cwd_hash}-${version_sanitised}.json; cwd_hash is the first 12 characters of SHA-1 for Craft’s canonical container working directory, and owner/repo/version are lowercased and sanitized to [a-z0-9._-]. This external XDG_STATE_HOME location prevents __repo__/ contents from pre-populating Craft state..github/workflows/publish.yml:328-351 revalidates approval immediately before Craft with REQUIRE_CI_READY_ATTESTATION: "true"; a revoked or invalid approval removes accepted, posts the same retry comment, and exits 1..github/workflows/publish.yml:353-407 publishes through pinned image docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b, executing craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} from __repo__/${{ fromJSON(steps.inputs.outputs.result).path }}. It sets XDG_STATE_HOME: /github/workspace/.craft-state, CRAFT_MERGE_TARGET, CRAFT_LOG_LEVEL defaulting to Info, CRAFT_DRY_RUN, Release Bot Git identity, and separate credentials for GitHub Packages versus cross-repository GitHub API access. Workflow secret environment-variable names include CLOUDFLARE_API_TOKEN, COCOAPODS_TRUNK_TOKEN, CRAFT_GCS_TARGET_CREDS_JSON, CRAFT_GCS_STORE_CREDS_JSON, CRATES_IO_TOKEN, DOCKER_PASSWORD, HEX_API_KEY, TWINE_PASSWORD, NPM_TOKEN, GEM_HOST_API_KEY, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, NUGET_API_TOKEN, POWERSHELL_API_KEY, GPG_PRIVATE_KEY, GPG_PASSPHRASE, OSSRH_USERNAME, OSSRH_PASSWORD, PUBDEV_ACCESS_TOKEN, PUBDEV_REFRESH_TOKEN, and VERCEL_TOKEN..github/workflows/publish.yml:409-435 runs node .__publish__/src/publish/update-issue.js on cancellation or failure to update completed targets and remove a label; it posts cancellation or failure using post-result.js cancelled / post-result.js failure, and posts successful completion via post-result.js success..github/workflows/auto-approve.yml triggers only when an issue is opened by sentry-release-bot[bot] or getsantry[bot] with title beginning publish: . It sparse-checks out auto-approve-repos.txt, records an auto-approval attestation via node src/publish/record-auto-approval-attestation.js, posts it as github-actions[bot], then adds accepted only if the parsed repo from publish: {repo}@{version} exactly matches a line in auto-approve-repos.txt.src/modules/approval-attestation.js defines HTML-comment prefixes <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready with suffix -->; attestations are base64url-encoded JSON.src/modules/approval-attestation.js:14-28 requestDigest({ body, labels, title }) validates string body and labels array, then returns a SHA-256 hex digest of JSON containing body, title, and dryRun derived from a dry-run label. Thus body, title, or dry-run-state changes invalidate attestations.src/modules/approval-attestation.js:31-56 approval attestations bind actor, stringified eventId, request digest, and title; auto-approval attestations bind autoApprover, request digest, and title; CI-ready attestations bind the current accepted actor/event ID, authenticated CI-ready actor, request digest, and title.src/modules/approval-attestation.js:129-174 compareEventIds() strips leading zeroes, requires numeric IDs, compares by digit length then locale ordering, and currentLabeledEvent() selects the latest valid labeled event by this ordering. currentAcceptedEvent() and currentCiReadyEvent() specialize it for accepted and ci-ready.src/modules/approval-attestation.js:176-241 only accepts approval, auto-approval, and CI-ready attestations in comments authored by the configured attestation author; matching additionally requires current event actors/event IDs and current request digest/title. CI-ready verification specifically requires its accepted actor/event ID and ciReadyActor to match the latest accepted and ci-ready events.src/modules/approval-authorizer.js allows human approvers with target-repository roles write, maintain, or admin; explicitly rejects direct approval by getsantry[bot], sentry-release-bot[bot], and auto-approval labeler sentry-internal-app[bot]. Automated approval applies only to requests from getsantry[bot] or sentry-release-bot[bot] for entries in auto-approve-repos.txt, normalized as getsentry/${title.repo}${title.path || ""}.src/publish/authorize-approval.js paginates issue events and comments at per_page=100; ordinary approvals fetch collaborator permission from repos/{owner}/{repository}/collaborators/{username}/permission. For the sentry-internal-app[bot] auto-approval path, it requires a live open issue with unchanged title, an automated requester, an eligible auto-approved repository, a current accepted event attributed to that labeler, and a matching github-actions[bot] auto-approval attestation.src/publish/authorize-approval.js:200-223 additionally rejects changed/closed issues, self-approval by a requester whose login case-insensitively matches the human actor, missing current accepted event, or accepted events not attributed to the actor. On success it outputs authorized=true and approval_attestation=${attestation}; otherwise it outputs authorized=false.src/publish/current-accepted-event.js retrieves paginated issue events via getAllPages({ resource: "events" }), returns the latest accepted-label actor/event ID, and throws The issue has no current accepted label event if absent.src/publish/validate-approval-attestation.js fetches the live issue plus all events and comments in parallel. It requires an open unchanged-title issue with accepted, a current accepted event—optionally matching EXPECTED_ACCEPTED_ACTOR and EXPECTED_ACCEPTED_EVENT_ID—and a matching approval attestation. With REQUIRE_CI_READY_ATTESTATION === "true", it additionally requires current ci-ready, current ci-ready label event, and matching CI-ready attestation.src/publish/record-auto-approval-attestation.js refuses to record automated approval if the issue is closed, title changed, or requester no longer case-insensitively matches AUTO_APPROVER; otherwise it outputs auto_approval_attestation=${attestation}.src/publish/record-ci-ready-attestation.js fetches the live issue, all issue events, and authenticated GitHub login in parallel; it rejects a closed/renamed issue, missing accepted, missing current accepted event, or mismatch with expected accepted actor/event ID, with error The approval changed before CI could be marked ready. On success it outputs ci_ready_attestation=${attestation}.src/modules/__tests__/approval-attestation.js tests that the latest accepted event (id: "200" over "100") matches a trusted github-actions[bot] approval attestation; GitHub numeric event ID 29503999078 is accepted and stringified; CI-ready attestations must match both accepted event and CI-ready actor; malformed base64 attestation, untrusted comment author, stale event/title, and changed dry-run state are rejected.