Skip to content

Define config precedence and add redacted effective-config startup logging - #14

Merged
ThomasBury merged 2 commits into
mainfrom
codex/define-config-precedence-and-add-debug-log
Mar 3, 2026
Merged

Define config precedence and add redacted effective-config startup logging#14
ThomasBury merged 2 commits into
mainfrom
codex/define-config-precedence-and-add-debug-log

Conversation

@ThomasBury

@ThomasBury ThomasBury commented Mar 3, 2026

Copy link
Copy Markdown
Owner

Motivation

  • Centralize runtime configuration and make source precedence explicit so deployments and local development behave predictably.
  • Ensure secrets (JWT secret) are not hardcoded and must be provided by the environment or a local .env during development.
  • Expose a minimal, non-secret “effective config” at startup to aid troubleshooting without leaking sensitive values.

Description

  • Add a new settings module src/acebet/app/config.py that loads configuration with precedence: process environment → local .env (load_dotenv(override=False)) → in-code defaults for non-sensitive values, and requires ACEBET_SECRET_KEY.
  • Wire the application to use settings: replace hardcoded auth constants in src/acebet/app/dependencies/auth.py and use settings for rate limits and logging in src/acebet/app/main.py, including a redacted debug log settings.redacted() emitted at startup.
  • Update docs (README.md, docs/getting-started.md) to document the precedence order and the required ACEBET_SECRET_KEY setup and note the startup redacted config log.
  • Add python-dotenv to pyproject.toml and the lockfile, and update tests/test_acebet.py to set ACEBET_SECRET_KEY before importing the app so the test suite runs deterministically.

Testing

  • Ran linting checks with uv run ruff check src/acebet/app/config.py src/acebet/app/main.py src/acebet/app/dependencies/auth.py tests/test_acebet.py and the selected files passed the checks.
  • Ran the test suite with uv run pytest tests and all tests passed (4 passed, with unrelated deprecation warnings reported by dependencies).

Codex Task

Summary by CodeRabbit

  • Documentation

    • Updated quickstart and getting-started guide with environment variable configuration instructions.
  • New Features

    • Runtime configuration via environment variables and .env files with precedence order (environment → .env → defaults).
    • Required ACEBET_SECRET_KEY environment variable; startup logs display effective configuration (secrets redacted) for troubleshooting.
  • Chores

    • Added python-dotenv dependency for .env file support.

@coderabbitai

coderabbitai Bot commented Mar 3, 2026

Copy link
Copy Markdown

Warning

Rate limit exceeded

@ThomasBury has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 25 minutes and 28 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9b325c8 and 58c82bf.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • README.md
  • docs/getting-started.md
  • pyproject.toml
  • src/acebet/app/main.py
  • tests/test_acebet.py
📝 Walkthrough

Walkthrough

This PR introduces centralized configuration management via a new config.py module with environment variable precedence (process env > .env file > code defaults) and integrates it throughout the application. Documentation is updated to reflect the configuration setup, and python-dotenv is added as a dependency.

Changes

Cohort / File(s) Summary
Documentation Updates
README.md, docs/getting-started.md
Added environment variable quickstart example (ACEBET_SECRET_KEY), documented config precedence rules (process env, local .env, code defaults), and noted startup log output showing effective redacted configuration for troubleshooting.
Configuration System
src/acebet/app/config.py
New module implementing centralized Settings dataclass with runtime configuration fields (secret_key, algorithm, access_token_expire_minutes, rate limits, logging). Includes load_settings() function with three-tier precedence handling and a redacted() method for safe logging. Validates ACEBET_SECRET_KEY presence.
Auth & Main Integration
src/acebet/app/dependencies/auth.py, src/acebet/app/main.py
Replaced hard-coded constants (SECRET_KEY, ALGORITHM, token expiration, rate limits, logging configuration) with values sourced from centralized settings object.
Dependencies & Tests
pyproject.toml, tests/test_acebet.py
Added python-dotenv>=1.0.1 dependency. Set ACEBET_SECRET_KEY test environment variable at import time to satisfy configuration validation.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

