Skip to content

Commit 06d2c4d

Browse files
authored
fix(project): validate list flags before client setup (#150)
1 parent 205b1fb commit 06d2c4d

2 files changed

Lines changed: 42 additions & 1 deletion

File tree

src/commands/project.test.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,47 @@ describe('runList', () => {
199199
});
200200
});
201201

202+
it('rejects invalid pagination before requiring credentials', async () => {
203+
const credentialsPath = join(mkdtempSync(join(tmpdir(), 'cli-p2-no-creds-')), 'credentials');
204+
const fetchImpl = vi.fn();
205+
206+
await expect(
207+
runList(
208+
{ profile: 'default', output: 'json', debug: false, pageSize: 1.5 },
209+
{ credentialsPath, fetchImpl: fetchImpl as unknown as typeof globalThis.fetch },
210+
),
211+
).rejects.toMatchObject({
212+
code: 'VALIDATION_ERROR',
213+
exitCode: 5,
214+
details: { field: 'page-size' },
215+
});
216+
217+
expect(fetchImpl).not.toHaveBeenCalled();
218+
});
219+
220+
it('rejects invalid dry-run pagination before emitting the dry-run banner', async () => {
221+
const stderr: string[] = [];
222+
const fetchImpl = vi.fn();
223+
224+
await expect(
225+
runList(
226+
{ profile: 'default', output: 'json', debug: false, dryRun: true, pageSize: 1.5 },
227+
{
228+
credentialsPath: join(mkdtempSync(join(tmpdir(), 'cli-p2-dryrun-')), 'credentials'),
229+
fetchImpl: fetchImpl as unknown as typeof globalThis.fetch,
230+
stderr: line => stderr.push(line),
231+
},
232+
),
233+
).rejects.toMatchObject({
234+
code: 'VALIDATION_ERROR',
235+
exitCode: 5,
236+
details: { field: 'page-size' },
237+
});
238+
239+
expect(fetchImpl).not.toHaveBeenCalled();
240+
expect(stderr.join('\n')).not.toContain(DRY_RUN_BANNER);
241+
});
242+
202243
it('rejects pageSize=101 with VALIDATION_ERROR exit 5 (Fix 7 — upper-bound enforced client-side)', async () => {
203244
// Previously silently clamped to 100; now rejected so callers get fast feedback.
204245
const { credentialsPath } = makeCreds();

src/commands/project.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,13 +51,13 @@ export async function runList(
5151
deps: ProjectDeps = {},
5252
): Promise<Page<CliProject>> {
5353
const out = makeOutput(opts.output, deps);
54-
const client = makeClient(opts, deps);
5554

5655
const paginationFlags: PaginationFlags = validatePaginationFlags({
5756
pageSize: opts.pageSize,
5857
startingToken: opts.startingToken,
5958
maxItems: opts.maxItems,
6059
});
60+
const client = makeClient(opts, deps);
6161

6262
// When the user explicitly passed a page-size flag and did NOT ask
6363
// for --max-items, treat that as a "give me one page and the cursor"

0 commit comments

Comments
 (0)