Commit Briefs

62bc6ad6d2 Alisdair MacLeod

migrate off github (main)



efaf222244 Alisdair MacLeod

Cleanup: Remove unused database queries and add strsep shim


cf0bb562ad Alisdair MacLeod

Batch safe characters in cgi_html_escape with fwrite

Instead of calling fputc for each non-special character, track runs of safe characters and emit them in a single fwrite call. Reduces function call overhead for typical alphanumeric inputs. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


d5d6368fec Alisdair MacLeod

Add index on bookings(day) for day-specific queries

The existing UNIQUE indexes have (desk, day) and (user, day) as their column order, so queries that filter by day alone cannot seek directly. This index lets the day bookings and LEFT JOIN queries use an index scan instead of a full table scan. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


22f3a7ce67 Alisdair MacLeod

Combine bookingform's two queries into a single LEFT JOIN

The booking form page previously ran separate queries for day bookings and available desks, each requiring its own prepare/bind/step/finalize cycle. A single LEFT JOIN query returns all desks with their booking status in one pass, halving the SQLite overhead for this route. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


77f906b3cf Alisdair MacLeod

Use stack buffer for URI path copy instead of strdup

CGI request URIs are short (the longest valid path is /book/YYYY-MM-DD at 16 characters). A 256-byte stack buffer avoids one heap allocation per request. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


b91d801835 Alisdair MacLeod

Use stack buffer for POST body instead of heap allocation

MAX_BODY is 4096, well within stack limits. The content_length check already ensures the read will not overflow. This avoids a malloc/free pair on every POST request. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


a35d82dbb6 Alisdair MacLeod

Remove -lpthread from default LDFLAGS

deskd is single-threaded. On macOS the shared SQLite library resolves pthread symbols through its own linkage. On OpenBSD with static linking the linker pulls in only the symbols that SQLite actually references; if the static build fails, restore -lpthread via the LDFLAGS override. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


8f34b0f4f1 Alisdair MacLeod

Remove unused -lm from LDFLAGS

No application code uses math.h functions. On a static build the linker would only pull in referenced symbols, but removing the flag avoids unnecessary library scanning during the link step. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


ff0a1945f4 Alisdair MacLeod

Use hex lookup table instead of snprintf for CSRF token encoding

Replace 16 snprintf("%02x") calls with direct table lookups. snprintf parses the format string on every iteration; the lookup table converts each byte to two hex characters with simple shifts and masks. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


41a02e31da Alisdair MacLeod

Enable -Os optimization for smaller binary output

The default optimization level (-O0) leaves dead code and misses size-reducing transformations. -Os is preferred over -O2 as it avoids aggressive inlining and loop unrolling that inflate the binary, which matters for a statically linked CGI deployment. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


3662c36f8b Alisdair MacLeod

Buffer stdout to reduce write(2) syscalls per CGI response

CGI route handlers make dozens of small printf/fputs calls. Under the CGI model stdout is piped to the web server and line-buffered by default, so each newline triggers a separate write(2) syscall. Switching to full buffering batches the entire response into one or two writes that flush when the process exits. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


89b827214e Alisdair MacLeod

Redirect unknown routes to home page instead of returning 404

Users with old bookmarks or shortcuts were getting a plain-text 404 error after d3b734c. Use a 302 temporary redirect to / so they land on the bookings page instead, without permanently caching the redirect. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


13e4d4f78b Alisdair MacLeod

Unveil /dev/urandom and SQLITE_TMPDIR for SQLite on OpenBSD

SQLite internally opens /dev/urandom to seed its PRNG and searches /var/tmp, /usr/tmp, /tmp for temporary files. Both are blocked by the unveil sandbox, producing spurious accounting log entries. Unveil /dev/urandom unconditionally so SQLite gets proper entropy instead of falling back to time()+getpid(). For temp files, unveil the path in SQLITE_TMPDIR when set, letting deployers point it at the database directory already inside the chroot. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


01e922766d Alisdair MacLeod

Modernize C style: declarations at point-of-use and const qualifiers

Move variable declarations from top-of-block to point of first use (C99/C23 style), add const qualifiers to locals and value parameters where appropriate, and remove #include directives made redundant by transitive includes through project headers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


ef786819d8 Alisdair MacLeod

Replace vmactions/openbsd-vm with cross-platform-actions/action

vmactions/openbsd-vm has a known reliability issue (vmactions/openbsd-vm#11) where the SSH connection to the VM drops mid-test, causing SIGPIPE failures. cross-platform-actions/action is faster and more stable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


50af281a18 Alisdair MacLeod

Refactor routing to branch on path first, then method

The flat if/else chain checked (method, path) pairs and required a separate block that re-enumerated every known path for the 405 case. Restructure as nested branches: outer level matches path, inner level matches method with a per-path else → 405 fallback. This makes each route self-contained so new paths cannot accidentally miss the 405 case. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


d3b734c59c Alisdair MacLeod

Return 404 for unknown routes and 405 for unsupported methods

The catch-all in the request router previously returned 400 for both unknown paths and unsupported methods. Split it into two branches: known paths with the wrong method now return 405 Method Not Allowed, and unrecognised paths return 404 Not Found. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


d421a78130 Alisdair MacLeod

Update routing tests to expect correct HTTP status codes

Change route-unknown to expect 404 Not Found instead of 400, and route-wrong-method to expect 405 Method Not Allowed instead of 400. These tests will fail until the routing logic in deskd.c is updated to distinguish unknown paths from unsupported methods. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


2895fd6ddc Alisdair MacLeod

Add 12 missing integration test cases

Cover previously untested code paths: routing catch-all (unknown routes, wrong methods), missing CSRF cookie (vs mismatch), missing day parameter in cancel form, empty request body on book, cancel of non-existent booking, past-booking filtering on the bookings page, empty day query parameter on dateform, no-desks-configured edge case on bookingform, and HTML escaping of desk names and usernames to guard against XSS regressions. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


c64c0d1524 Alisdair MacLeod

Statically link deskd for chroot deployment

The binary runs inside an OpenBSD httpd chroot with no access to shared libraries. Add -static to the default link flags via a LDFLAGS_STATIC variable that can be overridden (e.g. LDFLAGS_STATIC= on macOS where static linking is not supported). SQLite's static library depends on pthread and math, so add -lpthread and -lm to the link flags. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


4cc61ea32e Alisdair MacLeod

Add make test recipe and simplify CI to use it

Add a test target that depends on the deskd binary and runs the integration test suite. Simplify the CI workflow to just make test. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


e2fff6102a Alisdair MacLeod

Update actions/checkout to v6

v4 uses Node.js 20 which is deprecated on GitHub Actions runners and will be forced to Node.js 24 starting June 2026. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>


61e578392f Alisdair MacLeod

Document unveil and pledge rationale in main()

Expand comments to explain why the database parent directory is unveiled rather than the file itself, why unveil(NULL, NULL) locks the path list, and why fattr is included in the pledge promises. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>