Skip to content

Commit

Permalink
Add support for apphosting:secrets:describe, alias for functions:secr…
Browse files Browse the repository at this point in the history
…ets:get to align with gcloud (#6948)

* initial commit

* initial commit 2

* fix

* comments
  • Loading branch information
abhis3 authored Apr 2, 2024
1 parent ed46b01 commit dbb8573
Show file tree
Hide file tree
Showing 8 changed files with 81 additions and 19 deletions.
30 changes: 30 additions & 0 deletions src/commands/apphosting-secrets-describe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Command } from "../command";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";
import { logger } from "../logger";
import { requireAuth } from "../requireAuth";
import { listSecretVersions } from "../gcp/secretManager";
import * as secretManager from "../gcp/secretManager";
import { requirePermissions } from "../requirePermissions";

const Table = require("cli-table");

export const command = new Command("apphosting:secrets:describe <secretName>")
.description("Get metadata for secret and its versions.")
.before(requireAuth)
.before(secretManager.ensureApi)
.before(requirePermissions, ["secretmanager.secrets.get"])
.action(async (secretName: string, options: Options) => {
const projectId = needProjectId(options);
const versions = await listSecretVersions(projectId, secretName);

const table = new Table({
head: ["Name", "Version", "Status", "Create Time"],
style: { head: ["yellow"] },
});
for (const version of versions) {
table.push([secretName, version.versionId, version.state, version.createTime]);
}
logger.info(table.toString());
return { secrets: versions };
});
14 changes: 14 additions & 0 deletions src/commands/functions-secrets-describe.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { requireAuth } from "../requireAuth";
import { Command } from "../command";
import { requirePermissions } from "../requirePermissions";
import * as secretManager from "../gcp/secretManager";
import * as secrets from "../functions/secrets";

export const command = new Command("functions:secrets:describe <KEY>")
.description(
"Get metadata for secret and its versions. Alias for functions:secrets:get to align with gcloud",
)
.before(requireAuth)
.before(secretManager.ensureApi)
.before(requirePermissions, ["secretmanager.secrets.get"])
.action(secrets.describeSecret);
21 changes: 2 additions & 19 deletions src/commands/functions-secrets-get.ts
Original file line number Diff line number Diff line change
@@ -1,29 +1,12 @@
const Table = require("cli-table");

import { requireAuth } from "../requireAuth";
import { Command } from "../command";
import { logger } from "../logger";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";
import { listSecretVersions } from "../gcp/secretManager";
import { requirePermissions } from "../requirePermissions";
import * as secretManager from "../gcp/secretManager";
import * as secrets from "../functions/secrets";

