From 2e81443697f4f88a33841a6d27417187283dac7d Mon Sep 17 00:00:00 2001 From: umair Date: Fri, 13 Mar 2026 01:34:19 +0000 Subject: [PATCH] Fix auth keys get formatting and add ABLY_API_KEY override warning --- src/commands/auth/keys/get.ts | 66 ++++++++++++---- test/unit/commands/auth/keys/get.test.ts | 95 ++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 15 deletions(-) diff --git a/src/commands/auth/keys/get.ts b/src/commands/auth/keys/get.ts index fe76de6d..c5494f67 100644 --- a/src/commands/auth/keys/get.ts +++ b/src/commands/auth/keys/get.ts @@ -2,6 +2,13 @@ import { Args, Flags } from "@oclif/core"; import { ControlBaseCommand } from "../../../control-base-command.js"; import { formatCapabilities } from "../../../utils/key-display.js"; +import { + formatHeading, + formatLabel, + formatProgress, + formatResource, + formatWarning, +} from "../../../utils/output.js"; export default class KeysGetCommand extends ControlBaseCommand { static args = { @@ -51,34 +58,53 @@ export default class KeysGetCommand extends ControlBaseCommand { } if (!appId) { - this.fail( - 'No app specified. Please provide --app flag, include APP_ID in the key name, or switch to an app with "ably apps switch".', - flags, - "keyGet", - ); + appId = await this.requireAppId(flags); } try { + if (!this.shouldOutputJson(flags)) { + this.log(formatProgress("Fetching key details")); + } + const controlApi = this.createControlApi(flags); const key = await controlApi.getKey(appId, keyIdentifier); + const keyName = `${key.appId}.${key.id}`; + + // Check if env var overrides the current key + const currentKeyId = this.configManager.getKeyId(appId); + const currentKeyName = currentKeyId?.includes(".") + ? currentKeyId + : currentKeyId + ? `${appId}.${currentKeyId}` + : undefined; + const envKey = process.env.ABLY_API_KEY; + const envKeyPrefix = envKey ? envKey.split(":")[0] : undefined; + const hasEnvOverride = + envKey && currentKeyName === keyName && envKeyPrefix !== keyName; + if (this.shouldOutputJson(flags)) { - // Add the full key name to the JSON output this.logJsonResult( { key: { ...key, - keyName: `${key.appId}.${key.id}`, + keyName, }, + ...(hasEnvOverride + ? { + envKeyOverride: { + keyName: envKeyPrefix, + note: "ABLY_API_KEY env var overrides this key for product API commands", + }, + } + : {}), }, flags, ); } else { - this.log(`Key Details:\n`); - - const keyName = `${key.appId}.${key.id}`; - this.log(`Key Name: ${keyName}`); - this.log(`Key Label: ${key.name || "Unnamed key"}`); + this.log(formatHeading("Key Details")); + this.log(`${formatLabel("Key Name")} ${formatResource(keyName)}`); + this.log(`${formatLabel("Key Label")} ${key.name || "Unnamed key"}`); for (const line of formatCapabilities( key.capability as Record, @@ -86,9 +112,19 @@ export default class KeysGetCommand extends ControlBaseCommand { this.log(line); } - this.log(`Created: ${this.formatDate(key.created)}`); - this.log(`Updated: ${this.formatDate(key.modified)}`); - this.log(`Full key: ${key.key}`); + this.log(`${formatLabel("Created")} ${this.formatDate(key.created)}`); + this.log(`${formatLabel("Updated")} ${this.formatDate(key.modified)}`); + this.log(`${formatLabel("Full key")} ${key.key}`); + + if (hasEnvOverride) { + this.logToStderr(""); + this.logToStderr( + formatWarning( + `ABLY_API_KEY environment variable is set to a different key (${envKeyPrefix}). ` + + `The env var overrides this key for product API commands.`, + ), + ); + } } } catch (error) { this.fail(error, flags, "keyGet", { appId, keyIdentifier }); diff --git a/test/unit/commands/auth/keys/get.test.ts b/test/unit/commands/auth/keys/get.test.ts index acb0f98d..841a9fa9 100644 --- a/test/unit/commands/auth/keys/get.test.ts +++ b/test/unit/commands/auth/keys/get.test.ts @@ -18,13 +18,21 @@ import { describe("auth:keys:get command", () => { const mockKeyId = "testkey"; + let savedAblyApiKey: string | undefined; beforeEach(() => { controlApiCleanup(); + savedAblyApiKey = process.env.ABLY_API_KEY; + delete process.env.ABLY_API_KEY; }); afterEach(() => { controlApiCleanup(); + if (savedAblyApiKey === undefined) { + delete process.env.ABLY_API_KEY; + } else { + process.env.ABLY_API_KEY = savedAblyApiKey; + } }); describe("functionality", () => { @@ -116,6 +124,93 @@ describe("auth:keys:get command", () => { expect(result).toHaveProperty("key"); expect(result.key).toHaveProperty("id", mockKeyId); }); + + it("should show warning when fetched key is current and ABLY_API_KEY env var overrides it", async () => { + const mockConfig = getMockConfigManager(); + const appId = mockConfig.getCurrentAppId()!; + const currentKeyId = mockConfig.getKeyId(appId)!; + // Build a mock key whose appId.id matches the current key + const keyIdPart = currentKeyId.includes(".") + ? currentKeyId.split(".")[1] + : currentKeyId; + mockKeysList(appId, [buildMockKey(appId, keyIdPart)]); + + // Set env var to a different key + process.env.ABLY_API_KEY = `${appId}.differentkey:secret`; + + const { stderr } = await runCommand( + ["auth:keys:get", `${appId}.${keyIdPart}`], + import.meta.url, + ); + + expect(stderr).toContain( + "ABLY_API_KEY environment variable is set to a different key", + ); + expect(stderr).toContain(`${appId}.differentkey`); + }); + + it("should not show warning when fetched key is not the current key", async () => { + const mockConfig = getMockConfigManager(); + const appId = mockConfig.getCurrentAppId()!; + mockKeysList(appId, [ + buildMockKey(appId, mockKeyId), + buildMockKey(appId, "otherkey", { name: "Other" }), + ]); + + // Set env var to a different key — but we're fetching a non-current key + process.env.ABLY_API_KEY = `${appId}.differentkey:secret`; + + const { stderr } = await runCommand( + ["auth:keys:get", mockKeyId, "--app", appId], + import.meta.url, + ); + + expect(stderr).not.toContain("ABLY_API_KEY environment variable"); + }); + + it("should not show warning when ABLY_API_KEY matches the fetched key", async () => { + const mockConfig = getMockConfigManager(); + const appId = mockConfig.getCurrentAppId()!; + const currentKeyId = mockConfig.getKeyId(appId)!; + const keyIdPart = currentKeyId.includes(".") + ? currentKeyId.split(".")[1] + : currentKeyId; + mockKeysList(appId, [buildMockKey(appId, keyIdPart)]); + + // Set env var to same key + process.env.ABLY_API_KEY = `${appId}.${keyIdPart}:secret`; + + const { stdout } = await runCommand( + ["auth:keys:get", `${appId}.${keyIdPart}`], + import.meta.url, + ); + + expect(stdout).not.toContain("ABLY_API_KEY environment variable"); + }); + + it("should include envKeyOverride in JSON when condition is met", async () => { + const mockConfig = getMockConfigManager(); + const appId = mockConfig.getCurrentAppId()!; + const currentKeyId = mockConfig.getKeyId(appId)!; + const keyIdPart = currentKeyId.includes(".") + ? currentKeyId.split(".")[1] + : currentKeyId; + mockKeysList(appId, [buildMockKey(appId, keyIdPart)]); + + process.env.ABLY_API_KEY = `${appId}.differentkey:secret`; + + const { stdout } = await runCommand( + ["auth:keys:get", `${appId}.${keyIdPart}`, "--json"], + import.meta.url, + ); + + const result = JSON.parse(stdout); + expect(result).toHaveProperty("envKeyOverride"); + expect(result.envKeyOverride).toHaveProperty( + "keyName", + `${appId}.differentkey`, + ); + }); }); standardHelpTests("auth:keys:get", import.meta.url);