Skip to content

Commit

Permalink
Move FAH files from init directory to common library as there is no i…
Browse files Browse the repository at this point in the history
…nit command (#6945)
  • Loading branch information
inlined authored Apr 2, 2024
1 parent db7dd17 commit ee68b28
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 271 deletions.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as clc from "colorette";

import * as devConnect from "../../../gcp/devConnect";
import * as rm from "../../../gcp/resourceManager";
import * as poller from "../../../operation-poller";
import * as utils from "../../../utils";
import { FirebaseError } from "../../../error";
import { promptOnce } from "../../../prompt";
import { getProjectNumber } from "../../../getProjectNumber";
import { developerConnectOrigin } from "../../../api";
import * as devConnect from "../gcp/devConnect";
import * as rm from "../gcp/resourceManager";
import * as poller from "../operation-poller";
import * as utils from "../utils";
import { FirebaseError } from "../error";
import { promptOnce } from "../prompt";
import { getProjectNumber } from "../getProjectNumber";
import { developerConnectOrigin } from "../api";

import * as fuzzy from "fuzzy";
import * as inquirer from "inquirer";
Expand Down
34 changes: 14 additions & 20 deletions src/init/features/apphosting/index.ts → src/apphosting/index.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,29 @@
import * as clc from "colorette";

import * as repo from "./repo";
import * as poller from "../../../operation-poller";
import * as apphosting from "../../../gcp/apphosting";
import * as poller from "../operation-poller";
import * as apphosting from "../gcp/apphosting";
import * as githubConnections from "./githubConnections";
import { logBullet, logSuccess, logWarning } from "../../../utils";
import { logBullet, logSuccess, logWarning } from "../utils";
import {
apphostingOrigin,
artifactRegistryDomain,
cloudRunApiOrigin,
cloudbuildOrigin,
developerConnectOrigin,
secretManagerOrigin,
} from "../../../api";
import {
Backend,
BackendOutputOnlyFields,
API_VERSION,
Build,
Rollout,
} from "../../../gcp/apphosting";
import { addServiceAccountToRoles } from "../../../gcp/resourceManager";
import * as iam from "../../../gcp/iam";
import { Repository } from "../../../gcp/cloudbuild";
import { FirebaseError } from "../../../error";
import { promptOnce } from "../../../prompt";
} from "../api";
import { Backend, BackendOutputOnlyFields, API_VERSION, Build, Rollout } from "../gcp/apphosting";
import { addServiceAccountToRoles } from "../gcp/resourceManager";
import * as iam from "../gcp/iam";
import { Repository } from "../gcp/cloudbuild";
import { FirebaseError } from "../error";
import { promptOnce } from "../prompt";
import { DEFAULT_REGION } from "./constants";
import { ensure } from "../../../ensureApiEnabled";
import * as deploymentTool from "../../../deploymentTool";
import { DeepOmit } from "../../../metaprogramming";
import { GitRepositoryLink } from "../../../gcp/devConnect";
import { ensure } from "../ensureApiEnabled";
import * as deploymentTool from "../deploymentTool";
import { DeepOmit } from "../metaprogramming";
import { GitRepositoryLink } from "../gcp/devConnect";

const DEFAULT_COMPUTE_SERVICE_ACCOUNT_NAME = "firebase-app-hosting-compute";

Expand Down
16 changes: 8 additions & 8 deletions src/init/features/apphosting/repo.ts → src/apphosting/repo.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as clc from "colorette";

import * as gcb from "../../../gcp/cloudbuild";
import * as rm from "../../../gcp/resourceManager";
import * as poller from "../../../operation-poller";
import * as utils from "../../../utils";
import { cloudbuildOrigin } from "../../../api";
import { FirebaseError } from "../../../error";
import { promptOnce } from "../../../prompt";
import { getProjectNumber } from "../../../getProjectNumber";
import * as gcb from "../gcp/cloudbuild";
import * as rm from "../gcp/resourceManager";
import * as poller from "../operation-poller";
import * as utils from "../utils";
import { cloudbuildOrigin } from "../api";
import { FirebaseError } from "../error";
import { promptOnce } from "../prompt";
import { getProjectNumber } from "../getProjectNumber";

