Skip to content

Add scheduled monthly builds, full Renovate coverage, and inline documentation#3

Open
wahidyak wants to merge 124 commits intoopencadc:mainfrom
wahidyak:main
Open

Add scheduled monthly builds, full Renovate coverage, and inline documentation#3
wahidyak wants to merge 124 commits intoopencadc:mainfrom
wahidyak:main

Conversation

@wahidyak
Copy link
Copy Markdown

@wahidyak wahidyak commented Mar 2, 2026

Summary

  • Scheduled monthly builds: Added a cron trigger (0 6 1 * *) to the CI pipeline so all images are rebuilt on the 1st of every month at 06:00 UTC, picking up upstream base image security patches and dependency updates automatically.
  • Full Renovate dependency tracking: Added # renovate: comments to all previously untracked dependencies in the webterm Dockerfile — APT packages (emacs, vim, nano, tmux, unzip, procps, nodejs, npm), ttyd (Docker), Starship (GitHub Releases), OpenCode (GitHub Releases), and all npm-based AI CLI tools (Copilot, Claude Code, Gemini CLI, Codex). Every pinned version in the project is now automatically tracked.
  • Simplified CI push guards: Changed github.event_name == 'push' && github.ref == 'refs/heads/main' to github.event_name != 'pull_request' so that scheduled and manually dispatched runs also push to the registry.
  • Comprehensive inline documentation: Added descriptive comments to all Dockerfiles (python 3.10–3.14, terminal, webterm), docker-bake.hcl, image-pipeline.yml, and renovate.json explaining the architecture, multi-stage build strategy, dependency tracking, and CI/CD flow.

Test plan

  • Verify hadolint lint passes on all Dockerfiles
  • Verify Python matrix build (3.10–3.14) succeeds
  • Verify Interactive Stack (terminal + webterm via Bake) builds successfully
  • Confirm Renovate detects all newly annotated dependencies
  • Confirm scheduled trigger appears in the Actions tab after merge

Made with Cursor

