Skip to content

Load runtime config from config store#685

Closed
ChristianPavilonis wants to merge 3 commits into
mainfrom
feature/ts-config-in-config-store
Closed

Load runtime config from config store#685
ChristianPavilonis wants to merge 3 commits into
mainfrom
feature/ts-config-in-config-store

Conversation

@ChristianPavilonis
Copy link
Copy Markdown
Collaborator

@ChristianPavilonis ChristianPavilonis commented May 11, 2026

Summary

  • Load Trusted Server application config at runtime from Fastly Config Store ts_config_store key ts-config instead of baking TOML into the binary.
  • Add strict runtime config parsing, validation, canonical TOML generation, and config hashing.
  • Update local Fastly/Viceroy development docs and scripts to render runtime config into a local config store.

Changes

File Change
crates/trusted-server-adapter-fastly/src/main.rs Loads and validates runtime config from Config Store before routing requests; logs config hash and preserves security warnings.
crates/trusted-server-core/src/runtime_config.rs Adds runtime config loading, declared-field canonicalization, and SHA-256 hashing with tests.
crates/trusted-server-core/src/settings.rs Rejects unknown config fields, exposes known top-level keys, and moves env-override config loading to test-only compatibility.
crates/trusted-server-core/build.rs / src/settings_data.rs Removes build-time config baking.
crates/trusted-server-core/src/bin/ts-config-canonicalize.rs Adds CLI helper to canonicalize config and print the config hash.
scripts/fastly-dev.sh / scripts/render-fastly-local-config.py Adds local dev workflow for injecting canonical app config into fastly.local.toml.
trusted-server.example.toml Renames sample config from the runtime config filename.
crates/integration-tests/** Updates integration test setup and fixtures for runtime config-store loading.
docs/guide/** / docs/superpowers/specs/2026-04-20-config-store-runtime-config-design.md Documents runtime config-store behavior, local testing, and error modes.

Closes

Closes #166

Test plan

  • cargo test --workspace
  • cargo clippy --workspace --all-targets --all-features -- -D warnings
  • cargo fmt --all -- --check
  • JS tests: cd crates/js/lib && npx vitest run
  • JS format: cd crates/js/lib && npm run format
  • Docs format: cd docs && npm run format
  • WASM build: cargo build --package trusted-server-adapter-fastly --release --target wasm32-wasip1
  • Manual testing via fastly compute serve
  • Other: Not run locally; PR creation requested only.

Checklist

  • Changes follow CLAUDE.md conventions
  • No unwrap() in production code — use expect("should ...")
  • Uses logging macros (not println!)
  • New code has tests
  • No secrets or credentials committed

@ChristianPavilonis ChristianPavilonis force-pushed the feature/ts-config-in-config-store branch from 52963d2 to b8c0ab5 Compare May 11, 2026 19:48
Copy link
Copy Markdown
Collaborator

@prk-Jr prk-Jr left a comment

Choose a reason for hiding this comment

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

🔧 Request changes: config-store validation currently does not cover the full runtime startup surface.

🔧 crates/trusted-server-core/src/runtime_config.rs:42 validates only Settings::validate() before canonicalizing. Runtime startup still performs additional fallible construction later in crates/trusted-server-adapter-fastly/src/main.rs:97 and :106 via build_orchestrator(&settings) and IntegrationRegistry::new(&settings). I reproduced this by setting [integrations.prebid] server_url = ""; ts-config-canonicalize exited 0 and produced a config hash, even though the existing empty_prebid_server_url_fails_orchestrator_startup test documents that the same config fails startup. Please make load_runtime_config run the same startup validation needed to serve requests, or share a validate_runtime_startup(&Settings) helper between canonicalization and Fastly startup.

🔧 crates/trusted-server-core/src/settings.rs:97 / crates/trusted-server-core/src/integrations/prebid.rs:54: strict parsing still preserves unknown fields under known integrations. IntegrationSettings stores integration payloads as flattened JsonValue maps, and built-in typed configs such as PrebidIntegrationConfig do not deny unknown fields. I reproduced this by adding server_urll = "https://typo.example" under [integrations.prebid]; canonicalization exited 0 and preserved the typo in output. That lets misspelled production config be published while typed runtime code ignores it. Please reject unknown fields for built-in integration configs, either with deny_unknown_fields on typed structs or a registry-level validation pass during load_runtime_config.

🔧 crates/integration-tests/fixtures/configs/trusted-server.integration.toml:14 hardcodes origin_url = "http://127.0.0.1:8888", but scripts/integration-tests.sh and scripts/integration-tests-browser.sh still expose INTEGRATION_ORIGIN_PORT and export old TRUSTED_SERVER__* build-time overrides. Since this change removes env merging from runtime config, setting INTEGRATION_ORIGIN_PORT now changes the harness port without changing the config-store value consumed by Trusted Server. Please template/render the integration TOML with the selected port, or remove the port override and stale env-var build comments.

🔧 docs/guide/configuration.md and docs/guide/error-reference.md still instruct operators to use removed TRUSTED_SERVER__* overrides. For example, configuration.md says env overrides are no longer merged, but later has many Environment Override sections starting around line 104; error-reference.md says env loading was removed around line 130, but later recommends TRUSTED_SERVER__EDGE_COOKIE__SECRET_KEY and TRUSTED_SERVER__INTEGRATIONS__PREBID__DEBUG. Please replace these with TOML/config-store examples or clearly mark them as legacy/non-runtime-only if any tooling still consumes them.

😃 The fail-closed health behavior is a strong part of this change. Loading config before serving /health means missing or invalid config-store state makes the service unhealthy instead of silently serving with defaults.

Local verification on PR head:

  • cargo fmt --all -- --check exited 0
  • cargo clippy --workspace --all-targets --all-features -- -D warnings exited 0
  • cargo test --workspace exited 0

let settings = Settings::from_toml(toml_str)?;

settings
.validate()
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 This validation step is narrower than runtime startup. load_runtime_config accepts configs that build_orchestrator or IntegrationRegistry::new reject later; I reproduced this with [integrations.prebid] server_url = "" and ts-config-canonicalize still exited 0 with a hash. Please run the same startup validation here, or through a shared helper, before canonicalizing/publishing the config.

message: "Failed to serialize validated configuration".to_string(),
})?;

let canonical_value = retain_declared_fields(
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 This canonicalization path still preserves unknown fields under known integrations because Settings::from_toml keeps integration payloads as raw JsonValue. Repro: server_urll = "https://typo.example" under [integrations.prebid] canonicalizes and survives output, while typed Prebid config ignores it. Please reject unknown fields for built-in integrations during runtime config loading.

[publisher]
domain = "test-publisher.com"
cookie_domain = ".test-publisher.com"
origin_url = "http://127.0.0.1:8888"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 This hardcodes 8888, but the integration scripts still expose INTEGRATION_ORIGIN_PORT and export old TRUSTED_SERVER__PUBLISHER__ORIGIN_URL build-time overrides. Since env merging is gone, a non-default INTEGRATION_ORIGIN_PORT no longer changes the runtime config-store payload. Please template/render this fixture from the selected port, or remove the port override and stale env-var build comments.


> **Note:** Older revisions of this guide referred to build-time
> `TRUSTED_SERVER__*` application-setting overrides. That mechanism has been
> removed for application configuration.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

🔧 This says the TRUSTED_SERVER__* application-setting mechanism was removed, but the section immediately below still documents the override format and the rest of the page keeps many Environment Override examples. Operators following this page will set env vars that runtime no longer reads. Please convert those examples to TOML/config-store examples, or mark them legacy/test-only if they are only retained for compatibility tests.

log::debug!("Loaded runtime config hash={}", loaded_config.config_hash);
log::debug!("Settings {settings:?}");

// `/health` intentionally depends on successful runtime config loading.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

😃 Good call making /health depend on successful config-store loading. This makes readiness fail closed when ts-config is missing or invalid instead of serving with defaults.

@ChristianPavilonis
Copy link
Copy Markdown
Collaborator Author

Closing in favor of fuller CLI PR (#669)

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.

As publisher i would to configure Trusted Server without initiating rebuild

2 participants