Dashboard › craft › Session 186KrRvT2nRj
186KrRvT2nRj0tpq2Perform 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.
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:
<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>
<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>
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 ...
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 | ...
<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): ...
<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 ...
<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. ...
<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. ...
<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>
<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 ...
/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
No files found
<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>
<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 ...
<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>
<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: ...
<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. ...
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: ...
<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. ...
<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 ...
<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": ...
<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: ...
<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: ...
<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 ...
<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. ...
<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>
<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: ...
<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 "-" ? ...
<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: ...
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 ...
<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: ...
<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 ...
<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: ...
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}}.
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.craft/src/config.ts:332-380, with the same outer-only check at :287-296.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. ...
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…