- Archived legacy build.sh
- Implemented Python 3.10-3.13 slim images with uv and pixi
- Added GitHub Actions workflow with Hadolint and automated build/push
- Updated terminal layer to use Python 3.12 base
- Ignore DL3008 to allow latest OS security patches for curl and git
- Ignore DL3013 as we manage Python packages via uv and pixi
- Removed redundant system dependencies and directory setup
- Added Python 3.14-rc-slim image
- Updated CI/CD matrix to include 3.14
wahidyak added 30 commits March 12, 2026 17:38
Only rebuild images whose Dockerfiles actually changed:
- Uses dorny/paths-filter to detect changed paths
- Respects dependency chain: terminal changes trigger all downstream
- docker-bake.hcl changes also trigger full interactive stack rebuild
- Schedule/dispatch still rebuild everything (for upstream updates)
- Python matrix only runs when dockerfiles/python/** changes

This significantly speeds up CI when only one image is modified.

Made-with: Cursor
Workflow:
- Quote the echo command to fix YAML colon parsing error

OpenVSCode:
- Install extensions to /usr/share/openvscode-extensions (not the
  bundled extensions dir) so they're available to all users
- Pass --extensions-dir at runtime to load the shared extensions

Made-with: Cursor
Users can install extensions themselves as needed. The Cursor CLI
agent in the terminal provides AI assistance without requiring
additional extension configuration.

Made-with: Cursor
Image names are now:
- images.canfar.net/cadc/vscode
- images.canfar.net/cadc/jupyter-notebook

The Dockerfile directories remain unchanged (dockerfiles/openvscode,
dockerfiles/jupyterlab) but the bake targets and image tags are renamed.

Made-with: Cursor
Made-with: Cursor
The CANFAR proxy does NOT strip the session path, so JupyterLab needs
--ServerApp.base_url=/session/contrib/<session-id>/ for assets and
redirects to work correctly. Uses skaha_sessionid env var injected
by the platform at runtime.

Same fix pattern as the OpenVSCode --server-base-path fix.

Made-with: Cursor
The logs showed requests arriving at "/" not "/session/contrib/<id>/",
confirming the proxy DOES strip the path prefix. The base_url setting
was causing JupyterLab to expect the full path which didn't match.

Reverted to serving from root without base_url.

Made-with: Cursor
The CANFAR proxy strips the session path before forwarding to JupyterLab,
but JupyterLab's redirect from / to /lab loses the session path prefix.

Solution: Run JupyterLab on internal port 8888 and use a Python TCP proxy
on port 5000 that rewrites Location headers to include the session path
(/session/contrib/<session-id>/).

For local testing (no skaha_sessionid), uses socat for simple forwarding.

Made-with: Cursor
Remove the TCP proxy approach - it can rewrite redirects but not the
HTML content with hardcoded asset URLs (/static/lab/...).

Instead, set --ServerApp.base_url=/session/contrib/<session-id>/ so
JupyterLab generates correct URLs for all assets and redirects. This
matches the OpenVSCode approach with --server-base-path.

The CANFAR proxy apparently passes through the full path for asset
requests, it only strips the path for the initial request routing.

Made-with: Cursor
The CANFAR proxy strips the session path before forwarding to JupyterLab.
This caused 404 errors because JupyterLab's asset URLs (/static/...)
didn't include the session prefix.

Solution: Use nginx as a local reverse proxy that:
1. Accepts requests at / (what CANFAR proxy sends)
2. Proxies to JupyterLab on internal port 8888
3. Rewrites Location headers for redirects (/ -> /session/contrib/<id>/)
4. Rewrites URLs in HTML/JS responses using sub_filter

Includes debug logging to diagnose any remaining issues.

Made-with: Cursor
Add proxy_redirect to strip scheme+host from upstream Location headers.
Prevents browser from being sent to backend host (workload-uv.canfar.net:5000)
which is unreachable; redirect is now path-only so browser uses front-end host.

Made-with: Cursor
- Add proxy_redirect to strip scheme+host from upstream Location so browser
  keeps CANFAR host (avoid workload-uv.canfar.net:5000).
- Log [DEBUG-REDIRECT] Location from GET / in session log to verify
  redirect value (absolute vs path-only) for further debugging.

Made-with: Cursor
…ages

Pin emacs, unzip, nano, tmux, vim, procps, nodejs, npm (same versions as
webterm) in openvscode and jupyterlab Dockerfiles for consistent CLI tooling.

Made-with: Cursor
- Add dockerfiles/marimo/Dockerfile: terminal base, uv-installed marimo,
  /cadc/startup.sh with exec marimo edit on port 5000, /build_info, run as root
- Add marimo target to docker-bake.hcl and default group
- Add marimo to image-pipeline.yml: path filter, outputs, dependency cascade,
  bake targets
- Update README.md and agent.md with marimo in structure and image list

Made-with: Cursor
- jupyterlab: set --ServerApp.base_url=/session/contrib/${skaha_sessionid}/ when
  skaha_sessionid is set so redirects work behind CANFAR proxy
- marimo: add Starship prompt and Gruvbox theme (same as webterm) so in-app
  terminal (Ctrl+J) matches webterm shell look

Made-with: Cursor
This preserves the existing launch behavior while making session path and base_url resolution easier to debug in runtime logs.

Made-with: Cursor
…tup script

- Add startup.sh with mkdir for HOME, .token, .local/bin, .cache/uv, .pixi; cd HOME
- Session ID from skaha_sessionid env or first argument ($1), same base_url /session/contrib/
- Replace inline printf with COPY startup.sh for maintainability
- Keeps contributed session behaviour (port 5000, ServerApp options unchanged)

Made-with: Cursor
… path

When the reverse proxy forwards requests without the session path (GET /
instead of GET /session/contrib/ID/), set JUPYTER_SERVE_AT_ROOT=1 in the
session env so base_url is not set and Jupyter serves at root, fixing 404s
on / and /static/...

Made-with: Cursor
- Add customManagers (regex) for # renovate: lines followed by ARG *_VERSION
- Use pep440 for PyPI pins extracted via custom.regex
- Bump locales pin to 2.41-12+deb13u2 for current Debian Trixie archive
- JupyterLab: opt-in base_url via JUPYTER_USE_BASE_URL=1; remove debug logging

Made-with: Cursor
Debian security refreshed libnode115; old nodejs=20.19.2+dfsg-1 required
libnode115 (= 20.19.2+dfsg-1) while the archive only offered +deb13u2,
breaking apt-get install in openvscode/webterm/marimo/jupyterlab layers.

Made-with: Cursor
Drop dockerfiles/jupyterlab, bake target, CI path filters, and docs.
Interactive bake targets are now terminal, webterm, vscode, marimo.

Made-with: Cursor
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