diff --git a/src/artifacts/ArtifactSourceResolution.test.ts b/src/artifacts/ArtifactSourceResolution.test.ts index 745705b4aa..7101a31382 100644 --- a/src/artifacts/ArtifactSourceResolution.test.ts +++ b/src/artifacts/ArtifactSourceResolution.test.ts @@ -8,6 +8,9 @@ import { assertArtifactFileSelectedSource } from "./ArtifactFileSource.js"; import { assertArtifactSelectedSource } from "./ArtifactSelectedSource.js"; import { readStableArtifact } from "./readStableArtifact.js"; import { DirectoryArtifactReader } from "./DirectoryArtifactReader.js"; +import { createDesktopApplicationService } from "../composition/desktop.js"; +import { projectAnalysisError } from "../domain/analysisErrorProjection.js"; +import { desktopApplicationSchema } from "../domain/desktopApplication.js"; it.skipIf(process.platform === "win32")( "admits a caller-selected directory symlink without changing its target identity", @@ -46,6 +49,54 @@ it.skipIf(process.platform === "win32")( }, ); +it.skipIf(process.platform === "win32")( + "rejects desktop inspection when the selected spelling traverses a regular file", + async () => { + const root = await createTestTempDirectory( + "rea-desktop-enotdir-intermediate-", + ); + const app = join(root, "Demo.app"); + await mkdir(app); + await writeFile( + join(app, "Info.plist"), + ` + +CFBundleIdentifiercom.example.demo`, + ); + await writeFile(join(app, "marker.txt"), "marker\n"); + await writeFile(join(root, "regular"), "regular file\n"); + const service = createDesktopApplicationService(); + try { + const invalid = await service.inspect({ + path: `${root}/regular/../Demo.app`, + max_entries: 32, + max_probe_bytes: 4096, + }); + expect(invalid.ok).toBe(false); + if (invalid.ok) throw new Error("expected ENOTDIR refusal"); + expect(projectAnalysisError(invalid.error)).toMatchObject({ + code: "target_unavailable", + category: "unavailable", + }); + const valid = await service.inspect({ + path: app, + max_entries: 32, + max_probe_bytes: 4096, + }); + expect(valid.ok).toBe(true); + if (!valid.ok) throw valid.error; + expect( + desktopApplicationSchema + .parse(valid.value.normalized_result) + .files.map((file) => file.path) + .sort(), + ).toEqual(["Info.plist", "marker.txt"]); + } finally { + await service.close(); + } + }, +); + it.skipIf(process.platform === "win32")( "reports a replaced ancestor symlink loop as a changed admitted source", async () => {