Commit Graph
78 Commits
Author SHA1 Message Date
Emil 82eaec4c55 Make the wizard supervisor portable (no signal probing) and bind tests to an ephemeral port
coordinator / test (push) Waiting to run
python / test (push) Waiting to run
release / binaries (amd64, darwin) (push) Waiting to run
release / binaries (amd64, linux) (push) Waiting to run
release / binaries (amd64, windows) (push) Waiting to run
release / binaries (arm64, darwin) (push) Waiting to run
release / binaries (arm64, linux) (push) Waiting to run
release / binaries (arm64, windows) (push) Waiting to run
release / release (push) Blocked by required conditions
release / image (push) Waiting to run
users / test (push) Waiting to run
2026-08-03 00:38:33 +03:00
Emil 8b7094b0cb Open the admin console from serve --open and land login on the intended page 2026-08-03 00:32:47 +03:00
Emil 46645b8730 Add the worker setup wizard (setup, --config, --check) to worker-agent 2026-08-03 00:22:37 +03:00
Emil e923627ce0 Add admin console access and platform pages (trust, users, keys, workloads, settings) 2026-08-03 00:11:47 +03:00
Emil 7fb1059401 Add coordinator admin console foundation (system, jobs, metrics) 2026-08-02 23:51:26 +03:00
Emil 69a2d59b23 Add the coordinator token subcommand for joining workers 2026-08-02 22:43:17 +03:00
Emil 45d5c2eaad Update the add-worker command and expose the coordinator public URL in serve 2026-08-02 22:32:54 +03:00
Emil 76746187eb Add a standalone worker installer and dynamic userservice port 2026-08-02 22:23:54 +03:00
Emil c06d8673ce Add one-command installers and serve/agent make targets 2026-08-02 20:06:08 +03:00
Emil 1473bbe2a8 Embed the userservice and add serve/agent subcommands for one-binary operation 2026-08-02 19:49:54 +03:00
Emil 9883def0c2 Add an embedded SQLite storage backend for single-binary deployments 2026-08-02 19:23:44 +03:00
Emil 9fe81bc531 Use golang-migrate-compatible watermark tracking in migrations 2026-08-02 18:37:15 +03:00
Emil 771952e22e Fix golangci-lint findings across the coordinator and agent 2026-08-02 18:23:43 +03:00
Emil 565d4466e4 Run gofmt on the setup wizard and migration test 2026-08-02 18:16:44 +03:00
Emil 59e7fb0155 Add the coordinator setup wizard for self-provisioned databases 2026-08-02 18:14:36 +03:00
Emil 320f52615e Embed schema migrations and self-provision the schema on startup 2026-08-02 18:04:00 +03:00
Emil f2977a990e Add versioned release builds for coordinator and worker 2026-08-02 17:54:06 +03:00
Emil 361eb2e344 Advertise all catalog workloads from the worker by default 2026-08-02 17:47:52 +03:00
Emil 749396da05 Drive coordinator upload and reduction from the workload catalog 2026-08-02 17:47:47 +03:00
Emil a18b8b8ae4 Build the coordinator server as a static binary 2026-08-02 16:56:06 +03:00
Emil 706bc85e17 Replace Python worker daemon with the Go worker agent 2026-08-02 16:53:04 +03:00
Emil 644c287002 Add Go worker agent prototype 2026-08-02 16:27:58 +03:00
Emil f20cc7fe00 Serve documentation from the operator UI 2026-08-02 15:50:07 +03:00
Emil f059ac626c Add workload library page to the operator UI 2026-08-02 01:18:03 +03:00
Emil b9a975b0ea Merge self-service worker enrollment 2026-07-27 22:28:04 +03:00
Emil fa76133efc Secure user worker operations
coordinator / test (push) Waiting to run
users / test (push) Waiting to run
2026-07-27 22:23:08 +03:00
Efremenko Arhip 2991ed202b feat(demo): add demo-reset to wipe the demo's data volumes
demo-down / stop intentionally keep the Postgres and artifact volumes, so a
fresh start still carried old workers/jobs/tasks. Add a reset action (compose
down -v) and a make demo-reset target for a truly pristine restart.
2026-07-27 16:48:06 +03:00
Efremenko Arhip 9b235282fc fix(coordinator/ui): use the entered machine name in the generated worker command
The Add-your-machine page sent the typed name only to the worker key, while
the copyable command hard-coded --worker-name my-machine, so every self-service
worker registered as my-machine regardless of what the user entered. Thread the
name into the command (shell-quoted; falls back to my-machine when blank).
2026-07-27 16:48:06 +03:00
Efremenko Arhip 3a1461315f feat: self-service worker enrollment bound to a user account
Let a signed-in user turn their own machine into a worker without the
shared token. The coordinator already binds a JWT-authenticated
registration to owner_id as untrusted; this adds the missing pieces.

userservice: long-lived worker keys (scimesh_wk_live_*, hash-at-rest)
with create/list/revoke and a public /worker-tokens/exchange that trades
a key for a short-lived JWT carrying the owner current role/verified.

