Repository navigation
CI fix, /status, sidecar readiness, URL validation, TLS modes, date versioning - #4
Merged
Merged
Conversation
/api/slots and /healthz only probed the VNC port, so a slot whose sidecar was down showed as ready and opening a file then failed with 502. Probe the sidecar's /healthz too (1s timeout) and report vnc, sidecar and ready (= both) per slot. The tab tooltip says which half is down. First tests for internal/api cover all four combinations.
- staticcheck v0.8.1 (latest release) can't read go1.27.2 export data and crashed the lint job, which skipped every image build. Pin the action to master commit 452d5bb86b45 until a newer release ships. - With go.mod at go 1.27, staticcheck now flags SA1019: httputil.ReverseProxy.Director is deprecated since Go 1.26. Move the slot proxy to Rewrite. Rewrite strips inbound X-Forwarded-*, so append the client to X-Forwarded-For by hand to keep what upstreams saw (SetXForwarded would also add X-Forwarded-Host/Proto). - Add internal/proxy tests (path strip, Host, identity encoding, XFF, bare-prefix redirect, HTML shim + JS rewrite); they pass against both the old Director code and the new Rewrite code.
- proxy: replace hand-rolled jsonString with encoding/json (also escapes <, > and &, so the slot prefix can't close the shim's <script>); gofmt the shim doc-comment list. - api: paramsForLog prints keys sorted, so identical requests log identically. - web: open the ?url= doc in a slot only the first time it's shown, not on every tab switch (re-sending stacked duplicate windows in apps that hand off to a running instance). - control-center: drop trailing blank line (gofmt).
…tree-sidecar-readiness' into feat/status * worktree-fix-ci: test(proxy): accept either JSON escaping of the slot prefix in the shim fix(ci): make the lint job pass on Go 1.27.2 * worktree-small-cleanups: chore: small cleanups * worktree-sidecar-readiness: feat(control-center): count a slot as ready only when its sidecar is up
Opening a file only answered {"ok":true} once the hook was forked;
download failures, refused URLs and crashed apps were visible only in
the viewer's logs.
- viewdoc.sh records the outcome in /tmp/viewdoc.status: refused,
deduped, downloading, failed (+ error) or launched (+ app). A
dispatch helper names the app; $STATE also keeps the exit code.
- Sidecar: GET /status returns {phase, url, app, error, updated,
app_state, exit_code}. POST /params marks the request queued first,
app_state comes from $STATE (a dead running pid reads as exited),
and startup clears the file like the last-URL file.
- Control-center: GET /api/slot/{i}/status relays it (1s timeout).
- UI: status next to the buttons for the active slot, polled every 1s
while queued/downloading and every 5s otherwise.
- Tests for the sidecar handler and the relay; docs for both APIs.
viewdoc.sh already refuses non-http(s) URLs, but the control-center and sidecar accepted anything, so a value like --version.mp4 travelled all the way to the hook. Validate in internal/sanitize (used by both): - url (any case — keys are upper-cased into VIEWDOC_Q_*) must be an absolute http:// or https:// URL with a host; - keys that are equal after upper-casing are rejected, since they would map to the same shell variable. First tests for internal/sanitize.
The control-center could only serve the pre-generated self-signed cert
embedded from certs/. Keep that as the default and add two sources:
- embedded (default): certs/server.{crt,key} embedded in the binary
(make cert regenerates it) — same fingerprint everywhere, so the
browser's "accept once" sticks.
- generate: a P-256 self-signed pair generated on demand, persisted in
TLS_CERT_DIR (key 0600, reused on later starts; extra SANs via
TLS_HOSTS) or kept in memory when no dir is set.
- file: your own TLS_CERT_FILE + TLS_KEY_FILE, e.g. CA-issued.
Unset TLS_CERT infers file / generate / embedded from which variables
are set. The startup log names the source and its SHA-256 fingerprint.
Mode selection lives in tlsself.Config with table tests (plus
persistence, key mode and SAN tests). gen-cert reuses the package and
takes -dir. compose documents the alternatives and mounts a certs
volume at /certs (the image ships it owned by nonroot) for generate.
Both replicas of each viewer carried a build: section (via the YAML anchor), so compose built the Kasm and Webtop images twice. Move the shared settings into x-kasm / x-webtop fragments, give build: only to the first replica, and set pull_policy: never on the second so it reuses the local image instead of pulling the published tag. Also spell VIEWER_SLOTS with the kasm:// / webtop:// pseudo-schemes.
viewdoc had no version: images were only published as rolling <variant> tags. Follow the dockette pattern (a version pinned in the repo, tagged images, a Versions table — cf. dockette/grafana, tika) with a release date instead of an upstream version: - VERSION holds YYYY.MM.DD (YYYY.MM.DD.N for a same-day re-release); make release sets it to today's date, skipping already-tagged ones. - internal/version.Version is set via -ldflags from the VERSION build arg (compose: VIEWDOC_VERSION, make build), logged by both binaries and returned by /healthz and the sidecar's /status. Images carry org.opencontainers.image.version. - CI: validates VERSION, publishes <variant>-<VERSION> next to <variant> and <variant>-<sha>, and a new release job tags the commit and creates the GitHub release once all images are pushed. Docker Hub login now runs only when pushing (as in dockette/.github). - README: Versions section and release steps.
The CI runner's shellcheck flags it (the local stable image doesn't); use an explicit if so the lint job passes.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes the red
masterCI (no images have been published since85f9ac8) and adds the next round of features. Each commit stands on its own.CI fix
452d5bb86b45until a newer release ships.httputil.ReverseProxy.Directoris deprecated since Go 1.26, so the slot proxy now usesRewrite.X-Forwarded-Foris still appended by hand.internal/proxygets its first tests.Features
/status: the sidecar'sGET /statusand the control-center'sGET /api/slot/{i}/statusreport each slot's latest request. Phases arequeued,refused,deduped,downloading,failed(with an error) andlaunched(with the app's state). The UI shows it next to the buttons./healthzanswer.internal/sanitizerejects a non-http(s)urland keys that collide once upper-cased. This happens in both the control-center and the sidecar, before anything reachesviewdoc.sh.TLS_CERTpicks the cert:embedded(default) keeps the pre-generated cert.generatemakes a self-signed cert on demand, stored inTLS_CERT_DIRor kept in memory.fileloads your ownTLS_CERT_FILEandTLS_KEY_FILE.YYYY.MM.DD(.Nfor a second release on the same day).VERSIONholds the current one andmake releasebumps it./healthz, and CI publishes<variant>-<VERSION>tags.releasejob tags the commit and creates the GitHub release once all images are pushed.Cleanups
encoding/jsonreplaces the hand-writtenjsonString, log keys are sorted, and a?url=is sent to a slot only the first time it's shown.dockette/.github.Verification
go test -racepasses in 5 packages (all new tests), and shellcheck, hadolint and actionlint are clean./statusphase, URL rejection, all three TLS modes (embedded / file / in-memory / persisted volume / bad config), a cold compose start building each viewer image once, and the version in labels, logs,/healthzand/status.After merge
masterrun publishes<variant>-2026.10.12and creates release2026.10.12. Runmake releasebefore merging if you want a different date.master. It doesn't overlap this PR, so it can merge before or after.