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
100 changes: 0 additions & 100 deletions .github/workflows/codeql.yml

This file was deleted.

34 changes: 0 additions & 34 deletions .github/workflows/go-test-platforms.yml

This file was deleted.

99 changes: 79 additions & 20 deletions .github/workflows/update-aqua-checksum.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,23 @@
# code the branch controls. `aqua update-checksum` only downloads and
# hashes declared artifacts; the converge step executes exactly one
# binary, the checksum-pinned limen release the branch declares.
# - The push step runs only git, with the token scoped to that single step.
# - The commit step runs only runner-provided tools (git, jq, base64,
# curl) — no branch-pinned binary ever touches the token, which is
# scoped to that single step.
# - The branch name reaches the shell via env, never template interpolation
# (script-injection hygiene).
# - No loop: a push made with the default GITHUB_TOKEN triggers no further
# workflows — and the no-change early exit terminates recursion
# - No loop: a commit made with the default GITHUB_TOKEN triggers no
# further workflows — and the no-change early exit terminates recursion
# regardless.
#
# The commit is created through the GraphQL createCommitOnBranch mutation,
# never a local `git commit` + push: GitHub signs the mutation's commits, and
# the `limen:main` ruleset requires signatures — an unsigned fix-up commit
# made every aqua-bump PR unmergeable (see the commit step for the full
# argument). Consequence of the mutation: the commit's author IS the token's
# identity, always — with the default token that is github-actions[bot],
# already listed in the canonical renovate.json5's gitIgnoredAuthors.
#
# Known trade of the default token: GitHub suppresses workflow runs for
# commits it pushes, so the PR's CI does not re-run on the checksum commit.
# To get CI on the final state of Renovate PRs, register a GitHub App —
Expand All @@ -42,6 +52,10 @@
# long-lived broad credential and nothing that expires on a calendar. A
# fine-grained PAT with contents:write as UPDATE_AQUA_CHECKSUM_TOKEN is the
# drop-in alternative; the token preference order is App, PAT, default.
# With an App or PAT the commit is authored as that identity (the mutation
# offers no override), so it must be added to gitIgnoredAuthors in
# renovate.json5 — or Renovate treats the branch as human-modified and
# stops rebasing it.
name: update-aqua-checksum

on:
Expand Down Expand Up @@ -111,27 +125,72 @@ jobs:
# happens to hold now or later.
permission-contents: write

