Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
35cf37b
✨ feat(kasmvnc): add KasmVNC-based GUI studio environments
FloWuenne Feb 2, 2026
cf128c3
Merge branch 'master' into feat/kasmvnc-apps
FloWuenne Feb 3, 2026
9334a0c
💚 ci(docker): add kasmVNC containers to build matrix
FloWuenne Feb 3, 2026
c29e92e
🐛 fix(cellprofiler): use default Python 3.10 instead of unavailable 3.9
FloWuenne Feb 3, 2026
65b8a29
🐛 fix(kasmvnc): remove invalid setToolIdentifier command
FloWuenne Feb 3, 2026
2ad164d
Merge remote-tracking branch 'origin/master' into feat/kasmvnc-apps
FloWuenne Feb 3, 2026
34db9b2
💚 ci(workflows): add kasmVNC containers to PR and release workflows
FloWuenne Feb 3, 2026
13d4277
🐛 fix: resolve cleanup jq parsing and cellprofiler build issues
FloWuenne Feb 3, 2026
5f299ee
🐛 fix(cellprofiler): upgrade pip to find wxPython pre-built wheels
FloWuenne Feb 3, 2026
86dcb12
🐛 fix(cellprofiler): remove explicit scikit-learn to use CellProfiler…
FloWuenne Feb 3, 2026
3f6b143
🔥 remove(cellprofiler): drop CellProfiler from kasmVNC containers
FloWuenne Feb 3, 2026
3f0dc91
Add KasmVNC QuPath studio branch
cursoragent Jun 3, 2026
ceb37da
Fix KasmVNC QuPath container startup
cursoragent Jun 3, 2026
a95df55
Fix KasmVNC QuPath CI and branch isolation
cursoragent Jun 9, 2026
b9ecf98
Merge pull request #37 from seqeralabs/cursor/fix-kasmvnc-qupath-ci-d31c
FloWuenne Jun 9, 2026
d6aed56
Use registry cache for Docker workflows
cursoragent Jun 10, 2026
b3c4d2d
Merge pull request #38 from seqeralabs/cursor/pin-cache-actions-42f4
FloWuenne Jun 10, 2026
e6ffb51
Merge pull request #36 from seqeralabs/cursor/kasmvnc-qupath-f4f3
FloWuenne Jun 11, 2026
13f0181
Merge master into feat/kasmvnc-apps, resolving conflicts
Copilot Jun 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions .github/workflows/cleanup-pr-images.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,17 @@ jobs:

echo "Cleaning up images for PR #${PR_NUMBER}..."

# Get all versions of the package
# Get all versions of the package (merge paginated arrays)
VERSIONS=$(gh api \
-H "Accept: application/vnd.github+json" \
-H "X-GitHub-Api-Version: 2022-11-28" \
"/orgs/seqeralabs/packages/container/${PACKAGE_NAME}/versions" \
--paginate 2>/dev/null || echo "[]")
--paginate 2>/dev/null | jq -s 'add // []')

# Find all versions with tags ending in -pr<PR_NUMBER>
echo "$VERSIONS" | jq -r --arg pr "pr${PR_NUMBER}" '
.[] |
select(.metadata.container.tags[] | endswith("-" + $pr)) |
select(.metadata.container.tags[]? | endswith("-" + $pr)) |
.id
' | while read -r VERSION_ID; do
if [[ -n "$VERSION_ID" ]]; then
Expand Down
46 changes: 13 additions & 33 deletions .github/workflows/docker-pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,42 +15,22 @@ jobs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Detect changed Dockerfiles
id: changes
uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3
with:
filters: |
ttyd:
- 'ttyd/**'
streamlit:
- 'streamlit/**'
cellxgene:
- 'cellxgene/**'
shiny:
- 'shiny-simple-example/**'
marimo:
- 'marimo/**'
kasmvnc_qupath:
- '.seqera/**'

