Commit Graph

7 Commits

Author SHA1 Message Date
Alphaeus Mote 63701dd086 feat: real restore, portable secret key, multi-arch image, real CSRF
Addresses the gaps identified in the last audit.

Restore (was a stub returning "not yet implemented"). Every repository shares
one connection pool, so the database cannot be swapped underneath a live
server. Restore is therefore two-phase: RestoreBackup validates the file and
stages it beside the database; db.New applies it before the pool is opened,
which is the only safe moment. The database being replaced is preserved as
<db>.replaced-<timestamp>, and stale -wal/-shm are removed so SQLite cannot
replay the old journal over the restored file. Validation is strict — SQLite
integrity_check plus a schema probe — because applying an unrelated file
would destroy the install. GET/DELETE /api/v1/backups/restore inspect and
cancel a staged restore. The CLI does both phases at once, since it runs
standalone; `orchestrad backup` was also a stub and now works.

Secret key. With nothing configured the key is generated once and persisted
to <data>/secret.key, so restarts reuse it and moving the stack to another
server is a matter of copying the data directory. Upgrades are handled: if a
database already exists the install was silently running on the legacy
built-in default, so that value is adopted and written out rather than
replaced — generating a fresh key there would make every stored credential
undecryptable. The file is owner-only (ACL-restricted on Windows).

Multi-arch image: buildx now emits linux/amd64 + linux/arm64, matching the
architectures the release binaries already covered. The Dockerfile
cross-compiles via TARGETARCH rather than emulating, so arm64 costs little.

CSRF: the middleware previously checked only that a header was *present* and
was never wired up, and /auth/csrf returned "csrf-token-placeholder". Tokens
are now nonce + HMAC-SHA256 signed with the application secret, validated
properly, and the middleware is mounted on /api/v1. Bearer and API-key
requests are not CSRF-reachable and pass through untouched, so this is
transparent to the SPA and to API clients.

Also: the Windows store import drops CRYPT_EXPORTABLE (the store copy is not
the source of truth — <data>/tls holds the key, so portability is unaffected
and a non-exportable server key is the better posture), the PFX password is
written to server.pfx.password beside the bundle so an operator importing it
by hand does not have to hunt for a password they never chose, and the
"renewed" log line now reflects whether a leaf was actually issued instead of
guessing from its age.

Verified live: backup -> stage -> restart applies and preserves the previous
database; secret key generated, adopted, and read back across restarts with
the credential check confirming decryptability; CSRF endpoint issues real
signed tokens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-03 13:57:15 -04:00
Alphaeus Mote 300866d5cf feat(tls): auto-managed HTTPS with renewal; disable for edge termination
Add internal/tlsmgr: on startup, load-or-generate the CA, issue/reuse the leaf,
export the chain under <data>/tls, and hot-swap the cert on renewal via
GetCertificate. The server listens HTTPS when a manager is present. TLS is on by
default for the standalone binary/service (tls.enabled setting or
ORCHESTRAD_TLS_ENABLED, UI wins over env); the container image defaults it off so
it runs plain HTTP behind a TLS-terminating proxy. Startup logs a clickable URL.
Verified end to end: HTTPS serves, plain HTTP rejected, disable serves HTTP.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 11:06:42 -04:00
Alphaeus Mote 07b2fe021d feat(config): default listen address 0.0.0.0:18090
Change the default HTTP port from 8080 to 18090 and propagate it through the
Dockerfile (EXPOSE + healthcheck), docker-compose, and the README. Host default
stays 0.0.0.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 10:56:05 -04:00
Alphaeus Mote 6d8d6b713b ci: align Go toolchain to go.mod (1.25)
go get bumped go.mod to 'go 1.25.0' (modernc requirement), but CI used setup-go
1.24 and the image used golang:1.24 — with GOTOOLCHAIN=local the test step failed
('requires go >= 1.25.0'). Install the exact version from go.mod via
go-version-file, bump the builder image to golang:1.25-alpine, and drop the stray
GOTOOLCHAIN override in build.ps1.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 09:33:57 -04:00
Alphaeus Mote 25424322f1 refactor(db): switch to pure-Go modernc.org/sqlite, drop CGO
Replace mattn/go-sqlite3 (CGO) with modernc.org/sqlite and the modernc-based
golang-migrate driver, translating the DSN pragmas. This lets every target
(win/mac/linux, amd64/arm64) cross-compile from one runner with no C toolchain,
so the Docker build now sets CGO_ENABLED=0 and drops gcc/musl-dev. Verified:
DB opens (WAL + foreign keys), migrations run, bootstrap seeds admin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 08:49:14 -04:00
Alphaeus Mote 23e70d12a6 build(docker): compile and embed the web UI in a multi-stage image
The previous Dockerfile used Go 1.22 (too old for the go 1.24 module) and
never built the frontend, so the image shipped only the placeholder UI.
Rework it into three stages: build the Next.js static export, stage it into
the //go:embed dist dir and compile the CGO binary, then ship a minimal
Alpine runtime. .npmrc is copied before npm ci so legacy-peer-deps applies.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-09-02 00:13:36 -04:00
GraceSolutions 09a09d4a68 feat: Initial backend scaffold - Go service, database, CLI, API structure
Phase 1 foundations:
- Go backend with Chi router framework
- SQLite database with WAL mode and foreign keys
- Database migrations for users, roles, credentials, AD connections, schedules, rules, and audit
- CLI commands: init, run, install, uninstall, start, stop, migrate, backup, restore, doctor
- Configuration loading from environment variables
- Centralized logging with file rotation (lumberjack)
- Crypto package for Argon2id password hashing and AES-GCM encryption
- Auth service with session management
- Audit service for event logging
- Scheduler with 6-field cron support
- REST API routes scaffolded for all major resources
- CORS support with localhost defaults for development
- Docker support with Dockerfile and docker-compose.yml
- Multi-platform build script (PowerShell)
- Project structure per design specification

Version format: yyyy.MM.dd.HHmm
All PKs are UUIDv4, all timestamps UTC
2026-04-19 10:07:21 -04:00