Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
137 commits
Select commit Hold shift + click to select a range
f9e9046
add agents.md
catalysync Apr 20, 2026
1b54826
add health endpoint
catalysync Apr 20, 2026
04c846b
add ty
catalysync Apr 20, 2026
356c0d1
add pydantic settings dep
catalysync Apr 20, 2026
186171b
add config
catalysync Apr 20, 2026
9fe17d7
add validation aliases
catalysync Apr 20, 2026
562ef8c
add settings context
catalysync Apr 20, 2026
ff6e922
add secret log filter
catalysync Apr 20, 2026
92bd2db
add api secret masker
catalysync Apr 20, 2026
3993956
add envvar marker
catalysync Apr 20, 2026
4383142
add layered config
catalysync Apr 20, 2026
3c6ccb3
add profiles
catalysync Apr 20, 2026
c2a3138
gitignore agent state
catalysync Apr 20, 2026
50ae8d0
add dockerignore
catalysync Apr 21, 2026
e937576
add dockerfile
catalysync Apr 21, 2026
b37706a
add docker compose
catalysync Apr 21, 2026
3c21b86
add env example
catalysync Apr 21, 2026
beb0bf6
add justfile
catalysync Apr 21, 2026
c813eb3
add postgres deps
catalysync Apr 21, 2026
328f4fe
init alembic
catalysync Apr 21, 2026
2066600
add precommit config
catalysync Apr 21, 2026
bbfb367
add ty check to ci
catalysync Apr 21, 2026
ddcf653
add docker ci workflow
catalysync Apr 21, 2026
6208861
add live ready probes
catalysync Apr 21, 2026
5c7abea
add license and lifespan hooks
catalysync Apr 21, 2026
b95886b
add frontend scaffold
catalysync Apr 21, 2026
5c484e8
wire toml and profiles into settings
catalysync Apr 22, 2026
9fd20d5
silence unused arg warning
catalysync Apr 22, 2026
4d7f493
neutralize downstream refs in docs
catalysync Apr 22, 2026
8bc1ff0
docs: add development, deployment, release-please
catalysync Apr 22, 2026
193119b
feat: openapi dump script and integration tests
catalysync Apr 22, 2026
bc4155b
feat: constrained config fields and doc generation
catalysync Apr 22, 2026
2678d7b
ops: graceful-shutdown grace period and prestop
catalysync Apr 22, 2026
f1411a4
remove tool name from commit rule
catalysync Apr 23, 2026
4f1c0f9
add minio + setup sidecar
catalysync Apr 25, 2026
09163c5
polish alembic config
catalysync Apr 25, 2026
b989700
dockerfile production polish
catalysync Apr 25, 2026
44b88fd
add committed test env
catalysync Apr 25, 2026
0c47cd1
polish alembic env + template
catalysync Apr 25, 2026
50bdfe4
add cors middleware
catalysync Apr 25, 2026
5f2675d
add request-id middleware
catalysync Apr 25, 2026
89247f8
add unhandled-exception handler
catalysync Apr 25, 2026
ce55b02
add typed exception envelope
catalysync Apr 25, 2026
2ffa438
default messages + 401 www-auth
catalysync Apr 25, 2026
b1c1c24
expand exception envelope
catalysync Apr 25, 2026
8bdba3e
structlog with dev/prod renderers
catalysync Apr 25, 2026
ea4c6da
add json type aliases
catalysync Apr 25, 2026
f3a0fb7
add api router with autocommit + tag filter
catalysync Apr 25, 2026
4d9fc9c
add kit package + utils
catalysync Apr 25, 2026
b930b28
add kit schemas base
catalysync Apr 25, 2026
ffae8c2
add kit pagination
catalysync Apr 25, 2026
d2f073d
add kit sorting
catalysync Apr 25, 2026
c1cf755
add kit repository base
catalysync Apr 25, 2026
c9b927e
add kit pubsub
catalysync Apr 25, 2026
b0422c2
add redis client
catalysync Apr 25, 2026
2a4ae62
add rate limiting
catalysync Apr 25, 2026
d660e7c
add sentry config
catalysync Apr 25, 2026
e2ef1f6
add content-size limit middleware
catalysync Apr 25, 2026
0f34848
add kit sse helpers
catalysync Apr 25, 2026
d081702
add kit path traversal guard
catalysync Apr 25, 2026
4d411b2
wrap app in create_app factory
catalysync Apr 25, 2026
7203006
add development guide
catalysync Apr 25, 2026
de53d4a
add request-cancellation middleware
catalysync Apr 25, 2026
7d2fdaa
add multipart + forwarded-prefix + query-flatten
catalysync Apr 25, 2026
caf8f31
add validated path-segment deps
catalysync Apr 25, 2026
e6b0950
add gzip response helper
catalysync Apr 25, 2026
ea72030
add coverage tooling
catalysync Apr 25, 2026
da46703
test json_types
catalysync Apr 25, 2026
c85c544
test kit utils
catalysync Apr 25, 2026
746565f
test kit schemas
catalysync Apr 25, 2026
480548a
test kit paths
catalysync Apr 25, 2026
26be8ea
test kit sse
catalysync Apr 25, 2026
2b184a8
test kit pubsub
catalysync Apr 25, 2026
841e510
test kit sorting
catalysync Apr 25, 2026
fa18fc2
test kit pagination
catalysync Apr 25, 2026
f495d5e
test kit compression
catalysync Apr 25, 2026
7a6777a
test routing
catalysync Apr 25, 2026
1b9b61b
test middleware
catalysync Apr 25, 2026
f4490d7
test exceptions
catalysync Apr 25, 2026
cba8140
test rate limit
catalysync Apr 25, 2026
d172755
test sentry
catalysync Apr 25, 2026
9f8ad81
test kit redis
catalysync Apr 25, 2026
33ca6fa
test kit repository + fix soft-delete mro
catalysync Apr 25, 2026
f3708cf
fix .env leak in hermetic_env fixture
catalysync Apr 25, 2026
aeb670c
fix cors credentials default and wildcard guard
catalysync Apr 25, 2026
de18ded
document pubsub iterate-or-leak contract
catalysync Apr 25, 2026
0a8b873
fix rate-limit retry-after introspection
catalysync Apr 25, 2026
33fa3f5
fix multipart content-type parsing
catalysync Apr 25, 2026
7461310
expand readme with quickstart
catalysync Apr 25, 2026
02e223e
add contributing + security + coc
catalysync Apr 25, 2026
47f5348
drop branch refs and aspirational examples
catalysync Apr 25, 2026
810ddb9
wire default-on middlewares with trust-proxy gate
catalysync Apr 25, 2026
7564434
tag sentry events with request_id
catalysync Apr 25, 2026
28f4eb5
fix content-size docstring on chunked transfer
catalysync Apr 25, 2026
01a8312
use nagara tagline + add oss metadata
catalysync Apr 26, 2026
5895438
add github templates and dependabot
catalysync Apr 26, 2026
214be75
lazy probe engine + assert select 1
catalysync Apr 26, 2026
983ae18
routing reads settings via contextvar + autocommit caveats
catalysync Apr 26, 2026
dbd0f85
exercise request-cancel disconnect path
catalysync Apr 26, 2026
7d04a62
drop fragile getattr in rate-limit test
catalysync Apr 26, 2026
9075415
add ci + license + python badges
catalysync Apr 26, 2026
25a5b35
add postgres version preflight
catalysync Apr 26, 2026
207f1ed
stamp license copyright
catalysync Apr 26, 2026
b1d6672
drop nagara-planning link from contributing
catalysync Apr 26, 2026
83c0a71
add security-headers + last-request middlewares
catalysync Apr 26, 2026
7a2f96e
add idle health endpoint + version + uptime
catalysync Apr 26, 2026
f430aff
stable openapi operation ids
catalysync Apr 26, 2026
70d6b36
drop idle health endpoint as multi-replica unsafe
catalysync Apr 26, 2026
39f2570
wire verify_settings into startup
catalysync Apr 26, 2026
b885b76
honor rate-limit window multiplier
catalysync Apr 26, 2026
8d88edb
trim lifespan docstring to reality
catalysync Apr 26, 2026
b9db7c1
align dev docs with commit style
catalysync Apr 26, 2026
2299e10
loosen boundary regex per rfc 2046
catalysync Apr 26, 2026
69d8be3
drop unshipped auth claim
catalysync Apr 26, 2026
2fda95e
ship py.typed marker
catalysync Apr 26, 2026
777364b
expose public api surface
catalysync Apr 26, 2026
7ec6fd0
bounded pubsub queue option
catalysync Apr 26, 2026
8ac75e5
bring up minio in bootstrap
catalysync Apr 26, 2026
0740ee5
purge nagara-planning links
catalysync Apr 26, 2026
b02ebf7
robust content-type parsing
catalysync Apr 26, 2026
a97308a
polish main + preflight tests
catalysync Apr 26, 2026
761f477
expose request-cancel poll knob
catalysync Apr 26, 2026
87b084e
document include-in-schema policy
catalysync Apr 26, 2026
531c893
add pubsub topics introspection
catalysync Apr 26, 2026
45914e2
test hygiene fixes
catalysync Apr 26, 2026
702c49f
readme snippet + changelog
catalysync Apr 26, 2026
2d9f156
weekly uv lock workflow
catalysync Apr 26, 2026
7d9e2f5
ruff format + lint sweep
catalysync Apr 26, 2026
d9bbf76
ty ignore comments for known gaps
catalysync Apr 26, 2026
bbb5740
add redis service to ci
catalysync Apr 26, 2026
e976619
drop hedges + dead deprecation template
catalysync Apr 26, 2026
d978714
ship readme + license into image
catalysync Apr 26, 2026
79d38c2
tighten 8 audit-flagged tests
catalysync Apr 26, 2026
c7be2e9
format leftover
catalysync Apr 26, 2026
955a99b
trigger ci
catalysync Apr 26, 2026
746ff0b
drop unused _BOOT_TIME
catalysync Apr 26, 2026
fecd799
Merge remote-tracking branch 'origin/main' into feat/v0-infra
catalysync Apr 26, 2026
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
56 changes: 56 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# vcs
.git
.gitignore
.github

