Dashboard › craft › Distillation
f2815d8b-feb6-4686-bd6a-45423dea6a6f["lore_tm_v1_Tb_YmQuaWl76age3WVE2H8cM6Gn8jtm52ia_liwr6WI","lore_tm_v1_zjamMD1lp5JXmg3JkD6M3QgK52CEyFOXW7dAispjb1k","lore_tm_v1_GizzI_18iFjMFXMzjmT2vE1pAbX79DABDncOJo7dPSE","lore_tm_v1_o-S9V8Ku7gqFfNY7B4hUSHb-waB9iJn4gphVe-zNH2A","lore_tm_v1_F_3xTsqS4AQE6pkbs4Nl-4ZK-j06N7gwOo913zJ5qAg","lore_tm_v1_RD3rLNtvEvq_KUSng7aWGMNiARybeyYYDsCujfulAIY","lore_tm_v1_R62uGd67lK2nMF6ults-GcoPHkItYAZ4fbniFN3bak8","lore_tm_v1_DAyejA0QZeH6_8KwZegzeNJzxBjf3hN7td5JQsv9uj4"]
Date: Sep 8, 2026
pnpm; never use npm or yarn.pnpm install --frozen-lockfile.pnpm build outputs dist/craft; pnpm test runs tests; pnpm lint runs ESLint; pnpm fix auto-fixes lint; manual testing uses pnpm build && ./dist/craft./home/byk/Code/getsentry/craft-workspace-action-propagation of the current uncommitted fix for Craft PR #872; instructed not to edit, mutate, or format files; requested review of the exact diff from f174ceafa57355e71617f32ba1b0a030953be0a2 plus relevant source/tests.glob emits the broken-symlink candidate and that it is skipped only on ENOENT; verify unexpected realpath errors such as ELOOP/EACCES are rethrown; ensure no bypass of safe-path validation, lexical and physical realpath containment, directory-only checks, sorted determinism, or configuration behavior; confirm tests and diff hygiene; return severity-ranked file:line findings, PASS/FAIL coverage, test gaps, ending exactly MERGE or DO-NOT-MERGE.AGENTS.md: TypeScript project; Prettier 3.x configured for single quotes and no arrow parentheses; ESLint 9.x flat configuration in eslint.config.mjs using typescript-eslint; unused variables prefixed with _ are permitted; Vitest tests reside in src/__tests__/ as *.test.ts; CI tests Node.js 20 and 22; primary branch is master; configuration file is root .craft.yml and schema resides in src/schemas/.f174ceafa57355e71617f32ba1b0a030953be0a2 has modified src/__tests__/config.test.ts and src/config.ts: 53 insertions and 1 deletion total; src/__tests__/config.test.ts has 43 additions and src/config.ts has 10 additions/1 deletion. Base commit f174cea is test: describe workspace paths accurately on feat/workspace-action-propagation; preceding relevant commits are d48b906 (feat: support concrete release workspaces), 4862056 (feat: support compact release workspaces), 6dae341 (feat: propagate release workspaces), and 21270a1 (feat(config): add release workspaces).src/config.ts getWorkspaceGlobMatches() preserves existing checks: validates isSafeWorkspaceGlob(workspaceGlob); resolves root = path.resolve(workspaceDirectory) and realRoot = realpathSync(root); runs globSync(workspaceGlob, { absolute: false, cwd: root, dot: true, ignore: ['**/node_modules/**'], posix: true }); filters each match by isSafeWorkspacePath(match), lexical containment of resolvedMatch under root, physical containment of realMatch under realRoot, and lstatSync(resolvedMatch).isDirectory(); returns sorted results via .sort().src/config.ts around lines 251-261: wraps realpathSync(resolvedMatch) in try/catch; returns false only when (error as NodeJS.ErrnoException).code === 'ENOENT', thereby excluding that glob match; rethrows all other errors. Comment states glob candidates may disappear or be broken symlinks before resolution.globSync import from glob in src/__tests__/config.test.ts.ignores broken symlinks matched by workspace globs in src/__tests__/config.test.ts:505-527: creates temporary repository directory with packages/cli, adds broken symlink packages/broken targeting <directory>/missing-workspace, configures minVersion: ${WORKSPACES_MIN_VERSION} and workspace glob packages/*, changes CWD to the temp directory, asserts globSync('packages/*', { cwd: directory, dot: true, posix: true }) contains packages/broken, and asserts getWorkspaceNames() equals ['packages/cli'].fails on unexpected workspace glob resolution errors in src/__tests__/config.test.ts:529-545: creates packages/cli, creates self-referential symlink packages/loop with target loop, configures workspace glob packages/*, changes CWD, and expects getWorkspaceNames() to throw /ELOOP/.src/__tests__/config.test.ts cover: directory-only behavior by excluding file packages/README.md; glob expansion for braces, nested braces, ?, character classes, and **; negated character classes [!a]* and [^a]*; matching relative to repository root for remote config; no expansion through a symlinked directory outside the repository; rejection of unsafe brace alternatives {../outside/*,packages/*} and {/tmp/*,packages/*}; malformed brace globs; unsafe literal paths; multiple-pattern collision errors; and deterministic expected workspace-name ordering.src/config.ts:452-489 applies workspace selection: config with no workspaces and no active selection returns unchanged; active selection without configured workspaces throws; configured workspaces without an active selection call getWorkspaceNamesFromConfig(config, workspaceDirectory) to provide available names then throw a selection-required error; selected workspace enforces checkWorkspacesMinVersion(config) then calls resolveWorkspaceConfig(config, _activeWorkspaceName, workspaceDirectory).src/config.ts:623-638 getWorkspaceNames() reads and validates .craft.yml, checks minimal config version, expands names through getWorkspaceNamesFromConfig(parsed, path.dirname(configPath)), conditionally enforces checkWorkspacesMinVersion(parsed) when names are nonempty, and returns the names.