All checks were successful
CI / Format (push) Successful in 44s
CI / CUDA type-check (push) Successful in 1m40s
CI / Clippy (push) Successful in 3m14s
CI / Test (push) Successful in 6m29s
CI / Build cortex SRPM (push) Has been skipped
CI / Publish cortex to COPR (push) Has been skipped
CI / Build neuron SRPM (push) Has been skipped
CI / Publish neuron to COPR (push) Has been skipped
CI / Bump version in source (push) Has been skipped
The human-facing account surface the helexa.ai frontend (F4) consumes, on top of B2's authz surface. Email+password auth with JWT sessions (distinct from inference API keys); plain-JSON errors (the #63 envelope stays on the authz surface). - Auth lifecycle: register → email-verify → login → password-reset (request/confirm). argon2id passwords; verify/reset via single-use sha256-hashed email tokens; register and reset-request always return 202 (no account enumeration). Email via a pluggable EmailSender (lettre Smtp + dev Log transport). - API keys: create (sk-helexa-<base62(32 OsRng)>, raw shown once, stored as sha256 + non-secret prefix), list (prefix never the secret), archive, PATCH per-key limit (percent|hardcap). Protected by a JWT session middleware. - Account balance endpoint (allocation total/spent/reserved). - Silent fingerprint abuse: register captures the browser fingerprint; >= threshold (default 5) accounts sharing one fingerprint are silently deactivated + flagged — registration still returns a normal 202, and a deactivated account's key resolves as an ordinary 401 at the authz surface (no "banned" signal anywhere). - crypto: argon2 hash/verify + CSPRNG token/key minting (base62). config gains [auth] + [email]. CORS on the app for the browser SPA. Validated against a throwaway Postgres 16: verify-once, full lifecycle (register→verify→login→create key→account→list→authz resolve→archive→401), and 5-same-fingerprint → all accounts silently deactivated + no-clue 401. 8 unit + 11 gated integration tests; all skip cleanly without UPSTREAM_TEST_DATABASE_URL so CI stays green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01F6o3ddqmYNh9kzdwq6eowh
64 lines
1.7 KiB
TOML
64 lines
1.7 KiB
TOML
[package]
|
|
name = "helexa-upstream"
|
|
version.workspace = true
|
|
edition.workspace = true
|
|
license.workspace = true
|
|
repository.workspace = true
|
|
|
|
[[bin]]
|
|
name = "helexa-upstream"
|
|
path = "src/main.rs"
|
|
|
|
[lib]
|
|
name = "helexa_upstream"
|
|
path = "src/lib.rs"
|
|
|
|
[dependencies]
|
|
tokio = { workspace = true }
|
|
axum = { workspace = true }
|
|
tower-http = { workspace = true }
|
|
serde = { workspace = true }
|
|
serde_json = { workspace = true }
|
|
figment = { workspace = true }
|
|
anyhow = { workspace = true }
|
|
thiserror = { workspace = true }
|
|
clap = { workspace = true }
|
|
tracing = { workspace = true }
|
|
tracing-subscriber = { workspace = true }
|
|
chrono = { workspace = true }
|
|
|
|
# PostgreSQL — the mesh authority's system of record. Runtime query API
|
|
# (not the compile-time `query!` macros) so the crate builds in CI without a
|
|
# live database or a committed `.sqlx` offline cache; correctness is covered
|
|
# by the gated integration tests. (Macro adoption is a later refinement once
|
|
# a dev DB + offline cache exist.)
|
|
sqlx = { version = "0.8", default-features = false, features = [
|
|
"runtime-tokio",
|
|
"tls-rustls",
|
|
"postgres",
|
|
"macros",
|
|
"migrate",
|
|
"chrono",
|
|
"uuid",
|
|
] }
|
|
uuid = { version = "1", features = ["v4", "serde"] }
|
|
sha2 = "0.10"
|
|
subtle = "2.6"
|
|
# Web auth (B4): argon2id password hashing, JWT sessions, CSPRNG secrets,
|
|
# transactional email.
|
|
argon2 = "0.5"
|
|
jsonwebtoken = "9"
|
|
rand = "0.8"
|
|
lettre = { version = "0.11", default-features = false, features = [
|
|
"tokio1-rustls-tls",
|
|
"smtp-transport",
|
|
"builder",
|
|
] }
|
|
|
|
# cortex-core for the shared #63 OpenAiError envelope on the authz surface.
|
|
cortex-core = { workspace = true }
|
|
|
|
[dev-dependencies]
|
|
figment = { workspace = true, features = ["test"] }
|
|
reqwest = { workspace = true }
|