Skip to content

Restrict agent container autopull to latest tag#46

Merged
nezhar merged 3 commits into
mainfrom
autopull-latest
Mar 15, 2026
Merged

Restrict agent container autopull to latest tag#46
nezhar merged 3 commits into
mainfrom
autopull-latest

Conversation

@nezhar
Copy link
Copy Markdown
Collaborator

@nezhar nezhar commented Mar 15, 2026

Eensures that Docker images tagged as latest are checked for updates before container startup for agents

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 15, 2026

Warning

Rate limit exceeded

@nezhar has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 22 minutes and 53 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 811a15b6-0dc1-47ae-a6ce-10a25e479737

📥 Commits

Reviewing files that changed from the base of the PR and between 1e8039a and 8a6c61e.

📒 Files selected for processing (5)
  • src/vibepod/commands/logs.py
  • src/vibepod/commands/proxy.py
  • src/vibepod/commands/run.py
  • src/vibepod/core/docker.py
  • tests/test_run.py
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch autopull-latest
📝 Coding Plan
  • Generate coding plan for human review comments

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@greptile-apps
Copy link
Copy Markdown

greptile-apps Bot commented Mar 15, 2026

Greptile Summary

This PR restricts Docker image auto-pull to only images tagged as latest (explicit or implicit), preventing unnecessary network calls when a pinned/versioned image is in use. The same guard is applied consistently across the agent run, proxy start, and logs start commands. As a bonus, the PR also adds a --paste-images flag to forward the host's X11 socket into the agent container for clipboard-based image pasting.

Key changes:

  • New _is_latest_tag(image) helper in docker.py — logic looks correct for registries with port numbers, digest refs, and implicit-latest images, but the symbol uses a private-naming convention (_ prefix) while being imported as a public API across three modules.
  • run.py auto-pull is now pull or (auto_pull_enabled and _is_latest_tag(image)) — explicit --pull still forces a pull regardless of tag, which is the right behaviour.
  • --paste-images / _x11_volumes_and_env mounts /tmp/.X11-unix and sets DISPLAY, but does not forward the host's ~/.Xauthority cookie. Standard X11 authentication (MIT-MAGIC-COOKIE-1) requires that cookie; without it the feature will silently fail to connect on any host that hasn't disabled auth with xhost +local:.
  • The proxy pull check added inside run.py is missing the info("Checking for proxy image updates…") log message present in the analogous block in proxy.py, creating an inconsistent user experience.
  • No unit tests cover the case where auto-pull is skipped because the image tag is not latest.

Confidence Score: 3/5

  • Safe to merge for the core auto-pull restriction, but the --paste-images X11 feature has a bug that will prevent it from working in typical setups.
  • The _is_latest_tag logic and its application across all three commands is correct and well-guarded. The main concern is the --paste-images feature: it mounts the X11 socket but omits the Xauthority cookie, meaning it will fail silently on most standard X11 configurations. The missing info log for proxy pulls in run.py and the test coverage gap for non-latest tag skipping are minor but should be addressed.
  • Pay close attention to src/vibepod/commands/run.py — specifically _x11_volumes_and_env (missing Xauthority) and the proxy pull block (missing user-facing log message).

Important Files Changed

Filename Overview
src/vibepod/core/docker.py Adds _is_latest_tag helper that correctly identifies images that should be auto-pulled; naming convention (leading underscore) is inconsistent with its cross-module public usage.
src/vibepod/commands/run.py Restricts auto-pull to latest-tagged images and adds --paste-images (X11) feature; the X11 helper does not forward the Xauthority cookie so it will fail in standard secured X11 setups; proxy pull is also missing a user-facing status message.
src/vibepod/commands/logs.py Wraps existing datasette pull logic in _is_latest_tag guard; straightforward, no issues.
src/vibepod/commands/proxy.py Adds _is_latest_tag guard before pull_if_newer; correctly includes an info message to the user, unlike the analogous code in run.py.
tests/test_run.py Good coverage for --paste-images and X11 edge cases; existing auto-pull tests implicitly depend on the default image being :latest-tagged but lack an explicit test for the new non-latest skipping behaviour.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[CLI command invoked\nrun / proxy start / logs start] --> B{auto_pull enabled\nor --pull flag?}
    B -- "--pull flag" --> D[Pull image unconditionally]
    B -- "auto_pull enabled" --> C{_is_latest_tag?}
    C -- "Yes\nexplicit :latest or no tag" --> D
    C -- "No\npinned version/digest" --> E[Skip pull]
    D --> F[Start container]
    E --> F

    A2[run --paste-images] --> G{DISPLAY set?}
    G -- "No" --> H[Warn & skip X11 forwarding]
    G -- "Yes" --> I[Mount /tmp/.X11-unix\nSet DISPLAY env]
    I --> J[⚠️ Xauthority NOT forwarded\nX11 auth may fail]
    J --> F2[Start agent container]
    H --> F2
