├── .editorconfig ├── .eslintrc.js ├── .gitattributes ├── .github ├── .yamlfmt ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ └── feature_request.yml ├── actions │ ├── get-token │ │ └── action.yaml │ ├── setup-environment │ │ └── action.yaml │ ├── spelling │ │ ├── README.md │ │ ├── advice.md │ │ ├── allow.txt │ │ ├── candidate.patterns │ │ ├── excludes.txt │ │ ├── expect.txt │ │ ├── line_forbidden.patterns │ │ ├── patterns.txt │ │ └── reject.txt │ └── yarn-install │ │ └── action.yaml ├── dependabot.yml └── workflows │ ├── bats.yaml │ ├── bats │ ├── get-tests.py │ ├── sanitize-artifact-name.sh │ └── summarize.mjs │ ├── codeql.yaml │ ├── docker-cli-monitor.yaml │ ├── go-work-sync.yaml │ ├── k3s-versions.yaml │ ├── linux-e2e.yaml │ ├── linux-release.yaml │ ├── macM1-e2e.yaml │ ├── package.yaml │ ├── paths-ignore.yaml │ ├── rddepman.yaml │ ├── rdx-host-api-tests.yaml │ ├── release-merge-to-main.yaml │ ├── scorecard.yml │ ├── screenshot.yaml │ ├── smoke-test.yaml │ ├── smoke-test │ └── smoke-test.sh │ ├── spelling.yml │ ├── test.yaml │ ├── ucmonitor.yaml │ ├── upgrade-generate.yaml │ └── windows-e2e.yaml ├── .gitignore ├── .gitmodules ├── .golangci.yaml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── babel.config.js ├── background.ts ├── bats ├── Makefile ├── README.md ├── scripts │ ├── bats-lint.pl │ └── ghcr-mirror.sh └── tests │ ├── compose │ ├── compose.bats │ └── testdata │ │ ├── Dockerfile.nginx │ │ ├── app │ │ ├── Dockerfile │ │ ├── app.py │ │ └── requirements.txt │ │ ├── compose.yaml │ │ └── nginx.conf │ ├── containers │ ├── allowed-images.bats │ ├── auto-start.bats │ ├── catch-duplicate-api-patterns.bats │ ├── docker-buildx-python3-uname.bats │ ├── factory-reset-containerd-shims.bats │ ├── factory-reset-snapshots.bats │ ├── factory-reset.bats │ ├── host-connectivity.bats │ ├── host-network-ports.bats │ ├── init.bats │ ├── platform.bats │ ├── published-ports.bats │ ├── run-rancher.bats │ ├── split-dns-vpn.bats │ ├── switch-engines.bats │ ├── volumes.bats │ └── wasm.bats │ ├── extensions │ ├── allow-list.bats │ ├── containers.bats │ ├── install.bats │ └── testdata │ │ ├── Dockerfile │ │ ├── Makefile │ │ ├── README.md │ │ ├── basic.json │ │ ├── bin │ │ ├── dummy.go │ │ ├── dummy.sh │ │ └── server.go │ │ ├── compose.yaml │ │ ├── everything.json │ │ ├── extension-icon.svg │ │ ├── host-apis.json │ │ ├── host-binaries.json │ │ ├── missing-icon-file.json │ │ ├── missing-icon.json │ │ ├── ui.json │ │ ├── ui │ │ ├── host-apis.html │ │ └── index.html │ │ ├── vm-compose.json │ │ └── vm-image.json │ ├── helpers │ ├── commands.bash │ ├── defaults.bash │ ├── images.bash │ ├── info.bash │ ├── kubernetes.bash │ ├── kubernetes.bats │ ├── load.bash │ ├── os.bash │ ├── paths.bash │ ├── profile.bash │ ├── snapshots.bash │ ├── utils.bash │ ├── utils.bats │ └── vm.bash │ ├── k8s │ ├── enable-disable-k8s.bats │ ├── foreach-k3s-version.bats │ ├── helm-install-rancher.bats │ ├── port-forwarding.bats │ ├── specify-invalid-k8s-version.bats │ ├── spinkube-npm.bats │ ├── spinkube.bats │ ├── traefik.bats │ ├── up-downgrade-k8s.bats │ ├── wasm.bats │ └── wordpress.bats │ ├── preferences │ ├── move-from-roaming-to-local.bats │ ├── surface-invalid-args.bats │ ├── verify-paths.bats │ └── verify-settings.bats │ ├── profile │ ├── create-profile-output.bats │ ├── deployment.bats │ ├── invalid-locked-k8s-version.bats │ └── wasm.bats │ ├── registry │ └── creds.bats │ ├── snapshots │ ├── create-use-snapshot.bats │ ├── restore-snapshot-after-factory-reset.bats │ ├── test-snapshot-list.bats │ └── test_rdctl_snapshot.bats │ └── utils │ └── spin.bats ├── build ├── electron-publisher-custom.js ├── license.rtf ├── signing-config-mac.yaml ├── signing-config-win.yaml └── wix │ ├── bannrbmp.png │ ├── dialogs.wxs │ ├── dlgbmp.png │ ├── main.wxs │ ├── scope.wxs │ ├── string-overrides.wxl │ ├── verify.wxs │ └── welcome.wxs ├── dev-app-update.yml ├── docs ├── assets │ └── images │ │ └── contributing │ │ ├── e2e-failure-reports.png │ │ └── e2e-summary.png ├── development │ ├── README.md │ ├── env.md │ ├── factory-reset.md │ ├── features.md │ ├── linux-release-process.md │ ├── obs.md │ ├── release-checklist.md │ └── signing.md └── networking │ └── windows │ ├── README.md │ ├── rancher-desktop-guest-agent.md │ └── rancher-desktop-networking.md ├── e2e ├── assets │ └── k8s-deploy-sample │ │ └── nginx-sample-app.yaml ├── backend.e2e.spec.ts ├── config │ └── playwright-config.ts ├── credentials-server.e2e.spec.ts ├── extensions.e2e.spec.ts ├── lockedFields.e2e.spec.ts ├── main.e2e.spec.ts ├── pages │ ├── containers-page.ts │ ├── diagnostics-page.ts │ ├── extensions-page.ts │ ├── images-page.ts │ ├── k8s-page.ts │ ├── nav-page.ts │ ├── portforward-page.ts │ ├── preferences │ │ ├── application.ts │ │ ├── containerEngine.ts │ │ ├── index.ts │ │ ├── kubernetes.ts │ │ ├── virtualMachine.ts │ │ └── wsl.ts │ ├── snapshots-page.ts │ ├── troubleshooting-page.ts │ └── wsl-integrations-page.ts ├── preferences.e2e.spec.ts ├── quit-on-close.e2e.spec.ts ├── rdctl.e2e.spec.ts ├── start-in-background.e2e.spec.ts ├── startup-profiles.e2e.spec.ts ├── utils │ ├── ProfileUtils.ts │ └── TestUtils.ts └── wsl-integrations.e2e.spec.ts ├── go.work ├── jest.config.js ├── nuxt.config.js ├── package.json ├── packaging ├── electron-builder.yml └── linux │ ├── appimage.yml │ ├── flatpak.yaml │ ├── rancher-desktop.appdata.xml │ └── rancher-desktop.spec ├── pkg └── rancher-desktop │ ├── assets │ ├── dependencies.yaml │ ├── extension-data.yaml │ ├── fonts │ │ ├── lato │ │ │ ├── lato-v17-latin-700.woff │ │ │ ├── lato-v17-latin-700.woff2 │ │ │ ├── lato-v17-latin-regular.woff │ │ │ └── lato-v17-latin-regular.woff2 │ │ ├── poppins │ │ │ ├── poppins-v15-latin-300.woff │ │ │ ├── poppins-v15-latin-300.woff2 │ │ │ ├── poppins-v15-latin-500.woff │ │ │ └── poppins-v15-latin-500.woff2 │ │ └── roboto-mono │ │ │ ├── roboto-mono-v13-latin-regular.woff │ │ │ └── roboto-mono-v13-latin-regular.woff2 │ ├── images │ │ ├── kubernetes-black.svg │ │ └── logo.svg │ ├── lima-config.yaml │ ├── networks-config.yaml │ ├── scripts │ │ ├── 10-flannel.conflist │ │ ├── buildkit.confd │ │ ├── buildkit.initd │ │ ├── cert-manager.yaml │ │ ├── configure-allowed-images │ │ ├── docker-credential-rancher-desktop │ │ ├── install-containerd-shims │ │ ├── install-k3s │ │ ├── install-wsl-helpers │ │ ├── k3s-containerd-config.toml │ │ ├── logrotate-k3s │ │ ├── logrotate-lima-guestagent │ │ ├── logrotate-openresty │ │ ├── moproxy.initd │ │ ├── nerdctl │ │ ├── nginx.conf │ │ ├── rancher-desktop-guestagent.initd │ │ ├── service-cri-dockerd.initd │ │ ├── service-k3s.initd │ │ ├── service-wsl-dockerd.initd │ │ ├── spin-operator.yaml │ │ ├── wsl-data.conf │ │ ├── wsl-exec │ │ └── wsl-init │ ├── specs │ │ ├── README.md │ │ └── command-api.yaml │ ├── styles │ │ ├── app.scss │ │ ├── base │ │ │ ├── _basic.scss │ │ │ ├── _color.scss │ │ │ ├── _functions.scss │ │ │ ├── _helpers.scss │ │ │ ├── _mixins.scss │ │ │ ├── _typography.scss │ │ │ └── _variables.scss │ │ ├── fonts │ │ │ ├── _dots.scss │ │ │ ├── _fontstack.scss │ │ │ ├── _icons.scss │ │ │ └── _zerowidthspace.scss │ │ ├── global │ │ │ ├── _button.scss │ │ │ ├── _cards.scss │ │ │ ├── _columns.scss │ │ │ ├── _form.scss │ │ │ ├── _gauges.scss │ │ │ ├── _labeled-input.scss │ │ │ ├── _resource.scss │ │ │ ├── _select.scss │ │ │ ├── _table.scss │ │ │ └── _tooltip.scss │ │ ├── rancher-desktop.scss │ │ ├── themes │ │ │ ├── _dark.scss │ │ │ ├── _light.scss │ │ │ └── _suse.scss │ │ └── vendor │ │ │ ├── normalize.scss │ │ │ ├── vue-js-modal.scss │ │ │ ├── vue-js-modal │ │ │ └── styles.css │ │ │ └── vue-select.scss │ └── translations │ │ ├── en-us.yaml │ │ └── zh-hans.yaml │ ├── backend │ ├── __tests__ │ │ └── k3sHelper.spec.ts │ ├── backend.ts │ ├── backendHelper.ts │ ├── containerClient │ │ ├── __tests__ │ │ │ ├── auth.spec.ts │ │ │ ├── client.spec.ts │ │ │ └── registry.spec.ts │ │ ├── auth.ts │ │ ├── index.ts │ │ ├── mobyClient.ts │ │ ├── nerdctlClient.ts │ │ ├── registry.ts │ │ └── types.ts │ ├── factory.ts │ ├── images │ │ ├── imageFactory.ts │ │ ├── imageProcessor.ts │ │ ├── mobyImageProcessor.ts │ │ └── nerdctlImageProcessor.ts │ ├── k3sHelper.ts │ ├── k8s.ts │ ├── kube │ │ ├── client.ts │ │ ├── lima.ts │ │ └── wsl.ts │ ├── kubeconfig.ts │ ├── lima.ts │ ├── mock.ts │ ├── mock_screenshots.ts │ ├── progressTracker.ts │ ├── steve.ts │ └── wsl.ts │ ├── components │ ├── ActionDropdown.vue │ ├── ActionMenu.vue │ ├── Alert.vue │ ├── BackendProgress.vue │ ├── DashboardOpen.vue │ ├── DiagnosticsBody.vue │ ├── DiagnosticsButtonRun.vue │ ├── EmptyState.vue │ ├── EngineSelector.vue │ ├── ExtensionsError.vue │ ├── ExtensionsUninstalled.vue │ ├── Help.vue │ ├── ImageAddTabs.vue │ ├── Images.vue │ ├── ImagesButtonAdd.vue │ ├── ImagesFormAdd.vue │ ├── ImagesOutputWindow.vue │ ├── ImagesScanResults.vue │ ├── IncompatiblePreferencesAlert.vue │ ├── LoadingIndicator.vue │ ├── MarketplaceCard.vue │ ├── MarketplaceCatalog.vue │ ├── MountTypeSelector.vue │ ├── Nav.vue │ ├── NavIconExtension.vue │ ├── NavItem.vue │ ├── NetworkStatus.vue │ ├── Notifications.vue │ ├── PathManagementSelector.vue │ ├── PortForwarding.vue │ ├── Preferences │ │ ├── Alert.vue │ │ ├── ApplicationBehavior.vue │ │ ├── ApplicationEnvironment.vue │ │ ├── ApplicationGeneral.vue │ │ ├── BodyApplication.vue │ │ ├── BodyContainerEngine.vue │ │ ├── BodyKubernetes.vue │ │ ├── BodyVirtualMachine.vue │ │ ├── BodyWsl.vue │ │ ├── ButtonOpen.vue │ │ ├── ContainerEngineAllowedImages.vue │ │ ├── ContainerEngineGeneral.vue │ │ ├── Help.vue │ │ ├── ModalBody.vue │ │ ├── ModalFooter.vue │ │ ├── ModalHeader.vue │ │ ├── ModalNav.vue │ │ ├── ModalNavItem.vue │ │ ├── VirtualMachineEmulation.vue │ │ ├── VirtualMachineHardware.vue │ │ ├── VirtualMachineVolumes.vue │ │ ├── WslIntegrations.vue │ │ └── WslProxy.vue │ ├── Progress.vue │ ├── RdInput.vue │ ├── RdSelect.vue │ ├── SnapshotCard.vue │ ├── Snapshots.vue │ ├── SnapshotsButtonCreate.vue │ ├── SortableTable │ │ ├── THead.vue │ │ ├── actions.js │ │ ├── filtering.js │ │ ├── grouping.js │ │ ├── index.vue │ │ ├── paging.js │ │ ├── selection.js │ │ └── sorting.js │ ├── StatusBar.vue │ ├── StatusBarItem.vue │ ├── SystemPreferences.vue │ ├── Tabbed │ │ ├── RdTabbed.vue │ │ ├── Tab.vue │ │ └── index.vue │ ├── TelemetryOptIn.vue │ ├── TheTitle.vue │ ├── TroubleshootingLineItem.vue │ ├── UpdateStatus.vue │ ├── Version.vue │ ├── WSLIntegration.vue │ ├── __tests__ │ │ ├── PreferencesButton.spec.ts │ │ ├── StatusBar.spec.ts │ │ ├── SystemPreferences.spec.js │ │ └── UpdateStatus.spec.ts │ └── form │ │ ├── LabeledBadge.vue │ │ ├── LabeledTooltip.vue │ │ ├── RdCheckbox.vue │ │ ├── RdFieldset.vue │ │ ├── RdSlider.vue │ │ ├── SplitButton.vue │ │ ├── TextAreaAutoGrow.vue │ │ ├── TooltipIcon.vue │ │ └── __tests__ │ │ └── SplitButton.spec.ts │ ├── config │ ├── __tests__ │ │ ├── commandLineOptions.spec.ts │ │ ├── settings.spec.ts │ │ └── settingsMigrations.spec.ts │ ├── commandLineOptions.ts │ ├── cookies.js │ ├── emptyStubForJSLinter.js │ ├── help.ts │ ├── private-label.js │ ├── query-params.js │ ├── settings.ts │ ├── settingsImpl.ts │ ├── transientSettings.ts │ └── types.js │ ├── hocs │ ├── README.md │ └── withCredentials.ts │ ├── index.ts │ ├── integrations │ ├── __tests__ │ │ ├── manageLinesInFile.spec.ts │ │ ├── pathManager.spec.ts │ │ ├── unixIntegrationManager.spec.ts │ │ └── windowsIntegrationManager.spec.ts │ ├── integrationManager.ts │ ├── manageLinesInFile.ts │ ├── pathManager.ts │ ├── pathManagerImpl.ts │ ├── unixIntegrationManager.ts │ └── windowsIntegrationManager.ts │ ├── layouts │ ├── default.vue │ ├── dialog.vue │ └── preferences.vue │ ├── main │ ├── __tests__ │ │ ├── deploymentProfiles.spec.ts │ │ └── ipcMain.spec.ts │ ├── commandServer │ │ ├── __tests__ │ │ │ └── settingsValidator.spec.ts │ │ ├── httpCommandServer.ts │ │ └── settingsValidator.ts │ ├── credentialServer │ │ ├── README.md │ │ ├── __tests__ │ │ │ └── credentialUtils.spec.ts │ │ ├── credentialUtils.ts │ │ └── httpCredentialHelperServer.ts │ ├── dashboardServer │ │ ├── index.ts │ │ └── proxyUtils.ts │ ├── deploymentProfiles.ts │ ├── diagnostics │ │ ├── __tests__ │ │ │ ├── diagnostics.spec.ts │ │ │ ├── dockerCliSymlinks.spec.ts │ │ │ └── rdBinInShell.spec.ts │ │ ├── connectedToInternet.ts │ │ ├── diagnostics.ts │ │ ├── dockerCliSymlinks.ts │ │ ├── integrationsWindows.ts │ │ ├── kubeConfigSymlink.ts │ │ ├── kubeContext.ts │ │ ├── kubeVersionsAvailable.ts │ │ ├── limaDarwin.ts │ │ ├── mockForScreenshots.ts │ │ ├── pathManagement.ts │ │ ├── rdBinInShell.ts │ │ ├── testCheckers.ts │ │ ├── types.ts │ │ └── wslFromStore.ts │ ├── extensions │ │ ├── __tests__ │ │ │ ├── extensions.spec.ts │ │ │ └── manager.spec.ts │ │ ├── extensions.ts │ │ ├── index.ts │ │ ├── manager.ts │ │ └── types.ts │ ├── imageEvents.ts │ ├── ipcMain.ts │ ├── mainEvents.ts │ ├── mainmenu.ts │ ├── networking │ │ ├── __tests__ │ │ │ └── mac-ca.spec.ts │ │ ├── cert-parse.ts │ │ ├── index.ts │ │ ├── mac-ca.ts │ │ ├── proxy.ts │ │ └── win-ca.ts │ ├── serverHelper.ts │ ├── snapshots │ │ ├── snapshots.ts │ │ └── types.ts │ ├── tray.ts │ └── update │ │ ├── LonghornProvider.ts │ │ ├── MSIUpdater.ts │ │ ├── __tests__ │ │ └── LonghornProvider.spec.ts │ │ └── index.ts │ ├── middleware │ ├── i18n.js │ └── indexRedirect.js │ ├── mixins │ ├── labeled-form-element.js │ └── vue-select-overrides.js │ ├── nuxt │ ├── App.js │ ├── LICENSE │ ├── client.js │ ├── components │ │ ├── nuxt-build-indicator.vue │ │ ├── nuxt-child.js │ │ ├── nuxt-error.vue │ │ ├── nuxt-link.client.js │ │ ├── nuxt-link.server.js │ │ └── nuxt.js │ ├── cookie-universal-nuxt.js │ ├── empty.js │ ├── index.js │ ├── jsonp.js │ ├── middleware.js │ ├── mixins │ │ ├── fetch.client.js │ │ └── fetch.server.js │ ├── router.scrollBehavior.js │ ├── server.js │ ├── store.js │ ├── utils.js │ └── views │ │ ├── app.template.html │ │ └── error.html │ ├── pages │ ├── Containers.vue │ ├── DenyRoot.vue │ ├── Diagnostics.vue │ ├── Dialog.vue │ ├── Extensions.vue │ ├── FirstRun.vue │ ├── General.vue │ ├── Images.vue │ ├── KubernetesError.vue │ ├── PortForwarding.vue │ ├── Preferences.vue │ ├── Snapshots.vue │ ├── SudoPrompt.vue │ ├── Troubleshooting.vue │ ├── UnmetPrerequisites.vue │ ├── extensions │ │ ├── _root │ │ │ └── _src │ │ │ │ └── _id.vue │ │ └── installed.vue │ ├── images │ │ ├── add.vue │ │ └── scans │ │ │ └── _image-name.vue │ └── snapshots │ │ ├── create.vue │ │ └── dialog.vue │ ├── plugins │ ├── clean-html-directive.js │ ├── directives.js │ ├── extend-router.js │ ├── i18n.js │ ├── shortkey.js │ ├── tooltip.js │ ├── trim-whitespace.js │ ├── v-select.js │ └── vue-js-modal.js │ ├── preload │ ├── README.md │ ├── extensions.ts │ └── index.ts │ ├── product.js │ ├── public │ └── index.html │ ├── router.js │ ├── store │ ├── action-menu.js │ ├── applicationSettings.ts │ ├── credentials.ts │ ├── diagnostics.ts │ ├── extensions.ts │ ├── i18n.js │ ├── imageManager.js │ ├── k8sManager.js │ ├── page.ts │ ├── preferences.ts │ ├── prefs.js │ ├── snapshots.ts │ ├── transientSettings.ts │ └── ts-helpers.ts │ ├── sudo-prompt │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── index.d.ts │ ├── index.js │ ├── linux.png │ ├── macos.png │ ├── package.json │ ├── test-concurrent.js │ ├── test.js │ └── windows.png │ ├── tsconfig.json │ ├── typings │ ├── assets.d.ts │ ├── electron-ipc.d.ts │ ├── linux-ca.d.ts │ ├── shell.d.ts │ ├── shims-vue.d.ts │ ├── store.d.ts │ ├── unix.interface.ts │ └── vue-i18n.ts │ ├── utils │ ├── DownloadProgressListener.ts │ ├── __tests__ │ │ ├── assets │ │ │ └── safeRename │ │ │ │ └── safeRename.tar │ │ ├── childProcess.spec.ts │ │ ├── dockerDirManager.spec.ts │ │ ├── dockerUtils.spec.ts │ │ ├── iterator.spec.ts │ │ ├── kubeVersions.spec.ts │ │ ├── paths.spec.ts │ │ └── safeRename.spec.ts │ ├── array.js │ ├── backgroundProcess.ts │ ├── childProcess.ts │ ├── clone.ts │ ├── commandLine.ts │ ├── dateUtils.ts │ ├── dockerDirManager.ts │ ├── dockerUtils.ts │ ├── environment.ts │ ├── eventEmitter.ts │ ├── fetch.ts │ ├── filters.ts │ ├── imageOutputCuller.js │ ├── ipcRenderer.ts │ ├── iterator.ts │ ├── kubeVersions.ts │ ├── latch.ts │ ├── logging.ts │ ├── networks.ts │ ├── object.js │ ├── osVersion.ts │ ├── paths.ts │ ├── platform.js │ ├── position.js │ ├── processOutputInterpreters │ │ ├── __tests__ │ │ │ ├── assets │ │ │ │ ├── build.txt │ │ │ │ ├── pull.txt │ │ │ │ ├── pull03.txt │ │ │ │ ├── pull2.txt │ │ │ │ ├── push.txt │ │ │ │ ├── trivy-image-metric-server-input.txt │ │ │ │ ├── trivy-image-metric-server-output.txt │ │ │ │ ├── trivy-image-postgres-input.txt │ │ │ │ └── trivy-image-postgres-output.txt │ │ │ ├── image-build-output.spec.js │ │ │ ├── image-non-build-output.spec.js │ │ │ └── trivy-image-output.spec.js │ │ ├── image-build-output.js │ │ ├── image-non-build-output.js │ │ └── trivy-image-output.ts │ ├── protocols.ts │ ├── resources.ts │ ├── safeRename.ts │ ├── shortcuts.ts │ ├── sort.js │ ├── string-encode.ts │ ├── string.js │ ├── stringify.ts │ ├── testUtils │ │ ├── mockResources.ts │ │ └── setupElectron.ts │ ├── typeUtils.ts │ ├── units.js │ ├── version.ts │ └── wslVersion.ts │ ├── vue.config.js │ └── window │ ├── constants.ts │ ├── dashboard.ts │ ├── index.ts │ ├── preferenceConstants.ts │ └── preferences.ts ├── resources ├── darwin │ └── bin │ │ ├── nerdctl │ │ └── spin ├── icons │ ├── containerd-icon-color.png │ ├── issue-opened-16.png │ ├── issue-opened-16.svg │ ├── issue-opened-16@2x.png │ ├── kubernetes-icon-black-orig.png │ ├── kubernetes-icon-black.png │ ├── kubernetes-icon-color-orig.png │ ├── kubernetes-icon-color.png │ ├── logo-square-512.png │ ├── logo-square-bw.png │ ├── logo-square-bw@1.25x.png │ ├── logo-square-bw@1.5x.png │ ├── logo-square-bw@2.png │ ├── logo-square-red.png │ ├── logo-square-red@1.25x.png │ ├── logo-square-red@1.5x.png │ ├── logo-square-red@2x.png │ ├── logo-square.png │ ├── logo-square@1.25x.png │ ├── logo-square@1.5x.png │ ├── logo-square@2x.png │ ├── logo-tray-Template@2x.png │ ├── logo-tray-error-Template@2x.png │ ├── logo-tray-starting-Template@2x.png │ ├── logo-tray-stopped-Template@2x.png │ ├── logo-tray-stopping-Template@2x.png │ └── mac-icon.png ├── k3s-versions.json ├── linux │ └── bin │ │ ├── nerdctl │ │ └── spin └── setup-spin ├── screenshots ├── README.md ├── Screenshots.ts ├── extensions │ └── logs-explorer-0.2.2.png ├── playwright-config.ts ├── screenshot.ps1 ├── screenshots.e2e.spec.ts └── test-data │ ├── containers.ts │ ├── preferences.ts │ └── snapshots.ts ├── scripts ├── assets │ ├── extension-data.yaml │ └── options.go.templ ├── build.ts ├── check-api-schema.ts ├── dependencies │ ├── go-source.ts │ ├── lima.ts │ ├── moby-openapi.ts │ ├── sudo-prompt.ts │ ├── tar-archives.ts │ ├── tools.ts │ ├── wix.ts │ └── wsl.ts ├── dev.ts ├── docker-cli-monitor.ts ├── e2e.ts ├── extension-data.ts ├── generateCliCode.ts ├── go-license-check.sh ├── go.mod ├── go.sum ├── install-latest-ci.sh ├── k3s-versions.go ├── k3s-versions.sh ├── lib │ ├── build-utils.ts │ ├── dependencies.ts │ ├── download.ts │ ├── extension-data.ts │ ├── installer-win32-gen.tsx │ ├── installer-win32.tsx │ ├── sign-macos.ts │ └── sign-win32.ts ├── lint-go.ts ├── node-license-check.sh ├── package.ts ├── populate-update-server.ts ├── postinstall.ts ├── rddepman.ts ├── release-merge-to-main.ts ├── sign.ts ├── simple_process.ts ├── spelling.sh ├── ts-wrapper.js ├── unreleased-change-monitor.ts ├── windows-setup.ps1 ├── windows │ ├── generate-nerdctl-stub.ps1 │ ├── install-wsl.ps1 │ ├── restart-helpers.ps1 │ ├── sudo-install-wsl.ps1 │ └── uninstall-wsl.ps1 └── wix.ts ├── src ├── go │ ├── docker-credential-none │ │ ├── dcnone │ │ │ ├── dcnone.go │ │ │ ├── dcnone_test.go │ │ │ └── helpers.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── main.go │ ├── extension-proxy │ │ ├── README.md │ │ ├── go.mod │ │ └── main.go │ ├── guestagent │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── pkg │ │ │ ├── containerd │ │ │ ├── events_linux.go │ │ │ └── events_stub.go │ │ │ ├── docker │ │ │ └── events.go │ │ │ ├── forwarder │ │ │ ├── forwarder.go │ │ │ ├── serviceapi.go │ │ │ └── wslproxy.go │ │ │ ├── iptables │ │ │ ├── iptables.go │ │ │ ├── iptables_test.go │ │ │ └── scanner.go │ │ │ ├── kube │ │ │ ├── servicewatcher_linux.go │ │ │ ├── watcher_linux.go │ │ │ └── watcher_stub.go │ │ │ ├── procnet │ │ │ ├── scanner_linux.go │ │ │ └── scanner_stub.go │ │ │ ├── tracker │ │ │ ├── apitracker.go │ │ │ ├── apitracker_test.go │ │ │ ├── portstorage.go │ │ │ └── tracker.go │ │ │ ├── types │ │ │ ├── README.md │ │ │ └── portmapping.go │ │ │ └── utils │ │ │ └── utils.go │ ├── mock-wsl │ │ ├── README.md │ │ ├── go.mod │ │ ├── go.sum │ │ ├── lock_file_other.go │ │ ├── lock_file_windows.go │ │ ├── mock-wsl.go │ │ └── schema.json │ ├── nerdctl-stub │ │ ├── README.md │ │ ├── command_handlers.go │ │ ├── command_handlers_test.go │ │ ├── debugging.go │ │ ├── debugging_stub.go │ │ ├── generate │ │ │ ├── README.md │ │ │ ├── go.mod │ │ │ ├── go.sum │ │ │ ├── main_linux.go │ │ │ └── main_stub.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ ├── main_linux.go │ │ ├── main_shared.go │ │ ├── main_shared_test.go │ │ ├── main_unsupported.go │ │ ├── main_windows.go │ │ ├── nerdctl_commands_generated.go │ │ ├── parse_args.go │ │ └── parse_args_test.go │ ├── networking │ │ ├── .github │ │ │ └── workflows │ │ │ │ ├── go.yaml │ │ │ │ └── release.yaml │ │ ├── .gitignore │ │ ├── LICENSE │ │ ├── Makefile │ │ ├── README.md │ │ ├── cmd │ │ │ ├── host │ │ │ │ ├── config_windows.go │ │ │ │ └── switch_windows.go │ │ │ ├── network │ │ │ │ └── setup_linux.go │ │ │ ├── proxy │ │ │ │ └── wsl_integration_linux.go │ │ │ └── vm │ │ │ │ └── switch_linux.go │ │ ├── go.mod │ │ ├── go.sum │ │ └── pkg │ │ │ ├── config │ │ │ └── config.go │ │ │ ├── log │ │ │ └── log.go │ │ │ ├── portproxy │ │ │ ├── server.go │ │ │ └── server_test.go │ │ │ ├── utils │ │ │ └── pipe.go │ │ │ └── vsock │ │ │ ├── conn_windows.go │ │ │ ├── constants.go │ │ │ └── handshake_windows.go │ ├── rdctl │ │ ├── README.md │ │ ├── cmd │ │ │ ├── api.go │ │ │ ├── createProfile.go │ │ │ ├── extension.go │ │ │ ├── extensionInstall.go │ │ │ ├── extensionList.go │ │ │ ├── extensionUninstall.go │ │ │ ├── factoryReset.go │ │ │ ├── internal.go │ │ │ ├── internalProcess.go │ │ │ ├── internalProcessWaitKill.go │ │ │ ├── listSettings.go │ │ │ ├── paths.go │ │ │ ├── root.go │ │ │ ├── set.go │ │ │ ├── setup.go │ │ │ ├── shell.go │ │ │ ├── shutdown.go │ │ │ ├── snapshot.go │ │ │ ├── snapshotCreate.go │ │ │ ├── snapshotDelete.go │ │ │ ├── snapshotList.go │ │ │ ├── snapshotList_test.go │ │ │ ├── snapshotRestore.go │ │ │ ├── snapshotUnlock.go │ │ │ ├── start.go │ │ │ └── version.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ └── pkg │ │ │ ├── autostart │ │ │ ├── autostart_darwin.go │ │ │ ├── autostart_linux.go │ │ │ └── autostart_windows.go │ │ │ ├── client │ │ │ ├── client.go │ │ │ ├── handle_unix.go │ │ │ ├── handle_windows.go │ │ │ └── utils.go │ │ │ ├── config │ │ │ └── config.go │ │ │ ├── directories │ │ │ ├── directories.go │ │ │ ├── directories_test.go │ │ │ ├── directories_windows.go │ │ │ ├── directories_windows_test.go │ │ │ ├── empty.go │ │ │ └── lima_home.go │ │ │ ├── factoryreset │ │ │ ├── delete_data.go │ │ │ ├── delete_data_darwin.go │ │ │ ├── delete_data_linux.go │ │ │ ├── delete_data_unix.go │ │ │ ├── delete_data_unix_test.go │ │ │ ├── delete_data_windows.go │ │ │ ├── factory_reset_unix.go │ │ │ └── factory_reset_windows.go │ │ │ ├── lima │ │ │ └── name.go │ │ │ ├── lock │ │ │ ├── lock.go │ │ │ └── mock.go │ │ │ ├── options │ │ │ └── generated │ │ │ │ └── doc.go │ │ │ ├── paths │ │ │ ├── paths.go │ │ │ ├── paths_darwin.go │ │ │ ├── paths_darwin_test.go │ │ │ ├── paths_linux.go │ │ │ ├── paths_linux_test.go │ │ │ ├── paths_test.go │ │ │ ├── paths_unix.go │ │ │ ├── paths_windows.go │ │ │ └── paths_windows_test.go │ │ │ ├── plist │ │ │ ├── plist.go │ │ │ └── plist_test.go │ │ │ ├── process │ │ │ ├── process_darwin.go │ │ │ ├── process_linux.go │ │ │ ├── process_test.go │ │ │ ├── process_unix.go │ │ │ ├── process_windows.go │ │ │ └── process_windows_test.go │ │ │ ├── reg │ │ │ ├── reg.go │ │ │ └── reg_test.go │ │ │ ├── runner │ │ │ ├── runner.go │ │ │ └── runner_test.go │ │ │ ├── shutdown │ │ │ └── shutdown.go │ │ │ ├── snapshot │ │ │ ├── copyFile_darwin.go │ │ │ ├── copyFile_linux.go │ │ │ ├── manager.go │ │ │ ├── manager_test.go │ │ │ ├── manager_unix_test.go │ │ │ ├── manager_windows_test.go │ │ │ ├── snapshot.go │ │ │ ├── snapshotter.go │ │ │ ├── snapshotter_unix.go │ │ │ └── snapshotter_windows.go │ │ │ ├── utils │ │ │ └── utils.go │ │ │ ├── version │ │ │ └── version.go │ │ │ └── wsl │ │ │ ├── doc.go │ │ │ ├── mock_windows.go │ │ │ ├── names.go │ │ │ └── wsl_windows.go │ ├── spin-stub │ │ ├── README.md │ │ ├── go.mod │ │ └── main.go │ └── wsl-helper │ │ ├── .gitignore │ │ ├── cmd │ │ ├── certificates_windows.go │ │ ├── dockerproxy.go │ │ ├── dockerproxy_kill_linux.go │ │ ├── dockerproxy_serve_linux.go │ │ ├── dockerproxy_serve_windows.go │ │ ├── dockerproxy_start.go │ │ ├── enum.go │ │ ├── k3s.go │ │ ├── k3s_kubeconfig.go │ │ ├── kubeconfig.go │ │ ├── process_kill_windows.go │ │ ├── process_spawn_windows.go │ │ ├── process_windows.go │ │ ├── root.go │ │ ├── version.go │ │ ├── wsl.go │ │ ├── wsl_info.go │ │ ├── wsl_integration_docker_linux.go │ │ ├── wsl_integration_linux.go │ │ └── wsl_integration_state_linux.go │ │ ├── go.mod │ │ ├── go.sum │ │ ├── main.go │ │ ├── pkg │ │ ├── certificates │ │ │ ├── certificates_windows.go │ │ │ └── certificates_windows_test.go │ │ ├── dockerproxy │ │ │ ├── defaults.go │ │ │ ├── generate.go │ │ │ ├── models │ │ │ │ └── doc.go │ │ │ ├── mungers │ │ │ │ ├── containers_create_linux.go │ │ │ │ ├── containers_create_linux_test.go │ │ │ │ ├── containers_create_windows.go │ │ │ │ ├── containers_create_windows_test.go │ │ │ │ ├── doc.go │ │ │ │ ├── helpers.go │ │ │ │ └── helpers_linux.go │ │ │ ├── platform │ │ │ │ ├── hyperv.go │ │ │ │ ├── hyperv_test.go │ │ │ │ ├── serve_linux.go │ │ │ │ ├── serve_windows.go │ │ │ │ ├── serve_windows_test.go │ │ │ │ ├── vsock_linux.go │ │ │ │ └── wsl_mountpoint_linux.go │ │ │ ├── serve.go │ │ │ ├── start.go │ │ │ ├── swagger-configuration.yaml │ │ │ └── util │ │ │ │ ├── pipe.go │ │ │ │ ├── pipe_test.go │ │ │ │ └── reverse_proxy.go │ │ ├── integration │ │ │ ├── docker_linux.go │ │ │ ├── docker_linux_test.go │ │ │ └── integration.go │ │ ├── process │ │ │ ├── imports_windows.go │ │ │ ├── kill_others_linux.go │ │ │ ├── kill_windows.go │ │ │ ├── run_windows.go │ │ │ └── wait_windows.go │ │ ├── version │ │ │ └── version.go │ │ └── wsl-utils │ │ │ ├── doc.go │ │ │ ├── install_windows.go │ │ │ ├── run_windows.go │ │ │ ├── version_windows.go │ │ │ └── version_windows_test.go │ │ └── wix │ │ ├── check_windows.go │ │ ├── doc.go │ │ ├── helpers_windows.go │ │ ├── imports_windows.go │ │ ├── install_windows.go │ │ └── main_windows.go └── sudo-prompt │ ├── build-sudo-prompt │ ├── sudo-prompt-script │ └── sudo-prompt.applescript ├── tsconfig.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig helps developers define and maintain consistent 2 | # coding styles between different editors and IDEs 3 | # editorconfig.org 4 | 5 | root = true 6 | 7 | [*] 8 | charset = utf-8 9 | end_of_line = lf 10 | indent_size = 2 11 | indent_style = space 12 | insert_final_newline = true 13 | quote_type = single 14 | trim_trailing_whitespace = true 15 | 16 | [*.go] 17 | indent_style = tab 18 | 19 | [*.{sh,bash,bats}] 20 | indent_size = 4 21 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # All Linux scripts should have LF line endings 2 | # But only text files should be changed (not any binaries / images / etc.) 3 | resources/linux/** text=auto eol=lf 4 | resources/setup-spin text=auto eol=lf 5 | pkg/rancher-desktop/assets/scripts/** text=auto eol=lf 6 | -------------------------------------------------------------------------------- /.github/.yamlfmt: -------------------------------------------------------------------------------- 1 | formatter: 2 | indentless_arrays: true 3 | retain_line_breaks: true 4 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: true 2 | contact_links: 3 | - name: Ask a question (GitHub Discussions) 4 | url: https://github.com/rancher-sandbox/rancher-desktop/discussions 5 | about: We use GitHub Discussions for questions and GitHub issues for tracking bug reports and feature requests 6 | - name: Chat with Rancher Desktop users and developers 7 | url: https://slack.rancher.io/ 8 | about: We hang out in the `#rancher-desktop` channel in the Rancher Users slack 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: "Suggest a feature or idea to Rancher Desktop." 3 | labels: ["kind/enhancement"] 4 | body: 5 | - type: textarea 6 | attributes: 7 | label: Problem Description 8 | description: "A clear and concise description of what enhancement you'd like." 9 | validations: 10 | required: true 11 | - type: textarea 12 | attributes: 13 | label: Proposed Solution 14 | description: "Describe the solution you'd like in a clear and concise manner." 15 | validations: 16 | required: true 17 | - type: textarea 18 | attributes: 19 | label: Additional Information 20 | description: "Add any other context/information about the problem here." 21 | validations: 22 | required: false 23 | -------------------------------------------------------------------------------- /.github/actions/spelling/allow.txt: -------------------------------------------------------------------------------- 1 | emoji 2 | github 3 | https 4 | passwordless 5 | ssh 6 | ubuntu 7 | workarounds 8 | -------------------------------------------------------------------------------- /.github/actions/spelling/reject.txt: -------------------------------------------------------------------------------- 1 | ^attache$ 2 | ^bellow$ 3 | benefitting 4 | occurences? 5 | ^dependan.* 6 | ^oer$ 7 | Sorce 8 | ^[Ss]pae.* 9 | ^untill$ 10 | ^untilling$ 11 | ^wether.* 12 | -------------------------------------------------------------------------------- /.github/workflows/docker-cli-monitor.yaml: -------------------------------------------------------------------------------- 1 | name: Check for new releases of docker/cli 2 | on: 3 | schedule: 4 | - cron: '55 8 * * *' 5 | workflow_dispatch: {} 6 | 7 | jobs: 8 | check-for-token: 9 | outputs: 10 | has-token: ${{ steps.calc.outputs.HAS_SECRET }} 11 | runs-on: ubuntu-latest 12 | steps: 13 | - id: calc 14 | run: echo "HAS_SECRET=${HAS_SECRET}" >> "${GITHUB_OUTPUT}" 15 | env: 16 | HAS_SECRET: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW != '' }} 17 | 18 | check-docker-cli: 19 | needs: check-for-token 20 | if: needs.check-for-token.outputs.has-token == 'true' 21 | runs-on: ubuntu-latest 22 | permissions: 23 | issues: write 24 | steps: 25 | 26 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | with: 28 | fetch-depth: 0 29 | 30 | - uses: ./.github/actions/yarn-install 31 | 32 | - run: yarn dcmonitor 33 | env: 34 | GITHUB_CREATE_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }} 35 | GITHUB_TOKEN: ${{ github.token }} 36 | -------------------------------------------------------------------------------- /.github/workflows/rddepman.yaml: -------------------------------------------------------------------------------- 1 | name: Update external dependencies 2 | on: 3 | schedule: 4 | - cron: '23 8 * * *' 5 | workflow_dispatch: {} 6 | 7 | permissions: 8 | contents: write 9 | pull-requests: write 10 | 11 | jobs: 12 | check-for-token: 13 | outputs: 14 | has-token: ${{ steps.calc.outputs.HAS_SECRET }} 15 | runs-on: ubuntu-latest 16 | steps: 17 | - id: calc 18 | run: echo "HAS_SECRET=${HAS_SECRET}" >> "${GITHUB_OUTPUT}" 19 | env: 20 | HAS_SECRET: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW != '' }} 21 | 22 | check-update-versions: 23 | needs: check-for-token 24 | if: needs.check-for-token.outputs.has-token == 'true' 25 | runs-on: ubuntu-latest 26 | steps: 27 | 28 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 29 | with: 30 | fetch-depth: 0 31 | 32 | - uses: ./.github/actions/yarn-install 33 | 34 | - run: yarn rddepman 35 | env: 36 | GITHUB_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }} 37 | -------------------------------------------------------------------------------- /.github/workflows/release-merge-to-main.yaml: -------------------------------------------------------------------------------- 1 | name: "Release: Merge to main" 2 | 3 | on: 4 | release: 5 | types: 6 | - created 7 | - published 8 | - released 9 | 10 | concurrency: 11 | group: ${{ github.workflow }}-${{ github.ref }} 12 | cancel-in-progress: true 13 | 14 | permissions: {} 15 | 16 | jobs: 17 | check-for-token: 18 | outputs: 19 | has-token: ${{ steps.calc.outputs.HAS_SECRET }} 20 | runs-on: ubuntu-latest 21 | steps: 22 | - id: calc 23 | run: echo "HAS_SECRET=${HAS_SECRET}" >> "${GITHUB_OUTPUT}" 24 | env: 25 | HAS_SECRET: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW != '' }} 26 | 27 | create-pr: 28 | needs: check-for-token 29 | if: needs.check-for-token.outputs.has-token == 'true' 30 | runs-on: ubuntu-latest 31 | permissions: 32 | contents: write 33 | steps: 34 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 35 | - uses: ./.github/actions/yarn-install 36 | - run: node scripts/ts-wrapper.js scripts/release-merge-to-main.ts 37 | env: 38 | GITHUB_WRITE_TOKEN: ${{ github.token }} 39 | GITHUB_PR_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }} 40 | -------------------------------------------------------------------------------- /.github/workflows/ucmonitor.yaml: -------------------------------------------------------------------------------- 1 | name: Check for unreleased changes 2 | on: 3 | schedule: 4 | - cron: '48 8 * * *' 5 | workflow_dispatch: {} 6 | 7 | permissions: 8 | issues: write 9 | 10 | jobs: 11 | check-for-token: 12 | outputs: 13 | has-token: ${{ steps.calc.outputs.HAS_SECRET }} 14 | runs-on: ubuntu-latest 15 | steps: 16 | - id: calc 17 | run: echo "HAS_SECRET=${HAS_SECRET}" >> "${GITHUB_OUTPUT}" 18 | env: 19 | HAS_SECRET: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW != '' }} 20 | 21 | check-unreleased-changes: 22 | needs: check-for-token 23 | if: needs.check-for-token.outputs.has-token == 'true' 24 | runs-on: ubuntu-latest 25 | steps: 26 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | with: 28 | fetch-depth: 0 29 | 30 | - uses: ./.github/actions/yarn-install 31 | 32 | - run: yarn ucmonitor 33 | env: 34 | GITHUB_TOKEN: ${{ secrets.RUN_WORKFLOW_FROM_WORKFLOW }} 35 | -------------------------------------------------------------------------------- /.github/workflows/windows-e2e.yaml: -------------------------------------------------------------------------------- 1 | name: e2e tests on Windows 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches-ignore: 7 | - 'dependabot/**' 8 | pull_request: {} 9 | 10 | defaults: 11 | run: 12 | shell: powershell 13 | jobs: 14 | check-paths: 15 | uses: ./.github/workflows/paths-ignore.yaml 16 | e2e-tests: 17 | needs: check-paths 18 | if: needs.check-paths.outputs.should-run == 'true' 19 | timeout-minutes: 90 20 | runs-on: windows-latest 21 | steps: 22 | - uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 23 | with: 24 | persist-credentials: false 25 | - uses: ./.github/actions/setup-environment 26 | - uses: ./.github/actions/yarn-install 27 | - name: Run e2e Tests 28 | run: yarn test:e2e 29 | env: 30 | RD_DEBUG_ENABLED: '1' 31 | - name: Upload failure reports 32 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 33 | if: always() 34 | with: 35 | name: e2etest-artifacts 36 | path: ./e2e/reports/* 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.exe 2 | /bats/bats.tar.gz 3 | /bats/bin/ 4 | /bats/logs/ 5 | /coverage/ 6 | /dist/ 7 | /e2e/reports/ 8 | /go.work.sum 9 | /node_modules/ 10 | /pkg/rancher-desktop/nuxt/ 11 | /resources/cert-manager* 12 | /resources/darwin/ 13 | /resources/host/ 14 | /resources/linux/* 15 | !/resources/linux/rancher-desktop.desktop 16 | /resources/preload.js* 17 | /resources/rancher-dashboard/ 18 | /resources/rdx-proxy.tar 19 | /resources/spin-operator* 20 | /resources/win32/ 21 | /screenshots/output/ 22 | /src/go/rdctl/pkg/options/generated/*.go 23 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "bats/bats-core"] 2 | path = bats/bats-core 3 | url = https://github.com/rancher-sandbox/bats-core.git 4 | branch = master 5 | [submodule "bats/bats-assert"] 6 | path = bats/bats-assert 7 | url = https://github.com/rancher-sandbox/bats-assert.git 8 | branch = master 9 | [submodule "bats/bats-support"] 10 | path = bats/bats-support 11 | url = https://github.com/rancher-sandbox/bats-support.git 12 | branch = master 13 | [submodule "bats/bats-file"] 14 | path = bats/bats-file 15 | url = https://github.com/rancher-sandbox/bats-file.git 16 | branch = master 17 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | const packageJson = require('./package.json'); 2 | 3 | const electronVersion = parseInt(/\d+/.exec(packageJson.devDependencies.electron), 10); 4 | 5 | module.exports = { 6 | presets: [ 7 | [ 8 | '@vue/cli-plugin-babel/preset', 9 | { useBuiltIns: false }, 10 | ], 11 | [ 12 | '@babel/preset-env', 13 | { 14 | targets: { 15 | node: 'current', 16 | electron: electronVersion, 17 | }, 18 | }, 19 | ], 20 | ], 21 | env: { 22 | test: { 23 | presets: [ 24 | ['@babel/env', 25 | { targets: { node: 'current' } }, 26 | ], 27 | ], 28 | }, 29 | }, 30 | plugins: [ 31 | '@babel/plugin-proposal-class-properties', 32 | '@babel/plugin-proposal-nullish-coalescing-operator', 33 | '@babel/plugin-proposal-optional-chaining', 34 | '@babel/plugin-proposal-private-methods', 35 | '@babel/plugin-proposal-private-property-in-object', 36 | ], 37 | }; 38 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/Dockerfile.nginx: -------------------------------------------------------------------------------- 1 | ARG IMAGE_NGINX 2 | FROM ${IMAGE_NGINX} 3 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/app/Dockerfile: -------------------------------------------------------------------------------- 1 | ARG IMAGE_PYTHON=python:3.9-slim 2 | FROM ${IMAGE_PYTHON} 3 | 4 | WORKDIR /app 5 | 6 | COPY requirements.txt . 7 | RUN pip install --no-cache-dir -r requirements.txt 8 | 9 | COPY . . 10 | 11 | CMD ["python", "app.py"] 12 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/app/app.py: -------------------------------------------------------------------------------- 1 | from flask import Flask 2 | app = Flask(__name__) 3 | 4 | @app.route('/') 5 | def hello(): 6 | return "Hello World!" 7 | 8 | if __name__ == '__main__': 9 | app.run(host='0.0.0.0', port=8000) 10 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/app/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/compose.yaml: -------------------------------------------------------------------------------- 1 | services: 2 | nginx: 3 | container_name: nginx 4 | build: 5 | args: 6 | - IMAGE_NGINX 7 | dockerfile: Dockerfile.nginx 8 | volumes: 9 | - ./nginx.conf:/etc/nginx/nginx.conf 10 | ports: 11 | - '127.0.0.1:8080:80' 12 | web: 13 | build: 14 | args: 15 | - IMAGE_PYTHON 16 | context: app 17 | # flask requires SIGINT to stop gracefully 18 | # (default stop signal from Compose is SIGTERM) 19 | stop_signal: SIGINT 20 | ports: 21 | - '8000:8000' 22 | -------------------------------------------------------------------------------- /bats/tests/compose/testdata/nginx.conf: -------------------------------------------------------------------------------- 1 | worker_processes 1; 2 | 3 | error_log stderr info; 4 | 5 | events { 6 | worker_connections 1024; 7 | } 8 | 9 | http { 10 | include mime.types; 11 | sendfile on; 12 | proxy_read_timeout 5s; 13 | 14 | server { 15 | listen 80; 16 | server_name localhost; 17 | 18 | # Serve the default nginx welcome page 19 | location / { 20 | root /usr/share/nginx/html; 21 | index index.html; 22 | } 23 | 24 | # Proxy requests to /app to the backend service 25 | location /app { 26 | proxy_pass http://host.docker.internal:8000/; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /bats/tests/containers/catch-duplicate-api-patterns.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | RD_USE_IMAGE_ALLOW_LIST=true 3 | 4 | @test 'catch attempts to add duplicate patterns via the API with enabled on' { 5 | factory_reset 6 | start_kubernetes 7 | wait_for_kubelet 8 | wait_for_container_engine 9 | 10 | run update_allowed_patterns true "$IMAGE_NGINX" "$IMAGE_BUSYBOX" "$IMAGE_RUBY" "$IMAGE_BUSYBOX" 11 | assert_failure 12 | assert_output --partial $"field \"containerEngine.allowedImages.patterns\" has duplicate entries: \"$IMAGE_BUSYBOX\"" 13 | } 14 | 15 | @test 'catch attempts to add duplicate patterns via the API with enabled off' { 16 | run update_allowed_patterns false "$IMAGE_NGINX" "$IMAGE_BUSYBOX" "$IMAGE_RUBY" "$IMAGE_BUSYBOX" 17 | assert_failure 18 | assert_output --partial $"field \"containerEngine.allowedImages.patterns\" has duplicate entries: \"$IMAGE_BUSYBOX\"" 19 | } 20 | -------------------------------------------------------------------------------- /bats/tests/containers/factory-reset-containerd-shims.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | BOGUS_SHIM="${PATH_CONTAINERD_SHIMS}/containerd-shim-bogus-v1" 4 | 5 | local_setup_file() { 6 | RD_USE_RAMDISK=false # interferes with deleting $PATH_APP_HOME 7 | 8 | delete_all_snapshots 9 | rm -rf "$PATH_CONTAINERD_SHIMS" 10 | } 11 | 12 | local_teardown_file() { 13 | rm -rf "$PATH_CONTAINERD_SHIMS" 14 | } 15 | 16 | @test 'factory reset' { 17 | # On Windows the cache directory is under PATH_APP_HOME. 18 | factory_reset --remove-kubernetes-cache=true 19 | assert_not_exists "$PATH_APP_HOME" 20 | } 21 | 22 | @test 'factory reset will not remove any shims' { 23 | assert_not_exists "$PATH_CONTAINERD_SHIMS" 24 | create_file "$BOGUS_SHIM" <<<'' 25 | factory_reset 26 | assert_exists "$BOGUS_SHIM" 27 | assert_exists "$PATH_APP_HOME" 28 | } 29 | 30 | @test 'factory reset will remove empty shim directory' { 31 | rm "$BOGUS_SHIM" 32 | factory_reset 33 | assert_not_exists "$PATH_CONTAINERD_SHIMS" 34 | assert_not_exists "$PATH_APP_HOME" 35 | } 36 | -------------------------------------------------------------------------------- /bats/tests/containers/factory-reset-snapshots.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | local_setup_file() { 4 | RD_USE_RAMDISK=false # interferes with deleting $PATH_APP_HOME 5 | } 6 | 7 | @test 'factory reset' { 8 | delete_all_snapshots 9 | rm -rf "$PATH_CONTAINERD_SHIMS" 10 | # On Windows the cache directory is under PATH_APP_HOME. 11 | factory_reset --remove-kubernetes-cache=true 12 | } 13 | 14 | @test 'Start up Rancher Desktop with a snapshots subdirectory' { 15 | start_container_engine 16 | wait_for_container_engine 17 | wait_for_backend 18 | } 19 | 20 | @test "Verify the snapshot dir isn't deleted on factory-reset" { 21 | rdctl shutdown 22 | rdctl snapshot create shortlived-snapshot 23 | factory_reset --remove-kubernetes-cache=true 24 | assert_not_exists "$PATH_APP_HOME/rd-engine.json" 25 | assert_exists "$PATH_SNAPSHOTS" 26 | run ls -A "$PATH_SNAPSHOTS" 27 | assert_output 28 | } 29 | 30 | @test 'Verify factory-reset deletes an empty snapshots directory' { 31 | rdctl snapshot delete shortlived-snapshot 32 | factory_reset --remove-kubernetes-cache=true 33 | assert_not_exists "$PATH_APP_HOME" 34 | } 35 | -------------------------------------------------------------------------------- /bats/tests/containers/host-connectivity.bats: -------------------------------------------------------------------------------- 1 | # bats file_tags=opensuse 2 | 3 | load '../helpers/load' 4 | 5 | @test 'factory reset' { 6 | factory_reset 7 | } 8 | 9 | @test 'start container engine' { 10 | start_container_engine 11 | wait_for_container_engine 12 | } 13 | 14 | verify_host_connectivity() { 15 | run ctrctl run --rm "$IMAGE_BUSYBOX" timeout -s INT 10 ping -c 5 "$1" 16 | assert_success 17 | assert_output --partial "5 packets transmitted, 5 packets received, 0% packet loss" 18 | } 19 | 20 | @test 'ping host.docker.internal from a container' { 21 | verify_host_connectivity "host.docker.internal" 22 | } 23 | 24 | @test 'ping host.rancher-desktop.internal from a container' { 25 | verify_host_connectivity "host.rancher-desktop.internal" 26 | } 27 | -------------------------------------------------------------------------------- /bats/tests/containers/init.bats: -------------------------------------------------------------------------------- 1 | # verify that running a container with --init is working 2 | # bats file_tags=opensuse 3 | 4 | load '../helpers/load' 5 | 6 | @test 'factory reset' { 7 | factory_reset 8 | } 9 | 10 | @test 'start container engine' { 11 | start_container_engine 12 | wait_for_container_engine 13 | } 14 | 15 | @test 'run container with init process' { 16 | # BUG BUG BUG 17 | # The following `ctrctl run` command includes the `-i` option to work around a docker 18 | # bug on Windows: https://github.com/rancher-sandbox/rancher-desktop/issues/3239 19 | # It is harmless in other configurations, but should not be required here. 20 | # BUG BUG BUG 21 | run ctrctl run -i --rm --init "$IMAGE_BUSYBOX" ps -ef 22 | assert_success 23 | # PID USER TIME COMMAND 24 | # 1 root 0:00 /sbin/docker-init -- ps -ef 25 | # 1 root 0:00 /sbin/tini -- ps -ef 26 | assert_line --regexp '^ +1 .+ /sbin/(docker-init|tini) -- ps -ef$' 27 | } 28 | -------------------------------------------------------------------------------- /bats/tests/containers/run-rancher.bats: -------------------------------------------------------------------------------- 1 | # bats file_tags=opensuse 2 | 3 | load '../helpers/load' 4 | RD_FILE_RAMDISK_SIZE=12 # We need more disk to run the Rancher image. 5 | 6 | @test 'factory reset' { 7 | factory_reset 8 | } 9 | 10 | @test 'start container engine' { 11 | start_container_engine 12 | wait_for_container_engine 13 | } 14 | 15 | @test 'run rancher' { 16 | local rancher_image 17 | rancher_image="rancher/rancher:$(rancher_image_tag)" 18 | 19 | ctrctl pull "$rancher_image" 20 | ctrctl run --privileged -d --restart=no -p 8080:80 -p 8443:443 --name rancher "$rancher_image" 21 | } 22 | 23 | @test 'verify rancher' { 24 | local max_tries=9 25 | if [[ -n ${CI:-} ]]; then 26 | max_tries=30 27 | fi 28 | run try --max $max_tries --delay 10 curl --insecure --silent --show-error "https://localhost:8443/dashboard/auth/login" 29 | assert_success 30 | assert_output --partial "Rancher Dashboard" 31 | run ctrctl logs rancher 32 | assert_success 33 | assert_output --partial "Bootstrap Password:" 34 | } 35 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.opensuse.org/opensuse/bci/golang:stable AS builder 2 | WORKDIR /usr/src/app 3 | COPY bin/dummy.go . 4 | ENV GOOS=windows 5 | RUN go build -o /dummy.exe -ldflags '-s -w' dummy.go 6 | 7 | FROM registry.opensuse.org/opensuse/bci/golang:stable AS server-builder 8 | WORKDIR /usr/src/app 9 | COPY bin/server.go . 10 | ENV GOOS=linux 11 | RUN go build -o /server -ldflags '-s -w' server.go 12 | 13 | FROM registry.opensuse.org/opensuse/bci/bci-minimal 14 | ARG variant=basic 15 | 16 | ADD ${variant}.json /metadata.json 17 | ADD extension-icon.svg /extension-icon.svg 18 | ADD ui /ui/ 19 | ADD bin /bin/ 20 | COPY --from=builder /dummy.exe /bin/ 21 | COPY --from=server-builder /server /bin/ 22 | ADD compose.yaml /compose/ 23 | RUN ln -s does/not/exist /compose/dangling-link 24 | RUN ln -s compose.yaml /compose/link 25 | 26 | ENTRYPOINT ["/bin/server"] 27 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/Makefile: -------------------------------------------------------------------------------- 1 | all: \ 2 | image-basic image-missing-icon image-ui \ 3 | image-vm-image image-vm-compose image-host-binaries image-host-apis 4 | 5 | TOOL ?= docker 6 | NAMESPACE := $(if $(filter %nerdctl,${TOOL}),--namespace=rancher-desktop-extensions) 7 | 8 | NAMESPACE = $(if $(filter %nerdctl,${TOOL}),--namespace=rancher-desktop-extensions) 9 | 10 | image-%: 11 | ${TOOL} ${NAMESPACE} build -t rd/extension/$(@:image-%=%) --build-arg variant=$(@:image-%=%) . 12 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/README.md: -------------------------------------------------------------------------------- 1 | This directory contains sample docker extensions. 2 | 3 | ### basic 4 | A basic extension, containing the bare minimum (just an icon). 5 | 6 | ### missing-icon 7 | As above, but even the icon is missing. 8 | 9 | ### missing-icon-file 10 | Like the basic extension, but the icon file specified does not exist. 11 | 12 | ### ui 13 | Presents basic UI. We do not yet test interaction with UI. 14 | 15 | ### vm-image 16 | Contains a docker image to run. 17 | 18 | ### vm-compose 19 | Contains a docker compose file to run. (Not supported.) 20 | 21 | ### host-binaries 22 | Contains binaries to be copied to the host. 23 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/basic.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg" 3 | } 4 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/bin/dummy.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "log" 6 | "os" 7 | "os/exec" 8 | ) 9 | 10 | func main() { 11 | ctx := context.Background() 12 | cmd := exec.CommandContext(ctx, os.Args[1], os.Args[2:]...) 13 | cmd.Stdin = os.Stdin 14 | cmd.Stdout = os.Stdout 15 | cmd.Stderr = os.Stderr 16 | err := cmd.Run() 17 | if exitError, ok := err.(*exec.ExitError); ok { 18 | if exitError.ExitCode() > -1 { 19 | os.Exit(exitError.ExitCode()) 20 | } 21 | } 22 | if err != nil { 23 | log.Fatal(err) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/bin/dummy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | exec "$@" 4 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/compose.yaml: -------------------------------------------------------------------------------- 1 | name: sample-compose 2 | services: 3 | backend-service: 4 | image: "${DESKTOP_PLUGIN_IMAGE}" 5 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/everything.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg", 3 | "host": { 4 | "binaries": [ 5 | { 6 | "darwin": [ 7 | { 8 | "path": "/bin/dummy.sh" 9 | } 10 | ], 11 | "windows": [ 12 | { 13 | "path": "/bin/dummy.exe" 14 | } 15 | ], 16 | "linux": [ 17 | { 18 | "path": "/bin/dummy.sh" 19 | } 20 | ] 21 | } 22 | ] 23 | }, 24 | "ui": { 25 | "dashboard-tab": { 26 | "title": "Sample Extension With Everything", 27 | "root": "/ui", 28 | "src": "index.html", 29 | "backend": { 30 | "socket": "hello.sock" 31 | } 32 | } 33 | }, 34 | "vm": { 35 | "composefile": "/compose/compose.yaml", 36 | "exposes": { 37 | "socket": "hello.sock" 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/extension-icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/host-apis.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": "This is used to do manual testing of various host APIs", 3 | "icon": "extension-icon.svg", 4 | "ui": { 5 | "dashboard-tab": { 6 | "title": "RDX Host-APIs Test", 7 | "root": "/ui", 8 | "src": "host-apis.html" 9 | } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/host-binaries.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg", 3 | "host": { 4 | "binaries": [ 5 | { 6 | "darwin": [ 7 | { 8 | "path": "/bin/dummy.sh" 9 | } 10 | ], 11 | "windows": [ 12 | { 13 | "path": "/bin/dummy.exe" 14 | } 15 | ], 16 | "linux": [ 17 | { 18 | "path": "/bin/dummy.sh" 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/missing-icon-file.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "does-not-exist.svg", 3 | "info": "This extension uses an icon that does not exist." 4 | } 5 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/missing-icon.json: -------------------------------------------------------------------------------- 1 | { 2 | "info": "This extension definition is missing an icon." 3 | } 4 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/ui.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg", 3 | "ui": { 4 | "dashboard-tab": { 5 | "title": "Sample Extension", 6 | "root": "/ui", 7 | "src": "index.html" 8 | } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/ui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Test Extension 5 | 6 | 7 |

