Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
730a870
Add cloud-only Polar subscriptions and organization quotas
turgaybulut Sep 11, 2026
6e4fbef
Trim redundant billing work and record verification
turgaybulut Sep 11, 2026
092b190
Fix cloud and enterprise migration rollback order in CI
turgaybulut Sep 11, 2026
39c05f8
fix(gateway): scope token-count repeat identity to its own protocol
turgaybulut Sep 16, 2026
b39fee4
fix(accounting): restore the spend-denial audit key the overview reads
turgaybulut Sep 16, 2026
1a82f2a
docs: drop stale cloud records and make route ordering executable
turgaybulut Sep 16, 2026
24c4fe7
perf(cloud): keep the quota opt-in lock-free in the steady state
turgaybulut Sep 16, 2026
416ccb5
fix(accounting): point the spend-denial readers at the stored audit key
turgaybulut Sep 16, 2026
15c38d1
refactor(cloud): centralize the Polar retry policy and dedupe tenant …
turgaybulut Sep 16, 2026
b7db806
refactor: shrink gateway and cloud test scaffolding
turgaybulut Sep 16, 2026
48ef059
docs: drop orphaned verification section
turgaybulut Sep 16, 2026
18fff5f
test: assert compiled audit params instead of rendered SQL
turgaybulut Sep 16, 2026
d8ea038
test: exercise config redaction on the validator path
turgaybulut Sep 16, 2026
2308432
test: key quota mocks by argument instead of call order
turgaybulut Sep 16, 2026
f744193
style: group sqlalchemy with third-party test imports
turgaybulut Sep 16, 2026
79821a4
refactor: tighten comments and test fixtures to non-obvious facts
turgaybulut Sep 16, 2026
372f9c2
fix(cloud): stop config errors echoing secrets; verify cloud artifacts
turgaybulut Sep 16, 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
128 changes: 109 additions & 19 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,9 @@ jobs:
forbidden = {
"alembic", "asyncpg", "azure-identity", "azure-keyvault-secrets",
"boto3", "botocore", "email-validator",
"google-cloud-secret-manager", "redis", "reportlab",
"shim-enterprise", "sqlalchemy", "supabase",
"google-cloud-secret-manager", "polar-sdk", "redis", "reportlab",
"shim-cloud", "shim-enterprise", "sqlalchemy", "standardwebhooks",
"supabase",
}
assert forbidden.isdisjoint(installed), sorted(forbidden & installed)
direct = {
Expand All @@ -49,8 +50,9 @@ jobs:
forbidden_direct = {
"alembic", "asyncpg", "azure-identity", "azure-keyvault-secrets",
"boto3", "botocore", "cryptography", "email-validator",
"google-cloud-secret-manager", "pyyaml", "redis", "reportlab",
"sqlalchemy", "supabase",
"google-cloud-secret-manager", "polar-sdk", "pyyaml", "redis",
"reportlab", "shim-cloud", "sqlalchemy", "standardwebhooks",
"supabase",
}
assert forbidden_direct.isdisjoint(direct), sorted(forbidden_direct & direct)
'
Expand Down Expand Up @@ -115,13 +117,14 @@ jobs:
assert not any(
component in path.parts
for path in paths
for component in ("app", "ee", "shim_enterprise")
for component in ("app", "ee", "shim_cloud", "shim_enterprise")
)
forbidden_direct = {
"alembic", "asyncpg", "azure-identity", "azure-keyvault-secrets",
"boto3", "botocore", "cryptography", "email-validator",
"google-cloud-secret-manager", "pyyaml", "redis", "reportlab",
"sqlalchemy", "supabase",
"google-cloud-secret-manager", "polar-sdk", "pyyaml", "redis",
"reportlab", "shim-cloud", "sqlalchemy", "standardwebhooks",
"supabase",
}
direct = {
requirement.split(";", 1)[0]
Expand All @@ -146,7 +149,9 @@ jobs:
"$RUNNER_TEMP/community-venv/bin/python" -c '
from importlib.util import find_spec
import shim.application
assert find_spec("shim_enterprise") is None
assert all(find_spec(module) is None for module in (
"polar_sdk", "shim_cloud", "shim_enterprise", "standardwebhooks",
))
'
- name: Build community image from scratch
run: docker build --pull --no-cache --tag shim-community:ci .
Expand All @@ -160,9 +165,9 @@ jobs:
forbidden = {
"alembic", "asyncpg", "azure-identity", "azure-keyvault-secrets",
"boto3", "botocore", "email-validator",
"google-cloud-secret-manager", "pytest", "pytest-asyncio", "redis",
"reportlab", "ruff", "shim-enterprise", "sqlalchemy", "supabase",
"ty",
"google-cloud-secret-manager", "polar-sdk", "pytest", "pytest-asyncio",
"redis", "reportlab", "ruff", "shim-cloud", "shim-enterprise",
"sqlalchemy", "standardwebhooks", "supabase", "ty",
}
assert "shim-gateway" in installed
assert forbidden.isdisjoint(installed), sorted(forbidden & installed)
Expand All @@ -176,16 +181,19 @@ jobs:
forbidden_direct = {
"alembic", "asyncpg", "azure-identity", "azure-keyvault-secrets",
"boto3", "botocore", "cryptography", "email-validator",
"google-cloud-secret-manager", "pyyaml", "redis", "reportlab",
"sqlalchemy", "supabase",
"google-cloud-secret-manager", "polar-sdk", "pyyaml", "redis",
"reportlab", "shim-cloud", "sqlalchemy", "standardwebhooks",
"supabase",
}
assert forbidden_direct.isdisjoint(direct), sorted(forbidden_direct & direct)
package = distribution("shim-gateway")
assert package.metadata["License-Expression"] == "Apache-2.0"
assert package.metadata.get_all("License-File") == ["LICENSE", "NOTICE"]
assert {"LICENSE", "NOTICE"} <= {Path(path).name for path in package.files or ()}
assert find_spec("shim") is not None
assert find_spec("shim_enterprise") is None
assert all(find_spec(module) is None for module in (
"polar_sdk", "shim_cloud", "shim_enterprise", "standardwebhooks",
))
assert not any(Path(path).exists() for path in ("/app/app", "/app/ee", "/app/alembic"))
'
- name: Smoke community image
Expand Down Expand Up @@ -232,6 +240,11 @@ jobs:
ENCRYPTION_KEY: 1yuHjGCrKdLoXrHt6qVL4vd6GHUZ1KVDbsXWJsbq3Kw=
SUPABASE_URL: https://example.supabase.co
SUPABASE_KEY: ci-public-anon-key
POLAR_ACCESS_TOKEN: ci-only-polar-token
POLAR_WEBHOOK_SECRET: ci-only-polar-webhook-secret
POLAR_ORGANIZATION_ID: 00000000-0000-0000-0000-000000000001
POLAR_PRODUCTS: '{"managed:monthly":"00000000-0000-0000-0000-000000000011","managed:yearly":"00000000-0000-0000-0000-000000000012","agency:monthly":"00000000-0000-0000-0000-000000000013","agency:yearly":"00000000-0000-0000-0000-000000000014"}'
CLOUD_DASHBOARD_URL: https://cloud.example.test
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
Expand All @@ -252,15 +265,19 @@ jobs:
- run: uv sync --locked --all-packages
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini upgrade head
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini check
- run: uv run --locked --all-packages ruff format --check src ee/src tests ee/tests scripts ee/scripts ee/alembic
- run: uv run --locked --all-packages ruff check src ee/src tests ee/tests scripts ee/scripts ee/alembic
- run: uv run --locked --package shim-cloud python -m shim_cloud.migrate
- run: uv run --locked --package shim-cloud alembic -c ee/cloud/alembic.ini check
- run: uv run --locked --all-packages ruff format --check src ee/src ee/cloud/src tests ee/tests ee/cloud/tests scripts ee/scripts ee/alembic ee/cloud/alembic
- run: uv run --locked --all-packages ruff check src ee/src ee/cloud/src tests ee/tests ee/cloud/tests scripts ee/scripts ee/alembic ee/cloud/alembic
- run: uv run --locked --all-packages ty check
- run: uv run --locked --all-packages python -m pytest -q
- run: uv run --locked --package shim-enterprise python scripts/export_openapi.py --profile enterprise --check
- name: Build both packages from the validated lock
- run: uv run --locked --package shim-cloud python scripts/export_openapi.py --profile cloud --check
- name: Build all packages from the validated lock
run: |
uv build --package shim-gateway --wheel --sdist --out-dir dist/community
uv build --package shim-enterprise --wheel --sdist --out-dir dist/enterprise
uv build --package shim-cloud --wheel --sdist --out-dir dist/cloud
- name: Verify enterprise artifacts
run: |
python - <<'PY'
Expand Down Expand Up @@ -316,7 +333,7 @@ jobs:
assert not any(
component in path.parts
for path in paths
for component in ("app", "shim")
for component in ("app", "shim", "shim_cloud")
)
assert {
"ai_act.yaml", "gdpr.yaml", "iso27001.yaml", "kvkk.yaml",
Expand All @@ -326,15 +343,78 @@ jobs:
}
assert "shim-gateway==0.1.3" in metadata.get_all("Requires-Dist", [])
PY
- name: Verify cloud artifacts
run: |
python - <<'PY'
from email import message_from_bytes
from pathlib import Path, PurePosixPath
import tarfile
from zipfile import ZipFile

expected_legal = {
name: (Path("ee") / "cloud" / name).read_bytes()
for name in ("LICENSE", "NOTICE")
}
wheel = next(Path("dist/cloud").glob("*.whl"))
sdist = next(Path("dist/cloud").glob("*.tar.gz"))
with ZipFile(wheel) as archive:
wheel_paths = tuple(PurePosixPath(name) for name in archive.namelist())
metadata_path = next(
name for name in archive.namelist()
if name.endswith(".dist-info/METADATA")
)
metadata = message_from_bytes(archive.read(metadata_path))
wheel_legal = {
path.name: archive.read(str(path))
for path in wheel_paths
if path.parent.name == "licenses" and path.name in expected_legal
}
with tarfile.open(sdist) as archive:
members = archive.getmembers()
sdist_paths = tuple(PurePosixPath(member.name) for member in members)
sdist_legal = {
PurePosixPath(member.name).name: archive.extractfile(member).read()
for member in members
if member.isfile()
and PurePosixPath(member.name).name in expected_legal
}
pkg_info = next(
member for member in members if member.name.endswith("/PKG-INFO")
)
sdist_metadata = message_from_bytes(archive.extractfile(pkg_info).read())
assert wheel_legal == expected_legal
assert sdist_legal == expected_legal
for package_metadata in (metadata, sdist_metadata):
assert package_metadata["Metadata-Version"] == "2.4"
assert package_metadata["License-Expression"] == "Elastic-2.0"
assert package_metadata.get_all("License-File") == ["LICENSE", "NOTICE"]
assert package_metadata.get("License") is None
assert not any(
value.startswith("License ::")
for value in package_metadata.get_all("Classifier", [])
)
for paths in (wheel_paths, sdist_paths):
assert any("shim_cloud" in path.parts for path in paths)
assert not any(
component in path.parts
for path in paths
for component in ("app", "shim", "shim_enterprise", "tests")
)
assert "shim-enterprise==0.1.3" in metadata.get_all("Requires-Dist", [])
PY
- name: Smoke clean enterprise wheel installation
run: |
uv venv "$RUNNER_TEMP/enterprise-venv" --python 3.13
uv pip install --python "$RUNNER_TEMP/enterprise-venv/bin/python" \
dist/community/*.whl dist/enterprise/*.whl
"$RUNNER_TEMP/enterprise-venv/bin/python" -c '
from importlib import import_module
from importlib.util import find_spec
import shim.application
import shim_enterprise.application
assert all(find_spec(module) is None for module in (
"polar_sdk", "shim_cloud", "standardwebhooks",
))
for module in (
"shim_enterprise.workers.outbox",
"shim_enterprise.workers.reconciliation",
Expand All @@ -343,9 +423,13 @@ jobs:
):
import_module(module)
'
# Cloud foreign keys depend on enterprise tables; roll cloud back first.
- run: uv run --locked --package shim-cloud alembic -c ee/cloud/alembic.ini downgrade base
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini downgrade base
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini upgrade head
- run: uv run --locked --package shim-enterprise alembic -c ee/alembic.ini check
- run: uv run --locked --package shim-cloud python -m shim_cloud.migrate
- run: uv run --locked --package shim-cloud alembic -c ee/cloud/alembic.ini check
- name: Build enterprise image from scratch
run: docker build --pull --no-cache --file ee/Dockerfile --tag shim-enterprise:ci .
- name: Verify enterprise image boundary
Expand All @@ -356,7 +440,10 @@ jobs:
from importlib.util import find_spec
from pathlib import Path
installed = {item.metadata["Name"].lower().replace("_", "-") for item in distributions()}
forbidden = {"pytest", "pytest-asyncio", "ruff", "ty"}
forbidden = {
"polar-sdk", "pytest", "pytest-asyncio", "ruff", "shim-cloud",
"standardwebhooks", "ty",
}
assert {"shim-gateway", "shim-enterprise"} <= installed
assert forbidden.isdisjoint(installed), sorted(forbidden & installed)
for package_name, expression in (
Expand All @@ -371,6 +458,9 @@ jobs:
}
assert find_spec("shim") is not None
assert find_spec("shim_enterprise") is not None
assert all(find_spec(module) is None for module in (
"polar_sdk", "shim_cloud", "standardwebhooks",
))
assert all(find_spec(module) is not None for module in (
"shim_enterprise.workers.outbox",
"shim_enterprise.workers.reconciliation",
Expand Down
11 changes: 1 addition & 10 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,16 +38,7 @@ a demonstrated consumer. Reuse the existing contract or adapter first.

## Required gate

```bash
uv lock --check
uv run --locked ruff format --check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ruff check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ty check
uv run --locked python -m pytest -q
uv run --locked --package shim-gateway python scripts/export_openapi.py --profile community --check
uv run --locked --package shim-enterprise python scripts/export_openapi.py --profile enterprise --check
git diff --check
```
Run the full gate in [the developer guide](DEVELOPER_GUIDE.md#required-gates).

Continuous integration runs on pull requests and on pushes to `main`. Pushing a
branch verifies nothing, so run the gate locally and open a pull request rather
Expand Down
16 changes: 3 additions & 13 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,19 +39,9 @@ uv sync --locked --all-packages

## Verification

Run this before opening a pull request. Continuous integration runs the same
commands, plus the container builds.

```console
uv lock --check
uv sync --locked --all-packages
uv run --locked ruff format --check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ruff check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ty check
uv run --locked python -m pytest -q
uv run --locked --package shim-gateway python scripts/export_openapi.py --profile community --check
uv run --locked --package shim-enterprise python scripts/export_openapi.py --profile enterprise --check
```
Run the gate in [the developer guide](DEVELOPER_GUIDE.md#required-gates) before
opening a pull request. Continuous integration runs the same commands, plus the
container builds.

The enterprise tests need PostgreSQL and a Redis with the search and JSON
modules. `docker compose up` brings both up.
Expand Down
11 changes: 9 additions & 2 deletions DEVELOPER_GUIDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ ee/src/shim_enterprise/ enterprise runtime and adapters
ee/tests/ enterprise tests
ee/alembic/ enterprise schema history
ee/openapi/enterprise.json enterprise HTTP contract
ee/cloud/ hosted commerce package, schema, and OpenAPI contract
```

Community code must run without `ee/`, PostgreSQL, Redis, Supabase, or managed
Expand Down Expand Up @@ -103,12 +104,13 @@ Run the locked full gate before merging a cross-package or enterprise change:
```bash
uv lock --check
uv sync --locked --all-packages
uv run --locked ruff format --check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ruff check src ee/src tests ee/tests scripts ee/scripts ee/alembic
uv run --locked ruff format --check src ee/src tests ee/tests scripts ee/scripts ee/alembic ee/cloud/src ee/cloud/tests ee/cloud/alembic
uv run --locked ruff check src ee/src tests ee/tests scripts ee/scripts ee/alembic ee/cloud/src ee/cloud/tests ee/cloud/alembic
uv run --locked ty check
uv run --locked python -m pytest -q
uv run --locked --package shim-gateway python scripts/export_openapi.py --profile community --check
uv run --locked --package shim-enterprise python scripts/export_openapi.py --profile enterprise --check
uv run --locked --package shim-cloud python scripts/export_openapi.py --profile cloud --check
git diff --check
```

Expand Down Expand Up @@ -151,3 +153,8 @@ regions' `LICENSE`, `NOTICE`, and matching package metadata. Do not add a CLA,
runtime licence check, or commercial-validation policy without owner approval.
Never move enterprise source or assets outside `ee/` merely to simplify
packaging.

Hosted subscriptions use the separate [cloud composition and runbook](ee/cloud/README.md).
Apply its migrations after enterprise migrations before running cloud persistence tests.
Customer packages remain selected explicitly with `--package shim-enterprise`;
`--all-packages` is a development/verification choice, not a customer artifact install.
1 change: 1 addition & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ WORKDIR /app

COPY pyproject.toml uv.lock README.md LICENSE NOTICE ./
COPY ee/pyproject.toml ./ee/pyproject.toml
COPY ee/cloud/pyproject.toml ./ee/cloud/pyproject.toml
COPY src ./src
RUN uv sync --locked --no-dev --package shim-gateway --no-editable

Expand Down
1 change: 1 addition & 0 deletions Dockerfile.dockerignore
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,6 @@
!src/**
!ee/
!ee/pyproject.toml
!ee/cloud/pyproject.toml
**/__pycache__/
**/*.py[cod]
Loading