Files
SciMesh/users/internal/domain/workerkey_test.go
T
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

62 lines
1.7 KiB
Go

package domain_test
import (
"strings"
"testing"
"time"
"github.com/google/uuid"
"github.com/emil28092005/SciMesh/users/internal/domain"
)
func TestNewWorkerKeyShape(t *testing.T) {
owner := uuid.New()
now := time.Date(2026, 7, 26, 0, 0, 0, 0, time.UTC)
key, raw, err := domain.NewWorkerKey(owner, "home-desktop", now)
if err != nil {
t.Fatalf("NewWorkerKey: %v", err)
}
if !strings.HasPrefix(raw, "scimesh_wk_live_") {
t.Errorf("raw key has no recognisable label: %q", raw)
}
if key.TokenHash != domain.HashWorkerKey(raw) {
t.Error("stored hash does not match the plaintext")
}
if key.TokenHash == raw || strings.Contains(key.TokenHash, raw) {
t.Error("plaintext leaked into the stored hash")
}
if !strings.HasPrefix(raw, key.Prefix) {
t.Errorf("prefix %q is not a leading slice of the key", key.Prefix)
}
if key.UserID != owner || key.CreatedAt != now || key.Revoked() {
t.Errorf("unexpected key metadata: %+v", key)
}
}
func TestNewWorkerKeyDefaultsBlankName(t *testing.T) {
key, _, err := domain.NewWorkerKey(uuid.New(), " ", time.Now())
if err != nil {
t.Fatalf("NewWorkerKey: %v", err)
}
if key.Name == "" {
t.Error("blank name was not defaulted")
}
}
func TestNewWorkerKeyRejectsLongName(t *testing.T) {
_, _, err := domain.NewWorkerKey(uuid.New(), strings.Repeat("x", 101), time.Now())
if err != domain.ErrWorkerKeyNameTooLong {
t.Errorf("got %v, want ErrWorkerKeyNameTooLong", err)
}
}
func TestNewWorkerKeyUniquePerCall(t *testing.T) {
a, rawA, _ := domain.NewWorkerKey(uuid.New(), "a", time.Now())
b, rawB, _ := domain.NewWorkerKey(uuid.New(), "b", time.Now())
if rawA == rawB || a.TokenHash == b.TokenHash || a.ID == b.ID {
t.Error("two keys collided; generation is not random")
}
}