Pre-launch[SEC-I02 (H14)] : FACTORY_ADDRESS non-empty not enforced when RUN_MODE is not prod [SEC-I01] #451

Closed
opened 2026-06-30 16:09:23 +00:00 by totdking · 18 comments
totdking commented 2026-06-30 16:09:23 +00:00 (Migrated from gitlab.com)
No description provided.
totdking commented 2026-06-30 16:09:54 +00:00 (Migrated from gitlab.com)

changed title from Pre-launch: FACTORY_ADDRESS non-empty not enforced when RUN_MODE is not prod to Pre-launch[SEC-I02 (H14)] : FACTORY_ADDRESS non-empty not enforced when RUN_MODE is not prod [SEC-I01]

<p>changed title from <code class="idiff">Pre-launch: FACTORY_ADDRESS non-empty not enforced when RUN_MODE is not prod</code> to <code class="idiff">Pre-launch<span class="idiff left addition">[SEC-I02 (H14)] </span>: FACTORY_ADDRESS non-empty not enforced when RUN_MODE is not prod<span class="idiff right addition"> [SEC-I01]</span></code></p>
totdking commented 2026-06-30 16:09:54 +00:00 (Migrated from gitlab.com)

changed the description

changed the description
totdking commented 2026-06-30 16:11:46 +00:00 (Migrated from gitlab.com)

Summary

The indexer skips factory provenance checks when FACTORY_ADDRESS is empty. The verify_factory_provenance function in pair_discovery.rs (lines 163-168) logs a warning and returns Ok(()) without checking the factory, meaning any contract emitting swap events is indexed without validation. RUN_MODE=prod enforces a non-empty FACTORY_ADDRESS, but staging and QA deployments that do not set RUN_MODE=prod can ship with FACTORY_ADDRESS="" and silently index unverified pairs, including attacker-controlled clone contracts.


What Was Checked

  • indexer/src/indexer/pair_discovery.rs lines 163-168: if factory_addr.is_empty() { tracing::warn!(...); return Ok(()); } -- provenance check is entirely skipped when FACTORY_ADDRESS is empty.
  • docs/operator-secrets.md lines 35-38: RUN_MODE=prod requires non-empty FACTORY_ADDRESS. No equivalent guard for non-prod RUN_MODE.
  • No CI job or deploy script asserts FACTORY_ADDRESS is non-empty for staging environments.
  • Distinct from issue #442 (which covers VITE_* env-to-chain address matching, not the FACTORY_ADDRESS empty guard).

Expected (per checklist)

The indexer refuses to start or logs a startup error that fails the deploy if FACTORY_ADDRESS is empty, regardless of RUN_MODE. Alternatively, the post-deploy verification script or launch-checklist includes an explicit step asserting FACTORY_ADDRESS is non-empty before the indexer is considered healthy.


Actual

FACTORY_ADDRESS="" is silently accepted in non-prod RUN_MODE. Only a log warning is emitted at discovery time, not at startup.


Suggested Fix

Add a startup assertion in the indexer config validation (independent of RUN_MODE) that logs a prominent error and refuses to process blocks if FACTORY_ADDRESS is empty. Alternatively, add an explicit pre-flight check to scripts/qa/verify-deploy.sh and docs/runbooks/launch-checklist.md Phase 0 that confirms FACTORY_ADDRESS is non-empty before the deployment is marked healthy.


Verification Checklist

  • Indexer startup rejects or prominently errors when FACTORY_ADDRESS is empty, independent of RUN_MODE
  • OR post-deploy verification script asserts FACTORY_ADDRESS is non-empty as a pre-flight check
  • Launch-checklist Phase 0 includes FACTORY_ADDRESS non-empty as a named precondition
  • Staging deploy CI or runbook confirms FACTORY_ADDRESS is set before indexer starts

Cc: @PlasticDigits

