Repository navigation
feat: canonical audit logAction helpers, Horizon network-failure retry coverage, SEP-24 standard validation envelope - #850
Merged
Cjay-Cyber-2 merged 2 commits intoOct 19, 2026
Conversation
…EP-24 400 envelope - mergepay#660: add canonical logAction/logActionTx repository helpers to src/services/audit.ts and adopt them at the group, expense and settlement state-changing call sites (atomic, sanitized metadata). - mergepay#681: record actor type and outcome on group.create / group.join audit rows; add route-level tests proving the persisted rows. - mergepay#688: add network-failure retry tests for Horizon polling covering TransportError/TimeoutError retries, budget exhaustion, permanent rejection, configurable attempts, and structured Pino logging. - mergepay#687: add a consolidated standard-400 VALIDATION_ERROR envelope test across every SEP-24 surface (deposit, withdraw, transaction, transactions, callback), including both validator boundaries. Closes mergepay#660 Closes mergepay#681 Closes mergepay#687 Closes mergepay#688
|
@EniolaTrev Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
Cjay-Cyber-2
approved these changes
Oct 19, 2026
Cjay-Cyber-2
left a comment
Collaborator
There was a problem hiding this comment.
Looks good — approving.
Cjay-Cyber-2
approved these changes
Oct 19, 2026
Cjay-Cyber-2
left a comment
Collaborator
There was a problem hiding this comment.
Looks good — approving.
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.
Closes #660
Closes #681
Closes #687
Closes #688
Summary
This branch addresses four assigned issues together, in the way the repo's own history has handled them: each feature is already largely present from earlier upstream merges, so the work here is an audit against the acceptance criteria, closing the concrete gaps the audit found, and adding the missing proof — while leaving the existing, tested architecture intact.
The concrete deliverables added by this PR:
logAction(...)helper insrc/services/audit.ts; the durable audit writer existed under different names (audit/auditTx). This PR adds the canonicallogAction/logActionTxentry points and adopts them at the AC-named state-changing call sites, with unit tests pinning the column mapping.auditGroupMemberActionTx/auditMultisigActionTxalready existed; this PR adopts the canonical helper at group creation / member addition, recordsactorTypeandoutcomeon those rows, and adds the missing success-path route tests (member addition had no positive audit test).src/services/horizon-retry.ts+src/services/retry.tsand is wired into the worker. This PR adds the AC-worded network-failure suite: retry attempts, budget exhaustion, final error propagation, configurable attempt counts, and structured Pino logging.400 VALIDATION_ERRORenvelope withdetails+issuesacross all five SEP-24 surfaces and both validator boundaries.Changes in this PR
src/services/audit.tsLogActionParams,logAction,logActionTx(maps issue vocabulary → persisted columns)src/routes/groups.ts,src/routes/expenses.ts,src/routes/settlements.ts,src/services/settlement-machine.tsgroup.create,group.join,expense.create,settlement.create,settlement.status_changednow write throughlogActionTxtests/services/audit-logAction.test.ts(new, 7 tests),tests/audit-state-changing-operations.test.ts(new, 3 tests)tests/horizon-network-failure-retry.test.ts(new, 6 tests)maxAttempts, permanenttx_*rejection, Pino retry log fieldstests/sep24-standard-validation-envelope.test.ts(new, 28 tests)tests/audit-actor-attribution.test.ts,tests/settlement-reconciliation.test.ts,tests/settlement-memo-integration.test.tslogAction*helpers; two module mocks expose the newlogActionTxexportAcceptance criteria, mapped
#660 — AuditLog migration + Prisma repository service
AuditLogmodel inprisma/schema.prisma—prisma/schema.prisma:495(id, actoruserId,action, resourceentityType/entityId,metadataJSON,detailsJSON,createdAttimestamp; indexes onuserId,groupId,(entityType, entityId); mapped toaudit_logs).prisma/migrations/20260614120000_init(createsaudit_logs),20260725000001_add_audit_log,20260728000000_add_audit_log_group_id;npx prisma generateruns clean (verified on this branch).src/services/audit.tsprovideslogAction(...)used across route handlers — newlogAction/logActionTxinsrc/services/audit.ts; adopted insrc/routes/groups.ts(group.create,group.join),src/routes/expenses.ts(expense.create),src/routes/settlements.ts(settlement.create),src/services/settlement-machine.ts(settlement.status_changed).tests/services/audit-logAction.test.ts(mapping, null actor for worker/system, metadata sanitization, structured mirror, rollback semantics);tests/audit-state-changing-operations.test.tsasserts the exact rows handed toprisma.auditLog.createfor group creation and member addition; expense audit writes are covered bytests/expense-action-audit.test.tsand the unchanged route suites.#681 — Audit logging for state-changing group/treasury operations
groupId(migration20260728000000_add_audit_log_group_id), so every group-scoped row can be queried per group.src/services/—src/services/audit.ts: durableaudit/auditTx, canonicallogAction/logActionTx, plusauditGroupMemberActionTxandauditMultisigActionTxfor membership and multisig events.src/routes/groups.ts), expense creation (src/routes/expenses.ts), settlement creation and status transitions (src/routes/settlements.ts,src/services/settlement-machine.ts), treasury multisig proposal/sign/submit (src/routes/treasury.tsviaauditMultisigActionTx).tests/audit-state-changing-operations.test.ts(group.create + group.join rows with actor, target,outcome: "success",actorType: "user"); existingtests/integration/group-expense-database.test.tsassertsgroup.create/group.joinrows end-to-end;tests/treasury-multisig-audit.test.tscovers the multisig rows.sanitizeAuditMetadataredactsprivateKey/secret/token/xdrkeys to[REDACTED]; asserted intests/services/audit-logAction.test.ts. No private key material or signed envelopes are ever persisted or logged.logActionTxinside the sameprisma.$transactionas the mutation). A post-hoc request middleware would (a) double-log every route that already audits, and (b) break the atomicity guarantee — an audit row would survive a rolled-back mutation. The transactional helpers are the stronger implementation of the same requirement.#687 — Zod validation for SEP-24 deposit/withdrawal
src/validations/sep24.ts(sep24DepositRequestSchema,sep24WithdrawRequestSchema,sep24InitQuerySchema,sep24TransactionQuerySchema,sep24TransactionsQuerySchema,sep24CallbackQuerySchema), re-exported fromsrc/schemas/sep24.ts, which also exports thevalidateSep24Deposit/validateSep24WithdrawFastify middleware named in the issue.src/routes/sep24.ts— the deposit/withdraw preHandlers parse query + body before any anchor I/O; the transaction, transactions, and callback handlers parse inline before any database work.src/plugins/error-handler.tsrenders bothZodErrorand Fastify/ajvFST_ERR_VALIDATIONfailures as400with{ error: { code: "VALIDATION_ERROR", message, timestamp, requestId, details, issues } }and legacy top-level mirrors. Newtests/sep24-standard-validation-envelope.test.tsproves the identical envelope on all five surfaces, including the ajv boundary and unrecognized-key rejection, and asserts no anchor call or DB read happens first.tests/sep24-request-validation.test.ts,tests/sep24-callback-validation.test.ts,tests/sep24-init-validation.test.ts,tests/sep24-validation.test.ts,tests/sep24-transaction-status.test.ts,tests/sep24-transactions-list.test.ts) plus the new consolidated envelope suite (28 tests).#688 — Horizon retry logic in the background worker
src/services/—src/services/horizon-retry.ts:withHorizonRetrywithclassifyHorizonError(transient / indeterminate / permanent),horizonRetryDelayMs(exponential + jitter),HORIZON_RETRY_POLICY; andsrc/services/retry.ts(withRetry+defaultReadPolicy).TransportError/TimeoutError(src/services/timeout.ts) are classified explicitly;logRetryAttempt(src/services/retry.ts:471) emits structured per-attempt Pino records and is wired throughsrc/services/stellar.ts,src/services/anchor.ts,src/services/network.ts. New test pins the exact log fields.src/worker/tasks/tx-status-sync.tswraps every Horizon lookup inwithHorizonRetry; attempt budgets come from config:HORIZON_READ_RETRY_MAX_ATTEMPTS(src/services/horizonService.ts),UPSTREAM_RETRY_MAX_ATTEMPTS(src/services/retry.ts), and job-levelWORKER_SETTLEMENT_RETRY_*/WORKER_ANCHOR_RETRY_*(src/services/job-retry.ts).tests/horizon-network-failure-retry.test.ts(retry-then-succeed, timeout as indeterminate, exhaustion preserving the last error, configurablemaxAttempts); existingtests/horizon-retry.test.ts,tests/horizon-query-retry.test.ts,tests/stellar-horizon-retry.test.ts,tests/network-retry.test.ts,tests/worker/health.test.tsremain green.Tests & validation
npm test— 200 test files, 4077 passed, 22 skipped (baseline before this branch: 196 files / 4033 passed — the four new suites add 44 tests).npm run build(tscstrict) — clean.npm run lint— 0 errors (pre-existingno-unused-varswarnings unchanged).tests/services/audit-logAction.test.tsand the SEP-24 callback suite mock only public material.Reviewer notes
actorType/outcomemetadata on two group audit rows, and wider matching in an existing inventory test. No route contracts changed.