Skip to content

feat(goals#4): switch web panel licence to Elastic License 2.0#1465

Merged
rumblefrog merged 1 commit into
mainfrom
license-elastic
May 26, 2026
Merged

feat(goals#4): switch web panel licence to Elastic License 2.0#1465
rumblefrog merged 1 commit into
mainfrom
license-elastic

Conversation

@rumblefrog

Copy link
Copy Markdown
Member

Summary

  • Web panel relicensed from CC BY-NC-SA 3.0 to Elastic License 2.0 (source-available; self-hosting stays free, only third-party managed-service hosting is reserved). Bundled SourceMod plugins continue under GPLv3, unchanged.
  • Single source of truth: LICENSE.txt (ELv2) + LICENSE-plugins.txt (GPLv3). Headers across the panel (web/) updated to the 4-line v2.0 shape; install wizard step 1 surfaces both licences with concrete negative examples of what "managed service to third parties" means; release artifacts + production Docker image bundle the right files in the right places.
  • Legal basis: CLA §3(b) relicense grant + the sbpp/goals#3 pre-CLA contributor audit (every pre-CLA web/** contribution of substance was @rumblefrog's).

Why this licence, why now

The previous CC BY-NC-SA 3.0 licence had two problems:

  1. Wrong scope. The non-commercial restriction applied too broadly — it technically blocked legitimate community use by paid esports orgs, paid clans, and anyone paying for hosting. The actual rivalrous edge the project wants to reserve is much narrower: reselling the panel as a hosted/managed service to third parties (the "SourceBans++-as-a-feature" upsell from a game-server hosting business).
  2. Wrong tool. Creative Commons explicitly warns against using CC licences for software (CC's own FAQ).

ELv2 is the source-available standard that's converged across the industry for exactly this shape (Elasticsearch, MongoDB, Redis, Sentry, Codeium, …). It explicitly:

  • ✅ Allows free self-hosting (clans, esports orgs, communities, individual gameservers).
  • ✅ Allows commercial use of the panel for your own infrastructure (paid hosting customers running their own panel = fine).
  • ✅ Keeps full source code available and modifiable.
  • ❌ Reserves the right to operate the panel as a managed service to third parties.

Bundled SourceMod plugins (game/addons/sourcemod/) stay GPLv3 — copyleft is the right shape for runtime add-ons to SourceMod, and split-licensing is the established pattern for Sentry, MongoDB, Elasticsearch, etc.

What changed

Top-level license files

  • LICENSE.txt (new) — ELv2 verbatim text. LICENSE.md deleted (superseded).
  • LICENSE-plugins.txt (new) — GPLv3 verbatim text.
  • .github/GPLv3 + .github/SOURCEMOD-LICENSE.txt deleted — the GPL text moved to LICENSE-plugins.txt, the AlliedModders SourceMod link-exception notice consolidated into THIRD-PARTY-NOTICES.txt §6.

Web panel source headers

  • Every file under web/ that previously carried the legacy CC BY-NC-SA 3.0 (or pre-CLA 17-line GPLv3) header now carries the new 4-line ELv2 header. The sweep is "replace existing license headers", not "add headers universally" — files added during the v2.0 rewrite without a header keep their no-header state to bound git-blame churn.

Install wizard

Composer

  • web/composer.json: license: "Elastic-2.0" (SPDX). Stale version field removed (not standard for type: project). readme URL updated from v1.x to main.

Release workflow (.github/workflows/release.yml)

  • Webpanel zip bundles both LICENSE.txt AND LICENSE-plugins.txt at the install root (matches the install wizard's promise that both are shipped).
  • Plugin tarball renames LICENSE-plugins.txt to LICENSE.txt per GPLv3 §4/§5 convention and also bundles THIRD-PARTY-NOTICES.txt for the SourceMod link-exception notice.
  • CI smoke checks updated to verify the bundled files in each artifact.

Production Docker image (docker/Dockerfile.prod + .github/workflows/docker-image.yml)

  • Runtime image ships LICENSE.txt + LICENSE-plugins.txt + THIRD-PARTY-NOTICES.txt at /var/www/html/ (outside the Apache DocumentRoot /var/www/html/web/, so they're never HTTP-reachable but accessible via docker exec/docker cp for the ELv2 "Notices" obligation).
  • OCI label org.opencontainers.image.licenses set to Elastic-2.0 (the image only bundles the web panel; plugins ship via the separate tarball).

Docs

  • docs/src/content/docs/{index,faq/index,sponsor}.mdx — updated to use "source-available" rather than "open source" (ELv2 doesn't meet the OSI open-source definition; the project intentionally took a source-available shape per the rationale above).
  • docs/src/content/docs/updating/1-8-to-2-0.mdx — new "Licence change" section walks operators through the implication of the relicense for the four common use cases (self-hosted community panel / paid hosting customer running their own panel / managed-service-to-third-parties / commercial licence inquiry path).
  • docs/src/content/docs/getting-started/quickstart.mdx — license-acceptance step text matches the wizard's current UI literally (chrome drift cleanup).
  • Commercial-licensing contact path pinned to the GitHub Discussions "Commercial licensing" category + a DM to @rumblefrog on Discord (dedicated inbox is on the roadmap).

Root docs

  • README.md, CONTRIBUTING.md, THIRD-PARTY-NOTICES.txt, ARCHITECTURE.md, CHANGELOG.md v2.0.0 callout — all updated to reference ELv2 (web panel) + GPLv3 (plugins) consistently.
  • CLA.md §10 — new "Pre-CLA contribution history" subsection documenting the sbpp/goals#3 audit findings and how they enable the ELv2 relicense.
  • AGENTS.md — per-file-header anti-pattern entry refreshed for the new 4-line shape; CLA gate historical-contributor note updated to reference the goals#3 audit.

API contract

  • web/scripts/api-contract.js regenerated with the ELv2 header propagated through web/bin/generate-api-contract.php (the autogenerator). Byte-stable across re-runs.

Legal basis

The relicense rides two parallel paths:

  1. CLA §3(b)'s explicit relicense grant — every contributor who signed the CLA explicitly granted the project the right to relicense their contributions under any terms, including ELv2. This covers all post-CLA-workflow contributions.
  2. The sbpp/goals#3 pre-CLA contributor audit — every pre-CLA web/** contribution of substance was authored by the project maintainer (@rumblefrog), who as the licensor under ELv2 doesn't need a separate grant from himself. Small one-off external PRs from before the CLA workflow either:
    • Survived intact through the v2.0 panel rewrite — covered by §3(b) going forward (their authors are listed on goals#3, retroactive sign-off is a low-priority follow-up, not on the critical path).
    • Were removed during the v2.0 rewrite (goals#5 Route B rewrites) — question moot.

Future inbound PRs continue to ride the established CLA workflow (see .github/workflows/cla.yml + CLA.md).

Test plan

  • PHPStan: clean (2 pre-existing baseline mismatches on main unrelated to this PR — Auth/JWT.php base64Encoded pattern + updater/data/600.php str_replace pattern, both also present on main HEAD).
  • PHPUnit integration suite: 595 tests / 1888 assertions, all green.
  • PHPUnit api suite: 356 tests / 1511 assertions, all green.
  • ts-check: green.
  • api-contract regen: byte-stable across re-runs.
  • Manual smoke: walk the install wizard end-to-end on a fresh DB; verify step 1 chrome reads cleanly, the accept-checkbox gates the Continue button, both licence summaries match the linked LICENSE.txt / LICENSE-plugins.txt files.
  • Manual smoke: build the release artifacts locally (./sbpp.sh doesn't expose the release script; build manually with the workflow's commands), unzip the webpanel zip + plugin tarball, verify both carry the right licence files at the right paths per the smoke-check assertions in .github/workflows/release.yml.
  • Manual smoke: docker buildx build -f docker/Dockerfile.prod . (locally; the docker-image gate is release-tag-only per AGENTS.md's "Prod Docker image specifics"). Verify docker run --rm <image> cat /var/www/html/LICENSE.txt returns ELv2 text and the OCI labels list Elastic-2.0.

Refs

  • sbpp/goals#3 — pre-CLA contributor audit (prerequisite).
  • sbpp/goals#4 — this relicense (tracking issue).
  • sbpp/goals#5 — v2.0 panel rewrite (established the post-rewrite authorship baseline).

The web panel is now licensed under the Elastic License 2.0 (ELv2).
The bundled SourceMod plugins continue to ship under GPLv3 — that
half is unchanged and stays in `LICENSE-plugins.txt`. The split is
intentional: the panel is a server-side product where the rivalrous
edge is reselling it as a hosted service, which ELv2 reserves; the
plugins are SourceMod-runtime add-ons where copyleft (no commercial
restriction) is the right shape for the ecosystem.

Why: ELv2 keeps the panel free for community use (self-hosting your
own clan / network / community server fleet stays free, full source
remains available, no commercial restriction on operating the panel
yourself), while reserving the right to operate it as a managed
service to third parties — the classic "SourceBans++-as-a-feature"
upsell from a game-server hosting business. Self-hosters are
unaffected. The previous CC BY-NC-SA 3.0 licence had the
non-commercial restriction applied too broadly (it blocked legitimate
community use by paid clans / esports orgs / paid hosting customers
running their own panel) AND was not enforceable as a software
licence (CC explicitly warns against using CC licences for software).
ELv2 is the source-available standard the industry has converged on
for this exact use case (Elasticsearch, MongoDB, Redis, Sentry, etc.).

Legal basis: the relicense rides CLA §3(b)'s explicit relicense grant
plus the sbpp/goals#3 pre-CLA contributor audit, which established
that every pre-CLA `web/**` contribution of substance was authored
by the project maintainer (@rumblefrog). Small one-off external PRs
from before the CLA workflow either survived intact through the v2.0
panel rewrite (covered by §3(b) going forward) or were removed
during the v2.0 rewrite (question moot; goals#5 Route B rewrites).
Retroactive sign-off for the surviving-author set is an opt-in
follow-up, not on the critical path.

Scope:

- `LICENSE.txt` (new) — Elastic License 2.0 verbatim text.
- `LICENSE-plugins.txt` (new) — GPLv3 verbatim text, for the
  bundled SourceMod plugins.
- `LICENSE.md` (deleted) — superseded by `LICENSE.txt`.
- `.github/GPLv3` + `.github/SOURCEMOD-LICENSE.txt` (deleted) —
  the GPL text moved to `LICENSE-plugins.txt`; the AlliedModders
  SourceMod link-exception notice consolidated into
  `THIRD-PARTY-NOTICES.txt` §6.
- Web panel source headers (web/) — every file that previously
  carried the legacy CC BY-NC-SA 3.0 (or pre-CLA 17-line GPLv3)
  header now carries the new 4-line ELv2 header. Files added
  during the v2.0 rewrite without a header keep their no-header
  state — the sweep is "replace existing license headers", not
  "add headers universally", to keep git-blame churn bounded.
- Install wizard (`web/install/pages/page.1.php` +
  `web/themes/default/install/page_license.tpl`) — step 1
  surfaces both licences to operators with concrete negative
  examples of what "managed service to third parties" means
  under ELv2 (helps operators understand whether their use case
  is free or commercial).
- `web/composer.json` — `license` field set to `Elastic-2.0`
  (SPDX), stale `version` field removed (not standard for
  `type: project`), `readme` URL updated from `v1.x` to `main`.
- `web/scripts/api-contract.js` — regenerated with the ELv2
  header propagated through `web/bin/generate-api-contract.php`.
- Release workflow (`.github/workflows/release.yml`) — the
  webpanel zip bundles both `LICENSE.txt` AND `LICENSE-plugins.txt`
  (matches the install wizard's promise that both are shipped at
  the install root); the plugin tarball renames
  `LICENSE-plugins.txt` to `LICENSE.txt` per GPLv3 §4/§5
  convention and also bundles `THIRD-PARTY-NOTICES.txt` for the
  SourceMod link-exception notice. CI smoke checks updated to
  verify the bundled files.
- Production Docker image (`docker/Dockerfile.prod` +
  `.github/workflows/docker-image.yml`) — the runtime image
  ships `LICENSE.txt` + `LICENSE-plugins.txt` +
  `THIRD-PARTY-NOTICES.txt` at `/var/www/html/` (outside the
  Apache DocumentRoot `/var/www/html/web/`, so they're never
  HTTP-reachable but accessible via `docker exec`/`docker cp`
  for the ELv2 "Notices" obligation). OCI label
  `org.opencontainers.image.licenses` set to `Elastic-2.0`
  (the image only bundles the web panel; plugins ship via the
  separate tarball).
- Docs (`docs/src/content/docs/{index,faq/index,sponsor}.mdx`
  + the new "Licence change" section in
  `updating/1-8-to-2-0.mdx`) — updated to use "source-available"
  rather than "open source" (ELv2 doesn't meet the OSI
  open-source definition; the project intentionally took a
  source-available shape). Commercial licensing contact path
  pinned to the GitHub Discussions "Commercial licensing"
  category + a DM to @rumblefrog on Discord, with a dedicated
  inbox on the roadmap.
- Root docs (`README.md`, `CONTRIBUTING.md`, `CLA.md` §10
  audit note, `AGENTS.md` per-file-header anti-pattern entry
  + CLA gate historical-contributor note, `ARCHITECTURE.md`,
  `THIRD-PARTY-NOTICES.txt`, `CHANGELOG.md` v2.0.0 callout) —
  all updated to reference ELv2 (web panel) + GPLv3 (plugins)
  consistently.

Quality gates:

- PHPStan: clean (2 pre-existing baseline mismatches on main
  unrelated to this PR).
- PHPUnit integration: 595 tests / 1888 assertions, all green.
- PHPUnit api: 356 tests / 1511 assertions, all green.
- ts-check: green.
- api-contract: regenerated, byte-stable across re-runs.

Refs: sbpp/goals#3 (pre-CLA contributor audit), sbpp/goals#4
(this relicense), sbpp/goals#5 (v2.0 panel rewrite that
established the post-rewrite authorship baseline).
@rumblefrog
rumblefrog added this pull request to the merge queue May 26, 2026
Merged via the queue into main with commit e52d0ac May 26, 2026
7 checks passed
@rumblefrog
rumblefrog deleted the license-elastic branch May 26, 2026 16:39
@github-actions github-actions Bot locked and limited conversation to collaborators May 26, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant