Commit Graph

287 Commits

Author SHA1 Message Date
ship-bot
7c1c739555 chore: bump tower + tower-ui to 0.66.18
- ProjectsView: super-admin All-tenants mode now fans out across tenants
  (was falling back to platform tenant → empty Projects page)
- waitForJobTerminal: pod log tail spliced into job-failed errors
  (export, import, backup, restore — visibility into REAL cause)
- runSpawnEnv: register env BEFORE seed (was after) so a failed seed
  leaves a registered-but-empty env instead of a ghost instance
2026-05-02 14:22:08 +02:00
ship-bot
fea8246562 chore: bump tower-ui to 0.66.17 — unify tenant context (single source of truth across UI) 2026-05-02 14:03:11 +02:00
OdooSky Tower
e6afb17097 Bump tower to 0.66.16 — strict tenant isolation in /api/servers (#341) 2026-05-02 13:34:18 +02:00
OdooSky Tower
bb4edab194 Bump tower to 0.66.15 — DELETE /api/addons/{code} (full unpublish: tags + branch source) + ModuleDetailDrawer danger zone 2026-05-02 13:12:41 +02:00
OdooSky Tower
aee85dd453 Bump tower to 0.66.14 — fix manifest rewrite (#336) + slog visibility (#338) + addon delete button (UX) 2026-05-02 13:00:06 +02:00
OdooSky Tower
62455dbaf6 Bump tower to 0.66.13 — spawn-env confirm dialog (#333) + Promote disabled when in-sync (#334) 2026-05-02 11:58:16 +02:00
OdooSky Tower
7150de473c Bump tower to 0.66.12 — orphan project env sweep + RemoveProjectEnv writer (#321) 2026-05-02 11:47:54 +02:00
OdooSky Tower
ad2997a68c Bump tower to 0.66.11 — Domain Picker UI + smart deploy ETA + GET /api/tenants/{id}/cloudflare/zones 2026-05-02 11:40:05 +02:00
OdooSky Tower
681a572c06 Bump tower to 0.66.10 — close anonymous list-instance leak (fail-closed tenantFilter + requireAuth gates) 2026-05-02 11:30:38 +02:00
OdooSky Tower
07a178e0fc Bump tower image to 0.66.9 — CF/S3 token rotation propagates to all owned cluster Secrets (#330) 2026-05-02 11:00:12 +02:00
Tower deploy
388688bf71 feat: per-host TLS for non-wildcard instance domains — tower 0.66.8 + chart change 2026-05-02 10:11:32 +02:00
Tower deploy
0dbdcc4d59 fix: op actor can always see their own op (cross-tenant scope) — tower 0.66.7 2026-05-02 09:54:00 +02:00
Tower deploy
abbee48aad feat: addon publish is async (op + poll, no Traefik timeout) — tower 0.66.6 2026-05-02 09:34:11 +02:00
Tower deploy
98eca0184a feat: bulk Overwrite-all button in conflict wizard — tower-ui 0.66.5 2026-05-02 09:19:43 +02:00
Tower deploy
cb13cd3e33 fix: backfill handles canonical-already-exists case (delete orphan short tag) — tower 0.66.4 2026-05-02 09:16:05 +02:00
Tower deploy
80625e3123 perf: addon publish uses Gitea ChangeFiles batch (1 commit per addon, ~20x speedup) — tower 0.66.3 2026-05-02 09:10:15 +02:00
Tower deploy
20ece132a9 feat: bulk Odoo-major setter for multi-addon zips — tower-ui 0.66.2 2026-05-02 08:42:35 +02:00
Tower deploy
6376dc9357 feat: marketplace backfill admin endpoint — tower 0.66.1 2026-05-02 08:40:22 +02:00
Tower deploy
c2e39736a5 feat: addon upload wizard with operator-driven Odoo major picker + OCA-shape rewrite — tower 0.66.0 2026-05-02 08:31:08 +02:00
Tower deploy
5da802fe8d fix: catalog falls back to branch probe when version-derivation produces non-Odoo-major — tower 0.65.8 2026-05-02 08:15:11 +02:00
Tower deploy
57119556cb fix: ProjectsView uses tenant filter + super-admin fan-out — tower-ui 0.65.7 2026-05-02 08:06:33 +02:00
Tower deploy
443e69aac5 fix: Projects back in Admin sidebar for super-admin — tower-ui 0.65.6 2026-05-02 08:02:39 +02:00
Tower deploy
f0385dbc49 fix: hide tenant pill from non-super-admins — tower-ui 0.65.5 2026-05-02 07:48:41 +02:00
Tower deploy
b851071fc2 fix: spawn-env inherits source server URL + flat domain pattern — tower 0.65.4 2026-05-02 07:37:48 +02:00
Tower deploy
82424c2687 fix: spawn-env no-redirect + sticky tenant filter — tower-ui 0.65.3 2026-05-02 07:30:11 +02:00
Tower deploy
ece9a26bd7 fix: applicationExists treat 403 as missing — tower 0.65.2 2026-05-02 07:23:30 +02:00
Tower deploy
370b98e7fc fix: spawn-env stray 400 from projectEndpointAuth — bump tower 0.65.1 2026-05-02 07:19:14 +02:00
Tower deploy
57e15b25dd F-undo: tower 0.65.0 + tower-ui 0.65.0 (Instances primary + tenant pinning + spawn-env from instance card) 2026-05-02 07:11:21 +02:00
3c3f921854 ship 0.64.5 — resolve addon Odoo major from Gitea branch (fixes odoo:1.0 build error) 2026-05-02 04:48:38 +00:00
c625d9c29e ship 0.64.4 — derive Odoo major from filename when manifest version is short 2026-05-01 14:18:18 +00:00
820832a634 ship 0.64.3 — multi-addon zip + upload progress bar 2026-05-01 14:13:22 +00:00
8e0057b967 ship 0.64.2 — hide platform server from /servers (tower itself, not a deploy target) 2026-05-01 13:11:17 +00:00
dcfad63247 ship 0.64.1 — fix /instances → /projects links across views 2026-05-01 07:55:18 +00:00
89b80bca2d ship 0.64.0 — Phase F2 (Add Env buttons + sidebar reorder + Deploy Odoo CTA) 2026-05-01 07:48:37 +00:00
e8990f7f65 ship 0.63.2 — fix promotable null + bump frontend 2026-05-01 07:38:09 +00:00
183df42f1d ship 0.63.1 — Phase F1 fix: sweep reads actual env kind 2026-05-01 07:33:07 +00:00
baf04829a1 ship 0.63.0 — Phase F1 (Project as identity unit + spawn-env + sweep) 2026-05-01 07:28:52 +00:00
4d5aa41a91 ship 0.62.1 backend — pin k3s v1.34.6+k3s1 in bootstrap.sh (1.35.4 cloud-controller race) 2026-04-30 19:21:35 +00:00
6aabb11fff ship 0.62.0 — Phase E (Projects: dev/stage/prod + Promote ↑ + Refresh ↓ + Drift) 2026-04-30 18:38:47 +00:00
Claude
5f569ae2e0 tower-ui 0.61.25 — bell + activity follow the tenant filter
Backend SSE handler already accepts ?tenantId= as an additive filter
on top of canSeeOp (Phase G stays load-bearing); frontend now passes
the global tenant filter chip's value through both NotificationBell
and ActivityTab. Watcher clears + restarts the stream when the
super-admin switches tenant context. Dismissed Set is user-level
and survives the switch.
2026-04-30 18:38:59 +03:00
Claude
b5a3a3029b tower-ui 0.61.24 — bell dismiss + completion toasts
#2 Dismiss / Clear failed:
  - Per-row [×] (text 'Dismiss', shown on hover) on terminal ops
  - 'Clear' button in dropdown header when any dismissable rows exist
  - Dismissed IDs persisted to localStorage (tower_dismissed_ops)
  - Pruned during the 30s sweep when the underlying op falls out
    of the recent window — keeps storage from growing forever
  - badgeCount + failedCount filter dismissed entries so the red
    pill clears the moment the operator acks the failure

#4 Toast popups:
  - useToast composable + Toaster.vue mounted at App.vue
  - Triggered from NotificationBell.upsert on terminal transition
    when the op was running ≥30s AND the bell isn't open
  - Success: 5s auto-dismiss; Failure: sticky until clicked away
  - Click-through links to the per-instance Activity timeline
    (#op_<id>) for any op carrying instanceCode
  - Stack of 3, oldest drops on overflow
  - No external dep — hand-rolled to match v3's component style
2026-04-30 18:25:45 +03:00
Claude
6b7743ecaf tower 0.61.23 / tower-ui 0.61.23 — SSE auth via ?token=
NotificationBell + ActivityTab opened EventSource without auth
(native EventSource API can't set Authorization headers). Phase G's
canSeeOp guard correctly dropped every event for the resulting
anonymous viewer, leaving the bell silent except for the one-shot
backfill on mount.

Backend: claimsFromRequest now falls back to ?token= query param
when the Authorization header is absent. HTTPS-only ingress means
the token stays inside the TLS tunnel; the 15-min access-token TTL
bounds any leakage if it ever surfaces in browser history or proxy
logs.

Frontend: streamOperation + streamAllOperations append the access
token via streamURL(). Plus token-expiry-aware reconnect: on
EventSource error, debounce 5s, close, run authFetch('/me') to let
the 0.61.18 refresh path renew the access token, then re-open with
a fresh streamURL. Without this, the native auto-reconnect would
loop forever with the now-stale token after 15 min.
2026-04-30 18:15:11 +03:00
Claude
b96204312f tower 0.61.22 — import filestore-rename: head -1 + debug echo
The grep -oE for instanceCode matches BOTH provenance.instanceCode
AND the v2 root mirror, returning two lines. sed processes each line
but the resulting SOURCE_CODE shell variable was multi-line, which
made the directory check fail (-d "/var/lib/odoo/filestore/odoo16
[newline]odoo16") → rename branch silently skipped → Odoo with
db_name=odoo16v2 looks at /var/lib/odoo/filestore/odoo16v2/, finds
nothing, returns 500 on every asset.

Added head -1 to the pipe so SOURCE_CODE is single-line, plus an
echo so the rename branch's path is visible in Job logs even when
it short-circuits.
2026-04-30 17:43:37 +03:00
Claude
8024015b9e tower 0.61.21 — migrate + template-deploy use tenant CF resolver
Phase C made instance-create tenant-aware for Cloudflare DNS, but
migrate.go and templates_deploy.go kept using the legacy global
*cloudflareClient (zone=odoosky.org). Result: a tenant migrate to
4th.online silently created the A record under odoosky.org as a
literal subdomain ('odoo16v2.tenants.4th.online.odoosky.org' →
right IP) — Tower logged 'DNS A record set' successfully because
the API accepted the call, but the actual hostname the user
browses to was never published to the right zone.

Both flows now use cfResolver.clientFor(tenantID, fqdn) to find
the tenant's CF token + correct zone. If no token covers the
domain, the op fails with a clear 'configure tenant CF token'
message instead of silently writing to the wrong zone.
2026-04-30 17:31:44 +03:00
Claude
9ad0ce9f1f tower-ui 0.61.20 — Migrate picker hides platform server
MigrateDrawer hardcoded '<option value="">Platform server (default)</option>' as
the first picker entry, regardless of tenant scope. A tenant operator
saw it as a selectable default — and selecting it (or just leaving
the default empty) sent the migrate to the platform cluster, which
the operator has no business deploying to.

Now: removed the hardcoded option. Auto-pick the first deployable
non-platform server on load (matches DeployInstanceDrawer pattern).
Picker shows 'Pick a server…' as a disabled placeholder when nothing
is selected.
2026-04-30 17:17:35 +03:00
Claude
52f7030c8f tower 0.61.19 / tower-ui 0.61.19 — tenant-scoped S3 in export+import Jobs
The export Job was using a stale platform Secret (s3-backup-creds)
and hardcoded bucket/endpoint, so bundles landed in odoosky-v3-backups
while Tower's verify (tenant-scoped after Phase F) read from the
tenant's bucket. Result: 'bundle missing from S3 after job
succeeded' even though the upload itself worked.

Same bug existed in import. Both fixed: keys+region+endpoint+bucket
now come from Tower's resolver view of the tenant, passed directly
into the Job env.

Plus: BackupsView crashed on r.backups.runs.length when runs is
null. Added the missing null guard.
2026-04-30 16:42:33 +03:00
Claude
66b9c60c68 tower-ui 0.61.18 — refresh-and-retry on 401
Frontend authFetch was bouncing every 401 straight to /login,
ignoring the 30-day refresh-token cookie the backend already issues.
Result: access-token TTL is 15 min, so the operator was kicked to
login every 15 min of idle.

Now: on 401, authFetch silently calls /api/auth/refresh, retries
the original request once with the new access token, and only
bounces to /login if refresh ALSO fails (refresh cookie expired or
revoked). Concurrent 401s coalesce onto a single in-flight refresh
to avoid rotating the refresh-token jti N times in a burst.
2026-04-30 16:30:44 +03:00
Claude
fab8d62521 tower 0.61.17 / tower-ui 0.61.17 — async addon save (kill Saving freeze)
handleUpdateAddons was fully synchronous including BuildKit Jobs per
addon image. cetmix_tower auto-pulls 8 deps × ~30-90s each on a fresh
cluster = 5-15 min. Reverse proxy timeout (60-120s) cuts the request
mid-build, browser shows 'Saving' forever, drawer eventually closes
on the timeout error, AND the cancelled context kills the goroutine
mid-flight so values.yaml never gets committed.

Now: handler validates inline (immediate feedback on bad input),
spawns an addon-stage op, returns 202 + opId in <1s. The goroutine
runs phases (resolve → build → commit → refresh) with a fresh
context that survives client disconnect. Operator watches it in the
bell + Activity tab, can keep working in another tab. Same pattern
Deploy/Migrate/Apply already use.
2026-04-30 16:19:47 +03:00
Claude
971fd12fae tower 0.61.16 / tower-ui 0.61.16 — review fixes
Two bugs the calm re-review surfaced:

1. substrateGateRejection used ListApplications (instance-only
   selector) — same bug we fixed in handleListServers but missed in
   the gate function. Result: the BACKEND gate was a pass-through
   for every preparing server. Frontend disable held the line in
   normal use, but the non-bypassable layer wasn't actually
   non-bypassable. Now uses ListClusterPlatformApps.

2. PlatformAppBadge had its own Argo→state mapping that classified
   Health=Degraded as 'Failed' immediately. Backend's
   deriveSubstrateStatus is forgiving within the budget (Degraded
   inside 10-min window reads as preparing). The two parallel
   logics meant the badge could show red 'Failed' while the gate
   considered it 'preparing'. Refactored badge to consume the
   backend's substrateStatus enum directly — single source of
   truth, no more disagreement.
2026-04-30 15:06:50 +03:00
Claude
d2f86d7e1a tower 0.61.15 — substrate budget 5→10m + forgiving Degraded
DNS-01 against Cloudflare reliably takes 6-8 min for first-issue
(Cloudflare TXT write + global propagation + LE polling). The 5-min
budget red-flagged normal installs. Bumped to 10 min.

Also: Argo flickers to Degraded during retries while waiting on the
Certificate hook. Within the budget window we now classify Degraded
as 'preparing' instead of 'degraded' — only declare degraded after
the budget fully expires. Stops the badge from showing 'Failed'
during a healthy install.
2026-04-30 14:25:25 +03:00