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
27 changes: 27 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
version: 2
updates:
# Pull request titles look like "chore(deps): bump ...". The chore type
# makes no release. See docs/releasing.md for security fixes.
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
# Wait 7 days after a new version comes out, so that a bad release can
# be found and pulled first. Security updates do not wait.
cooldown:
default-days: 7
commit-message:
prefix: chore
include: scope

# Pull request titles look like "ci(deps): bump actions/checkout ...".
# Dependabot also updates the pinned commit SHA and its version comment.
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
cooldown:
default-days: 7
commit-message:
prefix: ci
include: scope
112 changes: 112 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
name: CI

on:
pull_request:
push:
branches: [main]
schedule:
# Every Monday: find vulnerabilities that became known since the last push.
- cron: "17 5 * * 1"

permissions:
contents: read

concurrency:
# A new push to a pull request cancels the older run for it.
# Each push to main gets its own group, so those runs are never cancelled.
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.run_id }}
cancel-in-progress: true

jobs:
test:
name: test (${{ matrix.go }})
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
# go.mod: the oldest Go we support (the go line in go.mod).
# stable: the newest Go release.
go: [go.mod, stable]
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: ${{ matrix.go == 'go.mod' && 'go.mod' || '' }}
go-version: ${{ matrix.go == 'stable' && 'stable' || '' }}
- name: Check formatting
run: |
unformatted="$(gofmt -l .)"
if [ -n "$unformatted" ]; then
echo "These files are not formatted with gofmt:"
echo "$unformatted"
exit 1
fi
- run: go vet ./...
- run: go test -race ./...

lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version-file: go.mod
- uses: golangci/golangci-lint-action@ba0d7d2ec06a0ea1cb5fa41b2e4a3ab91d21278a # v9.3.0
with:
# Dependabot does not update this version. Update it by hand.
version: v2.14.0

vuln:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
persist-credentials: false
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
# Release binaries are built with the newest Go (see release.yml),
# so check the standard library of that version.
go-version: stable
- name: govulncheck
# Dependabot does not update this version. Update it by hand.
run: go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 ./...