enhancement

Poem

🐰 A config so neat, organized and clean,
No more secrets scattered, hidden unseen!
From env to .env, defaults in place,
The rabbit hops faster through config's embrace! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title accurately describes the main change: centralizing configuration precedence and adding startup logging for effective (redacted) configuration.
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 unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch codex/define-config-precedence-and-add-debug-log

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@gemini-code-assist

Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the application's configuration management by introducing a robust and explicit system for loading settings. It centralizes all runtime parameters, enforces a clear precedence for their sources, and ensures that sensitive data like the ACEBET_SECRET_KEY is always provided securely via environment variables or .env files. Additionally, it improves debuggability by logging a redacted version of the effective configuration at startup, making it easier to troubleshoot deployment issues.

Highlights

  • Centralized Configuration: Introduced a new config.py module to centralize application settings, defining a clear precedence order for loading values from process environment variables, local .env files, and in-code defaults.
  • Required Secret Key: Mandated the ACEBET_SECRET_KEY environment variable for security, ensuring sensitive data is not hardcoded and must be provided externally.
  • Redacted Startup Logging: Implemented a debug log at application startup that displays a redacted version of the effective configuration, aiding troubleshooting without exposing sensitive information.
  • Configuration Integration: Refactored authentication constants and API rate limits to utilize the new centralized configuration system.
  • Documentation Updates: Updated README.md and docs/getting-started.md to reflect the new configuration precedence, the requirement for ACEBET_SECRET_KEY, and the presence of the startup config log.
  • Dependency Addition: Added python-dotenv to the project dependencies to facilitate loading environment variables from .env files.

🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console.

Changelog
  • README.md
    • Added instructions to export ACEBET_SECRET_KEY for local testing.
    • Documented the runtime configuration precedence order.
    • Mentioned the startup debug log for effective configuration.
  • docs/getting-started.md
    • Added a new section for configuring environment variables, detailing precedence and the ACEBET_SECRET_KEY.
    • Updated the "Start the API" section to reflect the new configuration step.
    • Included a note about the redacted effective config log in startup expectations.
  • pyproject.toml
    • Added python-dotenv as a project dependency.
  • src/acebet/app/config.py
    • Created a new module to define the Settings dataclass for application configuration.
    • Implemented load_settings to load values from environment variables and .env files with defined precedence.
    • Included a redacted method in Settings to provide a safe-for-logging version of the configuration.
  • src/acebet/app/dependencies/auth.py
    • Imported the new settings object.
    • Replaced hardcoded SECRET_KEY, ALGORITHM, and ACCESS_TOKEN_EXPIRE_MINUTES with values from settings.
  • src/acebet/app/main.py
    • Imported the new settings object.
    • Configured limiter with default_limits and login_rate_limit from settings.
    • Updated logging.basicConfig to use settings.log_file and settings.log_level.
    • Added a debug log message at startup to display the settings.redacted() output.
  • tests/test_acebet.py
    • Added os.environ.setdefault("ACEBET_SECRET_KEY", "test-secret-key") to ensure the secret key is set for tests.
Activity
  • The author ran linting checks on modified files (src/acebet/app/config.py, src/acebet/app/main.py, src/acebet/app/dependencies/auth.py, tests/test_acebet.py), which passed.
  • The author executed the full test suite (uv run pytest tests), and all tests passed.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@gemini-code-assist gemini-code-assist Bot left a comment

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.

Code Review

This pull request effectively refactors configuration management by centralizing settings, removing hardcoded secrets, and establishing a clear precedence for loading configuration values. The changes improve security and maintainability. I've added a couple of suggestions in src/acebet/app/config.py to enhance robustness against configuration errors and improve the maintainability of the settings redaction logic.

