Skip to content

fix(config): keep embedded-constructed structs constructible (un-break coordinode)#46

Merged
polaz merged 2 commits into
mainfrom
fix/#45-embedded-constructible
Jun 20, 2026
Merged

fix(config): keep embedded-constructed structs constructible (un-break coordinode)#46
polaz merged 2 commits into
mainfrom
fix/#45-embedded-constructible

Conversation

@polaz

@polaz polaz commented Jun 20, 2026

Copy link
Copy Markdown
Member

Summary

The blanket #[non_exhaustive] (shipped in 2.0.0) broke embedded consumers that build the config programmatically with struct literals, rather than loading YAML. coordinode does exactly this in coordinode-server to inject the runtime upstream port, listen address, and baked-in descriptors:

let config = ProxyConfig {
    upstream: UpstreamConfig { default: grpc_upstream },
    descriptors: vec![DescriptorSource::Embedded { bytes: DESCRIPTOR_BYTES }],
    listen: ListenConfig { http: rest_addr },
    service: ServiceConfig { name: "coordinode".into() },
    ...
};
ProxyServer::from_config(config)

With #[non_exhaustive] on those structs, this stops compiling for any external crate.

Fix: scope non_exhaustive correctly

  • Removed from the wiring structs an embedding consumer legitimately builds: ProxyConfig, UpstreamConfig, ListenConfig, ServiceConfig, and the DescriptorSource enum.
  • Kept on the 16 leaf auth/shield/oidc/etc. config structs that are deserialized (never hand-built) and that actually churn (these are what tripped cargo-semver-checks).

Principle: #[non_exhaustive] belongs on deserialized-only leaf config, not on the wiring structs consumers construct programmatically.

Dev UX

  • Added ProxyConfig::from_yaml_str(&str) so an embedded build can load a baked-in config (include_str!) without touching the filesystem.
  • Added tests/embedded.rs — a separate-crate integration test that reproduces coordinode's exact construction (ProxyConfig literal + DescriptorSource::Embedded + ProxyServer). Because it's an external crate, it sees non_exhaustive like a real consumer: if any wiring struct regains it, this test fails to compile and the regression is caught.

Versioning

Removing #[non_exhaustive] is a relaxation (more permissive), so this is a non-breaking patch (2.0.1), not a major bump. cargo-semver-checks is satisfied.

Testing

cargo nextest run --features redis: 121 passed (incl. the 2 new external-crate embedded tests). clippy (all-features) + fmt clean.

Closes #45

The previous blanket #[non_exhaustive] broke embedded consumers that
build the config programmatically with struct literals (runtime upstream
port, listen address, baked-in descriptors) instead of loading YAML.

Scope non_exhaustive correctly: remove it from the wiring structs an
embedding consumer legitimately constructs (ProxyConfig, UpstreamConfig,
ListenConfig, ServiceConfig, and the DescriptorSource enum); keep it on
the leaf auth/shield/oidc/etc. structs that are deserialized, not
hand-built, and that actually churn.

Add ProxyConfig::from_yaml_str for embedding a baked-in config without a
file, and a separate-crate integration test that reproduces the embedded
construction pattern so a re-added non_exhaustive is caught at compile
time.

Removing non_exhaustive is a relaxation (more permissive), so this is a
non-breaking patch.

Closes #45
@coderabbitai

coderabbitai Bot commented Jun 20, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: c2ed3609-1ff5-44da-a06f-430a5cb1906c

📥 Commits

Reviewing files that changed from the base of the PR and between 2535613 and bbc1fef.

📒 Files selected for processing (1)
  • tests/embedded.rs

📝 Walkthrough

Summary by CodeRabbit

  • New Features

    • Added support for constructing proxy configuration from in-memory YAML strings via ProxyConfig::from_yaml_str.
  • Tests

    • Added tests covering embedded/in-memory configuration construction and YAML-string parsing to validate ProxyServer::from_config and loaded service.name.

Walkthrough

