You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a running compose project's working_dir is a git checkout DockGate did NOT
deploy (user SSH'd in, git-cloned, and ran docker compose by hand), the detail
modal now shows a 'Git (detected)' card with ⤓ Pull / ↻ Redeploy.
Strictly non-destructive: runs PLAIN git in the user's own checkout (their own
remote + creds — no token/key injection) and is FAST-FORWARD ONLY (fetch +
merge --ff-only). Never reset --hard / clean. Refuses (changes nothing) on a
dirty tree, detached HEAD, no upstream, or non-fast-forward. Redeploy runs
docker compose -p <project> -f <configFile> up -d --build in the working dir
(no --force-recreate by default).
Works for the active server, local or remote SSH (git + compose over the same
channel). Detection is lazy (detail-modal only, 90s cache) — zero git/SSH work
in the list. DockGate-managed projects excluded. Untrusted labels validated
(isSafeHostPath) + shq-quoted; git via git -C resolved by rev-parse --show-toplevel.
New: GET /:project/git-detect, POST /:project/adopt-pull, POST /:project/adopt-redeploy
(reuse execRemote/shq, runCompose/runComposeInRemoteDir, deployJobs/openDeployLog).
Verified e2e (local): detect → ff pull → redeploy → dirty-refused(409) → non-git
& managed excluded. Remote command construction + injection-rejection verified.
- Until now the git badge + **⤓ Pull** / **↻ Redeploy** only appeared for projects deployed *through* DockGate. If you'd SSH'd into your server, `git clone`d a repo yourself, and run `docker compose up` by hand, DockGate listed the project but offered no git actions. Now it **detects** that case: when you open a project's detail and its working directory is a git checkout DockGate doesn't manage, a **"Git (detected)"** card appears with **⤓ Pull** and **↻ Redeploy**.
9
+
-**Strictly non-destructive.** Pull runs **plain `git` in your own checkout** (your already-configured remote + credentials — DockGate injects no token, overrides no SSH key) and is **fast-forward only** (`fetch` + `merge --ff-only`). It **never** runs `reset --hard` or `clean`, so it can't overwrite your files. If the working tree has uncommitted changes, is on a detached HEAD, has no upstream, or isn't a clean fast-forward, it **refuses and changes nothing**, telling you why. Redeploy then runs `docker compose -p <project> -f <configFile> up -d --build` in the working dir (one-shot/stateful services are **not** force-recreated).
10
+
- Works for the **active server** — local Docker **or** a remote SSH host (git + compose run over the same SSH channel). Detection is **lazy** (only when the detail modal opens, 90s-cached) so the project list does zero git/SSH work. DockGate-managed projects are excluded (no double-handling).
11
+
-**Security:** Docker `working_dir`/`config_files` labels are treated as untrusted — every path is validated (absolute, no `..`, no newline/NUL, strict charset) and shq-quoted before reaching a shell; git runs via `git -C <dir>` resolved through `rev-parse --show-toplevel`.
12
+
- Verified e2e (local) against a real external checkout with an upstream: detect → fast-forward pull (files updated in place) → redeploy (`up -d --build`, container recreated) → **dirty tree refused (409, files untouched)** → non-git and DockGate-managed projects correctly offer nothing. Remote SSH path's command construction + injection-rejection verified separately.
13
+
14
+
---
15
+
5
16
## [2.1.24] - 2026-06-27
6
17
7
18
### Added — Project Terminal: resizable (Normal / Large / Full screen)
<button class="btn btn-sm btn-secondary" id="xg-pull" title="Fast-forward this checkout from its own git remote — does not deploy">⤓ Pull</button>
206
+
<button class="btn btn-sm btn-primary" id="xg-redeploy" title="Pull (fast-forward), then docker compose up -d --build">↻ Redeploy…</button>
207
+
</div>
208
+
</div>
209
+
<div class="text-xs text-muted" style="margin-top:6px">DockGate didn't deploy this — it's your own git checkout ${where} (<code>${escapeHtml(d.repoRoot)}</code>). Pull is <strong>fast-forward only</strong> and never resets your files.${d.canPull ? '' : ` <span style="color:var(--warning)">⚠ ${escapeHtml(d.reason||'Pull unavailable')}.</span>`}</div>`;
0 commit comments