From 4791816b252639aba97dcbbb60cba934b10cb692 Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 6 Sep 2026 13:37:58 +0200 Subject: [PATCH 1/2] test: define what a release carries --- tests/test_release.py | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/test_release.py diff --git a/tests/test_release.py b/tests/test_release.py new file mode 100644 index 0000000..9ba3c39 --- /dev/null +++ b/tests/test_release.py @@ -0,0 +1,40 @@ +"""Acceptance tests for a release (issue #72). + +A release has one version, declared in ``pyproject.toml`` and mirrored by +``coretrace_python.__version__``, and a ``CHANGELOG.md`` whose first entry is that +version. The release workflow refuses a tag that does not match the version. + +Expected to remain red until ``CHANGELOG.md`` exists and the version is 0.2.0. +""" + +from __future__ import annotations + +import re +import tomllib +from pathlib import Path + +import pytest + +import coretrace_python + +REPO = Path(__file__).resolve().parent.parent +CHANGELOG = REPO / "CHANGELOG.md" + + +@pytest.fixture(autouse=True) +def require_changelog() -> None: + if not CHANGELOG.is_file(): + pytest.fail("CHANGELOG.md is not written yet") + + +def test_the_version_is_declared_once_and_mirrored() -> None: + project = tomllib.loads((REPO / "pyproject.toml").read_text(encoding="utf-8"))["project"] + + assert project["version"] == coretrace_python.__version__ == "0.2.0" + + +def test_the_changelog_starts_with_the_current_version() -> None: + headings = re.findall(r"^## \[?(\d+\.\d+\.\d+)\]?", CHANGELOG.read_text(encoding="utf-8"), re.MULTILINE) + + assert headings and headings[0] == coretrace_python.__version__ + assert "0.1.0" in headings From 1aadd336a98ca9f1426aa5a10c509b37bd1fbfac Mon Sep 17 00:00:00 2001 From: Hugo Date: Sun, 6 Sep 2026 13:37:58 +0200 Subject: [PATCH 2/2] chore: release 0.2.0 --- CHANGELOG.md | 42 ++++++++++++++++++++++++++++++++ docs/usage.md | 2 +- pyproject.toml | 2 +- src/coretrace_python/__init__.py | 2 +- 4 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..312ca68 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,42 @@ +# Changelog + +## 0.2.0 (2026-09-06) + +### Adoption in an existing repository + +- Report paths are relative to the checked root; the JSON report carries the root and the SARIF log declares it as the `SRCROOT` URI base, so code scanning attaches alerts to files (#75). +- `# coretrace: ignore` and `# coretrace: ignore[rule, rule]` silence a finding on its line, in Python sources and requirements files; suppressed findings are counted, listed and marked in the reports (#76). +- `--baseline PATH` records the accepted findings on the first run and fails later runs on new findings only; findings are recognised by file, rule, function and line text, not line number (#77). +- `--fail-on SEVERITY` sets the exit status to 1 only from that severity up (#78). + +### Analysis + +- Assignment expressions, `yield from`, starred assignment targets, class keyword arguments and any assignable `with` target are supported; they used to reject whole files (#80, #86). +- A `nonlocal` write made by a nested function flows back to the enclosing function when it calls that function directly, the last documented approximation (#84). +- An attribute a class does not define resolves through its base, so `self.get_argument` in a Tornado handler and `self.request` in a Django class-based view denote the framework's; static methods called on the class resolve to the method and pass no receiver (#89). +- Route registrations are found inside functions such as `setup_routes(app: Application)`, and `await f()` denotes what `f()` denotes (#88). + +### Detection + +- New security models: aiohttp, Tornado, Bottle, and the aiopg, asyncpg, psycopg2 and PyMySQL drivers (#88, #89). +- New rules: `insecure-tls`, `unsafe-xml`, `unsafe-archive-extraction`, `insecure-temp-file` and `weak-random` (#90). + +### Precision + +- Hex digests, subresource-integrity hashes and character-set constants are no longer high-entropy secrets; credentials in test code and template files are reported at low confidence; `token_type`-like names are not credentials (#81, #82, #87). +- Redirect sinks read their target argument only, so `redirect("url-name", arg)` is not an open redirect (#83). +- Environment variables and process output are operator-controlled: they carry no command or path kinds, except a downloaded script piped into a shell (#87). +- A container literal passed to a sink is serialised, never rendered, so it carries no HTML (#89). + +### Performance and corpus + +- A module's functions are collected once; 25 to 30 percent faster on large projects, measured on healthchecks, rich and wagtail and recorded in the usage guide (#79). +- The regression corpus grows to 19 repositories, including healthchecks, dvpwa, pygoat, the FastAPI full-stack template, httpie and luigi (#79, #85). + +### Packaging + +- The Apache License 2.0 text ships with the repository and the wheel (#74). + +## 0.1.0 (2026-09-04) + +First release on PyPI: the analyzer with its 26 bundled plugins, the regression suite on 13 public repositories and the usage and plugin guides. diff --git a/docs/usage.md b/docs/usage.md index c95b1c7..1e60046 100644 --- a/docs/usage.md +++ b/docs/usage.md @@ -198,7 +198,7 @@ the directory of the checked file; a path outside it is printed as it is. ```json { "schema_version": 1, - "tool": {"name": "coretrace-python-analyzer", "version": "0.1.0"}, + "tool": {"name": "coretrace-python-analyzer", "version": "0.2.0"}, "root": "/home/me/project", "findings": [ { diff --git a/pyproject.toml b/pyproject.toml index 610705b..0ff1b1e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "coretrace-python-analyzer" -version = "0.1.0" +version = "0.2.0" description = "Static security analysis infrastructure for Python code" readme = "README.md" requires-python = ">=3.11" diff --git a/src/coretrace_python/__init__.py b/src/coretrace_python/__init__.py index ceed008..a30f42f 100644 --- a/src/coretrace_python/__init__.py +++ b/src/coretrace_python/__init__.py @@ -1,4 +1,4 @@ """CoreTrace's Python static analysis frontend.""" -__version__ = "0.1.0" +__version__ = "0.2.0"