Skip to content

fix: use sentinel to distinguish unset config_filename from explicit None#280

Open
rahulpar2103 wants to merge 1 commit into
laurentS:masterfrom
rahulpar2103:fix/config-filename-sentinel
Open

fix: use sentinel to distinguish unset config_filename from explicit None#280
rahulpar2103 wants to merge 1 commit into
laurentS:masterfrom
rahulpar2103:fix/config-filename-sentinel

Conversation

@rahulpar2103

Copy link
Copy Markdown

Problem

When COPY . . is used in a Dockerfile, any local .env file gets baked
into the image. Inside the container, os.path.isfile(".env") returns True
and slowapi loads it, potentially overriding env vars injected by Docker
--env-file or Kubernetes secrets. The only workaround was the undocumented
config_filename="/dev/null" trick.

The deeper issue: config_filename=None (the default) and
config_filename=None (explicitly passed) were indistinguishable, so there
was no clean API surface to say "don't load any file."

Closes #256

Fix

Introduce a module-level _UNSET = object() sentinel. The parameter default
changes from None to _UNSET. The logic inside __init__ is:

  • config_filename is _UNSET → existing auto-detect behavior (backward-compatible)
  • config_filename is None → skip file loading entirely
  • config_filename is a string → load that specific file (unchanged)

Backward compatibility

Anyone who was calling Limiter(key_func=..., config_filename=None) explicitly
was getting auto-detect behavior, identical to passing nothing. That call now
disables file loading. In practice no one passes the default explicitly, but
this is worth noting in the changelog.

Tests added

  • test_config_filename_none_disables_dotenv_loading: verifies that
    config_filename=None does not load a .env file present in cwd
  • test_config_filename_unset_loads_dotenv_when_present: verifies that
    omitting the argument still auto-loads .env (no regression)
  • test_config_filename_unset_no_dotenv_does_not_error: verifies that
    the no-file case does not raise (the original bug scenario)

Docker note

As a complementary mitigation, users should add .env to .dockerignore
to prevent credentials from being baked into images regardless of library behavior.

…None

Previously, config_filename=None and the default (no argument passed) had
identical behavior: auto-detect .env. This left no clean way to disable
file loading, which breaks Docker/K8s deployments where COPY . . copies
.env into the image but env vars are injected by the orchestration layer.

Introduce _UNSET sentinel so that:
- Limiter(key_func=...)                  -> auto-detects .env (unchanged)
- Limiter(key_func=..., config_filename=None) -> disables file loading
- Limiter(key_func=..., config_filename='/path/to/other.env') -> loads that file

Fixes laurentS#256

@laurentS laurentS left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

@rahulpar2103 thanks for raising this PR. The problem indeed does feel annoying.
I'd be tempted to remove the backwards compatible behaviour here, and only load a config file if explicitly passed. This would both simplify the code in slowapi and follow what Starlette 1.0+ seems to do (and avoid this weird "None means .env" behaviour).
@detrax you raised the original issue, any thoughts on this?

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.

Limiter auto-loads .env file causing Docker permission errors

2 participants