Skip to content
Closed
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
3 changes: 0 additions & 3 deletions src/emulator/auth/operations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -349,10 +349,10 @@
const existingProviderAccounts = new Set<string>();
for (const userInfo of reqBody.users) {
for (const { providerId, rawId } of userInfo.providerUserInfo ?? []) {
const key = `${providerId}:${rawId}`;

Check warning on line 352 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression

Check warning on line 352 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression
assert(
!existingProviderAccounts.has(key),
`DUPLICATE_RAW_ID : Provider id(${providerId}), Raw id(${rawId})`,

Check warning on line 355 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression

Check warning on line 355 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Invalid type "string | undefined" of template literal expression
);
existingProviderAccounts.add(key);
}
Expand Down Expand Up @@ -497,7 +497,7 @@
);
}
state.overwriteUserWithLocalId(userInfo.localId, fields);
} catch (e: any) {

Check warning on line 500 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unexpected any. Specify a different type
if (e instanceof BadRequestError) {
// Use friendlier messages for some codes, consistent with production.
let message = e.message;
Expand Down Expand Up @@ -558,21 +558,21 @@
ctx: ExegesisContext,
): Schemas["GoogleCloudIdentitytoolkitV1DownloadAccountResponse"] {
assert(!state.disableAuth, "PROJECT_DISABLED");
const maxResults = Math.min(Math.floor(ctx.params.query.maxResults) || 20, 1000);

Check warning on line 561 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `number`
const queryTenantId = ctx.params.query.tenantId;

Check warning on line 562 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
let users: UserInfo[];

// Get the accounts from the tenant when tenantId is specified in the query.
if (queryTenantId && state instanceof AgentProjectState) {
const tenant = state.getTenantProject(queryTenantId);

Check warning on line 567 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe argument of type `any` assigned to a parameter of type `string`
users = tenant.queryUsers(
{},
{ sortByField: "localId", order: "ASC", startToken: ctx.params.query.nextPageToken },

Check warning on line 570 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
);
} else {
users = state.queryUsers(
{},
{ sortByField: "localId", order: "ASC", startToken: ctx.params.query.nextPageToken },

Check warning on line 575 in src/emulator/auth/operations.ts

View workflow job for this annotation

GitHub Actions / lint (20)

Unsafe assignment of an `any` value
);
}
let newPageToken: string | undefined = undefined;
Expand Down Expand Up @@ -1230,9 +1230,6 @@
}

if (reqBody.deleteProvider?.includes(PROVIDER_PASSWORD)) {
updates.email = undefined;
updates.emailVerified = undefined;
updates.emailLinkSignin = undefined;
updates.passwordHash = undefined;
updates.salt = undefined;
}
Expand Down
20 changes: 20 additions & 0 deletions src/emulator/auth/setAccountInfo.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1097,6 +1097,26 @@ describeAuthEmulator("accounts:update", ({ authApi, getClock }) => {
"google.com",
);

it("should retain email after deleting password provider", async () => {
const email = "alice@example.com";
const { idToken } = await registerUser(authApi(), { email, password: "notasecret" });

await authApi()
.post("/identitytoolkit.googleapis.com/v1/accounts:update")
.query({ key: "fake-api-key" })
.send({ idToken, deleteProvider: ["password"] })
.then((res) => expectStatusCode(200, res));

await authApi()
.post("/identitytoolkit.googleapis.com/v1/accounts:signUp")
.query({ key: "fake-api-key" })
.send({ email, password: "notasecret" })
.then((res) => {
expectStatusCode(400, res);
expect(res.body.error.message).to.equal("EMAIL_EXISTS");
});
});

it("should update user by localId when authenticated", async () => {
const { localId } = await registerUser(authApi(), {
email: "foo@example.com",
Expand Down
43 changes: 43 additions & 0 deletions src/functionsShellCommandAction.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect } from "chai";

import { initializeFunctionsShellContext } from "./functionsShellCommandAction";
import { EmulatedTriggerDefinition } from "./emulator/functionsEmulatorShared";
import { FunctionsEmulatorShell } from "./emulator/functionsEmulatorShell";

describe("initializeFunctionsShellContext", () => {
it("uses trigger.entryPoint for shell bindings", () => {
const hyphenatedTrigger: EmulatedTriggerDefinition = {
id: "us-central1-dummystore-bot",
region: "us-central1",
platform: "gcfv1",
name: "dummystore-bot",
entryPoint: "dummystore-bot",
httpsTrigger: {},
};
const groupedTrigger: EmulatedTriggerDefinition = {
id: "us-central1-grouped-fn",
region: "us-central1",
platform: "gcfv1",
name: "grouped-fn",
entryPoint: "grouped.fn",
httpsTrigger: {},
};

const emulator = {
triggers: [hyphenatedTrigger, groupedTrigger],
emulatedFunctions: [hyphenatedTrigger.id, groupedTrigger.id],
urls: {
[hyphenatedTrigger.id]: "http://127.0.0.1/hyphenated",
[groupedTrigger.id]: "http://127.0.0.1/grouped",
},
} as FunctionsEmulatorShell;

const context: Record<string, unknown> = {};
initializeFunctionsShellContext(context, emulator);

expect(context).to.have.property("dummystore-bot").that.is.a("function");
expect(context).to.not.have.nested.property("dummystore.bot");
expect(context).to.have.nested.property("grouped.fn").that.is.a("function");
expect(context).to.have.property("help").that.is.a("string");
});
});
32 changes: 17 additions & 15 deletions src/functionsShellCommandAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,21 @@ import { needProjectId } from "./projectUtils";

const serveFunctions = new FunctionsServer();

export const initializeFunctionsShellContext = (
context: Record<string, any>,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

According to the repository style guide (TypeScript section, line 38), any should not be used as an escape hatch. Since the context object is a dynamic key-value store where we only write values, we should use Record<string, unknown> instead of Record<string, any>. This is also consistent with the test file src/functionsShellCommandAction.spec.ts which already types the context as Record<string, unknown>.

Suggested change
context: Record<string, any>,
context: Record<string, unknown>,
References
  1. Never use any or unknown as an escape hatch. Define proper interfaces/types or use type guards. (link)

emulator: shell.FunctionsEmulatorShell,
) => {
for (const trigger of emulator.triggers) {
if (emulator.emulatedFunctions.includes(trigger.id)) {
const localFunction = new LocalFunction(trigger, emulator.urls, emulator);
_.set(context, trigger.entryPoint, localFunction.makeFn());
}
}
context.help =
"Instructions for the Functions Shell can be found at: " +
"https://firebase.google.com/docs/functions/local-emulator";
};

export const actionFunction = async (options: Options) => {
if (typeof options.port === "string") {
options.port = parseInt(options.port, 10);
Expand Down Expand Up @@ -95,19 +110,6 @@ export const actionFunction = async (options: Options) => {
process.exit();
}

const initializeContext = (context: any) => {
for (const trigger of emulator.triggers) {
if (emulator.emulatedFunctions.includes(trigger.id)) {
const localFunction = new LocalFunction(trigger, emulator.urls, emulator);
const triggerNameDotNotation = trigger.name.replace(/-/g, ".");
_.set(context, triggerNameDotNotation, localFunction.makeFn());
}
}
context.help =
"Instructions for the Functions Shell can be found at: " +
"https://firebase.google.com/docs/functions/local-emulator";
};

for (const e of runningEmulators) {
const info = remoteEmulators[e];
utils.logLabeledBullet(
Expand Down Expand Up @@ -138,8 +140,8 @@ export const actionFunction = async (options: Options) => {
writer: writer,
useColors: true,
});
initializeContext(replServer.context);
replServer.on("reset", initializeContext);
initializeFunctionsShellContext(replServer.context, emulator);
replServer.on("reset", (context) => initializeFunctionsShellContext(context, emulator));

return new Promise((resolve) => {
replServer.on("exit", () => {
Expand Down
50 changes: 50 additions & 0 deletions src/gcp/cloudfunctionsv2.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -925,6 +925,31 @@ describe("cloudfunctionsv2", () => {
await cloudfunctionsv2.createFunction(testFunction);
expect(scope.isDone()).to.be.true;
});

it("should preserve a hyphenated entry point in FUNCTION_TARGET", async () => {
const testFunction = {
...CLOUD_FUNCTION_V2,
buildConfig: {
...CLOUD_FUNCTION_V2.buildConfig,
entryPoint: "dummystore-bot",
environmentVariables: {},
},
};

const scope = nock(functionsV2Origin())
.post("/v2/projects/project/locations/region/functions", (body) => {
expect(body.serviceConfig.environmentVariables).to.have.property(
"FUNCTION_TARGET",
"dummystore-bot",
);
return true;
})
.query({ functionId: "id" })
.reply(200, { name: "operations/123", done: true });

await cloudfunctionsv2.createFunction(testFunction);
expect(scope.isDone()).to.be.true;
});
});

describe("updateFunction", () => {
Expand All @@ -951,5 +976,30 @@ describe("cloudfunctionsv2", () => {
await cloudfunctionsv2.updateFunction(CLOUD_FUNCTION_V2);
expect(scope.isDone()).to.be.true;
});

it("should preserve a hyphenated entry point in FUNCTION_TARGET", async () => {
const testFunction = {
...CLOUD_FUNCTION_V2,
buildConfig: {
...CLOUD_FUNCTION_V2.buildConfig,
entryPoint: "dummystore-bot",
environmentVariables: {},
},
};

const scope = nock(functionsV2Origin())
.patch("/v2/projects/project/locations/region/functions/id", (body) => {
expect(body.serviceConfig.environmentVariables).to.have.property(
"FUNCTION_TARGET",
"dummystore-bot",
);
return true;
})
.query(true)
.reply(200, { name: "operations/123", done: true });

await cloudfunctionsv2.updateFunction(testFunction);
expect(scope.isDone()).to.be.true;
});
});
});
4 changes: 2 additions & 2 deletions src/gcp/cloudfunctionsv2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ export async function createFunction(cloudFunction: InputCloudFunction): Promise

cloudFunction.serviceConfig.environmentVariables = {
...cloudFunction.serviceConfig.environmentVariables,
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint.replaceAll("-", "."),
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint,
// Enable logging execution id by default for better debugging
LOG_EXECUTION_ID: "true",
};
Expand Down Expand Up @@ -394,7 +394,7 @@ export async function updateFunction(cloudFunction: InputCloudFunction): Promise
};
cloudFunction.serviceConfig.environmentVariables = {
...cloudFunction.serviceConfig.environmentVariables,
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint.replaceAll("-", "."),
FUNCTION_TARGET: cloudFunction.buildConfig.entryPoint,
// Enable logging execution id by default for better debugging
LOG_EXECUTION_ID: "true",
};
Expand Down
Loading