Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .buildkite/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ steps:
timeout_in_minutes: 20
- label: "Check Generated :bash:"
command:
# Runs first: the sections below dirty the working tree it reads.
- echo "--- copyright"
- make copyright-check
- echo "--- go.mod"
- mkdir -p /tmp/test-artifacts
- cp go.mod go.sum /tmp/test-artifacts/
Expand Down
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,7 @@ logger.log
# Vagrant
#########
.vagrant

# copyright tool: the affiliation history is kept out of the repository
#######################################################################
/tools/copyright/affiliation-history.json
13 changes: 12 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all build build-dev dist-check-cgo dist-deb dist-test-release antlr clean docker-images gazelle go.mod licenses mocks mocksdiff protobuf scion-topo test test-integration write_all_source_files git-version
.PHONY: all build build-dev copyright-check copyright-update dist-check-cgo dist-deb dist-test-release antlr clean docker-images gazelle go.mod licenses mocks mocksdiff protobuf scion-topo test test-integration write_all_source_files git-version

build-dev:
rm -f bin/*
Expand Down Expand Up @@ -112,6 +112,17 @@ gazelle: go.mod
licenses:
tools/licenses.sh

# Report how many Go files carry copyright lines that do not match who worked on them,
# and who could not be attributed. Exits non-zero if any are out of date.
# See tools/copyright/README.md for more info.
# COPYRIGHT_FLAGS passes extra flags through, such as -base, -history or -verify.
copyright-check:
bazel run //tools/copyright -- -v -dir "${PWD}" $(COPYRIGHT_FLAGS)

# Bring copyright claims up to date.
copyright-update:
bazel run //tools/copyright -- -v -dir "${PWD}" -w $(COPYRIGHT_FLAGS)

antlr:
antlr/generate.sh fix
bazel run @rules_go//go -- fmt antlr/sequence/*.go
Expand Down
6 changes: 3 additions & 3 deletions private/underlay/ebpf/portfilter.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2025 SCION Association
// Copyright 2026 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -14,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// SPDX-License-Identifier: Apache-2.0

package ebpf

import (
Expand Down
6 changes: 3 additions & 3 deletions private/underlay/ebpf/portfilter_lint.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2025 SCION Association
// Copyright 2026 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -14,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// SPDX-License-Identifier: Apache-2.0

// Placeholder for generated code during lint.

//go:build lint
Expand Down
6 changes: 3 additions & 3 deletions private/underlay/ebpf/portfilter_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
// SPDX-License-Identifier: Apache-2.0
//
// Copyright 2025 SCION Association
// Copyright 2026 SCION Association
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -14,6 +12,8 @@
// See the License for the specific language governing permissions and
// limitations under the License.

// SPDX-License-Identifier: Apache-2.0

package ebpf_test

import (
Expand Down
38 changes: 38 additions & 0 deletions tools/copyright/BUILD.bazel
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
load("@rules_go//go:def.bzl", "go_binary", "go_library")
load("//tools:go.bzl", "go_test")

go_library(
name = "go_default_library",
srcs = [
"affiliation_history.go",
"config.go",
"doc.go",
"header.go",
"history.go",
"main.go",
],
embedsrcs = ["affiliations.json"],
importpath = "github.com/scionproto/scion/tools/copyright",
visibility = ["//visibility:private"],
)

go_binary(
name = "copyright",
embed = [":go_default_library"],
visibility = ["//visibility:public"],
)

go_test(
name = "go_default_test",
srcs = [
"affiliation_history_test.go",
"config_test.go",
"header_test.go",
"history_test.go",
],
embed = [":go_default_library"],
deps = [
"@com_github_stretchr_testify//assert:go_default_library",
"@com_github_stretchr_testify//require:go_default_library",
],
)
167 changes: 167 additions & 0 deletions tools/copyright/README.md
Original file line number Diff line number Diff line change
@@ -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.


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.

private/storage/beacon/sqlite/db.go
- // Copyright 2019 Anapaya Systems
+ // Copyright 2025 Anapaya Systems (roos@anapaya.net, 2025-09-30 38e79c43f)
+ // Copyright 2025 SCION Association (roman.scharkov@gmail.com, 2025-02-12 33de3e514)
```

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 explain what happens now. Is the output above good or bad?
Will it be committed like that or should I (the developer) do something to fix it?
Is there a script that (automatically) fixes it?

## What it will not do

It only adds claims and moves years forward, never drops one or moves a year back:
git history is not the only evidence of authorship.
`-verify` is the only way to ask it to remove claims.

Files it declines to touch, all listed under `-v`:

- Generated files.
- Third-party notices: a header claiming copyright in any form other than
`// Copyright <year> <configured organization>`. `// MIT License`,
`// Copyright (c) 2016 Max Mustermann` and `// Copyright 2020 Some Other Labs, Inc.`
(two spaces) all occur here.
- A well-formed line held by an undeclared organization,
such as `// Copyright 2013 The Prometheus Authors`.
- Files with no header. Claims go above an Apache license block,
and a missing license is not invented; `goheader` flags those.
- Files whose header does not open with the copyright line, an SPDX tag above it included.
The parser reads claims from the first line of the leading comment block,
so a tag belongs below the license block, as in `private/underlay/ebpf`.

An identity with no known affiliation claims nothing, and is reported.
Leaving an identity out is safe. Guessing its affiliation is not.

Uncommitted work is attributed to `git config user.email` and the current year;
having no date of its own, the affiliation is read at the end of that year.
Without a `user.email` the tool stops. `-committed-only` needs no identity.

## affiliations.json

Resolution order for an (email, date) pair:

1. an entry in `contributors` whose `emails` contains the address
2. the domain of the address in `domains`
3. otherwise nothing is claimed

```json
{
"name": "Max Mustermann",
"emails": ["max.m@example.com", "max@another.org"],
"affiliation": "Muster Org"
}
```

One organization per person, undated, so it answers for every day that address
contributed. It lists the people contributing now: an entry whose addresses have
not appeared for a year is dropped. Earlier spans live in the file below, which
is neither embedded nor read by default — the repository does not publish when
someone worked where.

The entries have no dates, so a plain run must skip the old commits. `-base`
draws the line between old and new: a commit that `-base` already contains is old,
and the tool reads only the commits that it does not.

```sh
go run ./tools/copyright # default -base origin/master: this branch only
go run ./tools/copyright -base upstream/master # on a fork, name the real upstream
go run ./tools/copyright -base '' # read every commit, with today's entries
```

The commits `-base` reaches are done. Their claims are already in the headers.
Reading them again would use today's entries, and give that old work to the
organization the author works for now.

If `-base` doesn't exist, the tool stops with an error.
It doesn't quietly read the whole history instead.

`ignoreEmails` drops bots. There is deliberately no list of excluded paths:
which files are ours to edit is read from each file's header.

Adding an entry can only add claims, so re-running after an edit is safe.
`go test ./tools/copyright` validates the embedded configuration.

## 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).

dropped others outright. `-history` points at a file of dated spans that
replaces the contributors of affiliations.json, so it carries its own addresses:

```json
[
{
"name": "Some Contributor",
"emails": ["some@example.com", "contributor@scion.org"],
"affiliations": [
{"org": "ETH Zurich", "from": "2018-09-01", "until": "2022-11-30"},
{"org": "SCION Association", "from": "2022-12-01"}
]
}
]
```

```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?

```

`.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?

give an absolute path: `bazel run` does not start in the repository root.

`from` and `until` are inclusive `YYYY-MM-DD` days. `from` is required,
so no span reaches further back than meant; `until` may be omitted while an
affiliation holds. Where the day is unknown, `-01-01` and `-12-31` bound the year.
A day no span covers claims nothing.

`name` only labels the entry; contributions are matched by address.
The file answers alone, so everyone whose work is to be claimed belongs in it,
the people in affiliations.json included; an address it omits is reported as a gap.
Its organizations must be declared in affiliations.json, but need not be current ones.
Only `organizations`, `domains` and `ignoreEmails` are still read from there:
those hold whenever an address was used.

Dating every revision is what puts the whole history in scope, so `-history`
ignores `-base`. Within a branch's own commits the two agree; over older history
the snapshot claims more, since someone who left an organization keeps claiming
for it, and the people it dropped claim nothing.

## Claims nothing accounts for

By default an existing claim is taken as given. `-verify` checks them too,
and reports every organization no contribution to that file accounts for:

```txt
pkg/private/util/fs.go
- // Copyright 2019 ETH Zurich (no contribution from ETH Zurich)
+ // Copyright 2022 Anapaya Systems (roos@anapaya.net, 2022-03-12 15d455f11)
```

Read-only without `-w`:

```sh
make copyright-check COPYRIGHT_FLAGS="-v -verify -history $PWD/tools/copyright/affiliation-history.json" > report.txt 2>/dev/null
```

A shared line keeps its other holders, and no file loses all its claims: a file
is only processed when it has contributions, and those get claims of their own.

Two limits:

- It needs `-history`: affiliations.json says where people work today,
so a claim for an organization its contributor has left would look unaccounted for.
- It leaves a file alone when someone who touched it has no known affiliation:
that person may be who a claim rests on. `-v` lists those files.

**A claim with nothing behind it is a question, not a verdict.** Code gets copied
between files by hand, work can predate this repository, and a commit can carry
someone else's patch. Read the report and decide; don't pipe it into `-w`.

## Not part of make lint

`goheader` in `.golangci.yml` enforces the shape of the header and the presence
of the license text. It does not know who worked on the file.

`make copyright-check` reports what is out of date; `make copyright-update` rewrites it.
Loading
Loading