Dashboard › publish › Distillation
ad2923fd-050f-46e5-ae51-4ac35eb147cc["lore_tm_v1_i74dLPBaorD_pCxURMoOHHfQts_cJBNxMp_rLPkMdfs","lore_tm_v1_7hZBTYKChbm5cagwQO8_eQ7VTV1vodSvOHNqfwFnKOo","lore_tm_v1_ErxLb4i17FOENwsvrMT2WhSq687Y6wpzcACSv-OnpSU","lore_tm_v1__Tpe4cRKxKfztUVkAxre_RbkY7TQoaim-piLQI3IyIY","lore_tm_v1_PThyKGxFIWS0RzGMTIw6bls-n_VfW58mg3E9mBbaCvY","lore_tm_v1_ft5asdT4GSV5ds-FEny-bDZ8pjPgRyEqqwVqJtTyD68","lore_tm_v1_xGrt-prujTBFH_6gXIPp6dfnMW49OrGumKtKq3_1YbE","lore_tm_v1_l2y29xHhZGbVjkUWObjkBGDQ2fR-pG6iJelkRQ8ZU_s","lore_tm_v1_TXk9Qpf_MzZfTTq69c39g68O5WuDJfOkNm-0ETZprWk","lore_tm_v1_p-6dPWQ8d2_xRRMJvOjdXuiRU3elWIpVZlPoY3O5DqA","lore_tm_v1_f1a_QQqrVJ9oYmdytIdiUJNM9Wx4VfnsM5qIcLKPqts","lore_tm_v1_IjbQ1JoyC5znmSbhVfEdXqCZvRnpmj2dVVctuZ590Vw","lore_tm_v1_yEt8CreCGNVf152qE3atOKLx3vGyqp8AS8CMw--onp4"]
/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.peggy is 86 lines and defines the canonical publish-issue title grammar plus release-revision parsing.PublishIssueTitle accepts "publish: ", an optional "getsentry/", Repository, an optional slash-prefixed Path, "@", and Version, requiring end-of-input; it returns { repo, path: path || "", version }.publish-issue-title.peggy, RepositoryCharacter is [A-Za-z0-9_.-]; Path consists of one or more "/" PathSegment components; and Version accepts one or more [A-Za-z0-9_.+-] characters.publish-issue-title.peggy, a title path suffix is syntactic only; the controller resolves the complete suffix as a workspace after checking out the CI-approved revision.ReleaseRevision parses a RequestHeader at the start of the issue body and ignores the remainder. The header requires Requested by: @..., Merge target: ..., Quick links:, a View changes link, and a View check runs link of the form https://github.com/getsentry/{repo}/commit/{revision}/checks with an optional trailing slash.CheckRunsRevision accepts lowercase hexadecimal characters only when the captured value is exactly 40 characters, returning { value, start, end } with Peggy byte offsets. CheckRunsLinkCount counts every literal "- [View check runs](" occurrence across the full body to protect against appended decoy links."\r\n" or "\n" newlines, spaces/tabs for Indent, zero or more blank lines, and a MergeTarget of either "(default)" or [A-Za-z0-9_./-]+; LinkDestination excludes newline characters and )./home/byk/Code/getsentry/publish/src/modules/update-issue.js is 84 lines and exports updateIssue and transformIssueBody.updateTargets({ octokit, stateFilePath, publishRepo, issue_number }) returns without action when stateFilePath is absent or does not exist; otherwise it concurrently fetches the issue and reads/parses the UTF-8 Craft state JSON, transforms the body, and updates the issue body through octokit.rest.issues.update.transformIssueBody(craftState, issueBody) replaces the matched Targets section: existing target checkboxes become checked when craftState.published[targetId] is truthy and unchecked otherwise; target IDs are tracked in a Set; keys in craftState.published not already declared are appended in object-key order with corresponding checkbox state and surrounding newlines.updateIssue({ context, octokit }) gets publishRepo from context.repo and issue_number from context.payload.issue.number, then concurrently calls updateTargets() using process.env.CRAFT_STATE_FILE_PATH and removes the "accepted" label with octokit.rest.issues.removeLabel.src/modules/ci-poller-input.js: getCiPollerInput() now accepts labels, imports requestDigest from ./approval-attestation, computes resolvedIssueBody by applying updateReleaseRevision({ issueBody, repo, revision }) when revision is supplied, conditionally returns that updated issueBody, and always returns requestDigest: requestDigest({ body: resolvedIssueBody, labels, title }).getCiPollerInput(), the returned revision remains currentRevision, obtained from the original issueBody before any supplied replacement revision is written into resolvedIssueBody.parsePublishTitle(title) in src/modules/details-from-context.js; other visible changes in src/libs/github.js, src/modules/post-workflow-details.js, src/modules/process-end-state.js, src/modules/publish-location.js, src/publish/discover-location.js, and src/publish/inputs.js are formatting-only.--pcre2.uses: entries across workflows: .github/workflows/test.yml lines 19–23 has actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803, actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38, and actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830; .github/workflows/publish.yml lines 36, 42, 56, 167, 220, 256, 284, 290, and 399 uses pinned checkout/app-token/setup-node actions plus docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b; .github/workflows/ci-poller.yml lines 49, 61, 72, and 459 uses pinned checkout and app-token actions; .github/workflows/auto-approve.yml lines 18 and 23 uses actions/checkout@11d5960a326750d5838078e36cf38b85af677262 and actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1./home/byk/Code/getsentry/publish/src/modules/__tests__/approval-attestation.js is 174 lines and tests createApprovalAttestation, createCiReadyAttestation, currentAcceptedEvent, hasApprovalAttestation, hasCiReadyAttestation, parseApprovalAttestation, and requestDigest.currentAcceptedEvent() selects the latest "accepted" labeled event and normalizes numeric GitHub event ID 29503999078 to string "29503999078"; a trusted github-actions[bot] comment is accepted only when its attestation matches the current actor, event ID, title/body/labels request digest, and expected attestation author.ciReadyActor; changing accepted event ID from "200" to "201" or using CI-ready actor "contractor" instead of "sentry-internal-app[bot]" is rejected.<!-- publish-approval not-base64 --> data, and requests whose "dry-run" label state changed after attestation./home/byk/Code/getsentry/publish/src/modules/__tests__/approval-authorizer.js is 147 lines and tests authorizeApproval.authorizeApproval tests reject direct approval by "getsantry[bot]" and "sentry-release-bot[bot]" without a target-repository permission lookup; reject "getsantry[bot]" when getsentry/sentry-javascript is outside the supplied auto-approval allowlist; and permit human collaborators only for exact GitHub role_name values "write", "maintain", or "admin".authorizeApproval tests reject collaborator role values "none", "read", "triage", "Elevated Bot", and undefined; malformed titles "publish: @1.0.0" and "publish: getsentry/sentry-javascript" return { authorized: false, repository: null } without querying GitHub; permission lookup failures such as Error("Not Found") propagate.authorizeApproval resolves both "publish: getsentry/sentry-javascript@10.0.0" and unqualified "publish: sentry-javascript/packages/core@10.0.0" to repository "getsentry/sentry-javascript" and calls getPermission({ owner: "getsentry", repository: "sentry-javascript", username: "contractor" })./home/byk/Code/getsentry/publish/src/publish/__tests__/authorize-approval.js is 279 lines. Its fixture sets GITHUB_OUTPUT=/tmp/github-output, APPROVAL_TOKEN=release-bot-token, APPROVAL_ISSUE_NUMBER=123, APPROVAL_ISSUE_REPOSITORY=getsentry/publish, actor/title variables, and EXPECTED_REQUEST_DIGEST from body "Merge target: main", label "accepted", and the issue title.getAutoApprovedRepositories() is tested to load exact newline-separated release paths into new Set(["getsentry/sentry-javascript", "getsentry/objectstore/clients"]).https://api.github.com/repos/getsentry/sentry-javascript/collaborators/contractor/permission with Authorization: "Bearer release-bot-token" and appends output matching authorized=true\napproval_attestation=<!-- publish-approval .+ -->\n.authorized=false\n when the approver is the issue requester, when the live request body/labels differ from the expected accepted-label event snapshot, when automated approval lacks a request proof, or when "sentry-release-bot[bot]" directly approves; the direct automated-opener case performs no fetch."getsantry[bot]" can be approved by "sentry-internal-app[bot]" without a collaborator lookup only when a github-actions[bot] comment contains a valid createAutoApprovalAttestation() proof bound to the issue.main() rejects with Could not retrieve contractor's permission for getsentry/sentry-javascript: GitHub returned 404, does not log through the spied console.error, and writes no GitHub output./home/byk/Code/getsentry/publish/src/publish/__tests__/auto-approval-workflow.js is 40 lines and checks .github/workflows/auto-approve.yml: checkout before "Record automated approval attestation" must not use sparse-checkout:; node src/publish/request-digest-from-event.js and EXPECTED_REQUEST_DIGEST: ${{ steps.request-digest.outputs.request_digest }} must feed node src/publish/record-auto-approval-attestation.js; proof recording must precede --add-label accepted."Post automated approval attestation" to use GH_TOKEN: ${{ github.token }} before labeling, while the later labeling path uses GH_TOKEN: ${{ steps.token.outputs.token }}./home/byk/Code/getsentry/publish/src/publish/__tests__/current-accepted-event.js is 38 lines. getCurrentAcceptedEvent() returns the latest accepted-label event as { actor: "contractor", eventId: "200" }; no valid event rejects with The issue has no current accepted label event./home/byk/Code/getsentry/publish/src/publish/__tests__/record-auto-approval-attestation.js is 92 lines. recordAutoApprovalAttestation() binds "getsantry[bot]" to the live issue and produces data parsed as { autoApprover: "getsantry[bot]", requestDigest: expect.any(String), title }.recordAutoApprovalAttestation() rejects with The automated approval request changed before approval if the live issue author differs from autoApprover or if the live body/labels snapshot differs from expectedRequestDigest, including a change from body "old request" and no labels to body "changed request" plus "dry-run"./home/byk/Code/getsentry/publish/src/publish/__tests__/record-ci-ready-attestation.js is 157 lines. A valid recordCiReadyAttestation() result binds accepted actor "contractor", accepted event ID "100", CI-ready actor "sentry-internal-app[bot]", the request digest, and the title.recordCiReadyAttestation() rejects with The approval changed before CI could be marked ready when the live title differs from the poller title, the current accepted event differs from expectedAcceptedEvent (for example event "200" replacing "100"), or the live request body/labels differ from expectedRequestDigest (for example "new revision" plus "dry-run" replacing "old revision" without it)./home/byk/Code/getsentry/publish/src/publish/__tests__/request-digest-from-event.js is 25 lines. requestDigestFromEvent({ issue }) hashes the exact issue event snapshot, including body, labels, and title; absent issue data throws The GitHub event has no issue snapshot, while an incomplete snapshot lacking a title throws Invalid publish request.