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.
This commit is contained in:
Efremenko Arhip
2026-07-26 19:18:50 +03:00
parent c6a66747eb
commit 80ff72a0fe
13 changed files with 195 additions and 18 deletions
+6 -4
View File
@@ -13,8 +13,9 @@ import (
// Claims is the subset of a userservice token the coordinator cares about.
type Claims struct {
UserID uuid.UUID
Role string
UserID uuid.UUID
Role string
Verified bool
}
// Verifier checks tokens against the shared HS256 secret.
@@ -32,7 +33,8 @@ func NewVerifier(secret string) *Verifier {
}
type claims struct {
Role string `json:"role"`
Role string `json:"role"`
Verified bool `json:"verified"`
jwt.RegisteredClaims
}
@@ -54,5 +56,5 @@ func (v *Verifier) Verify(raw string) (Claims, error) {
if err != nil {
return Claims{}, fmt.Errorf("token subject is not a uuid: %w", err)
}
return Claims{UserID: id, Role: c.Role}, nil
return Claims{UserID: id, Role: c.Role, Verified: c.Verified}, nil
}