Exposed docs endpoint, added default env
This commit is contained in:
10
.env.example
Normal file
10
.env.example
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
DOCKERDIR=/opt/compose/keywarden
|
||||||
|
|
||||||
|
KEYWARDEN_SECRET_KEY=
|
||||||
|
# PostgreSQL Connection (These are default values, unneeded if matching environment)
|
||||||
|
KEYWARDEN_POSTGRES_USER="postgres"
|
||||||
|
KEYWARDEN_POSTGRES_PASSWORD="postgres"
|
||||||
|
KEYWARDEN_POSTGRES_HOST="keywarden-db"
|
||||||
|
KEYWARDEN_POSTGRES_PORT=5432
|
||||||
|
KEYWARDEN_POSTGRES_DB="keywarden"
|
||||||
|
KEYWARDEN_ACCESS_TOKEN_EXPIRE_MINUTES=60
|
||||||
9
.github/workflows/ci.yml
vendored
9
.github/workflows/ci.yml
vendored
@@ -11,9 +11,12 @@ permissions:
|
|||||||
|
|
||||||
env:
|
env:
|
||||||
PYTHON_VERSION: "3.11"
|
PYTHON_VERSION: "3.11"
|
||||||
# Used by tests / alembic; matches docker-compose-style DSN
|
# Used by tests / alembic; matches docker compose environment
|
||||||
TEST_POSTGRES_DSN: postgresql+asyncpg://postgres:postgres@localhost:5432/keywarden
|
KEYWARDEN_POSTGRES_USER: postgres
|
||||||
|
KEYWARDEN_POSTGRES_PASSWORD: postgres
|
||||||
|
KEYWARDEN_POSTGRES_HOST: localhost
|
||||||
|
KEYWARDEN_POSTGRES_PORT: 5432
|
||||||
|
KEYWARDEN_POSTGRES_DB: keywarden
|
||||||
jobs:
|
jobs:
|
||||||
lint:
|
lint:
|
||||||
name: Lint & Format
|
name: Lint & Format
|
||||||
|
|||||||
@@ -25,11 +25,13 @@ if config.config_file_name is not None:
|
|||||||
target_metadata = Base.metadata
|
target_metadata = Base.metadata
|
||||||
|
|
||||||
# Get DB URL from env (prefer KEYWARDEN_ prefix, fall back to unprefixed, then a sane default for local)
|
# Get DB URL from env (prefer KEYWARDEN_ prefix, fall back to unprefixed, then a sane default for local)
|
||||||
DB_URL = (
|
DB_USER = os.getenv("KEYWARDEN_POSTGRES_USER", "postgres")
|
||||||
os.getenv("KEYWARDEN_POSTGRES_DSN")
|
DB_PASS = os.getenv("KEYWARDEN_POSTGRES_PASSWORD", "postgres")
|
||||||
or os.getenv("POSTGRES_DSN")
|
DB_HOST = os.getenv("KEYWARDEN_POSTGRES_HOST", "localhost")
|
||||||
or "postgresql+asyncpg://postgres:postgres@localhost:5432/keywarden"
|
DB_PORT = os.getenv("KEYWARDEN_POSTGRES_PORT", "5432")
|
||||||
)
|
DB_NAME = os.getenv("KEYWARDEN_POSTGRES_DB", "keywarden")
|
||||||
|
|
||||||
|
DB_URL = f"postgresql+asyncpg://{DB_USER}:{DB_PASS}@{DB_HOST}:{DB_PORT}/{DB_NAME}"
|
||||||
|
|
||||||
|
|
||||||
def run_migrations_offline():
|
def run_migrations_offline():
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
|
from pydantic import computed_field
|
||||||
from pydantic_settings import BaseSettings, SettingsConfigDict
|
from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||||
|
|
||||||
|
|
||||||
@@ -8,13 +8,33 @@ class Settings(BaseSettings):
|
|||||||
env_prefix="KEYWARDEN_",
|
env_prefix="KEYWARDEN_",
|
||||||
extra="ignore",
|
extra="ignore",
|
||||||
)
|
)
|
||||||
|
|
||||||
PROJECT_NAME: str = "Keywarden"
|
PROJECT_NAME: str = "Keywarden"
|
||||||
API_V1_STR: str = "/api/v1"
|
API_V1_STR: str = "/api/v1"
|
||||||
SECRET_KEY: str
|
|
||||||
|
# Postgres split vars (with defaults)
|
||||||
|
POSTGRES_USER: str = "postgres"
|
||||||
|
POSTGRES_PASSWORD: str = "postgres"
|
||||||
|
POSTGRES_HOST: str = "keywarden-db"
|
||||||
|
POSTGRES_PORT: int = 5432
|
||||||
|
POSTGRES_DB: str = "keywarden"
|
||||||
|
|
||||||
|
SECRET_KEY: str = "insecure-dev-secret" # default for local dev only
|
||||||
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
ACCESS_TOKEN_EXPIRE_MINUTES: int = 30
|
||||||
POSTGRES_DSN: str
|
|
||||||
|
OIDC_ENABLED: bool = False
|
||||||
OIDC_ISSUER: str | None = None
|
OIDC_ISSUER: str | None = None
|
||||||
OIDC_CLIENT_ID: str | None = None
|
OIDC_CLIENT_ID: str | None = None
|
||||||
OIDC_CLIENT_SECRET: str | None = None
|
OIDC_AUDIENCE: str | None = None # optional
|
||||||
|
OIDC_JWKS_URL: str | None = None # if not set, derive from issuer
|
||||||
|
|
||||||
|
@computed_field(return_type=str)
|
||||||
|
@property
|
||||||
|
def POSTGRES_DSN(self) -> str:
|
||||||
|
return (
|
||||||
|
f"postgresql+asyncpg://{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||||||
|
f"@{self.POSTGRES_HOST}:{self.POSTGRES_PORT}/{self.POSTGRES_DB}"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
settings = Settings()
|
settings = Settings()
|
||||||
@@ -3,7 +3,9 @@ from fastapi import FastAPI
|
|||||||
from app.api.v1 import auth, keys
|
from app.api.v1 import auth, keys
|
||||||
from app.core.config import settings
|
from app.core.config import settings
|
||||||
|
|
||||||
app = FastAPI(title=settings.PROJECT_NAME)
|
app = FastAPI(
|
||||||
|
title=settings.PROJECT_NAME
|
||||||
|
)
|
||||||
app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth", tags=["auth"])
|
app.include_router(auth.router, prefix=f"{settings.API_V1_STR}/auth", tags=["auth"])
|
||||||
app.include_router(keys.router, prefix=f"{settings.API_V1_STR}/keys", tags=["keys"])
|
app.include_router(keys.router, prefix=f"{settings.API_V1_STR}/keys", tags=["keys"])
|
||||||
|
|
||||||
|
|||||||
118
ci.yml
118
ci.yml
@@ -1,118 +0,0 @@
|
|||||||
name: CI
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches: [ "main" ]
|
|
||||||
pull_request:
|
|
||||||
branches: [ "main" ]
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
env:
|
|
||||||
PYTHON_VERSION: "3.11"
|
|
||||||
# Used by tests / alembic; matches docker-compose-style DSN
|
|
||||||
TEST_POSTGRES_DSN: postgresql+asyncpg://postgres:postgres@localhost:5432/keywarden
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
lint:
|
|
||||||
name: Lint & Format
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
|
|
||||||
- name: Install linters
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install ruff==0.6.4 black==24.8.0
|
|
||||||
|
|
||||||
- name: Ruff (lint)
|
|
||||||
run: ruff check .
|
|
||||||
|
|
||||||
- name: Black (format check)
|
|
||||||
run: black --check .
|
|
||||||
|
|
||||||
test:
|
|
||||||
name: Tests (Pytest + Alembic + Postgres)
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: lint
|
|
||||||
services:
|
|
||||||
postgres:
|
|
||||||
image: postgres:16
|
|
||||||
env:
|
|
||||||
POSTGRES_DB: keywarden
|
|
||||||
POSTGRES_USER: postgres
|
|
||||||
POSTGRES_PASSWORD: postgres
|
|
||||||
ports:
|
|
||||||
- 5432:5432
|
|
||||||
options: >-
|
|
||||||
--health-cmd="pg_isready -U postgres -d keywarden"
|
|
||||||
--health-interval=10s
|
|
||||||
--health-timeout=5s
|
|
||||||
--health-retries=10
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Python
|
|
||||||
uses: actions/setup-python@v5
|
|
||||||
with:
|
|
||||||
python-version: ${{ env.PYTHON_VERSION }}
|
|
||||||
|
|
||||||
- name: Cache pip
|
|
||||||
uses: actions/cache@v4
|
|
||||||
with:
|
|
||||||
path: ~/.cache/pip
|
|
||||||
key: pip-${{ runner.os }}-${{ env.PYTHON_VERSION }}-${{ hashFiles('**/requirements.txt') }}
|
|
||||||
restore-keys: |
|
|
||||||
pip-${{ runner.os }}-${{ env.PYTHON_VERSION }}-
|
|
||||||
|
|
||||||
- name: Install dependencies
|
|
||||||
run: |
|
|
||||||
python -m pip install --upgrade pip
|
|
||||||
pip install -r requirements.txt
|
|
||||||
|
|
||||||
- name: Create .env for tests
|
|
||||||
run: |
|
|
||||||
printf "KEYWARDEN_POSTGRES_DSN=%s\nKEYWARDEN_SECRET_KEY=%s\nKEYWARDEN_ACCESS_TOKEN_EXPIRE_MINUTES=60\n" \
|
|
||||||
"${{ env.TEST_POSTGRES_DSN }}" "testsecret" > .env
|
|
||||||
echo "Wrote .env with DSN=${{ env.TEST_POSTGRES_DSN }}"
|
|
||||||
|
|
||||||
- name: Run Alembic migrations
|
|
||||||
env:
|
|
||||||
KEYWARDEN_POSTGRES_DSN: ${{ env.TEST_POSTGRES_DSN }}
|
|
||||||
run: |
|
|
||||||
alembic upgrade head
|
|
||||||
|
|
||||||
- name: Pytest
|
|
||||||
env:
|
|
||||||
KEYWARDEN_POSTGRES_DSN: ${{ env.TEST_POSTGRES_DSN }}
|
|
||||||
run: |
|
|
||||||
pytest -q
|
|
||||||
|
|
||||||
docker-build:
|
|
||||||
name: Docker Build
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
needs: test
|
|
||||||
steps:
|
|
||||||
- name: Checkout
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
|
|
||||||
- name: Set up Docker Buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
|
|
||||||
- name: Build image (no push)
|
|
||||||
uses: docker/build-push-action@v5
|
|
||||||
with:
|
|
||||||
context: .
|
|
||||||
push: false
|
|
||||||
tags: keywarden:ci
|
|
||||||
# speeds up builds by caching layers on GH Actions
|
|
||||||
cache-from: type=gha
|
|
||||||
cache-to: type=gha,mode=max
|
|
||||||
@@ -9,6 +9,7 @@ services:
|
|||||||
- ${DOCKERDIR}/nginx/certs/:/certs/
|
- ${DOCKERDIR}/nginx/certs/:/certs/
|
||||||
- ${DOCKERDIR}/nginx/webdir/:/var/www/
|
- ${DOCKERDIR}/nginx/webdir/:/var/www/
|
||||||
- ${DOCKERDIR}/nginx/logs:/var/log/nginx/
|
- ${DOCKERDIR}/nginx/logs:/var/log/nginx/
|
||||||
|
# - "external:internal", change external to desired port
|
||||||
ports:
|
ports:
|
||||||
- "443:443"
|
- "443:443"
|
||||||
|
|
||||||
@@ -22,10 +23,13 @@ services:
|
|||||||
db:
|
db:
|
||||||
image: postgres:17-alpine
|
image: postgres:17-alpine
|
||||||
environment:
|
environment:
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD:-postgres}
|
POSTGRES_PASSWORD: ${KEYWARDEN_POSTGRES_PASSWORD:-postgres}
|
||||||
POSTGRES_DB: keywarden
|
POSTGRES_DB: ${KEYWARDEN_POSTGRES_DB:-keywarden}
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: ${KEYWARDEN_POSTGRES_USER:-keywarden}
|
||||||
# ports: ["5432:5432"]
|
POSTGRES_PORT: ${KEYWARDEN_POSTGRES_PORT:-5432}
|
||||||
|
# Do not enable unless debugging, not needed to be exposed outside of docker network
|
||||||
|
# ports:
|
||||||
|
# - "5432:5432"
|
||||||
volumes:
|
volumes:
|
||||||
- "pgdata:/var/lib/postgresql/data"
|
- "pgdata:/var/lib/postgresql/data"
|
||||||
|
|
||||||
@@ -33,12 +37,11 @@ services:
|
|||||||
build: .
|
build: .
|
||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
environment:
|
env_file:
|
||||||
- SECRET_KEY=[CREATE SECRET KEY]
|
- .env
|
||||||
- POSTGRES_DSN=postgresql+asyncpg://postgres:${POSTGRES_PASSWORD:-postgres}@keywarden-postgres:5432/keywarden
|
# API runs on port 8000, but is unneeded to be external unless using a custom reverse proxy on another machine
|
||||||
- ACCESS_TOKEN_EXPIRE_MINUTES=60
|
# ports:
|
||||||
ports:
|
# - "8000:8000"
|
||||||
- "8000:8000"
|
|
||||||
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
command: uvicorn app.main:app --host 0.0.0.0 --port 8000
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
|
|||||||
@@ -24,14 +24,18 @@ server {
|
|||||||
location / {
|
location / {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
location /docs {
|
||||||
|
proxy_pass http://api:8000;
|
||||||
|
}
|
||||||
|
location /openapi.json {
|
||||||
|
proxy_pass http://api:8000;
|
||||||
|
}
|
||||||
location /api/v1/ {
|
location /api/v1/ {
|
||||||
proxy_pass http://api:8000;
|
proxy_pass http://api:8000;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
|
proxy_set_header X-Forwarded-Proto $http_x_forwarded_proto;
|
||||||
add_header Strict-Transport-Security "max-age=15552000; includeSubDomains" always;
|
|
||||||
}
|
}
|
||||||
location /healthz {
|
location /healthz {
|
||||||
proxy_pass http://api:8000;
|
proxy_pass http://api:8000;
|
||||||
|
|||||||
Reference in New Issue
Block a user