diff --git a/.changeset/tame-apples-fly.md b/.changeset/tame-apples-fly.md new file mode 100644 index 0000000..aa5f85e --- /dev/null +++ b/.changeset/tame-apples-fly.md @@ -0,0 +1,5 @@ +--- +"@dormice/cli": patch +--- + +`dor apikey disable`, `enable` and `revoke` now trim the name argument before matching, the same way key creation trims a name before storing it. Before this, a name typed with the exact leading/trailing whitespace used at creation time (or any other spelling that only differs by whitespace) failed to resolve, so a script or operator could not disable or revoke a credential. diff --git a/packages/cli/src/commands.test.ts b/packages/cli/src/commands.test.ts index 319590d..9da290d 100644 --- a/packages/cli/src/commands.test.ts +++ b/packages/cli/src/commands.test.ts @@ -272,6 +272,24 @@ describe('apikey commands over real HTTP', () => { ); }); + it('disable and revoke resolve a name by the same trimmed spelling creation stored', async () => { + // Creation trims the name (apiKeyNameSchema), so `ls` and every other + // read shows "incident key". Disable/enable/revoke must resolve by + // that same trimmed spelling, whether the operator retypes it exactly + // or reuses the untrimmed spelling they originally typed at creation. + await apikeyCreate(client, ' incident key '); + expect(await apikeyLs(client)).toMatch(/incident key\s{2,}/); + + expect(await apikeyDisable(client, ' incident key ')).toBe( + 'Disabled API key " incident key " — it stops working until re-enabled.', + ); + expect(await apikeyLs(client)).toMatch(/incident key\s{2,}.*disabled/); + + expect(await apikeyRevoke(client, 'incident key')).toBe( + 'Revoked API key "incident key" — it stops working immediately.', + ); + }); + it('--expires mints a TTL key through end-of-day and refuses garbage dates', async () => { const created = await apikeyCreate(client, 'ttl', '2030-06-15'); expect(created.split('\n')[0]).toMatch( diff --git a/packages/cli/src/commands.ts b/packages/cli/src/commands.ts index beeda56..733d2a2 100644 --- a/packages/cli/src/commands.ts +++ b/packages/cli/src/commands.ts @@ -281,8 +281,14 @@ async function resolveApiKeyId( client: Dormice, name: string, ): Promise { + // Creation trims the name (apiKeyNameSchema), so the stored spelling + // never has surrounding whitespace — match on the same trimmed spelling + // here so the untrimmed input an operator originally typed still resolves. + const trimmed = name.trim(); const keys = await client.listApiKeys(); - return keys.find((k) => k.name === name && k.revokedAt === null)?.id ?? null; + return ( + keys.find((k) => k.name === trimmed && k.revokedAt === null)?.id ?? null + ); } /**