Metadata-Version: 2.4
Name: eai-core-infra
Version: 2.5.0
Summary: eai-core-infra
Requires-Python: >=3.11
Description-Content-Type: text/markdown
License-File: LICENSE.txt
Requires-Dist: PyNaCl<2.0.0,>=1.5.0
Requires-Dist: PyYAML<7.0,>=6.0
Requires-Dist: loguru>=0.7.3
Requires-Dist: pip>=26.1.1
Requires-Dist: pulumi<4.0.0,>=3.0.0
Requires-Dist: pulumi-aws<7.0.0,>=6.0.0
Requires-Dist: pulumi-gcp<10.0.0,>=9.0.0
Requires-Dist: pulumi-github<7.0.0,>=6.13.1
Requires-Dist: pulumi-kubernetes<5.0.0,>=4.0.0
Requires-Dist: pulumi-postgresql<4.0.0,>=3.0.0
Requires-Dist: pulumi-random<5.0.0,>=4.0.0
Requires-Dist: pulumi-tls<6.0.0,>=5.0.0
Requires-Dist: pydantic>=2
Requires-Dist: ruamel.yaml<0.19.0,>=0.18.0
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.4; extra == "dev"
Provides-Extra: testing
Requires-Dist: pytest>=7; extra == "testing"
Provides-Extra: publish
Requires-Dist: twine>=5; extra == "publish"
Requires-Dist: keyring>=24; extra == "publish"
Requires-Dist: keyrings.google-artifactregistry-auth>=0.0.3; extra == "publish"
Dynamic: license-file

# eai-core-infra

Python package to manage core Pulumi infrastructure resources for ExtensibilityAI-provided deployments.

## Install

From [PyPI](https://pypi.org/project/eai-core-infra/):

```bash
pip install eai-core-infra
# or
uv add eai-core-infra
```

**2.0 is a breaking release** (no deprecation shims). Pin `eai-core-infra<2`
until you migrate; see [docs/MIGRATION-2.0.md](docs/MIGRATION-2.0.md).

## Database pooler (PgBouncer)

Opt-in per app stack with `<cloud>.db.pooler`. Absent or `enabled: false` changes
nothing. An app **owns** a pooler in its namespace:

```yaml
cloud:
  db:
    flags: {max_connections: "100"}   # optional; enables the connection-budget check
    pooler:
      enabled: true
      replicas: 2                      # fixed; never autoscaled
      defaultPoolSize: 4               # pool for DATABASE_NAME
      pools: {api: 8, workers: 24}     # named pools: DATABASE_POOL_<NAME>=<db>__<name>
      clients:                         # other apps' DB users allowed through
        - {user: my-consumer, namespace: my-consumer, maxConnections: 6}
```

Or it is a **client** of another app's pooler:

```yaml
cloud:
  db:
    pooler: {enabled: true, namespace: owner-app, pool: workers}
```

- **Server connections:** `replicas × (Σ pool sizes + reservePoolSize per pool + Σ
  client maxConnections)`. With `db.flags.max_connections`, parsing checks that this,
  plus `directReserve` and 3 superuser connections, fits.
- **Transaction mode** (the default) doesn't support session state across
  transactions:
  - no session `SET` (use `SET LOCAL`);
  - no session advisory locks (use `pg_advisory_xact_lock`);
  - no `LISTEN`/`NOTIFY` and no `WITH HOLD` cursors.

  Protocol-level prepared statements work (`maxPreparedStatements`). Don't hold a
  transaction open across slow work.
- **Migrations and admin** connect directly, through `DATABASE_DIRECT_HOST` and
  `DATABASE_DIRECT_PORT`.

The infra library that owns the stack (e.g. `eai-web-app-infra`) calls
`create_pgbouncer` and writes the `app-env` keys.

## Test

```bash
uv sync --extra dev
uv run pytest
```

The guardrail suites (layout, import rules, contracts, models) and the
resource-graph snapshots run on `eai_core_infra.testing`, which other
`eai-*-infra` packages use too (`pip install "eai-core-infra[testing]"`).
Describe the package with a `GuardrailSpec` and call one `assert_*` per suite.
`RECORD_ALLOWLISTS=1` rewrites the ratchet allowlists and `RECORD_SNAPSHOTS=1`
rewrites snapshots; review every added line.

## Pre-commit

Hooks mirror CI lint and tests (`ruff check`, `pytest`):

```bash
uv tool install pre-commit   # once
pre-commit install
pre-commit run --all-files   # optional manual run
```

## License

Apache-2.0
