Skip to content
Merged
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
15 changes: 14 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ on:
- "go.sum"
- "LICENSE"
- "NOTICE"
- "scripts/collect-third-party-licenses.sh"
- "scripts/verify-release-artifacts.sh"
- "build/package/Dockerfile"
- "build/package/Dockerfile.goreleaser"
- ".dockerignore"
Expand All @@ -22,6 +24,8 @@ on:
- "go.sum"
- "LICENSE"
- "NOTICE"
- "scripts/collect-third-party-licenses.sh"
- "scripts/verify-release-artifacts.sh"
- "build/package/Dockerfile"
- "build/package/Dockerfile.goreleaser"
- ".dockerignore"
Expand Down Expand Up @@ -69,7 +73,13 @@ jobs:
# changes, so actually run the binary as the unprivileged user.
- name: Smoke test the image
if: github.event_name == 'pull_request'
run: docker run --rm ghcr.io/skyoo2003/kvs:dev version
run: |
docker run --rm ghcr.io/skyoo2003/kvs:dev version
docker run --rm --entrypoint sh ghcr.io/skyoo2003/kvs:dev -c '
test -s /usr/share/licenses/kvs/LICENSE &&
test -s /usr/share/licenses/kvs/NOTICE &&
test -s /usr/share/licenses/kvs/THIRD_PARTY_LICENSES/README
'

# The job above only builds Dockerfile. The release path uses
# Dockerfile.goreleaser + dockers_v2, which used to fail for the first time
Expand All @@ -95,3 +105,6 @@ jobs:
with:
version: "~> v2"
args: release --snapshot --clean --config build/package/goreleaser.yaml

- name: Verify archive license bundle
run: make verify-release-artifacts
4 changes: 4 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ on:
- "LICENSE"
- "NOTICE"
- "scripts/verify-notice.sh"
- "scripts/collect-third-party-licenses.sh"
- "scripts/verify-release-artifacts.sh"
- "build/package/goreleaser.yaml"
- "README.md"
- ".goreleaser.yml"
Expand All @@ -28,6 +30,8 @@ on:
- "LICENSE"
- "NOTICE"
- "scripts/verify-notice.sh"
- "scripts/collect-third-party-licenses.sh"
- "scripts/verify-release-artifacts.sh"
- "build/package/goreleaser.yaml"
- "README.md"
- ".goreleaser.yml"
Expand Down
2 changes: 2 additions & 0 deletions .github/workflows/release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ jobs:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
HOMEBREW_TAP_TOKEN: ${{ steps.tap_token.outputs.token }}
- name: Verify archive license bundle
run: make verify-release-artifacts
# GoReleaser 2.18 still emits the deprecated `postflight` stanza. Rewrite
# only its generated quarantine hook before the release job finishes.
- name: Modernize the generated Homebrew cask
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ coverage.html

# GoReleaser
dist/
.release/

# Hugo
/website/public/
Expand Down
5 changes: 5 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@ make setup # installs pre-commit hooks

## PR Guidelines

By submitting a contribution, you confirm that you have the right to submit it
and license it under the [Apache License 2.0](LICENSE). Do not include copied
or generated third-party material unless its license and required notices are
identified for inclusion in the release notice bundle.

- Keep PRs small and focused on a single concern
- Include tests for new functionality
- Add a changelog fragment for user-visible changes: `changie new`, one sentence, two at most.
Expand Down
9 changes: 8 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.PHONY: all setup clean build test lint lint-fix vet coverage race soak notice
.PHONY: all setup clean build test lint lint-fix vet coverage race soak notice licenses verify-release-artifacts

# How long `make soak` runs for. The full run behind the numbers in the docs is SOAK=4h.
SOAK ?= 5m
Expand All @@ -12,6 +12,13 @@ all: vet lint test build
notice:
@./scripts/verify-notice.sh

licenses:
@rm -rf dist/THIRD_PARTY_LICENSES
@./scripts/collect-third-party-licenses.sh dist/THIRD_PARTY_LICENSES

verify-release-artifacts:
@./scripts/verify-release-artifacts.sh dist

setup:
@pre-commit install

Expand Down
5 changes: 5 additions & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ Copyright 2020-2026 Sung-Kyu Yoo
This product includes third-party software. The inventory below describes the
modules linked into the kvs binary. Their respective license terms apply.

