firebase-tools 10.1.2 → 10.2.0
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/api.js +1 -0
- package/lib/apiv2.js +92 -48
- package/lib/archiveDirectory.js +63 -73
- package/lib/auth.js +62 -25
- package/lib/commands/ext-configure.js +1 -0
- package/lib/commands/ext-dev-usage.js +3 -8
- package/lib/commands/ext-install.js +1 -0
- package/lib/commands/ext-uninstall.js +1 -0
- package/lib/commands/ext-update.js +1 -0
- package/lib/commands/functions-secrets-access.js +17 -0
- package/lib/commands/functions-secrets-destroy.js +40 -0
- package/lib/commands/functions-secrets-get.js +21 -0
- package/lib/commands/functions-secrets-prune.js +50 -0
- package/lib/commands/functions-secrets-set.js +46 -0
- package/lib/commands/index.js +7 -3
- package/lib/commands/login.js +1 -1
- package/lib/database/metadata.js +16 -24
- package/lib/deploy/functions/backend.js +11 -1
- package/lib/deploy/functions/ensure.js +112 -0
- package/lib/deploy/functions/ensureCloudBuildEnabled.js +0 -49
- package/lib/deploy/functions/prepare.js +13 -19
- package/lib/deploy/functions/release/fabricator.js +4 -1
- package/lib/deploy/functions/runtimes/discovery/v1alpha1.js +1 -0
- package/lib/deploy/functions/runtimes/node/parseTriggers.js +12 -0
- package/lib/deploy/functions/validate.js +83 -1
- package/lib/deploy/hosting/convertConfig.js +45 -24
- package/lib/deploy/hosting/prepare.js +1 -1
- package/lib/emulator/controller.js +3 -1
- package/lib/emulator/emulatorLogger.js +7 -0
- package/lib/emulator/functionsEmulator.js +113 -79
- package/lib/emulator/functionsEmulatorRuntime.js +100 -83
- package/lib/emulator/functionsEmulatorShared.js +51 -1
- package/lib/emulator/functionsEmulatorShell.js +1 -2
- package/lib/emulator/functionsRuntimeWorker.js +1 -1
- package/lib/emulator/storage/apis/gcloud.js +2 -2
- package/lib/emulator/storage/files.js +8 -3
- package/lib/extensions/askUserForParam.js +1 -1
- package/lib/extensions/diagnose.js +56 -0
- package/lib/extensions/extensionsApi.js +0 -1
- package/lib/extensions/extensionsHelper.js +10 -17
- package/lib/extensions/resolveSource.js +1 -53
- package/lib/extensions/secretsUtils.js +1 -1
- package/lib/extensions/updateHelper.js +0 -14
- package/lib/extensions/utils.js +4 -2
- package/lib/functions/env.js +5 -7
- package/lib/functions/secrets.js +112 -0
- package/lib/gcp/cloudbilling.js +8 -19
- package/lib/gcp/cloudfunctions.js +24 -48
- package/lib/gcp/cloudlogging.js +8 -11
- package/lib/gcp/cloudmonitoring.js +8 -5
- package/lib/gcp/cloudscheduler.js +7 -18
- package/lib/gcp/firedata.js +5 -4
- package/lib/gcp/firestore.js +5 -5
- package/lib/gcp/iam.js +18 -33
- package/lib/gcp/resourceManager.js +8 -13
- package/lib/gcp/runtimeconfig.js +31 -53
- package/lib/gcp/secretManager.js +137 -77
- package/lib/gcp/storage.js +25 -29
- package/lib/previews.js +1 -1
- package/lib/serve/functions.js +2 -2
- package/lib/utils.js +6 -1
- package/npm-shrinkwrap.json +962 -987
- package/package.json +5 -3
- package/schema/firebase-config.json +387 -12
- package/templates/init/hosting/index.html +1 -1
package/lib/gcp/iam.js
CHANGED
|
@@ -1,72 +1,57 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.testIamPermissions = exports.testResourceIamPermissions = exports.getRole = exports.deleteServiceAccount = exports.createServiceAccountKey = exports.getServiceAccount = exports.createServiceAccount = void 0;
|
|
4
|
-
const
|
|
5
|
-
const utils_1 = require("../utils");
|
|
4
|
+
const api_1 = require("../api");
|
|
6
5
|
const lodash_1 = require("lodash");
|
|
7
6
|
const logger_1 = require("../logger");
|
|
7
|
+
const apiv2_1 = require("../apiv2");
|
|
8
8
|
const API_VERSION = "v1";
|
|
9
|
+
const apiClient = new apiv2_1.Client({ urlPrefix: api_1.iamOrigin, apiVersion: API_VERSION });
|
|
9
10
|
async function createServiceAccount(projectId, accountId, description, displayName) {
|
|
10
|
-
const response = await
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
serviceAccount: {
|
|
16
|
-
displayName,
|
|
17
|
-
description,
|
|
18
|
-
},
|
|
11
|
+
const response = await apiClient.post(`/projects/${projectId}/serviceAccounts`, {
|
|
12
|
+
accountId,
|
|
13
|
+
serviceAccount: {
|
|
14
|
+
displayName,
|
|
15
|
+
description,
|
|
19
16
|
},
|
|
20
17
|
});
|
|
21
18
|
return response.body;
|
|
22
19
|
}
|
|
23
20
|
exports.createServiceAccount = createServiceAccount;
|
|
24
21
|
async function getServiceAccount(projectId, serviceAccountName) {
|
|
25
|
-
const response = await
|
|
26
|
-
auth: true,
|
|
27
|
-
origin: api.iamOrigin,
|
|
28
|
-
});
|
|
22
|
+
const response = await apiClient.get(`/projects/${projectId}/serviceAccounts/${serviceAccountName}@${projectId}.iam.gserviceaccount.com`);
|
|
29
23
|
return response.body;
|
|
30
24
|
}
|
|
31
25
|
exports.getServiceAccount = getServiceAccount;
|
|
32
26
|
async function createServiceAccountKey(projectId, serviceAccountName) {
|
|
33
|
-
const response = await
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
data: {
|
|
37
|
-
keyAlgorithm: "KEY_ALG_UNSPECIFIED",
|
|
38
|
-
privateKeyType: "TYPE_GOOGLE_CREDENTIALS_FILE",
|
|
39
|
-
},
|
|
27
|
+
const response = await apiClient.post(`/projects/${projectId}/serviceAccounts/${serviceAccountName}@${projectId}.iam.gserviceaccount.com/keys`, {
|
|
28
|
+
keyAlgorithm: "KEY_ALG_UNSPECIFIED",
|
|
29
|
+
privateKeyType: "TYPE_GOOGLE_CREDENTIALS_FILE",
|
|
40
30
|
});
|
|
41
31
|
return response.body;
|
|
42
32
|
}
|
|
43
33
|
exports.createServiceAccountKey = createServiceAccountKey;
|
|
44
34
|
function deleteServiceAccount(projectId, accountEmail) {
|
|
45
|
-
return
|
|
46
|
-
auth: true,
|
|
47
|
-
origin: api.iamOrigin,
|
|
35
|
+
return apiClient.delete(`/projects/${projectId}/serviceAccounts/${accountEmail}`, {
|
|
48
36
|
resolveOnHTTPError: true,
|
|
49
37
|
});
|
|
50
38
|
}
|
|
51
39
|
exports.deleteServiceAccount = deleteServiceAccount;
|
|
52
40
|
async function getRole(role) {
|
|
53
|
-
const response = await
|
|
54
|
-
auth: true,
|
|
55
|
-
origin: api.iamOrigin,
|
|
41
|
+
const response = await apiClient.get(`/roles/${role}`, {
|
|
56
42
|
retryCodes: [500, 503],
|
|
57
43
|
});
|
|
58
44
|
return response.body;
|
|
59
45
|
}
|
|
60
46
|
exports.getRole = getRole;
|
|
61
47
|
async function testResourceIamPermissions(origin, apiVersion, resourceName, permissions) {
|
|
48
|
+
const localClient = new apiv2_1.Client({ urlPrefix: origin, apiVersion });
|
|
62
49
|
if (process.env.FIREBASE_SKIP_INFORMATIONAL_IAM) {
|
|
63
50
|
logger_1.logger.debug("[iam] skipping informational check of permissions", JSON.stringify(permissions), "on resource", resourceName);
|
|
64
51
|
return { allowed: permissions, missing: [], passed: true };
|
|
65
52
|
}
|
|
66
|
-
const response = await
|
|
67
|
-
|
|
68
|
-
data: { permissions },
|
|
69
|
-
origin,
|
|
53
|
+
const response = await localClient.post(`/${resourceName}:testIamPermissions`, {
|
|
54
|
+
permissions,
|
|
70
55
|
});
|
|
71
56
|
const allowed = (response.body.permissions || []).sort();
|
|
72
57
|
const missing = (0, lodash_1.difference)(permissions, allowed);
|
|
@@ -78,6 +63,6 @@ async function testResourceIamPermissions(origin, apiVersion, resourceName, perm
|
|
|
78
63
|
}
|
|
79
64
|
exports.testResourceIamPermissions = testResourceIamPermissions;
|
|
80
65
|
async function testIamPermissions(projectId, permissions) {
|
|
81
|
-
return testResourceIamPermissions(
|
|
66
|
+
return testResourceIamPermissions(api_1.resourceManagerOrigin, "v1", `projects/${projectId}`, permissions);
|
|
82
67
|
}
|
|
83
68
|
exports.testIamPermissions = testIamPermissions;
|
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.addServiceAccountToRoles = exports.setIamPolicy = exports.getIamPolicy = exports.firebaseRoles = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
|
-
const
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const apiv2_1 = require("../apiv2");
|
|
6
7
|
const iam_1 = require("./iam");
|
|
7
8
|
const API_VERSION = "v1";
|
|
9
|
+
const apiClient = new apiv2_1.Client({ urlPrefix: api_1.resourceManagerOrigin, apiVersion: API_VERSION });
|
|
8
10
|
exports.firebaseRoles = {
|
|
9
11
|
apiKeysViewer: "roles/serviceusage.apiKeysViewer",
|
|
10
12
|
authAdmin: "roles/firebaseauth.admin",
|
|
@@ -12,21 +14,14 @@ exports.firebaseRoles = {
|
|
|
12
14
|
runViewer: "roles/run.viewer",
|
|
13
15
|
};
|
|
14
16
|
async function getIamPolicy(projectId) {
|
|
15
|
-
const response = await
|
|
16
|
-
auth: true,
|
|
17
|
-
origin: api.resourceManagerOrigin,
|
|
18
|
-
});
|
|
17
|
+
const response = await apiClient.post(`/projects/${projectId}:getIamPolicy`);
|
|
19
18
|
return response.body;
|
|
20
19
|
}
|
|
21
20
|
exports.getIamPolicy = getIamPolicy;
|
|
22
|
-
async function setIamPolicy(projectId, newPolicy, updateMask) {
|
|
23
|
-
const response = await
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
data: {
|
|
27
|
-
policy: newPolicy,
|
|
28
|
-
updateMask: updateMask,
|
|
29
|
-
},
|
|
21
|
+
async function setIamPolicy(projectId, newPolicy, updateMask = "") {
|
|
22
|
+
const response = await apiClient.post(`/projects/${projectId}:setIamPolicy`, {
|
|
23
|
+
policy: newPolicy,
|
|
24
|
+
updateMask: updateMask,
|
|
30
25
|
});
|
|
31
26
|
return response.body;
|
|
32
27
|
}
|
package/lib/gcp/runtimeconfig.js
CHANGED
|
@@ -1,30 +1,25 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
const { runtimeconfigOrigin } = require("../api");
|
|
3
|
+
const { Client } = require("../apiv2");
|
|
4
4
|
const { logger } = require("../logger");
|
|
5
5
|
var _ = require("lodash");
|
|
6
|
-
|
|
6
|
+
const API_VERSION = "v1beta1";
|
|
7
|
+
const apiClient = new Client({ urlPrefix: runtimeconfigOrigin, apiVersion: API_VERSION });
|
|
7
8
|
function _listConfigs(projectId) {
|
|
8
|
-
return
|
|
9
|
-
.
|
|
10
|
-
auth: true,
|
|
11
|
-
origin: api.runtimeconfigOrigin,
|
|
9
|
+
return apiClient
|
|
10
|
+
.get(`/projects/${projectId}/configs`, {
|
|
12
11
|
retryCodes: [500, 503],
|
|
13
12
|
})
|
|
14
13
|
.then(function (resp) {
|
|
15
|
-
return
|
|
14
|
+
return resp.body.configs;
|
|
16
15
|
});
|
|
17
16
|
}
|
|
18
17
|
function _createConfig(projectId, configId) {
|
|
19
18
|
var path = _.join(["projects", projectId, "configs"], "/");
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
origin: api.runtimeconfigOrigin,
|
|
25
|
-
data: {
|
|
26
|
-
name: path + "/" + configId,
|
|
27
|
-
},
|
|
19
|
+
return apiClient
|
|
20
|
+
.post(`/projects/${projectId}/configs`, {
|
|
21
|
+
name: path + "/" + configId,
|
|
22
|
+
}, {
|
|
28
23
|
retryCodes: [500, 503],
|
|
29
24
|
})
|
|
30
25
|
.catch(function (err) {
|
|
@@ -35,10 +30,8 @@ function _createConfig(projectId, configId) {
|
|
|
35
30
|
});
|
|
36
31
|
}
|
|
37
32
|
function _deleteConfig(projectId, configId) {
|
|
38
|
-
return
|
|
39
|
-
.
|
|
40
|
-
auth: true,
|
|
41
|
-
origin: api.runtimeconfigOrigin,
|
|
33
|
+
return apiClient
|
|
34
|
+
.delete(`/projects/${projectId}/configs/${configId}`, {
|
|
42
35
|
retryCodes: [500, 503],
|
|
43
36
|
})
|
|
44
37
|
.catch(function (err) {
|
|
@@ -50,10 +43,8 @@ function _deleteConfig(projectId, configId) {
|
|
|
50
43
|
});
|
|
51
44
|
}
|
|
52
45
|
function _listVariables(configPath) {
|
|
53
|
-
return
|
|
54
|
-
.
|
|
55
|
-
auth: true,
|
|
56
|
-
origin: api.runtimeconfigOrigin,
|
|
46
|
+
return apiClient
|
|
47
|
+
.get(`${configPath}/variables`, {
|
|
57
48
|
retryCodes: [500, 503],
|
|
58
49
|
})
|
|
59
50
|
.then(function (resp) {
|
|
@@ -61,10 +52,8 @@ function _listVariables(configPath) {
|
|
|
61
52
|
});
|
|
62
53
|
}
|
|
63
54
|
function _getVariable(varPath) {
|
|
64
|
-
return
|
|
65
|
-
.
|
|
66
|
-
auth: true,
|
|
67
|
-
origin: api.runtimeconfigOrigin,
|
|
55
|
+
return apiClient
|
|
56
|
+
.get(varPath, {
|
|
68
57
|
retryCodes: [500, 503],
|
|
69
58
|
})
|
|
70
59
|
.then(function (resp) {
|
|
@@ -72,16 +61,12 @@ function _getVariable(varPath) {
|
|
|
72
61
|
});
|
|
73
62
|
}
|
|
74
63
|
function _createVariable(projectId, configId, varId, value) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
data: {
|
|
82
|
-
name: path + "/" + varId,
|
|
83
|
-
text: value,
|
|
84
|
-
},
|
|
64
|
+
const path = `/projects/${projectId}/configs/${configId}/variables`;
|
|
65
|
+
return apiClient
|
|
66
|
+
.post(path, {
|
|
67
|
+
name: `${path}/${varId}`,
|
|
68
|
+
text: value,
|
|
69
|
+
}, {
|
|
85
70
|
retryCodes: [500, 503],
|
|
86
71
|
})
|
|
87
72
|
.catch(function (err) {
|
|
@@ -94,15 +79,11 @@ function _createVariable(projectId, configId, varId, value) {
|
|
|
94
79
|
});
|
|
95
80
|
}
|
|
96
81
|
function _updateVariable(projectId, configId, varId, value) {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
data: {
|
|
103
|
-
name: path,
|
|
104
|
-
text: value,
|
|
105
|
-
},
|
|
82
|
+
const path = `/projects/${projectId}/configs/${configId}/variables/${varId}`;
|
|
83
|
+
return apiClient.put(path, {
|
|
84
|
+
name: path,
|
|
85
|
+
text: value,
|
|
86
|
+
}, {
|
|
106
87
|
retryCodes: [500, 503],
|
|
107
88
|
});
|
|
108
89
|
}
|
|
@@ -120,13 +101,10 @@ function _setVariable(projectId, configId, varId, value) {
|
|
|
120
101
|
});
|
|
121
102
|
}
|
|
122
103
|
function _deleteVariable(projectId, configId, varId) {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
return api
|
|
126
|
-
.request("DELETE", endpoint, {
|
|
127
|
-
auth: true,
|
|
128
|
-
origin: api.runtimeconfigOrigin,
|
|
104
|
+
return apiClient
|
|
105
|
+
.delete(`/projects/${projectId}/configs/${configId}/variables/${varId}`, {
|
|
129
106
|
retryCodes: [500, 503],
|
|
107
|
+
queryParams: { recursive: "true" },
|
|
130
108
|
})
|
|
131
109
|
.catch(function (err) {
|
|
132
110
|
if (_.get(err, "context.response.statusCode") === 404) {
|
package/lib/gcp/secretManager.js
CHANGED
|
@@ -1,37 +1,88 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.ensureServiceAgentRole = exports.setIamPolicy = exports.getIamPolicy = exports.addVersion = exports.deleteSecret = exports.patchSecret = exports.createSecret = exports.toSecretVersionResourceName = exports.parseSecretVersionResourceName = exports.parseSecretResourceName = exports.secretExists = exports.destroySecretVersion = exports.accessSecretVersion = exports.getSecretVersion = exports.listSecretVersions = exports.listSecrets = exports.getSecret = exports.secretManagerConsoleUri = void 0;
|
|
4
4
|
const utils_1 = require("../utils");
|
|
5
|
-
const
|
|
5
|
+
const error_1 = require("../error");
|
|
6
|
+
const apiv2_1 = require("../apiv2");
|
|
7
|
+
const api_1 = require("../api");
|
|
8
|
+
const SECRET_NAME_REGEX = new RegExp("projects\\/" +
|
|
9
|
+
"(?<project>(?:\\d+)|(?:[A-Za-z]+[A-Za-z\\d-]*[A-Za-z\\d]?))\\/" +
|
|
10
|
+
"secrets\\/" +
|
|
11
|
+
"(?<secret>[A-Za-z\\d\\-_]+)");
|
|
12
|
+
const SECRET_VERSION_NAME_REGEX = new RegExp(SECRET_NAME_REGEX.source + "\\/versions\\/" + "(?<version>latest|[0-9]+)");
|
|
6
13
|
const secretManagerConsoleUri = (projectId) => `https://console.cloud.google.com/security/secret-manager?project=${projectId}`;
|
|
7
14
|
exports.secretManagerConsoleUri = secretManagerConsoleUri;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
auth: true,
|
|
11
|
-
origin: api.secretManagerOrigin,
|
|
12
|
-
});
|
|
13
|
-
return listRes.body.secrets.map((s) => parseSecretResourceName(s.name));
|
|
14
|
-
}
|
|
15
|
-
exports.listSecrets = listSecrets;
|
|
15
|
+
const API_VERSION = "v1";
|
|
16
|
+
const client = new apiv2_1.Client({ urlPrefix: api_1.secretManagerOrigin, apiVersion: API_VERSION });
|
|
16
17
|
async function getSecret(projectId, name) {
|
|
17
18
|
var _a;
|
|
18
|
-
const getRes = await
|
|
19
|
-
auth: true,
|
|
20
|
-
origin: api.secretManagerOrigin,
|
|
21
|
-
});
|
|
19
|
+
const getRes = await client.get(`projects/${projectId}/secrets/${name}`);
|
|
22
20
|
const secret = parseSecretResourceName(getRes.body.name);
|
|
23
21
|
secret.labels = (_a = getRes.body.labels) !== null && _a !== void 0 ? _a : {};
|
|
24
22
|
return secret;
|
|
25
23
|
}
|
|
26
24
|
exports.getSecret = getSecret;
|
|
25
|
+
async function listSecrets(projectId, filter) {
|
|
26
|
+
var _a;
|
|
27
|
+
const secrets = [];
|
|
28
|
+
const path = `projects/${projectId}/secrets`;
|
|
29
|
+
const baseOpts = filter ? { queryParams: { filter } } : {};
|
|
30
|
+
let pageToken = "";
|
|
31
|
+
while (true) {
|
|
32
|
+
const opts = pageToken === ""
|
|
33
|
+
? baseOpts
|
|
34
|
+
: Object.assign(Object.assign({}, baseOpts), { queryParams: Object.assign(Object.assign({}, baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.queryParams), { pageToken }) });
|
|
35
|
+
const res = await client.get(path, opts);
|
|
36
|
+
for (const s of res.body.secrets) {
|
|
37
|
+
secrets.push(Object.assign(Object.assign({}, parseSecretResourceName(s.name)), { labels: (_a = s.labels) !== null && _a !== void 0 ? _a : {} }));
|
|
38
|
+
}
|
|
39
|
+
if (!res.body.nextPageToken) {
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
pageToken = res.body.nextPageToken;
|
|
43
|
+
}
|
|
44
|
+
return secrets;
|
|
45
|
+
}
|
|
46
|
+
exports.listSecrets = listSecrets;
|
|
47
|
+
async function listSecretVersions(projectId, name, filter) {
|
|
48
|
+
const secrets = [];
|
|
49
|
+
const path = `projects/${projectId}/secrets/${name}/versions`;
|
|
50
|
+
const baseOpts = filter ? { queryParams: { filter } } : {};
|
|
51
|
+
let pageToken = "";
|
|
52
|
+
while (true) {
|
|
53
|
+
const opts = pageToken === ""
|
|
54
|
+
? baseOpts
|
|
55
|
+
: Object.assign(Object.assign({}, baseOpts), { queryParams: Object.assign(Object.assign({}, baseOpts === null || baseOpts === void 0 ? void 0 : baseOpts.queryParams), { pageToken }) });
|
|
56
|
+
const res = await client.get(path, opts);
|
|
57
|
+
for (const s of res.body.versions || []) {
|
|
58
|
+
secrets.push(Object.assign(Object.assign({}, parseSecretVersionResourceName(s.name)), { state: s.state }));
|
|
59
|
+
}
|
|
60
|
+
if (!res.body.nextPageToken) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
pageToken = res.body.nextPageToken;
|
|
64
|
+
}
|
|
65
|
+
return secrets;
|
|
66
|
+
}
|
|
67
|
+
exports.listSecretVersions = listSecretVersions;
|
|
27
68
|
async function getSecretVersion(projectId, name, version) {
|
|
28
|
-
const getRes = await
|
|
29
|
-
|
|
30
|
-
origin: api.secretManagerOrigin,
|
|
31
|
-
});
|
|
32
|
-
return parseSecretVersionResourceName(getRes.body.name);
|
|
69
|
+
const getRes = await client.get(`projects/${projectId}/secrets/${name}/versions/${version}`);
|
|
70
|
+
return Object.assign(Object.assign({}, parseSecretVersionResourceName(getRes.body.name)), { state: getRes.body.state });
|
|
33
71
|
}
|
|
34
72
|
exports.getSecretVersion = getSecretVersion;
|
|
73
|
+
async function accessSecretVersion(projectId, name, version) {
|
|
74
|
+
const res = await client.get(`projects/${projectId}/secrets/${name}/versions/${version}:access`);
|
|
75
|
+
return Buffer.from(res.body.payload.data, "base64").toString();
|
|
76
|
+
}
|
|
77
|
+
exports.accessSecretVersion = accessSecretVersion;
|
|
78
|
+
async function destroySecretVersion(projectId, name, version) {
|
|
79
|
+
if (version === "latest") {
|
|
80
|
+
const sv = await getSecretVersion(projectId, name, "latest");
|
|
81
|
+
version = sv.versionId;
|
|
82
|
+
}
|
|
83
|
+
await client.post(`projects/${projectId}/secrets/${name}/versions/${version}:destroy`);
|
|
84
|
+
}
|
|
85
|
+
exports.destroySecretVersion = destroySecretVersion;
|
|
35
86
|
async function secretExists(projectId, name) {
|
|
36
87
|
try {
|
|
37
88
|
await getSecret(projectId, name);
|
|
@@ -46,21 +97,27 @@ async function secretExists(projectId, name) {
|
|
|
46
97
|
}
|
|
47
98
|
exports.secretExists = secretExists;
|
|
48
99
|
function parseSecretResourceName(resourceName) {
|
|
49
|
-
const
|
|
100
|
+
const match = SECRET_NAME_REGEX.exec(resourceName);
|
|
101
|
+
if (!(match === null || match === void 0 ? void 0 : match.groups)) {
|
|
102
|
+
throw new error_1.FirebaseError(`Invalid secret resource name [${resourceName}].`);
|
|
103
|
+
}
|
|
50
104
|
return {
|
|
51
|
-
projectId:
|
|
52
|
-
name:
|
|
105
|
+
projectId: match.groups.project,
|
|
106
|
+
name: match.groups.secret,
|
|
53
107
|
};
|
|
54
108
|
}
|
|
55
109
|
exports.parseSecretResourceName = parseSecretResourceName;
|
|
56
110
|
function parseSecretVersionResourceName(resourceName) {
|
|
57
|
-
const
|
|
111
|
+
const match = resourceName.match(SECRET_VERSION_NAME_REGEX);
|
|
112
|
+
if (!(match === null || match === void 0 ? void 0 : match.groups)) {
|
|
113
|
+
throw new error_1.FirebaseError(`Invalid secret version resource name [${resourceName}].`);
|
|
114
|
+
}
|
|
58
115
|
return {
|
|
59
116
|
secret: {
|
|
60
|
-
projectId:
|
|
61
|
-
name:
|
|
117
|
+
projectId: match.groups.project,
|
|
118
|
+
name: match.groups.secret,
|
|
62
119
|
},
|
|
63
|
-
versionId:
|
|
120
|
+
versionId: match.groups.version,
|
|
64
121
|
};
|
|
65
122
|
}
|
|
66
123
|
exports.parseSecretVersionResourceName = parseSecretVersionResourceName;
|
|
@@ -69,65 +126,68 @@ function toSecretVersionResourceName(secretVersion) {
|
|
|
69
126
|
}
|
|
70
127
|
exports.toSecretVersionResourceName = toSecretVersionResourceName;
|
|
71
128
|
async function createSecret(projectId, name, labels) {
|
|
72
|
-
const createRes = await
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
replication: {
|
|
77
|
-
automatic: {},
|
|
78
|
-
},
|
|
79
|
-
labels,
|
|
129
|
+
const createRes = await client.post(`projects/${projectId}/secrets`, {
|
|
130
|
+
name,
|
|
131
|
+
replication: {
|
|
132
|
+
automatic: {},
|
|
80
133
|
},
|
|
81
|
-
|
|
134
|
+
labels,
|
|
135
|
+
}, { queryParams: { secretId: name } });
|
|
82
136
|
return parseSecretResourceName(createRes.body.name);
|
|
83
137
|
}
|
|
84
138
|
exports.createSecret = createSecret;
|
|
85
|
-
async function
|
|
86
|
-
const
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
139
|
+
async function patchSecret(projectId, name, labels) {
|
|
140
|
+
const fullName = `projects/${projectId}/secrets/${name}`;
|
|
141
|
+
const res = await client.patch(fullName, { name: fullName, labels }, { queryParams: { updateMask: "labels" } });
|
|
142
|
+
return parseSecretResourceName(res.body.name);
|
|
143
|
+
}
|
|
144
|
+
exports.patchSecret = patchSecret;
|
|
145
|
+
async function deleteSecret(projectId, name) {
|
|
146
|
+
const path = `projects/${projectId}/secrets/${name}`;
|
|
147
|
+
await client.delete(path);
|
|
148
|
+
}
|
|
149
|
+
exports.deleteSecret = deleteSecret;
|
|
150
|
+
async function addVersion(projectId, name, payloadData) {
|
|
151
|
+
const res = await client.post(`projects/${projectId}/secrets/${name}:addVersion`, {
|
|
152
|
+
payload: {
|
|
153
|
+
data: Buffer.from(payloadData).toString("base64"),
|
|
93
154
|
},
|
|
94
155
|
});
|
|
95
|
-
|
|
96
|
-
return {
|
|
97
|
-
secret: {
|
|
98
|
-
projectId: nameTokens[1],
|
|
99
|
-
name: nameTokens[3],
|
|
100
|
-
},
|
|
101
|
-
versionId: nameTokens[5],
|
|
102
|
-
};
|
|
156
|
+
return Object.assign(Object.assign({}, parseSecretVersionResourceName(res.body.name)), { state: res.body.state });
|
|
103
157
|
}
|
|
104
158
|
exports.addVersion = addVersion;
|
|
105
|
-
async function
|
|
106
|
-
const
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
}
|
|
115
|
-
bindings.push({
|
|
116
|
-
role: role,
|
|
117
|
-
members: [`serviceAccount:${serviceAccountEmail}`],
|
|
118
|
-
});
|
|
119
|
-
await api.request("POST", `/v1beta1/projects/${secret.projectId}/secrets/${secret.name}:setIamPolicy`, {
|
|
120
|
-
auth: true,
|
|
121
|
-
origin: api.secretManagerOrigin,
|
|
122
|
-
data: {
|
|
123
|
-
policy: {
|
|
124
|
-
bindings,
|
|
125
|
-
},
|
|
126
|
-
updateMask: {
|
|
127
|
-
paths: "bindings",
|
|
128
|
-
},
|
|
159
|
+
async function getIamPolicy(secret) {
|
|
160
|
+
const res = await client.get(`projects/${secret.projectId}/secrets/${secret.name}:getIamPolicy`);
|
|
161
|
+
return res.body;
|
|
162
|
+
}
|
|
163
|
+
exports.getIamPolicy = getIamPolicy;
|
|
164
|
+
async function setIamPolicy(secret, bindings) {
|
|
165
|
+
await client.post(`projects/${secret.projectId}/secrets/${secret.name}:setIamPolicy`, {
|
|
166
|
+
policy: {
|
|
167
|
+
bindings,
|
|
129
168
|
},
|
|
169
|
+
updateMask: "bindings",
|
|
130
170
|
});
|
|
131
|
-
(0, utils_1.logLabeledSuccess)("SecretManager", `Granted ${role} on projects/${secret.projectId}/secrets/${secret.name} to ${serviceAccountEmail}`);
|
|
132
171
|
}
|
|
133
|
-
exports.
|
|
172
|
+
exports.setIamPolicy = setIamPolicy;
|
|
173
|
+
async function ensureServiceAgentRole(secret, serviceAccountEmails, role) {
|
|
174
|
+
const policy = await module.exports.getIamPolicy(secret);
|
|
175
|
+
const bindings = policy.bindings || [];
|
|
176
|
+
let binding = bindings.find((b) => b.role === role);
|
|
177
|
+
if (!binding) {
|
|
178
|
+
binding = { role, members: [] };
|
|
179
|
+
bindings.push(binding);
|
|
180
|
+
}
|
|
181
|
+
let shouldShortCircuit = true;
|
|
182
|
+
for (const serviceAccount of serviceAccountEmails) {
|
|
183
|
+
if (!binding.members.find((m) => m === `serviceAccount:${serviceAccount}`)) {
|
|
184
|
+
binding.members.push(`serviceAccount:${serviceAccount}`);
|
|
185
|
+
shouldShortCircuit = false;
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
if (shouldShortCircuit)
|
|
189
|
+
return;
|
|
190
|
+
await module.exports.setIamPolicy(secret, bindings);
|
|
191
|
+
(0, utils_1.logLabeledSuccess)("secretmanager", `Granted ${role} on projects/${secret.projectId}/secrets/${secret.name} to ${serviceAccountEmails.join(", ")}`);
|
|
192
|
+
}
|
|
193
|
+
exports.ensureServiceAgentRole = ensureServiceAgentRole;
|
package/lib/gcp/storage.js
CHANGED
|
@@ -2,15 +2,14 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.getServiceAccount = exports.getBucket = exports.deleteObject = exports.uploadObject = exports.upload = exports.getDefaultBucket = void 0;
|
|
4
4
|
const path = require("path");
|
|
5
|
-
const
|
|
5
|
+
const api_1 = require("../api");
|
|
6
|
+
const apiv2_1 = require("../apiv2");
|
|
6
7
|
const logger_1 = require("../logger");
|
|
7
8
|
const error_1 = require("../error");
|
|
8
9
|
async function getDefaultBucket(projectId) {
|
|
9
10
|
try {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
origin: api.appengineOrigin,
|
|
13
|
-
});
|
|
11
|
+
const appengineClient = new apiv2_1.Client({ urlPrefix: api_1.appengineOrigin, apiVersion: "v1" });
|
|
12
|
+
const resp = await appengineClient.get(`/apps/${projectId}`);
|
|
14
13
|
if (resp.body.defaultBucket === "undefined") {
|
|
15
14
|
logger_1.logger.debug("Default storage bucket is undefined.");
|
|
16
15
|
throw new error_1.FirebaseError("Your project is being set up. Please wait a minute before deploying again.");
|
|
@@ -25,15 +24,17 @@ async function getDefaultBucket(projectId) {
|
|
|
25
24
|
exports.getDefaultBucket = getDefaultBucket;
|
|
26
25
|
async function upload(source, uploadUrl, extraHeaders) {
|
|
27
26
|
const url = new URL(uploadUrl);
|
|
28
|
-
const
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
const localAPIClient = new apiv2_1.Client({ urlPrefix: url.origin, auth: false });
|
|
28
|
+
const res = await localAPIClient.request({
|
|
29
|
+
method: "PUT",
|
|
30
|
+
path: url.pathname,
|
|
31
|
+
queryParams: url.searchParams,
|
|
32
|
+
headers: Object.assign({ "content-type": "application/zip" }, extraHeaders),
|
|
33
|
+
body: source.stream,
|
|
34
|
+
skipLog: { resBody: true },
|
|
34
35
|
});
|
|
35
36
|
return {
|
|
36
|
-
generation:
|
|
37
|
+
generation: res.response.headers.get("x-goog-generation"),
|
|
37
38
|
};
|
|
38
39
|
}
|
|
39
40
|
exports.upload = upload;
|
|
@@ -41,38 +42,35 @@ async function uploadObject(source, bucketName) {
|
|
|
41
42
|
if (path.extname(source.file) !== ".zip") {
|
|
42
43
|
throw new error_1.FirebaseError(`Expected a file name ending in .zip, got ${source.file}`);
|
|
43
44
|
}
|
|
45
|
+
const localAPIClient = new apiv2_1.Client({ urlPrefix: api_1.storageOrigin });
|
|
44
46
|
const location = `/${bucketName}/${path.basename(source.file)}`;
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
47
|
+
const res = await localAPIClient.request({
|
|
48
|
+
method: "PUT",
|
|
49
|
+
path: location,
|
|
48
50
|
headers: {
|
|
49
51
|
"Content-Type": "application/zip",
|
|
50
52
|
"x-goog-content-length-range": "0,123289600",
|
|
51
53
|
},
|
|
52
|
-
|
|
53
|
-
origin: api.storageOrigin,
|
|
54
|
-
logOptions: { skipRequestBody: true },
|
|
54
|
+
body: source.stream,
|
|
55
55
|
});
|
|
56
56
|
return {
|
|
57
57
|
bucket: bucketName,
|
|
58
58
|
object: path.basename(source.file),
|
|
59
|
-
generation:
|
|
59
|
+
generation: res.response.headers.get("x-goog-generation"),
|
|
60
60
|
};
|
|
61
61
|
}
|
|
62
62
|
exports.uploadObject = uploadObject;
|
|
63
63
|
function deleteObject(location) {
|
|
64
|
-
return
|
|
64
|
+
return api_1.default.request("DELETE", location, {
|
|
65
65
|
auth: true,
|
|
66
|
-
origin:
|
|
66
|
+
origin: api_1.default.storageOrigin,
|
|
67
67
|
});
|
|
68
68
|
}
|
|
69
69
|
exports.deleteObject = deleteObject;
|
|
70
70
|
async function getBucket(bucketName) {
|
|
71
71
|
try {
|
|
72
|
-
const
|
|
73
|
-
|
|
74
|
-
origin: api.storageOrigin,
|
|
75
|
-
});
|
|
72
|
+
const localAPIClient = new apiv2_1.Client({ urlPrefix: api_1.storageOrigin });
|
|
73
|
+
const result = await localAPIClient.get(`/storage/v1/b/${bucketName}`);
|
|
76
74
|
return result.body;
|
|
77
75
|
}
|
|
78
76
|
catch (err) {
|
|
@@ -85,10 +83,8 @@ async function getBucket(bucketName) {
|
|
|
85
83
|
exports.getBucket = getBucket;
|
|
86
84
|
async function getServiceAccount(projectId) {
|
|
87
85
|
try {
|
|
88
|
-
const
|
|
89
|
-
|
|
90
|
-
origin: api.storageOrigin,
|
|
91
|
-
});
|
|
86
|
+
const localAPIClient = new apiv2_1.Client({ urlPrefix: api_1.storageOrigin });
|
|
87
|
+
const response = await localAPIClient.get(`/storage/v1/projects/${projectId}/serviceAccount`);
|
|
92
88
|
return response.body;
|
|
93
89
|
}
|
|
94
90
|
catch (err) {
|
package/lib/previews.js
CHANGED
|
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.previews = void 0;
|
|
4
4
|
const lodash_1 = require("lodash");
|
|
5
5
|
const configstore_1 = require("./configstore");
|
|
6
|
-
exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false,
|
|
6
|
+
exports.previews = Object.assign({ rtdbrules: false, ext: false, extdev: false, rtdbmanagement: false, functionsv2: false, golang: false, deletegcfartifacts: false, artifactregistry: false }, configstore_1.configstore.get("previews"));
|
|
7
7
|
if (process.env.FIREBASE_CLI_PREVIEWS) {
|
|
8
8
|
process.env.FIREBASE_CLI_PREVIEWS.split(",").forEach((feature) => {
|
|
9
9
|
if ((0, lodash_1.has)(exports.previews, feature)) {
|