# python
__pycache__
*.py[cod]
*$py.class
*.so
.Python
*.egg-info
.eggs
build
dist

# venv + caches
.venv
.uv-cache
.pytest_cache
.coverage
.coverage.*
htmlcov
.mypy_cache
.ruff_cache

# editors
.vscode
.idea
*.swp
.DS_Store

# docker
Dockerfile*
.dockerignore
docker-compose*.yml

# secrets
.env
.env.local
.env.*.local

# tests + tooling not needed in image
tests
notes
scratch
*.md
# but pyproject.toml references README.md — include it.
!README.md

# nothing in these belongs in the python image build context
frontend
mizu
node_modules
nagara-planning
nagara-private
90 changes: 90 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
# nagara environment template.
# Copy to .env and fill in values for local dev. NEVER commit a real .env.
#
# Every variable has a sensible default in src/nagara/config.py — only set
# the ones you need to override.

# ── App ─────────────────────────────────────────────────────────────────
# Selects which .env file is loaded and switches behavior helpers.
# One of: development | test | staging | production
NAGARA_ENV=development

# Logging level for the app (matches Python logging values).
NAGARA_LOG_LEVEL=INFO

# ── Security (REQUIRED in production) ──────────────────────────────────
# Used to sign sessions, JWTs, etc. In production, generate with:
# python -c "import secrets; print(secrets.token_urlsafe(64))"
# Empty string here means "unset" — verify_settings() will reject it in prod.
NAGARA_SECRET_KEY=

