Dashboard › publish › Distillation
c8a709aa-f4dc-4ecd-870e-31a9e7f4cfa5["lore_tm_v1_lVzs915Ab5oyh--XROEVIQdmup1KYCY-215XgdNCHps","lore_tm_v1_Vy-XRu26Ksa2ciPrgGjHRQ1xzn5QbwjnEyo4rvpAgTk","lore_tm_v1_jaR81_Pze5zgjSy54I4UBrA94raHK32O1GykM4bJcJo","lore_tm_v1_aqqI8adTgJWXcwTws5awVRRy2Jc373M3apDcYv0bt9E","lore_tm_v1_olPGR7ukDY8TpxM-ss4IR8m2V6DZBciVNyr7NVDCIzA","lore_tm_v1_SQvVHEkMY8NsrFCTHv91SEf5qhBXBYvsaF3-bpj7qr8"]
Date: Sep 8, 2026
src/publish/authorize-approval.js reads auto-approve-repos.txt into a Set via getAutoApprovedRepositories(), ignoring empty lines.authorize-approval.js uses APPROVAL_TOKEN to call GitHub API version "2026-03-10" with Accept: "application/vnd.github+json"; getPermission() fetches repos/{owner}/{repository}/collaborators/{username}/permission, while getIssue(), getIssueEvents(), and getIssueComments() fetch issue state, paginated events, and paginated comments respectively. Events/comments request per_page=100 and continue until a page has fewer than 100 records.authorize-approval.js requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, and APPROVAL_ISSUE_REPOSITORY; missing values throw exact No "{NAME}" environment variable found errors.authorize-approval.js special-cases actor === AUTO_APPROVAL_LABELER: concurrently retrieves the live issue, all events, and all comments; authorizes only if the issue is open with unchanged title, requester is a string in AUTO_APPROVERS, isAutoApprovedRepository({ actor: requester, autoApprovedRepositories, issueTitle }) succeeds, current "accepted" event actor equals the labeler, and a matching auto-approval attestation was authored by "github-actions[bot]".AUTO_APPROVAL_LABELER actors, authorize-approval.js delegates to authorizeApproval({ actor, issueTitle, getPermission, autoApprovedRepositories }); although passed, autoApprovedRepositories is not destructured or used by authorizeApproval() in src/modules/approval-authorizer.js.authorize-approval.js re-fetches issue/events when needed and rejects changed state: issue must remain open, title must equal APPROVAL_ISSUE_TITLE, requester must be a string, requester cannot equal the non-automated actor case-insensitively, and the current accepted event must exist with event.actor === actor. It writes authorized=false\n on either failed authorization/check; otherwise creates an approval attestation and writes authorized=true\napproval_attestation={attestation}\n.src/modules/approval-authorizer.js defines ALLOWED_ROLE_NAMES = new Set(["write", "maintain", "admin"]), AUTO_APPROVAL_LABELER = "sentry-internal-app[bot]", and AUTO_APPROVERS = new Set(["getsantry[bot]", "sentry-release-bot[bot]"]).isAutoApprovedRepository() rejects actors outside AUTO_APPROVERS and unparseable publish titles; otherwise checks autoApprovedRepositories for exact getsentry/${title.repo}${title.path || ""}.authorizeApproval() parses issueTitle with parsePublishTitle(); unparseable titles return { authorized: false, repository: null }; auto-approver or AUTO_APPROVAL_LABELER actors are rejected with { authorized: false, repository: \getsentry/${title.repo}` }; all other actors are authorized only when GitHub collaborator role_nameis"write", "maintain", or "admin"`.src/modules/approval-attestation.js encodes attestations as base64url JSON embedded in HTML comments: approval prefix "<!-- publish-approval ", auto-approval prefix "<!-- publish-auto-approval ", CI-ready prefix "<!-- publish-ci-ready ", all ending " -->".requestDigest({ body, labels, title }) requires a string body and labels array or throws "Invalid publish request"; it calculates SHA-256 over JSON containing body, dryRun: labels.some((label) => label.name === "dry-run"), and title.{ actor, eventId: String(eventId), requestDigest, title }; auto-approval attestations contain { autoApprover, requestDigest, title }; CI-ready attestations contain { acceptedActor, acceptedEventId: String(acceptedEvent.eventId), ciReadyActor, requestDigest, title }.parseApprovalAttestation(), parseAutoApprovalAttestation(), and parseCiReadyAttestation() validate their required string fields and return null for missing/malformed attestations. parseAttestation() returns null if prefix/suffix is missing or base64url JSON parsing fails.compareEventIds(left, right) strips leading zeroes, compares numeric IDs without JavaScript numeric conversion (first by normalized length, then localeCompare), and throws "Invalid issue event ID" for non-digit normalized IDs.currentLabeledEvent(events, labelName) considers only "labeled" events with matching event.label?.name, string/number event.id, and event.actor?.login; it selects the greatest ID using compareEventIds() and returns { actor, eventId: String(event.id) }, returning null for no candidates or invalid IDs. currentAcceptedEvent() targets "accepted" and currentCiReadyEvent() targets "ci-ready".hasApprovalAttestation(), hasAutoApprovalAttestation(), and hasCiReadyAttestation() search comments authored by the specified attestationAuthor for parsed attestations whose actors/event IDs (where applicable), request digest, and title match the current live issue/event data.src/publish/record-auto-approval-attestation.js exports recordAutoApprovalAttestation(), which fetches the issue and throws "The automated approval request changed before approval" unless it is open, retains issueTitle, and its requester login equals autoApprover case-insensitively; it then returns createAutoApprovalAttestation({ autoApprover, issue }).record-auto-approval-attestation.js requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, APPROVAL_ISSUE_TITLE, and AUTO_APPROVER; its main() writes auto_approval_attestation={attestation}\n to GITHUB_OUTPUT.src/publish/validate-approval-attestation.js fetches GitHub API resources using APPROVAL_TOKEN, GitHub API version "2026-03-10", and paginates arbitrary issue resource paths through getAllPages() with per_page=100.validateApprovalAttestation() concurrently loads issue, events, and comments; requires open issue, unchanged title, present "accepted" label, non-null current accepted event, optional exact match to expectedAcceptedEvent, and hasApprovalAttestation(). If requireCiReadyAttestation is true, it additionally requires current "ci-ready" event, present "ci-ready" label, and hasCiReadyAttestation() matching the current accepted event and CI-ready event.validate-approval-attestation.js requires APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, APPROVAL_ISSUE_TITLE, and APPROVAL_ATTESTATION_AUTHOR; optional expected accepted event is supplied only when both EXPECTED_ACCEPTED_ACTOR and EXPECTED_ACCEPTED_EVENT_ID exist, and CI-ready validation is enabled only when REQUIRE_CI_READY_ATTESTATION === "true". Invalid validation throws "The current accepted label has no matching approval attestation".src/publish/record-ci-ready-attestation.js gets the tokenβs authenticated GitHub login from GET /user; it errors on non-OK response or non-string login.recordCiReadyAttestation() concurrently loads issue, issue events, and authenticated login; it throws "The approval changed before CI could be marked ready" unless the issue is open, title is unchanged, "accepted" label exists, current accepted event exists, and optional expectedAcceptedEvent exactly matches actor/event ID. On success it creates a CI-ready attestation binding that accepted event, authenticated ciReadyActor, and current request digest.record-ci-ready-attestation.js requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, and APPROVAL_ISSUE_TITLE; it retrieves issue events through getAllPages({ resource: "events" }), conditionally forms expectedAcceptedEvent from EXPECTED_ACCEPTED_ACTOR plus EXPECTED_ACCEPTED_EVENT_ID, and writes ci_ready_attestation={attestation}\n to GITHUB_OUTPUT.