Dashboard › publish › Distillation
259bd22e-85a5-434f-a4cf-cb61b71c4220["lore_tm_v1_f2KDvvLwSdO1tyRX0EGgku3HGb0jVf2wEtQFHcVvKo4","lore_tm_v1_P17TzuZxnsF6xyyzaWKBSL7DiUfWD5hK0jNQpVAJ3ms","lore_tm_v1_lylxc0aOiP-GJJbmAh0AysU3BgTP27FoT4hmC_tfkyA","lore_tm_v1_Cg4Zc87xoi1M7SDKFSvD8KYksaCTHKYolSu_L791Vmg","lore_tm_v1_yYjLJxcDIRMOkiJcCjg2dTCJVKq8GXzg-46PSfwY-0I"]
Date: Sep 8, 2026
src/modules/update-issue.js defines updateTargets({ octokit, version, publishRepo, issue_number }), which reads ${process.env.GITHUB_WORKSPACE}/__repo__/.craft-publish-${version}.json only if it exists; concurrently fetches the issue with octokit.rest.issues.get and parses the craft state JSON; transforms issue.body via transformIssueBody(craftState, issue.body); then updates the issue body through octokit.rest.issues.update.transformIssueBody(craftState, issueBody) in src/modules/update-issue.js uses TARGETS_SECTION_PARSER_REGEX and TARGETS_PARSER_REGEX; it preserves declared target entries while changing each checkbox to checked iff craftState.published[targetId] is truthy, appends previously unlisted Object.keys(craftState.published) targets with corresponding checkbox states, and adds trailing newlines.updateIssue({ context, octokit, inputs }) extracts publishRepo from context.repo and issue_number from context.payload.issue.number; it concurrently runs version-gated updateTargets when inputs?.version exists and removes the "accepted" label with octokit.rest.issues.removeLabel.src/modules/details-from-context.js defines TARGETS_SECTION_PARSER_REGEX as /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m, TARGETS_PARSER_REGEX as /^\s*- \[[ x]\] (\S+)/gim, CHECKED_TARGETS_PARSER_REGEX as /^\s*- \[x\] (\S+)/gim, and PUBLISH_TITLE_REGEX as /^publish: (?:getsentry\/)?(?<repo>[^/@]+)(?<path>\/[\w./-]+)?@(?<version>[\w.+-]+)$/.parsePublishTitle(title) returns title.match(PUBLISH_TITLE_REGEX)?.groups || null; detailsFromContext({ context }) throws Error("Issue context is not defined") without context.payload.issue, and throws Error(\Invalid publish issue title: ${context.payload.issue.title}`)` when the title does not match.detailsFromContext derives dry_run as "1" when issue labels include "dry-run" or "" otherwise; derives path as "." + (titleMatch.path || ""); parses a Merge target: <merge_target> line using /^Merge target: (?<merge_target>[\w.\-/]+)$/m; parses checked targets from the matched targets section; and returns { ...titleMatch, dry_run, merge_target, path, targets }, where targets remains undefined if no targets section matches.workflow_dispatch must always run trusted code, specifically checking out the repository default branch with persist-credentials: false before app-token steps in .github/workflows/ci-poller.yml.ci-ready after it changes; the poll cycle must bind to the current accepted-label event before CI and revalidate after final CI checks so a renamed or re-approved issue never reaches ci-ready..github/workflows/ci-poller.yml, .github/workflows/publish.yml, AGENTS.md, src/libs/__tests__/github.js, src/libs/github.js, src/modules/__tests__/update-issue.js, src/modules/details-from-context.js, src/publish/post-workflow-details.js, and src/publish/update-issue.js; .github/workflows/ci-poller.yml changed permissions.issues from read to write..github/workflows/ci-poller.yml:29-56: actions/checkout@v6 uses ref: ${{ github.event.repository.default_branch }} and persist-credentials: false.src/modules/approval-attestation.js:13-46 bind the actor, accepted-label event, title, body, and dry-run state; src/publish/validate-approval-attestation.js:71-99 requires the current accepted event and an attestation comment from github-actions[bot]..github/workflows/ci-poller.yml:102-134 and :253-340 bind the accepted event before CI, revalidate after CI, record the app identity for ci-ready, and validate immediately before promotion; assistant concluded renamed or re-approved issues cannot progress to ci-ready..github/workflows/publish.yml:196-219 requires a CI-ready attestation tied to the current approval and to the actor that added ci-ready; failure cleanup in .github/workflows/ci-poller.yml:376-417 runs unconditionally and conservatively preserves the pending-state variable..github/workflows/publish.yml:61-67 supplies only the label actor, while authorizeApproval() in src/modules/approval-authorizer.js:28-34 authorizes any human with target-repository write access; although src/publish/authorize-approval.js:111-130 later fetches the issue, it does not compare issue.user.login to the approver. A target-repository collaborator can therefore approve their own release. Recommended fix: perform a live issue-author comparison, reject equal requester/approver logins, and add a regression test.git diff --check passed; yarn test --printConsoleTrace passed with 54 tests; yarn lint failed on unrelated existing .github/workflows/cocoapods-keepalive.yml:1 due to yml/plain-scalar. Assistant marked the change set DO-NOT-MERGE pending the self-approval fix.