Skip to content

feat(build): Push toolkit bundle as OCI zstd artifact#112

Open
m1so wants to merge 10 commits into
mainfrom
mb/oci-zstd-bundle
Open

feat(build): Push toolkit bundle as OCI zstd artifact#112
m1so wants to merge 10 commits into
mainfrom
mb/oci-zstd-bundle

Conversation

@m1so

@m1so m1so commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Summary by CodeRabbit

  • New Features
    • Added dual publishing modes for OCI artifact uploads: image-volume (default) and direct-files.
    • Publish toolkit bundles as a separate tar+zstd OCI artifact, and enable toolkit downloads via OCI zstd in addition to S3.
  • Bug Fixes
    • Improved validation for direct-files: enforces path:media-type format, requires relative existing files, prevents duplicate basenames, errors when no files are provided, and verifies the pushed manifest.
  • Tests
    • Added/strengthened unit tests for toolkit bundle reference building, OCI zstd download flow, and subprocess argument expectations.

@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The action now supports image-volume and direct-files publish modes. The workflow builds a .tar.zst toolkit bundle and publishes it as a separate OCI artifact. The cache downloader now supports fetching toolkit bundles from either S3 or an OCI registry using regctl, zstd, and tar, and the unit tests cover the new path.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Workflow
  participant cache-downloader.py
  participant regctl
  participant zstd
  participant tar

  Workflow->>cache-downloader.py: TOOLKIT_DOWNLOAD_METHOD=oci-zstd
  cache-downloader.py->>regctl: artifact get toolkit bundle ref
  regctl->>zstd: compressed payload
  zstd->>tar: decompressed archive
  tar-->>cache-downloader.py: extracted toolkit files
Loading

Possibly related PRs

Suggested reviewers: tkislan

🚥 Pre-merge checks | ✅ 5 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Updates Docs ⚠️ Warning The PR changes only code and tests; no docs files were updated in this repo. Please add the feature docs in deepnote/deepnote OSS and the landing-page roadmap in deepnote/deepnote-internal; I can’t verify the private repo here.
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
Title check ✅ Passed The title clearly matches the main change: publishing the toolkit bundle as an OCI zstd artifact.

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

@github-actions

github-actions Bot commented Jul 3, 2026

Copy link
Copy Markdown

📦 Python package built successfully!

  • Version: 2.4.0.dev11+fd62870
  • Wheel: deepnote_toolkit-2.4.0.dev11+fd62870-py3-none-any.whl
  • Install:
    pip install "deepnote-toolkit @ https://deepnote-staging-runtime-artifactory.s3.amazonaws.com/deepnote-toolkit-packages/2.4.0.dev11%2Bfd62870/deepnote_toolkit-2.4.0.dev11%2Bfd62870-py3-none-any.whl"

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
.github/actions/push-oci-artifact/action.yml (1)

131-196: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated annotation-building and file-parsing logic across both publish steps.

Lines 144-154 and 166-187 largely re-implement the manifest_annotations construction and file-descriptor parsing already present in the image-volume step (lines 64-87). Any future fix (e.g., descriptor edge cases) now needs to be applied in two places.

♻️ Suggested direction

Extract the shared annotation-building loop (and possibly descriptor parsing) into a small reusable script sourced by both steps, or a separate composite step that writes annotations/args to a temp file consumed by both branches.

🤖 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/push-oci-artifact/action.yml around lines 131 - 196, The
direct-files branch in the push step is duplicating the same annotation assembly
and file-descriptor parsing already implemented in the image-volume branch.
Refactor the shared logic out of the inline bash in the Push OCI direct file
artifact step into a reusable helper/script or composite step, and have both
publish_mode branches consume it so fixes to descriptor handling or annotation
rules only need to be made once.
🤖 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.

Nitpick comments:
In @.github/actions/push-oci-artifact/action.yml:
- Around line 131-196: The direct-files branch in the push step is duplicating
the same annotation assembly and file-descriptor parsing already implemented in
the image-volume branch. Refactor the shared logic out of the inline bash in the
Push OCI direct file artifact step into a reusable helper/script or composite
step, and have both publish_mode branches consume it so fixes to descriptor
handling or annotation rules only need to be made once.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 24f43dc9-a809-4d3c-88e8-c9e959c869ba

📥 Commits

Reviewing files that changed from the base of the PR and between 6198101 and 200cd4f.

📒 Files selected for processing (2)
  • .github/actions/push-oci-artifact/action.yml
  • .github/workflows/cd.yml

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026
@codecov

