diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index d81d7747f..00ffb2e0d 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,8 +1,13 @@ -## Contribution License +## Contribution Licensing (no CLA, inbound=outbound, DCO required) -By submitting this pull request, I represent that I have the right to contribute -the changes and agree that they are distributed under this repository's -[GNU Affero General Public License v3.0](../LICENSE). +This project does not use a CLA; contributions are accepted inbound=outbound. +By submitting this pull request I represent that I have the right to contribute +the changes, which are licensed under this repository's +[GNU Affero General Public License v3.0 or later](https://www.gnu.org/licenses/agpl-3.0.html) +and remain my copyright. Every commit must carry a DCO `Signed-off-by` trailer +(`git commit -s`) certifying the +[Developer Certificate of Origin](https://developercertificate.org/) — see +[CONTRIBUTING.md](https://github.com/pgsty/silo/blob/main/CONTRIBUTING.md). ## Description @@ -26,6 +31,7 @@ routes, storage metadata, module/import paths, upgrades, or rollback. --> - [ ] Breaking change (fix or feature that would cause existing functionality to change) ## Checklist: +- [ ] All commits are signed off (`git commit -s`) per the [DCO](https://developercertificate.org/) - [ ] Fixes a regression (If yes, please add `commit-id` or `PR #` here) - [ ] Unit tests added/updated - [ ] `make verifiers` passes diff --git a/.github/workflows/dco.yml b/.github/workflows/dco.yml new file mode 100644 index 000000000..b0e862c4a --- /dev/null +++ b/.github/workflows/dco.yml @@ -0,0 +1,43 @@ +name: DCO + +on: + pull_request: + branches: + - main + +permissions: + contents: read + +jobs: + check: + name: Verify DCO sign-off + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + + # Every non-merge commit in the pull request must carry a Signed-off-by + # trailer matching the commit author's email, certifying the Developer + # Certificate of Origin 1.1 (https://developercertificate.org/). + # Only commits authored from a GitHub-issued bot address are exempt; a + # display name is attacker-controlled and must never grant the exemption. + - name: Check Signed-off-by trailers + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + run: | + fail=0 + while read -r sha; do + author_name="$(git log -1 --format='%an' "${sha}")" + author_email="$(git log -1 --format='%ae' "${sha}")" + case "${author_email}" in + *"[bot]@users.noreply.github.com") continue ;; + esac + if ! git log -1 --format='%(trailers:key=Signed-off-by,valueonly)' "${sha}" | + grep -qiF "<${author_email}>"; then + echo "::error::commit ${sha} by ${author_name} <${author_email}> lacks a matching Signed-off-by trailer; sign with 'git commit -s', repair with 'git rebase --signoff'" + fail=1 + fi + done < <(git rev-list --no-merges "${BASE_SHA}..${HEAD_SHA}") + exit "${fail}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c44e91a8d..93f8d1695 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -51,10 +51,11 @@ Before opening a pull request: ### Commit changes -After verification, commit your changes with a concise message: +After verification, commit your changes with a concise message and a DCO +sign-off (see [Licensing of Contributions](#licensing-of-contributions)): ``` -git commit -am 'Fix object replication retry handling' +git commit -s -am 'Fix object replication retry handling' ``` ### Push to the branch @@ -72,6 +73,60 @@ test evidence, compatibility notes, and documentation impact. Public product documentation is owned by the separate [`pgsty/silo.pgsty.com`](https://github.com/pgsty/silo.pgsty.com) repository. +## Licensing of Contributions + +Silo is licensed under the [GNU AGPL v3.0 or later](LICENSE). Its core is +Copyright (c) MinIO, Inc.; the combined work can never be relicensed, and this +fork does not try to. + +* **No CLA.** We do not ask you to sign a Contributor License Agreement and we + do not take your copyright. Contributions are accepted inbound=outbound: you + keep the copyright to your changes and license them under the same + AGPL-3.0-or-later as the project itself. The maintainers receive no rights + beyond the project license. + +* **DCO sign-off required.** Every commit must carry a + `Signed-off-by: Your Name ` trailer certifying the + [Developer Certificate of Origin 1.1](https://developercertificate.org/) — + your statement that you have the right to submit the code under the project + license. Sign each commit with: + + ``` + git commit -s + ``` + + Forgot some? Repair your branch with `git rebase --signoff` and force-push. + CI rejects pull requests containing unsigned commits; the sign-off email + must match the commit author email. (Lowercase `-s` is the plain-text DCO + sign-off; cryptographic `-S`/GPG signing is welcome but independent.) + +* **Provenance.** Only submit code you are entitled to submit. This matters + more here than in most projects: Silo carries a downstream delta over an + upstream code base, and cherry-picks from the lineage remote or other forks + are routine. When relaying a patch written by someone else, preserve original + authorship (`git cherry-pick -x`, keep the author field and any existing + `Signed-off-by` trailers) and add your own sign-off as the person passing it + along. Never import code from a proprietary distribution. + +* **File headers.** Files derived from upstream keep the original MinIO + copyright header unchanged. New files added by this fork use the dual + header, followed by the standard AGPL boilerplate: + + ``` + // Copyright (c) 2015-2025 MinIO, Inc. + // Copyright (c) 2025-2026 PGSTY + ``` + +* **Squash merges** must keep the `Signed-off-by:` trailers in the resulting + commit message. + +* **Authorship and tooling.** The human contributor is the author of the commit + and the sole signatory of its DCO sign-off. Attribution trailers for + assistive tooling (for example `Co-Authored-By:` naming an AI assistant) are + informational only: they record which tools were used, and do not create + authorship, co-authorship, or any copyright claim. Whoever signs off remains + responsible for the content of the commit, whatever produced it. + ## FAQs ### How does Silo manage dependencies? diff --git a/NOTICE b/NOTICE index db41f206d..9111013e8 100644 --- a/NOTICE +++ b/NOTICE @@ -8,7 +8,7 @@ separate copyright notices and license terms. Your use of the source code for these subcomponents is subject to the terms and conditions of GNU Affero General Public License 3.0. -Silo Project modifications, (C) 2025-2026 The Silo Authors. +Silo Project modifications, (C) 2025-2026 PGSTY. Silo is an independent community-maintained project incorporating MinIO source code. It is not affiliated with or endorsed by MinIO, Inc. Modified diff --git a/README.md b/README.md index c39a1bb7c..d1f9ac210 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,8 @@ Useful contributions include security and dependency updates, reproducible bug f Issues and pull requests should include the affected version, reproduction steps, impact, expected behavior, tests, and compatibility notes. Discuss large changes in an issue first. +There is no CLA: contributions are accepted inbound=outbound under the project license (AGPL-3.0-or-later) and contributors keep their copyright. Every commit must be signed off (`git commit -s`) per the [Developer Certificate of Origin](https://developercertificate.org/); see [`CONTRIBUTING.md`](CONTRIBUTING.md). + ## Background This project was created in response to changes in the upstream community distribution and maintenance model. The maintainer’s analysis, alternatives considered, and early maintenance record are documented below: diff --git a/README_ZH.md b/README_ZH.md index 709aabab1..054c741fb 100644 --- a/README_ZH.md +++ b/README_ZH.md @@ -221,6 +221,8 @@ go build -o silo . Issue 与 Pull Request 应说明受影响版本、复现步骤、影响、预期行为、测试与兼容性说明。大型改动请先提交 Issue 讨论。 +本项目不要求签署 CLA:贡献按项目许可证(AGPL-3.0-or-later,inbound=outbound)接收,贡献者保留自己的版权。每个提交都必须按照 [DCO](https://developercertificate.org/) 签署(`git commit -s`),详见 [`CONTRIBUTING.md`](CONTRIBUTING.md)。 + ## 背景 本项目源于上游社区发行与维护模式的变化。维护者对相关变化的分析、替代方案评估与早期维护记录见以下文章: diff --git a/buildscripts/verify-rebrand.sh b/buildscripts/verify-rebrand.sh index 92236c4a0..ba810cbef 100755 --- a/buildscripts/verify-rebrand.sh +++ b/buildscripts/verify-rebrand.sh @@ -112,6 +112,21 @@ require_text .github/workflows/release.yml "packages_checksums.txt" require_text .github/workflows/docker-release.yml "Attest multi-architecture image provenance" require_text .github/workflows/docker-release.yml "index.docker.io/pgsty/silo" +# Copyright notices credit both parties with fixed terms: upstream MinIO +# development ends at its own last year, and the fork's own term starts when +# the fork did. Deriving the upstream end year from the clock would extend +# MinIO's copyright term every January. +require_text cmd/build-constants.go 'upstreamCopyrightEndYear = "2025"' +require_text cmd/build-constants.go 'forkCopyrightStartYear = "2025"' +require_text cmd/main.go 'upstreamCopyrightEndYear' +reject_text cmd/main.go 'CopyrightYear = strconv.Itoa(time.Now().Year())' + +# Contribution policy: no CLA, inbound=outbound, DCO sign-off enforced in CI. +require_file .github/workflows/dco.yml +require_text .github/workflows/dco.yml "Signed-off-by" +require_text CONTRIBUTING.md "developercertificate.org" +require_text CONTRIBUTING.md "No CLA" + for file in .github/nfpm.yml Dockerfile.goreleaser silo.service; do reject_text "${file}" "/usr/bin/minio" reject_text "${file}" "/usr/local/bin/minio" diff --git a/cmd/build-constants.go b/cmd/build-constants.go index 50088fc79..0f9bfc498 100644 --- a/cmd/build-constants.go +++ b/cmd/build-constants.go @@ -17,7 +17,30 @@ package cmd -import "runtime" +import ( + "runtime" + "strconv" + "time" +) + +// upstreamCopyrightEndYear is the last year of upstream MinIO, Inc. development +// this fork derives from. It is fixed: the fork's own maintenance does not +// extend the upstream copyright term. +const upstreamCopyrightEndYear = "2025" + +// forkCopyrightStartYear is the year the Silo fork began. +const forkCopyrightStartYear = "2025" + +// copyrightEndYear returns the end year shown in copyright notices for the +// fork's own modifications. Release builds inject CopyrightYear through +// ldflags; source builds keep the "0000" placeholder, for which the current +// year is used instead. +func copyrightEndYear() string { + if CopyrightYear == "" || CopyrightYear == "0000" { + return strconv.Itoa(time.Now().Year()) + } + return CopyrightYear +} // DO NOT EDIT THIS FILE DIRECTLY. These are build-time constants // set through ‘buildscripts/gen-ldflags.go’. diff --git a/cmd/main.go b/cmd/main.go index 4fb6f6db4..7e0f6cd1d 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -25,9 +25,7 @@ import ( "runtime" "runtime/debug" "sort" - "strconv" "strings" - "time" "github.com/minio/cli" "github.com/minio/minio/internal/color" @@ -176,9 +174,8 @@ func newApp(name string) *cli.App { } func startupBanner(banner io.Writer) { - CopyrightYear = strconv.Itoa(time.Now().Year()) - fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear)) - fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright 2026 PGSTY contributors")) + fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", upstreamCopyrightEndYear)) + fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright %s-%s PGSTY", forkCopyrightStartYear, copyrightEndYear())) fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" "+MinioLicense)) fmt.Fprintln(banner, color.Blue("Version:")+color.Bold(" %s (%s %s/%s)", ReleaseTag, runtime.Version(), runtime.GOOS, runtime.GOARCH)) } @@ -188,8 +185,8 @@ func versionBanner(c *cli.Context) io.Reader { fmt.Fprintln(banner, color.Bold("%s version %s (commit-id=%s)", c.App.Name, c.App.Version, CommitID)) fmt.Fprintln(banner, color.Blue("Runtime:")+color.Bold(" %s %s/%s", runtime.Version(), runtime.GOOS, runtime.GOARCH)) fmt.Fprintln(banner, color.Blue("License:")+color.Bold(" GNU AGPLv3 - https://www.gnu.org/licenses/agpl-3.0.html")) - fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", CopyrightYear)) - fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright 2026 PGSTY contributors")) + fmt.Fprintln(banner, color.Blue("Copyright:")+color.Bold(" 2015-%s MinIO, Inc.", upstreamCopyrightEndYear)) + fmt.Fprintln(banner, color.Blue("Modifications:")+color.Bold(" Copyright %s-%s PGSTY", forkCopyrightStartYear, copyrightEndYear())) fmt.Fprintln(banner, color.Blue("Source compatibility:")+color.Bold(" based on MinIO technology")) return strings.NewReader(banner.String()) }