…ers, cut the README
Prepares the repository for being promoted. Everything here is aimed at one question:
can a stranger find NodePilot, trust it, install it, and get to a first login without
asking anyone?
Legal and disclosure
- Remove two easter eggs, one of which shipped a third-party photo in every build
(server zip and desktop installer alike) under no license.
- Rename the `sparkasse` skin to `bank` across the codebase. The user-visible labels were
already neutral; the internal name and a "corporate fidelity" note were not.
- Stop naming file and class locations for open security work in the public roadmap, and
close its open "is a password in the git history?" question — all 433 commits scanned,
only dummy fixtures.
- Add SECURITY.md with a private reporting path and an explicit scope section, so
intended behaviour (operator trust, the localhost bypass, self-signed signing) is not
reported as a finding.
Security fix found while doing the above
- NetworkGuard treated the unspecified addresses 0.0.0.0 and :: as public. Both reach the
local host on Windows, and IPAddress.IsLoopback does not recognise them, so
http://0.0.0.0:5000/ walked straight through RestApi:BlockPrivateNetworks.
Onboarding blockers
- Desktop first run under a separate admin account: the setup token went to the elevated
account's profile while the app looked in the interacting user's. Anyone installing with
different admin credentials — the norm in managed environments — reached a login form for
an account that did not exist, with no documented way out.
- A failed desktop provisioning step reported success; the installer now fails and names
the log. The app's readiness timeout (120s) was below the provisioning script's own
(180s) and now sits above it.
- The publisher certificate is a build output covered by SHA256SUMS instead of a manual
upload that was forgotten after 1.2.8 — and was never checksum-covered even when present.
- The install scripts ship as their own checksum-covered zip, so verifying no longer
requires extracting the unverified archive first.
- Version placeholders replace hardcoded versions in copy-paste commands; the three npm
manifests move from 1.2.5 to the product version, guarded by a new parity test.
Documentation site
- Published to GitHub Pages, and made bilingual: all 42 pages exist in English and German
with the language in the route, a switcher, browser-language detection, and search over
the active language. A parity test fails the build if a page or nav title lands in only
one language. The site had no test suite; it now has 23 tests, wired into CI.
- Only content/en feeds the in-product AI knowledge assistant — embedding both languages
would double its token cost for no gain.
Public surface
- README: 1428 lines to 545. Its feature inventory duplicated the documentation site, so
it links there instead. The SCOrch import path — the strongest reason for a System Center
Orchestrator user to look at this at all — moves from undocumented to a section with a
comparison table.
- Add CHANGELOG.md, CODE_OF_CONDUCT.md, RELEASING.md and CODEOWNERS.
- Fix 56 broken relative links, retire a stale branch-name column, move E2ETests.md out of
the repository root, and label eight pinned action SHAs with the version they actually are.
- Screenshots retaken in the default dark skin; the old ones showed a non-default one.
Desktop build
- Assert the bundled PostgreSQL major version by reading the binary rather than trusting a
path. A 17.x payload produced an installer that failed against every existing database.
- The desktop shortcut is now an opt-out task rather than unconditional.
Prepares the repository for being promoted. Everything here answers one question: can a stranger find NodePilot, trust it, install it, and reach a first login without asking anyone?
I walked that path as an outsider — GitHub page → release → install → first login — and separately looked at what a lawyer, a security reviewer and a sceptical corporate admin would find.
Blockers this fixes
Desktop first run breaks under a separate admin account. The setup token was written to the elevated account's profile while the app looked in the interacting user's. When both are the same person — clicking "Yes" on the UAC prompt — it works, which is why it never showed up in the lab. Enter a different admin's credentials, the norm in any managed environment, and the token lands in the admin's profile, the app never finds it, and you face a login form for an account that does not exist. The only remaining copy is owned by SYSTEM, and opening its ACL carelessly invalidates the token permanently.
A failed desktop provisioning step reported success. The installer discarded the script's exit code. First symptom was an error from the app. The app also gave up after 120s while the provisioning script waits up to 180s.
The documented trust ceremony could not be performed. The deployment guide tells you to compare the publisher certificate's thumbprint — "that comparison is the trust decision" — but the
.cerstopped being attached after 1.2.8, and even when present it was never covered bySHA256SUMS. It is now a build output, listed in the checksums. The install scripts ship as their own checksum-covered zip, so verifying no longer requires extracting the unverified archive first.A real SSRF hole, found while cleaning up the roadmap. I had reported roadmap item 2 as "probably already fixed". Before striking it I read
NormalizeAddressand found0.0.0.0and::falling through every branch. Both reach the local host on Windows, andIPAddress.IsLoopbackdoes not recognise them, sohttp://0.0.0.0:5000/walked straight throughRestApi:BlockPrivateNetworks. Fixed, with tests.Legal and disclosure
sparkasseskin is renamed tobank. Visible labels were already neutral; the internal name and a "deliberate corporate fidelity" note were not.SECURITY.mdadded, including a scope section so intended behaviour (operator trust, the localhost bypass, self-signed signing) is not reported as a vulnerability.Documentation site
Published to GitHub Pages, and bilingual: all 42 pages exist in English and German, language in the route (
#/en/…,#/de/…), a switcher, browser-language detection, and search over the active language. A parity test fails the build if a page or nav title lands in only one language — the two half-states fail differently and neither is obvious to whoever wrote the page.The site had no test suite. It now has 23 tests covering language detection, the router's path split and corpus parity, wired into CI.
Only
content/enfeeds the in-product AI knowledge assistant. Embedding both languages would double its token cost for no gain — the model answers in the asker's language regardless.Public surface
README: 1428 lines → 545. Its feature inventory duplicated the documentation site, so it links there instead. The SCOrch import path — the strongest reason for a System Center Orchestrator user to look at this at all — moves from undocumented to a section of its own with a comparison table. It reads
.ois_exportfrom 2012/2016/2019, maps 13 activity types, carries links and conditions across, and rewrites Published Data references into the data bus. Nothing is dropped silently.Also:
CHANGELOG.md,CODE_OF_CONDUCT.md,RELEASING.md,CODEOWNERS; 56 broken links fixed; a stale branch-name column removed;E2ETests.mdmoved out of the repo root (with its gitleaks allowlist path); eight pinned action SHAs relabelled with the version they actually are (# v4on a v7.0.1 commit); screenshots retaken in the default dark skin.Desktop build
The bundled PostgreSQL major version is asserted by reading the binary rather than trusting a path — a 17.x payload produced an installer that failed against every existing database. The desktop shortcut is now an opt-out task.
Supersedes #227
#227 documents that the desktop package ships
tools\npandtools\mcp. It touchescontent/deployment/desktop.md, a path this branch restructured intocontent/{de,en}/, so it cannot merge cleanly. Its content is folded in here, in both languages. #227 can be closed.Verification
23/23 docs-site tests · 13/13
DocumentationCountsTests· 3/3PackageVersionParityTests· deployment template contracts · lint/tsc/build clean · 0 broken relative links repo-wide (from 56) · the built site served under the real/NodePilot/prefix and clicked through in a browser, both languages, zero failed resources.One manual step remains
Pages source is already set to GitHub Actions, so the deploy fires on merge. Repository topics, the social preview image and
homepageUrlstill need setting.