diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 926fcbb..85c36e2 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -325,18 +325,18 @@ jobs: name: base-cli-release-metadata-${{ github.run_id }} path: dist - - name: Create or update GitHub Release + - name: Create GitHub Release env: GH_TOKEN: ${{ github.token }} run: | tag="$GITHUB_REF_NAME" assets=(dist/*.whl dist/*.tar.gz dist/SHA256SUMS dist/SBOM.spdx.json dist/RELEASE-BOM-ROW.json) if gh release view "$tag" --repo "$GITHUB_REPOSITORY" >/dev/null 2>&1; then - gh release upload "$tag" "${assets[@]}" --clobber --repo "$GITHUB_REPOSITORY" - else - gh release create "$tag" "${assets[@]}" \ - --repo "$GITHUB_REPOSITORY" \ - --title "$tag" \ - --generate-notes \ - --notes "Published distributions and release metadata for $tag. See CHANGELOG.md for the reviewed release notes." + echo "Published release $tag already exists; refusing to replace immutable release assets." >&2 + exit 1 fi + gh release create "$tag" "${assets[@]}" \ + --repo "$GITHUB_REPOSITORY" \ + --title "$tag" \ + --generate-notes \ + --notes "Published distributions and release metadata for $tag. See CHANGELOG.md for the reviewed release notes." diff --git a/README.md b/README.md index 0d0ae5a..23dc8dd 100644 --- a/README.md +++ b/README.md @@ -33,6 +33,8 @@ Compatibility results and the permissioned-adopter policy are documented in the [adoption and compatibility evidence guide](https://basefoundry.github.io/base-cli/adoption-evidence/). The [compatibility dashboard](https://basefoundry.github.io/base-cli/compatibility-dashboard/) shows the declared and CI-tested dependency and platform support boundaries. +The shared Base ecosystem boundary is maintained in the [Base ecosystem +platform, license, and release policy](https://github.com/basefoundry/base/blob/main/docs/ecosystem-policy.md). ## Quick start @@ -67,8 +69,10 @@ Release builds, TestPyPI rehearsals, and protected PyPI publication are documented in [`docs/releasing.md`](https://basefoundry.github.io/base-cli/releasing/). The package exposes `base_cli.__version__`, which matches the distribution version. -The package is distributed under the Apache License 2.0. Base itself remains -licensed separately under AGPL-3.0-or-later. +The package is distributed under the Apache License 2.0. Base is licensed under +Apache-2.0 starting with v1.9.0; earlier Base releases retain the license stated +in their release documentation. The two projects remain independently licensed +and independently released. `base_cli` is designed to be embedded by applications rather than to define an application's project model. Base is one consumer of the library, not part diff --git a/docs/platform-support.md b/docs/platform-support.md index ce0824e..89a314d 100644 --- a/docs/platform-support.md +++ b/docs/platform-support.md @@ -19,6 +19,11 @@ Native Windows support applies to the generic Python package. It does not make Base or `basectl` natively Windows-compatible; those consumers have their own Unix-tooling and shell boundaries. The package does not provide package-manager integration, shell startup management, or WSL/Windows path translation. +The coordinated Base release matrix is intentionally narrower: Base records +Ubuntu 24.04 and macOS 14 combinations in its release BOM. See the [Base +ecosystem platform, license, and release +policy](https://github.com/basefoundry/base/blob/main/docs/ecosystem-policy.md) +for the cross-repository boundary. Recursive invocation-temp content erasure requires descriptor-relative, no-follow directory operations. Linux, macOS, and WSL2 provide those diff --git a/docs/releasing.md b/docs/releasing.md index b3c2766..99f8c94 100644 --- a/docs/releasing.md +++ b/docs/releasing.md @@ -4,6 +4,11 @@ The `base-cli` distribution is built and published from the standalone `basefoundry/base-cli` repository. The package name on PyPI is `base-cli`; the Python import name is `base_cli`. +`base-cli` releases are independent of Base releases. The shared provider, +platform, license, and release-artifact rules are summarized in the [Base +ecosystem platform, license, and release +policy](https://github.com/basefoundry/base/blob/main/docs/ecosystem-policy.md). + ## Version and tag contract `VERSION` is the release version source of truth. The build backend reads it for @@ -44,8 +49,9 @@ the exact reviewed wheel, sdist, `SHA256SUMS`, `SBOM.spdx.json`, and `RELEASE-BOM-ROW.json` downloaded from the build job. GitHub-generated comparison notes are supplemented by the dated section in `CHANGELOG.md`; the tagged release is rejected when `VERSION` -or that section does not match the tag. Rerunning a tag updates an existing -release's assets with `--clobber` instead of creating a second release. +or that section does not match the tag. Published tags and release assets are +immutable. A rerun that finds an existing GitHub Release fails closed; +corrections require a new patch version. ## Independent verification diff --git a/tests/test_package_workflow.py b/tests/test_package_workflow.py index 1ffb200..47fc459 100644 --- a/tests/test_package_workflow.py +++ b/tests/test_package_workflow.py @@ -8,3 +8,11 @@ def test_package_workflow_uses_numeric_reproducibility_epoch() -> None: assert "github.event.head_commit.timestamp" not in workflow assert workflow.count("SOURCE_DATE_EPOCH: '0'") == 2 + + +def test_package_workflow_does_not_replace_published_release_assets() -> None: + workflow = (Path(__file__).resolve().parents[1] / ".github/workflows/package.yml").read_text(encoding="utf-8") + + assert "Create GitHub Release" in workflow + assert "refusing to replace immutable release assets" in workflow + assert "--clobber" not in workflow