Dashboard › publish › Distillation
574479d6-5b3f-4226-95e6-02ed0c13f423["lore_tm_v1_CquRtbfGmHTQD_LoA99eIMHNvC977_WlBOOfvAyVgmw","lore_tm_v1_608edAv4uMjQL8l-54FtNmO7hRnz87erMjWxY8T-3eg","lore_tm_v1_1i2s50Gfcw1JgpaEQxsssRpL82hDwZrT5xetTLlacCk","lore_tm_v1_0DccIZnAHsn30hzNwYOHP_RP_QbVuBTM-B9B90cZVpo","lore_tm_v1_lO1ItL_mJMVHnRSuo0kM9g8wCeZUDsEfUuazdj6tt1g","lore_tm_v1_PEOStWSbWUlN2o0GoLNhWWNkRq2VAjHKzWHidMZK_Bk","lore_tm_v1_7TI3ogAAqCWqvYzo5LUZBfNliFWi5VwPdv7mio-VvJQ","lore_tm_v1_ZIEP-mEo1vsUxWm_sS6126BVoLtgll05VBwO_HmZtZY","lore_tm_v1__Tm5M2e9SqfnqptirI30R-8pbzR75BwXEdJkJlESjJ4","lore_tm_v1_iBPTL7JcS7yhMh_32MRU5IG-rZ0Rd1fjc5KXbNMliko"]
/home/byk/Code/getsentry/publish/package.json defines package publish version 0.0.1, private, Apache-2.0, repository git@github.com:getsentry/publish.git, description Approval-based publishing system for Sentry, author Sentry Open Source <oss@sentry.io>, Volta Node 24.0.0 and Yarn 1.22.22, with resolution undici: ^6.23.0./home/byk/Code/getsentry/publish/package.json scripts are test: vitest run, test:watch: vitest, lint: eslint src .github --ignore-pattern '!.github', and prettier: prettier --write src; dependencies are @actions/core: ^2.0.0, @actions/github: ^7.0.0, and @sentry/node: ^10.0.0; dev dependencies are eslint: ^8.9.0, eslint-config-prettier: ^8.3.0, eslint-plugin-yml: ^0.13.0, prettier: ^2.2.1, and vitest: ^4.1.0..github/workflows/auto-approve.yml defines auto-approve non-sdks, triggered by opened issues, with contents: read and issues: write; its production auto-approve job runs only when the actor is sentry-release-bot[bot] or getsantry[bot] and the issue title starts with publish: ..github/workflows/auto-approve.yml checks out only auto-approve-repos.txt using actions/checkout@11d5960a326750d5838078e36cf38b85af677262, obtains a GitHub App token using actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 with SENTRY_INTERNAL_APP_ID and protected SENTRY_INTERNAL_APP_PRIVATE_KEY, runs node src/publish/record-auto-approval-attestation.js, posts steps.attestation.outputs.auto_approval_attestation, then extracts the repository from ISSUE_TITLE; if it exactly matches a line in auto-approve-repos.txt, it adds the accepted label.actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803, actions/checkout@11d5960a326750d5838078e36cf38b85af677262, actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1, actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38, actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830, and docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b..github/workflows/publish.yml uses issue-title concurrency (group: ${{ github.event.issue.title }}, cancel-in-progress: false) so duplicate publish issues for the same repo@version share a concurrency group..github/workflows/publish.yml waiting-for-ci runs in production when accepted is added to an open issue whose title begins publish: . It obtains the internal app token, then best-effort obtains a release-bot app token scoped to owner getsentry; node src/publish/authorize-approval.js checks the actorβs effective role in the target repository.waiting-for-ci posts steps.authorization.outputs.approval_attestation and validates it with node src/publish/validate-approval-attestation.js, requiring author github-actions[bot]. If authorization, posting, or validation fails, it removes accepted, comments 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 resets an approved issue to clean CI state by removing ci-failed and ci-ready, then adding ci-pending; removing ci-ready ensures a later fresh ci-ready labeled event can trigger publishing after a retry..github/workflows/publish.yml comments either Retrying β CI was previously failed. Checking CI status now. or Approved. Checking CI status on the release branch. Publishing will start automatically when CI passes. It best-effort enables the cron poller via repository variable CI_POLLER_HAS_PENDING=true, using CI_POLLER_APP_CLIENT_ID and protected CI_POLLER_APP_PRIVATE_KEY, then immediately sends repository dispatch event type ci-poller because GITHUB_TOKEN-generated workflow_dispatch events are suppressed.main...origin/main [behind 1]; modified paths were .github/workflows/auto-approve.yml, .github/workflows/ci-poller.yml, .github/workflows/cocoapods-keepalive.yml, .github/workflows/publish.yml, .github/workflows/test.yml, AGENTS.md, README.md, docs/key_rotation_vault_changes.md, docs/rfc.md, src/libs/__tests__/github.js, src/libs/github.js, src/modules/__tests__/details-from-context.js, src/modules/__tests__/update-issue.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..github/workflows/ci-poller-dispatch.yml, .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, src/publish/current-accepted-event.js, src/publish/record-auto-approval-attestation.js, src/publish/record-ci-ready-attestation.js, and src/publish/validate-approval-attestation.js; the displayed diff summary covered 21 files changed, 499 insertions(+), 117 deletions(-).src/publish/record-ci-ready-attestation.js defines getAuthenticatedLogin(), recordCiReadyAttestation(), and main(). It concurrently retrieves the issue, issue events, and authenticated login; determines currentAcceptedEvent(events); and rejects with The approval changed before CI could be marked ready if the issue is not open, its title changed, accepted is missing, no accepted event exists, or the current accepted actor/event ID differs from optional EXPECTED_ACCEPTED_ACTOR and EXPECTED_ACCEPTED_EVENT_ID.src/publish/record-ci-ready-attestation.js requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, and APPROVAL_ISSUE_TITLE; it writes ci_ready_attestation=<attestation> to GITHUB_OUTPUT. getAuthenticatedLogin() calls GitHub resource user, errors on a non-OK response or missing string login, and recordCiReadyAttestation() returns createCiReadyAttestation({ acceptedEvent, ciReadyActor, issue }).src/modules/approval-attestation.js defines three hidden-comment formats with prefixes <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready and suffix -->; payloads are JSON encoded with base64url.requestDigest({ body, labels, title }) validates that body is a string and labels is an array, then computes a SHA-256 hexadecimal digest of JSON containing body, dryRun derived from the dry-run label, and title.actor, stringified eventId, requestDigest, and title; auto-approval attestations contain autoApprover, requestDigest, and title; CI-ready attestations contain acceptedActor, stringified acceptedEventId, ciReadyActor, requestDigest, and title.compareEventIds(left, right) strips leading zeroes, validates decimal-only IDs, and compares first by normalized length and then localeCompare, avoiding unsafe numeric conversion. currentLabeledEvent(events, labelName) selects the greatest valid event ID among matching labeled events with an actor login; malformed IDs result in null. currentAcceptedEvent() and currentCiReadyEvent() specialize this for accepted and ci-ready.hasApprovalAttestation(), hasAutoApprovalAttestation(), and hasCiReadyAttestation() require a comment by the designated attestationAuthor and exact agreement with the current issue digest/title and relevant actors/event IDs; CI-ready validation ties the accepted event to the actor who added the current ci-ready label.src/modules/details-from-context.js uses PUBLISH_TITLE_REGEX /^publish: (?:getsentry\/)?(?<repo>[^/@]+)(?<path>\/[\w./-]+)?@(?<version>[\w.+-]+)$/, accepting both qualified and legacy publish titles, optional monorepo paths, and versions containing +; detailsFromContext() returns repo, version, path prefixed with ., dry_run as "1" or "", merge_target, and checked targets.src/modules/details-from-context.js parses merge targets with /^Merge target: (?<merge_target>[\w.\-/]+)$/m; (default) does not match and therefore yields merge_target: "". It extracts only checked target lines from the matched targets section using CHECKED_TARGETS_PARSER_REGEX, and throws Issue context is not defined when the issue payload is absent or Invalid publish issue title: <title> for malformed titles.src/modules/__tests__/details-from-context.js verifies: publish: getsentry/sentry@21.3.1 with Merge target: custom-branch yields path ., repo sentry, version 21.3.1, and checked targets ["github", "npm[@sentry/node]", "docker[latest]"]; version 4.2.6+sentry1 parses intact; publish: getsentry/sentry-javascript/packages/core@10.0.0 yields path /packages/core; legacy publish: sentry-javascript@10.0.0 yields path: undefined; Merge target: (default) yields merge_target: ""; and missing issue context throws Issue context is not defined.ci-ready after checking CI, even if ci-ready had previously been present; waiting-for-ci removes it first so a fresh labeled event always fires on the happy path..github/workflows/publish.yml publish job runs in production, has timeout-minutes: 90, and triggers only on an open issueβs ci-ready label event when both accepted and ci-ready are present and neither ci-pending nor ci-failed is present.publish job validates approval before setup and revalidates immediately before Craft publishing, both times with REQUIRE_CI_READY_ATTESTATION: "true" via src/publish/validate-approval-attestation.js; either failure removes accepted, posts the invalid-approval retry message, and exits 1.publish job uses Node 24 with Yarn caching, runs yarn install --cwd ".__publish__", parses inputs via src/publish/inputs.js, and posts workflow-start details via src/publish/post-workflow-details.js.sentry-migr8/tmp-merge-target; sentry-javascript/v10, v9, v8, v7, or master; sentry-python/alpha; and sentry-wizard/1.x.Set targets step renders selected targets into Craftβs {"published": ...} state, stores it outside __repo__/ under $GITHUB_WORKSPACE/.craft-state/craft, hashes the container-side canonical working directory with SHA-1 truncated to 12 characters, sanitizes owner/repository/version, and writes publish-state-${owner_sanitised}-${repo_sanitised}-${cwd_hash}-${version_sanitised}.json; XDG_STATE_HOME is pinned to /github/workspace/.craft-state so target-repository contents cannot pre-populate Craft state.docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b, changes to __repo__/${{ fromJSON(steps.inputs.outputs.result).path }}, and executes craft publish <version>. It receives release-bot credentials plus protected publishing credentials for GHCR, Cloudflare, CocoaPods, GCS, crates.io, Docker, Hex, PyPI/Twine, npm, RubyGems, AWS, NuGet, PowerShell, GPG, OSSRH, pub.dev, and Vercel; no secret values were recorded..github/workflows/publish.yml runs src/publish/update-issue.js; it then runs src/publish/post-result.js cancelled or src/publish/post-result.js failure respectively. On success it runs src/publish/post-result.js success, which closes the issue.