Dashboard › publish › Distillation
979ca33d-c9b6-4d66-994f-190cf67aae4f["lore_tm_v1_0pxNTkOHfRoWppbpls37PBxmGKbT3ILKSMhW6kBcfPY","lore_tm_v1_T2muatVjBF4wvlbEwYsjbg_2CHEw6A_Tvd4ZZ96s-SM","lore_tm_v1_ig6SV_qAwk8QvqdRX9zHFDgpzh4fihOC-zGCeRMO_y8","lore_tm_v1_e0xQ866Pl34uMQ7UXN_lwiMhYyd5djI4MKK_WDv6bps","lore_tm_v1_wpC4HGmqoGd62RlsHaIVYSRUYqjrPyQzA71-oCoAN_A"]
Date: Aug 28, 2026
/home/byk/Code/getsentry/publish contains 15 entries: .eslintrc.js, .git/, .github/, .gitignore, .lore.md, AGENTS.md, auto-approve-repos.txt, docs/, LICENSE, node_modules/, package.json, README.md, src/, vitest.config.js, and yarn.lock..github/workflows/ci-poller.yml, .github/workflows/publish.yml, AGENTS.md, src/libs/__tests__/github.js, src/libs/github.js, src/modules/__tests__/details-from-context.js, src/modules/details-from-context.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, src/publish/post-workflow-details.js, and src/publish/update-issue.js; untracked files/directories include .lore.md, src/modules/__tests__/approval-attestation.js, src/modules/__tests__/approval-authorizer.js, src/modules/approval-attestation.js, src/modules/approval-authorizer.js, src/publish/__tests__/, src/publish/authorize-approval.js, and src/publish/validate-approval-attestation.js.ci-ready after either the publish-issue title or latest accepted-label event changes..github/workflows/ci-poller.yml changes add an initial actions/checkout@v6 step with persist-credentials: false; before parsing an accepted issue, it runs node src/publish/validate-approval-attestation.js with APPROVAL_TOKEN="$GH_TOKEN", APPROVAL_ATTESTATION_AUTHOR="github-actions[bot]", issue number/repository/title. On validation failure it removes ci-pending and accepted, comments that approval is invalid or unverifiable, and continues..github/workflows/ci-poller.yml replaces its inline sed title parser with parsePublishTitle imported from ./src/modules/details-from-context.js; it derives repo as getsentry/ plus parsed .repo and derives version from parsed .version, so CI and publishing target the same parsed repository/version..github/workflows/ci-poller.yml revalidates approval attestation after all CI checks pass and before applying ci-ready; validation failure removes ci-pending and accepted, comments an invalid/unverifiable approval message, and prevents the release from reaching ci-ready..github/workflows/publish.yml changes add initial checkout of publish code via actions/checkout@v6 with persist-credentials: false; creates a getsentry release-bot app token using actions/create-github-app-token@v3, vars.SENTRY_RELEASE_BOT_CLIENT_ID, and secrets.SENTRY_RELEASE_BOT_PRIVATE_KEY, with continue-on-error: true..github/workflows/publish.yml adds Authorize approval, which runs node src/publish/authorize-approval.js with the release-bot token and GitHub event actor/issue number/repository/title; it is continue-on-error: true..github/workflows/publish.yml records the authorization-produced approval attestation as an issue comment with ${{ github.token }} only when authorization succeeds and outputs authorized == 'true'; it then validates that attestation via node src/publish/validate-approval-attestation.js using ${{ github.token }} and attestation author github-actions[bot]..github/workflows/publish.yml adds fail-closed Reject invalid approval: if authorization failed/not authorized, attestation posting failed, or attestation validation failed, it 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.ci-ready; publish.yml is designed to fire only on ci-ready label events, not accepted, specifically to avoid racing with waiting-for-ci on the same event..__publish__ with persist-credentials: false, validates approval attestation before setup/publishing using node .__publish__/src/publish/validate-approval-attestation.js, and on validation failure removes accepted, comments the same retry message, and exits 1.src/modules/details-from-context.js introduces and exports PUBLISH_TITLE_REGEX and parsePublishTitle(title). The regex is /^publish: (?:getsentry\/)?(?<repo>[^/@]+)(?<path>\/[\w./-]+)?@(?<version>[\w.+-]+)$/; detailsFromContext() now throws Invalid publish issue title: ${context.payload.issue.title} when parsing fails.src/modules/approval-attestation.js is newly added. It encodes { actor, eventId: String(eventId), title } as base64url in an HTML comment delimited by <!-- publish-approval and -->; parses and type-checks all three fields; compares numeric event IDs after stripping leading zeroes; identifies the latest valid labeled accepted event by largest event ID; and accepts an attestation only if a comment author matches attestationAuthor and the attested actor, event ID, and title exactly match the current accepted event and title.src/modules/approval-authorizer.js is newly added. authorizeApproval() parses the publish title, derives target repository getsentry/${title.repo} and release path including optional title path, authorizes getsantry[bot] only for entries in auto-approve-repos.txt, rejects that bot for other repositories, and otherwise authorizes GitHub roles write, maintain, or admin obtained for the actor on the parsed target repository.src/publish/authorize-approval.js is newly added. It reads non-empty lines from auto-approve-repos.txt; requests GitHub REST API endpoints with Authorization: Bearer ${process.env.APPROVAL_TOKEN}, Accept: application/vnd.github+json, and X-GitHub-Api-Version: 2026-03-10; paginates issue events 100 per page; verifies the live issue title equals APPROVAL_ISSUE_TITLE and that the latest accepted-label event actor equals APPROVAL_ACTOR; then writes either authorized=false or authorized=true plus approval_attestation=<attestation> to GITHUB_OUTPUT.src/publish/validate-approval-attestation.js is newly added. It requires APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, APPROVAL_ISSUE_TITLE, and APPROVAL_ATTESTATION_AUTHOR; concurrently fetches the live issue, all issue events, and all issue comments in pages of 100; and succeeds only when the live title equals the supplied title, label accepted is present, a current accepted-label event exists, and a matching attestation comment exists. Otherwise it throws The current accepted label has no matching approval attestation..github/workflows/publish.yml, production publishing exposes secrets including 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; it also provides DOCKER_GHCR_IO_PASSWORD: ${{ secrets.GITHUB_TOKEN }}..github/workflows/publish.yml failure/cancellation cleanup invokes node .__publish__/src/publish/update-issue.js with PUBLISH_ARGS and ${{ secrets.GITHUB_TOKEN }}; cancellation and failure post post-result.js cancelled / post-result.js failure, while success posts post-result.js success.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, src/publish/post-workflow-details.js, and src/publish/update-issue.js; AGENTS.md adds a lore-managed Long-term Knowledge section pointing to .lore.md.