Skip to content

feat(certs): auto-generate TLS cert on first run (closes #62)#67

Merged
Aybook merged 3 commits into
mainfrom
feat/62-auto-cert
Jun 12, 2026
Merged

feat(certs): auto-generate TLS cert on first run (closes #62)#67
Aybook merged 3 commits into
mainfrom
feat/62-auto-cert

Conversation

@Aybook

@Aybook Aybook commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Sopor asked for hub-style auto-generation of the TLS cert on first run. New `core/cert_autogen.lua` module shells out to openssl when `certs/servercert.pem` / `certs/serverkey.pem` are missing, mirroring `make_cert.{bat,sh}` exactly (EC prime256v1 + single-use CA + 10-year validity + cleanup of transient cakey.pem / cacert.pem).

Hooked in two places for coverage across entry paths:

  1. `core/net.lua` module-load (before `ssl.newcontext` reads the files) - catches CLI + GUI worker. Failures print to stderr (drained into `logfile.txt` by GUI worker stderr is lost (wxProcess:Redirect with unread stream) #59 capture) AND `log.event`.
  2. GUI `validate.cert` at startup - replaces the legacy "Please generate manually" error with a silent successful generation. Only when openssl is unavailable does the manual-action hint show.

Behaviour

State What happens
Both files exist No-op fast path (two `file_exists` checks)
Either file missing + openssl on PATH Silent regenerate, log `Certificates verified at ...`
Either file missing + openssl NOT on PATH Clear error + hint to install OpenSSL or run `make_cert.{bat,sh}`

Live test (rc2 Windows install)

```
$ ls certs/*.pem
servercert.pem
serverkey.pem

$ mv certs/servercert.pem certs/serverkey.pem /tmp/

$ ./lua.exe frontends/cli/main.lua

... announcer starts normally, no errors

$ ls -la certs/*.pem
-rw-r--r-- 1 ... 602 ... certs/servercert.pem
-rw-r--r-- 1 ... 310 ... certs/serverkey.pem

$ grep cert log/logfile.txt
[ 2026-06-12 / 15:01:08 ] Certificates verified at certs/servercert.pem
```

Auto-gen ran, fresh pair created, no `cakey.pem` / `cacert.pem` leftover, announcer proceeded into normal directory scanning + announce loop without operator intervention.

Out of scope

  • Shipping `openssl.exe` in the Windows zip. The release already includes `libssl-3-x64.dll` + `libcrypto-3-x64.dll` for LuaSec but not the CLI binary; shipping it would inflate the zip. Deliberate non-decision; operators on Windows without OpenSSL installed still see the legacy manual hint.
  • Renewing expiring certs. 10-year validity matches the upstream make_cert. Renewal would be a separate feature.

Test plan

  • Lua 5.4 syntax check via `lua54 loadfile` on all 3 touched files -> OK
  • Live cert-regen test on rc2 Windows install
  • No leftover CA artefacts verified
  • CI smoke green (Linux + Windows GUI builds)

🤖 Generated with Claude Code

Aybook and others added 3 commits June 12, 2026 15:02
Hub-side luadch generates a server cert on first boot - the
operator never has to think about it. The announcer used to require
`certs/make_cert.{bat,sh}` to be run manually before the first
connect, which is poor UX for a tool that is otherwise
fire-and-forget. Sopor specifically asked for parity.

Fix: new `core/cert_autogen.lua` module with a single function
`cert_autogen.ensure(cert_path, key_path)`:

  - returns true immediately if both files exist (steady-state
    cost: two file_exists checks)
  - shells out to openssl to generate the pair if either is
    missing; chain mirrors make_cert.{bat,sh} exactly (EC
    prime256v1 + single-use CA, 10-year validity)
  - cleans up the transient cakey.pem + cacert.pem post-signing
    so the runtime certs/ holds only servercert.pem + serverkey.pem
  - cross-platform: Windows vs POSIX detected via package.config,
    null redirect + openssl probe (where/which) adapted per
    platform; openssl flags are identical
  - graceful failure when openssl is not on PATH: returns false +
    a message that points at the manual make_cert script as
    fallback

Hooked at two places so both CLI and GUI users get coverage
regardless of entry path:

  1. core/net.lua module-load (before ssl.newcontext reads the
     files) - catches the CLI frontend AND the GUI's spawned
     worker. Failures print to stderr (drained into logfile.txt
     by the #59 capture) AND log.event.
  2. frontends/gui/Announcer.wx.lua validate.cert at GUI startup -
     replaces the legacy "Please generate manually" error with a
     silent successful generation; only when openssl is unavailable
     do we fall through to the operator-action error.

Live test on rc2 install: moved existing certs/*.pem aside, ran
`lua.exe frontends/cli/main.lua`. Result: fresh servercert.pem
(602 B) + serverkey.pem (310 B) generated, no CA leftover, logfile
shows "Certificates verified at certs/servercert.pem", announcer
proceeded into normal directory scanning + announce loop.

Note: the Windows release zip already ships libssl-3 + libcrypto-3
DLLs for LuaSec but NOT the `openssl.exe` binary. Operators on
Windows without OpenSSL installed still see the legacy
"Run make_cert.bat manually" hint and can install OpenSSL OR run
the script with a PATH-resolved openssl from a different path.
Shipping openssl.exe is a deliberate non-decision; the Windows
binary footprint stays minimal.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
The original smoke test expected the announcer to die immediately at
ssl.newcontext with "error loading private key" because CI installs
have no cert pair. With #62 introducing cert_autogen.ensure() at
net.lua module load, the announcer NOW generates a working cert pair
on the fly (both CI runners have openssl available) so
ssl.newcontext succeeds, the announcer enters its reconnect loop,
and the smoke command never returns - the job hangs until the
60-minute GitHub Actions step timeout.

Two changes per platform (linux + windows):

  1. Wrap the announcer invocation in `timeout 5s` so the smoke
     step always returns within bounded time. The announcer's
     reconnect loop with cfg.sleeptime=10 would never exit on its
     own.

  2. Switch the success sentinel from the stdout-side
     "error loading private key" string to the logfile-side
     "Certificates verified at" line emitted by cert_autogen on
     success. This actually exercises #62 end-to-end: the smoke
     verifies cert_autogen ran and reached the post-gen log point.

  3. For the anchored-path run, `rm -f certs/*.pem` first so
     cert_autogen actually re-exercises its generate path on this
     second invocation (otherwise the first invocation's output
     is what the second test would observe).

Tested mentally against the failing #67 CI runs which hung exactly
at the smoke step "Frontend bootstrap smoke (relative arg[0],
fallback path)" with all earlier steps green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Make the cert_autogen grep airtight: previously the second
(anchored-path) test would have falsely passed if its own
cert_autogen step failed but the first (fallback-path) step's
"Certificates verified at" line was still in the appended logfile.
Wiping log/logfile.txt before each invocation ensures the grep
reflects only the current run.

Same cleanup added to both linux + windows smoke jobs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@Aybook
Aybook merged commit 26586f6 into main Jun 12, 2026
8 checks passed
@Aybook
Aybook deleted the feat/62-auto-cert branch June 12, 2026 14:15
@Aybook Aybook mentioned this pull request Jun 12, 2026
3 tasks
Aybook added a commit that referenced this pull request Jun 12, 2026
_VERSION bumped 1.0.0-dev -> 1.0.0-rc3 (visible in About window, title
bar, tray-icon tooltip, status bar, and the "ready" log line). Release
body re-leads with the rc2 -> rc3 delta:

  - #65 / #63 - TLS RadioBox overflow + missing taskbar .exe icon +
    branded About refresh
  - #66 / #59 - GUI worker stderr capture into log/logfile.txt
  - #67 / #62 - first-run cert auto-generation
  - #64 / #61 - tray exit crash + restore-from-tray (already in main
    since rc2-tag; documented for completeness as the load-bearing
    GUI fix between rc2 and rc3)

Tag will be pushed once this lands on main; release.yml auto-detects
the `-rc3` suffix as a SemVer pre-release.

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant