feat: support Git repository cloning in spawn workflow#22
Merged
KerwinTsaiii merged 41 commits intodevelopfrom Feb 25, 2026
Merged
feat: support Git repository cloning in spawn workflow#22KerwinTsaiii merged 41 commits intodevelopfrom
KerwinTsaiii merged 41 commits intodevelopfrom
Conversation
Rewrite the git init container implementation with several fixes:
- Base64-encode the shell script to avoid KubeSpawner _expand_all
treating shell braces as Python format string placeholders
- Reference existing home volume (volume-{username}) instead of adding
a duplicate PVC mount which causes RWO pods to hang
- Set HOME=/tmp so alpine/git can write .gitconfig without errors
- Validate repo URL against an allowed providers whitelist
- Exit 0 on any failure so spawn is never blocked
- Switch to alpine/git:2.47.2 with imagePullPolicy: IfNotPresent
Add optional Git repository URL input field to the React spawn UI.
- Add allowGitClone field to ResourceMetadata; only resources with this flag enabled show the git URL input (cpu resource enabled by default) - Move repo URL input above runtime selector in spawn UI - Add frontend URL validation using providers list from API (no hardcode) - Expose allowedGitProviders in /api/resources response - Backend double-checks allowGitClone before adding init container - Add dark mode styles and inline error state for repo URL input - Update values.schema.yaml and regenerate values.schema.json
- Add /hub/git/<provider/owner/repo> shortcut that validates the repo URL against allowed providers and redirects to the spawn page with repo_url pre-filled; supports ?autostart=1, ?resource=, ?accelerator= - Frontend reads repo_url/autostart/resource/accelerator query params, auto-selects matching resource, and auto-submits the form when autostart=1 - Validate initial repo_url and query params with user-visible warnings for unknown resource or accelerator keys
Add a GPU-accelerated resource profile using the default image, with 4 CPU / 16Gi memory / 1 AMD GPU, supporting strix-halo and dgpu accelerators; allow git clone and grant access to the official team.
- Show a "Git Repo" badge on resource cards that support git clone - Replace always-visible hint text with a hoverable question mark tooltip next to the Git Repository URL label - Add dark mode styles for badge and tooltip
- Extract clone script to core/scripts/git-clone.sh (pure shell, no Python string interpolation); pass REPO_URL/CLONE_DIR/MAX_CLONE_TIMEOUT as environment variables so the script is shellcheck-clean - Exit 1 on clone failure so Kubernetes marks the pod as Failed - Set restartPolicy=Never on user pods so a Failed init container does not enter CrashLoopBackOff - Add _monitor_pod_failure() coroutine that runs concurrently with super().start() and raises immediately when pod phase==Failed, avoiding the full start_timeout wait - Wire _hub_config and git clone settings in setup.py so allowGitClone and provider/timeout config are applied at spawn time
- Frontend normalizes URL on blur: adds https://, strips .git, extracts branch from /tree/<branch> path - Extracted branch shown as hint below input; sent as repo_branch form field - Backend mirrors normalization in _validate_and_sanitize_repo_url (defensive layer) - Branch name sanitized with allowlist regex before passing to init container - git-clone.sh: optional BRANCH env var, uses --branch on clone and fetch by ref
- Fix import sort order in kubernetes.py (I001) - Remove unused access_token variable in start() (F841) - Add 'raise ... from e' in handlers.py exception chain (B904)
Display value stays as typed; normalization (https prefix, .git strip, /tree/<branch> extraction) happens silently via hidden inputs. Validation still runs against the normalized form on every keystroke.
Frontend submits raw URL via name=repo_url; no hidden inputs needed. Backend extracts branch from /tree/<branch> path before sanitization, so both normalization and branch detection are fully server-side.
Without repo URL: generates /spawn?resource=...&accelerator=... With repo URL: generates /hub/git/...?resource=...&accelerator=...
- Only the group containing the pre-selected resource expands (once) - Other groups stay collapsed, respecting user manual collapse - Fallback to first resource when pre-selection fails (invalid resource key, no allowGitClone resource) to avoid all groups being collapsed
Cloned repositories are now ephemeral — they live in an emptyDir volume that is discarded when the session ends. This avoids accumulating stale repos on the user's persistent storage and gives a clean environment on each spawn. The shell script is simplified (no fetch/reset branch since the volume is always empty). Tooltip updated accordingly.
Clone repos directly onto home PVC and clean up via preStop lifecycle hook when session ends. Fix shareable URL regex to handle username in spawn path (e.g. /hub/spawn/admin).
…ch/aup-learning-cloud into feature/support-custom-spawner
… branch validation
e0831f0 to
1a394ff
Compare
…scroll container Add horizontal padding to .gpu-options-container so box-shadow on selected GPU option is not cut off by overflow. Co-authored-by: Cursor <cursoragent@cursor.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add support for users to optionally clone a Git repository when spawning a new session. The repository is cloned via an init container and automatically cleaned up when the session ends (ephemeral, not persisted between sessions).
Changes
Git Clone Backend (
runtime/hub/core/spawner/kubernetes.py)_validate_and_sanitize_repo_url()with URL normalization (prepend https://, strip/tree/<branch>, strip.git)_extract_repo_name()and_build_git_init_container()for init container constructionrepo_url,repo_branch,access_tokenfrom spawn formdefault_urlto open the cloned repo directory in JupyterLabALLOWED_GIT_PROVIDERS,MAX_CLONE_TIMEOUT,GIT_INIT_CONTAINER_IMAGEfrom values.yamlconfigure_from_config()Failedstatus from reflector cache_get_home_mount_path()(no hardcoded/home/jovyan)notebook_dirset to home mount path to ensure JupyterLab file browser matches clone targetGit Clone Script (
runtime/hub/core/scripts/git-clone.sh)git clone --depth 1with optional branch, respects timeoutGit Repo Validation (
runtime/hub/core/handlers.py)ValidateRepoHandlerat/hub/api/validate-repo— validates repo URL and optional branch viadulwich.porcelain.ls_remoterefs/heads/andrefs/tags/for branch existencerun_in_executordulwichadded torequirements.txtGitSpawnHandler (
runtime/hub/core/handlers.py)/hub/git/<provider/owner/repo>URL handler for direct repo spawning?autostart=1&resource=<key>&accelerator=<key>query paramsallowedGitProvidersin Resources API responseCUSTOM REPOandOTHERSpinned to bottomConfiguration (
runtime/hub/core/config.py,runtime/values.yaml,runtime/chart/values.schema.yaml)GitCloneSettingsmodel (initContainerImage,allowedProviders,maxCloneTimeout)allowGitCloneflag per resource metadatacustom.gitClonesection in values schemasetup.pydelegates toRemoteLabKubeSpawner.configure_from_config()ghcr.io/amdresearch/base-gfx1151:v0.1-fullSpawn UI (
runtime/hub/frontend/apps/spawn/)https://, extract branch from/tree/<branch>, strip.git/hub/git/link generation with resource and accelerator params?autostart=1)cpu,gpu) moved to dedicated CUSTOM REPO group (pinned to bottom)validateRepo()API function in@auplc/sharedpackageCleanup
resource_options_form.html(reverted to React bundle loader)Configuration
Git Clone Settings (
runtime/values.yaml)Per-Resource
allowGitCloneFlagTesting
/hub/git/github.com/owner/repoURL redirect?autostart=1auto-submit flow/tree/<branch>URLsChecklist