Metadata-Version: 2.4
Name: coffeehouse-common
Version: 0.15.1
Summary: Shared CSRF, security headers, logging, observability, flash messages, role-cleanup, and Auth client for Coffee House FastAPI apps
Author-email: Ruben Sukiasyan <rubsksn@gmail.com>
License: MIT License
        
        Copyright (c) 2026 Ruben Sukiasyan
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/coffeehouse-tools/coffeehouse-common
Project-URL: Repository, https://github.com/coffeehouse-tools/coffeehouse-common
Project-URL: Issues, https://github.com/coffeehouse-tools/coffeehouse-common/issues
Project-URL: Changelog, https://github.com/coffeehouse-tools/coffeehouse-common/blob/master/CHANGELOG.md
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Operating System :: OS Independent
Classifier: Framework :: FastAPI
Classifier: Typing :: Typed
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: itsdangerous==2.2.0
Requires-Dist: starlette>=0.38.0
Requires-Dist: starlette-csrf==3.0.0
Requires-Dist: SQLAlchemy>=2.0
Requires-Dist: requests>=2.31
Requires-Dist: sentry-sdk<3.0,>=2.20
Provides-Extra: testing
Requires-Dist: pytest>=8.0; extra == "testing"
Requires-Dist: PyJWT>=2.8; extra == "testing"
Requires-Dist: httpx>=0.27; extra == "testing"
Requires-Dist: python-multipart>=0.0.9; extra == "testing"
Dynamic: license-file

# coffeehouse-common

Shared Python package for Coffee House ecosystem FastAPI apps:

- `coffeehouse_common.csrf` — `CSRFMiddleware` subclass (form body + header + safe body replay)
- `coffeehouse_common.security_middleware` — `SecurityHeadersMiddleware` (raw ASGI)
- `coffeehouse_common.logging_config` — `RequestIdMiddleware` (raw ASGI), `RequestIdFilter`, `configure_logging`, `get_request_id`
- `coffeehouse_common.observability` — `init_sentry(app_slug)` Sentry SDK bootstrap; reads `SENTRY_DSN` from env (no-op when unset), tags events with `app_slug`, drops 4xx HTTP/CSRF noise, keeps 5xx

**v0.3.0+** implements security headers and request ID middleware as **raw ASGI** (not `BaseHTTPMiddleware`) so streaming responses are not fully buffered. **v0.3.1** sets `X-Frame-Options: SAMEORIGIN` (same-origin iframes allowed; third-party framing blocked). Logs include a per-request correlation id when `configure_logging()` + `RequestIdMiddleware` are used.

## Install

From GitHub (pinned tag):

```bash
pip install "coffeehouse-common @ git+https://github.com/rubencfh/coffeehouse-common.git@v0.9.0"
```

Local editable install:

```bash
pip install -e ../coffeehouse-common
```

## Development

Set up the repo for local development + testing:

```bash
git clone https://github.com/rubencfh/coffeehouse-common.git
cd coffeehouse-common
pip install -e ".[testing]"
pip install -r requirements-dev.txt
pre-commit install
```

Run the full test suite (with coverage, fails under 70%):

```bash
pytest
```

Run the pre-commit hooks against all files (format, lint, secret scan, syntax check):

```bash
pre-commit run --all-files
```

Individual checks:

```bash
ruff format --check .          # formatting
ruff check .                   # linting
mypy coffeehouse_common        # type-checking (lenient baseline)
bandit -c pyproject.toml -r coffeehouse_common coffeehouse_testing  # SAST
pip-audit -r requirements-dev.txt                                    # SCA
```

CI runs the same checks on every push / PR via `.github/workflows/ci.yml`.
See `coffeehouse-ecosystem/docs/pipeline.md` for the broader pipeline.

### Shared test fixtures

The `coffeehouse_testing` subpackage ships with this repo and provides shared
pytest fixtures that consumer apps import in their own `tests/conftest.py`:

```python
from coffeehouse_testing.jwt_factory import jwt_factory
from coffeehouse_testing.client import authed_client
from coffeehouse_testing.db import postgres_container, clean_db  # noqa: F401
from coffeehouse_testing.auth_stub import make_auth_stub, build_roles_manifest
```

All heavy dependencies (PyJWT, testcontainers, starlette) are loaded lazily —
import the modules you need in tests and the import errors only fire if the
underlying package is not installed.

## Usage

```python
from coffeehouse_common.csrf import CSRFMiddleware
from coffeehouse_common.logging_config import RequestIdMiddleware, configure_logging
from coffeehouse_common.observability import init_sentry
from coffeehouse_common.security_middleware import SecurityHeadersMiddleware

configure_logging()  # once at startup; attaches RequestIdFilter for %(request_id)s
init_sentry(app_slug="auth")  # no-op if SENTRY_DSN is unset
```

`init_sentry` reads `SENTRY_DSN`, `RAILWAY_ENVIRONMENT_NAME` (or `ENVIRONMENT`),
and `RAILWAY_GIT_COMMIT_SHA` from the environment. Errors-only sample rate by
default (`traces_sample_rate=0.0`). 401/403/404/405 responses, 4xx
`HTTPException`s, and `CSRFError`s are dropped client-side so they don't burn
the Sentry quota. 5xx HTTPExceptions and any other exception class are kept.
Pass `extra_ignored_status_codes=` / `extra_ignored_exceptions=` to extend the
filter per app.

Explicit dependency: **`itsdangerous`** (CSRF token signing).

See `CONVENTIONS.md` in the `coffeehouse-ecosystem` repo for middleware order and CSRF patterns.

## First-time publish (maintainers)

1. Create an empty repo on GitHub: `rubencfh/coffeehouse-common`
2. From this directory:

```bash
git remote add origin https://github.com/rubencfh/coffeehouse-common.git
git push -u origin master
git push origin v0.9.0
```

Until the repo and tag exist, app Docker builds that `pip install` from GitHub will fail. For local dev, use editable install (above).
