backend-manager 5.9.14 → 5.9.16

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "backend-manager",
3
- "version": "5.9.14",
3
+ "version": "5.9.16",
4
4
  "description": "Quick tools for developing Firebase functions",
5
5
  "main": "src/manager/index.js",
6
6
  "files": [
@@ -2,16 +2,10 @@ const BaseCommand = require('./base-command');
2
2
  const chalk = require('chalk').default;
3
3
  const powertools = require('node-powertools');
4
4
  const attachLogFile = require('../utils/attach-log-file');
5
- const { execSync } = require('child_process');
6
5
  const path = require('path');
7
6
  const jetpack = require('fs-jetpack');
8
7
 
9
8
  const DEFAULT_REGION = 'us-central1';
10
- const PUBLIC_HTTP_FUNCTIONS = [
11
- 'bm_api',
12
- 'bm_authBeforeCreate',
13
- 'bm_authBeforeSignIn',
14
- ];
15
9
 
16
10
  class DeployCommand extends BaseCommand {
17
11
  async execute() {
@@ -49,11 +43,14 @@ class DeployCommand extends BaseCommand {
49
43
  }
50
44
 
51
45
  /**
52
- * Ensure HTTP-triggered functions have allUsers as cloudfunctions.invoker.
46
+ * Ensure all HTTP-triggered functions have allUsers as cloudfunctions.invoker.
53
47
  *
54
48
  * Firebase CLI used to set this automatically but stopped around the Node 10
55
49
  * runtime transition. Without it, HTTP requests get a 403 at the IAM level
56
50
  * before BEM's application-level auth (backendManagerKey) can run.
51
+ *
52
+ * Dynamically discovers all deployed functions via gcloud and fixes any
53
+ * HTTP-triggered function missing the allUsers invoker binding.
57
54
  */
58
55
  async ensurePublicInvoker() {
59
56
  const projectId = this.getProjectId();
@@ -62,10 +59,23 @@ class DeployCommand extends BaseCommand {
62
59
  return;
63
60
  }
64
61
 
65
- const gcloud = this.findGcloud();
62
+ // Discover all deployed HTTP-triggered functions
63
+ let httpFunctions;
64
+
65
+ try {
66
+ const output = await powertools.execute(
67
+ `gcloud functions list --project ${projectId} --regions ${DEFAULT_REGION} --format="json(name,httpsTrigger)"`,
68
+ { log: false },
69
+ );
70
+
71
+ httpFunctions = JSON.parse(output)
72
+ .filter((fn) => fn.httpsTrigger)
73
+ .map((fn) => fn.name.split('/').pop());
74
+ } catch {
75
+ return;
76
+ }
66
77
 
67
- if (!gcloud) {
68
- this.log(chalk.gray('\n Skipping public invoker check (gcloud not found)\n'));
78
+ if (!httpFunctions.length) {
69
79
  return;
70
80
  }
71
81
 
@@ -74,12 +84,11 @@ class DeployCommand extends BaseCommand {
74
84
  let fixed = 0;
75
85
  let ok = 0;
76
86
 
77
- for (const fnName of PUBLIC_HTTP_FUNCTIONS) {
87
+ for (const fnName of httpFunctions) {
78
88
  try {
79
- // Check current IAM policy
80
- const policyOutput = execSync(
81
- `${gcloud} functions get-iam-policy ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --format=json`,
82
- { encoding: 'utf8', timeout: 15000, stdio: ['pipe', 'pipe', 'pipe'] },
89
+ const policyOutput = await powertools.execute(
90
+ `gcloud functions get-iam-policy ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --format=json`,
91
+ { log: false },
83
92
  );
84
93
 
85
94
  const policy = JSON.parse(policyOutput);
@@ -93,16 +102,15 @@ class DeployCommand extends BaseCommand {
93
102
  continue;
94
103
  }
95
104
 
96
- // Add allUsers as invoker
97
- execSync(
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'] },
105
+ await powertools.execute(
106
+ `gcloud functions add-iam-policy-binding ${fnName} --project ${projectId} --region ${DEFAULT_REGION} --member="allUsers" --role="roles/cloudfunctions.invoker"`,
107
+ { log: false },
100
108
  );
101
109
 
102
110
  this.log(` ${chalk.green('✓')} Set public invoker on ${chalk.cyan(fnName)}`);
103
111
  fixed++;
104
112
  } catch {
105
- // Function might not exist (not all projects use all functions) — skip silently
113
+ // Skip silently function may be in a transient state
106
114
  }
107
115
  }
108
116
 
@@ -121,23 +129,6 @@ class DeployCommand extends BaseCommand {
121
129
  return null;
122
130
  }
123
131
  }
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
132
  }
142
133
 
143
134
  module.exports = DeployCommand;
@@ -0,0 +1,26 @@
1
+ const BaseTest = require('./base-test');
2
+ const powertools = require('node-powertools');
3
+
4
+ class GcloudCliTest extends BaseTest {
5
+ getName() {
6
+ return 'gcloud CLI is installed (required by deploy)';
7
+ }
8
+
9
+ getWarning() {
10
+ return [
11
+ 'gcloud CLI is not installed.',
12
+ 'Install with: https://cloud.google.com/sdk/docs/install',
13
+ ];
14
+ }
15
+
16
+ async run() {
17
+ try {
18
+ await powertools.execute('gcloud --version', { log: false });
19
+ return true;
20
+ } catch (error) {
21
+ return 'warn';
22
+ }
23
+ }
24
+ }
25
+
26
+ module.exports = GcloudCliTest;
@@ -10,6 +10,7 @@ const NvmrcVersionTest = require('./nvmrc-version');
10
10
  const FirebaseCLITest = require('./firebase-cli');
11
11
  const FirebaseAuthTest = require('./firebase-auth');
12
12
  const JavaInstalledTest = require('./java-installed');
13
+ const GcloudCliTest = require('./gcloud-cli');
13
14
  const FunctionsPackageTest = require('./functions-package');
14
15
  const FirebaseAdminTest = require('./firebase-admin');
15
16
  const FirebaseFunctionsTest = require('./firebase-functions');
@@ -56,6 +57,7 @@ function getTests(context) {
56
57
  new FirebaseCLITest(context),
57
58
  new FirebaseAuthTest(context),
58
59
  new JavaInstalledTest(context),
60
+ new GcloudCliTest(context),
59
61
  new FunctionsPackageTest(context),
60
62
  new FirebaseAdminTest(context),
61
63
  new FirebaseFunctionsTest(context),