python worker: SCIMESH_WORKER_KEY + SCIMESH_USERSERVICE_URL; a token
provider exchanges the key and refreshes the JWT proactively and on 401,
so a long-running worker survives token expiry. Static bearer token path
is unchanged.

coordinator UI: an "add your machine" page that mints a key and shows a
ready-to-run command, proxying key management to the userservice; the
dashboard gains an owner-scoped "my machines" section.

docs: how to run a worker from your account, plus the untrusted/quorum/
verified trust model.
2026-07-27 16:11:07 +03:00
Efremenko Arhip 172ff76fb8 fix(test): update NewCompleteTask call to new signature
Pass workers/results repos and quorum in the postgres integration
test, matching the constructor change that added quorum voting.
2026-07-27 11:29:52 +03:00
Efremenko Arhip 6f14eeb32e fix(coordinator): silence nilerr on unresolvable-worker trust fallback 2026-07-27 11:05:36 +03:00
Efremenko Arhip 18d58cce84 feat(coordinator): quorum verification for untrusted (volunteer) results
Replaces the C1 quarantine with real verification. Trusted results (lab token,
verified, or admin worker) are accepted directly as before. An untrusted
worker's result is recorded as one vote per (task, owner) in a new task_results
table; the task only completes once QUORUM_SIZE distinct owners submit the same
result hash, otherwise it returns to the queue for another independent compute.

- migration 0013 task_results (one vote per owner, quorum by result_sha256)
- CompleteTask branches on worker trust; unknown worker defaults trusted (safe:
  completing needs the lease, whose owner is always a known registered worker)
- claim drops the quarantine and excludes chunks the owner already voted on
- domain Task.ReleaseAfterVote; QUORUM_SIZE config (default 2)
- unit tests: trusted direct-complete, untrusted needs-quorum, can-claim

Reducer and job done/total logic untouched — still one completed task per chunk.
2026-07-26 22:55:51 +03:00
Efremenko Arhip dcabfcd0c3 feat(coordinator): business metrics — jobs/tasks/workers by status
A scrape-time collector reports scimesh_tasks/jobs/workers gauges keyed by
status, sourced from cheap GROUP BY queries (StatsRepo), zero-filled across all
known statuses so the dashboard shows flat zeros instead of gaps. A failed
query yields no samples for that scrape rather than crashing it.

Metrics is now built in main so the DB-backed collector can be registered
(NewServer takes *metrics.Metrics; nil self-provisions for tests). Grafana
dashboard gains a Domain state row: tasks/jobs/workers by status and a queue-
depth stat.
2026-07-26 22:16:35 +03:00
Efremenko Arhip e9cf6f0842 build(coordinator): go 1.25 (prometheus deps require it), bump Docker base
The metrics deps pull in modules whose go directive is 1.25, so go mod tidy
raised the module to go 1.25.0. The build image is bumped golang:1.24 ->
golang:1.25-alpine to match (the image runs GOTOOLCHAIN=local and can't
auto-fetch a newer toolchain). CI reads go-version-file, so it follows along.
client_golang pinned to v1.19.1 (stable, same API).
2026-07-26 21:59:49 +03:00
Efremenko Arhip 779ff8c10e feat(demo): Prometheus + Grafana with a provisioned dashboard
make demo-ui now also starts Prometheus (scrapes coordinator:8080/metrics) and
Grafana with a provisioned datasource and a SciMesh Coordinator dashboard
(request rate & p95 by route, status mix, goroutines, RSS). Grafana allows
anonymous viewing so the dashboard opens without a login; admin/admin to edit.

- monitoring/prometheus.yml + grafana provisioning + dashboard JSON
- docker-compose.monitoring.yml overlay (third -f in demo-ui.sh)
- demo prints the Grafana and Prometheus URLs
2026-07-26 21:49:52 +03:00
Efremenko Arhip e584cfc481 feat(coordinator): Prometheus /metrics endpoint
Adds internal/metrics: a private registry with the Go runtime + process
collectors and HTTP RED instrumentation (scimesh_http_requests_total and
request_duration_seconds), labelled by method/status and a normalized route so
per-id paths collapse to {id} and never blow up label cardinality.

/metrics is unauthenticated (like /health) for a Prometheus scraper; the
middleware wraps the whole router so every request is measured once.
2026-07-26 21:47:27 +03:00
Efremenko Arhip 4ac19999a9 feat(coordinator): profile page at /ui/profile
Shows the signed-in user's id, email, role, verified status, and created-at by
proxying the session token to the userservice /me endpoint (email/created_at
are not in the JWT). Profile link added to the dashboard, job, and admin headers.
Tests: /me proxy forwards the bearer and renders the account; redirect without a session.
2026-07-26 21:39:08 +03:00
Efremenko Arhip df4bdc9de9 feat(coordinator): admin panel at /ui/admin
Admin-only page to promote/demote/verify/unverify a user by id. Actions proxy
to the userservice forwarding the admin's session JWT, which the userservice
re-checks (defense in depth). Non-admins are redirected off the panel; the
Admin link shows only for admins. Admins already see all jobs on the dashboard.

