From e50f9cbdde7053b87c8128d2de649e02da356286 Mon Sep 17 00:00:00 2001 From: 0xFantomMenace <93462858+0xFantomMenace@users.noreply.github.com> Date: Wed, 23 Sep 2026 02:34:49 +0000 Subject: [PATCH] Scope the sdist and wheel to the package The wheel was scoped to the oxarchive package but the sdist had no list, so the build backend packaged every non-ignored file in the directory. Both targets now include only the package's Python sources plus the readme, changelog, licence and project file. A CI job plants untracked files and fails unless every packaged file is tracked source or build metadata. Agent working directories are ignored. --- .github/workflows/package-contents.yml | 43 ++++++++++++++++++++++++++ .gitignore | 4 +++ pyproject.toml | 13 ++++++++ 3 files changed, 60 insertions(+) create mode 100644 .github/workflows/package-contents.yml diff --git a/.github/workflows/package-contents.yml b/.github/workflows/package-contents.yml new file mode 100644 index 0000000..99d4e98 --- /dev/null +++ b/.github/workflows/package-contents.yml @@ -0,0 +1,43 @@ +name: Package contents + +# Plants untracked files in the tree, builds the sdist and the wheel, and fails +# unless every file in them is a tracked source file or metadata the build +# backend generates. The check is an allowlist on purpose: anything else fails. +on: + pull_request: + push: + branches: [master, main] + +jobs: + package-scope: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.11' + - run: pip install build + - name: Plant untracked files that must not be packaged + run: | + mkdir -p .claude/worktrees/probe && echo stray > .claude/worktrees/probe/stray.rs + echo stray > oxarchive/stray.txt + mkdir -p oxarchive/.claude && echo stray > oxarchive/.claude/stray.py + - run: python -m build --outdir dist-check + - name: Every packaged file is tracked source or build metadata + run: | + set -euo pipefail + git ls-files > /tmp/tracked.txt + python - <<'PY' + import glob, sys, tarfile, zipfile + tracked = set(open("/tmp/tracked.txt").read().split()) + sdist = tarfile.open(glob.glob("dist-check/*.tar.gz")[0]) + sdist_files = {m.name.split("/", 1)[1] for m in sdist.getmembers() if m.isfile()} + wheel_files = set(zipfile.ZipFile(glob.glob("dist-check/*.whl")[0]).namelist()) + bad = sorted(f for f in sdist_files if f not in tracked and f != "PKG-INFO") + bad += sorted(f for f in wheel_files + if f not in tracked and ".dist-info/" not in f) + print("sdist:", len(sdist_files), "files; wheel:", len(wheel_files), "files") + if not any(f.startswith("oxarchive/") for f in wheel_files): + sys.exit("::error::the wheel has no oxarchive package") + sys.exit(f"::error::unexpected packaged files: {bad}" if bad else 0) + PY diff --git a/.gitignore b/.gitignore index def72e1..4b1ffad 100644 --- a/.gitignore +++ b/.gitignore @@ -77,3 +77,7 @@ dmypy.json # OS .DS_Store Thumbs.db + +# Agent working directories. Not source, never packaged. +.claude/ +.codex/ diff --git a/pyproject.toml b/pyproject.toml index f4fef5b..92737d3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,6 +54,19 @@ Issues = "https://github.com/0xArchiveIO/sdk-python/issues" [tool.hatch.build.targets.wheel] packages = ["oxarchive"] +include = ["/oxarchive/**/*.py"] + +# The sdist needs its own list: without one, hatchling packages every +# non-ignored file in the directory. List what ships instead of trusting the +# default. +[tool.hatch.build.targets.sdist] +include = [ + "/oxarchive/**/*.py", + "/README.md", + "/CHANGELOG.md", + "/LICENSE", + "/pyproject.toml", +] [tool.ruff] line-length = 100