Skip to content

Commit 97f2e88

Browse files
fix: resolve CodeQL high-severity findings and harden CI (#966)
* chore: gitignore CLAUDE.md (local agent notes) * fix: escape all backslashes in the venv activate path preview String.prototype.replace with a string pattern only replaces the first match, so a Windows activate path with multiple separators was left partially unescaped in the command preview. Use a global regex. Fixes a CodeQL incomplete-string-escaping finding (CWE-116). * fix: stop logging the server environment in clear text The launch debug log stringified execOptions, which embeds the full process environment (and any user-set server env vars), writing secrets to the log file. Log only cwd, shell, and the env var count. Fixes a CodeQL clear-text-logging finding (CWE-312). * fix: drop check-then-act before recursive mkdir in workspace save existsSync followed by mkdirSync is a TOCTOU pattern; mkdirSync with recursive: true is already idempotent, so the guard was both racy and redundant. Call it directly. Fixes a CodeQL file-system-race finding (CWE-367). * ci: add least-privilege permissions to workflows None of the release workflows declared GITHUB_TOKEN permissions, so they ran with the repository default. Scope each to what it needs: release workflows get contents: write (plus pull-requests: write for the release PR), winget and the publish workflow default to contents: read. Fixes CodeQL missing-workflow-permissions findings. * ci: pin workflow actions to commit SHAs Tags are mutable; a moved tag on any of these actions (several are third-party and handle release/signing secrets) could inject code into CI. Pin every action to a full-length commit SHA with the version in a trailing comment so Dependabot's github-actions config keeps them current. Fixes CodeQL unpinned-tag findings. * ci: drop unused GITHUB_TOKEN write scopes on release workflows The release PR and pre-release steps authenticate with secrets.JLAB_APP_TOKEN, not the default GITHUB_TOKEN, and no step uses GITHUB_TOKEN for writes. Reduce both workflows to contents: read for true least-privilege. Addresses Copilot review feedback on #966. * Update repo name from vedantmgoyal2009 to vedantmgoyal9 --------- Co-authored-by: Michał Krassowski <5832902+krassowski@users.noreply.github.com>
1 parent 9549bc1 commit 97f2e88

9 files changed

Lines changed: 63 additions & 49 deletions

File tree

.github/workflows/prerelease.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ name: Create Pre-release
33
on:
44
workflow_dispatch:
55

6+
permissions:
7+
contents: read
8+
69
jobs:
710
prerelease:
811
runs-on: ubuntu-latest
912
steps:
1013
- name: Checkout
11-
uses: actions/checkout@v4
14+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
1215

1316
- name: Get package info
1417
shell: bash
1518
id: package-info
1619
run: echo "version=$(python scripts/get_package_version.py)" >> $GITHUB_OUTPUT
1720

1821
- name: 'Find Release with tag v${{ steps.package-info.outputs.version}}'
19-
uses: actions/github-script@v7
22+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
2023
id: release-exists
2124
env:
2225
APP_VERSION: ${{ steps.package-info.outputs.version}}
@@ -32,7 +35,7 @@ jobs:
3235
result-encoding: string
3336

3437
- name: Create pre-release
35-
uses: softprops/action-gh-release@v2
38+
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
3639
if: steps.release-exists.outputs.result == 'false'
3740
with:
3841
token: ${{ secrets.JLAB_APP_TOKEN }}

.github/workflows/publish.yml

Lines changed: 25 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,18 @@ on:
99
# Allows you to run this workflow manually from the Actions tab
1010
workflow_dispatch:
1111

12+
permissions:
13+
contents: read
14+
1215
jobs:
1316
test:
1417
name: 'Unit tests'
1518
runs-on: ubuntu-latest
1619
permissions:
1720
contents: read
1821
steps:
19-
- uses: actions/checkout@v5
20-
- uses: actions/setup-node@v5
22+
- uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5
23+
- uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
2124
with:
2225
node-version: '20.x'
2326
cache: 'yarn'
@@ -42,8 +45,8 @@ jobs:
4245
shell: bash -el {0}
4346

4447
steps:
45-
- uses: actions/checkout@v4
46-
- uses: conda-incubator/setup-miniconda@v3
48+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
49+
- uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 # v3
4750
with:
4851
auto-update-conda: true
4952
auto-activate-base: true
@@ -53,7 +56,7 @@ jobs:
5356
- run: conda install --file ./workflow_env/conda-${{ matrix.cfg.build_platform }}.lock -y
5457

5558
- name: Install node
56-
uses: actions/setup-node@v5
59+
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
5760
with:
5861
node-version: '20.x'
5962
cache: 'yarn'
@@ -77,7 +80,7 @@ jobs:
7780
run: echo "version=$(python scripts/get_package_version.py)" >> $GITHUB_OUTPUT
7881

7982
- name: 'Find Release with tag v${{ steps.package-info.outputs.version}}'
80-
uses: actions/github-script@v7
83+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
8184
id: release-exists
8285
env:
8386
APP_VERSION: ${{ steps.package-info.outputs.version}}
@@ -150,23 +153,23 @@ jobs:
150153

151154
- name: Upload Debian x64 Installer
152155
if: matrix.cfg.platform == 'linux-64'
153-
uses: actions/upload-artifact@v4
156+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
154157
with:
155158
name: debian-installer-x64
156159
path: |
157160
dist/JupyterLab.deb
158161
159162
- name: Upload Fedora x64 Installer
160163
if: matrix.cfg.platform == 'linux-64'
161-
uses: actions/upload-artifact@v4
164+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
162165
with:
163166
name: fedora-installer-x64
164167
path: |
165168
dist/JupyterLab.rpm
166169
167170
- name: Upload Snap Installer
168171
if: matrix.cfg.platform == 'linux-64'
169-
uses: actions/upload-artifact@v4
172+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
170173
id: snap-artifact
171174
with:
172175
name: snap-installer
@@ -175,31 +178,31 @@ jobs:
175178
176179
- name: Upload macOS x64 Installer
177180
if: matrix.cfg.platform == 'osx-64'
178-
uses: actions/upload-artifact@v4
181+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
179182
with:
180183
name: mac-installer-x64
181184
path: |
182185
dist/JupyterLab-x64.dmg
183186
184187
- name: Upload macOS arm64 Installer
185188
if: matrix.cfg.platform == 'osx-arm64'
186-
uses: actions/upload-artifact@v4
189+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
187190
with:
188191
name: mac-installer-arm64
189192
path: |
190193
dist/JupyterLab-arm64.dmg
191194
192195
- name: Upload Windows x64 Installer
193196
if: matrix.cfg.platform == 'win-64'
194-
uses: actions/upload-artifact@v4
197+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
195198
with:
196199
name: windows-installer-x64
197200
path: |
198201
dist/JupyterLab-Setup.exe
199202
200203
- name: Upload Debian x64 Installer as Release asset
201204
if: matrix.cfg.platform == 'linux-64' && steps.release-exists.outputs.result == 'true'
202-
uses: svenstaro/upload-release-action@v2
205+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
203206
with:
204207
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
205208
file: dist/JupyterLab.deb
@@ -209,7 +212,7 @@ jobs:
209212

210213
- name: Upload Fedora x64 Installer as Release asset
211214
if: matrix.cfg.platform == 'linux-64' && steps.release-exists.outputs.result == 'true'
212-
uses: svenstaro/upload-release-action@v2
215+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
213216
with:
214217
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
215218
file: dist/JupyterLab.rpm
@@ -219,7 +222,7 @@ jobs:
219222

220223
- name: Upload macOS x64 Installer as Release asset
221224
if: matrix.cfg.platform == 'osx-64' && steps.release-exists.outputs.result == 'true'
222-
uses: svenstaro/upload-release-action@v2
225+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
223226
with:
224227
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
225228
file: dist/JupyterLab-x64.dmg
@@ -229,7 +232,7 @@ jobs:
229232

230233
- name: Upload macOS arm64 Installer as Release asset
231234
if: matrix.cfg.platform == 'osx-arm64' && steps.release-exists.outputs.result == 'true'
232-
uses: svenstaro/upload-release-action@v2
235+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
233236
with:
234237
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
235238
file: dist/JupyterLab-arm64.dmg
@@ -239,7 +242,7 @@ jobs:
239242

240243
- name: Upload macOS x64 App as Release asset
241244
if: matrix.cfg.platform == 'osx-64' && steps.release-exists.outputs.result == 'true'
242-
uses: svenstaro/upload-release-action@v2
245+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
243246
with:
244247
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
245248
file: dist/JupyterLab-x64.zip
@@ -249,7 +252,7 @@ jobs:
249252

250253
- name: Upload macOS arm64 App as Release asset
251254
if: matrix.cfg.platform == 'osx-arm64' && steps.release-exists.outputs.result == 'true'
252-
uses: svenstaro/upload-release-action@v2
255+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
253256
with:
254257
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
255258
file: dist/JupyterLab-arm64.zip
@@ -259,7 +262,7 @@ jobs:
259262

260263
- name: Upload Windows x64 Installer as Release asset
261264
if: matrix.cfg.platform == 'win-64' && steps.release-exists.outputs.result == 'true'
262-
uses: svenstaro/upload-release-action@v2
265+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
263266
with:
264267
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
265268
file: dist/JupyterLab-Setup.exe
@@ -269,7 +272,7 @@ jobs:
269272

270273
- name: Upload latest.yml Release asset
271274
if: matrix.cfg.platform == 'win-64' && steps.release-exists.outputs.result == 'true'
272-
uses: svenstaro/upload-release-action@v2
275+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
273276
with:
274277
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
275278
file: dist/latest.yml
@@ -279,7 +282,7 @@ jobs:
279282

280283
- name: Upload snap installer as Release asset
281284
if: matrix.cfg.platform == 'linux-64' && steps.release-exists.outputs.result == 'true'
282-
uses: svenstaro/upload-release-action@v2
285+
uses: svenstaro/upload-release-action@29e53e917877a24fad85510ded594ab3c9ca12de # v2
283286
with:
284287
repo_token: ${{ secrets.JLAB_APP_TOKEN }}
285288
file: dist/JupyterLab.snap
@@ -289,7 +292,7 @@ jobs:
289292

290293
- name: Publish snap to the latest/candidate channel in Snap Store
291294
if: matrix.cfg.platform == 'linux-64' && steps.release-exists.outputs.result == 'true'
292-
uses: snapcore/action-publish@v1
295+
uses: snapcore/action-publish@214b86e5ca036ead1668c79afb81e550e6c54d40 # v1
293296
env:
294297
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_STORE_CREDENTIALS }}
295298
with:

