Skip to content

feat: validate required environment variables at service startup (fail fast) - #98

Open
temisan0x wants to merge 2 commits into
clevercon-protocol:mainfrom
temisan0x:feat/env-validation-88
Open

feat: validate required environment variables at service startup (fail fast)#98
temisan0x wants to merge 2 commits into
clevercon-protocol:mainfrom
temisan0x:feat/env-validation-88

Conversation

@temisan0x

@temisan0x temisan0x commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds a fail-fast environment variable validation helper and wires it into
every service's entrypoint, so a misconfigured deploy exits immediately
with a single aggregated error listing everything wrong — instead of
failing late, deep inside a task, with a confusing runtime error.

Closes #88

Changes

  • packages/common/src/env.ts — new requireEnv(spec, source?) and
    validateEnvOrExit(serviceName, spec, source?) helpers. Collects all
    violations before throwing/exiting (not one at a time). Supports typed
    shape checks: string, url, number, stellarSecret, stellarContract.
    Empty/whitespace-only values are treated as missing.
  • packages/common/src/index.ts — exports the new module.
  • Every server.ts (orchestrator, registry, stellar-oracle, web-intel,
    web-intel-v2, analysis, reporter) now calls validateEnvOrExit before any
    process.env.X is read into a const, replacing the old ad-hoc
    single-key if (!SECRET_KEY) { ... process.exit(1) } checks.
  • LLM_PROVIDER=mock correctly waives ANTHROPIC_API_KEY on the
    orchestrator.
  • AGENT_VAULT_CONTRACT_ID stays optional (vault becomes a safe no-op when
    unset, per existing behavior).
  • web-intel's ANTHROPIC_API_KEY stays optional (used only for optional
    Claude summarisation).
  • Required-key lists reconciled against .env.example — already in sync,
    no changes needed there.
  • packages/common/src/env.test.ts — Vitest coverage for missing/present/
    whitespace-only values, aggregated multi-missing errors, optional keys,
    the mock exception (both directions), and malformed shapes for all 4
    typed checks.
  • All server.ts validation calls are skipped under process.env.VITEST
    so the existing test suite is unaffected.

Testing

  • npm test — 131 passed, 6 skipped (pre-existing integration test skip,
    unrelated to this change)
  • npm run typecheck — passes on all 8 packages

Summary by CodeRabbit

  • New Features

    • Added consistent startup validation for required service configuration across the registry, orchestrator, and agent services.
    • Configuration values are now checked for valid formats, including URLs, numbers, and Stellar identifiers.
    • Optional settings are handled explicitly, including provider-specific API keys and contract configuration.
    • Startup errors now report all detected configuration issues together with service-specific context.
  • Bug Fixes

    • Improved handling of missing, blank, or malformed environment values before services start.

Wires validateEnvOrExit into every service entrypoint (orchestrator,
registry, and all five agents), replacing ad-hoc single-var checks
with aggregated fail-fast validation that reports every missing/
malformed key at once instead of one at a time.

- orchestrator: REGISTRY_URL, ORCHESTRATOR_SECRET_KEY, ANTHROPIC_API_KEY
  (waived when LLM_PROVIDER=mock), AGENT_VAULT_CONTRACT_ID (optional)
- registry: no required keys currently, validated for consistency
- stellar-oracle, web-intel, web-intel-v2, analysis, reporter:
  REGISTRY_URL + service-specific wallet secret key
- web-intel: ANTHROPIC_API_KEY marked optional (summarisation only)

Adds packages/common/src/env.test.ts covering missing/present/
whitespace-only values, aggregated multi-key errors, optional keys,
the LLM_PROVIDER=mock exception, and malformed shape values for
url/number/stellarSecret/stellarContract types.

Closes clevercon-protocol#88
@coderabbitai

coderabbitai Bot commented Jul 29, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

A shared environment validation helper and tests are added to packages/common. The orchestrator, registry, and five agent servers now validate startup configuration outside Vitest, replacing local secret-key checks with centralized required, optional, and typed validation.

Changes

Environment validation

