diff --git a/.github/SECURITY.md b/.github/SECURITY.md index 96faa172..02bb9da5 100644 --- a/.github/SECURITY.md +++ b/.github/SECURITY.md @@ -14,7 +14,7 @@ verify a report against current `main` before filing. - **Preferred (always available, fully private):** open a [GitHub private security advisory](https://github.com/MEFORORG/MessageFoundry/security/advisories/new) ("Report a vulnerability") — GitHub keeps it private to the maintainers until coordinated disclosure. - This is the recommended channel on both this repository and the public mirror. + This is the recommended channel. - Alternatively, email the maintainer at the address on the GitHub profile. If you cannot reach a maintainer privately within a few business days, you may request a contact via a diff --git a/docs/CI-SELFHOSTED-RUNNER.md b/docs/CI-SELFHOSTED-RUNNER.md index abb3203c..a900330e 100644 --- a/docs/CI-SELFHOSTED-RUNNER.md +++ b/docs/CI-SELFHOSTED-RUNNER.md @@ -5,15 +5,15 @@ > **The self-hosted runners described here have been de-registered and their services removed.** The repo > has **zero** self-hosted runners, and no workflow targets a self-hosted label for the `test` legs. > -> **Why:** the OSS mirror is a **public** repo, where GitHub-hosted minutes are **free** — so the Windows -> test matrix now runs on **hosted** runners there at no cost, and self-hosting bought nothing. It also +> **Why:** this repo is **public**, where GitHub-hosted minutes are **free** — so the Windows test +> matrix runs on **hosted** runners at no cost, and self-hosting bought nothing. It also > removed three liabilities: (1) a **SPOF** — self-hosted *required* checks had no hosted fallback, so an > offline box left PRs queued ~24h and then failing, freezing auto-merge repo-wide; (2) a **security** > concern — a self-hosted runner must never be reachable from a public repo (a fork PR would mean code > execution on the maintainer's LAN); (3) ongoing **maintenance** (tool caches, PATH, service accounts). > -> The Windows `test` legs are now selected by a **per-repo matrix** in `ci.yml`: ubuntu-only on the private -> source repo, full ubuntu + Windows on the public mirror. +> The Windows `test` legs are selected by a **per-repo matrix** in `ci.yml`: full ubuntu + Windows here, +> ubuntu-only on a fork (so a contributor's own minutes are not spent on the 2x-billed Windows legs). > > Follow this guide **only** if you are deliberately re-introducing a self-hosted runner. Note > `selfhosted-win2025-sql.yml` remains dispatch-only and is currently **runner-less**. diff --git a/docs/FEATURE-MAP.md b/docs/FEATURE-MAP.md index 0ac0d483..01671e6a 100644 --- a/docs/FEATURE-MAP.md +++ b/docs/FEATURE-MAP.md @@ -204,7 +204,7 @@ IDE are separate surfaces over the localhost API. | Feature | Status | Notes | |---------|:--:|-------| | AGPL-3.0 license + dual-licensing plan | ✅ | | -| Public OSS mirror + curated publish pipeline (forbidden-string/gitleaks gate) | ✅ | Owner runs the push (exfil guard) | +| Customer/PHI leak gate — forbidden-string + gitleaks, on every commit and in CI | ✅ | Fails closed with no token source | | CI: quartet (ruff/format/mypy/pytest) + security scans | ✅ | PG/SQL Server store jobs are service-container-gated | | Version single-sourcing (drop the duplicate literal) | 🔨 | Workstream F | | CHANGELOG.md + README roadmap refresh | 🔨 | Workstream F | diff --git a/pyproject.toml b/pyproject.toml index b217fc40..4046bf26 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -11,8 +11,10 @@ path = "messagefoundry/__init__.py" # `python -m build` packs every git-tracked file (docs/, tests/, scripts/, CLAUDE.md, .claude/ …) into the # sdist, and release.yml uploads that sdist to PUBLIC PyPI — which shipped the private security-posture # docs (docs/security/*, docs/reviews/*, Secure_Development_Standards.md — the publish-denylist set) on -# every release 0.1.0..0.2.15. The mirror's leak gate (publish.ps1 + scan_forbidden.py) governs only the -# git mirror, NOT the PyPI path, so the sdist is pinned here to the package + its metadata. (The wheel was +# every release 0.1.0..0.2.15. The leak gate (scan_forbidden.py, in pre-commit and CI) governs what is +# COMMITTED, NOT what an sdist packages, so the sdist is pinned here to the package + its metadata. That +# separation is the whole point: those docs are git-ignored now, but an allowlist is what keeps a future +# tracked-but-private file out of a release tarball. (The wheel was # already package-only.) pyproject.toml + PKG-INFO are always added by hatchling; LICENSE/NOTICE also ship # via [project].license-files. release.yml has a belt-and-suspenders "sdist is package-only" gate. [tool.hatch.build.targets.sdist] diff --git a/tests/test_backlog_status_check.py b/tests/test_backlog_status_check.py index e436e9f8..9cddd1bf 100644 --- a/tests/test_backlog_status_check.py +++ b/tests/test_backlog_status_check.py @@ -139,13 +139,16 @@ def test_changelog_crossref_is_quiet_for_closed_items() -> None: @pytest.mark.skipif( not _BACKLOG.exists(), - reason="docs/BACKLOG.md is private-only (OSS-mirror deny-list); absent on the mirror snapshot", + reason="docs/BACKLOG.md absent — only expected in an installed wheel with no docs/ tree", ) def test_the_real_backlog_satisfies_the_invariant() -> None: """The operative guard: `docs/BACKLOG.md` itself must pass on every PR. - On the public mirror the file is deny-listed (never published), so this test skips there — - the guard is enforced by the private repo's CI, where the file always exists. + THE SKIP ABOVE SHOULD NEVER FIRE IN A SOURCE CHECKOUT. It used to read "private-only (OSS-mirror + deny-list); absent on the mirror snapshot" — true while the backlog was git-ignored and this repo + was a published mirror, and quietly false afterwards: the file was un-ignored and committed, but + the reason still described a topology that had ended, so a reader who saw a skip would have + concluded it was expected rather than a missing file. Same shape as the guard it protects. """ errors, _ = bsc.scan(_BACKLOG.read_text(encoding="utf-8")) assert errors == [], "docs/BACKLOG.md violates the status invariant:\n" + "\n".join(errors)