Repository navigation
feat: say when a newer release is out - #96
Merged
Merged
Conversation
4 tasks done
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.
#88 (
nodkey update, in #95) and #89 (the version header, in #93) are merged. This change builds on both.Nothing told you that a newer release is out. Now
nodkey versionsays it on a terminal, and the broker sends one silent Telegram notice.What changed
internal/release(new package): the lookup of the newest release.GET https://api.github.com/repos/code6x/nodkey/releases/latest, no login, withAccept: application/vnd.github+json,X-GitHub-Api-Version: 2022-11-28andUser-Agent: nodkey/<version>.Proxy: http.ProxyFromEnvironment, TLS 1.2 or newer with the system roots, HTTP/1.1 only, no redirects (a redirect is an error with its status), 10 s for each step of a connection, 30 s for the whole lookup, no connection kept open.tag_name,draftandprerelease, with the exact key names (Go's decoder would also takeTAG_NAMEfor a struct field). A draft, a prerelease, a missing key, or a tag that is notv+ a release version is an error. A tag longer than 21 bytes (v999999.999999.999999) is refused before it is parsed: a tag of 1 MiB of dots cost about 17 MiB inversion.ParseRelease, and now costs about 2 MiB. 403 and 429 giveErrRateLimit. Any other status but 200 is an error with the status only.release.Check, started bynodkey broker): it waits 10 minutes after the start (release.FirstWait), then asks, and then every 24 hours; after a failed lookup or a failed notice, after 1 hour. So a broker that systemd starts again and again, and that ends within 10 minutes, never asks GitHub and sends no notice in each start. A newer release gets one line in the journal and one silent notice throughtelegram.Approver.Inform, which it shares with the notices of feat: warn when the client and the broker run different versions #89 (3 in any 60 s). A notice counts as sent only afterInformreturns no error. A release that is not newer than the broker, or than a release that already got its notice, gets none. A build from the source, and[updates] check = false, never ask.LatestcallsCloseIdleConnectionswhen it returns, which ends such a dial. No request and no notice goes out after the step.ℹ️ nodkey: A newer release is out: nodkey 0.3.0. The broker runs nodkey 0.2.0. To update the broker, run as root on the broker host: nodkey update. Then restart it: systemctl restart nodkey. The restart ends all grants. Update the agent machines too: sudo nodkey update. Release notes: https://github.com/code6x/nodkey/releases/tag/v0.3.0nodkey version [--offline]: stdout is the samenodkey <version>line as before. Then, only when stdout is a terminal (ioctlTCGETS, like isatty; only stdout decides), the version is a release and--offlineis not given, it asks GitHub for at most 10 seconds and prints one line on stderr: a newer release (version,sudo nodkey update, release notes link),this is the newest release(also when GitHub's newest is older), orcannot check for a newer release: <fixed reason>. Exit code 0 also on errors. So$(nodkey version)in the installer of feat: install script and nodkey update #88 never calls GitHub and never gets another line.[updates]withcheck,trueby default (also without the table). Strict as every table: unknown keys, wrong types, dotted keys and inline tables are errors.[updates]; section 15: the usage,nodkey version, the lookup, the new start step 10 and stop step 1, and the step numbers that moved; section 17: the tests), THREAT-MODEL.md (a row for GitHub's API in section 3, a note in T9, and a new T34: what GitHub learns; that a false answer, from GitHub, a proxy that inspects TLS or any CA the host trusts, can only give a wrong notice or hide one, becausenodkey updatechecks the attestation and the version; that the notices cannot fill the chat; and two worse cases: an agent machine behind the same public address can use up GitHub's 60 calls an hour, so a security release gets no notice, and a release built from a merged pull request (T20) passes the attestation check, while the notice now asks every owner to install it within a day), docs/setup.md (section 2, the config key with a note on outbound HTTPS toapi.github.comandHTTPS_PROXY, the proxy notes of section 8, and the notice in section 13), docs/releasing.md (step 3 of "Verify a download": a newer nodkey asks GitHub from the machine where you check it, and prints one more stderr line;./nodkey version --offlineskips that, and 0.1.x does not know--offline), the comment about the proxy in the example unit, and AGENTS.md (the new package).Tests
No test reaches the real network:
httptestTLS server, with the real client (only the base URL and the CA pool differ): newer, same and older tags; bad tags (nov, leading zeros, junk, empty, a release candidate, too long, and more); a tag of 1 MiB of dots is refused with at most 6 MiB of allocation (without the length check: 18 MiB, and the test fails); a lookup that ends while the proxy holds the CONNECT ends its dial too (without the fix, the dial goes on, and the test fails after 10 s); draft, prerelease, missing ornullkeys; keys in another case; 403, 429, 500 and other statuses; exactly 1 MiB (read) and 1 MiB + 1 byte (error, also in chunks); five kinds of redirect (not followed: one request only); a server that hangs, and one that stops in the body; a cancelled context; an untrusted certificate; a TLS 1.1 server; no server; the headers of the request. A child process checks that the client takesHTTPS_PROXYfrom the environment: it may dial only the proxy, and the proxy seesCONNECT example.com:443but not the path.nodkey versionruns with a fake terminal and a fake lookup: each stderr line, stdout unchanged, exit 0 on errors; no lookup when stdout is not a terminal, with--offline, or for a source build; wrong usage gives 64 and no lookup.isTerminalis false for a pipe, a file,/dev/null, a closed file and a buffer, and true for/dev/ptmx.nodkey brokerin a child process: the fake proxy now also answers forapi.github.comwith a fake GitHub, with the same test CA. Without a seam, a release broker waits: it makes no call to GitHub before its stop, and the stop ends the wait first and is clean. With the seamfast-release-check(first wait 0), a release broker sends exactly one notice with the exact text, silent and without link preview, makes exactly one call to GitHub with the right headers, starts the check after the approver runs, stops it first, and stops cleanly. Withcheck = false, and in a build from the source, there is no call to GitHub.TestBrokerChildnow also refuses to start when calls toapi.github.comwould not go to the fake proxy.dev, so it never asks. It now also checks that the broker logs that the check is off. Its old check that the fake proxy saw onlyCONNECT api.telegram.org:443stays.truewithout the table and without the key,check = false, and errors for an unknown key, a key in upper case, a wrong type, a dotted key, an inline table, a subtable and[[updates]].Results, on 2026-10-17, after the fixes of the security review:
CI=true go test -race ./...(Go 1.27.1)CI=true go test -race ./...(Go 1.26.0)go vet ./...andgo vet -tags e2e ./test/e2e/...gofmt -l .golangci-lint run --build-tags e2e(v2.14.0)CI=true go test -race -tags e2e ./test/e2e/...go test -race -count=20 -cpu 1,2,4 ./internal/release/internal/configandcmd/nodkey(-run 'TestLoadBrokerUpdates|TestLoadBrokerErrors|TestLoadBrokerValid', and-run 'TestVersion|TestIsTerminal|TestBrokerRelease|TestBrokerVersionNotice|TestBrokerStartsAndStops|TestRun$')By hand, with a release build on a pseudo-terminal (
script) andHTTPS_PROXYset to a closed port on the loopback address, so nothing left the machine: the terminal getsnodkey 0.2.0andnodkey: cannot check for a newer release: cannot reach GitHub: cannot connect to the proxy, exit 0.$(nodkey version),--offline, adevbuild and>/dev/nullprint only the version line and make no call.gh api repos/code6x/nodkey/releases/latestshows that GitHub's real answer hastag_namev0.1.0,draftfalse andprereleasefalse, which the lookup accepts.Left out, and open points
main(with feat: install script and nodkey update #88 and feat: warn when the client and the broker run different versions #89) had small text conflicts in the usage text ofcmd/nodkey/main.goand in the command table and usage block of DESIGN.md. Both sides are kept. Tests pass again after it on Go 1.27 and 1.26.sudo nodkey updateare part of install: low points from the review of #88 (sudo hints, TMPDIR, CA, tests) #94..claude/agents/security-reviewer.mdran on this change. It found nothing high or medium. Its low findings and notes are fixed here: the first wait (L1), the cases in T34 (L2), "only stdout decides" (N3), and the length cap of the tag (N4). The review of the fixes found a dial that went on after the stop; that is fixed too, with a test.nodkey update(feat: install script and nodkey update #88): it does its own lookup ininstall.sh.Closes #90