DashboardpublishSession 1MdXRLzzwzI6

Session 1MdXRLzzwzI6

Full ID: 1MdXRLzzwzI66jNKD
Messages: 70
Distillations: 8
Time range: 2026-09-10 03:01:25 — 2026-09-10 03:19:10

Conversation (70 messages)

Perform a read-only adversarial correctness/security audit of the current uncommitted tree in /home/byk/Code/getsentry/publish, scoped to the release input, revision, target checkout, publish location, Craft invocation, and state-file identity paths. Inspect relevant workflows, source, and tests. Do not edit files. Look for mismatches between immutable event state, live state, parsed inputs, checked-out repo/revision, discovered path/workspace, state key, and actual Craft arguments/environment; shell/expression injection; path traversal; mutable references; credentials exposure. The snapshot-digest hardening currently being implemented is intentional. Return only substantive findings ordered by severity with exact file:line evidence, exploit/failure sequence, and a concrete fix; if none, state PASS and list residual test gaps. End exactly MERGE or DO-NOT-MERGE.

gateway · 2026-09-10 03:01:25
result
<path>/home/byk/Code/getsentry/publish</path>
<type>directory</type>
<entries>
.eslintrc.js
.git/
.github/
.gitignore
.lore.md
AGENTS.md
auto-approve-repos.txt
docs/
LICENSE
node_modules/
package.json
README.md
scripts/
src/
vitest.config.js
yarn.lock

(16 entries)
</entries>
gateway · 2026-09-10 03:01:48
result
[
  {
    "content": "Identify every changed and untracked file in the exact worktree",
    "status": "in_progress",
    "priority": "high"
  },
  {
    "content": "Trace release input through revision, checkout, path/workspace, state identity, and Craft execution",
    "status": "pending",
    "priority": "high"
  },
  {
    "content": "Inspect adversarial regression coverage and run read-only validation",
    "status": "pending",
    "priority": "high"
  },
  {
    "content": "Verify the worktree snapshot remained unchanged and issue a binary verdict",
    "status": "pending",
    "priority": "high"
  }
]
gateway · 2026-09-10 03:01:53
result
MM .github/workflows/auto-approve.yml
MM .github/workflows/ci-poller.yml
M  .github/workflows/cocoapods-keepalive.yml
MM .github/workflows/publish.yml
M  .github/workflows/test.yml
M  AGENTS.md
M  README.md
M  docs/key_rotation_vault_changes.md
M  docs/rfc.md
M  src/libs/__tests__/github.js
M  src/libs/github.js
 M src/modules/__tests__/ci-poller-input.js
 M src/modules/__tests__/ci-poller-workflow.js
MM src/modules/__tests__/details-from-context.js
 M src/modules/__tests__/publish-location.js
 M src/modules/__tests__/publish-workflow.js
 M src/modules/__tests__/release-revision.js
M  src/modules/__tests__/update-issue.js
 M src/modules/ci-poller-input.js
M  src/modules/details-from-context.js
M  src/modules/post-workflow-details.js
M  src/modules/process-end-state.js
 M src/modules/publish-location.js
 M src/modules/release-revision.js
 M src/publish/__tests__/discover-location.js
 M src/publish/__tests__/resolve-release-revision.js
 M src/publish/discover-location.js
M  ...
gateway · 2026-09-10 03:02:11
result
 .github/workflows/auto-approve.yml                |  30 +++-
 .github/workflows/ci-poller.yml                   | 202 +++++++++++++++++++---
 .github/workflows/cocoapods-keepalive.yml         |   1 -
 .github/workflows/publish.yml                     | 152 +++++++++++++++-
 .github/workflows/test.yml                        |   6 +-
 AGENTS.md                                         |   6 +
 README.md                                         |   4 +-
 docs/key_rotation_vault_changes.md                |  40 ++---
 docs/rfc.md                                       |   9 +-
 src/libs/__tests__/github.js                      |   2 +-
 src/libs/github.js                                |   6 +-
 src/modules/__tests__/ci-poller-input.js          |  22 ++-
 src/modules/__tests__/ci-poller-workflow.js       |  93 ++++++----
 src/modules/__tests__/details-from-context.js     |  22 ++-
 src/modules/__tests__/publish-location.js         |  19 +-
 src/modules/__tests__/publish-workflow.js         | ...
gateway · 2026-09-10 03:02:17

Your previous review returned an empty result, which is invalid. Resume the read-only adversarial audit of the exact unchanged tree in /home/byk/Code/getsentry/publish, scoped to release input, revision, target checkout, publish location, Craft invocation, and state-file identity. You MUST return a non-empty result. Inspect every relevant changed file and tests. For each area classify PASS, CONCERN, or MUST-FIX with exact current file:line evidence and reasoning. Any finding must include a concrete exploit/failure sequence and fix. If tool access blocks you, begin BLOCKED and name the exact tool/error. Do not edit files. End exactly MERGE or DO-NOT-MERGE.

