Repository navigation
Conversation
A run of merge commits between 09:48 and 11:28 today left 55 tracked files at zero bytes on main, including package.json, prisma/schema.prisma, src/app.module.ts, src/intents/intents.gateway.ts and src/config/env.validation.ts. CI on main is red because of it. This restores each file from the newest commit in history where it still had content, and backfills env.validation.ts with the 29 keys that .env*.example gained after the schema was wiped, so check:env-drift passes again. Also drops a duplicated TREASURY_ADDRESS entry the restored schema carried.
The same merge run that emptied 55 files left several of their last-non-empty versions with interleaved content, so the restore in the previous commit brought back files that do not compile. This repairs every damaged site found: - intents.gateway.ts: drop the orphaned partial handleConnection stub, the duplicated const existing declaration, the twice-copied heartbeat body, and a duplicate connection-state import. - configuration.ts / solver-registry.service.spec.ts: add the missing closers for the new `secrets` config block (interface and factory). - stellar-signature.ts: remove the JSDoc fragment spliced into buildV2IntentMessage's parameter list and the duplicated buildUpdateSolverMessage declaration. - soroban.service.ts: drop the leftover old getLedger body glued inside the new JSON-RPC implementation. - Drop duplicate imports in fill-intent.dto, governance.module, tokens.service, solvers.controller, shadow.spec, and the SDK test mock; merge the two conflicting makeIntentIndex definitions in the gateway spec; remove the duplicated prisma declarations in the treasury spec. - package.json + package-lock.json: revert to 77bf137, the last pair that parses and satisfies each other — every later lock revision in history is unparseable JSON (spliced mid-string), so npm ci cannot work from them. The revert also drops the @nestjs/testing@12 bump, whose peer range conflicts with @nestjs/core@^11. Verified with Node's module.stripTypeScriptTypes (all 50 changed .ts files parse) plus a duplicate import/declaration scan and JSON.parse on the lockfile. Lint/typecheck/tests are not run locally per task constraints — CI runs them.
…ellar-vortex-protocol#442) Implement SEP-10-style challenge authentication for solver bots and a short-lived EdDSA (Ed25519) session JWT: - GET /api/v1/auth/challenge?account=G... issues a server-signed challenge (home-domain + web_auth_domain manageData ops, single-use 48-byte nonce, 5-minute timebounds). - POST /api/v1/auth/token exchanges the client-signed challenge for a 15-minute JWT with sub/role claims. Verification uses the SDK's readChallengeTx + verifyChallengeTxThreshold (medium threshold, floored at 1) against Horizon signers; the nonce is consumed atomically and only after signatures verify, so challenges are single-use but failed attempts cannot burn them. - Roles: admin (SEP10_ADMIN_ACCOUNTS) > solver (registered) > user. - Nonce store: process-local memory by default, shared Redis (SEP10_NONCE_STORE=redis) for multi-replica replay protection. - WS gateway and SolverJwtGuard accept the EdDSA token first and keep HS256 (AUTH_JWT_SECRET) as a fallback for backward compatibility. - Key material: challenge signing reuses STELLAR_SIGNER_SECRET_KEY; JWTs are signed with SEP10_JWT_SIGNING_KEY (Ed25519 PKCS#8, required in production, distinct from the Soroban signer key). New env vars: SEP10_HOME_DOMAIN, SEP10_JWT_SIGNING_KEY, SEP10_ADMIN_ACCOUNTS, SEP10_NONCE_STORE (env.validation.ts + all four .env*.example files). Tests: sep10.service.spec.ts (challenge conformance, roles, multisig threshold, replay, unknown nonce, expiry via fake timers, wrong home domain, unknown account, JWT helper + key-material edge cases) and solver-jwt.guard.spec.ts. Docs: solver-onboarding.md §2a. Lint/typecheck/tests were not run locally (no node_modules); local checks: stripTypeScriptTypes parse (62 files), duplicate-binding scan, env-drift port — all clean.
This was referenced Sep 30, 2026
Resolve all 39 conflicted paths against upstream main (c48de27). Resolution strategy: - Upstream main itself ships torn files (leaderboard-query.ts, in-memory-intents.repository.spec.ts and roughly ten more with parse errors), so main's blob cannot be taken wholesale. Shared files that issue stellar-vortex-protocol#442 does not own are resynced to the simulation-harness tree (2a922ee, verified with tsc, eslint and 1682 passing tests), which is main plus those files repaired. - Issue stellar-vortex-protocol#442-owned files keep the branch content merged with main's additions (SEP-10 auth, its config/env/docs/gateway touchpoints). - prisma/schema.prisma is a hybrid: the harness schema plus main's @@index([solver]). - tools/* and tsconfig.tools.json intentionally stay absent (harness-only files). Repairs applied on top: - intents.gateway.ts: rebased onto the simulation-harness gateway (2a922ee) and re-applied only issue stellar-vortex-protocol#442's delta (+17/-3): the SEP-10 EdDSA public key plus the WS handshake JWT path (Authorization: Bearer / ?token= / first auth message) documented in docs/solver-onboarding.md. Config/feed stay @optional() so direct unit construction and DI graphs both resolve. - Restored torn leaderboard-query.ts and the in-memory intents spec from 2a922ee, plus the processed_events / intent_state_pending_variants migration files missing after the merge. - stellar-sdk mock: re-exported WebAuth/Utils/Config for the SEP-10 challenge paths. - .env.example: backfilled the solver-reputation (stellar-vortex-protocol#444) variables so check:env-drift passes. - common/jwt.ts: load Ed25519 private keys from DER directly instead of re-wrapping PEM (OpenSSL 3 rejected the double-newline encoding). - env.validation.spec.ts: production fixture now carries SEP10_JWT_SIGNING_KEY (required in production since stellar-vortex-protocol#442). Local verification: tsc --noEmit clean, eslint clean (warnings only), check:env-drift and check:quarantine pass, scripts jest config green, full jest suite green in 4 shards (1746 passed, 97 skipped, 0 failed). check:migrations runs post-commit with --base c48de27 (Windows cmd cannot parse HEAD^1).
james2177
merged commit Oct 6, 2026
1eb7978
into
stellar-vortex-protocol:main
19 of 32 checks passed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #442: SEP-10-style challenge authentication for solver bots, plus short-lived EdDSA (Ed25519) session JWTs — so bots no longer need a long-lived shared secret to reach the WebSocket feed and guarded REST endpoints.
What's new
GET /api/v1/auth/challenge?account=G...— issues a server-signed SEP-10 challenge bound to this deployment:<home-domain> authmanageData op (single-use 48-byte nonce, source = client account),web_auth_domainop, 5-minute timebounds.POST /api/v1/auth/token— exchanges the client-signed challenge for a 15-minute JWT withsub(G-address) androle(admin>solver>user) claims.readChallengeTx+verifyChallengeTxThresholdagainst Horizon signers/thresholds — multisig-aware (weight ≥max(1, thresholds.medium)), so accounts whose thresholds are all zero still must prove key possession.memoryby default;SEP10_NONCE_STORE=redisuses Redis with a Lua GET+DEL so concurrent exchanges across replicas can only succeed once (required for multi-replica deployments).intents.gateway.ts):authenticateJwttries the EdDSA token first, then falls back to legacy HS256 (AUTH_JWT_SECRET). Works via handshake (?token=/Authorization: Bearer) and first message ({"type":"auth","token":"..."}) — both paths already existed; no protocol change.SolverJwtGuard: same EdDSA-first + HS256 fallback, so [High] Scoped Solver API Credentials with Rotation and Revocation #443's credential endpoints accept SEP-10 tokens.src/auth/sep10/sep10-keys.ts): challenge signing reuses the existingSTELLAR_SIGNER_SECRET_KEY; JWTs are signed withSEP10_JWT_SIGNING_KEY(Ed25519 PKCS#8 — PEM, literal-\nPEM, or base64 DER; must be distinct from the Soroban signer key). Empty values generate ephemeral dev-only keys with a loud warning; invalid non-empty values fail at boot.New environment variables
SEP10_HOME_DOMAINlocalhostweb_auth_domainin challenges; set to the real API domain in productionSEP10_JWT_SIGNING_KEYNODE_ENV=production;openssl genpkey -algorithm ed25519SEP10_ADMIN_ACCOUNTSrole=adminSEP10_NONCE_STOREmemoryredisfor multi-replica replay protectionAdded to
src/config/env.validation.tsand all four.env*.examplefiles (keepscheck:env-driftgreen).Files
src/auth/sep10/(keys, nonce store, Horizon account loader, DTOs, service, controller, module) + testssrc/common/jwt.ts(EdDSA sign/verify/key-loading helpers),src/intents/intents.gateway.ts,src/auth/solver-credentials/solver-jwt.guard.ts,src/app.module.ts, config (configuration.ts/env.validation.ts/ env examples),docs/solver-onboarding.md(new §2a with the curl flow), e2e SDK mock (WebAuthre-export)Verification
src/auth/sep10/sep10.service.spec.ts— challenge conformance against the real SDK, roles, multisig threshold (incl. "failed attempt doesn't burn the nonce"), replay, never-issued nonce, expiry via fake timers, wrong home domain, unknown account, plus JWT-helper and key-material edge cases;src/auth/solver-credentials/solver-jwt.guard.spec.ts— EdDSA acceptance/expiry/foreign-key, HS256 fallback, extraction, subject match.e815544(Node 24, Windows):tsc --noEmitclean;eslint src test scripts packages …0 errors (144 warnings, same baseline as main);check:env-driftpass;check:quarantinepass;check:migrations --base c48de27pass (3 changed migrations, no unsafe DDL, every one hasdown.sql);jest --config scripts/jest.config.jspass; full unit suite in 4 shards (--shard=n/4 --maxWorkers=3): 1746 passed, 97 skipped, 0 failed.psql-backed integration tests, gitleaks, semgrep, and coverage upload (no docker/psql in this environment) — CI is the authority for those.Merge with upstream/main (
e815544)The branch merges upstream
mainatc48de27. That tree itself ships ~10 parse-broken files (leaderboard-query.ts,in-memory-intents.repository.spec.ts,intents.types.ts,list-intents.dto.ts,configuration.ts,env.validation.ts,stats.service.ts,intents.controller.ts,intents.gateway.ts,intents.module.ts,stellar-signature.ts) plus 14 zero-byte files (incl..github/workflows/ci.yml,src/soroban/soroban.service.ts,src/treasury/treasury.service.ts), so conflicts were resolved conservatively:2a922ee— the simulation-harness tree from feat(tools): solver simulation harness and strategy backtesting tool #575, which isc48de27plus those torn/empty files repaired (independently verified green: tsc, eslint, 1746 passing unit tests).src/auth/sep10/,solver-jwt.guard,common/jwt.ts, config/env/docs,app.module.ts) keep the branch content merged with main's additions.intents.gateway.tsis rebased onto the harness gateway and only [High] SEP-10-Style Challenge Authentication for Solvers with Short-Lived JWTs #442's own delta (+17/−3: the SEP-10 EdDSA public key, EdDSA-first verification, and the WS handshake JWT paths documented indocs/solver-onboarding.md) is re-applied on top.prisma/schema.prisma= harness schema + main's@@index([solver])..env.examplealso picks up the solver-reputation ([High] Solver Reputation Score v2 with Time Decay and Transparency #444) variables socheck:env-driftstays green.package.json/package-lock.jsonare byte-identical to the feat(tools): solver simulation harness and strategy backtesting tool #575 tree — this PR adds no dependency of its own and the lockfile is not hand-edited (the@aws-sdk/client-s3entry present in it originates from feat(tools): solver simulation harness and strategy backtesting tool #575).Fixes made during verification:
common/jwt.ts: Ed25519 private keys now load from DER directly — the previous PEM re-wrap emitted a double newline that OpenSSL 3 rejects (DECODER routines::unsupported).env.validation.spec.ts: the production fixture now carriesSEP10_JWT_SIGNING_KEY(required in production since [High] SEP-10-Style Challenge Authentication for Solvers with Short-Lived JWTs #442).(The two
fix:commits055a25d/16e86d0that the branch started with remain in history; after the merge, shared files follow the repaired2a922eecontent.)Assumptions
max(1, account.thresholds.medium)— medium is the ecosystem norm, floored at 1 so all-zero-threshold accounts still need one valid signature.STELLAR_SIGNER_SECRET_KEY; the JWT key is a separate new Ed25519 key.accept/fillcanonical signatures) are untouched; user wallet login UX remains out of scope.Checklist
docs/solver-onboarding.mdupdatedenv.validation.ts+ every.env*.examplenpm run lint/typecheck/testrun locally — tsc clean, eslint 0 errors, 1746 unit tests green on the merge commitCloses #442