runcloud 0.1.117 → 0.1.118

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/dist/diagnose.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { execFile } from 'node:child_process';
2
2
  import { promisify } from 'node:util';
3
- import { GoogleAuth, Impersonated } from 'google-auth-library';
3
+ import { GoogleAuth } from 'google-auth-library';
4
4
  import { renderSessionDiagnosticTerminal, writeSessionDiagnosticBundle, } from './sessionDiagnostics.js';
5
5
  const execFileAsync = promisify(execFile);
6
6
  const AUTH_ATTEMPT_TIMEOUT_MS = 10_000;
@@ -87,10 +87,8 @@ function extractAuthorization(headers) {
87
87
  const h = headers;
88
88
  return h?.Authorization ?? h?.authorization;
89
89
  }
90
- async function gcloudIdentityToken(audience, serviceAccount) {
91
- const args = ['auth', 'print-identity-token', `--audiences=${audience}`];
92
- if (serviceAccount)
93
- args.push(`--impersonate-service-account=${serviceAccount}`);
90
+ async function gcloudIdentityToken(audience) {
91
+ const args = ['auth', 'print-identity-token', '--audiences=' + audience];
94
92
  const { stdout } = await execFileAsync('gcloud', args, { timeout: 15_000, maxBuffer: 1024 * 1024 });
95
93
  const token = stdout.trim();
96
94
  if (!token)
@@ -123,22 +121,32 @@ function exactAudienceAuthorization(authorization, audience) {
123
121
  }
124
122
  return authorization;
125
123
  }
126
- async function impersonatedIdentityToken(audience, serviceAccount) {
127
- return withDeadline('service-account impersonation', async (signal) => {
124
+ async function serviceAccountIdentityToken(audience, serviceAccount) {
125
+ return withDeadline('service-account ID-token minting', async (signal) => {
128
126
  const sourceClient = await new GoogleAuth({
129
127
  projectId: AUTH_DISCOVERY_PROJECT_ID,
130
128
  scopes: ['https://www.googleapis.com/auth/cloud-platform'],
131
129
  clientOptions: { transporterOptions: { signal, timeout: AUTH_ATTEMPT_TIMEOUT_MS } },
132
130
  }).getClient();
133
- const impersonated = new Impersonated({
134
- sourceClient,
135
- targetPrincipal: serviceAccount,
136
- targetScopes: ['https://www.googleapis.com/auth/cloud-platform'],
137
- lifetime: 600,
138
- transporterOptions: { signal, timeout: AUTH_ATTEMPT_TIMEOUT_MS },
131
+ const sourceToken = await sourceClient.getAccessToken();
132
+ const authorization = typeof sourceToken === 'string' ? sourceToken : sourceToken.token;
133
+ if (!authorization)
134
+ throw new Error('ADC returned an empty source access token');
135
+ const response = await fetch('https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/' +
136
+ encodeURIComponent(serviceAccount) + ':generateIdToken', {
137
+ method: "POST",
138
+ headers: {
139
+ Authorization: 'Bearer ' + authorization,
140
+ 'Content-Type': 'application/json',
141
+ },
142
+ body: JSON.stringify({ audience, includeEmail: true }),
143
+ signal,
139
144
  });
140
- const token = await impersonated.fetchIdToken(audience, { includeEmail: true });
141
- return exactAudienceAuthorization(`Bearer ${token}`, audience);
145
+ const body = await response.json().catch(() => ({}));
146
+ if (!response.ok || typeof body.token !== 'string') {
147
+ throw new Error("generateIdToken failed (" + response.status + "): " + JSON.stringify(body.error ?? body));
148
+ }
149
+ return exactAudienceAuthorization('Bearer ' + body.token, audience);
142
150
  });
143
151
  }
144
152
  export async function resolveOpsAuthHeader(env = process.env, requestedAudience, requestedServiceAccount) {
@@ -158,13 +166,13 @@ export async function resolveOpsAuthHeader(env = process.env, requestedAudience,
158
166
  catch (error) {
159
167
  adcError = error instanceof Error ? error.message : String(error);
160
168
  }
161
- let impersonationError = 'not configured';
169
+ let serviceAccountError = 'not configured';
162
170
  if (serviceAccount && env.DIAGNOSE_DISABLE_IMPERSONATION !== '1') {
163
171
  try {
164
- return await impersonatedIdentityToken(audience, serviceAccount);
172
+ return await serviceAccountIdentityToken(audience, serviceAccount);
165
173
  }
166
174
  catch (error) {
167
- impersonationError = error instanceof Error ? error.message : String(error);
175
+ serviceAccountError = error instanceof Error ? error.message : String(error);
168
176
  }
169
177
  }
170
178
  const token = env.DIAGNOSE_OPS_TOKEN;
@@ -173,13 +181,13 @@ export async function resolveOpsAuthHeader(env = process.env, requestedAudience,
173
181
  }
174
182
  if (env.DIAGNOSE_DISABLE_GCLOUD !== '1') {
175
183
  try {
176
- return exactAudienceAuthorization(`Bearer ${await gcloudIdentityToken(audience, serviceAccount)}`, audience);
184
+ return exactAudienceAuthorization(`Bearer ${await gcloudIdentityToken(audience)}`, audience);
177
185
  }
178
186
  catch (error) {
179
187
  const gcloudError = error instanceof Error ? error.message : String(error);
180
188
  throw new Error(`No usable ops credential for audience ${audience}.\n` +
181
189
  `ADC failed: ${truncate(adcError, 500)}\n` +
182
- `Service-account impersonation failed: ${truncate(impersonationError, 500)}\n` +
190
+ `Service-account ID-token minting failed: ${truncate(serviceAccountError, 500)}\n` +
183
191
  `gcloud failed: ${truncate(gcloudError, 500)}\n\n` +
184
192
  'Repair access by adding the Google identity to control-plane `operators`, applying Terraform, ' +
185
193
  'and running `gcloud auth application-default login`, then rerun. ' +
@@ -188,7 +196,7 @@ export async function resolveOpsAuthHeader(env = process.env, requestedAudience,
188
196
  }
189
197
  throw new Error(`No ops credential available for audience ${audience}. ` +
190
198
  `ADC failed: ${truncate(adcError, 300)}. ` +
191
- `Service-account impersonation failed: ${truncate(impersonationError, 300)}. ` +
199
+ `Service-account ID-token minting failed: ${truncate(serviceAccountError, 300)}. ` +
192
200
  'Run `gcloud auth application-default login` after the operator Terraform has been applied, or export DIAGNOSE_OPS_TOKEN.');
193
201
  }
194
202
  function truncate(value, max = 200) {
package/dist/version.js CHANGED
@@ -1 +1 @@
1
- export const CLI_VERSION = '0.1.117';
1
+ export const CLI_VERSION = '0.1.118';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runcloud",
3
- "version": "0.1.117",
3
+ "version": "0.1.118",
4
4
  "description": "Create and control run.cloud remote mobile simulators and cloud sandboxes",
5
5
  "license": "Apache-2.0",
6
6
  "keywords": [
Binary file
Binary file