Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 27 additions & 6 deletions .docker/e2e-realm-export.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@
"implicitFlowEnabled": false,
"standardFlowEnabled": true,
"directAccessGrantsEnabled": true,
"redirectUris": ["*"],
"webOrigins": ["*"],
"redirectUris": [
"*"
],
"webOrigins": [
"*"
],
"protocol": "openid-connect",
"attributes": {
"pkce.code.challenge.method": "S256"
Expand Down Expand Up @@ -120,8 +124,12 @@
"implicitFlowEnabled": false,
"standardFlowEnabled": true,
"directAccessGrantsEnabled": false,
"redirectUris": ["http://localhost/docs/oauth2-redirect"],
"webOrigins": ["http://localhost"],
"redirectUris": [
"http://localhost/docs/oauth2-redirect"
],
"webOrigins": [
"http://localhost"
],
"protocol": "openid-connect",
"attributes": {
"pkce.code.challenge.method": "S256"
Expand Down Expand Up @@ -169,7 +177,20 @@
"temporary": false
}
],
"requiredActions": []
"requiredActions": [],
"realmRoles": [
"entities:write"
]
}
]
],
"roles": {
"realm": [
{
"name": "entities:write",
"description": "May create, update and delete entities",
"composite": false,
"clientRole": false
}
]
}
}
35 changes: 29 additions & 6 deletions .docker/realm-export.json
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,12 @@
"implicitFlowEnabled": false,
"standardFlowEnabled": true,
"directAccessGrantsEnabled": false,
"redirectUris": ["*"],
"webOrigins": ["*"],
"redirectUris": [
"*"
],
"webOrigins": [
"*"
],
"protocol": "openid-connect",
"attributes": {
"pkce.code.challenge.method": "S256"
Expand All @@ -106,8 +110,12 @@
"implicitFlowEnabled": false,
"standardFlowEnabled": true,
"directAccessGrantsEnabled": false,
"redirectUris": ["http://localhost/docs/oauth2-redirect"],
"webOrigins": ["http://localhost"],
"redirectUris": [
"http://localhost/docs/oauth2-redirect"
],
"webOrigins": [
"http://localhost"
],
"protocol": "openid-connect",
"attributes": {
"pkce.code.challenge.method": "S256"
Expand Down Expand Up @@ -149,7 +157,22 @@
"firstName": "Test",
"lastName": "User",
"credentials": [],
"requiredActions": ["UPDATE_PASSWORD"]
"requiredActions": [
"UPDATE_PASSWORD"
],
"realmRoles": [
"entities:write"
]
}
]
],
"roles": {
"realm": [
{
"name": "entities:write",
"description": "May create, update and delete entities",
"composite": false,
"clientRole": false
}
]
}
}
18 changes: 18 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.{yml,yaml,json,toml,md,tf,hcl}]
indent_size = 2

[Makefile]
indent_style = tab

[*.md]
trim_trailing_whitespace = false
5 changes: 5 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ APP_NAME=FastAPI Template
APP_HOST=127.0.0.1
PORT=80
RELOAD=False
# Trust X-Forwarded-* headers only from these proxies (uvicorn semantics; "*" trusts all).
PROXY_HEADERS=False
FORWARDED_ALLOW_IPS=127.0.0.1

## Docker Compose settings ##
# Optional Compose isolation. Give each simultaneous stack a unique project name.
Expand Down Expand Up @@ -35,6 +38,8 @@ OIDC_DOCS_CLIENT_ID=fastapi-docs
# Confidential-client credential used by the optional scenario-test workflow.
OIDC_CLIENT_SECRET=<oidc-client-secret>
OIDC_JWKS_CACHE_TTL_SECONDS=300
# Seconds to wait before refetching JWKS after a token with an unknown key id (0 disables the wait).
OIDC_JWKS_REFRESH_COOLDOWN_SECONDS=30
KEYCLOAK_ADMIN_PASSWORD=<keycloak-admin-password>
# Optional: override discovered endpoints (skips HTTP fetch — useful in air-gapped envs or tests)
# OIDC_JWKS_URI=http://localhost:8080/realms/fastapi-realm/protocol/openid-connect/certs
Expand Down
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* @Subhransu-De
14 changes: 14 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
## What changes

<!-- One or two sentences. Link the issue if there is one. -->

## Gates

- [ ] `make check` is green
- [ ] `make test-integration` is green (required for model, repository, database or migration changes)
- [ ] `tests/contract/openapi.json` is updated and the diff is intended (required for route, schema or error changes)
- [ ] New Keycloak roles are added to both realm exports in `.docker/`

## Notes for the reviewer

<!-- Anything that is not obvious from the diff: a decision, a trade-off, a follow-up. -->
42 changes: 42 additions & 0 deletions .github/workflows/quality-weekly.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: Weekly quality

