firebase-tools 11.8.0 → 11.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/auth.js CHANGED
@@ -23,7 +23,7 @@ const uuid_1 = require("uuid");
23
23
  const crypto_1 = require("crypto");
24
24
  const track_1 = require("./track");
25
25
  const api_1 = require("./api");
26
- portfinder.basePort = 9005;
26
+ portfinder.setBasePort(9005);
27
27
  function getGlobalDefaultAccount() {
28
28
  const user = configstore_1.configstore.get("user");
29
29
  const tokens = configstore_1.configstore.get("tokens");
@@ -9,7 +9,6 @@ const previews_1 = require("../../previews");
9
9
  const error_1 = require("../../error");
10
10
  const functional_1 = require("../../functional");
11
11
  const env_1 = require("../../functions/env");
12
- const logger_1 = require("../../logger");
13
12
  function empty() {
14
13
  return {
15
14
  requiredAPIs: [],
@@ -61,39 +60,58 @@ exports.AllIngressSettings = [
61
60
  "ALLOW_INTERNAL_AND_GCLB",
62
61
  ];
63
62
  async function resolveBackend(build, userEnvOpt, userEnvs, nonInteractive) {
64
- var _a;
65
63
  const projectId = userEnvOpt.projectId;
66
64
  let paramValues = {};
67
65
  if (previews_1.previews.functionsparams) {
68
- paramValues = await params.resolveParams(build.params, projectId, envWithTypes(userEnvs), nonInteractive);
66
+ paramValues = await params.resolveParams(build.params, projectId, envWithTypes(build.params, userEnvs), nonInteractive);
69
67
  const toWrite = {};
70
68
  for (const paramName of Object.keys(paramValues)) {
71
- if (userEnvs.hasOwnProperty(paramName)) {
69
+ const paramValue = paramValues[paramName];
70
+ if (Object.prototype.hasOwnProperty.call(userEnvs, paramName) || paramValue.secret) {
72
71
  continue;
73
72
  }
74
- toWrite[paramName] = ((_a = paramValues[paramName]) === null || _a === void 0 ? void 0 : _a.toString()) || "";
73
+ toWrite[paramName] = paramValue.toString();
75
74
  }
76
75
  (0, env_1.writeUserEnvs)(toWrite, userEnvOpt);
77
76
  }
78
- return toBackend(build, paramValues);
77
+ return { backend: toBackend(build, paramValues), envs: paramValues };
79
78
  }
80
79
  exports.resolveBackend = resolveBackend;
81
- function envWithTypes(rawEnvs) {
80
+ function envWithTypes(definedParams, rawEnvs) {
82
81
  const out = {};
83
82
  for (const envName of Object.keys(rawEnvs)) {
84
83
  const value = rawEnvs[envName];
85
- if (!isNaN(+value) && isFinite(+value) && !value.includes("e")) {
86
- out[envName] = +value;
87
- }
88
- else if (value === "true") {
89
- out[envName] = true;
90
- }
91
- else if (value === "false") {
92
- out[envName] = false;
93
- }
94
- else {
95
- out[envName] = value;
84
+ let providedType = {
85
+ string: true,
86
+ boolean: true,
87
+ number: true,
88
+ };
89
+ for (const param of definedParams) {
90
+ if (param.name === envName) {
91
+ if (param.type === "string") {
92
+ providedType = {
93
+ string: true,
94
+ boolean: false,
95
+ number: false,
96
+ };
97
+ }
98
+ else if (param.type === "int") {
99
+ providedType = {
100
+ string: false,
101
+ boolean: false,
102
+ number: true,
103
+ };
104
+ }
105
+ else if (param.type === "boolean") {
106
+ providedType = {
107
+ string: false,
108
+ boolean: true,
109
+ number: false,
110
+ };
111
+ }
112
+ }
96
113
  }
114
+ out[envName] = new params.ParamValue(value, false, providedType);
97
115
  }
98
116
  return out;
99
117
  }
@@ -152,10 +170,6 @@ function toBackend(build, paramValues) {
152
170
  if (typeof bdEndpoint.platform === "undefined") {
153
171
  throw new error_1.FirebaseError("platform can't be undefined");
154
172
  }
155
- if (bdEndpoint.availableMemoryMb != null &&
156
- !backend.isValidMemoryOption(bdEndpoint.availableMemoryMb)) {
157
- throw new error_1.FirebaseError("available memory must be a supported value, if present");
158
- }
159
173
  const bkEndpoint = Object.assign({ id: endpointId, project: bdEndpoint.project, region: region, entryPoint: bdEndpoint.entryPoint, platform: bdEndpoint.platform, runtime: bdEndpoint.runtime }, trigger);
160
174
  proto.copyIfPresent(bkEndpoint, bdEndpoint, "environmentVariables", "labels", "secretEnvironmentVariables", "serviceAccount");
161
175
  proto.convertIfPresent(bkEndpoint, bdEndpoint, "ingressSettings", (from) => {
@@ -167,9 +181,9 @@ function toBackend(build, paramValues) {
167
181
  proto.convertIfPresent(bkEndpoint, bdEndpoint, "availableMemoryMb", (from) => {
168
182
  const mem = r.resolveInt(from);
169
183
  if (mem !== null && !backend.isValidMemoryOption(mem)) {
170
- logger_1.logger.debug("Warning; setting memory to unexpected value", mem);
184
+ throw new error_1.FirebaseError(`Function memory (${mem}) must resolve to a supported value, if present: ${JSON.stringify(allMemoryOptions)}`);
171
185
  }
172
- return mem;
186
+ return mem || null;
173
187
  });
174
188
  r.resolveInts(bkEndpoint, bdEndpoint, "timeoutSeconds", "maxInstances", "minInstances", "concurrency");
175
189
  proto.convertIfPresent(bkEndpoint, bdEndpoint, "cpu", (0, functional_1.nullsafeVisitor)((cpu) => (cpu === "gcf_gen1" ? cpu : r.resolveInt(cpu))));
@@ -0,0 +1,29 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.applyBackendHashToBackends = void 0;
4
+ const backend_1 = require("../backend");
5
+ const hash_1 = require("./hash");
6
+ const functionsDeployHelper_1 = require("../functionsDeployHelper");
7
+ function applyBackendHashToBackends(wantBackends, context) {
8
+ var _a;
9
+ for (const [codebase, wantBackend] of Object.entries(wantBackends)) {
10
+ if ((0, functionsDeployHelper_1.isCodebaseFiltered)(codebase, context.filters || [])) {
11
+ continue;
12
+ }
13
+ const source = (_a = context === null || context === void 0 ? void 0 : context.sources) === null || _a === void 0 ? void 0 : _a[codebase];
14
+ const envHash = (0, hash_1.getEnvironmentVariablesHash)(wantBackend);
15
+ applyBackendHashToEndpoints(wantBackend, envHash, context.filters || [], source === null || source === void 0 ? void 0 : source.functionsSourceV1Hash, source === null || source === void 0 ? void 0 : source.functionsSourceV2Hash);
16
+ }
17
+ }
18
+ exports.applyBackendHashToBackends = applyBackendHashToBackends;
19
+ function applyBackendHashToEndpoints(wantBackend, envHash, endpointFilters, sourceV1Hash, sourceV2Hash) {
20
+ for (const endpoint of (0, backend_1.allEndpoints)(wantBackend)) {
21
+ const secretsHash = (0, hash_1.getSecretsHash)(endpoint);
22
+ const isV2 = endpoint.platform === "gcfv2";
23
+ const sourceHash = isV2 ? sourceV2Hash : sourceV1Hash;
24
+ if ((0, functionsDeployHelper_1.isEndpointFiltered)(endpoint, endpointFilters)) {
25
+ continue;
26
+ }
27
+ endpoint.hash = (0, hash_1.getEndpointHash)(sourceHash, envHash, secretsHash);
28
+ }
29
+ }
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getEndpointHash = exports.getSecretsHash = exports.getSourceHash = exports.getEnvironmentVariablesHash = void 0;
4
+ const promises_1 = require("node:fs/promises");
5
+ const crypto = require("crypto");
6
+ const secrets_1 = require("../../../functions/secrets");
7
+ function getEnvironmentVariablesHash(backend) {
8
+ return createHash(JSON.stringify(backend.environmentVariables || {}));
9
+ }
10
+ exports.getEnvironmentVariablesHash = getEnvironmentVariablesHash;
11
+ async function getSourceHash(pathToFile) {
12
+ const data = await (0, promises_1.readFile)(pathToFile);
13
+ return createHash(data);
14
+ }
15
+ exports.getSourceHash = getSourceHash;
16
+ function getSecretsHash(endpoint) {
17
+ const secretVersions = (0, secrets_1.getSecretVersions)(endpoint);
18
+ return createHash(JSON.stringify(secretVersions || {}));
19
+ }
20
+ exports.getSecretsHash = getSecretsHash;
21
+ function getEndpointHash(sourceHash, envHash, secretsHash) {
22
+ const combined = [sourceHash, envHash, secretsHash].filter((hash) => !!hash).join("");
23
+ return createHash(combined);
24
+ }
25
+ exports.getEndpointHash = getEndpointHash;
26
+ function createHash(data, algorithm = "sha1") {
27
+ const hash = crypto.createHash(algorithm);
28
+ hash.update(data);
29
+ return hash.digest("hex");
30
+ }
@@ -0,0 +1,249 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveExpression = exports.ExprParseError = exports.isCelExpression = void 0;
4
+ const error_1 = require("../../error");
5
+ const functional_1 = require("../../functional");
6
+ const identityRegexp = /{{ params\.(\S+) }}/;
7
+ const dualEqualityRegexp = /{{ params\.(\S+) == params\.(\S+) }}/;
8
+ const equalityRegexp = /{{ params\.(\S+) == (.+) }}/;
9
+ const dualTernaryRegexp = /{{ params\.(\S+) == params\.(\S+) \? (.+) : (.+) }/;
10
+ const ternaryRegexp = /{{ params\.(\S+) == (.+) \? (.+) : (.+) }/;
11
+ const literalTernaryRegexp = /{{ params\.(\S+) \? (.+) : (.+) }/;
12
+ const paramRegexp = /params\.(\S+)/;
13
+ function isCelExpression(value) {
14
+ return typeof value === "string" && value.includes("{{") && value.includes("}}");
15
+ }
16
+ exports.isCelExpression = isCelExpression;
17
+ function isIdentityExpression(value) {
18
+ return identityRegexp.test(value);
19
+ }
20
+ function isEqualityExpression(value) {
21
+ return equalityRegexp.test(value);
22
+ }
23
+ function isDualEqualityExpression(value) {
24
+ return dualEqualityRegexp.test(value);
25
+ }
26
+ function isTernaryExpression(value) {
27
+ return ternaryRegexp.test(value);
28
+ }
29
+ function isLiteralTernaryExpression(value) {
30
+ return literalTernaryRegexp.test(value);
31
+ }
32
+ function isDualTernaryExpression(value) {
33
+ return dualTernaryRegexp.test(value);
34
+ }
35
+ class ExprParseError extends error_1.FirebaseError {
36
+ }
37
+ exports.ExprParseError = ExprParseError;
38
+ function resolveExpression(wantType, expr, params) {
39
+ if (isIdentityExpression(expr)) {
40
+ return resolveIdentity(wantType, expr, params);
41
+ }
42
+ else if (isDualTernaryExpression(expr)) {
43
+ return resolveDualTernary(wantType, expr, params);
44
+ }
45
+ else if (isLiteralTernaryExpression(expr)) {
46
+ return resolveLiteralTernary(wantType, expr, params);
47
+ }
48
+ else if (isTernaryExpression(expr)) {
49
+ return resolveTernary(wantType, expr, params);
50
+ }
51
+ else if (isDualEqualityExpression(expr)) {
52
+ return resolveDualEquality(expr, params);
53
+ }
54
+ else if (isEqualityExpression(expr)) {
55
+ return resolveEquality(expr, params);
56
+ }
57
+ else {
58
+ throw new ExprParseError("CEL expression '" + expr + "' is of an unsupported form");
59
+ }
60
+ }
61
+ exports.resolveExpression = resolveExpression;
62
+ function assertType(wantType, paramName, paramValue) {
63
+ if ((wantType === "string" && !paramValue.legalString) ||
64
+ (wantType === "number" && !paramValue.legalNumber) ||
65
+ (wantType === "boolean" && !paramValue.legalBoolean)) {
66
+ throw new ExprParseError(`Illegal type coercion of param ${paramName} to type ${wantType}`);
67
+ }
68
+ }
69
+ function readParamValue(wantType, paramName, paramValue) {
70
+ assertType(wantType, paramName, paramValue);
71
+ if (wantType === "string") {
72
+ return paramValue.asString();
73
+ }
74
+ else if (wantType === "number") {
75
+ return paramValue.asNumber();
76
+ }
77
+ else if (wantType === "boolean") {
78
+ return paramValue.asBoolean();
79
+ }
80
+ else {
81
+ (0, functional_1.assertExhaustive)(wantType);
82
+ }
83
+ }
84
+ function resolveIdentity(wantType, expr, params) {
85
+ const match = identityRegexp.exec(expr);
86
+ if (!match) {
87
+ throw new ExprParseError("Malformed CEL identity expression '" + expr + "'");
88
+ }
89
+ const name = match[1];
90
+ const value = params[name];
91
+ if (!value) {
92
+ throw new ExprParseError("CEL identity expression '" + expr + "' was not resolvable to a param");
93
+ }
94
+ return readParamValue(wantType, name, value);
95
+ }
96
+ function resolveEquality(expr, params) {
97
+ const match = equalityRegexp.exec(expr);
98
+ if (!match) {
99
+ throw new ExprParseError("Malformed CEL equality expression '" + expr + "'");
100
+ }
101
+ const lhsName = match[1];
102
+ const lhsVal = params[lhsName];
103
+ if (!lhsVal) {
104
+ throw new ExprParseError("CEL equality expression '" + expr + "' references missing param " + lhsName);
105
+ }
106
+ let rhs;
107
+ if (lhsVal.legalString) {
108
+ rhs = resolveLiteral("string", match[2]);
109
+ return lhsVal.asString() === rhs;
110
+ }
111
+ else if (lhsVal.legalNumber) {
112
+ rhs = resolveLiteral("number", match[2]);
113
+ return lhsVal.asNumber() === rhs;
114
+ }
115
+ else if (lhsVal.legalBoolean) {
116
+ rhs = resolveLiteral("boolean", match[2]);
117
+ return lhsVal.asBoolean() === rhs;
118
+ }
119
+ else {
120
+ throw new ExprParseError(`Could not infer type of param ${lhsName} used in equality operation`);
121
+ }
122
+ }
123
+ function resolveDualEquality(expr, params) {
124
+ const match = dualEqualityRegexp.exec(expr);
125
+ if (!match) {
126
+ throw new ExprParseError("Malformed CEL equality expression '" + expr + "'");
127
+ }
128
+ const lhsName = match[1];
129
+ const lhsVal = params[lhsName];
130
+ if (!lhsVal) {
131
+ throw new ExprParseError("CEL equality expression '" + expr + "' references missing param " + lhsName);
132
+ }
133
+ const rhsName = match[2];
134
+ const rhsVal = params[rhsName];
135
+ if (!rhsVal) {
136
+ throw new ExprParseError("CEL equality expression '" + expr + "' references missing param " + lhsName);
137
+ }
138
+ if (lhsVal.legalString) {
139
+ if (!rhsVal.legalString) {
140
+ throw new ExprParseError(`CEL equality expression ${expr} has type mismatch between the operands`);
141
+ }
142
+ return lhsVal.asString() === rhsVal.asString();
143
+ }
144
+ else if (lhsVal.legalNumber) {
145
+ if (!rhsVal.legalNumber) {
146
+ throw new ExprParseError(`CEL equality expression ${expr} has type mismatch between the operands`);
147
+ }
148
+ return lhsVal.asNumber() === rhsVal.asNumber();
149
+ }
150
+ else if (lhsVal.legalBoolean) {
151
+ if (!rhsVal.legalBoolean) {
152
+ throw new ExprParseError(`CEL equality expression ${expr} has type mismatch between the operands`);
153
+ }
154
+ return lhsVal.asBoolean() === rhsVal.asBoolean();
155
+ }
156
+ else {
157
+ throw new ExprParseError(`could not infer type of param ${lhsName} used in equality operation`);
158
+ }
159
+ }
160
+ function resolveTernary(wantType, expr, params) {
161
+ const match = ternaryRegexp.exec(expr);
162
+ if (!match) {
163
+ throw new ExprParseError("malformed CEL ternary expression '" + expr + "'");
164
+ }
165
+ const equalityExpr = `{{ params.${match[1]} == ${match[2]} }}`;
166
+ const isTrue = resolveEquality(equalityExpr, params);
167
+ if (isTrue) {
168
+ return resolveParamOrLiteral(wantType, match[3], params);
169
+ }
170
+ else {
171
+ return resolveParamOrLiteral(wantType, match[4], params);
172
+ }
173
+ }
174
+ function resolveDualTernary(wantType, expr, params) {
175
+ const match = dualTernaryRegexp.exec(expr);
176
+ if (!match) {
177
+ throw new ExprParseError("Malformed CEL ternary expression '" + expr + "'");
178
+ }
179
+ const equalityExpr = `{{ params.${match[1]} == params.${match[2]} }}`;
180
+ const isTrue = resolveDualEquality(equalityExpr, params);
181
+ if (isTrue) {
182
+ return resolveParamOrLiteral(wantType, match[3], params);
183
+ }
184
+ else {
185
+ return resolveParamOrLiteral(wantType, match[4], params);
186
+ }
187
+ }
188
+ function resolveLiteralTernary(wantType, expr, params) {
189
+ const match = literalTernaryRegexp.exec(expr);
190
+ if (!match) {
191
+ throw new ExprParseError("Malformed CEL ternary expression '" + expr + "'");
192
+ }
193
+ const paramName = match[1];
194
+ const paramValue = params[match[1]];
195
+ if (!paramValue) {
196
+ throw new ExprParseError("CEL ternary expression '" + expr + "' references missing param " + paramName);
197
+ }
198
+ if (!paramValue.legalBoolean) {
199
+ throw new ExprParseError("CEL ternary expression '" + expr + "' is conditional on non-boolean param " + paramName);
200
+ }
201
+ if (paramValue.asBoolean()) {
202
+ return resolveParamOrLiteral(wantType, match[2], params);
203
+ }
204
+ else {
205
+ return resolveParamOrLiteral(wantType, match[3], params);
206
+ }
207
+ }
208
+ function resolveParamOrLiteral(wantType, field, params) {
209
+ const match = paramRegexp.exec(field);
210
+ if (!match) {
211
+ return resolveLiteral(wantType, field);
212
+ }
213
+ const paramValue = params[match[1]];
214
+ if (!paramValue) {
215
+ throw new ExprParseError("CEL expression resolved to the value of a missing param " + match[1]);
216
+ }
217
+ return readParamValue(wantType, match[1], paramValue);
218
+ }
219
+ function resolveLiteral(wantType, value) {
220
+ if (paramRegexp.exec(value)) {
221
+ throw new ExprParseError("CEL tried to evaluate param." + value + " in a context which only permits literal values");
222
+ }
223
+ if (wantType === "number") {
224
+ if (isNaN(+value)) {
225
+ throw new ExprParseError("CEL literal " + value + " does not seem to be a number");
226
+ }
227
+ return +value;
228
+ }
229
+ else if (wantType === "string") {
230
+ if (!value.startsWith('"') || !value.endsWith('"')) {
231
+ throw new ExprParseError("CEL literal " + value + ' does not seem to be a "-delimited string');
232
+ }
233
+ return value.slice(1, -1);
234
+ }
235
+ else if (wantType === "boolean") {
236
+ if (value === "true") {
237
+ return true;
238
+ }
239
+ else if (value === "false") {
240
+ return false;
241
+ }
242
+ else {
243
+ throw new ExprParseError("CEL literal " + value + "does not seem to be a true/false boolean");
244
+ }
245
+ }
246
+ else {
247
+ throw new ExprParseError("CEL literal '" + value + "' somehow was resolved with a non-string/number/boolean type");
248
+ }
249
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.groupEndpointsByCodebase = exports.targetCodebases = exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
3
+ exports.isEndpointFiltered = exports.isCodebaseFiltered = exports.groupEndpointsByCodebase = exports.targetCodebases = exports.getFunctionLabel = exports.getEndpointFilters = exports.parseFunctionSelector = exports.endpointMatchesFilter = exports.endpointMatchesAnyFilter = void 0;
4
4
  const backend = require("./backend");
5
5
  const projectConfig_1 = require("../../functions/projectConfig");
6
6
  function endpointMatchesAnyFilter(endpoint, filters) {
@@ -114,3 +114,14 @@ function groupEndpointsByCodebase(wantBackends, haveEndpoints) {
114
114
  return grouped;
115
115
  }
116
116
  exports.groupEndpointsByCodebase = groupEndpointsByCodebase;
117
+ function isCodebaseFiltered(codebase, filters) {
118
+ return filters.some((filter) => {
119
+ const noIdChunks = (filter.idChunks || []).length === 0;
120
+ return noIdChunks && filter.codebase === codebase;
121
+ });
122
+ }
123
+ exports.isCodebaseFiltered = isCodebaseFiltered;
124
+ function isEndpointFiltered(endpoint, filters) {
125
+ return filters.some((filter) => endpointMatchesFilter(endpoint, filter));
126
+ }
127
+ exports.isEndpointFiltered = isEndpointFiltered;