Skip to content

(MOT-3889) fix(scrapling): ship as python source bundle instead of deploy: image - #433

Merged
andersonleal merged 1 commit into
mainfrom
andersonleal/mot-3889-scrapling-python-bundle
Jul 6, 2026
Merged

(MOT-3889) fix(scrapling): ship as python source bundle instead of deploy: image#433
andersonleal merged 1 commit into
mainfrom
andersonleal/mot-3889-scrapling-python-bundle

Conversation

@andersonleal

@andersonleal andersonleal commented Jul 6, 2026

Copy link
Copy Markdown
Collaborator

Why

Release run for scrapling/v0.2.0 failed: https://github.com/iii-hq/workers/actions/runs/28822396424

deploy: image fires the container-build job, which runs buildx against scrapling/Dockerfile — but v0.2.0 moved scrapling to runtime.base_image + scripts.install and deleted the Dockerfile, so buildx dies with open Dockerfile: no such file or directory.

What

Ship scrapling as deploy: bundle and teach the pipeline about python bundles:

  • _bundle.yml — python path implemented: stages the worker source (src/ + pyproject.toml + iii.worker.yaml, minus tests/README) as the bundle. The engine's bundle validator executes only scripts.start (rejects scripts.install/setup), so the start command self-bootstraps; native deps + browsers can't be vendored per-arch into one archive anyway. Verify step is language-aware; pack step tars the stage dir generically.
  • _publish-registry.yml — bundle smoke-boot reads scripts.start from the extracted manifest instead of hardcoding node ./index.mjs, so it exercises the exact command the engine runs (works for node and python bundles alike). Interface-collection wait widened to 600s for bundles since they may pip-install at boot.
  • validate_worker.py — PR-time mirror of the engine's bundle-manifest rules: no scripts.setup/install, non-empty scripts.start, and runtime.base_image must name an engine-preset ref verbatim. Passes scrapling/claude-code/pi/opencode; rejects synthetic bad manifests.
  • scrapling/iii.worker.yamldeploy: bundle; runtime.base_image: docker.io/iiidev/python:latest (the documented field — runtime.kind is deprecated, and empty kind silently defaults to the node rootfs); dependency bootstrap (pip install -e . && scrapling install) folded into scripts.start.

Depends on

An engine-side change in the iii repo (uncommitted yet): bundle_download.rs now accepts runtime.base_image for bundles when it names an engine-preset ref verbatim (docker.io/iiidev/python:latest / iiidev/node:latest), still rejecting arbitrary refs. Without it, iii worker add of the published scrapling bundle is rejected at install time. CI in this repo does not exercise that path, so this PR is green independently.

After merge

