API designed to retrieve (
GET) documents from a VPS.
- Python 3.13
- FastAPI — web framework
- Uvicorn — ASGI server
- Pydantic Settings — environment variables management
- Ruff — linter & formatter
- Pytest — testing
- Poethepoet — task runner (
poe) - uv — package & virtual environment manager
pwd/
├── .venv/ # Virtual environment (managed by uv)
├── .zed/ # Zed editor configuration
├── docker/
│ ├── Dockerfile # Docker image definition
│ ├── Makefile # Docker shortcuts (up, rmi, sh)
│ └── docker-compose.yml # Service configuration
├── src/
│ ├── routes/
│ │ └── database.py # GET /database/ endpoint
│ ├── utils/
│ │ ├── middleware.py # CORS origins loader
│ │ ├── origins.json # Allowed origins list
│ │ └── resources.py # Database path resolver
│ ├── __init__.py
│ └── config.py # Settings (loaded from .env)
├── tests/
│ ├── conftest.py # Shared fixtures (TestClient, valid_api_key)
│ ├── test_database.py # Tests for GET /database/
│ └── test_middleware.py # Tests for get_origins()
├── .env # Environment variables (not committed)
├── .gitignore
├── .python-version # Python version in use (3.13)
├── main.py # Application entry point
├── pyproject.toml # Project configuration and dependencies
├── uv.lock # Lockfile generated by uv
└── README.md
Create a .env file at the root of the project with the following variables:
PWD_DATABASE_PATH= # Absolute path to the .kdbx database file
API_KEY= # Secret key required to access the API
ORIGINS_PATH= # Absolute path to the origins.json file
APP_PATH= # Absolute path to the project root (used by Docker)
PORT= # Port exposed by the container (used by Docker)
APP_PATHandPORTare only required when running the application with Docker.
git clone <repo-url> && cd pwduv venv --python 3.13source .venv/bin/activateuv syncuv run uvicorn main:app --reload- You can use the
poecommands
| Command | Description |
|---|---|
uv run poe up |
Build the image (if needed) and start the container in detached mode |
uv run poe rmi |
Stop the container and remove the local image |
Example — start the container
uv run poe up- You can move to the
docker/directory. Commands are available via theMakefile.
cd docker| Command | Description |
|---|---|
make up |
Build the image (if needed) and start the container in detached mode |
make rmi |
Stop the container and remove the local image |
make sh |
Open an interactive shell inside the running container |
Example — start the container
make upThe first run uses
COMPOSE_BAKE=trueto build the image via Docker's Bake feature. The container is namedpwdand the project is scoped under thedatabase-pwdCompose project.
Returns the database.kdbx file as a binary download.
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
api_key |
string |
✅ Yes | Secret key to access the API |
Responses
| Status | Description |
|---|---|
200 |
Returns the .kdbx file as an attachment |
401 |
Missing or invalid api_key |
403 |
Unauthorized |
404 |
Database file not found |
Example
curl -O "http://localhost:8000/database/?api_key=your_secret_key"| Command | Description |
|---|---|
uv run poe lint |
Check the code with Ruff (without modifying files) |
uv run poe format |
Format the code with Ruff |
uv run poe fix |
Automatically fix lint errors with Ruff |
uv run poe fixThis command runs
ruff check . --fix, which analyses the entire project and applies automatic fixes (unsorted imports, E/F/I/W rules...).
uv run pytestFor a more detailed output :
uv run pytest -vtests/
├── conftest.py # Shared fixtures
├── test_database.py # Tests for GET /database/
└── test_middleware.py # Tests for get_origins()
| Fixture | Type | Description |
|---|---|---|
client |
TestClient |
FastAPI test client wrapping the app |
valid_api_key |
str |
Fake API key used to simulate authorized access |
| Test | Scenario | Expected |
|---|---|---|
test_valid_file_returns_origins |
File exists with a valid "origins" key |
Returns the list of origins |
test_file_without_origins_key_returns_empty_list |
File exists but without the "origins" key |
[] |
test_missing_file_returns_empty_list |
File does not exist | [] |
If the origins file is missing,
get_origins()catches theFileNotFoundErrorand returns an empty list, preventing the application from crashing on startup.
| Test | Scenario | Expected |
|---|---|---|
test_no_api_key_returns_403 |
No api_key query param |
403 |
test_wrong_api_key_returns_403 |
Invalid api_key |
403 |
test_valid_api_key_but_missing_file_returns_404 |
Valid key, file absent | 404 |
test_valid_api_key_and_existing_file_returns_200 |
Valid key, file present | 200 + binary file |
Tests use
monkeypatchto overridesettingsvalues at runtime andtmp_pathto create a temporary.kdbxfile — no.envfile or real database needed.
| Parameter | Value |
|---|---|
target-version |
py313 |
line-length |
88 |
indent-width |
4 |
quote-style |
double |
| Enabled rules | E, F, I, W |