Codespace vigilant yodel qp7pgx6r5q93xp59 - #1
Conversation
Signed-off-by: gitworkflows <118260833+gitworkflows@users.noreply.github.com>
- Add Makefile with targets for build, test, push, release - Support BUILDX, CACHE_FROM, CACHE_TO variables - CI targets: ci-build, ci-test, ci-push - Development shortcuts: dev-build-full, dev-build-gpu - Add DOCKER_BUILD_IMPROVEMENTS.md documentation - Update requirements-base.txt and requirements-dev.txt with unique packages
Reviewer's GuideRefactors Docker build pipeline for ml-workspace to use BuildKit/caching, introduces a conda bootstrap stage and NVIDIA CUDA base image for GPU flavor, adds buildx-aware build tooling (Makefile, build.py) and CI workflow tweaks, and updates VS Code tooling and cleanup scripts for more robust, faster builds. Sequence diagram for build.py using buildx and running testssequenceDiagram
actor Developer
participant build_py as build_py
participant docker_cli as docker_cli
participant docker_daemon as docker_daemon
participant tests as pytest_container_tests
Developer->>build_py: python3 build.py --make --buildx --flavor full
build_py->>build_py: parse_arguments
build_py->>build_py: _build_with_buildx
build_py->>docker_cli: docker buildx build (with cache-from, cache-to)
docker_cli->>docker_daemon: build image ml-workspace:VERSION
docker_daemon-->>docker_cli: image built
docker_cli-->>build_py: completed_process
build_py->>docker_daemon: run container workspace-test-full
build_py->>tests: build_utils.run pytest /resources/tests
tests-->>build_py: completed_process
build_py->>docker_daemon: remove container workspace-test-full
build_py->>Developer: exit_process(0 or 1) based on tests
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
📝 WalkthroughWalkthroughThe PR adds Buildx and Makefile orchestration, restructures CPU and GPU Docker images with cache-aware dependency installation, updates container test cleanup, revises CI workflows, and changes VS Code installation scripts. ChangesDocker build overhaul
Estimated code review effort: 4 (Complex) | ~60 minutes Sequence Diagram(s)sequenceDiagram
participant Makefile
participant build.py
participant DockerBuildx
Makefile->>build.py: Invoke flavor and cache arguments
build.py->>DockerBuildx: Run docker buildx build
DockerBuildx-->>build.py: Return build result
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 inconclusive)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 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.
Hey - I've found 1 security issue, 2 other issues, and left some high level feedback:
Security issues:
- Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'. (link)
General comments:
- The new gpu-flavor/Dockerfile no longer builds FROM the main workspace image and assumes conda and workspace tooling already exist; this will break all subsequent conda/pip operations unless you reintroduce a base workspace stage or explicitly install the workspace stack in the GPU image.
- In gpu-flavor/Dockerfile the jax installation line appears corrupt (
pip install --# install jax: ...followed by anotherpip install), which will cause the RUN step to fail; clean this up to a single valid pip command. - The updated clean-layer.sh now hardcodes
/root/.cacheand drops$HOMEusage; if this script is ever reused outside root-only build stages it may miss user caches, so consider retaining$HOME-based cleanup or documenting that it is strictly for root builds.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The new gpu-flavor/Dockerfile no longer builds FROM the main workspace image and assumes conda and workspace tooling already exist; this will break all subsequent conda/pip operations unless you reintroduce a base workspace stage or explicitly install the workspace stack in the GPU image.
- In gpu-flavor/Dockerfile the jax installation line appears corrupt (`pip install --# install jax: ...` followed by another `pip install`), which will cause the RUN step to fail; clean this up to a single valid pip command.
- The updated clean-layer.sh now hardcodes `/root/.cache` and drops `$HOME` usage; if this script is ever reused outside root-only build stages it may miss user caches, so consider retaining `$HOME`-based cleanup or documenting that it is strictly for root builds.
## Individual Comments
### Comment 1
<location path="gpu-flavor/Dockerfile" line_range="81-82" />
<code_context>
# cuda111 -> >= 11.1
pip install --no-cache-dir mxnet-cu112 && \
# install jax: https://github.com/google/jax#pip-installation
+ pip install --# install jax: https://github.com/google/jax#pip-installation \
pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \
# Install pygpu - Required for theano: http://deeplearning.net/software/libgpuarray/
conda install -y pygpu && \
</code_context>
<issue_to_address>
**issue (bug_risk):** The JAX installation lines contain a malformed `pip install` command that will cause the Docker build to fail.
`pip install --# install jax: ...` is invalid syntax (`--#` is not a valid pip option) and will cause this layer to fail before the real JAX install runs. Remove this stray command or convert it to a shell comment (`# install jax: ...`) so only the actual `pip install --upgrade jax[cuda111] ...` executes.
</issue_to_address>
### Comment 2
<location path="Makefile" line_range="65-66" />
<code_context>
+build:
+ python3 build.py --make $(BUILD_ARGS)
+
+build-minimal:
+ python3 build.py --flavor minimal --make $(BUILD_ARGS)
+
+build-light:
</code_context>
<issue_to_address>
**issue (bug_risk):** Targets like `build-minimal` pass conflicting `--flavor` arguments due to `BUILD_ARGS` also containing `--flavor`.
For `build-minimal`, this expands to `python3 build.py --flavor minimal --make ... --flavor $(FLAVOR)`. With the default `FLAVOR=full`, the last `--flavor` wins and `build-minimal` (and similarly `build-light`, `build-full`, `build-gpu`) actually builds the full flavor. Fix either by removing `--flavor $(FLAVOR)` from `BUILD_ARGS` and setting `--flavor` only in each target, or by keeping `BUILD_ARGS` as-is and overriding `FLAVOR` per target instead of passing an explicit `--flavor` there.
</issue_to_address>
### Comment 3
<location path="build.py" line_range="139" />
<code_context>
completed_process = subprocess.run(buildx_args, env=env)
</code_context>
<issue_to_address>
**security (python.lang.security.audit.dangerous-subprocess-use-audit):** Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
*Source: opengrep*
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
| pip install --# install jax: https://github.com/google/jax#pip-installation \ | ||
| pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \ |
There was a problem hiding this comment.
issue (bug_risk): The JAX installation lines contain a malformed pip install command that will cause the Docker build to fail.
pip install --# install jax: ... is invalid syntax (--# is not a valid pip option) and will cause this layer to fail before the real JAX install runs. Remove this stray command or convert it to a shell comment (# install jax: ...) so only the actual pip install --upgrade jax[cuda111] ... executes.
| build-minimal: | ||
| python3 build.py --flavor minimal --make $(BUILD_ARGS) |
There was a problem hiding this comment.
issue (bug_risk): Targets like build-minimal pass conflicting --flavor arguments due to BUILD_ARGS also containing --flavor.
For build-minimal, this expands to python3 build.py --flavor minimal --make ... --flavor $(FLAVOR). With the default FLAVOR=full, the last --flavor wins and build-minimal (and similarly build-light, build-full, build-gpu) actually builds the full flavor. Fix either by removing --flavor $(FLAVOR) from BUILD_ARGS and setting --flavor only in each target, or by keeping BUILD_ARGS as-is and overriding FLAVOR per target instead of passing an explicit --flavor there.
| env = os.environ.copy() | ||
| env["DOCKER_BUILDKIT"] = "1" | ||
|
|
||
| completed_process = subprocess.run(buildx_args, env=env) |
There was a problem hiding this comment.
security (python.lang.security.audit.dangerous-subprocess-use-audit): Detected subprocess function 'run' without a static string. If this data can be controlled by a malicious actor, it may be an instance of command injection. Audit the use of this call to ensure it is not controllable by an external resource. You may consider using 'shlex.escape()'.
Source: opengrep
There was a problem hiding this comment.
Actionable comments posted: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
.github/workflows/release-pipeline.yml (1)
121-127: 🔒 Security & Privacy | 🟠 Major | ⚡ Quick winPin the checked-out release-drafter revision.
This workflow fetches
khulnasoft/release-drafterwithoutref, then executes it guarded byGITHUB_TOKEN. Pin the checkout to a reviewed immutable commit SHA so changes to the repository’s default branch cannot alter release behavior.Proposed fix
with: repository: khulnasoft/release-drafter + ref: <reviewed-immutable-commit-sha> path: ./.git/cloned-actions/release-drafter🤖 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 @.github/workflows/release-pipeline.yml around lines 121 - 127, Pin the actions/checkout step for khulnasoft/release-drafter to a reviewed immutable commit SHA by adding the appropriate ref under its with configuration. Keep the existing repository, checkout path, create-release-draft condition, and local action usage unchanged.
🧹 Nitpick comments (6)
.github/actions/build-environment/build_requirements.txt (1)
5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winPin the Docker SDK for reproducible builds.
.github/actions/build-environment/build_requirements.txtallows any Docker SDK 6.x release, so resolves can pick different versions between environments. Use the tested exact version, e.g.docker==6.1.3, or lock the build requirements.🤖 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 @.github/actions/build-environment/build_requirements.txt at line 5, Pin the Docker SDK dependency in build_requirements.txt to the tested exact version, such as docker==6.1.3, replacing the current 6.x version range while leaving other build requirements unchanged.Makefile (1)
14-24: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win
build-allre-implements the BUILDX/cache-arg logic instead of reusingBUILD_ARGS.Lines 14-24 already compute buildx/cache flags via
ifeq;build-allre-derives the same flags inline with$(if ...), a second implementation of the same logic that can silently drift fromBUILD_ARGSover time.Also applies to: 77-78
🤖 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 `@Makefile` around lines 14 - 24, Update the build-all target to reuse the existing BUILD_ARGS variable for buildx and cache flags instead of reconstructing them with inline conditional expressions. Keep the conditional logic centralized in the BUILD_ARGS definition and remove the duplicated flag assembly from build-all.Dockerfile (2)
328-343: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winGit clone timeout is fully disabled, not bounded.
http.lowSpeedLimit 0combined withhttp.lowSpeedTime 999999effectively removes git's stall-detection for the pyenv clones. If the network stalls mid-clone, this RUN step (and the build/CI job) can hang indefinitely instead of failing fast, wasting CI minutes with no automatic recovery.🤖 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 `@Dockerfile` around lines 328 - 343, Bound Git’s network stall detection in the pyenv installation RUN step by removing the unlimited http.lowSpeedLimit/http.lowSpeedTime settings and using finite, appropriate timeout values. Keep the existing pyenv and plugin clone sequence unchanged while ensuring stalled clones fail rather than hanging indefinitely.
329-330: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick winInconsistent
sharing=lockedon cache mounts.Only the very first apt cache mounts (lines 14-15, 85-86, 102-103) declare
sharing=locked; every later--mount=type=cachein this file (pyenv, pipx, node, supervisor, gui-tools, vnc, data-science) omits it. Withoutsharing=locked, concurrent builds sharing the same BuildKit cache backend (e.g. CI matrix-building multiple flavors, ormake -j) can write to the same apt/conda cache simultaneously, risking a corrupted package index/cache — apt in particular is documented as not safe for concurrent cache writers.Also applies to: 350-350, 359-362, 405-407, 425-426, 489-490, 583-587
🤖 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 `@Dockerfile` around lines 329 - 330, Update every later cache mount identified in the Dockerfile, including the mounts near the shown apt commands and the additional locations noted in the review, to use sharing=locked consistently. Preserve each mount’s existing cache target and build behavior while ensuring concurrent writers cannot modify shared package or tool caches simultaneously.gpu-flavor/Dockerfile (1)
5-5: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winBase image string duplicated between
FROMandLABEL.
workspace.baseimagehardcodesnvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04again at line 121, duplicating the literal from theFROMline. If the base image is bumped later, it's easy to update one and forget the other, leaving the label metadata stale.♻️ Proposed refactor
+ARG BASE_IMAGE="nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04" -FROM nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04 AS gpu-base +FROM $BASE_IMAGE AS gpu-base+ARG BASE_IMAGE LABEL \ "workspace.version"=$WORKSPACE_VERSION \ "workspace.flavor"=$WORKSPACE_FLAVOR \ - "workspace.baseimage"="nvidia/cuda:11.2.2-cudnn8-devel-ubuntu20.04" \ + "workspace.baseimage"=$BASE_IMAGE \Also applies to: 118-127
🤖 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 `@gpu-flavor/Dockerfile` at line 5, Remove the duplicated CUDA base-image literal from the workspace.baseimage LABEL metadata and derive or reuse the image reference declared by the FROM instruction, so updating the base image keeps the label synchronized.gpu-flavor/build.py (1)
27-35: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicate
_remove_existing_containerhelper — extract to shared module.This function is byte-for-byte identical to
_remove_existing_containeralready added inbuild.py(per the graph context). Maintaining the same try/except-NotFound logic in two places risks drift if one copy is updated later without the other.Consider moving it into
build_utils.py(already imported by both scripts) and importing it from there instead of duplicating.🤖 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 `@gpu-flavor/build.py` around lines 27 - 35, Move the duplicate _remove_existing_container helper into the shared build_utils.py module, then remove the local definition and import it in both build.py scripts. Preserve the existing client.containers.get, force removal, and docker.errors.NotFound handling exactly through the shared helper.
🤖 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 @.github/actions/build-environment/build_requirements.txt:
- Line 3: Update the urllib3 dependency pin in build_requirements.txt from
1.26.13 to a patched release, using urllib3==1.26.20 or newer as appropriate.
In @.github/workflows/build-pipeline.yml:
- Line 19: Update the actions/checkout@v4 step in the build job to set
persist-credentials to false. Preserve the existing explicit GITHUB_TOKEN
handling for the local action, and configure any other authenticated Git access
explicitly if required.
- Around line 16-30: Update the build job containing actions/checkout@v4 and
run-build-scripts to add a job-level permissions block granting only the minimum
required capability for checkout, such as contents read access. Remove
GITHUB_TOKEN from the run-build-scripts env unless build.py or the local build
action explicitly requires GitHub API access; do not grant broader permissions.
In `@build.py`:
- Line 133: Update _build_with_buildx() so build_args is tokenized using
shell-style parsing rather than plain whitespace splitting, preserving quoted
values containing spaces as single arguments before passing them to
subprocess.run.
In `@gpu-flavor/Dockerfile`:
- Around line 78-82: Fix the corrupted JAX installation command in the
Dockerfile by removing the merged `--# install jax...` artifact and preserving a
valid standalone `pip install --upgrade jax[cuda111]` command with its
continuation. Also clean up the stray Arrayfire TODO/install artifact near the
later installation block without changing the intended package setup.
In `@Makefile`:
- Around line 42-44: Update the Makefile release target so it performs the
promised release workflow: bump versions, create a tag, and push the release,
rather than duplicating push-all. Keep push-all limited to pushing all flavors
and ensure the release help text accurately reflects the implemented behavior.
- Around line 62-76: Remove the duplicate flavor argument from the per-flavor
targets build-minimal, build-light, build-full, and build-gpu, or otherwise
ensure each target’s explicit flavor is the final effective value after
BUILD_ARGS. Preserve the existing build command behavior while making each
target reliably select its named flavor.
In `@resources/tools/vs-code-desktop.sh`:
- Around line 19-21: Update the VS Code installation flow in the script to
download a fixed, versioned Microsoft .deb URL instead of the latest redirect,
define the expected SHA-256 for that artifact, and verify the downloaded
vscode.deb checksum before running apt-get install. Keep installation blocked
when checksum validation fails.
In `@resources/tools/vs-code-server.sh`:
- Line 26: Update the symlink creation command in the installation script to be
idempotent, replacing the plain ln -s behavior so retries succeed when
/usr/local/bin/code-server already exists as the expected symlink. Preserve
creation of the link when it is absent and ensure the command remains compatible
with set -e.
---
Outside diff comments:
In @.github/workflows/release-pipeline.yml:
- Around line 121-127: Pin the actions/checkout step for
khulnasoft/release-drafter to a reviewed immutable commit SHA by adding the
appropriate ref under its with configuration. Keep the existing repository,
checkout path, create-release-draft condition, and local action usage unchanged.
---
Nitpick comments:
In @.github/actions/build-environment/build_requirements.txt:
- Line 5: Pin the Docker SDK dependency in build_requirements.txt to the tested
exact version, such as docker==6.1.3, replacing the current 6.x version range
while leaving other build requirements unchanged.
In `@Dockerfile`:
- Around line 328-343: Bound Git’s network stall detection in the pyenv
installation RUN step by removing the unlimited
http.lowSpeedLimit/http.lowSpeedTime settings and using finite, appropriate
timeout values. Keep the existing pyenv and plugin clone sequence unchanged
while ensuring stalled clones fail rather than hanging indefinitely.
- Around line 329-330: Update every later cache mount identified in the
Dockerfile, including the mounts near the shown apt commands and the additional
locations noted in the review, to use sharing=locked consistently. Preserve each
mount’s existing cache target and build behavior while ensuring concurrent
writers cannot modify shared package or tool caches simultaneously.
In `@gpu-flavor/build.py`:
- Around line 27-35: Move the duplicate _remove_existing_container helper into
the shared build_utils.py module, then remove the local definition and import it
in both build.py scripts. Preserve the existing client.containers.get, force
removal, and docker.errors.NotFound handling exactly through the shared helper.
In `@gpu-flavor/Dockerfile`:
- Line 5: Remove the duplicated CUDA base-image literal from the
workspace.baseimage LABEL metadata and derive or reuse the image reference
declared by the FROM instruction, so updating the base image keeps the label
synchronized.
In `@Makefile`:
- Around line 14-24: Update the build-all target to reuse the existing
BUILD_ARGS variable for buildx and cache flags instead of reconstructing them
with inline conditional expressions. Keep the conditional logic centralized in
the BUILD_ARGS definition and remove the duplicated flag assembly from
build-all.
🪄 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: 72f2de80-ab32-402e-8344-55f587f0cca6
📒 Files selected for processing (16)
.github/actions/build-environment/Dockerfile.github/actions/build-environment/build_requirements.txt.github/workflows/build-pipeline.yml.github/workflows/release-pipeline.ymlDOCKER_BUILD_IMPROVEMENTS.mdDockerfileMakefilebuild.pybuild_requirements.txtgpu-flavor/Dockerfilegpu-flavor/build.pyresources/libraries/requirements-base.txtresources/libraries/requirements-dev.txtresources/scripts/clean-layer.shresources/tools/vs-code-desktop.shresources/tools/vs-code-server.sh
| @@ -0,0 +1,5 @@ | |||
| pipenv==2022.11.25 | |||
| ml_buildkit==0.6.18 | |||
| urllib3==1.26.13 | |||
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
python -m pip install --disable-pip-version-check pip-audit
pip-audit -r .github/actions/build-environment/build_requirements.txtRepository: FortiShield/ml-workspace
Length of output: 4715
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== requirements =="
cat -n .github/actions/build-environment/build_requirements.txt
echo
echo "== pip-audit installed to == "
python3 -m pip show pip-audit | sed -n '1,16p' || true
if [ -f /home/jailuser/.local/bin/pip-audit ]; then
/home/jailuser/.local/bin/pip-audit -r .github/actions/build-environment/build_requirements.txt || true
else
echo "pip-audit executable not on PATH"
fiRepository: FortiShield/ml-workspace
Length of output: 1180
🌐 Web query:
Python urllib3 CVE-2023-45803 fixed in version advisory
💡 Result:
The vulnerability CVE-2023-45803 in the Python urllib3 library, which involved a failure to strip the HTTP request body when performing certain redirects, has been fixed in the following versions: - urllib3 version 1.26.18 [1][2][3] - urllib3 version 2.0.7 [1][2][3] Users running any version of urllib3 prior to these releases are advised to upgrade to the patched versions [2][3]. If an immediate upgrade is not possible, the vulnerability can be mitigated by disabling automatic redirects for services where they are not expected, or by handling them manually to ensure the request body is stripped when required [1][3].
Citations:
- 1: GHSA-g4mx-q9vg-27p4
- 2: https://nvd.nist.gov/vuln/detail/cve-2023-45803
- 3: https://www.cve.org/CVERecord?id=CVE-2023-45803
🌐 Web query:
pip-audit --no-deps --only-fixed urllib3
💡 Result:
The command pip-audit --no-deps --only-fixed urllib3 is invalid because --only-fixed is not a recognized flag for the pip-audit tool [1][2][3][4]. According to the official pip-audit documentation, the available flags and options include [1][5][4]: --no-deps: This flag instructs pip-audit to skip dependency resolution [1][6][5]. It requires that all requirements be pinned to exact versions [1][2][6]. It is primarily designed for use with requirements files [7]. There is no --only-fixed flag in the current pip-audit CLI [1][2][4]. If you are attempting to filter for vulnerabilities that have a known fix, note that pip-audit does not currently provide a native flag for this specific purpose [8]. The tool is generally designed to report all discovered vulnerabilities, and you can manage specific entries using options like --ignore-vuln [1][8][4]. Additionally, the command structure you provided implies auditing a single package (urllib3) as a positional argument. Please be aware that pip-audit is typically used to audit local environments, projects, or requirement files, rather than individual packages passed directly as arguments [3][4]. If you wish to audit a specific version of a package, you can create a temporary requirements file containing that package and version, then point pip-audit to it using the -r flag [7][4].
Citations:
- 1: https://github.com/pypa/pip-audit?tab=readme-ov-file
- 2: https://pypi.org/project/pip-audit/2.10.1/
- 3: https://github.com/pypa/pip-audit/blob/main/README.md
- 4: https://deepwiki.com/pypa/pip-audit/1.1-installation-and-usage
- 5: https://pypi.org/project/pip-audit/
- 6: https://github.com/pypa/pip-audit/blob/v2.10.0/README.md
- 7: https://github.com/pypa/pip-audit/blob/fe414d39/pip_audit/_cli.py
- 8: CLI: add a flag to exit with non-zero code only for fixable vulnerabilities pypa/pip-audit#670
🏁 Script executed:
#!/bin/bash
set -euo pipefail
export PATH="/home/jailuser/.local/bin:$PATH"
python3 -m pip_audit.cli -r .github/actions/build-environment/build_requirements.txt || trueRepository: FortiShield/ml-workspace
Length of output: 210
🏁 Script executed:
#!/bin/bash
set -euo pipefail
export PATH="/home/jailuser/.local/bin:$PATH"
python3 -m pip audit -r .github/actions/build-environment/build_requirements.txt || true
echo
echo "== direct pip-audit with PATH =="
pip-audit -r .github/actions/build-environment/build_requirements.txt || trueRepository: FortiShield/ml-workspace
Length of output: 621
Upgrade the vulnerable urllib3 pin.
urllib3==1.26.13 is below the patched 1.26.18 release for CVE-2023-45803. Since this build environment receives CI credentials, use a patched pin such as urllib3==1.26.20.
🤖 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 @.github/actions/build-environment/build_requirements.txt at line 3, Update
the urllib3 dependency pin in build_requirements.txt from 1.26.13 to a patched
release, using urllib3==1.26.20 or newer as appropriate.
| build: | ||
| runs-on: ubuntu-latest | ||
| steps: | ||
| - name: set-input-build-args | ||
| if: ${{ github.event.inputs != null && github.event.inputs.build_args != null}} | ||
| run: echo "BUILD_ARGS=${{ github.event.inputs.build_args }}" >> $GITHUB_ENV | ||
| # new syntax: run: echo "BUILD_ARGS=${{ github.event.inputs.build_args }}" >> "$GITHUB_ENV" | ||
| - name: set-input-working-directory | ||
| if: ${{ github.event.inputs != null && github.event.inputs.working_directory != null}} | ||
| run: echo "WORKING_DIRECTORY=${{ github.event.inputs.working_directory }}" >> $GITHUB_ENV | ||
| # new syntax: run: echo "WORKING_DIRECTORY=${{ github.event.inputs.working_directory }}" >> "$GITHUB_ENV" | ||
| # Set host ip to env variable to be uside within container actions | ||
| - uses: actions/checkout@v4 | ||
|
|
||
| - name: set-host-ip | ||
| run: echo "_HOST_IP=$(hostname -I | cut -d ' ' -f 1)" >> $GITHUB_ENV | ||
| - uses: actions/checkout@v2 | ||
| run: echo "_HOST_IP=$(hostname -I | cut -d ' ' -f 1)" >> "$GITHUB_ENV" | ||
|
|
||
| - name: run-build-scripts | ||
| uses: ./.github/actions/build-environment | ||
| with: | ||
| build_args: ${{ env.BUILD_ARGS }} | ||
| working_directory: ${{ env.WORKING_DIRECTORY }} | ||
| build_args: ${{ github.event.inputs.build_args || secrets.BUILD_ARGS }} | ||
| working_directory: ${{ github.event.inputs.working_directory || secrets.WORKING_DIRECTORY }} | ||
| env: | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} No newline at end of file |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "== workflow =="
cat -n .github/workflows/build-pipeline.yml | sed -n '1,120p'
echo
echo "== local action manifest and dockerfiles =="
fd -a 'action.yml|Dockerfile|.*\.ya?ml|.*\.sh|.*\.ps1' .github/actions/build-environment || true
echo
echo "== files under local action =="
git ls-files .github/actions/build-environment | sed -n '1,200p'
echo
echo "== search GITHUB_TOKEN and permissions in workflow/action =="
rg -n "permissions:|GITHUB_TOKEN|secrets\.GITHUB_TOKEN|actions/checkout|gh |npm|yarn|pip|go build|cargo|build" .github/workflows/build-pipeline.yml .github/actions/build-environment || true
echo
echo "== changed files/stat =="
git diff --stat HEAD~1..HEAD 2>/dev/null || git diff --stat || trueRepository: FortiShield/ml-workspace
Length of output: 5991
Set a least-privilege GitHub token scope.
This workflow runs actions/checkout@v4, and the local build action forwards secrets.GITHUB_TOKEN into the build container for git config and build.py. Add a job-level permissions: block with only the required token capabilities, and omit GITHUB_TOKEN from the action unless the build actually needs GitHub API access.
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 19-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
[warning] 16-30: overly broad permissions (excessive-permissions): default permissions used due to no permissions: block
(excessive-permissions)
🤖 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 @.github/workflows/build-pipeline.yml around lines 16 - 30, Update the build
job containing actions/checkout@v4 and run-build-scripts to add a job-level
permissions block granting only the minimum required capability for checkout,
such as contents read access. Remove GITHUB_TOKEN from the run-build-scripts env
unless build.py or the local build action explicitly requires GitHub API access;
do not grant broader permissions.
Source: Linters/SAST tools
| run: echo "WORKING_DIRECTORY=${{ github.event.inputs.working_directory }}" >> $GITHUB_ENV | ||
| # new syntax: run: echo "WORKING_DIRECTORY=${{ github.event.inputs.working_directory }}" >> "$GITHUB_ENV" | ||
| # Set host ip to env variable to be uside within container actions | ||
| - uses: actions/checkout@v4 |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Disable persisted checkout credentials for the build job.
zizmor flags this checkout because credentials remain available to subsequent build tooling. Since GITHUB_TOKEN is already passed explicitly to the local action, add persist-credentials: false and configure any required authenticated Git access explicitly.
Proposed fix
- uses: actions/checkout@v4
+ with:
+ persist-credentials: false📝 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.
| - uses: actions/checkout@v4 | |
| - uses: actions/checkout@v4 | |
| with: | |
| persist-credentials: false |
🧰 Tools
🪛 zizmor (1.26.1)
[warning] 19-19: credential persistence through GitHub Actions artifacts (artipacked): does not set persist-credentials: false
(artipacked)
🤖 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 @.github/workflows/build-pipeline.yml at line 19, Update the
actions/checkout@v4 step in the build job to set persist-credentials to false.
Preserve the existing explicit GITHUB_TOKEN handling for the local action, and
configure any other authenticated Git access explicitly if required.
Source: Linters/SAST tools
| if flavor in ["minimal", "light"]: | ||
| buildx_args.extend(["--build-arg", f"ARG_WORKSPACE_FLAVOR={flavor}"]) | ||
|
|
||
| buildx_args.extend(build_args.split()) |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Inspect how version_build_arg / build_date_build_arg / vcs_ref_build_arg are constructed
grep -n "build_arg" build.pyRepository: FortiShield/ml-workspace
Length of output: 925
🏁 Script executed:
#!/bin/bash
set -euo pipefail
wc -l build.py
sed -n '1,220p' build.pyRepository: FortiShield/ml-workspace
Length of output: 6347
🏁 Script executed:
#!/bin/bash
set -euo pipefail
sed -n '120,165p' build.py | cat -n
python3 - <<'PY'
examples = [
' --build-arg ARG_BUILD_DATE=2026-01-02',
' --build-arg ARG_BUILD_DATE="2026-01 02"',
' --build-arg ARG_BUILD_DATE=2026-01-02 --build-arg ARG_WORKSPACE_FLAVOR=full',
]
for arg in examples:
print(repr(arg), "=>", arg.split(), "count", len(arg.split()))
PYRepository: FortiShield/ml-workspace
Length of output: 2216
Parse the build args as tokens, not naive whitespace.
build_args is a shell-style argument string, but _build_with_buildx() splits it with plain whitespace before calling subprocess.run. A build arg containing a quoted value with a space will be split into multiple arguments, so --build-arg can get the wrong value or be followed by a dangling fragment. Tokenize the string with a shell parser, or build the argument list directly.
🤖 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 `@build.py` at line 133, Update _build_with_buildx() so build_args is tokenized
using shell-style parsing rather than plain whitespace splitting, preserving
quoted values containing spaces as single arguments before passing them to
subprocess.run.
| # cuda111 -> >= 11.1 | ||
| pip install --no-cache-dir mxnet-cu112 && \ | ||
| # install jax: https://github.com/google/jax#pip-installation | ||
| pip install --# install jax: https://github.com/google/jax#pip-installation \ | ||
| pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \ |
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
Build-breaking merge artifact in the jax install line.
Line 81 (pip install --# install jax: https://github.com/google/jax#pip-installation \) looks like a corrupted merge of the comment on line 80 with the real install line on line 82. Since --# is a single token (not # at the start of a word), bash won't treat it as a comment — it passes --# as a literal (invalid) pip argument. Combined with line 82 via the backslash continuation, this produces one garbled pip install invocation that will fail, breaking the entire RUN and the GPU image build.
The same kind of leftover artifact also shows up at line 99 (# TODO: Install Arrayfire: ... pip install --no-cache-dir arrayfire && \) — harmless there since the whole line is a comment, but worth cleaning up while fixing this hunk.
🐛 Proposed fix
- # install jax: https://github.com/google/jax#pip-installation
- pip install --# install jax: https://github.com/google/jax#pip-installation \
+ # install jax: https://github.com/google/jax#pip-installation
pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \📝 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.
| # cuda111 -> >= 11.1 | |
| pip install --no-cache-dir mxnet-cu112 && \ | |
| # install jax: https://github.com/google/jax#pip-installation | |
| pip install --# install jax: https://github.com/google/jax#pip-installation \ | |
| pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \ | |
| # cuda111 -> >= 11.1 | |
| pip install --no-cache-dir mxnet-cu112 && \ | |
| # install jax: https://github.com/google/jax#pip-installation | |
| pip install --upgrade jax[cuda111] -f https://storage.googleapis.com/jax-releases/jax_releases.html && \ |
🤖 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 `@gpu-flavor/Dockerfile` around lines 78 - 82, Fix the corrupted JAX
installation command in the Dockerfile by removing the merged `--# install
jax...` artifact and preserving a valid standalone `pip install --upgrade
jax[cuda111]` command with its continuation. Also clean up the stray Arrayfire
TODO/install artifact near the later installation block without changing the
intended package setup.
| @echo " make push - Push single flavor" | ||
| @echo " make push-all - Push all flavors" | ||
| @echo " make release - Create release (bump versions, tag, push)" |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
release doesn't do what the help text promises.
Help text says make release should "bump versions, tag, push", but release (92-93) is byte-identical to push-all (89-90) — no version bump or tagging logic exists anywhere in this file.
Also applies to: 86-93
🤖 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 `@Makefile` around lines 42 - 44, Update the Makefile release target so it
performs the promised release workflow: bump versions, create a tag, and push
the release, rather than duplicating push-all. Keep push-all limited to pushing
all flavors and ensure the release help text accurately reflects the implemented
behavior.
| build: | ||
| python3 build.py --make $(BUILD_ARGS) | ||
|
|
||
| build-minimal: | ||
| python3 build.py --flavor minimal --make $(BUILD_ARGS) | ||
|
|
||
| build-light: | ||
| python3 build.py --flavor light --make $(BUILD_ARGS) | ||
|
|
||
| build-full: | ||
| python3 build.py --flavor full --make $(BUILD_ARGS) | ||
|
|
||
| build-gpu: | ||
| python3 build.py --flavor gpu --make $(BUILD_ARGS) | ||
|
|
There was a problem hiding this comment.
🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win
--flavor is passed twice, so per-flavor targets silently build the wrong flavor.
BUILD_ARGS (line 15) already appends --flavor $(FLAVOR) (default full). build-minimal/build-light/build-full/build-gpu additionally pass an explicit --flavor <x> before $(BUILD_ARGS). Since argparse takes the last occurrence of a repeated flag, the trailing --flavor full (from BUILD_ARGS, unless the caller also sets FLAVOR=...) wins — e.g. make build-minimal actually builds the full flavor.
🐛 Proposed fix
-build-minimal:
- python3 build.py --flavor minimal --make $(BUILD_ARGS)
-
-build-light:
- python3 build.py --flavor light --make $(BUILD_ARGS)
-
-build-full:
- python3 build.py --flavor full --make $(BUILD_ARGS)
-
-build-gpu:
- python3 build.py --flavor gpu --make $(BUILD_ARGS)
+build-minimal:
+ $(MAKE) build FLAVOR=minimal
+
+build-light:
+ $(MAKE) build FLAVOR=light
+
+build-full:
+ $(MAKE) build FLAVOR=full
+
+build-gpu:
+ $(MAKE) build FLAVOR=gpu📝 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.
| build: | |
| python3 build.py --make $(BUILD_ARGS) | |
| build-minimal: | |
| python3 build.py --flavor minimal --make $(BUILD_ARGS) | |
| build-light: | |
| python3 build.py --flavor light --make $(BUILD_ARGS) | |
| build-full: | |
| python3 build.py --flavor full --make $(BUILD_ARGS) | |
| build-gpu: | |
| python3 build.py --flavor gpu --make $(BUILD_ARGS) | |
| build: | |
| python3 build.py --make $(BUILD_ARGS) | |
| build-minimal: | |
| $(MAKE) build FLAVOR=minimal | |
| build-light: | |
| $(MAKE) build FLAVOR=light | |
| build-full: | |
| $(MAKE) build FLAVOR=full | |
| build-gpu: | |
| $(MAKE) build FLAVOR=gpu |
🤖 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 `@Makefile` around lines 62 - 76, Remove the duplicate flavor argument from the
per-flavor targets build-minimal, build-light, build-full, and build-gpu, or
otherwise ensure each target’s explicit flavor is the final effective value
after BUILD_ARGS. Preserve the existing build command behavior while making each
target reliably select its named flavor.
| wget -q https://go.microsoft.com/fwlink/?LinkID=760868 -O ./vscode.deb | ||
| apt-get update | ||
| apt-get install -y ./vscode.deb |
There was a problem hiding this comment.
🔒 Security & Privacy | 🟠 Major | 🏗️ Heavy lift
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Repo files matching vscode:\n'
fd -i 'vs-code-desktop|vscode|Dockerfile' . | sed 's#^\./##' | head -100
printf '\nresources/tools/vs-code-desktop.sh if present:\n'
if [ -f resources/tools/vs-code-desktop.sh ]; then
cat -n resources/tools/vs-code-desktop.sh
else
echo 'not found'
fi
printf '\nDockerfile references around 545-554 if present:\n'
if [ -f Dockerfile ]; then
sed -n '530,565p' Dockerfile | cat -n -v
else
echo 'Dockerfile not found at root'
fd -i '^Dockerfile$' . | while read -r f; do
echo "--- $f"
wc -l "$f"
sed -n '1,80p' "$f"
done
fi
printf '\nSearch for LinkID=760868 and vs-code-desktop usage:\n'
rg -n "LinkID=760868|vs-code-desktop|vscode.deb|go\.microsoft\.com/fwlink' --silentRepository: FortiShield/ml-workspace
Length of output: 3059
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf 'Search for LinkID=760868 and vs-code-desktop usage:\n'
rg -n 'LinkID=760868|vs-code-desktop|vscode\.deb|go\.microsoft\.com/fwlink' .
printf '\nDockerfile line numbers around VS Code install section:\n'
grep -nE 'Install Visual Studio Code|vs-code-desktop|WORKSPACE_FLAVOR' Dockerfile || trueRepository: FortiShield/ml-workspace
Length of output: 3298
🌐 Web query:
Visual Studio Code Linux installer go.microsoft.com/fwlink LinkID=760868
💡 Result:
The URL go.microsoft.com/fwlink/?LinkID=760868 is an official Microsoft forwarding link that redirects to the latest stable.deb (Debian-based) installer for Visual Studio Code on Linux [1][2][3]. Because this is a redirect link, it is often used in scripts and automated installation processes to ensure the most recent version of the software is downloaded [4][5]. If you are using this link in a command-line tool like curl, you must use the -L (or --location) flag to follow the HTTP redirect to the final file location [4]: curl -L -o code.deb https://go.microsoft.com/fwlink/?LinkID=760868 Once downloaded, the package can be installed using standard package managers, such as: sudo apt install./code.deb Alternatively, for older distributions, one might use: sudo dpkg -i code.deb sudo apt-get install -f # To resolve and install dependencies Official documentation recommends visiting the main Visual Studio Code download page for a comprehensive list of distribution options, including.rpm and Snap packages [6][3][7].
Citations:
- 1: Download attempt on Chrome returns ERR_SSL_PROTOCOL_ERROR microsoft/vscode#28283
- 2: https://vscode-docs.readthedocs.io/en/latest/editor/setup/
- 3: https://github.com/microsoft/vscode-docs/blob/main/docs/setup/linux.md
- 4: curl latest deb file microsoft/vscode#15529
- 5: https://gist.github.com/cprima/89c4aa76df9f8d8aa4616ca63580eb1f
- 6: https://code.visualstudio.com/docs/setup/linux
- 7: https://code.visualstudio.com/Download
Pin the VS Code artifact for reproducible image builds.
resources/tools/vs-code-desktop.sh:19 installs VS Code from Microsoft’s latest .deb redirect during Dockerfile image construction (Dockerfile:545-552), so non-minimal images can receive a different VS Code version after cache misses. Use a fixed, versioned .deb and verify its SHA-256 before apt-get install.
🤖 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 `@resources/tools/vs-code-desktop.sh` around lines 19 - 21, Update the VS Code
installation flow in the script to download a fixed, versioned Microsoft .deb
URL instead of the latest redirect, define the expected SHA-256 for that
artifact, and verify the downloaded vscode.deb checksum before running apt-get
install. Keep installation blocked when checksum validation fails.
| apt-get update | ||
| apt-get install -y ./code-server.deb | ||
| rm ./code-server.deb | ||
| ln -s /usr/bin/code-server /usr/local/bin/code-server |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Repository files around target:"
git ls-files | rg '(^|/)vs-code-server\.sh$|usr/local/bin|code-server' || true
echo
echo "Target file excerpt:"
if [ -f resources/tools/vs-code-server.sh ]; then
cat -n resources/tools/vs-code-server.sh | sed -n '1,80p'
fi
echo
echo "Search symlink command and shell behavior clues:"
rg -n 'ln -s .*code-server|code-server|set -e|bash|sh' resources || trueRepository: FortiShield/ml-workspace
Length of output: 50381
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Exact target excerpt:"
cat -n resources/tools/vs-code-server.sh | sed -n '1,80p'
echo
echo "Relevant shell tests in /tmp:"
test -d /tmp/code-server-link-test && rm -rf /tmp/code-server-link-test
mkdir -p /tmp/code-server-link-test
target_dir="$(mktemp -d /tmp/code-server-link-test-usr-local.XXXXXX)"
tmp_dir="$(mktemp -d /tmp/code-server-link-test-usr-bin.XXXXXX)"
export target_dir tmp_dir
python3 - <<'PY'
import os, subprocess, tempfile
from pathlib import Path
target_dir = os.environ["target_dir"].encode() if isinstance(os.environ["target_dir"], str) else os.environ["target_dir"]
tmp_dir = os.environ["tmp_dir"].encode() if isinstance(os.environ["tmp_dir"], str) else os.environ["tmp_dir"]
target_dir = Path(target_dir.decode())
tmp_dir = Path(tmp_dir.decode())
target_dir.symlink_to(tmp_dir)
bin_path = Path(target_dir / "dir")
bin_path.parent.mkdir()
bin_path.symlink_to("/usr/bin/code-server")
out = subprocess.run(
["bash", "-c", "set -e ; ln -s /usr/bin/code-server /usr/local/bin/code-server"],
executable="/bin/bash",
text=True,
)
print("plain_ln_rc=", out.returncode)
out2 = subprocess.run(
["bash", "-c", "set -e ; ln -sfn /usr/bin/code-server /usr/local/bin/code-server"],
executable="/bin/bash",
text=True,
)
print("force_ln_rc=", out2.returncode)
PY
echo
echo "Search for exact symlink command in repository:"
rg -n --glob '!resources/licenses/**' --glob '!docs/**' --glob '!node_modules/**' '\bln -s /usr/bin/code-server /usr/local/bin/code-server\b' . || trueRepository: FortiShield/ml-workspace
Length of output: 2392
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import os, subprocess, tempfile, stat
from pathlib import Path
with tempfile.TemporaryDirectory() as tmpdir:
bin_dir = Path(tmpdir) / "usr" / "bin"
local_dir = Path(tmpdir) / "usr" / "local" / "bin"
bin_dir.mkdir(parents=True)
local_dir.mkdir(parents=True)
target_file = bin_dir / "code-server"
target_file.write_text("echo target")
target_file.chmod(target_file.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
local_link = local_dir / "code-server"
local_link.symlink_to(target_file)
print("before_plain_is_ok=", local_link.exists(), os.path.lexists(str(local_link)))
out = subprocess.run(
["bash", "-c", "set -e ; ln -s /usr/bin/code-server /usr/local/bin/code-server"],
executable="/bin/bash",
cwd=tmpdir,
text=True,
capture_output=True,
)
print("plain_ln_returncode=", out.returncode)
print("plain_ln_stderr=", out.stderr.strip().replace(tmpdir, "<tmpdir>"))
print("after_plain_is_ok=", local_link.exists(), os.path.lexists(str(local_link)))
print("before_force_is_ok=", local_link.exists(), os.path.lexists(str(local_link)))
out2 = subprocess.run(
["bash", "-c", "set -e ; ln -sfn /usr/bin/code-server /usr/local/bin/code-server"],
executable="/bin/bash",
cwd=tmpdir,
text=True,
capture_output=True,
)
print("force_ln_returncode=", out2.returncode)
print("force_ln_stderr=", out2.stderr.strip().replace(tmpdir, "<tmpdir>"))
print("after_force_is_ok=", local_link.exists(), os.path.lexists(str(local_link)))
PYRepository: FortiShield/ml-workspace
Length of output: 526
🌐 Web query:
GNU coreutils ln command line options -sf overwrite existing destination documentation
💡 Result:
By default, the GNU coreutils ln command does not replace or overwrite existing files [1][2]. If you attempt to create a link with a name that already exists, the command will fail [3][4]. To manage existing destination files, you can use the following command-line options: --force (-f): This option removes any existing destination files unconditionally to allow the link to be created [1][3]. --interactive (-i): This option prompts you for confirmation before removing an existing destination file [1][2]. The operation proceeds only if you provide an affirmative response [2]. --backup (-b): This option creates a backup of each existing destination file before it is removed or replaced [1][5]. You can customize the backup method using the --backup[=CONTROL] option or the VERSION_CONTROL environment variable [6][3]. When using --backup, there is no brief moment where the destination file does not exist, which distinguishes GNU ln from standard POSIX behavior [1][2].
Citations:
- 1: https://www.gnu.org.cach3.com/software/coreutils/manual/html_node/ln-invocation.html
- 2: https://manpagez.com/info/coreutils/coreutils-9.3/ln_invocation.php
- 3: https://manpages.debian.org/unstable/coreutils/ln.1.en.html
- 4: https://manpages.debian.org/bookworm/coreutils/ln.1.en.html
- 5: https://devdoc.net/linux/coreutils-8.28/ln-invocation.html
- 6: https://man7.org/linux/man-pages/man1/ln.1.html
🌐 Web query:
POSIX ln command behavior existing destination file without -f
💡 Result:
According to the POSIX standard, the behavior of the ln command when a destination file already exists is as follows: If the -f (force) option is not specified and the destination path already exists, the ln utility is not permitted to remove or replace the existing destination file [1][2]. In this scenario, the utility will typically write a diagnostic message to standard error and skip the creation of the link for that specific source file [3][4]. The -f option is explicitly provided to change this behavior: when -f is specified, ln is authorized to remove the existing destination path to allow the new link to be created [1][2]. It is important to note that the standard explicitly leaves the exact behavior unspecified if the destination path was created by a previous step in the same execution (e.g., when linking multiple files at once) [1]. Additionally, while historical implementations might have prompted for confirmation before unlinking an existing file, the current POSIX specification does not require or define such interactive behavior [1].
Citations:
- 1: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/ln.html
- 2: https://manpages.ubuntu.com/manpages/noble/man1/ln.1posix.html
- 3: https://www.ibm.com/docs/zh/ssw_aix_71/l_commands/ln.html
- 4: https://pubs.opengroup.org/onlinepubs/007904875/utilities/ln.html
🌐 Web query:
APT DEB package /usr/bin/code-server conffile usr/local/bin/code-server conffile configuration file lintian
💡 Result:
In Debian packaging, marking files under /usr as conffiles triggers a Lintian error because of the Debian Policy Manual requirements [1][2][3]. According to the Debian Policy Manual, all configuration files must reside in /etc [4]. Files located under /usr (such as /usr/bin/code-server or /usr/local/bin/code-server) are not permitted to be marked as conffiles because /usr may be mounted as a read-only filesystem, preventing the local system administrator from modifying the configuration [1][2][3]. If you are encountering this issue while packaging software like code-server, you must adhere to the following Debian packaging standards: 1. Compliance with Location Policy: Move configuration files to /etc [4]. If your application requires a configuration file, create a subdirectory in /etc (e.g., /etc/code-server/) to hold it [4]. 2. Avoid Marking Binaries as Conffiles: Executables installed in /usr/bin or /usr/local/bin should never be marked as conffiles [1][4]. The conffiles mechanism is exclusively intended for files that a user is expected to customize, such as service configurations or application settings [5][4]. 3. Packaging Tooling: If you are using automated tools to build your.deb packages (such as nfpm, which is often used in code-server builds), ensure your configuration file mapping explicitly points to /etc [6][7]. If a file is incorrectly flagged by Lintian, you may have an error in your package's debian/conffiles file or your build system's configuration that is erroneously designating a binary path as a configuration file [8][9]. If you must manage application configuration that defaults to a path outside of /etc, you can use symlinks within /etc pointing to the actual configuration location, or use maintainer scripts (postinst) to manage the configuration file creation, provided they follow Debian policy on idempotency and user interaction [10][5][4].
Citations:
- 1: https://lintian.debian.org/tags/file-in-usr-marked-as-conffile.html
- 2: https://udd.debian.org/lintian-tag/file-in-usr-marked-as-conffile
- 3: https://udd.debian.org/lintian-tag/non-etc-file-marked-as-conffile
- 4: https://www.debian.org/doc/debian-policy/ch-files
- 5: https://www.debian.org/doc/manuals/maint-guide/dother.en.html
- 6: Failing to build Debian pkg on PPC64LE coder/code-server#3904
- 7: content conflicts when nfpm pkg coder/code-server#5810
- 8: https://manpages.debian.org/bookworm/dpkg-dev/deb-conffiles.5
- 9: https://www.debian.org/doc/debian-policy/ch-binary
- 10: https://www.debian.org/doc/debian-policy/ap-pkg-conffiles.html
🌐 Web query:
GitHub cdr code-server Debian package usr/bin/code-server usr/local/bin/code-server
💡 Result:
When you install the code-server.deb package on Debian or Ubuntu, the executable is installed to /usr/bin/code-server. This path is standard for system-level package installations on Debian-based distributions. In contrast, the /usr/local/bin/ directory is typically reserved for software compiled or installed manually by the user, or by scripts that do not follow standard packaging conventions. If you use the code-server automated installation script with the --prefix=/usr/local option, or if you perform a manual standalone installation, the binary may be placed in or symlinked to /usr/local/bin/code-server, but this is distinct from the standard Debian package installation behavior.
Citations:
- 1: https://github.com/coder/code-server/blob/main/install.sh
- 2: https://coder.com/docs/code-server/install.md
- 3: https://coder.com/docs/code-server/install
- 4: https://github.com/cdr/code-server/blob/main/install.sh
- 5: https://github.com/coder/code-server/blob/HEAD/install.sh
Make symlink creation idempotent.
If a retry follows a partial install, apt-get may restore the existing /usr/local/bin/code-server symlink so the subsequent plain ln -s fails under set -e.
Suggested fix
- ln -s /usr/bin/code-server /usr/local/bin/code-server
+ ln -sfn /usr/bin/code-server /usr/local/bin/code-server📝 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.
| ln -s /usr/bin/code-server /usr/local/bin/code-server | |
| ln -sfn /usr/bin/code-server /usr/local/bin/code-server |
🤖 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 `@resources/tools/vs-code-server.sh` at line 26, Update the symlink creation
command in the installation script to be idempotent, replacing the plain ln -s
behavior so retries succeed when /usr/local/bin/code-server already exists as
the expected symlink. Preserve creation of the link when it is absent and ensure
the command remains compatible with set -e.
What kind of change does this PR introduce?
Description:
Checklist:
Summary by Sourcery
Optimize Docker build performance and GPU image setup, introduce BuildKit/buildx support and Makefile helpers, and modernize CI workflows and editor tooling.
New Features:
Enhancements:
CI:
Documentation:
Tests:
Summary by CodeRabbit
New Features
Bug Fixes
Documentation