The scrapling/v0.2.0 tag still points at the deploy: image commit — re-run the release via workflow_dispatch (builds from main's tree) or cut v0.2.1.

Fixes MOT-3889

Summary by CodeRabbit

  • New Features

    • Added support for bundle-based worker deployments, including Python bundle packaging and startup handling.
    • Bundle workers now use the configured start command and can take longer to register interfaces when needed.
  • Bug Fixes

    • Improved validation for bundled workers to prevent unsupported setup/install settings and require a valid startup command.
    • Updated artifact checks so bundle builds are verified correctly for both Node and Python workers.

scrapling/v0.2.0 dropped its Dockerfile for runtime.base_image +
scripts.install, but deploy: image still fired the container-build job,
which died on `open Dockerfile: no such file or directory`
(run 28822396424).

Switch scrapling to deploy: bundle and teach the pipeline about python
bundles:

- _bundle.yml: python path stages the worker source (src/ +
  pyproject.toml + iii.worker.yaml); scripts.start self-bootstraps since
  the engine's bundle validator executes only scripts.start
- _publish-registry.yml: boot bundles via the manifest's scripts.start
  instead of hardcoded `node ./index.mjs`; widen the interface-collection
  wait to 600s for self-bootstrapping bundles
- validate_worker.py: mirror the engine's bundle-manifest rules at PR
  time (no scripts.install/setup, non-empty scripts.start,
  runtime.base_image must name an engine-preset ref)
- scrapling/iii.worker.yaml: deploy: bundle, runtime.base_image pinned
  to the engine-preset docker.io/iiidev/python:latest (runtime.kind is
  deprecated), dependency bootstrap folded into scripts.start

Requires the engine change accepting preset refs for bundle
runtime.base_image (iii repo, bundle_download.rs).

Fixes MOT-3889
@vercel

vercel Bot commented Jul 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 6, 2026 9:36pm
workers-tech-spec Ready Ready Preview, Comment Jul 6, 2026 9:36pm

Request Review

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 35 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

@coderabbitai

coderabbitai Bot commented Jul 6, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds deploy: bundle support across the worker validation script and CI workflows. validate_worker.py gains bundle-specific manifest checks and a preset image allowlist. _bundle.yml implements Python artifact staging, language-aware verification, and full-directory tarball packaging. _publish-registry.yml starts bundle workers via scripts.start with a longer interface-collection wait. scrapling/iii.worker.yaml migrates to deploy: bundle.

Changes

Bundle Deploy Pipeline

Layer / File(s) Summary
Validator rules for bundle workers
.github/scripts/validate_worker.py
Adds BUNDLE_PRESET_IMAGES allowlist; rejects scripts.setup/scripts.install, requires non-empty scripts.start, and validates runtime.base_image against the allowlist for deploy: bundle.
Python bundle staging, verification, and packaging
.github/workflows/_bundle.yml
Stages Python worker source (excluding tests/git/README), verifies pyproject.toml (Python) or index.mjs (Node) plus iii.worker.yaml, and tars the full staged directory.
Bundle worker startup in publish-registry
.github/workflows/_publish-registry.yml
Derives start_cmd from iii.worker.yaml scripts.start and runs it via sh -c for bundle deploys; extends interface-collection wait to 600s for bundle vs 120s otherwise.
scrapling worker migrated to bundle deploy
scrapling/iii.worker.yaml
Switches deploy: image to deploy: bundle, removes scripts.install, and combines bootstrap plus launch commands into scripts.start with updated comments.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CI as CI Workflow
  participant Bundle as "_bundle.yml"
  participant Registry as "_publish-registry.yml"
  participant Worker as "Bundled Worker Process"

  CI->>Bundle: Trigger bundle build
  Bundle->>Bundle: Stage worker source (exclude tests/git/README)
  Bundle->>Bundle: Verify staged artefact (pyproject.toml/index.mjs + iii.worker.yaml)
  Bundle->>Bundle: Tar staged directory
  CI->>Registry: Publish bundle
  Registry->>Registry: Parse iii.worker.yaml for scripts.start
  Registry->>Worker: sh -c "$start_cmd"
  Registry->>Worker: Wait up to 600s for interface registration
  Worker-->>Registry: Interfaces collected
Loading

Possibly related PRs

  • iii-hq/workers#178: Both PRs extend deploy: bundle support across validate_worker.py, _bundle.yml, and _publish-registry.yml.
  • iii-hq/workers#76: Both PRs modify the interface-collection start-worker branching logic in _publish-registry.yml based on deploy mode.
  • iii-hq/workers#113: Extends the same validate_worker.py manifest validation logic that this PR builds bundle-specific rules on top of.

Suggested reviewers: sergiofilhowz

Poem

A bundle hops where images stood,
scripts.start now does the good,
Tarballs packed from root to tip,
Six hundred seconds for the trip,
Carrots counted, checks all pass —
This rabbit thumps for bundled grass! 🥕📦

🚥 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 clearly summarizes the main change: switching scrapling from deploy:image to a Python source bundle.
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.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch andersonleal/mot-3889-scrapling-python-bundle

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.

@andersonleal
andersonleal merged commit ce2f82d into main Jul 6, 2026
14 of 15 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (3)
.github/workflows/_bundle.yml (2)

172-175: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Stale comment: no longer just "entrypoint + iii.worker.yaml".

Since the tarball now packs the entire $STAGE_DIR (including full Python source trees), the comment describing the archive contents as "the staged entrypoint + iii.worker.yaml" is inaccurate for Python bundles.

✏️ Suggested comment update
-          # straight to the staged files, not at `$STAGE_DIR`. The resulting archive expands
-          # straight to the staged entrypoint + `iii.worker.yaml`.
+          # `tar -C` so the archive contents are rooted at the staged
+          # files, not at `$STAGE_DIR`. The resulting archive expands to
+          # everything staged for the worker (entrypoint/source tree + `iii.worker.yaml`).
🤖 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/_bundle.yml around lines 172 - 175, The tarball comment in
the bundle workflow is stale and still says the archive contains only the staged
entrypoint plus iii.worker.yaml, but the bundle now includes the full contents
of $STAGE_DIR. Update the comment near the tar -C step to accurately describe
that the archive is rooted at the staged files and now packages the entire
staged bundle, including Python source trees.

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

Deny-list staging is more fragile than the Node path's allow-list.

Unlike Node staging (which copies only index.mjs + iii.worker.yaml), Python staging rsyncs the entire worker directory except tests, .git*, and README.md. Any future stray artifact (e.g., .venv/, __pycache__/, editor configs, or an accidentally-committed .env) would ship into the release tarball since nothing else is excluded.

♻️ Suggested additional excludes
           rsync -a --exclude tests --exclude '.git*' --exclude README.md \
+            --exclude '__pycache__' --exclude '*.egg-info' --exclude '.venv' \
+            --exclude '.env*' --exclude '.mypy_cache' --exclude '.ruff_cache' \
             "$WORKER/" "$stage/"
🤖 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/_bundle.yml around lines 117 - 136, The Python staging
step is too permissive because the rsync-based deny-list only excludes a few
paths, so unintended files can slip into the bundle. Update the Stage Python
artefact logic in the workflow to use a stricter allow-list or expand the rsync
excludes so only the required worker sources and manifest are staged, matching
the tighter Node staging approach. Make the fix in the Stage Python artefact
step that uses the WORKER, stage, and rsync command.
.github/scripts/validate_worker.py (1)

55-63: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep BUNDLE_PRESET_IMAGES in sync with the engine catalog
BUNDLE_PRESET_IMAGES duplicates the engine’s preset list, so changes in sandbox_daemon/catalog.rs can silently desync validation here. Pull this from the same source of truth or add a sync check.

🤖 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/scripts/validate_worker.py around lines 55 - 63,
BUNDLE_PRESET_IMAGES is duplicating the engine’s preset catalog, so validation
can drift from sandbox_daemon/catalog.rs. Update validate_worker.py to derive
the allowed base image set from the same source of truth used by the engine, or
add a startup/sync check that compares BUNDLE_PRESET_IMAGES against the engine
presets so mismatches are caught automatically; use the BUNDLE_PRESET_IMAGES
constant and the bundle validator/catalog preset definitions as the key anchors.
🤖 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/scripts/validate_worker.py:
- Around line 55-63: BUNDLE_PRESET_IMAGES is duplicating the engine’s preset
catalog, so validation can drift from sandbox_daemon/catalog.rs. Update
validate_worker.py to derive the allowed base image set from the same source of
truth used by the engine, or add a startup/sync check that compares
BUNDLE_PRESET_IMAGES against the engine presets so mismatches are caught
automatically; use the BUNDLE_PRESET_IMAGES constant and the bundle
validator/catalog preset definitions as the key anchors.

In @.github/workflows/_bundle.yml:
- Around line 172-175: The tarball comment in the bundle workflow is stale and
still says the archive contains only the staged entrypoint plus iii.worker.yaml,
but the bundle now includes the full contents of $STAGE_DIR. Update the comment
near the tar -C step to accurately describe that the archive is rooted at the
staged files and now packages the entire staged bundle, including Python source
trees.
- Around line 117-136: The Python staging step is too permissive because the
rsync-based deny-list only excludes a few paths, so unintended files can slip
into the bundle. Update the Stage Python artefact logic in the workflow to use a
stricter allow-list or expand the rsync excludes so only the required worker
sources and manifest are staged, matching the tighter Node staging approach.
Make the fix in the Stage Python artefact step that uses the WORKER, stage, and
rsync command.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 88e1ee98-e414-440c-b013-0cf8b51f1a81

📥 Commits

Reviewing files that changed from the base of the PR and between 190a331 and 5159e0e.

📒 Files selected for processing (4)
  • .github/scripts/validate_worker.py
  • .github/workflows/_bundle.yml
  • .github/workflows/_publish-registry.yml
  • scrapling/iii.worker.yaml

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant