Dashboard › publish › Distillation
83c1b67b-9d16-49a5-b603-a39c7d47ba17["lore_tm_v1_7zBVAynQ2xQGwwoCA1UP1wTN5cV8vW0e8CiCC-I8kz4","lore_tm_v1_w6ERToZ9WSnso5TOXJQEsVAxWup7dssRKrG5aWHklK4","lore_tm_v1_JrhUUKjo0y7NKwRUciJqVJgmeUB3xbOXTKtvMMZwlPo","lore_tm_v1_dVTzpsxE-v6N2F2lkRYS8Xxfc-KhKl9J9mV00oV2a1s","lore_tm_v1_rO0OcXDPEaQ3ogn4Mr2YxVXmKOeL5GlfXLMAYFnGoWg","lore_tm_v1_tVMgac8RAMEv-ulIVe3sf9uAhruMnm2iGIU_tcuMjp4","lore_tm_v1_pL06U-y169K9kah3XwmsM1GxcWO61UwsA7TPHxrjsOI","lore_tm_v1_HtBtFgWxA3DnGJr6KKAHKZ4FqFupiuGaSslhxWzC7FE","lore_tm_v1_T0rkKqtcgxwRzzIXMQqKruEnK4r1FWnm1eIj2tEppAI","lore_tm_v1_hhkEPK2MTx9MwUptOwuFC-9VkaSQxqgQ9jG_wzE23Lw","lore_tm_v1_9P4o0VssMBKAmkHU3ZLIfKVnjW6ntRKMEmHIytGTCVI","lore_tm_v1_IOltK46BvXz1tLXLA63RLeSZwl8q_rKmW4N_YMNKky8","lore_tm_v1_K779eDkykgXK-B3Vo2vpgbsljJ3uhnfYTLRnbGRas7k","lore_tm_v1_jJgI5UbqECxQcgleChOL9w0gh3-fxLvLnZZTkSwVEwE","lore_tm_v1_OAH7EmFqAqanYgJ01_TAJ5QbpHBZVkggBqrY7uSEUUE","lore_tm_v1_04_SCFXrkJNrgo8SRvtdXE1Ntj4H7_mgUkwHD-RPIQ0"]
Date: Aug 27, 2026
ses_fbb21c22effeAavAYTbRleeofj (“Security gate review”) completed but returned an empty <task_result> with no findings or report..github/workflows/auto-approve.yml (35 lines): triggers on opened issues; job auto-approve runs only when github.actor is sentry-release-bot[bot] or getsantry[bot] and issue title begins publish: ; checks out only auto-approve-repos.txt; creates an internal-app token through actions/create-github-app-token@v3 with vars.SENTRY_INTERNAL_APP_ID and secrets.SENTRY_INTERNAL_APP_PRIVATE_KEY; parses REPO from ISSUE_TITLE with sed -n 's/^publish: \(.*\)@.*/\1/p'; if that exact path is allowlisted, uses GH_TOKEN=${{ steps.token.outputs.token }} to run gh issue edit "$ISSUE_URL" --add-label accepted..github/workflows/publish.yml content stating that the ci-poller always adds ci-ready; its publishing job is named Publish a new version, uses node-version: 24, parses inputs via node .__publish__/src/publish/post-workflow-details.js, and invokes Craft publishing with CRAFT_PUBLISH_VERSION, CRAFT_PUBLISH_REPO, and CRAFT_PUBLISH_PATH.src/publish/authorize-approval.js (157 lines): getAutoApprovedRepositories() loads nonempty exact lines from auto-approve-repos.txt into a Set; GitHub API requests use APPROVAL_TOKEN bearer authentication and API version 2026-03-10; getIssueEvents() paginates 100 events per page; main() requires GITHUB_OUTPUT, APPROVAL_TOKEN, APPROVAL_ISSUE_NUMBER, and APPROVAL_ISSUE_REPOSITORY; calls authorizeApproval({ actor: APPROVAL_ACTOR, issueTitle: APPROVAL_ISSUE_TITLE, getPermission, autoApprovedRepositories }); on unauthorized writes authorized=false; on authorization, retrieves the current issue and all events, requires live title equality, a current accepted event, and event.actor === APPROVAL_ACTOR; then writes authorized=true and an approval_attestation created from { actor, eventId, title }.approval-authorizer uses live GitHub collaborator permission checks rather than private security-as-code, because Publish is public and GitHub reflects effective target-repository access without exposing RBAC; human approval requires write, maintain, or admin, while triage never authorizes.getsantry[bot] never authorizes through collaborator lookup; it authorizes only when the exact parsed repository/release path is in auto-approve-repos.txt, because bot repository access does not prove that an event followed an allowlisted auto-approval path.accepted using an internal-app token can cause GitHub to record the app rather than getsantry[bot] as the label-event actor; an approval gate authorizing github.actor could thereby reject legitimate allowlisted automation or check the app’s target-repository role. Proposed remedies in lore: preserve trusted auto-approval provenance independently of label-event actor, or consume an authenticated signal identifying the original bot.auto-approve.yml applies accepted with the internal-app token and said it would add a trusted pre-label provenance record for exact allowlisted releases, allowing authorization to consume it only for the internal-app event.src/modules/approval-attestation.js (108 lines): createApprovalAttestation({ actor, eventId, title }) encodes JSON { actor, eventId: String(eventId), title } as base64url inside <!-- publish-approval … -->; parseApprovalAttestation() validates string actor, eventId, and title; compareEventIds() normalizes leading zeroes, requires decimal IDs, and compares by length then lexicographically; currentAcceptedEvent() selects the largest-ID labeled event whose label is accepted and whose actor login exists; hasApprovalAttestation() requires an attestation comment authored by attestationAuthor whose actor, event ID, and title exactly match..github/workflows/ci-poller.yml must always allow workflow_dispatch for manual recovery: check-ci runs when vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch'.ci-ready after either the latest accepted label-event value or issue title changes; it validates approval attestations using src/publish/validate-approval-attestation.js with APPROVAL_TOKEN="$GH_TOKEN", APPROVAL_ATTESTATION_AUTHOR="github-actions[bot]", issue number/repository/title, and on validation failure removes ci-pending and accepted, then comments that approval is invalid or unverifiable..github/workflows/ci-poller.yml details: scheduled every 5 minutes (cron: "*/5 * * * *"), dispatch input attempt defaults to "0", concurrency.group is ci-status-poller with cancel-in-progress: false, checks out with actions/checkout@v6 and persist-credentials: false, creates internal-app and all-getsentry release-bot tokens, and only polls open issues carrying both ci-pending and accepted labels (limit 200).publish: owner/repo[/path]@version, extracts the first two path segments as GitHub repo and version after @, extracts a 40-hex commit SHA from a commit/{SHA}/checks URL in the issue body, resolves the original commit’s check-suite head_branch, then the branch HEAD SHA; when branch HEAD changed, updates the issue-body check-runs link.success, neutral, and skipped count as passing, while failure, cancelled, timed_out, action_required, stale, and startup_failure count as unsuccessful; at least one check run or one commit status must exist, otherwise CI is considered not started.README.md approval policy: packages installed by customers—including sentry-cli, SDKs, and symbolicator distributed utilities—require explicit approval; internal dependencies such as arroyo can receive auto-approval because their dependency bump later requires explicit approval in Sentry proper; the document notes that independent packages with sufficient independent use could warrant reconsideration of auto-approval due to attacker-target risk.README.md security architecture: Publish is read-only except for release managers because repository secrets include admin-level GitHub access tokens and package publishing tokens (npm, PyPI, cargo, etc.), and write access could permit arbitrary workflow execution exposing them; Craft and release workflows use short-lived Sentry Release Bot GitHub App tokens generated through actions/create-github-app-token using org-level SENTRY_RELEASE_BOT_CLIENT_ID and SENTRY_RELEASE_BOT_PRIVATE_KEY; GITHUB_TOKEN cannot trigger downstream workflows.accepted label event only when this record exists for an allowlisted release.src/publish/__tests__/authorize-approval.js (108 lines): tests use Vitest and reset environment/modules after each test; runAuthorization() sets GITHUB_OUTPUT="/tmp/github-output", APPROVAL_TOKEN="release-bot-token", APPROVAL_ISSUE_NUMBER="123", APPROVAL_ISSUE_REPOSITORY="getsentry/publish", and mocks global.fetch; allowlist test expects exact paths getsentry/sentry-javascript and getsentry/objectstore/clients; successful human authorization test uses actor contractor, title publish: getsentry/sentry-javascript@10.0.0, permission role_name: "write", latest accepted-event ID "100" by contractor, and expects authorized=true plus a publish-approval attestation; GitHub permission lookup failure 404 must throw Could not retrieve contractor's permission for getsentry/sentry-javascript: GitHub returned 404 without writing output.src/modules/approval-authorizer.js (37 lines): ALLOWED_ROLE_NAMES is exactly write, maintain, and admin; AUTO_APPROVER is getsantry[bot]; it matches titles with PUBLISH_TITLE_REGEX, builds repository as getsentry/${title.groups.repo} and releasePath with any path suffix; the auto-approver is authorized only when autoApprovedRepositories.has(releasePath), otherwise explicitly denied before collaborator lookup; all other actors are looked up at getsentry/<repo> and authorized only if their role_name is allowed.src/modules/__tests__/approval-attestation.js (90 lines): verifies the latest accepted event is selected by greatest event ID ("200" over "100"), numeric GitHub event ID 29503999078 is normalized to string "29503999078", trusted attestations require author github-actions[bot] in the positive case, and rejects attestation comments from the wrong author, stale event IDs/titles, and malformed <!-- publish-approval not-base64 -->.30127721394 by sentry-junior[bot] for issue 9365; 30125783461 by BYK for 9364; 30118737836, 30117262739, 30115600805, and 30114374562 by getsantry[bot] for 9363, 9362, 9361, and 9360; 30110879532 by getsantry[bot] for 9359; 30105020188 by runningcode for 9356; 30105019414 by Litarnus for 9357; 30101156858 by markushi for 9354; 30100304680 by NinjaLikesCheez for 9348; and 30098331858 by antonis for 9353.accepted label events from this workflow to getsantry[bot], rather than the internal app; it said the narrow allowlist path therefore has the expected event actor, that it is retaining the stricter provenance gate, and that it is requesting a substantive security review.