import * as fuzzy from "fuzzy";
import * as inquirer from "inquirer";
Expand Down
89 changes: 89 additions & 0 deletions src/apphosting/secrets/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,99 @@
import { FirebaseError } from "../../error";
import * as iam from "../../gcp/iam";
import * as gcsm from "../../gcp/secretManager";
import * as gcb from "../../gcp/cloudbuild";
import * as gce from "../../gcp/computeEngine";
import { FIREBASE_MANAGED } from "../../gcp/secretManager";
import { isFunctionsManaged } from "../../gcp/secretManager";
import * as utils from "../../utils";
import * as prompt from "../../prompt";

function fetchServiceAccounts(projectNumber: string): {
buildServiceAccount: string;
runServiceAccount: string;
} {
// TODO: For now we will always return the default CBSA and CESA. When the getBackend call supports returning
// the attached service account in a given backend/location then return that value instead.
// Sample Call: await apphosting.getBackend(projectId, location, backendId); & make this function async
return {
buildServiceAccount: gcb.getDefaultServiceAccount(projectNumber),
runServiceAccount: gce.getDefaultServiceAccount(projectNumber),
};
}

/**
* Grants the corresponding service accounts the necessary access permissions to the provided secret.
*/
export async function grantSecretAccess(
secretName: string,
location: string,
backendId: string,
projectId: string,
projectNumber: string,
): Promise<void> {
const isExist = await gcsm.secretExists(projectId, secretName);
if (!isExist) {
throw new FirebaseError(`Secret ${secretName} does not exist in project ${projectId}`);
}

let serviceAccounts = { buildServiceAccount: "", runServiceAccount: "" };
try {
serviceAccounts = fetchServiceAccounts(projectNumber);
} catch (err: any) {
throw new FirebaseError(
`Failed to get backend ${backendId} at location ${location}. Please check the parameters you have provided.`,
{ original: err },
);
}

const secret = {
projectId: projectId,
name: secretName,
};

// TODO: Document why Cloud Build SA needs viewer permission but Run doesn't.
// TODO: future proof for when therte is a single service account (currently will set the same
// secretAccessor permission twice)
const newBindings: iam.Binding[] = [
{
role: "roles/secretmanager.secretAccessor",
members: [
`serviceAccount:${serviceAccounts.buildServiceAccount}`,
`serviceAccount:${serviceAccounts.runServiceAccount}`,
],
},
// Cloud Build needs the viewer role so that it can list secret versions and pin the Build to the
// latest version.
{
role: "roles/secretmanager.viewer",
members: [`serviceAccount:${serviceAccounts.buildServiceAccount}`],
},
];

let existingBindings;
try {
existingBindings = (await gcsm.getIamPolicy(secret)).bindings;
} catch (err: any) {
throw new FirebaseError(
`Failed to get IAM bindings on secret: ${secret.name}. Ensure you have the permissions to do so and try again.`,
{ original: err },
);
}

try {
// TODO: Merge with existing bindings with the same role
const updatedBindings = existingBindings.concat(newBindings);
await gcsm.setIamPolicy(secret, updatedBindings);
} catch (err: any) {
throw new FirebaseError(
`Failed to set IAM bindings ${JSON.stringify(newBindings)} on secret: ${secret.name}. Ensure you have the permissions to do so and try again.`,
{ original: err },
);
}

utils.logSuccess(`Successfully set IAM bindings on secret ${secret.name}.\n`);
}

