firebase-tools 13.6.0 → 13.6.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/apphosting/config.js +31 -0
- package/lib/apphosting/githubConnections.js +261 -0
- package/lib/{init/features/apphosting → apphosting}/index.js +21 -17
- package/lib/{init/features/apphosting → apphosting}/repo.js +9 -9
- package/lib/apphosting/secrets/dialogs.js +169 -0
- package/lib/apphosting/secrets/index.js +98 -0
- package/lib/commands/apphosting-backends-create.js +4 -2
- package/lib/commands/apphosting-backends-delete.js +1 -1
- package/lib/commands/apphosting-secrets-describe.js +29 -0
- package/lib/commands/apphosting-secrets-grantaccess.js +45 -0
- package/lib/commands/apphosting-secrets-set.js +102 -0
- package/lib/commands/functions-secrets-access.js +2 -2
- package/lib/commands/functions-secrets-describe.js +14 -0
- package/lib/commands/functions-secrets-destroy.js +2 -2
- package/lib/commands/functions-secrets-get.js +3 -17
- package/lib/commands/functions-secrets-prune.js +2 -1
- package/lib/commands/functions-secrets-set.js +2 -2
- package/lib/commands/index.js +5 -0
- package/lib/deploy/functions/checkIam.js +3 -6
- package/lib/deploy/functions/containerCleaner.js +1 -11
- package/lib/deploy/functions/params.js +2 -2
- package/lib/deploy/functions/prepare.js +12 -3
- package/lib/deploy/functions/release/fabricator.js +5 -5
- package/lib/deploy/functions/runtimes/index.js +6 -43
- package/lib/deploy/functions/runtimes/node/index.js +3 -2
- package/lib/deploy/functions/runtimes/node/parseRuntimeAndValidateSDK.js +15 -34
- package/lib/deploy/functions/runtimes/python/index.js +11 -7
- package/lib/deploy/functions/runtimes/supported.js +135 -0
- package/lib/emulator/controller.js +8 -1
- package/lib/emulator/functionsEmulator.js +2 -2
- package/lib/emulator/hub.js +5 -0
- package/lib/extensions/emulator/specHelper.js +4 -3
- package/lib/functional.js +2 -2
- package/lib/functions/secrets.js +40 -22
- package/lib/gcp/apphosting.js +15 -2
- package/lib/gcp/cloudbuild.js +7 -3
- package/lib/gcp/cloudfunctions.js +5 -5
- package/lib/gcp/cloudfunctionsv2.js +3 -3
- package/lib/gcp/cloudscheduler.js +2 -2
- package/lib/gcp/computeEngine.js +7 -0
- package/lib/gcp/devConnect.js +24 -11
- package/lib/gcp/iam.js +9 -1
- package/lib/gcp/secretManager.js +53 -13
- package/lib/gcp/serviceusage.js +21 -5
- package/lib/init/features/functions/python.js +4 -3
- package/lib/init/features/index.js +1 -1
- package/package.json +1 -1
- package/schema/firebase-config.json +12 -2
- /package/lib/{init/features/apphosting → apphosting}/constants.js +0 -0
|
@@ -1,31 +1,17 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getRuntimeChoice = exports.
|
|
3
|
+
exports.getRuntimeChoice = exports.RUNTIME_NOT_SET = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const clc = require("colorette");
|
|
6
5
|
const error_1 = require("../../../../error");
|
|
7
|
-
const
|
|
6
|
+
const supported = require("../supported");
|
|
8
7
|
const cjson = require("cjson");
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
14: "nodejs14",
|
|
15
|
-
16: "nodejs16",
|
|
16
|
-
18: "nodejs18",
|
|
17
|
-
20: "nodejs20",
|
|
18
|
-
};
|
|
19
|
-
const ENGINE_RUNTIMES_NAMES = Object.values(ENGINE_RUNTIMES);
|
|
20
|
-
exports.RUNTIME_NOT_SET = "`runtime` field is required but was not found in firebase.json.\n" +
|
|
8
|
+
const supportedNodeVersions = Object.keys(supported.RUNTIMES)
|
|
9
|
+
.filter((s) => supported.runtimeIsLanguage(s, "nodejs"))
|
|
10
|
+
.filter((s) => !supported.isDecommissioned(s))
|
|
11
|
+
.map((s) => s.substring("nodejs".length));
|
|
12
|
+
exports.RUNTIME_NOT_SET = "`runtime` field is required but was not found in firebase.json or package.json.\n" +
|
|
21
13
|
"To fix this, add the following lines to the `functions` section of your firebase.json:\n" +
|
|
22
|
-
|
|
23
|
-
exports.UNSUPPORTED_NODE_VERSION_FIREBASE_JSON_MSG = clc.bold(`functions.runtime value is unsupported. ` +
|
|
24
|
-
`Valid choices are: ${clc.bold("nodejs{10|12|14|16|18|20}")}.`);
|
|
25
|
-
exports.UNSUPPORTED_NODE_VERSION_PACKAGE_JSON_MSG = clc.bold(`package.json in functions directory has an engines field which is unsupported. ` +
|
|
26
|
-
`Valid choices are: ${clc.bold('{"node": 10|12|14|16|18|20}')}`);
|
|
27
|
-
exports.DEPRECATED_NODE_VERSION_INFO = `\n\nDeploys to runtimes below Node.js 10 are now disabled in the Firebase CLI. ` +
|
|
28
|
-
`${clc.bold(`Existing Node.js 8 functions ${clc.underline("will stop executing at a future date")}`)}. Update existing functions to Node.js 10 or greater as soon as possible.`;
|
|
14
|
+
`"runtime": "${supported.latest("nodejs")}" or set the "engine" field in package.json\n`;
|
|
29
15
|
function getRuntimeChoiceFromPackageJson(sourceDir) {
|
|
30
16
|
const packageJsonPath = path.join(sourceDir, "package.json");
|
|
31
17
|
let loaded;
|
|
@@ -39,19 +25,14 @@ function getRuntimeChoiceFromPackageJson(sourceDir) {
|
|
|
39
25
|
if (!engines || !engines.node) {
|
|
40
26
|
throw new error_1.FirebaseError(exports.RUNTIME_NOT_SET);
|
|
41
27
|
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const errorMessage = (runtimeFromConfig
|
|
47
|
-
? exports.UNSUPPORTED_NODE_VERSION_FIREBASE_JSON_MSG
|
|
48
|
-
: exports.UNSUPPORTED_NODE_VERSION_PACKAGE_JSON_MSG) + exports.DEPRECATED_NODE_VERSION_INFO;
|
|
49
|
-
if (!runtime || !ENGINE_RUNTIMES_NAMES.includes(runtime)) {
|
|
50
|
-
throw new error_1.FirebaseError(errorMessage, { exit: 1 });
|
|
51
|
-
}
|
|
52
|
-
if (runtimes.isDeprecatedRuntime(runtime) || !runtimes.isValidRuntime(runtime)) {
|
|
53
|
-
throw new error_1.FirebaseError(errorMessage, { exit: 1 });
|
|
28
|
+
const runtime = `nodejs${engines.node}`;
|
|
29
|
+
if (!supported.isRuntime(runtime)) {
|
|
30
|
+
throw new error_1.FirebaseError(`Detected node engine ${engines.node} in package.json, which is not a ` +
|
|
31
|
+
`supported version. Valid versions are ${supportedNodeVersions.join(", ")}`);
|
|
54
32
|
}
|
|
55
33
|
return runtime;
|
|
56
34
|
}
|
|
35
|
+
function getRuntimeChoice(sourceDir, runtimeFromConfig) {
|
|
36
|
+
return runtimeFromConfig || getRuntimeChoiceFromPackageJson(sourceDir);
|
|
37
|
+
}
|
|
57
38
|
exports.getRuntimeChoice = getRuntimeChoice;
|
|
@@ -1,27 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Delegate = exports.getPythonBinary = exports.tryCreateDelegate =
|
|
3
|
+
exports.Delegate = exports.getPythonBinary = exports.tryCreateDelegate = void 0;
|
|
4
4
|
const fs = require("fs");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const node_fetch_1 = require("node-fetch");
|
|
7
7
|
const util_1 = require("util");
|
|
8
8
|
const portfinder = require("portfinder");
|
|
9
|
-
const runtimes = require("..");
|
|
10
9
|
const discovery = require("../discovery");
|
|
10
|
+
const supported = require("../supported");
|
|
11
11
|
const logger_1 = require("../../../../logger");
|
|
12
12
|
const python_1 = require("../../../../functions/python");
|
|
13
13
|
const error_1 = require("../../../../error");
|
|
14
|
-
|
|
14
|
+
const functional_1 = require("../../../../functional");
|
|
15
15
|
async function tryCreateDelegate(context) {
|
|
16
|
+
var _a;
|
|
16
17
|
const requirementsTextPath = path.join(context.sourceDir, "requirements.txt");
|
|
17
18
|
if (!(await (0, util_1.promisify)(fs.exists)(requirementsTextPath))) {
|
|
18
19
|
logger_1.logger.debug("Customer code is not Python code.");
|
|
19
20
|
return;
|
|
20
21
|
}
|
|
21
|
-
const runtime = context.runtime ?
|
|
22
|
-
if (!
|
|
22
|
+
const runtime = (_a = context.runtime) !== null && _a !== void 0 ? _a : supported.latest("python");
|
|
23
|
+
if (!supported.isRuntime(runtime)) {
|
|
23
24
|
throw new error_1.FirebaseError(`Runtime ${runtime} is not a valid Python runtime`);
|
|
24
25
|
}
|
|
26
|
+
if (!supported.runtimeIsLanguage(runtime, "python")) {
|
|
27
|
+
throw new error_1.FirebaseError(`Internal error. Trying to construct a python runtime delegate for runtime ${runtime}`, { exit: 1 });
|
|
28
|
+
}
|
|
25
29
|
return Promise.resolve(new Delegate(context.projectId, context.sourceDir, runtime));
|
|
26
30
|
}
|
|
27
31
|
exports.tryCreateDelegate = tryCreateDelegate;
|
|
@@ -38,7 +42,7 @@ function getPythonBinary(runtime) {
|
|
|
38
42
|
else if (runtime === "python312") {
|
|
39
43
|
return "python3.12";
|
|
40
44
|
}
|
|
41
|
-
|
|
45
|
+
(0, functional_1.assertExhaustive)(runtime, `Unhandled python runtime ${runtime}`);
|
|
42
46
|
}
|
|
43
47
|
exports.getPythonBinary = getPythonBinary;
|
|
44
48
|
class Delegate {
|
|
@@ -46,7 +50,7 @@ class Delegate {
|
|
|
46
50
|
this.projectId = projectId;
|
|
47
51
|
this.sourceDir = sourceDir;
|
|
48
52
|
this.runtime = runtime;
|
|
49
|
-
this.
|
|
53
|
+
this.language = "python";
|
|
50
54
|
this._bin = "";
|
|
51
55
|
this._modulesDir = "";
|
|
52
56
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.guardVersionSupport = exports.isDecommissioned = exports.latest = exports.runtimeIsLanguage = exports.isRuntime = exports.RUNTIMES = void 0;
|
|
4
|
+
const error_1 = require("../../../error");
|
|
5
|
+
const utils = require("../../../utils");
|
|
6
|
+
function runtimes(r) {
|
|
7
|
+
return r;
|
|
8
|
+
}
|
|
9
|
+
exports.RUNTIMES = runtimes({
|
|
10
|
+
nodejs6: {
|
|
11
|
+
friendly: "Node.js 6",
|
|
12
|
+
status: "decommissioned",
|
|
13
|
+
deprecationDate: "2019-04-17",
|
|
14
|
+
decommissionDate: "2020-08-01",
|
|
15
|
+
},
|
|
16
|
+
nodejs8: {
|
|
17
|
+
friendly: "Node.js 8",
|
|
18
|
+
status: "decommissioned",
|
|
19
|
+
deprecationDate: "2020-06-05",
|
|
20
|
+
decommissionDate: "2021-02-01",
|
|
21
|
+
},
|
|
22
|
+
nodejs10: {
|
|
23
|
+
friendly: "Node.js 10",
|
|
24
|
+
status: "GA",
|
|
25
|
+
deprecationDate: "2024-01-30",
|
|
26
|
+
decommissionDate: "2025-01-30",
|
|
27
|
+
},
|
|
28
|
+
nodejs12: {
|
|
29
|
+
friendly: "Node.js 12",
|
|
30
|
+
status: "GA",
|
|
31
|
+
deprecationDate: "2024-01-30",
|
|
32
|
+
decommissionDate: "2025-01-30",
|
|
33
|
+
},
|
|
34
|
+
nodejs14: {
|
|
35
|
+
friendly: "Node.js 14",
|
|
36
|
+
status: "GA",
|
|
37
|
+
deprecationDate: "2024-01-30",
|
|
38
|
+
decommissionDate: "2025-01-30",
|
|
39
|
+
},
|
|
40
|
+
nodejs16: {
|
|
41
|
+
friendly: "Node.js 16",
|
|
42
|
+
status: "GA",
|
|
43
|
+
deprecationDate: "2024-01-30",
|
|
44
|
+
decommissionDate: "2025-01-30",
|
|
45
|
+
},
|
|
46
|
+
nodejs18: {
|
|
47
|
+
friendly: "Node.js 18",
|
|
48
|
+
status: "GA",
|
|
49
|
+
deprecationDate: "2025-04-30",
|
|
50
|
+
decommissionDate: "2025-10-31",
|
|
51
|
+
},
|
|
52
|
+
nodejs20: {
|
|
53
|
+
friendly: "Node.js 20",
|
|
54
|
+
status: "GA",
|
|
55
|
+
deprecationDate: "2026-04-30",
|
|
56
|
+
decommissionDate: "2026-10-31",
|
|
57
|
+
},
|
|
58
|
+
python310: {
|
|
59
|
+
friendly: "Python 3.10",
|
|
60
|
+
status: "GA",
|
|
61
|
+
deprecationDate: "2026-10-04",
|
|
62
|
+
decommissionDate: "2027-04-30",
|
|
63
|
+
},
|
|
64
|
+
python311: {
|
|
65
|
+
friendly: "Python 3.11",
|
|
66
|
+
status: "GA",
|
|
67
|
+
deprecationDate: "2027-10-24",
|
|
68
|
+
decommissionDate: "2028-04-30",
|
|
69
|
+
},
|
|
70
|
+
python312: {
|
|
71
|
+
friendly: "Python 3.12",
|
|
72
|
+
status: "GA",
|
|
73
|
+
deprecationDate: "2028-10-02",
|
|
74
|
+
decommissionDate: "2029-04-30",
|
|
75
|
+
},
|
|
76
|
+
});
|
|
77
|
+
function isRuntime(maybe) {
|
|
78
|
+
return maybe in exports.RUNTIMES;
|
|
79
|
+
}
|
|
80
|
+
exports.isRuntime = isRuntime;
|
|
81
|
+
function runtimeIsLanguage(runtime, language) {
|
|
82
|
+
return runtime.startsWith(language);
|
|
83
|
+
}
|
|
84
|
+
exports.runtimeIsLanguage = runtimeIsLanguage;
|
|
85
|
+
function latest(language, runtimes = Object.keys(exports.RUNTIMES)) {
|
|
86
|
+
const sorted = runtimes
|
|
87
|
+
.filter((s) => runtimeIsLanguage(s, language))
|
|
88
|
+
.sort((left, right) => {
|
|
89
|
+
const leftVersion = +left.substring(language.length);
|
|
90
|
+
const rightVersion = +right.substring(language.length);
|
|
91
|
+
if (isNaN(leftVersion) || isNaN(rightVersion)) {
|
|
92
|
+
throw new error_1.FirebaseError("Internal error. Runtime or language names are malformed", {
|
|
93
|
+
exit: 1,
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
return leftVersion - rightVersion;
|
|
97
|
+
});
|
|
98
|
+
const latest = utils.last(sorted);
|
|
99
|
+
if (!latest) {
|
|
100
|
+
throw new error_1.FirebaseError(`Internal error trying to find the latest supported runtime for ${language}`, { exit: 1 });
|
|
101
|
+
}
|
|
102
|
+
return latest;
|
|
103
|
+
}
|
|
104
|
+
exports.latest = latest;
|
|
105
|
+
function isDecommissioned(runtime, now = new Date()) {
|
|
106
|
+
const cutoff = new Date(exports.RUNTIMES[runtime].decommissionDate);
|
|
107
|
+
return cutoff < now;
|
|
108
|
+
}
|
|
109
|
+
exports.isDecommissioned = isDecommissioned;
|
|
110
|
+
function guardVersionSupport(runtime, now = new Date()) {
|
|
111
|
+
const { deprecationDate, decommissionDate } = exports.RUNTIMES[runtime];
|
|
112
|
+
const decommission = new Date(decommissionDate);
|
|
113
|
+
if (now >= decommission) {
|
|
114
|
+
throw new error_1.FirebaseError(`Runtime ${exports.RUNTIMES[runtime].friendly} was decommissioned on ${decommissionDate}. To deploy ` +
|
|
115
|
+
"you must first upgrade your runtime version.", { exit: 1 });
|
|
116
|
+
}
|
|
117
|
+
const deprecation = new Date(deprecationDate);
|
|
118
|
+
if (now >= deprecation) {
|
|
119
|
+
utils.logLabeledWarning("functions", `Runtime ${exports.RUNTIMES[runtime].friendly} was deprecated on ${deprecationDate} and will be ` +
|
|
120
|
+
`decommissioned on ${decommissionDate}, after which you will not be able ` +
|
|
121
|
+
"to deploy without upgrading. Consider upgrading now to avoid disruption. See " +
|
|
122
|
+
"https://cloud.google.com/functions/docs/runtime-support for full " +
|
|
123
|
+
"details on the lifecycle policy");
|
|
124
|
+
return;
|
|
125
|
+
}
|
|
126
|
+
const warning = new Date(deprecation.getTime() - 90 * 24 * 60 * 60 * 1000);
|
|
127
|
+
if (now >= warning) {
|
|
128
|
+
utils.logLabeledWarning("functions", `Runtime ${exports.RUNTIMES[runtime].friendly} will be deprecated on ${deprecationDate} and will be ` +
|
|
129
|
+
`decommissioned on ${decommissionDate}, after which you will not be able ` +
|
|
130
|
+
"to deploy without upgrading. Consider upgrading now to avoid disruption. See " +
|
|
131
|
+
"https://cloud.google.com/functions/docs/runtime-support for full " +
|
|
132
|
+
"details on the lifecycle policy");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
exports.guardVersionSupport = guardVersionSupport;
|
|
@@ -41,6 +41,7 @@ const downloadableEmulators_1 = require("./downloadableEmulators");
|
|
|
41
41
|
const frameworks_1 = require("../frameworks");
|
|
42
42
|
const experiments = require("../experiments");
|
|
43
43
|
const portUtils_1 = require("./portUtils");
|
|
44
|
+
const supported_1 = require("../deploy/functions/runtimes/supported");
|
|
44
45
|
const START_LOGGING_EMULATOR = utils.envOverride("START_LOGGING_EMULATOR", "false", (val) => val === "true");
|
|
45
46
|
async function exportOnExit(options) {
|
|
46
47
|
const exportOnExitDir = options.exportOnExit;
|
|
@@ -308,7 +309,13 @@ async function startAll(options, showUI = true, runningTestScript = false) {
|
|
|
308
309
|
utils.assertIsStringOrUndefined(options.extDevDir);
|
|
309
310
|
for (const cfg of functionsCfg) {
|
|
310
311
|
const functionsDir = path.join(projectDir, cfg.source);
|
|
311
|
-
|
|
312
|
+
let runtime = ((_e = options.extDevRuntime) !== null && _e !== void 0 ? _e : cfg.runtime);
|
|
313
|
+
if (!runtime) {
|
|
314
|
+
runtime = (0, supported_1.latest)("nodejs");
|
|
315
|
+
}
|
|
316
|
+
if (!(0, supported_1.isRuntime)(runtime)) {
|
|
317
|
+
throw new error_1.FirebaseError(`Cannot load functions from ${functionsDir} because it has invalid runtime ${runtime}`);
|
|
318
|
+
}
|
|
312
319
|
emulatableBackends.push({
|
|
313
320
|
functionsDir,
|
|
314
321
|
runtime,
|
|
@@ -297,9 +297,9 @@ class FunctionsEmulator {
|
|
|
297
297
|
runtime: emulatableBackend.runtime,
|
|
298
298
|
};
|
|
299
299
|
const runtimeDelegate = await runtimes.getRuntimeDelegate(runtimeDelegateContext);
|
|
300
|
-
logger_1.logger.debug(`Validating ${runtimeDelegate.
|
|
300
|
+
logger_1.logger.debug(`Validating ${runtimeDelegate.language} source`);
|
|
301
301
|
await runtimeDelegate.validate();
|
|
302
|
-
logger_1.logger.debug(`Building ${runtimeDelegate.
|
|
302
|
+
logger_1.logger.debug(`Building ${runtimeDelegate.language} source`);
|
|
303
303
|
await runtimeDelegate.build();
|
|
304
304
|
emulatableBackend.runtime = runtimeDelegate.runtime;
|
|
305
305
|
emulatableBackend.bin = runtimeDelegate.bin;
|
package/lib/emulator/hub.js
CHANGED
|
@@ -53,6 +53,11 @@ class EmulatorHub extends ExpressBasedEmulator_1.ExpressBasedEmulator {
|
|
|
53
53
|
res.json(body);
|
|
54
54
|
});
|
|
55
55
|
app.post(EmulatorHub.PATH_EXPORT, async (req, res) => {
|
|
56
|
+
if (req.headers.origin) {
|
|
57
|
+
res.status(403).json({
|
|
58
|
+
message: `Export cannot be triggered by external callers.`,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
56
61
|
const path = req.body.path;
|
|
57
62
|
const initiatedBy = req.body.initiatedBy || "unknown";
|
|
58
63
|
utils.logLabeledBullet("emulators", `Received export request. Exporting data to ${path}.`);
|
|
@@ -4,6 +4,7 @@ exports.getRuntime = exports.DEFAULT_RUNTIME = exports.getFunctionProperties = e
|
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
const fs = require("fs-extra");
|
|
7
|
+
const supported = require("../../deploy/functions/runtimes/supported");
|
|
7
8
|
const error_1 = require("../../error");
|
|
8
9
|
const extensionsHelper_1 = require("../extensionsHelper");
|
|
9
10
|
const utils_1 = require("../utils");
|
|
@@ -77,7 +78,7 @@ function getFunctionProperties(resources) {
|
|
|
77
78
|
return resources.map((r) => r.properties);
|
|
78
79
|
}
|
|
79
80
|
exports.getFunctionProperties = getFunctionProperties;
|
|
80
|
-
exports.DEFAULT_RUNTIME = "
|
|
81
|
+
exports.DEFAULT_RUNTIME = supported.latest("nodejs");
|
|
81
82
|
function getRuntime(resources) {
|
|
82
83
|
if (resources.length === 0) {
|
|
83
84
|
return exports.DEFAULT_RUNTIME;
|
|
@@ -88,7 +89,7 @@ function getRuntime(resources) {
|
|
|
88
89
|
if (!runtime) {
|
|
89
90
|
return exports.DEFAULT_RUNTIME;
|
|
90
91
|
}
|
|
91
|
-
if (
|
|
92
|
+
if (!supported.runtimeIsLanguage(runtime, "nodejs")) {
|
|
92
93
|
invalidRuntimes.push(runtime);
|
|
93
94
|
return exports.DEFAULT_RUNTIME;
|
|
94
95
|
}
|
|
@@ -97,6 +98,6 @@ function getRuntime(resources) {
|
|
|
97
98
|
if (invalidRuntimes.length) {
|
|
98
99
|
throw new error_1.FirebaseError(`The following runtimes are not supported by the Emulator Suite: ${invalidRuntimes.join(", ")}. \n Only Node runtimes are supported.`);
|
|
99
100
|
}
|
|
100
|
-
return
|
|
101
|
+
return supported.latest("nodejs", runtimes);
|
|
101
102
|
}
|
|
102
103
|
exports.getRuntime = getRuntime;
|
package/lib/functional.js
CHANGED
|
@@ -52,8 +52,8 @@ const zipIn = (other) => (elem, ndx) => {
|
|
|
52
52
|
return [elem, other[ndx]];
|
|
53
53
|
};
|
|
54
54
|
exports.zipIn = zipIn;
|
|
55
|
-
function assertExhaustive(val) {
|
|
56
|
-
throw new Error(`Never has a value (${val}).`);
|
|
55
|
+
function assertExhaustive(val, message) {
|
|
56
|
+
throw new Error(message || `Never has a value (${val}).`);
|
|
57
57
|
}
|
|
58
58
|
exports.assertExhaustive = assertExhaustive;
|
|
59
59
|
function partition(arr, predicate) {
|
package/lib/functions/secrets.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.updateEndpointSecret = exports.pruneAndDestroySecrets = exports.pruneSecrets = exports.versionInUse = exports.inUse = exports.getSecretVersions = exports.of = exports.ensureSecret = exports.ensureValidKey =
|
|
3
|
+
exports.describeSecret = exports.updateEndpointSecret = exports.pruneAndDestroySecrets = exports.pruneSecrets = exports.versionInUse = exports.inUse = exports.getSecretVersions = exports.of = exports.ensureSecret = exports.ensureValidKey = void 0;
|
|
4
4
|
const utils = require("../utils");
|
|
5
5
|
const poller = require("../operation-poller");
|
|
6
6
|
const gcfV1 = require("../gcp/cloudfunctions");
|
|
7
7
|
const gcfV2 = require("../gcp/cloudfunctionsv2");
|
|
8
|
-
const ensureApiEnabled = require("../ensureApiEnabled");
|
|
9
8
|
const api_1 = require("../api");
|
|
10
9
|
const secretManager_1 = require("../gcp/secretManager");
|
|
11
10
|
const error_1 = require("../error");
|
|
@@ -14,8 +13,10 @@ const prompt_1 = require("../prompt");
|
|
|
14
13
|
const env_1 = require("./env");
|
|
15
14
|
const logger_1 = require("../logger");
|
|
16
15
|
const functional_1 = require("../functional");
|
|
16
|
+
const secretManager_2 = require("../gcp/secretManager");
|
|
17
|
+
const secretManager_3 = require("../gcp/secretManager");
|
|
17
18
|
const projectUtils_1 = require("../projectUtils");
|
|
18
|
-
const
|
|
19
|
+
const Table = require("cli-table");
|
|
19
20
|
const gcfV1PollerOptions = {
|
|
20
21
|
apiOrigin: (0, api_1.functionsOrigin)(),
|
|
21
22
|
apiVersion: "v1",
|
|
@@ -28,25 +29,12 @@ const gcfV2PollerOptions = {
|
|
|
28
29
|
masterTimeout: 25 * 60 * 1000,
|
|
29
30
|
maxBackoff: 10000,
|
|
30
31
|
};
|
|
31
|
-
function isFirebaseManaged(secret) {
|
|
32
|
-
return Object.keys(secret.labels || []).includes(FIREBASE_MANAGED);
|
|
33
|
-
}
|
|
34
|
-
exports.isFirebaseManaged = isFirebaseManaged;
|
|
35
|
-
function labels() {
|
|
36
|
-
return { [FIREBASE_MANAGED]: "true" };
|
|
37
|
-
}
|
|
38
|
-
exports.labels = labels;
|
|
39
32
|
function toUpperSnakeCase(key) {
|
|
40
33
|
return key
|
|
41
34
|
.replace(/[.-]/g, "_")
|
|
42
35
|
.replace(/([a-z])([A-Z])/g, "$1_$2")
|
|
43
36
|
.toUpperCase();
|
|
44
37
|
}
|
|
45
|
-
function ensureApi(options) {
|
|
46
|
-
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
47
|
-
return ensureApiEnabled.ensure(projectId, (0, api_1.secretManagerOrigin)(), "secretmanager", true);
|
|
48
|
-
}
|
|
49
|
-
exports.ensureApi = ensureApi;
|
|
50
38
|
async function ensureValidKey(key, options) {
|
|
51
39
|
const transformedKey = toUpperSnakeCase(key);
|
|
52
40
|
if (transformedKey !== key) {
|
|
@@ -76,18 +64,34 @@ exports.ensureValidKey = ensureValidKey;
|
|
|
76
64
|
async function ensureSecret(projectId, name, options) {
|
|
77
65
|
try {
|
|
78
66
|
const secret = await (0, secretManager_1.getSecret)(projectId, name);
|
|
79
|
-
if (
|
|
67
|
+
if ((0, secretManager_1.isAppHostingManaged)(secret)) {
|
|
68
|
+
(0, utils_1.logWarning)("Your secret is managed by Firebase App Hosting. Continuing will disable automatic deletion of old versions.");
|
|
69
|
+
const stopTracking = await (0, prompt_1.promptOnce)({
|
|
70
|
+
name: "doNotTrack",
|
|
71
|
+
type: "confirm",
|
|
72
|
+
default: false,
|
|
73
|
+
message: "Do you wish to continue?",
|
|
74
|
+
}, options);
|
|
75
|
+
if (stopTracking) {
|
|
76
|
+
delete secret.labels[secretManager_2.FIREBASE_MANAGED];
|
|
77
|
+
await (0, secretManager_1.patchSecret)(secret.projectId, secret.name, secret.labels);
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
throw new Error("A secret cannot be managed by both Firebase App Hosting and Cloud Functions for Firebase");
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else if (!(0, secretManager_2.isFunctionsManaged)(secret)) {
|
|
80
84
|
if (!options.force) {
|
|
81
|
-
(0, utils_1.logWarning)("Your secret is not managed by Firebase. " +
|
|
85
|
+
(0, utils_1.logWarning)("Your secret is not managed by Cloud Functions for Firebase. " +
|
|
82
86
|
"Firebase managed secrets are automatically pruned to reduce your monthly cost for using Secret Manager. ");
|
|
83
87
|
const confirm = await (0, prompt_1.promptOnce)({
|
|
84
88
|
name: "updateLabels",
|
|
85
89
|
type: "confirm",
|
|
86
90
|
default: true,
|
|
87
|
-
message: `Would you like to have your secret ${secret.name} managed by Firebase?`,
|
|
91
|
+
message: `Would you like to have your secret ${secret.name} managed by Cloud Functions for Firebase?`,
|
|
88
92
|
}, options);
|
|
89
93
|
if (confirm) {
|
|
90
|
-
return (0, secretManager_1.patchSecret)(projectId, secret.name, Object.assign(Object.assign({}, secret.labels), labels()));
|
|
94
|
+
return (0, secretManager_1.patchSecret)(projectId, secret.name, Object.assign(Object.assign({}, secret.labels), (0, secretManager_3.labels)()));
|
|
91
95
|
}
|
|
92
96
|
}
|
|
93
97
|
}
|
|
@@ -98,7 +102,7 @@ async function ensureSecret(projectId, name, options) {
|
|
|
98
102
|
throw err;
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
|
-
return await (0, secretManager_1.createSecret)(projectId, name, labels());
|
|
105
|
+
return await (0, secretManager_1.createSecret)(projectId, name, (0, secretManager_3.labels)());
|
|
102
106
|
}
|
|
103
107
|
exports.ensureSecret = ensureSecret;
|
|
104
108
|
function of(endpoints) {
|
|
@@ -139,7 +143,7 @@ async function pruneSecrets(projectInfo, endpoints) {
|
|
|
139
143
|
const { projectId, projectNumber } = projectInfo;
|
|
140
144
|
const pruneKey = (name, version) => `${name}@${version}`;
|
|
141
145
|
const prunedSecrets = new Set();
|
|
142
|
-
const haveSecrets = await (0, secretManager_1.listSecrets)(projectId, `labels.${FIREBASE_MANAGED}=true`);
|
|
146
|
+
const haveSecrets = await (0, secretManager_1.listSecrets)(projectId, `labels.${secretManager_2.FIREBASE_MANAGED}=true`);
|
|
143
147
|
for (const secret of haveSecrets) {
|
|
144
148
|
const versions = await (0, secretManager_1.listSecretVersions)(projectId, secret.name, `NOT state: DESTROYED`);
|
|
145
149
|
for (const version of versions) {
|
|
@@ -237,3 +241,17 @@ async function updateEndpointSecret(projectInfo, secretVersion, endpoint) {
|
|
|
237
241
|
}
|
|
238
242
|
}
|
|
239
243
|
exports.updateEndpointSecret = updateEndpointSecret;
|
|
244
|
+
async function describeSecret(key, options) {
|
|
245
|
+
const projectId = (0, projectUtils_1.needProjectId)(options);
|
|
246
|
+
const versions = await (0, secretManager_1.listSecretVersions)(projectId, key);
|
|
247
|
+
const table = new Table({
|
|
248
|
+
head: ["Version", "State"],
|
|
249
|
+
style: { head: ["yellow"] },
|
|
250
|
+
});
|
|
251
|
+
for (const version of versions) {
|
|
252
|
+
table.push([version.versionId, version.state]);
|
|
253
|
+
}
|
|
254
|
+
logger_1.logger.info(table.toString());
|
|
255
|
+
return { secrets: versions };
|
|
256
|
+
}
|
|
257
|
+
exports.describeSecret = describeSecret;
|
package/lib/gcp/apphosting.js
CHANGED
|
@@ -31,9 +31,22 @@ async function getBackend(projectId, location, backendId) {
|
|
|
31
31
|
}
|
|
32
32
|
exports.getBackend = getBackend;
|
|
33
33
|
async function listBackends(projectId, location) {
|
|
34
|
+
var _a;
|
|
34
35
|
const name = `projects/${projectId}/locations/${location}/backends`;
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
let pageToken;
|
|
37
|
+
const res = {
|
|
38
|
+
backends: [],
|
|
39
|
+
unreachable: [],
|
|
40
|
+
};
|
|
41
|
+
do {
|
|
42
|
+
const queryParams = pageToken ? { pageToken } : {};
|
|
43
|
+
const int = await exports.client.get(name, { queryParams });
|
|
44
|
+
res.backends.push(...(int.body.backends || []));
|
|
45
|
+
(_a = res.unreachable) === null || _a === void 0 ? void 0 : _a.push(...(int.body.unreachable || []));
|
|
46
|
+
pageToken = int.body.nextPageToken;
|
|
47
|
+
} while (pageToken);
|
|
48
|
+
res.unreachable = [...new Set(res.unreachable)];
|
|
49
|
+
return res;
|
|
37
50
|
}
|
|
38
51
|
exports.listBackends = listBackends;
|
|
39
52
|
async function deleteBackend(projectId, location, backendId) {
|
package/lib/gcp/cloudbuild.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.getDefaultServiceAgent = exports.getDefaultServiceAccount = exports.deleteRepository = exports.getRepository = exports.createRepository = exports.fetchLinkableRepositories = exports.deleteConnection = exports.listConnections = exports.getConnection = exports.createConnection = void 0;
|
|
4
4
|
const apiv2_1 = require("../apiv2");
|
|
5
5
|
const api_1 = require("../api");
|
|
6
6
|
const PAGE_SIZE_MAX = 100;
|
|
@@ -74,7 +74,11 @@ async function deleteRepository(projectId, location, connectionId, repositoryId)
|
|
|
74
74
|
return res.body;
|
|
75
75
|
}
|
|
76
76
|
exports.deleteRepository = deleteRepository;
|
|
77
|
-
function
|
|
77
|
+
function getDefaultServiceAccount(projectNumber) {
|
|
78
|
+
return `${projectNumber}@cloudbuild.gserviceaccount.com`;
|
|
79
|
+
}
|
|
80
|
+
exports.getDefaultServiceAccount = getDefaultServiceAccount;
|
|
81
|
+
function getDefaultServiceAgent(projectNumber) {
|
|
78
82
|
return `service-${projectNumber}@gcp-sa-cloudbuild.iam.gserviceaccount.com`;
|
|
79
83
|
}
|
|
80
|
-
exports.
|
|
84
|
+
exports.getDefaultServiceAgent = getDefaultServiceAgent;
|
|
@@ -7,7 +7,7 @@ const logger_1 = require("../logger");
|
|
|
7
7
|
const backend = require("../deploy/functions/backend");
|
|
8
8
|
const utils = require("../utils");
|
|
9
9
|
const proto = require("./proto");
|
|
10
|
-
const
|
|
10
|
+
const supported = require("../deploy/functions/runtimes/supported");
|
|
11
11
|
const projectConfig = require("../functions/projectConfig");
|
|
12
12
|
const apiv2_1 = require("../apiv2");
|
|
13
13
|
const api_1 = require("../api");
|
|
@@ -241,8 +241,8 @@ function endpointFromFunction(gcfFunction) {
|
|
|
241
241
|
uri = gcfFunction.httpsTrigger.url;
|
|
242
242
|
securityLevel = gcfFunction.httpsTrigger.securityLevel;
|
|
243
243
|
}
|
|
244
|
-
if (!
|
|
245
|
-
logger_1.logger.debug("
|
|
244
|
+
if (!supported.isRuntime(gcfFunction.runtime)) {
|
|
245
|
+
logger_1.logger.debug("GCF 1st gen function has unsupported runtime:", JSON.stringify(gcfFunction, null, 2));
|
|
246
246
|
}
|
|
247
247
|
const endpoint = Object.assign(Object.assign({ platform: "gcfv1", id,
|
|
248
248
|
project,
|
|
@@ -273,9 +273,9 @@ function functionFromEndpoint(endpoint, sourceUploadUrl) {
|
|
|
273
273
|
if (endpoint.platform !== "gcfv1") {
|
|
274
274
|
throw new error_1.FirebaseError("Trying to create a v1 CloudFunction with v2 API. This should never happen");
|
|
275
275
|
}
|
|
276
|
-
if (!
|
|
276
|
+
if (!supported.isRuntime(endpoint.runtime)) {
|
|
277
277
|
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
278
|
-
" This should never happen");
|
|
278
|
+
" This should never happen", { exit: 1 });
|
|
279
279
|
}
|
|
280
280
|
const gcfFunction = {
|
|
281
281
|
name: backend.functionName(endpoint),
|
|
@@ -7,7 +7,7 @@ const api_1 = require("../api");
|
|
|
7
7
|
const logger_1 = require("../logger");
|
|
8
8
|
const v2_1 = require("../functions/events/v2");
|
|
9
9
|
const backend = require("../deploy/functions/backend");
|
|
10
|
-
const
|
|
10
|
+
const supported = require("../deploy/functions/runtimes/supported");
|
|
11
11
|
const proto = require("./proto");
|
|
12
12
|
const utils = require("../utils");
|
|
13
13
|
const projectConfig = require("../functions/projectConfig");
|
|
@@ -175,7 +175,7 @@ function functionFromEndpoint(endpoint) {
|
|
|
175
175
|
if (endpoint.platform !== "gcfv2") {
|
|
176
176
|
throw new error_1.FirebaseError("Trying to create a v2 CloudFunction with v1 API. This should never happen");
|
|
177
177
|
}
|
|
178
|
-
if (!
|
|
178
|
+
if (!supported.isRuntime(endpoint.runtime)) {
|
|
179
179
|
throw new error_1.FirebaseError("Failed internal assertion. Trying to deploy a new function with a deprecated runtime." +
|
|
180
180
|
" This should never happen");
|
|
181
181
|
}
|
|
@@ -337,7 +337,7 @@ function endpointFromFunction(gcfFunction) {
|
|
|
337
337
|
else {
|
|
338
338
|
trigger = { httpsTrigger: {} };
|
|
339
339
|
}
|
|
340
|
-
if (!
|
|
340
|
+
if (!supported.isRuntime(gcfFunction.buildConfig.runtime)) {
|
|
341
341
|
logger_1.logger.debug("GCFv2 function has a deprecated runtime:", JSON.stringify(gcfFunction, null, 2));
|
|
342
342
|
}
|
|
343
343
|
const endpoint = Object.assign(Object.assign({ platform: "gcfv2", id,
|
|
@@ -8,7 +8,7 @@ const api_1 = require("../api");
|
|
|
8
8
|
const apiv2_1 = require("../apiv2");
|
|
9
9
|
const backend = require("../deploy/functions/backend");
|
|
10
10
|
const proto = require("./proto");
|
|
11
|
-
const
|
|
11
|
+
const gce = require("../gcp/computeEngine");
|
|
12
12
|
const functional_1 = require("../functional");
|
|
13
13
|
const VERSION = "v1";
|
|
14
14
|
const DEFAULT_TIME_ZONE_V1 = "America/Los_Angeles";
|
|
@@ -130,7 +130,7 @@ function jobFromEndpoint(endpoint, location, projectNumber) {
|
|
|
130
130
|
uri: endpoint.uri,
|
|
131
131
|
httpMethod: "POST",
|
|
132
132
|
oidcToken: {
|
|
133
|
-
serviceAccountEmail: (_a = endpoint.serviceAccount) !== null && _a !== void 0 ? _a :
|
|
133
|
+
serviceAccountEmail: (_a = endpoint.serviceAccount) !== null && _a !== void 0 ? _a : gce.getDefaultServiceAccount(projectNumber),
|
|
134
134
|
},
|
|
135
135
|
};
|
|
136
136
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getDefaultServiceAccount = void 0;
|
|
4
|
+
function getDefaultServiceAccount(projectNumber) {
|
|
5
|
+
return `${projectNumber}-compute@developer.gserviceaccount.com`;
|
|
6
|
+
}
|
|
7
|
+
exports.getDefaultServiceAccount = getDefaultServiceAccount;
|