Conversation
## Walkthrough
The changes refactor the application's startup process and container initialization. The Dockerfile now uses a new shell script (`entrypoint.sh`) as the entrypoint, which runs a Python script (`entrypoint.py`) that prints and executes a Uvicorn server command. The FastAPI application's startup logic is migrated from a synchronous function to an asynchronous lifespan context manager, with improved error handling and initialization flow.
## Changes
| Files/Group | Change Summary |
|------------------------------------------------|----------------|
| Dockerfile | Replaces direct Gunicorn startup by copying and using `entrypoint.sh` and `entrypoint.py` for container entrypoint logic. Entrypoint command now runs the shell script instead of invoking Gunicorn via `uv run`. |
| entrypoint.py | New script that loads configuration and prints a Uvicorn server command string with host, port, and worker count for running the FastAPI app. |
| entrypoint.sh | New shell script that runs `uv run ./entrypoint.py`, captures and prints its output, then executes the printed command. Uses strict shell options for error handling and command tracing. |
| webhook_server/app.py | Refactors startup logic from synchronous `on_starting` function to async lifespan context manager with `@asynccontextmanager`. Moves initialization into lifespan, adds error logging, and updates FastAPI app instantiation to use the lifespan handler. Removes webhook secret retrieval and repository/webhook settings call from startup. Refactors webhook processing background task with improved error handling and logging. Renames response keys and messages. |
| webhook_server/utils/github_repository_settings.py | Replaces direct `os.system` call for `podman login` with a call to `run_command` with error checking enabled. Consolidates logger usage to a module-level logger instance passed to `Config`. |
| webhook_server/utils/helpers.py | Extends `get_logger_with_params` to accept parameters for sensitive data masking. Updates `run_command` to use a logger that masks sensitive information by default using predefined patterns. |
| webhook_server/utils/github_repository_and_webhook_settings.py | Introduces a module-level logger instance replacing local loggers. Simplifies repository iteration and passes shared logger to `Config`. |
| pyproject.toml | Removes `gunicorn>=23.0.0` and `uvicorn-worker>=0.3.0` dependencies from the project dependencies list. Adds trailing comma after last dependency. |
## Possibly related PRs
- myk-org/github-webhook-server#735: The main PR replaces the direct Gunicorn startup in the Dockerfile with a new entrypoint script that runs a Python script to generate the Uvicorn command, while the retrieved PR replaces the entrypoint script with a direct Gunicorn invocation and adds a Gunicorn config file using the `on_starting` hook; both modify container startup and server launch but in opposite directions.
- myk-org/github-webhook-server#741: Related changes to `webhook_server/app.py` startup logic, both modifying app initialization and lifecycle handling.
- myk-org/github-webhook-server#579: Related Dockerfile and entrypoint script changes switching from Gunicorn to `uv` for running commands.
## Suggested labels
`verified`, `commented-coderabbitai[bot]`
## Suggested reviewers
- rnetserTip ⚡️ Faster reviews with caching
Enjoy the performance boost—your workflow just got faster. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
⏰ Context from checks skipped due to timeout of 90000ms (9)
✨ Finishing Touches
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
|
Report bugs in Issues The following are automatically added:
Available user actions:
PR will be approved when the following conditions are met:
Approvers and Reviewers
Supported /retest check runs
Supported labels
|
There was a problem hiding this comment.
Actionable comments posted: 2
🔭 Outside diff range comments (1)
entrypoint.py (1)
9-15: 🛠️ Refactor suggestion
⚠️ Potential issueAvoid the “double uv run” & drop unused Gunicorn leftovers
entrypoint.shalready executes
uv run ./entrypoint.py.
The printed string therefore must not start with anotheruv run; otherwise we end up nestinguv run→uv run→uvicorn …, which adds unnecessary process-spawning cost and makes debugging signals harder.In addition, the variables
bind,workers, andon_startingare no longer consumed and only create confusion.-bind = f"{_ip_bind}:{_port}" -workers = int(_max_workers) -on_starting = "webhook_server.app.on_starting" - -print(f"uv run uvicorn webhook_server.app:FASTAPI_APP --host {_ip_bind} --port {_port} --workers {_max_workers}") +print(f"uvicorn webhook_server.app:FASTAPI_APP " + f"--host {_ip_bind} --port {_port} --workers {int(_max_workers)}") + +# NOTE: This file is executed via `uv run`; we therefore print only +# the final command, not another `uv run …`.Cleaning this up prevents a redundant process layer and eliminates dead code.
🧹 Nitpick comments (4)
entrypoint.py (1)
1-8: Guard side-effects & improve discoverabilityBecause the module is imported only for its side-effect (printing), wrap it in the canonical guard to avoid accidental execution when the file is imported elsewhere:
-print(f"uvicorn webhook_server.app:FASTAPI_APP " - f"--host {_ip_bind} --port {_port} --workers {int(_max_workers)}") +if __name__ == "__main__": + print( + f"uvicorn webhook_server.app:FASTAPI_APP " + f"--host {_ip_bind} --port {_port} --workers {int(_max_workers)}" + )This costs nothing but prevents surprises in tests or REPL sessions.
Dockerfile (1)
63-67: Minor: collapse layers by chaining RUN commandsYou can append the
chmodto the existingRUN uv syncline or combine it with the earlierRUN mkdir …to keep the image smaller, but this is optional.webhook_server/app.py (2)
87-123: Refine lifespan error-handling & remove duplicateyield
- Calling
os.kill(os.getpid(), signal.SIGTERM)from within the startup coroutine kills the whole process immediately, bypassing proper shutdown of already-started tasks (e.g. DB pools). Consider re-raising the exception and lettinguvicornexit cleanly, or usesys.exit(1)after logging.- The
yieldstatement is duplicated in theif/else; move it once after the allow-list handling for clarity.- if verify_github_ips or verify_cloudflare_ips: - … - logger.info(f"IP allowlist initialized successfully. {ALLOWED_IPS}") - yield - else: - yield + if verify_github_ips or verify_cloudflare_ips: + … + logger.info("IP allowlist initialized successfully. %s", ALLOWED_IPS) + + # Hand control back to FastAPI + yield … - logger.error(f"Application failed to start up: {e}") - os.kill(os.getpid(), signal.SIGTERM) - # sys.exit(1) + logger.exception("Application failed to start up") + raiseThis keeps the control-flow simple and lets the process manager (supervisor/K8s) see a non-zero exit code.
105-114: Type hint: avoid private_BaseNetworkUsing
_BaseNetworkties you toipaddressinternals. Prefer the publicipaddress.IPv4Network | ipaddress.IPv6Network(oripaddress.IPv4Network, ipaddress.IPv6Networkunion) for forward compatibility.-ALLOWED_IPS: tuple[ipaddress._BaseNetwork, ...] = () +ALLOWED_IPS: tuple[ipaddress.IPv4Network | ipaddress.IPv6Network, ...] = ()
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (4)
Dockerfile(2 hunks)entrypoint.py(1 hunks)entrypoint.sh(1 hunks)webhook_server/app.py(4 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (1)
webhook_server/app.py (1)
webhook_server/utils/helpers.py (1)
get_logger_with_params(20-29)
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: tox
- GitHub Check: build-container
- GitHub Check: pre-commit
- GitHub Check: python-module-install
There was a problem hiding this comment.
Actionable comments posted: 1
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
uv.lockis excluded by!**/*.lock
📒 Files selected for processing (3)
Dockerfile(2 hunks)entrypoint.sh(1 hunks)pyproject.toml(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- entrypoint.sh
- Dockerfile
⏰ Context from checks skipped due to timeout of 90000ms (9)
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: can-be-merged
- GitHub Check: pre-commit
- GitHub Check: tox
- GitHub Check: python-module-install
- GitHub Check: build-container
|
/verified |
|
/approve |
Summary by CodeRabbit