Skip to content

Introduce FastAPI - #2745

Open
lbarcziova wants to merge 4 commits into
packit:mainfrom
lbarcziova:fastapi
Open

Introduce FastAPI#2745
lbarcziova wants to merge 4 commits into
packit:mainfrom
lbarcziova:fastapi

Conversation

@lbarcziova

@lbarcziova lbarcziova commented Mar 10, 2025

Copy link
Copy Markdown
Member

Merge after #2749 (needed for tests to pass)

Fixes #2715

To discuss:

  • which ASGI server to use: currently I played with this with uvicorn, which is simple and lightweight, it doesn’t have http2 support though (for that we could use e.g. hypercorn), you can see some info on the alternatives here
    • after reading few articles, I went with uvicorn for local development and gunicorn + uvicorn workers for prod/stg, as it is supposed to be more suitable for prod envs (scalable, robust)
  • Flask runs under /api and is hardcoded as WSGI, so I couldn’t make it work so that new endpoints are under /api/v1, for now I put them to /v1, wdyt? (redoc and swagger are also on /v1/redoc and /v1/docs)

TODO:

  • tests
  • rename of run_httpd.sh and occurrences
  • polish the code, FastAPI settings, look into security_and_https_middleware more

RELEASE NOTES BEGIN

N/A

RELEASE NOTES END

@softwarefactory-project-zuul

This comment was marked as outdated.

@softwarefactory-project-zuul

This comment was marked as outdated.

@softwarefactory-project-zuul

Copy link
Copy Markdown
Contributor

@Venefilyn Venefilyn 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.

Looks like a good start! I think going with /v1 etc. instead of /api/v1 is fine. Would API documentation go to /v1/docs or /docs?

Comment on lines +149 to +161
# Swagger and ReDoc don't work without these
"style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "
"script-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net; "

@Venefilyn Venefilyn Mar 11, 2025

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.

Something we should track in a separate issue. If auth ever becomes something Packit implements this might then be a security threat - especially with JS scripts

Comment thread tests/unit/test_views.py
@lbarcziova

Copy link
Copy Markdown
Member Author

Would API documentation go to /v1/docs or /docs?

Currently it goes under /docs, but this can be easily changed.

@Venefilyn

Copy link
Copy Markdown
Contributor

Would API documentation go to /v1/docs or /docs?

Currently it goes under /docs, but this can be easily changed.

Ah okay. Yeah I'd say put it under the specific api version due to using versioning

Comment thread CONTRIBUTING.md Outdated
Comment thread packit_service/service/app.py
@lbarcziova
lbarcziova marked this pull request as ready for review March 13, 2025 05:49
@lbarcziova
lbarcziova requested a review from a team as a code owner March 13, 2025 05:49
@softwarefactory-project-zuul

Copy link
Copy Markdown
Contributor

softwarefactory-project-zuul Bot added a commit that referenced this pull request Mar 13, 2025
Add dependencies for FastAPI changes

Related to #2715
Needed for #2745

Reviewed-by: Nikola Forró
Introduce FastAPI running with Uvicorn (+Gunicorn in prod/stg), keep old Flask endpoints under /api hardcoded as WSGI.
New endpoints will come under /v1, Swagger is at /docs and Redoc under /redoc.
We no longer run httpd.

@majamassarini majamassarini left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

I think we should land this on stg soon, because now our stg service instance is down.

Thanks!

@lbarcziova

Copy link
Copy Markdown
Member Author

recheck

@softwarefactory-project-zuul

Copy link
Copy Markdown
Contributor

@lbarcziova

Copy link
Copy Markdown
Member Author

I fixed the staging in #2750 so I would wait with merging this until Monday afternoon (prod deployment), so that this can be observed a bit more in staging.

@lbarcziova

Copy link
Copy Markdown
Member Author

Unfortunately, with the recent capacity reduction of our team, we needed to deprioritise few of the epics so that we are able to deliver the high-prio ones (see board). I won't merge this until we have the necessary capacity to continue with the epic, as changing the framework may introduce additional work.

@lbarcziova lbarcziova added the do-not-merge Do not merge! Work in progress label Mar 31, 2025
@TomasTomecek

Copy link
Copy Markdown
Member

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 10:01 AM UTC · Completed 10:20 AM UTC
Commit: 5cd7aeb · View workflow run →

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

High

  • [CORS-misconfiguration] packit_service/service/app.py — The FastAPI CORS middleware combines allow_origins=["*"] with allow_credentials=True. Starlette's CORSMiddleware reflects the request's Origin header verbatim in this configuration, allowing any origin to make credentialed cross-origin requests. The previous Flask-CORS setup (CORS(app)) defaults to allow_origins="*" without credentials, making this a security regression.
    Remediation: Either remove allow_credentials=True if credentials are not needed, or replace allow_origins=["*"] with a specific allowlist of trusted origins.