codecov Bot commented Jul 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 74.42%. Comparing base (6198101) to head (a2d70bb).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@           Coverage Diff           @@
##             main     #112   +/-   ##
=======================================
  Coverage   74.42%   74.42%           
=======================================
  Files          95       95           
  Lines        5704     5704           
  Branches      850      850           
=======================================
  Hits         4245     4245           
  Misses       1182     1182           
  Partials      277      277           
Flag Coverage Δ
combined 74.42% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026
@deepnote-bot

deepnote-bot commented Jul 3, 2026

Copy link
Copy Markdown

🚀 Review App Deployment Started

📝 Description 🌐 Link / Info
🌍 Review application ra-112
🔑 Sign-in URL Click to sign-in
Envoy review application ra-112 Envoy
Envoy sign-in URL Click to sign-in
📊 Application logs View logs
🔄 Actions Click to redeploy
🚀 ArgoCD deployment View deployment
Last deployed 2026-07-06 12:08:29 (UTC)
📜 Deployed commit eff36091d6ad21f1ac5a549b3f1cf553815bd78a
🛠️ Toolkit version fd62870

coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026
coderabbitai[bot]
coderabbitai Bot previously approved these changes Jul 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🧹 Nitpick comments (3)
tests/unit/test_cache_downloader.py (1)

177-183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add test method annotations/docstring.

Use -> None on the new tests, and add a short docstring for test_build_toolkit_bundle_ref.

As per coding guidelines, **/*.py: “Use explicit type hints for function parameters and return values” and “Use docstrings for all functions/classes”.

Also applies to: 243-244

🤖 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 `@tests/unit/test_cache_downloader.py` around lines 177 - 183, The new test
methods in test_cache_downloader need explicit return type hints and a short
docstring to match the Python coding guidelines. Update
test_build_toolkit_bundle_ref and the other affected test(s) in this file
(including the ones around test_build_toolkit_bundle_ref and the later
occurrences noted in the review) to use -> None, and add a concise docstring
describing each test’s purpose. Keep the changes localized to the test method
definitions so they remain easy to find by their test_* names.

Source: Coding guidelines

dockerfiles/cache-downloader/Dockerfile (1)

5-5: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Pin the regctl source image by digest.

v0.11.5 is a mutable tag. Use a digest-pinned reference for reproducible, safer builds.

🤖 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 `@dockerfiles/cache-downloader/Dockerfile` at line 5, The regctl source image
reference in the Dockerfile is still tag-based and mutable, so update the COPY
--from=... source to use a digest-pinned regclient/regctl image instead of
v0.11.5. Keep the existing regctl copy step, but replace the source image
reference with a fixed digest to make the build reproducible and safer.
dockerfiles/cache-downloader/cache-downloader.py (1)

17-36: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Align the new APIs with project Python style.

New/changed functions need docstrings and explicit -> None where applicable. Line 132 also keeps path handling split across os.path/os.makedirs; prefer Path consistently.

As per coding guidelines, **/*.py: “Use type hints consistently”, “Use docstrings for all functions/classes”, and “Use pathlib.Path for file path operations instead of os.path”.

Also applies to: 69-74, 123-141, 166-172

🤖 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 `@dockerfiles/cache-downloader/cache-downloader.py` around lines 17 - 36, The
new/updated functions in cache-downloader.py need to follow project Python style
by adding docstrings to each function, making return types explicit with -> None
where the function does not return a value, and keeping type hints consistent
across the module. Update the relevant helpers such as build_toolkit_bundle_ref,
_read_stderr, and download_dependency_from_s3 accordingly, and replace mixed
os.path/os.makedirs path handling with pathlib.Path throughout the path-related
code, including the sections around version path and directory creation.

Source: Coding guidelines

🤖 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 `@dockerfiles/cache-downloader/cache-downloader.py`:
- Around line 257-269: The cache-downloader flow currently defers validation
until after cleanup, so an invalid TOOLKIT_DOWNLOAD_METHOD can trigger
cleanup_old_versions() before failing, and submit_downloading() can still be
called with a missing toolkit_index_bucket_name in S3 mode. Validate the backend
configuration first in the cache-downloader entry path before calling
cleanup_old_versions() or submit_downloading(), using the existing
download_method, oci_repository, and toolkit_index_bucket_name values to reject
unsupported methods and missing S3 bucket configuration early.
- Around line 52-57: The pipeline in cache-downloader.py is leaving stderr pipes
unread while aws/regctl/zstd and tar run, which can block noisy subprocesses and
hang the download flow. Update the subprocess handling in the download path and
the OCI path so stderr is drained concurrently or redirected away from PIPE
during execution, then preserve the collected stderr for error reporting in the
existing failure branches around the aws_process/tar_process logic and the OCI
equivalents.

