diff --git a/.github/actions/build-cli/action.yml b/.github/actions/build-cli/action.yml index 39a4e2cce4..f479382f51 100644 --- a/.github/actions/build-cli/action.yml +++ b/.github/actions/build-cli/action.yml @@ -30,6 +30,13 @@ runs: shell: bash run: pnpm install --frozen-lockfile + # The CLI typechecks against the SDK sources, which import the workspace-only + # `@e2b/dockerfile-utils`; the SDK build builds it first (`prebuild`). + - name: Build the SDK + shell: bash + run: pnpm build + working-directory: ./packages/js-sdk + - name: Build the CLI shell: bash run: pnpm build diff --git a/.github/workflows/desktop_js_tests.yml b/.github/workflows/desktop_js_tests.yml index 565a590a96..358f25e2b6 100644 --- a/.github/workflows/desktop_js_tests.yml +++ b/.github/workflows/desktop_js_tests.yml @@ -11,6 +11,11 @@ on: required: false type: boolean default: true + # Template to run the tests against; empty = the SDK default (`desktop`). + E2B_TESTS_TEMPLATE: + required: false + type: string + default: '' secrets: E2B_API_KEY: required: true @@ -102,4 +107,5 @@ jobs: env: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} + E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} E2B_TEST_MAX_WORKERS: 1 diff --git a/.github/workflows/desktop_python_tests.yml b/.github/workflows/desktop_python_tests.yml index 8861c728da..b5e48c07a9 100644 --- a/.github/workflows/desktop_python_tests.yml +++ b/.github/workflows/desktop_python_tests.yml @@ -11,6 +11,11 @@ on: required: false type: boolean default: true + # Template to run the tests against; empty = the SDK default (`desktop`). + E2B_TESTS_TEMPLATE: + required: false + type: string + default: '' secrets: E2B_API_KEY: required: true @@ -56,3 +61,4 @@ jobs: env: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} + E2B_TESTS_TEMPLATE: ${{ inputs.E2B_TESTS_TEMPLATE }} diff --git a/.github/workflows/desktop_template_build.yml b/.github/workflows/desktop_template_build.yml new file mode 100644 index 0000000000..085ce00747 --- /dev/null +++ b/.github/workflows/desktop_template_build.yml @@ -0,0 +1,62 @@ +name: Build Desktop Test Template + +on: + workflow_call: + inputs: + E2B_DOMAIN: + required: false + type: string + default: '' + secrets: + E2B_API_KEY: + required: true + outputs: + template: + description: 'Name of the built test template' + value: ${{ jobs.build.outputs.template }} + +permissions: + contents: read + +jobs: + build: + defaults: + run: + working-directory: ./templates/desktop + name: Desktop Template - Build + runs-on: ubuntu-22.04 + outputs: + template: ${{ steps.name.outputs.template }} + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + + - name: Parse .tool-versions + uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 + with: + filename: '.tool-versions' + uppercase: 'true' + prefix: 'tool_version_' + + - name: Install uv + uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 + with: + version: '${{ env.TOOL_VERSION_UV }}' + python-version: '${{ env.TOOL_VERSION_PYTHON }}' + enable-cache: true + + - name: Install dependencies + run: uv sync --locked --project ../../packages/python-sdk + + # Unique per run attempt; exposed before the build so a failed build can + # still be cleaned up by name. + - name: Generate template name + id: name + run: echo "template=desktop-ci-${{ github.run_id }}-${{ github.run_attempt }}" >> "$GITHUB_OUTPUT" + + - name: Build E2B template + run: uv run --project ../../packages/python-sdk python build_ci.py + env: + E2B_API_KEY: ${{ secrets.E2B_API_KEY }} + E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} + E2B_TESTS_TEMPLATE: ${{ steps.name.outputs.template }} diff --git a/.github/workflows/desktop_template_cleanup.yml b/.github/workflows/desktop_template_cleanup.yml new file mode 100644 index 0000000000..7b096ba2e2 --- /dev/null +++ b/.github/workflows/desktop_template_cleanup.yml @@ -0,0 +1,35 @@ +name: Delete Desktop Test Template + +on: + workflow_call: + inputs: + E2B_DOMAIN: + required: false + type: string + default: '' + template: + required: true + type: string + secrets: + E2B_API_KEY: + required: true + +permissions: + contents: read + +jobs: + cleanup: + name: Desktop Template - Delete + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + + - name: Build and install E2B CLI + uses: ./.github/actions/build-cli + + - name: Delete E2B template + run: e2b template delete -y "${{ inputs.template }}" + env: + E2B_API_KEY: ${{ secrets.E2B_API_KEY }} + E2B_DOMAIN: ${{ inputs.E2B_DOMAIN }} diff --git a/.github/workflows/sdk_tests.yml b/.github/workflows/sdk_tests.yml index 4aeaea69a1..605a777faf 100644 --- a/.github/workflows/sdk_tests.yml +++ b/.github/workflows/sdk_tests.yml @@ -33,6 +33,7 @@ jobs: code_interpreter_python: ${{ steps.filter.outputs.code_interpreter_python }} desktop_js: ${{ steps.filter.outputs.desktop_js }} desktop_python: ${{ steps.filter.outputs.desktop_python }} + desktop_template: ${{ steps.filter.outputs.desktop_template }} dockerfile_utils_js: ${{ steps.filter.outputs.dockerfile_utils_js }} dockerfile_utils_python: ${{ steps.filter.outputs.dockerfile_utils_python }} steps: @@ -93,14 +94,24 @@ jobs: - 'tsdown.sdk.config.mts' - 'vitest.sdk.config.mts' - 'packages/desktop-js/**/!(*.md)' + - 'templates/desktop/**/!(*.md)' + - '.github/workflows/desktop_template_*.yml' - 'packages/js-sdk/**/!(*.md)' - 'packages/dockerfile-utils-js/**/!(*.md)' desktop_python: - *shared - '.github/workflows/desktop_python_tests.yml' - 'packages/desktop-python/**/!(*.md)' + - 'templates/desktop/**/!(*.md)' + - '.github/workflows/desktop_template_*.yml' - 'packages/python-sdk/**/!(*.md)' - 'packages/dockerfile-utils-python/**/!(*.md)' + # The Desktop SDK suites run against a fresh build of the + # template when it changes, instead of the published one. + desktop_template: + - '.github/workflows/sdk_tests.yml' + - '.github/workflows/desktop_template_*.yml' + - 'templates/desktop/**/!(*.md)' dockerfile_utils_js: - *shared - '.github/workflows/dockerfile_utils_js_tests.yml' @@ -152,19 +163,43 @@ jobs: secrets: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} + desktop-template: + name: Production / Desktop Test Template + needs: changes + if: ${{ needs.changes.outputs.desktop_template == 'true' || github.event_name == 'workflow_dispatch' }} + uses: ./.github/workflows/desktop_template_build.yml + secrets: + E2B_API_KEY: ${{ secrets.E2B_API_KEY }} + + # `!cancelled()` so the suites still run when `desktop-template` is skipped + # (template unchanged); they then fall back to the published `desktop`. desktop-js-tests: name: Production / Desktop JS SDK Tests - needs: changes - if: ${{ needs.changes.outputs.desktop_js == 'true' || github.event_name == 'workflow_dispatch' }} + needs: [changes, desktop-template] + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.desktop-template.result != 'failure' && (needs.changes.outputs.desktop_js == 'true' || github.event_name == 'workflow_dispatch') }} uses: ./.github/workflows/desktop_js_tests.yml + with: + E2B_TESTS_TEMPLATE: ${{ needs.desktop-template.outputs.template }} secrets: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} desktop-python-tests: name: Production / Desktop Python SDK Tests - needs: changes - if: ${{ needs.changes.outputs.desktop_python == 'true' || github.event_name == 'workflow_dispatch' }} + needs: [changes, desktop-template] + if: ${{ !cancelled() && needs.changes.result == 'success' && needs.desktop-template.result != 'failure' && (needs.changes.outputs.desktop_python == 'true' || github.event_name == 'workflow_dispatch') }} uses: ./.github/workflows/desktop_python_tests.yml + with: + E2B_TESTS_TEMPLATE: ${{ needs.desktop-template.outputs.template }} + secrets: + E2B_API_KEY: ${{ secrets.E2B_API_KEY }} + + desktop-template-cleanup: + name: Production / Delete Desktop Test Template + needs: [desktop-template, desktop-js-tests, desktop-python-tests] + if: ${{ always() && needs.desktop-template.result != 'skipped' && needs.desktop-template.outputs.template != '' }} + uses: ./.github/workflows/desktop_template_cleanup.yml + with: + template: ${{ needs.desktop-template.outputs.template }} secrets: E2B_API_KEY: ${{ secrets.E2B_API_KEY }} @@ -271,6 +306,7 @@ jobs: - cli-tests - code-interpreter-js-tests - code-interpreter-python-tests + - desktop-template - desktop-js-tests - desktop-python-tests - dockerfile-utils-js-tests diff --git a/.github/workflows/templates.yml b/.github/workflows/templates.yml index f5cb0aea65..1f61fe1011 100644 --- a/.github/workflows/templates.yml +++ b/.github/workflows/templates.yml @@ -12,6 +12,14 @@ on: - all - base - httpbin + - desktop + # The desktop template is rebuilt whenever its sources change on main. + push: + branches: + - main + paths: + - 'templates/desktop/**' + - '.github/workflows/templates.yml' permissions: contents: read @@ -48,6 +56,7 @@ jobs: --tag ${{ secrets.DOCKERHUB_USERNAME }}/base:latest . buildTemplate: + if: ${{ contains(fromJSON('["all", "base", "httpbin"]'), inputs.template) }} name: Build and Publish E2B Template runs-on: ubuntu-22.04 steps: @@ -78,3 +87,54 @@ jobs: e2b template create httpbin --memory-mb 512 \ --cmd 'go-httpbin -host 0.0.0.0 -port 8080' \ --ready-cmd 'curl -fsS http://localhost:8080/status/200 > /dev/null' + + buildDesktopTemplate: + if: ${{ github.event_name == 'push' || inputs.template == 'all' || inputs.template == 'desktop' }} + defaults: + run: + working-directory: ./templates/desktop + + name: Build and Publish Desktop Template + runs-on: ubuntu-22.04 + steps: + - name: Checkout repository + uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + + - name: Parse .tool-versions + uses: wistia/parse-tool-versions@32f568a4ffd4bfa7720ebf93f171597d1ebc979a # v2.1.1 + with: + filename: '.tool-versions' + uppercase: 'true' + prefix: 'tool_version_' + + - name: Install uv + uses: astral-sh/setup-uv@d0cc045d04ccac9d8b7881df0226f9e82c39688e # v6.8.0 + with: + version: '${{ env.TOOL_VERSION_UV }}' + python-version: '${{ env.TOOL_VERSION_PYTHON }}' + enable-cache: true + + # The build scripts run on the Python SDK from this repo. + - name: Install dependencies + run: uv sync --locked --project ../../packages/python-sdk + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 + + - name: Log in to DockerHub + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push to DockerHub + run: | + uv run --project ../../packages/python-sdk python build_docker.py | docker buildx build \ + --platform linux/amd64 \ + --push \ + --tag ${{ secrets.DOCKERHUB_USERNAME }}/desktop:latest -f - files + + - name: Build E2B template + run: uv run --project ../../packages/python-sdk python build_prod.py + env: + E2B_API_KEY: ${{ secrets.E2B_API_KEY }} diff --git a/packages/desktop-js/README.md b/packages/desktop-js/README.md index 62006fa827..e54623e604 100644 --- a/packages/desktop-js/README.md +++ b/packages/desktop-js/README.md @@ -266,4 +266,4 @@ await desktop.wait(1000) // Wait for 1 second ## Under the hood The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment. -Check out the sandbox template's code [here](https://github.com/e2b-dev/desktop/tree/main/template). +Check out the sandbox template's code [here](https://github.com/e2b-dev/E2B/tree/main/templates/desktop). diff --git a/packages/desktop-js/tests/setup.ts b/packages/desktop-js/tests/setup.ts index dba79881f3..269697dfcc 100644 --- a/packages/desktop-js/tests/setup.ts +++ b/packages/desktop-js/tests/setup.ts @@ -2,7 +2,7 @@ import { Sandbox } from '../src' import { test as base } from 'vitest' const timeoutMs = 180_000 -const template = 'desktop' +const template = process.env.E2B_TESTS_TEMPLATE || 'desktop' interface SandboxFixture { sandbox: Sandbox diff --git a/packages/desktop-python/README.md b/packages/desktop-python/README.md index df7b118208..a20b4360e1 100644 --- a/packages/desktop-python/README.md +++ b/packages/desktop-python/README.md @@ -259,4 +259,4 @@ desktop.wait(1000) # Wait for 1 second ## Under the hood The desktop-like environment is based on Linux and [Xfce](https://www.xfce.org/) at the moment. We chose Xfce because it's a fast and lightweight environment that's also popular and actively supported. However, this Sandbox template is fully customizable and you can create your own desktop environment. -Check out the sandbox template's code [here](https://github.com/e2b-dev/desktop/tree/main/template). +Check out the sandbox template's code [here](https://github.com/e2b-dev/E2B/tree/main/templates/desktop). diff --git a/packages/desktop-python/tests/conftest.py b/packages/desktop-python/tests/conftest.py index 7b96c2c4a2..84b9d3457a 100644 --- a/packages/desktop-python/tests/conftest.py +++ b/packages/desktop-python/tests/conftest.py @@ -11,7 +11,9 @@ @pytest.fixture(scope="function") def sandbox(debug): # Create a new sandbox instance for each test - sandbox = Sandbox.create(timeout=timeout) + sandbox = Sandbox.create( + template=os.getenv("E2B_TESTS_TEMPLATE") or None, timeout=timeout + ) try: yield sandbox diff --git a/templates/desktop/README.md b/templates/desktop/README.md new file mode 100644 index 0000000000..8d0d336cf5 --- /dev/null +++ b/templates/desktop/README.md @@ -0,0 +1,106 @@ +# E2B Desktop Template + +This is the template for the E2B Desktop Sandbox. + +## Building the production template + +The official `desktop` template is built by the +[`templates.yml`](../../.github/workflows/templates.yml) workflow on every push to +`main` that touches this directory (or manually via `workflow_dispatch`). It +uses the Python SDK from this repo (`packages/python-sdk`), so the build scripts +run in that package's uv environment. + +1. Install the build dependencies: + +```bash +uv sync --project ../../packages/python-sdk +``` + +2. Provide your credentials in `.env`: + +``` +E2B_API_KEY=e2b_*** +``` + +3. Build the template: + +```bash +uv run --project ../../packages/python-sdk python build_prod.py +``` + +During development you can build the `desktop-dev` template instead: + +```bash +uv run --project ../../packages/python-sdk python build_dev.py +``` + +If you want to customize the Desktop sandbox (e.g.: add a preinstalled package) +you can do that by creating a [custom sandbox template](https://e2b.dev/docs/template/quickstart). + +## Creating a custom template + +1. Install E2B SDK + +```bash +pip install e2b python-dotenv +``` + +2. Create a custom sandbox template: + +**template.py** + +```python +from e2b import Template + +template = Template().from_template("desktop") +``` + +3. Create a build script: + +**build.py** + +```python +from dotenv import load_dotenv +from template import template +from e2b import Template, default_build_logger + +load_dotenv() + +Template.build( + template, + "desktop-custom", + cpu_count=8, + memory_mb=8192, + on_build_logs=default_build_logger(), +) +``` + +4. Set your environment variables in a `.env` file (loaded by `load_dotenv()`): + +``` +E2B_API_KEY=e2b_*** +``` + +5. Build the template: + +```bash +python build.py +``` + +6. Use the custom template: + +**Python** + +```python +from e2b_desktop import Sandbox + +desktop = Sandbox.create(template="desktop-custom") +``` + +**JavaScript** + +```javascript +import { Sandbox } from '@e2b/desktop' + +const desktop = await Sandbox.create('desktop-custom') +``` diff --git a/templates/desktop/build_ci.py b/templates/desktop/build_ci.py new file mode 100644 index 0000000000..719d581136 --- /dev/null +++ b/templates/desktop/build_ci.py @@ -0,0 +1,12 @@ +import os + +from e2b import Template, default_build_logger +from template import template_with_user_workdir + +Template.build( + template_with_user_workdir, + os.environ["E2B_TESTS_TEMPLATE"], + cpu_count=8, + memory_mb=8192, + on_build_logs=default_build_logger(), +) diff --git a/templates/desktop/build_dev.py b/templates/desktop/build_dev.py new file mode 100644 index 0000000000..9e8f5f3b93 --- /dev/null +++ b/templates/desktop/build_dev.py @@ -0,0 +1,13 @@ +from dotenv import load_dotenv +from e2b import Template, default_build_logger +from template import template_with_user_workdir + +load_dotenv() + +Template.build( + template_with_user_workdir, + "desktop-dev", + cpu_count=8, + memory_mb=8192, + on_build_logs=default_build_logger(), +) diff --git a/templates/desktop/build_docker.py b/templates/desktop/build_docker.py new file mode 100644 index 0000000000..72a439bcdb --- /dev/null +++ b/templates/desktop/build_docker.py @@ -0,0 +1,5 @@ +from e2b import Template +from template import template + +# output the template to stdout to pipe into docker buildx +print(Template.to_dockerfile(template)) diff --git a/templates/desktop/build_prod.py b/templates/desktop/build_prod.py new file mode 100644 index 0000000000..595236c1ff --- /dev/null +++ b/templates/desktop/build_prod.py @@ -0,0 +1,13 @@ +from dotenv import load_dotenv +from e2b import Template, default_build_logger +from template import template_with_user_workdir + +load_dotenv() + +Template.build( + template_with_user_workdir, + "desktop", + cpu_count=8, + memory_mb=8192, + on_build_logs=default_build_logger(), +) diff --git a/templates/desktop/files/firefox-autoconfig.js b/templates/desktop/files/firefox-autoconfig.js new file mode 100644 index 0000000000..7c6fba9c27 --- /dev/null +++ b/templates/desktop/files/firefox-autoconfig.js @@ -0,0 +1,2 @@ +pref("general.config.filename", "firefox.cfg"); +pref("general.config.obscure_value", 0); diff --git a/templates/desktop/files/firefox-policies.json b/templates/desktop/files/firefox-policies.json new file mode 100644 index 0000000000..4ef094bce1 --- /dev/null +++ b/templates/desktop/files/firefox-policies.json @@ -0,0 +1,7 @@ +{ + "policies": { + "DisableFirstRunPage": true, + "OverrideFirstRunPage": "", + "OverridePostUpdatePage": "" + } +} \ No newline at end of file diff --git a/templates/desktop/files/firefox.cfg b/templates/desktop/files/firefox.cfg new file mode 100644 index 0000000000..4a0eb5021e --- /dev/null +++ b/templates/desktop/files/firefox.cfg @@ -0,0 +1,34 @@ +// Disable first-run and onboarding +pref("browser.startup.homepage_override.mstone", "ignore"); +pref("browser.startup.homepage_override.buildID", ""); +pref("browser.aboutwelcome.enabled", false); +pref("browser.messaging-system.whatsNewPanel.enabled", false); + +// Disable Firefox studies and telemetry +pref("app.shield.optoutstudies.enabled", false); +pref("app.normandy.enabled", false); +pref("app.normandy.api_url", ""); +pref("toolkit.telemetry.enabled", false); +pref("toolkit.telemetry.unified", false); +pref("toolkit.telemetry.archive.enabled", false); +pref("datareporting.healthreport.uploadEnabled", false); +pref("datareporting.policy.dataSubmissionEnabled", false); + +// Disable sponsored suggestions in address bar (Firefox Suggest) +pref("browser.urlbar.suggest.quicksuggest.nonsponsored", false); +pref("browser.urlbar.suggest.quicksuggest.sponsored", false); +pref("browser.urlbar.quicksuggest.enabled", false); + +// Disable Pocket and all new tab sponsored stuff +pref("extensions.pocket.enabled", false); +pref("browser.newtabpage.activity-stream.feeds.section.topstories", false); +pref("browser.newtabpage.activity-stream.feeds.snippets", false); +pref("browser.newtabpage.activity-stream.showSponsored", false); +pref("browser.newtabpage.activity-stream.showSponsoredTopSites", false); + +// Disable extension recommendations +pref("extensions.htmlaboutaddons.recommendations.enabled", false); +pref("browser.discovery.enabled", false); + +// Disable automatic updates +pref("app.update.auto", false); diff --git a/templates/desktop/files/google-chrome.desktop b/templates/desktop/files/google-chrome.desktop new file mode 100644 index 0000000000..7c39f27037 --- /dev/null +++ b/templates/desktop/files/google-chrome.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Version=1.0 +Name=Google Chrome +Exec=/usr/bin/google-chrome-stable --no-first-run --no-default-browser-check --password-store=basic --disable-extensions --disable-default-apps --disable-sync --disable-spell-check --disable-breakpad --metrics-recording-only --no-pings --mute-audio --disable-features=Autofill,AutofillEnableUpi,PasswordManager,FederatedCredentialsManagement,InterestFeedContentSuggestions,PromotionalTabsEnabled,Translate,TranslateUI,ReadAnything,DistilledPageContent,PictureInPicture,Notifications,WebUSB,WebHID,WebMIDI,WebBluetooth,WebSerial,WebXR,MediaRouter,PaymentRequest,Payments,GlobalMediaControls,MediaSession,WebRTC,WebRtcHWEncoding,BackgroundSync,BackgroundFetch,Push,Prerender2 +Terminal=false +Icon=google-chrome +Type=Application +Categories=Network;WebBrowser; +MimeType=text/html;text/xml;application/xhtml_xml;x-scheme-handler/http;x-scheme-handler/https; +StartupWMClass=Google-chrome \ No newline at end of file diff --git a/templates/desktop/files/screensaver.desktop b/templates/desktop/files/screensaver.desktop new file mode 100644 index 0000000000..d5bebfe2e3 --- /dev/null +++ b/templates/desktop/files/screensaver.desktop @@ -0,0 +1,7 @@ +[Desktop Entry] +Type=Application +Name=Disable Screen Blanking +Exec=sh -c "sleep 2; xset s off; xset s noblank; xset -dpms" +Hidden=false +NoDisplay=true +X-GNOME-Autostart-enabled=true diff --git a/templates/desktop/files/settings.json b/templates/desktop/files/settings.json new file mode 100644 index 0000000000..4473fa2b7e --- /dev/null +++ b/templates/desktop/files/settings.json @@ -0,0 +1,9 @@ +{ + "files.autoSave": "afterDelay", + "files.autoSaveDelay": 200, + "security.allowHttp": true, + "security.workspace.trust.startupPrompt": "never", + "security.workspace.trust.enabled": false, + "security.workspace.trust.banner": "never", + "security.workspace.trust.emptyWindow": false +} diff --git a/templates/desktop/files/wallpaper.png b/templates/desktop/files/wallpaper.png new file mode 100644 index 0000000000..2c8588e3db Binary files /dev/null and b/templates/desktop/files/wallpaper.png differ diff --git a/templates/desktop/files/xfce4-desktop.xml b/templates/desktop/files/xfce4-desktop.xml new file mode 100644 index 0000000000..ddc5593171 --- /dev/null +++ b/templates/desktop/files/xfce4-desktop.xml @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/templates/desktop/template.py b/templates/desktop/template.py new file mode 100644 index 0000000000..44b6f6ad4b --- /dev/null +++ b/templates/desktop/template.py @@ -0,0 +1,129 @@ +from pathlib import Path + +from e2b import CopyItem, Template + +template = ( + Template(file_context_path=Path(__file__).parent / "files") + .from_image("ubuntu:22.04") + .set_user("root") + .set_workdir("/") + .set_envs( + { + # Avoid system prompts + "DEBIAN_FRONTEND": "noninteractive", + "DEBIAN_PRIORITY": "high", + # Pip settings + "PIP_DEFAULT_TIMEOUT": "100", + "PIP_DISABLE_PIP_VERSION_CHECK": "1", + "PIP_NO_CACHE_DIR": "1", + } + ) + # Initial system setup and packages + .run_cmd("yes | unminimize") + .apt_install( + [ + "xserver-xorg", + "x11-xserver-utils", + "xvfb", + "x11-utils", + "xauth", + "xfce4", + "xfce4-goodies", + "util-linux", + "sudo", + "curl", + "git", + "wget", + "python3-pip", + "xdotool", + "scrot", + "ffmpeg", + "x11vnc", + "net-tools", + "netcat", + "x11-apps", + "libreoffice", + "xpdf", + "gedit", + "xpaint", + "tint2", + "galculator", + "pcmanfm", + "software-properties-common", + "apt-transport-https", + "libgtk-3-bin", + ] + ) + .pip_install("numpy") + # Setup NoVNC and websockify + .git_clone( + "https://github.com/e2b-dev/noVNC.git", "/opt/noVNC", branch="e2b-desktop" + ) + .make_symlink("/opt/noVNC/vnc.html", "/opt/noVNC/index.html") + .git_clone( + "https://github.com/novnc/websockify.git", + "/opt/noVNC/utils/websockify", + branch="v0.12.0", + ) + # Install browsers and set up repositories + .run_cmd( + [ + "add-apt-repository ppa:mozillateam/ppa", + "wget -q -O - https://dl-ssl.google.com/linux/linux_signing_key.pub | apt-key add -", + 'echo "deb [arch=amd64] http://dl.google.com/linux/chrome/deb/ stable main" > /etc/apt/sources.list.d/google-chrome.list', + "wget -qO- https://packages.microsoft.com/keys/microsoft.asc | apt-key add -", + 'add-apt-repository -y "deb [arch=amd64] https://packages.microsoft.com/repos/vscode stable main"', + "apt-get update", + ], + ) + # Install browsers and VS Code + .apt_install(["firefox-esr", "google-chrome-stable", "code"]) + # Configure system settings + .make_symlink( + "/usr/bin/xfce4-terminal.wrapper", + "/etc/alternatives/x-terminal-emulator", + force=True, + ) + .run_cmd("update-alternatives --set x-www-browser /usr/bin/firefox-esr") + .make_dir("/home/user/.config/Code/User") + .make_dir("/home/user/.config/xfce4/xfconf/xfce-perchannel-xml/") + .make_dir("/home/user/.config/autostart") + .run_cmd("update-desktop-database /usr/share/applications/") + # Copy all configuration files + .copy_items( + [ + CopyItem( + src="google-chrome.desktop", + dest="/usr/share/applications/google-chrome.desktop", + ), + CopyItem( + src="settings.json", + dest="/home/user/.config/Code/User/settings.json", + ), + CopyItem( + src="wallpaper.png", + dest="/usr/share/backgrounds/xfce/wallpaper.png", + ), + CopyItem( + src="xfce4-desktop.xml", + dest="/home/user/.config/xfce4/xfconf/xfce-perchannel-xml/xfce4-desktop.xml", + ), + CopyItem( + src="screensaver.desktop", + dest="/home/user/.config/autostart/screensaver.desktop", + ), + CopyItem( + src="firefox-policies.json", + dest="/usr/lib/firefox-esr/distribution/policies.json", + ), + CopyItem( + src="firefox-autoconfig.js", + dest="/usr/lib/firefox-esr/defaults/pref/autoconfig.js", + ), + CopyItem(src="firefox.cfg", dest="/usr/lib/firefox-esr/firefox.cfg"), + ] + ) +) + +# Template with user and workdir set +template_with_user_workdir = template.set_user("user").set_workdir("/home/user")