-
Notifications
You must be signed in to change notification settings - Fork 0
GitHub Clone & Import Pipelines
Two sibling core services handle GitHub repository acquisition. src/core/github-clone.ts is the desktop/main-process clone helper used through the github:clone IPC handler. src/core/github-import.ts is the Electron-free Server Edition import service used through the server's github:import RPC. Both consume a short-lived, credential-bearing clone URL minted by Termsprawl Cloud, validate it, shallow-clone with git clone --depth 1, guard the destination, and redact secret material from errors.
| Path | Responsibility | Key exports / behavior |
|---|---|---|
src/core/github-clone.ts |
Desktop twin of the import service. Clones a cloud-minted clone URL into a caller-provided absolute destination. |
cloneRepo, GitHubCloneDeps, CloneRequest, CloneResult
|
src/core/github-import.ts |
Server Edition import service. Validates owner/repo, asks the cloud for a one-shot clone URL, shallow-clones into destRoot/<repoName>, and lists repo suggestions. |
importGitHubRepo, listSuggestedRepos, GitHubImportDeps, ImportRequest, ImportResult, SuggestedRepo
|
src/core/github-clone.test.ts |
Unit coverage for the local clone helper with injected spawnFn. |
Happy path, URL refusal, destination guard, empty-dir allowance, redacted stderr |
src/core/github-import.test.ts |
Unit coverage for import and suggestion listing with injected fetchFn/spawnFn. |
No network or real git; token/URL leak assertions |
scripts/github-import-e2e.sh |
E2E proof for the Phase 17 GitHub import path. Boots a fake cloud plus a real ts-space container and drives the server RPC over WebSocket. |
github:suggest, github:import, workspace snapshot, credential-leak checks, re-import refusal |
- Termsprawl Cloud mints a short-lived bearer clone URL.
- The desktop main process invokes
cloneRepo(deps, { url, dest })via thegithub:cloneIPC handler. -
cloneRepovalidates the URL withisAllowedCloneUrl: onlyhttps:ongithub.com. - It refuses a non-empty existing destination; an existing empty directory is allowed because git tolerates it.
- It spawns
git clone --depth 1 <url> <dest>through the injectedspawnFnor defaultexecFile. - On failure, it redacts the URL from git stderr before throwing.
- It returns
{ path: dest, ok: true }; the URL and credential are never returned to the renderer.
- The server RPC
github:importcallsimportGitHubRepo(deps, { fullName, destRoot }). -
fullNamemust match the strictowner/reposhape and cannot contain traversal segments. - The destination is resolved as
join(destRoot, basename(fullName).replace(/\.git$/, '')); a non-empty existing destination is refused. - The service sends
POST /api/v1/github/import-urlwithAuthorization: Bearer <bootToken>and JSON{ fullName }. - A
404becomesgithub_not_connected; other non-OK responses use the clouderrorstring when present, otherwise a generic status message. - The returned
{ url }is validated with the same https/github.com allowlist before git runs. -
git clone --depth 1 <cloneUrl> <dest>runs through the injected/default spawn. - The result is
{ name, path, fullName }; the clone URL and boot token are not returned.
The E2E script asserts a boot broadcast named github:suggest. The core computation is listSuggestedRepos(deps, projectNames):
-
GET /api/v1/github/reposwith the boot token. - Normalize either a raw array or
{ repos: [...] }. - Drop repos whose names are already represented in
projectNames. - Also treat the last path segment of an existing project cwd or remote URL as taken, plus the suffix of any
clone_url. - Never throw: network errors, non-OK responses, malformed JSON, and non-array bodies all degrade to
[].
flowchart TD
Desktop["github:clone IPC handler"] --> Clone["cloneRepo"]
Clone --> V1["Validate https + github.com"]
V1 --> D1["Refuse non-empty dest"]
D1 --> G1["git clone --depth 1 url dest"]
G1 --> R1["Return path, ok true"]
Server["github:import RPC"] --> Import["importGitHubRepo"]
Import --> V2["Validate owner/repo fullName"]
V2 --> D2["Resolve destRoot/repoName; refuse non-empty"]
D2 --> Broker["POST /api/v1/github/import-url<br/>Bearer bootToken"]
Broker --> Cloud["Termsprawl Cloud"]
Cloud --> Mint["Mint short-lived bearer clone URL"]
Mint --> V3["Validate https + github.com"]
V3 --> G2["git clone --depth 1 url dest"]
G2 --> R2["Return name, path, fullName"]
Boot["Boot suggestion path"] --> Suggest["listSuggestedRepos"]
Suggest --> List["GET /api/v1/github/repos<br/>Bearer bootToken"]
List --> Filter["Filter against projectNames"]
Key nodes: both clone paths converge on the same allowlist and shallow-clone command, but only the server path brokers through /api/v1/github/import-url. The suggestion path is read-only and best-effort. Validation and destination guards always run before git is spawned.
| Shape | Meaning |
|---|---|
CloneRequest |
{ url, dest }; url carries the GitHub credential, dest is the absolute clone destination. |
CloneResult |
{ path, ok: true }; no URL or token. |
ImportRequest |
{ fullName, destRoot }; fullName is validated owner/repo. |
ImportResult |
{ name, path, fullName }; name is the last path segment minus .git. |
SuggestedRepo |
{ fullName, name, private, updatedAt }; safe metadata for UI suggestions. |
CloudRepo |
Internal snake_case cloud shape: full_name, clone_url, private, updated_at. |
GitHubCloneDeps |
Injectable spawnFn; default is execFile. |
GitHubImportDeps |
cloudApi, bootToken, injectable fetchFn, injectable spawnFn. |
-
URL allowlist: only
https:and hostnamegithub.comare accepted.http, other hosts, scp-style URLs,file://, and non-URL strings are refused before git runs. -
Credential redaction: invalid-URL errors expose only a parsed origin or empty string. Git failures replace the full URL with
<clone-url>in stderr. - Destination guard: a non-empty existing directory is refused. An existing empty directory is allowed.
-
Full-name validation:
FULL_NAME_REis^[\w.-]+\/[\w.-]+$with exactly one slash;.and..owner/repo segments are rejected. -
Cloud errors: import maps any
404togithub_not_connected; other non-OK responses usebody.erroronly when it is a string. -
Suggestion degradation:
listSuggestedReposnever throws; every failure mode returns[]. - Filtering: suggestions are filtered case-insensitively by project name, last segment of project paths/URLs, and clone URL suffix.
-
Duplication:
isAllowedCloneUrl,safeOrigin-style origin handling, anddefaultSpawnare duplicated between the desktop clone and server import modules; policy changes must be mirrored or extracted.
scripts/github-import-e2e.sh boots a fake cloud with /api/v1/github/repos and /api/v1/github/import-url, then starts a real ts-space container and drives the server's WebSocket bridge. The script's stated assertions are:
- Boot
github:suggestlists repos not yet on the canvas. -
github:importclones the repo for real, with git objects on the volume. - The imported project exists in the workspace with the clone as cwd.
- The credential never appears in container logs, the response, or
/data. - Re-import of the same repo is refused because the project cwd is already known.
The fake cloud returns repo listings as { repos: REPOS } and mints { url, expiresIn: 90 } from the import-url broker. The visible import-url response is an https://github.com/... URL, matching the strict allowlist that importGitHubRepo enforces. The drive script sends github:import, then requests workspace:snapshot after the import response.
- Inject
spawnFnin either core service to test without git or substitute a different process runner. - Inject
fetchFningithub-import.tsto test cloud behavior or replace the transport. - Configure
cloudApiandbootTokenthroughGitHubImportDepsfor Server Edition boot. - Update
IMPORT_URL_PATHandREPOS_PATHfor broker endpoint changes. - Extend
CloudReponormalization when the cloud response shape changes; the array/{ repos }handling is centralized inextractReposArray. - Adjust
isAllowedCloneUrlonly with awareness that the clone URL is a credential-bearing secret and currently restricted tohttps://github.com. - Keep auth header construction aligned:
importGitHubRepobuilds the Bearer header inline whilelistSuggestedReposusesauthHeaders().
Sources: src/core/github-clone.ts, src/core/github-import.ts, src/core/github-clone.test.ts, src/core/github-import.test.ts, scripts/github-import-e2e.sh.
Generated from termsprawl at 0d4393be54c6200beedd91bb636e5296c30472c5.
App Shell & Platform Foundations
- Electron Main Process & Window Lifecycle
- Preload Bridge & IPC Contract
- Shared Domain Types and File/URL Helpers
- Renderer Bootstrap & App Composition
- Build Targets & TypeScript Configuration
Canvas, Nodes & Renderer State
- Infinite Canvas Surface & Viewport Interaction
- Workspace, Project & Tab State
- Node Links, Edges & Link Inspector
- Sticky, Group, Editor & Diff Nodes
- Keyboard Canvas Navigation & Cross-Panel Requests
- Theme, Accent & Visual Language
- Boot Overlay, Onboarding & Shared UI Kit
Terminals & Session Continuity
- PTY Lifecycle & Terminal Sessions
- tmux Session Naming & Reattach
- Scrollback Snapshots & Cold Replay
- Terminal Node Rendering (xterm.js)
- SSH Remote Projects, Terminals & Files
Persistence, Projects & Files
- Workspace Store & Project File Layout
- Project Scope, Deletion & Worktree Registry
- Workspace Bundle Export/Import
- File Service & File Tree UI
Agent Runtime & Tooling
- Agent Status Model & Hook Normalization
- Hook Server & CLI Hook Installers
- Agent Launch, CLI Probing & Managed Accounts
- Agent Tool Protocol & In-Process Server
- Agent Tool Client, CLI & MCP Entry
- Transcripts, Context Discovery & Context CLI
- Agent Canvas State & Status Badges
Chat Nodes & Model Providers
- Chat Runtime, Conversation & Cost
- Model Provider Adapters & Streaming
- Chat Tool Calling & Project Tools
- Chat Node UI
Git & Source Control
Embedded Browser Nodes
- Browser Manager & Guest Runtime
- CDP Facade & Browser Agent Server
- Browser Navigation Policy & Node UI
Server Edition
- Server Bootstrap & HTTP/WebSocket Entry
- RPC Dispatch, Handlers & Service Bridges
- Renderer Shim & Server Boundary
- Server Auth & Security Boundary
Relay & Remote Access
- Relay Hub & WebSocket Frame Routing
- Relay End-to-End Cryptography
- Relay Auth, Invites, Store & Admin API
- Relay Client, Pairing & Terminal Tunneling
- Relay Trust UI
Integrations & Secondary Surfaces
- Telegram Bot, Commands & Pairing
- A2A Peers: Protocol, Client & Server
- Node Link Engine, Registry & Scheduler
- Cloud Spaces, Snapshots & Sync
Settings, Updates & Maintenance