53151dfd4285e9280623ffb991e2904eac2b7d94
12
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
53151dfd42 |
Gateway upgrade: review round 8 fixes
Secret Scan / scan (push) Successful in 7s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Build App (Preview) / test (pull_request) Successful in 4m36s
Secret Scan / scan (pull_request) Successful in 7s
Build App (Preview) / create-release (pull_request) Successful in 4s
Build App (Preview) / build-macos (pull_request) Successful in 3m14s
Build App (Preview) / build-linux (pull_request) Successful in 9m29s
Build App (Preview) / build-windows (pull_request) Successful in 6m51s
Build App (Preview) / prune-previews (pull_request) Successful in 1s
- A failed lookup of the preferred local build is "unknown", not "use the registry image", so a transient error can't swap a working local-build gateway onto the upstream image. - One image predicate (`image_switch_pending`) behind both `needs_recreate` and status `image_outdated`, so they agree, including for a container whose image id is unknown. - A failed tag after a successful digest pull is logged, not reported as a failed pull. - Keep Dockerfile parser directives (`# syntax=` etc.) in the build-context hash; hash config.yaml whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
7077d36f54 |
Gateway upgrade: config-only fingerprint, tag digest pulls, drop cleanup
Secret Scan / scan (push) Successful in 10s
Build App (Preview) / compute-version (pull_request) Successful in 9s
Secret Scan / scan (pull_request) Successful in 10s
Build App (Preview) / create-release (pull_request) Successful in 2s
Build App (Preview) / build-macos (pull_request) Successful in 3m13s
Build App (Preview) / test (pull_request) Successful in 6m6s
Build App (Preview) / build-windows (pull_request) Successful in 6m46s
Build App (Preview) / build-linux (pull_request) Successful in 9m25s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Review round 7: - Keep the fingerprint in its earlier format (config + secret version) so the app update alone recreates no gateway; image changes go through one `needs_recreate` rule (pinned image present and container on another image), which the status `image_outdated` mirrors. - Tag the image after a digest pull so `docker image prune` doesn't treat it as dangling; lookups still go by digest. - Drop superseded-build cleanup: `reference=` is daemon-wide, so it could delete another installed app's build, and the version parsing didn't cope with suffixed LiteLLM tags. - Derive the lockstep test's `repo:tag` from the repo/version constants; correct the `image_outdated` docs for the no-pinned-image case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
b2cae374f9 |
Gateway upgrade: review round 6 fixes
Secret Scan / scan (push) Successful in 5s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 5s
Build App (Preview) / create-release (pull_request) Successful in 4s
Build App (Preview) / build-macos (pull_request) Successful in 3m15s
Build App (Preview) / test (pull_request) Successful in 4m10s
Build App (Preview) / build-windows (pull_request) Successful in 6m50s
Build App (Preview) / build-linux (pull_request) Successful in 8m3s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
- Hash only significant lines of the build context, so a comment edit in a later release doesn't mark every local build outdated. - A failed image lookup no longer fails ensure for a gateway that is fine: it takes the keep-current-image path. - Recreates stop with Docker's default grace again, as before; the 3s grace stays for app exit. - Cleanup keeps every build of the current pin (a stable and a preview app no longer delete each other's), removing only `latest` and older pins; parse locally instead of depending on the commands layer. - GatewayContainer struct instead of a 4-tuple; separate repo/version constants; cache the local tag; fix the outdated-check doc. - UI says "gateway image update available" rather than claiming a LiteLLM update. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2ea5bba830 |
Gateway upgrade: drop auto-pull, pull by digest, content-tag local builds
Secret Scan / scan (push) Successful in 6s
Build App (Preview) / compute-version (pull_request) Successful in 6s
Secret Scan / scan (pull_request) Successful in 5s
Build App (Preview) / create-release (pull_request) Successful in 3s
Build App (Preview) / build-macos (pull_request) Successful in 3m14s
Build App (Preview) / test (pull_request) Successful in 5m38s
Build App (Preview) / build-linux (pull_request) Successful in 5m45s
Build App (Preview) / build-windows (pull_request) Successful in 6m48s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Per the decision to drop the automatic pull and keep an outdated gateway running (flagged) when the new image is absent: - Remove the launch-time pull; lib.rs is unchanged from main. Updating is Pull or Build, then Stop/Start (or the next launch). - Pull and look up the registry image by the pinned digest (the same one the Dockerfile's FROM uses, enforced by test), not the mutable tag. image::pull_image now handles digest references. - Local builds are tagged `<pin>-<hash of Dockerfile+config>`, so a changed build context also stops an old build from winning. - A failed lookup of one image no longer hides the other. - Superseded-build cleanup runs off the lock, never forces, and also drops earlier builds of the current pin; recreate stops with the same grace as Stop; reuse update_commands::parse_semver. - Settings: a stopped outdated gateway without a new image says so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1ef5220961 |
Gateway upgrade: start before pulling, graceful recreate, safer cleanup
Secret Scan / scan (push) Successful in 5s
Build App (Preview) / compute-version (pull_request) Successful in 4s
Build App (Preview) / create-release (pull_request) Successful in 3s
Secret Scan / scan (pull_request) Successful in 11s
Build App (Preview) / build-macos (pull_request) Successful in 3m15s
Build App (Preview) / test (pull_request) Successful in 5m39s
Build App (Preview) / build-linux (pull_request) Successful in 5m36s
Build App (Preview) / build-windows (pull_request) Successful in 6m46s
Build App (Preview) / prune-previews (pull_request) Successful in 2s
Fourth-review follow-ups: - Autostart starts the gateway on whatever image it has first, then pulls the new pin (only if the gateway is configured) and moves it over, so the gateway isn't down for the download; a first start with no image at all still gets the pull. - Recreates stop the container gracefully before removing it again, so in-flight requests can drain. - `image_outdated` now means exactly "ensure would recreate it", so status and the fingerprint can't disagree; the label says "new gateway image ready" rather than claiming a LiteLLM update. - Cleanup removes only `latest` and builds for older pins, never a newer pin or a custom tag. - Settings: Start is offered for a stopped container even without a pinned image (it restarts on its own image); outdated no longer uses the "starting" tone. Concurrent lookups via join. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
1ef4505a69 |
Gateway upgrade: pull only at launch, never tear down a working gateway
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (push) Successful in 7s
Secret Scan / scan (pull_request) Successful in 5s
Build App (Preview) / create-release (pull_request) Successful in 2s
Build App (Preview) / build-macos (pull_request) Successful in 3m14s
Build App (Preview) / test (pull_request) Successful in 5m34s
Build App (Preview) / build-linux (pull_request) Successful in 5m45s
Build App (Preview) / build-windows (pull_request) Successful in 6m56s
Build App (Preview) / prune-previews (pull_request) Successful in 6s
Third-review follow-ups: - The pinned image is pulled in the background at app launch only, not inside every ensure, so Start and settings saves never stall on a download. - With no pinned image present, ensure keeps the gateway on the image it already runs (recreated with new config if that changed) instead of removing it; status reports it as outdated. - The container is created from the resolved image id, so a concurrent build/pull retag can't make it disagree with its fingerprint. - "Outdated" means the container runs neither pinned image, so a later local build of the same pin doesn't flag a registry-image gateway. - After starting on the pin, superseded triple-c-gateway:* tags (the old floating `latest`, earlier pins) are removed so they don't linger. - Reuse container::remove_container (404-tolerant); fix misplaced docs. - Settings: Start needs an image again (no silent pull); the outdated label says whether to Pull/Build or to Stop and Start. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
03c77c5f55 |
Gateway upgrade: tag local builds with the pin; pull outside the lock
Build App (Preview) / compute-version (pull_request) Successful in 8s
Secret Scan / scan (push) Successful in 12s
Secret Scan / scan (pull_request) Successful in 9s
Build App (Preview) / create-release (pull_request) Successful in 1s
Build App (Preview) / test (pull_request) Successful in 4m18s
Build App (Preview) / build-macos (pull_request) Successful in 3m15s
Build App (Preview) / build-windows (pull_request) Successful in 6m51s
Build App (Preview) / build-linux (pull_request) Successful in 9m31s
Build App (Preview) / prune-previews (pull_request) Successful in 3s
Second-review follow-ups, replacing the label + probe approach: - Local builds are tagged `triple-c-gateway:<pin>` instead of `latest`, so a build for an older pin simply doesn't match. Drops the version label, the probe container, its cache and version normalisation — and with them the case where a failed probe made a current build look stale. - The pinned image is pulled before taking the gateway lock, so a long pull no longer blocks Stop, shutdown or settings saves; skipped when the start would fail on configuration anyway. - If no pinned image is available, the old container is removed and the error keeps the pull failure, reporting a removal failure alongside it. - Status gains `image_outdated` (container image id != pinned image id). Settings uses it for the label, keeps Stop for any running gateway, and always offers Start, since Start pulls the image. - Reuse `migration::image_id` and one container-removal helper. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
00b504063f |
Gateway upgrade: auto-pull, never leave a stale gateway, probe old builds
Secret Scan / scan (push) Successful in 5s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 5s
Build App (Preview) / create-release (pull_request) Successful in 2s
Build App (Preview) / build-macos (pull_request) Successful in 3m13s
Build App (Preview) / test (pull_request) Successful in 4m12s
Build App (Preview) / build-windows (pull_request) Successful in 6m45s
Build App (Preview) / build-linux (pull_request) Successful in 7m57s
Build App (Preview) / prune-previews (pull_request) Successful in 3s
Review follow-ups: - When no usable image is present, pull the pinned image instead of failing. If the pull fails, stop and remove the existing gateway rather than leave an old LiteLLM (and, after a settings change or key rotation, an old config and old keys) serving. - A local build without the version label is probed for its LiteLLM version (cached by image id) instead of being treated as stale. - An engine that reports no image id still gets a fingerprint component that changes on rebuild/re-pull. - Inspect the two candidate images concurrently; log the ignored-build line at debug. - Settings shows a running gateway, and its Stop button, even when its image is no longer the pinned one. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
9d2e5734b6 |
Move existing gateways onto the pinned LiteLLM after an app update
Secret Scan / scan (push) Successful in 5s
Build App (Preview) / compute-version (pull_request) Successful in 5s
Secret Scan / scan (pull_request) Successful in 4s
Build App (Preview) / create-release (pull_request) Successful in 3s
Build App (Preview) / build-macos (pull_request) Successful in 3m15s
Build App (Preview) / test (pull_request) Successful in 4m4s
Build App (Preview) / build-windows (pull_request) Successful in 6m49s
Build App (Preview) / build-linux (pull_request) Successful in 8m10s
Build App (Preview) / prune-previews (pull_request) Successful in 3s
An app update that bumps the LiteLLM pin left existing gateways on the old version: the container fingerprint covered only config and secrets, so the old container kept matching, and a local `triple-c-gateway:latest` from an earlier app version always won over the new pinned image. - Resolve the gateway image once, and put its image id in the container fingerprint so a newly pulled or rebuilt image recreates the container. - Label local builds with the pinned LiteLLM version and ignore a local build whose label doesn't match (older or unlabelled builds), falling back to the pinned upstream image; status reports no usable image so the UI offers a pull/build. - Test that the gateway Dockerfile's FROM stays in lockstep with the pin, since the build label relies on it. Every gateway is recreated once on its next start after this ships. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
e223a3f64b |
Security updates + terminal URL, /tmp file-link and copy fixes (#68)
Build App / compute-version (push) Successful in 22s
Secret Scan / scan (push) Successful in 8s
Build App / build-macos (push) Successful in 3m14s
Build STT Container / build-stt-container (push) Successful in 4m12s
Build App / build-windows (push) Successful in 7m23s
Build App / build-linux (push) Successful in 7m29s
Build App / create-tag (push) Successful in 10s
Build App / sync-to-github (push) Successful in 10s
Build Container / build-container (push) Successful in 18m41s
npm/cargo/LiteLLM/STT/sandbox security updates; URL trailing punctuation, hard-wrapped /tmp file links, UTF-8 OSC 52 and copy cleanup; CI fixes for AppImage permissions, STT gha cache and needrestart. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> |
||
|
|
2de00b3c55 |
Fix review findings: secrets in snapshots, URL spoofing, migration data loss
Adversarial review of the branch produced findings across four areas. This addresses them, plus the Windows CI environment. Secrets. commit_container_snapshot baked the container's full env into the per-project snapshot image, so the shared OAuth token — and the AWS keys, git token and gateway master key — outlived revocation and were readable via docker inspect. Verified against Engine 29.6 that a commit body's config merges over the container's: keys cannot be dropped but can be overwritten, so all of them now commit as KEY=. clear_claude_token additionally rewrites images from earlier builds and reports honestly when a tag could not be rewritten. The recommendation to move the token out of env entirely was not taken, with reasoning: apiKeyHelper is a different auth method that outranks CLAUDE_CODE_OAUTH_TOKEN rather than a transport for it, and no file-based delivery exists. The durable exposure — the image — is what is closed here. Separately noted, not fixed: entrypoint.sh captures the token into the scheduler's .env inside the persisted volume. URL spoofing. Three call sites reached openUrl with container-controlled strings, one of which the review missed (the WebLinksAddon handler). The sign-in URL was scraped from container output with a longest-match tie-break and no userinfo check, so claude.ai@evil.tld rendered as "claude.ai…" in a truncating element. There is now one sanitizer in front of every sink — scheme allowlist, no userinfo, C0/C1 and quote rejection, host allowlist for the sign-in case, first-match — and the origin renders un-truncated. The toast is keyed so a changed URL remounts, closing a bait-and-switch where the user read one URL and clicked another. Migration. The rollback pin was best-effort: a tag failure was logged and the migration continued past remove_container, after which the final commit overwrote the only copy of the old system layer. It now aborts before anything destructive and reads the tag back. /var was destroyed while the ordinary recreate path preserves it — making the "safe" alternative to Reset more destructive than Reset's alternative; data-bearing subtrees are now detected and disclosed in the pre-flight rather than copied, since tarring a live database onto a different base's packages is a corruption risk. resume_migration now verifies the migration-state label instead of reporting success for a container that never swapped. dismiss actually resolves the record rather than leaving the feature permanently refusing to migrate. Start and Reset are guarded while a migration is live. Lifecycle. The gateway no longer publishes on 0.0.0.0 — bind address and advertised URL are derived together so they cannot drift. Disabling it now stops it. App exit runs teardown concurrently under a budget with a visible shutting-down state instead of blocking for minutes. Auto-starts retry when Docker is not up yet, and the polling-recovery path now reconciles, so interrupted migrations are still recovered. Auth-bridge forwards are capped, closing a container-driven fd exhaustion. Windows CI. build-windows failed on this branch with "linker link.exe not found". The runner had no MSVC build tools and the workflow assumed a hand-provisioned machine, so a bare runner registers, accepts jobs and fails at link time after downloading the whole crate graph. The job now installs the VC++ workload when vswhere cannot find it, matching how it already conditionally installs Rust and Node. 192 Rust tests, 274 frontend tests, both builds clean, zero warnings. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
|
|
cc5f691677 |
Add llama.cpp backend, model gateway, URL relay and browser view
Four features, plus a latent bug fix.
llama.cpp backend. Claude Code only ever speaks the Anthropic Messages
API — confirmed empirically by pointing it at a logging server, which
received POST /v1/messages?beta=true. llama-server implements that
natively (verified in its README, alongside --port default 8080), so
this is a plain base-URL backend with no translation shim, the same
shape as Ollama. Its --api-key defaults to none, so the auth token is a
placeholder Claude Code requires and llama-server ignores.
Model alias fix. ANTHROPIC_DEFAULT_HAIKU_MODEL is documented as "also
used for background functionality", and Triple-C set none of the alias
vars. So on every custom-endpoint backend, Claude Code resolved `haiku`
to an Anthropic model id and sent it to a local server that does not
have it — background features failed silently. All four
ANTHROPIC_DEFAULT_{OPUS,SONNET,HAIKU,FABLE}_MODEL vars are now pinned to
the backend's configured model, with an optional Haiku override, and
blanked for Anthropic and Bedrock so those keep Claude Code's defaults.
The deprecated ANTHROPIC_SMALL_FAST_MODEL is never emitted. Existing
Ollama and OpenAI-Compatible containers are recreated once so the new
env reaches them; the snapshot is preserved.
Model gateway. Optional LiteLLM sibling container, off by default,
mirroring stt.rs — this is what makes real OpenAI usable, since
api.openai.com has no /v1/messages. Pinned to v1.96.0 by tag and digest:
the 1.82.7/1.82.8 malware was PyPI-only and never affected the official
images, which is precisely why this builds FROM the image rather than
pip-installing, but 1.84.0 is still the floor for proxy CVEs (API-key
SQLi, Host-header auth bypass, MCP auth bypass). Binds 0.0.0.0 because
project containers consume it, and therefore always sets a master_key —
LiteLLM without one accepts any key. The provider key lives in the OS
keychain and is uploaded into a volume, never an image layer or label.
URL relay. A container-side xdg-open/BROWSER shim opens URLs in the
host's browser. Uses an OSC sequence to /dev/tty rather than a printed
sentinel, because the shim usually runs as a grandchild of a process
capturing its children's output. Degrades to printing the URL when no
terminal is attached, so scheduled tasks do not hang. Only http/https,
with control characters rejected before new URL() — which strips
newlines, so java\nscript: would otherwise parse as javascript:. Nothing
auto-opens; the user confirms. The web terminal shows a tap-to-open
banner instead, since that browser may be a phone across a tunnel.
Browser view. A Project Home tab that watches and takes over the browser
Claude drives with Playwright, using Playwright's own dashboard. Zero
image cost — Playwright stays user-installed. It does not reuse the auth
bridge's PortForward, which binds an unauthenticated port: correct for a
throwaway OAuth listener, wrong for mouse and keyboard control of a
browser in a passwordless-sudo container. Instead a token-gated loopback
proxy checks Host, then token or a forbidden-header origin signal,
before a byte reaches the container. Host ports are confined to
47820..=47827 so CSP frame-src can enumerate them rather than widening
to a wildcard, with a test asserting the two agree.
188 frontend tests, 107 Rust tests, both builds clean.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|