.github/workflows/releasepr.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,20 +3,23 @@ name: Create Release PR
33
on:
44
workflow_dispatch:
55

6+
permissions:
7+
contents: read
8+
69
jobs:
710
createPR:
811
runs-on: ubuntu-latest
912
steps:
1013
- name: Checkout
11-
uses: actions/checkout@v4
14+
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
1215

1316
- name: Get package info
1417
shell: bash
1518
id: package-info
1619
run: echo "version=$(python scripts/get_package_version.py)" >> $GITHUB_OUTPUT
1720

1821
- name: 'Find pre-release with tag v${{ steps.package-info.outputs.version}}'
19-
uses: actions/github-script@v7
22+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
2023
id: pre-release-exists
2124
env:
2225
APP_VERSION: ${{ steps.package-info.outputs.version}}
@@ -37,7 +40,7 @@ jobs:
3740

3841
- name: Create Release pull request
3942
if: steps.pre-release-exists.outputs.result == 'true'
40-
uses: peter-evans/create-pull-request@v6
43+
uses: peter-evans/create-pull-request@c5a7806660adbe173f04e3e038b0ccdcd758773c # v6
4144
with:
4245
token: ${{ secrets.JLAB_APP_TOKEN }}
4346
commit-message: Update auto-release logs

.github/workflows/sync_lab_release.yml

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,16 +18,16 @@ jobs:
1818
latest: ${{ steps.get-latest-jupyterlab-version.outputs.result }}
1919
update_available: ${{ steps.check-update.outputs.update_available }}
2020
steps:
21-
- uses: actions/create-github-app-token@v2
21+
- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2
2222
id: app-token
2323
with:
2424
app-id: ${{ vars.APP_ID }}
2525
private-key: ${{ secrets.APP_PRIVATE_KEY }}
2626