# ── HTTP ────────────────────────────────────────────────────────────────
# Public-facing base URL. Used to build absolute links in emails, webhooks, etc.
NAGARA_BASE_URL=http://127.0.0.1:8000

# Frontend URL — used by the API to redirect after auth flows.
NAGARA_FRONTEND_BASE_URL=http://127.0.0.1:3000

# Comma-separated list of allowed CORS origins. Empty = none.
# Pydantic settings parses JSON arrays for list fields:
# NAGARA_CORS_ORIGINS=["http://localhost:3000"]
NAGARA_CORS_ORIGINS=[]

# Optional regex matched against the Origin header (in addition to the list above).
# Useful for ephemeral preview hosts.
# NAGARA_CORS_ORIGIN_REGEX=

# Allow cookies/auth on cross-origin requests. Cannot combine with "*" origin.
# NAGARA_CORS_ALLOW_CREDENTIALS=false

# Trust X-Forwarded-* headers from an upstream reverse proxy. Only enable when
# the proxy strips these from client requests (otherwise spoofable).
# NAGARA_TRUST_PROXY=false

# Reject requests whose Content-Length exceeds this many bytes with 413.
# NAGARA_REQUEST_MAX_BYTES=10485760

# How often the request-cancel middleware checks for client disconnect.
# NAGARA_REQUEST_CANCEL_POLL_SECONDS=0.1