Layer / File(s) Summary
Validation helper and coverage
packages/common/src/env.ts, packages/common/src/env.test.ts, packages/common/src/index.ts
Adds environment specifications, trimming and shape validation, aggregated EnvValidationError reporting, process-exit handling, tests for required and optional values, mock-provider behavior, and top-level exports.
Service startup adoption
packages/orchestrator/src/server.ts, packages/registry/src/server.ts, packages/agents/*/src/server.ts
Adds startup validation for service-specific environment variables, skips validation under VITEST, and removes manual secret-key exit guards.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Suggested reviewers: bosun-josh121

Sequence Diagram(s)

sequenceDiagram
  participant ServiceServer
  participant validateEnvOrExit
  participant requireEnv
  participant Process
  ServiceServer->>validateEnvOrExit: validate service environment
  validateEnvOrExit->>requireEnv: check required and optional variables
  requireEnv-->>validateEnvOrExit: return trimmed values or validation issues
  validateEnvOrExit->>Process: exit with status 1 on invalid configuration
Loading
🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (2 warnings)

Check name Status Explanation Resolution
Linked Issues check ⚠️ Warning The PR adds startup validation and tests, but registry validation uses an empty spec and there is no evidence .env.example was reconciled. Add the missing registry required vars and reconcile every service's required-key list with .env.example, including any optional exceptions.
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: fail-fast environment validation at service startup.
Out of Scope Changes check ✅ Passed The changes stay focused on shared env validation, service startup checks, and related tests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/common/src/env.ts`:
- Around line 76-79: Update the return type of requireEnv so keys marked
optional in EnvSpec are exposed as string | undefined while required keys remain
string, matching the function’s omission behavior. Preserve the existing runtime
result and add a regression test verifying an absent optional key is typed as
possibly undefined.
- Around line 37-38: Replace STELLAR_SECRET_RE and STELLAR_CONTRACT_RE in
packages/common/src/env.ts lines 37-38 with checksum-aware Stellar validation,
reusing an existing shared Stellar parser or validator where available rather
than checking textual shape only. In packages/common/src/env.test.ts lines
144-166, add cases that mutate one character of VALID_SECRET and VALID_CONTRACT
and assert both checksum-invalid values fail validation.

In `@packages/orchestrator/src/server.ts`:
- Around line 63-70: Retain the normalized object returned by validateEnvOrExit
and use it for startup configuration instead of raw process.env values: update
packages/orchestrator/src/server.ts (lines 63-70) for required orchestrator
settings; packages/agents/analysis/src/server.ts (lines 12-17),
packages/agents/reporter/src/server.ts (lines 12-17),
packages/agents/stellar-oracle/src/server.ts (lines 20-25), and
packages/agents/web-intel-v2/src/server.ts (lines 12-17) for the validated
secret and registry URL; and packages/agents/web-intel/src/server.ts (lines
14-20) for the validated secret, registry URL, and present optional key.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 4b61a0a7-328e-456f-886a-a298369920d8

📥 Commits

Reviewing files that changed from the base of the PR and between 5715da1 and 8e4687b.

📒 Files selected for processing (10)
  • packages/agents/analysis/src/server.ts
  • packages/agents/reporter/src/server.ts
  • packages/agents/stellar-oracle/src/server.ts
  • packages/agents/web-intel-v2/src/server.ts
  • packages/agents/web-intel/src/server.ts
  • packages/common/src/env.test.ts
  • packages/common/src/env.ts
  • packages/common/src/index.ts
  • packages/orchestrator/src/server.ts
  • packages/registry/src/server.ts

Comment on lines +37 to +38
const STELLAR_SECRET_RE = /^S[A-Z2-7]{55}$/;
const STELLAR_CONTRACT_RE = /^C[A-Z2-7]{55}$/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Validate Stellar checksums, not only the textual shape.

The regexes accept any 56-character base32 value with the right prefix, including values whose final character has been changed and whose Stellar checksum is invalid. Those malformed credentials pass fail-fast validation and fail later when used.

  • packages/common/src/env.ts#L37-L38: replace shape-only checks with checksum-aware Stellar secret and contract validation.
  • packages/common/src/env.test.ts#L144-L166: add checksum-invalid cases by mutating one character of VALID_SECRET and VALID_CONTRACT.
#!/bin/bash
# Check whether a checksum-aware Stellar parser already exists in shared dependencies.
fd -a 'package.json' packages -x sh -c '
  printf "\n--- %s ---\n" "$1"
  jq -r ".dependencies // {} | keys[]?" "$1" | grep -E "`@stellar`|stellar" || true
' sh {}

rg -n -C 2 --glob '*.ts' '\b(StrKey|Keypair)\.(fromSecret|fromPublicKey|isValid[A-Za-z]+)' packages
📍 Affects 2 files
  • packages/common/src/env.ts#L37-L38 (this comment)
  • packages/common/src/env.test.ts#L144-L166
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/common/src/env.ts` around lines 37 - 38, Replace STELLAR_SECRET_RE
and STELLAR_CONTRACT_RE in packages/common/src/env.ts lines 37-38 with
checksum-aware Stellar validation, reusing an existing shared Stellar parser or
validator where available rather than checking textual shape only. In
packages/common/src/env.test.ts lines 144-166, add cases that mutate one
character of VALID_SECRET and VALID_CONTRACT and assert both checksum-invalid
values fail validation.

Comment on lines +76 to +79
export function requireEnv<S extends EnvSpec>(
spec: S,
source: NodeJS.ProcessEnv = process.env
): { [K in keyof S]: string } {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Inspect consumers that may rely on optional returned values being strings.
rg -n -C 3 --glob '*.ts' '\brequireEnv\s*\(' packages

Repository: clevercon-protocol/clevercon

Length of output: 8972


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the file shape first, then inspect the relevant section.
ast-grep outline packages/common/src/env.ts --view expanded || true
printf '\n--- env.ts excerpt ---\n'
sed -n '1,220p' packages/common/src/env.ts

printf '\n--- optional-key usages ---\n'
rg -n -C 2 --glob '*.ts' 'optional:\s*true|optional:\s*source' packages/common/src

Repository: clevercon-protocol/clevercon

Length of output: 6539


Make optional env keys optional in the return type
requireEnv omits missing optional keys from result, but the signature still exposes every key as string. That lets requireEnv({ MY_OPT: { optional: true } }).MY_OPT.trim() type-check even when MY_OPT is absent. Return string | undefined for optional keys (or model the result as Partial) and add a regression test.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/common/src/env.ts` around lines 76 - 79, Update the return type of
requireEnv so keys marked optional in EnvSpec are exposed as string | undefined
while required keys remain string, matching the function’s omission behavior.
Preserve the existing runtime result and add a regression test verifying an
absent optional key is typed as possibly undefined.

Comment on lines +63 to +70
if (!process.env.VITEST) {
validateEnvOrExit('orchestrator', {
REGISTRY_URL: { type: 'url' },
ORCHESTRATOR_SECRET_KEY: { type: 'stellarSecret' },
ANTHROPIC_API_KEY: { optional: process.env.LLM_PROVIDER === 'mock' },
AGENT_VAULT_CONTRACT_ID: { optional: true, description: 'vault calls become safe no-ops when unset' },
});
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | 🏗️ Heavy lift

Consume the normalized values returned by validation.

Each entrypoint discards validateEnvOrExit’s trimmed result and continues reading raw process.env. A whitespace-padded secret therefore validates successfully but remains padded when passed to downstream startup configuration.

  • packages/orchestrator/src/server.ts#L63-L70: retain the validated object and source required orchestrator configuration from it.
  • packages/agents/analysis/src/server.ts#L12-L17: use the validated secret and registry URL instead of raw environment reads.
  • packages/agents/reporter/src/server.ts#L12-L17: use the validated secret and registry URL instead of raw environment reads.
  • packages/agents/stellar-oracle/src/server.ts#L20-L25: use the validated secret and registry URL instead of raw environment reads.
  • packages/agents/web-intel-v2/src/server.ts#L12-L17: use the validated secret and registry URL instead of raw environment reads.
  • packages/agents/web-intel/src/server.ts#L14-L20: use the validated secret, registry URL, and present optional key instead of raw environment reads.
📍 Affects 6 files
  • packages/orchestrator/src/server.ts#L63-L70 (this comment)
  • packages/agents/analysis/src/server.ts#L12-L17
  • packages/agents/reporter/src/server.ts#L12-L17
  • packages/agents/stellar-oracle/src/server.ts#L20-L25
  • packages/agents/web-intel-v2/src/server.ts#L12-L17
  • packages/agents/web-intel/src/server.ts#L14-L20
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/orchestrator/src/server.ts` around lines 63 - 70, Retain the
normalized object returned by validateEnvOrExit and use it for startup
configuration instead of raw process.env values: update
packages/orchestrator/src/server.ts (lines 63-70) for required orchestrator
settings; packages/agents/analysis/src/server.ts (lines 12-17),
packages/agents/reporter/src/server.ts (lines 12-17),
packages/agents/stellar-oracle/src/server.ts (lines 20-25), and
packages/agents/web-intel-v2/src/server.ts (lines 12-17) for the validated
secret and registry URL; and packages/agents/web-intel/src/server.ts (lines
14-20) for the validated secret, registry URL, and present optional key.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Task]: Validate required environment variables at service startup (fail fast)

1 participant