### Summary The indexer skips factory provenance checks when FACTORY_ADDRESS is empty. The verify_factory_provenance function in `pair_discovery.rs` (lines 163-168) logs a warning and returns Ok(()) without checking the factory, meaning any contract emitting swap events is indexed without validation. RUN_MODE=prod enforces a non-empty FACTORY_ADDRESS, but staging and QA deployments that do not set RUN_MODE=prod can ship with FACTORY_ADDRESS="" and silently index unverified pairs, including attacker-controlled clone contracts. --- ### What Was Checked - `indexer/src/indexer/pair_discovery.rs` lines 163-168: `if factory_addr.is_empty() { tracing::warn!(...); return Ok(()); }` -- provenance check is entirely skipped when FACTORY_ADDRESS is empty. - `docs/operator-secrets.md` lines 35-38: RUN_MODE=prod requires non-empty FACTORY_ADDRESS. No equivalent guard for non-prod RUN_MODE. - No CI job or deploy script asserts FACTORY_ADDRESS is non-empty for staging environments. - Distinct from issue #442 (which covers VITE\_\* env-to-chain address matching, not the FACTORY_ADDRESS empty guard). --- ### Expected (per checklist) The indexer refuses to start or logs a startup error that fails the deploy if FACTORY_ADDRESS is empty, regardless of RUN_MODE. Alternatively, the post-deploy verification script or launch-checklist includes an explicit step asserting FACTORY_ADDRESS is non-empty before the indexer is considered healthy. --- ### Actual FACTORY_ADDRESS="" is silently accepted in non-prod RUN_MODE. Only a log warning is emitted at discovery time, not at startup. --- ### Suggested Fix Add a startup assertion in the indexer config validation (independent of RUN_MODE) that logs a prominent error and refuses to process blocks if FACTORY_ADDRESS is empty. Alternatively, add an explicit pre-flight check to `scripts/qa/verify-deploy.sh` and `docs/runbooks/launch-checklist.md` Phase 0 that confirms FACTORY_ADDRESS is non-empty before the deployment is marked healthy. --- ### Verification Checklist - [ ] Indexer startup rejects or prominently errors when FACTORY_ADDRESS is empty, independent of RUN_MODE - [ ] OR post-deploy verification script asserts FACTORY_ADDRESS is non-empty as a pre-flight check - [ ] Launch-checklist Phase 0 includes FACTORY_ADDRESS non-empty as a named precondition - [ ] Staging deploy CI or runbook confirms FACTORY_ADDRESS is set before indexer starts Cc: @PlasticDigits
totdking commented 2026-06-30 18:37:55 +00:00 (Migrated from gitlab.com)

mentioned in issue #381

mentioned in issue #381
Brouie commented 2026-06-30 19:05:22 +00:00 (Migrated from gitlab.com)

mentioned in merge request !983

mentioned in merge request !983
Brouie commented 2026-06-30 19:08:38 +00:00 (Migrated from gitlab.com)

Fixed. FACTORY_ADDRESS empty was only rejected under RUN_MODE=prod, so a staging/QA indexer with FACTORY_ADDRESS="" would sail past and verify_factory_provenance skips the provenance check — indexing unverified (possibly spoofed clone) pairs.

Now it's a hard config error in EVERY run mode (ConfigError::EmptyFactoryAddress), checked before the prod block, so the indexer refuses to start with an empty/whitespace factory address regardless of RUN_MODE.

Test: empty_factory_address_rejected_in_dev (whitespace FACTORY_ADDRESS in dev -> EmptyFactoryAddress). indexer lib 167/0.

Shipped together with #458 (the other config.rs finding) in MR !983, branch qa/451-458-indexer-config-guards, commit 6ae40413. Needs review/merge @PlasticDigits — leaving open for verification.

Fixed. FACTORY_ADDRESS empty was only rejected under RUN_MODE=prod, so a staging/QA indexer with FACTORY_ADDRESS="" would sail past and `verify_factory_provenance` skips the provenance check — indexing unverified (possibly spoofed clone) pairs. Now it's a hard config error in EVERY run mode (`ConfigError::EmptyFactoryAddress`), checked before the prod block, so the indexer refuses to start with an empty/whitespace factory address regardless of RUN_MODE. Test: `empty_factory_address_rejected_in_dev` (whitespace FACTORY_ADDRESS in dev -> EmptyFactoryAddress). indexer lib 167/0. Shipped together with #458 (the other config.rs finding) in MR !983, branch `qa/451-458-indexer-config-guards`, commit `6ae40413`. Needs review/merge @PlasticDigits — leaving open for verification.
Brouie commented 2026-06-30 19:08:40 +00:00 (Migrated from gitlab.com)

mentioned in issue #458

mentioned in issue #458
PlasticDigits commented 2026-06-30 21:58:48 +00:00 (Migrated from gitlab.com)

mentioned in commit d326a2e188

mentioned in commit d326a2e18850f73f5694451b58172e3a5d965ee4
PlasticDigits commented 2026-06-30 22:20:52 +00:00 (Migrated from gitlab.com)

mentioned in commit 0529634a84

mentioned in commit 0529634a84940d314e8599c9f0a3b0330c32b058
PlasticDigits commented 2026-06-30 22:21:10 +00:00 (Migrated from gitlab.com)

mentioned in merge request !996

mentioned in merge request !996
PlasticDigits commented 2026-07-01 00:10:46 +00:00 (Migrated from gitlab.com)

mentioned in commit b5752c20c5

mentioned in commit b5752c20c50b8a03699921d32dcff5d0c797ae34
PlasticDigits commented 2026-07-01 00:30:33 +00:00 (Migrated from gitlab.com)

mentioned in commit 9b98249d3b

mentioned in commit 9b98249d3bc72a35877edc899e94a6e18a6cfbd2
PlasticDigits commented 2026-07-01 00:41:32 +00:00 (Migrated from gitlab.com)

mentioned in merge request !997

mentioned in merge request !997
PlasticDigits commented 2026-07-01 00:44:05 +00:00 (Migrated from gitlab.com)

Verification — #451 (SEC-I02 / H14): FACTORY_ADDRESS non-empty guard

Verified on main @ 772a7dec (includes fix from MR !983 / 6ae40413).

Acceptance criteria

