Dashboard › publish › Distillation
650376be-79a2-4e70-afde-7f231374c491["lore_tm_v1_XUi7eZztijHAEvWgnovzdVh4v1kCoYD-eLrybaORme4","lore_tm_v1_wUCKevRZrZ6CUKJA3XkOfKWgIVGxQAP_M56oOlAM62M","lore_tm_v1_fMlZgGTVDjQ8_9s2_1f-sGidI4zI1kW0uI4pOPKeWRQ","lore_tm_v1_6itWq6d0cwzeyVnnizz8q8Cz9q3ir6T5ZNXWQ4dlyg8","lore_tm_v1_kEmRFSrNUSwwSNpEgt-D34GKI9wX_fJNCnjBUclLnSQ","lore_tm_v1_Od__cvog1y61VInxmWZzLKOGjyPxtM-hZOvIp4BfDZ4","lore_tm_v1_neRGHCi4LmGj5jCZeVcfx5_98zP0K5aPR-YoRWjLbto","lore_tm_v1_Nop4LsWP3yQ6AEGHB8QVBICQPagz6LVlBNyWyqyUQSg","lore_tm_v1_5_R3qwAe_psy6Dp_t2otTSjIXFDzBHQzYyRCWP-9yvQ","lore_tm_v1_eMBV1HdU_LzenS7dwFRAtR8ylJmAbbF6v0teJ9YKQZo","lore_tm_v1_wlsIzp-UoaztsvRDYh8MUKRZbchW6ocJhSVUkvBfxO0"]
Date: Sep 8, 2026
ci-poller.yml changes: “Always run trusted code.” workflow_dispatch can target any ref, therefore the poller must check out ${{ github.event.repository.default_branch }} with persist-credentials: false.accepted-label event before inspecting CI.ci-poller.yml revalidates the approval after CI checks complete because checks can take hours..github/workflows/auto-approve.yml:1-35 runs only on opened issues, with contents: read; auto-approve runs on ubuntu-latest only when github.actor is sentry-release-bot[bot] or getsantry[bot] and the title starts publish: . It uses actions/checkout@v4 with sparse checkout of auto-approve-repos.txt, creates an internal-app token via actions/create-github-app-token@v3, extracts REPO using sed -n 's/^publish: \(.*\)@.*/\1/p', and adds accepted with gh issue edit "$ISSUE_URL" --add-label accepted only for exact allowlist matches.src/publish/__tests__/authorize-approval.js:43-51 tests that getAutoApprovedRepositories() preserves exact allowlist paths, specifically getsentry/sentry-javascript and getsentry/objectstore/clients.src/publish/__tests__/authorize-approval.js:53-90 successful human authorization test uses actor contractor, title publish: getsentry/sentry-javascript@10.0.0, requester requester, current accepted event ID "100", and confirms the target permission endpoint is https://api.github.com/repos/getsentry/sentry-javascript/collaborators/contractor/permission with Authorization: Bearer release-bot-token; output must match authorized=true\napproval_attestation=<!-- publish-approval .+ -->\n.src/publish/__tests__/authorize-approval.js:92-119 verifies requester/approver separation: when requester login and approver actor are both contractor, authorization writes exactly authorized=false\n, even though contractor has write permission and added the current accepted label.src/publish/__tests__/authorize-approval.js:121-141 verifies closed failure when GitHub permission lookup returns HTTP 404: main() rejects with Could not retrieve contractor's permission for getsentry/sentry-javascript: GitHub returned 404, writes no output, and does not log an error.src/modules/__tests__/approval-authorizer.js:8-42 tests that getsantry[bot] is authorized for exact allowlisted getsentry/sentry-javascript without calling getPermission, but is rejected outside the allowlist even if a hypothetical target permission lookup would return write.src/modules/__tests__/approval-authorizer.js:44-103 tests that human contractor is authorized only for target-repository roles write, maintain, or admin; roles none, read, triage, Elevated Bot, and undefined are rejected. Permission lookup is scoped to { owner: "getsentry", repository: "sentry-javascript", username: "contractor" }.src/modules/__tests__/approval-authorizer.js:68-87 confirms legacy/unqualified title publish: sentry-javascript/packages/core@10.0.0 resolves to repository getsentry/sentry-javascript for authorization.src/modules/__tests__/approval-authorizer.js:105-143 verifies malformed titles publish: @1.0.0 and publish: getsentry/sentry-javascript return { authorized: false, repository: null } without GitHub lookup; GitHub lookup failures, such as Error("Not Found"), propagate.src/modules/details-from-context.js:18-23 centralizes publish-title parsing in exported PUBLISH_TITLE_REGEX and parsePublishTitle(title), where the regex accepts optional getsentry/, captures repo, optional path matching /[\w./-]+, and version matching [\w.+-]+; parsing returns named groups or null.src/modules/details-from-context.js:25-65 now fails explicitly with Invalid publish issue title: ${context.payload.issue.title} when title parsing returns null; otherwise it derives dry_run from a dry-run label, path as "." + (titleMatch.path || ""), merge_target from Merge target: <[\w.\-/]+>, and checked target IDs from the Targets section..github/workflows/ci-poller.yml diff changes workflow permissions from issues: read to issues: write, then checks out trusted default-branch code using actions/checkout@v6, ${{ github.event.repository.default_branch }}, and persist-credentials: false before requesting app tokens..github/workflows/ci-poller.yml diff replaces separate shell sed parsing of repository/version with parsePublishTitle from ./src/modules/details-from-context.js; it constructs repo as "getsentry/" + .repo and version as .version, preventing CI targeting from diverging from Publish title semantics..github/workflows/ci-poller.yml diff binds accepted_actor and accepted_event_id via node src/publish/current-accepted-event.js; if binding fails, it removes ci-pending and accepted, comments Approval is invalid or could not be verified. Re-add the accepted label to retry after resolving the issue., and continues..github/workflows/ci-poller.yml diff validates approval attestation three times for a bound accepted event—before CI inspection, after successful final CI status evaluation, and immediately after posting CI-ready proof—using node src/publish/validate-approval-attestation.js, APPROVAL_ATTESTATION_AUTHOR="github-actions[bot]", EXPECTED_ACCEPTED_ACTOR, and EXPECTED_ACCEPTED_EVENT_ID; any failure removes ci-pending and accepted, posts the invalid-approval comment, and continues..github/workflows/ci-poller.yml diff records a CI-ready proof before adding ci-ready: node src/publish/record-ci-ready-attestation.js writes ci_ready_attestation=... to a mktemp output file; malformed/missing output or proof-generation failure removes ci-pending and accepted; valid proof is posted as an issue comment with GH_TOKEN="${{ github.token }}"..github/workflows/publish.yml diff adds a Get publish code step to waiting-for-ci using actions/checkout@v6 and persist-credentials: false, allowing subsequent authorization scripts to run from checked-out Publish code..github/workflows/publish.yml diff adds best-effort Get release bot auth token using actions/create-github-app-token@v3, SENTRY_RELEASE_BOT_CLIENT_ID, SENTRY_RELEASE_BOT_PRIVATE_KEY, and owner: getsentry; it is used by Authorize approval to query the approver’s current effective target-repository role without exposing RBAC data..github/workflows/publish.yml diff authorizes the accepted label actor using node src/publish/authorize-approval.js, then posts its approval attestation with gh issue comment under ${{ github.token }}, then validates it under github-actions[bot]. If authorization, attestation posting, or validation fails, Reject invalid approval removes accepted, posts Approval is invalid or could not be verified. Re-add the accepted label to retry after resolving the issue., and exits 1..github/workflows/publish.yml diff adds publish-job validation of approval and CI-ready attestations before Node setup and release operations: node .__publish__/src/publish/validate-approval-attestation.js with REQUIRE_CI_READY_ATTESTATION: "true"; failure removes accepted, posts the invalid-approval comment, and exits 1..github/workflows/publish.yml:327-381 Craft publishing uses docker://getsentry/craft:latest, runs craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} from __repo__/${{ fromJSON(steps.inputs.outputs.result).path }}, pins XDG_STATE_HOME to /github/workspace/.craft-state outside __repo__/, and supplies release credentials through named environment variables without revealing their values.src/modules/__tests__/details-from-context.js adds coverage that parsePublishTitle("publish: getsentry/sentry-javascript/packages/core@10.0.0") returns { path: "/packages/core", repo: "sentry-javascript", version: "10.0.0" }, while legacy publish: sentry-javascript@10.0.0 returns { path: undefined, repo: "sentry-javascript", version: "10.0.0" }.src/modules/update-issue.js changes updateIssue() so updateTargets() executes only when inputs?.version exists, while octokit.rest.issues.removeLabel({ ...publishRepo, issue_number, name: "accepted" }) always executes. New test verifies undefined parsed inputs neither check Craft state nor fetch/update issue body, but remove accepted from issue "211" in getsentry/publish.src/publish/update-issue.js now defines async main(), parses PUBLISH_ARGS only if present, catches JSON parse errors to warn Could not parse publish inputs; skipping target update, awaits updateIssue({ context, octokit, inputs }), invokes main() only when run directly, sets process.exitCode = 1 on errors, and exports { main }.AGENTS.md, src/libs/github.js, src/modules/post-workflow-details.js, src/modules/process-end-state.js, src/modules/update-issue.js, src/publish/inputs.js, src/publish/post-result.js, and src/publish/post-workflow-details.js; AGENTS.md additionally points long-term lore-managed project knowledge to .lore.md.src/modules/__tests__/approval-attestation.js:22-69 verifies the latest accepted event is selected by ID ("200" over "100"), and numeric GitHub issue-event ID 29503999078 normalizes to string "29503999078".src/modules/__tests__/approval-attestation.js:71-114 verifies a CI-ready attestation binds accepted actor/event contractor/"200" and expected CI-ready actor sentry-internal-app[bot]; it fails if either accepted event changes or the eventual ci-ready label actor differs.src/modules/__tests__/approval-attestation.js:116-173 verifies malformed/stale approval attestations are rejected, including wrong comment author, changed event ID/title, invalid base64 payload <!-- publish-approval not-base64 -->, and any change in dry-run label state after attestation.src/publish/__tests__/ci-poller-workflow.js:6-16 asserts .github/workflows/ci-poller.yml contains default-branch actions/checkout@v6 trusted-code checkout and that Get publish code occurs before Get auth token.src/publish/__tests__/current-accepted-event.js:5-38 verifies getCurrentAcceptedEvent() returns newest accepted event { actor: "contractor", eventId: "200" } and rejects absent valid accepted events with The issue has no current accepted label event.src/publish/__tests__/record-ci-ready-attestation.js:10-45 verifies recordCiReadyAttestation() binds the current accepted event contractor/"100" to authenticated CI-ready actor sentry-internal-app[bot], retaining the current issue digest and title publish: getsentry/sentry-javascript@10.0.0.src/publish/__tests__/record-ci-ready-attestation.js:47-91 verifies CI-ready attestation recording rejects a changed title or absent accepted event, and rejects a re-approval whose event ID "200" differs from poller-observed expected event "100", with The approval changed before CI could be marked ready.