Dashboard › publish › Distillation
5b92ceec-24c5-4d74-8c3b-e8b62eae6cb5["lore_tm_v1_k-JpU-3H5ULeJfqmInGhaZRdk_1fXBuHaGJ4y_DfLg4","lore_tm_v1_uWUpinmidj59c7_2Zt2ISAYfYm68ktsYAU5sjw-zHJE","lore_tm_v1_34YSk82m0E3iie6CFR39pgVsZi3iXWvulkc10ch-kDY","lore_tm_v1_TB65fBmV9ylGzjiiv-MBLQGdf6RdVyd5FWRgYQPVsnM","lore_tm_v1_WwyQvjJZ8Q-6LdfEXPwIc7KGQjYnBt4huYOVt6kHa4g","lore_tm_v1_jfPOACc1Ps5PMwBWK-Solo_obCRU2KJMxr-wE19iZ-Y","lore_tm_v1_K6zveng9O1LRLSYi-jxgHiBuGSVhZDNfmPvcT7W6Gdw","lore_tm_v1_YnaJjHmqU-sk24IvhD5bX2lQNGNl_S2xOdT-pE0f2To","lore_tm_v1_kxbWMXxWMlaqKybcuzkQ5kHhJ7YOklS4hQ0KlsqvvN0","lore_tm_v1_HKb49-KtpHu6fTITb8fg6p31TAkORFr6AWE5SSh6gIk","lore_tm_v1_10sVOIJnAUs8StFVaeSqc9-5luNbNC3FfdGF_8rp0ms","lore_tm_v1_27NDiElSNNrnPz8KoCgjs7gZbzyFOJgapwA37h-LU48","lore_tm_v1_N7ObwIvPJzg-n7gutnnk77i0iuVOBuMR0rj-ux--iWA","lore_tm_v1_ZUdyr8q17aLpImml_4zbTuQ2NyBCVH_XFwOzQMbs99c","lore_tm_v1_URqvKaNW3EckrJsesOYy0CafoahRySToEx297cvxNr8"]
2026-09-10
/home/byk/Code/getsentry/publish/src/modules/__tests__/publish-workflow.js./home/byk/Code/getsentry/publish/src/modules/__tests__/publish-workflow.js (170 lines): getSetTargetsScript() extracts the Bash body between workflow steps Set targets and Revalidate approval attestation; runSetTargets() executes it with CRAFT_PUBLISH_TARGETS_JSON='["github"]', a temporary GITHUB_OUTPUT, and a temporary GITHUB_WORKSPACE, then reads the emitted state_file.publish-workflow.js verifies publish-step ordering: Resolve CI-approved release revision → Inform start → Check out target repo → Resolve publish location → Set targets → Publish using Craft; checkout uses ref: ${{ steps.release-revision.outputs.revision }} and exactly 2 occurrences of actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1.publish-workflow.js verifies location/publish wiring: node .__publish__/src/publish/discover-location.js, PUBLISH_REPOSITORY_DIRECTORY: __repo__, docker://getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b, CRAFT_PUBLISH_PATH: ${{ fromJSON(steps.location.outputs.result).path }}, CRAFT_PUBLISH_WORKSPACE: ${{ fromJSON(steps.location.outputs.result).workspace || '' }}, and craft publish ${{ fromJSON(steps.inputs.outputs.result).version }} --rev ${{ steps.release-revision.outputs.revision }}.publish-workflow.js verifies publishing only on a fresh ci-ready label event: label name is ci-ready; issue must contain accepted and ci-ready; issue must not contain ci-pending or ci-failed.publish-workflow.js expects a root sentry release version 21.3.1 to use /.craft-state/craft/publish-state-getsentry-sentry-c232c383e26f-21.3.1.json and initialize { published: { github: true } }.publish-workflow.js expects monorepo path ./packages/cli with workspace packages/cli, repository toolkit, and version 1.2.3 to use /.craft-state/craft/publish-state-getsentry-toolkit-c232c383e26f-workspace-cGFja2FnZXMvY2xp-1.2.3.json and initialize { published: { github: true } }.publish-workflow.js verifies versions differing only by case do not collide: 4.2.6+sentry1 ends with -version-NC4yLjYrc2VudHJ5MQ.json, while 4.2.6+Sentry1 ends with -version-NC4yLjYrU2VudHJ5MQ.json./home/byk/Code/getsentry/publish/src/modules/__tests__/publish-location.js./home/byk/Code/getsentry/publish/src/modules/__tests__/publish-location.js (88 lines): resolvePublishLocation() treats exact, case-sensitive full workspace path ./packages/CLI among ["packages/cli", "packages/CLI"] as { path: ".", workspace: "packages/CLI" } without normalization.publish-location.js tests retain non-workspace checkout paths: ./packages with workspace cli remains { path: "./packages" }; ./packages/cli with workspace cli remains { path: "./packages/cli" }; root . remains { path: "." }.publish-location.js tests reject unsafe publish paths ./., ./.., and ./packages/../other with Invalid publish path..publish-location.js tests fail closed on invalid Craft workspace discovery output: packages/../cli and cli-日本語 are rejected, as are workspace names ., .., packages/./cli, packages/../cli, packages/__proto__/cli, packages/-cli, packages/foo], packages/foo!, and packages/foo^, with Craft workspace discovery returned an invalid workspace list../home/byk/Code/getsentry/publish/src/modules/__tests__/release-revision.js./home/byk/Code/getsentry/publish/src/modules/__tests__/release-revision.js (152 lines): canonical revision is 7e5ca7ed5581552de066e2a8bc295b8306be38ac; getReleaseRevision() extracts it from the request-header View check runs URL for getsentry/toolkit, accepts CRLF bodies, and accepts /checks with or without a trailing slash.release-revision.js tests reject a check-runs URL missing /checks or pointing to getsentry/other, with Expected a View check runs link for getsentry/toolkit.release-revision.js tests reject decoy or embedded check-runs links outside the request header with Expected exactly one View check runs link in Quick links; a complete Quick links block or complete request header occurring after ### Changelog is also rejected.updateReleaseRevision() is tested to replace only the canonical request-header revision while preserving CRLF and trailing content; replacement revisions "A".repeat(40), "a".repeat(39), and "a".repeat(41) are rejected with Release revision must be a lowercase 40-character SHA../home/byk/Code/getsentry/publish/src/modules/__tests__/ci-poller-input.js./home/byk/Code/getsentry/publish/src/modules/__tests__/ci-poller-input.js (105 lines): getCiPollerInput() parses both publish: getsentry/toolkit/cli@1.2.3 and publish: toolkit/packages/cli/v2@1.2.3 into repo: "getsentry/toolkit", revision: "7e5ca7ed5581552de066e2a8bc295b8306be38ac", version: "1.2.3", and a requestDigest() bound to the title, issue body, and labels accepted plus dry-run.ci-poller-input.js verifies .github/workflows/ci-poller.yml checks out publish code at .__publish__, invokes node .__publish__/src/publish/resolve-ci-poller-input.js, and no longer uses grep -oP '(?<=commit/.ci-poller-input.js rejects unsafe repository identities -toolkit, ., .., and __proto__ with Invalid publish issue repository; invalid versions --config and 1.2 with Invalid publish issue version; malformed titles publish: getsentry/@1.2.3 and publish: getsentry/toolkit$@1.2.3 with Invalid publish issue title; and unsafe paths containing ../other, ./other, __proto__/other, or --config with Invalid publish issue path./home/byk/Code/getsentry/publish/src/publish/__tests__/discover-location.js./home/byk/Code/getsentry/publish/src/publish/__tests__/discover-location.js (66 lines): when root .craft.yml is absent, discoverLocation() retains checkout path ./packages/cli; when present, exact workspace ./packages/CLI resolves to { path: ".", workspace: "packages/CLI" }.discover-location.js tests require workspace discovery to execute docker with pinned image getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b and arguments including workspace list, using { encoding: "utf8" }.discover-location.js tests fail closed with Craft workspace discovery returned an invalid workspace list. when Craft returns non-array JSON {} or blank output "\n"./home/byk/Code/getsentry/publish/.github/workflows/auto-approve.yml..github/workflows/auto-approve.yml (57 lines): workflow auto-approve non-sdks runs on opened issues in the production environment only when actor is sentry-release-bot[bot] or getsantry[bot] and the issue title starts with publish: ; permissions are contents: read and issues: write.auto-approve.yml uses actions/checkout@11d5960a326750d5838078e36cf38b85af677262 with persist-credentials: false, then actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 with SENTRY_INTERNAL_APP_ID and SENTRY_INTERNAL_APP_PRIVATE_KEY.auto-approve.yml binds the request snapshot via node src/publish/request-digest-from-event.js, records an automated approval attestation via node src/publish/record-auto-approval-attestation.js, posts AUTO_APPROVAL_ATTESTATION using gh issue comment, and adds accepted only if the title-derived REPO exactly matches a line in auto-approve-repos.txt via grep -qxF./home/byk/Code/getsentry/publish/src/modules/approval-attestation.js.src/modules/approval-attestation.js (263 lines): attestation comment prefixes are <!-- publish-approval , <!-- publish-auto-approval , and <!-- publish-ci-ready ; payloads are JSON encoded with base64url and terminated by -->.requestDigest({ body, labels, title }) validates body/title strings and a labels array, then computes SHA-256 over JSON containing exact body, title, and dryRun, where dryRun is true if any label is named dry-run; invalid input throws Invalid publish request.actor, stringified eventId, requestDigest, and title; auto-approval payload contains autoApprover, requestDigest, and title; CI-ready payload contains acceptedActor, stringified acceptedEventId, ciReadyActor, requestDigest, and title.null for absent prefixes/suffixes, invalid base64url/JSON, or missing/wrongly typed required fields; hasApprovalAttestation(), hasAutoApprovalAttestation(), and hasCiReadyAttestation() require the comment author to match attestationAuthor and all bound actor/event/digest/title fields to match current data.compareEventIds() strips leading zeros, validates decimal-only IDs, compares by normalized digit length and then lexicographically, and throws Invalid issue event ID for invalid IDs.currentLabeledEvent(events, labelName) filters valid matching labeled events with actor logins, chooses the greatest event ID using compareEventIds(), and returns { actor, eventId }; malformed comparisons or no events return null. currentAcceptedEvent() and currentCiReadyEvent() specialize it for accepted and ci-ready./home/byk/Code/getsentry/publish/src/publish/validate-approval-attestation.js.src/publish/validate-approval-attestation.js (158 lines): GitHub requests use https://api.github.com/, bearer APPROVAL_TOKEN, Accept: application/vnd.github+json, and X-GitHub-Api-Version: 2026-03-10.getAllPages() retrieves issue events or comments with per_page=100&page=<n> until a page contains fewer than 100 records; failed issue retrieval throws Could not retrieve issue #<number>: GitHub returned <status>, and failed paginated retrieval names the resource and status.validateApprovalAttestation() concurrently retrieves issue, events, and comments; approval requires an open issue, exact title, exact expected request digest, current accepted label/event, optional exact expected accepted actor/event ID, and a matching approval attestation.requireCiReadyAttestation is true, validation additionally requires a current ci-ready event, current ci-ready label, and matching CI-ready attestation bound to the current accepted event, CI-ready actor, request digest, and title.validate-approval-attestation.js requires environment variables APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, APPROVAL_ISSUE_REPOSITORY, APPROVAL_ISSUE_TITLE, APPROVAL_ATTESTATION_AUTHOR, and EXPECTED_REQUEST_DIGEST; optional EXPECTED_ACCEPTED_ACTOR plus EXPECTED_ACCEPTED_EVENT_ID bind the accepted event, and REQUIRE_CI_READY_ATTESTATION === "true" enables CI-ready validation. Invalid approval throws The current accepted label has no matching approval attestation./home/byk/Code/getsentry/publish/src/publish/request-digest-from-event.js.src/publish/request-digest-from-event.js (34 lines): requestDigestFromEvent(event) requires a non-null object event.issue, otherwise throws The GitHub event has no issue snapshot, and delegates to requestDigest(event.issue).request-digest-from-event.js requires GITHUB_EVENT_PATH and GITHUB_OUTPUT, reads the event as UTF-8 JSON, and appends request_digest=<digest>\n to the GitHub output file; missing variables produce explicit No "<name>" environment variable found errors.sha256:fc314146c06b14791ab860e80e73043c7c5fa06f61bce3081a34a8a227305a5a, tag getsentry/craft:2.30.1, and digest getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b; image was created 2026-08-08T00:37:30.542283842Z, is Linux/amd64, and has size 6480950136 bytes.craft and environment values including NODE_VERSION=24.18.0, YARN_VERSION=1.22.22, CRAFT_BUILD_SHA=cd1e8294061fd970b40d98b77aaa109cb1e00e78, DOTNET_CLI_TELEMETRY_OPTOUT=1, COCOAPODS_ALLOW_ROOT=1, CARGO_HOME=/root/.cargo, and RUSTUP_HOME=/root/.rustup./usr/local/bin/craft; file inspection identified it as a Node.js script executable, ASCII text, with very long lines (438), beginning with #!/usr/bin/env node.getCraftStateDir() uses <XDG_STATE_HOME>/craft when nonempty, otherwise <homedir>/.local/state/craft; sanitiseForFilename(raw) lowercases and replaces non-[a-z0-9._-] runs with _, trimming leading/trailing underscores.shortCwdHash(cwd) computes SHA-1 of cwd and takes the first 12 hex characters; getPublishStateFilename(version2, githubConfig, cwd) uses publish-state-${owner}-${repo}-${shortCwdHash(cwd)}-${safeVersion}.json when GitHub config exists, otherwise SHA-256 of cwd truncated to 16 hex characters in publish-state-${cwdDigest}-${safeVersion}.json.CRAFT_PUBLISH_STATE_GITHUB_REPO, cwdHash, or /workspace.*base64/i; XDG_STATE_HOME appeared only in the state-directory logic.publish NEW-VERSION aliases are pp and publish; the default post-release script path is scripts/post-release.sh.getGlobalGitHubConfig() inside try/catch, passing the resulting config or null to getPublishStatePath(newVersion, publishStateGithubConfig); it logs the resolved state path.publish-workflow.js: state filename identity is derived from sanitized lowercase version plus a 12-character SHA-1 of the current working directory when GitHub config is available, with no workspace-base64 suffix..craft-publish-${newVersion}.json as a legacy project-local state file that is no longer read for security reasons; if found, it warns users to pre-seed the new state path instead.targetsToPublish from configured target IDs; otherwise it initializes publishState as { published: Object.create(null) }.