export const command = new Command("functions:secrets:get <KEY>")
.description("Get metadata for secret and its versions")
.before(requireAuth)
.before(secretManager.ensureApi)
.before(requirePermissions, ["secretmanager.secrets.get"])
.action(async (key: string, options: Options) => {
const projectId = needProjectId(options);
const versions = await listSecretVersions(projectId, key);

const table = new Table({
head: ["Version", "State"],
style: { head: ["yellow"] },
});
for (const version of versions) {
table.push([version.versionId, version.state]);
}
logger.info(table.toString());
});
.action(secrets.describeSecret);
2 changes: 2 additions & 0 deletions src/commands/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ export function load(client: any): any {
client.functions.secrets.access = loadCommand("functions-secrets-access");
client.functions.secrets.destroy = loadCommand("functions-secrets-destroy");
client.functions.secrets.get = loadCommand("functions-secrets-get");
client.functions.secrets.describe = loadCommand("functions-secrets-describe");
client.functions.secrets.prune = loadCommand("functions-secrets-prune");
client.functions.secrets.set = loadCommand("functions-secrets-set");
client.help = loadCommand("help");
Expand Down Expand Up @@ -172,6 +173,7 @@ export function load(client: any): any {
client.apphosting.builds.create = loadCommand("apphosting-builds-create");
client.apphosting.secrets = {};
client.apphosting.secrets.grantaccess = loadCommand("apphosting-secrets-grantaccess");
client.apphosting.secrets.describe = loadCommand("apphosting-secrets-describe");
client.apphosting.rollouts = {};
client.apphosting.rollouts.create = loadCommand("apphosting-rollouts-create");
client.apphosting.rollouts.list = loadCommand("apphosting-rollouts-list");
Expand Down
21 changes: 21 additions & 0 deletions src/functions/secrets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ import { logger } from "../logger";
import { assertExhaustive } from "../functional";
import { isFunctionsManaged, FIREBASE_MANAGED } from "../gcp/secretManager";
import { labels } from "../gcp/secretManager";
import { needProjectId } from "../projectUtils";

const Table = require("cli-table");

// For mysterious reasons, importing the poller option in fabricator.ts leads to some
// value of the poller option to be undefined at runtime. I can't figure out what's going on,
Expand Down Expand Up @@ -371,3 +374,21 @@ export async function updateEndpointSecret(
assertExhaustive(endpoint.platform);
}
}

/**
* Describe the given secret.
*/
export async function describeSecret(key: string, options: Options): Promise<any> {
const projectId = needProjectId(options);
const versions = await listSecretVersions(projectId, key);

const table = new Table({
head: ["Version", "State"],
style: { head: ["yellow"] },
});
for (const version of versions) {
table.push([version.versionId, version.state]);
}
logger.info(table.toString());
return { secrets: versions };
}
6 changes: 6 additions & 0 deletions src/gcp/secretManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ export interface SecretVersion {

// Output-only fields
readonly state?: SecretVersionState;
readonly createTime?: string;
}

interface CreateSecretRequest {
Expand All @@ -72,6 +73,7 @@ interface AddVersionRequest {
interface SecretVersionResponse {
name: string;
state: SecretVersionState;
createTime: string;
}

interface AccessSecretVersionResponse {
Expand Down Expand Up @@ -178,6 +180,7 @@ export async function listSecretVersions(
secrets.push({
...parseSecretVersionResourceName(s.name),
state: s.state,
createTime: s.createTime,
});
}

Expand All @@ -203,6 +206,7 @@ export async function getSecretVersion(
return {
...parseSecretVersionResourceName(getRes.body.name),
state: getRes.body.state,
createTime: getRes.body.createTime,
};
}

Expand Down Expand Up @@ -282,6 +286,7 @@ export function parseSecretVersionResourceName(resourceName: string): SecretVers
replication: {},
},
versionId: match.groups.version,
createTime: "",
};
}

Expand Down Expand Up @@ -380,6 +385,7 @@ export async function addVersion(
return {
...parseSecretVersionResourceName(res.body.name),
state: res.body.state,
createTime: "",
};
}

Expand Down
5 changes: 5 additions & 0 deletions src/test/functions/secrets.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -235,10 +235,12 @@ describe("functions/secret", () => {
const secretVersion11: secretManager.SecretVersion = {
secret: secret1,
versionId: "1",
createTime: "2024-03-28T19:43:26",
};
const secretVersion12: secretManager.SecretVersion = {
secret: secret1,
versionId: "2",
createTime: "2024-03-28T19:43:26",
};

const secret2: secretManager.Secret = {
Expand All @@ -250,6 +252,7 @@ describe("functions/secret", () => {
const secretVersion21: secretManager.SecretVersion = {
secret: secret2,
versionId: "1",
createTime: "2024-03-28T19:43:26",
};

function toSecretEnvVar(sv: secretManager.SecretVersion): backend.SecretEnvVar {
Expand Down Expand Up @@ -391,6 +394,7 @@ describe("functions/secret", () => {
labels: {},
replication: {},
},
createTime: "2024-03-28T19:43:26",
};

it("returns true if secret version is in use", () => {
Expand Down Expand Up @@ -511,6 +515,7 @@ describe("functions/secret", () => {
replication: {},
},
versionId: "2",
createTime: "2024-03-28T19:43:26",
};

let gcfMock: sinon.SinonMock;
Expand Down
1 change: 1 addition & 0 deletions src/test/gcp/secretManager.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ describe("secretManager", () => {
).to.deep.equal({
secret: { projectId: "my-project", name: "my-secret", labels: {}, replication: {} },
versionId: "7",
createTime: "",
});
});

Expand Down

0 comments on commit dbb8573

Please sign in to comment.