Skip to content

w3a-foundation/onboarding

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

2 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

W3A Onboarding

The Web3 Alliance member-application lifecycle service. Receives applications from partners applying to join the W3A federation, moves them through review and committee voting, and emits state-change events to sponsoring members.

This is the canonical onboarding backend referenced by Web3_Alliance.tex §8 (Governance and Coordination) and the member-application taxonomy in members/REGISTRY.md.

Architecture

                      ┌───────────────────────┐
                      │   Hanzo IAM (JWKS)    │
                      └───────────┬───────────┘
                                  │ RS256 reviewer tokens
                                  ▼
  applicant  ──HMAC─►  ┌──────────────────────┐  ──CEK seal──►  ┌────────────┐
                       │   onboardingd (ZIP)  │                 │ Hanzo KMS  │
  reviewer  ──Bearer─► │  /v1/onboarding/*    │  ◄──KEK unwrap──│  (KEK)     │
                       └──────────┬───────────┘                 └────────────┘
                                  │
                                  ▼ append-only
                       ┌──────────────────────┐
                       │  SQLite + WAL +      │
                       │  Litestream replica  │
                       └──────────────────────┘
  • HTTP edge: github.com/hanzoai/zip (Sinatra-style on Fiber v3 / fasthttp). No net/http, no chi / gin / echo, no nginx / caddy.
  • Storage: SQLite via modernc.org/sqlite with the canonical Hanzo Base pragma list (WAL, synchronous=NORMAL, busy_timeout=10000, foreign_keys=ON, temp_store=MEMORY, cache_size=-32000). Litestream is configured at the orchestration layer (replica URL via env), not implemented in-process.
  • Auth: Hanzo IAM JWT bearer; JWKS fetched once at boot, refreshed on a fixed cadence. Two tiers:
    • applicant (HS256, service-issued at submit time) — read-only on the application's own status; can withdraw.
    • reviewer (RS256, IAM-issued) — can review, vote, and (with gc_override) drive manual transitions and register webhooks.
  • KMS: Application material is sealed under a random per-application AES-256-GCM CEK, which is in turn wrapped under the W3A KEK held by Hanzo KMS. Storage rows hold opaque ciphertext + wrapped CEK + AAD; decryption requires an auditable KMS unwrap call.
  • Audit: Every state transition, review, vote, manual transition, withdrawal, KMS unwrap, and webhook registration writes one immutable row.

State machine

SUBMITTED → UNDER_REVIEW → REVIEW_COMPLETE → COMMITTEE_VOTING → APPROVED → ONBOARDING → ACTIVE
                                            ↓
                                       REJECTED  (terminal)
                                       WITHDRAWN (applicant; terminal)

13 enumerated transitions; the table is the single source of truth (pkg/statemachine/statemachine.go). Review quorum is 2 distinct reviewers; vote quorum is 3 committee ballots.

API

All routes under /v1/onboarding. Authentication is Authorization: Bearer <jwt>.

Method Path Auth Description
POST /applications HMAC-signed (anon) Submit a new application; returns id + applicant-tier JWT.
GET /applications/:id applicant or reviewer Read the application's current state.
POST /applications/:id/withdraw applicant Applicant-initiated terminal exit.
GET /applications reviewer List + filter (state, jurisdiction, contribution_category).
POST /applications/:id/review reviewer Submit one review. Two reviews → COMMITTEE_VOTING.
POST /applications/:id/vote reviewer + committee Cast committee ballot. Quorum → APPROVED/REJECTED.
POST /applications/:id/transition reviewer + gc_override Manual GC override transition.
GET /applications/:id/audit-log applicant (own) or reviewer Full audit history.
POST /webhooks/state-change reviewer + gc_override Register outbound webhook URL for a sponsor.
GET /health none K8s liveness.
GET /ready none K8s readiness (store + JWKS).

Environment variables

Name Default Description
ONBOARDING_LISTEN :8080 HTTP listen address.
ONBOARDING_DB_PATH ./data/onboarding.db SQLite file path.
ONBOARDING_IAM_ISSUER https://iam.w3a.foundation JWT iss claim.
ONBOARDING_IAM_AUDIENCE w3a-onboarding JWT aud claim.
ONBOARDING_IAM_JWKS_URL derived JWKS endpoint.
ONBOARDING_HMAC_SECRET required base64 ≥32 bytes; applicant-token signing.
ONBOARDING_SUBMIT_HMAC required base64 ≥32 bytes; public submit HMAC.
ONBOARDING_KMS_ENDPOINT _required_¹ Hanzo KMS URL.
ONBOARDING_KMS_IAM_URL _required_¹ Hanzo IAM URL for KMS svc-auth.
ONBOARDING_KMS_CLIENT_ID _required_¹ KMS svc-account client_id.
ONBOARDING_KMS_SECRET _required_¹ KMS svc-account client_secret.
ONBOARDING_KMS_ORG w3a KMS org slug.
ONBOARDING_KEK_VERSION 1 KEK rotation marker.
ONBOARDING_LOCAL_KEK_B64 _unset_² base64 32-byte KEK for local dev.
ONBOARDING_SKIP_JWKS_FETCH _unset_² 1 to disable JWKS refresh (local dev).

¹ Required unless ONBOARDING_LOCAL_KEK_B64 is set.
² Local-dev only; never set in production.

Run

Local (compose)

docker compose up --build
curl -s http://localhost:8080/v1/onboarding/health | jq .

Tests

go test ./... -race

Build

go build ./...
go vet ./...
docker build -t ghcr.io/w3a-foundation/onboarding:dev .

CI

.github/workflows/ci.yml runs go build, go vet, and go test -race on every push. On tag v* it cross-builds static linux/amd64 and linux/arm64 binaries (matrix), then builds the multi-arch image on native runners (ubuntu-24.04 for amd64; ubuntu-24.04-arm for arm64) and pushes ghcr.io/w3a-foundation/onboarding:VERSION + :latest with a unified manifest. SLSA build-provenance attestations are pushed to GHCR alongside the image.

Native arm64 runners are the canonical path — they're meaningfully faster than QEMU emulation. If ubuntu-24.04-arm is unavailable on your GitHub plan, swap that matrix entry back to ubuntu-24.04 and add docker/setup-qemu-action@v3 before buildx; the build still produces the same multi-arch manifest, just slower.

No CI secrets beyond the default GITHUB_TOKEN are required — packages: write lets the GITHUB_TOKEN push to ghcr.io under the repository's namespace automatically.

Layout

cmd/onboardingd/        # service entrypoint + Hanzo KMS HTTP adapter
pkg/types/              # domain types (Application, Review, Vote, State, …)
pkg/store/              # Store interface + BaseStore (SQLite) + MemoryStore
pkg/store/migrations/   # embedded *.sql schema
pkg/handlers/           # ZIP route handlers (applications, reviews, votes, webhooks, health)
pkg/auth/               # JWT verifier + applicant/reviewer token issuance
pkg/kms/                # narrow KMSGetter + envelope seal/open
pkg/audit/              # immutable append-only audit writer
pkg/statemachine/       # transition table + quorum constants
pkg/webhook/            # outbound delivery with HMAC + retry

Discipline

  • One way to do everything. No alternate transports, no alternate storage engines, no alternate HTTP frameworks.
  • Every line owned by this repo or a pinned upstream — no vendored deltas, no forks.
  • Hash and sign — never store plaintext credentials, never store plaintext application material at rest.
  • Audit every action. The audit log is the system of record for who did what when.

About

Web3 Alliance (onboarding)

Resources

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors