diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index b8fc2bf..4e796ed 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2,3 +2,4 @@ /.github/ @aws/aws-code-editor /patches/sagemaker.series @aws/aws-code-editor @aws/sagemaker-code-editor /patches/sagemaker/ @aws/aws-code-editor @aws/sagemaker-code-editor +/sagemaker-tests/ @aws/aws-code-editor @aws/sagemaker-code-editor diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 971445f..8c5cea0 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -22,8 +22,8 @@ jobs: - name: Validate tag run: | - if ! echo "$VERSION_NUM" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+$'; then - echo "Tag $VERSION_NUM does not follow semantic version pattern (x.y.z). Skipping release." + if ! echo "$VERSION_NUM" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$'; then + echo "Tag $VERSION_NUM does not follow semantic version pattern (x.y.z or x.y.z-rc.N). Skipping release." exit 78 # neutral exit code fi echo "Tag $VERSION_NUM follows valid semantic version pattern" @@ -90,6 +90,13 @@ jobs: - name: Create GitHub release run: | + # Check if this is a release candidate + PRERELEASE_FLAG="" + if echo "$VERSION_NUM" | grep -qE '^[0-9]+\.[0-9]+\.[0-9]+-rc\.[0-9]+$'; then + PRERELEASE_FLAG="--prerelease" + echo "Detected release candidate version, will mark as prerelease" + fi + # Check if release already exists. Needed when release created via new release in guthub ui if gh release view "$VERSION_NUM" > /dev/null 2>&1; then echo "Release for tag $VERSION_NUM already exists, uploading additional assets..." @@ -98,7 +105,8 @@ jobs: echo "Creating new release for tag $VERSION_NUM..." gh release create "$VERSION_NUM" ./*.tar.gz \ --title "Release $VERSION_NUM" \ - --notes "Release $VERSION_NUM" + --notes "Release $VERSION_NUM" \ + $PRERELEASE_FLAG fi handle-failures: name: Handle Failures diff --git a/.gitignore b/.gitignore index da03cda..55b6cc3 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,7 @@ build-artifacts build-private code-editor-src vscode-reh-web-* -code-editor-src-* \ No newline at end of file +code-editor-src-* +node_modules +package-lock.json +package.json \ No newline at end of file diff --git a/LICENSE-THIRD-PARTY b/LICENSE-THIRD-PARTY index b687e8e..1683548 100644 --- a/LICENSE-THIRD-PARTY +++ b/LICENSE-THIRD-PARTY @@ -3746,6 +3746,60 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@parcel/watcher-linux-x64-glibc +2.5.1 +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@parcel/watcher-linux-x64-musl +2.5.1 +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ****************************** @tootallnate/once diff --git a/overrides/LICENSE-THIRD-PARTY b/overrides/LICENSE-THIRD-PARTY index b687e8e..1683548 100644 --- a/overrides/LICENSE-THIRD-PARTY +++ b/overrides/LICENSE-THIRD-PARTY @@ -3746,6 +3746,60 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +****************************** + +@parcel/watcher-linux-x64-glibc +2.5.1 +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + +****************************** + +@parcel/watcher-linux-x64-musl +2.5.1 +MIT License + +Copyright (c) 2017-present Devon Govett + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + ****************************** @tootallnate/once diff --git a/package-lock-overrides/sagemaker.series/package-lock.json b/package-lock-overrides/sagemaker.series/package-lock.json index c4a2f88..699b3e9 100644 --- a/package-lock-overrides/sagemaker.series/package-lock.json +++ b/package-lock-overrides/sagemaker.series/package-lock.json @@ -96,7 +96,7 @@ "css-loader": "^6.9.1", "debounce": "^1.0.0", "deemon": "^1.13.4", - "electron": "^35.7.5", + "electron": "38.7.1", "eslint": "^9.11.1", "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", @@ -5760,9 +5760,9 @@ "dev": true }, "node_modules/electron": { - "version": "35.7.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-35.7.5.tgz", - "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "version": "38.7.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-38.7.1.tgz", + "integrity": "sha512-mdFVpL80nZvIvajtl1Xz+2Q/a9tFGVnPO0YW/N+MqQUyZG8D9r3wrWoaEVBXTc1jI+Vkg77Eqqwh5FLiaYRI+A==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package-lock-overrides/web-embedded-with-terminal.series/package-lock.json b/package-lock-overrides/web-embedded-with-terminal.series/package-lock.json index 5d66559..e92c19b 100644 --- a/package-lock-overrides/web-embedded-with-terminal.series/package-lock.json +++ b/package-lock-overrides/web-embedded-with-terminal.series/package-lock.json @@ -94,7 +94,7 @@ "css-loader": "^6.9.1", "debounce": "^1.0.0", "deemon": "^1.13.4", - "electron": "^35.7.5", + "electron": "38.7.1", "eslint": "^9.11.1", "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", @@ -5780,9 +5780,9 @@ "dev": true }, "node_modules/electron": { - "version": "35.7.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-35.7.5.tgz", - "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "version": "38.7.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-38.7.1.tgz", + "integrity": "sha512-mdFVpL80nZvIvajtl1Xz+2Q/a9tFGVnPO0YW/N+MqQUyZG8D9r3wrWoaEVBXTc1jI+Vkg77Eqqwh5FLiaYRI+A==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package-lock-overrides/web-embedded.series/package-lock.json b/package-lock-overrides/web-embedded.series/package-lock.json index 5d66559..e92c19b 100644 --- a/package-lock-overrides/web-embedded.series/package-lock.json +++ b/package-lock-overrides/web-embedded.series/package-lock.json @@ -94,7 +94,7 @@ "css-loader": "^6.9.1", "debounce": "^1.0.0", "deemon": "^1.13.4", - "electron": "^35.7.5", + "electron": "38.7.1", "eslint": "^9.11.1", "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", @@ -5780,9 +5780,9 @@ "dev": true }, "node_modules/electron": { - "version": "35.7.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-35.7.5.tgz", - "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "version": "38.7.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-38.7.1.tgz", + "integrity": "sha512-mdFVpL80nZvIvajtl1Xz+2Q/a9tFGVnPO0YW/N+MqQUyZG8D9r3wrWoaEVBXTc1jI+Vkg77Eqqwh5FLiaYRI+A==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/package-lock-overrides/web-server.series/package-lock.json b/package-lock-overrides/web-server.series/package-lock.json index 3fb9a2b..95e8d8d 100644 --- a/package-lock-overrides/web-server.series/package-lock.json +++ b/package-lock-overrides/web-server.series/package-lock.json @@ -96,7 +96,7 @@ "css-loader": "^6.9.1", "debounce": "^1.0.0", "deemon": "^1.13.4", - "electron": "^35.7.5", + "electron": "38.7.1", "eslint": "^9.11.1", "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", @@ -5792,9 +5792,9 @@ "dev": true }, "node_modules/electron": { - "version": "35.7.5", - "resolved": "https://registry.npmjs.org/electron/-/electron-35.7.5.tgz", - "integrity": "sha512-dnL+JvLraKZl7iusXTVTGYs10TKfzUi30uEDTqsmTm0guN9V2tbOjTzyIZbh9n3ygUjgEYyo+igAwMRXIi3IPw==", + "version": "38.7.1", + "resolved": "https://registry.npmjs.org/electron/-/electron-38.7.1.tgz", + "integrity": "sha512-mdFVpL80nZvIvajtl1Xz+2Q/a9tFGVnPO0YW/N+MqQUyZG8D9r3wrWoaEVBXTc1jI+Vkg77Eqqwh5FLiaYRI+A==", "dev": true, "hasInstallScript": true, "license": "MIT", diff --git a/patches/common/build.diff b/patches/common/build.diff index f1b9191..08dc126 100644 --- a/patches/common/build.diff +++ b/patches/common/build.diff @@ -33,7 +33,7 @@ Index: third-party-src/package.json "debounce": "^1.0.0", "deemon": "^1.13.4", - "electron": "35.5.1", -+ "electron": "^35.7.5", ++ "electron": "38.7.1", "eslint": "^9.11.1", "eslint-formatter-compact": "^8.40.0", "eslint-plugin-header": "3.1.1", diff --git a/patches/sagemaker/fix-port-forwarding.diff b/patches/sagemaker/fix-port-forwarding.diff index 6d6f803..f531ec6 100644 --- a/patches/sagemaker/fix-port-forwarding.diff +++ b/patches/sagemaker/fix-port-forwarding.diff @@ -1,7 +1,7 @@ -Index: third-party-src/src/vs/code/browser/workbench/workbench.ts +Index: code-editor-src/src/vs/code/browser/workbench/workbench.ts =================================================================== ---- third-party-src.orig/src/vs/code/browser/workbench/workbench.ts -+++ third-party-src/src/vs/code/browser/workbench/workbench.ts +--- code-editor-src.orig/src/vs/code/browser/workbench/workbench.ts ++++ code-editor-src/src/vs/code/browser/workbench/workbench.ts @@ -635,7 +635,7 @@ function readCookie(name: string): strin const localhostMatch = extractLocalHostUriMetaDataForPortMapping(resolvedUri) if (localhostMatch && resolvedUri.authority !== location.host) { diff --git a/patches/sagemaker/post-startup-notifications.diff b/patches/sagemaker/post-startup-notifications.diff index 482661b..168b6e6 100644 --- a/patches/sagemaker/post-startup-notifications.diff +++ b/patches/sagemaker/post-startup-notifications.diff @@ -1,17 +1,17 @@ -Index: third-party-src/extensions/post-startup-notifications/.vscode/extensions.json +Index: code-editor-src/extensions/post-startup-notifications/.vscode/extensions.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/.vscode/extensions.json ++++ code-editor-src/extensions/post-startup-notifications/.vscode/extensions.json @@ -0,0 +1,5 @@ +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": ["dbaeumer.vscode-eslint", "amodio.tsl-problem-matcher", "ms-vscode.extension-test-runner"] +} -Index: third-party-src/extensions/post-startup-notifications/.vscode/launch.json +Index: code-editor-src/extensions/post-startup-notifications/.vscode/launch.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/.vscode/launch.json ++++ code-editor-src/extensions/post-startup-notifications/.vscode/launch.json @@ -0,0 +1,21 @@ +// A launch configuration that compiles the extension and then opens it inside a new window +// Use IntelliSense to learn about possible attributes. @@ -35,10 +35,10 @@ Index: third-party-src/extensions/post-startup-notifications/.vscode/launch.json + ] +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/.vscode/settings.json +Index: code-editor-src/extensions/post-startup-notifications/.vscode/settings.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/.vscode/settings.json ++++ code-editor-src/extensions/post-startup-notifications/.vscode/settings.json @@ -0,0 +1,13 @@ +// Place your settings in this file to overwrite default and user settings. +{ @@ -54,10 +54,10 @@ Index: third-party-src/extensions/post-startup-notifications/.vscode/settings.js + "typescript.tsc.autoDetect": "off" +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/.vscode/tasks.json +Index: code-editor-src/extensions/post-startup-notifications/.vscode/tasks.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/.vscode/tasks.json ++++ code-editor-src/extensions/post-startup-notifications/.vscode/tasks.json @@ -0,0 +1,40 @@ +// See https://go.microsoft.com/fwlink/?LinkId=733558 +// for the documentation about the tasks.json format @@ -100,10 +100,10 @@ Index: third-party-src/extensions/post-startup-notifications/.vscode/tasks.json + ] +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/.vscodeignore +Index: code-editor-src/extensions/post-startup-notifications/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/.vscodeignore ++++ code-editor-src/extensions/post-startup-notifications/.vscodeignore @@ -0,0 +1,14 @@ +.vscode/** +.vscode-test/** @@ -119,10 +119,10 @@ Index: third-party-src/extensions/post-startup-notifications/.vscodeignore +**/*.map +**/*.ts +**/.vscode-test.* -Index: third-party-src/extensions/post-startup-notifications/CHANGELOG.md +Index: code-editor-src/extensions/post-startup-notifications/CHANGELOG.md =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/CHANGELOG.md ++++ code-editor-src/extensions/post-startup-notifications/CHANGELOG.md @@ -0,0 +1,9 @@ +# Change Log + @@ -134,19 +134,19 @@ Index: third-party-src/extensions/post-startup-notifications/CHANGELOG.md + +- Initial release \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/README.md +Index: code-editor-src/extensions/post-startup-notifications/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/README.md ++++ code-editor-src/extensions/post-startup-notifications/README.md @@ -0,0 +1,4 @@ +# post-startup-notifications README + +This extension monitors post startup script execution and notifies users on success/failure. + -Index: third-party-src/extensions/post-startup-notifications/eslint.config.mjs +Index: code-editor-src/extensions/post-startup-notifications/eslint.config.mjs =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/eslint.config.mjs ++++ code-editor-src/extensions/post-startup-notifications/eslint.config.mjs @@ -0,0 +1,28 @@ +import typescriptEslint from "@typescript-eslint/eslint-plugin"; +import tsParser from "@typescript-eslint/parser"; @@ -177,10 +177,10 @@ Index: third-party-src/extensions/post-startup-notifications/eslint.config.mjs + }, +}]; \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/package.json +Index: code-editor-src/extensions/post-startup-notifications/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/package.json ++++ code-editor-src/extensions/post-startup-notifications/package.json @@ -0,0 +1,57 @@ +{ + "name": "post-startup-notifications", @@ -240,19 +240,19 @@ Index: third-party-src/extensions/post-startup-notifications/package.json + } +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/src/constant.ts +Index: code-editor-src/extensions/post-startup-notifications/src/constant.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/src/constant.ts ++++ code-editor-src/extensions/post-startup-notifications/src/constant.ts @@ -0,0 +1,3 @@ +export const POST_START_UP_STATUS_FILE = '/tmp/.post-startup-status.json'; +export const SERVICE_NAME_ENV_VALUE = 'SageMakerUnifiedStudio'; +export const SERVICE_NAME_ENV_KEY = 'SERVICE_NAME'; \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/src/extension.ts +Index: code-editor-src/extensions/post-startup-notifications/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/src/extension.ts ++++ code-editor-src/extensions/post-startup-notifications/src/extension.ts @@ -0,0 +1,117 @@ +import * as vscode from 'vscode'; +import * as fs from 'fs'; @@ -371,10 +371,10 @@ Index: third-party-src/extensions/post-startup-notifications/src/extension.ts + outputChannel.dispose(); + } +} -Index: third-party-src/extensions/post-startup-notifications/src/test/extension.test.ts +Index: code-editor-src/extensions/post-startup-notifications/src/test/extension.test.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/src/test/extension.test.ts ++++ code-editor-src/extensions/post-startup-notifications/src/test/extension.test.ts @@ -0,0 +1,267 @@ +import * as vscode from 'vscode'; +import * as fs from 'fs'; @@ -643,10 +643,10 @@ Index: third-party-src/extensions/post-startup-notifications/src/test/extension. + }); +}); + -Index: third-party-src/extensions/post-startup-notifications/src/types.ts +Index: code-editor-src/extensions/post-startup-notifications/src/types.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/src/types.ts ++++ code-editor-src/extensions/post-startup-notifications/src/types.ts @@ -0,0 +1,6 @@ +export interface StatusFile { + status: string; @@ -655,10 +655,10 @@ Index: third-party-src/extensions/post-startup-notifications/src/types.ts + label: string; +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/tsconfig.json +Index: code-editor-src/extensions/post-startup-notifications/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/tsconfig.json ++++ code-editor-src/extensions/post-startup-notifications/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { @@ -678,10 +678,10 @@ Index: third-party-src/extensions/post-startup-notifications/tsconfig.json + } +} \ No newline at end of file -Index: third-party-src/extensions/post-startup-notifications/webpack.config.js +Index: code-editor-src/extensions/post-startup-notifications/webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/webpack.config.js ++++ code-editor-src/extensions/post-startup-notifications/webpack.config.js @@ -0,0 +1,48 @@ +//@ts-check + @@ -732,11 +732,11 @@ Index: third-party-src/extensions/post-startup-notifications/webpack.config.js +}; +module.exports = [extensionConfig]; \ No newline at end of file -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js -@@ -42,6 +42,7 @@ const dirs = [ +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js +@@ -43,6 +43,7 @@ const dirs = [ 'extensions/sagemaker-terminal-crash-mitigation', 'extensions/sagemaker-open-notebook-extension', 'extensions/sagemaker-ui-dark-theme', @@ -744,11 +744,11 @@ Index: third-party-src/build/npm/dirs.js 'extensions/search-result', 'extensions/simple-browser', 'extensions/tunnel-forwarding', -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js -@@ -64,6 +64,7 @@ const compilations = [ +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js +@@ -65,6 +65,7 @@ const compilations = [ 'extensions/sagemaker-terminal-crash-mitigation/tsconfig.json', 'extensions/sagemaker-open-notebook-extension/tsconfig.json', 'extensions/sagemaker-ui-dark-theme/tsconfig.json', @@ -756,10 +756,10 @@ Index: third-party-src/build/gulpfile.extensions.js 'extensions/tunnel-forwarding/tsconfig.json', 'extensions/typescript-language-features/test-workspace/tsconfig.json', 'extensions/typescript-language-features/web/tsconfig.json', -Index: third-party-src/extensions/post-startup-notifications/extension-browser.webpack.config.js +Index: code-editor-src/extensions/post-startup-notifications/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/extension-browser.webpack.config.js ++++ code-editor-src/extensions/post-startup-notifications/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -778,10 +778,10 @@ Index: third-party-src/extensions/post-startup-notifications/extension-browser.w + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/post-startup-notifications/extension.webpack.config.js +Index: code-editor-src/extensions/post-startup-notifications/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/post-startup-notifications/extension.webpack.config.js ++++ code-editor-src/extensions/post-startup-notifications/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. diff --git a/patches/sagemaker/sagemaker-extension-smus-support.diff b/patches/sagemaker/sagemaker-extension-smus-support.diff index 0cff797..275acf9 100644 --- a/patches/sagemaker/sagemaker-extension-smus-support.diff +++ b/patches/sagemaker/sagemaker-extension-smus-support.diff @@ -1,7 +1,7 @@ -Index: third-party-src/extensions/sagemaker-extension/src/constant.ts +Index: code-editor-src/extensions/sagemaker-extension/src/constant.ts =================================================================== ---- third-party-src.orig/extensions/sagemaker-extension/src/constant.ts -+++ third-party-src/extensions/sagemaker-extension/src/constant.ts +--- code-editor-src.orig/extensions/sagemaker-extension/src/constant.ts ++++ code-editor-src/extensions/sagemaker-extension/src/constant.ts @@ -27,6 +27,10 @@ export const FIVE_MINUTES_INTERVAL_MILLI export const SAGEMAKER_METADATA_PATH = '/opt/ml/metadata/resource-metadata.json'; @@ -63,10 +63,10 @@ Index: third-party-src/extensions/sagemaker-extension/src/constant.ts + + return `https://${DataZoneDomainId}.sagemaker.${DataZoneDomainRegion}.on.aws/projects/${DataZoneProjectId}/overview`; +} -Index: third-party-src/extensions/sagemaker-extension/src/extension.ts +Index: code-editor-src/extensions/sagemaker-extension/src/extension.ts =================================================================== ---- third-party-src.orig/extensions/sagemaker-extension/src/extension.ts -+++ third-party-src/extensions/sagemaker-extension/src/extension.ts +--- code-editor-src.orig/extensions/sagemaker-extension/src/extension.ts ++++ code-editor-src/extensions/sagemaker-extension/src/extension.ts @@ -11,7 +11,8 @@ import { WARNING_BUTTON_SAVE_AND_RENEW_SESSION, SagemakerCookie, diff --git a/patches/sagemaker/sagemaker-extensions-sync.diff b/patches/sagemaker/sagemaker-extensions-sync.diff index 599587f..819b5bd 100644 --- a/patches/sagemaker/sagemaker-extensions-sync.diff +++ b/patches/sagemaker/sagemaker-extensions-sync.diff @@ -1,7 +1,7 @@ -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js @@ -63,6 +63,7 @@ const compilations = [ 'extensions/sagemaker-extension/tsconfig.json', 'extensions/sagemaker-idle-extension/tsconfig.json', @@ -10,10 +10,10 @@ Index: third-party-src/build/gulpfile.extensions.js 'extensions/sagemaker-open-notebook-extension/tsconfig.json', 'extensions/sagemaker-ui-dark-theme/tsconfig.json', 'extensions/post-startup-notifications/tsconfig.json', -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js @@ -41,6 +41,7 @@ const dirs = [ 'extensions/sagemaker-extension', 'extensions/sagemaker-idle-extension', @@ -22,10 +22,10 @@ Index: third-party-src/build/npm/dirs.js 'extensions/sagemaker-open-notebook-extension', 'extensions/sagemaker-ui-dark-theme', 'extensions/post-startup-notifications', -Index: third-party-src/extensions/sagemaker-extensions-sync/.vscodeignore +Index: code-editor-src/extensions/sagemaker-extensions-sync/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/.vscodeignore ++++ code-editor-src/extensions/sagemaker-extensions-sync/.vscodeignore @@ -0,0 +1,11 @@ +.vscode/** +.vscode-test/** @@ -38,19 +38,19 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/.vscodeignore +out/** +cgmanifest.json +preview-src/** -Index: third-party-src/extensions/sagemaker-extensions-sync/README.md +Index: code-editor-src/extensions/sagemaker-extensions-sync/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/README.md ++++ code-editor-src/extensions/sagemaker-extensions-sync/README.md @@ -0,0 +1,3 @@ +# SageMaker Code Editor Extensions Sync + +Notifies users if the extensions directory is missing pre-packaged extensions from SageMaker Distribution and give them the option to sync them. \ No newline at end of file -Index: third-party-src/extensions/sagemaker-extensions-sync/extension-browser.webpack.config.js +Index: code-editor-src/extensions/sagemaker-extensions-sync/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/extension-browser.webpack.config.js ++++ code-editor-src/extensions/sagemaker-extensions-sync/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -69,10 +69,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/extension-browser.we + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/sagemaker-extensions-sync/extension.webpack.config.js +Index: code-editor-src/extensions/sagemaker-extensions-sync/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/extension.webpack.config.js ++++ code-editor-src/extensions/sagemaker-extensions-sync/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -94,10 +94,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/extension.webpack.co + extension: './src/extension.ts', + } +}); -Index: third-party-src/extensions/sagemaker-extensions-sync/package.json +Index: code-editor-src/extensions/sagemaker-extensions-sync/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/package.json ++++ code-editor-src/extensions/sagemaker-extensions-sync/package.json @@ -0,0 +1,44 @@ +{ + "name": "sagemaker-extensions-sync", @@ -143,10 +143,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/package.json + "dependencies": {}, + "repository": {} +} -Index: third-party-src/extensions/sagemaker-extensions-sync/src/constants.ts +Index: code-editor-src/extensions/sagemaker-extensions-sync/src/constants.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/src/constants.ts ++++ code-editor-src/extensions/sagemaker-extensions-sync/src/constants.ts @@ -0,0 +1,21 @@ +// constants +export const PERSISTENT_VOLUME_EXTENSIONS_DIR = "/home/sagemaker-user/sagemaker-code-editor-server-data/extensions"; @@ -169,10 +169,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/src/constants.ts + return `ExtensionInfo: ${this.identifier} (${this.path})`; + } +} -Index: third-party-src/extensions/sagemaker-extensions-sync/src/extension.ts +Index: code-editor-src/extensions/sagemaker-extensions-sync/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/src/extension.ts ++++ code-editor-src/extensions/sagemaker-extensions-sync/src/extension.ts @@ -0,0 +1,100 @@ +import * as process from "process"; +import * as vscode from 'vscode'; @@ -275,10 +275,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/src/extension.ts + } +} \ No newline at end of file -Index: third-party-src/extensions/sagemaker-extensions-sync/tsconfig.json +Index: code-editor-src/extensions/sagemaker-extensions-sync/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/tsconfig.json ++++ code-editor-src/extensions/sagemaker-extensions-sync/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.base.json", @@ -290,10 +290,10 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/tsconfig.json + "../../src/vscode-dts/vscode.d.ts" + ] +} -Index: third-party-src/extensions/sagemaker-extensions-sync/src/utils.ts +Index: code-editor-src/extensions/sagemaker-extensions-sync/src/utils.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-extensions-sync/src/utils.ts ++++ code-editor-src/extensions/sagemaker-extensions-sync/src/utils.ts @@ -0,0 +1,168 @@ +import * as fs from "fs/promises"; +import * as path from "path"; @@ -463,4 +463,4 @@ Index: third-party-src/extensions/sagemaker-extensions-sync/src/utils.ts + console.error(`${LOG_PREFIX} ${error}`); + } +} -\ No newline at end of file \ No newline at end of file +\ No newline at end of file diff --git a/patches/sagemaker/sagemaker-idle-extension.diff b/patches/sagemaker/sagemaker-idle-extension.diff index d6950a2..05560d9 100644 --- a/patches/sagemaker/sagemaker-idle-extension.diff +++ b/patches/sagemaker/sagemaker-idle-extension.diff @@ -1,16 +1,16 @@ -Index: third-party-src/extensions/sagemaker-idle-extension/README.md +Index: code-editor-src/extensions/sagemaker-idle-extension/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/README.md ++++ code-editor-src/extensions/sagemaker-idle-extension/README.md @@ -0,0 +1,3 @@ +# Code Editor Idle Extension + +The Code Editor Idle Extension tracks user activity and logs the last active timestamp (in UTC) to a local file. User activities monitored include file changes, text editor selection changes, and terminal interactions. Additionally, it provides an API endpoint `/api/idle` that returns the lastActiveTimestamp. \ No newline at end of file -Index: third-party-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js +Index: code-editor-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js ++++ code-editor-src/extensions/sagemaker-idle-extension/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -29,10 +29,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/extension-browser.web + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/sagemaker-idle-extension/extension.webpack.config.js +Index: code-editor-src/extensions/sagemaker-idle-extension/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/extension.webpack.config.js ++++ code-editor-src/extensions/sagemaker-idle-extension/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -54,10 +54,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/extension.webpack.con + extension: './src/extension.ts', + } +}); -Index: third-party-src/extensions/sagemaker-idle-extension/package.json +Index: code-editor-src/extensions/sagemaker-idle-extension/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/package.json ++++ code-editor-src/extensions/sagemaker-idle-extension/package.json @@ -0,0 +1,43 @@ +{ + "name": "sagemaker-idle-extension", @@ -102,10 +102,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/package.json + "dependencies": {}, + "repository": {} +} -Index: third-party-src/extensions/sagemaker-idle-extension/tsconfig.json +Index: code-editor-src/extensions/sagemaker-idle-extension/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/tsconfig.json ++++ code-editor-src/extensions/sagemaker-idle-extension/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.base.json", @@ -117,10 +117,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/tsconfig.json + "../../src/vscode-dts/vscode.d.ts" + ] +} -Index: third-party-src/extensions/sagemaker-idle-extension/.vscodeignore +Index: code-editor-src/extensions/sagemaker-idle-extension/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/.vscodeignore ++++ code-editor-src/extensions/sagemaker-idle-extension/.vscodeignore @@ -0,0 +1,11 @@ +.vscode/** +.vscode-test/** @@ -133,42 +133,34 @@ Index: third-party-src/extensions/sagemaker-idle-extension/.vscodeignore +out/** +cgmanifest.json +preview-src/** -Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts +Index: code-editor-src/extensions/sagemaker-idle-extension/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-idle-extension/src/extension.ts -@@ -0,0 +1,112 @@ ++++ code-editor-src/extensions/sagemaker-idle-extension/src/extension.ts +@@ -0,0 +1,58 @@ +import * as vscode from "vscode"; +import * as fs from "fs"; +import * as path from "path"; + -+let idleFilePath: string -+let terminalActivityInterval: NodeJS.Timeout | undefined -+const LOG_PREFIX = "[sagemaker-idle-extension]" -+const CHECK_INTERVAL = 60000; // 60 seconds interval ++let idleFilePath: string; + +export function activate(context: vscode.ExtensionContext) { + initializeIdleFilePath(); + registerEventListeners(context); -+ startMonitoringTerminalActivity(); +} + -+export function deactivate() { -+ if(terminalActivityInterval) { -+ clearInterval(terminalActivityInterval) -+ } -+} ++export function deactivate() {} + +/** + * Initializes the file path where the idle timestamp will be stored. + * It sets the path to a hidden file in the /tmp/ directory. + */ +function initializeIdleFilePath() { -+ const tmpDirectory = "/tmp/"; ++ const tmpDirectory = "/tmp/"; + idleFilePath = path.join(tmpDirectory, ".sagemaker-last-active-timestamp"); + + // Set initial lastActivetimestamp -+ updateLastActivityTimestamp() ++ updateLastActivityTimestamp(); +} + +/** @@ -197,52 +189,6 @@ Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts +} + +/** -+ * Starts monitoring terminal activity by setting an interval to check for activity in the /dev/pts directory. -+ */ -+const startMonitoringTerminalActivity = () => { -+ terminalActivityInterval = setInterval(checkTerminalActivity, CHECK_INTERVAL); -+}; -+ -+ -+/** -+ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files. -+ * -+ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices. -+ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory. -+ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal, -+ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification -+ * times of the files in the /dev/pts directory, we can detect terminal activity. -+ * -+ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function -+ * updates the last activity timestamp. -+ */ -+const checkTerminalActivity = () => { -+ fs.readdir("/dev/pts", (err, files) => { -+ if (err) { -+ console.error(`${LOG_PREFIX} Error reading /dev/pts directory:`, err); -+ return; -+ } -+ -+ const now = Date.now(); -+ const activityDetected = files.some((file) => { -+ const filePath = path.join("/dev/pts", file); -+ try { -+ const stats = fs.statSync(filePath); -+ const mtime = new Date(stats.mtime).getTime(); -+ return now - mtime < CHECK_INTERVAL; -+ } catch (error) { -+ console.error(`${LOG_PREFIX} Error reading file stats:`, error); -+ return false; -+ } -+ }); -+ -+ if (activityDetected) { -+ updateLastActivityTimestamp(); -+ } -+ }); -+}; -+ -+/** + * Updates the last activity timestamp by recording the current timestamp in the idle file and + * refreshing the status bar. The timestamp should be in ISO 8601 format and set to the UTC timezone. + */ @@ -251,10 +197,10 @@ Index: third-party-src/extensions/sagemaker-idle-extension/src/extension.ts + fs.writeFileSync(idleFilePath, timestamp); +} \ No newline at end of file -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js @@ -61,6 +61,7 @@ const compilations = [ 'extensions/search-result/tsconfig.json', 'extensions/simple-browser/tsconfig.json', @@ -263,10 +209,10 @@ Index: third-party-src/build/gulpfile.extensions.js 'extensions/tunnel-forwarding/tsconfig.json', 'extensions/typescript-language-features/test-workspace/tsconfig.json', 'extensions/typescript-language-features/web/tsconfig.json', -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js @@ -39,6 +39,7 @@ const dirs = [ 'extensions/php-language-features', 'extensions/references-view', @@ -275,28 +221,69 @@ Index: third-party-src/build/npm/dirs.js 'extensions/search-result', 'extensions/simple-browser', 'extensions/tunnel-forwarding', -Index: third-party-src/src/vs/server/node/webClientServer.ts +Index: code-editor-src/src/vs/server/node/webClientServer.ts =================================================================== ---- third-party-src.orig/src/vs/server/node/webClientServer.ts -+++ third-party-src/src/vs/server/node/webClientServer.ts -@@ -3,7 +3,7 @@ +--- code-editor-src.orig/src/vs/server/node/webClientServer.ts ++++ code-editor-src/src/vs/server/node/webClientServer.ts +@@ -3,8 +3,10 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { createReadStream, promises } from 'fs'; +import { createReadStream, promises, existsSync, writeFileSync } from 'fs'; ++import * as fs from 'fs'; import * as http from 'http'; ++import * as path from 'path'; import * as url from 'url'; import * as cookie from 'cookie'; -@@ -96,6 +96,7 @@ const APP_ROOT = dirname(FileAccess.asFi + import * as crypto from 'crypto'; +@@ -91,11 +93,45 @@ export async function serveFile(filePath + } + } + ++const CHECK_INTERVAL = 60000; // 60 seconds interval + const APP_ROOT = dirname(FileAccess.asFileUri('').fsPath); + const STATIC_PATH = `/static`; const CALLBACK_PATH = `/callback`; const WEB_EXTENSION_PATH = `/web-extension-resource`; +const IDLE_EXTENSION_PATH = `/api/idle`; ++ ++/** ++ * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files. ++ * ++ * The /dev/pts directory is used in Unix-like operating systems to represent pseudo-terminal (PTY) devices. ++ * Each active terminal session is assigned a PTY device. These devices are represented as files within the /dev/pts directory. ++ * When a terminal session has activity, such as when a user inputs commands or output is written to the terminal, ++ * the modification time (mtime) of the corresponding PTY device file is updated. By monitoring the modification ++ * times of the files in the /dev/pts directory, we can detect terminal activity. ++ * ++ * If activity is detected (i.e., if any PTY device file was modified within the CHECK_INTERVAL), this function ++ * updates the last activity timestamp. ++ */ ++function checkTerminalActivity(idleFilePath: string) { ++ try { ++ const files: string[] = fs.readdirSync('/dev/pts'); ++ const now = new Date(); ++ ++ const activityDetected = files.some((file: string) => { ++ const filePath = path.join('/dev/pts', file); ++ const stats = fs.statSync(filePath); ++ const mtime = new Date(stats.mtime).getTime(); ++ return now.getTime() - mtime < CHECK_INTERVAL; ++ }); ++ ++ if (activityDetected) { ++ fs.writeFileSync(idleFilePath, now.toISOString()); ++ } ++ } catch (err) { ++ console.error('Error checking terminal activity:', err); ++ } ++} export class WebClientServer { -@@ -133,6 +134,9 @@ export class WebClientServer { +@@ -133,6 +169,9 @@ export class WebClientServer { // callback support return this._handleCallback(res); } @@ -306,7 +293,7 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts if (pathname.startsWith(WEB_EXTENSION_PATH) && pathname.charCodeAt(WEB_EXTENSION_PATH.length) === CharCode.Slash) { // extension resource support return this._handleWebExtensionResource(req, res, pathname.substring(WEB_EXTENSION_PATH.length)); -@@ -505,6 +509,31 @@ export class WebClientServer { +@@ -505,6 +544,33 @@ export class WebClientServer { }); return void res.end(data); } @@ -318,16 +305,18 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts + try { + const tmpDirectory = '/tmp/' + const idleFilePath = join(tmpDirectory, '.sagemaker-last-active-timestamp'); -+ ++ + // If idle shutdown file does not exist, this indicates the app UI may never been opened + // Create the initial metadata file + if (!existsSync(idleFilePath)) { + const timestamp = new Date().toISOString(); + writeFileSync(idleFilePath, timestamp); + } -+ ++ ++ checkTerminalActivity(idleFilePath); ++ + const data = await promises.readFile(idleFilePath, 'utf8'); -+ ++ + res.statusCode = 200; + res.setHeader('Content-Type', 'application/json'); + res.end(JSON.stringify({ lastActiveTimestamp: data })); @@ -336,3 +325,5 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts + } + } } + + diff --git a/patches/sagemaker/sagemaker-open-notebook-extension.diff b/patches/sagemaker/sagemaker-open-notebook-extension.diff index 19e932c..0b22b87 100644 --- a/patches/sagemaker/sagemaker-open-notebook-extension.diff +++ b/patches/sagemaker/sagemaker-open-notebook-extension.diff @@ -1,37 +1,35 @@ -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js -@@ -61,6 +61,7 @@ const compilations = [ - 'extensions/simple-browser/tsconfig.json', +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js +@@ -63,6 +63,7 @@ const compilations = [ 'extensions/sagemaker-extension/tsconfig.json', + 'extensions/sagemaker-idle-extension/tsconfig.json', 'extensions/sagemaker-terminal-crash-mitigation/tsconfig.json', + 'extensions/sagemaker-open-notebook-extension/tsconfig.json', 'extensions/tunnel-forwarding/tsconfig.json', 'extensions/typescript-language-features/test-workspace/tsconfig.json', 'extensions/typescript-language-features/web/tsconfig.json', -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js -@@ -39,6 +39,7 @@ const dirs = [ - 'extensions/references-view', +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js +@@ -41,6 +41,7 @@ const dirs = [ 'extensions/sagemaker-extension', + 'extensions/sagemaker-idle-extension', 'extensions/sagemaker-terminal-crash-mitigation', + 'extensions/sagemaker-open-notebook-extension', 'extensions/search-result', 'extensions/simple-browser', 'extensions/tunnel-forwarding', -Index: third-party-src/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +Index: code-editor-src/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts =================================================================== ---- third-party-src.orig/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts -+++ third-party-src/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts -@@ -262,7 +262,12 @@ Registry.as(Conf - type: 'boolean', +--- code-editor-src.orig/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts ++++ code-editor-src/src/vs/workbench/contrib/extensions/browser/extensions.contribution.ts +@@ -263,6 +263,11 @@ Registry.as(Conf description: localize('extensionsInQuickAccess', "When enabled, extensions can be searched for via Quick Access and report issues from there."), default: true -- }, -+ }, + }, + 'extensions.openNotebookData': { + type: 'object', + scope: ConfigurationScope.APPLICATION, @@ -40,10 +38,10 @@ Index: third-party-src/src/vs/workbench/contrib/extensions/browser/extensions.co [VerifyExtensionSignatureConfigKey]: { type: 'boolean', description: localize('extensions.verifySignature', "When enabled, extensions are verified to be signed before getting installed."), -Index: third-party-src/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +Index: code-editor-src/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts =================================================================== ---- third-party-src.orig/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts -+++ third-party-src/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts +--- code-editor-src.orig/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts ++++ code-editor-src/src/vs/workbench/contrib/extensions/browser/extensionsWorkbenchService.ts @@ -1084,6 +1084,17 @@ export class ExtensionsWorkbenchService urlService.registerHandler(this); @@ -62,10 +60,10 @@ Index: third-party-src/src/vs/workbench/contrib/extensions/browser/extensionsWor } private async initialize(): Promise { -Index: third-party-src/extensions/sagemaker-open-notebook-extension/extension-browser.webpack.config.js +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/extension-browser.webpack.config.js ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -84,10 +82,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/extension-br + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/sagemaker-open-notebook-extension/extension.webpack.config.js +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/extension.webpack.config.js ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -109,10 +107,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/extension.we + extension: './src/extension.ts', + } +}); -Index: third-party-src/extensions/sagemaker-open-notebook-extension/package.json +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/package.json ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/package.json @@ -0,0 +1,44 @@ +{ + "name": "sagemaker-open-notebook-extension", @@ -158,10 +156,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/package.json + "dependencies": {}, + "repository": {} +} -Index: third-party-src/extensions/sagemaker-open-notebook-extension/src/extension.ts +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/src/extension.ts ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/src/extension.ts @@ -0,0 +1,100 @@ + +import * as vscode from 'vscode'; @@ -263,10 +261,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/src/extensio + }); +} +export function deactivate() {} -Index: third-party-src/extensions/sagemaker-open-notebook-extension/tsconfig.json +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/tsconfig.json ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.base.json", @@ -278,10 +276,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/tsconfig.jso + "../../src/vscode-dts/vscode.d.ts" + ] +} -Index: third-party-src/extensions/sagemaker-open-notebook-extension/.vscodeignore +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/.vscodeignore ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/.vscodeignore @@ -0,0 +1,11 @@ +.vscode/** +.vscode-test/** @@ -294,10 +292,10 @@ Index: third-party-src/extensions/sagemaker-open-notebook-extension/.vscodeignor +out/** +cgmanifest.json +preview-src/** -Index: third-party-src/extensions/sagemaker-open-notebook-extension/README.md +Index: code-editor-src/extensions/sagemaker-open-notebook-extension/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-open-notebook-extension/README.md ++++ code-editor-src/extensions/sagemaker-open-notebook-extension/README.md @@ -0,0 +1,18 @@ +# Code Editor Open Notebook Extension + diff --git a/patches/sagemaker/sagemaker-ui-dark-theme.diff b/patches/sagemaker/sagemaker-ui-dark-theme.diff index 58c4f50..4ab2f57 100644 --- a/patches/sagemaker/sagemaker-ui-dark-theme.diff +++ b/patches/sagemaker/sagemaker-ui-dark-theme.diff @@ -1,7 +1,7 @@ -Index: third-party-src/extensions/sagemaker-ui-dark-theme/.vscodeignore +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/.vscodeignore ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/.vscodeignore @@ -0,0 +1,11 @@ +.vscode/** +.vscode-test/** @@ -14,16 +14,16 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/.vscodeignore +out/** +cgmanifest.json +preview-src/** -Index: third-party-src/extensions/sagemaker-ui-dark-theme/README.md +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/README.md ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/README.md @@ -0,0 +1 @@ +# SageMaker UI Dark Theme -Index: third-party-src/extensions/sagemaker-ui-dark-theme/extension-browser.webpack.config.js +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/extension-browser.webpack.config.js ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -42,10 +42,10 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/extension-browser.webp + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/sagemaker-ui-dark-theme/extension.webpack.config.js +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/extension.webpack.config.js ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -67,10 +67,10 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/extension.webpack.conf + extension: './src/extension.ts', + } +}); -Index: third-party-src/extensions/sagemaker-ui-dark-theme/src/extension.ts +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/src/extension.ts ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/src/extension.ts @@ -0,0 +1,51 @@ +import * as vscode from 'vscode'; + @@ -123,10 +123,10 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/src/extension.ts + outputChannel.dispose(); + } +} -Index: third-party-src/extensions/sagemaker-ui-dark-theme/tsconfig.json +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/tsconfig.json ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.base.json", @@ -138,11 +138,11 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/tsconfig.json + "../../src/vscode-dts/vscode.d.ts" + ] +} -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js -@@ -63,6 +63,7 @@ const compilations = [ +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js +@@ -64,6 +64,7 @@ const compilations = [ 'extensions/sagemaker-idle-extension/tsconfig.json', 'extensions/sagemaker-terminal-crash-mitigation/tsconfig.json', 'extensions/sagemaker-open-notebook-extension/tsconfig.json', @@ -150,11 +150,11 @@ Index: third-party-src/build/gulpfile.extensions.js 'extensions/tunnel-forwarding/tsconfig.json', 'extensions/typescript-language-features/test-workspace/tsconfig.json', 'extensions/typescript-language-features/web/tsconfig.json', -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js -@@ -41,6 +41,7 @@ const dirs = [ +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js +@@ -42,6 +42,7 @@ const dirs = [ 'extensions/sagemaker-idle-extension', 'extensions/sagemaker-terminal-crash-mitigation', 'extensions/sagemaker-open-notebook-extension', @@ -162,10 +162,10 @@ Index: third-party-src/build/npm/dirs.js 'extensions/search-result', 'extensions/simple-browser', 'extensions/tunnel-forwarding', -Index: third-party-src/extensions/sagemaker-ui-dark-theme/package.json +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/package.json ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/package.json @@ -0,0 +1,46 @@ +{ + "name": "sagemaker-ui-dark-theme", @@ -213,10 +213,10 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/package.json + "repository": { + } +} -Index: third-party-src/.vscode-test.js +Index: code-editor-src/.vscode-test.js =================================================================== ---- third-party-src.orig/.vscode-test.js -+++ third-party-src/.vscode-test.js +--- code-editor-src.orig/.vscode-test.js ++++ code-editor-src/.vscode-test.js @@ -63,6 +63,11 @@ const extensions = [ mocha: { timeout: 60_000 } }, @@ -229,11 +229,10 @@ Index: third-party-src/.vscode-test.js label: 'microsoft-authentication', mocha: { timeout: 60_000 } }, - -Index: third-party-src/extensions/sagemaker-ui-dark-theme/src/test/extension.test.ts +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/src/test/extension.test.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/src/test/extension.test.ts ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/src/test/extension.test.ts @@ -0,0 +1,123 @@ +import * as assert from 'assert'; +import * as vscode from 'vscode'; @@ -358,10 +357,10 @@ Index: third-party-src/extensions/sagemaker-ui-dark-theme/src/test/extension.tes + assert.strictEqual(theme?.globalValue, undefined, 'Global theme should not be set'); + }); +}); -Index: third-party-src/extensions/sagemaker-ui-dark-theme/src/test/index.ts +Index: code-editor-src/extensions/sagemaker-ui-dark-theme/src/test/index.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-ui-dark-theme/src/test/index.ts ++++ code-editor-src/extensions/sagemaker-ui-dark-theme/src/test/index.ts @@ -0,0 +1,33 @@ +import * as path from 'path'; +import * as testRunner from '../../../../test/integration/electron/testrunner'; diff --git a/patches/sagemaker/sagemaker-ui-post-startup.diff b/patches/sagemaker/sagemaker-ui-post-startup.diff index 3e22397..ed06db9 100644 --- a/patches/sagemaker/sagemaker-ui-post-startup.diff +++ b/patches/sagemaker/sagemaker-ui-post-startup.diff @@ -1,17 +1,16 @@ -Index: third-party-src/src/vs/server/node/webClientServer.ts +Index: code-editor-src/src/vs/server/node/webClientServer.ts =================================================================== ---- third-party-src.orig/src/vs/server/node/webClientServer.ts -+++ third-party-src/src/vs/server/node/webClientServer.ts -@@ -5,6 +5,8 @@ - - import { createReadStream, promises, existsSync, writeFileSync } from 'fs'; - import * as http from 'http'; -+import { spawn } from 'child_process'; -+import * as fs from 'fs'; +--- code-editor-src.orig/src/vs/server/node/webClientServer.ts ++++ code-editor-src/src/vs/server/node/webClientServer.ts +@@ -10,6 +10,7 @@ import * as path from 'path'; import * as url from 'url'; import * as cookie from 'cookie'; import * as crypto from 'crypto'; -@@ -38,6 +40,10 @@ const textMimeType: { [ext: string]: str ++import { spawn } from 'child_process'; + import { isEqualOrParent } from '../../base/common/extpath.js'; + import { getMediaMime } from '../../base/common/mime.js'; + import { isLinux } from '../../base/common/platform.js'; +@@ -40,6 +41,10 @@ const textMimeType: { [ext: string]: str '.svg': 'image/svg+xml', }; @@ -22,15 +21,15 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts /** * Return an error to the client. */ -@@ -97,6 +103,7 @@ const STATIC_PATH = `/static`; +@@ -100,6 +105,7 @@ const STATIC_PATH = `/static`; const CALLBACK_PATH = `/callback`; const WEB_EXTENSION_PATH = `/web-extension-resource`; const IDLE_EXTENSION_PATH = `/api/idle`; +const POST_STARTUP_SCRIPT_PATH = `/api/poststartup`; - export class WebClientServer { - -@@ -137,6 +144,9 @@ export class WebClientServer { + /** + * Checks for terminal activity by reading the /dev/pts directory and comparing modification times of the files. +@@ -172,6 +178,9 @@ export class WebClientServer { if (pathname === IDLE_EXTENSION_PATH) { return this._handleIdle(req, res); } @@ -40,7 +39,7 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts if (pathname.startsWith(WEB_EXTENSION_PATH) && pathname.charCodeAt(WEB_EXTENSION_PATH.length) === CharCode.Slash) { // extension resource support return this._handleWebExtensionResource(req, res, pathname.substring(WEB_EXTENSION_PATH.length)); -@@ -534,6 +544,41 @@ export class WebClientServer { +@@ -571,6 +580,41 @@ export class WebClientServer { serveError(req, res, 500, error.message) } } @@ -80,3 +79,5 @@ Index: third-party-src/src/vs/server/node/webClientServer.ts + } + } } + + diff --git a/patches/sagemaker/terminal-crash-mitigation.diff b/patches/sagemaker/terminal-crash-mitigation.diff index a936399..6ab4fed 100644 --- a/patches/sagemaker/terminal-crash-mitigation.diff +++ b/patches/sagemaker/terminal-crash-mitigation.diff @@ -1,7 +1,7 @@ -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/.vscodeignore +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/.vscodeignore =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/.vscodeignore ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/.vscodeignore @@ -0,0 +1,11 @@ +.vscode/** +.vscode-test/** @@ -14,10 +14,10 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/.vscodeign +out/** +cgmanifest.json +preview-src/** -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension-browser.webpack.config.js +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/extension-browser.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension-browser.webpack.config.js ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/extension-browser.webpack.config.js @@ -0,0 +1,17 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -36,10 +36,10 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension- + extension: './src/extension.ts' + }, +}); -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension.webpack.config.js +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/extension.webpack.config.js =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension.webpack.config.js ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/extension.webpack.config.js @@ -0,0 +1,20 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright Amazon.com Inc. or its affiliates. All rights reserved. @@ -61,18 +61,18 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/extension. + extension: './src/extension.ts', + } +}); -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/README.md +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/README.md =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/README.md ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/README.md @@ -0,0 +1,2 @@ +# Terminal Crash Mitigation +This extension addresses a critical issue where terminals fail to open. As of August 9, 2024, the root cause remains unidentified. The extension works by monitoring the creation of new terminals and detects if a terminal closes within 1 second of being opened. When this condition is met, it assumes the issue has occurred and attempts to mitigate it by terminating any background terminal processes. However, it will not terminate any terminal processes if there is an active terminal in the UI. \ No newline at end of file -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/package.json +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/package.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/package.json ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/package.json @@ -0,0 +1,43 @@ +{ + "name": "sagemaker-terminal-crash-mitigation", @@ -117,10 +117,10 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/package.js + "dependencies": {}, + "repository": {} +} -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/src/extension.ts +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/src/extension.ts =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/src/extension.ts ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/src/extension.ts @@ -0,0 +1,103 @@ +import * as vscode from 'vscode'; +import { exec } from 'child_process'; @@ -225,10 +225,10 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/src/extens +} + +export function deactivate() {} -Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/tsconfig.json +Index: code-editor-src/extensions/sagemaker-terminal-crash-mitigation/tsconfig.json =================================================================== --- /dev/null -+++ third-party-src/extensions/sagemaker-terminal-crash-mitigation/tsconfig.json ++++ code-editor-src/extensions/sagemaker-terminal-crash-mitigation/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.base.json", @@ -240,10 +240,10 @@ Index: third-party-src/extensions/sagemaker-terminal-crash-mitigation/tsconfig.j + "../../src/vscode-dts/vscode.d.ts" + ] +} -Index: third-party-src/build/gulpfile.extensions.js +Index: code-editor-src/build/gulpfile.extensions.js =================================================================== ---- third-party-src.orig/build/gulpfile.extensions.js -+++ third-party-src/build/gulpfile.extensions.js +--- code-editor-src.orig/build/gulpfile.extensions.js ++++ code-editor-src/build/gulpfile.extensions.js @@ -62,6 +62,7 @@ const compilations = [ 'extensions/simple-browser/tsconfig.json', 'extensions/sagemaker-extension/tsconfig.json', @@ -252,10 +252,10 @@ Index: third-party-src/build/gulpfile.extensions.js 'extensions/tunnel-forwarding/tsconfig.json', 'extensions/typescript-language-features/test-workspace/tsconfig.json', 'extensions/typescript-language-features/web/tsconfig.json', -Index: third-party-src/build/npm/dirs.js +Index: code-editor-src/build/npm/dirs.js =================================================================== ---- third-party-src.orig/build/npm/dirs.js -+++ third-party-src/build/npm/dirs.js +--- code-editor-src.orig/build/npm/dirs.js ++++ code-editor-src/build/npm/dirs.js @@ -40,6 +40,7 @@ const dirs = [ 'extensions/references-view', 'extensions/sagemaker-extension', diff --git a/sagemaker-tests/README.md b/sagemaker-tests/README.md new file mode 100644 index 0000000..d6ace57 --- /dev/null +++ b/sagemaker-tests/README.md @@ -0,0 +1,60 @@ +# SageMaker Code Editor Unit Tests + +This directory contains TypeScript unit tests that validate all patches applied to the VSCode codebase. + +## Test Structure + +Each patch file in `patches/series` has a corresponding test file: + +- `sagemaker-extension.test.ts` - Validates sagemaker-extension.diff patch +- `disable-online-services.test.ts` - Validates disable-online-services.diff patch +- `disable-telemetry.test.ts` - Validates disable-telemetry.diff patch +- `update-csp.test.ts` - Validates update-csp.diff patch +- `webview.test.ts` - Validates webview.diff patch +- `local-storage.test.ts` - Validates local-storage.diff patch +- `sagemaker-integration.test.ts` - Validates sagemaker-integration.diff patch +- `license.test.ts` - Validates license.diff patch +- `base-path-compatibility.test.ts` - Validates base-path-compatibility.diff patch +- `sagemaker-idle-extension.test.ts` - Validates sagemaker-idle-extension.patch +- `terminal-crash-mitigation.test.ts` - Validates terminal-crash-mitigation.patch +- `sagemaker-open-notebook-extension.test.ts` - Validates sagemaker-open-notebook-extension.patch +- `sagemaker-ui-dark-theme.test.ts` - Validates sagemaker-ui-dark-theme.patch +- `sagemaker-ui-post-startup.test.ts` - Validates sagemaker-ui-post-startup.patch +- `sagemaker-extension-smus-support.test.ts` - Validates sagemaker-extension-smus-support.patch +- `post-startup-notifications.test.ts` - Validates post-startup-notifications.patch +- `sagemaker-extensions-sync.test.ts` - Validates sagemaker-extensions-sync.patch +- `custom-extensions-marketplace.test.ts` - Validates custom-extensions-marketplace.diff patch +- `signature-verification.test.ts` - Validates signature-verification.diff patch +- `display-language.test.ts` - Validates display-language.patch + +**Total: 20 test files covering all patches in the series** + +## Running Tests + +### Locally +```bash +./scripts/run-unit-tests.sh +``` + +### In CI +Tests run automatically on every push via GitHub Actions in `.github/workflows/ci.yml` + +## Test Framework + +Tests use a simple Node.js-based framework defined in `test-framework.ts` with: +- `describe()` - Test suite grouping +- `test()` - Individual test cases + +## What Tests Validate + +Tests check that: +1. Patches are properly applied to `patched-vscode/` directory +2. Expected code modifications exist in target files +3. New files/directories are created where needed +4. Configuration changes are present + +## Requirements + +- Node.js 20+ +- TypeScript compiler (npx tsc) +- Patches must be applied (script handles this automatically) diff --git a/sagemaker-tests/base-path-compatibility.test.ts b/sagemaker-tests/base-path-compatibility.test.ts new file mode 100644 index 0000000..79d8c4a --- /dev/null +++ b/sagemaker-tests/base-path-compatibility.test.ts @@ -0,0 +1,37 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('base-path-compatibility.diff validation', () => { + test('serverEnvironmentService.ts should have base-path option added', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/serverEnvironmentService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for base-path option in serverOptions + const basePathOption = "'base-path': { type: 'string' },"; + if (!content.includes(basePathOption)) { + throw new Error(`Expected base-path option not found in ${filePath}`); + } + + // Check for base-path in ServerParsedArgs interface + const basePathArg = "'base-path'?: string,"; + if (!content.includes(basePathArg)) { + throw new Error(`Expected base-path argument type not found in ${filePath}`); + } + + // Check for constructor modification + const constructorLogic = "if (args['base-path']) {\n\t\t\targs['server-base-path'] = args['base-path'];\n\t\t}"; + if (!content.includes(constructorLogic)) { + throw new Error(`Expected constructor base-path mapping not found in ${filePath}`); + } + + console.log('PASS: Base path compatibility modifications found in serverEnvironmentService.ts'); + }); +}); diff --git a/sagemaker-tests/custom-extensions-marketplace.test.ts b/sagemaker-tests/custom-extensions-marketplace.test.ts new file mode 100644 index 0000000..94f0193 --- /dev/null +++ b/sagemaker-tests/custom-extensions-marketplace.test.ts @@ -0,0 +1,61 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('custom-extensions-marketplace.diff validation', () => { + test('product.ts should have custom extensions gallery logic', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/product/common/product.ts'); + const productPath = join(PATCHED_VSCODE_DIR, 'product.json'); + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const productContent = readFileSync(productPath, 'utf8'); + // Check for custom extensions gallery environment variable check + const customGalleryCheck = "if (env['EXTENSIONS_GALLERY']) {"; + if (!content.includes(customGalleryCheck)) { + throw new Error(`Expected custom extensions gallery check not found in ${filePath}`); + } + + // Check for custom gallery parsing log + const customGalleryLog = "console.log(`Custom extensions gallery detected. Parsing...`);"; + if (!content.includes(customGalleryLog)) { + throw new Error(`Expected custom gallery log not found in ${filePath}`); + } + + // Check for default gallery log - not needed for Code Editor, reference patches/web-server/marketplace.diff and patches/common/integration.diff + // const defaultGalleryLog = "console.log(`Using default extensions gallery.`);"; + // if (!content.includes(defaultGalleryLog)) { + // throw new Error(`Expected default gallery log not found in ${filePath}`); + // } + + // Check for open-vsx gallery configuration + const openVsxGallery = '"serviceUrl": "https://open-vsx.org/vscode/gallery",'; + if (!productContent.includes(openVsxGallery)) { + throw new Error(`Expected open-vsx gallery URL not found in ${productPath}`); + } + + // Check for item URL + const itemUrl = '"itemUrl": "https://open-vsx.org/vscode/item",'; + if (!productContent.includes(itemUrl)) { + throw new Error(`Expected open-vsx item URL not found in ${productPath}`); + } + + // Check for resource URL template + const resourceUrl = '"resourceUrlTemplate": "https://open-vsx.org/vscode/unpkg/{publisher}/{name}/{version}/{path}",'; + if (!productContent.includes(resourceUrl)) { + throw new Error(`Expected open-vsx resource URL template not found in ${productPath}`); + } + + // Check for gallery logging + const galleryLogging = "console.log(JSON.stringify(product.extensionsGallery, null, 2));"; + if (!content.includes(galleryLogging)) { + throw new Error(`Expected gallery logging not found in ${filePath}`); + } + + console.log('PASS: Custom extensions marketplace logic found in product.ts'); + }); +}); diff --git a/sagemaker-tests/disable-online-services.test.ts b/sagemaker-tests/disable-online-services.test.ts new file mode 100644 index 0000000..7dd4f65 --- /dev/null +++ b/sagemaker-tests/disable-online-services.test.ts @@ -0,0 +1,31 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('disable-online-services.diff validation', () => { + test('update.config.contribution.ts should disable automatic updates', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/update/common/update.config.contribution.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check update mode is set to none + const updateModeDefault = "default: 'none',"; + if (!content.includes(updateModeDefault)) { + throw new Error(`Expected update mode 'none' not found in ${filePath}`); + } + + // Check release notes are disabled + const releaseNotesDefault = "default: false,"; + if (!content.includes(releaseNotesDefault)) { + throw new Error(`Expected release notes disabled not found in ${filePath}`); + } + + console.log('PASS: Online services disabled in update configuration'); + }); +}); diff --git a/sagemaker-tests/disable-telemetry.test.ts b/sagemaker-tests/disable-telemetry.test.ts new file mode 100644 index 0000000..419b5db --- /dev/null +++ b/sagemaker-tests/disable-telemetry.test.ts @@ -0,0 +1,73 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('disable-telemetry.diff validation', () => { + test('telemetryService.ts should have telemetry disabled by default', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/telemetry/common/telemetryService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check that enum only contains OFF + const enumLine = "'enum': [TelemetryConfiguration.OFF],"; + if (!content.includes(enumLine)) { + throw new Error(`Expected telemetry enum restriction not found in ${filePath}`); + } + + // Check that default is OFF + const defaultLine = "'default': TelemetryConfiguration.OFF,"; + if (!content.includes(defaultLine)) { + throw new Error(`Expected telemetry default OFF not found in ${filePath}`); + } + + console.log('PASS: Telemetry disabled by default in telemetryService.ts'); + }); + + test('desktop.contribution.ts should have crash reporter disabled', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/electron-sandbox/desktop.contribution.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check crash reporter is disabled + const crashReporterDisabled = "'default': false,"; + if (!content.includes(crashReporterDisabled)) { + throw new Error(`Expected crash reporter disabled not found in ${filePath}`); + } + + console.log('PASS: Crash reporter disabled in desktop.contribution.ts'); + }); + + test('1dsAppender.ts should have Microsoft endpoints blocked', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/telemetry/common/1dsAppender.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check endpoints are redirected to 0.0.0.0 + const blockedEndpoint = "const endpointUrl = 'https://0.0.0.0/OneCollector/1.0';"; + const blockedHealthEndpoint = "const endpointHealthUrl = 'https://0.0.0.0/ping';"; + + if (!content.includes(blockedEndpoint)) { + throw new Error(`Expected blocked endpoint not found in ${filePath}`); + } + + if (!content.includes(blockedHealthEndpoint)) { + throw new Error(`Expected blocked health endpoint not found in ${filePath}`); + } + + console.log('PASS: Microsoft telemetry endpoints blocked in 1dsAppender.ts'); + }); +}); diff --git a/sagemaker-tests/display-language.test.ts b/sagemaker-tests/display-language.test.ts new file mode 100644 index 0000000..9e83e7f --- /dev/null +++ b/sagemaker-tests/display-language.test.ts @@ -0,0 +1,72 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('display-language.diff validation', () => { + test('remoteLanguagePacks.ts should have locale functions', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/remoteLanguagePacks.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + if (!content.includes('export const getLocaleFromConfig') || + !content.includes('export async function getBrowserNLSConfiguration')) { + throw new Error(`Failed to find locale functions in ${filePath}`); + } + + console.log('PASS: Locale functions found in remoteLanguagePacks.ts'); + }); + + test('webClientServer.ts should use locale from args', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + if (!content.includes('this._environmentService.args.locale')) { + throw new Error(`Failed to find locale from args in ${filePath}`); + } + + console.log('PASS: Locale from args found in webClientServer.ts'); + }); + + test('serverEnvironmentService.ts should have locale option', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/serverEnvironmentService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + if (!content.includes("'locale': { type: 'string' }")) { + throw new Error(`Failed to find locale option in ${filePath}`); + } + + console.log('PASS: Locale option found in serverEnvironmentService.ts'); + }); + + test('languagePacks.ts should use remote service', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/languagePacks/browser/languagePacks.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + if (!content.includes('ProxyChannel.toService')) { + throw new Error(`Failed to find ProxyChannel usage in ${filePath}`); + } + + console.log('PASS: Remote language pack service found in languagePacks.ts'); + }); +}); diff --git a/sagemaker-tests/globals.d.ts b/sagemaker-tests/globals.d.ts new file mode 100644 index 0000000..b63ece9 --- /dev/null +++ b/sagemaker-tests/globals.d.ts @@ -0,0 +1,6 @@ +declare global { + function describe(name: string, fn: () => void): void; + function test(name: string, fn: () => void): void; +} + +export {}; diff --git a/sagemaker-tests/license.test.ts b/sagemaker-tests/license.test.ts new file mode 100644 index 0000000..4a06935 --- /dev/null +++ b/sagemaker-tests/license.test.ts @@ -0,0 +1,40 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('license.diff validation', () => { + test('LICENSE file should exist with Amazon copyright', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'LICENSE'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for MIT License + if (!content.includes('MIT License')) { + throw new Error(`Expected MIT License header not found in ${filePath}`); + } + + // Check for Amazon copyright + const amazonCopyright = "Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved."; + if (!content.includes(amazonCopyright)) { + throw new Error(`Expected Amazon copyright not found in ${filePath}`); + } + + console.log('PASS: Amazon MIT License found in LICENSE file'); + }); + + test('LICENSE-THIRD-PARTY file should exist', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'LICENSE-THIRD-PARTY'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + console.log('PASS: Third-party license file exists'); + }); +}); diff --git a/sagemaker-tests/local-storage.test.ts b/sagemaker-tests/local-storage.test.ts new file mode 100644 index 0000000..71a173e --- /dev/null +++ b/sagemaker-tests/local-storage.test.ts @@ -0,0 +1,66 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('local-storage.diff validation', () => { + test('webClientServer.ts should pass userDataPath to browser', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedLine = "userDataPath: this._environmentService.userDataPath,"; + + if (!content.includes(expectedLine)) { + throw new Error(`Expected userDataPath configuration not found in ${filePath}`); + } + + console.log('PASS: userDataPath configuration found in webClientServer.ts'); + }); + + test('web.api.ts should have userDataPath property', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/browser/web.api.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for userDataPath property + const userDataPathProperty = "readonly userDataPath?: string"; + if (!content.includes(userDataPathProperty)) { + throw new Error(`Expected userDataPath property not found in ${filePath}`); + } + + console.log('PASS: userDataPath property found in web.api.ts'); + }); + + test('environmentService.ts should have userDataPath getter', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/services/environment/browser/environmentService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for userDataPath getter + const userDataPathGetter = "get userDataPath(): string {"; + if (!content.includes(userDataPathGetter)) { + throw new Error(`Expected userDataPath getter not found in ${filePath}`); + } + + // Check for modified userRoamingDataHome + const userRoamingDataHome = "get userRoamingDataHome(): URI { return joinPath(URI.file(this.userDataPath).with({ scheme: Schemas.vscodeRemote }), 'User'); }"; + if (!content.includes(userRoamingDataHome)) { + throw new Error(`Expected modified userRoamingDataHome not found in ${filePath}`); + } + + console.log('PASS: Local storage modifications found in environmentService.ts'); + }); +}); diff --git a/sagemaker-tests/post-startup-notifications.test.ts b/sagemaker-tests/post-startup-notifications.test.ts new file mode 100644 index 0000000..8223ad8 --- /dev/null +++ b/sagemaker-tests/post-startup-notifications.test.ts @@ -0,0 +1,70 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('post-startup-notifications.patch validation', () => { + test('post-startup-notifications should have .vscode/extensions.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/post-startup-notifications/.vscode/extensions.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const cleanContent = content.replace(/\/\/.*$/gm, '').replace(/\/\*[\s\S]*?\*\//g, ''); + const extensionsJson = JSON.parse(cleanContent); + + // Check for recommended extensions + const expectedRecommendations = ['dbaeumer.vscode-eslint', 'amodio.tsl-problem-matcher', 'ms-vscode.extension-test-runner']; + for (const recommendation of expectedRecommendations) { + if (!extensionsJson.recommendations.includes(recommendation)) { + throw new Error(`Expected recommendation '${recommendation}' not found in ${filePath}`); + } + } + + console.log('PASS: Post-startup notifications .vscode/extensions.json found'); + }); + + test('post-startup-notifications should have .vscode/launch.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/post-startup-notifications/.vscode/launch.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const cleanContent = content.replace(/^\s*\/\/.*$/gm, ''); + const launchJson = JSON.parse(cleanContent); + + // Check for Run Extension configuration + const runExtensionConfig = launchJson.configurations.find((config: any) => config.name === 'Run Extension'); + if (!runExtensionConfig) { + throw new Error(`Expected 'Run Extension' configuration not found in ${filePath}`); + } + + if (runExtensionConfig.type !== 'extensionHost') { + throw new Error(`Expected extensionHost type not found in ${filePath}`); + } + + console.log('PASS: Post-startup notifications .vscode/launch.json found'); + }); + + test('post-startup-notifications should have package.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/post-startup-notifications/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'post-startup-notifications') { + throw new Error(`Expected extension name 'post-startup-notifications', got: ${packageJson.name}`); + } + + console.log('PASS: Post-startup notifications package.json is valid'); + }); +}); diff --git a/sagemaker-tests/sagemaker-extension-smus-support.test.ts b/sagemaker-tests/sagemaker-extension-smus-support.test.ts new file mode 100644 index 0000000..d0442e1 --- /dev/null +++ b/sagemaker-tests/sagemaker-extension-smus-support.test.ts @@ -0,0 +1,37 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-extension-smus-support.patch validation', () => { + test('constant.ts should have SMUS support constants', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-extension/src/constant.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for SMUS service name constant + const smusServiceName = "export const SMUS_SERVICE_NAME = 'SageMakerUnifiedStudio';"; + if (!content.includes(smusServiceName)) { + throw new Error(`Expected SMUS service name constant not found in ${filePath}`); + } + + // Check for service name environment variable + const serviceNameEnvVar = "export const SERVICE_NAME_ENV_VAR = 'SERVICE_NAME';"; + if (!content.includes(serviceNameEnvVar)) { + throw new Error(`Expected service name env var constant not found in ${filePath}`); + } + + // Check for AdditionalMetadata interface extension + const additionalMetadata = "AdditionalMetadata?: {\n\t\tDataZoneDomainId?: string\n\t\tDataZoneProjectId?: string\n\t\tDataZoneDomainRegion?: string\n\t}"; + if (!content.includes(additionalMetadata)) { + throw new Error(`Expected AdditionalMetadata interface not found in ${filePath}`); + } + + console.log('PASS: SMUS support constants found in sagemaker-extension constant.ts'); + }); +}); diff --git a/sagemaker-tests/sagemaker-extension.test.ts b/sagemaker-tests/sagemaker-extension.test.ts new file mode 100644 index 0000000..13bfaaf --- /dev/null +++ b/sagemaker-tests/sagemaker-extension.test.ts @@ -0,0 +1,60 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-extension.diff validation', () => { + test('sagemaker-extension should have main extension.ts with required imports', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-extension/src/extension.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for SessionWarning import + const sessionWarningImport = 'import { SessionWarning } from "./sessionWarning";'; + if (!content.includes(sessionWarningImport)) { + throw new Error(`Expected SessionWarning import not found in ${filePath}`); + } + + // Check for constants import + const constantsImport = 'SAGEMAKER_METADATA_PATH,'; + if (!content.includes(constantsImport)) { + throw new Error(`Expected constants import not found in ${filePath}`); + } + + // Check for command constants + const parseCommand = "const PARSE_SAGEMAKER_COOKIE_COMMAND = 'sagemaker.parseCookies';"; + if (!content.includes(parseCommand)) { + throw new Error(`Expected parse cookie command not found in ${filePath}`); + } + + // Check for showWarningDialog function + const warningFunction = 'function showWarningDialog() {'; + if (!content.includes(warningFunction)) { + throw new Error(`Expected showWarningDialog function not found in ${filePath}`); + } + + console.log('PASS: SageMaker extension main file has required content'); + }); + + test('sagemaker-extension should have package.json with correct configuration', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-extension/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-extension') { + throw new Error(`Expected extension name 'sagemaker-extension', got: ${packageJson.name}`); + } + + console.log('PASS: SageMaker extension package.json is valid'); + }); +}); diff --git a/sagemaker-tests/sagemaker-extensions-sync.test.ts b/sagemaker-tests/sagemaker-extensions-sync.test.ts new file mode 100644 index 0000000..f229fdf --- /dev/null +++ b/sagemaker-tests/sagemaker-extensions-sync.test.ts @@ -0,0 +1,75 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-extensions-sync.patch validation', () => { + test('gulpfile.extensions.js should include sagemaker-extensions-sync', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'build/gulpfile.extensions.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedEntry = "'extensions/sagemaker-extensions-sync/tsconfig.json',"; + + if (!content.includes(expectedEntry)) { + throw new Error(`Expected gulpfile entry not found in ${filePath}`); + } + + console.log('PASS: Extensions sync added to gulpfile.extensions.js'); + }); + + test('dirs.js should include sagemaker-extensions-sync', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'build/npm/dirs.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedEntry = "'extensions/sagemaker-extensions-sync',"; + + if (!content.includes(expectedEntry)) { + throw new Error(`Expected dirs.js entry not found in ${filePath}`); + } + + console.log('PASS: Extensions sync added to dirs.js'); + }); + + test('sagemaker-extensions-sync should have .vscodeignore', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-extensions-sync/.vscodeignore'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for .vscode ignore pattern + if (!content.includes('.vscode/**')) { + throw new Error(`Expected .vscode ignore pattern not found in ${filePath}`); + } + + console.log('PASS: Extensions sync .vscodeignore found'); + }); + + test('sagemaker-extensions-sync should have package.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-extensions-sync/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-extensions-sync') { + throw new Error(`Expected extension name 'sagemaker-extensions-sync', got: ${packageJson.name}`); + } + + console.log('PASS: Extensions sync package.json is valid'); + }); +}); diff --git a/sagemaker-tests/sagemaker-idle-extension.test.ts b/sagemaker-tests/sagemaker-idle-extension.test.ts new file mode 100644 index 0000000..34d4e84 --- /dev/null +++ b/sagemaker-tests/sagemaker-idle-extension.test.ts @@ -0,0 +1,58 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-idle-extension.patch validation', () => { + test('sagemaker-idle-extension should have README with correct description', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-idle-extension/README.md'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedDescription = "The Code Editor Idle Extension tracks user activity and logs the last active timestamp (in UTC) to a local file."; + + if (!content.includes(expectedDescription)) { + throw new Error(`Expected README description not found in ${filePath}`); + } + + console.log('PASS: SageMaker idle extension README found with correct description'); + }); + + test('sagemaker-idle-extension should have webpack config', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-idle-extension/extension-browser.webpack.config.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedEntry = "entry: {\n extension: './src/extension.ts'\n },"; + + if (!content.includes(expectedEntry)) { + throw new Error(`Expected webpack entry not found in ${filePath}`); + } + + console.log('PASS: SageMaker idle extension webpack config found'); + }); + + test('sagemaker-idle-extension should have package.json with correct name', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-idle-extension/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-idle-extension') { + throw new Error(`Expected extension name 'sagemaker-idle-extension', got: ${packageJson.name}`); + } + + console.log('PASS: SageMaker idle extension package.json is valid'); + }); +}); diff --git a/sagemaker-tests/sagemaker-integration.test.ts b/sagemaker-tests/sagemaker-integration.test.ts new file mode 100644 index 0000000..1b734b8 --- /dev/null +++ b/sagemaker-tests/sagemaker-integration.test.ts @@ -0,0 +1,62 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-integration.diff validation', () => { + test('client.ts should exist with SagemakerServerClient class', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/browser/client.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for SagemakerServerClient class + const clientClass = "export class SagemakerServerClient extends Disposable {"; + if (!content.includes(clientClass)) { + throw new Error(`Expected SagemakerServerClient class not found in ${filePath}`); + } + + // Check for registerSagemakerCommands method call + const registerCommands = "this.registerSagemakerCommands();"; + if (!content.includes(registerCommands)) { + throw new Error(`Expected registerSagemakerCommands call not found in ${filePath}`); + } + + // Check for getCookieValue method + const getCookieMethod = "private getCookieValue(name: string): string | undefined {"; + if (!content.includes(getCookieMethod)) { + throw new Error(`Expected getCookieValue method not found in ${filePath}`); + } + + console.log('PASS: SagemakerServerClient integration found in client.ts'); + }); + + test('web.main.ts should instantiate SagemakerServerClient', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/browser/web.main.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for SagemakerServerClient import + const clientImport = "import { SagemakerServerClient } from" + + if (!content.includes(clientImport)) { + throw new Error(`Expected SagemakerServerClient import not found in ${filePath}`); + } + + // Check for SagemakerServerClient instantiation with register + const clientInstantiation = "this._register(instantiationService.createInstance(SagemakerServerClient));"; + if (!content.includes(clientInstantiation)) { + throw new Error(`Expected SagemakerServerClient instantiation not found in ${filePath}`); + } + + console.log('PASS: SagemakerServerClient integration found in web.main.ts'); + }); +}); diff --git a/sagemaker-tests/sagemaker-open-notebook-extension.test.ts b/sagemaker-tests/sagemaker-open-notebook-extension.test.ts new file mode 100644 index 0000000..7d4fff1 --- /dev/null +++ b/sagemaker-tests/sagemaker-open-notebook-extension.test.ts @@ -0,0 +1,68 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-open-notebook-extension.patch validation', () => { + test('gulpfile.extensions.js should include sagemaker-open-notebook-extension', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'build/gulpfile.extensions.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedEntry = "'extensions/sagemaker-open-notebook-extension/tsconfig.json',"; + + if (!content.includes(expectedEntry)) { + throw new Error(`Expected gulpfile entry not found in ${filePath}`); + } + + console.log('PASS: Open notebook extension added to gulpfile.extensions.js'); + }); + + test('dirs.js should include sagemaker-open-notebook-extension', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'build/npm/dirs.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedEntry = "'extensions/sagemaker-open-notebook-extension',"; + + if (!content.includes(expectedEntry)) { + throw new Error(`Expected dirs.js entry not found in ${filePath}`); + } + + console.log('PASS: Open notebook extension added to dirs.js'); + }); + + test('sagemaker-open-notebook-extension should have package.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-open-notebook-extension/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-open-notebook-extension') { + throw new Error(`Expected extension name 'sagemaker-open-notebook-extension', got: ${packageJson.name}`); + } + + console.log('PASS: Open notebook extension package.json is valid'); + }); + + test('sagemaker-open-notebook-extension should have main extension file', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-open-notebook-extension/src/extension.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + console.log('PASS: Open notebook extension main file exists'); + }); +}); diff --git a/sagemaker-tests/sagemaker-ui-dark-theme.test.ts b/sagemaker-tests/sagemaker-ui-dark-theme.test.ts new file mode 100644 index 0000000..5de9baf --- /dev/null +++ b/sagemaker-tests/sagemaker-ui-dark-theme.test.ts @@ -0,0 +1,79 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-ui-dark-theme.patch validation', () => { + test('sagemaker-ui-dark-theme should have README', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-ui-dark-theme/README.md'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedTitle = '# SageMaker UI Dark Theme'; + + if (!content.includes(expectedTitle)) { + throw new Error(`Expected README title not found in ${filePath}`); + } + + console.log('PASS: SageMaker UI dark theme README found'); + }); + + test('sagemaker-ui-dark-theme should have .vscodeignore', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-ui-dark-theme/.vscodeignore'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for specific ignore patterns + const ignorePatterns = ['.vscode/**', 'src/**', 'cgmanifest.json']; + for (const pattern of ignorePatterns) { + if (!content.includes(pattern)) { + throw new Error(`Expected ignore pattern '${pattern}' not found in ${filePath}`); + } + } + + console.log('PASS: UI dark theme .vscodeignore found'); + }); + + test('sagemaker-ui-dark-theme should have webpack config', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-ui-dark-theme/extension-browser.webpack.config.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for Amazon copyright + const copyright = 'Copyright Amazon.com Inc. or its affiliates. All rights reserved.'; + if (!content.includes(copyright)) { + throw new Error(`Expected Amazon copyright not found in ${filePath}`); + } + + console.log('PASS: UI dark theme webpack config found'); + }); + + test('sagemaker-ui-dark-theme should have package.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-ui-dark-theme/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-ui-dark-theme') { + throw new Error(`Expected extension name 'sagemaker-ui-dark-theme', got: ${packageJson.name}`); + } + + console.log('PASS: UI dark theme package.json is valid'); + }); +}); diff --git a/sagemaker-tests/sagemaker-ui-post-startup.test.ts b/sagemaker-tests/sagemaker-ui-post-startup.test.ts new file mode 100644 index 0000000..fa6fe49 --- /dev/null +++ b/sagemaker-tests/sagemaker-ui-post-startup.test.ts @@ -0,0 +1,63 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('sagemaker-ui-post-startup.patch validation', () => { + test('webClientServer.ts should have post-startup imports and constants', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for spawn import + const spawnImport = "import { spawn } from 'child_process';"; + if (!content.includes(spawnImport)) { + throw new Error(`Expected spawn import not found in ${filePath}`); + } + + // Check for fs import + const fsImport = "import * as fs from 'fs';"; + if (!content.includes(fsImport)) { + throw new Error(`Expected fs import not found in ${filePath}`); + } + + // Check for ServiceName enum + const serviceNameEnum = "const enum ServiceName {\n\tSAGEMAKER_UNIFIED_STUDIO = 'SageMakerUnifiedStudio',\n}"; + if (!content.includes(serviceNameEnum)) { + throw new Error(`Expected ServiceName enum not found in ${filePath}`); + } + + // Check for POST_STARTUP_SCRIPT_PATH constant + const postStartupPath = "const POST_STARTUP_SCRIPT_PATH = `/api/poststartup`;"; + if (!content.includes(postStartupPath)) { + throw new Error(`Expected POST_STARTUP_SCRIPT_PATH constant not found in ${filePath}`); + } + + console.log('PASS: Post-startup modifications found in webClientServer.ts'); + }); + + test('gettingStarted.ts should exist and may contain UI modifications', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/contrib/welcomeGettingStarted/browser/gettingStarted.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + console.log('PASS: gettingStarted.ts file exists'); + }); + + test('gettingStartedContent.ts should exist and may contain content modifications', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/contrib/welcomeGettingStarted/common/gettingStartedContent.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + console.log('PASS: gettingStartedContent.ts file exists'); + }); +}); diff --git a/sagemaker-tests/signature-verification.test.ts b/sagemaker-tests/signature-verification.test.ts new file mode 100644 index 0000000..65bebe9 --- /dev/null +++ b/sagemaker-tests/signature-verification.test.ts @@ -0,0 +1,37 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('signature-verification.diff validation', () => { + test('extensionManagementService.ts should have signature verification disabled', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/platform/extensionManagement/node/extensionManagementService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for first @ts-expect-error comment before VerifyExtensionSignatureConfigKey - not required in Code Editor due to patches/common/allow-unused-vars.diff + // const firstBypassComment = "\t// @ts-expect-error no-unused-variable\n\tVerifyExtensionSignatureConfigKey,"; + // if (!content.includes(firstBypassComment)) { + // throw new Error(`Expected first @ts-expect-error comment not found in ${filePath}`); + // } + + // Check for second @ts-expect-error comment before configurationService - not required in Code Editor due to patches/common/allow-unused-vars.diff + // const secondBypassComment = "\t\t// @ts-expect-error no-unused-variable\n\t\t@IConfigurationService private readonly configurationService: IConfigurationService,"; + // if (!content.includes(secondBypassComment)) { + // throw new Error(`Expected second @ts-expect-error comment not found in ${filePath}`); + // } + + // Check for verifySignature = false modification + const verifySignatureFalse = "\t\t\tverifySignature = false;"; + if (!content.includes(verifySignatureFalse)) { + throw new Error(`Expected verifySignature = false not found in ${filePath}`); + } + + console.log('PASS: All signature verification modifications found in extensionManagementService.ts'); + }); +}); diff --git a/sagemaker-tests/terminal-crash-mitigation.test.ts b/sagemaker-tests/terminal-crash-mitigation.test.ts new file mode 100644 index 0000000..a018db5 --- /dev/null +++ b/sagemaker-tests/terminal-crash-mitigation.test.ts @@ -0,0 +1,62 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('terminal-crash-mitigation.patch validation', () => { + test('sagemaker-terminal-crash-mitigation should have .vscodeignore', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-terminal-crash-mitigation/.vscodeignore'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for specific ignore patterns + const ignorePatterns = ['.vscode/**', 'src/**', 'tsconfig.json']; + for (const pattern of ignorePatterns) { + if (!content.includes(pattern)) { + throw new Error(`Expected ignore pattern '${pattern}' not found in ${filePath}`); + } + } + + console.log('PASS: Terminal crash mitigation .vscodeignore found'); + }); + + test('sagemaker-terminal-crash-mitigation should have webpack config', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-terminal-crash-mitigation/extension-browser.webpack.config.js'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + + // Check for Amazon copyright + const copyright = 'Copyright Amazon.com Inc. or its affiliates. All rights reserved.'; + if (!content.includes(copyright)) { + throw new Error(`Expected Amazon copyright not found in ${filePath}`); + } + + console.log('PASS: Terminal crash mitigation webpack config found'); + }); + + test('sagemaker-terminal-crash-mitigation should have package.json', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'extensions/sagemaker-terminal-crash-mitigation/package.json'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const packageJson = JSON.parse(content); + + if (packageJson.name !== 'sagemaker-terminal-crash-mitigation') { + throw new Error(`Expected extension name 'sagemaker-terminal-crash-mitigation', got: ${packageJson.name}`); + } + + console.log('PASS: Terminal crash mitigation package.json is valid'); + }); +}); diff --git a/sagemaker-tests/test-framework.ts b/sagemaker-tests/test-framework.ts new file mode 100644 index 0000000..4559973 --- /dev/null +++ b/sagemaker-tests/test-framework.ts @@ -0,0 +1,24 @@ +// Simple test framework for Node.js +export function describe(name: string, fn: () => void) { + console.log(`\n${name}`); + try { + fn(); + } catch (error) { + console.error(`Test suite failed: ${error.message}`); + process.exit(1); + } +} + +export function test(name: string, fn: () => void) { + try { + fn(); + console.log(` ${name}`); + } catch (error) { + console.error(`${name}: ${error.message}`); + throw error; + } +} + +// Make functions global for test files +(global as any).describe = describe; +(global as any).test = test; diff --git a/sagemaker-tests/tsconfig.json b/sagemaker-tests/tsconfig.json new file mode 100644 index 0000000..74e907c --- /dev/null +++ b/sagemaker-tests/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "es2020", + "module": "commonjs", + "esModuleInterop": true, + "skipLibCheck": true, + "types": ["node"] + }, + "include": ["*.ts", "globals.d.ts"] +} diff --git a/sagemaker-tests/update-csp.test.ts b/sagemaker-tests/update-csp.test.ts new file mode 100644 index 0000000..c64d4a7 --- /dev/null +++ b/sagemaker-tests/update-csp.test.ts @@ -0,0 +1,51 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('update-csp.diff validation', () => { + test('webClientServer.ts should have required CSP configuration', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const cspKeywords = [ + 'connect-src', + 'https://main.vscode-cdn.net', + 'http://localhost:*', + 'https://localhost:*', + 'https://login.microsoftonline.com/', + 'https://update.code.visualstudio.com', + 'https://*.vscode-unpkg.net/', + 'https://default.exp-tas.com/vscode/ab', + 'https://vscode-sync.trafficmanager.net', + 'https://vscode-sync-insiders.trafficmanager.net', + 'https://*.gallerycdn.vsassets.io', + 'https://marketplace.visualstudio.com', + 'https://openvsxorg.blob.core.windows.net', + 'https://az764295.vo.msecnd.net', + 'https://code.visualstudio.com', + 'https://*.gallery.vsassets.io', + 'https://*.rel.tunnels.api.visualstudio.com', + 'https://*.servicebus.windows.net/', + 'https://vscode.blob.core.windows.net', + 'https://vscode.search.windows.net', + 'https://vsmarketplacebadges.dev', + 'https://vscode.download.prss.microsoft.com', + 'https://download.visualstudio.microsoft.com', + 'https://*.vscode-unpkg.net', + 'https://open-vsx.org' + ]; + + const hasAllKeywords = cspKeywords.every(keyword => content.includes(keyword)); + if (!hasAllKeywords) { + throw new Error(`Required CSP directive not found in ${filePath}`); + } + + console.log('PASS: Required CSP configuration found in webClientServer.ts'); + }); +}); diff --git a/sagemaker-tests/webview.test.ts b/sagemaker-tests/webview.test.ts new file mode 100644 index 0000000..2c1ec78 --- /dev/null +++ b/sagemaker-tests/webview.test.ts @@ -0,0 +1,109 @@ +import { readFileSync, existsSync } from 'fs'; +import { join } from 'path'; +import './test-framework'; + +const PATCHED_VSCODE_DIR = join(process.cwd(), 'code-editor-src'); + +describe('webview.diff validation', () => { + test('environmentService.ts should have webview endpoint modification', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/services/environment/browser/environmentService.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedLine = 'const endpoint = (this.options.webviewEndpoint && new URL(this.options.webviewEndpoint, window.location.toString()).toString())'; + + if (!content.includes(expectedLine)) { + throw new Error(`Expected webview endpoint modification not found in ${filePath}`); + } + + console.log('PASS: webview endpoint modification found in environmentService.ts'); + }); + + test('webClientServer.ts should have webviewEndpoint configuration', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/server/node/webClientServer.ts'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedLine = "webviewEndpoint: staticRoute + '/out/vs/workbench/contrib/webview/browser/pre',"; + + if (!content.includes(expectedLine)) { + throw new Error(`Expected webviewEndpoint configuration not found in ${filePath}`); + } + + console.log('PASS: webviewEndpoint configuration found in webClientServer.ts'); + }); + + test('webview pre/index.html should have updated CSP hash', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/contrib/webview/browser/pre/index.html'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedHash = "script-src 'sha256-Oi71Tq4Buohx0KDH3yEbVJUzABnqYv9iVLo420HZXqI=' 'self'"; + + if (!content.includes(expectedHash)) { + throw new Error(`Expected CSP hash not found in ${filePath}`); + } + + console.log('PASS: Updated CSP hash found in webview pre/index.html'); + }); + + test('webview pre/index.html should have hostname bypass logic', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/contrib/webview/browser/pre/index.html'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedLogic = 'if (parent.hostname === hostname) {\n\t\t\t\t\treturn start(parentOrigin)\n\t\t\t\t}'; + + if (!content.includes(expectedLogic)) { + throw new Error(`Expected hostname bypass logic not found in ${filePath}`); + } + + console.log('PASS: Hostname bypass logic found in webview pre/index.html'); + }); + + test('webWorkerExtensionHostIframe.html should have updated CSP hash', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedHash = "script-src 'self' 'wasm-unsafe-eval' 'sha256-yhZXuB8LS6t73dvNg6rtLX8y4PHLnqRm5+6DdOGkOcw=' https: http://localhost:* blob:;"; + + if (!content.includes(expectedHash)) { + throw new Error(`Expected CSP hash not found in ${filePath}`); + } + + console.log('PASS: Updated CSP hash found in webWorkerExtensionHostIframe.html'); + }); + + test('webWorkerExtensionHostIframe.html should have hostname bypass logic', () => { + const filePath = join(PATCHED_VSCODE_DIR, 'src/vs/workbench/services/extensions/worker/webWorkerExtensionHostIframe.html'); + + if (!existsSync(filePath)) { + throw new Error(`File not found: ${filePath}`); + } + + const content = readFileSync(filePath, 'utf8'); + const expectedLogic = 'if (parent.hostname === hostname) {\n\t\t\treturn start()\n\t\t}'; + + if (!content.includes(expectedLogic)) { + throw new Error(`Expected hostname bypass logic not found in ${filePath}`); + } + + console.log('PASS: Hostname bypass logic found in webWorkerExtensionHostIframe.html'); + }); +}); diff --git a/scripts/run-sagemaker-unit-tests.sh b/scripts/run-sagemaker-unit-tests.sh new file mode 100755 index 0000000..148fa90 --- /dev/null +++ b/scripts/run-sagemaker-unit-tests.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +set -e + +echo "INFO: Running SageMaker Code Editor Unit Tests" + +# Get project root +PROJ_ROOT=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd) +cd "$PROJ_ROOT" + +# Check if code-editor-src exists, if not prepare it +if [ ! -d "code-editor-src" ]; then + echo "INFO: code-editor-src not found, preparing source..." + ./scripts/prepare-src.sh code-editor-sagemaker-server +fi + +# Check if Node.js and npx are available +if ! command -v node &> /dev/null || ! command -v npx &> /dev/null; then + echo "ERROR: Node.js and npm are required to run tests" + exit 1 +fi + +#Install required dependencies +echo "Installing dependencies..." +npm install -g typescript +npm install --save-dev @types/node + +# Compile and run each test file +TEST_DIR="sagemaker-tests" +FAILED_TESTS=0 +TOTAL_TESTS=0 + +# First compile all TypeScript files +echo "Compiling TypeScript files..." +if ! npx tsc --project "$TEST_DIR/tsconfig.json" --outDir /tmp/tests; then + echo "ERROR: TypeScript compilation failed" + exit 1 +fi + +for test_file in "$TEST_DIR"/*.test.ts; do + if [ -f "$test_file" ]; then + TOTAL_TESTS=$((TOTAL_TESTS + 1)) + test_name=$(basename "$test_file" .test.ts) + + echo "Running $test_name tests..." + + # Run the compiled JavaScript + if node "/tmp/tests/$(basename "$test_file" .ts).js"; then + echo "SUCCESS: $test_name tests passed" + else + echo "FAILED: $test_name tests failed" + FAILED_TESTS=$((FAILED_TESTS + 1)) + fi + echo "" + fi +done + +# Summary +echo "INFO: Test Summary:" +echo "Total test suites: $TOTAL_TESTS" +echo "Failed test suites: $FAILED_TESTS" +echo "Passed test suites: $((TOTAL_TESTS - FAILED_TESTS))" + +if [ $FAILED_TESTS -eq 0 ]; then + echo "SUCCESS: All tests passed!" + exit 0 +else + echo "FAILED: $FAILED_TESTS test suite(s) failed" + exit 1 +fi