From d0feb5d6524739b4895d9fa3718c7830370e6825 Mon Sep 17 00:00:00 2001 From: Kayode Bristol Date: Mon, 31 Aug 2026 13:15:20 -0700 Subject: [PATCH 1/3] chore: standardize BUSL licensing metadata --- LICENSE | 6 ------ README.md | 8 ++++++-- pyproject.toml | 5 +++-- tests/test_licensing_metadata.py | 19 +++++++++++++++++++ 4 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 tests/test_licensing_metadata.py diff --git a/LICENSE b/LICENSE index d9d55eb..85e9e58 100644 --- a/LICENSE +++ b/LICENSE @@ -1,8 +1,5 @@ Business Source License 1.1 -Dual License Notice: This project is dual-licensed under BSL-1.1 (this file) -and MIT (LICENSE-MIT). You may choose either license at your option. - Parameters Licensor: Plures @@ -22,9 +19,6 @@ Notice Business Source License 1.1 -Dual License Notice: This project is dual-licensed under BSL-1.1 (this file) -and MIT (LICENSE-MIT). You may choose either license at your option. - Terms The Licensor hereby grants you the right to copy, modify, create derivative diff --git a/README.md b/README.md index 7406511..787e0c0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Version](https://img.shields.io/github/v/release/plures/netops-toolkit?display_name=tag&sort=semver)](https://github.com/plures/netops-toolkit/releases) [![Python](https://img.shields.io/badge/python-3.9%2B-blue.svg)](https://www.python.org/downloads/) -[![License: BSL-1.1](https://img.shields.io/badge/License-BSL--1.1-blue.svg)](LICENSE) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE-MIT) +[![License: BUSL-1.1](https://img.shields.io/badge/License-BUSL--1.1-blue.svg)](LICENSE) [![CI](https://github.com/plures/netops-toolkit/actions/workflows/release.yml/badge.svg)](https://github.com/plures/netops-toolkit/actions/workflows/release.yml) [![interrogate](https://img.shields.io/badge/interrogate-100%25-brightgreen.svg)](https://interrogate.readthedocs.io) [![docs](https://img.shields.io/badge/docs-mkdocs-blue.svg)](https://plures.io/netops-toolkit/) @@ -249,4 +249,8 @@ require their corresponding extras. ## License -See [LICENSE](LICENSE). +netops-toolkit is source-available under the [Business Source License 1.1](LICENSE). +Personal and non-commercial use is permitted under its Additional Use Grant; +production use requires a commercial license from Plures. Each released version +changes to Apache License 2.0 no later than four years after its first public +distribution. For commercial terms, contact `licensing@plures.io`. diff --git a/pyproject.toml b/pyproject.toml index d7e8098..1dc6a76 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=68.0"] +requires = ["setuptools>=77.0"] build-backend = "setuptools.build_meta" [project] @@ -7,7 +7,8 @@ name = "netops-toolkit" version = "0.52.1" description = "Modular network automation utilities for telco operations" requires-python = ">=3.9" -license = {text = "MIT"} +license = "BUSL-1.1" +license-files = ["LICENSE"] dependencies = [ "netmiko>=4.3.0,<4.5.0", diff --git a/tests/test_licensing_metadata.py b/tests/test_licensing_metadata.py new file mode 100644 index 0000000..2472554 --- /dev/null +++ b/tests/test_licensing_metadata.py @@ -0,0 +1,19 @@ +"""Regression checks for the single, source-available licensing declaration.""" + +from pathlib import Path + +REPOSITORY_ROOT = Path(__file__).resolve().parents[1] + + +def test_public_license_surfaces_consistently_declare_busl() -> None: + """Distribution metadata, license text, and README cannot drift into dual licensing.""" + license_text = (REPOSITORY_ROOT / "LICENSE").read_text(encoding="utf-8") + package_metadata = (REPOSITORY_ROOT / "pyproject.toml").read_text(encoding="utf-8") + readme = (REPOSITORY_ROOT / "README.md").read_text(encoding="utf-8") + + assert "Business Source License 1.1" in license_text + assert "Dual License Notice" not in license_text + assert 'license = "BUSL-1.1"' in package_metadata + assert 'license-files = ["LICENSE"]' in package_metadata + assert "LICENSE-MIT" not in readme + assert "BUSL--1.1" in readme From 64e9c56666844cb9ebf97689a793bc7574d316aa Mon Sep 17 00:00:00 2001 From: Kayode Bristol <3579196+kayodebristol@users.noreply.github.com> Date: Mon, 31 Aug 2026 13:35:21 -0700 Subject: [PATCH 2/3] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 787e0c0..fcb60e2 100644 --- a/README.md +++ b/README.md @@ -251,6 +251,6 @@ require their corresponding extras. netops-toolkit is source-available under the [Business Source License 1.1](LICENSE). Personal and non-commercial use is permitted under its Additional Use Grant; -production use requires a commercial license from Plures. Each released version +production use outside that grant requires a commercial license from Plures. Each released version changes to Apache License 2.0 no later than four years after its first public distribution. For commercial terms, contact `licensing@plures.io`. From 2d60169d67b006043d4555c9969c89652c05bf85 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 31 Aug 2026 20:37:21 +0000 Subject: [PATCH 3/3] fix: align ansible role license surfaces with BUSL Co-authored-by: kayodebristol <3579196+kayodebristol@users.noreply.github.com> --- netops/ansible/roles/netops_acl/README.md | 2 +- netops/ansible/roles/netops_acl/meta/main.yml | 2 +- netops/ansible/roles/netops_backup/README.md | 2 +- netops/ansible/roles/netops_backup/meta/main.yml | 2 +- netops/ansible/roles/netops_health/README.md | 2 +- netops/ansible/roles/netops_health/meta/main.yml | 2 +- netops/ansible/roles/netops_ntp/README.md | 2 +- netops/ansible/roles/netops_ntp/meta/main.yml | 2 +- netops/ansible/roles/netops_update/README.md | 2 +- netops/ansible/roles/netops_update/meta/main.yml | 2 +- tests/test_ansible_roles.py | 4 ++-- tests/test_licensing_metadata.py | 9 ++++++++- 12 files changed, 20 insertions(+), 13 deletions(-) diff --git a/netops/ansible/roles/netops_acl/README.md b/netops/ansible/roles/netops_acl/README.md index 44caa5b..2d2310a 100644 --- a/netops/ansible/roles/netops_acl/README.md +++ b/netops/ansible/roles/netops_acl/README.md @@ -82,4 +82,4 @@ molecule test ## License -MIT +BUSL-1.1 diff --git a/netops/ansible/roles/netops_acl/meta/main.yml b/netops/ansible/roles/netops_acl/meta/main.yml index 600e25f..19d3fbd 100644 --- a/netops/ansible/roles/netops_acl/meta/main.yml +++ b/netops/ansible/roles/netops_acl/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: Deploy Access Control Lists to network devices with an optional diff preview and safety checks to prevent unintentional ACL removal. company: "" - license: MIT + license: BUSL-1.1 min_ansible_version: "2.16" platforms: - name: all diff --git a/netops/ansible/roles/netops_backup/README.md b/netops/ansible/roles/netops_backup/README.md index d42e699..262ed9b 100644 --- a/netops/ansible/roles/netops_backup/README.md +++ b/netops/ansible/roles/netops_backup/README.md @@ -49,4 +49,4 @@ molecule test ## License -MIT +BUSL-1.1 diff --git a/netops/ansible/roles/netops_backup/meta/main.yml b/netops/ansible/roles/netops_backup/meta/main.yml index d01b566..9e7b1ac 100644 --- a/netops/ansible/roles/netops_backup/meta/main.yml +++ b/netops/ansible/roles/netops_backup/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: Back up the running configuration of network devices and enforce a configurable retention policy on the Ansible control node. company: "" - license: MIT + license: BUSL-1.1 min_ansible_version: "2.16" platforms: - name: all diff --git a/netops/ansible/roles/netops_health/README.md b/netops/ansible/roles/netops_health/README.md index 2b03224..9922ae6 100644 --- a/netops/ansible/roles/netops_health/README.md +++ b/netops/ansible/roles/netops_health/README.md @@ -55,4 +55,4 @@ molecule test ## License -MIT +BUSL-1.1 diff --git a/netops/ansible/roles/netops_health/meta/main.yml b/netops/ansible/roles/netops_health/meta/main.yml index 47d0be6..82bfbe3 100644 --- a/netops/ansible/roles/netops_health/meta/main.yml +++ b/netops/ansible/roles/netops_health/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: Run health checks (CPU, memory, interfaces, BGP, OSPF) against network devices and fail the play on any CRITICAL finding. company: "" - license: MIT + license: BUSL-1.1 min_ansible_version: "2.16" platforms: - name: all diff --git a/netops/ansible/roles/netops_ntp/README.md b/netops/ansible/roles/netops_ntp/README.md index d2d9887..ec6fd86 100644 --- a/netops/ansible/roles/netops_ntp/README.md +++ b/netops/ansible/roles/netops_ntp/README.md @@ -75,4 +75,4 @@ molecule test ## License -MIT +BUSL-1.1 diff --git a/netops/ansible/roles/netops_ntp/meta/main.yml b/netops/ansible/roles/netops_ntp/meta/main.yml index 6a8463a..4a79e88 100644 --- a/netops/ansible/roles/netops_ntp/meta/main.yml +++ b/netops/ansible/roles/netops_ntp/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: Standardise NTP configuration on network devices: add/remove servers, configure authentication keys and timezone, and validate synchronisation. company: "" - license: MIT + license: BUSL-1.1 min_ansible_version: "2.16" platforms: - name: all diff --git a/netops/ansible/roles/netops_update/README.md b/netops/ansible/roles/netops_update/README.md index a17fb76..2cc5346 100644 --- a/netops/ansible/roles/netops_update/README.md +++ b/netops/ansible/roles/netops_update/README.md @@ -57,4 +57,4 @@ molecule test ## License -MIT +BUSL-1.1 diff --git a/netops/ansible/roles/netops_update/meta/main.yml b/netops/ansible/roles/netops_update/meta/main.yml index 7689b45..6cb7320 100644 --- a/netops/ansible/roles/netops_update/meta/main.yml +++ b/netops/ansible/roles/netops_update/meta/main.yml @@ -8,7 +8,7 @@ galaxy_info: Upgrade the OS of network devices with pre/post validation and automatic rollback on failure. company: "" - license: MIT + license: BUSL-1.1 min_ansible_version: "2.16" platforms: - name: all diff --git a/tests/test_ansible_roles.py b/tests/test_ansible_roles.py index c83cac0..4588d00 100644 --- a/tests/test_ansible_roles.py +++ b/tests/test_ansible_roles.py @@ -102,9 +102,9 @@ def test_galaxy_meta_role_name_matches(role: str) -> None: @pytest.mark.parametrize("role", ROLE_NAMES) -def test_galaxy_meta_license_is_mit(role: str) -> None: +def test_galaxy_meta_license_is_busl(role: str) -> None: meta = _load_yaml(ROLES_ROOT / role / "meta/main.yml") - assert meta["galaxy_info"]["license"] == "MIT", f"{role}/meta/main.yml license should be MIT" + assert meta["galaxy_info"]["license"] == "BUSL-1.1", f"{role}/meta/main.yml license should be BUSL-1.1" # --------------------------------------------------------------------------- diff --git a/tests/test_licensing_metadata.py b/tests/test_licensing_metadata.py index 2472554..d03680f 100644 --- a/tests/test_licensing_metadata.py +++ b/tests/test_licensing_metadata.py @@ -16,4 +16,11 @@ def test_public_license_surfaces_consistently_declare_busl() -> None: assert 'license = "BUSL-1.1"' in package_metadata assert 'license-files = ["LICENSE"]' in package_metadata assert "LICENSE-MIT" not in readme - assert "BUSL--1.1" in readme + assert "BUSL-1.1" in readme + + for role in ("netops_acl", "netops_backup", "netops_health", "netops_ntp", "netops_update"): + role_meta = REPOSITORY_ROOT / "netops" / "ansible" / "roles" / role / "meta" / "main.yml" + role_readme = REPOSITORY_ROOT / "netops" / "ansible" / "roles" / role / "README.md" + + assert 'license: BUSL-1.1' in role_meta.read_text(encoding="utf-8") + assert "BUSL-1.1" in role_readme.read_text(encoding="utf-8")