Repository navigation
Audit hash chain, IPFS pinning, dynamic limits, OTel - #1732
Merged
ayomideadeniran merged 2 commits intoOct 22, 2026
Merged
ayomideadeniran merged 2 commits into
ayomideadeniran merged 2 commits into
Conversation
Resolves StellarDevHub#1581. Resolves StellarDevHub#1583. Resolves StellarDevHub#1584. Resolves StellarDevHub#1585.
|
@nafiisatu is attempting to deploy a commit to the Ayomide Adeniran's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@nafiisatu 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! 🚀 |
Contributor
|
Thank you for your contribution! This PR is currently under review. If I find any incorrect implementation or issues, I will leave comments on what needs to be adjusted next. |
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 #1581, closes #1583, closes #1584, closes #1585
#1581 — BE-009: Tamper-evident audit hash chain + Stellar anchoring
backend/src/db/auditChainStore.ts: stores the chain in the newaudit_chain_entriesandaudit_chain_anchorstables. Appends run under a PostgreSQL advisory lock, so concurrent instances always link to the real head. The app assigns sequence numbers itself (head + 1), so a deleted row always leaves a gap. An in-memory store is included for tests.backend/src/services/tamperEvidentAuditService.ts: each entry'sentryHash = SHA-256(prevHash ‖ canonicalJSON(entry)), starting from an all-zero genesis hash.verifyChain()reads the chain in batches with one hash per entry, so it is designed to stay under 1s per 10k rows. It detects:HASH_MISMATCH)SEQUENCE_GAP,CHAIN_BREAK)TRUNCATED)ANCHOR_MISMATCH, checked against the latest Stellar anchor)On any failure it raises a critical alarm through a structured
CRITICALlog, Sentry, atamperevent and an optionalAUDIT_ALARM_WEBHOOK_URL.backend/src/jobs/anchorMerkleRootJob.ts:MEMO_HASHand in amanageDataentry namedw3sl_audit_root.verifyPublishedAnchor()reads the memo back from Horizon and compares it with a fresh local computation.startAuditChainJobs()schedules routine verification and anchoring whenAUDIT_CHAIN_JOBS_ENABLED=true.The migration adds an append-only trigger to
audit_chain_entriesas an extra safeguard. The hash chain and the anchors still catch anyone who drops the trigger.logAudit()now also writes every existing audit event into the chain.New admin endpoints:
GET /api/v1/audit/chain/verifyGET /api/v1/audit/chain/anchorsGET /api/v1/audit/chain/anchors/:id/verify#1583 — BE-011: IPFS/Filecoin dual-pinning pipeline
backend/src/config/ipfs.ts: environment-driven settings for:backend/src/services/ipfsPinningService.ts:pinned_assetstable. A trigger blocks any rewrite of a stored CID.autoPinCertificate()pins a rendered certificate SVG plus the metadata JSON (withimage: ipfs://<svgCid>) within a 3s deadline.CertificateServicecalls it right after minting.backend/src/controllers/mediaController.tsandroutes/media.routes.ts, mounted at/api/v1/media:#1584 — BE-012: Sliding-window limiter with IP/DID reputation
backend/src/utils/slidingWindow.ts: a Redis sorted-set limiter that keeps a timestamp per request, so there are no fixed-window boundary spikes. The burst and sustained windows are checked in one atomic Lua call: a request either counts against every window or against none, so rejected requests use no quota. Keys use a hash tag so all of a caller's windows land on the same Redis Cluster node. If Redis fails, it falls back to an in-memory limiter.backend/src/services/reputationService.ts: scores each caller from these signals:The score sets the tier:
restricted→anonymous→authenticated→verified→staker. Only authenticated DIDs with an active stake reachstaker. Profiles are cached for 60s.backend/src/middleware/dynamicRateLimiter.ts: applies the caller's tier limits on every response.X-RateLimit-Limit,X-RateLimit-Remaining,X-RateLimit-Reset,X-RateLimit-TierandRateLimit-Policy.Retry-After, and the violation is recorded so repeat offenders drop a tier./api. Disable it withDYNAMIC_RATE_LIMIT_ENABLED=false; it is skipped underNODE_ENV=test.#1585 — BE-013: OpenTelemetry tracing with Jaeger and Prometheus
backend/src/instrumentation.ts:@opentelemetry/sdk-nodeand exports traces over OTLP/HTTP to Jaeger (OTEL_EXPORTER_JAEGER_ENDPOINT).injectTraceContext,extractTraceContext,runInSpan,traceEnqueue,traceJob.skipOpenTelemetrySetupso the OTel SDK owns the global tracer.backend/src/middleware/tracingMiddleware.ts:traceparent, and returns atraceresponseheader.w3sl_tracing_overhead_secondsso the < 1.5ms budget can be checked.compileQueue.enqueueadds the trace context to job data inside a PRODUCER span.compileWorkerruns each job as a CONSUMER child span.createWsSync) carries_tracein each message envelope and continues it on receive.backend/src/metrics/prometheusExporter.ts: dependency-free histograms and counters in the standard Prometheus text format, appended to the existing/api/v1/metrics/prometheusscrape:w3sl_http_server_request_duration_secondsw3sl_tracing_overhead_secondsw3sl_queue_job_duration_secondsw3sl_pubsub_messages_totalNotes
@opentelemetry/*dependencies tobackend/package.json. Lockfiles were not regenerated, since nothing was installed or run.20261020000000_audit_chain_and_pinned_assetsand matching Prisma models (PinnedAsset,AuditChainEntry,AuditChainAnchor).backend/.env.example.Closes #1581
Closes #1583
Closes #1584
Closes #1585