Skip to content

drenv: Add automatic kustomize installation#2538

Open
raaizik wants to merge 1 commit intoRamenDR:mainfrom
raaizik:issue-1493-drenv-tools
Open

drenv: Add automatic kustomize installation#2538
raaizik wants to merge 1 commit intoRamenDR:mainfrom
raaizik:issue-1493-drenv-tools

Conversation

@raaizik
Copy link
Copy Markdown
Member

@raaizik raaizik commented May 4, 2026

Change

Implements automatic installation of kustomize tool for drenv:

  • New tools module in test/drenv/tools/
  • Kustomize class with version detection and installation
  • Integration with 'drenv setup' command

This is the first tool in the series. Future commits will add support for the rest.

Related: #1493

Test results


No kustomize installed

Setup

$ rm -f ~/.venv/ramen/bin/kustomize
$ sudo rm -f /usr/local/bin/kustomize
$ which kustomize
/usr/bin/which: no kustomize in (...)

Test

$ cd test
$ python3 test_tools_kustomize.py
Testing kustomize installation...

============================================================
Checking and installing required tools (Proof of Concept)
============================================================

Checking kustomize...
  Required version: >= 5.7.0
  Install directory: /home/usr/.venv/ramen/bin
  Status: NOT FOUND
  Action: Installing 5.7.0...
  Installing kustomize 5.7.0...
  Downloading from https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.7.0/kustomize_v5.7.0_linux_amd64.tar.gz
  ✓ Installed kustomize 5.7.0

============================================================
✓ Tool installation complete
============================================================
  kustomize: 5.7.0 (installed at /home/usr/.venv/ramen/bin/kustomize)
============================================================

✓ Test successful!

Verification

$ which kustomize
/home/usr/.venv/ramen/bin/kustomize

$ kustomize version
v5.7.0

Old kustomize version (5.3.0)

Setup

$ rm -f ~/.venv/ramen/bin/kustomize
$ sudo rm -f /usr/local/bin/kustomize
$ which kustomize
/usr/bin/which: no kustomize in (...)

$ curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | bash -s -- 5.3.0
v5.3.0
kustomize installed to /home/usr/ramen/test/kustomize

$ ./kustomize version
v5.3.0

$ which kustomize
/usr/bin/which: no kustomize in (...)

Test

$ python3 test_tools_kustomize.py
Testing kustomize installation...

============================================================
Checking and installing required tools (Proof of Concept)
============================================================

Checking kustomize...
  Required version: >= 5.7.0
  Install directory: /home/usr/.venv/ramen/bin
  Status: NOT FOUND
  Action: Installing 5.7.0...
  Installing kustomize 5.7.0...
  Downloading from https://github.com/kubernetes-sigs/kustomize/releases/download/kustomize%2Fv5.7.0/kustomize_v5.7.0_linux_amd64.tar.gz
  ✓ Installed kustomize 5.7.0

============================================================
✓ Tool installation complete
============================================================
  kustomize: 5.7.0 (installed at /home/usr/.venv/ramen/bin/kustomize)
============================================================

✓ Test successful!

Verification

$ which kustomize
/home/usr/.venv/ramen/bin/kustomize

$ kustomize version
v5.7.0

Correct version already in venv (5.7.0)

Setup

$ which kustomize
/home/usr/.venv/ramen/bin/kustomize

$ kustomize version
v5.7.0

Test

$ cd test
$ python3 test_tools_kustomize.py
Testing kustomize installation...

============================================================
Checking and installing required tools (Proof of Concept)
============================================================

Checking kustomize...
  Required version: >= 5.7.0
  Install directory: /home/usr/.venv/ramen/bin
  Status: UP TO DATE (found 5.7.0)
  Action: None needed

============================================================
✓ Tool installation complete
============================================================
  kustomize: 5.7.0 (installed at /home/usr/.venv/ramen/bin/kustomize)
============================================================

✓ Test successful!

Verification

$ which kustomize
/home/usr/.venv/ramen/bin/kustomize

$ kustomize version
v5.7.0

System kustomize with newer version (5.8.1)

Setup

$ rm -f ~/.venv/ramen/bin/kustomize
$ curl -s "https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh" | sudo bash -s -- /usr/local/bin
v5.8.1
kustomize installed to /usr/local/bin/kustomize

