DashboardcraftSession 186KrRvT2nRj

Session 186KrRvT2nRj

Full ID: 186KrRvT2nRj0tpq2
Messages: 35
Distillations: 1
Time range: 2026-09-04 21:57:08 — 2026-09-04 22:07:59

Conversation (35 messages)

Perform a strict final READ-ONLY adversarial audit of the CURRENT uncommitted diffs and relevant code in BOTH worktrees. Do not edit, format, generate, run mutating commands, or change git state.

  • /home/byk/Code/getsentry/craft-workspace-action-propagation
  • /home/byk/Code/getsentry/publish-workspace-acceptance

IMPORTANT: getsentry/craft:latest in Publish is intentional and REQUIRED: latest released Craft provides workspace behavior, while checked-out CI revision and craft publish --rev bind target repository operations. Do NOT treat it as a concern.

The prior audit’s only applicable blocker was malformed brace patterns (packages/{cli, packages/{cli}) accepted because an empty expansion passed .every(). This fix now rejects empty expansions in schema and runtime and has fail-first regression coverage. Verify it is truly closed in both src/schemas/project_config.ts and src/config.ts, covers unclosed, no-alternative, nested and empty alternatives safely, and cannot fail open due to empty arrays.

Also independently verify all release-workspace contracts with exact line citations:

  1. CI poller validates repository, Craft-compatible version, and title path pre-API; path root allowed, unsafe segments reject.
  2. Craft and Publish state filename version encoding is lossless and identical; safe legacy values preserved, case/punctuation collisions impossible.
  3. Workspace glob safety: safe braces/character classes/negated classes/globstar work, unsafe alternatives fail pre-glob, literal safety, overlap rejection, POSIX spelling, physical symlink containment, remote config root.
  4. Action pre-side-effect path/workspace validation, ambient workspace cleared, full exact concrete title paths.
  5. Exact CI SHA checkout precedes discovery; exact workspace match/missing-root path fallback; discovery validation; fresh ci-ready gate; external scoped state and --rev.
  6. Canonical path-only parser/generated/docs parity, regression coverage, intended diff hygiene. ...
gateway · 2026-09-04 21:57:08
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation</path>
<type>directory</type>
<entries>
.craft.yml
.dockerignore
.eslintcache
.git
.github/
.gitignore
.lore.md
.nojekyll
.npmignore
.prettierignore
.prettierrc.yml
.tsbuildinfo
.vscode/
action.yml
AGENTS.md
blog-post-draft.md
build.mjs
CHANGELOG.md
CONTRIBUTING.md
dist/
Dockerfile
docs/
eslint.config.mjs
img/
LICENSE
node_modules/
package.json
pnpm-lock.yaml
README.md
src/
tsconfig.build.json
tsconfig.json
vitest.config.mts

(33 entries)
</entries>
gateway · 2026-09-04 21:58:43
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance</path>
<type>directory</type>
<entries>
.eslintrc.js
.git
.github/
.gitignore
AGENTS.md
auto-approve-repos.txt
docs/
LICENSE
node_modules/
package.json
README.md
scripts/
src/
vitest.config.js
yarn.lock

(15 entries)
</entries>
gateway · 2026-09-04 22:00:20
result
 M action.yml
 M docs/src/content/docs/targets/github.md
 M src/__tests__/action.test.ts
 M src/__tests__/config.test.ts
 M src/commands/prepare.ts
 M src/config.ts
 M src/schemas/project_config.ts
 M src/utils/__tests__/publishState.test.ts
 M src/utils/publishState.ts
 action.yml                               |  11 +-
 docs/src/content/docs/targets/github.md  |  20 ++-
 src/__tests__/action.test.ts             | 101 +++++++++---
 src/__tests__/config.test.ts             | 185 +++++++++++++++++++++-
 src/commands/prepare.ts                  |   3 +-
 src/config.ts                            | 260 +++++++++++++++++++++++++++++--
 src/schemas/project_config.ts            |  94 +++++++++++
 src/utils/__tests__/publishState.test.ts |  15 ++
 src/utils/publishState.ts                |   9 +-
 9 files changed, 654 insertions(+), 44 deletions(-)
diff --git a/action.yml b/action.yml
index 94f3158..d160509 100644
--- a/action.yml
+++ b/action.yml
@@ -74,6 +74,7 @@ runs:
     - name: Validate ...
gateway · 2026-09-04 22:00:28
result
 M .github/workflows/publish.yml
 M docs/publish-issue-format.md
 M src/modules/__tests__/ci-poller-input.js
 M src/modules/__tests__/details-from-context.js
 M src/modules/__tests__/publish-location.js
 M src/modules/__tests__/publish-workflow.js
 M src/modules/ci-poller-input.js
 M src/modules/details-from-context.js
 M src/modules/publish-issue-title.js
 M src/modules/publish-issue-title.peggy
 M src/modules/publish-location.js
 M src/publish/resolve-location.js
?? src/modules/publish-issue-validation.js
 .github/workflows/publish.yml                 |  14 +-
 docs/publish-issue-format.md                  |  56 +++----
 src/modules/__tests__/ci-poller-input.js      |  48 +++++-
 src/modules/__tests__/details-from-context.js | 219 ++++++-------------------
 src/modules/__tests__/publish-location.js     |  94 +++++------
 src/modules/__tests__/publish-workflow.js     |  35 +++-
 src/modules/ci-poller-input.js                |  15 ++
 src/modules/details-from-context.js           |  ...
gateway · 2026-09-04 22:00:36
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/schemas/project_config.ts</path>
<type>file</type>
<content>
200: /**
201:  * Configuration for a single named workspace (release unit).
202:  *
203:  * A workspace mirrors the release-relevant subset of the top-level config;
204:  * every field is optional and inherits the top-level value when omitted. The
205:  * `github` block is *partial* (all fields optional) so a workspace can override
206:  * `owner` and/or `repo` while inheriting the rest from the top-level `github`.
207:  */
208: export const WorkspaceSchema = z.object({
209:   ...releaseUnitFields,
210:   github: GitHubGlobalConfigSchema.partial()
211:     .refine(github => github.projectPath === undefined, {
212:       message: 'Workspace github.projectPath is not supported.',
213:     })
214:     .optional(),
215: });
216: 
217: export type Workspace = z.infer<typeof WorkspaceSchema>;
218: 
219: function isSafeWorkspaceGlobSegment(segment: string): ...
gateway · 2026-09-04 22:00:41
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts</path>
<type>file</type>
<content>
1: import { existsSync, lstatSync, readFileSync, realpathSync } from 'fs';
2: import path from 'path';
3: import { globSync, hasMagic } from 'glob';
4: 
5: import { load } from 'js-yaml';
6: import GitUrlParse from 'git-url-parse';
7: import { createGitClient } from './utils/git';
8: import { ZodError } from 'zod';
9: 
10: import { logger } from './logger';
11: import {
12:   CraftProjectConfig,
13:   CraftProjectConfigSchema,
14:   GitHubGlobalConfig,
15:   ArtifactProviderName,
16:   StatusProviderName,
17:   TargetConfig,
18:   ChangelogPolicy,
19:   VersioningPolicy,
20:   Workspace,
21: } from './schemas/project_config';
22: import { ConfigurationError } from './utils/errors';
23: import { isCompiledGitHubAction } from './utils/detection';
24: import {
25:   getPackageVersion,
26:   parseVersion,
27:   versionGreaterOrEqualThan,
28:   SemVer,
29: } from ...
gateway · 2026-09-04 22:00:45
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/action.yml</path>
<type>file</type>
<content>
1: name: 'Craft Prepare Release'
2: description: 'Prepare a new release using Craft'
3: 
4: inputs:
5:   version:
6:     description: >
7:       Version to release. Can be a semver string (e.g., "1.2.3"),
8:       a bump type ("major", "minor", "patch"), or "auto" for automatic detection.
9:     required: false
10:   merge_target:
11:     description: Target branch to merge into. Uses the default branch as a fallback. ...
gateway · 2026-09-04 22:00:48
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts</path>
<type>file</type>
<content>
1: /**
2:  * Helpers for locating Craft's publish-state file in a path that is NOT
3:  * writable by the repository being published.
4:  *
5:  * Background: `craft publish` writes a small JSON file listing targets
6:  * that have completed so a resumed run can skip them. Before this module
7:  * existed, the file lived at `.craft-publish-<version>.json` in the
8:  * project's cwd. That path is inside the repository checkout, so any
9:  * committed file at the same path (or any earlier CI step) could
10:  * pre-populate the "published" set and trick Craft into silently
11:  * skipping targets.
12:  *
13:  * The file now lives under `$XDG_STATE_HOME/craft/` (falling back to
14:  * `$HOME/.local/state/craft/`). The filename is keyed on
15:  * owner, repo, a hash of cwd (to disambiguate monorepo subpaths), and
16:  * the version being published. ...
gateway · 2026-09-04 22:00:57
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/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-04 22:01:02
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.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 ...
gateway · 2026-09-04 22:01:10
result
/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/resolve-ci-poller-input.js
/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/ci-poller-input.js
/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/ci-poller-input.js
gateway · 2026-09-04 22:01:15
result
No files found
gateway · 2026-09-04 22:01:19
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows</path>
<type>directory</type>
<entries>
auto-approve.yml
ci-poller.yml
cocoapods-keepalive.yml
publish.yml
test.yml

(5 entries)
</entries>
gateway · 2026-09-04 22:01:24
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/.github/workflows/ci-poller.yml</path>
<type>file</type>
<content>
1: name: CI Status Poller
2: 
3: on:
4:   schedule:
5:     - cron: "*/5 * * * *"
6:   workflow_dispatch:
7:     inputs:
8:       attempt:
9:         description: Self-dispatch attempt counter (internal use)
10:         required: false
11:         default: "0"
12: 
13: permissions:
14:   contents: read
15:   issues: read
16: 
17: jobs:
18:   check-ci:
19:     runs-on: ubuntu-latest
20:     environment: production
21:     # Skip entirely (no runner provisioned) when there's nothing to check.
22:     # Set to "true" by ci-pending.yml, reset to "false" here when done.
23:     # Always allow workflow_dispatch for manual recovery.
24:     if: vars.CI_POLLER_HAS_PENDING == 'true' || github.event_name == 'workflow_dispatch'
25:     concurrency:
26:       group: ci-status-poller
27:       cancel-in-progress: false
28:     steps:
29:       # sentry-internal-app token ...
gateway · 2026-09-04 22:01:31
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/publish/resolve-ci-poller-input.js</path>
<type>file</type>
<content>
1: const { getCiPollerInput } = require("../modules/ci-poller-input");
2: 
3: process.stdout.write(
4:   JSON.stringify(
5:     getCiPollerInput({
6:       issueBody: process.env.PUBLISH_ISSUE_BODY || "",
7:       title: process.env.PUBLISH_TITLE || "",
8:       revision: process.env.PUBLISH_REVISION || "",
9:     })
10:   )
11: );

(End of file - total 11 lines)
</content>
gateway · 2026-09-04 22:01:36
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/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: 
12: function getCiPollerInput({ title, issueBody, revision }) {
13:   let parsedTitle;
14:   try {
15:     parsedTitle = parsePublishIssueTitle(title);
16:   } catch {
17:     throw new Error(`Invalid publish issue title: '${title}'`);
18:   }
19:   const { repo, version } = parsedTitle;
20:   if (!isPublishRepository(repo)) {
21:     throw new Error(`Invalid publish issue repository: '${repo}'`);
22:   }
23:   if (!isReleaseVersion(version)) {
24:     throw new Error(`Invalid publish issue version: ...
gateway · 2026-09-04 22:01:43
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/version.ts</path>
<type>file</type>
<content>
1: import { getGitTagPrefix } from '../config';
2: 
3: /**
4:  * Regular expression for matching semver versions.
5:  *
6:  * Modified to match version components
7:  * Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (sindresorhus.com)
8:  * @see https://github.com/sindresorhus/semver-regex
9:  */
10: const semverRegex = () =>
11:   /\bv?(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)(?:-?([\da-z-]+(?:\.[\da-z-]+)*))?(?:\+([\da-z-]+(?:\.[\da-z-]+)*))?\b/gi;
12: 
13: /**
14:  * Extracts a version number from the given text.
15:  *
16:  * In case the version contains a leading "v", it is stripped from the result.
17:  * All semantic versions are supported. See {@link http://semver.org/} for
18:  * more information. ...
gateway · 2026-09-04 22:02:32
result
Found 33 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/publishState.ts:
  Line 89: export function getPublishStateFilename(

  Line 118: export function getPublishStatePath(

  Line 126:     getPublishStateFilename(version, githubConfig, cwd, workspace),


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/utils/__tests__/publishState.test.ts:
  Line 7:   getPublishStateFilename,

  Line 8:   getPublishStatePath,

  Line 42:   describe('getPublishStateFilename', () => {

  Line 46:       const name = getPublishStateFilename(

  Line 57:       const a = getPublishStateFilename(

  Line 62:       const b = getPublishStateFilename(

  Line 71:       const cli = getPublishStateFilename(

  Line 77:       const mcp = getPublishStateFilename(

  Line 91:         getPublishStateFilename(

  Line 104:         getPublishStateFilename(version, { owner: 'o', repo: 'r' }, cwd),

  Line 117:       const name = getPublishStateFilename(

  Line 126:       ...
gateway · 2026-09-04 22:02:37
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/publish.ts</path>
<type>file</type>
<content>
150:   /** One or more targets we want to publish */
151:   target?: string | string[];
152:   /** The new version to publish */
153:   newVersion: string;
154:   /** Do not perform merge after publishing */
155:   noMerge: boolean;
156:   /** Do not remove downloads after publishing */
157:   keepDownloads: boolean;
158:   /** Do not perform build status check */
159:   noStatusCheck: boolean;
160:   /** Do not remove release branch after publishing */
161:   keepBranch: boolean;
162:   /** Do not perform basic git checks */
163:   noGitChecks: boolean;
164: }
165: 
166: export interface PublishState {
167:   published: {
168:     [targetId: string]: boolean;
169:   };
170: }
171: 
172: /**
173:  * The Publish controller prepopulates a secure state file using the issue's
174:  * checkout repository. ...
gateway · 2026-09-04 22:02:44
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/release-revision.js</path>
<type>file</type>
<content>
1: const CHECK_RUNS_LINK =
2:   /^Requested by: @[^\r\n]+\r?\n(?:[ \t]*\r?\n)?[ \t]*Merge target: [^\r\n]+\r?\n(?:[ \t]*\r?\n)?[ \t]*Quick links:\r?\n(?:[ \t]*\r?\n)?[ \t]*- \[View changes\]\([^\r\n]+\)\r?\n[ \t]*- \[View check runs\]\(https:\/\/github\.com\/getsentry\/(?<repo>[A-Za-z0-9_.-]+)\/commit\/(?<revision>[0-9a-f]{40})\/checks\/?\)(?=\r?\n|$)/;
3: const CHECK_RUNS_LINK_COUNT = /^[ \t]*- \[View check runs\]\(/gm;
4: 
5: function getReleaseRevision({ issueBody, repo }) {
6:   if ((issueBody.match(CHECK_RUNS_LINK_COUNT) || []).length !== 1) {
7:     throw new Error(
8:       `Expected exactly one View check runs link in Quick links for getsentry/${repo}.`
9:     );
10:   }
11: 
12:   const match = issueBody.match(CHECK_RUNS_LINK);
13:   if (!match?.groups || match.groups.repo !== repo) {
14:     throw new Error(
15:       `Expected a View check runs link ...
gateway · 2026-09-04 22:02:51
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/package.json</path>
<type>file</type>
<content>
1: {
2:   "name": "publish",
3:   "private": true,
4:   "version": "0.0.1",
5:   "description": "Approval-based publishing system for Sentry",
6:   "main": "index.js",
7:   "repository": "git@github.com:getsentry/publish.git",
8:   "author": "Sentry Open Source <oss@sentry.io>",
9:   "license": "Apache-2.0",
10:   "volta": {
11:     "node": "24.0.0",
12:     "yarn": "1.22.22"
13:   },
14:   "resolutions": {
15:     "undici": "^6.23.0"
16:   },
17:   "scripts": {
18:     "generate": "node scripts/generate-publish-issue-title-parser.js",
19:     "check:generated": "node scripts/generate-publish-issue-title-parser.js --check",
20:     "test": "yarn check:generated && vitest run",
21:     "test:watch": "vitest",
22:     "lint": "eslint src .github --ignore-pattern '!.github'",
23:     "prettier": "prettier --write src"
24:   },
25:   "devDependencies": {
26:     "eslint": ...
gateway · 2026-09-04 22:02:59
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/config.test.ts</path>
<type>file</type>
<content>
340:     // Overridden by the workspace.
341:     expect(config.releaseBranchPrefix).toBe('release/cli');
342:     expect(getGitTagPrefix()).toBe('cli@');
343:     expect(config.github).toEqual({ owner: 'getsentry', repo: 'toolkit' });
344:     // Inherited from the top level.
345:     expect(config.changelog).toBe('CHANGELOG.md');
346:     // `workspaces` is stripped from the resolved config.
347:     expect(config.workspaces).toBeUndefined();
348:   });
349: 
350:   test('a different workspace resolves independently', () => {
351:     setActiveWorkspace('mcp');
352:     const config = loadConfigurationFromString(WS_CONFIG);
353:     expect(config.releaseBranchPrefix).toBe('release/mcp');
354:     expect(getGitTagPrefix()).toBe('mcp@');
355:     expect(getVersioningPolicy()).toBe('calver');
356:     expect(config.github).toEqual({ owner: 'getsentry', repo: ...
gateway · 2026-09-04 22:03:10
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.peggy</path>
<type>file</type>
<content>
1: {
2:   function join(characters) {
3:     return characters.join("");
4:   }
5: }
6: 
7: // Canonical grammar for publish issue titles. A path suffix is syntactic only:
8: // the controller resolves the complete suffix as a workspace after checking
9: // out the CI-approved revision.
10: PublishIssueTitle
11:   = "publish: " "getsentry/"? repo:Repository path:Path? "@" version:Version !. {
12:       return {
13:         repo,
14:         path: path || "",
15:         version,
16:       };
17:     }
18: 
19: Repository
20:   = characters:RepositoryCharacter+ { return join(characters); }
21: 
22: RepositoryCharacter
23:   = [A-Za-z0-9_.-]
24: 
25: Path
26:   = segments:("/" segment:PathSegment { return `/${segment}`; })+ { return join(segments); }
27: 
28: PathSegment
29:   = characters:RepositoryCharacter+ { return join(characters); }
30: 
31: ...
gateway · 2026-09-04 22:03:17
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/publish-issue-title.js</path>
<type>file</type>
<content>
195:   const peg$source = options.grammarSource;
196: 
197:   const peg$startRuleFunctions = {
198:     PublishIssueTitle: peg$parsePublishIssueTitle,
199:   };
200:   let peg$startRuleFunction = peg$parsePublishIssueTitle;
201: 
202:   const peg$c0 = "publish: ";
203:   const peg$c1 = "getsentry/";
204:   const peg$c2 = "@";
205:   const peg$c3 = "/";
206: 
207:   const peg$r0 = /^[A-Za-z0-9_.\-]/;
208:   const peg$r1 = /^[A-Za-z0-9_.+\-]/;
209: 
210:   const peg$e0 = peg$literalExpectation("publish: ", false);
211:   const peg$e1 = peg$literalExpectation("getsentry/", false);
212:   const peg$e2 = peg$literalExpectation("@", false);
213:   const peg$e3 = peg$anyExpectation();
214:   const peg$e4 = peg$classExpectation(
215:     [["A", "Z"], ["a", "z"], ["0", "9"], "_", ".", "-"],
216:     false,
217:     false,
218:     false
219:   );
220:   const peg$e5 ...
gateway · 2026-09-04 22:03:26
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/details-from-context.js</path>
<type>file</type>
<content>
1: const { parse: parsePublishIssueTitle } = require("./publish-issue-title");
2: const { isPublishPath } = require("./publish-location");
3: const {
4:   isPublishRepository,
5:   isReleaseVersion,
6: } = require("./publish-issue-validation");
7: 
8: /**
9:  * Matches the entire "Targets" section of a github publish issue body.
10:  */
11: const TARGETS_SECTION_PARSER_REGEX =
12:   /^(?!### Targets$\s)(?: *- \[[ xX]\] \S+\s*$(?:\r?\n)?)+/m;
13: 
14: /**
15:  * Matches all targets of a github publish issue body in a section that was already matched and extracted with `TARGETS_PARSER_REGEX`.
16:  * The "id" of the targets is captured within a capture group. ...
gateway · 2026-09-04 22:03:31
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/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', result);
10: }
11: 
12: 
13: inputs();

(End of file - total 13 lines)
</content>
gateway · 2026-09-04 22:05:45
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/package.json</path>
<type>file</type>
<content>
1: {
2:   "name": "@sentry/craft",
3:   "version": "2.31.0-dev.0",
4:   "description": "The universal sentry workflow CLI",
5:   "main": "dist/craft",
6:   "repository": "https://github.com/getsentry/craft",
7:   "author": "Sentry",
8:   "license": "MIT",
9:   "bin": {
10:     "craft": "dist/craft",
11:     "sentry-craft": "dist/craft"
12:   },
13:   "devDependencies": {
14:     "@aws-sdk/client-lambda": "^3.984.0",
15:     "@eslint/js": "^9.17.0",
16:     "@google-cloud/storage": "^7.14.0",
17:     "@octokit/plugin-retry": "^7.1.2",
18:     "@octokit/request-error": "^7.0.0",
19:     "@octokit/rest": "^21.0.2",
20:     "@sentry/esbuild-plugin": "^2.23.0",
21:     "@sentry/node": "^10.27.0",
22:     "@types/async": "^3.0.1",
23:     "@types/aws4": "^1.5.1",
24:     "@types/cli-table": "^0.3.0",
25:     "@types/git-url-parse": "^9.0.0",
26:     "@types/is-ci": "^2.0.0",
27: ...
gateway · 2026-09-04 22:05:52
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/docs/publish-issue-format.md</path>
<type>file</type>
<content>
1: # Publish Issue Format
2: 
3: The Publish workflow treats a publish issue as a release request. The title identifies
4: the release; the body supplies the merge target and selected targets. Do not edit the
5: title by hand unless it remains valid under this format.
6: 
7: ## Title
8: 
9: Every title starts with `publish: `. This EBNF is canonical:
10: 
11: ```text
12: title             = "publish: ", [ "getsentry/" ], repository, [ path ],
13:                     "@", version ;
14: repository        = token, { token } ;
15: path              = "/", path-segment, { "/", path-segment } ;
16: path-segment      = token, { token } ;
17: version           = version-character, { version-character } ;
18: token             = ? ASCII letter, digit, ".", "_", or "-" ? ...
gateway · 2026-09-04 22:05:56
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/docs/src/content/docs/targets/github.md</path>
<type>file</type>
<content>
65: github:
66:   owner: getsentry
67:   repo: toolkit
68: releaseBranchPrefix: release/mcp
69: targets:
70:   - name: github
71:     tagPrefix: "mcp@"
72: ```
73: 
74: Releasing `1.2.3` for each product then produces the tags `cli@1.2.3` / `mcp@1.2.3` on release branches `release/cli/1.2.3` / `release/mcp/1.2.3` — no collisions.
75: 
76: ## Release Workspaces
77: 
78: Use top-level `workspaces:` to define independently versioned release units in
79: one repository. Keys may be literal paths or glob patterns, and Craft expands
80: patterns to concrete directories relative to `.craft.yml`. Select one concrete
81: path explicitly with `--workspace <path>` or
82: `CRAFT_WORKSPACE`:
83: 
84: ```yaml
85: minVersion: 2.29.0
86: github:
87:   owner: getsentry
88:   repo: toolkit
89: workspaces:
90:   packages/*:
91:     releaseBranchPrefix: ...
gateway · 2026-09-04 22:06:09
result
Found 20 matches
/home/byk/Code/getsentry/craft-workspace-action-propagation/src/config.ts:
  Line 124:     const available = getWorkspaceNamesFromConfig(base, workspaceDirectory);

  Line 201: function getWorkspaceNamesFromConfig(

  Line 452:     const available = getWorkspaceNamesFromConfig(

  Line 604: export function getWorkspaceNames(): string[] {

  Line 612:   const workspaceNames = getWorkspaceNamesFromConfig(


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/__tests__/list.test.ts:
  Line 4:   getWorkspaceNames: vi.fn(),

  Line 10: import { getWorkspaceNames } from '../../../config';

  Line 13: describe('workspace list command', () => {

  Line 15:     vi.mocked(getWorkspaceNames).mockReturnValue(['cli', 'mcp.v2']);

  Line 24:     vi.mocked(getWorkspaceNames).mockReturnValue([]);


/home/byk/Code/getsentry/craft-workspace-action-propagation/src/commands/workspace_cmds/list.ts:
  Line 1: import { getWorkspaceNames } from ...
gateway · 2026-09-04 22:07:01
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/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: 
8: const REVISION = "7e5ca7ed5581552de066e2a8bc295b8306be38ac";
9: const issueBody = `Requested by: @byk
10: 
11: Merge target: (default)
12: 
13: Quick links:
14: - [View changes](https://github.com/getsentry/toolkit/compare/1.2.2...release/1.2.3)
15: - [View check runs](https://github.com/getsentry/toolkit/commit/${REVISION}/checks/)`;
16: 
17: test("parses root and full-path publish titles", () => {
18:   expect(
19:     getCiPollerInput({
20:       issueBody,
21:       title: "publish: getsentry/toolkit/cli@1.2.3",
22:     })
23:   ).toEqual({
24:     repo: "getsentry/toolkit",
25:     revision: REVISION,
26:     version: "1.2.3",
27:   });
28: 
29:   ...
gateway · 2026-09-04 22:07:07
result
<path>/home/byk/Code/getsentry/craft-workspace-action-propagation/src/__tests__/action.test.ts</path>
<type>file</type>
<content>
150: test('forwards workspace input to every Craft command', () => {
151:   expect(getActionStep('Validate workspace').env?.PATH_INPUT).toBe(
152:     '${{ inputs.path }}',
153:   );
154:   expect(getActionStep('Craft Prepare').env?.WORKSPACE).toBe(
155:     '${{ inputs.workspace }}',
156:   );
157:   expect(getActionStep('Read Craft Targets').env?.WORKSPACE).toBe(
158:     '${{ inputs.workspace }}',
159:   );
160: });
161: 
162: test.each([
163:   ['control', 'cli\tnext'],
164:   ['format', 'cli\u202enext'],
165:   ['line separator', 'cli\u2028next'],
166:   ['paragraph separator', 'cli\u2029next'],
167:   ['non-ASCII', 'cli-é'],
168: ])(
169:   'rejects %s characters before every action side effect',
170:   (_name, workspace) => {
171:     const environment = createActionEnvironment();
172: 
173:     expect(getActionSteps()[0]?.name).toBe('Validate ...
gateway · 2026-09-04 22:07:14
result
<path>/home/byk/Code/getsentry/publish-workspace-acceptance/src/modules/__tests__/publish-workflow.js</path>
<type>file</type>
<content>
50:   expect(result.status, result.stderr).toBe(0);
51:   const stateFile = readFileSync(output, "utf8")
52:     .trim()
53:     .replace("state_file=", "");
54:   return { stateFile, state: readFileSync(stateFile, "utf8") };
55: }
56: 
57: afterEach(() => {
58:   for (const directory of temporaryDirectories.splice(0)) {
59:     rmSync(directory, { recursive: true, force: true });
60:   }
61: });
62: 
63: test("uses the CI-approved revision for checkout, location resolution, and publishing", () => {
64:   const workflow = getWorkflow();
65:   const revision = workflow.indexOf(
66:     "name: Resolve CI-approved release revision"
67:   );
68:   const informStart = workflow.indexOf("name: Inform start");
69:   const checkout = workflow.indexOf("name: Check out target repo");
70:   const location = workflow.indexOf("name: Resolve publish location");
71: ...
gateway · 2026-09-04 22:07:59

MUST-FIX

3) Workspace glob safety — MUST-FIX. Nested malformed braces still fail open in both validation layers. packages/{cli,{mcp}} expands the valid cli branch, silently drops the nested {mcp} branch when it returns [], then passes the outer nonempty check. The same bypass accepts nested empty constructs such as packages/{cli,{{},mcp}}.

  • Schema: flatMap discards an invalid nested expansion at craft/src/schemas/project_config.ts:269-278; only the final outer array is checked at :281-288.
  • Runtime: identical flaw at craft/src/config.ts:332-380, with the same outer-only check at :287-296.
  • Regression coverage only tests flat malformed patterns at craft/src/__tests__/config.test.ts:518-524; it lacks nested no-alternative and nested-empty cases.

1) CI poller input validation — PASS. It parses and validates repository, Craft-compatible version, and safe path before the first cross-repository API call: publish/src/modules/ci-poller-input.js:12-30, invoked before check-suites at .github/workflows/ci-poller.yml:100-115. Root paths pass and unsafe segments reject in publish/src/modules/publish-location.js:22-34.

2) Publish-state filename identity — PASS. Craft preserves safe legacy versions and base64url-encodes changed values at craft/src/utils/publishState.ts:51-63,95-105. Publish uses the same lowercase/sanitize and base64url algorithm at publish/.github/workflows/publish.yml:217-235. Version case-collision regressions exist in both worktrees: craft/src/utils/__tests__/publishState.test.ts:98-113 and publish/src/modules/__tests__/publish-workflow.js:138-152.

4) Action input and ambient-workspace handling — PASS. The first action step validates mutually exclusive path/workspace inputs before side effects at craft/action.yml:74-92; root commands clear inherited CRAFT_WORKSPACE at :191,220; titles retain the full workspace path at :245,275. ...

gpt-5.6-terra · 2026-09-04 22:07:59 · ~722 tokens

Distillations (1)

Gen 0 2026-09-04 22:07:48 · 1055 tokens

Date: Sep 4, 2026 * 🔴 (21:57) User directive: Never return empty. * 🔴 (22:00) User directive: Always carry the full concrete path. * 🔴 [requested-read-only-audit] (21:57) User requested a strict final READ-ONLY adversarial audit of current uncommitted diffs and relevant code in both worktrees: `/home/byk/Code/getsentry/craft-workspace-action-propagation` and `/home/byk/Code/getsentry/publish-w…