Skip to content

Implement settings validation and boundary checking#181

Open
eli-litzelman wants to merge 4 commits into
cwbi-devfrom
fix/87-default-settings-to-none-where-appropriate
Open

Implement settings validation and boundary checking#181
eli-litzelman wants to merge 4 commits into
cwbi-devfrom
fix/87-default-settings-to-none-where-appropriate

Conversation

@eli-litzelman
Copy link
Copy Markdown
Collaborator

  • Default optional settings to None with proper validation
  • Add boundary validation to catch missing env vars early
  • Use new property for computed settings (fastapi_root_path)
  • Move validation checks closer to where settings are used
  • Add tests for settings validation

- Default optional settings to None with proper validation
- Add boundary validation to catch missing env vars early
- Use new property for computed settings (fastapi_root_path)
- Move validation checks closer to where settings are used
- Add comprehensive tests for settings validation
@eli-litzelman eli-litzelman requested a review from jbkolze April 29, 2026 15:13
@eli-litzelman eli-litzelman self-assigned this Apr 29, 2026
@eli-litzelman eli-litzelman linked an issue Apr 29, 2026 that may be closed by this pull request
Copy link
Copy Markdown
Contributor

@jbkolze jbkolze left a comment

Choose a reason for hiding this comment

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

Looks good but I would go ahead and wipe out (most of) the existing settings defaults as well -- that way the application won't assume configuration that has potentially been missed during environment setup.

Comment thread cwms_batch_events/core/settings.py Outdated
Comment on lines 9 to 20
@@ -13,16 +14,49 @@ class Settings(BaseSettings):
cda_api_root: str = "http://traefik/cwms-data/"
default_job_runner: str = "batch"
dynamodb_host: str = "http://dynamodb:9010"
pguser: str = ""
pgpassword: str = ""
pguser: str | None = None
pgpassword: str | None = None
pgdatabase: str = "postgres"
pghost: str = "db"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I would probably go ahead and default these fields to None. Ideally everything will be provided to the environment through either the ECS infrastructure in CWBI or locally through the docker compose config. Keeping defaults set within the app source could lead to debugging confusion -- expected config should be provided explicitly through environment setup for consistency.

default_job_runner is an exception and can remain "batch" -- it isn't provided within the ECS infra.

token,
key,
algorithms=["RS256"],
issuer=ISSUER[settings.auth_environment],
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pylance/Pyright shows an error here due to the change to settings.auth_environment. It's not actually an issue since Pyright just isn't smart enough to fully interpret the validator_boundaries function, but I'm a big fan of getting rid of all linting errors so you might consider re-enforcing the check at the function level (here). Up to you.

@eli-litzelman eli-litzelman requested a review from jbkolze April 30, 2026 13:40
Copy link
Copy Markdown
Contributor

@jbkolze jbkolze left a comment

Choose a reason for hiding this comment

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

Well it looks like we've opened up a bit of a can of worms here...

After the changes, if you spin up a local dev environment from the docker compose file you'll notice that the dispatcher container errors out. It doesn't have sufficient env var configuration to meet the new requirements.

Due to the way the application is structured, any component using the core app (e.g. the API and the local dispatcher container) inherits all of the settings and the associated validation. The API and dispatcher don't require the same config but use the same validation regardless.

Off of the top of my head there are three main ways to resolve this:

  1. Abandon the changes and go back to setting defaults within the pydantic settings. This is the easiest fix but could potentially obfuscate environment configuration issues.
  2. Set "dummy" env vars to avoid errors in the dispatcher container. This would sort of sidestep the issue, but would really only affect a local dev component and nothing used in production so is arguably acceptable.
  3. Break apart the base Settings class into targeted settings classes, e.g. BaseSettings, DispatcherSettings, ApiSettings, etc. using inheritance as appropriate. This is probably the cleanest approach.

Given that this is a national enterprise application I would ultimately lean toward going the 3 route. That will, however, require:

  • Identifying the config dependencies for each component to separate them
  • Removing the global settings = get_settings() and retrieving the appropriate settings as required within each module

So, if you want to go with 1 or 2 I think that'd be acceptable for now. Just depends on how deep you want to dive in. Let me know if you want to discuss.

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.

Default settings to None where appropriate

2 participants