27-
- uses: actions/checkout@v4
27+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
2828

2929
- name: Set up Python
30-
uses: actions/setup-python@v6
30+
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
3131
with:
3232
python-version: '3.9'
3333

@@ -36,7 +36,7 @@ jobs:
3636

3737
- name: Get latest JupyterLab version
3838
id: get-latest-jupyterlab-version
39-
uses: actions/github-script@v7
39+
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
4040
with:
4141
github-token: ${{ steps.app-token.outputs.token }}
4242
script: |
@@ -61,7 +61,7 @@ jobs:
6161
fi
6262
6363
- name: Upload updated version spec files
64-
uses: actions/upload-artifact@v4
64+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
6565
if: steps.check-update.outputs.update_available == 'true'
6666
with:
6767
name: updated-version-info
@@ -82,16 +82,16 @@ jobs:
8282
permissions:
8383
contents: read
8484
steps:
85-
- uses: actions/checkout@v4
85+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
8686

8787
- name: Download updated version info
88-
uses: actions/download-artifact@v4
88+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
8989
with:
9090
name: updated-version-info
9191
path: .
9292

9393
- name: Install Node
94-
uses: actions/setup-node@v5
94+
uses: actions/setup-node@a0853c24544627f65ddf259abe73b1d18a591444 # v5
9595
with:
9696
node-version: '20.x'
9797