Medium

  • [logic-error] packit_service/service/app.py — The HTTPS redirect middleware hardcodes port=443, but the service listens on port 8443. If the redirect fires (e.g., behind a TLS-terminating proxy), it sends clients to the wrong port. The PR body acknowledges this middleware needs further investigation.
    Remediation: Remove the HTTPS redirect (the server already listens on HTTPS), or omit the port=443 override to preserve the existing port.

  • [stale-reference] files/install-deps.yaml — Still installs python3-mod_wsgi, mod_http2, and mod_ssl, which are no longer needed after switching from mod_wsgi-express to uvicorn/gunicorn.
    Remediation: Remove these packages from the install list.

  • [module-level-side-effects] packit_service/service/app.py — The lazy proxy pattern (Proxy(get_flask_application)) is replaced with eager initialization. setup_logging_and_sentry() and get_flask_application() now execute at import time, triggering sentry init, config loading, and syslog connections for every module that imports from app.py, including test files.
    Remediation: Consider retaining lazy initialization or ensuring test imports handle the initialization cleanly.

Low

  • [content-security-policy] packit_service/service/app.py — CSP for FastAPI routes allows https://cdn.jsdelivr.net in script-src and style-src (for Swagger UI/ReDoc), while Flask routes via Talisman use a stricter CSP without it. Standard FastAPI practice but creates a policy inconsistency.

  • [edge-case] packit_service/service/app.py — Flask SERVER_NAME is commented out with a TODO. Without it, Flask derives hostnames from request headers, which may produce incorrect absolute URLs behind a reverse proxy.

  • [duplicate-mechanism] packit_service/service/app.py — CORS is configured on both Flask (CORS(flask_app)) and FastAPI (CORSMiddleware). Requests to /api/* pass through both layers, potentially producing duplicate CORS headers.

  • [scope-creep] files/run_server.sh — The ASGI server migration (mod_wsgi to uvicorn/gunicorn) is a necessary consequence of introducing FastAPI but extends beyond the issue scope. Consider updating the tracking issue.

  • [design-direction] packit_service/service/app.py — URL scheme asymmetry: Flask endpoints at /api/<resource> vs FastAPI at /v1/<resource>. The PR author acknowledges this as a discussion point.

  • [naming-convention] packit_service/service/app.py — App names changed from the distinctive packit_as_a_service to generic flask_app and app.

  • [stale-reference] CONTRIBUTING.md — Example curl output still shows Server: Apache/... mod_wsgi/... headers.

  • [import-ordering] packit_service/service/app.py — Imports from starlette instead of fastapi re-exports for CORSMiddleware and RedirectResponse.

  • [test-structure-consistency] tests_openshift/service/test_api_v1.py — Uses module-level TestClient(app) instead of the established @pytest.fixture pattern.

  • [code-duplication] packit_service/service/api_v1/system.pyget_commit_from_version() is duplicated from the Flask version rather than shared.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

@fullsend-ai-review fullsend-ai-review 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.

See the review comment for full details.


Note: The following inline comments could not be posted on the diff (GitHub returned 422) and are included here instead:

  • packit_service/service/app.py:128: [high] CORS-misconfiguration

The FastAPI CORS middleware combines allow_origins=[''] with allow_credentials=True. Starlette's CORSMiddleware reflects the request's Origin header verbatim in this configuration, allowing any origin to make credentialed cross-origin requests. The previous Flask-CORS setup (CORS(app)) defaults to allow_origins='' without credentials, making this a security regression.

Suggested fix: Either remove allow_credentials=True if credentials are not needed, or replace allow_origins=['*'] with a specific allowlist of trusted origins.

  • packit_service/service/app.py:153: [medium] logic-error

The HTTPS redirect middleware hardcodes port=443, but the service listens on port 8443 (in run_server.sh and docker-compose.yml). If the redirect fires (e.g., behind a TLS-terminating proxy), it sends clients to the wrong port.

Suggested fix: Remove the HTTPS redirect (the server already listens on HTTPS), or omit the port=443 override to preserve the existing port: url = request.url.replace(scheme='https').

  • packit_service/service/app.py:85: [low] edge-case

Flask SERVER_NAME config is commented out with a TODO. Without it, Flask derives hostnames from request headers, which may produce incorrect absolute URLs behind a reverse proxy. The TODO acknowledges local deployment issues.

  • CONTRIBUTING.md (file-level): Line 73 · [low] stale-reference

Example curl output still shows Server: Apache/... mod_wsgi/... headers, which are no longer accurate since the server now runs Uvicorn/Gunicorn.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

do-not-merge Do not merge! Work in progress

Projects

No open projects
Status: in-review

Development

Successfully merging this pull request may close these issues.

Introduce FastAPI alongside Flask

5 participants