@mcpher/gas-fakes 2.2.6 → 2.3.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/README.md +8 -5
- package/package.json +3 -3
- package/src/cli/lib-manager.js +3 -1
- package/src/cli/setup.js +50 -12
- package/src/services/scriptapp/app.js +3 -1
- package/src/services/spreadsheetapp/fakecontainerinfo.js +58 -0
- package/src/services/spreadsheetapp/fakeembeddedchart.js +9 -1
- package/src/support/auth.js +24 -1
- package/src/support/msgraph/msauth.js +1 -1
- package/src/support/sxauth.js +18 -0
package/README.md
CHANGED
|
@@ -19,8 +19,10 @@ For a complete guide on how to set up your local environment for authentication
|
|
|
19
19
|
Collaborators should fork the repo and use the local versions of these files - see collaborators info.
|
|
20
20
|
|
|
21
21
|
### Use exactly the same code as in Apps Script
|
|
22
|
+
## Usage
|
|
23
|
+
Just as on Apps Script, everything is executed synchronously so you don't need to bother with handling Promises/async/await. Just write normal Apps Script code. Usually you would have an associated App Script project if that's your eventual target. Just like Apps Script, you need a manifest file (appsscript.json) so you can be sure that the correct scopes are authorized and asked for.
|
|
22
24
|
|
|
23
|
-
|
|
25
|
+
> **Note on `appsscript.json`:** For full fidelity with live Apps Script, you should have a manifest available. However, as a workaround for "pure" `gas-fakes` projects where there is no intention to run in live Apps Script, if `appsscript.json` is missing or has no scopes, the runtime will automatically emulate one using the `DEFAULT_SCOPES` and `EXTRA_SCOPES` defined in your `.env` file, and will default the script's `timeZone` to `America/New_York` (or `GF_TIMEZONE`).
|
|
24
26
|
|
|
25
27
|
# gas-fakes-cli
|
|
26
28
|
|
|
@@ -168,11 +170,12 @@ As I mentioned earlier, to take this further, I'm going to need a lot of help to
|
|
|
168
170
|
## Read more docs
|
|
169
171
|
|
|
170
172
|
- [gas fakes intro video](https://youtu.be/oEjpIrkYpEM)
|
|
171
|
-
- [getting started](GETTING_STARTED.md) - how to handle authentication for
|
|
173
|
+
- [getting started](GETTING_STARTED.md) - how to handle authentication for Workspace scopes.
|
|
172
174
|
- [readme](README.md)
|
|
173
175
|
- [gas fakes cli](gas-fakes-cli.md)
|
|
174
176
|
- [ksuite as a back end](ksuite_poc.md)
|
|
175
177
|
- [msgraph as a back end](msgraph.md)
|
|
178
|
+
- [gas-fakes in serverless containers](https://docs.google.com/presentation/d/1JlXF9T--DD4ERHopyP3WyAMhjRCxxHblgCP5ynxaJ3k/edit?usp=sharing)
|
|
176
179
|
- [apps script - a lingua franca for workspace platforms](https://ramblings.mcpher.com/apps-script-a-lingua-franca/)
|
|
177
180
|
- [Apps Script: A ‘Lingua Franca’ for the Multi-Cloud Era](https://ramblings.mcpher.com/apps-script-with-ksuite/)
|
|
178
181
|
- [running gas-fakes on google cloud run](https://github.com/brucemcpherson/gas-fakes-containers)
|
|
@@ -191,17 +194,17 @@ As I mentioned earlier, to take this further, I'm going to need a lot of help to
|
|
|
191
194
|
- [oddities](oddities.md) - a collection of oddities uncovered during this project
|
|
192
195
|
- [named colors](named-colors.md)
|
|
193
196
|
- [sandbox](sandbox.md)
|
|
194
|
-
- [senstive scopes](
|
|
197
|
+
- [senstive scopes](workspace_scopes.md)
|
|
195
198
|
- [using apps script libraries with gas-fakes](libraries.md)
|
|
196
199
|
- [how libhandler works](libhandler.md)
|
|
197
200
|
- [article:using apps script libraries with gas-fakes](https://ramblings.mcpher.com/how-to-use-apps-script-libraries-directly-from-node/)
|
|
198
201
|
- [named range identity](named-range-identity.md)
|
|
199
|
-
- [
|
|
202
|
+
- [Workspace scopes with local authentication](workspace_scopes.md)
|
|
200
203
|
- [push test pull](pull-test-push.md)
|
|
201
204
|
- [sharing cache and properties between gas-fakes and live apps script](https://ramblings.mcpher.com/sharing-cache-and-properties-between-gas-fakes-and-live-apps-script/)
|
|
202
205
|
- [gas-fakes-cli now has built in mcp server and gemini extension](https://ramblings.mcpher.com/gas-fakes-cli-now-has-built-in-mcp-server-and-gemini-extension/)
|
|
203
206
|
- [gas-fakes CLI: Run apps script code directly from your terminal](https://ramblings.mcpher.com/gas-fakes-cli-run-apps-script-code-directly-from-your-terminal/)
|
|
204
|
-
- [How to allow access to
|
|
207
|
+
- [How to allow access to Workspace scopes with Application Default Credentials](https://ramblings.mcpher.com/how-to-allow-access-to-sensitive-scopes-with-application-default-credentials/)
|
|
205
208
|
- [Supercharge Your Google Apps Script Caching with GasFlexCache](https://ramblings.mcpher.com/supercharge-your-google-apps-script-caching-with-gasflexcache/)
|
|
206
209
|
- [Fake-Sandbox for Google Apps Script: Granular controls.](https://ramblings.mcpher.com/fake-sandbox-for-google-apps-script-granular-controls/)
|
|
207
210
|
- [A Fake-Sandbox for Google Apps Script: Securely Executing Code Generated by Gemini CLI](https://ramblings.mcpher.com/gas-fakes-sandbox/)
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"node": ">=20.11.0"
|
|
4
4
|
},
|
|
5
5
|
"dependencies": {
|
|
6
|
-
"@azure/identity": "^4.13.
|
|
6
|
+
"@azure/identity": "^4.13.1",
|
|
7
7
|
"@mcpher/fake-gasenum": "^1.0.6",
|
|
8
8
|
"@mcpher/gas-flex-cache": "^1.1.5",
|
|
9
9
|
"@microsoft/microsoft-graph-client": "^3.0.7",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"archiver": "^7.0.1",
|
|
14
14
|
"commander": "^14.0.3",
|
|
15
15
|
"dotenv": "^17.3.1",
|
|
16
|
-
"fast-xml-parser": "^5.
|
|
16
|
+
"fast-xml-parser": "^5.5.9",
|
|
17
17
|
"get-stream": "^9.0.1",
|
|
18
18
|
"google-auth-library": "^10.6.2",
|
|
19
19
|
"googleapis": "^171.4.0",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
},
|
|
40
40
|
"name": "@mcpher/gas-fakes",
|
|
41
41
|
"author": "bruce mcpherson",
|
|
42
|
-
"version": "2.
|
|
42
|
+
"version": "2.3.0",
|
|
43
43
|
"license": "MIT",
|
|
44
44
|
"main": "main.js",
|
|
45
45
|
"description": "An implementation of the Google Workspace Apps Script runtime: Run native App Script Code on Node and Cloud Run",
|
package/src/cli/lib-manager.js
CHANGED
|
@@ -6,8 +6,10 @@ import { checkForGcloudCli, spawnCommand } from "./utils.js";
|
|
|
6
6
|
async function getAccessToken(pattern) {
|
|
7
7
|
if (pattern == 1) {
|
|
8
8
|
// Authorization pattern 1
|
|
9
|
+
// We use cloud-platform as it provides sufficient access for Drive API fetching
|
|
10
|
+
// while avoiding the 'well-known client ID' block that targets Workspace scopes like drive.readonly.
|
|
9
11
|
const auth = await Auth.setAuth(
|
|
10
|
-
["https://www.googleapis.com/auth/
|
|
12
|
+
["https://www.googleapis.com/auth/cloud-platform"],
|
|
11
13
|
true
|
|
12
14
|
);
|
|
13
15
|
auth.cachedCredential = null;
|
package/src/cli/setup.js
CHANGED
|
@@ -285,9 +285,26 @@ export async function initializeConfiguration(options = {}) {
|
|
|
285
285
|
"https://www.googleapis.com/auth/cloud-platform",
|
|
286
286
|
];
|
|
287
287
|
responses.DEFAULT_SCOPES = DEFAULT_SCOPES_VALUES.join(",");
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
288
|
+
|
|
289
|
+
let extraScopes = manifestScopes.filter(s => !DEFAULT_SCOPES_VALUES.includes(s));
|
|
290
|
+
|
|
291
|
+
// Restricted scopes that trigger blocks for the default 'well-known' ADC client ID
|
|
292
|
+
const restrictedMatch = (s) =>
|
|
293
|
+
s.includes("auth/drive") ||
|
|
294
|
+
s.includes("auth/spreadsheets") ||
|
|
295
|
+
s.includes("auth/documents") ||
|
|
296
|
+
s.includes("auth/forms") ||
|
|
297
|
+
s.includes("auth/presentations") ||
|
|
298
|
+
s.includes("auth/script.external_request");
|
|
299
|
+
|
|
300
|
+
if (responses.AUTH_TYPE === "adc" && !responses.CLIENT_CREDENTIAL_FILE) {
|
|
301
|
+
const toSkip = extraScopes.filter(restrictedMatch);
|
|
302
|
+
if (toSkip.length > 0) {
|
|
303
|
+
console.log(`\n\x1b[1;33mWarning: ADC requested with Workspace scopes (${toSkip.map(s => s.split("/").pop()).join(", ")}). Google now blocks these scopes when using the default gcloud CLI client ID. You MUST provide a custom OAuth client credential file.\x1b[0m`);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
responses.EXTRA_SCOPES = extraScopes.join(",");
|
|
291
308
|
|
|
292
309
|
const googleQuestions = [
|
|
293
310
|
{
|
|
@@ -303,12 +320,12 @@ export async function initializeConfiguration(options = {}) {
|
|
|
303
320
|
initial: existingConfig.GOOGLE_SERVICE_ACCOUNT_NAME || "gas-fakes-sa",
|
|
304
321
|
},
|
|
305
322
|
{
|
|
306
|
-
type: "text",
|
|
323
|
+
type: responses.AUTH_TYPE === "adc" ? "text" : null,
|
|
307
324
|
name: "CLIENT_CREDENTIAL_FILE",
|
|
308
|
-
message: "Enter path to OAuth client credentials JSON (optional, required for
|
|
325
|
+
message: "Enter path to OAuth client credentials JSON (optional, required for Workspace scopes with ADC)",
|
|
309
326
|
initial: existingConfig.CLIENT_CREDENTIAL_FILE || "",
|
|
310
327
|
}
|
|
311
|
-
|
|
328
|
+
];
|
|
312
329
|
|
|
313
330
|
const googleResponses = await prompts(googleQuestions);
|
|
314
331
|
if (typeof googleResponses.GOOGLE_CLOUD_PROJECT === "undefined") {
|
|
@@ -342,10 +359,10 @@ export async function initializeConfiguration(options = {}) {
|
|
|
342
359
|
message: "What type of Microsoft account are you using?",
|
|
343
360
|
choices: [
|
|
344
361
|
{ title: "Consumer (Personal, Outlook.com, Hotmail, etc.)", value: "consumers" },
|
|
345
|
-
{ title: "Business/Education (Work or School)", value: "organizations" },
|
|
362
|
+
{ title: "Business/Education (Work or School) ", value: "organizations" },
|
|
346
363
|
{ title: "Standard Multi-tenant", value: "common" }
|
|
347
364
|
],
|
|
348
|
-
initial: existingConfig.MS_GRAPH_TENANT_ID === "
|
|
365
|
+
initial: existingConfig.MS_GRAPH_TENANT_ID === "organizations" ? 1 : (existingConfig.MS_GRAPH_TENANT_ID === "common" ? 2 : 0)
|
|
349
366
|
});
|
|
350
367
|
|
|
351
368
|
if (typeof msAccountType.type === "undefined") {
|
|
@@ -604,13 +621,13 @@ export async function authenticateUser(options = {}) {
|
|
|
604
621
|
const msScopes = mapGasScopesToMsGraph(gasScopes);
|
|
605
622
|
|
|
606
623
|
try {
|
|
624
|
+
const tenantId = process.env.MS_GRAPH_TENANT_ID || 'consumers';
|
|
607
625
|
const azCmd = `az config set core.login_experience_v2=off && az login --allow-no-subscriptions --output none`;
|
|
608
626
|
|
|
609
627
|
console.log(`Executing: ${azCmd}`);
|
|
610
628
|
try {
|
|
611
629
|
runCommandSync(azCmd);
|
|
612
630
|
console.log(`\n\x1b[1;32mSuccess!\x1b[0m Azure CLI session discovered.`);
|
|
613
|
-
const tenantId = process.env.MS_GRAPH_TENANT_ID || 'consumers';
|
|
614
631
|
console.log(`Silent fallback is now enabled for: \x1b[1;36m${tenantId}\x1b[0m`);
|
|
615
632
|
} catch (e) {
|
|
616
633
|
console.error(`\x1b[1;31mAzure CLI Login failed.\x1b[0m`);
|
|
@@ -662,7 +679,27 @@ export async function authenticateUser(options = {}) {
|
|
|
662
679
|
...(EXTRA_SCOPES || "").split(","),
|
|
663
680
|
])).filter(s => s).join(",");
|
|
664
681
|
|
|
665
|
-
|
|
682
|
+
let adcScopes = AUTH_TYPE === "dwd"
|
|
683
|
+
? Array.from(new Set((DEFAULT_SCOPES || "").split(","))).filter(s => s).join(",")
|
|
684
|
+
: scopes;
|
|
685
|
+
|
|
686
|
+
const hasClientId = CLIENT_CREDENTIAL_FILE && fs.existsSync(path.resolve(process.cwd(), CLIENT_CREDENTIAL_FILE));
|
|
687
|
+
if (AUTH_TYPE !== "dwd" && !hasClientId) {
|
|
688
|
+
const scopeList = adcScopes.split(",");
|
|
689
|
+
const workspaceScopes = scopeList.filter(s =>
|
|
690
|
+
s.includes("auth/drive") ||
|
|
691
|
+
s.includes("auth/spreadsheets") ||
|
|
692
|
+
s.includes("auth/documents") ||
|
|
693
|
+
s.includes("auth/forms") ||
|
|
694
|
+
s.includes("auth/presentations")
|
|
695
|
+
);
|
|
696
|
+
|
|
697
|
+
if (workspaceScopes.length > 0) {
|
|
698
|
+
console.warn(`\n\x1b[1;33mWarning: Workspace scopes (${workspaceScopes.map(s => s.split("/").pop()).join(", ")}) requested with ADC and no CLIENT_CREDENTIAL_FILE. This is expected to be blocked by Google.\x1b[0m`);
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
console.log(`...requesting scopes: ${adcScopes}`);
|
|
666
703
|
|
|
667
704
|
const driveAccessFlag = "--enable-gdrive-access";
|
|
668
705
|
const activeConfig = AC || "default";
|
|
@@ -684,7 +721,7 @@ export async function authenticateUser(options = {}) {
|
|
|
684
721
|
runCommandSync(`gcloud auth login ${driveAccessFlag}`);
|
|
685
722
|
|
|
686
723
|
let clientFlag = "";
|
|
687
|
-
if (CLIENT_CREDENTIAL_FILE) {
|
|
724
|
+
if (AUTH_TYPE !== "dwd" && CLIENT_CREDENTIAL_FILE) {
|
|
688
725
|
const clientPath = path.resolve(process.cwd(), CLIENT_CREDENTIAL_FILE);
|
|
689
726
|
if (fs.existsSync(clientPath)) {
|
|
690
727
|
console.log(`...using client credentials from ${clientPath}`);
|
|
@@ -693,7 +730,8 @@ export async function authenticateUser(options = {}) {
|
|
|
693
730
|
}
|
|
694
731
|
|
|
695
732
|
console.log("Setting up Application Default Credentials (ADC)...");
|
|
696
|
-
|
|
733
|
+
const adcScopeFlag = `--scopes="${adcScopes}"`;
|
|
734
|
+
runCommandSync(`gcloud auth application-default login ${adcScopeFlag} ${clientFlag}`.trim());
|
|
697
735
|
runCommandSync(`gcloud auth application-default set-quota-project ${projectId}`);
|
|
698
736
|
|
|
699
737
|
// --- DWD Specific Setup (if configured) ---
|
|
@@ -114,7 +114,9 @@ const checkScopesMatch = (required) => {
|
|
|
114
114
|
"https://www.googleapis.com/auth/script.external_request",
|
|
115
115
|
"https://www.googleapis.com/auth/documents",
|
|
116
116
|
"https://www.googleapis.com/auth/presentations",
|
|
117
|
-
"https://www.googleapis.com/auth/forms"
|
|
117
|
+
"https://www.googleapis.com/auth/forms",
|
|
118
|
+
"https://www.googleapis.com/auth/drive",
|
|
119
|
+
"https://www.googleapis.com/auth/spreadsheets"
|
|
118
120
|
]
|
|
119
121
|
const hasIgnore = ignores.some(i => i.replace(/\/$/, "") === ns)
|
|
120
122
|
if (hasIgnore) {
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { Proxies } from "../../support/proxies.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* create a new FakeContainerInfo instance
|
|
5
|
+
* @param {...any} args
|
|
6
|
+
* @returns {FakeContainerInfo}
|
|
7
|
+
*/
|
|
8
|
+
export const newFakeContainerInfo = (...args) => {
|
|
9
|
+
return Proxies.guard(new FakeContainerInfo(...args));
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Access to the chart's container position.
|
|
14
|
+
*/
|
|
15
|
+
export class FakeContainerInfo {
|
|
16
|
+
/**
|
|
17
|
+
* @param {object} overlayPosition The overlayPosition object from Sheets API
|
|
18
|
+
*/
|
|
19
|
+
constructor(overlayPosition) {
|
|
20
|
+
this.__overlayPosition = overlayPosition || {};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Returns the column index where the drawing is anchored.
|
|
25
|
+
* @returns {number}
|
|
26
|
+
*/
|
|
27
|
+
getAnchorColumn() {
|
|
28
|
+
return (this.__overlayPosition.anchorCell?.columnIndex || 0) + 1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Returns the row index where the drawing is anchored.
|
|
33
|
+
* @returns {number}
|
|
34
|
+
*/
|
|
35
|
+
getAnchorRow() {
|
|
36
|
+
return (this.__overlayPosition.anchorCell?.rowIndex || 0) + 1;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Returns the horizontal offset in pixels from the anchor column.
|
|
41
|
+
* @returns {number}
|
|
42
|
+
*/
|
|
43
|
+
getOffsetX() {
|
|
44
|
+
return this.__overlayPosition.offsetXPixels || 0;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Returns the vertical offset in pixels from the anchor row.
|
|
49
|
+
* @returns {number}
|
|
50
|
+
*/
|
|
51
|
+
getOffsetY() {
|
|
52
|
+
return this.__overlayPosition.offsetYPixels || 0;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
toString() {
|
|
56
|
+
return "ContainerInfo";
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -2,6 +2,7 @@ import { Proxies } from "../../support/proxies.js";
|
|
|
2
2
|
import { notYetImplemented, signatureArgs } from "../../support/helpers.js";
|
|
3
3
|
import { batchUpdate } from "./sheetrangehelpers.js";
|
|
4
4
|
import { newFakeEmbeddedChartBuilder } from "./fakeembeddedchartbuilder.js";
|
|
5
|
+
import { newFakeContainerInfo } from "./fakecontainerinfo.js";
|
|
5
6
|
|
|
6
7
|
/**
|
|
7
8
|
* @returns {FakeEmbeddedChart}
|
|
@@ -25,13 +26,20 @@ export class FakeEmbeddedChart {
|
|
|
25
26
|
const props = [
|
|
26
27
|
"getAs",
|
|
27
28
|
"getBlob",
|
|
28
|
-
"getContainerInfo",
|
|
29
29
|
];
|
|
30
30
|
props.forEach((f) => {
|
|
31
31
|
this[f] = () => notYetImplemented(f);
|
|
32
32
|
});
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
+
/**
|
|
36
|
+
* Returns information about where the chart is positioned within a sheet.
|
|
37
|
+
* @returns {FakeContainerInfo}
|
|
38
|
+
*/
|
|
39
|
+
getContainerInfo() {
|
|
40
|
+
return newFakeContainerInfo(this.__apiChart.position?.overlayPosition);
|
|
41
|
+
}
|
|
42
|
+
|
|
35
43
|
/**
|
|
36
44
|
* Returns the ID of this chart.
|
|
37
45
|
* @returns {number}
|
package/src/support/auth.js
CHANGED
|
@@ -167,6 +167,22 @@ const setAuth = async (scopes = [], mcpLoading = false) => {
|
|
|
167
167
|
|
|
168
168
|
if (!useDwd) {
|
|
169
169
|
id.authMethod = 'adc'
|
|
170
|
+
|
|
171
|
+
const workspaceScopes = scopes.filter(s =>
|
|
172
|
+
s.includes('auth/drive') ||
|
|
173
|
+
s.includes('auth/spreadsheets') ||
|
|
174
|
+
s.includes('auth/documents') ||
|
|
175
|
+
s.includes('auth/forms') ||
|
|
176
|
+
s.includes('auth/presentations')
|
|
177
|
+
)
|
|
178
|
+
|
|
179
|
+
const creds = await id.auth.getCredentials();
|
|
180
|
+
const isDefaultClient = creds && creds.client_id === '764086051850-6qr4p6gpi6hn506pt8ejuq83di341hur.apps.googleusercontent.com';
|
|
181
|
+
|
|
182
|
+
if (isDefaultClient && workspaceScopes.length > 0) {
|
|
183
|
+
throw new Error(`ADC error: Google no longer allows the use of the default gcloud client ID for regular Workspace scopes (${workspaceScopes.map(s => s.split('/').pop()).join(', ')}). You must use a custom client credential file. See https://docs.cloud.google.com/docs/authentication/troubleshoot-adc#access_blocked_when_using_scopes`);
|
|
184
|
+
}
|
|
185
|
+
|
|
170
186
|
id.authClient = await id.auth.getClient({ scopes })
|
|
171
187
|
id.sourceClient = id.authClient
|
|
172
188
|
} else {
|
|
@@ -175,7 +191,14 @@ const setAuth = async (scopes = [], mcpLoading = false) => {
|
|
|
175
191
|
id.authMethod = 'dwd'
|
|
176
192
|
const targetPrincipal = `${saName}@${id.projectId}.iam.gserviceaccount.com`
|
|
177
193
|
|
|
178
|
-
|
|
194
|
+
// For DWD source client, we only need identity and enough scope to sign JWT
|
|
195
|
+
// cloud-platform is sufficient for IAM signJwt and avoid Drive-related blocks
|
|
196
|
+
const sourceScopes = scopes.filter(s =>
|
|
197
|
+
s === 'openid' ||
|
|
198
|
+
s === 'https://www.googleapis.com/auth/userinfo.email' ||
|
|
199
|
+
s === 'https://www.googleapis.com/auth/cloud-platform'
|
|
200
|
+
)
|
|
201
|
+
|
|
179
202
|
id.sourceClient = await id.auth.getClient(sourceScopes.length > 0 ? { scopes: sourceScopes } : {})
|
|
180
203
|
|
|
181
204
|
const { tokenInfo: userInfo } = await _getTokenInfo(id.sourceClient);
|
|
@@ -166,7 +166,7 @@ async function isGcpEnv() {
|
|
|
166
166
|
* Gets a Microsoft Graph token.
|
|
167
167
|
*/
|
|
168
168
|
export async function getMsGraphToken(scopes = ['User.Read']) {
|
|
169
|
-
const envTenant = process.env.MS_GRAPH_TENANT_ID || '
|
|
169
|
+
const envTenant = process.env.MS_GRAPH_TENANT_ID || 'consumers';
|
|
170
170
|
const clientId = process.env.MS_GRAPH_CLIENT_ID;
|
|
171
171
|
const clientSecret = process.env.MS_GRAPH_CLIENT_SECRET;
|
|
172
172
|
const msAuthType = process.env.MS_AUTH_TYPE;
|
package/src/support/sxauth.js
CHANGED
|
@@ -52,6 +52,24 @@ export const sxInit = async ({ manifestPath, claspPath, settingsPath, cachePath,
|
|
|
52
52
|
getIfExists(claspFile)
|
|
53
53
|
])
|
|
54
54
|
|
|
55
|
+
// Emulate manifest scopes from .env if missing or empty
|
|
56
|
+
if (!manifest.oauthScopes || manifest.oauthScopes.length === 0) {
|
|
57
|
+
const envScopes = Array.from(new Set([
|
|
58
|
+
...(process.env.DEFAULT_SCOPES || "").split(","),
|
|
59
|
+
...(process.env.EXTRA_SCOPES || "").split(",")
|
|
60
|
+
])).map(s => s.trim()).filter(s => s);
|
|
61
|
+
|
|
62
|
+
if (envScopes.length > 0) {
|
|
63
|
+
manifest.oauthScopes = envScopes;
|
|
64
|
+
if (!manifest.timeZone) {
|
|
65
|
+
manifest.timeZone = process.env.GF_TIMEZONE || "America/New_York";
|
|
66
|
+
}
|
|
67
|
+
if (!_loggedSummary) {
|
|
68
|
+
syncLog(`...appsscript.json missing or missing scopes. Emulating manifest using scopes from .env file`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
55
73
|
const settings = {
|
|
56
74
|
manifest: manifestFile,
|
|
57
75
|
clasp: claspFile,
|