- name: Set matrix
id: set-matrix
run: |
CONTAINERS="[]"
if [[ "${{ steps.changes.outputs.ttyd }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"ttyd","path":"./ttyd"}]')
fi
if [[ "${{ steps.changes.outputs.streamlit }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"streamlit","path":"./streamlit"}]')
fi
if [[ "${{ steps.changes.outputs.cellxgene }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"cellxgene","path":"./cellxgene"}]')
fi
if [[ "${{ steps.changes.outputs.shiny }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"shiny","path":"./shiny-simple-example"}]')
fi
if [[ "${{ steps.changes.outputs.marimo }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"marimo","path":"./marimo"}]')
if [[ "${{ steps.changes.outputs.kasmvnc_qupath }}" == "true" ]]; then
CONTAINERS=$(echo "$CONTAINERS" | jq -c '. + [{"name":"kasmvnc-qupath","path":"./.seqera"}]')
fi
echo "matrix={\"container\":$CONTAINERS}" >> "$GITHUB_OUTPUT"

Expand All @@ -69,21 +49,21 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Log in to the Container registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/development
tags: |
Expand All @@ -97,16 +77,16 @@ jobs:
platforms: linux/amd64
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ matrix.container.name }}
cache-to: type=gha,mode=max,scope=${{ matrix.container.name }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/development:${{ matrix.container.name }}-buildcache,mode=max

- name: Get image reference for scan
id: scanref
run: |
echo "ref=${{ fromJSON(steps.meta.outputs.json).tags[0] }}" >> $GITHUB_OUTPUT

- name: Run security scan
uses: aquasecurity/trivy-action@0.31.0
uses: aquasecurity/trivy-action@76071ef0d7ec797419534a183b498b4d6366cf37 # v0
with:
image-ref: ${{ steps.scanref.outputs.ref }}
format: "table"
Expand Down Expand Up @@ -145,7 +125,7 @@ jobs:
echo "- **Commit**: \`${{ github.sha }}\`" >> $GITHUB_STEP_SUMMARY

- name: Comment on PR
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7
with:
script: |
const fs = require('fs');
Expand Down
26 changes: 9 additions & 17 deletions .github/workflows/docker-release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,7 @@ on:
required: true
type: choice
options:
- ttyd
- streamlit
- cellxgene
- shiny
- marimo
- kasmvnc-qupath
version:
description: 'Version to release (e.g., 1.0.0)'
required: true
Expand All @@ -36,32 +32,28 @@ jobs:

steps:
- name: Checkout repository
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4

- name: Set container path
id: container
run: |
case "${{ inputs.container }}" in
ttyd) echo "path=./ttyd" >> "$GITHUB_OUTPUT" ;;
streamlit) echo "path=./streamlit" >> "$GITHUB_OUTPUT" ;;
cellxgene) echo "path=./cellxgene" >> "$GITHUB_OUTPUT" ;;
shiny) echo "path=./shiny-simple-example" >> "$GITHUB_OUTPUT" ;;
marimo) echo "path=./marimo" >> "$GITHUB_OUTPUT" ;;
kasmvnc-qupath) echo "path=./.seqera" >> "$GITHUB_OUTPUT" ;;
esac

- name: Log in to the Container registry
uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3
uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 # v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GHCR_TOKEN }}

- name: Set up Docker Buildx
uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3
uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 # v3

- name: Extract metadata
id: meta
uses: docker/metadata-action@c299e40c65443455700f0fdfc63efafe5b349051 # v5
uses: docker/metadata-action@902fa8ec7d6ecbf8d84d538b9b233a880e428804 # v5
with:
images: ${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}
tags: |
Expand All @@ -81,11 +73,11 @@ jobs:
CONNECT_CLIENT_VERSION=${{ inputs.connect_client_version || '0.9' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha,scope=${{ inputs.container }}
cache-to: type=gha,mode=max,scope=${{ inputs.container }}
cache-from: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache
cache-to: type=registry,ref=${{ env.REGISTRY }}/${{ github.repository }}/${{ inputs.container }}:buildcache,mode=max

- name: Create GitHub Release
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
uses: softprops/action-gh-release@72f2c25fcb47643c292f7107632f7a47c1df5cd8 # v2
with:
tag_name: ${{ inputs.container }}/${{ inputs.version }}
name: ${{ inputs.container }} ${{ inputs.version }}
Expand Down
69 changes: 69 additions & 0 deletions .seqera/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
# ---------------------------------------------------------------
# 1) Multi-stage build: Pull the connect-client binary
# ---------------------------------------------------------------
ARG CONNECT_CLIENT_VERSION=0.9
FROM public.cr.seqera.io/platform/connect-client:${CONNECT_CLIENT_VERSION} AS connect

# ---------------------------------------------------------------
# 2) KasmVNC base image with QuPath
# ---------------------------------------------------------------
FROM lscr.io/linuxserver/baseimage-kasmvnc:ubuntujammy

# Just for the automation at Seqera
LABEL org.opencontainers.image.source="https://github.com/seqeralabs/custom-studios-examples"

ENV TITLE="QuPath"

# KasmVNC performance tuning for interactive desktop streaming
ENV KASM_VNC_ENABLE_WEBP=1
ENV KASM_VNC_JPEG_QUALITY=5
ENV KASM_VNC_MAX_FRAME_RATE=30
ENV KASM_VNC_THREADS=4

# Install dependencies for QuPath. The base image can carry stale third-party apt
# sources, so drop NodeSource before refreshing Ubuntu package indexes.
RUN rm -f /etc/apt/sources.list.d/nodesource*.list \
&& apt-get update && apt-get install -y --no-install-recommends \
wget \
xz-utils \
libgl1 \
libgtk-3-0 \
libopenslide0 \
libglib2.0-0 \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

# Install QuPath
ARG QUPATH_VERSION="0.6.0"
RUN wget -q https://github.com/qupath/qupath/releases/download/v${QUPATH_VERSION}/QuPath-v${QUPATH_VERSION}-Linux.tar.xz -O /tmp/qupath.tar.xz \
&& mkdir -p /opt/qupath \
&& tar -xf /tmp/qupath.tar.xz -C /opt/qupath --strip-components=1 \
&& chmod +x /opt/qupath/bin/QuPath \
&& rm /tmp/qupath.tar.xz


# Create the X socket directory before KasmVNC drops privileges to the abc user.
RUN sed -i '/^exec s6-setuidgid/i mkdir -p /tmp/.X11-unix && chmod 1777 /tmp/.X11-unix' /etc/s6-overlay/s6-rc.d/svc-kasmvnc/run

# Single-app mode: application launches directly, no desktop
RUN echo "/opt/qupath/bin/QuPath" > /defaults/autostart

# ---------------------------------------------------------------
# 3) Seqera Studios integration
# ---------------------------------------------------------------

# Add connect-client version label to image for supported capabilities tracking
ARG CONNECT_CLIENT_VERSION
LABEL io.seqera.connect.version="${CONNECT_CLIENT_VERSION}"

# Copy connect-client from the first stage
COPY --from=connect /usr/bin/connect-client /usr/bin/connect-client

# Install connect-client
RUN /usr/bin/connect-client --install

# Seqera Studios entrypoint (connect-client handles Fusion filesystem)
ENTRYPOINT ["/usr/bin/connect-client", "--entrypoint"]

# Bridge CONNECT_TOOL_PORT to KasmVNC's CUSTOM_PORT and launch the init system
CMD ["/bin/bash", "-c", "export CUSTOM_PORT=${CONNECT_TOOL_PORT:-6901} && exec /init"]
6 changes: 6 additions & 0 deletions .seqera/studio-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
schemaVersion: "0.0.1"
kind: "studio-config"
session:
template:
kind: "dockerfile"
dockerfile: "Dockerfile"
Loading