Binary archives and container images also include a THIRD_PARTY_LICENSES
directory containing the exact license and upstream NOTICE files for these
module versions. The inventory is verified in CI against the modules linked
into ./cmd/kvs.

Third-party components
----------------------
- github.com/boltdb/bolt@v1.3.1 — MIT
Expand Down
3 changes: 3 additions & 0 deletions build/package/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,14 @@ RUN apk --no-cache --no-progress add make
WORKDIR /github.com/skyoo2003/kvs
COPY . .
RUN make build
RUN ./scripts/collect-third-party-licenses.sh /third_party_licenses

FROM alpine:3.23

WORKDIR /kvs
COPY --from=builder /github.com/skyoo2003/kvs/dist/kvs /usr/bin/kvs
COPY LICENSE NOTICE /usr/share/licenses/kvs/
COPY --from=builder /third_party_licenses /usr/share/licenses/kvs/THIRD_PARTY_LICENSES

EXPOSE 3456 3457 6379

Expand Down
2 changes: 2 additions & 0 deletions build/package/Dockerfile.goreleaser
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ FROM alpine:3.23
WORKDIR /kvs
ARG TARGETPLATFORM
COPY ${TARGETPLATFORM}/kvs /usr/bin/kvs
COPY LICENSE NOTICE /usr/share/licenses/kvs/
COPY .release/third_party_licenses /usr/share/licenses/kvs/THIRD_PARTY_LICENSES

EXPOSE 3456 3457 6379

Expand Down
10 changes: 9 additions & 1 deletion build/package/goreleaser.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ env:
before:
hooks:
- go mod download
- rm -rf .release/third_party_licenses
- ./scripts/collect-third-party-licenses.sh .release/third_party_licenses

