Dashboard › craft › Distillation
b06192d8-4a3b-450d-a16a-884e86279a6d["lore_tm_v1_bC5wXVhZeCpd3ZEiok_s7-7OIvEI1fcAnU66hE8GpFg","lore_tm_v1_rjC1nVLi4NEkqZrQl6oyxniGXzn_g9ki2rmsEhj4sFY","lore_tm_v1_s-ozyMuhcp5KSuUekJ9QYcdi59pr1teu1j0nLPUMQU8","lore_tm_v1_ZeKLFeCy5Z_Ts90efggejgtZDDMW8azqDTF71TYV0Dg","lore_tm_v1_ecczeZ9ANLg4RUXbiGKUZxdZTqawTxc8PtBxAAuzp3w","lore_tm_v1_MqKJiZ4j1214Y7QICstUDONaKhe2AJIgEjAZz1WJADs","lore_tm_v1_2WAl1k-GS4H0wm83H6FmgWhQhGomq7LpiaiD73Bu704","lore_tm_v1_9oBO42qLDr1cK4D-ZYTgSLAhwlAu5GffB5GjpwJU8AM","lore_tm_v1_KlFX0fO5EPbadm_G6KT5WksVyAEN7t8_Ywibtf-hPwE","lore_tm_v1_bFGclIfp6d1lAsCqrgucLn1odads49mmPA6RuYZdnoE","lore_tm_v1_O1AZOXMoTPJOdtQyziWrGhf5FpXK4K7HgsqFsS8lQ5A","lore_tm_v1_yDZjBMu5lXMxU5UaeKqCaxk3_LYPKRK2has1c2mt_UE","lore_tm_v1_oM8Tt6P2CkcDMbFQc58o_sICnaZrIkGrH6lULHkv7Ng","lore_tm_v1_9Hkg_8G05WDeVThS1lrzakdfO6lMChqCvlfSxOr89i8"]
Date: Sep 8, 2026
/home/byk/Code/getsentry/craft-workspace-action-propagation of the current uncommitted fix for Craft PR #872 against current HEAD f174ceafa57355e71617f32ba1b0a030953be0a2; instructed not to edit or mutate files. Requested review of src/config.ts, src/__tests__/config.test.ts, and relevant callers; verification that realpath error handling skips only broken/racy glob candidates, cannot hide unsafe entries or bypass lexical/physical containment, preserves determinism, and that the regression genuinely fails before the fix; requested diff-hygiene check, severity-ranked file:line findings, explicit PASS/FAIL, test gaps, and a response ending exactly MERGE or DO-NOT-MERGE.pnpm; never use npm or yarn.AGENTS.md: Node.js is Volta-managed at v22.12.0; dependencies install with pnpm install --frozen-lockfile; development commands are pnpm build, pnpm test, pnpm lint, and pnpm fix; manual testing is pnpm build && ./dist/craft..prettierrc.yml; ESLint 9.x flat config in eslint.config.mjs using typescript-eslint; unused variables prefixed _ are allowed.src/__tests__/, follow *.test.ts, and use vi.fn(), vi.mock(), and vi.spyOn(); CI tests Node.js 20 and 22; main branch is master..craft.yml is project configuration at repository root; schemas are in src/schemas/; dry-run destructive operations use getGitClient()/createGitClient(directory), getGitHubClient(), safeFs, safeExec(), or safeExecSync().src/config.ts and src/__tests__/config.test.ts (28 insertions, 1 deletion); HEAD is f174ceafa57355e71617f32ba1b0a030953be0a2.src/config.ts:249-258: getWorkspaceGlobMatches() changed from unconditional const realMatch = realpathSync(resolvedMatch); to let realMatch: string; try { realMatch = realpathSync(resolvedMatch); } catch { // Glob candidates may disappear or be broken symlinks before resolution. return false; }, then retains isSafeWorkspacePath(match), lexical containment based on resolvedMatch under root, and physical containment based on realMatch under realRoot.src/__tests__/config.test.ts:504-523, ignores broken symlinks matched by workspace globs: creates temp directory craft-workspaces-*, creates packages/cli, symlinks packages/broken to nonexistent missing-workspace, writes .craft.yml with minVersion: ${WORKSPACES_MIN_VERSION} and workspace glob packages/*: {}, changes cwd to fixture directory, and expects getWorkspaceNames() to equal ['packages/cli'].packages/**/release does not expand through symlinked packages/external pointing outside the workspace root, returning only ['packages/internal/release']; unsafe brace alternatives {../outside/*,packages/*} and {/tmp/*,packages/*} must throw Workspace paths must use safe ASCII segments.; overlapping globs packages/* and packages/cli* must report that packages/cli matches multiple workspace patterns.src/index.ts:92-99 resolves active workspace before yargs parsing via setActiveWorkspace(extractWorkspaceSelection(argv)), because builders can read configuration before middleware; src/commands/prepare.ts:796-815 fetches and loads .craft.yml from trusted --config-from remote branch using loadConfigurationFromString(configContent, repositoryRoot.trim()); getWorkspaceNames() reads config, calls getWorkspaceNamesFromConfig(parsed, path.dirname(configPath)), and checks workspace minVersion when results are nonempty./home/byk/Code/getsentry/craft-workspace-action-propagation; 1 test file passed, 68 tests passed, duration 1.48s (transform 383ms, import 1.16s, tests 121ms).src/config.ts:253-258 catches every realpathSync error, not only broken/racy candidates; this silently drops EACCES/EPERM, ELOOP, and unexpected I/O errors. Since lexical and physical containment checks occur only afterward at :260-265, rejected candidates receive neither validation nor diagnostics. Assistant assessed that this cannot admit a candidate past containment checks, but can hide unsafe or ambiguous filesystem state; recommended rethrowing non-disappearance errors.src/__tests__/config.test.ts:504-523 does not prove the broken symlink reaches globSync; it passes whether globSync returns the link and the new filter skips it or whether globSync omits it before filtering, so it does not demonstrate that pre-fix f174ce…:src/config.ts:252 fails. Recommended asserting the fixture is returned by globSync or adding a deterministic mock/spying seam that makes realpathSync throw ENOENT for a glob candidate.isSafeWorkspacePath() at src/config.ts:235-239 and :260; physical containment remains enforced for successfully resolved candidates at :263-265; ordering remains deterministic through .sort() at :268; selection (:197), listing (:210, :628-635), and remote config loading (src/commands/prepare.ts:805-815) route glob expansion through the reviewed function; only the two requested files changed; git diff --check passed; focused src/__tests__/config.test.ts suite passed with 68 tests.realpathSync errors should fail rather than disappear; candidates removed between globbing and realpathSync should be skipped; regression must prove baseline failure rather than merely fixed behavior.DO-NOT-MERGE.