# ── Database ────────────────────────────────────────────────────────────
# Override the assembled DSN entirely (Render/Heroku/Supabase typically
# inject DATABASE_URL — both NAGARA_DATABASE_URL and DATABASE_URL work).
# DATABASE_URL=postgresql+asyncpg://user:pwd@host:5432/dbname

# Or set the parts and we'll assemble the DSN at runtime.
NAGARA_POSTGRES_USER=nagara
NAGARA_POSTGRES_PWD=nagara
NAGARA_POSTGRES_HOST=127.0.0.1
NAGARA_POSTGRES_PORT=5432
NAGARA_POSTGRES_DB=nagara

# Minimum supported Postgres major version. Boot fails if the server reports
# a lower version. Set to 0 to disable the check.
# NAGARA_POSTGRES_MIN_VERSION=15

# Pool tuning. Defaults are reasonable for a single-process dev app.
# NAGARA_DATABASE_POOL_SIZE=5
# NAGARA_DATABASE_POOL_RECYCLE_SECONDS=600
# NAGARA_DATABASE_COMMAND_TIMEOUT_SECONDS=30

# ── Redis ───────────────────────────────────────────────────────────────
# Used by the rate limiter.
# NAGARA_REDIS_URL=redis://127.0.0.1:6379/0

# ── Observability ───────────────────────────────────────────────────────
# Sentry DSN. No-op when unset.
# NAGARA_SENTRY_DSN=

# Release version reported by /health endpoints (commit SHA / git tag).
# NAGARA_RELEASE_VERSION=dev

# ── Sessions ───────────────────────────────────────────────────────────
# How long a user session lasts before requiring re-auth.
# Pydantic parses this as a timedelta (e.g., "P31D" / "31 days").
# NAGARA_USER_SESSION_TTL=31 days

# ── Profile (optional, CLI feature) ─────────────────────────────────────
# Selects an active profile from ~/.config/nagara/profiles.toml
# (only applies if you've set up profiles via the CLI).
# NAGARA_PROFILE=dev
23 changes: 23 additions & 0 deletions .env.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Test-suite environment. Loaded by src/nagara/config.py when
# NAGARA_ENV=test (e.g., ``NAGARA_ENV=test pytest``).

NAGARA_ENV=test
NAGARA_LOG_LEVEL=WARNING

# Deterministic signing key. 32+ chars to satisfy production-grade
# secret-length checks even though we're in test.
NAGARA_SECRET_KEY=test-secret-not-for-production-use-32chars

