Skip to content

feat: tool/copyright - #4983

Open
romshark wants to merge 11 commits into
masterfrom
copyright-tool
Open

feat: tool/copyright#4983
romshark wants to merge 11 commits into
masterfrom
copyright-tool

Conversation

@romshark

@romshark romshark commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

A task I long wanted to automate, assisted with Claude Code (Opus 5)

It makes copyright claims easier to maintain.
This PR does not change any copyright claims, it only begins to enforce them starting with attributions.json since 2026-09-01. I kept history changes out of this PR to avoid blowing the scope. We can do a general cleanup in a later PR.

Adds make copyright-check and make copyright-update:

private/storage/trust/dbtest/dbtest.go
    - // Copyright 2020 Anapaya Systems
    + // Copyright 2024 Anapaya Systems    (hitz@anapaya.net, 2024-03-31 25e37a002)
    + // Copyright 2024 SCION Association  (matzf@scion.org, 2024-07-09 68bd2bcae)
private/storage/trust/fspersister/db.go
    - // Copyright 2020 Anapaya Systems
    + // Copyright 2022 Anapaya Systems  (roos@anapaya.net, 2022-03-12 15d455f11)
private/storage/trust/fspersister/db_test.go
    - // Copyright 2020 Anapaya Systems
    + // Copyright 2025 Anapaya Systems    (roos@anapaya.net, 2025-09-30 38e79c43f)
    + // Copyright 2025 SCION Association  (roman.scharkov@gmail.com, 2025-01-30 29ef0b75c)
private/storage/trust/metrics/db.go
    - // Copyright 2020 Anapaya Systems
    + // Copyright 2022 Anapaya Systems  (roos@anapaya.net, 2022-03-12 15d455f11)
  • attributes uncommitted work to configured git user.email
  • enforces order of copyright claims (most recent at the top)
  • allows copyright claims to be rewritten across the entire project according to attribution settings (including by attribution date).
  • allows CI to tell people they didn't run copyright-update, making it harder to miss.

Alternatives Analysis

I haven't found an off the shelf tool that does what we need.

DISCLAIMER: I did use Claude Code (Opus 5) to generate this table so keep in mind that there can be mistakes even though I tried to check some of them manually:

Tool Purpose Writes headers Holder from git Holder = org Dated affiliation Multi-holder/file Never retracts Excludes by
tools/copyright Credit the organizations behind a file the file's own header
REUSE License compliance REUSE.toml
hashicorp/copywrite Company-wide header stamping path globs
google/addlicense Add missing license headers path args
shybyte/copyright-header Keep header years current path globs
Eclipse Oomph UpdateCopyrightsAction Keep header years current Eclipse project config
Poettering's copyright.py Credit authors of a file n/a
klange/generate-copyright Credit authors of a file n/a
cncf/gitdm Contribution statistics per employer n/a
goheader (in .golangci.yml) Enforce header shape lint config

@romshark romshark self-assigned this Sep 1, 2026
@romshark romshark added the c/documentation Improvements or additions to documentation label Sep 1, 2026
Checks the claims in the headers against git history and
reports any organization with no contribution behind it.
-w removes them. Needs -dates, and skips a file when a
contributor's affiliation is unknown.
@romshark
romshark marked this pull request as ready for review September 2, 2026 14:33
@romshark
romshark requested review from a team and katyatitkova September 2, 2026 14:36
@tzaeschke

Copy link
Copy Markdown
Contributor

Is there a documentation of what is required?

The additional copyright information seems to be just a duplicate? The individual authors with date can be derived from the commit history.
The potentially useful information is probably only the entity (Association, Anapaya, ETHZ Zurich). If we add all individual committers with dates and individual commits then this would result in a lot of boilerplate copyright headers....

Separately, how about adopting the REUSE recommendation with SPDX identifier: SPDX-FileCopyrightText:
https://reuse.software/tutorial/

@romshark

romshark commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

Separately, how about adopting the REUSE recommendation with SPDX identifier

Yes, I'm all for it! I think a short:

// SPDX-License-Identifier: Apache-2.0

is better than the entire license boilerplate we have right now in each file:

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

But I wanted to keep it out of this PR. This change would belong to another PR.

@romshark

romshark commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

The additional copyright information seems to be just a duplicate? The individual authors with date can be derived from the commit history.

Legally speaking, this PR changes nothing and is not supposed to change anything about licenses and copyright claims. It only adds a new tool that can help automate bumping/updating the copyright claims we have right now. I can just run make copyright-update and bump/add claims in all files I touched in my changes, and CI will also detect and tell me that I didn't, if I'm listed in the affiliations.json config.

The history-rewrite functionality that it provides is not used in this PR yet. We may or may not use it to clean up the entire codebase in a later PR.

Changing the way we do copyright claims, attributions and license disclosure is not in the scope of this PR.

@tzaeschke

Copy link
Copy Markdown
Contributor

So what do these scripts actually do? To me the example looked like they added author email, date, and commit hash to the copyright?
If they add that I would propose to not add that and instead only replace // Copyright with SPDX-FileCopyrightText: (or add it if there is nothing in the file).

If they do something else then I misunderstood what the scripts are meant to do...

@romshark

romshark commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

To me the example looked like they added author email, date, and commit hash to the copyright?