- name: Push the update, if any
- name: Commit the update through the API, if any
env:
BRANCH: ${{ github.ref_name }}
TOKEN: ${{ steps.app-token.outputs.token || secrets.UPDATE_AQUA_CHECKSUM_TOKEN || github.token }}
run: |
[ -z "$(git status --porcelain)" ] && { echo "checksums and baseline already in sync"; exit 0; }
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
# `--all` is deliberate, not sloppiness. The tree is fully accounted
# for: a fresh checkout, aqua rooted outside the workspace, and
# exactly two writers between checkout and here — update-checksum
# and the pinned limen's fix. Whatever is dirty IS the payload. An
# enumerated path list would be wrong: the converge step's job is to
# commit whatever the NEW limen's baseline says, and a list baked
# into the older running workflow cannot know that surface (the
# updated workflow arrives in the very commit being built). Nor
# would a list add safety — the only writer that could plant a file
# is limen fix itself, and .limen/.github would be on any list.
git add --all
# The commit is made through GraphQL createCommitOnBranch, not a
# local `git commit` + push, because commits made through that
# mutation are signed by GitHub — and the `limen:main` ruleset
# requires signatures on everything landing on the default branch.
# A plain git push is unsigned, and one unsigned commit on the
# branch made every aqua-bump PR unmergeable: a merge commit would
# land it, GitHub disables rebase while signatures are required,
# and squash of a bot-authored PR is refused to everyone but the
# bot (see limen's book/github.md).
#
# Enumerating the whole dirty tree is deliberate, not sloppiness.
# The tree is fully accounted for: a fresh checkout, aqua rooted
# outside the workspace, and exactly two writers between checkout
# and here — update-checksum and the pinned limen's fix. Whatever
# is dirty IS the payload. An enumerated path list would be wrong:
# the converge step's job is to commit whatever the NEW limen's
# baseline says, and a list baked into the older running workflow
# cannot know that surface (the updated workflow arrives in the
# very commit being built). Nor would a list add safety — the only
# writer that could plant a file is limen fix itself, and
# .limen/.github would be on any list.
#
# Limit of the mutation, accepted: FileAddition carries no file
# mode, so an executable bit cannot travel — both writers here
# only ever produce plain configuration files.
additions="[]"
deletions="[]"
while IFS= read -r -d '' entry; do
path="${entry:3}"
if [ -f "${path}" ]; then
additions="$(jq --arg path "${path}" --arg contents "$(base64 -w0 "${path}")" \
'. + [{path: $path, contents: $contents}]' <<<"${additions}")"
else
deletions="$(jq --arg path "${path}" '. + [{path: $path}]' <<<"${deletions}")"
fi
done < <(git status --porcelain -z)
# Signed-off-by: `just do lint commits` enforces DCO on the PR range,
# bot commits included.
git commit -m "chore: update aqua checksums and converge the limen baseline" \
-m "Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
git push "https://x-access-token:${TOKEN}@github.com/${GITHUB_REPOSITORY}.git" "HEAD:${BRANCH}"
payload="$(jq -n \
--arg query 'mutation ($input: CreateCommitOnBranchInput!) { createCommitOnBranch(input: $input) { commit { oid } } }' \
--arg repository "${GITHUB_REPOSITORY}" \
--arg branch "${BRANCH}" \
--arg head "$(git rev-parse HEAD)" \
--argjson additions "${additions}" \
--argjson deletions "${deletions}" \
'{query: $query, variables: {input: {
branch: {repositoryNameWithOwner: $repository, branchName: $branch},
expectedHeadOid: $head,
message: {
headline: "chore: update aqua checksums and converge the limen baseline",
body: "Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>"
},
fileChanges: {additions: $additions, deletions: $deletions}}}}')"
# GraphQL reports failure in-body over HTTP 200, so success is the
# presence of the new commit oid, never the HTTP status.
response="$(curl -sS -X POST -H "Authorization: bearer ${TOKEN}" \
-d "${payload}" https://api.github.com/graphql)"
oid="$(jq -r '.data.createCommitOnBranch.commit.oid // empty' <<<"${response}")"
if [ -z "${oid}" ]; then
echo "${response}" >&2
exit 1
fi
echo "pushed ${oid}"
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# .gitignore

build

TODO.html
README.html

Expand Down Expand Up @@ -28,4 +30,4 @@ cmd/xb/xb
enwik8*

# file generated by example
example.xz
example.xz
20 changes: 19 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,22 @@ import '.limen/just/main.just'
# The FIRST recipe defined here becomes `just`'s default.
lint: do::lint::go::default do::lint::default
fix: do::fix::go::default do::fix::default
test:
test: do::test::go::unit do::test::go::race test-386
bench: do::test::go::bench