/**
* Ensures a secret exists for use with app hosting, optionally locked to a region.
* If a secret exists, we verify the user is not trying to change the region and verifies a secret
Expand Down
2 changes: 1 addition & 1 deletion src/commands/apphosting-backends-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Command } from "../command";
import { Options } from "../options";
import { needProjectId } from "../projectUtils";
import requireInteractive from "../requireInteractive";
import { doSetup } from "../init/features/apphosting";
import { doSetup } from "../apphosting";
import { ensureApiEnabled } from "../gcp/apphosting";

export const command = new Command("apphosting:backends:create")
Expand Down
2 changes: 1 addition & 1 deletion src/commands/apphosting-backends-delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Options } from "../options";
import { needProjectId } from "../projectUtils";
import { FirebaseError } from "../error";
import { promptOnce } from "../prompt";
import { DEFAULT_REGION } from "../init/features/apphosting/constants";
import { DEFAULT_REGION } from "../apphosting/constants";
import * as utils from "../utils";
import * as apphosting from "../gcp/apphosting";
import { printBackendsTable } from "./apphosting-backends-list";
Expand Down
2 changes: 1 addition & 1 deletion src/commands/apphosting-secrets-grantaccess.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { requireAuth } from "../requireAuth";
import * as secretManager from "../gcp/secretManager";
import { requirePermissions } from "../requirePermissions";
import * as apphosting from "../gcp/apphosting";
import { grantSecretAccess } from "../init/features/apphosting/secrets";
import { grantSecretAccess } from "../apphosting/secrets";

export const command = new Command("apphosting:secrets:grantaccess <secretName>")
.description("grant service accounts permissions to the provided secret")
Expand Down
92 changes: 0 additions & 92 deletions src/init/features/apphosting/secrets.ts

This file was deleted.

2 changes: 1 addition & 1 deletion src/init/features/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ export { doSetup as extensions } from "./extensions";
export { doSetup as project } from "./project";
export { doSetup as remoteconfig } from "./remoteconfig";
export { initGitHub as hostingGithub } from "./hosting/github";
export { doSetup as apphosting } from "./apphosting";
export { doSetup as apphosting } from "../../apphosting";
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as sinon from "sinon";
import { expect } from "chai";
import * as prompt from "../../../prompt";
import * as poller from "../../../operation-poller";
import * as devconnect from "../../../gcp/devConnect";
import * as repo from "../../../init/features/apphosting/githubConnections";
import * as utils from "../../../utils";
import * as srcUtils from "../../../../src/getProjectNumber";
import * as rm from "../../../gcp/resourceManager";
import { FirebaseError } from "../../../error";
import * as prompt from "../../prompt";
import * as poller from "../../operation-poller";
import * as devconnect from "../../gcp/devConnect";
import * as repo from "../../apphosting/githubConnections";
import * as utils from "../../utils";
import * as srcUtils from "../../getProjectNumber";
import * as rm from "../../gcp/resourceManager";
import { FirebaseError } from "../../error";

const projectId = "projectId";
const location = "us-central1";
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
import * as sinon from "sinon";
import { expect } from "chai";

import * as apphosting from "../../../gcp/apphosting";
import * as iam from "../../../gcp/iam";
import * as resourceManager from "../../../gcp/resourceManager";
import * as poller from "../../../operation-poller";
import { createBackend, setDefaultTrafficPolicy } from "../../../init/features/apphosting/index";
import * as deploymentTool from "../../../deploymentTool";
import { FirebaseError } from "../../../error";
import * as apphosting from "../../gcp/apphosting";
import * as iam from "../../gcp/iam";
import * as resourceManager from "../../gcp/resourceManager";
import * as poller from "../../operation-poller";
import { createBackend, setDefaultTrafficPolicy } from "../../apphosting/index";
import * as deploymentTool from "../../deploymentTool";
import { FirebaseError } from "../../error";

describe("operationsConverter", () => {
const sandbox: sinon.SinonSandbox = sinon.createSandbox();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import * as sinon from "sinon";
import { expect } from "chai";

import * as gcb from "../../../gcp/cloudbuild";
import * as rm from "../../../gcp/resourceManager";
import * as prompt from "../../../prompt";
import * as poller from "../../../operation-poller";
import * as repo from "../../../init/features/apphosting/repo";
import * as utils from "../../../utils";
import * as srcUtils from "../../../../src/getProjectNumber";
import { FirebaseError } from "../../../error";
import * as gcb from "../../gcp/cloudbuild";
import * as rm from "../../gcp/resourceManager";
import * as prompt from "../../prompt";
import * as poller from "../../operation-poller";
import * as repo from "../../apphosting/repo";
import * as utils from "../../utils";
import * as srcUtils from "../../getProjectNumber";
import { FirebaseError } from "../../error";

const projectId = "projectId";
const location = "us-central1";
Expand Down
Loading

0 comments on commit ee68b28

Please sign in to comment.