From 82aed68cfb9a09d81d6b84448099a24031821987 Mon Sep 17 00:00:00 2001 From: Evan Newman Date: Sat, 3 Oct 2026 13:25:49 -0230 Subject: [PATCH] chore: prepare v0.1.0 for release Add the user-selected MIT license, version and package metadata, release notes, and a release-readiness checklist. Verify installed wheels in CI and link the public wiki. Keep runtime behavior unchanged; tagging and publication remain separate approval steps. --- .github/workflows/checks.yml | 25 ++++++++ CHANGELOG.md | 33 ++++++++++ LICENSE | 21 ++++++ MANIFEST.in | 4 ++ README.md | 11 +++- docs/release-v0.1.0.md | 121 +++++++++++++++++++++++++++++++++++ pyproject.toml | 11 +++- uv.lock | 2 +- 8 files changed, 224 insertions(+), 4 deletions(-) create mode 100644 CHANGELOG.md create mode 100644 LICENSE create mode 100644 docs/release-v0.1.0.md diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 3e16a7f..b2f2b29 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -40,3 +40,28 @@ jobs: uv run --offline watchpost compare examples/baseline.xml examples/after.xml \ --confirm-same-context --output "$output_dir/report.md" diff -u examples/report.md "$output_dir/report.md" + - name: Build and smoke-test the installed wheel + run: | + uv build --out-dir "$RUNNER_TEMP/watchpost-dist" + uv venv "$RUNNER_TEMP/watchpost-wheel" --python "${{ matrix.python-version }}" + uv pip install --python "$RUNNER_TEMP/watchpost-wheel/bin/python" \ + "$RUNNER_TEMP/watchpost-dist/"*.whl + cd "$RUNNER_TEMP" + "$RUNNER_TEMP/watchpost-wheel/bin/python" -I - <<'PY' + import os + import tomllib + from importlib.metadata import metadata + from pathlib import Path + + expected = tomllib.loads( + (Path(os.environ["GITHUB_WORKSPACE"]) / "pyproject.toml").read_text() + )["project"] + installed = metadata("watchpost") + assert installed["Version"] == expected["version"] + assert installed["License-Expression"] == expected["license"] + PY + "$RUNNER_TEMP/watchpost-wheel/bin/watchpost" inspect \ + "$GITHUB_WORKSPACE/examples/baseline.xml" + "$RUNNER_TEMP/watchpost-wheel/bin/watchpost" compare \ + "$GITHUB_WORKSPACE/examples/baseline.xml" "$GITHUB_WORKSPACE/examples/after.xml" \ + --confirm-same-context --output "$RUNNER_TEMP/wheel-report.md" diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..77db50e --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,33 @@ +# Changelog + +## 0.1.0 — prepared, not yet released + +Initial release candidate for local-first review of saved Nmap XML. +This entry describes the proposed v0.1.0 release, not an existing tag or registry publication. + +### Included + +- Inspect explicit IPv4/TCP observations in one saved scan. +- Compare completed TCP connect or SYN scans with matching Nmap versions and declared port coverage. +- Require human confirmation of scan location, intended targets, and remaining settings. +- Preserve missing observations as `not observed`, never assumed closed. +- Generate deterministic Markdown reports with evidence, limitations, suggested checks, and blank review fields. +- Protect existing report files and notes with non-replacing output. +- Reject unsafe XML, unsupported inputs, incompatible scans, and reported host timeouts. +- Provide three synthetic walkthroughs and a [user wiki](https://github.com/ejames-dev/watchpost/wiki). +- Distribute Watchpost under the MIT license. + +### Boundaries + +Python 3.11+ on Linux or Ubuntu WSL. CI covers Python 3.11, 3.12, and 3.13. +Inputs are limited to 10 MiB per snapshot. Report output requires a trusted directory with hard-link support. +Watchpost does not scan, upload data, or make runtime network calls. +It does not infer device/application identity or declare a network secure or compromised. + +No live scanning, scheduling, dashboard, packet capture, UDP/IPv6 support, AI verdicts, or automatic remediation. + +### Verification + +See [the release-readiness checklist](docs/release-v0.1.0.md). +The package version alone does not prove publication. +Published releases, when available, appear on [GitHub Releases](https://github.com/ejames-dev/watchpost/releases). diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..5fc95a5 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 Evan Newman + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/MANIFEST.in b/MANIFEST.in index e365a12..aa68622 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,3 +1,6 @@ +include LICENSE +include CHANGELOG.md +include uv.lock include examples/baseline.xml include examples/after.xml include examples/incomplete.xml @@ -6,3 +9,4 @@ include docs/brief-v0.1.md include docs/compare-milestone.md include docs/reporting-milestone.md include docs/scenarios.md +include docs/release-v0.1.0.md diff --git a/README.md b/README.md index 8685b59..e10136e 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,11 @@ Local-first, evidence-backed reviews of changes between saved Nmap scans. **Status: inspection, comparison, Markdown reporting, and synthetic walkthroughs implemented.** Two saved XML files can produce a change-review report. The [three walkthroughs](docs/scenarios.md) cover expected deployment, unintended backend exposure, and an incomplete scan. -The package remains a development build (`0.1.0.dev0`), not a tagged v0.1 release. +**v0.1.0 is prepared for release, not yet tagged or published.** +See the [release notes](CHANGELOG.md) and [release-readiness checklist](docs/release-v0.1.0.md). + +**[User wiki](https://github.com/ejames-dev/watchpost/wiki)** — setup, report interpretation, +scenarios, troubleshooting, and safety. ## Scope @@ -176,6 +180,11 @@ The tests use the standard library's `unittest`. Pytest is an optional developme - IP addresses are not device identities. Port numbers are not application identities. - An observed change does not prove vulnerability or compromise. +## License + +Watchpost is licensed under the [MIT License](LICENSE). +Third-party dependencies retain their own licenses. + ## Roadmap - [x] Safely inspect one saved IPv4/TCP scan. diff --git a/docs/release-v0.1.0.md b/docs/release-v0.1.0.md new file mode 100644 index 0000000..3d1fd5d --- /dev/null +++ b/docs/release-v0.1.0.md @@ -0,0 +1,121 @@ +# v0.1.0 release readiness + +Status: local release-readiness checks passed on 2026-10-03. PR review and CI remain required. +No release tag or registry publication is authorized by this checklist. +The package metadata targets `0.1.0`. That value alone does not mean a release exists. + +## Scope and evidence + +The [approved brief](brief-v0.1.md) defines the release scope. +The [changelog](../CHANGELOG.md) describes the proposed release. + +| Requirement | Evidence in the repository | +|---|---| +| Offline report from saved XML | README report command, `examples/report.md`, CLI report tests | +| No-change result without a safety verdict | Identical/unchanged comparison and report tests | +| Explicit changes and newly observed ports | Comparison and report tests for both categories | +| Missing evidence never becomes closure | Missing/grouped observation tests | +| Invalid/incompatible inputs fail clearly | XML, metadata, scan-window, completion, and timeout tests | +| Three documented scenarios | `docs/scenarios.md`, `examples/incomplete.xml` | +| Repeatable findings | Deterministic output and sample-report equality tests | +| Existing reports and notes stay intact | Existing destination, symlink, race, and I/O-failure tests | + +## Preparation changes + +- Set package version to `0.1.0` and update the lockfile. +- Add the user-selected MIT license and package license metadata. +- Require Setuptools 77.0.3 or newer for modern license metadata. +- Include the license, changelog, lockfile, and release checklist in the source archive. +- Add repository, documentation, and issue links to package metadata. +- Add an installed-wheel build/smoke check to the existing Python CI matrix. +- Link the public GitHub wiki from the README. + +No runtime behavior or runtime dependencies change in this preparation step. +The build-tool minimum changes, but dependency installation remains separate from offline application use. + +## Verification commands + +From the repository root: + +```bash +uv sync --locked --dev --python 3.11 +uv run --offline python -m unittest discover -s tests -v +uv run --offline pytest +uv run --offline ruff format --check . +uv run --offline ruff check . +``` + +Repeat the unittest suite on Python 3.12 and 3.13: + +```bash +uv run --offline --isolated --python 3.12 python -m unittest discover -s tests -v +uv run --offline --isolated --python 3.13 python -m unittest discover -s tests -v +``` + +Build fresh artifacts in a new temporary directory: + +```bash +build_dir="$(mktemp -d)" +uv build --out-dir "$build_dir" +``` + +Before release, inspect both archives for version/license metadata and unexpected files. +The source archive must contain the synthetic examples, tests, docs, license, changelog, and lockfile. +It must not contain `scans/`, `reports/`, credentials, or local environment files. +Install the wheel in a fresh environment outside the checkout. +Check help, inspection, comparison, report creation, rejected inputs, and preservation of existing notes. +Run the tests from an extracted source archive as well. + +The CI build step checks installed version/license metadata and runs the wheel outside the source checkout. +Build and dependency installation can use the network. Watchpost must not use it at runtime. + +## Audit status + +Local results on 2026-10-03: + +| Check | Result | +|---|---| +| Unittest suite | 50 tests passed on Python 3.11, 3.12, and 3.13 | +| Pytest | 50 tests and 125 subtests passed | +| Ruff format and lint | Passed | +| Locked dependency installation | Passed in the checkout and extracted source archive | +| Source archive and wheel | Built successfully, version `0.1.0`, MIT license present | +| Archive contents | Required docs/examples/tests/lock present, no private data directories | +| Extracted source archive | All 50 tests passed | +| Installed wheel outside checkout | Help, invalid arguments, inspect, compare, and report checks passed | +| Report safety | Sample bytes matched, existing notes preserved, timeout created no report | +| Offline behavior | Installed-code comparison passed with network entry points disabled | +| New CI shell step | Executed locally without modification except the Python matrix value | +| Package consistency | `uv pip check` passed for the installed wheel environment | +| Dependency advisory check | No known vulnerabilities reported for seven locked Linux runtime/dev dependencies | +| Self-review | No release-blocking correctness, security, performance, or clarity findings identified | + +The advisory check used `pip-audit` with the PyPI service and made no dependency changes. +It sent package names and versions, not scan data. It does not cover every build tool or platform-specific dependency. +To repeat that separate, network-enabled maintenance check: + +```bash +audit_dir="$(mktemp -d)" +uv export --locked --offline --no-emit-project --format requirements-txt \ + --output-file "$audit_dir/requirements.txt" +uvx pip-audit --disable-pip --require-hashes --progress-spinner off \ + --requirement "$audit_dir/requirements.txt" +``` + +The self-review covered XML parsing, evidence interpretation, report-path escaping, non-replacing output, and package boundaries. +The runtime modules are unchanged by release preparation. +Independent reviewer tools were unavailable. This is not a comprehensive independent security audit or a guarantee of safety. + +## Before tagging or publishing + +1. Review and merge the release-preparation PR through the normal repository workflow. +2. Wait for successful post-merge CI and sync a clean local `main`. +3. Obtain explicit approval for the release tag and publication destination. +4. Update release-status text with the actual release date and state. +5. Rebuild and verify artifacts from the exact approved release commit. +6. Create and verify the signed `v0.1.0` tag only after approval. +7. Publish the approved release notes and artifacts, then confirm the public result. +8. Update the wiki's status to match the published release. + +Do not reuse artifacts built before the final commit. +No PyPI upload is part of this preparation. A registry release needs separate authorization and name/ownership checks. diff --git a/pyproject.toml b/pyproject.toml index ab0beee..29992bb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,15 +1,22 @@ [build-system] -requires = ["setuptools>=68"] +requires = ["setuptools>=77.0.3"] build-backend = "setuptools.build_meta" [project] name = "watchpost" -version = "0.1.0.dev0" +version = "0.1.0" description = "Local-first, evidence-backed reviews of changes between saved Nmap scans." readme = "README.md" +license = "MIT" +license-files = ["LICENSE"] requires-python = ">=3.11" dependencies = ["defusedxml>=0.7.1,<0.8"] +[project.urls] +Repository = "https://github.com/ejames-dev/watchpost" +Documentation = "https://github.com/ejames-dev/watchpost/wiki" +Issues = "https://github.com/ejames-dev/watchpost/issues" + [project.scripts] watchpost = "watchpost:main" diff --git a/uv.lock b/uv.lock index 3dcecf5..26f9543 100644 --- a/uv.lock +++ b/uv.lock @@ -99,7 +99,7 @@ wheels = [ [[package]] name = "watchpost" -version = "0.1.0.dev0" +version = "0.1.0" source = { editable = "." } dependencies = [ { name = "defusedxml" },