No. Nothing changes in that regard.
This is pure automation to keep copyright claims up to date (unless you opt out by not having yourself listed under tools/copyright/affiliations.json).

So what do these scripts actually do?

If I change a bunch of files and I'm listed under affiliations.json:

{
  "name": "Roman Sharkov",
  "emails": ["roman.scharkov@gmail.com", "rsc@scion.org"],
  "affiliation": "SCION Association"
}

then:

  1. I can run make copyright-update to bump all years and add where necessary the:
// Copyright 2026 SCION Association
  1. CI will tell me I didn't update the copyright notices correctly if I didn't.

What it also can do is rewrite claims in a sub-tree of the repository with:

make copyright-update COPYRIGHT_FLAGS="-history $PWD/tools/copyright/affiliation-history.json"
  1. We don't want to do this now, but we can in a later PR.
  2. The affiliation history file should not be in git though since it may expose information that is currently not public and that cannot be easily derived from git history.

@romshark

romshark commented Sep 3, 2026

Copy link
Copy Markdown
Contributor Author

FYI: REUSE and tools/copyright are compatible. If we ever decide to introduce REUSE they will not conflict.

@tzaeschke tzaeschke left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In summary:

  • I think the documentation could be cleaned up a bit
  • It is unclear to me why we need a history file and why it needs to be private (outside the repo)
  • It still seems to me that the scripts may add committer name + date + commit ID (at least of someone is not listed in the affiliation file?). I don't fully understand what the point is and also I don't quite understand whether this is temporary or will actually be committed.

Comment thread tools/copyright/README.md
go run ./tools/copyright -w -history tools/copyright/affiliation-history.json
```

`.gitignore` reserves that path, but the file may live anywhere. Through `make`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
`.gitignore` reserves that path, but the file may live anywhere. Through `make`,
`.gitignore` excludes that path from being committed, but the file may live anywhere. Through `make`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, maybe the path shouldn't be hardcoded in .gitignore if it can live anywhere? Usually, I'd say, ignored file should live in the project root or a dedicated subfolder, not somewhere in the code?

Comment thread tools/copyright/README.md
@@ -0,0 +1,167 @@
# copyright

See [doc.go](doc.go), or `go doc ./tools/copyright`.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it a bit confusing that part of the documentation lives in README and the other part in doc.go.
Maybe merge them?
Also, it seems the reading order is README.md, the doc.go.

Comment thread tools/copyright/README.md

## affiliation-history.json

People change employer while keeping the same address, and the snapshot has

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don´t quite understand this. What is the snapshot and how can it drop things?
What is "others", does it refer to employers?

It is also not clear to me why we need this history?
Either people claim their copyright correctly, or they don't. If they don't, then it probably doesn't help if someone keeps in unofficial file on their personal device that somehow records this history? I don't see any legal or practical benefit from that (but I am not a lawyer).

Comment thread tools/copyright/README.md
```

```sh
go run ./tools/copyright -w -history tools/copyright/affiliation-history.json

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is the hostory private? I think, git history should contain all that information publicly?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I initially raised a concern to Roman about this. Then he mentioned that this is anyway public in Git history. So if that is the case, we can keep this file public too

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So if it is in the git history, why store it in a file?

Comment thread tools/copyright/README.md
By default it reports how many files are out of date, and which identities it could not
attribute. Under `-v`, every line it adds or moves cites the contribution behind it:

```txt

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This example looks very much like it is adding lines with attribution date and commit ID. Is it not?

Maybe explain what this example shows: to me this looks like the output of diff, i.e. "+" means a line is added "-" means a line is removed.

Comment thread tools/copyright/doc.go
// # report what is out of date here and below, exit non-zero if anything is
// go run ./tools/copyright
// # bring this subtree's headers up to date
// go run ./tools/copyright -w

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The -w option is not mentioned in the text above. I assume id does "write"?

Comment thread tools/copyright/doc.go
// Dating every revision is what puts the whole history back in scope,
// so -history ignores -base.
//
// Each line the report adds or moves cites the contribution it rests on:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What "report"? That was not mentioned before?
Also, why does a report add or move lines? I would expect it to be read-only?

Comment thread tools/copyright/doc.go
// claim it for whoever its author works for today.
// -base defaults to origin/master, and an empty one reads the whole history.
//
// -history points at an optional file that dates the affiliations instead,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this whole text could be restructured a bit? It seems to be a mixture of explaining argument flags and explaining what the tools does. Maybe explain first what the too does and then list all flags with an explanation?

Comment thread tools/copyright/doc.go
Comment on lines +25 to +26
// A run therefore reads only the commits -base does not reach, the work on this branch,
// where that snapshot is current by definition. Everything -base reaches is settled:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// A run therefore reads only the commits -base does not reach, the work on this branch,
// where that snapshot is current by definition. Everything -base reaches is settled:
// A run therefore reads only the commits that -base does not reach: the work on this branch,
// where that snapshot is current by definition. Everything -base reaches is settled:

Clarify what "work on this branch" refers to.

Comment thread tools/copyright/doc.go
Comment on lines +25 to +26
// A run therefore reads only the commits -base does not reach, the work on this branch,
// where that snapshot is current by definition. Everything -base reaches is settled:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you specify what a "run" is? Is it independent of the arguments? Does it require -w? Is it independent of specifying -base?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c/documentation Improvements or additions to documentation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants