Repository navigation
Conversation
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.
Requirement
Hub Phase 1, slice 3 (RFC #466, sections 3, 5, 6, 8): a runnable Hub that can be deployed (Dokploy) and verified end to end without the daemon connector.
Stacked: base is
feat/hub-store(#480); it also carries the contract commit from #479, so those two merge first and this retargets tomain.Expected behavior
packages/hubgainssrc/server.ts(startHub),src/main.ts(env config), a tsdown bundle andpackages/hub/Dockerfile.GET /healthz; everything else needs the Hub token (HUB_TOKEN, at least 32 chars, constant-time compare).POST /enrollment-tokens: mints a 256-bit token, returns it once; 429 at ten unused.POST /events{ environmentId, type, payload, id? }: committed before the 202; 404 for an unknown or revoked target (records nothing); 413 aboveHUB_MAX_EVENT_BYTES(default 1 MiB,Content-Lengthand a streaming cap); duplicate id returns 200duplicate.DELETE /environments/:id: revokes (persisted first), closes the socket with 4403.WSS /daemon: bearer token +hub.hello; first valid hello enrolls (or authenticates the known credential), replieshub.welcome, delivers held events oldest first, resends unacked events every 30 s, recordshub.event.ack, 30 s ping with two missed closing. Bad token or UUID conflict closes 4403; a second live socket closes 4409; 10 s hello deadline, 64 KiB frame bound, at most 32 pending upgrades.locking_mode=EXCLUSIVE, so a second Hub on the same file fails (no stale lock file).Changes and risks
New code only; nothing else imports it. Host write:
$HUB_HOME/hub.sqlite, documented indocs/host-persistence.md(new "Pie Hub data" section), per the persistence gate.Security notes: the Hub token and every credential compare via SHA-256 digests with
timingSafeEqual; WebSocket auth is a header, never a query parameter; no body, token or peer error text is logged; payloads are cleared at a terminal outcome. Not implemented (RFC section 5 lists it): the per-source limit of five Hub-token/enrollment failures per minute and bounded concurrent webhook handling with 429. Tokens are 256-bit random andHUB_TOKENmust be 32+ characters, so brute force is not realistic, but the limiter should land before Hub is exposed beyond a trusted operator. Retry is a fixed 30 s, not exponential backoff with jitter. TLS is the reverse proxy's job.Verification
Tested revision
e42d9294.vitestinpackages/hub: 24 passed, no type errors, repeated 5 times without a flake (found and fixed one flake caused by a silent test client being closed for missed pings). Covers auth failures, enroll/welcome/reconnect, 4403 and 4409, held delivery with resend and ack, immediate push, 404/413/400 recording nothing, revoke, ping timeout, malformed hello, unauthenticated upgrade.oxlint packages/hub(plugin built),oxfmtclean./healthz, token mint, 0600 files. Docker image built (pie-hub:test), run with a named volume: healthy, files0600, data directory survives a container restart.