$ which kustomize
/usr/local/bin/kustomize

$ kustomize version
v5.8.1

Test

$ cd test
$ python3 test_tools_kustomize.py
Testing kustomize installation...

============================================================
Checking and installing required tools (Proof of Concept)
============================================================

Checking kustomize...
  Required version: >= 5.7.0
  Install directory: /home/usr/.venv/ramen/bin
  Status: UP TO DATE (found 5.8.1)
  Action: None needed

============================================================
✓ Tool installation complete
============================================================
  kustomize: 5.8.1 (installed at /home/usr/.venv/ramen/bin/kustomize)
============================================================

✓ Test successful!

Verification

$ which kustomize
/usr/local/bin/kustomize

$ kustomize version
v5.8.1

Integration test: drenv setup

Setup

$ which kustomize
/usr/local/bin/kustomize

$ kustomize version
v5.8.1

Test

$ drenv setup envs/regional-dr.yaml
2026-05-04 08:34:23,917 INFO    [main] Setting up drenv
2026-05-04 08:34:23,918 INFO    [main] Installing required tools
2026-05-04 08:34:23,918 INFO    ============================================================
2026-05-04 08:34:23,918 INFO    Checking and installing required tools (Proof of Concept)
2026-05-04 08:34:23,918 INFO    ============================================================
2026-05-04 08:34:23,918 INFO
Checking kustomize...
2026-05-04 08:34:23,918 INFO      Required version: >= 5.7.0
2026-05-04 08:34:23,918 INFO      Install directory: /home/usr/.venv/ramen/bin
2026-05-04 08:34:23,924 INFO      Status: UP TO DATE (found 5.8.1)
2026-05-04 08:34:23,924 INFO      Action: None needed
2026-05-04 08:34:23,933 INFO
============================================================
2026-05-04 08:34:23,933 INFO    ✓ Tool installation complete
2026-05-04 08:34:23,933 INFO    ============================================================
2026-05-04 08:34:23,934 INFO      kustomize: 5.8.1 (installed at /home/usr/.venv/ramen/bin/kustomize)
2026-05-04 08:34:23,934 INFO    ============================================================

2026-05-04 08:34:23,934 INFO    [main] Setting up 'minikube' for drenv
2026-05-04 08:34:24,383 INFO    [registry] Removed container drenv-cache-quay-io
2026-05-04 08:34:24,527 INFO    [registry] Created container drenv-cache-quay-io on port 5051 (id: d81a378837d3bf0f937f07005fe140ea966978edca207a315d212afe4702b380)
2026-05-04 08:34:24,703 INFO    [registry] Removed container drenv-cache-docker-io
2026-05-04 08:34:24,825 INFO    [registry] Created container drenv-cache-docker-io on port 5052 (id: 9015285ccf405ab9737d50d10d6dee49370febecc5ec90fdf02c27201d7dd0b4)
...

TODOs

  • Implement for the rest of the tools
  • Deprecate the respective hack scripts
  • Add and revise documentation

Summary by CodeRabbit

  • New Features

    • Added tool management infrastructure to support automatic installation and version verification of required tools.
    • Implemented support for kustomize tool with automatic download and setup.
  • Tests

    • Added comprehensive test coverage for tool management and kustomize functionality.
    • Added integration test script for tool setup validation.

