windows-development-sandbox 1.5.0 → 1.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -0
- package/config.example.json +27 -1
- package/dist/app/context.d.ts +8 -0
- package/dist/app/context.js +12 -0
- package/dist/app/features/defs.d.ts +322 -0
- package/dist/app/features/defs.js +28 -0
- package/dist/app/features/sandbox/index.d.ts +2 -0
- package/dist/app/features/sandbox/index.js +3 -0
- package/dist/app/features/sandbox/sandbox.def.d.ts +193 -0
- package/dist/app/features/sandbox/sandbox.def.js +245 -0
- package/dist/app/features/sandbox/sandbox.run.d.ts +72 -0
- package/dist/app/features/sandbox/sandbox.run.js +98 -0
- package/dist/app/features/sessions/index.d.ts +2 -0
- package/dist/app/features/sessions/index.js +3 -0
- package/dist/app/features/sessions/sessions.def.d.ts +141 -0
- package/dist/app/features/sessions/sessions.def.js +176 -0
- package/dist/app/features/sessions/sessions.run.d.ts +39 -0
- package/dist/app/features/sessions/sessions.run.js +58 -0
- package/dist/{cli/menu/settings/categories.d.ts → app/features/settings/categories.def.d.ts} +4 -0
- package/dist/{cli/menu/settings/categories.js → app/features/settings/categories.def.js} +40 -46
- package/dist/app/features/settings/index.d.ts +5 -0
- package/dist/app/features/settings/index.js +6 -0
- package/dist/{cli/menu/settings/config-file.d.ts → app/features/settings/settings-file.d.ts} +1 -1
- package/dist/{cli/menu/settings/config-file.js → app/features/settings/settings-file.js} +1 -1
- package/dist/app/features/settings/settings-rows.d.ts +35 -0
- package/dist/app/features/settings/settings-rows.js +94 -0
- package/dist/app/features/settings/settings.def.d.ts +157 -0
- package/dist/app/features/settings/settings.def.js +179 -0
- package/dist/app/features/settings/settings.run.d.ts +67 -0
- package/dist/app/features/settings/settings.run.js +84 -0
- package/dist/app/kernel/define.d.ts +143 -0
- package/dist/app/kernel/define.js +42 -0
- package/dist/app/kernel/errors.d.ts +34 -0
- package/dist/app/kernel/errors.js +45 -0
- package/dist/app/kernel/fields.d.ts +70 -0
- package/dist/app/kernel/fields.js +243 -0
- package/dist/app/kernel/index.d.ts +8 -0
- package/dist/app/kernel/index.js +10 -0
- package/dist/app/kernel/io.d.ts +193 -0
- package/dist/app/kernel/io.js +126 -0
- package/dist/app/kernel/rpc.d.ts +156 -0
- package/dist/app/kernel/rpc.js +47 -0
- package/dist/{cli/menu/settings → app/kernel}/schema-node.d.ts +9 -0
- package/dist/{cli/menu/settings → app/kernel}/schema-node.js +26 -0
- package/dist/app/kernel/text.d.ts +6 -0
- package/dist/app/kernel/text.js +57 -0
- package/dist/app/kernel/view.d.ts +146 -0
- package/dist/app/kernel/view.js +28 -0
- package/dist/app/registry.d.ts +10 -0
- package/dist/app/registry.js +50 -0
- package/dist/cli/args.d.ts +18 -2
- package/dist/cli/args.js +101 -24
- package/dist/cli/commands/accounts.js +45 -17
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.js +9 -2
- package/dist/cli/commands/data/clean.js +32 -9
- package/dist/cli/commands/engine.d.ts +2 -0
- package/dist/cli/commands/engine.js +60 -0
- package/dist/cli/commands/index.d.ts +2 -1
- package/dist/cli/commands/index.js +2 -1
- package/dist/cli/commands/launch/add-root.d.ts +3 -2
- package/dist/cli/commands/launch/add-root.js +11 -10
- package/dist/cli/commands/launch/launch.js +102 -9
- package/dist/cli/commands/launch/prepare.js +6 -4
- package/dist/cli/commands/launch/running.js +2 -1
- package/dist/cli/commands/launch/summary.d.ts +2 -0
- package/dist/cli/commands/maintenance/audit.js +1 -1
- package/dist/cli/commands/maintenance/clean.d.ts +1 -1
- package/dist/cli/commands/maintenance/clean.js +17 -3
- package/dist/cli/commands/maintenance/config-share.d.ts +12 -0
- package/dist/cli/commands/maintenance/config-share.js +80 -0
- package/dist/cli/commands/maintenance/config.d.ts +1 -1
- package/dist/cli/commands/maintenance/config.js +38 -10
- package/dist/cli/commands/maintenance/doctor.d.ts +1 -1
- package/dist/cli/commands/maintenance/doctor.js +2 -4
- package/dist/cli/commands/maintenance/logs.js +14 -0
- package/dist/cli/commands/maintenance/migrate.d.ts +2 -1
- package/dist/cli/commands/maintenance/migrate.js +19 -4
- package/dist/cli/commands/maintenance/sync.js +2 -0
- package/dist/cli/commands/maintenance/update.d.ts +2 -0
- package/dist/cli/commands/maintenance/update.js +27 -4
- package/dist/cli/commands/projects/here.js +12 -7
- package/dist/cli/commands/projects/projects.js +26 -17
- package/dist/cli/commands/registry.js +10 -7
- package/dist/cli/commands/repair/checks/agents.d.ts +2 -0
- package/dist/cli/commands/repair/checks/agents.js +70 -0
- package/dist/cli/commands/repair/checks/common.d.ts +8 -0
- package/dist/cli/commands/repair/checks/common.js +22 -0
- package/dist/cli/commands/repair/checks/contained.d.ts +2 -0
- package/dist/cli/commands/repair/checks/contained.js +139 -0
- package/dist/cli/commands/repair/checks/data.d.ts +2 -0
- package/dist/cli/commands/repair/checks/data.js +241 -0
- package/dist/cli/commands/repair/checks/hcs.d.ts +7 -0
- package/dist/cli/commands/repair/checks/hcs.js +28 -0
- package/dist/cli/commands/repair/checks/index.d.ts +2 -0
- package/dist/cli/commands/repair/checks/index.js +24 -0
- package/dist/cli/commands/repair/checks/install.d.ts +5 -0
- package/dist/cli/commands/repair/checks/install.js +318 -0
- package/dist/cli/commands/repair/checks/machine.d.ts +2 -0
- package/dist/cli/commands/repair/checks/machine.js +232 -0
- package/dist/cli/commands/repair/checks/network.d.ts +6 -0
- package/dist/cli/commands/repair/checks/network.js +60 -0
- package/dist/cli/commands/repair/checks/pc.d.ts +4 -0
- package/dist/cli/commands/repair/checks/pc.js +86 -0
- package/dist/cli/commands/repair/checks/sandbox.d.ts +2 -0
- package/dist/cli/commands/repair/checks/sandbox.js +282 -0
- package/dist/cli/commands/repair/checks/settings.d.ts +2 -0
- package/dist/cli/commands/repair/checks/settings.js +169 -0
- package/dist/cli/commands/repair/checks/vpn.d.ts +2 -0
- package/dist/cli/commands/repair/checks/vpn.js +78 -0
- package/dist/cli/commands/repair/engine.d.ts +32 -0
- package/dist/cli/commands/repair/engine.js +127 -0
- package/dist/cli/commands/repair/env.d.ts +7 -0
- package/dist/cli/commands/repair/env.js +50 -0
- package/dist/cli/commands/repair/index.d.ts +1 -9
- package/dist/cli/commands/repair/index.js +2 -54
- package/dist/cli/commands/repair/log.d.ts +17 -0
- package/dist/cli/commands/repair/log.js +82 -0
- package/dist/cli/commands/repair/printer.d.ts +32 -0
- package/dist/cli/commands/repair/printer.js +132 -0
- package/dist/cli/commands/repair/run.d.ts +33 -0
- package/dist/cli/commands/repair/run.js +133 -0
- package/dist/cli/commands/repair/types.d.ts +97 -9
- package/dist/cli/commands/repair/types.js +11 -7
- package/dist/cli/commands/resume.js +2 -2
- package/dist/cli/commands/sessions/index.d.ts +0 -4
- package/dist/cli/commands/sessions/index.js +3 -7
- package/dist/cli/commands/setup/index.d.ts +5 -0
- package/dist/cli/commands/setup/index.js +25 -1
- package/dist/cli/commands/shared-use.d.ts +5 -2
- package/dist/cli/commands/shared-use.js +11 -8
- package/dist/cli/commands/storage/contained.d.ts +3 -0
- package/dist/cli/commands/storage/contained.js +179 -0
- package/dist/cli/commands/storage/index.d.ts +2 -0
- package/dist/cli/commands/storage/index.js +2 -0
- package/dist/cli/commands/storage/offer.d.ts +3 -0
- package/dist/cli/commands/storage/offer.js +91 -0
- package/dist/cli/commands/storage/storage.d.ts +8 -0
- package/dist/cli/commands/storage/storage.js +179 -0
- package/dist/cli/commands/user-config.js +2 -2
- package/dist/cli/commands/vpn.d.ts +4 -0
- package/dist/cli/commands/vpn.js +91 -0
- package/dist/cli/commands/web.d.ts +4 -0
- package/dist/cli/commands/web.js +97 -0
- package/dist/cli/history.js +1 -1
- package/dist/cli/index.js +48 -4
- package/dist/cli/manifest.d.ts +339 -97
- package/dist/cli/manifest.js +222 -67
- package/dist/cli/menu/add-agent.d.ts +47 -0
- package/dist/cli/menu/add-agent.js +168 -0
- package/dist/cli/menu/apps.d.ts +38 -3
- package/dist/cli/menu/apps.js +80 -5
- package/dist/cli/menu/command-fields.d.ts +18 -0
- package/dist/cli/menu/command-fields.js +61 -0
- package/dist/cli/menu/command-form.d.ts +22 -0
- package/dist/cli/menu/command-form.js +169 -46
- package/dist/cli/menu/data-folder.d.ts +18 -0
- package/dist/cli/menu/data-folder.js +99 -0
- package/dist/cli/menu/io-menu.d.ts +29 -0
- package/dist/cli/menu/io-menu.js +126 -0
- package/dist/cli/menu/live.d.ts +27 -0
- package/dist/cli/menu/live.js +69 -0
- package/dist/cli/menu/memory.d.ts +19 -0
- package/dist/cli/menu/memory.js +53 -0
- package/dist/cli/menu/menu.d.ts +11 -2
- package/dist/cli/menu/menu.js +36 -15
- package/dist/cli/menu/pages/accounts-page.js +55 -24
- package/dist/cli/menu/pages/agents-page.d.ts +68 -0
- package/dist/cli/menu/pages/agents-page.js +345 -0
- package/dist/cli/menu/pages/apps-page.d.ts +3 -1
- package/dist/cli/menu/pages/apps-page.js +20 -4
- package/dist/cli/menu/pages/list-page.d.ts +43 -3
- package/dist/cli/menu/pages/list-page.js +146 -12
- package/dist/cli/menu/pages/maintenance-page.d.ts +9 -5
- package/dist/cli/menu/pages/maintenance-page.js +172 -85
- package/dist/cli/menu/pages/sandbox-page.d.ts +7 -6
- package/dist/cli/menu/pages/sandbox-page.js +117 -120
- package/dist/cli/menu/pages/scopes.d.ts +1 -1
- package/dist/cli/menu/pages/sessions-page.d.ts +6 -8
- package/dist/cli/menu/pages/sessions-page.js +22 -75
- package/dist/cli/menu/pages/settings-page.d.ts +10 -14
- package/dist/cli/menu/pages/settings-page.js +95 -102
- package/dist/cli/menu/render-view.d.ts +28 -0
- package/dist/cli/menu/render-view.js +112 -0
- package/dist/cli/menu/settings/ask-path.d.ts +14 -0
- package/dist/cli/menu/settings/ask-path.js +14 -0
- package/dist/cli/menu/settings/collections/collection-editor.d.ts +8 -2
- package/dist/cli/menu/settings/collections/collection-editor.js +12 -8
- package/dist/cli/menu/settings/collections/map-editor.js +5 -1
- package/dist/cli/menu/settings/collections/object-list-editor.js +2 -2
- package/dist/cli/menu/settings/collections/object-map-editor.js +2 -2
- package/dist/cli/menu/settings/collections/string-list-editor.d.ts +10 -1
- package/dist/cli/menu/settings/collections/string-list-editor.js +23 -0
- package/dist/cli/menu/settings/draft.d.ts +1 -1
- package/dist/cli/menu/settings/format.d.ts +1 -3
- package/dist/cli/menu/settings/format.js +6 -36
- package/dist/cli/menu/settings/index.d.ts +1 -3
- package/dist/cli/menu/settings/index.js +3 -3
- package/dist/cli/menu/settings/object-editor.d.ts +6 -2
- package/dist/cli/menu/settings/object-editor.js +15 -4
- package/dist/cli/menu/settings/share.d.ts +36 -0
- package/dist/cli/menu/settings/share.js +131 -0
- package/dist/cli/menu/settings/value-editor.d.ts +10 -1
- package/dist/cli/menu/settings/value-editor.js +99 -63
- package/dist/cli/menu/several.js +7 -5
- package/dist/cli/menu/share-settings.d.ts +21 -0
- package/dist/cli/menu/share-settings.js +112 -0
- package/dist/cli/menu/shell.d.ts +53 -10
- package/dist/cli/menu/shell.js +115 -10
- package/dist/cli/menu/views.d.ts +7 -0
- package/dist/cli/menu/views.js +11 -0
- package/dist/cli/menu/vpn-login.d.ts +16 -0
- package/dist/cli/menu/vpn-login.js +74 -0
- package/dist/cli/operations/handler.d.ts +6 -0
- package/dist/cli/operations/handler.js +61 -0
- package/dist/cli/operations/index.d.ts +4 -0
- package/dist/cli/operations/index.js +5 -0
- package/dist/cli/operations/input.d.ts +6 -0
- package/dist/cli/operations/input.js +37 -0
- package/dist/cli/operations/io-cli.d.ts +7 -0
- package/dist/cli/operations/io-cli.js +62 -0
- package/dist/cli/operations/spec.d.ts +18 -0
- package/dist/cli/operations/spec.js +108 -0
- package/dist/cli/output/colors.d.ts +2 -2
- package/dist/cli/output/colors.js +2 -11
- package/dist/cli/output/index.d.ts +1 -0
- package/dist/cli/output/index.js +1 -0
- package/dist/cli/output/print.d.ts +5 -1
- package/dist/cli/output/print.js +15 -4
- package/dist/cli/output/progress.d.ts +15 -0
- package/dist/cli/output/progress.js +44 -0
- package/dist/cli/output/render-view.d.ts +4 -0
- package/dist/cli/output/render-view.js +63 -0
- package/dist/cli/services/accounts-service.d.ts +2 -0
- package/dist/cli/services/accounts-service.js +2 -2
- package/dist/cli/services/agent-commands-service.d.ts +2 -0
- package/dist/cli/services/agent-commands-service.js +11 -2
- package/dist/cli/services/health-service.d.ts +0 -6
- package/dist/cli/services/health-service.js +5 -42
- package/dist/cli/services/index.d.ts +3 -1
- package/dist/cli/services/index.js +3 -1
- package/dist/cli/services/logs-service.js +4 -3
- package/dist/cli/services/migrate-service.js +1 -1
- package/dist/cli/services/update-service.d.ts +2 -0
- package/dist/cli/services/update-service.js +13 -6
- package/dist/cli/services/vpn-service.d.ts +28 -0
- package/dist/cli/services/vpn-service.js +46 -0
- package/dist/cli/services/web-service.d.ts +22 -0
- package/dist/cli/services/web-service.js +111 -0
- package/dist/cli/tui/app.d.ts +12 -4
- package/dist/cli/tui/app.js +38 -9
- package/dist/cli/tui/dialogs/path-listing.d.ts +43 -0
- package/dist/cli/tui/dialogs/path-listing.js +127 -0
- package/dist/cli/tui/dialogs/path-picker.d.ts +67 -0
- package/dist/cli/tui/dialogs/path-picker.js +423 -0
- package/dist/cli/tui/dialogs/text-screen.d.ts +6 -0
- package/dist/cli/tui/dialogs/text-screen.js +10 -3
- package/dist/cli/tui/frame.d.ts +7 -10
- package/dist/cli/tui/frame.js +19 -10
- package/dist/cli/tui/index.d.ts +4 -3
- package/dist/cli/tui/index.js +2 -1
- package/dist/cli/tui/list/list-screen.d.ts +28 -2
- package/dist/cli/tui/list/list-screen.js +130 -66
- package/dist/cli/tui/list/list-types.d.ts +10 -4
- package/dist/cli/tui/nav.d.ts +29 -0
- package/dist/cli/tui/nav.js +67 -0
- package/dist/cli/tui/terminal.d.ts +7 -0
- package/dist/cli/tui/terminal.js +30 -10
- package/dist/cli/validate.d.ts +1 -1
- package/dist/cli/validate.js +3 -3
- package/dist/cli/version.d.ts +2 -0
- package/dist/cli/version.js +11 -0
- package/dist/core/config/defaults.js +13 -1
- package/dist/core/config/loader.js +12 -2
- package/dist/core/local-config/overrides.js +1 -0
- package/dist/core/prompt.d.ts +19 -0
- package/dist/core/prompt.js +43 -3
- package/dist/core/schema/common.d.ts +6 -0
- package/dist/core/schema/common.js +8 -0
- package/dist/core/schema/config.d.ts +36 -0
- package/dist/core/schema/config.js +26 -2
- package/dist/core/schema/harness.d.ts +2 -0
- package/dist/core/schema/harness.js +13 -2
- package/dist/core/schema/index.d.ts +3 -1
- package/dist/core/schema/index.js +3 -1
- package/dist/core/schema/profile.d.ts +1 -0
- package/dist/core/schema/profile.js +3 -0
- package/dist/core/schema/redact.d.ts +13 -0
- package/dist/core/schema/redact.js +75 -0
- package/dist/core/schema/sandbox.d.ts +6 -0
- package/dist/core/schema/sandbox.js +21 -3
- package/dist/core/schema/vpn.d.ts +18 -0
- package/dist/core/schema/vpn.js +22 -0
- package/dist/core/schema/web.d.ts +6 -0
- package/dist/core/schema/web.js +14 -0
- package/dist/core/types.d.ts +44 -0
- package/dist/core/util/fs.d.ts +2 -0
- package/dist/core/util/fs.js +9 -0
- package/dist/core/util/index.d.ts +1 -1
- package/dist/core/util/index.js +1 -1
- package/dist/guest/agents/agent-files.d.ts +54 -0
- package/dist/guest/agents/agent-files.js +67 -0
- package/dist/guest/agents/agent-installer.js +2 -9
- package/dist/guest/agents/local-state.d.ts +14 -0
- package/dist/guest/agents/local-state.js +218 -0
- package/dist/guest/agents/sbx-agent.d.ts +2 -0
- package/dist/guest/agents/sbx-agent.js +35 -0
- package/dist/guest/boot/boot.d.ts +4 -0
- package/dist/guest/boot/boot.js +51 -11
- package/dist/guest/daemon/daemon.js +8 -1
- package/dist/guest/daemon/exec.js +2 -1
- package/dist/guest/daemon/idle-shutdown.js +2 -0
- package/dist/guest/daemon/sessions.d.ts +5 -0
- package/dist/guest/daemon/sessions.js +20 -3
- package/dist/guest/entries/agent.d.ts +1 -0
- package/dist/guest/entries/agent.js +10 -0
- package/dist/guest/entries/daemon.js +5 -0
- package/dist/guest/governor/decide.d.ts +61 -0
- package/dist/guest/governor/decide.js +182 -0
- package/dist/guest/governor/governor.d.ts +42 -0
- package/dist/guest/governor/governor.js +214 -0
- package/dist/guest/governor/index.d.ts +2 -0
- package/dist/guest/governor/index.js +2 -0
- package/dist/guest/runtime/csc.d.ts +2 -0
- package/dist/guest/runtime/csc.js +2 -0
- package/dist/guest/runtime/secrets.d.ts +12 -0
- package/dist/guest/runtime/secrets.js +63 -0
- package/dist/guest/sessions/viewer.js +3 -1
- package/dist/guest/setup/claude-profile.d.ts +2 -1
- package/dist/guest/setup/claude-profile.js +12 -1
- package/dist/guest/setup/environment.d.ts +6 -0
- package/dist/guest/setup/environment.js +56 -6
- package/dist/guest/setup/path-plan.d.ts +32 -0
- package/dist/guest/setup/path-plan.js +67 -0
- package/dist/guest/setup/shell-path.d.ts +1 -0
- package/dist/guest/setup/shell-path.js +22 -0
- package/dist/guest/toolchains/languages/python.js +1 -1
- package/dist/guest/toolchains/native/rust-extras.js +4 -2
- package/dist/guest/toolchains/runtimes.js +2 -2
- package/dist/guest/vpn/index.d.ts +1 -0
- package/dist/guest/vpn/index.js +1 -0
- package/dist/guest/vpn/openvpn.d.ts +9 -0
- package/dist/guest/vpn/openvpn.js +47 -0
- package/dist/guest/vpn/tunnel.d.ts +17 -0
- package/dist/guest/vpn/tunnel.js +78 -0
- package/dist/guest/vpn/vpn.d.ts +6 -0
- package/dist/guest/vpn/vpn.js +174 -0
- package/dist/guest/vpn/wireguard.d.ts +32 -0
- package/dist/guest/vpn/wireguard.js +132 -0
- package/dist/host/agent-commands/commands.d.ts +4 -0
- package/dist/host/agent-commands/commands.js +31 -7
- package/dist/host/audit/log.d.ts +1 -1
- package/dist/host/channel/attach.d.ts +6 -2
- package/dist/host/channel/attach.js +6 -3
- package/dist/host/channel/channel.d.ts +9 -0
- package/dist/host/channel/channel.js +30 -2
- package/dist/host/engines/engine.d.ts +12 -0
- package/dist/host/engines/engine.js +1 -0
- package/dist/host/engines/hcs/check.d.ts +25 -0
- package/dist/host/engines/hcs/check.js +95 -0
- package/dist/host/engines/hcs/documents.d.ts +44 -0
- package/dist/host/engines/hcs/documents.js +155 -0
- package/dist/host/engines/hcs/engine.d.ts +39 -0
- package/dist/host/engines/hcs/engine.js +171 -0
- package/dist/host/engines/hcs/helper.d.ts +43 -0
- package/dist/host/engines/hcs/helper.js +173 -0
- package/dist/host/engines/hcs/images.d.ts +37 -0
- package/dist/host/engines/hcs/images.js +152 -0
- package/dist/host/engines/index.d.ts +7 -0
- package/dist/host/engines/index.js +5 -0
- package/dist/host/engines/registry.d.ts +16 -0
- package/dist/host/engines/registry.js +30 -0
- package/dist/host/engines/types.d.ts +58 -0
- package/dist/host/engines/types.js +1 -0
- package/dist/host/engines/windows-sandbox/engine.d.ts +16 -0
- package/dist/host/engines/windows-sandbox/engine.js +63 -0
- package/dist/host/engines/windows-sandbox/wsb-text.d.ts +2 -0
- package/dist/host/engines/windows-sandbox/wsb-text.js +29 -0
- package/dist/host/health/acl-read.d.ts +17 -0
- package/dist/host/health/acl-read.js +45 -0
- package/dist/host/health/config-backup.d.ts +11 -0
- package/dist/host/health/config-backup.js +73 -0
- package/dist/host/health/index.d.ts +6 -0
- package/dist/host/health/index.js +7 -0
- package/dist/host/health/install-state.d.ts +33 -0
- package/dist/host/health/install-state.js +110 -0
- package/dist/host/health/path-copies.d.ts +32 -0
- package/dist/host/health/path-copies.js +82 -0
- package/dist/host/health/stale.d.ts +45 -0
- package/dist/host/health/stale.js +120 -0
- package/dist/host/health/system.d.ts +37 -0
- package/dist/host/health/system.js +87 -0
- package/dist/host/install/copies.d.ts +13 -0
- package/dist/host/install/copies.js +63 -0
- package/dist/host/install/index.d.ts +1 -0
- package/dist/host/install/index.js +1 -0
- package/dist/host/launch/generate.d.ts +5 -1
- package/dist/host/launch/generate.js +73 -7
- package/dist/host/launch/index.d.ts +3 -1
- package/dist/host/launch/index.js +3 -1
- package/dist/host/launch/launch-plan.d.ts +13 -0
- package/dist/host/launch/launch-plan.js +26 -0
- package/dist/host/launch/mappings.js +2 -1
- package/dist/host/launch/risk-notes.d.ts +10 -0
- package/dist/host/launch/risk-notes.js +18 -0
- package/dist/host/launch/session-file.d.ts +2 -0
- package/dist/host/launch/session-file.js +11 -2
- package/dist/host/launch/stage.js +1 -1
- package/dist/host/launch/wsb-file.d.ts +28 -4
- package/dist/host/launch/wsb-file.js +61 -42
- package/dist/host/life/crash-report.d.ts +27 -1
- package/dist/host/life/crash-report.js +173 -7
- package/dist/host/life/host-memory.d.ts +40 -0
- package/dist/host/life/host-memory.js +137 -0
- package/dist/host/life/index.d.ts +2 -0
- package/dist/host/life/index.js +2 -0
- package/dist/host/life/stop-events.d.ts +2 -0
- package/dist/host/life/stop-events.js +20 -3
- package/dist/host/life/stop-warning.js +1 -1
- package/dist/host/life/watchdog.d.ts +54 -0
- package/dist/host/life/watchdog.js +108 -0
- package/dist/host/migrate/backup.js +3 -0
- package/dist/host/migrate/migrations/config-file.d.ts +2 -0
- package/dist/host/migrate/migrations/config-file.js +7 -0
- package/dist/host/migrate/migrations/follow-machine-storage.js +9 -1
- package/dist/host/migrate/migrations/pin-storage-root.d.ts +4 -0
- package/dist/host/migrate/migrations/pin-storage-root.js +46 -0
- package/dist/host/migrate/migrations/unpin-config-defaults.js +4 -1
- package/dist/host/migrate/registry.js +2 -1
- package/dist/host/native.d.ts +3 -2
- package/dist/host/native.js +22 -3
- package/dist/host/profile/accounts.d.ts +25 -1
- package/dist/host/profile/accounts.js +96 -13
- package/dist/host/profile/agent-accounts.d.ts +5 -1
- package/dist/host/profile/agent-accounts.js +35 -5
- package/dist/host/profile/claude-login.js +3 -2
- package/dist/host/profile/index.d.ts +2 -1
- package/dist/host/profile/index.js +1 -0
- package/dist/host/profile/plugin-share.d.ts +26 -0
- package/dist/host/profile/plugin-share.js +146 -0
- package/dist/host/projects/join.d.ts +7 -1
- package/dist/host/projects/join.js +21 -4
- package/dist/host/projects/registry.d.ts +16 -10
- package/dist/host/projects/registry.js +74 -6
- package/dist/host/sandbox/contained-deps.d.ts +2 -0
- package/dist/host/sandbox/contained-deps.js +17 -0
- package/dist/host/sandbox/index.d.ts +2 -0
- package/dist/host/sandbox/index.js +2 -0
- package/dist/host/sandbox/platform.d.ts +4 -0
- package/dist/host/sandbox/platform.js +23 -4
- package/dist/host/sandbox/tasklist.d.ts +13 -0
- package/dist/host/sandbox/tasklist.js +47 -0
- package/dist/host/secrets/index.d.ts +2 -0
- package/dist/host/secrets/index.js +2 -0
- package/dist/host/secrets/launch-secrets.d.ts +17 -0
- package/dist/host/secrets/launch-secrets.js +94 -0
- package/dist/host/secrets/secret-store.d.ts +25 -0
- package/dist/host/secrets/secret-store.js +89 -0
- package/dist/host/sharing/acl.d.ts +16 -2
- package/dist/host/sharing/acl.js +35 -10
- package/dist/host/sharing/current.js +8 -3
- package/dist/host/sharing/doctor.d.ts +2 -0
- package/dist/host/sharing/doctor.js +44 -0
- package/dist/host/sharing/group-access.d.ts +6 -0
- package/dist/host/sharing/group-access.js +24 -0
- package/dist/host/sharing/index.d.ts +2 -1
- package/dist/host/sharing/index.js +2 -1
- package/dist/host/sharing/lifecycle.d.ts +8 -2
- package/dist/host/sharing/lifecycle.js +16 -7
- package/dist/host/storage/cleanup.d.ts +2 -0
- package/dist/host/storage/cleanup.js +2 -1
- package/dist/host/storage/contained/check.d.ts +9 -0
- package/dist/host/storage/contained/check.js +37 -0
- package/dist/host/storage/contained/contained-storage.d.ts +66 -0
- package/dist/host/storage/contained/contained-storage.js +168 -0
- package/dist/host/storage/contained/disk-port.d.ts +43 -0
- package/dist/host/storage/contained/disk-port.js +122 -0
- package/dist/host/storage/contained/index.d.ts +9 -0
- package/dist/host/storage/contained/index.js +8 -0
- package/dist/host/storage/contained/layout.d.ts +28 -0
- package/dist/host/storage/contained/layout.js +45 -0
- package/dist/host/storage/contained/resolve.d.ts +4 -0
- package/dist/host/storage/contained/resolve.js +30 -0
- package/dist/host/storage/contained/setting.d.ts +1 -0
- package/dist/host/storage/contained/setting.js +5 -0
- package/dist/host/storage/contained/state.d.ts +89 -0
- package/dist/host/storage/contained/state.js +166 -0
- package/dist/host/storage/contained/transfer.d.ts +24 -0
- package/dist/host/storage/contained/transfer.js +121 -0
- package/dist/host/storage/history.d.ts +21 -0
- package/dist/host/storage/history.js +49 -0
- package/dist/host/storage/index.d.ts +6 -0
- package/dist/host/storage/index.js +6 -0
- package/dist/host/storage/move.d.ts +95 -0
- package/dist/host/storage/move.js +384 -0
- package/dist/host/storage/offer.d.ts +11 -0
- package/dist/host/storage/offer.js +36 -0
- package/dist/host/storage/providers/contained.d.ts +15 -0
- package/dist/host/storage/providers/contained.js +39 -0
- package/dist/host/storage/providers/folder.d.ts +12 -0
- package/dist/host/storage/providers/folder.js +20 -0
- package/dist/host/storage/providers/index.d.ts +4 -0
- package/dist/host/storage/providers/index.js +3 -0
- package/dist/host/storage/providers/registry.d.ts +9 -0
- package/dist/host/storage/providers/registry.js +14 -0
- package/dist/host/storage/providers/types.d.ts +33 -0
- package/dist/host/storage/providers/types.js +1 -0
- package/dist/host/storage/root.d.ts +18 -0
- package/dist/host/storage/root.js +77 -0
- package/dist/host/tools/conpty.js +3 -2
- package/dist/host/tools/windows-terminal.d.ts +2 -0
- package/dist/host/tools/windows-terminal.js +31 -12
- package/dist/host/update/index.d.ts +1 -1
- package/dist/host/update/index.js +1 -1
- package/dist/host/update/notice.d.ts +2 -0
- package/dist/host/update/notice.js +13 -1
- package/dist/host/update/update-state.d.ts +6 -0
- package/dist/host/update/update-state.js +2 -0
- package/dist/host/update/updater.d.ts +19 -0
- package/dist/host/update/updater.js +88 -12
- package/dist/host/vpn/index.d.ts +4 -0
- package/dist/host/vpn/index.js +4 -0
- package/dist/host/vpn/login.d.ts +24 -0
- package/dist/host/vpn/login.js +79 -0
- package/dist/host/vpn/nordvpn.d.ts +21 -0
- package/dist/host/vpn/nordvpn.js +77 -0
- package/dist/host/vpn/prepare.d.ts +19 -0
- package/dist/host/vpn/prepare.js +138 -0
- package/dist/host/vpn/status.d.ts +12 -0
- package/dist/host/vpn/status.js +53 -0
- package/dist/host/web/auth.d.ts +38 -0
- package/dist/host/web/auth.js +96 -0
- package/dist/host/web/backend.d.ts +14 -0
- package/dist/host/web/backend.js +1 -0
- package/dist/host/web/bridge.d.ts +27 -0
- package/dist/host/web/bridge.js +144 -0
- package/dist/host/web/browser.d.ts +3 -0
- package/dist/host/web/browser.js +23 -0
- package/dist/host/web/control.d.ts +17 -0
- package/dist/host/web/control.js +67 -0
- package/dist/host/web/index.d.ts +10 -0
- package/dist/host/web/index.js +9 -0
- package/dist/host/web/rpc.d.ts +24 -0
- package/dist/host/web/rpc.js +149 -0
- package/dist/host/web/runner.d.ts +16 -0
- package/dist/host/web/runner.js +44 -0
- package/dist/host/web/server.d.ts +47 -0
- package/dist/host/web/server.js +238 -0
- package/dist/host/web/state.d.ts +20 -0
- package/dist/host/web/state.js +41 -0
- package/dist/host/web/static-files.d.ts +13 -0
- package/dist/host/web/static-files.js +57 -0
- package/dist/runtime/agent.js +27675 -0
- package/dist/runtime/daemon.js +1950 -1122
- package/dist/runtime/db.js +302 -111
- package/dist/runtime/main.js +1560 -275
- package/dist/runtime/netproxy.js +168 -8
- package/dist/runtime/view.js +186 -13
- package/dist/selftest/accounts.test.js +40 -0
- package/dist/selftest/agent-paths.test.d.ts +2 -0
- package/dist/selftest/agent-paths.test.js +125 -0
- package/dist/selftest/app.test.d.ts +2 -0
- package/dist/selftest/app.test.js +324 -0
- package/dist/selftest/channel.test.js +18 -0
- package/dist/selftest/cli.test.js +35 -4
- package/dist/selftest/config.test.js +59 -0
- package/dist/selftest/contained.test.d.ts +2 -0
- package/dist/selftest/contained.test.js +544 -0
- package/dist/selftest/credentials.test.d.ts +2 -0
- package/dist/selftest/credentials.test.js +198 -0
- package/dist/selftest/engine.test.d.ts +2 -0
- package/dist/selftest/engine.test.js +127 -0
- package/dist/selftest/generate.test.js +1 -1
- package/dist/selftest/hcs.test.d.ts +2 -0
- package/dist/selftest/hcs.test.js +482 -0
- package/dist/selftest/health.test.d.ts +2 -0
- package/dist/selftest/health.test.js +470 -0
- package/dist/selftest/heavy-load.test.d.ts +2 -0
- package/dist/selftest/heavy-load.test.js +329 -0
- package/dist/selftest/host-sim.test.js +2 -0
- package/dist/selftest/index.js +31 -0
- package/dist/selftest/layout.test.js +14 -0
- package/dist/selftest/menu-perf.test.d.ts +2 -0
- package/dist/selftest/menu-perf.test.js +248 -0
- package/dist/selftest/menu-screens.d.ts +7 -0
- package/dist/selftest/menu-screens.js +68 -17
- package/dist/selftest/menu.test.js +603 -22
- package/dist/selftest/migrate.test.js +1 -1
- package/dist/selftest/personalization.test.js +3 -1
- package/dist/selftest/projects.test.js +39 -1
- package/dist/selftest/shared-use.test.js +64 -2
- package/dist/selftest/sharing.test.js +50 -1
- package/dist/selftest/storage.test.d.ts +2 -0
- package/dist/selftest/storage.test.js +363 -0
- package/dist/selftest/support/engine-cases.d.ts +8 -0
- package/dist/selftest/support/engine-cases.js +65 -0
- package/dist/selftest/support/engine-golden.d.ts +3 -0
- package/dist/selftest/support/engine-golden.js +66 -0
- package/dist/selftest/support/fixtures.d.ts +20 -0
- package/dist/selftest/support/hcs-probes.d.ts +17 -0
- package/dist/selftest/support/hcs-probes.js +41 -0
- package/dist/selftest/support/releases.js +1 -1
- package/dist/selftest/toolchains.test.js +21 -0
- package/dist/selftest/update-service.test.js +87 -3
- package/dist/selftest/vpn.test.d.ts +2 -0
- package/dist/selftest/vpn.test.js +412 -0
- package/dist/selftest/web.test.d.ts +2 -0
- package/dist/selftest/web.test.js +402 -0
- package/dist/shared/apps/catalogue.js +31 -0
- package/dist/shared/channel/index.d.ts +1 -0
- package/dist/shared/channel/index.js +1 -0
- package/dist/shared/channel/run-dir.d.ts +9 -1
- package/dist/shared/channel/run-dir.js +18 -1
- package/dist/shared/channel/schema.d.ts +53 -0
- package/dist/shared/channel/schema.js +38 -0
- package/dist/shared/channel/secrets.d.ts +29 -0
- package/dist/shared/channel/secrets.js +50 -0
- package/dist/shared/memory/index.d.ts +1 -0
- package/dist/shared/memory/index.js +1 -0
- package/dist/shared/memory/policy.d.ts +33 -0
- package/dist/shared/memory/policy.js +55 -0
- package/dist/shared/pty/output-filter.d.ts +14 -1
- package/dist/shared/pty/output-filter.js +22 -4
- package/dist/shared/pty/terminal.d.ts +4 -1
- package/dist/shared/pty/terminal.js +4 -2
- package/dist/shared/system.d.ts +1 -0
- package/dist/shared/system.js +1 -0
- package/dist/shared/vpn/download.d.ts +29 -0
- package/dist/shared/vpn/download.js +30 -0
- package/dist/shared/vpn/kill-switch.d.ts +18 -0
- package/dist/shared/vpn/kill-switch.js +81 -0
- package/dist/shared/vpn/ovpn.d.ts +23 -0
- package/dist/shared/vpn/ovpn.js +244 -0
- package/dist/shared/vpn/wireguard.d.ts +51 -0
- package/dist/shared/vpn/wireguard.js +227 -0
- package/dist/shared/web/index.d.ts +1 -0
- package/dist/shared/web/index.js +1 -0
- package/dist/shared/web/protocol.d.ts +61 -0
- package/dist/shared/web/protocol.js +35 -0
- package/dist/sync/sync-cycle.js +9 -5
- package/dist/sync/sync-state.d.ts +1 -0
- package/dist/sync/sync-state.js +1 -0
- package/dist/sync/watcher.d.ts +13 -0
- package/dist/sync/watcher.js +102 -3
- package/dist/web/index.html +14 -0
- package/dist/web/main-NRRS5O6Z.js +157 -0
- package/dist/web/main-T5DMCHYV.css +1 -0
- package/native/csharp/FolderSecurity.cs +29 -0
- package/native/csharp/HcsHost/AssemblyInfo.cs +14 -0
- package/native/csharp/HcsHost/Guard.cs +100 -0
- package/native/csharp/HcsHost/Hcs.cs +256 -0
- package/native/csharp/HcsHost/Json.cs +78 -0
- package/native/csharp/HcsHost/Program.cs +185 -0
- package/native/csharp/HcsHost/VirtualDisk.cs +95 -0
- package/native/csharp/HostTools/AssemblyInfo.cs +14 -0
- package/native/csharp/HostTools/MemoryStatus.cs +107 -0
- package/native/csharp/HostTools/Program.cs +58 -17
- package/native/scripts/check-contained.ps1 +28 -0
- package/native/scripts/contained-common.ps1 +241 -0
- package/native/scripts/dismount-contained.ps1 +66 -0
- package/native/scripts/memory-status.ps1 +34 -0
- package/native/scripts/mount-contained.ps1 +139 -0
- package/native/scripts/protect-data.ps1 +29 -0
- package/native/scripts/read-folder-sddl.ps1 +10 -0
- package/native/scripts/run-elevated.ps1 +17 -4
- package/native/scripts/set-folder-access.ps1 +49 -7
- package/native/scripts/stop-events.ps1 +23 -8
- package/node_modules/ws/LICENSE +20 -0
- package/node_modules/ws/README.md +548 -0
- package/node_modules/ws/browser.js +8 -0
- package/node_modules/ws/index.js +22 -0
- package/node_modules/ws/lib/buffer-util.js +131 -0
- package/node_modules/ws/lib/constants.js +19 -0
- package/node_modules/ws/lib/event-target.js +292 -0
- package/node_modules/ws/lib/extension.js +203 -0
- package/node_modules/ws/lib/limiter.js +55 -0
- package/node_modules/ws/lib/permessage-deflate.js +530 -0
- package/node_modules/ws/lib/receiver.js +743 -0
- package/node_modules/ws/lib/sender.js +607 -0
- package/node_modules/ws/lib/stream.js +161 -0
- package/node_modules/ws/lib/subprotocol.js +62 -0
- package/node_modules/ws/lib/validation.js +152 -0
- package/node_modules/ws/lib/websocket-server.js +562 -0
- package/node_modules/ws/lib/websocket.js +1421 -0
- package/node_modules/ws/package.json +74 -0
- package/node_modules/ws/wrapper.mjs +21 -0
- package/package.json +22 -5
- package/sandbox/csharp/EnvBroadcast.cs +33 -0
- package/sandbox/csharp/MemGov.cs +398 -0
- package/sandbox/csharp/PathSync.cs +90 -0
- package/sandbox/csharp/PtyHost.cs +111 -5
- package/sandbox/scripts/install-shell-path.ps1 +73 -0
- package/sandbox/scripts/set-machine-environment.ps1 +37 -4
- package/schemas/config.schema.json +136 -7
- package/schemas/sandbox-config.schema.json +17 -4
- package/dist/cli/commands/repair/checks.d.ts +0 -2
- package/dist/cli/commands/repair/checks.js +0 -246
- package/dist/cli/commands/sessions/control.d.ts +0 -4
- package/dist/cli/commands/sessions/control.js +0 -66
- package/dist/cli/commands/sessions/list.d.ts +0 -2
- package/dist/cli/commands/sessions/list.js +0 -45
- package/dist/cli/commands/sessions/status.d.ts +0 -2
- package/dist/cli/commands/sessions/status.js +0 -93
- package/dist/cli/commands/sessions/window.d.ts +0 -3
- package/dist/cli/commands/sessions/window.js +0 -18
- package/dist/cli/menu/pages/start-page.d.ts +0 -43
- package/dist/cli/menu/pages/start-page.js +0 -192
- package/dist/cli/tui/tab-bar.d.ts +0 -9
- package/dist/cli/tui/tab-bar.js +0 -33
|
@@ -0,0 +1,412 @@
|
|
|
1
|
+
// The VPN: profiles are untrusted (programs refused), the kill switch rules, NordVPN server choice, the saved login,
|
|
2
|
+
// the settings rules for projects, and that the login never lands in session.json or the launch folder.
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { DEFAULTS } from '../core/config/index.js';
|
|
6
|
+
import { applyOverrides, loosenedRequests, NEVER_LOOSER, normalizeOverrides } from '../core/local-config/index.js';
|
|
7
|
+
import { ConfigSchema, LocalOverridesSchema } from '../core/schema/index.js';
|
|
8
|
+
import { SecretStore } from '../host/secrets/index.js';
|
|
9
|
+
import { clearSecrets } from '../host/secrets/index.js';
|
|
10
|
+
import { generateSandbox } from '../host/launch/index.js';
|
|
11
|
+
import { findCountry, nordProfile, prepareVpn, wireguardFileProblem, recommendedServer, VpnLogin, vpnLine, vpnNotes, } from '../host/vpn/index.js';
|
|
12
|
+
import { RunDir } from '../shared/channel/index.js';
|
|
13
|
+
import { OPENVPN_MSI, WIREGUARD_MSI } from '../shared/vpn/download.js';
|
|
14
|
+
import { cleanServers, killSwitchCommands, removeKillSwitchCommands, tunnelAddressFromLog, tunnelCommands, } from '../shared/vpn/kill-switch.js';
|
|
15
|
+
import { assertSafeOvpn, inspectOvpn, PROGRAM_DIRECTIVES } from '../shared/vpn/ovpn.js';
|
|
16
|
+
import { assertSafeWireguard, handshakeDone, inspectWireguard, renderWireguard, serviceRunning, WIREGUARD_PROGRAM_KEYS, wireguardEndpoints, wireguardTunnelAddress, } from '../shared/vpn/wireguard.js';
|
|
17
|
+
const PROFILE = [
|
|
18
|
+
'client',
|
|
19
|
+
'dev tun',
|
|
20
|
+
'proto udp',
|
|
21
|
+
'remote 185.1.2.3 1194',
|
|
22
|
+
'remote-random',
|
|
23
|
+
'resolv-retry infinite',
|
|
24
|
+
'nobind',
|
|
25
|
+
'tun-mtu 1500',
|
|
26
|
+
'tun-mtu-extra 32',
|
|
27
|
+
'mssfix 1450',
|
|
28
|
+
'persist-key',
|
|
29
|
+
'persist-tun',
|
|
30
|
+
'ping 15',
|
|
31
|
+
'ping-restart 0',
|
|
32
|
+
'ping-timer-rem',
|
|
33
|
+
'reneg-sec 0',
|
|
34
|
+
'comp-lzo no',
|
|
35
|
+
'remote-cert-tls server',
|
|
36
|
+
'auth-user-pass',
|
|
37
|
+
'verb 3',
|
|
38
|
+
'pull',
|
|
39
|
+
'fast-io',
|
|
40
|
+
'cipher AES-256-CBC',
|
|
41
|
+
'auth SHA512',
|
|
42
|
+
'<ca>',
|
|
43
|
+
'-----BEGIN CERTIFICATE-----',
|
|
44
|
+
'MIIDxx',
|
|
45
|
+
'-----END CERTIFICATE-----',
|
|
46
|
+
'</ca>',
|
|
47
|
+
'key-direction 1',
|
|
48
|
+
'<tls-auth>',
|
|
49
|
+
'-----BEGIN OpenVPN Static key V1-----',
|
|
50
|
+
'abcd',
|
|
51
|
+
'-----END OpenVPN Static key V1-----',
|
|
52
|
+
'</tls-auth>',
|
|
53
|
+
'',
|
|
54
|
+
].join('\r\n');
|
|
55
|
+
const PRIVATE_KEY = 'PrivPlanted' + 'A'.repeat(32) + '=';
|
|
56
|
+
const PUBLIC_KEY = 'PubPlanted' + 'B'.repeat(33) + '=';
|
|
57
|
+
const PRESHARED_KEY = 'PskPlanted' + 'C'.repeat(33) + '=';
|
|
58
|
+
const WG_CONFIG = [
|
|
59
|
+
'[Interface]',
|
|
60
|
+
'PrivateKey = ' + PRIVATE_KEY,
|
|
61
|
+
'Address = 10.64.0.2/32, fd00::2/128',
|
|
62
|
+
'DNS = 10.64.0.1',
|
|
63
|
+
'MTU = 1380',
|
|
64
|
+
'',
|
|
65
|
+
'[Peer] # the office',
|
|
66
|
+
'PublicKey = ' + PUBLIC_KEY,
|
|
67
|
+
'PresharedKey = ' + PRESHARED_KEY,
|
|
68
|
+
'AllowedIPs = 0.0.0.0/0, ::/0',
|
|
69
|
+
'Endpoint = vpn.example.com:51820',
|
|
70
|
+
'PersistentKeepalive = 25',
|
|
71
|
+
'',
|
|
72
|
+
].join('\r\n');
|
|
73
|
+
const PASSWORD = 'vpn-pass-planted-91c2d7';
|
|
74
|
+
const USERNAME = 'vpn-user-planted-5e8a40';
|
|
75
|
+
export const vpnSuite = {
|
|
76
|
+
name: 'vpn',
|
|
77
|
+
title: 'VPN: profile checks, kill switch rules, NordVPN, login storage, settings rules',
|
|
78
|
+
run: async (t, f) => {
|
|
79
|
+
t.section('a profile is untrusted data');
|
|
80
|
+
const good = inspectOvpn(PROFILE);
|
|
81
|
+
t.check(good.ok && good.remotes.length === 1 && good.remotes[0].host === '185.1.2.3' && good.remotes[0].proto === 'udp', 'a NordVPN-style profile is accepted and says where it connects (and with which protocol)', JSON.stringify(good));
|
|
82
|
+
const byName = inspectOvpn('remote vpn.example.com 443\r\nproto tcp-client\r\nclient');
|
|
83
|
+
t.check(byName.ok && byName.remotes[0].proto === 'tcp' && byName.remotes[0].host === 'vpn.example.com', 'the proto line counts even after the remote line, and a host name is allowed');
|
|
84
|
+
for (const name of ['script-security', 'up', 'down', 'plugin', 'route-up', 'ipchange', 'tls-verify']) {
|
|
85
|
+
const bad = inspectOvpn(PROFILE + name + ' 2 C:\\evil.cmd\r\n');
|
|
86
|
+
t.check(!bad.ok && bad.problems.some((p) => p.includes(name + ' runs a program')), name + ' is refused as something that runs a program', JSON.stringify(bad));
|
|
87
|
+
}
|
|
88
|
+
t.check(PROGRAM_DIRECTIVES.every((name) => !inspectOvpn(PROFILE + name + ' x\r\n').ok), 'every listed program-running directive is refused');
|
|
89
|
+
const odd = [
|
|
90
|
+
['--up x', 'a leading -- does not hide it'],
|
|
91
|
+
['UP x', 'upper case does not hide it'],
|
|
92
|
+
['\tscript-security 2', 'leading white space does not hide it'],
|
|
93
|
+
['"up" x', 'quotes around the name do not hide it'],
|
|
94
|
+
['made-up-directive 1', 'an unknown directive is refused, not passed on'],
|
|
95
|
+
['ca /etc/ca.crt', 'a certificate file on this machine is refused'],
|
|
96
|
+
['auth-user-pass C:\\secret.txt', 'a login file named in the profile is refused'],
|
|
97
|
+
['setenv FOO bar', 'setenv for anything but CLIENT_CERT is refused'],
|
|
98
|
+
['<connection>', 'a <connection> section (it could hide more) is refused'],
|
|
99
|
+
];
|
|
100
|
+
for (const [line, why] of odd)
|
|
101
|
+
t.check(!inspectOvpn(PROFILE + line + '\r\n').ok, why, line);
|
|
102
|
+
t.check(!inspectOvpn(PROFILE.replace('</ca>', '')).ok &&
|
|
103
|
+
!inspectOvpn('client\r\n').ok &&
|
|
104
|
+
!inspectOvpn('x'.repeat(300 * 1024)).ok &&
|
|
105
|
+
!inspectOvpn(PROFILE.replace('<tls-auth>', '<tls-auth>\r\nup evil\r\n<ca>')).ok, 'an unclosed section, no remote, an oversized file and a section inside a section are refused');
|
|
106
|
+
t.check(inspectOvpn(PROFILE.replace('</ca>', '</ca>\r\n# up /bin/evil\r\n; plugin evil.dll\r\n')).ok, 'comments are comments (a commented-out up line is not a directive)');
|
|
107
|
+
await t.throws(() => assertSafeOvpn(PROFILE + 'script-security 2\r\nup evil.cmd\r\n', 'uk1.nordvpn.com'), 'uk1.nordvpn.com was refused', 'a refused profile names its source and the reason');
|
|
108
|
+
t.section('the kill switch as netsh commands');
|
|
109
|
+
const servers = [
|
|
110
|
+
{ ip: '185.1.2.3', port: 1194, proto: 'udp' },
|
|
111
|
+
{ ip: '185.1.2.3', port: 1194, proto: 'udp' },
|
|
112
|
+
{ ip: 'not-an-ip', port: 1194, proto: 'udp' },
|
|
113
|
+
{ ip: '185.9.9.9', port: 443, proto: 'tcp' },
|
|
114
|
+
];
|
|
115
|
+
t.equal(cleanServers(servers).map((s) => s.ip + ':' + s.port), ['185.1.2.3:1194', '185.9.9.9:443'], 'servers are valid and each once');
|
|
116
|
+
const phase1 = killSwitchCommands(servers, 'C:\\AgentLaunch\\ptyhost.exe').map((c) => c.join(' '));
|
|
117
|
+
const policyAt = phase1.findIndex((c) => c.includes('firewallpolicy blockinbound,blockoutbound'));
|
|
118
|
+
const firstAllow = phase1.findIndex((c) => c.includes('action=allow'));
|
|
119
|
+
t.check(policyAt > 0 && policyAt < firstAllow, 'outbound is blocked by default before any allow rule is added', phase1.join('\n'));
|
|
120
|
+
t.check(phase1.some((c) => c.includes('name=AgentSandbox-VPN-Loopback') && c.includes('remoteip=127.0.0.0/8')) &&
|
|
121
|
+
phase1.some((c) => c.includes('name=AgentSandbox-VPN-Server-1') &&
|
|
122
|
+
c.includes('protocol=udp') &&
|
|
123
|
+
c.includes('remoteip=185.1.2.3') &&
|
|
124
|
+
c.includes('remoteport=1194')) &&
|
|
125
|
+
phase1.some((c) => c.includes('name=AgentSandbox-VPN-Server-2') && c.includes('protocol=tcp') && c.includes('remoteport=443')) &&
|
|
126
|
+
phase1.some((c) => c.includes('name=AgentSandbox-VPN-Host') &&
|
|
127
|
+
c.includes('remoteip=LocalSubnet') &&
|
|
128
|
+
c.includes('program=C:\\AgentLaunch\\ptyhost.exe')) &&
|
|
129
|
+
phase1.some((c) => c.includes('name=AgentSandbox-VPN-DHCP')), 'it allows loopback, each VPN server endpoint, the attach channel on the Hyper-V network and DHCP');
|
|
130
|
+
t.check(!phase1.some((c) => c.includes('localip=') || (c.includes('action=allow') && c.includes('remoteip=any'))), 'nothing else is allowed before the tunnel exists (no blanket rule)');
|
|
131
|
+
t.check(killSwitchCommands([], null).every((c) => !c.join(' ').includes('Server-1') || c[2] === 'delete') &&
|
|
132
|
+
!killSwitchCommands([], null).some((c) => c.join(' ').includes('name=AgentSandbox-VPN-Host') && c[2] === 'add'), 'with no servers and no session host only the block and the loopback rules remain (the failure case: offline)');
|
|
133
|
+
t.equal(tunnelCommands('10.8.0.6')
|
|
134
|
+
.map((c) => c.join(' '))
|
|
135
|
+
.filter((c) => c.includes(' add ')), [
|
|
136
|
+
'advfirewall firewall add rule name=AgentSandbox-VPN-Tunnel dir=out action=allow enable=yes profile=any protocol=any localip=10.8.0.6',
|
|
137
|
+
], 'once the tunnel is up, traffic from its own address (the tunnel) is allowed');
|
|
138
|
+
await t.throws(() => tunnelCommands('10.8.0.6; calc'), 'Not an IPv4', 'a tunnel address that is not an address makes no rule');
|
|
139
|
+
t.check(removeKillSwitchCommands().some((c) => c.join(' ').includes('blockinbound,allowoutbound')) &&
|
|
140
|
+
removeKillSwitchCommands().some((c) => c.join(' ').includes('name=AgentSandbox-VPN-Tunnel')), 'taking it away restores the default and deletes the rules');
|
|
141
|
+
t.equal([
|
|
142
|
+
tunnelAddressFromLog('... net_addr_v4_add: 10.100.0.2/16 dev Wintun ...'),
|
|
143
|
+
tunnelAddressFromLog('ifconfig 10.8.0.6 255.255.255.0'),
|
|
144
|
+
tunnelAddressFromLog('nothing'),
|
|
145
|
+
], ['10.100.0.2', '10.8.0.6', null], "the tunnel's address is read from OpenVPN's log");
|
|
146
|
+
t.check(OPENVPN_MSI.x64.sha256.length === 64 &&
|
|
147
|
+
OPENVPN_MSI.arm64.sha256.length === 64 &&
|
|
148
|
+
OPENVPN_MSI.base.startsWith('https://'), 'the OpenVPN download has a checksum for each architecture (downloads.requireChecksum passes)');
|
|
149
|
+
t.section('NordVPN: the server for the country and protocol');
|
|
150
|
+
const asked = [];
|
|
151
|
+
const fake = (url) => {
|
|
152
|
+
asked.push(url);
|
|
153
|
+
if (url.endsWith('/servers/countries'))
|
|
154
|
+
return Promise.resolve(JSON.stringify([
|
|
155
|
+
{ id: 227, name: 'United Kingdom', code: 'GB' },
|
|
156
|
+
{ id: 81, name: 'Germany', code: 'DE' },
|
|
157
|
+
]));
|
|
158
|
+
if (url.includes('/servers/recommendations'))
|
|
159
|
+
return Promise.resolve(JSON.stringify([{ hostname: 'uk2201.nordvpn.com', station: '185.1.2.3' }]));
|
|
160
|
+
if (url.endsWith('.ovpn'))
|
|
161
|
+
return Promise.resolve(PROFILE);
|
|
162
|
+
return Promise.reject(new Error('unexpected ' + url));
|
|
163
|
+
};
|
|
164
|
+
t.check(findCountry([{ id: 227, name: 'United Kingdom', code: 'GB' }], 'uk') === 227 &&
|
|
165
|
+
findCountry([{ id: 81, name: 'Germany', code: 'DE' }], 'germany') === 81, 'uk and Germany are found by code, alias or name');
|
|
166
|
+
await t.throws(() => findCountry([{ id: 81, name: 'Germany', code: 'DE' }], 'atlantis'), 'no country', 'an unknown country says so');
|
|
167
|
+
const server = await recommendedServer('udp', 'uk', fake);
|
|
168
|
+
t.check(server.hostname === 'uk2201.nordvpn.com' &&
|
|
169
|
+
asked.some((u) => u.includes('filters[country_id]=227') && u.includes('openvpn_udp')), 'the recommendation asks for the country and the protocol', asked.join('\n'));
|
|
170
|
+
t.check((await nordProfile(server, 'udp', fake)) === PROFILE &&
|
|
171
|
+
asked.some((u) => u === 'https://downloads.nordcdn.com/configs/files/ovpn_udp/servers/uk2201.nordvpn.com.udp.ovpn'), "the server's own profile is fetched from NordVPN's download host");
|
|
172
|
+
await t.throws(() => recommendedServer('udp', '', () => Promise.resolve(JSON.stringify([{ hostname: 'evil.example.com; calc', station: '1.2.3.4' }]))), 'did not recommend', 'an answer that is not a NordVPN host name is refused (it becomes part of a URL and a file name)');
|
|
173
|
+
t.section('the saved login');
|
|
174
|
+
const storage = t.dir('vpn-storage');
|
|
175
|
+
const login = new VpnLogin(storage, SecretStore.memory());
|
|
176
|
+
t.check(login.state('nordvpn') === 'none', 'nothing is saved at first');
|
|
177
|
+
await t.throws(() => login.save('nordvpn', { username: 'a\nb', password: 'x' }), 'line breaks', 'a login with a line break is refused (it goes on two lines of a file)');
|
|
178
|
+
login.save('nordvpn', { username: USERNAME, password: PASSWORD });
|
|
179
|
+
const file = path.join(storage, 'vpn', 'nordvpn.json');
|
|
180
|
+
t.check(login.state('nordvpn') === 'saved' &&
|
|
181
|
+
!fs.readFileSync(file, 'utf8').includes(USERNAME) &&
|
|
182
|
+
!fs.readFileSync(file, 'utf8').includes(PASSWORD), 'it is saved sealed: neither value is in the file');
|
|
183
|
+
t.equal(login.read('nordvpn'), { username: USERNAME, password: PASSWORD }, 'and it opens for the launch');
|
|
184
|
+
fs.writeFileSync(file, fs.readFileSync(file, 'utf8').replace(/"sealed": "[^"]*"/, '"sealed": "dpapi1:AAAA"'));
|
|
185
|
+
t.check(login.state('nordvpn') === 'unreadable', 'a login this Windows user cannot open is reported as unreadable');
|
|
186
|
+
login.remove('nordvpn');
|
|
187
|
+
t.check(login.state('nordvpn') === 'none', 'logout deletes it');
|
|
188
|
+
t.section('settings: what a project may and may not do');
|
|
189
|
+
t.check(DEFAULTS.vpn.enabled === false && DEFAULTS.vpn.provider === 'nordvpn' && DEFAULTS.vpn.killSwitch === true, 'the VPN is off by default, NordVPN, with the kill switch on');
|
|
190
|
+
t.check(ConfigSchema.safeParse(DEFAULTS).success, 'the defaults are valid');
|
|
191
|
+
t.check(!ConfigSchema.safeParse({ ...DEFAULTS, vpn: { ...DEFAULTS.vpn, country: 'uk; calc' } }).success &&
|
|
192
|
+
!ConfigSchema.safeParse({ ...DEFAULTS, vpn: { ...DEFAULTS.vpn, protocol: 'icmp' } }).success &&
|
|
193
|
+
!ConfigSchema.safeParse({ ...DEFAULTS, vpn: { ...DEFAULTS.vpn, username: 'x' } }).success, 'a country with odd characters, an unknown protocol and a login setting are all invalid (no login setting exists)');
|
|
194
|
+
for (const bad of [
|
|
195
|
+
{ vpn: { enabled: true } },
|
|
196
|
+
{ vpn: { provider: 'openvpn-file' } },
|
|
197
|
+
{ vpn: { configFile: 'C:\\evil.ovpn' } },
|
|
198
|
+
{ vpn: { country: 'uk' } },
|
|
199
|
+
{ vpn: { username: 'x', password: 'y' } },
|
|
200
|
+
{ vpn: { credentials: 'x' } },
|
|
201
|
+
{ vpn: { servers: ['1.2.3.4'] } },
|
|
202
|
+
])
|
|
203
|
+
t.check(!LocalOverridesSchema.safeParse(bad).success, "a project's .sandbox-config.json cannot set " + Object.keys(bad.vpn).join(', '));
|
|
204
|
+
t.check(LocalOverridesSchema.safeParse({ vpn: { killSwitch: true } }).success, 'it can ask for the kill switch');
|
|
205
|
+
t.check(NEVER_LOOSER.includes('vpn.killSwitch'), 'the kill switch is a protection a project may only tighten');
|
|
206
|
+
const mine = structuredClone(DEFAULTS);
|
|
207
|
+
mine.vpn.enabled = true;
|
|
208
|
+
const loosen = normalizeOverrides({ vpn: { killSwitch: false } }, f.workA, 'x');
|
|
209
|
+
t.check(applyOverrides(mine, loosen).vpn.killSwitch === true &&
|
|
210
|
+
loosenedRequests(mine, loosen).some((r) => r.key === 'vpn.killSwitch'), 'a project cannot turn the kill switch off (it is flagged and ignored)');
|
|
211
|
+
const off = structuredClone(mine);
|
|
212
|
+
off.vpn.killSwitch = false;
|
|
213
|
+
t.check(applyOverrides(off, normalizeOverrides({ vpn: { killSwitch: true } }, f.workA, 'x')).vpn.killSwitch === true, 'but it can turn it on');
|
|
214
|
+
t.section('the login never lands in session.json, the launch folder or --json');
|
|
215
|
+
const config = f.makeConfig();
|
|
216
|
+
config.vpn = { ...config.vpn, enabled: true, country: 'uk' };
|
|
217
|
+
const store = new VpnLogin(config.storage.root, SecretStore.memory());
|
|
218
|
+
store.save('nordvpn', { username: USERNAME, password: PASSWORD });
|
|
219
|
+
const run = await f.run({}, config);
|
|
220
|
+
const prepared = await prepareVpn({
|
|
221
|
+
config: run.config,
|
|
222
|
+
storageRoot: config.storage.root,
|
|
223
|
+
login: store,
|
|
224
|
+
fetchText: fake,
|
|
225
|
+
});
|
|
226
|
+
t.check(prepared !== null &&
|
|
227
|
+
prepared.session.server === 'uk2201.nordvpn.com' &&
|
|
228
|
+
prepared.credentials?.password === PASSWORD, 'a launch picks the server, checks its profile and holds the login in memory');
|
|
229
|
+
await t.throws(() => prepareVpn({
|
|
230
|
+
config: run.config,
|
|
231
|
+
storageRoot: config.storage.root,
|
|
232
|
+
login: store,
|
|
233
|
+
fetchText: fake,
|
|
234
|
+
sandboxRunning: true,
|
|
235
|
+
}), 'already', 'the login is not handed over while a sandbox is running (one that is not being started now)');
|
|
236
|
+
await t.throws(() => prepareVpn({
|
|
237
|
+
config: run.config,
|
|
238
|
+
storageRoot: config.storage.root,
|
|
239
|
+
login: store,
|
|
240
|
+
fetchText: (url) => (url.endsWith('.ovpn') ? Promise.resolve(PROFILE + 'up evil.cmd\r\n') : fake(url)),
|
|
241
|
+
}), 'refused', 'a profile that would run a program stops the launch before anything is written');
|
|
242
|
+
await t.throws(() => prepareVpn({
|
|
243
|
+
config: run.config,
|
|
244
|
+
storageRoot: config.storage.root,
|
|
245
|
+
login: new VpnLogin(t.dir('vpn-empty'), SecretStore.memory()),
|
|
246
|
+
fetchText: fake,
|
|
247
|
+
}), 'sandbox vpn login', 'no saved login says how to save one');
|
|
248
|
+
clearSecrets(config.storage.root, run.dataPath);
|
|
249
|
+
const withVpn = generateSandbox({
|
|
250
|
+
packageRoot: t.packageRoot,
|
|
251
|
+
run,
|
|
252
|
+
harnessArgs: [],
|
|
253
|
+
probe: f.probe,
|
|
254
|
+
pcLanguages: ['python', 'rust', 'cpp', 'dotnet'],
|
|
255
|
+
...(prepared ? { vpn: prepared } : {}),
|
|
256
|
+
});
|
|
257
|
+
const session = fs.readFileSync(withVpn.sessionPath, 'utf8');
|
|
258
|
+
const everything = [];
|
|
259
|
+
const walk = (d) => {
|
|
260
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
261
|
+
const p = path.join(d, e.name);
|
|
262
|
+
if (e.isDirectory())
|
|
263
|
+
walk(p);
|
|
264
|
+
else
|
|
265
|
+
everything.push(fs.readFileSync(p, 'latin1'));
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
walk(withVpn.launchPath);
|
|
269
|
+
t.check(!session.includes(PASSWORD) &&
|
|
270
|
+
!session.includes(USERNAME) &&
|
|
271
|
+
!everything.some((text) => text.includes(PASSWORD) || text.includes(USERNAME)), 'neither the service user name nor the password is in session.json or any file of the launch folder');
|
|
272
|
+
const vpnSession = f.readJson(withVpn.sessionPath).vpn;
|
|
273
|
+
t.check(vpnSession.server === 'uk2201.nordvpn.com' &&
|
|
274
|
+
vpnSession.killSwitch === true &&
|
|
275
|
+
fs.readFileSync(path.join(withVpn.launchPath, 'vpn', 'server.ovpn'), 'utf8') === PROFILE, 'session.json says which server and whether the kill switch is on; the checked profile is in the launch folder');
|
|
276
|
+
const handed = f.readJson(new RunDir(run.dataPath).secretFile(withVpn.launchId));
|
|
277
|
+
t.equal(handed.vpn, { username: USERNAME, password: PASSWORD }, 'the login is only in the one-shot file for the sandbox');
|
|
278
|
+
clearSecrets(config.storage.root, run.dataPath);
|
|
279
|
+
t.check(vpnNotes(config.vpn).some((n) => n.includes('can read the VPN login') && n.includes('turn the tunnel off')) &&
|
|
280
|
+
vpnNotes(config.vpn).some((n) => n.includes('kill switch on')) &&
|
|
281
|
+
vpnNotes({ ...config.vpn, killSwitch: false }).some((n) => n.includes('kill switch OFF')) &&
|
|
282
|
+
vpnNotes({ ...config.vpn, enabled: false }).length === 0, 'the launch warns that the agent can read the login and turn the tunnel off, and says what the kill switch does');
|
|
283
|
+
t.section('what the host says about the tunnel');
|
|
284
|
+
const status = (state, extra = {}) => vpnLine({ state, message: 'm', killSwitch: true, updatedAt: 'now', ...extra }, '203.0.113.9');
|
|
285
|
+
t.check(status('up', { publicIp: '185.1.2.3', server: 'uk2201.nordvpn.com' }).level === 'ok' &&
|
|
286
|
+
status('up', { publicIp: '203.0.113.9' }).level === 'bad' &&
|
|
287
|
+
status('failed', { message: 'login refused' }).text.includes('NO internet') === false &&
|
|
288
|
+
status('failed', { message: 'login refused' }).text.includes('no internet') &&
|
|
289
|
+
vpnLine({ state: 'failed', message: 'x', killSwitch: false, updatedAt: 'now' }).text.includes('normal connection') &&
|
|
290
|
+
status('starting').level === 'warn', "up with another address is fine, up with this PC's own address is flagged, a failure says what the kill switch did");
|
|
291
|
+
t.check(!vpnLine({
|
|
292
|
+
state: 'failed',
|
|
293
|
+
message: 'bad \u001b]52;c;ZXZpbA==\u0007 text',
|
|
294
|
+
killSwitch: true,
|
|
295
|
+
updatedAt: 'n',
|
|
296
|
+
}).text.includes('\u001b'), 'text the sandbox wrote loses its escape sequences before it is printed');
|
|
297
|
+
t.section('WireGuard: your own config is untrusted data');
|
|
298
|
+
const wg = inspectWireguard(WG_CONFIG);
|
|
299
|
+
t.check(wg.ok &&
|
|
300
|
+
wg.config.peers.length === 1 &&
|
|
301
|
+
wg.config.peers[0].endpointHost === 'vpn.example.com' &&
|
|
302
|
+
wg.config.peers[0].endpointPort === 51820 &&
|
|
303
|
+
wireguardTunnelAddress(wg.config) === '10.64.0.2' &&
|
|
304
|
+
wireguardEndpoints(wg.config)[0].port === 51820, 'a plain config is accepted and says where it connects and which address the tunnel has', JSON.stringify(wg));
|
|
305
|
+
for (const key of WIREGUARD_PROGRAM_KEYS) {
|
|
306
|
+
const bad = inspectWireguard(WG_CONFIG.replace('MTU = 1380', key + ' = calc.exe'));
|
|
307
|
+
t.check(!bad.ok && bad.problems.some((p) => p.toLowerCase().includes(key)), key + ' is refused by name', JSON.stringify(bad));
|
|
308
|
+
}
|
|
309
|
+
const wgOdd = [
|
|
310
|
+
['FwMark = 7', 'an unknown [Interface] key is refused, not passed on'],
|
|
311
|
+
['postup = calc', 'lower case does not hide PostUp'],
|
|
312
|
+
['[Socks]', 'an unknown section is refused'],
|
|
313
|
+
['DNS = evil.example.com', 'a DNS name (a search domain) is refused: only addresses'],
|
|
314
|
+
['MTU = 99999', 'an MTU out of range is refused'],
|
|
315
|
+
['PrivateKey = ' + PRIVATE_KEY, 'a second PrivateKey is refused'],
|
|
316
|
+
];
|
|
317
|
+
for (const [line, why] of wgOdd) {
|
|
318
|
+
const text = line.startsWith('[') ? WG_CONFIG + line + '\r\n' : WG_CONFIG.replace('MTU = 1380', line);
|
|
319
|
+
t.check(!inspectWireguard(text).ok, why, line);
|
|
320
|
+
}
|
|
321
|
+
t.check(!inspectWireguard(WG_CONFIG.replace(PRIVATE_KEY, 'tooshort')).ok &&
|
|
322
|
+
!inspectWireguard(WG_CONFIG.replace('10.64.0.2/32, fd00::2/128', 'fd00::2/128')).ok &&
|
|
323
|
+
!inspectWireguard(WG_CONFIG.replace('vpn.example.com:51820', '[2001:db8::1]:51820')).ok &&
|
|
324
|
+
!inspectWireguard(WG_CONFIG.replace('Endpoint = vpn.example.com:51820', '')).ok &&
|
|
325
|
+
!inspectWireguard(WG_CONFIG.replace('vpn.example.com:51820', 'vpn.example.com:0')).ok &&
|
|
326
|
+
!inspectWireguard(WG_CONFIG.replace('[Peer] # the office', '')).ok &&
|
|
327
|
+
!inspectWireguard('x'.repeat(20 * 1024)).ok &&
|
|
328
|
+
!inspectWireguard(WG_CONFIG.replace('AllowedIPs = 0.0.0.0/0, ::/0', 'AllowedIPs = 300.0.0.0/0')).ok, 'a bad key, an IPv6-only address or endpoint, a missing endpoint or peer, a bad port, a huge file and a bad range are refused');
|
|
329
|
+
t.check(inspectWireguard(WG_CONFIG.replace('MTU = 1380', '# PostUp = calc\r\nMTU = 1380 # PreUp = calc')).ok, 'comments are comments (a commented-out PostUp is not a key)');
|
|
330
|
+
const refusals = [
|
|
331
|
+
WG_CONFIG.replace('MTU = 1380', 'PostUp = ' + PRIVATE_KEY),
|
|
332
|
+
WG_CONFIG.replace('MTU = 1380', 'Bogus = ' + PRESHARED_KEY),
|
|
333
|
+
WG_CONFIG.replace(PUBLIC_KEY, 'bad' + PRESHARED_KEY),
|
|
334
|
+
WG_CONFIG.replace(PRIVATE_KEY, PRIVATE_KEY + 'x'),
|
|
335
|
+
].map(inspectWireguard);
|
|
336
|
+
t.check(refusals.every((r) => !r.ok && !JSON.stringify(r).includes('PrivPlanted') && !JSON.stringify(r).includes('PskPlanted')), 'what a refusal says never contains a key');
|
|
337
|
+
await t.throws(() => assertSafeWireguard(WG_CONFIG.replace('MTU = 1380', 'PostUp = calc'), 'office.conf'), 'office.conf was refused', 'a refused config names its file and the reason');
|
|
338
|
+
if (wg.ok) {
|
|
339
|
+
const text = renderWireguard(wg.config, { 0: '203.0.113.7' });
|
|
340
|
+
t.check(text.includes('Endpoint = 203.0.113.7:51820') &&
|
|
341
|
+
!text.includes('vpn.example.com') &&
|
|
342
|
+
!text.includes('the office') &&
|
|
343
|
+
inspectWireguard(text).ok, 'the config handed on is written again from the checked values, with the endpoint as an address, and is itself valid');
|
|
344
|
+
}
|
|
345
|
+
const wgRules = killSwitchCommands([{ ip: '203.0.113.7', port: 51820, proto: 'udp' }], null).map((c) => c.join(' '));
|
|
346
|
+
t.check(wgRules.some((c) => c.includes('name=AgentSandbox-VPN-Server-1') &&
|
|
347
|
+
c.includes('protocol=udp') &&
|
|
348
|
+
c.includes('remoteip=203.0.113.7') &&
|
|
349
|
+
c.includes('remoteport=51820')) && wgRules.findIndex((c) => c.includes('blockoutbound')) < wgRules.findIndex((c) => c.includes('action=allow')), 'the kill switch blocks first and lets only the endpoint host:port through, over udp');
|
|
350
|
+
t.check(tunnelCommands('10.64.0.2').some((c) => c.join(' ').includes('localip=10.64.0.2') && c[2] === 'add'), "the tunnel's own address (from Address) is let through once the service runs");
|
|
351
|
+
t.check(WIREGUARD_MSI.x64.sha256.length === 64 &&
|
|
352
|
+
WIREGUARD_MSI.arm64.sha256.length === 64 &&
|
|
353
|
+
WIREGUARD_MSI.base.startsWith('https://download.wireguard.com/') &&
|
|
354
|
+
serviceRunning('STATE : 4 RUNNING') &&
|
|
355
|
+
!serviceRunning('STATE : 1 STOPPED') &&
|
|
356
|
+
handshakeDone('abc=\t1700000000\r\n') &&
|
|
357
|
+
!handshakeDone('abc=\t0\r\n') &&
|
|
358
|
+
!handshakeDone(''), 'the WireGuard download is pinned by checksum; the service state and handshake are read from the tools output');
|
|
359
|
+
t.section('WireGuard: the keys never land in session.json or the launch folder');
|
|
360
|
+
const wgDir = t.dir('wg-config');
|
|
361
|
+
const wgFile = path.join(wgDir, 'office.conf');
|
|
362
|
+
fs.writeFileSync(wgFile, WG_CONFIG);
|
|
363
|
+
const wgSettings = f.makeConfig();
|
|
364
|
+
wgSettings.vpn = { ...wgSettings.vpn, enabled: true, provider: 'wireguard-file', configFile: wgFile };
|
|
365
|
+
const wgRun = await f.run({}, wgSettings);
|
|
366
|
+
const wgPrepared = await prepareVpn({
|
|
367
|
+
config: wgRun.config,
|
|
368
|
+
storageRoot: wgSettings.storage.root,
|
|
369
|
+
login: new VpnLogin(t.dir('wg-nologin'), SecretStore.memory()),
|
|
370
|
+
});
|
|
371
|
+
t.check(wgPrepared !== null &&
|
|
372
|
+
wgPrepared.session.server === 'office.conf' &&
|
|
373
|
+
wgPrepared.session.profile === undefined &&
|
|
374
|
+
wgPrepared.credentials === undefined &&
|
|
375
|
+
(wgPrepared.wireguardConfig ?? '').includes(PRIVATE_KEY), 'a launch needs no saved login; it holds the checked config (with the private key) in memory only');
|
|
376
|
+
fs.writeFileSync(wgFile, WG_CONFIG.replace('MTU = 1380', 'PostUp = calc.exe'));
|
|
377
|
+
await t.throws(() => prepareVpn({ config: wgRun.config, storageRoot: wgSettings.storage.root }), 'refused', 'a config with PostUp stops the launch before anything is written');
|
|
378
|
+
t.check(wireguardFileProblem(wgFile, wgDir)?.includes('refused') === true &&
|
|
379
|
+
wireguardFileProblem(path.join(wgDir, 'missing.conf'), wgDir) !== null &&
|
|
380
|
+
!(wireguardFileProblem(wgFile, wgDir) ?? '').includes('PrivPlanted'), 'doctor says a bad or missing config is a problem, without a key');
|
|
381
|
+
fs.writeFileSync(wgFile, WG_CONFIG);
|
|
382
|
+
t.check(wireguardFileProblem('office.conf', wgDir) === null, 'a good config, even by a relative path, is fine');
|
|
383
|
+
clearSecrets(wgSettings.storage.root, wgRun.dataPath);
|
|
384
|
+
const wgLaunch = generateSandbox({
|
|
385
|
+
packageRoot: t.packageRoot,
|
|
386
|
+
run: wgRun,
|
|
387
|
+
harnessArgs: [],
|
|
388
|
+
probe: f.probe,
|
|
389
|
+
pcLanguages: ['python', 'rust', 'cpp', 'dotnet'],
|
|
390
|
+
...(wgPrepared ? { vpn: wgPrepared } : {}),
|
|
391
|
+
});
|
|
392
|
+
const wgSession = fs.readFileSync(wgLaunch.sessionPath, 'utf8');
|
|
393
|
+
const wgAll = [];
|
|
394
|
+
const wgWalk = (d) => {
|
|
395
|
+
for (const e of fs.readdirSync(d, { withFileTypes: true })) {
|
|
396
|
+
const p = path.join(d, e.name);
|
|
397
|
+
if (e.isDirectory())
|
|
398
|
+
wgWalk(p);
|
|
399
|
+
else
|
|
400
|
+
wgAll.push(fs.readFileSync(p, 'latin1'));
|
|
401
|
+
}
|
|
402
|
+
};
|
|
403
|
+
wgWalk(wgLaunch.launchPath);
|
|
404
|
+
const hasKey = (text) => text.includes(PRIVATE_KEY) || text.includes(PRESHARED_KEY) || text.includes('PrivPlanted');
|
|
405
|
+
t.check(!hasKey(wgSession) && !wgAll.some(hasKey) && !fs.existsSync(path.join(wgLaunch.launchPath, 'vpn')), 'neither the private key nor the preshared key is in session.json or any file of the launch folder');
|
|
406
|
+
const wgHanded = f.readJson(new RunDir(wgRun.dataPath).secretFile(wgLaunch.launchId));
|
|
407
|
+
t.check((wgHanded.wireguardConfig ?? '').includes(PRIVATE_KEY) && wgHanded.vpn === undefined, 'the config is only in the one-shot file for the sandbox');
|
|
408
|
+
clearSecrets(wgSettings.storage.root, wgRun.dataPath);
|
|
409
|
+
t.check(!fs.existsSync(new RunDir(wgRun.dataPath).secretFile(wgLaunch.launchId)) &&
|
|
410
|
+
vpnNotes(wgSettings.vpn).some((n) => n.includes('WireGuard private key') && n.includes('turn the tunnel off')), 'the launch warns that the agent can read the key and turn the tunnel off');
|
|
411
|
+
},
|
|
412
|
+
};
|