3 Commits

Author SHA1 Message Date
rob thijssen
ce825d9c93 host: build and publish the local server as a signed RPM
Some checks failed
host-release / build (push) Failing after 19m50s
host-release / package (43) (push) Has been skipped
host-release / package (44) (push) Has been skipped
host-release / publish (43) (push) Has been skipped
host-release / publish (44) (push) Has been skipped
The banner on a host comes from `npx vibe-kanban` fetching upstream's
published 0.1.44, which embeds upstream's frontend. Our fork already fixes
that UI -- the revert restored LocalProjectKanban and showCloudShutdownBanner
is pinned false in SharedAppLayout, which local-web uses -- it just was not
in the binary anyone was running.

npx cannot be pointed at us. npx-cli resolves its download from R2_BASE_URL,
a placeholder substituted at npm-publish time to BloopAI's bucket, with no
runtime override. That bucket serves the sunset binary and dies with them.

So build our own. crates/server embeds packages/local-web/dist via rust-embed
and crates/server/build.rs reads VK_SHARED_API_BASE at compile time, so one
build yields the fixed UI and our endpoints as defaults, with no environment
on the command line -- std::env::var still wins at runtime for overrides.

Packaged as an RPM to rpm.lair.cafe, mirroring lair/claude-desktop-package:
package and publish on the `rpm` runner, sign, rsync to oolon, createrepo
under the shared flock. The compile runs first on a podman runner instead, so
this never depends on the rpm host's toolchain matching the nightly pinned in
rust-toolchain.toml.

Built on bookworm although the target is Fedora 43/44: glibc compatibility is
forward-only, so one binary covers both. The build fails closed if the sunset
strings reappear or the baked endpoint is missing.

Needs RPM_SIGNING_KEY, RPM_SIGNING_KEY_ID and RSYNC_SSH_KEY on this repo;
they currently exist only on lair/claude-desktop-package.
2026-07-21 19:34:06 +03:00
rob thijssen
e06652a57a relay: build and deploy the relay under a path of the existing host
All checks were successful
container / relay (push) Successful in 17m20s
container / remote (push) Successful in 36m11s
Pairing needs a third service we never deployed. Hosts run the ordinary
local vibe-kanban server (the `server` crate, shipped as `npx
vibe-kanban`); it registers with a relay over a websocket control channel,
and the browser reaches the host's local API through that relay over
WebRTC. The remote server we deploy contains none of it -- its hosts.rs is
a single read-only GET /hosts -- so the UI could list hosts and never pair
one.

Mount it on a path of the existing name (https://kanban.internal/relay-api/)
rather than giving it a domain. Every relay URL on both sides is composed
as {base}/v1/..., the host turns the base into wss:// by stripping only the
scheme, and RelayServerConfig is just database_url/listen_addr/jwt_secret
with no notion of its own public address and no redirects -- so a prefix is
invisible to it. That buys same-origin (no CORS), one less certificate and
one less renewal timer, and when kanban.l4ir.net lands it inherits the
relay by copying one nginx location block.

For that second hostname to work from the SAME build, the SPA's relay base
is origin-relative ("/relay-api") rather than an absolute URL baked at
build time. Two consequences:

- The previous empty value was not "relay disabled", as the comment
  inherited from lair/containers claimed. Empty makes Bootstrap.tsx fall
  back to window.location.origin, aiming relay calls at the remote API,
  which does not serve them. Comment corrected.
- fetch() paths take a relative base fine (plain concatenation), but
  relayHostApi built its websocket by string-replacing http->ws, which
  silently leaves a relative URL that the WebSocket constructor rejects.
  It now uses openBrowserWebSocket, already imported in that file, which
  resolves wss://, https:// and relative alike.

The relay shares the remote's JWT secret -- that is how it trusts tokens
the remote issued -- so both read /etc/vibe-kanban/env.
2026-07-21 17:29:27 +03:00
rob thijssen
ccff6fc539 ci: build and publish the remote-server image from this repo
All checks were successful
container / vibe-kanban-remote (push) Successful in 4m31s
The build lived in lair/containers, which is for third-party images built
from someone else's source. We own this fork now, so it belongs next to
the code it builds: a source change and the image it produces become one
commit rather than two repos that can drift.

Differences from the lair/containers job it replaces:

- Builds the checked-out tree instead of resolving a tag from the mirror
  and building `<mirror-url>#<tag>`. There is no upstream release to track
  any more; what is on main is what ships.
- Publishes an immutable ${version}-g${sha} tag alongside :latest, and
  prints the pin. A floating tag decides which build you are running based
  on whenever something last pulled, which is not a deployment strategy.
- Drops the `skopeo inspect` already-published guard. skopeo is not
  installed on the metal runner, so that check silently failed and always
  fell through to a build -- an accident, not a policy. Building every
  push to main is the intent here anyway.
- Adds a guard that greps the built bundle for the sunset page and refuses
  to publish if it reappears. This fork exists to remove it; a bad merge
  should fail the build, not ship a dead product. Verified against the
  currently-deployed image, where it correctly fires.

concurrency keeps two builds from racing over :latest.
2026-07-21 15:46:49 +03:00