Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
66 changes: 51 additions & 15 deletions src/commands/auth/keys/get.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -51,44 +58,73 @@ 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<string, string[] | string>,
)) {
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 });
Expand Down
95 changes: 95 additions & 0 deletions test/unit/commands/auth/keys/get.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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);
Expand Down
Loading