@@ -100,7 +100,7 @@ jobs:
100100
npm install --global yarn
101101
yarn install
102102
103-
- uses: conda-incubator/setup-miniconda@v3
103+
- uses: conda-incubator/setup-miniconda@fc2d68f6413eb2d87b895e92f8584b5b94a10167 # v3
104104
with:
105105
auto-update-conda: true
106106
auto-activate-base: true
@@ -134,7 +134,7 @@ jobs:
134134
done
135135
136136
- name: Upload updated repo as artifact
137-
uses: actions/upload-artifact@v4
137+
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
138138
with:
139139
name: updated-repo
140140
path: changed-files/
@@ -149,18 +149,18 @@ jobs:
149149
contents: write
150150
pull-requests: write
151151
steps:
152-
- uses: actions/create-github-app-token@v2
152+
- uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2
153153
id: app-token
154154
with:
155155
app-id: ${{ vars.APP_ID }}
156156
private-key: ${{ secrets.APP_PRIVATE_KEY }}
157157

158-
- uses: actions/checkout@v4
158+
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
159159
with:
160160
token: ${{ steps.app-token.outputs.token }}
161161

162162
- name: Download updated lock files and sign lists
163-
uses: actions/download-artifact@v4
163+
uses: actions/download-artifact@d3f86a106a0bac45b974a628896c90dbdf5c8093 # v4
164164
with:
165165
name: updated-repo
166166
path: .

.github/workflows/winget.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,16 @@ on:
77
description: Version to release
88
required: true
99

10+
permissions:
11+
contents: read
12+
1013
jobs:
1114
publish:
1215
# Action can only be run on windows
1316
runs-on: windows-latest
1417
steps:
15-
- uses: vedantmgoyal2009/winget-releaser@v2
16-
# https://github.com/vedantmgoyal2009/winget-releaser
18+
- uses: vedantmgoyal9/winget-releaser@4ffc7888bffd451b357355dc214d43bb9f23917e # v2
19+
# https://github.com/vedantmgoyal9/winget-releaser
1720
with:
1821
identifier: ProjectJupyter.JupyterLab
1922
token: ${{ secrets.WINGET_TOKEN }}

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
MANIFEST
2+
CLAUDE.md
23
build
34
dist
45
lib

src/main/config/settings.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,10 +326,7 @@ export class WorkspaceSettings extends UserSettings {
326326
const exists = fs.existsSync(wsSettingsPath);
327327
if (Object.keys(wsSettings).length > 0 || exists) {
328328
if (!exists) {
329-
const dirPath = path.dirname(wsSettingsPath);
330-
if (!fs.existsSync(dirPath)) {
331-
fs.mkdirSync(dirPath, { recursive: true });
332-
}
329+
fs.mkdirSync(path.dirname(wsSettingsPath), { recursive: true });
333330
}
334331
fs.writeFileSync(wsSettingsPath, JSON.stringify(wsSettings, null, 2));
335332
}

0 commit comments

Comments
 (0)