Tests: requireAdmin gate, bearer forwarding, action/id validation, admin link.
2026-07-26 21:27:39 +03:00
Efremenko Arhip 49eb662798 feat(coordinator): logout button in the operator UI
The dashboard and job pages show a 'Log out' control (POST /ui/logout) and a
'Signed in · <role>' label when a userservice session is active. Under basic
auth (no session) neither appears, so the fallback UI is unchanged.

Threads a template-only Session view (json:"-") from authctx into the
dashboard and job views. Tests assert the control renders only in session mode.
2026-07-26 21:03:50 +03:00
Efremenko Arhip 5a9a10c681 feat(demo): bring up coordinator + userservice, seed root admin
make demo-ui now starts the userservice (own Postgres + migrations) beside the
coordinator on a shared JWT secret, and seeds a root admin. The coordinator runs
in UI session mode, so /ui opens a login page instead of a basic-auth prompt.

- docker-compose.users.yml overlay: userservice stack + coordinator JWT wiring
- demo-ui.sh: waits for the userservice, logs in as the seeded admin to poll the
  now session-gated dashboard, and prints the admin credentials
- validated with docker compose config (6 services, merged env)
2026-07-26 20:55:54 +03:00
Efremenko Arhip c8c6455caf feat(coordinator): owner-scope UI views by logged-in user
With a UI session, the dashboard and job pages are scoped to the caller:
- Overview lists only the user's own jobs (admin/basic-auth operator: all)
- JobDetail, artifact download, and preview 404 on another user's job
- scoping keys off authctx: no requester (basic auth) still sees everything,
  so the fallback operator UI is unchanged

ListJobs gains an owner filter (SQL WHERE) so paging stays correct per user.
Tests cover Overview scoping and cross-user JobDetail rejection.
2026-07-26 20:12:49 +03:00
Efremenko Arhip 33f629f387 feat(coordinator): UI login/register via userservice (cookie session)
When JWT_SECRET + USERSERVICE_URL are set, the operator UI authenticates
through userservice login/registration instead of the static UI_AUTH_TOKEN:
- /ui/login, /ui/register, /ui/logout pages proxy to the userservice
- successful login stores the JWT in an httpOnly, /ui-scoped cookie
- withUISession verifies the cookie locally and stamps the requester
- unset -> falls back to basic auth, so the team's existing flow is unchanged

Tests cover the session gate, cookie set/clear, and the login/register proxy.
2026-07-26 19:54:39 +03:00
Efremenko Arhip 163cbe14bf fix(coordinator): bind JWT caller to worker at claim (close quarantine bypass)
The trust tier was read off the caller-supplied worker_id, so a JWT user who
knew any trusted worker's id could claim as it — draining and poisoning the
trusted queue and bypassing the untrusted-worker quarantine entirely.

Claim now requires a JWT caller to own the worker it acts as; a shared-token
caller (lab operator) may still act as any worker. Claim is the sole grantor of
a lease, so this also protects the downstream heartbeat/result/failure paths.

Tests: reject claim as another user's worker; allow claim as own worker.
2026-07-26 19:26:30 +03:00
Efremenko Arhip 80ff72a0fe feat(coordinator): worker trust tiers (C1) — enroll volunteers, quarantine untrusted
- migration 0012: workers.owner_id + trust_level (trusted/untrusted)
- verifier/authctx read the JWT verified claim; IsTrusted() = admin||verified
- /workers/register resolves trust from auth: service token or verified/admin
  JWT -> trusted; plain user JWT -> untrusted, tagged with owner_id
- claim quarantines untrusted workers (no tasks) until quorum (C2) lands
- unit tests for trust resolution, quarantine, and the verified claim

Additive and backward compatible: shared-token workers stay trusted, so the
existing worker flow and team tests are unchanged. Quorum verification (C2)
is deferred.
2026-07-26 19:18:50 +03:00
Efremenko Arhip 1b1b971378 fix(coordinator): scan owner_id in UIReadRepo.ListJobs
jobColumns gained owner_id but ListJobs' Scan still read 12 targets,
so the query returned 13 columns and pgx failed at runtime. Only the
integration tests (real DB) caught it; memstore-backed unit tests did not.
2026-07-26 16:24:34 +03:00
Efremenko Arhip a3db1a1e67 add users logic 2026-07-26 14:38:24 +03:00
Emil 746958884e Document local pipeline demo 2026-07-24 17:37:46 +03:00
Emil 7ad28b939d Show live processing speed chart 2026-07-24 17:28:16 +03:00
Emil 1012f5d95a Allow demo worker count override 2026-07-24 17:21:45 +03:00
Emil f5baec507c Add final result preview button 2026-07-24 17:19:31 +03:00