Test Extension

8 |

This is a test extension.

9 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/vm-compose.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg", 3 | "info": "This image uses vm.composefile", 4 | "vm": { 5 | "composefile": "/compose/compose.yaml" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bats/tests/extensions/testdata/vm-image.json: -------------------------------------------------------------------------------- 1 | { 2 | "icon": "extension-icon.svg", 3 | "info": "This extension contains a reference to an image.", 4 | "vm": { 5 | "image": "rd/extension/vm-image" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /bats/tests/helpers/kubernetes.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | : "${RD_INFO:=false}" 4 | 5 | @test 'unwrap_kube_list: no list' { 6 | run echo '{"kind": "Pod"}' 7 | assert_success 8 | 9 | run unwrap_kube_list 10 | assert_success 11 | 12 | run jq_output .kind 13 | assert_success 14 | assert_output Pod 15 | } 16 | 17 | @test 'unwrap_kube_list: no items' { 18 | run echo '{"kind": "List"}' 19 | assert_success 20 | 21 | run unwrap_kube_list 22 | assert_failure 23 | } 24 | 25 | @test 'unwrap_kube_list: one item' { 26 | run echo '{"kind": "List", "items": [{"kind": "Pod"}]}' 27 | assert_success 28 | 29 | run unwrap_kube_list 30 | assert_success 31 | 32 | run jq_output .kind 33 | assert_success 34 | assert_output Pod 35 | } 36 | 37 | @test 'unwrap_kube_list: two items' { 38 | run echo '{"kind": "List", "items": [{"kind": "Pod"},{"kind": "Pod"}]}' 39 | assert_success 40 | 41 | run unwrap_kube_list 42 | assert_failure 43 | } 44 | 45 | @test 'unwrap_kube_list: not JSON' { 46 | run echo 'Some random error message' 47 | assert_success 48 | 49 | run unwrap_kube_list 50 | assert_failure 51 | } 52 | -------------------------------------------------------------------------------- /bats/tests/helpers/snapshots.bash: -------------------------------------------------------------------------------- 1 | delete_all_snapshots() { 2 | run rdctl snapshot list --json 3 | assert_success 4 | # On Windows, executing native Windows executables consumes stdin. 5 | # https://github.com/microsoft/WSL/issues/10429 6 | # Work around the issue by using `run` to populate `${lines[@]}` ahead of 7 | # time, so that we don't need the buffer during the loop. 8 | run jq_output .name 9 | assert_success 10 | local name 11 | for name in "${lines[@]}"; do 12 | rdctl snapshot delete "$name" 13 | done 14 | run rdctl snapshot list 15 | assert_success 16 | assert_output --partial 'No snapshots' 17 | } 18 | -------------------------------------------------------------------------------- /bats/tests/k8s/enable-disable-k8s.bats: -------------------------------------------------------------------------------- 1 | # Test case 8, 13, 22 2 | 3 | load '../helpers/load' 4 | 5 | @test 'factory reset' { 6 | factory_reset 7 | } 8 | 9 | verify_k8s_is_running() { 10 | wait_for_container_engine 11 | wait_for_service_status k3s started 12 | } 13 | 14 | @test 'start rancher desktop with kubernetes enabled' { 15 | start_kubernetes 16 | wait_for_kubelet 17 | verify_k8s_is_running 18 | } 19 | 20 | @test 'disable kubernetes' { 21 | rdctl set --kubernetes.enabled=false 22 | wait_for_container_engine 23 | wait_for_service_status k3s stopped 24 | } 25 | 26 | @test 're-enable kubernetes' { 27 | rdctl set --kubernetes.enabled=true 28 | wait_for_kubelet 29 | verify_k8s_is_running 30 | } 31 | -------------------------------------------------------------------------------- /bats/tests/k8s/foreach-k3s-version.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | wait_for_dns() { 4 | try assert_pod_containers_are_running \ 5 | --namespace kube-system \ 6 | --selector k8s-app=kube-dns 7 | } 8 | 9 | foreach_k3s_version \ 10 | factory_reset \ 11 | start_kubernetes \ 12 | wait_for_kubelet \ 13 | wait_for_dns 14 | -------------------------------------------------------------------------------- /bats/tests/k8s/specify-invalid-k8s-version.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | @test 'factory reset' { 4 | factory_reset 5 | } 6 | 7 | @test 'invalid k8s version' { 8 | start_kubernetes --kubernetes.version=moose 9 | wait_for_container_engine 10 | # Can't use wait_for_api_server because it hard-wires a valid k8s version and we're specifying an invalid one here. 11 | # and we're specifying an invalid one here 12 | local timeout="$(($(date +%s) + 10 * 60))" 13 | until kubectl get --raw /readyz &>/dev/null; do 14 | assert [ "$(date +%s)" -lt "$timeout" ] 15 | sleep 1 16 | done 17 | # No way there's a race-condition here. 18 | # The version was checked and written to the log file before starting k8s, 19 | # and we have to wait a few minutes before k8s is ready and we're at the next line. 20 | assert_file_contains "$PATH_LOGS/kube.log" "Requested kubernetes version 'moose' is not a supported version. Falling back to" 21 | } 22 | 23 | # on macOS it still hangs without this 24 | @test 'shutdown' { 25 | if is_macos; then 26 | rdctl shutdown 27 | fi 28 | } 29 | -------------------------------------------------------------------------------- /bats/tests/profile/wasm.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | local_teardown_file() { 4 | foreach_profile delete_profile 5 | } 6 | 7 | @test 'create version 10 locked profile' { 8 | PROFILE_TYPE=$PROFILE_LOCKED 9 | create_profile 10 | add_profile_int version 10 11 | } 12 | 13 | @test 'start application' { 14 | factory_reset 15 | start_container_engine 16 | wait_for_container_engine 17 | } 18 | 19 | @test 'WASM mode should be locked down' { 20 | run rdctl set --experimental.container-engine.web-assembly.enabled 21 | assert_failure 22 | assert_output --partial 'field "experimental.containerEngine.webAssembly.enabled" is locked' 23 | } 24 | 25 | @test 'update locked profile to version 11' { 26 | PROFILE_TYPE=$PROFILE_LOCKED 27 | add_profile_int version 11 28 | } 29 | 30 | @test 'restart application with version 11 locked profile' { 31 | factory_reset 32 | start_container_engine 33 | wait_for_backend 34 | } 35 | 36 | @test 'WASM mode is now unlocked' { 37 | run rdctl set --experimental.container-engine.web-assembly.enabled 38 | assert_success 39 | assert_output --partial 'reconfiguring Rancher Desktop to apply changes' 40 | } 41 | -------------------------------------------------------------------------------- /bats/tests/snapshots/test_rdctl_snapshot.bats: -------------------------------------------------------------------------------- 1 | load '../helpers/load' 2 | 3 | # TODO: Uncomment this test when snapshots go unhidden. 4 | #@test 'snapshot shows up in general help' { 5 | # run rdctl --help 6 | # assert_success 7 | # assert_output -partial snapshot 8 | #} 9 | 10 | @test 'complain about missing argument' { 11 | # These test the rdctl cmd layer, can't be easily unit-tested 12 | for arg in create restore delete; do 13 | run rdctl snapshot "$arg" 14 | assert_failure 15 | done 16 | } 17 | -------------------------------------------------------------------------------- /build/signing-config-win.yaml: -------------------------------------------------------------------------------- 1 | # This file describes the code signing configuration for Windows. 2 | 3 | # The key is a directory name, relative to the unpacked zip file. 4 | # The value is an array of files in that directory to sign, or an explicit 5 | # negation (prefixed with "!"). Any files not listed is an error. 6 | .: 7 | - Rancher Desktop.exe 8 | - wix-custom-action.dll 9 | - '!d3dcompiler_47.dll' # spellcheck-ignore-line 10 | - '!ffmpeg.dll' 11 | - '!libEGL.dll' # spellcheck-ignore-line 12 | - '!libGLESv2.dll' # spellcheck-ignore-line 13 | - '!vk_swiftshader.dll' # spellcheck-ignore-line 14 | - '!vulkan-1.dll' # spellcheck-ignore-line 15 | resources/resources/win32/bin: 16 | - docker.exe 17 | - docker-credential-none.exe 18 | - nerdctl.exe 19 | - rdctl.exe 20 | - spin.exe 21 | - '!docker-credential-ecr-login.exe' 22 | - '!docker-credential-wincred.exe' 23 | - '!helm.exe' 24 | - '!kubectl.exe' 25 | - '!kuberlr.exe' 26 | resources/resources/win32/docker-cli-plugins: 27 | - '!docker-buildx.exe' 28 | - '!docker-compose.exe' 29 | resources/resources/win32/internal: 30 | - host-switch.exe 31 | - steve.exe 32 | - wsl-helper.exe 33 | - '!spin.exe' 34 | -------------------------------------------------------------------------------- /build/wix/bannrbmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/build/wix/bannrbmp.png -------------------------------------------------------------------------------- /build/wix/dlgbmp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/build/wix/dlgbmp.png -------------------------------------------------------------------------------- /dev-app-update.yml: -------------------------------------------------------------------------------- 1 | owner: rancher-sandbox 2 | repo: rancher-desktop 3 | updaterCacheDirName: rancher-desktop 4 | provider: custom 5 | upgradeServer: https://desktop.version.rancher.io/v1/checkupgrade 6 | vPrefixedTagName: true 7 | -------------------------------------------------------------------------------- /docs/assets/images/contributing/e2e-failure-reports.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/docs/assets/images/contributing/e2e-failure-reports.png -------------------------------------------------------------------------------- /docs/assets/images/contributing/e2e-summary.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/docs/assets/images/contributing/e2e-summary.png -------------------------------------------------------------------------------- /docs/development/README.md: -------------------------------------------------------------------------------- 1 | # Developer Documentation 2 | 3 | Note that the below table of contents may be out of date 4 | (we may forget to update it). If you don't find what you need, 5 | ask around! 6 | 7 | [Information About Factory Reset](factory-reset.md) 8 | [Feature Tracker](features.md) 9 | [Tips for Working with OBS](obs.md) 10 | [Linux Release Process](linux-release-process.md) 11 | [Release Checklist](release-checklist.md) 12 | [Signing Rancher Desktop Releases](signing.md) 13 | [Generating Screenshots for User Documentation](../../screenshots/README.md) 14 | [Information on how to setup and run BATS tests](../../bats/README.md) 15 | -------------------------------------------------------------------------------- /docs/development/env.md: -------------------------------------------------------------------------------- 1 | # Internal Rancher Desktop environment variables 2 | 3 | These variables are used for build and development purposes; they are not meant to be set by users. 4 | 5 | They do not form an API and may be changed or removed at any time without prior notice. 6 | 7 | ## RD_DEBUG_ENABLED=anything 8 | 9 | Forces debug logging to always be enabled. Useful to debug first-run issues when there is no `settings.yaml` yet to set debug mode. 10 | 11 | ## RD_FORCE_UPDATES_ENABLED=anything 12 | 13 | When set, it will force auto-update to be enabled even in `yarn dev` mode. Updates will be checked and downloaded, but **not** installed. 14 | 15 | ## RD_MOCK_MACOS_VERSION=semver 16 | 17 | Used for testing compatibility of the app with the OS version, for upgrade responder tests, and for enabling/disabling certain parts of the preferences (related to VZ emulation mode). 18 | 19 | ## RD_UPGRADE_RESPONDER_URL=http://localhost:8314/v1/checkupgrade 20 | 21 | Set an alternate upgrade responder endpoint for testing. 22 | -------------------------------------------------------------------------------- /docs/development/factory-reset.md: -------------------------------------------------------------------------------- 1 | When `rdctl factory-reset` is launched from the UI, it writes its stdout into 2 | `TMP/rdctl-stdout.txt` 3 | 4 | where on linux `TMP` is usually `/tmp`, 5 | 6 | on macOS it's given by `$TMPDIR` 7 | 8 | and on Windows by `%TEMP%`(command shell) or `$env:TEMP`(powershell). 9 | 10 | 11 | This is most useful during development. When the UI runs in debug mode, it spawns `rdctl factory-reset` with the `--verbose` option. 12 | 13 | We can't write the output into the `logs` directory as `factory-reset` deletes it. 14 | -------------------------------------------------------------------------------- /e2e/assets/k8s-deploy-sample/nginx-sample-app.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: nginx-app 5 | spec: 6 | selector: 7 | matchLabels: 8 | app: nginx 9 | version: v1 10 | replicas: 1 11 | template: 12 | metadata: 13 | labels: 14 | app: nginx 15 | version: v1 16 | spec: 17 | containers: 18 | - name: nginx 19 | image: nginx:latest 20 | ports: 21 | - containerPort: 80 22 | --- 23 | apiVersion: v1 24 | kind: Service 25 | metadata: 26 | name: nginx-app 27 | labels: 28 | app: nginx 29 | spec: 30 | type: NodePort 31 | ports: 32 | - port: 80 33 | name: http 34 | selector: 35 | app: nginx 36 | -------------------------------------------------------------------------------- /e2e/config/playwright-config.ts: -------------------------------------------------------------------------------- 1 | import * as path from 'path'; 2 | 3 | import type { Config, PlaywrightTestOptions } from '@playwright/test'; 4 | 5 | const outputDir = path.join(__dirname, '..', 'e2e', 'test-results'); 6 | const testDir = path.join(__dirname, '..', '..', 'e2e'); 7 | // The provisioned github runners are much slower overall than cirrus's, so allow 2 hours for a full e2e run 8 | const timeScale = process.env.CI ? 4 : 1; 9 | 10 | const config: Config = { 11 | testDir, 12 | outputDir, 13 | timeout: 10 * 60 * 1000 * timeScale, 14 | globalTimeout: 30 * 60 * 1000 * timeScale, 15 | workers: 1, 16 | reporter: 'list', 17 | }; 18 | 19 | export default config; 20 | -------------------------------------------------------------------------------- /e2e/pages/containers-page.ts: -------------------------------------------------------------------------------- 1 | import { Page } from '@playwright/test'; 2 | 3 | export class ContainersPage { 4 | readonly page: Page; 5 | 6 | constructor(page: Page) { 7 | this.page = page; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /e2e/pages/diagnostics-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | interface CheckerRows { 4 | muteButton: Locator; 5 | } 6 | 7 | export class DiagnosticsPage { 8 | readonly page: Page; 9 | readonly diagnostics: Locator; 10 | 11 | constructor(page: Page) { 12 | this.page = page; 13 | this.diagnostics = page.locator('[data-test="diagnostics"]'); 14 | } 15 | 16 | checkerRows(id: string): CheckerRows { 17 | return { muteButton: this.page.locator(`[data-test="diagnostics-mute-row-${ id }"]`) }; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /e2e/pages/extensions-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class ExtensionsPage { 4 | readonly page: Page; 5 | readonly cardEpinio: Locator; 6 | readonly buttonInstall: Locator; 7 | readonly tabInstalled: Locator; 8 | readonly tabCatalog: Locator; 9 | readonly navEpinio: Locator; 10 | 11 | constructor(page: Page) { 12 | this.page = page; 13 | this.cardEpinio = page.locator('[data-test="extension-card-epinio"]'); 14 | this.buttonInstall = page.locator('[data-test="button-install"]'); 15 | this.tabInstalled = page.locator('.tab >> text=Installed'); 16 | this.tabCatalog = page.locator('.tab >> text=Catalog'); 17 | this.navEpinio = page.locator('[data-test="extension-nav-epinio"]'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /e2e/pages/images-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class ImagesPage { 4 | readonly page: Page; 5 | readonly fixedHeader: Locator; 6 | readonly table: Locator; 7 | readonly rows: Locator; 8 | 9 | constructor(page: Page) { 10 | this.page = page; 11 | this.fixedHeader = page.locator('.fixed-header-actions'); 12 | this.table = page.locator('[data-test="imagesTable"]'); 13 | this.rows = page.locator('[data-test="imagesTableRows"]'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /e2e/pages/k8s-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | export class K8sPage { 3 | readonly page: Page; 4 | readonly engineRuntime: Locator; 5 | readonly memorySlider: Locator; 6 | readonly resetButton: Locator; 7 | readonly cpuSlider: Locator; 8 | readonly port: Locator; 9 | readonly enableKubernetes: Locator; 10 | 11 | constructor(page: Page) { 12 | this.page = page; 13 | this.memorySlider = page.locator('[id="memoryInGBWrapper"]'); 14 | this.resetButton = page.locator('[data-test="k8sResetBtn"]'); 15 | this.cpuSlider = page.locator('[id="numCPUWrapper"]'); 16 | this.engineRuntime = page.locator('.engine-selector'); 17 | this.port = page.locator('[data-test="portConfig"]'); 18 | this.enableKubernetes = page.locator('[data-test="enableKubernetes"]'); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /e2e/pages/portforward-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | export class PortForwardPage { 3 | readonly page: Page; 4 | readonly fixedHeader: Locator; 5 | readonly content: Locator; 6 | readonly table: Locator; 7 | 8 | constructor(page: Page) { 9 | this.page = page; 10 | this.fixedHeader = page.locator('.fixed-header-actions'); 11 | this.table = page.locator('.sortable-table-header'); 12 | this.content = page.locator('.content'); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /e2e/pages/preferences/containerEngine.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class ContainerEngineNav { 4 | readonly page: Page; 5 | readonly nav: Locator; 6 | readonly tabGeneral: Locator; 7 | readonly tabAllowedImages: Locator; 8 | readonly containerEngine: Locator; 9 | readonly allowedImages: Locator; 10 | readonly allowedImagesCheckbox: Locator; 11 | readonly enabledLockedField: Locator; 12 | 13 | constructor(page: Page) { 14 | this.page = page; 15 | this.nav = page.locator('[data-test="nav-container-engine"]'); 16 | this.tabGeneral = page.locator('.tab >> text=General'); 17 | this.tabAllowedImages = page.locator('.tab >> text=Allowed Images'); 18 | this.containerEngine = page.locator('[data-test="containerEngine"]'); 19 | this.allowedImages = page.locator('[data-test="allowedImages"]'); 20 | this.allowedImagesCheckbox = page.getByTestId('allowedImagesCheckbox'); 21 | this.enabledLockedField = this.allowedImagesCheckbox.locator('.icon-lock'); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /e2e/pages/preferences/index.ts: -------------------------------------------------------------------------------- 1 | import { ApplicationNav } from './application'; 2 | import { ContainerEngineNav } from './containerEngine'; 3 | import { KubernetesNav } from './kubernetes'; 4 | import { VirtualMachineNav } from './virtualMachine'; 5 | import { WslNav } from './wsl'; 6 | 7 | import type { Page } from '@playwright/test'; 8 | 9 | export class PreferencesPage { 10 | readonly page: Page; 11 | readonly application: ApplicationNav; 12 | readonly virtualMachine: VirtualMachineNav; 13 | readonly containerEngine: ContainerEngineNav; 14 | readonly kubernetes: KubernetesNav; 15 | readonly wsl: WslNav; 16 | 17 | constructor(page: Page) { 18 | this.page = page; 19 | this.application = new ApplicationNav(page); 20 | this.virtualMachine = new VirtualMachineNav(page); 21 | this.containerEngine = new ContainerEngineNav(page); 22 | this.kubernetes = new KubernetesNav(page); 23 | this.wsl = new WslNav(page); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /e2e/pages/preferences/kubernetes.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class KubernetesNav { 4 | readonly page: Page; 5 | readonly nav: Locator; 6 | readonly kubernetesToggle: Locator; 7 | readonly kubernetesVersion: Locator; 8 | readonly kubernetesPort: Locator; 9 | readonly kubernetesOptions: Locator; 10 | readonly kubernetesVersionLockedFields: Locator; 11 | 12 | constructor(page: Page) { 13 | this.page = page; 14 | this.nav = page.locator('[data-test="nav-kubernetes"]'); 15 | this.kubernetesToggle = page.locator('[data-test="kubernetesToggle"]'); 16 | this.kubernetesVersion = page.locator('[data-test="kubernetesVersion"]'); 17 | this.kubernetesPort = page.locator('[data-test="kubernetesPort"]'); 18 | this.kubernetesOptions = page.locator('[data-test="kubernetesOptions"]'); 19 | this.kubernetesVersionLockedFields = page.locator('[data-test="kubernetesVersion"] > .select-k8s-version > .icon-lock'); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /e2e/pages/preferences/wsl.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class WslNav { 4 | readonly page: Page; 5 | readonly nav: Locator; 6 | readonly wslIntegrations: Locator; 7 | readonly addressTitle: Locator; 8 | readonly tabIntegrations: Locator; 9 | readonly tabProxy: Locator; 10 | 11 | constructor(page: Page) { 12 | this.page = page; 13 | this.nav = page.locator('[data-test="nav-wsl"]'); 14 | this.tabIntegrations = page.locator('.tab >> text=Integrations'); 15 | this.tabProxy = page.locator('.tab >> text=Proxy'); 16 | this.wslIntegrations = page.locator('[data-test="wslIntegrations"]'); 17 | this.addressTitle = page.locator('[data-test="addressTitle"]'); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /e2e/pages/snapshots-page.ts: -------------------------------------------------------------------------------- 1 | import { Locator, Page } from '@playwright/test'; 2 | 3 | export class SnapshotsPage { 4 | readonly page: Page; 5 | readonly snapshotsPage: Locator; 6 | readonly createSnapshotButton: Locator; 7 | readonly createSnapshotNameInput: Locator; 8 | readonly createSnapshotDescInput: Locator; 9 | 10 | constructor(page: Page) { 11 | this.page = page; 12 | this.snapshotsPage = page.locator('[data-test="snapshotsPage"]'); 13 | this.createSnapshotButton = page.locator('[data-test="createSnapshotButton"]'); 14 | this.createSnapshotNameInput = page.locator('[data-test="createSnapshotNameInput"]'); 15 | this.createSnapshotDescInput = page.locator('[data-test="createSnapshotDescInput"]'); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /e2e/pages/troubleshooting-page.ts: -------------------------------------------------------------------------------- 1 | import type { Page, Locator } from '@playwright/test'; 2 | 3 | export class TroubleshootingPage { 4 | readonly page: Page; 5 | readonly factoryResetButton: Locator; 6 | readonly logsButton: Locator; 7 | readonly troubleshooting: Locator; 8 | 9 | constructor(page: Page) { 10 | this.page = page; 11 | this.factoryResetButton = page.locator('[data-test="factoryResetButton"]'); 12 | this.logsButton = page.locator('[data-test="logsButton"]'); 13 | this.troubleshooting = page.locator('.troubleshooting'); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /go.work: -------------------------------------------------------------------------------- 1 | go 1.24.0 2 | 3 | toolchain go1.24.2 4 | 5 | use ( 6 | ./scripts 7 | ./src/go/docker-credential-none 8 | ./src/go/extension-proxy 9 | ./src/go/guestagent 10 | ./src/go/mock-wsl 11 | ./src/go/nerdctl-stub 12 | ./src/go/nerdctl-stub/generate 13 | ./src/go/networking 14 | ./src/go/rdctl 15 | ./src/go/spin-stub 16 | ./src/go/wsl-helper 17 | ) 18 | -------------------------------------------------------------------------------- /packaging/linux/rancher-desktop.appdata.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | rancher-desktop 4 | CC0-1.0 5 | Apache-2.0 6 | Rancher Desktop 7 | Kubernetes and container management on the desktop 8 | 9 |