on:
schedule:
- cron: "0 3 * * 1"
workflow_dispatch:

permissions:
contents: read

jobs:
mutation-testing:
runs-on: ubuntu-latest
timeout-minutes: 120

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0

- name: Install Python
run: uv python install

- name: Install dependencies
run: uv sync --locked --no-build --group test

- name: Run mutation testing
run: uv run --locked --no-build --with mutmut mutmut run

- name: Summarize surviving mutants
if: always()
run: uv run --locked --no-build --with mutmut mutmut results | tee mutmut-results.txt

- name: Upload mutation report
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: mutmut-results
path: |
mutmut-results.txt
mutants/
if-no-files-found: ignore
39 changes: 30 additions & 9 deletions .github/workflows/workflow.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ on:
- "docker-compose*.yml"
- ".docker/**"
- "scenario-tests/**"
- "tests/**"
- "renovate.json"
- "sonar-project.properties"
- ".sonarcloud.properties"
Expand All @@ -30,6 +31,7 @@ on:
- "docker-compose*.yml"
- ".docker/**"
- "scenario-tests/**"
- "tests/**"
- "renovate.json"
- "sonar-project.properties"
- ".sonarcloud.properties"
Expand Down Expand Up @@ -83,6 +85,16 @@ jobs:
- name: Lint GitHub Actions workflows
uses: raven-actions/actionlint@3d39aea434753780c3b3d4a1a31c854b4dbf49d7 # v2

typos:
runs-on: ubuntu-latest
needs: [hadolint]

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Check spelling
uses: crate-ci/typos@00f422f3b19c57bc6338715ebfe3316d38768461 # v1.50.3

dependency-audit:
runs-on: ubuntu-latest
needs: [hadolint]
Expand Down Expand Up @@ -130,7 +142,7 @@ jobs:
run: uv sync --locked --no-build --group lint --all-packages

- name: Run Ruff
run: make lint-ruff
run: make lint-ruff lint-format

ty:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -165,10 +177,15 @@ jobs:
test:
runs-on: ubuntu-latest
needs: [hadolint]
continue-on-error: ${{ matrix.experimental }}
strategy:
fail-fast: false
matrix:
python-version: ["3.13", "3.14"]
experimental: [false]
include:
- python-version: "3.15"
experimental: true

steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -181,18 +198,22 @@ jobs:
- name: Install dependencies
run: uv sync --locked --no-build --python ${{ matrix.python-version }} --group test

- name: Run unit tests
run: uv run --locked --no-build --python ${{ matrix.python-version }} --group test pytest -m unit

- name: Run integration tests
run: uv run --locked --no-build --python ${{ matrix.python-version }} --group test pytest -m integration

- name: Run tests with coverage
run: uv run --locked --no-build --python ${{ matrix.python-version }} pytest --cov=app --cov-report=term-missing --cov-fail-under=80
run: uv run --locked --no-build --python ${{ matrix.python-version }} --group test pytest --cov --cov-report=term-missing --cov-report=xml:coverage.xml --junit-xml=junit.xml

- name: Upload test reports
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
with:
name: test-reports-${{ matrix.python-version }}
path: |
junit.xml
coverage.xml
if-no-files-found: ignore

build:
runs-on: ubuntu-latest
needs: [actionlint, dependency-audit, ruff, ty, import-linter, test]
needs: [actionlint, typos, dependency-audit, ruff, ty, import-linter, test]
permissions:
contents: read
strategy:
Expand Down
46 changes: 46 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
repos:
- repo: local
hooks:
- id: ruff-check
name: ruff check
entry: uv run --group lint ruff check --fix
language: system
types_or: [python, pyi]
- id: ruff-format
name: ruff format
entry: uv run --group lint ruff format
language: system
types_or: [python, pyi]
- id: ty
name: ty
entry: make lint-ty
language: system
pass_filenames: false
types_or: [python, pyi, toml]
- id: import-linter
name: import-linter
entry: make lint-imports
language: system
pass_filenames: false
files: ^(app/.*\.py|\.importlinter)$
- id: type-discipline
name: type discipline
entry: uv run --group test pytest tests/architecture -q -p no:cacheprovider
language: system
pass_filenames: false
files: ^app/.*\.py$
- id: typos
name: typos
entry: uvx typos
language: system
- id: actionlint
name: actionlint
entry: actionlint
language: system
files: ^\.github/workflows/.*\.ya?ml$
pass_filenames: false
- id: hadolint
name: hadolint
entry: hadolint --failure-threshold warning
language: system
files: ^Dockerfile
2 changes: 1 addition & 1 deletion .python-version
Original file line number Diff line number Diff line change
@@ -1 +1 @@
3.13
3.14
Loading
Loading