@raaizik raaizik changed the title drenv: Add automatic kustomize installation (Issue #1493) drenv: Add automatic kustomize installation May 4, 2026
Copy link
Copy Markdown
Member

@nirs nirs left a comment

Choose a reason for hiding this comment

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

Since the code for specific tool is pretty simple and we can reuse most code, we can start with single drenv/tools.py.

The public API for the module is the setup() function. We don't need anything else public.

Not sure why we have tools_kustomize.py when all the other tools are classes in tools.py.

Comment thread test/drenv/__main__.py Outdated
Comment thread test/drenv/__main__.py Outdated
Copy link
Copy Markdown
Member

@nirs nirs left a comment

Choose a reason for hiding this comment

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

The tools.py module duplicate the same code for every tool. We ned to implement once install from single binary and from tar file and keep the needed configuration (download_url, tar_member_name) in a class attribute.

Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Comment thread test/drenv/tools/tools.py Outdated
Copy link
Copy Markdown
Member

@nirs nirs left a comment

Choose a reason for hiding this comment

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

Added move comments fro the tests.

Comment thread test/drenv/tools/tools_kustomize.py Outdated
Comment thread test/drenv/tools/tools_kustomize.py Outdated
Comment thread test/drenv/tools/tools_kustomize.py Outdated
Comment thread test/drenv/tools/tools_kustomize.py Outdated
Comment thread test/drenv/tools/tools_kustomize.py Outdated
Comment thread test/drenv/tools/tools_test.py Outdated
Comment thread test/drenv/tools/tools_test.py Outdated
Comment thread test/drenv/tools/tools_test.py
Comment thread test/drenv/tools/tools_test.py Outdated
Comment thread test/drenv/tools/tools_test.py Outdated
Copy link
Copy Markdown
Member

@nirs nirs left a comment

Choose a reason for hiding this comment

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

Added move comments for the tests.

Comment thread test/drenv/tools/tools_test.py Outdated
raaizik added a commit to raaizik/ramen that referenced this pull request May 5, 2026
This commit addresses PR RamenDR#2538 review comments by refactoring the tool
management system with a minimal kustomize-only implementation. This
incremental approach allows for focused review before extending to
other tools.

Key changes addressing review comments:

1. Tool base class improvements:
   - name and required_version are now class attributes (not instance)
   - install_dir() is now a method returning venv bin directory
   - Removed instance variables in favor of class-level declarations

2. Error handling:
   - Use drenv.commands.run() instead of subprocess directly
   - Narrow error handling: only catch FileNotFoundError for missing tools
   - Let other errors propagate to avoid hiding bugs
   - Work around commands.Error.with_exception() setting __cause__ to None

3. Python idioms:
   - Use 'f' for file handles (not 'file')
   - Use tarfile mode 'r' for auto-detection instead of 'r:gz'
   - Simplified version parsing for kustomize output format

4. Code organization:
   - Removed binary name guessing - each tool knows its exact name
   - Imports organized at module top level
   - Single tools.setup() call in __main__.py

5. Implementation scope:
   - Start with kustomize only (other tools removed temporarily)
   - Updated __init__.py to export only Tool, Kustomize, setup
   - Removed tools_kustomize.py (functionality merged into tools.py)
   - Renamed test_tools_kustomize.py to test_tools.py for generality

Testing:
- Verified kustomize installation on macOS
- Verified version detection works correctly
- Verified upgrade detection (version comparison)
- Integration with drenv setup command confirmed

Related: RamenDR#1493
Addresses: PR RamenDR#2538 review comments from nirs
@raaizik raaizik force-pushed the issue-1493-drenv-tools branch 8 times, most recently from f368eeb to e04fbdf Compare May 5, 2026 12:06
@raaizik raaizik marked this pull request as ready for review May 7, 2026 10:07
@raaizik raaizik marked this pull request as draft May 7, 2026 10:07
@raaizik raaizik force-pushed the issue-1493-drenv-tools branch from e04fbdf to 4ac56a7 Compare May 7, 2026 10:11
@raaizik raaizik marked this pull request as ready for review May 7, 2026 10:12
@raaizik raaizik requested a review from nirs May 7, 2026 10:12
@raaizik raaizik marked this pull request as draft May 7, 2026 10:25
@raaizik raaizik force-pushed the issue-1493-drenv-tools branch 6 times, most recently from 9f7e166 to 09211fc Compare May 7, 2026 10:50
Implements automatic installation of kustomize tool for drenv:
- New tools module in test/drenv/tools/
- Kustomize class with version detection and installation
- Integration with 'drenv setup' command

This is the first tool in the series. Future commits will add
support for the rest.

Related: RamenDR#1493

Signed-off-by: raaizik <132667934+raaizik@users.noreply.github.com>
@raaizik raaizik force-pushed the issue-1493-drenv-tools branch from f93a1e2 to c96aaae Compare May 7, 2026 10:59
@raaizik raaizik marked this pull request as ready for review May 7, 2026 11:16
@nirs
Copy link
Copy Markdown
Member

nirs commented May 7, 2026

@coderabbitai full review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

✅ Actions performed

Full review triggered.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a tool-management system to the drenv test infrastructure. It introduces a Tool base class for managing binary tool installations, implements Kustomize as a concrete tool with platform detection and GitHub release downloading, integrates tool setup into drenv initialization, and includes comprehensive unit and integration test coverage.

Changes

Tool Management System for drenv

Layer / File(s) Summary
Tool Base Class and Contracts
test/drenv/tools/tools.py (lines 1–110)
Tool base class defines install_dir(), path(), abstract version() and install() methods, and verify() logic comparing installed vs. required versions. Module-level OS_NAME and ARCH constants are detected at import time.
Kustomize Implementation
test/drenv/tools/tools.py (lines 114–189)
Kustomize class extends Tool, constructs GitHub release URLs using OS and architecture, downloads and extracts the kustomize binary, parses version output (handling missing/invalid cases), and sets executable permissions.
Helper Functions
test/drenv/tools/tools.py (lines 114–145)
download() and extract_tar() utilities provide file download via urllib and binary extraction from tar archives, flattening the archive structure.
Setup Orchestration
test/drenv/tools/tools.py (lines 194–227)
setup(install_dir=None) iterates tool instances, checks version status, runs install/update with logging, and propagates exceptions on failure.
Package Interface
test/drenv/tools/__init__.py
Defines package docstring, re-exports Tool, Kustomize, and setup from .tools, and declares __all__ for explicit exports.
drenv Integration
test/drenv/__main__.py (lines 28, 344–351)
Imports tools module and calls tools.setup() at the start of do_setup() before SSH and provider setup.
Unit Tests
test/drenv/tools/tools_test.py (lines 17–141)
TestKustomize validates metadata and version parsing (with/without leading v); TestHelpers checks platform constants and downloads; TestSetup confirms setup is callable.
Integration Test Script
test/test_tools.py
Standalone test script that imports drenv, configures logging, runs tools.setup(), and exits with code 0 on success or 1 on failure with traceback output.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'drenv: Add automatic kustomize installation' directly and clearly describes the main change: adding automatic kustomize tool installation to drenv, which is the primary objective evident across all file changes (new tools module, Kustomize class, integration into setup, and tests).
Docstring Coverage ✅ Passed Docstring coverage is 95.65% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


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

@nirs
Copy link
Copy Markdown
Member

nirs commented May 7, 2026

@coderabbitai help

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 7, 2026

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.

CodeRabbit commands

These commands are invoked using PR/Issue comments.

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai rate limit to show your current review rate limit status.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai evaluate custom pre-merge check --instructions <custom-checks-instructions> --name <custom-checks-title> [--mode <error|warning>] to validate the custom pre-merge checks instructions. Defaults to error when --mode is omitted.
  • @coderabbitai ignore pre-merge checks to override pre-merge checks and get an approval on PR.
  • @coderabbitai run pre-merge checks to run pre-merge checks on the pull request.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve merge conflict to automatically resolve merge conflicts.
  • @coderabbitai autofix to automatically fix issues identified in unresolved review comments.
  • @coderabbitai resolve to resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai generate configuration to create a PR that adds the current resolved configuration as .coderabbit.yaml (or show it if already present).
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore or @coderabbit ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit configuration file (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • You can also validate your configuration using the online YAML validator.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Status, support, documentation and community

  • Visit our status page to check the current availability of CodeRabbit.
  • Create a ticket on our support page for assistance with any issues or questions.
  • Visit our documentation site for detailed information on how to use CodeRabbit.
  • Join our Discord community to connect with other users and get help from the community.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

♻️ Duplicate comments (1)
test/drenv/tools/tools.py (1)

182-188: ⚠️ Potential issue | 🟠 Major | ⚡ Quick win

install() leaves a partial binary in install_dir() if extraction fails

extract_tar writes the binary directly to self.install_dir(). A network error, disk-full condition, or FilterError mid-extraction leaves a truncated/corrupted binary at the final path. Subsequent version() calls will then either crash or mis-report the version.

The fix is to extract into tmpdir (already created for the archive download) and atomically rename to the final path on success:

🛡️ Proposed fix
 def install(self):
     """Install kustomize from GitHub releases."""
     with tempfile.TemporaryDirectory() as tmpdir:
         archive_path = os.path.join(tmpdir, "kustomize.tar.gz")
         download(self.download_url, archive_path)
-        extract_tar(archive_path, self.install_dir(), self.archive_binary_path)
-        os.chmod(self.path(), 0o755)
+        extract_tar(archive_path, tmpdir, self.archive_binary_path)
+        tmp_binary = os.path.join(tmpdir, self.name)
+        os.chmod(tmp_binary, 0o755)
+        shutil.move(tmp_binary, self.path())
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/drenv/tools/tools.py` around lines 182 - 188, The install() method
currently extracts the binary directly into self.install_dir(), risking a
partial/corrupt binary on extraction failure; change install() to extract into
the existing temporary directory (tmpdir) first (use extract_tar to a temp
destination inside tmpdir using self.archive_binary_path as the extracted name),
verify extraction succeeded, then atomically move/rename the temp binary into
its final location returned by self.path()/self.install_dir() (e.g., os.replace
or similar) and set permissions with os.chmod only after the atomic rename;
ensure any temporary extracted file is cleaned up on error so a truncated file
is never left at the final path.
🧹 Nitpick comments (1)
test/drenv/tools/tools_test.py (1)

128-137: ⚡ Quick win

test_setup_accepts_install_dir never exercises the install_dir parameter

callable(tools.setup) is always True for a defined function — this test provides no coverage whatsoever. The past reviewer's intent was specifically to use install_dir= to run setup() without touching the real venv. That path is still untested.

♻️ Proposed replacement
 class TestSetup(unittest.TestCase):
     """Test setup function."""

     def test_setup_accepts_install_dir(self):
-        """Test setup accepts custom install_dir parameter."""
-        # This test verifies the parameter is accepted
-        # Actual installation testing would require more setup
-        # Just verify setup() accepts the parameter without error
-        # We don't actually call it to avoid modifying the system
-        self.assertTrue(callable(tools.setup))
+        """Test setup installs tools into a custom install_dir."""
+        with tempfile.TemporaryDirectory() as tmpdir:
+            tools.setup(install_dir=tmpdir)
+            kustomize_bin = os.path.join(tmpdir, "kustomize")
+            self.assertTrue(os.path.isfile(kustomize_bin))
+            self.assertTrue(os.access(kustomize_bin, os.X_OK))
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/drenv/tools/tools_test.py` around lines 128 - 137, Replace the no-op
assertion with an actual call to tools.setup using an isolated temp dir: in
test_setup_accepts_install_dir, create a temporary directory via
tempfile.TemporaryDirectory() (or pytest tmp_path), call
tools.setup(install_dir=temp_dir) and assert it completes (no exception) and/or
that the returned value or side-effect references the temp_dir (e.g.,
os.path.exists(temp_dir) or returned_path.startswith(temp_dir)). If tools.setup
performs external actions, wrap the call in mocks for those helpers or teardown
the temp dir after the test to avoid touching the real environment; keep the
test focused on exercising the install_dir parameter and cleaning up the temp
directory.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@test/drenv/tools/tools.py`:
- Around line 138-143: The tar.extract call in the install routine is missing
the filter argument which triggers DeprecationWarning; update the extraction to
call tar.extract(member, target_dir, filter='data') so the archive extraction of
the single binary (the code that uses tar.getmember(archive_binary_path), sets
member.name = os.path.basename(member.name), and then calls tar.extract(...))
uses the safer 'data' filter for trusted GitHub release archives.

In `@test/test_tools.py`:
- Around line 13-16: The import order is wrong: the sys.path.insert(0, ".") call
currently runs after the import "from drenv.tools import tools", so it never
affects that import; move the sys.path.insert(0, ".") statement to before the
"from drenv.tools import tools" line (or remove the sys.path manipulation
entirely if drenv is guaranteed to be installed in the test venv) so that the
import can succeed when loading drenv from the repository.

---

Duplicate comments:
In `@test/drenv/tools/tools.py`:
- Around line 182-188: The install() method currently extracts the binary
directly into self.install_dir(), risking a partial/corrupt binary on extraction
failure; change install() to extract into the existing temporary directory
(tmpdir) first (use extract_tar to a temp destination inside tmpdir using
self.archive_binary_path as the extracted name), verify extraction succeeded,
then atomically move/rename the temp binary into its final location returned by
self.path()/self.install_dir() (e.g., os.replace or similar) and set permissions
with os.chmod only after the atomic rename; ensure any temporary extracted file
is cleaned up on error so a truncated file is never left at the final path.

---

Nitpick comments:
In `@test/drenv/tools/tools_test.py`:
- Around line 128-137: Replace the no-op assertion with an actual call to
tools.setup using an isolated temp dir: in test_setup_accepts_install_dir,
create a temporary directory via tempfile.TemporaryDirectory() (or pytest
tmp_path), call tools.setup(install_dir=temp_dir) and assert it completes (no
exception) and/or that the returned value or side-effect references the temp_dir
(e.g., os.path.exists(temp_dir) or returned_path.startswith(temp_dir)). If
tools.setup performs external actions, wrap the call in mocks for those helpers
or teardown the temp dir after the test to avoid touching the real environment;
keep the test focused on exercising the install_dir parameter and cleaning up
the temp directory.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 9786e58e-2219-408b-90fa-21a7864956d6

📥 Commits

Reviewing files that changed from the base of the PR and between b609889 and c96aaae.

📒 Files selected for processing (5)
  • test/drenv/__main__.py
  • test/drenv/tools/__init__.py
  • test/drenv/tools/tools.py
  • test/drenv/tools/tools_test.py
  • test/test_tools.py
📜 Review details
🧰 Additional context used
🪛 Ruff (0.15.12)
test/test_tools.py

[warning] 28-28: Do not catch blind exception: Exception

(BLE001)

test/drenv/tools/__init__.py

[warning] 20-24: __all__ is not sorted

Apply an isort-style sorting to __all__

(RUF022)

test/drenv/tools/tools_test.py

[error] 44-44: Probable insecure usage of temporary file or directory: "/tmp/custom"

(S108)

test/drenv/tools/tools.py

[error] 123-123: Audit URL open for permitted schemes. Allowing use of file: or custom schemes is often unexpected.

(S310)


[error] 188-188: os.chmod setting a permissive mask 0o755 on file or directory

(S103)

🔇 Additional comments (3)
test/drenv/tools/__init__.py (1)

1-24: LGTM

Clean re-export package; the module docstring, __all__, and imports are all consistent with the implementation in tools.py.

test/drenv/__main__.py (1)

28-28: LGTM

Both past review concerns are fully addressed: tools is imported at module level (Line 28), and do_setup delegates to the single tools.setup() call rather than importing tools inline or listing them individually.

Also applies to: 344-355

test/drenv/tools/tools.py (1)

164-180: ⚡ Quick win

Remove this comment — the exception handling is correct as-is

commands.run() wraps all OSError exceptions (including FileNotFoundError) in a commands.Error at line 136 of test/drenv/commands.py:

except OSError as e:
    raise Error(args, f"Could not execute: {e}").with_exception(e)

When a binary doesn't exist, subprocess.Popen raises FileNotFoundError (a subclass of OSError), which is caught and wrapped. FileNotFoundError never propagates directly from commands.run(). The current code correctly catches commands.Error and checks the message. Catching FileNotFoundError directly in version() would never match because the exception is always wrapped.

The "install missing tool" path is not dead — the exception handling works as intended.

			> Likely an incorrect or invalid review comment.

Comment thread test/drenv/tools/tools.py
Comment on lines +138 to +143
with tarfile.open(archive_path, "r") as tar:
member = tar.getmember(archive_binary_path)
# Extract binary to target_dir root, removing any directory structure from archive
# This ensures the binary is placed directly in install_dir, not in a subdirectory
member.name = os.path.basename(member.name)
tar.extract(member, target_dir)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

Python 3.12 3.13 tar.extract DeprecationWarning filter parameter

💡 Result:

In Python 3.12 and 3.13, calling tarfile.TarFile.extract or extractall without the filter parameter (or with filter=None) triggers a DeprecationWarning: "Python 3.14 will, by default, filter extracted tar archives and reject files or modify their metadata. Use the filter argument to control this behavior." [1][2][3] This behavior was introduced in Python 3.12 via PEP 706 to address security issues like CVE-2007-4559 (path traversal in tar extraction). When no filter is specified, it falls back to the 'fully_trusted' filter (matching pre-3.12 behavior) but emits the warning. The default changes in Python 3.14 to 'data', which blocks dangerous features like absolute paths, symlinks outside the target directory, and certain metadata. [1][4][2][3] To silence the warning and prepare for 3.14: - Use filter='data' for safe extraction of data archives (recommended for most cases, ignores/block most UNIX-specific features). [1][3] - Use filter='fully_trusted' if you need full legacy behavior and trust the archive. [2] - Use filter='tar' to honor tar-specific features but block highly dangerous ones. [1] - Or set TarFile.extraction_filter globally/class-wide, e.g., TarFile.extraction_filter = 'data' [1][3] Example: import tarfile with tarfile.open('archive.tar') as tf: tf.extractall(path='dest', filter='data') # No warning, safe for 3.14+ Python 3.13 retains this exact deprecation behavior (no changes noted in 3.13 docs or changelog); the switch happens in 3.14. [1][5] Note: There was a CVE-2024-12718 in 3.12+ filters='data'/'tar' allowing limited metadata changes outside dest, but patches are available—upgrade Python. [6][7]

Citations:


🌐 Web query:

Python 3.14 tarfile extract filter default behavior changes

💡 Result:

In Python 3.14, the default behavior of tarfile.TarFile.extract and extractall changed significantly regarding the filter parameter. Previously (in 3.12 and 3.13), when the filter argument was None (the default), it would use the 'fully_trusted' filter after emitting a DeprecationWarning, allowing potentially dangerous operations like extracting to absolute paths or paths outside the destination directory [1][2]. In Python 3.14, the default filter is now 'data', which disallows such dangerous features including links to absolute paths or paths outside the destination, making extraction safer by default [1][3]. This implements PEP 706 [2][4]. The official documentation states: "Changed in version 3.14: The default filter is set to data, which disallows some dangerous features such as links to absolute paths or paths outside of the destination. Previously, the default was equivalent to fully_trusted." [1]. Developers are recommended to explicitly set the filter if specific behavior is needed, especially for compatibility across versions [1]. Note that even the 'data' filter does not prevent all security issues, as seen in later CVEs like CVE-2024-12718, but it addresses the most critical path traversal risks [5][6][3].

Citations:


🏁 Script executed:

# Check the context around the code to understand if filter='data' is appropriate
cat -n test/drenv/tools/tools.py | head -160 | tail -40

Repository: RamenDR/ramen

Length of output: 1741


Add filter='data' to tar.extract() to silence DeprecationWarning and prepare for Python 3.14

Without an explicit filter argument, tar.extract() emits a DeprecationWarning on Python 3.12–3.13 and will use a safer default ('data') in Python 3.14. Since the archive is from a trusted GitHub release and contains only a single binary, filter='data' is the recommended approach.

Fix
-        tar.extract(member, target_dir)
+        tar.extract(member, target_dir, filter='data')
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/drenv/tools/tools.py` around lines 138 - 143, The tar.extract call in
the install routine is missing the filter argument which triggers
DeprecationWarning; update the extraction to call tar.extract(member,
target_dir, filter='data') so the archive extraction of the single binary (the
code that uses tar.getmember(archive_binary_path), sets member.name =
os.path.basename(member.name), and then calls tar.extract(...)) uses the safer
'data' filter for trusted GitHub release archives.

Comment thread test/test_tools.py
Comment on lines +13 to +16
from drenv.tools import tools

# Add test directory to path so we can import drenv
sys.path.insert(0, ".")
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

sys.path.insert is dead code — it executes after the import it was meant to enable

The from drenv.tools import tools import on Line 13 runs before sys.path.insert(0, ".") on Line 16. If drenv is not already importable, the script errors at Line 13, never reaching Line 16. The path manipulation should either be moved above the imports or removed entirely if drenv is guaranteed to be installed in the active venv.

🐛 Proposed fix
+# Add test directory to path so we can import drenv
+sys.path.insert(0, ".")
+
 from drenv.tools import tools
-
-# Add test directory to path so we can import drenv
-sys.path.insert(0, ".")
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
from drenv.tools import tools
# Add test directory to path so we can import drenv
sys.path.insert(0, ".")
# Add test directory to path so we can import drenv
sys.path.insert(0, ".")
from drenv.tools import tools
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/test_tools.py` around lines 13 - 16, The import order is wrong: the
sys.path.insert(0, ".") call currently runs after the import "from drenv.tools
import tools", so it never affects that import; move the sys.path.insert(0, ".")
statement to before the "from drenv.tools import tools" line (or remove the
sys.path manipulation entirely if drenv is guaranteed to be installed in the
test venv) so that the import can succeed when loading drenv from the
repository.

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.

2 participants