@mcpher/gas-fakes 1.0.19 → 1.0.21
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 +63 -30
- package/gasmess/bruce/pbx.js +53 -2
- package/gprompts/gas-inventory.js +92 -0
- package/gprompts/gas-inventory.json +176 -0
- package/gprompts/inventory-list.json +1 -0
- package/gprompts/model.json +34 -0
- package/gprompts/package-lock.json +1103 -0
- package/gprompts/package.json +18 -0
- package/gprompts/temp_fetch.mjs +9 -0
- package/gprompts/update-progress.js +142 -0
- package/package.json +6 -2
- package/setup.sh +147 -0
- package/src/index.js +9 -2
- package/src/services/advdocs/app.js +4 -23
- package/src/services/advdrive/app.js +6 -28
- package/src/services/advforms/app.js +6 -25
- package/src/services/advgmail/app.js +11 -0
- package/src/services/advgmail/fakeadvgmail.js +39 -0
- package/src/services/advgmail/fakeadvgmaillabels.js +119 -0
- package/src/services/advgmail/fakeadvgmailusers.js +23 -0
- package/src/services/advgmail/gmailapis.js +15 -0
- package/src/services/advsheets/app.js +6 -26
- package/src/services/advslides/app.js +6 -28
- package/src/services/common/lazyloader.js +22 -0
- package/src/services/documentapp/app.js +8 -42
- package/src/services/documentapp/appenderhelpers.js +21 -23
- package/src/services/documentapp/elementhelpers.js +0 -1
- package/src/services/documentapp/elementoptions.js +22 -32
- package/src/services/documentapp/fakeelement.js +20 -3
- package/src/services/documentapp/fakelistitem.js +177 -28
- package/src/services/documentapp/fakeparagraph.js +194 -7
- package/src/services/documentapp/faketable.js +16 -0
- package/src/services/documentapp/faketablerow.js +15 -0
- package/src/services/documentapp/nrhelpers.js +1 -0
- package/src/services/documentapp/shadowdocument.js +10 -0
- package/src/services/driveapp/app.js +6 -28
- package/src/services/enums/gmailenums.js +8 -0
- package/src/services/formapp/app.js +5 -40
- package/src/services/gmailapp/app.js +11 -0
- package/src/services/gmailapp/fakegmailapp.js +35 -0
- package/src/services/gmailapp/fakegmaillabel.js +44 -0
- package/src/services/logger/app.js +8 -0
- package/src/services/logger/fakelogger.js +162 -0
- package/src/services/scriptapp/app.js +7 -1
- package/src/services/scriptapp/behavior.js +1 -1
- package/src/services/session/app.js +10 -0
- package/src/services/slidesapp/app.js +5 -40
- package/src/services/spreadsheetapp/app.js +6 -50
- package/src/services/spreadsheetapp/fakeprotection.js +6 -7
- package/src/services/spreadsheetapp/fakesheet.js +3 -4
- package/src/services/stores/app.js +0 -1
- package/src/services/urlfetchapp/app.js +0 -1
- package/src/services/utilities/app.js +6 -20
- package/src/support/gmailcacher.js +7 -0
- package/src/support/helpers.js +2 -2
- package/src/support/proxies.js +20 -1
- package/src/support/sxgmail.js +55 -0
- package/src/support/syncit.js +5 -2
- package/src/support/utils.js +46 -15
- package/src/support/workersync/sxfunctions.js +5 -10
- package/togas.bash +18 -5
- package/ghissues/image-size-inconsistency-issue.sh +0 -46
- package/ghissues/issue-formapp-create-title-inconsistency.sh +0 -51
- package/ghissues/issue-positioned-image.sh +0 -25
- package/ghissues/post-issue.sh +0 -53
- package/ghissues/protection-editors-issue.sh +0 -33
- package/ghissues/review-sandbox-listing-issue.sh +0 -45
- package/ghissues/sandbox-issue.sh +0 -31
- package/ghissues/setup-under-construction.sh +0 -107
- package/src/services/base/app.js +0 -33
- /package/{regenerate-progress-reports.sh → gprompts/regenerate-progress-reports.sh} +0 -0
- /package/src/services/{base → session}/fakesession.js +0 -0
package/src/support/utils.js
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import is from '@sindresorhus/is';
|
|
4
4
|
import { assert } from '@sindresorhus/is'
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
const isNU = (item) => is.null(item) || is.undefined(item)
|
|
7
8
|
|
|
8
9
|
const arrify = (item) => is.array(item)
|
|
@@ -128,7 +129,7 @@ export const mergeParamStrings = (...args) => {
|
|
|
128
129
|
}
|
|
129
130
|
const [_, key, items] = match
|
|
130
131
|
if (!itemMap.has(key)) itemMap.set(key, new Set())
|
|
131
|
-
const item = itemMap.get(key)
|
|
132
|
+
const item = itemMap.get(key)
|
|
132
133
|
assert.set(item)
|
|
133
134
|
items.split(",").forEach(f => itemMap.get(key).add(f))
|
|
134
135
|
})
|
|
@@ -376,29 +377,59 @@ const deepEqual = (obj1, obj2) => {
|
|
|
376
377
|
}
|
|
377
378
|
|
|
378
379
|
return true;
|
|
379
|
-
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
function stringCircular(obj, space = null) {
|
|
384
|
+
// First pass: remove circular references
|
|
385
|
+
const withoutCircular = removeCircularReferences(obj);
|
|
380
386
|
|
|
381
|
-
//
|
|
382
|
-
const
|
|
383
|
-
|
|
384
|
-
return (
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
387
|
+
// Second pass: stabilize key order
|
|
388
|
+
const stabilized = stabilizeKeyOrder(withoutCircular);
|
|
389
|
+
|
|
390
|
+
return JSON.stringify(stabilized, null, space);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function removeCircularReferences(obj) {
|
|
394
|
+
const seen = new WeakSet();
|
|
395
|
+
|
|
396
|
+
return JSON.parse(JSON.stringify(obj, (key, value) => {
|
|
397
|
+
if (typeof value === 'object' && value !== null) {
|
|
388
398
|
if (seen.has(value)) {
|
|
389
|
-
return
|
|
399
|
+
return '[Circular]';
|
|
390
400
|
}
|
|
391
|
-
// If it's a new object, add it to our cache
|
|
392
401
|
seen.add(value);
|
|
393
402
|
}
|
|
394
|
-
// Return the value to be serialized
|
|
395
403
|
return value;
|
|
396
|
-
};
|
|
397
|
-
}
|
|
404
|
+
}));
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function stabilizeKeyOrder(obj) {
|
|
408
|
+
if (obj === null || typeof obj !== 'object') {
|
|
409
|
+
return obj;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if (Array.isArray(obj)) {
|
|
413
|
+
return obj.map(stabilizeKeyOrder);
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
const sortedKeys = Object.keys(obj).sort();
|
|
417
|
+
const result = {};
|
|
398
418
|
|
|
399
|
-
const
|
|
419
|
+
for (const key of sortedKeys) {
|
|
420
|
+
result[key] = stabilizeKeyOrder(obj[key]);
|
|
421
|
+
}
|
|
400
422
|
|
|
423
|
+
return result;
|
|
424
|
+
}
|
|
425
|
+
const lobify = (ob, mess = '') => {
|
|
426
|
+
let lob = ob
|
|
427
|
+
if (is.object(lob)) lob = stringCircular(lob)
|
|
428
|
+
console.log(mess, lob)
|
|
429
|
+
return ob
|
|
430
|
+
}
|
|
401
431
|
export const Utils = {
|
|
432
|
+
lobify,
|
|
402
433
|
stringCircular,
|
|
403
434
|
hexToRgb,
|
|
404
435
|
stringToBytes,
|
|
@@ -1,15 +1,10 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file aggregates and exports all the asynchronous functions
|
|
3
|
-
* that can be called by the main thread via the synchronizer.
|
|
4
|
-
* The worker thread imports this single file to get access to all
|
|
5
|
-
* sx* functions.
|
|
6
|
-
*/
|
|
7
|
-
export * from '../sxauth.js';
|
|
8
1
|
export * from '../sxdrive.js';
|
|
9
2
|
export * from '../sxsheets.js';
|
|
10
3
|
export * from '../sxdocs.js';
|
|
11
|
-
export * from '../sxforms.js';
|
|
12
4
|
export * from '../sxslides.js';
|
|
13
|
-
export * from '../
|
|
5
|
+
export * from '../sxforms.js';
|
|
14
6
|
export * from '../sxfetch.js';
|
|
15
|
-
export * from '../sxstore.js';
|
|
7
|
+
export * from '../sxstore.js';
|
|
8
|
+
export * from '../sxzip.js';
|
|
9
|
+
export * from '../sxauth.js';
|
|
10
|
+
export * from '../sxgmail.js';
|
package/togas.bash
CHANGED
|
@@ -25,15 +25,26 @@ cp ${SOURCE}/test*.js ${TARGET}/test
|
|
|
25
25
|
|
|
26
26
|
# find all the copied files and comment/fixes out import and export statements
|
|
27
27
|
# note - this simple version naively expects that to be on 1 line
|
|
28
|
-
|
|
28
|
+
# version below only works on linux - the perl version should work on both mac and linux
|
|
29
|
+
#find "${TARGET}" -name "${EXT}" -type f -exec perl -i -pe 'if (/^import\b/) { $in_import=1 } if ($in_import) { s/^/\/\//; if (/['\''"][^'\''"]*['\''"];?\s*$/) { $in_import=0 } }' {} +
|
|
29
30
|
# sed -i 's/^import\s\s*/\/\/import /g' $(find "${TARGET}" -name "${EXT}" -type f)
|
|
30
|
-
sed -i 's/^\s*export\s\s*//g' $(find "${TARGET}" -name "${EXT}" -type f)
|
|
31
|
+
#sed -i 's/^\s*export\s\s*//g' $(find "${TARGET}" -name "${EXT}" -type f)
|
|
32
|
+
|
|
31
33
|
|
|
34
|
+
# Perl works consistently across platforms
|
|
35
|
+
find "${TARGET}" -name "${EXT}" -type f -exec perl -i -pe 's/^\s*export\s\s*//g' {} \;
|
|
36
|
+
find "${TARGET}" -name "${EXT}" -type f -exec perl -i -pe 'if (/^import\b/) { $in_import=1 } if ($in_import) { s/^/\/\//; if (/['\''"][^'\''"]*['\''"];?\s*$/) { $in_import=0 } }' {} +
|
|
37
|
+
# sed -i 's/^import\s\s*/\/\/import /g' $(find "${TARGET}" -name "${EXT}" -type f)
|
|
32
38
|
# replace all process.env.VAR_NAME occurrences with actual value
|
|
33
39
|
# process.env is not usable in apps script
|
|
34
|
-
for var in $(grep -oP 'process\.env\.\K\w+' "${TARGET}/test/testinit.js"); do
|
|
35
|
-
|
|
40
|
+
#for var in $(grep -oP 'process\.env\.\K\w+' "${TARGET}/test/testinit.js"); do
|
|
41
|
+
|
|
42
|
+
# Use macos + linux version
|
|
43
|
+
vars=($(grep -oE 'process\.env\.\w+' "${TARGET}/test/testinit.js" | sed 's/process\.env\.//'))
|
|
36
44
|
|
|
45
|
+
for var in "${vars[@]}"; do
|
|
46
|
+
|
|
47
|
+
value=$(printenv "$var") # Get the environment variable value
|
|
37
48
|
|
|
38
49
|
# Escape characters for sed, e.g. \n becomes \\n, & becomes \&
|
|
39
50
|
value=$(printf '%q' "$value")
|
|
@@ -44,7 +55,9 @@ for var in $(grep -oP 'process\.env\.\K\w+' "${TARGET}/test/testinit.js"); do
|
|
|
44
55
|
fi
|
|
45
56
|
|
|
46
57
|
# Replace process.env.VARIABLE_NAME with the actual value
|
|
47
|
-
sed -i "s|process.env.$var|$value|g" ${TARGET}/test/testinit.js
|
|
58
|
+
#sed -i "s|process.env.$var|$value|g" ${TARGET}/test/testinit.js
|
|
59
|
+
#macos + linux
|
|
60
|
+
sed -i "" "s|process.env.$var|$value|g" "${TARGET}/test/testinit.js"
|
|
48
61
|
done
|
|
49
62
|
|
|
50
63
|
# now go to the target and push and open if required
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to create a GitHub issue for the image sizing inconsistency.
|
|
4
|
-
|
|
5
|
-
# Issue title
|
|
6
|
-
TITLE="Investigate and Align Image Insertion Sizing Behavior"
|
|
7
|
-
|
|
8
|
-
# Issue body in markdown
|
|
9
|
-
BODY=$(cat <<'EOF'
|
|
10
|
-
## Summary
|
|
11
|
-
|
|
12
|
-
There is a significant and inconsistent discrepancy in how the live `DocumentApp` service and the `gas-fakes` emulation (via the Docs API) handle the dimensions of an image when it is inserted using `body.insertImage(image.copy())` or `body.appendImage(image.copy())`.
|
|
13
|
-
|
|
14
|
-
The `testdocsimages.js` test suite has repeatedly failed and required adjustments because the expected dimensions of the inserted image are unpredictable in the live environment.
|
|
15
|
-
|
|
16
|
-
## Observed Behaviors in Live Apps Script
|
|
17
|
-
|
|
18
|
-
Our testing has revealed several conflicting behaviors from the live API:
|
|
19
|
-
|
|
20
|
-
1. **Intrinsic Size:** Sometimes, the API ignores the dimensions of the copied `InlineImage` object and re-fetches the image from its source URI, using its original intrinsic dimensions (e.g., `544x184` for the Google logo).
|
|
21
|
-
2. **Copied Object Size:** At other times, the API correctly respects the dimensions of the copied `InlineImage` object (e.g., `61x181` in our tests).
|
|
22
|
-
3. **Default/Fixed Size:** On at least one occasion, the API appeared to resize the image to a seemingly arbitrary fixed size (e.g., `240x80`).
|
|
23
|
-
4. **State-Dependent:** The behavior seems to be dependent on the state of the document. A brand-new document might exhibit one behavior, while a reused document (even after `doc.clear()`) exhibits another.
|
|
24
|
-
|
|
25
|
-
## Current Workaround
|
|
26
|
-
|
|
27
|
-
The current test (`insertImage behavior on new documents` in `testdocsimages.js`) has been made more robust by:
|
|
28
|
-
- Forcing the creation of a new document for the test using `maketdoc(..., { forceNew: true })`.
|
|
29
|
-
- Abandoning exact dimension checks in the live environment and instead verifying the image's **aspect ratio** within a tolerance.
|
|
30
|
-
|
|
31
|
-
While this makes the test pass, it highlights a core emulation inaccuracy.
|
|
32
|
-
|
|
33
|
-
## TODO
|
|
34
|
-
|
|
35
|
-
1. **Investigate Further:** Conduct a definitive set of tests to determine if there is *any* predictable pattern to the live API's behavior.
|
|
36
|
-
2. **Decide on Emulation Strategy:**
|
|
37
|
-
- Should `gas-fakes` emulate the most common or most "correct" behavior (i.e., respecting the copied object's dimensions)?
|
|
38
|
-
- Or should it attempt to mimic the most recently observed "new document" behavior (using intrinsic size)?
|
|
39
|
-
3. **Document the Oddity:** Regardless of the chosen strategy, this inconsistency is a significant "oddity" and should be thoroughly documented in `oddities.md` to inform users who might encounter similar issues when working with images in `DocumentApp`.
|
|
40
|
-
|
|
41
|
-
This will improve the accuracy of the fake environment and provide valuable documentation for the community.
|
|
42
|
-
EOF
|
|
43
|
-
)
|
|
44
|
-
|
|
45
|
-
# Create the issue using GitHub CLI
|
|
46
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "bug" --label "emulation-accuracy" --label "document-app"
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to create a GitHub issue for the FormApp.create() title inconsistency.
|
|
4
|
-
|
|
5
|
-
# Issue title
|
|
6
|
-
TITLE="Discrepancy between FormApp.create(title) and Forms API behavior regarding form title and file name"
|
|
7
|
-
|
|
8
|
-
# Issue body in markdown
|
|
9
|
-
BODY=$(cat <<'EOF'
|
|
10
|
-
### Summary
|
|
11
|
-
|
|
12
|
-
There is a significant and counter-intuitive discrepancy between the documented behavior of `FormApp.create(title)` in Google Apps Script and the constraints of the underlying Google Forms API. `FormApp.create(title)` sets the Google Drive *file name* to the provided `title`, but leaves the form's internal title (retrieved by `form.getTitle()`) blank.
|
|
13
|
-
|
|
14
|
-
This makes it impossible to accurately emulate the Apps Script behavior using the public Forms API, as the API requires a non-empty title for both creation and updates.
|
|
15
|
-
|
|
16
|
-
### Live Apps Script Behavior
|
|
17
|
-
|
|
18
|
-
When the following Apps Script code is executed:
|
|
19
|
-
|
|
20
|
-
```javascript
|
|
21
|
-
function testFormCreation() {
|
|
22
|
-
const formName = "foo-form";
|
|
23
|
-
const form = FormApp.create(formName);
|
|
24
|
-
const id = form.getId();
|
|
25
|
-
|
|
26
|
-
console.log('Internal form title:', form.getTitle()); // Logs: "" (an empty string)
|
|
27
|
-
|
|
28
|
-
const file = DriveApp.getFileById(id);
|
|
29
|
-
console.log('Drive file name:', file.getName()); // Logs: "foo-form"
|
|
30
|
-
|
|
31
|
-
// cleanup
|
|
32
|
-
file.setTrashed(true);
|
|
33
|
-
}
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The output demonstrates that `FormApp.create()` uses the argument to set the Drive file name, but the form's own title property remains empty.
|
|
37
|
-
|
|
38
|
-
### The Problem with API Emulation
|
|
39
|
-
|
|
40
|
-
This behavior is problematic to replicate with the v1 Google Forms API because the `forms.create` method requires a non-empty `info.title`. Attempting to then `batchUpdate` the title to an empty string also fails, as the API rejects an empty title on update.
|
|
41
|
-
|
|
42
|
-
### Conclusion
|
|
43
|
-
|
|
44
|
-
This disconnect means it's impossible for developers using the public Forms API to programmatically create a form that exactly matches the state of one created by `FormApp.create()`. This poses a significant challenge for testing and emulation frameworks.
|
|
45
|
-
|
|
46
|
-
The expected behavior would be for `FormApp.create(title)` to set both the Drive file name and the internal form title, or for the API to allow setting the title to an empty string via an update.
|
|
47
|
-
EOF
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
# Create the issue using GitHub CLI
|
|
51
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "bug" --label "emulation-accuracy" --label "form-app"
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A script to create a GitHub issue for the PositionedImage API limitation.
|
|
4
|
-
|
|
5
|
-
# Issue details
|
|
6
|
-
TITLE="Cannot emulate Paragraph.addPositionedImage() due to missing public API"
|
|
7
|
-
BODY=$(cat <<'EOF'
|
|
8
|
-
The `DocumentApp.Paragraph.addPositionedImage()` method exists in the live Google Apps Script environment, allowing for the creation of positioned images anchored to a paragraph.
|
|
9
|
-
|
|
10
|
-
However, as of May 2024, there is no corresponding public endpoint in the Google Docs API v1 to programmatically create a `PositionedObject`. The `createPositionedObject` request does not exist in the public API.
|
|
11
|
-
|
|
12
|
-
This has been a requested feature, but it appears that the Apps Script service uses a private, non-public API to achieve this functionality.
|
|
13
|
-
|
|
14
|
-
Because `gas-fakes` relies exclusively on the public Google Workspace APIs, it is not possible to emulate this method. Tests that use `addPositionedImage` are skipped when run in the fake environment.
|
|
15
|
-
|
|
16
|
-
This issue is to track this limitation and can be closed if Google exposes a public API for this feature.
|
|
17
|
-
|
|
18
|
-
See this related issue tracker for the API feature request: https://issuetracker.google.com/issues/183845501 (Note: This is a guess at a relevant issue, a real one might need to be found or created).
|
|
19
|
-
EOF
|
|
20
|
-
)
|
|
21
|
-
LABELS="emulation-accuracy,document-app"
|
|
22
|
-
|
|
23
|
-
# Create the issue using the GitHub CLI
|
|
24
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "$LABELS"
|
|
25
|
-
|
package/ghissues/post-issue.sh
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to post a markdown file from ./ghissues as a GitHub issue.
|
|
4
|
-
# It automatically extracts the title, labels, and body from the file.
|
|
5
|
-
#
|
|
6
|
-
# Usage: ./ghissues/post-issue.sh <filename>
|
|
7
|
-
# Example: ./ghissues/post-issue.sh document-clear-behavior.md
|
|
8
|
-
|
|
9
|
-
set -e
|
|
10
|
-
|
|
11
|
-
# The directory where issue files are stored, relative to the script's location.
|
|
12
|
-
SCRIPT_DIR=$(dirname "$0")
|
|
13
|
-
|
|
14
|
-
# Check for filename argument
|
|
15
|
-
if [ -z "$1" ]; then
|
|
16
|
-
echo "Usage: $0 <filename_in_ghissues_dir>"
|
|
17
|
-
echo "Example: $0 document-clear-behavior.md"
|
|
18
|
-
exit 1
|
|
19
|
-
fi
|
|
20
|
-
|
|
21
|
-
ISSUE_FILE="$SCRIPT_DIR/$1"
|
|
22
|
-
|
|
23
|
-
# Check if file exists
|
|
24
|
-
if [ ! -f "$ISSUE_FILE" ]; then
|
|
25
|
-
echo "Error: Issue file not found at $ISSUE_FILE"
|
|
26
|
-
exit 1
|
|
27
|
-
fi
|
|
28
|
-
|
|
29
|
-
echo "Reading issue from $ISSUE_FILE..."
|
|
30
|
-
|
|
31
|
-
# Extract the title (first line, remove markdown heading)
|
|
32
|
-
TITLE=$(head -n 1 "$ISSUE_FILE" | sed 's/^# //')
|
|
33
|
-
|
|
34
|
-
# Extract labels from the second line (e.g., **Labels**: `label1`, `label2`)
|
|
35
|
-
LABELS_LINE=$(sed -n '2p' "$ISSUE_FILE")
|
|
36
|
-
LABELS_STRING=$(echo "$LABELS_LINE" | grep -o '`.*`' | sed 's/`//g' || echo "")
|
|
37
|
-
|
|
38
|
-
LABEL_ARGS=()
|
|
39
|
-
if [ -n "$LABELS_STRING" ]; then
|
|
40
|
-
IFS=',' read -ra ADDR <<< "$LABELS_STRING"
|
|
41
|
-
for label in "${ADDR[@]}"; do
|
|
42
|
-
trimmed_label=$(echo "$label" | xargs) # trim whitespace
|
|
43
|
-
if [ -n "$trimmed_label" ]; then
|
|
44
|
-
LABEL_ARGS+=("--label" "$trimmed_label")
|
|
45
|
-
fi
|
|
46
|
-
done
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# Use the rest of the file (from line 3) as the body
|
|
50
|
-
gh issue create --title "$TITLE" --body-file <(tail -n +3 "$ISSUE_FILE") "${LABEL_ARGS[@]}"
|
|
51
|
-
|
|
52
|
-
echo "Issue '$TITLE' created successfully."
|
|
53
|
-
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to create a GitHub issue for the Protection.getEditors() behavior.
|
|
4
|
-
|
|
5
|
-
# Issue title
|
|
6
|
-
TITLE="Align Protection.getEditors() behavior with Live Apps Script"
|
|
7
|
-
|
|
8
|
-
# Issue body in markdown
|
|
9
|
-
BODY=$(cat <<'EOF'
|
|
10
|
-
## Summary
|
|
11
|
-
|
|
12
|
-
There is a discrepancy between the live Google Apps Script environment and the `gas-fakes` emulation regarding the return value of `Protection.getEditors()` on a newly created protection.
|
|
13
|
-
|
|
14
|
-
- **Live Apps Script:** `protection.getEditors().length` returns `0`.
|
|
15
|
-
- **`gas-fakes` (current):** `protection.getEditors().length` incorrectly returns `1`.
|
|
16
|
-
|
|
17
|
-
## Live Behavior Details
|
|
18
|
-
|
|
19
|
-
In the live environment, the owner of a spreadsheet can always edit a protected range or sheet (`protection.canEdit()` returns `true`). However, the owner is **not** automatically included in the explicit list of editors returned by `getEditors()`. This is confirmed by live testing.
|
|
20
|
-
|
|
21
|
-
## `gas-fakes` Behavior
|
|
22
|
-
|
|
23
|
-
The `gas-fakes` implementation in `fakeprotection.js` was incorrectly adding the current user (as the owner) to the list of editors upon creation of a new `Protection` object.
|
|
24
|
-
|
|
25
|
-
## TODO
|
|
26
|
-
|
|
27
|
-
1. Modify `fakeprotection.js` to no longer automatically add the owner to the `editors` list when a new protection is created. The `canEdit()` method should still return `true` for the owner.
|
|
28
|
-
2. Run the full test suite to ensure this change doesn't have unintended side effects and that the `Protection` tests now pass in both environments.
|
|
29
|
-
EOF
|
|
30
|
-
)
|
|
31
|
-
|
|
32
|
-
# Create the issue using GitHub CLI
|
|
33
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "bug" --label "emulation-accuracy" --label "spreadsheet-app"
|
|
@@ -1,45 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to create a GitHub issue for reviewing sandbox listing behavior.
|
|
4
|
-
|
|
5
|
-
# Issue title
|
|
6
|
-
TITLE="Review Sandbox Strategy for File Listing Operations"
|
|
7
|
-
|
|
8
|
-
# Issue body in markdown
|
|
9
|
-
BODY=$(cat <<'EOF'
|
|
10
|
-
## Summary
|
|
11
|
-
|
|
12
|
-
Currently, tests that perform broad file/folder listing operations (e.g., `DriveApp.getFiles()`, `someFolder.getFolders()`) fail when `strictSandbox` is `true`. This is because the underlying iterators may need to access metadata of parent folders that are not explicitly whitelisted, causing the sandbox to correctly deny access.
|
|
13
|
-
|
|
14
|
-
The current workaround, as implemented in `testdrive.js`, is to temporarily disable `strictSandbox` for the duration of these tests:
|
|
15
|
-
|
|
16
|
-
```javascript
|
|
17
|
-
const wasStrict = behavior.strictSandbox;
|
|
18
|
-
behavior.strictSandbox = false;
|
|
19
|
-
try {
|
|
20
|
-
// ... listing operations ...
|
|
21
|
-
} finally {
|
|
22
|
-
behavior.strictSandbox = wasStrict;
|
|
23
|
-
}
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
While this works, it feels like a patch rather than a fundamental solution. We should review if there's a more robust and elegant way to handle this.
|
|
27
|
-
|
|
28
|
-
## TODO
|
|
29
|
-
|
|
30
|
-
Investigate and decide on the best long-term strategy for handling file listings in strict sandbox mode.
|
|
31
|
-
|
|
32
|
-
### Options to Consider:
|
|
33
|
-
|
|
34
|
-
1. **Implicit Parent Whitelisting:** Could the file/folder iterators be enhanced to automatically (and temporarily) whitelist parent folders as they are encountered? This would keep the sandbox strict for all other operations but allow listings to complete. This seems like the most robust solution if feasible.
|
|
35
|
-
|
|
36
|
-
2. **Refined Iterator Logic:** Can the iterators be modified to avoid the specific checks that cause the failure when in strict mode? This might involve fetching less metadata for items outside the session/whitelist scope.
|
|
37
|
-
|
|
38
|
-
3. **Accept and Document:** If the current `try...finally` workaround is deemed the most practical approach, we should formally document it in `sandbox.md` as the recommended pattern for this scenario.
|
|
39
|
-
|
|
40
|
-
This review will help ensure the sandbox feature is both as secure and as user-friendly as possible.
|
|
41
|
-
EOF
|
|
42
|
-
)
|
|
43
|
-
|
|
44
|
-
# Create the issue using GitHub CLI
|
|
45
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "enhancement"
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
# A shell script to create a GitHub issue for the sandbox feature.
|
|
4
|
-
|
|
5
|
-
# Issue title
|
|
6
|
-
TITLE="Improve Sandbox Mode to fully emulate drive.file scope"
|
|
7
|
-
|
|
8
|
-
# Issue body in markdown
|
|
9
|
-
BODY=$(cat <<'EOF'
|
|
10
|
-
## Summary
|
|
11
|
-
|
|
12
|
-
The current implementation of `gas-fakes` requires the full `https://www.googleapis.com/auth/drive` scope for initialization, primarily to access metadata about the root Drive folder. This is a stumbling block for users who want to run tests in a more restrictive environment using only the `drive.file` scope.
|
|
13
|
-
|
|
14
|
-
The `ScriptApp.__behavior.sandBoxMode` was introduced as a clever workaround to *emulate* the `drive.file` scope during test execution, but it doesn't solve the initial authorization requirement.
|
|
15
|
-
|
|
16
|
-
For more details on the current sandbox implementation, see sandbox.md.
|
|
17
|
-
|
|
18
|
-
## TODO
|
|
19
|
-
|
|
20
|
-
We need to investigate ways to remove the dependency on root folder access during the `FakeDriveApp` initialization. This would allow `gas-fakes` to operate with only the `drive.file` scope, making the sandbox feature a true end-to-end emulation.
|
|
21
|
-
|
|
22
|
-
Possible areas to explore:
|
|
23
|
-
- Can we mock or bypass the root folder check during initialization if a specific `drive.file` mode is detected?
|
|
24
|
-
- Can we lazy-initialize parts of `FakeDriveApp` that require root access, and only fail if those specific methods (like `getRootFolder()`) are called without sufficient permissions?
|
|
25
|
-
|
|
26
|
-
This would be a significant improvement for security-conscious development and testing workflows.
|
|
27
|
-
EOF
|
|
28
|
-
)
|
|
29
|
-
|
|
30
|
-
# Create the issue using GitHub CLI
|
|
31
|
-
gh issue create --title "$TITLE" --body "$BODY" --label "enhancement" --label "help wanted"
|
|
@@ -1,107 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
|
|
3
|
-
echo "Welcome to the gas-fakes configuration tool!"
|
|
4
|
-
echo "This script will help you set up your .env and gasfakes.json files."
|
|
5
|
-
|
|
6
|
-
# --- Check for existing .env file ---
|
|
7
|
-
if [ -f ".env" ]; then
|
|
8
|
-
echo ""
|
|
9
|
-
echo "An existing .env file was found. We will update the values."
|
|
10
|
-
UPDATE_MODE=true
|
|
11
|
-
else
|
|
12
|
-
echo ""
|
|
13
|
-
echo "No .env file found. We will create a new one."
|
|
14
|
-
UPDATE_MODE=false
|
|
15
|
-
fi
|
|
16
|
-
|
|
17
|
-
# --- Get .env file details ---
|
|
18
|
-
echo ""
|
|
19
|
-
echo "First, let's configure your .env file for Application Default Credentials (ADC)."
|
|
20
|
-
echo "These are necessary for gas-fakes to access Google Workspace APIs on your behalf."
|
|
21
|
-
|
|
22
|
-
read -p "Enter your Google Cloud Project ID: " gcp_project_id
|
|
23
|
-
read -p "Enter the ID of a Google Drive file you have access to: " drive_test_file_id
|
|
24
|
-
read -p "Enter the default scopes (e.g., \"https://www.googleapis.com/auth/userinfo.email,openid,https://www.googleapis.com/auth/cloud-platform\"): " default_scopes
|
|
25
|
-
read -p "Enter any EXTRA_SCOPES (e.g., ,https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/spreadsheets): " extra_scopes
|
|
26
|
-
|
|
27
|
-
# --- Update or create .env file ---
|
|
28
|
-
if [ "$UPDATE_MODE" = true ]; then
|
|
29
|
-
# Use sed to replace the values in the existing file
|
|
30
|
-
sed -i "s|^GCP_PROJECT_ID=.*|GCP_PROJECT_ID=$gcp_project_id|" .env
|
|
31
|
-
sed -i "s|^DRIVE_TEST_FILE_ID=.*|DRIVE_TEST_FILE_ID=$drive_test_file_id|" .env
|
|
32
|
-
sed -i "s|^DEFAULT_SCOPES=.*|DEFAULT_SCOPES=\"$default_scopes\"|" .env
|
|
33
|
-
sed -i "s|^EXTRA_SCOPES=.*|EXTRA_SCOPES=\"$extra_scopes\"|" .env
|
|
34
|
-
echo ""
|
|
35
|
-
echo "Successfully updated the .env file."
|
|
36
|
-
else
|
|
37
|
-
# Write a new .env file
|
|
38
|
-
cat <<EOF > .env
|
|
39
|
-
# Required for gas-fakes to use Application Default Credentials
|
|
40
|
-
GCP_PROJECT_ID="$gcp_project_id"
|
|
41
|
-
DRIVE_TEST_FILE_ID="$drive_test_file_id"
|
|
42
|
-
|
|
43
|
-
# This should generally be left as default for ADC
|
|
44
|
-
AC=default
|
|
45
|
-
|
|
46
|
-
# These are the scopes set by default - customize as needed
|
|
47
|
-
DEFAULT_SCOPES="$default_scopes"
|
|
48
|
-
|
|
49
|
-
# Add additional scopes here
|
|
50
|
-
EXTRA_SCOPES="$extra_scopes"
|
|
51
|
-
EOF
|
|
52
|
-
echo ""
|
|
53
|
-
echo "Successfully created the .env file."
|
|
54
|
-
fi
|
|
55
|
-
|
|
56
|
-
# --- Get gasfakes.json details ---
|
|
57
|
-
echo ""
|
|
58
|
-
echo "Next, let's configure your gasfakes.json file."
|
|
59
|
-
echo "This file informs gas-fakes about your local environment."
|
|
60
|
-
|
|
61
|
-
# Using default values as suggested by the repository
|
|
62
|
-
DEFAULT_MANIFEST="./appsscript.json"
|
|
63
|
-
DEFAULT_CLASP="./.clasp.json"
|
|
64
|
-
DEFAULT_CACHE="/tmp/gas-fakes/cache"
|
|
65
|
-
DEFAULT_PROPERTIES="/tmp/gas-fakes/properties"
|
|
66
|
-
DEFAULT_SCRIPT_ID=$(uuidgen) # A fake script ID if clasp file is not used
|
|
67
|
-
|
|
68
|
-
read -p "Enter the path to your manifest file (default: $DEFAULT_MANIFEST): " manifest_path
|
|
69
|
-
manifest_path=${manifest_path:-$DEFAULT_MANIFEST}
|
|
70
|
-
|
|
71
|
-
read -p "Enter the path to your clasp file (default: $DEFAULT_CLASP): " clasp_path
|
|
72
|
-
clasp_path=${clasp_path:-$DEFAULT_CLASP}
|
|
73
|
-
|
|
74
|
-
read -p "Enter a bound document ID if applicable (leave blank for none): " document_id
|
|
75
|
-
if [ -z "$document_id" ]; then
|
|
76
|
-
document_id="null"
|
|
77
|
-
else
|
|
78
|
-
document_id="\"$document_id\""
|
|
79
|
-
fi
|
|
80
|
-
|
|
81
|
-
read -p "Enter the local cache directory (default: $DEFAULT_CACHE): " cache_path
|
|
82
|
-
cache_path=${cache_path:-$DEFAULT_CACHE}
|
|
83
|
-
|
|
84
|
-
read -p "Enter the local properties directory (default: $DEFAULT_PROPERTIES): " properties_path
|
|
85
|
-
properties_path=${properties_path:-$DEFAULT_PROPERTIES}
|
|
86
|
-
|
|
87
|
-
read -p "Enter the script ID (default: a new random ID will be created): " script_id
|
|
88
|
-
script_id=${script_id:-$DEFAULT_SCRIPT_ID}
|
|
89
|
-
|
|
90
|
-
# --- Write gasfakes.json file ---
|
|
91
|
-
cat <<EOF > gasfakes.json
|
|
92
|
-
{
|
|
93
|
-
"manifest": "$manifest_path",
|
|
94
|
-
"clasp": "$clasp_path",
|
|
95
|
-
"documentId": $document_id,
|
|
96
|
-
"cache": "$cache_path",
|
|
97
|
-
"properties": "$properties_path",
|
|
98
|
-
"scriptId": "$script_id"
|
|
99
|
-
}
|
|
100
|
-
EOF
|
|
101
|
-
|
|
102
|
-
echo ""
|
|
103
|
-
echo "Successfully created the gasfakes.json file."
|
|
104
|
-
|
|
105
|
-
echo ""
|
|
106
|
-
echo "Setup complete! You can now run your gas-fakes project locally."
|
|
107
|
-
echo "Be sure to follow the remaining setup instructions in the gas-fakes repository."
|
package/src/services/base/app.js
DELETED
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
|
|
2
|
-
/**
|
|
3
|
-
* fake Apps Script Session
|
|
4
|
-
* the idea here is to create a global entry for the singleton
|
|
5
|
-
* before we actually have everything we need to create it.
|
|
6
|
-
* We do this by using a proxy, intercepting calls to the
|
|
7
|
-
* initial sigleton and diverting them to a completed one
|
|
8
|
-
*/
|
|
9
|
-
|
|
10
|
-
import { Proxies } from '../../support/proxies.js'
|
|
11
|
-
import { newFakeSession } from './fakesession.js'
|
|
12
|
-
|
|
13
|
-
let _app = null
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* adds to global space to mimic Apps Script behavior
|
|
17
|
-
*/
|
|
18
|
-
const name = "Session"
|
|
19
|
-
if (typeof globalThis[name] === typeof undefined) {
|
|
20
|
-
|
|
21
|
-
const getApp = () => {
|
|
22
|
-
// if it hasn't been intialized yet then do that
|
|
23
|
-
if (!_app) {
|
|
24
|
-
console.log('...activating proxy for', name)
|
|
25
|
-
_app = newFakeSession()
|
|
26
|
-
}
|
|
27
|
-
// this is the actual driveApp we'll return from the proxy
|
|
28
|
-
return _app
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
Proxies.registerProxy(name, getApp)
|
|
32
|
-
|
|
33
|
-
}
|
|
File without changes
|
|
File without changes
|