From 55ef36f430af130fa536b0afe1e91663bcadc705 Mon Sep 17 00:00:00 2001 From: Andre van Zuydam Date: Wed, 21 Oct 2026 14:10:04 +0200 Subject: [PATCH] release: stage tina4-python 3.13.153 (restore bundled skills) Bump 3.13.152 -> 3.13.153 across the version-bearing files and open the 3.13.153 CHANGELOG section. No framework code change; the release re-tags the restored tina4-seo / tina4-a11y / tina4-design skills (#117, #128) for the install bundle and its fallback mirrors. Co-Authored-By: Claude Opus 4.8 Signed-off-by: Andre van Zuydam --- AGENTS.md | 2 +- CHANGELOG.md | 10 +++++++++- CLAUDE.md | 4 ++-- pyproject.toml | 2 +- tina4_python/__init__.py | 2 +- uv.lock | 2 +- 6 files changed, 15 insertions(+), 7 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ed63317e..47892c92 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,6 +1,6 @@ # Tina4 Python — Agent Instructions -v3.13.152. 140 cataloged features, zero dependencies. Python 3.12+. +v3.13.153. 140 cataloged features, zero dependencies. Python 3.12+. ## AI Skills diff --git a/CHANGELOG.md b/CHANGELOG.md index 5a523988..860751ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,15 @@ https://tina4.com/python/36-releases This file records framework-specific changes. The release notes above remain the authority for shipped versions. -## 3.13.152 - 2026-10-20 +## 3.13.153 - 2026-10-21 + +### Fixed +- Skills: restore the bundled AI skills that earlier releases dropped — + tina4-seo and tina4-a11y (#117), and tina4-design's stop-and-wait approval + gates (#128). No framework code change; this release re-tags the restored + skills so the install bundle and its CDN fallback mirrors carry them again, + and the bundle generator now refuses to ship a skill set smaller than the one + already published.## 3.13.152 - 2026-10-20 ### Fixed - Database: the PostgreSQL adapter recovers after a dropped connection even diff --git a/CLAUDE.md b/CLAUDE.md index 3555eb3a..32af4f80 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -15,7 +15,7 @@ The full discipline lives in `.claude/skills/tina4-maintainer/SKILL.md`; this bl # Tina4 Python -Version 3.13.152 - Lightweight Python web framework. See https://tina4.com for full documentation. +Version 3.13.153 - Lightweight Python web framework. See https://tina4.com for full documentation. ## Build & Test @@ -943,7 +943,7 @@ uv run tina4python test # Discovers @tests in src/**/*.py - SSE/Streaming via `response.stream()` — Server-Sent Events support for real-time data push. Pass an async generator; framework handles chunked transfer encoding, `text/event-stream` content type, and connection keep-alive - MCP server (`tina4_python.mcp`): built-in dev tools auto-start when MCP is a capability of the deployment. Developer API: `McpServer`, `@mcp_tool`, `@mcp_resource`. JSON-RPC 2.0 over SSE. **Security is a two-layer gate (v3.13.40):** `is_enabled()` is a pure capability gate (explicit `TINA4_MCP` wins, else `TINA4_DEBUG`; host-independent), and `is_request_allowed(remote_ip, has_valid_token)` authorises each request on the RAW socket peer (`request.remote_ip`, never X-Forwarded-For): loopback always; a remote caller needs `TINA4_MCP_REMOTE=true` AND a token matching `TINA4_MCP_TOKEN` (never `TINA4_API_KEY`, ADR-0078; sent as Authorization Bearer / X-MCP-Token; no configured token means remote is always denied). Every `/__dev` request (reads too), the MCP endpoints and the `/__dev_reload` socket also require a loopback Host (`localhost`, `127.0.0.1`, `[::1]` or `TINA4_HOST`) and refuse `Sec-Fetch-Site: same-site`/`cross-site` (ADR-0078). `/health` omits `version` outside debug. All MCP surfaces (REST shim, JSON-RPC, SSE) 404 a disallowed caller. `database_query` is SELECT/WITH-only and rejects stacked statements; the file tools are sandboxed to the project root. `is_localhost()` is informational only, not the gate. **`TINA4_DEV_ALLOWED_PEERS`** (opt-in, default none) is a comma-separated IP/CIDR allow-list of RAW socket peers (v4/v6, never a forwarded header) admitted to `/__dev` - the documented way to reach the dashboard from a Docker dev box whose requests arrive from the container-network gateway, e.g. `172.16.0.0/12` (#279). `/__dev/toolbar.css` and `/__dev/toolbar.js` are static and always load; a viewer the gate would refuse gets no toolbar injected - Tests: 6,088 passing, 0 failures, **0 skipped** — measured 2026-09-17 on the lab (Ubuntu 24.04.4 LTS x86_64, Python 3.13.13, live services, `TINA4_REQUIRE_SERVICES=1`, 604s, run as root). **Firebird is NOT excluded.** The lab provisions a live Firebird 5 (`firebirdsql/firebird:5` on :3050, `TINA4_TEST_FIREBIRD_URL`) and those tests run. What IS deliberate is Firebird's absence from the `TINA4_REQUIRE_SERVICES` keyword gate in `tests/conftest.py`: GitHub CI does not provision Firebird, so a Firebird skip has to stay green *there*. Those are two different things and this line used to conflate them into "excluded by design", which read as "the Firebird tests do not run" — they do. **Nothing skips any more.** Reaching 0 skips now also needs the graph engines (Neo4j, Memgraph, ArangoDB, Ultipa, wired via `TINA4_TEST_NEO4J_URL`/`_MEMGRAPH_URL`/`_ARANGO_URL`/`_ULTIPA_URL` + the `graph` extra) and the lab Keycloak OIDC realm (`TINA4_REQUIRE_OIDC=1`), both added after the August baseline; without them `test_graph.py` (Feature 139) and the real OIDC contract test skip. The last skip was `tests/test_session_backend_failure.py` `[needs:no-dac-override]`: the suite runs as root, root holds `CAP_DAC_OVERRIDE`, so a write went straight through a 0400 file and no real `EACCES` was reachable — and as root the second `save()` returned `True`, so that skip was hiding a FAILING assertion, not merely an unrunnable one. The test now stops being root for the length of the failing write (`os.seteuid` to `nobody`; the saved uid stays 0, so a `finally` always restores it) and the kernel raises the genuine errno-13 the test asserts. Two parts of that are load-bearing: the log directory is handed to the same uid, because dropping the uid otherwise denies `Log.error` as well and the EACCES under test goes unrecorded (`_LogWriter.write` swallows `OSError` unless `TINA4_LOG_STRICT`); and the fixture root is its own 0755 `mkdtemp` rather than `tmp_path`, whose 0700 root-owned parents make every denial a directory traversal, which would pass for the wrong reason. Re-measure with `.venv/bin/python -m pytest tests/ -q` and quote the summary line, never the exit code -- Version: 3.13.152 +- Version: 3.13.153 ## Links diff --git a/pyproject.toml b/pyproject.toml index 3007b07a..35cc6b41 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "tina4-python" -version = "3.13.152" +version = "3.13.153" description = "Tina4 Python v3 — Zero-dependency, lightweight web framework" authors = [ {name = "Andre van Zuydam", email = "andrevanzuydam@gmail.com"} diff --git a/tina4_python/__init__.py b/tina4_python/__init__.py index a9c2ad17..802248c9 100644 --- a/tina4_python/__init__.py +++ b/tina4_python/__init__.py @@ -57,7 +57,7 @@ def _resolve_version() -> str: # # test_version_constant.py now asserts this literal equals the pyproject # version, so the release bump cannot leave it behind again. - return "3.13.152" + return "3.13.153" __version__ = _resolve_version() diff --git a/uv.lock b/uv.lock index 719ab819..f1175913 100644 --- a/uv.lock +++ b/uv.lock @@ -1599,7 +1599,7 @@ wheels = [ [[package]] name = "tina4-python" -version = "3.13.152" +version = "3.13.153" source = { editable = "." } [package.optional-dependencies]