fix(ci): pin code-server to v4.113.1 for Selenium tests#2752
Conversation
code-server v4.114.0 (released April 4, 2026) has a bug preventing extensions from loading properly in the selenium-adt container, causing all Selenium UI tests to fail with TimeoutException waiting for the Ansible extension to activate. This change: - Adds a local Containerfile that extends selenium-adt:main and pins code-server to v4.113.1 (last known working version) - Updates docker-compose.yml to build from this local Containerfile - Removes the @pytest.mark.skip decorators from all 15 previously flaky Selenium tests Fixes: #2580 Related: ansible/ansible-dev-tools#677 Made-with: Cursor
📝 WalkthroughWalkthroughThe changes pin the selenium-adt Docker image locally to ensure consistent test environments and enable 14 previously skipped UI tests across five test files. A new Containerfile builds the selenium image with pinned code-server and extensions, while skip decorators are removed from tests to allow execution in CI. Changes
Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (3)
test/ui/Containerfile.selenium (2)
11-11: Consider asserting the installed version.Since the whole point of this file is version pinning, a follow-up
RUN code-server --version | grep -q '^4\.113\.1'would fail the build early ifinstall.shsilently ignored the--versionflag or resolved to something else.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/ui/Containerfile.selenium` at line 11, Add a verification step after the installer RUN that asserts the installed code-server matches the pinned version: after the existing RUN that pipes to install.sh with --version 4.113.1, run a command that invokes code-server --version and greps/validates it starts with "4.113.1" so the build fails early if install.sh ignored or resolved the version incorrectly; update the Docker instruction sequence that calls the installer to include this verification and ensure it runs in the same layer or follows immediately so failures stop the build.
5-5: Base image uses the mutable:maintag — undermines the pin.Pinning
code-serveronly helps if the base layer is also stable.ghcr.io/ansible/selenium-adt:maincan be re-tagged at any time, which means a rebuild may pull a newer base that bundles code-server 4.114.0 (or later) and yourRUN curl … install.shonly layers over whatever is already there. Consider pinning to an immutable digest (@sha256:…) or a released tag so this workaround is reproducible.-FROM ghcr.io/ansible/selenium-adt:main +FROM ghcr.io/ansible/selenium-adt@sha256:<digest>🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@test/ui/Containerfile.selenium` at line 5, The Dockerfile’s base image currently uses a mutable tag "ghcr.io/ansible/selenium-adt:main" which defeats your code-server pin; change the FROM line to reference an immutable image (either a released tag like "ghcr.io/ansible/selenium-adt:<release-tag>" or preferably a digest "ghcr.io/ansible/selenium-adt@sha256:<digest>") so the base layer is reproducible, and ensure the chosen tag/digest corresponds to the expected code-server version that your RUN curl … install.sh step assumes.docker-compose.yml (1)
7-10: LGTM on the compose change.Switching to a local build with a stable
selenium-adt-pinned:localtag is the right shape. One minor consideration: withbuild:present,docker compose upwill rebuild/cache based on the Containerfile, but CI that previously relied onpull_policy: missingto skip network work will now always evaluate the build. If build time becomes a concern, enabling BuildKit cache or pushing the pinned image to a registry would help.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docker-compose.yml` around lines 7 - 10, The compose change switches the service to a local build (build.context / build.dockerfile) with image "selenium-adt-pinned:local", which will force builds where CI previously relied on pull_policy: missing; to avoid unnecessary rebuilds add build cache support or use a pushed pinned image: enable BuildKit in CI (set DOCKER_BUILDKIT=1), add a cache source by configuring build.cache_from to reference the pinned image (e.g., cache_from: ["selenium-adt-pinned:local"] or a registry-tagged image) or push "selenium-adt-pinned:local" to your registry and reference that image in cache_from so CI can reuse layers instead of rebuilding each run.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@test/ui/Containerfile.selenium`:
- Around line 13-17: The extension install commands run as root so they land in
/root/.local/share/code-server/extensions and won't be visible to the runtime
user; move the three code-server --install-extension invocations out of the root
section and run them after the Dockerfile switches to USER 1001 (or run them as
UID 1001) so the extensions are installed into
/home/selenium/.local/share/code-server/extensions used at runtime; remove or
avoid the root-level install to prevent duplicate/misplaced extension files.
---
Nitpick comments:
In `@docker-compose.yml`:
- Around line 7-10: The compose change switches the service to a local build
(build.context / build.dockerfile) with image "selenium-adt-pinned:local", which
will force builds where CI previously relied on pull_policy: missing; to avoid
unnecessary rebuilds add build cache support or use a pushed pinned image:
enable BuildKit in CI (set DOCKER_BUILDKIT=1), add a cache source by configuring
build.cache_from to reference the pinned image (e.g., cache_from:
["selenium-adt-pinned:local"] or a registry-tagged image) or push
"selenium-adt-pinned:local" to your registry and reference that image in
cache_from so CI can reuse layers instead of rebuilding each run.
In `@test/ui/Containerfile.selenium`:
- Line 11: Add a verification step after the installer RUN that asserts the
installed code-server matches the pinned version: after the existing RUN that
pipes to install.sh with --version 4.113.1, run a command that invokes
code-server --version and greps/validates it starts with "4.113.1" so the build
fails early if install.sh ignored or resolved the version incorrectly; update
the Docker instruction sequence that calls the installer to include this
verification and ensure it runs in the same layer or follows immediately so
failures stop the build.
- Line 5: The Dockerfile’s base image currently uses a mutable tag
"ghcr.io/ansible/selenium-adt:main" which defeats your code-server pin; change
the FROM line to reference an immutable image (either a released tag like
"ghcr.io/ansible/selenium-adt:<release-tag>" or preferably a digest
"ghcr.io/ansible/selenium-adt@sha256:<digest>") so the base layer is
reproducible, and ensure the chosen tag/digest corresponds to the expected
code-server version that your RUN curl … install.sh step assumes.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro Plus
Run ID: cfe87dae-cc72-4c05-a712-09575816bb67
📒 Files selected for processing (7)
docker-compose.ymltest/ui/Containerfile.seleniumtest/ui/test_00_commands.pytest/ui/test_01_dev_webviews.pytest/ui/test_02_welcome_webviews.pytest/ui/test_03_llm_provider_webview.pytest/ui/test_50_mcp_server.py
💤 Files with no reviewable changes (5)
- test/ui/test_00_commands.py
- test/ui/test_02_welcome_webviews.py
- test/ui/test_01_dev_webviews.py
- test/ui/test_50_mcp_server.py
- test/ui/test_03_llm_provider_webview.py
| # Reinstall extensions that may have been affected | ||
| RUN code-server --install-extension ms-python.vscode-python-envs \ | ||
| --install-extension ms-python.python \ | ||
| --install-extension redhat.vscode-yaml \ | ||
| --install-extension redhat.vscode-redhat-account |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect the base image to confirm selenium user home and existing extension location.
podman run --rm --entrypoint sh ghcr.io/ansible/selenium-adt:main -c '
id
getent passwd 1001
ls -la /home/selenium/.local/share/code-server/extensions 2>/dev/null || echo "no selenium extensions dir"
ls -la /root/.local/share/code-server/extensions 2>/dev/null || echo "no root extensions dir"
which code-server && code-server --version
'Repository: ansible/vscode-ansible
Length of output: 112
🏁 Script executed:
find . -name "Containerfile*" -o -name "docker-compose*" | head -20Repository: ansible/vscode-ansible
Length of output: 159
🏁 Script executed:
cat -n test/ui/Containerfile.seleniumRepository: ansible/vscode-ansible
Length of output: 998
🏁 Script executed:
find . -name "docker-compose*" -type fRepository: ansible/vscode-ansible
Length of output: 86
🏁 Script executed:
cat -n docker-compose.ymlRepository: ansible/vscode-ansible
Length of output: 1449
🏁 Script executed:
grep -A 20 "selenium-adt" docker-compose.ymlRepository: ansible/vscode-ansible
Length of output: 787
🏁 Script executed:
grep -r "selenium\|USER 1001" --include="*.md" --include="*.txt" .Repository: ansible/vscode-ansible
Length of output: 149
🏁 Script executed:
cat -n ContainerfileRepository: ansible/vscode-ansible
Length of output: 2539
🏁 Script executed:
rg "selenium|user.*1001|1001.*home" -iRepository: ansible/vscode-ansible
Length of output: 4847
🏁 Script executed:
find . -name "README*" -o -name "*.md" | xargs grep -l "selenium\|user.*1001" 2>/dev/null | head -10Repository: ansible/vscode-ansible
Length of output: 97
🏁 Script executed:
rg "home.*selenium|selenium.*home|UID|GID" --include="*.md" --include="*.txt" --include="*.yml" -iRepository: ansible/vscode-ansible
Length of output: 507
🏁 Script executed:
# Check if there are any other references to the base image or its setup
rg "ghcr.io/ansible/selenium-adt" -A 5 -B 5Repository: ansible/vscode-ansible
Length of output: 825
🏁 Script executed:
cat -n docs/development/test_code.mdRepository: ansible/vscode-ansible
Length of output: 3674
Installing extensions as root places them in the wrong user's home directory.
The extensions are installed at lines 14–17 while the container is in USER root context. The code-server --install-extension command writes to the invoking user's $HOME — in this case, /root/.local/share/code-server/extensions. However, the container switches to USER 1001 at line 19, and the docker-compose.yml mounts code-server data directories under /home/selenium/.local/share/code-server/... (the home directory of user 1001). The runtime process will look for extensions under /home/selenium/.local/share/code-server/extensions and will not find the ones installed under /root, silently reproducing the very extension-loading failure this PR aims to fix.
Move the extension installation after switching to the runtime user:
🛠️ Suggested fix
-# Reinstall extensions that may have been affected
-RUN code-server --install-extension ms-python.vscode-python-envs \
- --install-extension ms-python.python \
- --install-extension redhat.vscode-yaml \
- --install-extension redhat.vscode-redhat-account
-
-USER 1001
+USER 1001
+
+# Reinstall extensions under the runtime user's data dir
+RUN code-server --install-extension ms-python.vscode-python-envs \
+ --install-extension ms-python.python \
+ --install-extension redhat.vscode-yaml \
+ --install-extension redhat.vscode-redhat-account🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@test/ui/Containerfile.selenium` around lines 13 - 17, The extension install
commands run as root so they land in /root/.local/share/code-server/extensions
and won't be visible to the runtime user; move the three code-server
--install-extension invocations out of the root section and run them after the
Dockerfile switches to USER 1001 (or run them as UID 1001) so the extensions are
installed into /home/selenium/.local/share/code-server/extensions used at
runtime; remove or avoid the root-level install to prevent duplicate/misplaced
extension files.
Summary
Background
code-server v4.114.0 (released April 4, 2026) has a bug preventing VS Code extensions from loading properly in the selenium-adt container. This caused all Selenium UI tests to fail with
TimeoutExceptionwhile waiting for the Ansible extension to activate.Changes
test/ui/Containerfile.selenium: Extendsghcr.io/ansible/selenium-adt:mainand pins code-server to v4.113.1docker-compose.yml: Builds from the local Containerfile instead of using the upstream image directlyTest plan
Fixes: #2580
Related: ansible/ansible-dev-tools#677
Made with Cursor