10 | Rancher Desktop is an open-source project to bring Kubernetes and container management to the desktop 11 |

12 |
13 | 14 | rancher-desktop 15 | 16 | 17 | 18 | 19 | https://rancherdesktop.io/ 20 | https://github.com/rancher-sandbox/rancher-desktop/issues 21 |
22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/dependencies.yaml: -------------------------------------------------------------------------------- 1 | lima: 1.1.1.rd1 2 | qemu: 9.2.0.rd2 3 | socketVMNet: 1.2.1 4 | alpineLimaISO: 5 | isoVersion: 0.2.43.rd5 6 | alpineVersion: 3.21.3 7 | WSLDistro: "0.84" 8 | kuberlr: 0.6.0 9 | helm: 3.18.1 10 | dockerCLI: 28.2.2 11 | dockerBuildx: 0.24.0 12 | dockerCompose: 2.36.2 13 | golangci-lint: 2.1.6 14 | trivy: 0.63.0 15 | steve: 0.1.0-beta9 16 | rancherDashboard: 2.11.0.rd2 17 | dockerProvidedCredentialHelpers: 0.9.3 18 | ECRCredentialHelper: 0.9.1 19 | mobyOpenAPISpec: "1.50" 20 | wix: v3.14.1 21 | hostSwitch: 1.2.7 22 | moproxy: 0.5.1 23 | spinShim: 0.19.0 24 | spinOperator: 0.5.0 25 | certManager: 1.17.2 26 | spinCLI: 3.2.0 27 | spinKubePlugin: 0.4.0 28 | check-spelling: 0.0.25 29 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-700.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-700.woff -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-700.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-700.woff2 -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-regular.woff -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/lato/lato-v17-latin-regular.woff2 -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-300.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-300.woff -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-300.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-300.woff2 -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-500.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-500.woff -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-500.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/poppins/poppins-v15-latin-500.woff2 -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/assets/fonts/roboto-mono/roboto-mono-v13-latin-regular.woff2 -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/10-flannel.conflist: -------------------------------------------------------------------------------- 1 | { 2 | "name":"cbr0", 3 | "cniVersion":"0.3.1", 4 | "plugins":[ 5 | { 6 | "type":"flannel", 7 | "delegate":{ 8 | "hairpinMode":true, 9 | "forceAddress":true, 10 | "isDefaultGateway":true 11 | } 12 | }, 13 | { 14 | "type":"portmap", 15 | "capabilities":{ 16 | "portMappings":true 17 | } 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/buildkit.confd: -------------------------------------------------------------------------------- 1 | # config file for /etc/init.d/buildkit 2 | 3 | # overrides the main command executed by the supervise daemon 4 | buildkitd_command="/usr/local/bin/buildkitd" 5 | 6 | # any other options you want to pass to buildkitd_command 7 | buildkitd_opts="--addr=unix:///run/buildkit/buildkitd.sock --containerd-worker=true --containerd-worker-addr=/run/k3s/containerd/containerd.sock --containerd-worker-gc --oci-worker=false" 8 | 9 | # Settings for process limits (ulimit) 10 | #ulimit_opts="-c unlimited -n 1048576 -u unlimited" 11 | 12 | # seconds to wait for sending SIGTERM and SIGKILL signals when stopping buildkitd 13 | #signal_retry="TERM/60/KILL/10" 14 | 15 | # where buildkit stdout (and perhaps stderr) goes. 16 | #log_file="/var/log/buildkit.log" 17 | 18 | # where buildkit stderr optionally goes. 19 | # if this is not set, the value in 'logfile' is used 20 | #err_file="/var/log/buildkit-err.log" 21 | 22 | # mode of the log files 23 | #log_mode=0644 24 | 25 | # user that owns the log files (no group root on WSL) 26 | log_owner=root 27 | 28 | # to override the default supervise_daemon_args 29 | #supervise_daemon_opts="" 30 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/buildkit.initd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | supervisor=supervise-daemon 3 | 4 | name="BuildKit Daemon" 5 | description="Standalone buildkitd" 6 | 7 | command="${buildkitd_command:-/usr/bin/buildkitd}" 8 | command_args="${buildkitd_opts:---oci-worker=false --containerd-worker=true}" 9 | rc_ulimit="${ulimit_opts:--c unlimited -n 1048576 -u unlimited}" 10 | retry="${signal_retry:-TERM/60/KILL/10}" 11 | 12 | log_file="${log_file:-/var/log/${RC_SVCNAME}.log}" 13 | err_file="${err_file:-${log_file}}" 14 | log_mode="${log_mode:-0644}" 15 | log_owner="${log_owner:-root}" 16 | 17 | supervise_daemon_args="${supervise_daemon_opts:---stderr \"${err_file}\" --stdout \"${log_file}\"}" 18 | 19 | start_pre() { 20 | checkpath -f -m "$log_mode" -o "$log_owner" "$log_file" "$err_file" 21 | } 22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/cert-manager.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Namespace 4 | metadata: 5 | name: cert-manager 6 | --- 7 | apiVersion: helm.cattle.io/v1 8 | kind: HelmChart 9 | metadata: 10 | name: cert-manager 11 | namespace: kube-system 12 | spec: 13 | chart: "https://%{KUBERNETES_API}%/static/rancher-desktop/cert-manager.tgz" 14 | targetNamespace: cert-manager 15 | # Old versions of the helm-controller don't support createNamespace, so we 16 | # created the namespace ourselves. 17 | createNamespace: false 18 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/docker-credential-rancher-desktop: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -eu 4 | 5 | source /etc/rancher/desktop/credfwd 6 | 7 | DATA="@-" 8 | # The "list" command doesn't have a payload on STDIN 9 | [ "$1" = "list" ] && DATA="" 10 | 11 | # $CREDFWD_CURL_OPTS is intentionally *not* quoted 12 | exec curl --silent --user "$CREDFWD_AUTH" --data "$DATA" --noproxy '*' --fail-with-body ${CREDFWD_CURL_OPTS:-} "$CREDFWD_URL/$1" 13 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/install-containerd-shims: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | dest=/usr/local/containerd-shims 6 | 7 | # Copy all shims into the data volume so they become part of snapshots. 8 | # TODO Maybe use rsync to avoid copying files repeatedly? 9 | mkdir -p "$dest" 10 | for dir in "$@"; do 11 | if [[ "$(uname -a)" =~ microsoft ]]; then 12 | dir=$(wslpath -a -u "$dir") 13 | fi 14 | cp "${dir}/containerd-shim-"* "$dest" || : 15 | done 16 | 17 | # Make sure all shims are executable. 18 | for file in "${dest}/"*; do 19 | if [ -e "$file" ]; then 20 | chmod 755 "$file" 21 | fi 22 | done 23 | 24 | # Create symlinks to each shim into /usr/local/bin. 25 | # In the future this will enable us putting only shims from an allow list on the PATH. 26 | find /usr/local/bin -type l -name 'containerd-shim-*' -delete 27 | find "$dest" -type f -exec ln -sf {} /usr/local/bin \; 28 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/install-wsl-helpers: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # This script installs WSL helpers into the shared WSL mount at `/mnt/wsl`. 4 | # Usage: $0 5 | 6 | # shellcheck shell=ash 7 | 8 | set -o errexit -o nounset 9 | 10 | # The nerdctl shim must be setuid root to be able to create bind mounts within 11 | # /mnt/wsl so that nerdctl can see it. 12 | mkdir -p "/mnt/wsl/rancher-desktop/bin/" 13 | cp "${1}" "/mnt/wsl/rancher-desktop/bin/nerdctl" 14 | chmod u+s "/mnt/wsl/rancher-desktop/bin/nerdctl" 15 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/k3s-containerd-config.toml: -------------------------------------------------------------------------------- 1 | version = 2 2 | 3 | root = "/var/lib/rancher/k3s/agent/containerd" 4 | state = "/run/k3s/containerd" 5 | 6 | [grpc] 7 | address = "/run/k3s/containerd/containerd.sock" 8 | 9 | [plugins."io.containerd.internal.v1.opt"] 10 | path = "/var/lib/rancher/k3s/agent/containerd" 11 | 12 | [plugins."io.containerd.grpc.v1.cri"] 13 | stream_server_address = "127.0.0.1" 14 | stream_server_port = "10010" 15 | enable_selinux = false 16 | enable_unprivileged_ports = true 17 | enable_unprivileged_icmp = true 18 | sandbox_image = "rancher/mirrored-pause:3.6" 19 | 20 | [plugins."io.containerd.grpc.v1.cri".containerd] 21 | snapshotter = "overlayfs" 22 | disable_snapshot_annotations = true 23 | 24 | [plugins."io.containerd.grpc.v1.cri".cni] 25 | bin_dir = "/usr/libexec/cni" 26 | conf_dir = "/etc/cni/net.d" 27 | 28 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc] 29 | runtime_type = "io.containerd.runc.v2" 30 | 31 | [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.runc.options] 32 | SystemdCgroup = false 33 | 34 | [plugins."io.containerd.grpc.v1.cri".registry] 35 | config_path = "/var/lib/rancher/k3s/agent/etc/containerd/certs.d" 36 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/logrotate-k3s: -------------------------------------------------------------------------------- 1 | /var/log/k3s.log { 2 | missingok 3 | notifempty 4 | copytruncate 5 | } 6 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/logrotate-lima-guestagent: -------------------------------------------------------------------------------- 1 | /var/log/lima-guestagent.log { 2 | missingok 3 | notifempty 4 | copytruncate 5 | } 6 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/logrotate-openresty: -------------------------------------------------------------------------------- 1 | /var/log/openresty/*.log { 2 | missingok 3 | sharedscripts 4 | postrotate 5 | /etc/init.d/rd-openresty --quiet --ifstarted reopen 6 | endscript 7 | } 8 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/nerdctl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | export CONTAINERD_ADDRESS=/run/k3s/containerd/containerd.sock 3 | if [ -f /usr/local/openresty/nginx/conf/allowed-images.conf ]; then 4 | export HTTPS_PROXY=http://127.0.0.1:3128 5 | fi 6 | 7 | # On WSL, we need to enter the correct pid &c. namespace for nerdctl to work 8 | # correctly. 9 | 10 | if [ -r /run/wsl-init.pid ]; then 11 | parent="$(cat /run/wsl-init.pid)" 12 | pid="$(ps -o pid,ppid,comm | awk '$2 == "'"${parent}"'" && $3 == "init" { print $1 }')" 13 | if [ -n "${pid}" ]; then 14 | exec /usr/bin/nsenter -p -m -n -t "${pid}" /usr/local/libexec/nerdctl/nerdctl "$@" 15 | fi 16 | fi 17 | 18 | exec /usr/local/libexec/nerdctl/nerdctl "$@" 19 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/service-cri-dockerd.initd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | # This script is used to manage cri-dockerd via OpenRC. 4 | 5 | # shellcheck shell=ksh 6 | 7 | name="cri-dockerd" 8 | description="Rancher Desktop Shim for Docker Engine" 9 | 10 | 11 | supervisor=supervise-daemon 12 | command=/usr/local/bin/cri-dockerd 13 | command_args="--container-runtime-endpoint unix:///run/cri-dockerd.sock --network-plugin=cni --cni-bin-dir=/usr/libexec/cni --cni-conf-dir=/etc/cni/net.d --cni-cache-dir=/var/lib/cni/cache" 14 | 15 | CRI_DOCKERD_LOGFILE="${CRI_DOCKERD_LOGFILE:-${LOG_DIR:-/var/log}/${RC_SVCNAME}.log}" 16 | output_log="'${CRI_DOCKERD_LOGFILE}'" 17 | error_log="'${CRI_DOCKERD_LOGFILE}'" 18 | 19 | depend() { 20 | need docker 21 | } 22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/service-wsl-dockerd.initd: -------------------------------------------------------------------------------- 1 | #!/sbin/openrc-run 2 | 3 | # This is an OpenRC service script (/etc/init.d/wsl-dockerd) that runs 4 | # wsl-helper docker-proxy start. 5 | 6 | # shellcheck shell=ksh 7 | 8 | name="Rancher Desktop Docker Daemon" 9 | description="Starts dockerd for Rancher Desktop" 10 | 11 | supervisor=supervise-daemon 12 | if [ -f /usr/local/openresty/nginx/conf/allowed-images.conf ]; then 13 | supervise_daemon_args="-e HTTPS_PROXY=http://127.0.0.1:3128" 14 | fi 15 | command="'${WSL_HELPER_BINARY:-/usr/local/bin/wsl-helper}'" 16 | command_args="docker-proxy start" 17 | 18 | DOCKER_LOGFILE="${DOCKER_LOGFILE:-${LOG_DIR:-/var/log}/${RC_SVCNAME}.log}" 19 | output_log="'${DOCKER_LOGFILE}'" 20 | error_log="'${DOCKER_LOGFILE}'" 21 | 22 | rc_ulimit="${DOCKER_ULIMIT:--c unlimited -n 1048576 -u unlimited}" 23 | 24 | depend() { 25 | need sysfs cgroups 26 | after iptables ip6tables 27 | } 28 | 29 | healthcheck() { 30 | /usr/bin/curl --fail --unix-socket /mnt/wsl/rancher-desktop/run/docker.sock --url http://./_ping 31 | } 32 | healthcheck_timer=60 33 | respawn_delay=5 34 | respawn_max=10 35 | respawn_period=10 36 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/spin-operator.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: core.spinkube.dev/v1alpha1 3 | kind: SpinAppExecutor 4 | metadata: 5 | name: containerd-shim-spin 6 | spec: 7 | createDeployment: true 8 | deploymentConfig: 9 | runtimeClassName: spin 10 | --- 11 | apiVersion: v1 12 | kind: Namespace 13 | metadata: 14 | name: spin-operator 15 | --- 16 | apiVersion: helm.cattle.io/v1 17 | kind: HelmChart 18 | metadata: 19 | name: spin-operator 20 | namespace: kube-system 21 | spec: 22 | chart: "https://%{KUBERNETES_API}%/static/rancher-desktop/spin-operator.tgz" 23 | targetNamespace: spin-operator 24 | # Old versions of the helm-controller don't support createNamespace, so we 25 | # created the namespace ourselves. 26 | createNamespace: false 27 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/scripts/wsl-data.conf: -------------------------------------------------------------------------------- 1 | # This is the /etc/wsl.conf for use with rancher-desktop-data 2 | # As we do not have an actual data distribution, this file is included as part 3 | # of the application and written out at runtime. 4 | 5 | [automount] 6 | # Prevent processing /etc/fstab, since it doesn't exist. 7 | mountFsTab = false 8 | # Prevent running ldconfig, since that doesn't exist. 9 | ldconfig = false 10 | # Needed for compatibility with some `yarn` scenarios. 11 | options = metadata 12 | 13 | # We _do_ want to generate `/etc/hosts` here, so that it can be used by the main 14 | # distribution. 15 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/specs/README.md: -------------------------------------------------------------------------------- 1 | ## Generators 2 | 3 | ### To generate go code: 4 | 5 | `oapi-codegen pkg/rancher-desktop/assets/specs/command-api.yaml > api/commands.go` 6 | 7 | #### Dependencies: 8 | 9 | * opai-codegen: To install: 10 | 11 | ```bash 12 | go get github.com/deepmap/oapi-codegen/cmd/oapi-codegen 13 | ``` 14 | 15 | ### To generate documentation: 16 | 17 | ``` 18 | mkdir tmp 19 | docker run --rm -v ${PWD}:/local openapitools/openapi-generator-cli:v5.4.2 generate -i /local/src/assets/specs/command-api.yaml -g html -o /local/tmp/ 20 | open tmp/index.html # (macOS) 21 | start tmp/index.html # (Powershell) 22 | xdg-open tmp/index.html # (linux, replace with path to a specific browser if you prefer). 23 | ``` 24 | 25 | Recommended tag: openapitools/openapi-generator-cli:v5.4.2 26 | 27 | So run: 28 | ``` 29 | docker run ... openapitools/openapi-generator-cli@sha256:3d7c84e4b8f25a2074d6ab44d936cd69d08a223021197269e75d29992204e15e 30 | ``` 31 | 32 | ## References: 33 | 34 | * OpenAPI spec: https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.0.md#mediaTypeObject 35 | 36 | * Tools: https://openapi.tools/ 37 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/app.scss: -------------------------------------------------------------------------------- 1 | @import "./vendor/normalize"; 2 | 3 | @import "./base/variables"; 4 | @import "./base/functions"; 5 | @import "./base/mixins"; 6 | @import "./base/helpers"; 7 | @import "./base/color"; 8 | @import "./base/basic"; 9 | @import "./base/typography"; 10 | 11 | @import "./fonts/fontstack"; 12 | @import "./fonts/dots"; 13 | @import "./fonts/zerowidthspace"; 14 | @import "./fonts/icons"; 15 | 16 | @import "./themes/light"; 17 | @media screen and (prefers-color-scheme: dark) { 18 | @import "./themes/dark"; 19 | } 20 | @import './themes/_suse.scss'; 21 | 22 | 23 | @import "./global/columns"; 24 | @import "./global/cards"; 25 | @import "./global/button"; 26 | @import "./global/form"; 27 | @import "./global/gauges"; 28 | @import "./global/labeled-input"; 29 | @import "./global/tooltip"; 30 | @import "./global/table"; 31 | @import "./global/select"; 32 | @import "./global/resource"; 33 | 34 | @import "./vendor/vue-select"; 35 | @import "./vendor/vue-js-modal"; 36 | 37 | @import "./rancher-desktop.scss"; 38 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/base/_color.scss: -------------------------------------------------------------------------------- 1 | .bg-transparent { 2 | background-color: transparent; 3 | } 4 | 5 | .bg-disabled { 6 | background-color: var(--disabled-bg) !important; 7 | } 8 | 9 | .text-disabled { 10 | color: var(--disabled-text) !important; 11 | } 12 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/base/_typography.scss: -------------------------------------------------------------------------------- 1 | HTML, BODY { 2 | font-family: $body-font; 3 | font-size: 14px; 4 | } 5 | 6 | H1, H2, H3, H4, H5, H6 { 7 | color: var(--body-text); 8 | font-style: normal; 9 | font-weight: 400; 10 | margin: 0 0 10px 0; 11 | } 12 | 13 | H1 { 14 | font-size: 24px; 15 | } 16 | 17 | H2 { 18 | font-size: 21px; 19 | } 20 | 21 | H3 { 22 | font-size: 18px; 23 | } 24 | 25 | H4 { 26 | font-size: 16px; 27 | } 28 | 29 | H5 { 30 | font-size: 14px; 31 | } 32 | 33 | H6 { 34 | font-size: 12px; 35 | text-transform: uppercase; 36 | } 37 | 38 | P { 39 | font-weight: 400; 40 | font-style: normal; 41 | margin: 0; 42 | } 43 | 44 | //code 45 | code, samp, kbd, .monospace { 46 | font-family: $mono-font; 47 | text-align: left; 48 | } 49 | 50 | pre { 51 | padding: 10px; 52 | border-radius: var(--border-radius); 53 | background: var(--box-bg); 54 | margin: 5px; 55 | overflow: auto; 56 | } 57 | 58 | code { 59 | background-color: var(--box-bg); 60 | display: inline-block; 61 | padding: 5px; 62 | border: 1px solid var(--border); 63 | border-radius: var(--border-radius); 64 | } 65 | 66 | pre code { 67 | background: transparent; 68 | padding: 0; 69 | } 70 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/base/_variables.scss: -------------------------------------------------------------------------------- 1 | $header-font: 'Poppins', sans-serif; 2 | $body-font: 'Lato', arial, helvetica, sans-serif; 3 | $mono-font: 'Roboto Mono', monospace; 4 | 5 | $max-width: 1440px !default; 6 | $min-width: 75% !default; 7 | $input-height: 61px; 8 | 9 | $input-padding-lg: 18px; 10 | $input-padding-sm: 10px; 11 | $input-line-height: 18px; 12 | 13 | $column-gutter: 1.75%; 14 | 15 | $sideways-tabs-width: 200px; 16 | 17 | $array-list-remove-margin: 75px; 18 | 19 | $z-indexes: ( 20 | zero: 0, 21 | default: 1, 22 | overContent: 2, 23 | hoverOverContent: 3, 24 | 25 | tableGroup: 10, 26 | fixedTableHeader: 11, 27 | 28 | modalOverlay: 20, 29 | modalContent: 21, 30 | 31 | tooltip: 30, 32 | 33 | dropdownOverlay: 40, 34 | dropdownContent: 41, 35 | 36 | loadingOverlay: 50, 37 | loadingContent: 51 38 | ); 39 | 40 | // Usage Example: 41 | // @media only screen and (min-width: map-get($breakpoints, '--viewport-*')) { 42 | // } 43 | $breakpoints: ( 44 | '--viewport-4': 480px, 45 | '--viewport-7': 768px, 46 | '--viewport-9': 992px, 47 | '--viewport-12': 1281px, 48 | ); 49 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/rancher-desktop.scss: -------------------------------------------------------------------------------- 1 | /** Rancher Desktop specific styles */ 2 | body { 3 | background-color: var(--body-bg); 4 | color: var(--body-text); 5 | font-size: 14px; 6 | } 7 | 8 | .labeled-input { 9 | margin-bottom: 1em; 10 | } 11 | label > button:first-child:not(.btn-sm) { 12 | margin-right: 1em; 13 | } 14 | 15 | .locked-radio .radio-container span.radio-custom { 16 | &[aria-checked="true"] { 17 | opacity: 1; 18 | } 19 | 20 | &:not([aria-checked="true"]) { 21 | opacity: 1; 22 | background-color: var(--radio-locked-bg); 23 | box-shadow: var(--radio-locked-shadow); 24 | } 25 | } 26 | 27 | @media screen and (prefers-color-scheme: dark) { 28 | option { 29 | background-color: var(--input-bg); 30 | } 31 | } 32 | 33 | :is(.btn, button, [class*='btn-']):not([class*='role-']) { 34 | /* buttons should have one of the role- classes: 35 | * .role-primary, .role-secondary, .role-tertiary, .role-multi-action, etc. 36 | */ 37 | outline: 10px dashed red !important; 38 | } 39 | 40 | .btn-icon-text { 41 | display: flex; 42 | align-items: center; 43 | gap: 0.5rem; 44 | } 45 | 46 | :root { 47 | --preferences-content-padding: 0.75rem; 48 | } 49 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/assets/styles/vendor/vue-js-modal.scss: -------------------------------------------------------------------------------- 1 | /* NOTE: Commenting out everything in this Sass file for the time being. Rancher 2 | * Desktop does not use vue-js-modal in any capacity and modals are handled via 3 | * native windows. 4 | * 5 | * @import '~/../../node_modules/vue-js-modal/dist/styles.css'; 6 | * 7 | * .v--modal-overlay { 8 | * background-color: var(--overlay-bg); 9 | * z-index: z-index('modalOverlay'); 10 | * } 11 | * 12 | * .v--modal { 13 | * background-color: var(--modal-bg)!important; 14 | * box-shadow: none; 15 | * border: 2px solid var(--modal-border); 16 | * } 17 | */ 18 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/backend/containerClient/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | export { MobyClient } from './mobyClient'; 3 | export { NerdctlClient } from './nerdctlClient'; 4 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Alert.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 42 | 43 | 56 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/DashboardOpen.vue: -------------------------------------------------------------------------------- 1 | 26 | 27 | 37 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/ExtensionsError.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 27 | 28 | 33 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/ImageAddTabs.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 50 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/ImagesButtonAdd.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/NavItem.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | 26 | 55 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Preferences/ButtonOpen.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Preferences/Help.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Preferences/ModalHeader.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 13 | 14 | 30 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Preferences/ModalNavItem.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 38 | 39 | 52 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/Preferences/VirtualMachineVolumes.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 36 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/SnapshotsButtonCreate.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 25 | 26 | 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/SortableTable/grouping.js: -------------------------------------------------------------------------------- 1 | import { get } from '@pkg/utils/object'; 2 | 3 | export default { 4 | computed: { 5 | groupedRows() { 6 | const groupKey = this.groupBy; 7 | const refKey = this.groupRef || groupKey; 8 | 9 | if ( !groupKey) { 10 | return [{ 11 | key: 'default', 12 | ref: 'default', 13 | rows: this.pagedRows, 14 | }]; 15 | } 16 | 17 | const out = []; 18 | const map = {}; 19 | 20 | for ( const obj of this.pagedRows ) { 21 | const key = get(obj, groupKey) || ''; 22 | const ref = get(obj, refKey); 23 | let entry = map[key]; 24 | 25 | if ( entry ) { 26 | entry.rows.push(obj); 27 | } else { 28 | entry = { 29 | key, 30 | ref, 31 | rows: [obj], 32 | }; 33 | map[key] = entry; 34 | out.push(entry); 35 | } 36 | } 37 | 38 | return out; 39 | }, 40 | }, 41 | }; 42 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/TroubleshootingLineItem.vue: -------------------------------------------------------------------------------- 1 | 10 | 29 | 30 | 42 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/__tests__/PreferencesButton.spec.ts: -------------------------------------------------------------------------------- 1 | import { shallowMount } from '@vue/test-utils'; 2 | 3 | import PreferencesButton from '../Preferences/ButtonOpen.vue'; 4 | 5 | describe('Preferences/ButtonOpen.vue', () => { 6 | it(`renders a button`, () => { 7 | const wrapper = shallowMount(PreferencesButton, { mocks: { t: jest.fn() } }); 8 | 9 | expect(wrapper.find('button').classes()).toStrictEqual(['btn', 'role-secondary', 'btn-icon-text']); 10 | }); 11 | 12 | it(`emits 'open-preferences' on click`, () => { 13 | const wrapper = shallowMount(PreferencesButton, { mocks: { t: jest.fn() } }); 14 | 15 | wrapper.find('button').trigger('click'); 16 | 17 | expect(wrapper.emitted('open-preferences')).toHaveLength(1); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/form/LabeledBadge.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 32 | 33 | 40 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/components/form/TooltipIcon.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 29 | 30 | 41 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/config/cookies.js: -------------------------------------------------------------------------------- 1 | export const CSRF = 'CSRF'; 2 | export const USERNAME = 'R_USERNAME'; 3 | export const LOCALE = 'R_LOCALE'; 4 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/config/emptyStubForJSLinter.js: -------------------------------------------------------------------------------- 1 | // See https://stackoverflow.com/questions/39418555/syntaxerror-with-jest-and-react-and-importing-css-files 2 | // to continue to use jest-based unit-testing with CSS import statements. 3 | 4 | module.exports = {}; 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/config/private-label.js: -------------------------------------------------------------------------------- 1 | import { SETTING } from './settings'; 2 | 3 | export const ANY = 0; 4 | export const STANDARD = 1; 5 | export const CUSTOM = 2; 6 | 7 | const STANDARD_VENDOR = 'Rancher'; 8 | const STANDARD_PRODUCT = 'Explorer'; 9 | 10 | let mode = STANDARD; 11 | let vendor = STANDARD_VENDOR; 12 | let product = STANDARD_PRODUCT; 13 | 14 | export function setMode(m) { 15 | mode = m; 16 | } 17 | 18 | export function setVendor(v) { 19 | vendor = v; 20 | } 21 | 22 | export function setProduct(p) { 23 | product = p; 24 | } 25 | 26 | // ------------------------------------- 27 | 28 | export function getMode() { 29 | return mode; 30 | } 31 | 32 | export function isStandard() { 33 | return mode === STANDARD; 34 | } 35 | 36 | export function matches(pl) { 37 | if ( pl === ANY ) { 38 | return true; 39 | } 40 | 41 | return pl === mode; 42 | } 43 | 44 | export function getVendor() { 45 | if ( vendor === SETTING.PL_RANCHER_VALUE ) { 46 | return STANDARD_VENDOR; 47 | } 48 | 49 | return vendor; 50 | } 51 | 52 | export function getProduct() { 53 | return product; 54 | } 55 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/hocs/README.md: -------------------------------------------------------------------------------- 1 | Higher-Order Components (HOCs) are functions that take in a component as an argument and return a new component with additional functionality. HOCs are a useful pattern for reusing component logic and implementing cross-cutting concerns, such as authentication and authorization, caching, logging, and error handling. They allow for extracting common functionality into a separate component and apply it to multiple components without duplicating code. 2 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/index.ts: -------------------------------------------------------------------------------- 1 | /*** 2 | * NOTE: @rancher/shell was removed from this project during the Nuxt removal. 3 | * I'm keeping this file around for it's eventual reintroduction; it was easier 4 | * to limit the potential scope of issues associated with the Nuxt removal by 5 | * removing @rancher/shell 6 | */ 7 | // import { importTypes } from '@rancher/auto-import'; 8 | // import { IPlugin } from '@shell/core/types'; 9 | 10 | // import routes from './router'; 11 | 12 | // // Init the package 13 | // export default function(plugin: IPlugin) { 14 | // // Auto-import model, detail, edit from the folders 15 | // importTypes(plugin); 16 | 17 | // // Provide plugin metadata from package.json 18 | // plugin.metadata = require('./package.json'); 19 | 20 | // // Load a product 21 | // plugin.addProduct(require('./product')); 22 | 23 | // plugin.addRoutes(routes); 24 | // } 25 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/integrations/pathManager.ts: -------------------------------------------------------------------------------- 1 | // Definitions only 2 | 3 | /** 4 | * PathManager is the interface that anything that manages the 5 | * PATH variable must implement. 6 | */ 7 | export interface PathManager { 8 | /** The PathManagementStrategy that corresponds to the implementation. */ 9 | readonly strategy: PathManagementStrategy 10 | /** 11 | * Applies changes to the system. Should be idempotent, and should not throw 12 | * any exceptions. 13 | */ 14 | enforce(): Promise 15 | /** 16 | * Removes any changes that the PathManager may have made. Should be 17 | * idempotent, and should not throw any exceptions. 18 | */ 19 | remove(): Promise 20 | } 21 | 22 | /** 23 | * ManualPathManager is for when the user has chosen to manage 24 | * their PATH themselves. It does nothing. 25 | */ 26 | export class ManualPathManager implements PathManager { 27 | readonly strategy = PathManagementStrategy.Manual; 28 | async enforce(): Promise {} 29 | async remove(): Promise {} 30 | } 31 | 32 | export enum PathManagementStrategy { 33 | Manual = 'manual', 34 | RcFiles = 'rcfiles', 35 | } 36 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/layouts/preferences.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 27 | 28 | 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/credentialServer/README.md: -------------------------------------------------------------------------------- 1 | # Credential Helper Server protocol 2 | 3 | This server isn't intended to be used publicly; 4 | it's for other tools that we use in order to find docker credentials. 5 | 6 | The protocol is described at [https://github.com/docker/docker-credential-helpers#development](https://github.com/docker/docker-credential-helpers#development). 7 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/diagnostics/__tests__/rdBinInShell.spec.ts: -------------------------------------------------------------------------------- 1 | import { RDBinInShellPath } from '../rdBinInShell'; 2 | 3 | describe(RDBinInShellPath, () => { 4 | it('should remove trailing slashes', () => { 5 | expect(RDBinInShellPath.removeTrailingSlash('/Users/mikey/.rd/bin/')).toBe('/Users/mikey/.rd/bin'); 6 | expect(RDBinInShellPath.removeTrailingSlash('/Users/mikey/.rd/bin////')).toBe('/Users/mikey/.rd/bin'); 7 | expect(RDBinInShellPath.removeTrailingSlash('/Users/mikey/.rd/bin')).toBe('/Users/mikey/.rd/bin'); 8 | expect(RDBinInShellPath.removeTrailingSlash('/')).toBe('/'); 9 | expect(RDBinInShellPath.removeTrailingSlash('//')).toBe('/'); 10 | expect(RDBinInShellPath.removeTrailingSlash('/////')).toBe('/'); 11 | expect(RDBinInShellPath.removeTrailingSlash('')).toBe(''); 12 | }); 13 | }); 14 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/diagnostics/mockForScreenshots.ts: -------------------------------------------------------------------------------- 1 | import { DiagnosticsCategory, DiagnosticsChecker } from './types'; 2 | 3 | /** 4 | * Sample tests for testing 5 | */ 6 | class MockChecker implements DiagnosticsChecker { 7 | get id() { 8 | return 'MOCK_CHECKER'; 9 | } 10 | 11 | category = DiagnosticsCategory.Utilities; 12 | applicable(): Promise { 13 | return Promise.resolve(!!process.env.RD_MOCK_FOR_SCREENSHOTS); 14 | } 15 | 16 | check() { 17 | return Promise.resolve({ 18 | passed: false, 19 | documentation: 'https://www.example.com/not-a-valid-link', 20 | description: `The \`~/.rd/bin\` directory has not been added to the \`PATH\`, so command-line utilities are not configured in your shell.`, 21 | fixes: [], 22 | }); 23 | } 24 | } 25 | 26 | export default [new MockChecker()]; 27 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/diagnostics/testCheckers.ts: -------------------------------------------------------------------------------- 1 | import { DiagnosticsCategory, DiagnosticsChecker } from './types'; 2 | 3 | import { isDevEnv } from '@pkg/utils/environment'; 4 | 5 | /** 6 | * Sample tests for testing 7 | */ 8 | class CheckTesting implements DiagnosticsChecker { 9 | pass: boolean; 10 | constructor(pass: boolean) { 11 | this.pass = pass; 12 | } 13 | 14 | get id() { 15 | return `STATIC_${ this.pass.toString().toUpperCase() }`; 16 | } 17 | 18 | category = DiagnosticsCategory.Testing; 19 | applicable(): Promise { 20 | return Promise.resolve(isDevEnv && !process.env.RD_MOCK_FOR_SCREENSHOTS); 21 | } 22 | 23 | check() { 24 | return Promise.resolve({ 25 | passed: this.pass, 26 | documentation: 'https://www.example.com/not-a-valid-link', 27 | description: `This is a \`sample\` test that will **${ this.pass ? 'always' : 'never' }** pass.`, 28 | fixes: [], 29 | }); 30 | } 31 | } 32 | 33 | export default [new CheckTesting(true), new CheckTesting(false)]; 34 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/extensions/index.ts: -------------------------------------------------------------------------------- 1 | export * from './types'; 2 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/main/snapshots/types.ts: -------------------------------------------------------------------------------- 1 | export type SnapshotEvent = { 2 | type?: 'restore' | 'delete' | 'create' | 'confirm' | 'backend-lock', 3 | result?: 'success' | 'cancel' | 'error', 4 | error?: string, 5 | snapshotName?: string, 6 | eventTime?: string, 7 | }; 8 | 9 | export type SpawnResult = { 10 | stdout: string, 11 | stderr: string, 12 | error?: any, 13 | }; 14 | 15 | export interface SnapshotDialog { 16 | header: string, 17 | snapshot?: Snapshot, 18 | message?: string, 19 | detail?: string, 20 | info?: string | null, 21 | showProgressBar?: boolean, 22 | type?: string, 23 | snapshotEventType?: SnapshotEvent['type'], 24 | } 25 | 26 | export interface Snapshot { 27 | name: string, 28 | created: string, 29 | description?: string, 30 | } 31 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/middleware/i18n.js: -------------------------------------------------------------------------------- 1 | export default async function({ 2 | isHMR, app, store, route, params, error, redirect, 3 | }) { 4 | // If middleware is called from hot module replacement, ignore it 5 | if (isHMR) { 6 | return; 7 | } 8 | 9 | await store.dispatch('i18n/init'); 10 | } 11 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/middleware/indexRedirect.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This middleware redirects / to /General 3 | */ 4 | export default ({ route, next, redirect }) => { 5 | switch (route.path) { 6 | case process.env.RD_ENV_PLUGINS_DEV: 7 | next(); 8 | break; 9 | case '/': 10 | redirect(301, '/General'); 11 | break; 12 | default: 13 | next(); 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-present - Nuxt Team 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/components/nuxt-link.server.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default { 4 | name: 'NuxtLink', 5 | extends: Vue.component('RouterLink'), 6 | props: { 7 | prefetch: { 8 | type: Boolean, 9 | default: false 10 | }, 11 | noPrefetch: { 12 | type: Boolean, 13 | default: false 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/cookie-universal-nuxt.js: -------------------------------------------------------------------------------- 1 | import cookieUniversal from 'cookie-universal' 2 | 3 | export default ({ req, res }, inject) => { 4 | const options = { 5 | "alias": "cookies", 6 | "parseJSON": true 7 | } 8 | inject(options.alias, cookieUniversal(req, res, options.parseJSON)) 9 | } 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/empty.js: -------------------------------------------------------------------------------- 1 | // This file is intentionally left empty for noop aliases 2 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/middleware.js: -------------------------------------------------------------------------------- 1 | const middleware = {} 2 | 3 | middleware['i18n'] = require('../middleware/i18n.js') 4 | middleware['i18n'] = middleware['i18n'].default || middleware['i18n'] 5 | 6 | middleware['indexRedirect'] = require('../middleware/indexRedirect.js') 7 | middleware['indexRedirect'] = middleware['indexRedirect'].default || middleware['indexRedirect'] 8 | 9 | export default middleware 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/nuxt/views/app.template.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {{ HEAD }} 5 | 6 | 7 | {{ APP }} 8 | 9 | 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/pages/DenyRoot.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 39 | 40 | 45 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/pages/Diagnostics.vue: -------------------------------------------------------------------------------- 1 | 27 | 28 | 34 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/pages/Snapshots.vue: -------------------------------------------------------------------------------- 1 | 21 | 22 | 31 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/clean-html-directive.js: -------------------------------------------------------------------------------- 1 | import DOMPurify from 'dompurify'; 2 | import Vue from 'vue'; 3 | 4 | const ALLOWED_TAGS = [ 5 | 'code', 6 | 'li', 7 | 'a', 8 | 'p', 9 | 'b', 10 | 'br', 11 | 'ul', 12 | 'pre', 13 | 'span', 14 | 'div', 15 | 'i', 16 | 'em', 17 | 'strong', 18 | ]; 19 | 20 | const purifyHTML = value => DOMPurify.sanitize(value, { ALLOWED_TAGS }); 21 | 22 | export const cleanHtmlDirective = { 23 | inserted(el, binding) { 24 | el.innerHTML = purifyHTML(binding.value); 25 | }, 26 | componentUpdated(el, binding) { 27 | el.innerHTML = purifyHTML(binding.value); 28 | }, 29 | unbind(el) { 30 | el.innerHTML = ''; 31 | }, 32 | }; 33 | 34 | Vue.directive('clean-html', cleanHtmlDirective); 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/directives.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | Vue.directive('focus', { 4 | inserted(_el, _binding, vnode) { 5 | const element = getElement(vnode); 6 | 7 | if (element) { 8 | element.focus(); 9 | } 10 | }, 11 | }); 12 | 13 | const getElement = (vnode) => { 14 | const { componentInstance, componentOptions: { tag } } = vnode; 15 | 16 | if (tag === 'labeled-input') { 17 | return componentInstance.$refs.value; 18 | } 19 | }; 20 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/shortkey.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import ShortKey from 'vue-shortkey'; 3 | 4 | Vue.use(ShortKey, { prevent: ['input', 'textarea', 'select'] }); 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/tooltip.js: -------------------------------------------------------------------------------- 1 | import vTooltip from 'v-tooltip'; 2 | import Vue from 'vue'; 3 | 4 | Vue.use(vTooltip); 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/trim-whitespace.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | export function trimWhitespace(el, dir) { 4 | for (const node of el.childNodes) { 5 | if (node.nodeType === Node.TEXT_NODE ) { 6 | const trimmed = node.data.trim(); 7 | 8 | if ( trimmed === '') { 9 | node.remove(); 10 | } else if ( trimmed !== node.data ) { 11 | node.data = trimmed; 12 | } 13 | } 14 | } 15 | } 16 | 17 | export function trimWhitespaceSsr(el, dir) { 18 | // This causes server<->client dom mismatches sometimes... gave up for now. 19 | /* 20 | for ( const node of (el.children || []) ) { 21 | if ( node.text ) { 22 | const trimmed = node.text.trim(); 23 | 24 | if ( trimmed !== node.text ) { 25 | node.text = trimmed; 26 | } 27 | } else if ( node.children ) { 28 | trimWhitespaceSsr(node); 29 | } 30 | } 31 | */ 32 | } 33 | 34 | Vue.directive('trim-whitespace', { 35 | inserted: trimWhitespace, 36 | componentUpdated: trimWhitespace, 37 | }); 38 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/v-select.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import vSelect from 'vue-select'; 3 | 4 | Vue.component('v-select', vSelect); 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/plugins/vue-js-modal.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VModal from 'vue-js-modal'; 3 | 4 | Vue.use(VModal); 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/preload/README.md: -------------------------------------------------------------------------------- 1 | # Preload Scripts 2 | 3 | This directory contains code exposed to the renderer as [preload scripts]. 4 | 5 | [preload scripts]: https://www.electronjs.org/docs/latest/tutorial/tutorial-preload 6 | 7 | ## Extensions 8 | 9 | See https://docs.docker.com/desktop/extensions-sdk/ for details. 10 | 11 | e.g. splatform/epinio-docker-desktop 12 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/preload/index.ts: -------------------------------------------------------------------------------- 1 | import initExtensions from './extensions'; 2 | 3 | function init() { 4 | initExtensions(); 5 | } 6 | 7 | try { 8 | init(); 9 | } catch (ex) { 10 | console.error(ex); 11 | throw ex; 12 | } 13 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/product.js: -------------------------------------------------------------------------------- 1 | export const NAME = 'rancher-desktop'; 2 | 3 | export function init(plugin, store) { 4 | const { product } = plugin.DSL(store, NAME); 5 | 6 | product({ 7 | inStore: 'management', 8 | icon: 'globe', 9 | label: 'Rancher Desktop', 10 | removable: false, 11 | showClusterSwitcher: false, 12 | category: 'global', 13 | to: { name: 'rancher-desktop-general' }, 14 | }); 15 | } 16 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/store/imageManager.js: -------------------------------------------------------------------------------- 1 | export const state = () => ({ imageManagerState: false }); 2 | 3 | export const mutations = { 4 | SET_IMAGE_MANAGER_STATE(state, imageManagerState) { 5 | state.imageManagerState = imageManagerState; 6 | }, 7 | }; 8 | 9 | export const actions = { 10 | setImageManagerState({ commit }, imageManagerState) { 11 | commit('SET_IMAGE_MANAGER_STATE', imageManagerState); 12 | }, 13 | }; 14 | 15 | export const getters = { 16 | getImageManagerState({ imageManagerState }) { 17 | return imageManagerState; 18 | }, 19 | }; 20 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/store/k8sManager.js: -------------------------------------------------------------------------------- 1 | import { State as EngineStates } from '@pkg/backend/k8s'; 2 | import { ipcRenderer } from '@pkg/utils/ipcRenderer'; 3 | 4 | export const state = () => ({ k8sState: ipcRenderer.sendSync('k8s-state') }); 5 | 6 | export const mutations = { 7 | SET_K8S_STATE(state, k8sState) { 8 | state.k8sState = k8sState; 9 | }, 10 | }; 11 | 12 | export const actions = { 13 | setK8sState({ commit }, k8sState) { 14 | commit('SET_K8S_STATE', k8sState); 15 | }, 16 | }; 17 | 18 | export const getters = { 19 | getK8sState({ k8sState }) { 20 | return k8sState; 21 | }, 22 | isReady({ k8sState }) { 23 | return [EngineStates.STARTED, EngineStates.DISABLED].includes(k8sState); 24 | }, 25 | }; 26 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/store/ts-helpers.ts: -------------------------------------------------------------------------------- 1 | import type { UpperSnakeCase } from '@pkg/utils/typeUtils'; 2 | 3 | import type { CommitOptions, Dispatch } from 'vuex'; 4 | 5 | type MutationsPayloadType = { 6 | [key in keyof T as `SET_${ UpperSnakeCase }`]: T[key]; 7 | }; 8 | 9 | /** 10 | * MutationsType is used to describe the type that `mutations` should have. 11 | * This has a `SET_` method per property in `State`, that takes a payload of the 12 | * correct type. 13 | */ 14 | export type MutationsType = { 15 | [key in keyof T as `SET_${ UpperSnakeCase }`]: (state: T, payload: T[key]) => any; 16 | }; 17 | 18 | /** 19 | * ActionContext is the first argument for an action. We only declare the 20 | * subset we currently need. We're not using the types from Vuex as that does 21 | * not provide typing to match the mutations. 22 | */ 23 | export type ActionContext = { 24 | commit>( 25 | type: mutationType, 26 | payload: MutationsPayloadType[mutationType], 27 | commitOptions?: CommitOptions): void; 28 | dispatch: Dispatch; 29 | state: T; 30 | rootState: any; 31 | getters: any; 32 | }; 33 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Joran Dirk Greef 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/index.d.ts: -------------------------------------------------------------------------------- 1 | export function exec(cmd: string, 2 | options?: ((error?: Error, stdout?: string | Buffer, stderr?: string | Buffer) => void) 3 | | { name?: string, icns?: string, env?: { [key: string]: string } }, 4 | callback?: (error?: Error, stdout?: string | Buffer, stderr?: string | Buffer) => void): void; 5 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/linux.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/sudo-prompt/linux.png -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/macos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/sudo-prompt/macos.png -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "sudo-prompt", 3 | "version": "9.2.1", 4 | "description": "Run a command using sudo, prompting the user with an OS dialog if necessary", 5 | "main": "index.js", 6 | "types": "index.d.ts", 7 | "files": [ 8 | "LICENSE", 9 | "README.md", 10 | "index.d.ts", 11 | "index.js", 12 | "package.json", 13 | "test.js", 14 | "test-concurrent.js" 15 | ], 16 | "repository": { 17 | "type": "git", 18 | "url": "git+https://github.com/jorangreef/sudo-prompt.git" 19 | }, 20 | "keywords": [ 21 | "sudo", 22 | "os", 23 | "dialog", 24 | "prompt", 25 | "command", 26 | "exec", 27 | "user access control", 28 | "UAC", 29 | "privileges", 30 | "administrative", 31 | "elevate", 32 | "run as administrator" 33 | ], 34 | "author": "Joran Dirk Greef", 35 | "license": "MIT", 36 | "bugs": { 37 | "url": "https://github.com/jorangreef/sudo-prompt/issues" 38 | }, 39 | "homepage": "https://github.com/jorangreef/sudo-prompt#readme", 40 | "scripts": {} 41 | } 42 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/test-concurrent.js: -------------------------------------------------------------------------------- 1 | import { exec } from 'child_process'; 2 | 3 | import { exec as sudo } from './'; 4 | 5 | function kill(end) { 6 | if (process.platform === 'win32') { 7 | return end(); 8 | } 9 | exec('sudo -k', end); 10 | } 11 | 12 | kill( 13 | () => { 14 | const options = { name: 'Sudo Prompt' }; 15 | 16 | let sleep; 17 | 18 | if (process.platform === 'win32') { 19 | sleep = 'timeout /t 10\r\necho world'; 20 | } else { 21 | sleep = 'sleep 10 && echo world'; 22 | } 23 | sudo(sleep, options, 24 | (error, stdout, stderr) => { 25 | console.log(error, stdout, stderr); 26 | }, 27 | ); 28 | sudo('echo hello', options, 29 | (error, stdout, stderr) => { 30 | console.log(error, stdout, stderr); 31 | }, 32 | ); 33 | }, 34 | ); 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/sudo-prompt/windows.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/pkg/rancher-desktop/sudo-prompt/windows.png -------------------------------------------------------------------------------- /pkg/rancher-desktop/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "lib": [ 7 | "ESNext", 8 | "ESNext.AsyncIterable", 9 | "DOM" 10 | ], 11 | "esModuleInterop": true, 12 | "allowJs": true, 13 | "sourceMap": true, 14 | "strict": true, 15 | "noEmit": false, 16 | "experimentalDecorators": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@pkg/*": [ 20 | "./*" 21 | ] 22 | }, 23 | "typeRoots": [ 24 | "../../node_modules", 25 | "../../node_modules/@types", 26 | ], 27 | "types": [ 28 | "@nuxt/types", 29 | "@types/node", 30 | "@types/jest" 31 | ] 32 | }, 33 | "exclude": [ 34 | "node_modules", 35 | ".nuxt", 36 | "dist", 37 | "babel.config.js" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/assets.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@pkg/assets/*.yaml' { 2 | const content: any; 3 | export default content; 4 | } 5 | 6 | declare module '@pkg/assets/scripts/*' { 7 | const content: string; 8 | export default content; 9 | } 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/linux-ca.d.ts: -------------------------------------------------------------------------------- 1 | declare module 'linux-ca' { 2 | import * as forge from 'node-forge'; 3 | 4 | export function getAllCerts(readSync?: boolean): Promise; 5 | export function getFilteredCerts(filterAttribute: string, filterMethod?: (cert: forge.pki.Certificate, attribute: string) => boolean): Promise; 6 | export function pemToCert(pem: string): forge.pki.Certificate; 7 | export function certToPem(cert: forge.pki.Certificate): string; 8 | export function defaultFilter(cert: forge.pki.Certificate, subject: string): boolean; 9 | } 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/shell.d.ts: -------------------------------------------------------------------------------- 1 | declare module '@shell/core/types' { 2 | class IPlugin { 3 | metadata: any; 4 | addProduct: any; 5 | addRoutes: any; 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.vue' { 2 | import Vue from 'vue'; 3 | /* Load @nuxt/types, as a side effect it augments Vue */ 4 | import {} from '@nuxt/types'; 5 | export default Vue; 6 | } 7 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/unix.interface.ts: -------------------------------------------------------------------------------- 1 | export interface UnixError { 2 | stdout: string; 3 | stderr: string; 4 | code: string; 5 | message: string; 6 | } 7 | 8 | export const isUnixError = (val: any): val is UnixError => { 9 | return 'stdout' in val && 10 | 'stderr' in val && 11 | 'code' in val && 12 | 'message' in val; 13 | }; 14 | 15 | export interface NodeError { 16 | syscall: string; 17 | path: string; 18 | code: string; 19 | message: string; 20 | errno: number; 21 | } 22 | 23 | export const isNodeError = (val: any): val is NodeError => { 24 | return 'syscall' in val && 25 | 'path' in val && 26 | 'code' in val && 27 | 'message' in val; 28 | }; 29 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/typings/vue-i18n.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/no-unused-vars -- imported for side effect. 2 | import Vue from 'vue'; 3 | 4 | // This is required to keep typescript from complaining. It is required for 5 | // our i18n plugin. For more info see: 6 | // https://v2.vuejs.org/v2/guide/typescript.html?redirect=true#Augmenting-Types-for-Use-with-Plugins 7 | declare module 'vue/types/vue' { 8 | interface Vue { 9 | /** 10 | * Lookup a given string with the given arguments 11 | * @param raw if set, do not do HTML escaping. 12 | */ 13 | t: (key: string, args?: Record, raw?: boolean) => string, 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/DownloadProgressListener.ts: -------------------------------------------------------------------------------- 1 | import stream from 'stream'; 2 | 3 | /** 4 | * DownloadProgressListener observes a stream pipe to monitor progress. 5 | */ 6 | export default class DownloadProgressListener extends stream.Transform { 7 | protected status: { current: number }; 8 | 9 | /** 10 | * Construct a new DownloadProgressListener, which will update the passed-in 11 | * object on progress. No events will be emitted to avoid redrawing the UI 12 | * too often; a timer/interval should be used instead. 13 | * @param status A object that will be modified when download progress occurs. 14 | * @param options Options to pass to {stream.Transform}. 15 | */ 16 | constructor(status: { current: number }, options: stream.TransformOptions = {}) { 17 | super(options); 18 | this.status = status; 19 | } 20 | 21 | _transform(chunk: any, encoding: string, callback: stream.TransformCallback): void { 22 | if (encoding === 'buffer') { 23 | this.status.current += (chunk as Buffer).length; 24 | } else { 25 | this.status.current += (chunk as string).length; 26 | } 27 | callback(null, chunk); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/clone.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Clone a given object, returning a disconnected copy. 3 | * 4 | * @note This should be replaced via StructuredClone in NodeJS 18. 5 | * @note This only supports primitive objects (array, object, string, etc.) 6 | */ 7 | export default function clone(input: T): T { 8 | return JSON.parse(JSON.stringify(input)); 9 | } 10 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/dateUtils.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | export function currentTime(): string { 4 | const date = dayjs(Date.now()); 5 | 6 | return date.format('YYYY-MM-DD HH:mm'); 7 | } 8 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/environment.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Checks if Rancher Desktop is running in a development or test environment 3 | * @returns True if Rancher Desktop is running in a development or test 4 | * environment 5 | */ 6 | const isDev = /^(?:dev|test)/i.test(process.env.NODE_ENV || ''); 7 | const isE2E = /^e2e/i.test(process.env.RD_TEST ?? ''); 8 | 9 | export const isDevEnv = isDev || isE2E; 10 | export const isDevBuild = !isE2E && isDev; 11 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/filters.ts: -------------------------------------------------------------------------------- 1 | import { isArray } from './array'; 2 | 3 | /** 4 | * Can be used to merge arrays of primitive data types in lodash.mergeWith() function 5 | * 6 | * @param {*} objValue first array 7 | * @param {*} srcValue second array 8 | * @returns always second array (incoming value) 9 | */ 10 | export function arrayCustomizer(objValue: any, srcValue: any) { 11 | if (isArray(objValue) && objValue.every((i: any) => typeof i !== 'object')) { 12 | return srcValue; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/imageOutputCuller.js: -------------------------------------------------------------------------------- 1 | import ImageBuildOutputCuller from '@pkg/utils/processOutputInterpreters/image-build-output'; 2 | import ImageNonBuildOutputCuller from '@pkg/utils/processOutputInterpreters/image-non-build-output'; 3 | import TrivyScanImageOutputCuller from '@pkg/utils/processOutputInterpreters/trivy-image-output'; 4 | 5 | const cullersByName = { 6 | build: ImageBuildOutputCuller, 7 | 'trivy-image': TrivyScanImageOutputCuller, 8 | }; 9 | 10 | export default function getImageOutputCuller(command) { 11 | const klass = cullersByName[command] || ImageNonBuildOutputCuller; 12 | 13 | return new klass(); 14 | } 15 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/latch.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * Interface Latch is a simple extension on Promise that is resolved via calling 3 | * a method. It is essentially a simplified barrier. 4 | * 5 | * @see https://en.wikipedia.org/wiki/Barrier_(computer_science) 6 | */ 7 | interface Latch extends Promise { 8 | /** Calling the resolve() method resolves the Latch. */ 9 | resolve(): void; 10 | } 11 | 12 | /** 13 | * Creates a Latch that is an extension of a Promise that can be resolved via 14 | * calling a method on that Promise. 15 | */ 16 | export default function Latch(): Latch { 17 | const holder: {resolve?: () => void} = {}; 18 | const result: Latch = new Promise((resolve) => { 19 | holder.resolve = resolve; 20 | }) as any; 21 | 22 | if (!holder.resolve) { 23 | throw new Error('Promise created, but resolve function not set'); 24 | } 25 | result.resolve = holder.resolve; 26 | 27 | return result; 28 | } 29 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/networks.ts: -------------------------------------------------------------------------------- 1 | import os from 'os'; 2 | 3 | export enum networkStatus { 4 | CHECKING = 'checking...', 5 | CONNECTED = 'online', 6 | OFFLINE = 'offline', 7 | } 8 | 9 | export function wslHostIPv4Address(): string | undefined { 10 | const interfaces = os.networkInterfaces(); 11 | // The veth interface name changed at some time on Windows 11, so try the new name if the old one doesn't exist 12 | const iface = interfaces['vEthernet (WSL)'] ?? interfaces['vEthernet (WSL (Hyper-V firewall))'] ?? []; 13 | 14 | return iface.find(addr => addr.family === 'IPv4')?.address; 15 | } 16 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/osVersion.ts: -------------------------------------------------------------------------------- 1 | import * as process from 'process'; 2 | 3 | import semver from 'semver'; 4 | 5 | import { spawnFile } from '@pkg/utils/childProcess'; 6 | import { Log } from '@pkg/utils/logging'; 7 | 8 | let macOsVersion: semver.SemVer; 9 | 10 | export async function fetchMacOsVersion(console: Log) { 11 | let versionString = process.env.RD_MOCK_MACOS_VERSION; 12 | 13 | if (!versionString) { 14 | const { stdout } = await spawnFile('/usr/bin/sw_vers', ['-productVersion'], { stdio: ['ignore', 'pipe', console] }); 15 | 16 | versionString = stdout.trimEnd(); 17 | } 18 | const currentVersion = semver.coerce(versionString); 19 | 20 | if (currentVersion) { 21 | macOsVersion = currentVersion; 22 | } else { 23 | throw new Error(`Cannot convert "${ versionString }" to macOS semver`); 24 | } 25 | } 26 | 27 | export function getMacOsVersion(): semver.SemVer { 28 | return macOsVersion; 29 | } 30 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/processOutputInterpreters/__tests__/assets/trivy-image-metric-server-input.txt: -------------------------------------------------------------------------------- 1 | 2021-07-09T15:58:24.556-0700 INFO Detected OS: debian 2 | 2021-07-09T15:58:24.557-0700 INFO Detecting Debian vulnerabilities... 3 | 2021-07-09T15:58:24.559-0700 INFO Number of PL dependency files: 0 4 | 5 | rancher/metrics-server:v0.3.6 (debian 9.9) 6 | ========================================== 7 | Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) 8 | 9 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/processOutputInterpreters/__tests__/assets/trivy-image-metric-server-output.txt: -------------------------------------------------------------------------------- 1 | INFO Detected OS: debian 2 | INFO Detecting Debian vulnerabilities... 3 | INFO Number of PL dependency files: 0 4 | 5 | rancher/metrics-server:v0.3.6 (debian 9.9) 6 | ========================================== 7 | Total: 0 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0) 8 | 9 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/processOutputInterpreters/__tests__/image-build-output.spec.js: -------------------------------------------------------------------------------- 1 | import fs from 'fs'; 2 | import path from 'path'; 3 | 4 | import ImageBuildOutputCuller from '@pkg/utils/processOutputInterpreters/image-build-output'; 5 | 6 | describe('image build output', () => { 7 | it('returns the raw text back', () => { 8 | const buildOutputPath = path.join('./pkg/rancher-desktop/utils/processOutputInterpreters/__tests__/assets', 'build.txt'); 9 | const data = fs.readFileSync(buildOutputPath).toString(); 10 | const culler = new ImageBuildOutputCuller(); 11 | 12 | culler.addData(data); 13 | expect(culler.getProcessedData()).toBe(data.replace(/\r/g, '')); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/processOutputInterpreters/image-build-output.js: -------------------------------------------------------------------------------- 1 | const LineSplitter = /\r?\n/; 2 | 3 | export default class ImageBuildOutputCuller { 4 | constructor() { 5 | this.lines = []; 6 | } 7 | 8 | addData(data) { 9 | // TODO (possibly): Deal with partial final lines - I haven't seen this happen yet 10 | const lines = data.split(LineSplitter); 11 | 12 | this.lines.push(...lines); 13 | } 14 | 15 | getProcessedData() { 16 | return this.lines.join('\n'); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/string-encode.ts: -------------------------------------------------------------------------------- 1 | export const hexEncode = (str: string): string => Array.from(str) 2 | .map(c => `0${ c.charCodeAt(0).toString(16) }`.slice(-2)) 3 | .join(''); 4 | 5 | export const hexDecode = (hexString: string): string | undefined => hexString.match(/.{1,2}/g) 6 | ?.map(hex => String.fromCharCode(parseInt(hex, 16))) 7 | .join(''); 8 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/stringify.ts: -------------------------------------------------------------------------------- 1 | export function jsonStringifyWithWhiteSpace(obj: Record): string { 2 | return `${ JSON.stringify(obj, undefined, 2) }\n`; 3 | } 4 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/testUtils/mockResources.ts: -------------------------------------------------------------------------------- 1 | // `Symbol.dispose` exists as of NodeJS 20; if it's unset, set it (because we 2 | // are currently on NodeJS 18). 3 | (Symbol as any).dispose ??= Symbol.for('nodejs.dispose'); 4 | 5 | /** 6 | * Given a Jest SpyInstance, return it as a Disposable such that mockRestore will 7 | * be called when the instance goes out of scope. 8 | * @note This will no longer be needed as of Jest 30 (where it's built in). 9 | */ 10 | export function withResource< 11 | T = any, 12 | Y extends any[] = any, 13 | C = any, 14 | U extends jest.MockInstance = any, 15 | >(input: U): U & Disposable { 16 | (input as any)[Symbol.dispose] = () => { 17 | input.mockRestore(); 18 | }; 19 | 20 | return input as U & Disposable; 21 | } 22 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/testUtils/setupElectron.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file is preloaded into all Jest tests (see package.json, 3 | * `jest.setupFiles`) and is used to force-mock Electron as that does not work 4 | * inside Jest. 5 | */ 6 | 7 | import path from 'path'; 8 | 9 | if ('jest' in globalThis && 'mock' in jest) { 10 | jest.mock('electron', () => { 11 | return { 12 | __esModule: true, 13 | default: { 14 | app: { 15 | isPackaged: false, 16 | getAppPath: () => path.resolve('.'), 17 | }, 18 | ipcMain: {}, 19 | }, 20 | }; 21 | }); 22 | } 23 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/utils/wslVersion.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This exports a single function to ask wsl-helper about the current WSL 3 | * version. 4 | */ 5 | 6 | import { spawnFile } from '@pkg/utils/childProcess'; 7 | import logging from '@pkg/utils/logging'; 8 | import { executable } from '@pkg/utils/resources'; 9 | 10 | export type WSLVersionInfo = { 11 | installed: boolean; 12 | inbox: boolean; 13 | 14 | has_kernel: boolean; 15 | outdated_kernel: boolean; 16 | version: { 17 | major: number; 18 | minor: number; 19 | build: number; 20 | revision: number; 21 | }; 22 | kernel_version: { 23 | major: number; 24 | minor: number; 25 | build: number; 26 | revision: number; 27 | } 28 | }; 29 | 30 | const console = logging['wsl-version']; 31 | 32 | /** 33 | * Get information about the currently installed WSL version. 34 | */ 35 | export default async function getWSLVersion(): Promise { 36 | const { stdout } = await spawnFile(executable('wsl-helper'), 37 | ['wsl', 'info'], { stdio: ['ignore', 'pipe', console] }); 38 | 39 | return JSON.parse(stdout); 40 | } 41 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/window/constants.ts: -------------------------------------------------------------------------------- 1 | export const mainRoutes = [ 2 | { route: '/General' }, 3 | { route: '/Containers', experimental: true }, 4 | { route: '/PortForwarding' }, 5 | { route: '/Images' }, 6 | { route: '/Snapshots' }, 7 | { route: '/Troubleshooting' }, 8 | { route: '/Diagnostics' }, 9 | { route: '/Extensions' }, 10 | ]; 11 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/window/dashboard.ts: -------------------------------------------------------------------------------- 1 | import { BrowserWindow } from 'electron'; 2 | 3 | import { windowMapping, restoreWindow } from '.'; 4 | 5 | const dashboardURL = 'http://127.0.0.1:6120/c/local/explorer'; 6 | 7 | const getDashboardWindow = () => ('dashboard' in windowMapping) ? BrowserWindow.fromId(windowMapping['dashboard']) : null; 8 | 9 | export function openDashboard() { 10 | let window = getDashboardWindow(); 11 | 12 | if (restoreWindow(window)) { 13 | return window; 14 | } 15 | 16 | window = new BrowserWindow({ 17 | title: 'Rancher Dashboard', 18 | width: 800, 19 | height: 600, 20 | show: false, 21 | }); 22 | 23 | window.loadURL(dashboardURL); 24 | 25 | windowMapping['dashboard'] = window.id; 26 | 27 | window.once('ready-to-show', () => { 28 | window?.show(); 29 | }); 30 | } 31 | 32 | export function closeDashboard() { 33 | getDashboardWindow()?.close(); 34 | } 35 | -------------------------------------------------------------------------------- /pkg/rancher-desktop/window/preferenceConstants.ts: -------------------------------------------------------------------------------- 1 | import { NavItemName } from '@pkg/config/transientSettings'; 2 | 3 | interface NavItems { 4 | name: NavItemName; 5 | tabs?: string[]; 6 | } 7 | const wslTabs: string[] = ['integrations', 'network', 'proxy']; 8 | const vmLinuxTabs: string[] = ['hardware', 'volumes']; 9 | const vmDarwinTabs: string[] = vmLinuxTabs.concat(['network', 'emulation']); 10 | 11 | export const preferencesNavItems: NavItems[] = [ 12 | { 13 | name: 'Application', 14 | tabs: ['general', 'behavior', 'environment'], 15 | }, 16 | { 17 | name: process.platform === 'win32' ? 'WSL' : 'Virtual Machine', 18 | tabs: process.platform === 'win32' ? wslTabs : ( process.platform === 'linux' ? vmLinuxTabs : vmDarwinTabs ), 19 | }, 20 | { 21 | name: 'Container Engine', 22 | tabs: ['general', 'allowed-images'], 23 | }, 24 | { name: 'Kubernetes' }, 25 | ]; 26 | -------------------------------------------------------------------------------- /resources/darwin/bin/nerdctl: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu -o pipefail 3 | 4 | scriptname="${BASH_SOURCE[0]}" 5 | while [ -L "${scriptname}" ]; do 6 | scriptname="$(readlink "${scriptname}")" 7 | done 8 | scriptdir="$(cd "$(dirname "${scriptname}")" && pwd)" 9 | 10 | if ! LIMA_HOME="$HOME/Library/Application Support/rancher-desktop/lima" "${scriptdir}/../lima/bin/limactl" ls --json | grep '"name":"0"' | grep -q '"status":"Running"'; then 11 | echo "Rancher Desktop is not running. Please start Rancher Desktop to use nerdctl"; 12 | exit 1 13 | else 14 | "${scriptdir}/rdctl" shell sudo --preserve-env=SSH_AUTH_SOCK nerdctl "$@" 15 | fi 16 | -------------------------------------------------------------------------------- /resources/darwin/bin/spin: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu -o pipefail 3 | 4 | scriptname="${BASH_SOURCE[0]}" 5 | while [ -L "${scriptname}" ]; do 6 | scriptname=$(readlink "${scriptname}") 7 | done 8 | scriptdir=$(cd "$(dirname "${scriptname}")" && pwd) 9 | internal=$(cd "${scriptdir}/../internal" && pwd) 10 | 11 | export SPIN_DATA_DIR="$HOME/Library/Application Support/rancher-desktop/spin" 12 | mkdir -p "$SPIN_DATA_DIR" 13 | exec "${internal}/spin" "$@" 14 | -------------------------------------------------------------------------------- /resources/icons/containerd-icon-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/containerd-icon-color.png -------------------------------------------------------------------------------- /resources/icons/issue-opened-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/issue-opened-16.png -------------------------------------------------------------------------------- /resources/icons/issue-opened-16.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /resources/icons/issue-opened-16@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/issue-opened-16@2x.png -------------------------------------------------------------------------------- /resources/icons/kubernetes-icon-black-orig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/kubernetes-icon-black-orig.png -------------------------------------------------------------------------------- /resources/icons/kubernetes-icon-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/kubernetes-icon-black.png -------------------------------------------------------------------------------- /resources/icons/kubernetes-icon-color-orig.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/kubernetes-icon-color-orig.png -------------------------------------------------------------------------------- /resources/icons/kubernetes-icon-color.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/kubernetes-icon-color.png -------------------------------------------------------------------------------- /resources/icons/logo-square-512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-512.png -------------------------------------------------------------------------------- /resources/icons/logo-square-bw.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-bw.png -------------------------------------------------------------------------------- /resources/icons/logo-square-bw@1.25x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-bw@1.25x.png -------------------------------------------------------------------------------- /resources/icons/logo-square-bw@1.5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-bw@1.5x.png -------------------------------------------------------------------------------- /resources/icons/logo-square-bw@2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-bw@2.png -------------------------------------------------------------------------------- /resources/icons/logo-square-red.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-red.png -------------------------------------------------------------------------------- /resources/icons/logo-square-red@1.25x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-red@1.25x.png -------------------------------------------------------------------------------- /resources/icons/logo-square-red@1.5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-red@1.5x.png -------------------------------------------------------------------------------- /resources/icons/logo-square-red@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square-red@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square.png -------------------------------------------------------------------------------- /resources/icons/logo-square@1.25x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square@1.25x.png -------------------------------------------------------------------------------- /resources/icons/logo-square@1.5x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square@1.5x.png -------------------------------------------------------------------------------- /resources/icons/logo-square@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-square@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-tray-Template@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-tray-Template@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-tray-error-Template@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-tray-error-Template@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-tray-starting-Template@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-tray-starting-Template@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-tray-stopped-Template@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-tray-stopped-Template@2x.png -------------------------------------------------------------------------------- /resources/icons/logo-tray-stopping-Template@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/logo-tray-stopping-Template@2x.png -------------------------------------------------------------------------------- /resources/icons/mac-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/resources/icons/mac-icon.png -------------------------------------------------------------------------------- /resources/linux/bin/nerdctl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | if grep -q -i 'microsoft.*wsl' /proc/version; then 4 | exec /mnt/wsl/rancher-desktop/bin/nerdctl "$@" 5 | else 6 | limaloc="${XDG_DATA_HOME:-$HOME/.local/share}/rancher-desktop" 7 | scriptname="$0" 8 | while [ -L "${scriptname}" ]; do 9 | scriptname="$(readlink "${scriptname}")" 10 | done 11 | scriptdir="$(cd "$(dirname "${scriptname}")" && pwd)" 12 | 13 | if ! LIMA_HOME="${limaloc}/lima" "${scriptdir}/../lima/bin/limactl" ls --json | grep '"name":"0"' | grep -q '"status":"Running"'; then 14 | echo "Rancher Desktop is not running. Please start Rancher Desktop to use nerdctl"; 15 | exit 1 16 | else 17 | "${scriptdir}/rdctl" shell sudo --preserve-env=SSH_AUTH_SOCK nerdctl "$@" 18 | fi 19 | fi 20 | -------------------------------------------------------------------------------- /resources/linux/bin/spin: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -eu -o pipefail 3 | 4 | scriptname="${BASH_SOURCE[0]}" 5 | while [ -L "${scriptname}" ]; do 6 | scriptname=$(readlink "${scriptname}") 7 | done 8 | scriptdir=$(cd "$(dirname "${scriptname}")" && pwd) 9 | internal=$(cd "${scriptdir}/../internal" && pwd) 10 | 11 | export SPIN_DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/rancher-desktop/spin" 12 | mkdir -p "$SPIN_DATA_DIR" 13 | exec "${internal}/spin" "$@" 14 | -------------------------------------------------------------------------------- /screenshots/extensions/logs-explorer-0.2.2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rancher-sandbox/rancher-desktop/0216266849036b910dd0edd5c9f3c28a3424320e/screenshots/extensions/logs-explorer-0.2.2.png -------------------------------------------------------------------------------- /screenshots/test-data/preferences.ts: -------------------------------------------------------------------------------- 1 | export const lockedSettings = { 2 | body: JSON.stringify({ 3 | containerEngine: { 4 | allowedImages: { 5 | enabled: true, 6 | patterns: true, 7 | }, 8 | }, 9 | kubernetes: { version: true }, 10 | }), 11 | status: 200, 12 | headers: {}, 13 | }; 14 | -------------------------------------------------------------------------------- /screenshots/test-data/snapshots.ts: -------------------------------------------------------------------------------- 1 | import dayjs from 'dayjs'; 2 | 3 | export const snapshotsList = { 4 | body: JSON.stringify([{ 5 | name: 'Snapshot 1', 6 | created: dayjs(new Date(), 'YYYY-MM-DD_HH_mm_ss').subtract(5, 'minute'), 7 | }, { 8 | name: 'Snapshot 2', 9 | created: dayjs(new Date(), 'YYYY-MM-DD_HH_mm_ss'), 10 | }]), 11 | status: 200, 12 | headers: {}, 13 | }; 14 | -------------------------------------------------------------------------------- /scripts/dependencies/sudo-prompt.ts: -------------------------------------------------------------------------------- 1 | import path from 'path'; 2 | 3 | import { Dependency, DownloadContext } from 'scripts/lib/dependencies'; 4 | import { simpleSpawn } from 'scripts/simple_process'; 5 | 6 | /** 7 | * SudoPrompt represents the sudo-prompt.app applet used by sudo-prompt on macOS. 8 | */ 9 | export class SudoPrompt implements Dependency { 10 | readonly name = 'sudo-prompt'; 11 | 12 | async download(_: DownloadContext): Promise { 13 | // Rather than actually downloading anything, this builds the source code. 14 | const sourceDir = path.join(process.cwd(), 'src', 'sudo-prompt'); 15 | 16 | console.log(`Building sudo-prompt applet`); 17 | await simpleSpawn('./build-sudo-prompt', [], { cwd: sourceDir }); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /scripts/extension-data.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file generates pkg/rancher-desktop/assets/extension-data.yaml 3 | * 4 | * Usage: `yarn generate:extension-data` 5 | */ 6 | 7 | import { generateExtensionMarketplaceData } from './lib/extension-data'; 8 | 9 | generateExtensionMarketplaceData().catch((ex) => { 10 | console.error(ex); 11 | process.exit(1); 12 | }); 13 | -------------------------------------------------------------------------------- /scripts/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/scripts 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.4 6 | 7 | require golang.org/x/mod v0.24.0 8 | -------------------------------------------------------------------------------- /scripts/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= 2 | golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= 3 | -------------------------------------------------------------------------------- /scripts/node-license-check.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | set -o errexit -o nounset -o pipefail 4 | 5 | # There is a single module with 0BSD license which is actually BSD-2-clause on GitHub 6 | ALLOWED="Apache-2.0|0?BSD|ISC|MIT|Python-2.0|Unlicense" 7 | 8 | # jq doesn't support \b word boundaries, so expand "\b(${ALLOWED})\b" into something supported 9 | REGEX="(^|[^a-zA-Z0-9_])(${ALLOWED})($|[^a-zA-Z0-9_])" 10 | 11 | JQ=".data.body[] | select(.[2] | test(\"${REGEX}\") | not)" 12 | FORBIDDEN=$(yarn licenses list --prod --json --no-progress | jq -r "$JQ") 13 | 14 | if [[ -z $FORBIDDEN ]]; then 15 | echo "All NPM modules have licenses matching ${ALLOWED}" 16 | exit 0 17 | fi 18 | 19 | echo "Forbidden license(s) detected; allowed are ${ALLOWED}" 20 | echo "$FORBIDDEN" 21 | exit 1 22 | -------------------------------------------------------------------------------- /scripts/ts-wrapper.js: -------------------------------------------------------------------------------- 1 | /** 2 | * This script is a wrapper to run TypeScript scripts via tsx. This is mostly 3 | * to set defaults for our tools, such as disabling BrowsersList updates and 4 | * showing deprecations. 5 | */ 6 | 7 | const { spawnSync } = require('node:child_process'); 8 | 9 | function main(args) { 10 | const childArgs = [ 11 | '--trace-warnings', 12 | '--trace-deprecation', 13 | 'node_modules/tsx/dist/cli.mjs', 14 | '--conditions=import', 15 | ]; 16 | 17 | const finalArgs = [...childArgs, ...args]; 18 | 19 | console.log(process.argv0, ...finalArgs); 20 | const result = spawnSync(process.argv0, finalArgs, { stdio: 'inherit' }); 21 | 22 | if (result.error) { 23 | throw result.error; 24 | } 25 | 26 | if (typeof result.status === 'number') { 27 | process.exit(result.status); 28 | } 29 | 30 | if (result.signal) { 31 | console.log(`Process exited with signal ${ result.signal }`); 32 | process.exit(-1); 33 | } 34 | } 35 | 36 | if (require.main === module) { 37 | // Silence BrowsersList warnings because they're pointless for us 38 | process.env.BROWSERSLIST_IGNORE_OLD_DATA = 'true'; // spellcheck-ignore-line 39 | main(process.argv.slice(2)); 40 | } 41 | -------------------------------------------------------------------------------- /scripts/windows/generate-nerdctl-stub.ps1: -------------------------------------------------------------------------------- 1 | # This script is executed on Windows to regenerate the nerdctl stub argument 2 | # parsers. This must be executed on Windows as we need a stable platform to be 3 | # able to find nerdctl. 4 | 5 | param( 6 | [switch]$Verbose 7 | ) 8 | 9 | $ENV:GOOS = "linux" 10 | 11 | Set-Location src/go/nerdctl-stub/generate 12 | go build . 13 | wsl.exe -d rancher-desktop --exec ./generate "-verbose=$Verbose" 14 | Remove-Item ./generate 15 | gofmt -w ../nerdctl_commands_generated.go 16 | -------------------------------------------------------------------------------- /scripts/windows/sudo-install-wsl.ps1: -------------------------------------------------------------------------------- 1 | # ////////////////////////////////////////////////////////////////////// 2 | # sudo-install-ws1.ps1 3 | 4 | Param( 5 | [Parameter(Mandatory)] 6 | [ValidateSet("EnableWSL-01", "EnableVMPlatform-02", "InstallLinuxUpdatePackage-03")] 7 | $Step = "EnableWSL-01") 8 | 9 | $script = $myInvocation.MyCommand.Definition 10 | $scriptPath = Split-Path -parent $script 11 | . (Join-Path $scriptpath restart-helpers.ps1) 12 | 13 | try { 14 | Start-Process $psHome\powershell.exe -Verb Runas -ArgumentList "$ScriptPath/install-wsl.ps1 -Step $Step" 15 | } catch { 16 | echo "Something bad happened" 17 | pause 18 | } 19 | -------------------------------------------------------------------------------- /scripts/windows/uninstall-wsl.ps1: -------------------------------------------------------------------------------- 1 | # ////////////////////////////////////////////////////////////////////// 2 | # uninstall-wsl.ps1 3 | 4 | $script = $myInvocation.MyCommand.Definition 5 | $scriptPath = Split-Path -parent $script 6 | . (Join-Path $scriptpath restart-helpers.ps1) 7 | 8 | # Magic PowerShell comment to require admin; see 9 | # https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_requires?view=powershell-5.1#-runasadministrator 10 | 11 | #Requires -RunAsAdministrator 12 | 13 | wslconfig /u k3s 14 | 15 | Disable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux -NoRestart 16 | 17 | Restart-Machine-On-Acceptance -Action "uninstall wsl" 18 | -------------------------------------------------------------------------------- /scripts/wix.ts: -------------------------------------------------------------------------------- 1 | // This script builds the wix installer, assuming the zip file has already been 2 | // built (and dist/win-unpacked is populated). 3 | // This is only used during development. 4 | 5 | import fs from 'fs'; 6 | import path from 'path'; 7 | 8 | import buildInstaller, { buildCustomAction } from './lib/installer-win32'; 9 | 10 | async function run() { 11 | const distDir = path.join(process.cwd(), 'dist'); 12 | const appDir = path.join(distDir, 'win-unpacked'); 13 | 14 | try { 15 | await fs.promises.access(path.join(appDir, 'resources', 'app.asar'), fs.constants.R_OK); 16 | } catch (ex) { 17 | if ((ex as NodeJS.ErrnoException).code !== 'ENOENT') { 18 | throw ex; 19 | } 20 | console.error(`Could not find ${ appDir }, please run \`yarn build\` first.`); 21 | process.exit(1); 22 | } 23 | 24 | const customActionFile = await buildCustomAction(); 25 | 26 | await fs.promises.copyFile(customActionFile, 27 | path.join(appDir, path.basename(customActionFile))); 28 | await buildInstaller(distDir, appDir); 29 | } 30 | 31 | run().catch((ex) => { 32 | console.error(ex); 33 | process.exit(1); 34 | }); 35 | -------------------------------------------------------------------------------- /src/go/docker-credential-none/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/src/go/docker-credential-none 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.24.1 6 | 7 | require ( 8 | github.com/docker/cli v28.2.2+incompatible 9 | github.com/docker/docker-credential-helpers v0.9.3 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 14 | github.com/google/go-cmp v0.7.0 // indirect 15 | github.com/pkg/errors v0.9.1 // indirect 16 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 17 | github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af // indirect 18 | github.com/stretchr/testify v1.10.0 // indirect 19 | golang.org/x/sys v0.33.0 // indirect 20 | gotest.tools/v3 v3.5.1 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /src/go/docker-credential-none/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "github.com/docker/docker-credential-helpers/credentials" 5 | 6 | "github.com/rancher-sandbox/rancher-desktop/src/go/docker-credential-none/dcnone" 7 | ) 8 | 9 | func main() { 10 | credentials.Serve(dcnone.DCNone{}) 11 | } 12 | -------------------------------------------------------------------------------- /src/go/extension-proxy/README.md: -------------------------------------------------------------------------------- 1 | # extension-proxy 2 | 3 | This program is used to forward HTTP requests from the extension frontend to the 4 | extension backend. The frontend makes a HTTP request using a relative URL 5 | (doing something like `ddClient.extension.vm.service.get('/foo')`), which must 6 | be routed to the backend listening on a Unix socket. This program is used to 7 | handle the forwarding from some TCP port into that Unix socket. 8 | 9 | The environment variable `SOCKET` should be set to the path of a Unix socket, 10 | which will be forwarded to port 80. Typically this would be set to the name of 11 | a socket in `/run/guest-services/`, which is then shared (via a volume) with 12 | other containers. 13 | -------------------------------------------------------------------------------- /src/go/extension-proxy/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/src/go/extension-port-forwarder 2 | 3 | go 1.22.0 4 | -------------------------------------------------------------------------------- /src/go/guestagent/README.md: -------------------------------------------------------------------------------- 1 | [Rancher Desktop Guest Agent](/docs/networking/windows/rancher-desktop-guest-agent.md) -------------------------------------------------------------------------------- /src/go/guestagent/pkg/forwarder/forwarder.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 SUSE LLC 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | // Package forwarder implements a forwarding mechanism to forward 15 | // port mappings over the network. 16 | package forwarder 17 | 18 | import ( 19 | "github.com/rancher-sandbox/rancher-desktop/src/go/guestagent/pkg/types" 20 | ) 21 | 22 | // Forwarder is the interface that wraps the Send method which 23 | // to forward the port mappings. 24 | type Forwarder interface { 25 | // Send sends the give port mappings to the Peer via 26 | // a tcp connection. 27 | Send(portMapping types.PortMapping) error 28 | } 29 | -------------------------------------------------------------------------------- /src/go/guestagent/pkg/kube/watcher_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | /* 4 | Copyright © 2024 SUSE LLC 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package kube 17 | 18 | import ( 19 | "context" 20 | "fmt" 21 | "net" 22 | 23 | "github.com/rancher-sandbox/rancher-desktop/src/go/guestagent/pkg/tracker" 24 | ) 25 | 26 | func WatchForServices( 27 | ctx context.Context, 28 | configPath string, 29 | k8sServiceListenerIP net.IP, 30 | portTracker tracker.Tracker, 31 | ) error { 32 | return fmt.Errorf("not implemented for non-linux") 33 | } 34 | -------------------------------------------------------------------------------- /src/go/guestagent/pkg/procnet/scanner_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | /* 4 | Copyright © 2024 SUSE LLC 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | package procnet 17 | 18 | import ( 19 | "context" 20 | "fmt" 21 | "time" 22 | 23 | "github.com/rancher-sandbox/rancher-desktop/src/go/guestagent/pkg/tracker" 24 | ) 25 | 26 | type ProcNetScanner struct{} 27 | 28 | func NewProcNetScanner(context.Context, tracker.Tracker, time.Duration) (*ProcNetScanner, error) { 29 | panic("only implemented for Linux") 30 | } 31 | 32 | func (p *ProcNetScanner) ForwardPorts() error { 33 | return fmt.Errorf("only implemented for Linux") 34 | } 35 | -------------------------------------------------------------------------------- /src/go/mock-wsl/README.md: -------------------------------------------------------------------------------- 1 | # mock-wsl 2 | 3 | This is a mock `wsl.exe` that is used in the E2E tests, used to stub out 4 | interaction with the real WSL. 5 | 6 | ## Configuration 7 | 8 | The environment variable `RD_MOCK_WSL_DATA` should be set to the absolute path 9 | of a JSON file describing how the executable should act. This file will be 10 | modified as part of the run to contain the results and errors. 11 | 12 | Please see [`schema.json`](./schema.json) for the JSON schema for the file. 13 | -------------------------------------------------------------------------------- /src/go/mock-wsl/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/e2e/assets/mock-wsl 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.4 6 | 7 | require ( 8 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 9 | golang.org/x/sys v0.33.0 10 | golang.org/x/text v0.25.0 11 | ) 12 | -------------------------------------------------------------------------------- /src/go/mock-wsl/go.sum: -------------------------------------------------------------------------------- 1 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= 2 | golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= 3 | golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= 4 | golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 5 | golang.org/x/text v0.25.0 h1:qVyWApTSYLk/drJRO5mDlNYskwQznZmkpV2c8q9zls4= 6 | golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA= 7 | -------------------------------------------------------------------------------- /src/go/mock-wsl/lock_file_other.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | /* 4 | Copyright © 2024 SUSE LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package main 20 | 21 | import ( 22 | "fmt" 23 | "os" 24 | ) 25 | 26 | func lockFile(_ *os.File) error { 27 | return fmt.Errorf("not implemented") 28 | } 29 | -------------------------------------------------------------------------------- /src/go/mock-wsl/lock_file_windows.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "fmt" 5 | "math" 6 | "os" 7 | 8 | "golang.org/x/sys/windows" 9 | ) 10 | 11 | // lockFile locks the given file for exclusive access; if the file is already 12 | // locked, this function will wait until it is unlocked. 13 | func lockFile(f *os.File) error { 14 | err := windows.LockFileEx( 15 | windows.Handle(f.Fd()), 16 | windows.LOCKFILE_EXCLUSIVE_LOCK, 17 | 0, 18 | math.MaxUint32, math.MaxUint32, 19 | &windows.Overlapped{}) 20 | if err != nil { 21 | return fmt.Errorf("failed to lock file: %w", err) 22 | } 23 | return nil 24 | } 25 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/README.md: -------------------------------------------------------------------------------- 1 | # nerdctl-stub 2 | 3 | This is a stub executable used to launch nerdctl on Windows (and WSL). 4 | 5 | ## Usage 6 | 7 | Use like normal nerdctl, except that some things can be controlled via 8 | environment variables: 9 | 10 | Variable | Meaning | Default 11 | --- | --- | --- 12 | RD_WSL_DISTRO | WSL distribution to run in | `rancher-desktop` 13 | RD_NERDCTL | `nerdctl` executable | `/usr/local/bin/nerdctl` 14 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/debugging_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !debug 2 | 3 | /* 4 | Copyright © 2024 SUSE LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package main 20 | 21 | // describeCommands is a debugging function that prints out all commands. 22 | // This implementation is a stub that does nothing. 23 | func describeCommands() { 24 | } 25 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/generate/README.md: -------------------------------------------------------------------------------- 1 | # nerdctl-sub/generate 2 | 3 | This directory contains a tool that generates the argument parser for 4 | nerdctl-stub (by parsing the output of `nerdctl -help`). 5 | 6 | ## Usage 7 | 8 | ```powershell 9 | yarn generate:nerdctl-stub 10 | ``` 11 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/generate/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/src/go/nerdctl-stub/generate 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.4 6 | 7 | require github.com/sirupsen/logrus v1.9.4-0.20230606125235-dd1b4c2e81af 8 | 9 | require ( 10 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 11 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 12 | github.com/stretchr/testify v1.10.0 // indirect 13 | golang.org/x/sys v0.33.0 // indirect 14 | ) 15 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/generate/main_stub.go: -------------------------------------------------------------------------------- 1 | //go:build !linux 2 | 3 | package main 4 | 5 | import ( 6 | "log" 7 | ) 8 | 9 | func main() { 10 | log.Fatal("nerdctl-stub generate needs to be done on Linux") 11 | } 12 | -------------------------------------------------------------------------------- /src/go/nerdctl-stub/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/src/go/nerdctl-stub 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.4 6 | 7 | require ( 8 | github.com/hashicorp/go-multierror v1.1.1 9 | github.com/stretchr/testify v1.10.0 10 | golang.org/x/sys v0.33.0 11 | ) 12 | 13 | require ( 14 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 15 | github.com/hashicorp/errwrap v1.1.0 // indirect 16 | github.com/kr/pretty v0.3.1 // indirect 17 | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 18 | github.com/rogpeppe/go-internal v1.13.1 // indirect 19 | gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect 20 | gopkg.in/yaml.v3 v3.0.1 // indirect 21 | ) 22 | -------------------------------------------------------------------------------- /src/go/networking/.gitignore: -------------------------------------------------------------------------------- 1 | /bin/ 2 | capture.pcap 3 | tmp/ 4 | *.exe 5 | -------------------------------------------------------------------------------- /src/go/networking/Makefile: -------------------------------------------------------------------------------- 1 | LDFLAGS = -ldflags '-s -w' 2 | 3 | .PHONY: build 4 | build: host-switch vm-switch network-setup wsl-proxy 5 | 6 | bin/host-switch.exe: 7 | GOOS=windows go build $(LDFLAGS) -o $@ ./cmd/host 8 | 9 | .PHONY: host-switch 10 | host-switch: bin/host-switch.exe 11 | 12 | bin/vm-switch: 13 | GOOS=linux go build $(LDFLAGS) -o $@ ./cmd/vm 14 | 15 | .PHONY: vm-switch 16 | vm-switch: bin/vm-switch 17 | 18 | bin/network-setup: 19 | GOOS=linux go build $(LDFLAGS) -o $@ ./cmd/network 20 | 21 | .PHONY: network-setup 22 | network-setup: bin/network-setup 23 | 24 | bin/wsl-proxy: 25 | GOOS=linux go build $(LDFLAGS) -o $@ ./cmd/proxy 26 | 27 | .PHONY: wsl-proxy 28 | wsl-proxy: bin/wsl-proxy 29 | 30 | .PHONY: fmt 31 | fmt: 32 | gofmt -l -s -w . 33 | 34 | .PHONY: clean 35 | clean: 36 | rm -rf ./bin 37 | 38 | .PHONY: vendor 39 | vendor: 40 | go mod tidy 41 | go mod vendor 42 | -------------------------------------------------------------------------------- /src/go/networking/pkg/log/log.go: -------------------------------------------------------------------------------- 1 | package log 2 | 3 | /* 4 | Copyright © 2023 SUSE LLC 5 | Licensed under the Apache License, Version 2.0 (the "License"); 6 | you may not use this file except in compliance with the License. 7 | You may obtain a copy of the License at 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | */ 15 | 16 | import ( 17 | "os" 18 | 19 | "github.com/sirupsen/logrus" 20 | ) 21 | 22 | const fileMode = 0o666 23 | 24 | // SetOutputFile sets the logger output with a given file 25 | func SetOutputFile(filePath string, logger *logrus.Logger) error { 26 | logFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, fileMode) 27 | if err != nil { 28 | return err 29 | } 30 | logger.SetOutput(logFile) 31 | 32 | return nil 33 | } 34 | -------------------------------------------------------------------------------- /src/go/networking/pkg/vsock/conn_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 SUSE LLC 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | package vsock 15 | 16 | import ( 17 | "fmt" 18 | "net" 19 | 20 | "github.com/Microsoft/go-winio" 21 | "github.com/linuxkit/virtsock/pkg/hvsock" 22 | ) 23 | 24 | func Listen(vmGUID hvsock.GUID, vsockPort uint32) (net.Listener, error) { 25 | svcPort, err := hvsock.GUIDFromString(winio.VsockServiceID(vsockPort).String()) 26 | if err != nil { 27 | return nil, fmt.Errorf("Listen, could not parse Hyper-v service GUID: %v", err) 28 | } 29 | 30 | addr := hvsock.Addr{ 31 | VMID: vmGUID, 32 | ServiceID: svcPort, 33 | } 34 | 35 | return hvsock.Listen(addr) 36 | } 37 | -------------------------------------------------------------------------------- /src/go/networking/pkg/vsock/constants.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | http://www.apache.org/licenses/LICENSE-2.0 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | */ 13 | 14 | package vsock 15 | 16 | const ( 17 | SignaturePhrase = "github.com/rancher-sandbox/rancher-desktop/src/go/networking" 18 | ReadySignal = "READY" 19 | ) 20 | -------------------------------------------------------------------------------- /src/go/rdctl/README.md: -------------------------------------------------------------------------------- 1 | # rdctl 2 | 3 | This is the command-line interface (CLI) for Rancher Desktop. 4 | 5 | ## Prerequisites 6 | 7 | This tool depends on code generated during `yarn postinstall`. 8 | 9 | ## Usage 10 | 11 | Run `rdctl --help` for usage information. 12 | 13 | Much of `rdctl`'s functionality depends on the HTTP server running within Rancher Desktop, 14 | but some functionality is available when it isn't running, in particular the 15 | `rdctl factory-reset` command, which can be used to remove files generated by Rancher Desktop, 16 | those required for its functionality, and state files, such as a VM snapshot. 17 | -------------------------------------------------------------------------------- /src/go/rdctl/cmd/paths.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "os" 7 | 8 | "github.com/spf13/cobra" 9 | 10 | p "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" 11 | ) 12 | 13 | var pathsCmd = &cobra.Command{ 14 | Hidden: true, 15 | Use: "paths", 16 | Short: "Print the paths to directories that Rancher Desktop uses", 17 | RunE: func(cmd *cobra.Command, args []string) error { 18 | paths, err := p.GetPaths() 19 | if err != nil { 20 | return fmt.Errorf("failed to construct Paths: %w", err) 21 | } 22 | encoder := json.NewEncoder(os.Stdout) 23 | err = encoder.Encode(paths) 24 | if err != nil { 25 | return fmt.Errorf("failed to output paths: %w", err) 26 | } 27 | return nil 28 | }, 29 | } 30 | 31 | func init() { 32 | rootCmd.AddCommand(pathsCmd) 33 | } 34 | -------------------------------------------------------------------------------- /src/go/rdctl/cmd/setup.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "errors" 5 | 6 | "github.com/spf13/cobra" 7 | 8 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/autostart" 9 | ) 10 | 11 | var setupSettings struct { 12 | AutoStart bool 13 | } 14 | 15 | var setupCmd = &cobra.Command{ 16 | Hidden: true, 17 | Use: "setup", 18 | Short: "Configure the system without modifying settings", 19 | RunE: func(cmd *cobra.Command, args []string) error { 20 | if cmd.Flags().Changed("auto-start") { 21 | return autostart.EnsureAutostart(cmd.Context(), setupSettings.AutoStart) 22 | } 23 | return errors.New("no changes were specified") 24 | }, 25 | } 26 | 27 | func init() { 28 | rootCmd.AddCommand(setupCmd) 29 | setupCmd.Flags().BoolVar(&setupSettings.AutoStart, "auto-start", false, "Whether to start Rancher Desktop at login") 30 | } 31 | -------------------------------------------------------------------------------- /src/go/rdctl/cmd/snapshotDelete.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "fmt" 5 | 6 | "github.com/spf13/cobra" 7 | 8 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/snapshot" 9 | ) 10 | 11 | var snapshotDeleteCmd = &cobra.Command{ 12 | Use: "delete ", 13 | Short: "Delete a snapshot", 14 | Args: cobra.ExactArgs(1), 15 | RunE: func(cmd *cobra.Command, args []string) error { 16 | cmd.SilenceUsage = true 17 | err := deleteSnapshot(cmd, args) 18 | return exitWithJSONOrErrorCondition(err) 19 | }, 20 | } 21 | 22 | func init() { 23 | snapshotCmd.AddCommand(snapshotDeleteCmd) 24 | snapshotDeleteCmd.Flags().BoolVarP(&outputJSONFormat, "json", "", false, "output json format") 25 | } 26 | 27 | func deleteSnapshot(_ *cobra.Command, args []string) error { 28 | manager, err := snapshot.NewManager() 29 | if err != nil { 30 | return fmt.Errorf("failed to create snapshot manager: %w", err) 31 | } 32 | if err = manager.Delete(args[0]); err != nil { 33 | return fmt.Errorf("failed to delete snapshot %q: %w", args[0], err) 34 | } 35 | return nil 36 | } 37 | -------------------------------------------------------------------------------- /src/go/rdctl/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2022 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import ( 20 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/cmd" 21 | ) 22 | 23 | func main() { 24 | cmd.Execute() 25 | } 26 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/client/handle_unix.go: -------------------------------------------------------------------------------- 1 | //go:build unix 2 | 3 | package client 4 | 5 | import ( 6 | "errors" 7 | 8 | "golang.org/x/sys/unix" 9 | ) 10 | 11 | func handleConnectionRefused(err error) error { 12 | if errors.Is(err, unix.ECONNREFUSED) { 13 | return ErrConnectionRefused 14 | } 15 | return err 16 | } 17 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/client/handle_windows.go: -------------------------------------------------------------------------------- 1 | package client 2 | 3 | import ( 4 | "errors" 5 | 6 | "golang.org/x/sys/windows" 7 | ) 8 | 9 | func handleConnectionRefused(err error) error { 10 | if errors.Is(err, windows.WSAECONNREFUSED) { 11 | return ErrConnectionRefused 12 | } 13 | return err 14 | } 15 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/directories/empty.go: -------------------------------------------------------------------------------- 1 | //go:build !windows 2 | 3 | /* 4 | Copyright © 2022 SUSE LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package directories 20 | 21 | import "fmt" 22 | 23 | func GetLocalAppDataDirectory() (string, error) { 24 | return "", fmt.Errorf("internal error: GetLocalAppDataDirectory shouldn't be called") 25 | } 26 | 27 | func GetRoamingAppDataDirectory() (string, error) { 28 | return "", fmt.Errorf("internal error: GetRoamingAppDataDirectory shouldn't be called") 29 | } 30 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/factoryreset/factory_reset_unix.go: -------------------------------------------------------------------------------- 1 | //go:build unix 2 | 3 | /* 4 | Copyright © 2022 SUSE LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package factoryreset 20 | 21 | import ( 22 | "context" 23 | "fmt" 24 | ) 25 | 26 | func CheckProcessWindows() (bool, error) { 27 | return false, fmt.Errorf("internal error: CheckProcessWindows shouldn't be called") 28 | } 29 | 30 | func KillRancherDesktop(ctx context.Context) error { 31 | return fmt.Errorf("internal error: KillRancherDesktop shouldn't be called") 32 | } 33 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/lima/name.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2025 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package lima contains the constants related to running Rancher Desktop using 18 | // lima (i.e. darwin / Linux). 19 | package lima 20 | 21 | const ( 22 | // The name of the lima instance, without the `lima-` prefix. 23 | InstanceName = "0" 24 | // The name of the lima instance, including the `lima-` prefix. 25 | InstanceFullName = "lima-" + InstanceName 26 | ) 27 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/lock/mock.go: -------------------------------------------------------------------------------- 1 | package lock 2 | 3 | import ( 4 | "context" 5 | 6 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" 7 | ) 8 | 9 | type MockBackendLock struct { 10 | } 11 | 12 | func (lock *MockBackendLock) Lock(ctx context.Context, appPaths *paths.Paths, action string) error { 13 | return nil 14 | } 15 | 16 | func (lock *MockBackendLock) Unlock(ctx context.Context, appPaths *paths.Paths, restart bool) error { 17 | return nil 18 | } 19 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/options/generated/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package options contains the generated options. 18 | package options 19 | 20 | // This file exists so that dependabot can find the package; the actual options 21 | // are generated via `yarn postinstall`. 22 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/paths/paths_test.go: -------------------------------------------------------------------------------- 1 | package paths 2 | 3 | import ( 4 | "path/filepath" 5 | "runtime" 6 | "testing" 7 | 8 | "github.com/stretchr/testify/assert" 9 | ) 10 | 11 | const fakeResourcesPath = "fakePath" 12 | 13 | func mockGetResourcesPath() (string, error) { 14 | return fakeResourcesPath, nil 15 | } 16 | 17 | func TestGetResourcesPath(t *testing.T) { 18 | dir := t.TempDir() 19 | rdctlPathOverride = filepath.Join(dir, "resources", runtime.GOOS, "bin", "rdctl") 20 | actual, err := GetResourcesPath() 21 | if assert.NoError(t, err) { 22 | assert.Equal(t, filepath.Join(dir, "resources"), actual) 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/process/process_test.go: -------------------------------------------------------------------------------- 1 | package process_test 2 | 3 | import ( 4 | "os" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | 10 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/process" 11 | ) 12 | 13 | func TestFindPidOfProcess(t *testing.T) { 14 | exe, err := os.Executable() 15 | require.NoError(t, err) 16 | pid, err := process.FindPidOfProcess(exe) 17 | require.NoError(t, err) 18 | assert.Equal(t, os.Getpid(), pid) 19 | } 20 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/process/process_windows_test.go: -------------------------------------------------------------------------------- 1 | package process 2 | 3 | import ( 4 | "strings" 5 | "testing" 6 | 7 | "github.com/stretchr/testify/assert" 8 | "github.com/stretchr/testify/require" 9 | "golang.org/x/sys/windows" 10 | ) 11 | 12 | func TestBuildCommandLine(t *testing.T) { 13 | t.Parallel() 14 | cases := [][]string{ 15 | {"arg0", "a b c", "d", "e"}, 16 | {"C:\\Program Files\\arg0\\\\", "ab\"c", "\\", "d"}, 17 | {"\\\\", "a\\\\\\b", "de fg", "h"}, 18 | {"arg0", "a\\\"b", "c", "d"}, 19 | {"arg0", "a\\\\b c", "d", "e"}, 20 | {"arg0", "ab\" c d"}, 21 | {"C:/Path\\with/mixed slashes"}, 22 | {"arg0", " leading", " and ", "trailing ", "space"}, 23 | {"special characters", "&", "|", ">", "<", "*", "\"", " "}, 24 | } 25 | for _, testcase := range cases { 26 | t.Run(strings.Join(testcase, " "), func(t *testing.T) { 27 | t.Parallel() 28 | result := buildCommandLine(testcase) 29 | argv, err := windows.DecomposeCommandLine(result) 30 | require.NoError(t, err, "failed to parse result %s", result) 31 | assert.Equal(t, testcase, argv, "failed to round trip arguments via [%s]", result) 32 | }) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/snapshot/snapshot.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "encoding/json" 5 | "time" 6 | ) 7 | 8 | type Snapshot struct { 9 | Created time.Time `json:"created"` 10 | Name string `json:"name"` 11 | ID string `json:"id,omitempty"` 12 | Description string `json:"description"` 13 | } 14 | 15 | func (s *Snapshot) getTimeString() string { 16 | return s.Created.Format(time.RFC3339) 17 | } 18 | 19 | func (s *Snapshot) MarshalJSON() ([]byte, error) { 20 | type Alias Snapshot 21 | return json.Marshal(&struct { 22 | *Alias 23 | Created string `json:"created"` 24 | }{ 25 | Alias: (*Alias)(s), 26 | Created: s.getTimeString(), 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/snapshot/snapshotter.go: -------------------------------------------------------------------------------- 1 | package snapshot 2 | 3 | import ( 4 | "context" 5 | "errors" 6 | 7 | "github.com/rancher-sandbox/rancher-desktop/src/go/rdctl/pkg/paths" 8 | ) 9 | 10 | // Types that implement Snapshotter are responsible for copying/creating 11 | // files that need to be copied/created for the creation and restoration of 12 | // snapshots. 13 | type Snapshotter interface { 14 | // Does all of the things that can fail when creating a snapshot, 15 | // so that the snapshot creation can easily be rolled back upon 16 | // a failure. 17 | CreateFiles(ctx context.Context, appPaths *paths.Paths, snapshotDir string) error 18 | // Like CreateFiles, but for restoring: does all of the things 19 | // that can fail when restoring a snapshot so that restoration can 20 | // easily be rolled back in the event of a failure. Returns ErrDataReset 21 | // when data has been reset due to an error in this process. 22 | RestoreFiles(ctx context.Context, appPaths *paths.Paths, snapshotDir string) error 23 | } 24 | 25 | // Returned by Snapshotter.RestoreFiles when data has been reset 26 | // due to an error restoring the files. 27 | var ErrDataReset = errors.New("data reset") 28 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | var Version = "0.0.0" 4 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/wsl/doc.go: -------------------------------------------------------------------------------- 1 | // Package wsl defines an interface, and implements types, that wrap 2 | // the WSL command line. As of the time of writing, the main purpose 3 | // of this type is to ease testing. 4 | package wsl 5 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/wsl/mock_windows.go: -------------------------------------------------------------------------------- 1 | package wsl 2 | 3 | type MockWSL struct{} 4 | 5 | func (wsl MockWSL) UnregisterDistros() error { 6 | return nil 7 | } 8 | 9 | func (wsl MockWSL) ExportDistro(distroName, fileName string) error { 10 | return nil 11 | } 12 | 13 | func (wsl MockWSL) ImportDistro(distroName, installLocation, fileName string) error { 14 | return nil 15 | } 16 | -------------------------------------------------------------------------------- /src/go/rdctl/pkg/wsl/names.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2025 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package wsl 18 | 19 | const ( 20 | // The name of the WSL distribution (when not using lima). 21 | DistributionName = "rancher-desktop" 22 | // The name of the WSL data distribution (when not using lima). 23 | DataDistributionName = DistributionName + "-data" 24 | ) 25 | -------------------------------------------------------------------------------- /src/go/spin-stub/README.md: -------------------------------------------------------------------------------- 1 | # spin-stub 2 | 3 | This is a stub executable used to launch spin on Windows. 4 | 5 | ## Usage 6 | 7 | Use it as you would with a normal `spin` command. It simply configures the `SPIN_DATA_DIR` environment variable to point to the spin subdirectory within the Rancher Desktop application data directory, and then runs `../internal/spin.exe` (relative to the location of the `spin-stub` binary). 8 | -------------------------------------------------------------------------------- /src/go/spin-stub/go.mod: -------------------------------------------------------------------------------- 1 | module github.com/rancher-sandbox/rancher-desktop/src/go/spin-stub 2 | 3 | go 1.22.0 4 | -------------------------------------------------------------------------------- /src/go/wsl-helper/.gitignore: -------------------------------------------------------------------------------- 1 | /pkg/dockerproxy/models/ 2 | /pkg/dockerproxy/swagger.yaml 3 | -------------------------------------------------------------------------------- /src/go/wsl-helper/cmd/dockerproxy.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/spf13/cobra" 21 | ) 22 | 23 | // dockerproxyStartCmd is the `wsl-helper docker-proxy` command. 24 | // It only has subcommands, and no functionality of its own. 25 | var dockerproxyCmd = &cobra.Command{ 26 | Use: "docker-proxy", 27 | Short: "Commands for managing the docker socket proxy", 28 | } 29 | 30 | func init() { 31 | rootCmd.AddCommand(dockerproxyCmd) 32 | } 33 | -------------------------------------------------------------------------------- /src/go/wsl-helper/cmd/k3s.go: -------------------------------------------------------------------------------- 1 | //go:build linux 2 | 3 | /* 4 | Copyright © 2021 SUSE LLC 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this file except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | */ 18 | 19 | package cmd 20 | 21 | import ( 22 | "github.com/spf13/cobra" 23 | ) 24 | 25 | // k3sCmd represents the k3s command 26 | var k3sCmd = &cobra.Command{ 27 | Use: "k3s", 28 | Short: "Commands for interacting with k3s in WSL", 29 | } 30 | 31 | func init() { 32 | rootCmd.AddCommand(k3sCmd) 33 | } 34 | -------------------------------------------------------------------------------- /src/go/wsl-helper/cmd/process_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/spf13/cobra" 21 | ) 22 | 23 | // processCmd represents the `wsl-helper process ...` subcommand 24 | var processCmd = &cobra.Command{ 25 | Use: "process", 26 | Short: "Commands for managing processes on Windows", 27 | Hidden: true, 28 | } 29 | 30 | func init() { 31 | rootCmd.AddCommand(processCmd) 32 | } 33 | -------------------------------------------------------------------------------- /src/go/wsl-helper/cmd/wsl.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/spf13/cobra" 21 | ) 22 | 23 | // k3sCmd represents the k3s command 24 | var wslCmd = &cobra.Command{ 25 | Use: "wsl", 26 | Short: "Commands for interacting with WSL", 27 | Hidden: true, 28 | } 29 | 30 | func init() { 31 | rootCmd.AddCommand(wslCmd) 32 | } 33 | -------------------------------------------------------------------------------- /src/go/wsl-helper/cmd/wsl_integration_linux.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package cmd 18 | 19 | import ( 20 | "github.com/spf13/cobra" 21 | ) 22 | 23 | // wslIntegrationCmd represents the `wsl integration` command 24 | var wslIntegrationCmd = &cobra.Command{ 25 | Use: "integration", 26 | Short: "Commands for managing with WSL integration", 27 | } 28 | 29 | func init() { 30 | wslCmd.AddCommand(wslIntegrationCmd) 31 | } 32 | -------------------------------------------------------------------------------- /src/go/wsl-helper/main.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | package main 17 | 18 | import "github.com/rancher-sandbox/rancher-desktop/src/go/wsl-helper/cmd" 19 | 20 | func main() { 21 | cmd.Execute() 22 | } 23 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/dockerproxy/defaults.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package dockerproxy 18 | 19 | // DefaultPort is the default (vsock) port we're listening on. 20 | const DefaultPort = 23752375 21 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/dockerproxy/generate.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package dockerproxy 18 | 19 | import ( 20 | _ "github.com/go-swagger/go-swagger" 21 | ) 22 | 23 | //go:generate -command swagger go run github.com/go-swagger/go-swagger/cmd/swagger@v0.30.5 24 | //go:generate swagger generate server --quiet --skip-validation --config-file swagger-configuration.yaml --server-package models --spec swagger.yaml 25 | 26 | func init() { 27 | } 28 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/dockerproxy/models/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2024 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package models contains the auto-generated OpenAPI models. 18 | package models 19 | 20 | // These imports exist so that dependabot is aware we use them. 21 | import ( 22 | _ "github.com/go-openapi/errors" 23 | _ "github.com/go-openapi/strfmt" // spellcheck-ignore-line 24 | _ "github.com/go-openapi/swag" 25 | _ "github.com/go-openapi/validate" 26 | ) 27 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/dockerproxy/mungers/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2021 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package mungers includes the code to modify each moby API. 18 | package mungers 19 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/dockerproxy/swagger-configuration.yaml: -------------------------------------------------------------------------------- 1 | # Copyright © 2021 SUSE LLC 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | # This is a go-swagger configuration file to generate the models for moby from 16 | # its OpenAPI specification. 17 | 18 | layout: 19 | models: 20 | - name: definition 21 | source: asset:model 22 | target: "{{ joinFilePath .Target .ModelPackage }}" 23 | file_name: "{{ pascalize .Name | snakize }}.go" 24 | application: 25 | - name: embedded_spec 26 | source: asset:swaggerJsonEmbed 27 | target: "{{ joinFilePath .Target (toPackagePath .ServerPackage) }}" 28 | file_name: "embedded_spec.go" 29 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/process/imports_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package process 18 | 19 | import "golang.org/x/sys/windows" 20 | 21 | var ( 22 | kernel32Dll = windows.NewLazySystemDLL("kernel32.dll") 23 | openProcess = kernel32Dll.NewProc("OpenProcess") 24 | attachConsole = kernel32Dll.NewProc("AttachConsole") 25 | freeConsole = kernel32Dll.NewProc("FreeConsole") 26 | setConsoleCtrlHandler = kernel32Dll.NewProc("SetConsoleCtrlHandler") 27 | ) 28 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/process/run_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package process 18 | 19 | import ( 20 | "fmt" 21 | "os/exec" 22 | ) 23 | 24 | func Launch(executable string, args ...string) error { 25 | err := exec.Command(executable, args...).Start() 26 | if err != nil { 27 | return fmt.Errorf("failed to start %s: %w", executable, err) 28 | } 29 | return nil 30 | } 31 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/version/version.go: -------------------------------------------------------------------------------- 1 | package version 2 | 3 | var Version = "0.0.0" 4 | -------------------------------------------------------------------------------- /src/go/wsl-helper/pkg/wsl-utils/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package wslutils retrieves information about WSL. 18 | package wslutils 19 | -------------------------------------------------------------------------------- /src/go/wsl-helper/wix/doc.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | // Package main implements a Windows Installer custom action DLL. That is, it 18 | // exports functions using CGO that will be called by Windows Installer. 19 | package main 20 | -------------------------------------------------------------------------------- /src/go/wsl-helper/wix/imports_windows.go: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright © 2023 SUSE LLC 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | You may obtain a copy of the License at 7 | 8 | http://www.apache.org/licenses/LICENSE-2.0 9 | 10 | Unless required by applicable law or agreed to in writing, software 11 | distributed under the License is distributed on an "AS IS" BASIS, 12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | See the License for the specific language governing permissions and 14 | limitations under the License. 15 | */ 16 | 17 | package main 18 | 19 | import "golang.org/x/sys/windows" 20 | 21 | type MSIHANDLE uint32 22 | 23 | var ( 24 | dllMsi = windows.NewLazySystemDLL("msi.dll") 25 | msiCloseHandle = dllMsi.NewProc("MsiCloseHandle") 26 | msiCreateRecord = dllMsi.NewProc("MsiCreateRecord") 27 | msiRecordSetStringW = dllMsi.NewProc("MsiRecordSetStringW") 28 | msiProcessMessage = dllMsi.NewProc("MsiProcessMessage") 29 | msiSetPropertyW = dllMsi.NewProc("MsiSetPropertyW") 30 | ) 31 | -------------------------------------------------------------------------------- /src/sudo-prompt/build-sudo-prompt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # shellcheck disable=SC2164 # Use 'cd ... || exit' or 'cd ... || return' in case cd fails. 4 | REPO=$(cd "$(dirname "${BASH_SOURCE[0]}")/../.."; pwd) 5 | 6 | # The APP name must be "Rancher Desktop.app" because this name is used in the dialog as 7 | # "Rancher Desktop wants to make changes." 8 | RESOURCES="${REPO}/resources" 9 | APP="${RESOURCES}/darwin/internal/Rancher Desktop.app" 10 | CONTENTS="${APP}/Contents" 11 | 12 | rm -rf "$APP" 13 | mkdir -p "$(dirname "$APP")" 14 | osacompile -o "$APP" sudo-prompt.applescript 15 | 16 | # Don't put the script into ${CONTENTS}/MacOS/ because that breaks signing the applet 17 | cp sudo-prompt-script "${CONTENTS}/Resources/Scripts/" 18 | sips -s format icns "${RESOURCES}/icons/mac-icon.png" --out "${CONTENTS}/Resources/applet.icns" 19 | 20 | plutil -replace CFBundleName -string "Rancher Desktop Password Prompt" "${CONTENTS}/Info.plist" 21 | -------------------------------------------------------------------------------- /src/sudo-prompt/sudo-prompt-script: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script is executed by the applet with root permissions. 3 | # The caller will have created a temporary directory containing just the 4 | # `sudo-prompt-command` shell script. This script will add the `code`, 5 | # `stdout` and `stderr` files. The caller will delete this directory 6 | # again after reading the files. 7 | 8 | # Set sudo timestamp for subsequent sudo calls if tty_tickets are disabled: 9 | /bin/mkdir -p /var/db/sudo/$USER > /dev/null 2>&1 10 | /usr/bin/touch /var/db/sudo/$USER > /dev/null 2>&1 11 | # AppleScript's "do shell script" may alter stdout line-endings. 12 | # It may also set stdout to stderr if there was a non-zero return code and no stderr. 13 | # We therefore prefer to redirect output streams and capture return code manually: 14 | /bin/bash sudo-prompt-command 1>stdout 2>stderr 15 | /bin/echo $? > code 16 | # Correct ownership of stdout, stderr and code so that user can delete them: 17 | /usr/sbin/chown $USER stdout stderr code 18 | # Always return 0 so that AppleScript does not show error dialog: 19 | exit 0 20 | -------------------------------------------------------------------------------- /src/sudo-prompt/sudo-prompt.applescript: -------------------------------------------------------------------------------- 1 | set appletPath to POSIX path of (path to me) 2 | if appletPath ends with ".app/" then 3 | set appletPath to appletPath & "Contents/Resources/Scripts" 4 | else 5 | set appletPath to do shell script "dirname " & quoted form of appletPath 6 | end if 7 | set promptScript to appletPath & "/sudo-prompt-script" 8 | do shell script (quoted form of promptScript) with administrator privileges 9 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2018", 4 | "module": "ESNext", 5 | "moduleResolution": "Node", 6 | "jsx": "react", 7 | "lib": [ 8 | "ESNext", 9 | "ESNext.AsyncIterable", 10 | "DOM" 11 | ], 12 | "esModuleInterop": true, 13 | "allowJs": true, 14 | "sourceMap": true, 15 | "strict": true, 16 | "experimentalDecorators": true, 17 | "baseUrl": ".", 18 | "paths": { 19 | "@pkg/*": [ 20 | "pkg/rancher-desktop/*" 21 | ], 22 | "@shell/*": [ 23 | "./node_modules/@rancher/shell/*" 24 | ] 25 | }, 26 | "typeRoots": [ 27 | "./node_modules", 28 | "./node_modules/@types", 29 | "./node_modules/@rancher/shell/types" 30 | ], 31 | "types": [ 32 | "@types/node", 33 | "@types/jest" 34 | ] 35 | }, 36 | "exclude": [ 37 | "node_modules", 38 | ".nuxt", 39 | "dist", 40 | "scripts/lib/installer-*.tsx", 41 | "scripts/lib/installer-win32-gen.tsx" 42 | ], 43 | "include": [ 44 | "**/*", 45 | "**/*.ts", 46 | "**/*.d.ts", 47 | "**/*.tsx", 48 | "**/*.vue", 49 | ".eslintrc.js" 50 | ] 51 | } 52 | --------------------------------------------------------------------------------