backend-manager 5.9.14 → 5.9.15
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/package.json +1 -1
- package/src/cli/commands/deploy.js +41 -36
package/package.json
CHANGED
|
@@ -3,15 +3,23 @@ const chalk = require('chalk').default;
|
|
|
3
3
|
const powertools = require('node-powertools');
|
|
4
4
|
const attachLogFile = require('../utils/attach-log-file');
|
|
5
5
|
const { execSync } = require('child_process');
|
|
6
|
+
const { homedir } = require('os');
|
|
6
7
|
const path = require('path');
|
|
7
8
|
const jetpack = require('fs-jetpack');
|
|
8
9
|
|
|
9
10
|
const DEFAULT_REGION = 'us-central1';
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
'
|
|
14
|
-
|
|
11
|
+
|
|
12
|
+
function gcloudExec(cmd, options = {}) {
|
|
13
|
+
const env = { ...process.env };
|
|
14
|
+
env.PATH = `${path.join(homedir(), 'google-cloud-sdk', 'bin')}:${env.PATH}`;
|
|
15
|
+
|
|
16
|
+
return execSync(cmd, {
|
|
17
|
+
encoding: 'utf8',
|
|
18
|
+
timeout: options.timeout || 30000,
|
|
19
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
20
|
+
env,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
15
23
|
|
|
16
24
|
class DeployCommand extends BaseCommand {
|
|
17
25
|
async execute() {
|
|
@@ -49,11 +57,14 @@ class DeployCommand extends BaseCommand {
|
|
|
49
57
|
}
|
|
50
58
|
|
|
51
59
|
/**
|
|
52
|
-
* Ensure HTTP-triggered functions have allUsers as cloudfunctions.invoker.
|
|
60
|
+
* Ensure all HTTP-triggered functions have allUsers as cloudfunctions.invoker.
|
|
53
61
|
*
|
|
54
62
|
* Firebase CLI used to set this automatically but stopped around the Node 10
|
|
55
63
|
* runtime transition. Without it, HTTP requests get a 403 at the IAM level
|
|
56
64
|
* before BEM's application-level auth (backendManagerKey) can run.
|
|
65
|
+
*
|
|
66
|
+
* Dynamically discovers all deployed functions and fixes any HTTP-triggered
|
|
67
|
+
* function missing the allUsers invoker binding.
|
|
57
68
|
*/
|
|
58
69
|
async ensurePublicInvoker() {
|
|
59
70
|
const projectId = this.getProjectId();
|
|
@@ -62,10 +73,24 @@ class DeployCommand extends BaseCommand {
|
|
|
62
73
|
return;
|
|
63
74
|
}
|
|
64
75
|
|
|
65
|
-
|
|
76
|
+
// Discover all deployed HTTP-triggered functions
|
|
77
|
+
let httpFunctions;
|
|
78
|
+
|
|
79
|
+
try {
|
|
80
|
+
const output = gcloudExec(
|
|
81
|
+
`gcloud functions list --project ${projectId} --regions ${DEFAULT_REGION} --format="json(name,httpsTrigger)"`,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const allFunctions = JSON.parse(output);
|
|
85
|
+
|
|
86
|
+
httpFunctions = allFunctions
|
|
87
|
+
.filter((fn) => fn.httpsTrigger)
|
|
88
|
+
.map((fn) => fn.name.split('/').pop());
|
|
89
|
+
} catch {
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
66
92
|
|
|
67
|
-
if (!
|
|
68
|
-
this.log(chalk.gray('\n Skipping public invoker check (gcloud not found)\n'));
|
|
93
|
+
if (!httpFunctions.length) {
|
|
69
94
|
return;
|
|
70
95
|
}
|
|
71
96
|
|
|
@@ -74,12 +99,11 @@ class DeployCommand extends BaseCommand {
|
|
|
74
99
|
let fixed = 0;
|
|
75
100
|
let ok = 0;
|
|
76
101
|
|
|
77
|
-
for (const fnName of
|
|
102
|
+
for (const fnName of httpFunctions) {
|
|
78
103
|
try {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
{ encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] },
|
|
104
|
+
const policyOutput = gcloudExec(
|
|
105
|
+
`gcloud functions get-iam-policy ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --format=json`,
|
|
106
|
+
{ timeout: 15000 },
|
|
83
107
|
);
|
|
84
108
|
|
|
85
109
|
const policy = JSON.parse(policyOutput);
|
|
@@ -93,16 +117,14 @@ class DeployCommand extends BaseCommand {
|
|
|
93
117
|
continue;
|
|
94
118
|
}
|
|
95
119
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`${gcloud} functions add-iam-policy-binding ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --member="allUsers" --role="roles/cloudfunctions.invoker"`,
|
|
99
|
-
{ encoding: 'utf8', timeout: 30000, stdio: ['pipe', 'pipe', 'pipe'] },
|
|
120
|
+
gcloudExec(
|
|
121
|
+
`gcloud functions add-iam-policy-binding ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --member="allUsers" --role="roles/cloudfunctions.invoker"`,
|
|
100
122
|
);
|
|
101
123
|
|
|
102
124
|
this.log(` ${chalk.green('✓')} Set public invoker on ${chalk.cyan(fnName)}`);
|
|
103
125
|
fixed++;
|
|
104
126
|
} catch {
|
|
105
|
-
//
|
|
127
|
+
// Skip silently — function may be in a transient state
|
|
106
128
|
}
|
|
107
129
|
}
|
|
108
130
|
|
|
@@ -121,23 +143,6 @@ class DeployCommand extends BaseCommand {
|
|
|
121
143
|
return null;
|
|
122
144
|
}
|
|
123
145
|
}
|
|
124
|
-
|
|
125
|
-
findGcloud() {
|
|
126
|
-
const homeDir = require('os').homedir();
|
|
127
|
-
const sdkPath = path.join(homeDir, 'google-cloud-sdk', 'bin', 'gcloud');
|
|
128
|
-
|
|
129
|
-
if (jetpack.exists(sdkPath)) {
|
|
130
|
-
return sdkPath;
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
// Try PATH
|
|
134
|
-
try {
|
|
135
|
-
execSync('which gcloud', { encoding: 'utf8', stdio: ['pipe', 'pipe', 'pipe'] });
|
|
136
|
-
return 'gcloud';
|
|
137
|
-
} catch {
|
|
138
|
-
return null;
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
146
|
}
|
|
142
147
|
|
|
143
148
|
module.exports = DeployCommand;
|