Skip to content

fix: pip version constraint escaping in container build#41

Merged
nathan-weinberg merged 1 commit intoopendatahub-io:mainfrom
derekhiggins:escape-versions
Sep 18, 2025
Merged

fix: pip version constraint escaping in container build#41
nathan-weinberg merged 1 commit intoopendatahub-io:mainfrom
derekhiggins:escape-versions

Conversation

@derekhiggins
Copy link
Copy Markdown
Collaborator

@derekhiggins derekhiggins commented Sep 18, 2025

  • Add quotes around packages with > or < characters to prevent bash redirection
  • Prevents files like '=0.12.0' in final container
  • ensures the required version constraints are applied
  • Affects packages: datasets>=4.0.0, mcp>=1.8.1, pymilvus>=2.4.10, torchao>=0.12.0

--

(base) derekh@laptop:~/workarea/llama-stack-distribution$ podman run -it --entrypoint bash quay.io/opendatahub/llama-stack -c 'ls /opt/app-root'
'=0.12.0'  '=1.8.1'  '=2.4.10'	'=4.0.0'   bin	 etc   include	 lib   lib64   pyvenv.cfg   run.yaml   share   src

Summary by CodeRabbit

  • Bug Fixes

    • Prevented shell redirection issues during container builds by quoting dependency version constraints so pip installs treat them as literal arguments across all build paths.
  • Chores

    • Updated several Python package version specifications in the container image for improved stability and compatibility.
    • Standardized pip install argument formatting for more consistent, reproducible builds.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Sep 18, 2025

Walkthrough

Wraps pip package specifiers containing comparison operators in single quotes when constructing install commands and updates several package specifiers in the Dockerfile to use quoted forms.

Changes

Cohort / File(s) Summary
Container image manifest
distribution/Containerfile
Several pip package specifiers in RUN pip install lines were changed to be wrapped in single quotes (e.g., 'datasets>=4.0.0', 'mcp>=1.8.1', 'pymilvus>=2.4.10', 'torchao>=0.12.0').
Build script: safe quoting of specifiers
distribution/build.py
After deduplicating and sorting dependency tokens, any token containing > or < is wrapped in single quotes to avoid shell redirection when forming pip install commands (applies to index-url/extra-index-url, no-deps, no-cache, and standard command variants).

Sequence Diagram(s)

sequenceDiagram
    autonumber
    actor Dev as Developer
    participant Build as distribution/build.py
    participant Dep as dependency generator
    participant Shell as Shell
    participant Pip as pip

    Dev->>Build: run build script
    Build->>Dep: fetch dependency tokens
    Dep-->>Build: return tokens
    Note over Build: dedupe & sort tokens

    loop each token
        alt token contains ">" or "<"
            Build->>Build: wrap token in single quotes
        else
            Build->>Build: keep token as-is
        end
    end

    Build->>Shell: emit pip install command (tokens quoted as needed)
    Shell->>Pip: invoke pip install ...
    Pip-->>Shell: install result
    Shell-->>Build: exit status
    Build-->>Dev: report outcome
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

I nibble on specs with careful hops,
Quoting the points so the shell won't stop.
Tokens tucked in single marks,
No stray redirects in the dark.
Hooray — packages hop home safe and sound. 🐰✨

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The title "fix: pip version constraint escaping in container build" accurately and concisely describes the primary change in this PR—adding quoting/escaping for pip version constraints to prevent shell redirection during container builds—using a short, single sentence that is clear for teammates scanning history.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09002ef and 22386fc.

