Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Handle process.env.GCLOUD_PROJECT missing but process.env.PROJECT_ID present #1312

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
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.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 6 additions & 5 deletions src/common/config.ts
Expand Up @@ -3,6 +3,7 @@ import { readFileSync } from "fs";
import * as path from "path";

import * as logger from "../logger";
import { currentProjectId } from "./utilities/utils";

let cache: AppOptions | null = null;

Expand Down Expand Up @@ -36,15 +37,15 @@ export function firebaseConfig(): AppOptions | null {
return cache;
}

if (process.env.GCLOUD_PROJECT) {
const projectId = currentProjectId();
if (projectId) {
logger.warn(
"Warning, estimating Firebase Config based on GCLOUD_PROJECT. Initializing firebase-admin may fail"
);
cache = {
databaseURL:
process.env.DATABASE_URL || `https://${process.env.GCLOUD_PROJECT}.firebaseio.com`,
storageBucket: process.env.STORAGE_BUCKET_URL || `${process.env.GCLOUD_PROJECT}.appspot.com`,
projectId: process.env.GCLOUD_PROJECT,
databaseURL: process.env.DATABASE_URL || `https://${projectId}.firebaseio.com`,
storageBucket: process.env.STORAGE_BUCKET_URL || `${projectId}.appspot.com`,
projectId: projectId,
};
return cache;
} else {
Expand Down
9 changes: 6 additions & 3 deletions src/common/encoding.ts
Expand Up @@ -20,6 +20,8 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { currentProjectId } from "./utilities/utils";

// Copied from firebase-tools/src/gcp/proto

/**
Expand Down Expand Up @@ -76,12 +78,13 @@ export function serviceAccountFromShorthand(serviceAccount: string): string | nu
if (serviceAccount === "default") {
return null;
} else if (serviceAccount.endsWith("@")) {
if (!process.env.GCLOUD_PROJECT) {
const projectId = currentProjectId();
if (!projectId) {
throw new Error(
`Unable to determine email for service account '${serviceAccount}' because process.env.GCLOUD_PROJECT is not set.`
`Unable to determine email for service account '${serviceAccount}' (process.env.GCLOUD_PROJECT and process.env.GCP_PROJECT missing)`
);
}
return `${serviceAccount}${process.env.GCLOUD_PROJECT}.iam.gserviceaccount.com`;
return `${serviceAccount}${projectId}.iam.gserviceaccount.com`;
} else if (serviceAccount.includes("@")) {
return serviceAccount;
} else {
Expand Down
5 changes: 3 additions & 2 deletions src/common/providers/database.ts
Expand Up @@ -24,6 +24,7 @@ import { App } from "firebase-admin/app";
import * as database from "firebase-admin/database";
import { firebaseConfig } from "../../common/config";
import { joinPath, pathParts } from "../../common/utilities/path";
import { currentProjectId } from "../utilities/utils";

/**
* Interface representing a Firebase Realtime database data snapshot.
Expand Down Expand Up @@ -60,8 +61,8 @@ export class DataSnapshot implements database.DataSnapshot {
this.instance = app.options.databaseURL;
} else if (config.databaseURL) {
this.instance = config.databaseURL;
} else if (process.env.GCLOUD_PROJECT) {
this.instance = "https://" + process.env.GCLOUD_PROJECT + "-default-rtdb.firebaseio.com";
} else if (currentProjectId()) {
this.instance = "https://" + currentProjectId() + "-default-rtdb.firebaseio.com";
}

this._path = path;
Expand Down
3 changes: 2 additions & 1 deletion src/common/providers/identity.ts
Expand Up @@ -26,6 +26,7 @@ import * as logger from "../../logger";
import { EventContext } from "../../v1/cloud-functions";
import { getApp } from "../app";
import { isDebugFeatureEnabled } from "../debug";
import { currentProjectId } from "../utilities/utils";
import { HttpsError, unsafeDecodeToken } from "./https";

export { HttpsError };
Expand Down Expand Up @@ -784,7 +785,7 @@ export function getUpdateMask(authResponse?: BeforeCreateResponse | BeforeSignIn
export function wrapHandler(eventType: AuthBlockingEventType, handler: HandlerV1 | HandlerV2) {
return async (req: express.Request, res: express.Response): Promise<void> => {
try {
const projectId = process.env.GCLOUD_PROJECT;
const projectId = currentProjectId();
if (!isValidRequest(req)) {
logger.error("Invalid request, unable to process");
throw new HttpsError("invalid-argument", "Bad Request");
Expand Down
18 changes: 18 additions & 0 deletions src/common/utilities/utils.ts
Expand Up @@ -24,6 +24,24 @@ function isObject(obj: any): boolean {
return typeof obj === "object" && !!obj;
}

/**
* Retrieves the current GCL project ID from process.env.GCLOUD_PROJECT (which
* is guaranteed to be set during firebase deploy) or process.env.PROJECT_ID
* (which is guaranteed to be set by the Extensions backend). Use this instead
* of directly querying process.env if your code can be used in either context.
*
* @internal
*/
export function currentProjectId(assertPresence = false): string {
const projectId = process.env.GCLOUD_PROJECT || process.env.PROJECT_ID;
if (!projectId && assertPresence) {
throw new Error(
`Unable to determine current GCP project--neither process.env.GCLOUD_PROJECT nor process.env.GCP_PROJECT are set.`
);
}
return projectId;
}

/** @hidden */
export function applyChange(src: any, dest: any) {
// if not mergeable, don't merge
Expand Down
3 changes: 2 additions & 1 deletion src/logger/index.ts
Expand Up @@ -22,6 +22,7 @@

import { format } from "util";
import { traceContext } from "../common/trace";
import { currentProjectId } from "../common/utilities/utils";

import { CONSOLE_SEVERITY, UNPATCHED_CONSOLE } from "./common";

Expand Down Expand Up @@ -156,7 +157,7 @@ function entryFromArgs(severity: LogSeverity, args: any[]): LogEntry {
}
return {
"logging.googleapis.com/trace": ctx?.traceId
? `projects/${process.env.GCLOUD_PROJECT}/traces/${ctx.traceId}`
? `projects/${currentProjectId()}/traces/${ctx.traceId}`
: undefined,
...entry,
severity,
Expand Down
6 changes: 2 additions & 4 deletions src/v1/providers/analytics.ts
Expand Up @@ -20,6 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { currentProjectId } from "../../common/utilities/utils";
import { CloudFunction, Event, EventContext, makeCloudFunction } from "../cloud-functions";
import { DeploymentOptions } from "../function-configuration";

Expand All @@ -43,10 +44,7 @@ export function event(analyticsEventType: string) {
/** @internal */
export function _eventWithOptions(analyticsEventType: string, options: DeploymentOptions) {
return new AnalyticsEventBuilder(() => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
return "projects/" + process.env.GCLOUD_PROJECT + "/events/" + analyticsEventType;
return "projects/" + currentProjectId(true) + "/events/" + analyticsEventType;
}, options);
}

Expand Down
6 changes: 2 additions & 4 deletions src/v1/providers/auth.ts
Expand Up @@ -44,6 +44,7 @@ import {
} from "../cloud-functions";
import { DeploymentOptions } from "../function-configuration";
import { initV1Endpoint } from "../../runtime/manifest";
import { currentProjectId } from "../../common/utilities/utils";

// TODO: yank in next breaking change release
export { UserRecord, UserInfo, UserRecordMetadata, userRecordConstructor };
Expand Down Expand Up @@ -88,10 +89,7 @@ export function user(userOptions?: UserOptions): UserBuilder {
export function _userWithOptions(options: DeploymentOptions, userOptions: UserOptions) {
return new UserBuilder(
() => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
return "projects/" + process.env.GCLOUD_PROJECT;
return "projects/" + currentProjectId(true);
},
options,
userOptions
Expand Down
11 changes: 2 additions & 9 deletions src/v1/providers/firestore.ts
Expand Up @@ -27,6 +27,7 @@ import { getApp } from "../../common/app";
import { Change } from "../../common/change";
import { ParamsOf } from "../../common/params";
import { dateToTimestampProto } from "../../common/utilities/encoder";
import { currentProjectId } from "../../common/utilities/utils";
import * as logger from "../../logger";
import { CloudFunction, Event, EventContext, makeCloudFunction } from "../cloud-functions";
import { DeploymentOptions } from "../function-configuration";
Expand Down Expand Up @@ -101,15 +102,7 @@ export class NamespaceBuilder {

document<Path extends string>(path: Path) {
return new DocumentBuilder<Path>(() => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
const database = posix.join(
"projects",
process.env.GCLOUD_PROJECT,
"databases",
this.database
);
const database = posix.join("projects", currentProjectId(true), "databases", this.database);
return posix.join(
database,
this.namespace ? `documents@${this.namespace}` : "documents",
Expand Down
11 changes: 3 additions & 8 deletions src/v1/providers/pubsub.ts
Expand Up @@ -20,6 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { currentProjectId } from "../../common/utilities/utils";
import { CloudFunction, EventContext, makeCloudFunction } from "../cloud-functions";
import { DeploymentOptions, ScheduleRetryConfig } from "../function-configuration";

Expand All @@ -46,10 +47,7 @@ export function _topicWithOptions(topic: string, options: DeploymentOptions): To
}

return new TopicBuilder(() => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
return `projects/${process.env.GCLOUD_PROJECT}/topics/${topic}`;
return `projects/${currentProjectId(true)}/topics/${topic}`;
}, options);
}

Expand Down Expand Up @@ -101,11 +99,8 @@ export function _scheduleWithOptions(
options: DeploymentOptions
): ScheduleBuilder {
const triggerResource = () => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
// The CLI will append the correct topic name based on region and function name
return `projects/${process.env.GCLOUD_PROJECT}/topics`;
return `projects/${currentProjectId(true)}/topics`;
};
return new ScheduleBuilder(triggerResource, {
...options,
Expand Down
6 changes: 2 additions & 4 deletions src/v1/providers/remoteConfig.ts
Expand Up @@ -20,6 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { currentProjectId } from "../../common/utilities/utils";
import { CloudFunction, EventContext, makeCloudFunction } from "../cloud-functions";
import { DeploymentOptions } from "../function-configuration";

Expand Down Expand Up @@ -49,10 +50,7 @@ export function _onUpdateWithOptions(
options: DeploymentOptions
): CloudFunction<TemplateVersion> {
const triggerResource = () => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
return `projects/${process.env.GCLOUD_PROJECT}`;
return `projects/${currentProjectId(true)}`;
};
return new UpdateBuilder(triggerResource, options).onUpdate(handler);
}
Expand Down
6 changes: 2 additions & 4 deletions src/v1/providers/testLab.ts
Expand Up @@ -20,6 +20,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

import { currentProjectId } from "../../common/utilities/utils";
import { CloudFunction, Event, EventContext, makeCloudFunction } from "../cloud-functions";
import { DeploymentOptions } from "../function-configuration";

Expand All @@ -38,10 +39,7 @@ export function testMatrix() {
/** @internal */
export function _testMatrixWithOpts(opts: DeploymentOptions) {
return new TestMatrixBuilder(() => {
if (!process.env.GCLOUD_PROJECT) {
throw new Error("process.env.GCLOUD_PROJECT is not set.");
}
return "projects/" + process.env.GCLOUD_PROJECT + "/testMatrices/{matrix}";
return "projects/" + currentProjectId(true) + "/testMatrices/{matrix}";
}, opts);
}

Expand Down
3 changes: 2 additions & 1 deletion src/v2/providers/pubsub.ts
Expand Up @@ -33,6 +33,7 @@ import { wrapTraceContext } from "../trace";
import { Expression } from "../../params";
import * as options from "../options";
import { SecretParam } from "../../params/types";
import { currentProjectId } from "../../common/utilities/utils";

/**
* Google Cloud Pub/Sub is a globally distributed message bus that automatically scales as you need it.
Expand Down Expand Up @@ -323,7 +324,7 @@ export function onMessagePublished<T = any>(
},
eventTrigger: {
eventType: "google.cloud.pubsub.topic.v1.messagePublished",
resource: `projects/${process.env.GCLOUD_PROJECT}/topics/${topic}`,
resource: `projects/${currentProjectId()}/topics/${topic}`,
},
};
},
Expand Down