Dashboard › publish › Distillation
5bad7f81-fbc2-41fc-96ab-ba99f194c795["lore_tm_v1_8hRleD0Nz6DO1DMFEx5OsoSYhotHp1UZEktLUDu1JFI","lore_tm_v1_r3l5uHHQAqlWc__r0mljpKirIu0gPjNerDjmMOhdjXc","lore_tm_v1_u1mOO0HzLQdbbyiAtDhJtS4RLDldTLtqAShq62oPwiw","lore_tm_v1_iJVAP4paFUBzH-ZyHiiR1PQGzwuwbO0Stew-XjA2NvQ","lore_tm_v1_kdAkCZiBYbWSH5GVZYLUaFNZrOu4f2NWQOF6ewFGjgw","lore_tm_v1_OOATMdCp1MpIczlkC9lKFfaAIftIP8qMrC5oN4OR1XM","lore_tm_v1_Xc5rghYpO5EW4lRgA8XcNbT3p339DJx2ukbdpXlDD7M","lore_tm_v1_trgv18dVhhPuGaKcQE-LSEA1dX-95qL2OGTXN3ndCNY","lore_tm_v1_MOJp9tepUy1fF_6Dq360WJ9E4FMLX3xQU9t4IH_RPoU"]
Date: Sep 8, 2026
.github/workflows/ci-poller-dispatch.yml defines Run CI Status Poller, triggered only by workflow_dispatch, with empty permissions: {} and one dispatch job on ubuntu-latest whose sole step is run: true; this workflow serves as a relay for the main pollerβs workflow_run trigger.src/modules/approval-attestation.js implements base64url-encoded HTML-comment attestations using prefixes <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready with suffix -->. requestDigest({ body, labels, title }) SHA-256-hashes JSON containing body, title, and dryRun derived from a "dry-run" label, and throws Invalid publish request unless body is a string and labels is an array.createApprovalAttestation() bind actor, stringified eventId, request digest, and issue title; auto-approval attestations created by createAutoApprovalAttestation() bind autoApprover, digest, and title; CI-ready attestations created by createCiReadyAttestation() bind accepted-label actor/event ID, authenticated CI-ready actor, digest, and title.parseApprovalAttestation(), parseAutoApprovalAttestation(), and parseCiReadyAttestation() validate decoded attestation field types and return null for missing, malformed, invalid-base64/JSON, or structurally invalid attestations. hasApprovalAttestation(), hasAutoApprovalAttestation(), and hasCiReadyAttestation() only trust comments authored by the supplied attestationAuthor and require every bound field to match the current issue/event state.compareEventIds(left, right) normalizes leading zeroes and compares numeric GitHub issue-event IDs by digit length then localeCompare; nonnumeric IDs throw Invalid issue event ID. currentLabeledEvent(events, labelName) selects the latest valid labeled event for a label with numeric/string ID and actor.login, returning { actor, eventId } or null; currentAcceptedEvent() and currentCiReadyEvent() specialize it for "accepted" and "ci-ready".src/modules/approval-authorizer.js authorizes manual approvals only for GitHub roles "write", "maintain", or "admin" via getPermission({ owner: "getsentry", repository: title.repo, username: actor }). It rejects invalid publish titles, AUTO_APPROVERS, and AUTO_APPROVAL_LABELER ("sentry-internal-app[bot]"); AUTO_APPROVERS are "getsantry[bot]" and "sentry-release-bot[bot]".isAutoApprovedRepository() requires the requester to be an AUTO_APPROVER, parses the publish title, and allows automation only when autoApprovedRepositories contains getsentry/${title.repo}${title.path || ""}, allowing path-specific entries such as package paths.src/publish/authorize-approval.js reads newline-separated auto-approve-repos.txt into a Set; accesses GitHub API using APPROVAL_TOKEN and API version "2026-03-10"; paginates issue events/comments at per_page=100; and requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, and APPROVAL_ISSUE_REPOSITORY.authorize-approval.js has a separate auto-labeler path for "sentry-internal-app[bot]": it concurrently fetches the live issue, all events, and all comments; requires an open, title-matching request from an allowed auto-approver for an auto-approved repository; requires the current accepted event actor to be the auto-labeler; and requires a matching auto-approval attestation authored by "github-actions[bot]". Other actors are permission-authorized through authorizeApproval().authorized=true and approval_attestation=..., authorize-approval.js re-fetches/validates the live issue and current accepted event: issue must be open and retain the expected title, requester must be a string and cannot self-approve case-insensitively (except the auto-labeler flow), and the current accepted event must exist and have the approving actor. Failed authorization or changed state writes authorized=false to GITHUB_OUTPUT.src/publish/current-accepted-event.js exports getCurrentAcceptedEvent() and main(). It retrieves paginated issue events through getAllPages({ resource: "events" }), returns the current accepted-label event, and throws The issue has no current accepted label event if none exists; its CLI requires APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, and APPROVAL_ISSUE_REPOSITORY and outputs JSON to stdout.src/publish/record-auto-approval-attestation.js exports recordAutoApprovalAttestation(), which fetches the live issue and throws The automated approval request changed before approval unless it remains open, retains its expected title, and is owned case-insensitively by autoApprover; on success it writes auto_approval_attestation=... to GITHUB_OUTPUT. Its CLI additionally requires APPROVAL_ISSUE_TITLE and AUTO_APPROVER.src/publish/record-ci-ready-attestation.js obtains the authenticated GitHub login from GET /user, throwing on non-OK response or non-string login. recordCiReadyAttestation() concurrently reads issue, issue events, and CI-ready actor; it requires an open, title-matching issue with an "accepted" label and current accepted event, optionally exactly matching EXPECTED_ACCEPTED_ACTOR/EXPECTED_ACCEPTED_EVENT_ID, otherwise throws The approval changed before CI could be marked ready; success writes ci_ready_attestation=... to GITHUB_OUTPUT.src/publish/validate-approval-attestation.js paginates GitHub issue resources at per_page=100, validates an open issue/title/current "accepted" label and event against an optional expected accepted actor/event ID and a matching approval attestation. When requireCiReadyAttestation is true, it additionally requires current "ci-ready" event and label plus a matching CI-ready attestation. CLI input REQUIRE_CI_READY_ATTESTATION === "true" enables this stricter validation; invalid validation throws The current accepted label has no matching approval attestation.workflow_dispatch relay must always be allowed for manual recovery.ci-ready after its approval changes.ci-ready..github/workflows/ci-poller.yml defines CI Status Poller, triggered every 5 minutes (cron: "*/5 * * * *"), on repository_dispatch type ci-poller, and after completion of the Run CI Status Poller relay via workflow_run. It has contents: read and issues: write permissions, runs check-ci in the production environment, and uses concurrency group ci-status-poller with cancel-in-progress: false.vars.CI_POLLER_HAS_PENDING == 'true', or for workflow_run, or repository_dispatch; repository dispatches validate client_payload.attempt as integer 0 through 59. Checkout is pinned to actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803, uses ref: ${{ github.event.repository.default_branch }} so workflow-dispatch cannot run untrusted target-ref code, and sets persist-credentials: false.actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 using SENTRY_INTERNAL_APP_ID/SENTRY_INTERNAL_APP_PRIVATE_KEY, plus an all-getsentry cross-repository release token using SENTRY_RELEASE_BOT_CLIENT_ID/SENTRY_RELEASE_BOT_PRIVATE_KEY and owner: getsentry; the latter is needed for private repositories where the internal app returns 404, including sentry-xbox, sentry-playstation, sentry-switch, and service-registry.ci-pending and accepted; issues without both labels are not polled, avoiding CI polling for abandoned unapproved releases. It calls current-accepted-event.js before inspecting CI and removes both ci-pending and accepted plus posts Approval is invalid or could not be verified. Re-add the accepted label to retry after resolving the issue. when it cannot bind the current approval event.parsePublishTitle, and extracts a 40-character lowercase SHA from an issue-body .../commit/{SHA}/checks link. Invalid approval removes ci-pending and accepted; unparseable title/version or absent SHA is skipped without label changes.repos/${repo}/commits/${issue_sha}/check-suites and resolves its current HEAD via repos/${repo}/git/ref/heads/${branch}, falling back to the original issue SHA on API failure/missing data. If branch HEAD differs, it replaces the SHA in the issue body so the βView check runsβ link remains current for humans and later poller runs."success" or there are zero commit statuses, all check runs are complete, and no completed check has a conclusion other than "success", "neutral", or "skipped".ci-ready, the poller revalidates the attested approval with the captured accepted event; records a CI-ready attestation binding the authenticated label-app actor and approval state; comments that attestation using ${{ github.token }}; then revalidates approval once more immediately before moving labels. Any failure/change in these stages removes ci-pending and accepted and posts the invalid-approval retry comment.ci-pending, adds ci-ready, and comments CI checks passed for ${repo}@${version}. Publishing is starting now. On failed completed check runs, it removes ci-pending and accepted, adds ci-failed, and comments failed check names plus a check-runs link; on failing combined commit status with otherwise successful checks, it similarly adds ci-failed and comments failed status contexts/links.ci-pending and accepted; with a dedicated CI_POLLER_APP_CLIENT_ID/CI_POLLER_APP_PRIVATE_KEY token it sets repository variable CI_POLLER_HAS_PENDING to "false" when none remain and "true" otherwise, preventing the cron gate from staying enabled or disabled incorrectly.repository_dispatch event type ci-poller with incremented client_payload.attempt; it caps at 60 attempts, then warns Max self-dispatch attempts (60) reached. Relying on cron fallback. Self-dispatch is intended to provide roughly 30β60-second checks versus potentially 30β40-minute delayed cron execution, while the concurrency group limits accumulation to one running and one queued workflow.