Comment thread src/acebet/app/config.py Outdated
Comment on lines +52 to +62
return Settings(
secret_key=secret_key,
algorithm=os.getenv("ACEBET_ALGORITHM", "HS256"),
access_token_expire_minutes=int(
os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES", "30")
),
default_rate_limit=os.getenv("ACEBET_DEFAULT_RATE_LIMIT", "12/minute"),
login_rate_limit=os.getenv("ACEBET_LOGIN_RATE_LIMIT", "5/minute"),
log_level=os.getenv("ACEBET_LOG_LEVEL", "DEBUG"),
log_file=os.getenv("ACEBET_LOG_FILE", "info.log"),
)

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.

high

The direct int() conversion for ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES could lead to an unhandled ValueError if the environment variable is set to a non-integer string, causing the application to crash on startup. It's safer to wrap this conversion in a try-except block to handle potential malformed input gracefully and provide a clearer error message.

    try:
        expire_minutes = int(os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES", "30"))
    except ValueError as e:
        raise ValueError("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES must be an integer.") from e

    return Settings(
        secret_key=secret_key,
        algorithm=os.getenv("ACEBET_ALGORITHM", "HS256"),
        access_token_expire_minutes=expire_minutes,
        default_rate_limit=os.getenv("ACEBET_DEFAULT_RATE_LIMIT", "12/minute"),
        login_rate_limit=os.getenv("ACEBET_LOGIN_RATE_LIMIT", "5/minute"),
        log_level=os.getenv("ACEBET_LOG_LEVEL", "DEBUG"),
        log_file=os.getenv("ACEBET_LOG_FILE", "info.log"),
    )

@ThomasBury ThomasBury Mar 3, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@codex implement the fix

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.

As an AI assistant, I am unable to directly implement changes or commit code to the repository. My role is to provide suggestions and answer technical questions. The code suggestion I provided in the previous comment outlines the fix for handling the ValueError when converting ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES to an integer. You can apply that suggestion to resolve the issue.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@codex implement the fix

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Summary

  • Implemented the requested config hardening in AppSettings by adding explicit pre-parse validation for ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES so malformed values now raise a clear targeted error message instead of an opaque conversion failure. src/acebet/app/config.pyL32-L42
  • Updated secret handling to normalize ACEBET_SECRET_KEY and reject whitespace-only values as missing, preserving the existing required-secret validation behavior in non-dev environments. src/acebet/app/config.pyL54-L72
  • Added the missing settings fields used by app startup/rate limiting (ACEBET_DEFAULT_RATE_LIMIT, ACEBET_LOGIN_RATE_LIMIT, ACEBET_LOG_LEVEL, ACEBET_LOG_FILE) and kept a redacted settings payload for startup logging. src/acebet/app/config.pyL21-L31 src/acebet/app/config.pyL74-L86
  • Updated main.py to use the settings object correctly for limiter/logging configuration and rate-limit decorators. src/acebet/app/main.pyL34-L46 src/acebet/app/main.pyL115-L117
  • Made tests deterministic by explicitly setting ACEBET_ENV and ACEBET_SECRET_KEY before importing the app module. tests/test_acebet.pyL6-L10
  • Clarified docs to state that the redacted effective-config message is written to configured app logs (default info.log / ACEBET_LOG_FILE). docs/getting-started.mdL77-L78

Testing

  • curl -I -A 'Mozilla/5.0' https://docs.pydantic.dev/latest/concepts/validators/ | head
  • uv run ruff check src/acebet/app/config.py src/acebet/app/main.py tests/test_acebet.py
  • uv run pytest tests

Also completed:

  • Committed changes on the current branch (e1163ce).
  • Created a follow-up PR via the make_pr tool with title: “Follow-up: harden config validation for malformed env vars and deterministic tests.”

View task →

Comment thread src/acebet/app/config.py Outdated
Comment on lines +29 to +38
def redacted(self) -> dict[str, str | int]:
"""Return configuration values safe for debug logging."""
return {
"algorithm": self.algorithm,
"access_token_expire_minutes": self.access_token_expire_minutes,
"default_rate_limit": self.default_rate_limit,
"login_rate_limit": self.login_rate_limit,
"log_level": self.log_level,
"log_file": self.log_file,
}

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.

medium

The redacted method manually lists non-sensitive fields. This approach is brittle and can lead to accidental leakage of new sensitive fields if they are not explicitly excluded, or failure to log new non-sensitive fields if they are not explicitly included. A more maintainable and robust approach is to convert the dataclass to a dictionary and programmatically remove the known sensitive keys.

The suggestion uses __import__ to be self-contained. A cleaner approach would be to add from dataclasses import asdict to your file-level imports and then call asdict(self) directly.

    def redacted(self) -> dict[str, str | int]:
        """Return configuration values safe for debug logging."""
        config_dict = __import__("dataclasses").asdict(self)
        del config_dict["secret_key"]
        return config_dict

@ThomasBury ThomasBury Mar 3, 2026

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

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

@codex implement this suggestion

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.

Thank you for your comment. As an AI, I am unable to directly implement changes or commit code to the repository. My role is to provide suggestions and feedback.

The code suggestion I provided earlier can be applied by you to fix the issue. For a cleaner approach, you can add from dataclasses import asdict to your file-level imports and then use asdict(self) directly, as mentioned in my previous comment. Here is the suggested code again for your convenience:

Suggested change
def redacted(self) -> dict[str, str | int]:
"""Return configuration values safe for debug logging."""
return {
"algorithm": self.algorithm,
"access_token_expire_minutes": self.access_token_expire_minutes,
"default_rate_limit": self.default_rate_limit,
"login_rate_limit": self.login_rate_limit,
"log_level": self.log_level,
"log_file": self.log_file,
}
def redacted(self) -> dict[str, str | int]:
"""Return configuration values safe for debug logging."""
config_dict = __import__("dataclasses").asdict(self)
del config_dict["secret_key"]
return config_dict

@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: 2

🧹 Nitpick comments (3)
src/acebet/app/config.py (1)

55-57: Improve invalid integer config error reporting.

Lines 55–57 raise a generic conversion traceback on bad input. Wrapping this with a targeted message will make startup failures much easier to diagnose.

🛠️ Proposed fix
-    return Settings(
+    try:
+        access_token_expire_minutes = int(
+            os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES", "30")
+        )
+    except ValueError as exc:
+        raise ValueError(
+            "ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES must be a valid integer."
+        ) from exc
+
+    return Settings(
         secret_key=secret_key,
         algorithm=os.getenv("ACEBET_ALGORITHM", "HS256"),
-        access_token_expire_minutes=int(
-            os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES", "30")
-        ),
+        access_token_expire_minutes=access_token_expire_minutes,
         default_rate_limit=os.getenv("ACEBET_DEFAULT_RATE_LIMIT", "12/minute"),
         login_rate_limit=os.getenv("ACEBET_LOGIN_RATE_LIMIT", "5/minute"),
         log_level=os.getenv("ACEBET_LOG_LEVEL", "DEBUG"),
         log_file=os.getenv("ACEBET_LOG_FILE", "info.log"),
     )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/acebet/app/config.py` around lines 55 - 57, The conversion of
ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES to int in the access_token_expire_minutes
assignment can raise an opaque traceback on invalid input; wrap the int(...)
call in a try/except in config.py around the access_token_expire_minutes
assignment (the expression using os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES",
"30")) and on ValueError raise a new error with a clear message that includes
the invalid value and guidance (e.g., "Invalid
ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES='...': must be integer"), so startup logs
clearly indicate which environment variable is malformed.
src/acebet/app/main.py (1)

41-44: Fail fast on invalid ACEBET_LOG_LEVEL instead of silently defaulting.

Line 43 currently falls back to DEBUG on typos, which can hide config mistakes. Consider validating the level and raising a clear startup error.

🧭 Proposed fix
-logging.basicConfig(
-    filename=settings.log_file,
-    level=getattr(logging, settings.log_level.upper(), logging.DEBUG),
-)
+resolved_level = getattr(logging, settings.log_level.upper(), None)
+if not isinstance(resolved_level, int):
+    raise ValueError("ACEBET_LOG_LEVEL must be a valid logging level (e.g. DEBUG, INFO, WARNING, ERROR).")
+
+logging.basicConfig(
+    filename=settings.log_file,
+    level=resolved_level,
+)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/acebet/app/main.py` around lines 41 - 44, Replace the silent fallback in
logging.basicConfig that uses getattr(logging, settings.log_level.upper(),
logging.DEBUG) with explicit validation of settings.log_level (e.g., check
settings.log_level.upper() against logging._nameToLevel or call
logging._nameToLevel.get(level_name)) and, if the level name is not valid, raise
a clear startup error (ValueError) referencing ACEBET_LOG_LEVEL and the invalid
value; only call logging.basicConfig with the validated numeric level when
validation succeeds (use logging.basicConfig(..., level=numeric_level)).
docs/getting-started.md (1)

60-60: Clarify where the redacted config message is emitted.

Line 60 is accurate but ambiguous; the message is written via configured logging output (default file), not guaranteed in console output. Consider explicitly pointing to ACEBET_LOG_FILE/info.log.

✏️ Suggested doc tweak
-- Startup logs include an `Effective config (secrets redacted)` debug message for troubleshooting.
+- The configured application logs (default: `info.log`, configurable via `ACEBET_LOG_FILE`) include an
+  `Effective config (secrets redacted)` debug message for troubleshooting.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@docs/getting-started.md` at line 60, Update the sentence that mentions
"Effective config (secrets redacted)" to explicitly state that this debug
message is written to the configured logging output (not guaranteed to appear on
stdout), and point readers to the ACEBET_LOG_FILE (defaulting to info.log) as
the place to look for it; change the wording around the existing "Effective
config (secrets redacted)" reference so it clarifies the message emitter
(configured logger) and mentions ACEBET_LOG_FILE/info.log as the default log
location.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/acebet/app/config.py`:
- Around line 45-50: The current secret_key obtained via
os.getenv("ACEBET_SECRET_KEY") considers whitespace-only strings valid; update
the check around secret_key in config.py to reject values that are empty after
trimming (e.g., treat None, '', or strings where secret_key.strip() == '' as
missing) and raise the same ValueError; locate the secret_key variable and its
validation and replace the truthy check with a stripped-empty-aware check so
whitespace-only secrets are rejected.

In `@tests/test_acebet.py`:
- Line 6: Replace the non-deterministic os.environ.setdefault call with an
explicit assignment so tests always use the same secret: change the
os.environ.setdefault("ACEBET_SECRET_KEY", "test-secret-key") usage in the
test_acebet module to assign os.environ["ACEBET_SECRET_KEY"] = "test-secret-key"
(referencing ACEBET_SECRET_KEY and os.environ).

---

Nitpick comments:
In `@docs/getting-started.md`:
- Line 60: Update the sentence that mentions "Effective config (secrets
redacted)" to explicitly state that this debug message is written to the
configured logging output (not guaranteed to appear on stdout), and point
readers to the ACEBET_LOG_FILE (defaulting to info.log) as the place to look for
it; change the wording around the existing "Effective config (secrets redacted)"
reference so it clarifies the message emitter (configured logger) and mentions
ACEBET_LOG_FILE/info.log as the default log location.

In `@src/acebet/app/config.py`:
- Around line 55-57: The conversion of ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES to int
in the access_token_expire_minutes assignment can raise an opaque traceback on
invalid input; wrap the int(...) call in a try/except in config.py around the
access_token_expire_minutes assignment (the expression using
os.getenv("ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES", "30")) and on ValueError raise a
new error with a clear message that includes the invalid value and guidance
(e.g., "Invalid ACEBET_ACCESS_TOKEN_EXPIRE_MINUTES='...': must be integer"), so
startup logs clearly indicate which environment variable is malformed.

In `@src/acebet/app/main.py`:
- Around line 41-44: Replace the silent fallback in logging.basicConfig that
uses getattr(logging, settings.log_level.upper(), logging.DEBUG) with explicit
validation of settings.log_level (e.g., check settings.log_level.upper() against
logging._nameToLevel or call logging._nameToLevel.get(level_name)) and, if the
level name is not valid, raise a clear startup error (ValueError) referencing
ACEBET_LOG_LEVEL and the invalid value; only call logging.basicConfig with the
validated numeric level when validation succeeds (use logging.basicConfig(...,
level=numeric_level)).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 67ac4f8 and 9b325c8.

⛔ Files ignored due to path filters (1)
  • uv.lock is excluded by !**/*.lock
📒 Files selected for processing (7)
  • README.md
  • docs/getting-started.md
  • pyproject.toml
  • src/acebet/app/config.py
  • src/acebet/app/dependencies/auth.py
  • src/acebet/app/main.py
  • tests/test_acebet.py

Comment thread src/acebet/app/config.py Outdated
Comment on lines +45 to +50
secret_key = os.getenv("ACEBET_SECRET_KEY")
if not secret_key:
raise ValueError(
"Missing ACEBET_SECRET_KEY. Set it in the process environment "
"or a local .env file."
)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Reject whitespace-only secret keys.

Line 46 currently accepts values like " " as valid secrets. That weakens auth security guarantees and should be rejected like empty values.

🔐 Proposed fix
-    secret_key = os.getenv("ACEBET_SECRET_KEY")
-    if not secret_key:
+    secret_key = (os.getenv("ACEBET_SECRET_KEY") or "").strip()
+    if not secret_key:
         raise ValueError(
             "Missing ACEBET_SECRET_KEY. Set it in the process environment "
             "or a local .env file."
         )
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
secret_key = os.getenv("ACEBET_SECRET_KEY")
if not secret_key:
raise ValueError(
"Missing ACEBET_SECRET_KEY. Set it in the process environment "
"or a local .env file."
)
secret_key = (os.getenv("ACEBET_SECRET_KEY") or "").strip()
if not secret_key:
raise ValueError(
"Missing ACEBET_SECRET_KEY. Set it in the process environment "
"or a local .env file."
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/acebet/app/config.py` around lines 45 - 50, The current secret_key
obtained via os.getenv("ACEBET_SECRET_KEY") considers whitespace-only strings
valid; update the check around secret_key in config.py to reject values that are
empty after trimming (e.g., treat None, '', or strings where secret_key.strip()
== '' as missing) and raise the same ValueError; locate the secret_key variable
and its validation and replace the truthy check with a stripped-empty-aware
check so whitespace-only secrets are rejected.

Comment thread tests/test_acebet.py

from fastapi.testclient import TestClient

os.environ.setdefault("ACEBET_SECRET_KEY", "test-secret-key")

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Use explicit test secret assignment for deterministic runs.

Line 6 uses setdefault, so an externally set ACEBET_SECRET_KEY can change test behavior across environments. Force a known test value here.

✅ Proposed fix
-os.environ.setdefault("ACEBET_SECRET_KEY", "test-secret-key")
+os.environ["ACEBET_SECRET_KEY"] = "test-secret-key"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
os.environ.setdefault("ACEBET_SECRET_KEY", "test-secret-key")
os.environ["ACEBET_SECRET_KEY"] = "test-secret-key"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/test_acebet.py` at line 6, Replace the non-deterministic
os.environ.setdefault call with an explicit assignment so tests always use the
same secret: change the os.environ.setdefault("ACEBET_SECRET_KEY",
"test-secret-key") usage in the test_acebet module to assign
os.environ["ACEBET_SECRET_KEY"] = "test-secret-key" (referencing
ACEBET_SECRET_KEY and os.environ).

@ThomasBury
ThomasBury merged commit 7a5dcf1 into main Mar 3, 2026
3 checks passed
@ThomasBury
ThomasBury deleted the codex/define-config-precedence-and-add-debug-log branch April 29, 2026 15:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant