Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# .devcontainer/Dockerfile
FROM mcr.microsoft.com/devcontainers/python:3.12
FROM mcr.microsoft.com/devcontainers/python:3.14

# Install system dependencies
RUN apt-get update && export DEBIAN_FRONTEND=noninteractive \
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ concurrency:
cancel-in-progress: true

env:
PYTHON_VERSION: "3.12"
PYTHON_VERSION: "3.14"
POETRY_VERSION: "2.4.1"

# ──────────────────────────────────────────────────────────────
Expand Down Expand Up @@ -78,7 +78,7 @@ jobs:
strategy:
fail-fast: false
matrix:
python-version: ["3.12", "3.13"]
python-version: ["3.14"]

steps:
- uses: actions/checkout@v4
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ permissions:
pull-requests: write

env:
PYTHON_VERSION: "3.12"
PYTHON_VERSION: "3.14"

jobs:
build:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"

- name: Install Poetry
uses: snok/install-poetry@v1
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release-manual.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ permissions:
actions: write

env:
PYTHON_VERSION: "3.12"
PYTHON_VERSION: "3.14"
POETRY_VERSION: "2.4.1"

jobs:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ permissions:
contents: read

env:
PYTHON_VERSION: "3.12"
PYTHON_VERSION: "3.14"
POETRY_VERSION: "2.4.1"

jobs:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"

- name: Install Poetry
uses: snok/install-poetry@v1
Expand Down Expand Up @@ -54,7 +54,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"

- name: Install Bandit
run: pip install bandit[toml]
Expand Down Expand Up @@ -115,7 +115,7 @@ jobs:
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: "3.13"
python-version: "3.14"

- name: Install Poetry
uses: snok/install-poetry@v1
Expand Down
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.8.0] - 2026-10-01