builds:
- id: kvs
Expand Down Expand Up @@ -48,6 +50,8 @@ archives:
- README.md
- CHANGELOG.md
- CODE_OF_CONDUCT.md
- src: .release/third_party_licenses/**
dst: THIRD_PARTY_LICENSES

changelog:
disable: false
Expand Down Expand Up @@ -88,12 +92,16 @@ dockers_v2:
- images:
- ghcr.io/skyoo2003/kvs
dockerfile: build/package/Dockerfile.goreleaser
extra_files:
- LICENSE
- NOTICE
- .release/third_party_licenses
ids:
- kvs
platforms:
- linux/amd64
- linux/arm64
sbom: false
sbom: true
flags:
- "--provenance=false"
tags:
Expand Down
74 changes: 74 additions & 0 deletions scripts/collect-third-party-licenses.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#!/usr/bin/env sh
# Collect the license and notice files for every module linked into kvs.
# The output is intentionally built from the module cache so its contents match
# the exact module versions selected by go.mod/go.sum.
set -eu

if [ "$#" -ne 1 ]; then
echo "usage: $0 OUTPUT_DIRECTORY" >&2
exit 2
fi

root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
output=$1

case "$output" in
''|/|.)
echo "refusing unsafe output directory: $output" >&2
exit 2
;;
esac

if [ -e "$output" ]; then
echo "output directory already exists: $output" >&2
exit 2
fi

modules=$(mktemp)
trap 'rm -f "$modules"' EXIT

cd "$root"
go list -deps -json ./cmd/kvs |
awk '
/"Path":/ { path = $2; gsub(/[",]/, "", path) }
/"Version":/ { version = $2; gsub(/[",]/, "", version) }
/"Main": true/ { main = 1 }
/^}/ {
if (path != "" && version != "" && !main) print path "@" version
path = version = ""; main = 0
}
' | sort -u > "$modules"

mkdir -p "$output"
{
echo "Third-party license bundle for KVS"
echo
echo "This directory contains the license and notice files distributed by the"
echo "exact Go modules linked into this KVS binary. See ../NOTICE for the"
echo "component inventory."
echo
echo "Modules"
echo "-------"
sed 's/^/- /' "$modules"
} > "$output/README"

while IFS= read -r module; do
path=${module%@*}
version=${module##*@}
module_dir=$(go list -m -f '{{.Dir}}' "$path")
destination="$output/$path@$version"
found=0

mkdir -p "$destination"
for file in "$module_dir"/LICENSE* "$module_dir"/COPYING* "$module_dir"/NOTICE*; do
if [ -f "$file" ]; then
cp "$file" "$destination/"
found=1
fi
done

if [ "$found" -eq 0 ]; then
echo "no top-level license or notice file found for $module" >&2
exit 1
fi
done < "$modules"
8 changes: 7 additions & 1 deletion scripts/verify-notice.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ set -eu
root=$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)
actual=$(mktemp)
recorded=$(mktemp)
trap 'rm -f "$actual" "$recorded"' EXIT
licenses=$(mktemp -d)
trap 'rm -f "$actual" "$recorded"; rm -rf "$licenses"' EXIT

cd "$root"
go list -deps -json ./cmd/kvs |
Expand All @@ -26,3 +27,8 @@ if ! diff -u "$recorded" "$actual"; then
echo "NOTICE's third-party component inventory is stale." >&2
exit 1
fi

# A component list alone is not enough for licenses such as BSD-3-Clause:
# binary distributions must reproduce their copyright and license terms. The
# collector fails if any linked module lacks the material we package at release.
"$root/scripts/collect-third-party-licenses.sh" "$licenses/THIRD_PARTY_LICENSES"
61 changes: 61 additions & 0 deletions scripts/verify-release-artifacts.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/usr/bin/env sh
# Verify that every released archive carries the project's and dependencies'
# license material. GoReleaser emits tar.gz archives on Unix and zip archives
# on Windows.
set -eu

if [ "$#" -ne 1 ]; then
echo "usage: $0 DIST_DIRECTORY" >&2
exit 2
fi

dist=$1
found=0
modules=$(mktemp)
trap 'rm -f "$modules"' EXIT

go list -deps -json ./cmd/kvs |
awk '
/"Path":/ { path = $2; gsub(/[",]/, "", path) }
/"Version":/ { version = $2; gsub(/[",]/, "", version) }
/"Main": true/ { main = 1 }
/^}/ {
if (path != "" && version != "" && !main) print path "@" version
path = version = ""; main = 0
}
' | sort -u > "$modules"

check_entries() {
archive=$1
entries=$2
for required in LICENSE NOTICE THIRD_PARTY_LICENSES/README; do
if ! printf '%s\n' "$entries" | grep -Fx "$required" >/dev/null; then
echo "$archive is missing $required" >&2
exit 1
fi
done

while IFS= read -r module; do
if ! printf '%s\n' "$entries" | grep -F "THIRD_PARTY_LICENSES/$module/" >/dev/null; then
echo "$archive is missing license material for $module" >&2
exit 1
fi
done < "$modules"
}

for archive in "$dist"/*.tar.gz; do
[ -e "$archive" ] || continue
check_entries "$archive" "$(tar -tzf "$archive")"
found=1
done

for archive in "$dist"/*.zip; do
[ -e "$archive" ] || continue
check_entries "$archive" "$(unzip -Z1 "$archive")"
found=1
done

if [ "$found" -eq 0 ]; then
echo "no release archives found in $dist" >&2
exit 1
fi
6 changes: 4 additions & 2 deletions website/content/docs/release.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,10 @@ go in the same change — while it is there, it wins and the migration never fir
| Homebrew cask | `skyoo2003/homebrew-tap`, installed with `brew install skyoo2003/tap/kvs` |
| Release notes | The GitHub release body, taken from `changes/v1.2.3.md` |

Each archive carries the binary plus `LICENSE`, `NOTICE`, `README.md`, `CHANGELOG.md`, and
`CODE_OF_CONDUCT.md`. The binary reports the tag through `kvs version`.
Each archive carries the binary plus `LICENSE`, `NOTICE`, `THIRD_PARTY_LICENSES`, `README.md`,
`CHANGELOG.md`, and `CODE_OF_CONDUCT.md`. The license bundle contains the exact upstream license
and notice files for the modules linked into that release. The binary reports the tag through
`kvs version`.

**Every container tag but the first moves.** `latest-alpine`, `v1-alpine`, and `v1.2-alpine` point
at whatever was released most recently, which is why there are no pre-release tags: publishing
Expand Down
Loading