[Audit M-02] Indexer production config should fail closed on registry/chain/address mismatch #156
Labels
No labels
agent:fix_bugfix
agent:fix_conflicts
agent:fix_security
agent:gap_analysis
agent:implement
agent:open_issues
agents
agent:security_audit
agent:verify
area
timecurve
arena
arena-v2
audit
block:feature_review
block:security
bug
contracts
design
devops
docs
documentation
enhancement
epic
feature
frontend
indexer
low priority
megaeth
operations
ops
performance
QA
qa checklist
referrals
removal
security
smart-contracts
tech-debt
testing
time-arena
timecurve
visual-qa
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
code/yieldomega#156
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Source
Internal full-stack audit
audits/audit_full_1777967937.md(2026-05-05), finding M-02 (Medium). Commit reviewed:3b3bd0c6c501f9cf908667d304146b7b63302b87.Problem
For production, a wrong registry file, wrong
CHAIN_ID, implementation instead of proxy address, invalid/unparseable address, missing buy router when the stack expects it,deploy_blockmis-set, or an empty resolved address list can yield a partial or entirely wrong indexer read model. The frontend and automation consume this API for history, leaderboards, TimeCurve timers, and referral metrics.Today:
Config::from_envwarns whenADDRESS_REGISTRY.chain_iddiffers fromCHAIN_IDbut continues.AddressRegistry::index_addressessilently skips invalid address strings with a warning.That permissive behavior helps local bring-up but is unsafe for production deployments.
Relevant code
Chain mismatch warns only:
Invalid registry entries are skipped (not fatal):
Empty address list leads to idle ingestion:
(Related:
INDEXER_PRODUCTIONalready fail-closes on placeholder DB URLs.)Recommended fix
When
INDEXER_PRODUCTION=1(or equivalent explicit flag already used by the indexer), fail startup if:chain_id != CHAIN_ID.ADDRESS_REGISTRY_PATHis missing (for production ingestion expectations — clarify vs API-only mode).deploy_blockis zero for a non-local chain (if that remains the operational rule).TimeCurveBuyRouterwhen frontend env expects Kumbaya ingestion) are absent from the registry.Keep warn-and-idle (or current behavior) for non-production / development.
Add unit tests for production registry validation and document an operator checklist comparing proxy addresses with deployment artifacts.
Acceptance criteria
Verification checklist
INDEXER_PRODUCTION=1+ mismatched registrychain_id→ process exits non-zero at startup.INDEXER_PRODUCTION=1+ registry with invalid proxy string → fails closed per policy (not silent skip).INDEXER_PRODUCTION=0(or dev) → existing warn/skip behavior unchanged for local workflows.cargo test/ clippy clean for indexer changes.mentioned in commit
e54ca04827mentioned in commit
4fd5041fb4Implemented (merged to
main)Fail-closed production indexer config for GitLab #156 / audit M-02:
ensure_production_address_registry/validate_address_registry_for_productioninindexer/src/config.rs: whenINDEXER_PRODUCTIONis truthy,CHAIN_IDmust match registrychain_id(no warn-only in production).INGESTION_ENABLED(default on),ADDRESS_REGISTRY_PATHis required — no silent API-only idle in production.TimeCurve,RabbitTreasury,LeprechaunNFT,FeeRouter,ReferralRegistry,PodiumPool; any other non-empty field must parse (no silent skip).deploy_block > 0for all chains except31337(Anvil).TimeCurveBuyRouter: omit unlessINDEXER_REGISTRY_REQUIRE_BUY_ROUTER=1(then required forBuyViaKumbaya/ #67).Docs / invariants:
INV-INDEXER-156indocs/testing/invariants-and-business-logic.md,indexer/README.mdoperator checklist,docs/indexer/design.md, manual QA §156,qa-local-full-stack.md,skills/README.md+.cursor/skills/yieldomega-guardrails/SKILL.mdcross-links.Tests:
cd indexer && cargo test production_registry_validation(10 unit tests) + fullcargo test/cargo clippy --all-targets -- -D warningsclean./cc @brouie please verify on a staging or dry-run deploy.
Verification checklist
INDEXER_PRODUCTION=1+ default ingestion + noADDRESS_REGISTRY_PATH→ process exits at config load with a clear error.INDEXER_PRODUCTION=1+ registry JSONchain_id≠CHAIN_ID→ non-zero exit (message mentions mismatch / #156).INDEXER_PRODUCTION=1+ non-empty invalid address in registry → non-zero exit (not "skipping invalid address").INDEXER_PRODUCTION=1+CHAIN_ID=4326(or any non-31337) +deploy_block: 0→ non-zero exit.INDEXER_PRODUCTION=1+INDEXER_REGISTRY_REQUIRE_BUY_ROUTER=1+ emptyTimeCurveBuyRouter→ non-zero exit; with router proxy set → starts.INDEXER_PRODUCTION: chain mismatch still warns only; invalid strings still warn-and-skip; behavior unchanged for local stacks.Issue left open for your sign-off.
mentioned in commit
955228fd7fmentioned in issue #157
@PlasticDigits — verification PASS on
e54ca04.unit tests:
cargo test production_registry_validation→ 10/10 PASS.mapping tests to your checklist:
rejects_registry_chain_id_mismatch→ checklist item 2 (chain mismatch → non-zero exit)rejects_invalid_address_when_non_empty→ item 3 (invalid address string → non-zero, not silent skip)rejects_deploy_block_zero_on_non_local_chain_with_ingestion+allows_deploy_block_zero_on_anvil_chain_with_ingestion→ item 4 (deploy_block=0 enforced on non-anvil chains, anvil 31337 exempted)require_buy_router_missing_fails+require_buy_router_present_ok→ item 5 (router required when flag set, accepts proxy when present)rejects_empty_mandatory_when_ingestion+rejects_zero_mandatory_when_ingestion+rejects_empty_index_set_when_all_mandatory_unparseable_ingestion→ mandatory address coverage (TimeCurve, RabbitTreasury, LeprechaunNFT, FeeRouter, ReferralRegistry, PodiumPool)api_only_skips_mandatory_addresses_but_still_validates_nonempty_fields→ API-only mode policysource review of
indexer/src/config.rs:if !indexer_production_enabled() { return Ok(()); }— non-prod stays permissive (item 6 covered, existing dev warn-and-skip unchanged)if ingestion_enabled && address_registry.is_none() { bail!(...) }— item 1 covered (noADDRESS_REGISTRY_PATH→ exit at config load with clear message referencing #156)bail!("INDEXER_PRODUCTION: deploy_block is 0 in ADDRESS_REGISTRY for chain_id {chain_id} ...")for non-anvil chainsbail!("...no contract addresses resolved for eth_getLogs...")covers empty resolved setclippy + full test suite:
cargo clippy --all-targets -- -D warnings→ cleancargo test→ 40 unit + 0 doc + 2 integration = 42/42 PASS at HEAD390f9belive process-exit walks (items 1-5 with actual misconfigured registries) not run — would require either running the indexer with custom env in parallel to the live stack (port collision on 3100) or stopping the live stack mid-session (collateral on other concurrent verifications). 10 named unit tests + source review cover the same matrix. happy to walk a live induce explicitly if you want it.
ready for close on your side.
mentioned in issue #168
mentioned in commit
278c631bd2mentioned in commit
858300b261mentioned in commit
f43ac77e85mentioned in issue #207
mentioned in issue #237
mentioned in issue #267
mentioned in issue #266
mentioned in issue #325
mentioned in issue #326
mentioned in issue #341