-
Notifications
You must be signed in to change notification settings - Fork 12
619 lines (498 loc) · 22.3 KB
/
pmg-e2e.yml
File metadata and controls
619 lines (498 loc) · 22.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
name: PMG E2E Tests
on:
pull_request:
branches:
- main
paths-ignore:
- "**/*.md"
- "docs/**"
push:
branches:
- main
paths-ignore:
- "**/*.md"
- "docs/**"
workflow_dispatch:
# PRs share a concurrency group (cancel/serialize); Pushes use unique groups to avoid cancellation/queuing
concurrency:
group: ${{ github.workflow }}-${{ (github.event_name == 'pull_request' && github.ref) || github.run_id }}
cancel-in-progress: ${{ github.event_name == 'pull_request' }}
permissions:
contents: read
jobs:
e2e-test:
name: PMG E2E Tests - All Package Managers
runs-on: ${{ matrix.os }}
timeout-minutes: 20
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest]
defaults:
run:
shell: bash
steps:
- name: Checkout Source
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: go.mod
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 20
check-latest: true
- name: Setup PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
version: 10
- name: Setup Bun
uses: oven-sh/setup-bun@735343b667d3e6f658f44d0eca948eb6282f2b76 # v2
with:
bun-version: latest
- name: Setup Python
uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5
with:
python-version: "3.11"
- name: Setup uv
uses: astral-sh/setup-uv@caf0cab7a618c569241d31dcd442f54681755d39
- name: Install Poetry
uses: snok/install-poetry@76e04a911780d5b312d89783f7b1cd627778900a
- name: Build PMG
run: make
- name: Add pmg to PATH
run: echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
- name: Setup PMG
run: pmg setup install
- name: Test PMG - Config File is Created
run: |
test -f $HOME/.config/safedep/pmg/config.yml
- name: Test pmg.rc File is Created
run: |
test -f $HOME/.pmg.rc
- name: Test NPM - Single Package & Manifest
run: |
echo "Testing NPM single package installation..."
mkdir npm-test && cd npm-test
pmg --proxy-mode=false npm init -y
pmg --proxy-mode=false npm install express@5.2.1
pmg --proxy-mode=false npm install lodash@4.17.21
# Verification: npm added packages present and manifest updated
test -d node_modules/express
test -d node_modules/lodash
grep -q '"express"' package.json
grep -q '"lodash"' package.json
echo "Testing NPM manifest installation..."
rm -rf node_modules package-lock.json
pmg --proxy-mode=false npm install
# Verification: npm lockfile and installed modules exist after manifest install
test -f package-lock.json
test -d node_modules/express
test -d node_modules/lodash
cd .. && rm -rf npm-test
- name: Test NPM - Proxy Mode
run: |
echo "Testing NPM with proxy-based interception..."
mkdir npm-proxy-test && cd npm-proxy-test
pmg npm init -y
echo "Testing proxy mode single package installation..."
pmg npm install express@5.2.1
pmg npm install lodash@4.17.21
# Verification: packages installed via proxy mode
test -d node_modules/express
test -d node_modules/lodash
grep -q '"express"' package.json
grep -q '"lodash"' package.json
echo "Testing proxy mode manifest installation..."
rm -rf node_modules package-lock.json
pmg npm install
# Verification: manifest install via proxy mode works
test -f package-lock.json
test -d node_modules/express
test -d node_modules/lodash
echo "Testing proxy mode with scoped package..."
pmg npm install @types/node@18.0.0
# Verification: scoped package installed via proxy
test -d node_modules/@types
test -d node_modules/@types/node
grep -q '"@types/node"' package.json
echo "Testing proxy mode dry-run (should not create files)..."
rm -rf node_modules package-lock.json
pmg --dry-run npm install
# Verification: dry-run doesn't create files even in proxy mode
test ! -d node_modules
test ! -f package-lock.json
cd .. && rm -rf npm-proxy-test
- name: Test PyPI - Proxy Mode
run: |
echo "Testing PyPI package managers with proxy-based interception..."
mkdir pypi-proxy-test && cd pypi-proxy-test
echo "Setting up Python virtual environment for pip and pip3 tests..."
python -m venv venv && source venv/bin/activate
python --version
pip --version
echo "Testing pip single package installation via proxy mode..."
pmg pip install requests==2.32.4
pmg pip install numpy==2.3.5
# Verification: packages installed and importable
python -c "import requests, numpy; print('pip ok:', requests.__version__, numpy.__version__)"
echo "Testing pip manifest installation via proxy mode..."
pmg pip freeze > requirements.txt
pmg pip uninstall -y requests numpy
pmg pip install -r <(grep -v '^PMG:' requirements.txt)
python -c "import requests, numpy; print('pip manifest ok:', requests.__version__, numpy.__version__)"
deactivate
echo "Setting up Python virtual environment for pip3 tests..."
python -m venv venv3 && source venv3/bin/activate
python --version
pip3 --version
echo "Testing pip3 single package installation via proxy mode..."
pmg pip3 install requests==2.32.4
pmg pip3 install numpy==2.3.5
# Verification: packages installed and importable
python -c "import requests, numpy; print('pip3 ok:', requests.__version__, numpy.__version__)"
echo "Testing pip3 manifest installation via proxy mode..."
pmg pip3 freeze > requirements3.txt
pmg pip3 uninstall -y requests numpy
pmg pip3 install -r <(grep -v '^PMG:' requirements3.txt)
python -c "import requests, numpy; print('pip3 manifest ok:', requests.__version__, numpy.__version__)"
deactivate
echo "Testing uv add and uv pip install via proxy mode..."
mkdir uv-proxy && cd uv-proxy
pmg uv init --no-readme
pmg uv add requests==2.32.4
pmg uv add numpy==2.3.5
# Verification: pyproject.toml lists expected dependencies
test -f pyproject.toml
grep -q 'requests' pyproject.toml
grep -q 'numpy' pyproject.toml
echo "Sync environment and verify installations..."
pmg uv sync
pmg uv pip show requests >/dev/null
pmg uv pip show numpy >/dev/null
echo "Testing uv pip install from requirements via proxy mode..."
pmg uv pip freeze > requirements.txt
pmg uv pip install -r <(grep -v '^PMG:' requirements.txt)
pmg uv pip show requests >/dev/null
pmg uv pip show numpy >/dev/null
cd ..
cd .. && rm -rf pypi-proxy-test
- name: Test PNPM - Single Package & Manifest
run: |
echo "Testing PNPM single package installation..."
mkdir pnpm-test && cd pnpm-test
pmg --proxy-mode=false pnpm init
pmg --proxy-mode=false pnpm add express@5.2.1
pmg --proxy-mode=false pnpm add lodash@4.17.21
# Verification: pnpm packages installed and lockfile created
test -d node_modules/express
test -d node_modules/lodash
test -f pnpm-lock.yaml
echo "Testing PNPM manifest installation..."
rm -rf node_modules pnpm-lock.yaml
pmg --proxy-mode=false pnpm install
# Verification: pnpm lockfile and modules exist after manifest install
test -f pnpm-lock.yaml
test -d node_modules/express
test -d node_modules/lodash
cd .. && rm -rf pnpm-test
- name: Test Bun - Single Package & Manifest
run: |
echo "Testing Bun single package installation..."
mkdir bun-test && cd bun-test
pmg --proxy-mode=false bun init -y
pmg --proxy-mode=false bun add express@5.2.1
pmg --proxy-mode=false bun add lodash@4.17.21
# Verification: bun packages installed and lockfile created
test -d node_modules/express
test -d node_modules/lodash
test -f bun.lock
echo "Testing Bun manifest installation..."
rm -rf node_modules bun.lock
pmg --proxy-mode=false bun install
# Verification: bun lockfile and modules exist after manifest install
test -f bun.lock
test -d node_modules/express
test -d node_modules/lodash
cd .. && rm -rf bun-test
- name: Test Yarn - Single Package & Manifest
run: |
echo "Testing Yarn single package installation..."
export YARN_ENABLE_HARDENED_MODE=0
npm install -g yarn@1.22.22
yarn --version
mkdir yarn-test && cd yarn-test
pmg --proxy-mode=false yarn init -y
pmg --proxy-mode=false yarn add express@5.2.1
pmg --proxy-mode=false yarn add lodash@4.17.21
# Verification: yarn packages installed and lockfile created
test -d node_modules/express
test -d node_modules/lodash
test -f yarn.lock
echo "Testing Yarn manifest installation..."
rm -rf node_modules yarn.lock
pmg --proxy-mode=false yarn install
# Verification: yarn lockfile and modules exist after manifest install
test -f yarn.lock
test -d node_modules/express
test -d node_modules/lodash
cd .. && rm -rf yarn-test
- name: Test NPX - Package Execution
run: |
echo "Testing NPX package execution..."
mkdir npx-test && cd npx-test
echo "Testing npx with a simple package..."
pmg --proxy-mode=false npx cowsay@1.6.0 "Hello from pmg npx" | tee npx-output.txt
# Verification: cowsay output contains our message
grep -q "Hello from pmg npx" npx-output.txt
echo "Testing npx with --package flag..."
pmg --proxy-mode=false npx --package cowsay@1.6.0 -- cowsay "Hello with package flag" | tee npx-pkg-output.txt
# Verification: package flag execution produces expected output
grep -q "Hello with package flag" npx-pkg-output.txt
echo "Testing npx dry-run mode..."
pmg --proxy-mode=false --dry-run npx cowsay@1.6.0 "This should not execute" | tee npx-dry-output.txt
# Verification: dry-run should NOT produce cowsay ASCII art (cow face ^__^ should not appear)
! grep -q '\^__\^' npx-dry-output.txt
cd .. && rm -rf npx-test
- name: Test PNPX - Package Execution
run: |
echo "Testing PNPX package execution..."
mkdir pnpx-test && cd pnpx-test
echo "Testing pnpx with a simple package..."
pmg --proxy-mode=false pnpx cowsay@1.6.0 "Hello from pmg pnpx" | tee pnpx-output.txt
# Verification: cowsay output contains our message
grep -q "Hello from pmg pnpx" pnpx-output.txt
echo "Testing pnpx with --package flag..."
pmg --proxy-mode=false pnpx --package cowsay@1.6.0 -- cowsay "Hello with package flag" | tee pnpx-pkg-output.txt
# Verification: package flag execution produces expected output
grep -q "Hello with package flag" pnpx-pkg-output.txt
echo "Testing pnpx dry-run mode..."
pmg --proxy-mode=false --dry-run pnpx cowsay@1.6.0 "This should not execute" | tee pnpx-dry-output.txt
# Verification: dry-run should NOT produce cowsay ASCII art (cow face ^__^ should not appear)
! grep -q '\^__\^' pnpx-dry-output.txt
cd .. && rm -rf pnpx-test
- name: Test Pip - Single Package & Manifest
run: |
echo "Testing Pip single package installation..."
mkdir pip-test && cd pip-test
python -m venv venv && source venv/bin/activate
pmg --proxy-mode=false pip install requests==2.32.4
pmg --proxy-mode=false pip install numpy==2.3.5
pmg --proxy-mode=false pip freeze > requirements.txt
# Verification: requirements.txt contains expected packages
test -s requirements.txt
grep -E '^requests==' requirements.txt
grep -E '^numpy==' requirements.txt
echo "Testing Pip manifest installation..."
pmg --proxy-mode=false pip uninstall -y requests numpy
pmg --proxy-mode=false pip install -r requirements.txt
# Verification: imported packages are available in the environment
python -c "import requests, numpy; print(requests.__version__); print(numpy.__version__)"
deactivate
cd .. && rm -rf pip-test
- name: Test Pip3 - Single Package & Manifest
run: |
echo "Testing Pip3 single package installation..."
mkdir pip3-test && cd pip3-test
python -m venv venv && source venv/bin/activate
pmg --proxy-mode=false pip3 install requests==2.32.4
pmg --proxy-mode=false pip3 install numpy==2.3.5
pmg --proxy-mode=false pip3 freeze > requirements.txt
# Verification: requirements.txt contains expected packages
test -s requirements.txt
grep -E '^requests==' requirements.txt
grep -E '^numpy==' requirements.txt
echo "Testing Pip3 manifest installation..."
pmg --proxy-mode=false pip3 uninstall -y requests numpy
pmg --proxy-mode=false pip3 install -r requirements.txt
# Verification: imported packages are available in the environment
python -c "import requests, numpy; print(requests.__version__); print(numpy.__version__)"
deactivate
cd .. && rm -rf pip3-test
- name: Test UV - Single Package & Manifest
run: |
echo "Testing UV single package installation..."
mkdir uv-test && cd uv-test
pmg --proxy-mode=false uv init --no-readme
pmg --proxy-mode=false uv add requests==2.32.4
pmg --proxy-mode=false uv add numpy==2.3.5
# Verification: pyproject.toml lists expected dependencies
test -f pyproject.toml
grep -q 'requests' pyproject.toml
grep -q 'numpy' pyproject.toml
echo "Testing UV manifest installation..."
rm -rf .venv uv.lock
pmg --proxy-mode=false uv sync
# Verification: uv lockfile and virtualenv created; packages present
test -d .venv
test -f uv.lock
pmg --proxy-mode=false uv pip show requests >/dev/null
pmg --proxy-mode=false uv pip show numpy >/dev/null
echo "Testing UV pip commands..."
pmg --proxy-mode=false uv pip freeze > requirements.txt
pmg --proxy-mode=false uv pip install -r requirements.txt
pmg --proxy-mode=false uv pip sync requirements.txt
# Verification: uv pip can show installed packages after requirements sync
pmg --proxy-mode=false uv pip show requests >/dev/null
pmg --proxy-mode=false uv pip show numpy >/dev/null
cd .. && rm -rf uv-test
- name: Test Poetry - Single Package & Manifest
run: |
echo "Testing Poetry single package installation..."
mkdir poetry-test && cd poetry-test
pmg --proxy-mode=false poetry init --name poetry-test --no-interaction --quiet
pmg --proxy-mode=false poetry add requests==2.32.4
pmg --proxy-mode=false poetry add numpy==2.3.5
# Verification: pyproject.toml dependencies updated
test -f pyproject.toml
grep -q 'requests' pyproject.toml
grep -q 'numpy' pyproject.toml
echo "Testing Poetry manifest installation..."
rm -rf .venv poetry.lock
pmg --proxy-mode=false poetry install --no-root
cd .. && rm -rf poetry-test
- name: Test Malicious Package Detection
run: |
echo "Testing malicious package detection..."
mkdir malicious-test && cd malicious-test
pmg --proxy-mode=false npm init -y
! pmg --proxy-mode=false npm install nyc-config@10.0.0 || echo "Malicious package correctly blocked"
cd .. && rm -rf malicious-test
- name: Test safedep-test-pkg is Blocked using Proxy mode
run: |
echo "Testing that safedep-test-pkg is blocked..."
mkdir safedep-test-pkg-test && cd safedep-test-pkg-test
pmg npm init -y
# Attempt to install safedep-test-pkg - should fail
if pmg npm --no-cache --prefer-online i safedep-test-pkg@0.1.3; then
echo "ERROR: safedep-test-pkg was not blocked!"
exit 1
else
echo "SUCCESS: safedep-test-pkg correctly blocked"
fi
# Verify package is not installed locally
if [ -d "node_modules/safedep-test-pkg" ]; then
echo "ERROR: safedep-test-pkg found in node_modules!"
exit 1
else
echo "SUCCESS: safedep-test-pkg not present in node_modules"
fi
cd .. && rm -rf safedep-test-pkg-test
- name: Test PMG Modes
run: |
echo "Testing different PMG modes..."
mkdir pmg-modes-test && cd pmg-modes-test
pmg npm init -y
# Mode: --dry-run should not create node_modules or lockfiles
pmg --proxy-mode=false --dry-run npm install express
# Verification: no files created during dry-run
test ! -d node_modules
test ! -f package-lock.json
# Mode: --silent should install without noisy output
pmg --proxy-mode=false --silent npm install express
# Verification: package installed
test -d node_modules/express
# Clean and test --verbose installation
rm -rf node_modules package-lock.json
pmg --proxy-mode=false --verbose npm install express
# Verification: package installed
test -d node_modules/express
# Clean and test --debug with log output
rm -rf node_modules package-lock.json
pmg --proxy-mode=false --debug --log debug.json npm install express
# Verification: debug log written
test -f debug.json
# Mode: --paranoid may require cloud credentials; run non-blocking with dry-run
pmg --proxy-mode=false --paranoid --dry-run npm install express || true
cd .. && rm -rf pmg-modes-test
sandbox-e2e-macos:
name: Sandbox E2E - macOS
runs-on: macos-latest
timeout-minutes: 10
steps:
- name: Checkout Source
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: go.mod
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 20
check-latest: true
- name: Setup PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
version: 10
- name: Build PMG
run: make
- name: Add pmg to PATH
run: echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
- name: Setup PMG
run: pmg setup install
- name: Create Test Directories for Sandbox Permissions Tests
run: mkdir -p ~/.aws ~/.gcloud ~/.kube ~/.ssh
- name: Create Test Files for Sandbox Permissions Tests
run: |
touch ~/.aws/credentials
touch ~/.gcloud/credentials.json
touch ~/.kube/config
touch ~/.ssh/id_rsa
- name: Run Sandbox E2E Test
run: pmg --sandbox --sandbox-enforce npm exec -- node test/sandbox-e2e.js
- name: Run Package Manager E2E Test
run: pmg --sandbox --sandbox-enforce npm exec -- node test/pm-e2e.js
sandbox-e2e-linux:
name: Sandbox E2E - Linux (Bubblewrap)
runs-on: ubuntu-latest
timeout-minutes: 10
defaults:
run:
shell: bash
steps:
- name: Checkout Source
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4
- name: Setup Go
uses: actions/setup-go@0aaccfd150d50ccaeb58ebd88d36e91967a5f35b # v5
with:
go-version-file: go.mod
- name: Setup Node.js
uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
with:
node-version: 20
check-latest: true
- name: Setup PNPM
uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda # v4
with:
version: 10
- name: Install Bubblewrap
run: sudo apt-get update && sudo apt-get install -y bubblewrap
- name: Verify Bubblewrap Installation
run: bwrap --version
- name: Build PMG
run: make
- name: Add pmg to PATH
run: echo "$GITHUB_WORKSPACE/bin" >> $GITHUB_PATH
- name: Setup PMG
run: pmg setup install
- name: Create Test Directories for Sandbox Permissions Tests
run: mkdir -p ~/.aws ~/.gcloud ~/.kube ~/.ssh ~/.gnupg ~/.docker
- name: Create Test Files for Sandbox Permissions Tests
run: |
touch ~/.aws/credentials
touch ~/.gcloud/credentials.json
touch ~/.kube/config
touch ~/.ssh/id_rsa
touch ~/.gnupg/pubring.kbx
touch ~/.docker/config.json
- name: Disable AppArmor for Bubblewrap
run: |
sudo systemctl stop apparmor
sudo systemctl disable apparmor
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
- name: Run Sandbox E2E Test
run: pmg --sandbox --sandbox-enforce --sandbox-profile npm-restrictive npm exec -- node test/sandbox-e2e.js
- name: Run Package Manager E2E Test
run: pmg --sandbox --sandbox-enforce --sandbox-profile npm-restrictive npm exec -- node test/pm-e2e.js