NAGARA_BASE_URL=http://127.0.0.1:8000
NAGARA_FRONTEND_BASE_URL=http://127.0.0.1:3000
NAGARA_CORS_ORIGINS=["http://127.0.0.1:3000","http://localhost:3000"]

# Separate DB so a botched test run can never trash dev data. The
# matching database needs to exist; create it with
# createdb -h 127.0.0.1 -U nagara nagara_test
# or let CI run ``just createdb-test``.
NAGARA_POSTGRES_USER=nagara
NAGARA_POSTGRES_PWD=nagara
NAGARA_POSTGRES_HOST=127.0.0.1
NAGARA_POSTGRES_PORT=5432
NAGARA_POSTGRES_DB=nagara_test
28 changes: 28 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
---
name: Bug report
about: Report unexpected behavior in nagara
title: ''
labels: bug
---

## Description

<!-- What happened? What did you expect to happen? -->

## Reproduction

```python
# Minimal code or steps to reproduce.
```

## Environment

- nagara version / git SHA:
- Python: `python -V`
- OS:

## Logs / stack trace

```
<paste here>
```
18 changes: 18 additions & 0 deletions .github/ISSUE_TEMPLATE/feature_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
name: Feature request
about: Propose a new capability for nagara
title: ''
labels: enhancement
---

## Problem

<!-- What can't you do today? Or what's painful? -->

## Proposal

<!-- What would the API / behavior / config look like? -->

## Alternatives considered

<!-- Other approaches you thought about. Helps avoid bikeshedding. -->
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

<!-- One paragraph: what changed and why. -->

## How

<!-- Brief technical approach. Skip for trivial changes. -->

## Test plan

- [ ] `just check` passes locally
- [ ] New tests added for new behavior
- [ ] Manually verified the happy path
- [ ]
23 changes: 23 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
version: 2
# Python deps are managed by .github/workflows/uv-upgrade.yml — Dependabot's
# `pip` ecosystem can't update uv.lock, so it would open PRs that always fail
# CI on lock drift. Everything else (npm, GHA, docker) is fine here.
updates:
- package-ecosystem: "npm"
directory: "/frontend"
schedule:
interval: "weekly"
open-pull-requests-limit: 5
groups:
js-minor-and-patch:
update-types: ["minor", "patch"]

- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"

- package-ecosystem: "docker"
directory: "/"
schedule:
interval: "weekly"
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,39 @@ on:
jobs:
check:
runs-on: ubuntu-latest

services:
postgres:
image: postgres:16-alpine
env:
POSTGRES_USER: nagara
POSTGRES_PASSWORD: nagara
POSTGRES_DB: nagara
ports:
- 5432:5432
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
redis:
image: redis:7-alpine
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5

env:
NAGARA_POSTGRES_HOST: 127.0.0.1
NAGARA_POSTGRES_PORT: "5432"
NAGARA_POSTGRES_USER: nagara
NAGARA_POSTGRES_PWD: nagara
NAGARA_POSTGRES_DB: nagara
NAGARA_REDIS_URL: redis://127.0.0.1:6379/0

steps:
- uses: actions/checkout@v4

Expand All @@ -26,5 +59,8 @@ jobs:
- name: ruff lint
run: uv run ruff check

- name: ty check
run: uv run ty check

- name: pytest
run: uv run pytest
60 changes: 60 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: docker

on:
push:
branches: [main]
tags: ["v*"]
pull_request:
branches: [main]

env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}

jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4

- name: set up qemu
uses: docker/setup-qemu-action@v3

- name: set up buildx
uses: docker/setup-buildx-action@v3

- name: log in to ghcr
if: github.event_name != 'pull_request'
uses: docker/login-action@v3
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}

- name: extract metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
tags: |
type=ref,event=branch
type=ref,event=pr
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=sha

- name: build and push
uses: docker/build-push-action@v6
with:
context: .
platforms: linux/amd64,linux/arm64
push: ${{ github.event_name != 'pull_request' }}
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
RELEASE_VERSION=${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
Loading
Loading