Criterion Result How verified
Indexer startup rejects empty FACTORY_ADDRESS in every RUN_MODE PASS make verify-issue-451 (8/8); unit test empty_factory_address_rejected_in_dev; manual: RUN_MODE=dev FACTORY_ADDRESS="" → exit 1, message FACTORY_ADDRESS must be non-empty in every RUN_MODE; whitespace-only also rejected at startup
Post-deploy verification asserts FACTORY_ADDRESS non-empty PASS scripts/qa/verify-deploy.sh exits 1 with FACTORY_ADDRESS not found when unset; covered by make verify-issue-451 grep check
Launch-checklist Phase 0 names FACTORY_ADDRESS precondition PASS docs/runbooks/launch-checklist.md — Indexer FACTORY_ADDRESS (SEC-I02) checkbox; make check-factory-address-docs OK
Staging deploy CI / runbook confirms FACTORY_ADDRESS before indexer PASS Phase 0 applies to staging/testnet deploys; CI test-indexer-lib runs cargo test --lib (includes config guard); operator docs (docs/operator-secrets.md, docs/qa-invariants.md Q5) and agent skill skills/AGENTS_FACTORY_ADDRESS_GUARD.md

Commands run

make verify-issue-451          # PASS 8 / FAIL 0
make check-factory-address-docs  # OK
cd indexer && cargo test --lib empty_factory_address_rejected_in_dev  # ok
RUN_MODE=dev FACTORY_ADDRESS="" DATABASE_URL=postgres://localhost/db CORS_ORIGINS=http://localhost:5173 ./target/debug/cl8y-dex-indexer  # exit 1

Implementation confirmed

  • indexer/src/config.rs: unconditional ConfigError::EmptyFactoryAddress when factory_address.trim().is_empty() (before prod-only block).
  • pair_discovery.rs warn-and-skip branch is documented as unreachable in normal operation once startup guard is in place.

No repo changes required for verification. Closing as verified.

## Verification — #451 (SEC-I02 / H14): FACTORY_ADDRESS non-empty guard Verified on `main` @ `772a7dec` (includes fix from MR !983 / `6ae40413`). ### Acceptance criteria | Criterion | Result | How verified | |-----------|--------|--------------| | Indexer startup rejects empty `FACTORY_ADDRESS` in every `RUN_MODE` | **PASS** | `make verify-issue-451` (8/8); unit test `empty_factory_address_rejected_in_dev`; manual: `RUN_MODE=dev FACTORY_ADDRESS=""` → exit 1, message `FACTORY_ADDRESS must be non-empty in every RUN_MODE`; whitespace-only also rejected at startup | | Post-deploy verification asserts `FACTORY_ADDRESS` non-empty | **PASS** | `scripts/qa/verify-deploy.sh` exits 1 with `FACTORY_ADDRESS not found` when unset; covered by `make verify-issue-451` grep check | | Launch-checklist Phase 0 names `FACTORY_ADDRESS` precondition | **PASS** | `docs/runbooks/launch-checklist.md` — **Indexer FACTORY_ADDRESS (SEC-I02)** checkbox; `make check-factory-address-docs` OK | | Staging deploy CI / runbook confirms `FACTORY_ADDRESS` before indexer | **PASS** | Phase 0 applies to staging/testnet deploys; CI `test-indexer-lib` runs `cargo test --lib` (includes config guard); operator docs (`docs/operator-secrets.md`, `docs/qa-invariants.md` Q5) and agent skill `skills/AGENTS_FACTORY_ADDRESS_GUARD.md` | ### Commands run ```bash make verify-issue-451 # PASS 8 / FAIL 0 make check-factory-address-docs # OK cd indexer && cargo test --lib empty_factory_address_rejected_in_dev # ok RUN_MODE=dev FACTORY_ADDRESS="" DATABASE_URL=postgres://localhost/db CORS_ORIGINS=http://localhost:5173 ./target/debug/cl8y-dex-indexer # exit 1 ``` ### Implementation confirmed - `indexer/src/config.rs`: unconditional `ConfigError::EmptyFactoryAddress` when `factory_address.trim().is_empty()` (before prod-only block). - `pair_discovery.rs` warn-and-skip branch is documented as unreachable in normal operation once startup guard is in place. No repo changes required for verification. Closing as verified.
PlasticDigits (Migrated from gitlab.com) closed this issue 2026-07-01 00:44:06 +00:00
Brouie commented 2026-07-01 11:19:29 +00:00 (Migrated from gitlab.com)

mentioned in issue #447

mentioned in issue #447
Brouie commented 2026-07-01 11:30:47 +00:00 (Migrated from gitlab.com)

mentioned in issue #337

mentioned in issue #337
totdking commented 2026-07-02 16:13:11 +00:00 (Migrated from gitlab.com)

mentioned in commit 9ff4ea7b60

mentioned in commit 9ff4ea7b6091af242260e3566c86b126f590411c
totdking commented 2026-07-02 16:14:08 +00:00 (Migrated from gitlab.com)

mentioned in merge request !1007

mentioned in merge request !1007
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
code/cl8y-dex-terraclassic#451
No description provided.