Initial Commit

This commit is contained in:
jb
2026-09-18 23:15:05 -04:00
commit fdcc4863f5
118 changed files with 16868 additions and 0 deletions
+28
View File
@@ -0,0 +1,28 @@
# Security invariants and validation gates
These are requirements for the first implementation, not a claim of a production security audit.
- EVE character IDs identify characters, not EVE accounts. Application-user ownership is the aggregation boundary. No EVE account discovery exists here.
- SSO callback must verify OAuth state, browser binding, expiry, one-time use, PKCE, token signature, issuer, audience, authorized client, subject and granted scopes. A character-owner change cannot silently reuse the previous owner's identity.
- Connecting another character is an authenticated, explicit operation. Callback must preserve the initiating user/session binding. Character ownership conflicts fail closed; there is no implicit merge or transfer.
- Refresh tokens are envelope encrypted using a server-held encryption key with authenticated associated data. No raw refresh token or client secret may be a browser property, public Convex query field, URL parameter, log or exception message.
- Browser sessions use high-entropy opaque identifiers, server-side hashes, HttpOnly/SameSite cookies and bounded expiration. Application JWTs use a dedicated issuer/audience/key and short expiry, not EVE bearer tokens. Queries independently enforce the application identity and ownership.
- Server bridge authority is distinct from the deployment administrator credential and browser sessions. All privileged Convex entrypoints require it. Deployment keys are not application runtime defaults.
- State-changing browser requests require an exact allowed origin. Normal app pages use `Referrer-Policy: same-origin`: global `no-referrer` would make native POST navigations send `Origin: null` and fail CSRF verification. Auth responses retain `no-referrer` so callback grant URLs never become referrers. Null/missing/foreign origins remain rejected. No arbitrary user-provided fetch URLs, SQL identifiers, executable function names or tool invocations.
- Market/ESI errors are redacted before display. Observability reports route, status, timings and cache/rate-limit signals, never Authorization headers, OAuth codes or secrets.
- Authenticated ESI caches are keyed by character and authorization context. A partial sync cannot replace a complete snapshot. Token refresh is serialized for a character; stale token rotations cannot overwrite newer credentials.
- Fixture/demo data is explicitly opt-in and visibly marked. Live errors never trigger a silent fallback to demo assets or prices; live reference readers require a production-profile artifact.
- Reference archives are untrusted input. The production importer reads members without extracting arbitrary filesystem paths, rejects unsafe paths and unsupported member types, and enforces compressed/decompressed/member limits, XZ memory limits, archive checksums, and schema validation. Artifact paths/manifests must remain inside the configured reference directory. Cache reuse and fallback verify canonical hashes and the active artifact’s bound provenance; fixture caches cannot satisfy a production import.
- Infisical bootstrap credentials stay in an owner-only local file, separate from application keys. The launcher pins the approved instance and selected project/environment/path, suppresses raw credential-command output, and does not pass bootstrap credentials or the vault token to the application. Application secrets are injected only from an allowlist; deployment admin access requires an explicit operator command. Docker/host administrators can still inspect container environment values.
- No model determines permissions, financial arithmetic, ownership, scope grants, docking rights or whether a synchronization succeeded.
## First-pass operational limits
- Explicit character synchronization revalidates the refresh grant and owner continuity even if ESI asset pages remain fresh in the cache. Ordinary report reads use previously authorized snapshots until their advertised expiry; there is no claim of instantaneous EVE revocation/transfer detection.
- Logout clears the local cookie even if Convex is unavailable, and reports when server-side revocation could not be confirmed. A copied server session may remain valid until normal expiry in that failure case.
- OAuth initiation is origin-checked and rate-limited. Expired OAuth states are reclaimed in bounded batches during subsequent initiation; this is not a full retention service.
- Old asset generations, session tombstones and interaction summaries still need production retention/GC. Monitor disk usage and do not expose this initial deployment to untrusted multi-user traffic before that work. Pending OAuth state is consumed before token exchange deliberately: an uncertain exchange must restart authorization rather than risk replaying a one-time code.
## Deployment gate
Before exposing a host: configure HTTPS and exact origins/callback URL; generate independent high-entropy signing/encryption/bridge secrets; pin backend image digests; back up and restore-test Convex and reference artifact volumes; exercise live SSO/refresh/revocation, account separation and partial-sync recovery. Restrict the dashboard/admin ports to loopback or a management network. Establish secret rotation, account recovery/unlink and retention procedures before inviting other users.