feat(config): fail-fast validation + standalone typecheck script (#230) - #231
Merged
Jagadeeshftw merged 8 commits intoAug 29, 2026
Conversation
…t monetary precision (AnchorNet-Org#236) * fix(AnchorNet-Org#225): replace float arithmetic with bigint for exact monetary precision * fix(AnchorNet-Org#225): add all bigint migration files missing from previous commit
…et-Org#228] (AnchorNet-Org#235) Aggregate metrics (participant counts, liquidity totals, settlement volume and fees over time) describe the network's operational state. Exposing that publicly should be deliberate, not a side effect of the write-only auth middleware, whose MUTATING_METHODS set left every GET unauthenticated and unlimited. - Auth: new metricsAuth guards GET /api/v1/metrics and /history. When API_KEY or the new read-only METRICS_API_KEY is set, reads require a matching x-api-key (401 otherwise); when neither is set they stay open, matching the existing write-auth model. METRICS_API_KEY unlocks metrics only, so a scraper never needs the write key. - Rate limiting: opt-in limitReads flag on rateLimiter (default off, so global behaviour is unchanged) enabled only on the metrics mount via METRICS_RATE_LIMIT_MAX (default 120/min), so the history endpoint is not an unlimited load generator. Global read limiting and the shared store remain owned by the separate rate-limiter issue. - Retention: history stays bounded at MAX_HISTORY = 50, now pinned by route-level tests (eviction of the oldest entry). - openapi.ts declares an ApiKeyAuth scheme and marks both metrics operations as protected; README/CHANGELOG document the scraper path. npm run lint, npm run build and npm test (43 suites, 509 tests) pass. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
…Org#234) Close the per-middleware Map hole that let the same key execute twice across mounts, add a hard entry cap with soonest-expiry eviction, and coalesce concurrent same-key requests onto one in-flight handler. Replay semantics stay response-body based; headers are never cached. Cross-replica sharing waits on the separate persistence issue.
…dd operational documentation (AnchorNet-Org#232)
…rg#230) (AnchorNet-Org#237) - validateConfig() enforces required values before the server binds: API_KEY required in production, PORT valid 1-65535, non-negative rate-limit/idempotency values; warns loudly (non-prod) on open access. - Wire validateConfig into createApp/getConfig in app.ts. - Add typecheck script (tsc --noEmit) and a distinct CI Typecheck step. - Extend config.test.ts with a validateConfig suite. closes AnchorNet-Org#230 Co-authored-by: ChainBid Developer <developer@chain-bid.io>
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.
Fail-fast configuration validation + standalone
typecheckscript (#230)Resolves #230 (GrantFox OSS / Third Campaign).
Summary
package.jsonhad no standalonetypecheck— types were only checked as aside effect of
build. More importantly, configuration failures degradedsilently:
src/middleware/apiKeyAuth.tsmakes the auth middleware a no-op(open access) whenever
API_KEYis unset, so a missing environment variablechanged the service's security posture instead of refusing to start.
This PR adds a fail-fast configuration contract (
validateConfig) that runs atstartup before the port binds, a
typecheckscript wired into CI as a stepdistinct from
build, the full configuration inventory, and tests for therequired-value failure path.
Configuration inventory
PORT30013001FEE_BPS100–10000API_KEYproduction; optional in dev/testproduction: refuses to start namingAPI_KEYCORS_ORIGINBODY_LIMIT"100kb"MAINTENANCE_MODEfalseNODE_ENV"development"METRICS_SNAPSHOT_INTERVAL_MSIDEMPOTENCY_TTL_MS86_400_000RATE_LIMIT_MAX30RATE_LIMIT_WINDOW_MS60_000TRUST_PROXYfalse(Full reasoning in
docs/CONFIGURATION.md.)Required-vs-optional classification
API_KEY→ required inproductiononly. Its absence silently disablesauth on every mutating endpoint — a security-relevant fail-open — so it must
be present in production. In
development/testthe historical open accessis preserved (no secret needed for local runs).
control when absent.
FEE_BPSis range-validated but still optional.Environment-sensitivity policy
Requirements are
NODE_ENV-driven, never an unset variable:production⇒API_KEYmandatory;development/test⇒API_KEYoptional. The mechanismis explicit and centralised in
validateConfig.Validation approach
Hand-written checks in
src/config.ts— no new dependency. The serviceships exactly three runtime deps; a schema-validation library would be
unjustified for a twelve-value config that already has parsing helpers.
validateConfigis invoked fromloadConfig, so it runs once at startupbefore the server binds a port. Failures are actionable: the thrown
ConfigValidationErrornames the offending variable and explains the fix.Deliberate fail-open closure (called out)
The only behaviour change vs. the previous release: a
productiondeploymentwithout
API_KEYnow refuses to start instead of running with openmutating endpoints. No default was changed.
Coordination with the
apiKeyAuthissueThis issue owns the general configuration contract (fail fast on a missing
required value). The concrete authentication policy (when/how
API_KEYisenforced on routes) is owned by the separate
apiKeyAuthissue.Evidence — fail-fast at startup
What changed
src/config.ts— addedvalidateConfig()+ConfigValidationError; calledfrom
loadConfigso validation runs before the port binds.src/index.ts— wraps startup so an invalid configuration exits non-zerowith a clear message before binding; keeps the default
appexport fortests.
src/config.test.ts— addedvalidateConfigtests: production-without-API_KEYthrows (
ConfigValidationError, namesAPI_KEY), blank key treated as unset,dev/test allow missing key, production-with-key passes.
package.json— added"typecheck": "tsc --noEmit"..github/workflows/ci.yml— added a distinct Type check step (runsbefore
build).docs/CONFIGURATION.md— full inventory, classification, and policy.Acceptance criteria (from #230)
typecheckscript exists and runs in CI as a separate step frombuild.npm run lint,npm run typecheck,npm run buildandnpm testall pass (494 tests, 42 suites).Verification
Closes #230.