#[non_exhaustive] is removed from ProxyConfig, UpstreamConfig, ListenConfig, and ServiceConfig. A new public method ProxyConfig::from_yaml_str is added for parsing YAML strings, and from_file is refactored to delegate to it. A new integration test file tests/embedded.rs verifies both programmatic struct construction and YAML string parsing.

Changes

Embedded Config Constructibility

Layer / File(s) Summary
Remove #[non_exhaustive] and add from_yaml_str
src/config.rs
Removes #[non_exhaustive] from ProxyConfig, UpstreamConfig, ListenConfig, and ServiceConfig. Adds from_yaml_str(yaml: &str) -> anyhow::Result<Self> and refactors from_file to delegate to it via read_to_string.
Integration tests for embedded construction and YAML parsing
tests/embedded.rs
Adds embedded_config_is_constructible (builds ProxyConfig in code with DescriptorSource::Embedded and calls ProxyServer::from_config) and from_yaml_str_loads_config (parses YAML via from_yaml_str and asserts the service name).

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Possibly related PRs

  • structured-world/structured-proxy#44: Added #[non_exhaustive] to the same config structs in src/config.rs that this PR removes it from, making it the direct predecessor change being partially reversed.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly indicates the primary fix: removing non_exhaustive from constructible structs to restore embedded consumer compatibility.
Description check ✅ Passed The description provides comprehensive context about the breaking change, the fix strategy, dev improvements, and testing rationale.
Linked Issues check ✅ Passed The changes fully implement the objectives from issue #45: removing non_exhaustive from wiring structs, keeping it on leaf deserialized-only configs, adding from_yaml_str method, and introducing separate-crate integration tests.
Out of Scope Changes check ✅ Passed All changes are directly aligned with issue #45 requirements: scoped non_exhaustive removal, new from_yaml_str method, and embedded integration tests.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/#45-embedded-constructible

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

@greptile-apps

greptile-apps Bot commented Jun 20, 2026

Copy link
Copy Markdown

Greptile Summary

Scopes #[non_exhaustive] correctly by removing it from the five "wiring" types (ProxyConfig, UpstreamConfig, ListenConfig, ServiceConfig, DescriptorSource) that embedding consumers construct programmatically, while keeping it on the 16+ leaf auth/shield/oidc structs that are deserialized-only. A new from_yaml_str helper enables include_str!-style embedded configs without filesystem access.

  • from_file is refactored to delegate to from_yaml_str; the two are functionally identical, just with the read step moved out.
  • tests/embedded.rs is an external-crate integration test that will fail to compile if any wiring struct inadvertently regains #[non_exhaustive], guarding the regression permanently.

Confidence Score: 5/5

Safe to merge — the change relaxes the public API (removes restrictions on struct construction) without altering any runtime behavior.

Removing #[non_exhaustive] from the wiring structs is a purely additive API change. from_file is correctly refactored to delegate to from_yaml_str with identical semantics. The leaf configs that actually churn retain their #[non_exhaustive] guard. The new external-crate test permanently catches any regression where a wiring struct regains the attribute.

No files require special attention.

Important Files Changed

Filename Overview
src/config.rs Removes #[non_exhaustive] from five wiring structs/enum, adds from_yaml_str convenience method (and delegates from_file to it). The leaf auth/shield/oidc structs retain #[non_exhaustive]; the refactoring is functionally equivalent to the old from_file body.
tests/embedded.rs New external-crate integration test that reproduces the coordinode embedding pattern; includes a structural-literal test and a from_yaml_str parse test. Comment on forwarded_headers correctly warns about bypassing serde defaults.

Reviews (2): Last reviewed commit: "docs(test): clarify forwarded_headers in..." | Re-trigger Greptile

Comment thread tests/embedded.rs
A programmatic config literal bypasses serde defaults, so note that the
single header is arbitrary for this constructibility test and that real
embeddings must set the headers they need (or load via from_file /
from_yaml_str where the default list applies).

Part of #45
@polaz polaz merged commit 919c957 into main Jun 20, 2026
1 check passed
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.

fix(config): keep embedded-constructed structs constructible

1 participant