open-design/apps/daemon/tests/server-image-paths.test.ts
Caprika 76c7d31c53
chore: bump vela cli to 0.0.4 (#3239)
* chore: bump vela cli to 0.0.4-test.0

* chore: refresh lockfile for vela cli 0.0.4-test.0

* chore(nix): refresh pnpm deps hash

* fix: materialize electron before mac release checks

* fix: rebuild electron when mac framework links are invalid

* revert: drop release workflow experiments

* chore(nix): refresh pnpm deps hash

* fix: stop blocking beta mac release on electron symlink preflight

* fix: stop using custom electron dist for beta mac packaging

* fix: guard oversized chat images and opencode overflow

* chore: bump vela cli to 0.0.4

* chore(nix): refresh pnpm deps hash

* fix(daemon): surface prompt-image stat failures instead of dropping them

resolveSafePromptImagePaths only swallowed unresolvable path input; once a
path was confirmed inside UPLOAD_DIR and existed, a statSync failure
(EACCES/EPERM, a file vanishing mid-run) silently dropped the image and let
the run continue without that prompt context. Since this helper is now also
the 1 MB enforcement point, that turned an infra/validation failure into a
'successful' run with missing required context.

Collect those into a new failedImages bucket and fail the run with
INTERNAL_ERROR at the call site, mirroring the oversized-image guard. Add a
unit test covering statSync throwing.

---------

Co-authored-by: open-design-bot[bot] <282769551+open-design-bot[bot]@users.noreply.github.com>
Co-authored-by: lefarcen <935902669@qq.com>
2026-05-29 06:41:17 +00:00

77 lines
2.3 KiB
TypeScript

import { expect, test } from 'vitest';
import { resolveSafePromptImagePaths, selectPromptImagePaths } from '../src/server.js';
test('selectPromptImagePaths uses staged AMR paths in prompt text', () => {
expect(
selectPromptImagePaths(
'amr',
['/tmp/od-uploads/original.png'],
['/project/.amr-attachments/staged.png'],
),
).toEqual(['/project/.amr-attachments/staged.png']);
});
test('selectPromptImagePaths keeps original paths for non-AMR agents', () => {
expect(
selectPromptImagePaths(
'opencode',
['/tmp/od-uploads/original.png'],
['/project/.amr-attachments/staged.png'],
),
).toEqual(['/tmp/od-uploads/original.png']);
});
test('resolveSafePromptImagePaths rejects images larger than 1 MB', () => {
const result = resolveSafePromptImagePaths(
['/tmp/od-uploads/too-large.png', '/tmp/od-uploads/ok.png'],
{
uploadDir: '/tmp/od-uploads',
existsSync: () => true,
statSync: (inputPath: string) => ({
isFile: () => true,
size: inputPath.endsWith('too-large.png') ? 1024 * 1024 + 1 : 1024,
}),
},
);
expect(result.safeImages).toEqual(['/tmp/od-uploads/ok.png']);
expect(result.oversizedImages).toEqual([
{ path: '/tmp/od-uploads/too-large.png', sizeBytes: 1024 * 1024 + 1 },
]);
});
test('resolveSafePromptImagePaths keeps images at or below 1 MB', () => {
const result = resolveSafePromptImagePaths(
['/tmp/od-uploads/exactly-1mb.png'],
{
uploadDir: '/tmp/od-uploads',
existsSync: () => true,
statSync: () => ({
isFile: () => true,
size: 1024 * 1024,
}),
},
);
expect(result.safeImages).toEqual(['/tmp/od-uploads/exactly-1mb.png']);
expect(result.oversizedImages).toEqual([]);
});
test('resolveSafePromptImagePaths surfaces stat failures instead of dropping the image', () => {
const result = resolveSafePromptImagePaths(['/tmp/od-uploads/unreadable.png'], {
uploadDir: '/tmp/od-uploads',
existsSync: () => true,
statSync: () => {
throw Object.assign(new Error('EACCES: permission denied'), {
code: 'EACCES',
});
},
});
expect(result.safeImages).toEqual([]);
expect(result.oversizedImages).toEqual([]);
expect(result.failedImages).toEqual([
{ path: '/tmp/od-uploads/unreadable.png', error: 'EACCES: permission denied' },
]);
});