### Changed
- **BREAKING: the minimum supported Python is now 3.14** (`requires-python = ">=3.14,<4.0"`, was `>=3.12`). Development, the benchmarks behind the 2.6.x lifecycle/GC work and every release smoke test already ran on CPython 3.14, while the CI matrix only exercised 3.12 and 3.13 — so the versions the project claimed to support were not the ones it was actually run on. Consequences for users: `pip install XCoreRuntime` on Python 3.12 or 3.13 will no longer select this version or later (pip's `Requires-Python` check falls back to 2.7.x); stay on `XCoreRuntime<2.8` there.
- **CI now runs on 3.14 only**: the `Tests & Coverage` matrix is `["3.14"]` (jobs are renamed `Tests & Coverage (3.14)`; there is no required-status-check rule on those names), and the lint, docs, security, PR and both release workflows moved to 3.14 (they were pinned to 3.12 or 3.13). The wheel published by `release.yml` is built on 3.14 (pure Python, `py3-none-any`).
- `poetry.lock` regenerated for the new floor: only the Python-version markers and metadata change (the `python_version < "3.13"` backport markers on `typing-extensions` and the pydantic marker ladder collapse); **no package version changes**.
- `.devcontainer` image moved to `python:3.14`; install/requirements pages, `CLAUDE.md` and `GEMINI.md` updated.

### Known limitation
- **The `[cpp]` extra (`xcorescanner`) has no 3.14 wheel yet**: `xcorescanner 0.1.0` on PyPI ships `cp312` and `cp313` wheels plus an sdist, so on Python 3.14 `pip install 'XCoreRuntime[cpp]'` builds it from source and needs a C++ toolchain until a `cp314` wheel is published. Without the extra, xcore falls back to the Python AST scanner.

### Notes
- Black stays on `target-version = ["py313"]`: with `py314` it rewrites `except (A, B):` into the PEP 758 form `except A, B:` across the code base — valid on 3.14, but easy to misread and not handled by all tooling. The code itself already requires 3.14 through `requires-python`.
- The `Upload to Codecov` step in `ci.yml` is still guarded by `matrix.python-version == '3.11'` (a leftover that has been false for a long time), so it still never runs; left untouched here.

## [2.7.0] - 2026-10-01

### Changed
Expand Down
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,10 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co

## Présentation

**xcore v2.7.0** — framework d'orchestration plugin-first construit sur FastAPI.
**xcore v2.8.0** — framework d'orchestration plugin-first construit sur FastAPI.
Charge, isole et gère des plugins modulaires dans un environnement sandboxé.

- **Language** : Python 3.12+
- **Language** : Python 3.14+
- **Framework** : FastAPI + uvicorn
- **Dépendances** : Poetry
- **Config** : `integration.yaml` (principal) — pas `xcore.yaml`
Expand Down
4 changes: 2 additions & 2 deletions GEMINI.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
- **Security**: Supports plugin signing, manifest validation, and strict import/resource restriction.

### Main Technologies
- **Language**: Python 3.12+ (with C++ extensions for security)
- **Language**: Python 3.14+ (with C++ extensions for security)
- **Framework**: FastAPI [standard]
- **Dependency Management**: Poetry / UV
- **Data Validation**: Pydantic v2
Expand All @@ -26,7 +26,7 @@
## Building and Running

### Prerequisites
- Python 3.12 or higher
- Python 3.14 or higher
- [Poetry](https://python-poetry.org/) 2.0+

### Key Commands
Expand Down
15 changes: 15 additions & 0 deletions doc/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,21 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [2.8.0] - 2026-10-01

### Changed
- **BREAKING: the minimum supported Python is now 3.14** (`requires-python = ">=3.14,<4.0"`, was `>=3.12`). Development, the benchmarks behind the 2.6.x lifecycle/GC work and every release smoke test already ran on CPython 3.14, while the CI matrix only exercised 3.12 and 3.13 — so the versions the project claimed to support were not the ones it was actually run on. Consequences for users: `pip install XCoreRuntime` on Python 3.12 or 3.13 will no longer select this version or later (pip's `Requires-Python` check falls back to 2.7.x); stay on `XCoreRuntime<2.8` there.
- **CI now runs on 3.14 only**: the `Tests & Coverage` matrix is `["3.14"]` (jobs are renamed `Tests & Coverage (3.14)`; there is no required-status-check rule on those names), and the lint, docs, security, PR and both release workflows moved to 3.14 (they were pinned to 3.12 or 3.13). The wheel published by `release.yml` is built on 3.14 (pure Python, `py3-none-any`).
- `poetry.lock` regenerated for the new floor: only the Python-version markers and metadata change (the `python_version < "3.13"` backport markers on `typing-extensions` and the pydantic marker ladder collapse); **no package version changes**.
- `.devcontainer` image moved to `python:3.14`; install/requirements pages, `CLAUDE.md` and `GEMINI.md` updated.

### Known limitation
- **The `[cpp]` extra (`xcorescanner`) has no 3.14 wheel yet**: `xcorescanner 0.1.0` on PyPI ships `cp312` and `cp313` wheels plus an sdist, so on Python 3.14 `pip install 'XCoreRuntime[cpp]'` builds it from source and needs a C++ toolchain until a `cp314` wheel is published. Without the extra, xcore falls back to the Python AST scanner.

### Notes
- Black stays on `target-version = ["py313"]`: with `py314` it rewrites `except (A, B):` into the PEP 758 form `except A, B:` across the code base — valid on 3.14, but easy to misread and not handled by all tooling. The code itself already requires 3.14 through `requires-python`.
- The `Upload to Codecov` step in `ci.yml` is still guarded by `matrix.python-version == '3.11'` (a leftover that has been false for a long time), so it still never runs; left untouched here.

## [2.7.0] - 2026-10-01

### Changed
Expand Down
2 changes: 1 addition & 1 deletion doc/cli/getting-started/install.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Getting started with `xcorecli` is straightforward. The project uses [Poetry](ht

## Prerequisites

- **Python**: 3.12 or higher.
- **Python**: 3.14 or higher.
- **Poetry**: Recommended for environment management.
- **Make**: To use the provided automation scripts.

Expand Down
4 changes: 2 additions & 2 deletions doc/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ icon: material/download

# Installation & Setup

Xcore requires **Python 3.12** or higher.
Xcore requires **Python 3.14** or higher.

## Using Xcore in a project (PyPI)

Expand Down Expand Up @@ -41,7 +41,7 @@ no external dependency. `[sdk]` unlocks the extended feature set above.

## Contributing to Xcore itself (from source)

- [x] Python 3.12+ installed
- [x] Python 3.14+ installed
- [x] [Poetry](https://python-poetry.org/docs/#installation) installed
- [x] C++ compiler (GCC, Clang, or MSVC) — only needed to build the optional `scanner_core` accelerator in-place
- [ ] Redis (optional, required for Redis cache and background workers)
Expand Down
2 changes: 1 addition & 1 deletion doc/plugins/trusted-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ Trusted plugins are native Python extensions that run directly in the main Xcore
### Prerequisites

- [x] [Plugin Anatomy](./plugin-anatomy.md) understood
- [x] Python 3.12+ and `asyncio` proficiency
- [x] Python 3.14+ and `asyncio` proficiency

---

Expand Down
2 changes: 1 addition & 1 deletion doc/sdk/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

| Requirement | Version |
|-------------|---------|
| Python | 3.12+ |
| Python | 3.14+ |
| uv | latest |
| xcore | installed in the environment |

Expand Down
14 changes: 3 additions & 11 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "XCoreRuntime"
version = "2.7.0"
version = "2.8.0"
description = "Plugin-first orchestration framework built on FastAPI"
authors = [
{ name = "Eliezer Traore", email = "68350805+traoreera@users.noreply.github.com" },
Expand All @@ -15,7 +15,7 @@ classifiers = [
"Operating System :: OS Independent",
]

requires-python = ">=3.12,<4.0"
requires-python = ">=3.14,<4.0"

# ── Noyau ───────────────────────────────────────────────────────────────────────
# Ce que `import xcore` et la config par défaut (zero-config) chargent
Expand Down Expand Up @@ -138,7 +138,10 @@ markdown = "^3.8.2"
# ── Linting ────────────────────────────────────────────────────────────────────
[tool.black]
line-length = 88
target-version = ["py312"] # était py311, ton requires-python est >=3.12
# py313 et non py314 : avec py314, black réécrit `except (A, B):` en `except A, B:`
# (PEP 758, sans parenthèses) — valide en 3.14 mais trompeur à lire et mal géré par
# une partie de l'outillage. Le code reste valide sur 3.14 (requires-python >=3.14).
target-version = ["py313"]

[tool.isort]
profile = "black"
Expand Down
42 changes: 42 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

import os
import shutil
import sys
import tempfile
from pathlib import Path
from typing import Generator
Expand Down Expand Up @@ -163,6 +164,47 @@ def _cleanup_stray_tmp_dirs() -> Generator[None, None, None]:
sweep_stray_tmp_dirs()


@pytest.fixture(autouse=True)
def _no_process_rlimit_leak() -> Generator[None, None, None]:
"""
Un test ne doit jamais modifier les limites de ressources du process pytest.

RLIMIT_AS / RLIMIT_DATA / RLIMIT_CPU sont globaux au process et la limite DURE
ne se relève pas : un `setrlimit` réel dans un test s'applique à tous les tests
suivants de la session. RLIMIT_AS à 512 Mo suffisait à faire échouer
`threading.Thread.start()` (« can't start new thread ») dans les tests placés
plus loin — selon l'empreinte mémoire de l'interpréteur. Tester ces limites en
patchant `resource.setrlimit`, ou dans un sous-processus.
"""
if sys.platform == "win32":
yield
return
import resource

tracked = [
getattr(resource, name)
for name in ("RLIMIT_AS", "RLIMIT_DATA", "RLIMIT_CPU")
if hasattr(resource, name)
]
before = {r: resource.getrlimit(r) for r in tracked}
yield
changed = {
r: resource.getrlimit(r) for r in tracked if resource.getrlimit(r) != before[r]
}
if changed:
for r, (soft, _hard) in changed.items(): # remet au moins la limite souple
try:
resource.setrlimit(r, (before[r][0], resource.getrlimit(r)[1]))
except (ValueError, OSError):
pass
pytest.fail(
"ce test a modifié les limites de ressources du process pytest "
f"({sorted(changed)}) — irréversible et valable pour toute la session ; "
"patcher resource.setrlimit ou utiliser un sous-processus",
pytrace=False,
)


@pytest.fixture
def invalid_plugin_dir(plugins_dir: Path) -> Path:
"""Plugin invalide — manque PLUGIN_INFO."""
Expand Down
29 changes: 25 additions & 4 deletions tests/unit/kernel/test_isolation.py
Original file line number Diff line number Diff line change
Expand Up @@ -69,10 +69,31 @@ def test_apply_negative_noop(self):
MemoryLimiter.apply(-1) # should not raise

def test_apply_positive(self):
"""
Vérifie l'appel à setrlimit SANS l'exécuter : RLIMIT_AS est irréversible
(la limite dure baisse) et s'appliquerait à tout le process pytest — chaque
thread créé ensuite (TestClient, to_thread…) réserve ~72 Mo d'espace
d'adressage, et au bout de quelques-uns `can't start new thread`. Les tests
placés après celui-ci dans la session plantaient selon l'empreinte mémoire
de l'interpréteur (vu sur Python 3.14).
"""
import resource
import sys
from unittest.mock import patch

if sys.platform == "win32":
pytest.skip("Not supported on Windows")
with patch("resource.setrlimit") as mock_setrlimit:
MemoryLimiter.apply(512)

limit = 512 * 1024 * 1024
mock_setrlimit.assert_called_once_with(resource.RLIMIT_AS, (limit, limit))

def test_apply_failure_is_logged_not_raised(self):
import sys
from unittest.mock import patch

if sys.platform == "win32":
pytest.skip("Not supported on Windows")
try:
MemoryLimiter.apply(512) # may raise or not depending on OS limits
except Exception:
pass # some systems don't allow raising RLIMIT_AS
with patch("resource.setrlimit", side_effect=ValueError("not allowed")):
MemoryLimiter.apply(512) # ne lève pas
4 changes: 2 additions & 2 deletions xcore/__version__.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
__version__ = "2.7.0"
__version_info__ = (2, 7, 0)
__version__ = "2.8.0"
__version_info__ = (2, 8, 0)
__author__ = "xcore contributors"
__license__ = "MIT"
Loading