vuln-release:
name: vuln (latest release)
# Weekly only. The published binaries contain the Go standard library
# they were built with, so check the binaries themselves. A finding here
# needs a new release (see docs/releasing.md).
if: github.event_name == 'schedule'
runs-on: ubuntu-latest
steps:
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
go-version: stable
cache: false
- name: govulncheck on the binaries of the latest release
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="$(gh release list --repo "$GITHUB_REPOSITORY" --exclude-drafts \
--exclude-pre-releases --limit 1 --json tagName --jq '.[0].tagName // empty')"
if [ -z "$tag" ]; then
echo "No release yet. Nothing to check."
exit 0
fi
dir="${RUNNER_TEMP}/release"
gh release download "$tag" --repo "$GITHUB_REPOSITORY" --dir "$dir" \
--pattern 'nodkey_*_linux_*.tar.gz'
status=0
for tarball in "$dir"/*.tar.gz; do
out="${tarball%.tar.gz}"
mkdir -p "$out"
tar -xzf "$tarball" -C "$out" nodkey
echo "== ${tag}: $(basename "$tarball")"
go run golang.org/x/vuln/cmd/govulncheck@v1.9.0 -mode=binary "$out/nodkey" || status=1
done
exit "$status"
42 changes: 42 additions & 0 deletions .github/workflows/pr-title.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
name: PR title

# The squash merge uses the pull request title as the commit message, and
# release-please reads those messages. So the title must follow
# Conventional Commits. See docs/releasing.md.

on:
# pull_request_target also runs for pull requests from forks. It runs with
# this repository's token, so this workflow must never check out or run
# code from the pull request. It only reads the title.
pull_request_target:
types: [opened, edited, synchronize, reopened]

permissions:
pull-requests: read # read the pull request

concurrency:
# Check only the newest title of a pull request.
group: ${{ github.workflow }}-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
title:
name: Conventional Commits title
runs-on: ubuntu-latest
steps:
- uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
types: |
feat
fix
perf
revert
docs
chore
ci
test
refactor
build
style
150 changes: 150 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
name: Release

# How releases work, and the one-time setup: docs/releasing.md.

on:
push:
branches: [main]

# Each job asks for only the permissions it needs.
permissions: {}

concurrency:
# One release run at a time. Never cancel a run in the middle of a release.
group: ${{ github.workflow }}
cancel-in-progress: false

jobs:
release-please:
# Skip until the GitHub App is set up (see docs/releasing.md).
if: vars.RELEASE_APP_CLIENT_ID != ''
runs-on: ubuntu-latest
# The App private key is a secret of this environment. Only main may use
# the environment, so only runs on main can read the key.
environment: release
# This job uses the App token, not GITHUB_TOKEN.
permissions: {}
outputs:
release_created: ${{ steps.release.outputs.release_created }}
tag_name: ${{ steps.release.outputs.tag_name }}
version: ${{ steps.release.outputs.version }}
steps:
- id: app-token
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
with:
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
permission-contents: write
permission-pull-requests: write
- id: release
uses: googleapis/release-please-action@45996ed1f6d02564a971a2fa1b5860e934307cf7 # v5.0.0
with:
token: ${{ steps.app-token.outputs.token }}
config-file: release-please-config.json
manifest-file: .release-please-manifest.json

# Builds the files. It can only read the repository: no OIDC token, and no
# write access to the release.
build:
needs: release-please
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-latest
permissions:
contents: read
env:
TAG: ${{ needs.release-please.outputs.tag_name }}
VERSION: ${{ needs.release-please.outputs.version }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
ref: refs/tags/${{ needs.release-please.outputs.tag_name }}
persist-credentials: false
- name: Check that the tag is the commit of this run
# The provenance attestation names $GITHUB_SHA as the source commit.
# Build only that commit.
run: |
set -euo pipefail
head="$(git rev-parse HEAD)"
tagged="$(git rev-parse "refs/tags/${TAG}^{commit}")"
echo "HEAD: $head tag ${TAG}: $tagged run: $GITHUB_SHA"
if [ "$head" != "$GITHUB_SHA" ] || [ "$tagged" != "$GITHUB_SHA" ]; then
echo "::error::The tag ${TAG} is not the commit of this run. See docs/releasing.md."
exit 1
fi
- uses: actions/setup-go@b7ad1dad31e06c5925ef5d2fc7ad053ef454303e # v7.0.0
with:
# The newest Go, so the binaries get the newest standard library fixes.
go-version: stable
# No cache for release builds: a bad cache entry could change the binaries.
cache: false
- name: Build
# -w drops the debug data. The symbol table stays (no -s): govulncheck
# needs it to check the published binaries (see ci.yml).
run: |
set -euo pipefail
mkdir -p dist
# Fixed owner, mode and time in the tarball, so a rebuild of the
# same commit with the same Go version gives the same file.
mtime="@$(git log -1 --format=%ct)"
for arch in amd64 arm64; do
name="nodkey_${VERSION}_linux_${arch}"
stage="${RUNNER_TEMP}/${name}"
mkdir -p "$stage"
CGO_ENABLED=0 GOOS=linux GOARCH="$arch" \
go build -trimpath -ldflags "-w -X main.version=${VERSION}" \
-o "${stage}/nodkey" ./cmd/nodkey
cp LICENSE README.md "$stage/"
tar --owner=0 --group=0 --numeric-owner --mode=go-w --mtime="$mtime" \
-C "$stage" -cf - nodkey LICENSE README.md | gzip -9n > "dist/${name}.tar.gz"
done
cd dist
sha256sum -- *.tar.gz > SHA256SUMS
cat SHA256SUMS
- uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: release-files
path: dist/
if-no-files-found: error

# Signs and publishes the files from the build job. It runs no code from
# the repository.
publish:
needs: [release-please, build]
if: needs.release-please.outputs.release_created == 'true'
runs-on: ubuntu-latest
permissions:
contents: write # upload the files and publish the draft release
id-token: write # sign the attestation (Sigstore)
attestations: write # store the attestation
env:
TAG: ${{ needs.release-please.outputs.tag_name }}
steps:
- uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: release-files
path: dist
- name: Check the files and the tag
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
(cd dist && sha256sum --strict -c SHA256SUMS)
tagged="$(gh api "repos/${GITHUB_REPOSITORY}/commits/refs/tags/${TAG}" --jq .sha)"
if [ "$tagged" != "$GITHUB_SHA" ]; then
echo "::error::The tag ${TAG} points to ${tagged}, not to ${GITHUB_SHA}. See docs/releasing.md."
exit 1
fi
- uses: actions/attest@1e69f48acb82d1966a394da916b4c1698aa569d6 # v4.2.2
with:
subject-path: dist/*.tar.gz
# release-please made a draft release (see release-please-config.json).
# Add the files first and publish after that, so the release is never
# public without its files. Immutable releases need this order.
- name: Upload the files to the draft release
env:
GH_TOKEN: ${{ github.token }}
run: gh release upload "$TAG" dist/*.tar.gz dist/SHA256SUMS --clobber --repo "$GITHUB_REPOSITORY"
- name: Publish the release
env:
GH_TOKEN: ${{ github.token }}
run: gh release edit "$TAG" --draft=false --repo "$GITHUB_REPOSITORY"
18 changes: 18 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Release build output
/dist/

# Binary from "go build ./..." or "go build ./cmd/nodkey"
/nodkey

# Test coverage output
*.out
*.coverprofile
coverage.html

# Editor and OS files
.idea/
.vscode/
*.swp
*.swo
*~
.DS_Store
Loading
Loading