📒 Files selected for processing (2)
  • distribution/Containerfile (3 hunks)
  • distribution/build.py (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • distribution/build.py
  • distribution/Containerfile
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test-push (linux/amd64)

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.

Copy link
Copy Markdown
Contributor

@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: 0

🧹 Nitpick comments (1)
distribution/build.py (1)

83-85: Good fix for shell redirection; harden quoting + satisfy ruff

Quoting specifiers prevents Bash from creating stray files. Use shlex.quote for correctness (handles embedded quotes) and wrap the comprehension to keep ruff-format happy.

Apply this diff within these lines:

-                    # Add quotes to packages with > or < to prevent bash redirection
-                    packages = [f"'{package}'" if (">" in package or "<" in package) else package for package in packages]
+                    # Add quotes to packages with > or < to prevent shell redirection
+                    packages = [
+                        shlex.quote(p) if any(op in p for op in ("<", ">")) else p
+                        for p in packages
+                    ]

Add the missing import near the other imports:

import shlex
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b535695 and 4742f54.

📒 Files selected for processing (2)
  • distribution/Containerfile (3 hunks)
  • distribution/build.py (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📓 Common learnings
Learnt from: nathan-weinberg
PR: opendatahub-io/llama-stack-distribution#33
File: distribution/Containerfile:17-21
Timestamp: 2025-09-15T14:25:54.837Z
Learning: In the opendatahub-io/llama-stack-distribution repository, the distribution/Containerfile is auto-generated by distribution/build.py based on configuration in build.yaml. When providers are added to build.yaml, the build script automatically regenerates the Containerfile with the required dependencies. Changes to the Containerfile should not be flagged as manual edits if they correspond to legitimate changes in the build configuration.
📚 Learning: 2025-09-15T14:25:54.837Z
Learnt from: nathan-weinberg
PR: opendatahub-io/llama-stack-distribution#33
File: distribution/Containerfile:17-21
Timestamp: 2025-09-15T14:25:54.837Z
Learning: In the opendatahub-io/llama-stack-distribution repository, the distribution/Containerfile is auto-generated by distribution/build.py based on configuration in build.yaml. When providers are added to build.yaml, the build script automatically regenerates the Containerfile with the required dependencies. Changes to the Containerfile should not be flagged as manual edits if they correspond to legitimate changes in the build configuration.

Applied to files:

  • distribution/Containerfile
🪛 GitHub Actions: Pre-commit
distribution/build.py

[error] 81-92: ruff-format formatting failed. 1 file reformatted (distribution/build.py); 1 file left unchanged.

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build-test-push (linux/amd64)
🔇 Additional comments (3)
distribution/Containerfile (1)

14-14: Quoting version constraints is correct and aligns with generator.

The single quotes around packages containing >= prevent redirection and match the build.py behavior. Looks good.

If this file is regenerated as part of CI, ensure the committed output matches the generator by re-running the build script before merging.

Also applies to: 20-20, 29-29, 45-45

distribution/build.py (2)

83-85: Re-run pre-commit/format and commit the formatted file

pre-commit was not available in the verification environment (pre-commit: command not found) and the attempted commit failed due to missing git identity; ruff reformatted distribution/build.py (1 file reformatted). Run locally and commit the changes:

  • pre-commit run -a
  • or: ruff format
  • git add distribution/build.py
  • git config user.email "you@example.com" && git config user.name "Your Name" (if not configured)
  • git commit -m "Format distribution/build.py with ruff-format"

73-101: Don't sort option/value tokens — only sort package specifiers

Sorting flags and their values together can pair an option (e.g., --index-url) with the wrong URL; keep option/value pairs in original order and only sort/dedupe package specifiers.

File: distribution/build.py Lines: 73-101

-                parts = line.replace("uv ", "RUN ", 1).split(" ", 3)
+                parts = line.replace("uv ", "RUN ", 1).split(" ", 3)
                 if len(parts) >= 4:  # We have packages to sort
                     cmd_parts = parts[:3]  # "RUN pip install"
-                    packages = sorted(
-                        set(parts[3].split())
-                    )  # Sort the package names and remove duplicates
+                    raw_tokens = parts[3].split()
+                    # Keep options (and their values) in-order; collect specifiers to sort/dedupe
+                    option_value_flags = {"--index-url", "--extra-index-url"}
+                    options = []
+                    specs = []
+                    i = 0
+                    while i < len(raw_tokens):
+                        tok = raw_tokens[i]
+                        if tok.startswith("--"):
+                            if tok in option_value_flags and i + 1 < len(raw_tokens):
+                                options.extend([tok, raw_tokens[i + 1]])
+                                i += 2
+                                continue
+                            options.append(tok)
+                        else:
+                            specs.append(tok)
+                        i += 1
+                    # Dedupe while preserving order for options; sort/dedupe specs for determinism
+                    from collections import OrderedDict
+                    options = list(OrderedDict.fromkeys(options))
+                    specs = sorted(set(specs))
+                    packages = options + specs

rg search for 'RUN pip install' lines with both --index-url and --extra-index-url in distribution/Containerfile returned no matches; manual verification required.

@derekhiggins derekhiggins changed the title Fix pip version constraint escaping in container build fix: pip version constraint escaping in container build Sep 18, 2025
- Add quotes around packages with > or < characters to prevent bash redirection
- Prevents files like '=0.12.0' in final container
- Affects packages: datasets>=4.0.0, mcp>=1.8.1, pymilvus>=2.4.10, torchao>=0.12.0

Signed-off-by: Derek Higgins <derekh@redhat.com>
@nathan-weinberg nathan-weinberg merged commit c5a3bd4 into opendatahub-io:main Sep 18, 2025
5 checks passed
nathan-weinberg pushed a commit to nathan-weinberg/llama-stack-distribution that referenced this pull request Feb 11, 2026
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.

3 participants