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
45 changes: 25 additions & 20 deletions .aqua/aqua-checksums.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,53 +46,58 @@
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.7.3/limen_0.7.3_darwin_arm64.tar.gz",
"checksum": "E69100548B8ECC30BFCD3239659D4B17D48FDA79F436854680081242ABCBAAF4",
"id": "github_release/github.com/farcloser/limen/v0.8.0/limen_0.8.0_darwin_arm64.tar.gz",
"checksum": "E73ED78C7076867ACE43D7EBC1A1254CCAE50D5992095B405CAD7F2F10787B89",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.7.3/limen_0.7.3_linux_amd64.tar.gz",
"checksum": "C92BFA791A0CE63725F172D2796D33CC36092E5844CF73D8E2F146E8C52409EA",
"id": "github_release/github.com/farcloser/limen/v0.8.0/limen_0.8.0_linux_amd64.tar.gz",
"checksum": "63A637D15AB78CE8C1ED4CC64CBEE419E467BAADB4FF290C04228D106B0BFF22",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.7.3/limen_0.7.3_linux_arm64.tar.gz",
"checksum": "CA1353D91BBFDE0AD4B29BBDEA945FD30E7BDFC739ABAF710FC2F8346BD99EDD",
"id": "github_release/github.com/farcloser/limen/v0.8.0/limen_0.8.0_linux_arm64.tar.gz",
"checksum": "E2D2BB0DE0D81092D2D590DAB80E71979A0EA883E5F81A3DF59F034703F4E0ED",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.7.3/limen_0.7.3_windows_amd64.tar.gz",
"checksum": "A5C43720E9D883CCCFF257EA88AFF6CC6E400983BB76BC26EB609FBD37EDA1A4",
"id": "github_release/github.com/farcloser/limen/v0.8.0/limen_0.8.0_windows_amd64.tar.gz",
"checksum": "9FF90A269A63C6739FD1AB73FD5262BB98D36145916E0D28D3E873453BDD6D57",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.7.3/limen_0.7.3_windows_arm64.tar.gz",
"checksum": "F4DF068E3790E236723AD8E52E6E5D58D684A989DE0EBB6452684B41600D856B",
"id": "github_release/github.com/farcloser/limen/v0.8.0/limen_0.8.0_windows_arm64.tar.gz",
"checksum": "EF61BC2AD757370C00AD313F2BBD247D7847E8C1A1F8E14FB72EBBCB19FEB12A",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.21.0/curl_8.21.0_darwin_arm64.tar.gz",
"checksum": "B2936D3902EC6ED96F9582C00616D2B033B5BB8EC5CB6330101D144482A56F85",
"id": "github_release/github.com/farcloser/ossein/v0.3.0/ossein_0.3.0_darwin_arm64.tar.gz",
"checksum": "3272F1D1117C2D4F2A8FD484963B0CE8979199D047D0FFA1D110838AB1C16E5F",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.21.0/curl_8.21.0_linux_amd64.tar.gz",
"checksum": "EC32B4B26F78F5AD98C64338DC29E67A3C61984E41A95B8792C77457D32DEF73",
"id": "github_release/github.com/forkcloser/curl/v8.22.0/curl_8.22.0_darwin_arm64.tar.gz",
"checksum": "E733869CF4FED3F5CB0F67E0AA37DD21216690D27C56525749E3F3A211227DD3",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.21.0/curl_8.21.0_linux_arm64.tar.gz",
"checksum": "841829B51F1F80FA05BB7382B25E0EBDD765325FA4F8B567461B4FCFB5653B5C",
"id": "github_release/github.com/forkcloser/curl/v8.22.0/curl_8.22.0_linux_amd64.tar.gz",
"checksum": "0DEE3074F44F56ADBCBB94C3DF506EC60BBFDA31DAA98FA537827C2A290A4666",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.21.0/curl_8.21.0_windows_amd64.tar.gz",
"checksum": "DCF632D027EC21B129D06C415C3C008D8DF241BC3516D43FC6B0327C6E35A087",
"id": "github_release/github.com/forkcloser/curl/v8.22.0/curl_8.22.0_linux_arm64.tar.gz",
"checksum": "C78C61656EC58AB22EA5107B686772811478B91BB97BAD1EADD259C990058EE0",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.21.0/curl_8.21.0_windows_arm64.tar.gz",
"checksum": "78EB1B53E55037111534CD2B87AD204DE04318A92C646554A78390BFB60E466F",
"id": "github_release/github.com/forkcloser/curl/v8.22.0/curl_8.22.0_windows_amd64.tar.gz",
"checksum": "9057B8D7890C58B7254F7207938ECA51C0A43D66B88B1FFD713DD84248941CD9",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/forkcloser/curl/v8.22.0/curl_8.22.0_windows_arm64.tar.gz",
"checksum": "4CEBEC6D937A154AE2DC16815E144831CA8F90B85C5E22BA93C6A128518C11DC",
"algorithm": "sha256"
},
{
Expand Down
2 changes: 1 addition & 1 deletion .aqua/aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ packages:
# are go.mod tools"). aqua's go_install would build it once per tool
# version, with whichever go ran first, and share that binary.
# --- farcloser tools (local registry; standard once registered upstream) ---
- name: farcloser/limen@v0.7.3 # renovate: depName=farcloser/limen
- name: farcloser/limen@v0.8.0 # renovate: depName=farcloser/limen
registry: local
- import: ../.limen/aqua.yaml
84 changes: 84 additions & 0 deletions .github/actions/windows-cache-image/action.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
name: Windows cache image
description: >
Windows only. Holds the Go build and module caches, aqua's root and the linter cache in one NTFS disk image (VHDX), cached as a single file. Restoring that file and attaching it costs under a minute; restoring the same caches as files writes 100,000+ small files, which costs several on the Windows runners. mode attach (before setup-aqua) restores or creates the image, attaches it at C:\vcache, points GOCACHE, GOMODCACHE and AQUA_ROOT_DIR into it, and excludes it from Defender's real-time scan; mode save (last, on a cache miss) detaches it and saves it.
inputs:
mode:
description: attach or save.
required: true
prefix:
description: The cache key's prefix, also the restore fallback (attach).
required: false
default: ''
hash:
description: What the key varies on, hashed before attach (attach).
required: false
default: ''
key:
description: The key attach reported (save).
required: false
default: ''
outputs:
key:
description: The exact cache key.
value: ${{ steps.attach.outputs.key }}
cache-hit:
description: true when the exact key was restored.
value: ${{ steps.restore.outputs.cache-hit }}
runs:
using: composite
steps:
- id: restore
if: inputs.mode == 'attach'
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: C:\vhd\cache.vhdx
key: ${{ inputs.prefix }}${{ inputs.hash }}
restore-keys: ${{ inputs.prefix }}

- name: Attach the image
id: attach
if: inputs.mode == 'attach'
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
"key=${{ inputs.prefix }}${{ inputs.hash }}" >> $env:GITHUB_OUTPUT
$vhd = 'C:\vhd\cache.vhdx'
New-Item -ItemType Directory -Force -Path C:\vhd, C:\vcache | Out-Null
if (Test-Path $vhd) {
$disk = Mount-DiskImage -ImagePath $vhd -NoDriveLetter -PassThru | Get-Disk
$part = Get-Partition -DiskNumber $disk.Number | Where-Object Type -eq 'Basic'
} else {
# Expandable: the file holds only what is written, so 40 GB is a ceiling.
"create vdisk file=`"$vhd`" maximum=40960 type=expandable`nselect vdisk file=`"$vhd`"`nattach vdisk" |
Set-Content -Encoding ascii C:\vhd\create.txt
diskpart /s C:\vhd\create.txt | Out-Null
$disk = Get-DiskImage -ImagePath $vhd | Get-Disk
Initialize-Disk -Number $disk.Number -PartitionStyle GPT
$part = New-Partition -DiskNumber $disk.Number -UseMaximumSize
# NTFS, not a Dev Drive: ReFS measured slower here.
Format-Volume -Partition $part -FileSystem NTFS -Confirm:$false -Force | Out-Null
}
Add-PartitionAccessPath -DiskNumber $disk.Number -PartitionNumber $part.PartitionNumber -AccessPath 'C:\vcache\'
# Without it, Defender scans every file on its first read from the
# image, and lint pays what the restore saved.
Add-MpPreference -ExclusionPath 'C:\vcache', 'C:\vhd'
# The linter cache lives under the workspace (main.just pins it there).
New-Item -ItemType Directory -Force -Path C:\vcache\golangci, "$env:GITHUB_WORKSPACE\build" | Out-Null
New-Item -ItemType Junction -Path "$env:GITHUB_WORKSPACE\build\cache" -Target C:\vcache\golangci | Out-Null
"GOCACHE=C:\vcache\go-build" >> $env:GITHUB_ENV
"GOMODCACHE=C:\vcache\mod" >> $env:GITHUB_ENV
"AQUA_ROOT_DIR=C:/vcache/aqua" >> $env:GITHUB_ENV

- name: Detach the image
if: inputs.mode == 'save'
shell: pwsh
run: |
$ErrorActionPreference = 'Stop'
Remove-Item "$env:GITHUB_WORKSPACE\build\cache" -Force
Dismount-DiskImage -ImagePath C:\vhd\cache.vhdx | Out-Null

- if: inputs.mode == 'save'
uses: actions/cache/save@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
with:
path: C:\vhd\cache.vhdx
key: ${{ inputs.key }}
6 changes: 5 additions & 1 deletion .limen/aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,5 +34,9 @@ packages:
# --- spec tooling (local registry; see .limen/aqua-registry.yaml) ---
- name: quint-co/quint@v0.33.0 # renovate: depName=quint-co/quint
registry: local
- name: forkcloser/curl@v8.21.0
- name: forkcloser/curl@v8.22.0
registry: local
# darwin/arm64 only. Its `docker` link shadows the machine's Docker on the
# hermetic PATH there; aqua skips the package everywhere else.
- name: farcloser/ossein@v0.3.0
registry: local
9 changes: 9 additions & 0 deletions .limen/just/lib.just
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,15 @@ _go-tool name pkg:
exit 1
fi

# The Go vulnerability database, fetched once into build/vulndb by `limen
# vulndb`, which retries (govulncheck's own client does not). Recipes depend
# on this, then pass govulncheck `-db "$(cat build/vulndb.url)"`.
_vulndb:
#!/usr/bin/env bash
set -euo pipefail
mkdir -p build
${LIMEN_BIN:-limen} vulndb build/vulndb > build/vulndb.url

# The golangci-lint configuration the lint and fix recipes run: the baseline
# limen-lint-go embeds with the project's .lint-go.yaml applied, rendered on
# every run into build/ (gitignored) — so an edit to the overlay is live at
Expand Down
18 changes: 16 additions & 2 deletions .limen/just/lint.just
Original file line number Diff line number Diff line change
Expand Up @@ -53,12 +53,12 @@ just: (_banner "lint" "just")
just --fmt --check --justfile "$f"
done < "$list"

# godolint — hadolint as pure Go (https://github.com/farcloser/godolint) —
# godolint — hadolint as pure Go (https://github.com/forkcloser/godolint) —
# over every Dockerfile in the repository; passes vacuously when there are
# none, so it can sit in the default set for every repo. Rule exceptions
# belong next to the instruction they excuse, as inline
# `# hadolint ignore=DLxxxx` pragmas — not in the recipe.
dockerfile: (_banner "lint" "dockerfile") (_go-tool "godolint" "github.com/farcloser/godolint/cmd/godolint")
dockerfile: (_banner "lint" "dockerfile") (_go-tool "godolint" "github.com/forkcloser/godolint/cmd/godolint")
#!/usr/bin/env bash
set -euo pipefail
# Same enumeration as `lint just` (through a file, see there), over both
Expand Down Expand Up @@ -243,6 +243,20 @@ commits range="": (_banner "lint" "commits") (_go-tool "git-validation" "github.
fi
done
fi
# git-validation asks git for every commit's signature status, so git
# verifies each signature: without the signers file and a gpg it prints
# an error per commit that reads like a failure. GIT_CONFIG_* hands git
# both without writing .git/config.
n=0
if [ -f .lint-signers ]; then
export GIT_CONFIG_KEY_0=gpg.ssh.allowedSignersFile GIT_CONFIG_VALUE_0=.lint-signers
n=1
fi
if [ -n "${GPG_BIN:-}" ]; then
export "GIT_CONFIG_KEY_$n=gpg.program" "GIT_CONFIG_VALUE_$n=$GPG_BIN"
n=$((n + 1))
fi
export GIT_CONFIG_COUNT=$n
if [ -n "$range" ]; then
build/tools/git-validation -run DCO,short-subject,dangling-whitespace -range "$range"
else
Expand Down
5 changes: 5 additions & 0 deletions .limen/just/main.just
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ project := file_name(justfile_directory())
# homebrew recipes then refuse); override by exporting BREW_BIN.
export BREW_BIN := env_var_or_default('BREW_BIN', `command -v brew || true`)

# gpg likewise, for git to check a PGP-signed commit (GitHub signs its merge
# and web-UI commits that way): macOS has none in the base system. Empty when
# absent; Windows' ambient PATH already carries Git for Windows' own.
export GPG_BIN := if os() == 'windows' { '' } else { env_var_or_default('GPG_BIN', `command -v gpg || true`) }

# aqua-pinned tools + base system only, so an unpinned tool fails loudly.
# Windows (git-bash) has no knowable base-system list and uses ';': pins are
# prepended to the ambient PATH there instead.
Expand Down
4 changes: 2 additions & 2 deletions .limen/just/security-go.just
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'lib.just'
default: vuln

# Known-vulnerability scan of the module's dependency graph against the Go
# vulnerability database (network: govulncheck fetches vuln.go.dev), once per
# vulnerability database (fetched once, see _vulndb in lib.just), once per
# supported platform (see _per-platform in lib.just: call paths and
# dependencies differ by platform). Reports what the module reaches, not what
# it merely imports: a finding is a call path to cut or a bump to take. No
Expand All @@ -29,4 +29,4 @@ vuln: (_banner "security go" "vuln")
fi
just do security go _vuln

_vuln: (_go-tool "govulncheck" "golang.org/x/vuln/cmd/govulncheck") (_per-platform "build/tools/govulncheck ./...")
_vuln: (_go-tool "govulncheck" "golang.org/x/vuln/cmd/govulncheck") _vulndb (_per-platform 'build/tools/govulncheck -db "$(cat build/vulndb.url)" ./...')
9 changes: 5 additions & 4 deletions .limen/just/security.just
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ default: go::default
# Every Go binary aqua pins carries its own copy of the standard library, built
# by its upstream with whatever Go they used that day: a fixed net/http or
# crypto/tls reaches us only when THEY rebuild. This scans each such binary
# against the Go vulnerability database (network: govulncheck fetches
# vuln.go.dev), by the symbols it links, so a known standard-library or module
# against the Go vulnerability database (fetched once, see _vulndb in
# lib.just), by the symbols it links, so a known standard-library or module
# vulnerability in a pinned tool is seen the day the advisory lands, whoever
# built it. The binaries the pinned toolchain builds here (tools/go.mod) are
# the go vuln lane's; this one is for what we did not build. Enumerated from
Expand All @@ -41,9 +41,10 @@ default: go::default
# vulnerabilities, aqua included, and a red no repository can clear is
# noise. It joins the default set once the pinned tools are built here with
# the pinned toolchain and aqua's own pin is current.
binaries: (_banner "security" "binaries") (_go-tool "govulncheck" "golang.org/x/vuln/cmd/govulncheck")
binaries: (_banner "security" "binaries") (_go-tool "govulncheck" "golang.org/x/vuln/cmd/govulncheck") _vulndb
#!/usr/bin/env bash
set -euo pipefail
db=$(cat build/vulndb.url)
bin="$(aqua root-dir)/bin"
# A newline-delimited list, not an associative array: macOS ships bash 3.
seen=$'\n'
Expand All @@ -60,7 +61,7 @@ binaries: (_banner "security" "binaries") (_go-tool "govulncheck" "golang.org/x/
# A darwin universal binary (goreleaser ships one) is beyond govulncheck's
# reader; the other platforms' legs scan that tool's thin binaries, so
# the darwin leg says so and moves on rather than failing on a format.
if ! out=$(build/tools/govulncheck -mode binary "$path" 2>&1); then
if ! out=$(build/tools/govulncheck -db "$db" -mode binary "$path" 2>&1); then
case "$out" in
*"unrecognized binary format"*) echo " skipped: universal binary, scanned on the other platforms";;
*) printf '%s\n' "$out"; fail=1;;
Expand Down
2 changes: 1 addition & 1 deletion .limen/renovate.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
],
"matchDepNames": [
"github.com/vbatts/git-validation",
"github.com/farcloser/godolint",
"github.com/forkcloser/godolint",
"github.com/forkcloser/dot",
"golang.org/x/tools",
"golang.org/x/vuln",
Expand Down
14 changes: 13 additions & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,9 @@ chapter; the procedure is limen's `skills/contribute`.
branches — `work`, and anything not named after you — are the human's: never commit
there unless pairing interactively at their request, and never on `main`.
- **Commits** are signed as you, with a DCO sign-off as you; when the change is the
human's own work, the human is the author. No scratchpads (`AUDIT.md` and its kind).
human's own work, the human is the author. No scratchpads (`AUDIT.md` and its kind):
they live under `_scratch/` at the repository root, which `.gitignore` ignores, and
nowhere else in the tree.
- **One commit per thing.** Different things get different commits; iteration on the
same thing — a review round, a fix to your own commit — is squashed into the commit it
amends before the review is requested. Never a stack of fix-ups for one change.
Expand Down Expand Up @@ -54,6 +56,11 @@ chapter; the procedure is limen's `skills/contribute`.
a one-line workflow bug: on the way through. Onboarding a legacy repository, a
wholesale cleanup of a broken one: the human decides first. Measure before moving.
- **A red inherited from `main`** is explained on the pull request, not fixed in it.
- **A flake is fixed when it is noticed.** A check that fails, then passes on a rerun, gets
its root cause and its fix at once, in a pull request of its own: by whoever noticed it,
or by the owning session when it is another repository's. The rerun found the flake; it
did not fix it. The one exception is a flake whose cause is known and whose fix was
declined, documented as such (windows-11-arm's silent exit 4 or 127): it is rerun, and named.
- **Doctrine can lose the argument, never silently.** A fix that cuts against the book is
named as such and argued; it is decided, not discovered.
- **Broken tooling is reported, never worked around in silence.** The rig — limen, the
Expand Down Expand Up @@ -126,6 +133,11 @@ chapter; the procedure is limen's `skills/contribute`.
get wrong at that spot; never provenance, versions, or what the code visibly does. The
reasoning goes in the commit message. See the book's
[generic principles](https://github.com/farcloser/limen/blob/main/book/index.md#generic-principles).
- **A module's `go` directive is the earliest Go release still supported upstream**, as
its first version (`go 1.N.0`), or the patch a dependency requires when that is higher
(what `go mod tidy` raises it to); never a newer release. The tools modules
(`tools/go.mod`, `tools/<name>/go.mod`) are exempt. See the book's
[baseline version](https://github.com/farcloser/limen/blob/main/book/per-language.md#go--the-baseline-version).
- **A `replace` directive is never committed**, nor anything that permits one (a
`gomoddirectives` `replace-local` or `replace-allow-list`). A local replace is a
temporary tool for working on two modules in parallel, on your machine, and stays there.
Expand Down
Loading
Loading