diff --git a/.github/workflows/package-contents.yml b/.github/workflows/package-contents.yml new file mode 100644 index 0000000..8aa8ed9 --- /dev/null +++ b/.github/workflows/package-contents.yml @@ -0,0 +1,31 @@ +name: Package contents + +# The sdist once shipped an entire agent working directory because it had no +# include list and the build backend defaults to "everything not ignored". +# This fails the build if anything outside the package ever ships again. +on: + pull_request: + push: + branches: [master, main] + +jobs: + sdist-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 a stray directory the way an agent would + run: mkdir -p .claude/worktrees/probe && echo leak > .claude/worktrees/probe/leak.rs + - run: python -m build --sdist --outdir dist-check + - name: The sdist must contain only the package and its metadata + run: | + set -euo pipefail + tar tzf dist-check/*.tar.gz | sed 's|^[^/]*/||' | grep -v '^$' \ + | awk -F/ '{print $1}' | sort -u > /tmp/top.txt + echo "top-level entries in the sdist:"; cat /tmp/top.txt + if grep -qE '^\.claude|^\.codex|^backend|^crates|^migrations' /tmp/top.txt; then + echo "::error::the sdist contains files from outside the package"; exit 1 + fi diff --git a/.gitignore b/.gitignore index 06fed4f..3793469 100644 --- a/.gitignore +++ b/.gitignore @@ -76,3 +76,8 @@ dmypy.json # OS .DS_Store Thumbs.db + +# Agent working directories. These are not source and must never be packaged; +# an unscoped sdist published one to PyPI once already. +.claude/ +.codex/ diff --git a/pyproject.toml b/pyproject.toml index d2f4898..e194ad5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -55,6 +55,19 @@ Issues = "https://github.com/0xArchiveIO/sdk-python/issues" [tool.hatch.build.targets.wheel] packages = ["oxarchive"] +# The wheel is scoped to the package, but the sdist had no scope at all, so +# hatchling swept in every non-gitignored file in the directory. That published +# an agent working directory, and with it a copy of the private backend, inside +# oxarchive 1.8.0's sdist. List what ships instead of trusting the default. +[tool.hatch.build.targets.sdist] +include = [ + "/oxarchive", + "/README.md", + "/CHANGELOG.md", + "/LICENSE", + "/pyproject.toml", +] + [tool.ruff] line-length = 100 target-version = "py39"