---

Nitpick comments:
In `@dockerfiles/cache-downloader/cache-downloader.py`:
- Around line 17-36: The new/updated functions in cache-downloader.py need to
follow project Python style by adding docstrings to each function, making return
types explicit with -> None where the function does not return a value, and
keeping type hints consistent across the module. Update the relevant helpers
such as build_toolkit_bundle_ref, _read_stderr, and download_dependency_from_s3
accordingly, and replace mixed os.path/os.makedirs path handling with
pathlib.Path throughout the path-related code, including the sections around
version path and directory creation.

In `@dockerfiles/cache-downloader/Dockerfile`:
- Line 5: The regctl source image reference in the Dockerfile is still tag-based
and mutable, so update the COPY --from=... source to use a digest-pinned
regclient/regctl image instead of v0.11.5. Keep the existing regctl copy step,
but replace the source image reference with a fixed digest to make the build
reproducible and safer.

In `@tests/unit/test_cache_downloader.py`:
- Around line 177-183: The new test methods in test_cache_downloader need
explicit return type hints and a short docstring to match the Python coding
guidelines. Update test_build_toolkit_bundle_ref and the other affected test(s)
in this file (including the ones around test_build_toolkit_bundle_ref and the
later occurrences noted in the review) to use -> None, and add a concise
docstring describing each test’s purpose. Keep the changes localized to the test
method definitions so they remain easy to find by their test_* names.
🪄 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

Run ID: 9135739c-e84b-42c0-bfb4-4a3c5e3e3572

📥 Commits

Reviewing files that changed from the base of the PR and between bbf9396 and 54d13bf.

📒 Files selected for processing (3)
  • dockerfiles/cache-downloader/Dockerfile
  • dockerfiles/cache-downloader/cache-downloader.py
  • tests/unit/test_cache_downloader.py

Comment thread dockerfiles/cache-downloader/cache-downloader.py Outdated
Comment thread dockerfiles/cache-downloader/cache-downloader.py

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
dockerfiles/cache-downloader/cache-downloader.py (1)

77-84: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Use a specific exception type. Bare Exception (here and in the OCI path at Lines 135-146) hampers targeted handling.

Proposed fix
-        raise Exception(
+        raise RuntimeError(
             f"Error downloading {release_name} (aws s3 command failed): aws stderr: {aws_process_stderr_bytes}, tar stderr: {tar_process_stderr_bytes}"
         )

As per coding guidelines: "Use appropriate exception types for error handling".

🤖 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 `@dockerfiles/cache-downloader/cache-downloader.py` around lines 77 - 84,
Replace the broad Exception raises in the cache downloader error paths with a
more specific exception type so callers can handle download failures distinctly.
Update the AWS download branch and the OCI path error handling in the same
downloader flow to throw a targeted runtime/error class from the existing
download logic instead of bare Exception, keeping the same failure messages and
using the relevant error-handling blocks in the cache downloader routine.

Source: Coding guidelines

🤖 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 `@dockerfiles/cache-downloader/cache-downloader.py`:
- Around line 26-30: Update validate_download_config to use Optional[str] for
the nullable parameters instead of str | None, since this module must remain
importable on Python 3.9 and should follow the existing Optional[T] typing rule.
Adjust the annotations on toolkit_index_bucket_name and oci_repository in
validate_download_config accordingly, and keep the rest of the function behavior
unchanged.

---

Nitpick comments:
In `@dockerfiles/cache-downloader/cache-downloader.py`:
- Around line 77-84: Replace the broad Exception raises in the cache downloader
error paths with a more specific exception type so callers can handle download
failures distinctly. Update the AWS download branch and the OCI path error
handling in the same downloader flow to throw a targeted runtime/error class
from the existing download logic instead of bare Exception, keeping the same
failure messages and using the relevant error-handling blocks in the cache
downloader routine.
🪄 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

Run ID: 83b01aab-f3ab-4623-8c89-46fb0d03ac51

📥 Commits

Reviewing files that changed from the base of the PR and between 54d13bf and a2d70bb.

📒 Files selected for processing (2)
  • dockerfiles/cache-downloader/cache-downloader.py
  • tests/unit/test_cache_downloader.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/test_cache_downloader.py

Comment thread dockerfiles/cache-downloader/cache-downloader.py
@m1so m1so marked this pull request as ready for review July 7, 2026 12:37
@m1so m1so requested a review from a team as a code owner July 7, 2026 12:37
@m1so m1so requested review from mfranczel and tkislan July 7, 2026 12:37
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