# 32-bit coverage: this codebase is int-width sensitive — dictionary and buffer
# arithmetic, int64 stream sizes narrowed to int, and index records whose
# declared sizes are bounded against the address space — and none of that is
# exercised by a 64-bit run. No development machine is 32-bit, but 386 binaries
# execute natively on amd64 hosts, so the amd64 CI legs run this for free;
# other hosts skip it loudly rather than silently reporting a pass they never
# obtained. The race detector does not support 386.
[doc('Run the tests as GOARCH=386 (executes natively on amd64 hosts; skipped elsewhere)')]
test-386:
#!/usr/bin/env bash
set -euo pipefail
if [ "$(go env GOHOSTARCH)" != "amd64" ]; then
echo "GOARCH=386 binaries need an amd64 host to execute; skipping"
exit 0
fi
CGO_ENABLED=0 GOARCH=386 go test -count=1 -timeout "${TEST_GO_TIMEOUT:-10m}" ./...
3 changes: 2 additions & 1 deletion TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,8 @@
* Update README.md
* xb copyright . in xz directory to ensure all new files have Copyright header
* `VERSION=<version> go generate github.com/forkcloser/xz/...` to update version files
* Execute [test for Linux/amd64, Linux/x86 and Windows/amd64](.github/workflows/go-test-platforms.yml).
* Run `just lint` and `just test` (the CI matrix runs the same recipes on
linux, macos and windows, amd64 and arm64, plus the 386 leg).
* Update TODO.md - write short log entry
* `git checkout main && git merge dev`
* `git tag -a <version>`
Expand Down
20 changes: 10 additions & 10 deletions aqua-checksums.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,28 +46,28 @@
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.0.11/limen_0.0.11_darwin_arm64.tar.gz",
"checksum": "D02B0AD949E5DFDA70BA7E8A65DC52EF1FBA30D61E714539D7A8124B13471CBA",
"id": "github_release/github.com/farcloser/limen/v0.0.12/limen_0.0.12_darwin_arm64.tar.gz",
"checksum": "EDCA1AF957C0F14178F6B29D473EC899F479BB3AF2A240020FAD5965F044AC99",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.0.11/limen_0.0.11_linux_amd64.tar.gz",
"checksum": "F53D6F8D32A05CE23E22F3603FDA224571949421F6AFDFED4EEC441CBA94242C",
"id": "github_release/github.com/farcloser/limen/v0.0.12/limen_0.0.12_linux_amd64.tar.gz",
"checksum": "551BC67781A4FD18F1941A9BE68320DB730B982DA62BBF41988F88E721B5EE65",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.0.11/limen_0.0.11_linux_arm64.tar.gz",
"checksum": "B16B8D8CCBF36E4C9FBAD5D1F5450E6A0ECEF347FDF8AFD1634A86950C16E076",
"id": "github_release/github.com/farcloser/limen/v0.0.12/limen_0.0.12_linux_arm64.tar.gz",
"checksum": "13C508CC4ECE232D033AA4E336DA96EFAE35E6C247F7BFE52F8E38824EC502B1",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.0.11/limen_0.0.11_windows_amd64.tar.gz",
"checksum": "2582F2A161D8E21BF0EA7EBA8C538438419FA333E1ACBC741CB7454603E9670F",
"id": "github_release/github.com/farcloser/limen/v0.0.12/limen_0.0.12_windows_amd64.tar.gz",
"checksum": "3CFE919FF7CBD49C0DACA0397B5E76330861C96CE4575E997B9D3C4833AE05E0",
"algorithm": "sha256"
},
{
"id": "github_release/github.com/farcloser/limen/v0.0.11/limen_0.0.11_windows_arm64.tar.gz",
"checksum": "0E87B3F45818510D3B2C83586664E04C43B947E88689B04A0FDDD03F9A2E71AB",
"id": "github_release/github.com/farcloser/limen/v0.0.12/limen_0.0.12_windows_arm64.tar.gz",
"checksum": "8DA23959424BABC09D0AED2798F1E3393A7DC2F594AE4BC8A098BADDAB03F210",
"algorithm": "sha256"
},
{
Expand Down
2 changes: 1 addition & 1 deletion aqua.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ packages:
- name: github.com/farcloser/godolint/cmd/godolint@v0.1.0
registry: local
# --- farcloser tools (local registry; standard once registered upstream) ---
- name: farcloser/limen@v0.0.11 # renovate: depName=farcloser/limen
- name: farcloser/limen@v0.0.12 # renovate: depName=farcloser/limen
registry: local
# --- toolchain + binary-release tools (standard registry, aqua-verified) ---
- name: golang/go@go1.26.5
Expand Down
19 changes: 16 additions & 3 deletions malformed_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,11 @@ import (
"errors"
"hash/crc32"
"io"
"math"
"math/rand"
"testing"

"github.com/forkcloser/xz/lzma"
)

// The parser's error branches are most of its code and were among its least
Expand Down Expand Up @@ -282,12 +285,22 @@ func TestHeaderAndFooterValidation(t *testing.T) {
// difference between a clear failure at construction and a confusing one
// later.
func TestWriterConfigValidation(t *testing.T) {
for name, c := range map[string]WriterConfig{
cases := map[string]WriterConfig{
"negative block size": {BlockSize: -1},
"bad checksum": {CheckSum: 0x7},
"tiny dict": {DictCap: 1},
"huge dict": {DictCap: 1 << 40},
} {
}
// A dictionary capacity above lzma.MaxDictCap (1<<32 - 1) is representable
// only where int is 64 bits wide. On a 32-bit platform every positive int
// is a legal capacity, so there is no over-range value to reject — and
// spelling one as a constant would not compile there. Both branches are
// type-checked on every platform, so math.MaxInt is what keeps this
// portable: it is in range for the int of whatever platform builds it.
if math.MaxInt > lzma.MaxDictCap {
cases["huge dict"] = WriterConfig{DictCap: math.MaxInt}
}

for name, c := range cases {
t.Run(name, func(t *testing.T) {
cfg := c
if err := cfg.Verify(); err == nil {
Expand Down