Loading

Comments Outside Diff (1)

  1. tests/test_run.py, line 462-469 (link)

    Existing auto-pull tests now pass by coincidence on the default :latest image

    test_auto_pull_global_triggers_pull (and its siblings) rely on run_cmd.run(agent="claude", ...) pulling the default Claude image. With this PR's change, should_pull is now gated by auto_pull_enabled and _is_latest_tag(image). These tests continue to pass only because the claude default image resolves to a latest-tagged image; if that default ever changes to a pinned digest, the tests would silently stop asserting the pull path.

    Consider adding a dedicated test that asserts auto-pull is skipped when the effective image has a non-latest tag (e.g. vibepod/claude:1.2.3), so the new _is_latest_tag gating has explicit coverage.

Last reviewed commit: 8a6c61e

Comment on lines +152 to +156
def _x11_volumes_and_env(display: str) -> tuple[list[tuple[str, str, str]], dict[str, str]]:
"""Return X11 socket volumes and DISPLAY env for paste-image support."""
volumes: list[tuple[str, str, str]] = [("/tmp/.X11-unix", "/tmp/.X11-unix", "rw")]
env: dict[str, str] = {"DISPLAY": display}
return volumes, env
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

X11 authentication cookie not forwarded

The _x11_volumes_and_env helper mounts the X11 socket and sets DISPLAY, but standard X11 security (MIT-MAGIC-COOKIE-1) also requires the authorization cookie file (~/.Xauthority). Without mounting that file and setting the XAUTHORITY env var, any X11 client inside the container will fail with Authorization required, use MIT-MAGIC-COOKIE-1 — unless the host happens to have xhost +local: enabled, which is an insecure configuration.

To make --paste-images work in the default case, the host's Xauthority file needs to be forwarded:

def _x11_volumes_and_env(display: str) -> tuple[list[tuple[str, str, str]], dict[str, str]]:
    """Return X11 socket volumes and DISPLAY env for paste-image support."""
    xauth_path = os.environ.get("XAUTHORITY", os.path.expanduser("~/.Xauthority"))
    volumes: list[tuple[str, str, str]] = [("/tmp/.X11-unix", "/tmp/.X11-unix", "rw")]
    env: dict[str, str] = {"DISPLAY": display}
    if os.path.exists(xauth_path):
        volumes.append((xauth_path, xauth_path, "ro"))
        env["XAUTHORITY"] = xauth_path
    return volumes, env

Comment on lines +327 to +328
if _is_latest_tag(proxy_image):
manager.pull_if_newer(proxy_image)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing user-facing info message for proxy update check

In proxy.py the equivalent block emits info("Checking for proxy image updates…") before calling pull_if_newer, so the user can see what is happening. This call site in run.py silently pulls in the background, which can look like a hang for larger images.

Suggested change
if _is_latest_tag(proxy_image):
manager.pull_if_newer(proxy_image)
if _is_latest_tag(proxy_image):
info("Checking for proxy image updates…")
manager.pull_if_newer(proxy_image)

Comment on lines +44 to +47
def _is_latest_tag(image: str) -> bool:
"""Return True when *image* uses the ``latest`` tag (explicitly or by omission)."""
name = image.split("/")[-1]
return ":" not in name or name.endswith(":latest")
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Private-name function imported as a public API

_is_latest_tag carries a leading underscore, which in Python signals "private to this module / implementation detail". However it is now imported explicitly in three separate command modules (logs.py, proxy.py, run.py), making it a de-facto public utility. Either rename it to is_latest_tag to signal the intended public use, or document why the single-underscore prefix is intentional (e.g. "not part of the stable API"). As-is, tools like linters, documentation generators, and other contributors will reasonably assume this symbol should not be imported externally.

@nezhar nezhar merged commit 4c34cfa into main Mar 15, 2026
20 checks passed
@nezhar nezhar deleted the autopull-latest branch March 20, 2026 13:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant