diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ce10435..61c63fb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -63,7 +63,7 @@ jobs: # no checkout and no workspace: the published distributions have to resolve each other and # their dependencies from the index and the wheels alone - run: uv venv --python 3.11 clean - - run: uv pip install --python clean --find-links dist --no-build "easyssf-receiver-fastapi==0.7.0" "easyssf-test==0.7.0" + - run: uv pip install --python clean --find-links dist --no-build "easyssf-receiver-fastapi==0.8.0.dev0" "easyssf-test==0.8.0.dev0" - run: uv pip list --python clean | grep easyssf - run: | clean/bin/python - <<'EOF' diff --git a/AGENTS.md b/AGENTS.md index 88751dc..95c510c 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -220,6 +220,11 @@ A release goes through a commit like every other change: 3. Push and let CI pass, then push the tag on that commit (`git tag v && git push origin v`) and watch the workflow. +After a release, `main` starts the next version as a development version, as Java's +`0.8.0-SNAPSHOT` and .NET's `0.8.0-alpha.1` do: `version = "0.8.0.dev0"` everywhere, the pins at +`>=0.8.0.dev0,<0.9` (`<0.8` would exclude it), and the version `ci.yml` installs, then `uv lock`. +The release sets them to `0.8.0` and `>=0.8,<0.9`. + A rerun after a partial upload is safe: `skip-existing` leaves the files already on PyPI alone. PyPI never accepts a file name twice, so a broken release is fixed with a new version, not a re-upload. diff --git a/README.md b/README.md index aca7e99..9a27d42 100644 --- a/README.md +++ b/README.md @@ -49,17 +49,15 @@ Version 0.7.0 is at feature parity with [easyssf 0.7.0 for Java](https://github. the version follows the Java library, and below 1.0 a release may break the API when the CHANGELOG says so. Python 3.11 or later, Apache-2.0. -## Distributions +## Modules One `uv` workspace, one `easyssf` namespace: -| Distribution | Import | Holds | +| Module | Import | Holds | |---|---|---| | `easyssf-core` | `easyssf.core` | The vocabulary: SETs (`EventToken`, the `new_set` builder), subjects, delivery methods, stream configuration, transmitter metadata; `easyssf.core.event_types` the event type URIs with aliases; `easyssf.core.caep`, `.risc`, `.scim` the typed events; `easyssf.core.signing` signs SETs (`easyssf-core[signing]`) | | `easyssf-receiver` | `easyssf.receiver` | The receiver: verification, de-duplication with a lease, push and poll, stream management, typed handlers, token revocation, session termination, metrics; `ReceiverConfig` and `Receiver`, which assembles a receiver from it; `PushHandler`, mounted on any framework with `easyssf.receiver.asgi.push_app` or `easyssf.receiver.wsgi.push_wsgi_app`; `RevocationMiddleware` | -| `easyssf-receiver-sqlalchemy` (planned) | `easyssf.sqlalchemy` | The three tables shared with Java, Go, .NET and Rust, on SQLAlchemy 2 | | `easyssf-receiver-fastapi` | `easyssf.fastapi` | The push endpoint as an `APIRouter` (`push_router_for`), the rejection of revoked access tokens as a dependency (`revocation_dependency`) or middleware, the receiver's lifecycle as a lifespan (`receiver_lifespan`), its health as a route (`health_router`), see [FastAPI](#fastapi) | -| `easyssf-receiver-litestar`, `-flask` (planned) | `easyssf.litestar`, `.flask` | The push route, the revocation middleware or guard and the lifecycle of each framework | | `easyssf-test` | `easyssf.testing` | `TestTransmitter`: signs SETs, serves metadata and the JWK Set, issues tokens, emulates stream management and the poll endpoint, in-process through the `httpx.AsyncClient` it hands out, no socket involved | | `conformance/` (not published) | `easyssf.conformance` | Runs the OpenID conformance suite's SSF receiver test plans against the receiver, with the suite started by testcontainers-python, see [Conformance](#conformance) | diff --git a/conformance/pyproject.toml b/conformance/pyproject.toml index 6c522f6..b34b5c6 100644 --- a/conformance/pyproject.toml +++ b/conformance/pyproject.toml @@ -1,15 +1,15 @@ [project] name = "easyssf-conformance" -version = "0.7.0" +version = "0.8.0.dev0" description = "Runs the OpenID conformance suite's SSF receiver test plans against easyssf-receiver, with the suite started by testcontainers; not published" readme = "README.md" requires-python = ">=3.11" license = "Apache-2.0" classifiers = ["Private :: Do Not Upload"] dependencies = [ - "easyssf-core>=0.7,<0.8", - "easyssf-receiver>=0.7,<0.8", - "easyssf-test>=0.7,<0.8", + "easyssf-core>=0.8.0.dev0,<0.9", + "easyssf-receiver>=0.8.0.dev0,<0.9", + "easyssf-test>=0.8.0.dev0,<0.9", "httpx>=0.28,<1", "testcontainers>=4.15,<5", "uvicorn>=0.34", diff --git a/easyssf-core/pyproject.toml b/easyssf-core/pyproject.toml index 94aa7a7..9cc4281 100644 --- a/easyssf-core/pyproject.toml +++ b/easyssf-core/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "easyssf-core" -version = "0.7.0" +version = "0.8.0.dev0" description = "The vocabulary of the OpenID Shared Signals Framework: SETs, subjects, event types, the typed CAEP, RISC and SCIM events, stream configuration and transmitter metadata" readme = "README.md" requires-python = ">=3.11" diff --git a/easyssf-receiver-fastapi/pyproject.toml b/easyssf-receiver-fastapi/pyproject.toml index 8fba066..a8719dd 100644 --- a/easyssf-receiver-fastapi/pyproject.toml +++ b/easyssf-receiver-fastapi/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "easyssf-receiver-fastapi" -version = "0.7.0" +version = "0.8.0.dev0" description = "The easyssf SSF receiver for FastAPI: the push endpoint, the rejection of revoked access tokens and the receiver's lifecycle" readme = "README.md" requires-python = ">=3.11" @@ -17,7 +17,7 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "easyssf-receiver>=0.7,<0.8", + "easyssf-receiver>=0.8.0.dev0,<0.9", "fastapi>=0.115,<1", ] diff --git a/easyssf-receiver/pyproject.toml b/easyssf-receiver/pyproject.toml index 72228b1..3047747 100644 --- a/easyssf-receiver/pyproject.toml +++ b/easyssf-receiver/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "easyssf-receiver" -version = "0.7.0" +version = "0.8.0.dev0" description = "An SSF receiver for Python, framework independent: SET verification, push and poll delivery, stream management, typed CAEP, RISC and SCIM handlers, token revocation and session termination" readme = "README.md" requires-python = ">=3.11" @@ -16,7 +16,7 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "easyssf-core>=0.7,<0.8", + "easyssf-core>=0.8.0.dev0,<0.9", "joserfc>=1.7,<2", "httpx>=0.28,<1", ] diff --git a/easyssf-test/pyproject.toml b/easyssf-test/pyproject.toml index 4f2dd76..d871829 100644 --- a/easyssf-test/pyproject.toml +++ b/easyssf-test/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "easyssf-test" -version = "0.7.0" +version = "0.8.0.dev0" description = "A test transmitter for SSF receivers: signs SETs, serves metadata and a JWK Set, issues tokens, emulates stream management and the poll endpoint, in-process through an httpx transport" readme = "README.md" requires-python = ">=3.11" @@ -17,7 +17,7 @@ classifiers = [ "Typing :: Typed", ] dependencies = [ - "easyssf-core[signing]>=0.7,<0.8", + "easyssf-core[signing]>=0.8.0.dev0,<0.9", "joserfc>=1.7,<2", "httpx>=0.28,<1", ] diff --git a/examples/fastapi/resource-server/pyproject.toml b/examples/fastapi/resource-server/pyproject.toml index a8d44c6..6f16559 100644 --- a/examples/fastapi/resource-server/pyproject.toml +++ b/examples/fastapi/resource-server/pyproject.toml @@ -1,13 +1,13 @@ [project] name = "example-fastapi-resource-server" -version = "0.7.0" +version = "0.8.0.dev0" description = "An OAuth2 resource server on FastAPI that rejects access tokens once their Keycloak session was revoked; the port of the Spring Boot example, not published" requires-python = ">=3.11" license = "Apache-2.0" classifiers = ["Private :: Do Not Upload"] dependencies = [ - "easyssf-receiver>=0.7,<0.8", - "easyssf-receiver-fastapi>=0.7,<0.8", + "easyssf-receiver>=0.8.0.dev0,<0.9", + "easyssf-receiver-fastapi>=0.8.0.dev0,<0.9", "fastapi>=0.115,<1", "uvicorn>=0.34", "joserfc>=1.7,<2", diff --git a/pyproject.toml b/pyproject.toml index a3d22e5..af4158c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "easyssf-python" -version = "0.7.0" +version = "0.8.0.dev0" description = "Workspace root of easyssf for Python: not published, see the packages" requires-python = ">=3.11" license = "Apache-2.0" diff --git a/uv.lock b/uv.lock index 33110e5..30911bf 100644 --- a/uv.lock +++ b/uv.lock @@ -469,7 +469,7 @@ wheels = [ [[package]] name = "easyssf-conformance" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "conformance" } dependencies = [ { name = "easyssf-core" }, @@ -492,7 +492,7 @@ requires-dist = [ [[package]] name = "easyssf-core" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "easyssf-core" } [package.optional-dependencies] @@ -506,7 +506,7 @@ provides-extras = ["signing"] [[package]] name = "easyssf-python" -version = "0.7.0" +version = "0.8.0.dev0" source = { virtual = "." } dependencies = [ { name = "easyssf-conformance" }, @@ -547,7 +547,7 @@ dev = [ [[package]] name = "easyssf-receiver" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "easyssf-receiver" } dependencies = [ { name = "easyssf-core" }, @@ -572,7 +572,7 @@ dev = [{ name = "easyssf-test", editable = "easyssf-test" }] [[package]] name = "easyssf-receiver-fastapi" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "easyssf-receiver-fastapi" } dependencies = [ { name = "easyssf-receiver" }, @@ -599,7 +599,7 @@ dev = [ [[package]] name = "easyssf-test" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "easyssf-test" } dependencies = [ { name = "easyssf-core", extra = ["signing"] }, @@ -616,7 +616,7 @@ requires-dist = [ [[package]] name = "example-fastapi-resource-server" -version = "0.7.0" +version = "0.8.0.dev0" source = { editable = "examples/fastapi/resource-server" } dependencies = [ { name = "easyssf-receiver" },