gateway · 2026-09-10 03:03:35
result
<path>/home/byk/Code/getsentry/publish/.github/workflows/publish.yml</path>
<type>file</type>
<content>
1: name: Publish
2: on:
3:   issues:
4:     types: [labeled]
5: 
6: concurrency:
7:   # Use the issue title (e.g. "publish: getsentry/foo@1.2.3") so duplicate
8:   # issues for the same repo@version share a concurrency group.
9:   group: ${{ github.event.issue.title }}
10:   cancel-in-progress: false
11: 
12: permissions:
13:   contents: read
14:   issues: write
15:   packages: write
16: 
17: jobs:
18:   # When accepted is added to a publish issue:
19:   #   - Add ci-pending (and remove ci-failed if retrying)
20:   #   - Enable the poller via CI_POLLER_HAS_PENDING=true
21:   #   - Comment on the issue
22:   #   - Trigger the poller immediately so we don't wait for the next cron tick
23:   # The publish job below requires ci-ready, so it will not fire until the
24:   # poller flips ci-pending → ci-ready (which also prevents publishing without
25:   # CI verification in the ...
gateway · 2026-09-10 03:03:45
result
Found 100 matches (more matches available)
/home/byk/Code/getsentry/publish/src/publish/update-issue.js:
  Line 10:   if (process.env.PUBLISH_ARGS) {

  Line 12:       inputs = JSON.parse(process.env.PUBLISH_ARGS);


/home/byk/Code/getsentry/publish/src/publish/post-result.js:
  Line 7: const inputs = JSON.parse(process.env.PUBLISH_ARGS);


/home/byk/Code/getsentry/publish/src/publish/resolve-release-revision.js:
  Line 2: const { getReleaseRevision } = require("../modules/release-revision");

  Line 5:   const { repo } = JSON.parse(process.env.PUBLISH_ARGS || "{}");


/home/byk/Code/getsentry/publish/src/publish/resolve-location.js:
  Line 5:   const input = JSON.parse(process.env.PUBLISH_ARGS || "{}");

  Line 6:   const workspaceNames = JSON.parse(process.env.CRAFT_WORKSPACE_NAMES || "[]");

  Line 8:   if (!Array.isArray(workspaceNames)) {

  Line 10:       "Craft workspace discovery returned an invalid workspace list."

  Line 19:         ...
gateway · 2026-09-10 03:03:54
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-issue-validation.js</path>
<type>file</type>
<content>
1: function isPublishRepository(name) {
2:   return (
3:     /^[A-Za-z0-9_.-]+$/.test(name) &&
4:     name !== "." &&
5:     name !== ".." &&
6:     name !== "__proto__" &&
7:     !name.startsWith("-")
8:   );
9: }
10: 
11: function isReleaseVersion(version) {
12:   return /^(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-?([0-9a-z-]+(?:\.[0-9a-z-]+)*))?(?:\+([0-9a-z-]+(?:\.[0-9a-z-]+)*))?$/i.test(
13:     version
14:   );
15: }
16: 
17: module.exports = { isPublishRepository, isReleaseVersion };

(End of file - total 17 lines)
</content>
gateway · 2026-09-10 03:03:58
result
<path>/home/byk/Code/getsentry/publish/src/modules/details-from-context.js</path>
<type>file</type>
<content>
1: const { parse: parsePublishIssueTitle } = require("./publish-issue-title");
2: const { getReleaseRevisionDetails } = require("./release-revision");
3: const { isPublishPath } = require("./publish-location");
4: const {
5:   isPublishRepository,
6:   isReleaseVersion,
7: } = require("./publish-issue-validation");
8: 
9: /**
10:  * Matches the entire "Targets" section of a github publish issue body.
11:  */
12: const TARGETS_SECTION_PARSER_REGEX =
13:   /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m;
14: 
15: /**
16:  * Matches all targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
17:  * The "id" of the targets is captured within a capture group. ...
gateway · 2026-09-10 03:04:02
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-location.js</path>
<type>file</type>
<content>
1: function resolvePublishLocation({ path, workspaceNames }) {
2:   if (!isPublishPath(path)) {
3:     throw new Error("Invalid publish path.");
4:   }
5: 
6:   if (!workspaceNames.every(isWorkspaceName)) {
7:     throw new Error(
8:       "Craft workspace discovery returned an invalid workspace list."
9:     );
10:   }
11: 
12:   if (path === ".") {
13:     return { path };
14:   }
15: 
16:   const workspace = path.slice(2);
17:   if (workspaceNames.includes(workspace)) {
18:     return { path: ".", workspace };
19:   }
20: 
21:   return { path };
22: }
23: 
24: function isPublishPath(path) {
25:   return (
26:     typeof path === "string" &&
27:     (path === "." ||
28:       (path.startsWith("./") &&
29:         path.slice(2).split("/").every(isSafeWorkspaceSegment)))
30:   );
31: }
32: 
33: function isWorkspaceName(name) {
34:   return (
35:     typeof name === "string" && ...
gateway · 2026-09-10 03:04:08
result
<path>/home/byk/Code/getsentry/publish/src/modules/release-revision.js</path>
<type>file</type>
<content>
1: const { parse } = require("./publish-issue-title");
2: 
3: function isRevision(revision) {
4:   return /^[0-9a-f]{40}$/.test(revision);
5: }
6: 
7: function getReleaseRevisionDetails({ issueBody, repo }) {
8:   if (parse(issueBody, { startRule: "CheckRunsLinkCount" }) !== 1) {
9:     throw new Error(
10:       `Expected exactly one View check runs link in Quick links for getsentry/${repo}.`
11:     );
12:   }
13: 
14:   let details;
15:   try {
16:     details = parse(issueBody, { startRule: "ReleaseRevision" });
17:   } catch {
18:     throw new Error(
19:       `Expected a View check runs link for getsentry/${repo} in the publish issue body.`
20:     );
21:   }
22: 
23:   if (details.repo !== repo) {
24:     throw new Error(
25:       `Expected a View check runs link for getsentry/${repo} in the publish issue body.`
26:     );
27:   }
28: 
29:   return details;
30: }
31: 
32: ...
gateway · 2026-09-10 03:04:13
result
<path>/home/byk/Code/getsentry/publish/src/modules/ci-poller-input.js</path>
<type>file</type>
<content>
1: const { parse: parsePublishIssueTitle } = require("./publish-issue-title");
2: const {
3:   getReleaseRevision,
4:   updateReleaseRevision,
5: } = require("./release-revision");
6: const {
7:   isPublishRepository,
8:   isReleaseVersion,
9: } = require("./publish-issue-validation");
10: const { isPublishPath } = require("./publish-location");
11: const { requestDigest } = require("./approval-attestation");
12: 
13: function getCiPollerInput({ title, issueBody, labels, revision }) {
14:   let parsedTitle;
15:   try {
16:     parsedTitle = parsePublishIssueTitle(title);
17:   } catch {
18:     throw new Error(`Invalid publish issue title: '${title}'`);
19:   }
20:   const { repo, version } = parsedTitle;
21:   if (!isPublishRepository(repo)) {
22:     throw new Error(`Invalid publish issue repository: '${repo}'`);
23:   }
24:   if (!isReleaseVersion(version)) {
25:     throw new ...
gateway · 2026-09-10 03:04:24
result
<path>/home/byk/Code/getsentry/publish/.github/workflows/ci-poller.yml</path>
<type>file</type>
<content>
1: name: CI Status Poller
2: 
3: on:
4:   schedule:
5:     - cron: "*/5 * * * *"
6:   repository_dispatch:
7:     types: [ci-poller]
8:   workflow_run:
9:     workflows: [Run CI Status Poller]
10:     types: [completed]
11: 
12: permissions:
13:   contents: read
14:   issues: write
15: 
16: jobs:
17:   check-ci:
18:     runs-on: ubuntu-latest
19:     environment: production
20:     # Skip entirely (no runner provisioned) when there's nothing to check.
21:     # Set to "true" by ci-pending.yml, reset to "false" here when done.
22:     # repository_dispatch and a successful main-branch run of the protected
23:     # workflow_dispatch relay are the trusted manual-recovery paths.
24:     if: >-
25:       vars.CI_POLLER_HAS_PENDING == 'true'
26:       || github.event_name == 'repository_dispatch'
27:       || (
28:       github.event_name == 'workflow_run'
29:       && ...
gateway · 2026-09-10 03:04:36
result
Found 12 matches
/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.js:
  Line 199:     ReleaseRevision: peg$parseReleaseRevision,

  Line 200:     CheckRunsLinkCount: peg$parseCheckRunsLinkCount,

  Line 305:   function peg$f7(mergeTarget, repo, revision) {

  Line 306:     return { repo, mergeTarget, revision };

  Line 760:   function peg$parseReleaseRevision() {

  Line 922:                                   s23 = peg$parseCheckRunsRevision();

  Line 1046:   function peg$parseCheckRunsRevision() {

  Line 1105:   function peg$parseCheckRunsLinkCount() {

  Line 1110:     s2 = peg$parseCheckRunsLink();

  Line 1130:       s2 = peg$parseCheckRunsLink();

  Line 1178:   function peg$parseCheckRunsLink() {

  Line 1470:   StartRules: ["PublishIssueTitle", "ReleaseRevision", "CheckRunsLinkCount"],
gateway · 2026-09-10 03:04:43
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.js</path>
<type>file</type>
<content>
260:       ["a", "f"],
261:     ],
262:     false,
263:     false,
264:     false
265:   );
266:   const peg$e16 = peg$literalExpectation("- [View check runs](", false);
267:   const peg$e17 = peg$classExpectation([" ", "\t"], false, false, false);
268:   const peg$e18 = peg$literalExpectation("\r\n", false);
269:   const peg$e19 = peg$literalExpectation("\n", false);
270:   const peg$e20 = peg$classExpectation(["\r", "\n"], true, false, false);
271:   const peg$e21 = peg$literalExpectation("(default)", false);
272:   const peg$e22 = peg$classExpectation(
273:     [["A", "Z"], ["a", "z"], ["0", "9"], "_", ".", "/", "-"],
274:     false,
275:     false,
276:     false
277:   );
278:   const peg$e23 = peg$classExpectation(["\r", "\n", ")"], true, false, false);
279: 
280:   function peg$f0(repo, path, version) {
281:     return {
282:       repo,
283:       path: path || "",
284: ...
gateway · 2026-09-10 03:04:49
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.js</path>
<type>file</type>
<content>
740:           peg$currPos++;
741:         } else {
742:           s2 = peg$FAILED;
743:           if (peg$silentFails === 0) {
744:             peg$fail(peg$e6);
745:           }
746:         }
747:       }
748:     } else {
749:       s1 = peg$FAILED;
750:     }
751:     if (s1 !== peg$FAILED) {
752:       peg$savedPos = s0;
753:       s1 = peg$f5(s1);
754:     }
755:     s0 = s1;
756: 
757:     return s0;
758:   }
759: 
760:   function peg$parseReleaseRevision() {
761:     let s0, s1, s2, s3;
762: 
763:     s0 = peg$currPos;
764:     s1 = peg$parseRequestHeader();
765:     if (s1 !== peg$FAILED) {
766:       s2 = [];
767:       if (input.length > peg$currPos) {
768:         s3 = input.charAt(peg$currPos);
769:         peg$currPos++;
770:       } else {
771:         s3 = peg$FAILED;
772:         if (peg$silentFails === 0) {
773:           peg$fail(peg$e3);
774:         }
775: ...
gateway · 2026-09-10 03:04:57
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.js</path>
<type>file</type>
<content>
180: 
181:     return (
182:       "Expected " +
183:       describeExpected(expected) +
184:       " but " +
185:       describeFound(found) +
186:       " found."
187:     );
188:   }
189: }
190: 
191: function peg$parse(input, options) {
192:   options = options !== undefined ? options : {};
193: 
194:   const peg$FAILED = {};
195:   const peg$source = options.grammarSource;
196: 
197:   const peg$startRuleFunctions = {
198:     PublishIssueTitle: peg$parsePublishIssueTitle,
199:     ReleaseRevision: peg$parseReleaseRevision,
200:     CheckRunsLinkCount: peg$parseCheckRunsLinkCount,
201:   };
202:   let peg$startRuleFunction = peg$parsePublishIssueTitle;
203: 
204:   const peg$c0 = "publish: ";
205:   const peg$c1 = "getsentry/";
206:   const peg$c2 = "@";
207:   const peg$c3 = "/";
208:   const peg$c4 = "Requested by: @";
209:   const peg$c5 = "Merge target: ";
210:   const ...
gateway · 2026-09-10 03:05:04
result
/home/byk/Code/getsentry/publish/scripts/generate-publish-issue-title-parser.js
/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.peggy
/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.js
/home/byk/Code/getsentry/publish/src/modules/__tests__/generate-publish-issue-title-parser.js
gateway · 2026-09-10 03:05:08
result
<path>/home/byk/Code/getsentry/publish/src/publish/inputs.js</path>
<type>file</type>
<content>
1: const github = require("@actions/github");
2: const core = require("@actions/core");
3: const { detailsFromContext } = require("../modules/details-from-context");
4: 
5: async function inputs() {
6:   const result = await detailsFromContext({
7:     context: github.context,
8:   });
9:   core.setOutput("result", JSON.stringify(result));
10: }
11: inputs();

(End of file - total 11 lines)
</content>
gateway · 2026-09-10 03:05:14
result
<path>/home/byk/Code/getsentry/publish/src/publish/resolve-release-revision.js</path>
<type>file</type>
<content>
1: const core = require("@actions/core");
2: const { getReleaseRevision } = require("../modules/release-revision");
3: 
4: function resolveReleaseRevision() {
5:   const { repo } = JSON.parse(process.env.PUBLISH_ARGS || "{}");
6:   if (!repo) {
7:     throw new Error("Publish input must define a repository.");
8:   }
9: 
10:   core.setOutput(
11:     "revision",
12:     getReleaseRevision({
13:       issueBody: process.env.PUBLISH_ISSUE_BODY || "",
14:       repo,
15:     })
16:   );
17: }
18: 
19: resolveReleaseRevision();

(End of file - total 19 lines)
</content>
gateway · 2026-09-10 03:05:19
result
<path>/home/byk/Code/getsentry/publish/src/publish/discover-location.js</path>
<type>file</type>
<content>
1: const { execFileSync } = require("child_process");
2: const { existsSync } = require("fs");
3: const path = require("path");
4: 
5: const core = require("@actions/core");
6: 
7: const { resolvePublishLocation } = require("../modules/publish-location");
8: 
9: const CRAFT_IMAGE =
10:   "getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b";
11: 
12: function getWorkspaceNames({
13:   repositoryDirectory,
14:   exists = existsSync,
15:   execFile = execFileSync,
16: }) {
17:   if (!exists(path.join(repositoryDirectory, ".craft.yml"))) {
18:     return [];
19:   }
20: 
21:   const output = execFile(
22:     "docker",
23:     [
24:       "run",
25:       "--rm",
26:       "--volume",
27:       `${path.resolve(repositoryDirectory)}:/github/workspace/__repo__`,
28:       "--workdir",
29:       "/github/workspace/__repo__",
30:       ...
gateway · 2026-09-10 03:05:27
result
<path>/home/byk/Code/getsentry/publish/src/publish/resolve-ci-poller-input.js</path>
<type>file</type>
<content>
1: const { getCiPollerInput } = require("../modules/ci-poller-input");
2: const { readFileSync } = require("fs");
3: 
4: const issueBody = process.env.PUBLISH_ISSUE_BODY_FILE
5:   ? readFileSync(process.env.PUBLISH_ISSUE_BODY_FILE, "utf8")
6:   : process.env.PUBLISH_ISSUE_BODY || "";
7: 
8: process.stdout.write(
9:   JSON.stringify(
10:     getCiPollerInput({
11:       issueBody,
12:       labels: JSON.parse(process.env.PUBLISH_ISSUE_LABELS || ""),
13:       title: process.env.PUBLISH_TITLE || "",
14:       revision: process.env.PUBLISH_REVISION || "",
15:     })
16:   )
17: );

(End of file - total 17 lines)
</content>
gateway · 2026-09-10 03:05:31
result
<path>/home/byk/Code/getsentry/publish/src/publish/update-issue.js</path>
<type>file</type>
<content>
1: const { updateIssue } = require("../modules/update-issue.js");
2: const { getGitHubToken } = require("../libs/github");
3: const github = require("@actions/github");
4: 
5: async function main() {
6:   const context = github.context;
7:   const octokit = github.getOctokit(getGitHubToken());
8:   let inputs;
9: 
10:   if (process.env.PUBLISH_ARGS) {
11:     try {
12:       inputs = JSON.parse(process.env.PUBLISH_ARGS);
13:     } catch {
14:       console.warn("Could not parse publish inputs; skipping target update");
15:     }
16:   }
17: 
18:   await updateIssue({ context, octokit, inputs });
19: }
20: 
21: if (require.main === module) {
22:   main().catch((error) => {
23:     console.error(error);
24:     process.exitCode = 1;
25:   });
26: }
27: 
28: module.exports = { main };

(End of file - total 28 lines)
</content>
gateway · 2026-09-10 03:05:36
result
<path>/home/byk/Code/getsentry/publish/src/modules/update-issue.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const {
3:   TARGETS_SECTION_PARSER_REGEX,
4:   TARGETS_PARSER_REGEX,
5: } = require("./details-from-context");
6: 
7: async function updateTargets({
8:   octokit,
9:   stateFilePath,
10:   publishRepo,
11:   issue_number,
12: }) {
13:   if (!stateFilePath || !fs.existsSync(stateFilePath)) {
14:     return;
15:   }
16: 
17:   const issueRequest = octokit.rest.issues.get({
18:     ...publishRepo,
19:     issue_number,
20:   });
21: 
22:   const craftStateRequest = fs.promises
23:     .readFile(stateFilePath, { encoding: "utf-8" })
24:     .then((data) => JSON.parse(data));
25: 
26:   const [{ data: issue }, craftState] = await Promise.all([
27:     issueRequest,
28:     craftStateRequest,
29:   ]);
30: 
31:   const newIssueBody = transformIssueBody(craftState, issue.body);
32: 
33:   await octokit.rest.issues.update({
34:     ...publishRepo,
35:     ...
gateway · 2026-09-10 03:05:42
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/publish-workflow.js</path>
<type>file</type>
<content>
1: import { spawnSync } from "child_process";
2: import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "fs";
3: import { tmpdir } from "os";
4: import { join } from "path";
5: 
6: import { afterEach, expect, test } from "vitest";
7: 
8: const { resolvePublishLocation } = require("../publish-location.js");
9: 
10: const temporaryDirectories = [];
11: 
12: function getWorkflow() {
13:   return readFileSync(
14:     join(__dirname, "../../../.github/workflows/publish.yml"),
15:     "utf8"
16:   );
17: }
18: 
19: function getSetTargetsScript() {
20:   const workflow = getWorkflow();
21:   const section = workflow.match(
22:     / {6}- name: Set targets[\s\S]*? {8}run: \|\n(?<script>[\s\S]*?)\n {6}- name: Revalidate approval attestation/
23:   );
24:   if (!section?.groups?.script) {
25:     throw new Error("Missing Set targets workflow script");
26:   }
27:   ...
gateway · 2026-09-10 03:05:50
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/publish-location.js</path>
<type>file</type>
<content>
1: import { expect, test } from "vitest";
2: 
3: const { resolvePublishLocation } = require("../publish-location.js");
4: 
5: test("classifies an exact full workspace path without normalizing it", () => {
6:   expect(
7:     resolvePublishLocation({
8:       path: "./packages/CLI",
9:       workspaceNames: ["packages/cli", "packages/CLI"],
10:     })
11:   ).toStrictEqual({ path: ".", workspace: "packages/CLI" });
12: });
13: 
14: test("keeps a non-workspace suffix as a checkout path", () => {
15:   expect(
16:     resolvePublishLocation({
17:       path: "./packages",
18:       workspaceNames: ["cli"],
19:     })
20:   ).toStrictEqual({ path: "./packages" });
21: });
22: 
23: test("keeps a multi-segment suffix that is not an exact workspace path", () => {
24:   expect(
25:     resolvePublishLocation({
26:       path: "./packages/cli",
27:       workspaceNames: ...
gateway · 2026-09-10 03:05:54
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/release-revision.js</path>
<type>file</type>
<content>
1: import { expect, test } from "vitest";
2: 
3: const {
4:   getReleaseRevision,
5:   updateReleaseRevision,
6: } = require("../release-revision.js");
7: 
8: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
9: 
10: function requestBody(quickLinks) {
11:   return `Requested by: @byk
12: 
13: Merge target: (default)
14: 
15: Quick links:
16: ${quickLinks}`;
17: }
18: 
19: function canonicalQuickLinks(revision = REVISION) {
20:   return `- [View changes](https://github.com/getsentry/toolkit/compare/1.2.2...release/1.2.3)
21: - [View check runs](https://github.com/getsentry/toolkit/commit/${revision}/checks/)`;
22: }
23: 
24: test("gets the CI-approved revision from the request header", () => {
25:   expect(
26:     getReleaseRevision({
27:       repo: "toolkit",
28:       issueBody: requestBody(canonicalQuickLinks()),
29:     })
30:   ).toBe(REVISION);
31: ...
gateway · 2026-09-10 03:05:59
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/ci-poller-input.js</path>
<type>file</type>
<content>
1: import { readFileSync } from "fs";
2: import { join } from "path";
3: 
4: import { expect, test } from "vitest";
5: 
6: const { getCiPollerInput } = require("../ci-poller-input.js");
7: const { requestDigest } = require("../approval-attestation.js");
8: 
9: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
10: const labels = [{ name: "accepted" }, { name: "dry-run" }];
11: const issueBody = `Requested by: @byk
12: 
13: Merge target: (default)
14: 
15: Quick links:
16: - [View changes](https://github.com/getsentry/toolkit/compare/1.2.2...release/1.2.3)
17: - [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)`;
18: 
19: test("parses root and full-path publish titles", () => {
20:   const rootTitle = "publish: getsentry/toolkit/cli@1.2.3";
21:   expect(
22:     getCiPollerInput({
23:       issueBody,
24:       labels,
25:       ...
gateway · 2026-09-10 03:06:10
result
<path>/home/byk/Code/getsentry/publish/src/publish/__tests__/discover-location.js</path>
<type>file</type>
<content>
1: import { afterEach, expect, test, vi } from "vitest";
2: 
3: const {
4:   discoverLocation,
5:   getWorkspaceNames,
6: } = require("../discover-location.js");
7: 
8: afterEach(() => {
9:   vi.restoreAllMocks();
10: });
11: 
12: test("retains checkout-path behavior when the root config is absent", () => {
13:   expect(
14:     discoverLocation({
15:       input: { path: "./packages/cli" },
16:       repositoryDirectory: "__repo__",
17:       exists: () => false,
18:     })
19:   ).toEqual({ path: "./packages/cli" });
20: });
21: 
22: test("discovers exact workspace paths using the released Craft image", () => {
23:   const execFile = vi.fn(() => '["packages/CLI"]');
24: 
25:   expect(
26:     discoverLocation({
27:       input: { path: "./packages/CLI" },
28:       repositoryDirectory: "__repo__",
29:       exists: () => true,
30:       execFile,
31:     })
32:   ...
gateway · 2026-09-10 03:06:16
result
<path>/home/byk/Code/getsentry/publish/.github/workflows/auto-approve.yml</path>
<type>file</type>
<content>
1: name: auto-approve non-sdks
2: on:
3:   issues:
4:     types: [opened]
5: 
6: permissions:
7:   contents: read
8:   issues: write
9: 
10: jobs:
11:   auto-approve:
12:     runs-on: ubuntu-latest
13:     environment: production
14:     if: |
15:       (github.actor == 'sentry-release-bot[bot]' || github.actor == 'getsantry[bot]') &&
16:       startsWith(github.event.issue.title, 'publish: ')
17:     steps:
18:       - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262
19:         with:
20:           persist-credentials: false
21:       - name: Get auth token
22:         id: token
23:         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
24:         with:
25:           client-id: ${{ vars.SENTRY_INTERNAL_APP_ID }}
26:           private-key: ${{ secrets.SENTRY_INTERNAL_APP_PRIVATE_KEY }}
27:       - name: Bind request snapshot
28:   ...
gateway · 2026-09-10 03:06:21
result
<path>/home/byk/Code/getsentry/publish/src/modules/approval-attestation.js</path>
<type>file</type>
<content>
1: const crypto = require("crypto");
2: 
3: const APPROVAL_ATTESTATION_PREFIX = "<!-- publish-approval ";
4: const AUTO_APPROVAL_ATTESTATION_PREFIX = "<!-- publish-auto-approval ";
5: const CI_READY_ATTESTATION_PREFIX = "<!-- publish-ci-ready ";
6: const ATTESTATION_SUFFIX = " -->";
7: 
8: function createAttestation(prefix, value) {
9:   return `${prefix}${Buffer.from(JSON.stringify(value)).toString(
10:     "base64url"
11:   )}${ATTESTATION_SUFFIX}`;
12: }
13: 
14: function requestDigest({ body, labels, title }) {
15:   if (
16:     typeof body !== "string" ||
17:     !Array.isArray(labels) ||
18:     typeof title !== "string"
19:   ) {
20:     throw new Error("Invalid publish request");
21:   }
22: 
23:   return crypto
24:     .createHash("sha256")
25:     .update(
26:       JSON.stringify({
27:         body,
28:         dryRun: labels.some((label) => label.name === ...
gateway · 2026-09-10 03:06:26
result
<path>/home/byk/Code/getsentry/publish/src/publish/validate-approval-attestation.js</path>
<type>file</type>
<content>
1: const {
2:   currentAcceptedEvent,
3:   currentCiReadyEvent,
4:   hasApprovalAttestation,
5:   hasCiReadyAttestation,
6:   requestDigest,
7: } = require("../modules/approval-attestation.js");
8: 
9: async function getGitHubResponse(path) {
10:   return fetch(`https://api.github.com/${path}`, {
11:     headers: {
12:       Accept: "application/vnd.github+json",
13:       Authorization: `Bearer ${process.env.APPROVAL_TOKEN}`,
14:       "X-GitHub-Api-Version": "2026-03-10",
15:     },
16:   });
17: }
18: 
19: async function getIssue({ repository, issueNumber }) {
20:   const response = await getGitHubResponse(
21:     `repos/${repository}/issues/${issueNumber}`
22:   );
23: 
24:   if (!response.ok) {
25:     throw new Error(
26:       `Could not retrieve issue #${issueNumber}: GitHub returned ${response.status}`
27:     );
28:   }
29: 
30:   return ...
gateway · 2026-09-10 03:06:38
result
<path>/home/byk/Code/getsentry/publish/src/publish/request-digest-from-event.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const { requestDigest } = require("../modules/approval-attestation.js");
3: 
4: function requestDigestFromEvent(event) {
5:   if (!event || typeof event.issue !== "object" || event.issue === null) {
6:     throw new Error("The GitHub event has no issue snapshot");
7:   }
8: 
9:   return requestDigest(event.issue);
10: }
11: 
12: function main() {
13:   if (!process.env.GITHUB_EVENT_PATH) {
14:     throw new Error('No "GITHUB_EVENT_PATH" environment variable found');
15:   }
16: 
17:   if (!process.env.GITHUB_OUTPUT) {
18:     throw new Error('No "GITHUB_OUTPUT" environment variable found');
19:   }
20: 
21:   const event = JSON.parse(
22:     fs.readFileSync(process.env.GITHUB_EVENT_PATH, "utf8")
23:   );
24:   fs.appendFileSync(
25:     process.env.GITHUB_OUTPUT,
26:     `request_digest=${requestDigestFromEvent(event)}\n`
27:   );
28: ...
gateway · 2026-09-10 03:06:54
result
[
    {
        "Id": "sha256:fc314146c06b14791ab860e80e73043c7c5fa06f61bce3081a34a8a227305a5a",
        "RepoTags": [
            "getsentry/craft:2.30.1"
        ],
        "RepoDigests": [
            "getsentry/craft@sha256:9a4a5d5efa44a00c2215078ead39800d4aaa5a97908b94f45a64d7d506d6e14b"
        ],
        "Comment": "buildkit.dockerfile.v0",
        "Created": "2026-08-08T00:37:30.542283842Z",
        "Config": {
            "Env": [
                "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/root/.cargo/bin:/opt/flutter/bin:/venv/bin",
                "NODE_VERSION=24.18.0",
                "YARN_VERSION=1.22.22",
                "DEBIAN_FRONTEND=noninteractive",
                "DOTNET_CLI_TELEMETRY_OPTOUT=1",
                "COCOAPODS_ALLOW_ROOT=1",
                "CARGO_HOME=/root/.cargo",
                "RUSTUP_HOME=/root/.rustup",
                "CRAFT_BUILD_SHA=cd1e8294061fd970b40d98b77aaa109cb1e00e78"
            ],
            "Entrypoint": ...
gateway · 2026-09-10 03:07:05
result
/usr/local/bin/craft
gateway · 2026-09-10 03:07:16
result
/usr/local/bin/craft: Node.js script executable, ASCII text, with very long lines (438)
gateway · 2026-09-10 03:07:27
result
#!/usr/bin/env node
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __esm = (fn, res, err) => function __init() {
  if (err) throw err[0];
  try {
    return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
  } catch (e4) {
    throw err = [e4], e4;
  }
};
var __commonJS = (cb, mod) => function __require() {
  try {
    return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
  } catch (e4) {
    throw mod = 0, e4;
  }
};
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to2, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of ...
gateway · 2026-09-10 03:07:41
result
PATTERN /publish-state-/
241195: function shortCwdHash(cwd) {
241196:   return (0, import_crypto6.createHash)("sha1").update(cwd).digest("hex").slice(0, 12);
241197: }
241198: function getPublishStateFilename(version2, githubConfig, cwd = process.cwd()) {
241199:   const safeVersion = sanitiseForFilename(version2);
241200:   if (githubConfig) {
241201:     const owner = sanitiseForFilename(githubConfig.owner);
241202:     const repo = sanitiseForFilename(githubConfig.repo);
241203:     return `publish-state-${owner}-${repo}-${shortCwdHash(cwd)}-${safeVersion}.json`;
241204:   }
241205:   const cwdDigest = (0, import_crypto6.createHash)("sha256").update(cwd).digest("hex").slice(0, 16);
241206:   return `publish-state-${cwdDigest}-${safeVersion}.json`;
241207: }
241208: function getPublishStatePath(version2, githubConfig, cwd = process.cwd()) {
241209:   return (0, import_path29.join)(
241210:     getCraftStateDir(),
241211:     getPublishStateFilename(version2, githubConfig, ...
gateway · 2026-09-10 03:07:55
result
241196:   return (0, import_crypto6.createHash)("sha1").update(cwd).digest("hex").slice(0, 12);
241197: }
241198: function getPublishStateFilename(version2, githubConfig, cwd = process.cwd()) {
241199:   const safeVersion = sanitiseForFilename(version2);
241200:   if (githubConfig) {
241201:     const owner = sanitiseForFilename(githubConfig.owner);
241202:     const repo = sanitiseForFilename(githubConfig.repo);
241203:     return `publish-state-${owner}-${repo}-${shortCwdHash(cwd)}-${safeVersion}.json`;
241204:   }
241205:   const cwdDigest = (0, import_crypto6.createHash)("sha256").update(cwd).digest("hex").slice(0, 16);
241206:   return `publish-state-${cwdDigest}-${safeVersion}.json`;
241207: }
241208: function getPublishStatePath(version2, githubConfig, cwd = process.cwd()) {
241209:   return (0, import_path29.join)(
241210:     getCraftStateDir(),
241211:     getPublishStateFilename(version2, githubConfig, cwd)
241212:   );
241213: }
241214: 
241215: // ...
gateway · 2026-09-10 03:08:14
result
...output truncated...

Full output saved to: /home/byk/.local/share/opencode/tool-output/tool_08949908a001Oeg86d0g4h6DfX

120698:       async getReleaseByTag(tag2) {
120699:         try {
120700:           const { data: data2 } = await this.github.repos.getReleaseByTag({
120701:             owner: this.githubConfig.owner,
120702:             repo: this.githubConfig.repo,
120703:             tag: tag2
120704:           });
120705:           return data2;
120706:         } catch (error3) {
120707:           if (error3.status === 404) {
120708:             return void 0;
120709:           }
120710:           throw error3;
120711:         }
120712:       }
120713:       /**
120714:        * Fetches a list of all assets for the given release
120715:        *
120716:        * The result includes unfinished asset uploads. ...
gateway · 2026-09-10 03:08:26
result
NEEDLE async function getGlobalGitHubConfig INDEX 232496
232476: function requiresMinVersion(requiredVersion) {
232477:   const config3 = getConfiguration();
232478:   const minVersionRaw = config3.minVersion;
232479:   if (!minVersionRaw) {
232480:     return false;
232481:   }
232482:   const configuredMinVersion = parseVersion(minVersionRaw);
232483:   const required = parseVersion(requiredVersion);
232484:   if (!configuredMinVersion || !required) {
232485:     return false;
232486:   }
232487:   return versionGreaterOrEqualThan(configuredMinVersion, required);
232488: }
232489: function getVersioningPolicy() {
232490:   const config3 = getConfiguration();
232491:   if (config3.versioning?.policy) {
232492:     return config3.versioning.policy;
232493:   }
232494:   return requiresMinVersion(AUTO_VERSION_MIN_VERSION) ? "auto" /* Auto */ : "manual" /* Manual */;
232495: }
232496: async function getGlobalGitHubConfig(clearCache = false) {
232497:   if (!clearCache && ...
gateway · 2026-09-10 03:10:30
result
<path>/home/byk/Code/getsentry/publish/src/modules/publish-issue-title.peggy</path>
<type>file</type>
<content>
1: {
2:   function join(characters) {
3:     return characters.join("");
4:   }
5: }
6: 
7: // BEGIN TITLE GRAMMAR
8: // Canonical grammar for publish issue titles. A path suffix is syntactic only:
9: // the controller resolves the complete suffix as a workspace after checking
10: // out the CI-approved revision.
11: PublishIssueTitle
12:   = "publish: " "getsentry/"? repo:Repository path:Path? "@" version:Version !. {
13:       return {
14:         repo,
15:         path: path || "",
16:         version,
17:       };
18:     }
19: 
20: Repository
21:   = characters:RepositoryCharacter+ { return join(characters); }
22: 
23: RepositoryCharacter
24:   = [A-Za-z0-9_.-]
25: 
26: Path
27:   = segments:("/" segment:PathSegment { return `/${segment}`; })+ { return join(segments); }
28: 
29: PathSegment
30:   = characters:RepositoryCharacter+ { return join(characters); }
31: 
32: ...
gateway · 2026-09-10 03:10:50
result
NEEDLE CRAFT_MERGE_TARGET
NEEDLE CRAFT_WORKSPACE
NEEDLE CRAFT_DRY_RUN
242617:   "no-input": {
242618:     coerce: envToBool2,
242619:     default: import_is_ci2.default,
242620:     describe: "Suppresses all user prompts",
242621:     global: true
242622:   },
242623:   "dry-run": {
242624:     coerce: envToBool2,
242625:     // TODO(byk): Deprecate this in favor of CRAFT_DRY_RUN
242626:     default: process.env.DRY_RUN,
242627:     global: true,
242628:     describe: "Dry run mode: no file writes, commits, pushes, or API mutations"
242629:   }
242630: };
242631: function fixGlobalBooleanFlags(argv) {
242632:   const result = [];
242633:   for (const arg of argv) {
242634:     result.push(arg);
242635:     if (arg.slice(2) in GLOBAL_BOOLEAN_FLAGS) {
242636:       result.push("1");
242637:     }
242638:   }
242639:   return result;
gateway · 2026-09-10 03:11:07
result
NEEDLE .env("CRAFT
HITS 1
242643:   printVersion();
242644:   warnIfCraftEnvFileExists();
242645:   const argv = fixGlobalBooleanFlags(process.argv.slice(2));
242646:   await yargs_default().parserConfiguration({
242647:     "boolean-negation": false
242648:   }).env("CRAFT").command(prepare_exports).command(publish_exports).command(targets_exports2).command(config_exports).command(artifacts_exports).command(changelog_exports).demandCommand().version(getPackageVersion()).alias("v", "version").help().alias("h", "help").options(GLOBAL_BOOLEAN_FLAGS).option("log-level", {
242649:     default: "Info",
242650:     choices: Object.keys(import_consola.LogLevel).filter((level) => isNaN(Number(level))),
242651:     coerce: (level) => level[0].toUpperCase() + level.slice(1).toLowerCase(),
242652:     describe: "Logging level",
242653:     global: true
242654:   }).strictCommands().showHelpOnFail(true).middleware(setGlobals).parse(argv);
242655: }
242656: withTracing(main, { name: "craft.cli", ...
gateway · 2026-09-10 03:11:21
result
.option("workspace": 0
argv.workspace: 0
process.env.CRAFT_PUBLISH_STATE_GITHUB_REPO: 0
gateway · 2026-09-10 03:11:39
result
TERM workspace list: 0
TERM CRAFT_WORKSPACE: 0
TERM selected workspace: 0
TERM Unknown workspace: 0
TERM workspace config: 0
TERM Workspace name: 0
gateway · 2026-09-10 03:11:51
result
hits 131
232641:   return {
232642:     noMerge: false,
232643:     source: "default"
232644:   };
232645: }
232646: function isExpandableTarget(targetClass) {
232647:   return typeof targetClass === "function" && "expand" in targetClass && typeof targetClass.expand === "function";
232648: }
232649: async function expandWorkspaceTargets(targets) {
232650:   const { getTargetByName: getTargetByName2 } = (init_targets(), __toCommonJS(targets_exports));
232651:   const rootDir = getConfigFileDir() || process.cwd();
232652:   const expandedTargets = [];
232653:   for (const target of targets) {
232654:     const targetClass = getTargetByName2(target.name);
232655:     if (targetClass && isExpandableTarget(targetClass)) {
232656:       const expanded = await targetClass.expand(target, rootDir);
232657:       expandedTargets.push(...expanded);
232658:     } else {
232659:       expandedTargets.push(target);
232660:     }
232661:   }
232662:   return expandedTargets;
232663: }
232664: var ...
gateway · 2026-09-10 03:12:00
result
craft <command>

Commands:
  craft prepare [NEW-VERSION]  🚢 Prepare a new release branch
                          [aliases: p, prerelease, prepublish, prepare, release]
  craft publish NEW-VERSION    🛫 Publish artifacts       [aliases: pp, publish]
  craft targets                List defined targets as JSON array
  craft config                 Print the parsed, processed, and validated Craft
                               config for the current project in pretty-JSON.
  craft artifacts <command>    📦 Manage artifacts        [aliases: a, artifact]
  craft changelog              Generate changelog from git history

Options:
      --no-input   Suppresses all user prompts                  [default: false]
      --dry-run    Dry run mode: no file writes, commits, pushes, or API
                   mutations
      --log-level  Logging level
          [choices: "Fatal", "Error", "Warn", "Log", "Info", "Success", "Debug",
                                 "Trace", "Silent", "Verbose"] ...
gateway · 2026-09-10 03:12:13
result
craft <command>

Commands:
  craft prepare [NEW-VERSION]  🚢 Prepare a new release branch
                          [aliases: p, prerelease, prepublish, prepare, release]
  craft publish NEW-VERSION    🛫 Publish artifacts       [aliases: pp, publish]
  craft targets                List defined targets as JSON array
  craft config                 Print the parsed, processed, and validated Craft
                               config for the current project in pretty-JSON.
  craft artifacts <command>    📦 Manage artifacts        [aliases: a, artifact]
  craft changelog              Generate changelog from git history

Options:
      --no-input   Suppresses all user prompts                  [default: false]
      --dry-run    Dry run mode: no file writes, commits, pushes, or API
                   mutations
      --log-level  Logging level
          [choices: "Fatal", "Error", "Warn", "Log", "Info", "Success", "Debug",
                                 "Trace", "Silent", "Verbose"] ...
gateway · 2026-09-10 03:12:34
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/details-from-context.js</path>
<type>file</type>
<content>
1: import { test, expect } from "vitest";
2: 
3: const {
4:   detailsFromContext,
5:   parsePublishTitle,
6: } = require("../details-from-context.js");
7: 
8: const inputsArgs = {
9:   context: {
10:     repo: { owner: "getsentry", repo: "publish" },
11:     payload: {
12:       issue: {
13:         number: "223",
14:         title: "publish: getsentry/sentry@21.3.1",
15:         body: `Requested by: @BYK
16: 
17: Merge target: custom-branch
18: 
19: Quick links:
20: - [View changes](https://github.com/getsentry/sentry/compare/21.3.0...refs/heads/releases/21.3.1)
21: - [View check runs](https://github.com/getsentry/sentry/commit/7e5ca7ed5581552de066e2a8bc295b8306be38ac/checks/)
22: 
23: Assign the **accepted** label to this issue to approve the release. ...
gateway · 2026-09-10 03:12:54
result
<path>/home/byk/Code/getsentry/publish/src/publish/__tests__/publish-workflow.js</path>
<type>file</type>
<content>
1: import { readFileSync } from "fs";
2: import { describe, expect, test } from "vitest";
3: 
4: const workflow = readFileSync(".github/workflows/publish.yml", "utf8");
5: 
6: describe("publish workflow", () => {
7:   test("binds approval and publication to the triggering issue snapshot", () => {
8:     expect(workflow).toContain("node src/publish/request-digest-from-event.js");
9:     expect(
10:       workflow.match(
11:         /EXPECTED_REQUEST_DIGEST: \$\{\{ steps\.request-digest\.outputs\.request_digest \}\}/g
12:       )
13:     ).toHaveLength(4);
14:   });
15: 
16:   test("revalidates approval immediately before Craft", () => {
17:     const fence = workflow.indexOf("Revalidate approval attestation");
18: 
19:     expect(fence).toBeGreaterThan(workflow.indexOf("Set targets"));
20:     expect(fence).toBeLessThan(workflow.indexOf("Publish using Craft"));
21:     ...
gateway · 2026-09-10 03:12:59
result
<path>/home/byk/Code/getsentry/publish/src/modules/__tests__/ci-poller-workflow.js</path>
<type>file</type>
<content>
1: import {
2:   mkdtempSync,
3:   mkdirSync,
4:   readFileSync,
5:   readdirSync,
6:   rmSync,
7:   writeFileSync,
8: } from "fs";
9: import { tmpdir } from "os";
10: import { join } from "path";
11: import { spawnSync } from "child_process";
12: 
13: import { afterEach, expect, test } from "vitest";
14: 
15: const temporaryDirectories = [];
16: const INITIAL_REVISION = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
17: const UPDATED_REVISION = "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb";
18: 
19: function getPollerScript() {
20:   const workflow = readFileSync(
21:     join(__dirname, "../../../.github/workflows/ci-poller.yml"),
22:     "utf8"
23:   );
24:   const section = workflow.match(
25:     / {6}- name: Check CI status for ci-pending issues[\s\S]*? {8}run: \|\n(?<script>[\s\S]*?)\n {6}- name: Check for remaining pending issues/
26:   );
27: 
28:   if ...
gateway · 2026-09-10 03:14:23
result
<path>/home/byk/Code/getsentry/publish/auto-approve-repos.txt</path>
<type>file</type>
<content>
1: getsentry/arroyo
2: getsentry/auto-type-annotate
3: getsentry/devenv
4: getsentry/infra-event-notifier
5: getsentry/jest-sentry-environment
6: getsentry/json-schema-diff
7: getsentry/js-source-scopes
8: getsentry/objectstore/clients
9: getsentry/ophio
10: getsentry/pdb
11: getsentry/pyo3-python-tracing-subscriber
12: getsentry/pytest-sentry
13: getsentry/relay/py
14: getsentry/responses
15: getsentry/rust-proguard
16: getsentry/rust-sourcemap
17: getsentry/rust-usage-accountant
18: getsentry/script-runner
19: getsentry/sentry-api-schema
20: getsentry/sentry-forked-djangorestframework-stubs
21: getsentry/sentry-forked-django-stubs
22: getsentry/sentry-forked-jsonnet
23: getsentry/sentry-infra-tools
24: getsentry/sentry-kafka-management
25: getsentry/sentry-kafka-schemas
26: getsentry/sentry-protos
27: getsentry/sentry-redis-tools
28: getsentry/service-registry
29: getsentry/skrooge
30: ...
gateway · 2026-09-10 03:14:29
result
<path>/home/byk/Code/getsentry/publish/src/publish/record-auto-approval-attestation.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const {
3:   createAutoApprovalAttestation,
4:   requestDigest,
5: } = require("../modules/approval-attestation.js");
6: const { getIssue } = require("./validate-approval-attestation.js");
7: 
8: async function recordAutoApprovalAttestation({
9:   autoApprover,
10:   expectedRequestDigest,
11:   getIssue,
12:   issueNumber,
13:   issueTitle,
14:   repository,
15: }) {
16:   const issue = await getIssue({ repository, issueNumber });
17: 
18:   if (
19:     issue.state !== "open" ||
20:     issue.title !== issueTitle ||
21:     requestDigest(issue) !== expectedRequestDigest ||
22:     issue.user?.login?.toLowerCase() !== autoApprover.toLowerCase()
23:   ) {
24:     throw new Error("The automated approval request changed before approval");
25:   }
26: 
27:   return createAutoApprovalAttestation({ autoApprover, issue });
28: }
29: 
30: ...
gateway · 2026-09-10 03:14:37
result
<path>/home/byk/Code/getsentry/publish/src/modules/approval-authorizer.js</path>
<type>file</type>
<content>
1: const ALLOWED_ROLE_NAMES = new Set(["write", "maintain", "admin"]);
2: const { parsePublishTitle } = require("./details-from-context.js");
3: 
4: const AUTO_APPROVAL_LABELER = "sentry-internal-app[bot]";
5: const AUTO_APPROVERS = new Set(["getsantry[bot]", "sentry-release-bot[bot]"]);
6: 
7: function isAutoApprovedRepository({
8:   actor,
9:   autoApprovedRepositories,
10:   issueTitle,
11: }) {
12:   if (!AUTO_APPROVERS.has(actor)) {
13:     return false;
14:   }
15: 
16:   const title = parsePublishTitle(issueTitle);
17: 
18:   if (!title) {
19:     return false;
20:   }
21: 
22:   return autoApprovedRepositories.has(
23:     `getsentry/${title.repo}${title.path || ""}`
24:   );
25: }
26: 
27: async function authorizeApproval({ actor, issueTitle, getPermission }) {
28:   const title = parsePublishTitle(issueTitle);
29: 
30:   if (!title) {
31:     return { authorized: ...
gateway · 2026-09-10 03:14:42
result
<path>/home/byk/Code/getsentry/publish/src/publish/authorize-approval.js</path>
<type>file</type>
<content>
1: const fs = require("fs");
2: const {
3:   createApprovalAttestation,
4:   currentAcceptedEvent,
5:   hasAutoApprovalAttestation,
6:   requestDigest,
7: } = require("../modules/approval-attestation.js");
8: const {
9:   AUTO_APPROVAL_LABELER,
10:   AUTO_APPROVERS,
11:   authorizeApproval,
12:   isAutoApprovedRepository,
13: } = require("../modules/approval-authorizer.js");
14: 
15: function getAutoApprovedRepositories() {
16:   return new Set(
17:     fs
18:       .readFileSync("auto-approve-repos.txt", "utf8")
19:       .split(/\r?\n/)
20:       .filter(Boolean)
21:   );
22: }
23: 
24: async function getPermission({ owner, repository, username }) {
25:   const response = await getGitHubResponse(
26:     `repos/${encodeURIComponent(owner)}/${encodeURIComponent(
27:       repository
28:     )}/collaborators/${encodeURIComponent(username)}/permission`
29:   );
30: 
31:   if ...
gateway · 2026-09-10 03:14:53
result
<path>/home/byk/Code/getsentry/publish/src/modules/post-workflow-details.js</path>
<type>file</type>
<content>
1: async function postWorkflowDetails({ context, octokit }) {
2:   const { repo: publishRepo, runId: run_id } = context;
3:   const { number: issue_number } = context.payload.issue;
4: 
5:   const workflowInfo = (
6:     await octokit.rest.actions.getWorkflowRun({
7:       ...publishRepo,
8:       run_id,
9:     })
10:   ).data;
11: 
12:   return octokit.rest.issues.createComment({
13:     ...publishRepo,
14:     issue_number,
15:     body: `Publishing: [run#${run_id}](${workflowInfo.html_url})`,
16:   });
17: }
18: 
19: module.exports = postWorkflowDetails;

(End of file - total 19 lines)
</content>
gateway · 2026-09-10 03:14:58
result
<path>/home/byk/Code/getsentry/publish/src/modules/process-end-state.js</path>
<type>file</type>
<content>
1: const Sentry = require("@sentry/node");
2: 
3: async function processEndState({ context, octokit, inputs, status }) {
4:   const { repo, version } = inputs;
5:   const { repo: publishRepo, runId: run_id } = context;
6:   const { number: issue_number } = context.payload.issue;
7:   const workflowInfo = (
8:     await octokit.rest.actions.getWorkflowRun({
9:       ...publishRepo,
10:       run_id,
11:     })
12:   ).data;
13: 
14:   const details = {
15:     repo,
16:     version,
17:     publishRepo,
18:     run_id,
19:     issue_number,
20:     workflowInfo,
21:     status,
22:   };
23: 
24:   await postIssueComment({
25:     octokit,
26:     details,
27:   });
28: 
29:   if (status === "success") {
30:     await octokit.rest.issues.update({
31:       ...publishRepo,
32:       issue_number,
33:       state: "closed",
34:     });
35:   }
36: 
37:   await reportSession({ ...
gateway · 2026-09-10 03:15:04
result
<path>/home/byk/Code/getsentry/publish/src/publish/post-workflow-details.js</path>
<type>file</type>
<content>
1: const postWorkflowDetails = require("../modules/post-workflow-details.js");
2: const { getGitHubToken } = require("../libs/github");
3: const github = require("@actions/github");
4: 
5: const context = github.context;
6: const octokit = github.getOctokit(getGitHubToken());
7: 
8: postWorkflowDetails({ context, octokit });

(End of file - total 8 lines)
</content>
gateway · 2026-09-10 03:15:08
result
<path>/home/byk/Code/getsentry/publish/src/publish/post-result.js</path>
<type>file</type>
<content>
1: const processEndState = require("../modules/process-end-state");
2: const { getGitHubToken } = require("../libs/github");
3: const github = require("@actions/github");
4: 
5: const context = github.context;
6: const octokit = github.getOctokit(getGitHubToken());
7: const inputs = JSON.parse(process.env.PUBLISH_ARGS);
8: const args = process.argv.slice(2);
9: const status = args[0];
10: 
11: processEndState({ context, octokit, inputs, status });

(End of file - total 11 lines)
</content>
gateway · 2026-09-10 03:15:14
result
<path>/home/byk/Code/getsentry/publish/src/libs/github.js</path>
<type>file</type>
<content>
1: /**
2:  * This is a helper function that throws a useful error message if the
3:  * workflow environment is not configured correctly.
4:  *
5:  * @returns string
6:  */
7: function getGitHubToken() {
8:   if (!process.env.GITHUB_TOKEN) {
9:     throw new Error(
10:       'No "GITHUB_TOKEN" environment variable found. ' +
11:         "Please ensure the workflow is configured correctly"
12:     );
13:   }
14:   return process.env.GITHUB_TOKEN;
15: }
16: 
17: module.exports = {
18:   getGitHubToken,
19: };

(End of file - total 19 lines)
</content>
gateway · 2026-09-10 03:15:51
result
<path>/home/byk/Code/getsentry/publish/src/publish/__tests__/resolve-release-revision.js</path>
<type>file</type>
<content>
1: import { spawnSync } from "child_process";
2: import { expect, test } from "vitest";
3: 
4: const script = new URL("../resolve-release-revision.js", import.meta.url)
5:   .pathname;
6: 
7: test("rejects missing workflow input through release revision validation", () => {
8:   const result = spawnSync(process.execPath, [script], {
9:     encoding: "utf8",
10:     env: {
11:       ...process.env,
12:       PUBLISH_ARGS: "",
13:       PUBLISH_ISSUE_BODY: "",
14:     },
15:   });
16: 
17:   expect(result.status).not.toBe(0);
18:   expect(result.stderr).toContain("Publish input must define a repository.");
19:   expect(result.stderr).not.toContain("Unexpected end of JSON input");
20: });

(End of file - total 20 lines)
</content>
gateway · 2026-09-10 03:16:02
result
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2635ea6..69210d1 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -32,13 +32,90 @@ jobs:
       && github.event.issue.state == 'open'
       && startsWith(github.event.issue.title, 'publish: ')
     steps:
+      - name: Get publish code
+        uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803
+        with:
+          persist-credentials: false
+
       - name: Get auth token
         id: token
-        uses: actions/create-github-app-token@v3
+        uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1
         with:
           client-id: ${{ vars.SENTRY_INTERNAL_APP_ID }}
           private-key: ${{ secrets.SENTRY_INTERNAL_APP_PRIVATE_KEY }}
 
+      - name: Bind request snapshot
+        id: request-digest
+        run: node src/publish/request-digest-from-event.js
+
+      # The release bot sees all target repositories. ...
gateway · 2026-09-10 03:16:18
result
<path>/home/byk/Code/getsentry/publish/src/publish/resolve-location.js</path>
<type>file</type>
<content>
1: const core = require("@actions/core");
2: const { resolvePublishLocation } = require("../modules/publish-location");
3: 
4: function resolveLocation() {
5:   const input = JSON.parse(process.env.PUBLISH_ARGS || "{}");
6:   const workspaceNames = JSON.parse(process.env.CRAFT_WORKSPACE_NAMES || "[]");
7: 
8:   if (!Array.isArray(workspaceNames)) {
9:     throw new Error(
10:       "Craft workspace discovery returned an invalid workspace list."
11:     );
12:   }
13: 
14:   core.setOutput(
15:     "result",
16:     JSON.stringify(
17:       resolvePublishLocation({
18:         path: input.path,
19:         workspaceNames,
20:       })
21:     )
22:   );
23: }
24: 
25: resolveLocation();

(End of file - total 25 lines)
</content>
gateway · 2026-09-10 03:16:53
result
rg: regex parse error:
    (?:uses:\s+[^\s]+@(?![0-9a-f]{40}(?:\s|$)|sha256:[0-9a-f]{64}(?:\s|$)))
                      ^^^
error: look-around, including look-ahead and look-behind, is not supported

Consider enabling PCRE2 with the --pcre2 flag, which can handle backreferences
and look-around.
gateway · 2026-09-10 03:17:02
result
Found 18 matches
/home/byk/Code/getsentry/publish/.github/workflows/test.yml:
  Line 19:       - uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803

  Line 20:       - uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38

  Line 23:       - uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830


/home/byk/Code/getsentry/publish/.github/workflows/publish.yml:
  Line 36:         uses: actions/checkout@d23441a48e516b6c34aea4fa41551a30e30af803

  Line 42:         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

  Line 56:         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

  Line 155:         uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1

  Line 198:         uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1

  Line 234:         uses: actions/setup-node@249970729cb0ef3589644e2896645e5dc5ba9c38

  Line 262:         uses: ...
gateway · 2026-09-10 03:17:24
result
241216: var DEFAULT_POST_RELEASE_SCRIPT_PATH = (0, import_path30.join)("scripts", "post-release.sh");
241217: var command2 = ["publish NEW-VERSION"];
241218: var aliases = ["pp", "publish"];
241219: var description = "\u{1F6EB} Publish artifacts";
241220: var builder = (yargs) => {
241221:   const definedTargets = getConfiguration().targets || [];
241222:   const possibleTargetNames = new Set(getAllTargetNames());
241223:   const allowedTargetNames = definedTargets.filter((target) => target.name && possibleTargetNames.has(target.name)).map(BaseTarget.getId);
241224:   return yargs.positional("NEW-VERSION", {
241225:     description: "Version to publish",
241226:     type: "string"
241227:   }).option("target", {
241228:     alias: "t",
241229:     choices: allowedTargetNames.concat([
241230:       "all" /* All */,
241231:       "none" /* None */
241232:     ]),
241233:     default: "all" /* All */,
241234:     description: "Publish to this target",
241235:     type: "string"
241236:   ...
gateway · 2026-09-10 03:18:02
result
process.env.GITHUB_TOKEN: 3
74598: });
74599: 
74600: // src/utils/githubApi.ts
74601: function getGitHubApiToken() {
74602:   const githubApiToken = process.env.GITHUB_TOKEN || process.env.GITHUB_API_TOKEN;
74603:   if (!githubApiToken) {
74604:     throw new ConfigurationError(
74605:       "GITHUB_TOKEN not found. This is required to fetch PR information from GitHub.\nTip: Run `gh auth token` if you have GitHub CLI installed."
74606:     );
74607:   }
74608:   return githubApiToken;
74609: }
74610: function getGitHubClient(token = "") {
74611:   const githubApiToken = token || getGitHubApiToken();
117422:           }
117423:           if (!username || !password) {
117424:             if (registry === "ghcr.io") {
117425:               username = username || process.env.GITHUB_ACTOR || "x-access-token";
117426:               password = password || process.env.GITHUB_TOKEN || process.env.GITHUB_API_TOKEN;
117427:             }
117428:           }
117429:           if ...
gateway · 2026-09-10 03:18:23
result
function getGitClient: 1
57062: function stripRemoteName(branch, remoteName) {
57063:   const branchName = branch || "";
57064:   const remotePrefix = `${remoteName}/`;
57065:   if (branchName.startsWith(remotePrefix)) {
57066:     return branchName.slice(remotePrefix.length);
57067:   }
57068:   return branchName;
57069: }
57070: async function getGitClient() {
57071:   const configFileDir = getConfigFileDir() || ".";
57072:   process.chdir(configFileDir);
57073:   logger.debug("Working directory:", process.cwd());
57074:   const git = esm_default2(configFileDir);
57075:   const isRepo = await git.checkIsRepo();
57076:   if (!isRepo) {
57077:     throw new ConfigurationError("Not in a git repository!");
57078:   }
57079:   return createDryRunGit(git);
57080: }
57081: function createGitClient(directory) {
57082:   return createDryRunGit(esm_default2(directory));
57083: }
57084: async function cloneRepo(url2, targetDirectory, options) {
async function getGitClient: 1
57062: function ...
gateway · 2026-09-10 03:19:10

Distillations (8)

Gen 0 2026-09-10 05:52:45 · 674 tokens

Date: Sep 10, 2026 * 🔴 (03:19) User’s compiled-bundle search found exactly 1 `function getGitClient`, 1 `async function getGitClient`, and 4 occurrences of `getGitClient()`. * 🔴 (03:19) `getGitClient()` at lines 57070–57079 uses `getConfigFileDir() || "."`, calls `process.chdir(configFileDir)`, logs `"Working directory:"` with `process.cwd()`, creates the client via `esm_default2(configFileDir)…

Gen 0 2026-09-10 05:52:16 · 882 tokens

Date: Sep 10, 2026 * 🔴 (03:18) User provided a compiled JavaScript excerpt defining `DEFAULT_POST_RELEASE_SCRIPT_PATH = join("scripts", "post-release.sh")`, publish command `["publish NEW-VERSION"]`, aliases `["pp", "publish"]`, and description `"🛫 Publish artifacts"`. * 🔴 (03:18) The compiled publish command builder derives `allowedTargetNames` by filtering configured targets against `new Set…

Gen 0 2026-09-10 05:46:32 · 3980 tokens

2026-09-10 - 🔴 (03:14) User provided `/home/byk/Code/getsentry/publish/src/modules/__tests__/ci-poller-workflow.js`, a 228-line Vitest integration-style test file that extracts the shell script between `"Check CI status for ci-pending issues"` and `"Check for remaining pending issues"` from `.github/workflows/ci-poller.yml`. - 🔴 (03:14) `/home/byk/Code/getsentry/publish/src/modules/__tests__/ci…

Gen 0 2026-09-10 05:39:17 · 2839 tokens

2026-09-10 - 🔴 (03:10) User provided bundled Craft code at lines 232476-232525: `requiresMinVersion(requiredVersion)` parses configured and required versions and returns `versionGreaterOrEqualThan(configuredMinVersion, required)`; `getVersioningPolicy()` uses configured `versioning.policy`, otherwise selects `"auto"` when `requiresMinVersion(AUTO_VERSION_MIN_VERSION)` is true and `"manual"` othe…

Gen 0 2026-09-10 05:35:11 · 240 tokens

2026-09-10 - 🔴 (03:08) User provided the full truncated tool-output path `/home/byk/.local/share/opencode/tool-output/tool_08949908a001Oeg86d0g4h6DfX`. - 🔴 (03:08) User stated that Craft resolves a floating tag pattern by replacing placeholders with version components. - 🟡 (03:08) Bundled Craft code at lines 120698-120711 defines `getReleaseByTag(tag2)`, which calls `this.github.repos.getRelea…

Gen 0 2026-09-10 05:29:40 · 4313 tokens

2026-09-10 - 🔴 (03:05) User provided the file path `/home/byk/Code/getsentry/publish/src/modules/__tests__/publish-workflow.js`. - 🟡 (03:05) Inspected `/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 wit…

Gen 0 2026-09-10 05:27:14 · 2083 tokens

2026-09-10 - 🔴 (03:04) [enforced-workflow] User required `workflow_dispatch` to check out and run trusted code from `${{ github.event.repository.default_branch }}`, rather than code from an arbitrary dispatch ref; workflow comment at line 51 states: “workflow_dispatch can target any ref. Always run trusted code.” - 🔴 (03:04) [enforced-workflow] User required that a release never be moved to `ci…

Gen 0 2026-09-10 05:19:56 · 1754 tokens

2026-09-10 - 🔴 (03:03) User stated the previous review returned an empty result and that an empty result is invalid. - 🟡 (03:03) User requested resumption of a read-only adversarial audit of the exact unchanged tree at `/home/byk/Code/getsentry/publish`; scope is release input, revision, target checkout, publish location, Craft invocation, and state-file identity. - 🔴 (03:03) [enforced-workflo…