From 5029191cdf03b588fb083871b113fae7b8a99052 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Tue, 10 Nov 2026 08:31:37 +0000 Subject: [PATCH 1/2] chore(deps): update dependency farcloser/limen to v0.26.0 Signed-off-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .hermetic/hermetic.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.hermetic/hermetic.yaml b/.hermetic/hermetic.yaml index e388807..b8a4938 100644 --- a/.hermetic/hermetic.yaml +++ b/.hermetic/hermetic.yaml @@ -18,7 +18,7 @@ registries: packages: # --- farcloser tools (local registry; standard once registered upstream) --- - - name: farcloser/limen@v0.24.0 # renovate: depName=farcloser/limen + - name: farcloser/limen@v0.26.0 # renovate: depName=farcloser/limen registry: local - name: golang/go@go1.27.3 - import: ../.limen/hermetic.yaml From 7c5b0f54615ece966bd7c09a2be74247cf719003 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Tue, 10 Nov 2026 08:32:06 +0000 Subject: [PATCH 2/2] chore: refresh checksums and converge the limen baseline Signed-off-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> --- .github/actions/setup-hermetic/action.yaml | 35 ++++++++------ .hermetic/aqua-checksums.json | 56 +++++++++++----------- .limen/hermetic.yaml | 4 +- .limen/just/apple.just | 49 +++++++++++++++---- .limen/just/release.just | 46 ++++++++++++++++-- .limen/renovate.json | 15 ++++++ AGENTS.md | 17 ++++--- 7 files changed, 158 insertions(+), 64 deletions(-) diff --git a/.github/actions/setup-hermetic/action.yaml b/.github/actions/setup-hermetic/action.yaml index 87e30cd..f60cbfc 100644 --- a/.github/actions/setup-hermetic/action.yaml +++ b/.github/actions/setup-hermetic/action.yaml @@ -21,9 +21,9 @@ runs: # renovate: depName=forkcloser/hermetic HERMETIC_VERSION: v0.2.3 HERMETIC_CHECKSUMS_SHA256: c7eb09712dc3d756bead96ae1286b53de275134d0012601ef37f57ec793f9431 - # The job's own token, for `gh attestation verify` only, here and not - # exported: a read of GitHub's attestations API, before any - # branch-declared binary runs. + # The job's own token, for gh alone (the release download and + # `gh attestation verify`), here and not exported: reads of GitHub's + # API, before any branch-declared binary runs. GH_TOKEN: ${{ github.token }} run: | # Pin the root explicitly: hermetic's own default differs per @@ -71,16 +71,23 @@ runs: echo "hermetic ${HERMETIC_VERSION} already in the root (the cache image)" else tmp="$(mktemp -d)" - base="https://github.com/forkcloser/hermetic/releases/download/${HERMETIC_VERSION}" - # Retries for transient runner failures. Windows curl (schannel) - # refuses a handshake when the CA's revocation server is unreachable - # (exit 35, seen repeatedly): best-effort revocation still rejects a - # known-revoked certificate, and the checksums below are the real - # guard. schannel-only flag, so windows-only. - revoke=() - [ "$RUNNER_OS" != Windows ] || revoke=(--ssl-revoke-best-effort) - curl --proto '=https' --tlsv1.2 -fsSL --retry 5 --retry-delay 3 --retry-all-errors "${revoke[@]}" \ - -o "${tmp}/checksums.txt" "${base}/checksums.txt" + # Through the releases API with the job's token, by gh: the release + # page's download URL is an anonymous fetch, which GitHub throttles + # per runner IP under load (a 504 on every lane of a run, through + # curl's own retries), and a token sent there is routed, not checked. + # gh retries nothing itself; --clobber so a retry starts over. A + # pattern no asset matches is not an error to gh while another + # matches, so each file is checked for. + attempt=0 + until gh release download "${HERMETIC_VERSION}" --repo forkcloser/hermetic --dir "${tmp}" --clobber \ + --pattern checksums.txt --pattern "${asset}"; do + attempt=$((attempt + 1)) + [ "$attempt" -lt 5 ] || { echo "::error::hermetic ${HERMETIC_VERSION}: checksums.txt or ${asset} could not be downloaded"; exit 1; } + sleep 3 + done + for f in checksums.txt "${asset}"; do + [ -f "${tmp}/${f}" ] || { echo "::error::hermetic ${HERMETIC_VERSION} has no release asset ${f}"; exit 1; } + done # No single digest tool exists everywhere: linux and windows git-bash # ship coreutils sha256sum, macOS ships perl shasum. A mismatch names # the computed digest and the size beside the expected one: a stale @@ -101,8 +108,6 @@ runs: echo "sha256 ok: $(basename "$file")" } verify_sha256 "${HERMETIC_CHECKSUMS_SHA256}" "${tmp}/checksums.txt" - curl --proto '=https' --tlsv1.2 -fsSL --retry 5 --retry-delay 3 --retry-all-errors "${revoke[@]}" \ - -o "${tmp}/${asset}" "${base}/${asset}" expected="$(awk -v a="$asset" '$2 == a {print $1}' "${tmp}/checksums.txt")" [ -n "$expected" ] || { echo "::error::checksums.txt of hermetic ${HERMETIC_VERSION} does not list ${asset}"; exit 1; } verify_sha256 "${expected}" "${tmp}/${asset}" diff --git a/.hermetic/aqua-checksums.json b/.hermetic/aqua-checksums.json index e04cdb4..8d8088d 100644 --- a/.hermetic/aqua-checksums.json +++ b/.hermetic/aqua-checksums.json @@ -1,23 +1,23 @@ { "checksums": [ { - "id": "github_release/github.com/anchore/syft/v1.55.0/syft_1.55.0_darwin_arm64.tar.gz", - "checksum": "1217C258BD5EB91EF3189CF22A82E02F9CAC07E4CE934350F428E93AFF674625", + "id": "github_release/github.com/anchore/syft/v1.57.0/syft_1.57.0_darwin_arm64.tar.gz", + "checksum": "17012A5A110323BB1069E513A8665F1AE445905C56B4E3F9A9DF4F95C5BB6161", "algorithm": "sha256" }, { - "id": "github_release/github.com/anchore/syft/v1.55.0/syft_1.55.0_linux_amd64.tar.gz", - "checksum": "BB65249542DB5FEDEEB4D3F9B018B75E7264DBFBBB10486F044581A92F90490D", + "id": "github_release/github.com/anchore/syft/v1.57.0/syft_1.57.0_linux_amd64.tar.gz", + "checksum": "9C077A7D43029B3B13E98A8DB720661E700C4D58DB6352153A06395AE4A2A704", "algorithm": "sha256" }, { - "id": "github_release/github.com/anchore/syft/v1.55.0/syft_1.55.0_linux_arm64.tar.gz", - "checksum": "929BD163DB2D7CD2255D3BCB8967208079813D7B46B0C952F7B794D8E2C7D304", + "id": "github_release/github.com/anchore/syft/v1.57.0/syft_1.57.0_linux_arm64.tar.gz", + "checksum": "410CBFA0AE0F63246BC0057843760B1DE2833CD23919E025E368FD7681308CDB", "algorithm": "sha256" }, { - "id": "github_release/github.com/anchore/syft/v1.55.0/syft_1.55.0_windows_amd64.zip", - "checksum": "ADA4C9B93AF575F479CE80FCE6629897272A2D41F300A14BC49BACE020767CA2", + "id": "github_release/github.com/anchore/syft/v1.57.0/syft_1.57.0_windows_amd64.zip", + "checksum": "06E9663E55F7F38FF966710670FBE0763182C621F7AC2F191BCB209A6DFBD969", "algorithm": "sha256" }, { @@ -66,28 +66,28 @@ "algorithm": "sha256" }, { - "id": "github_release/github.com/farcloser/limen/v0.24.0/limen_0.24.0_darwin_arm64.tar.gz", - "checksum": "BB7F8386488E585FE59F871CD3D5A4F74E8DA17B51118A11FE6FABA1C91E6FEB", + "id": "github_release/github.com/farcloser/limen/v0.26.0/limen_0.26.0_darwin_arm64.tar.gz", + "checksum": "6C013BBA485F3081BBA15342E7F6A9BB62B63E5D10D548DC2D425FACBE01CE87", "algorithm": "sha256" }, { - "id": "github_release/github.com/farcloser/limen/v0.24.0/limen_0.24.0_linux_amd64.tar.gz", - "checksum": "8FD7C868E5C26E3E04C2F0F83D0904D271A9D7FD596E8D4303DC9689B8869209", + "id": "github_release/github.com/farcloser/limen/v0.26.0/limen_0.26.0_linux_amd64.tar.gz", + "checksum": "C054388FC8BD99D049C2D342FEC6422AAD181FFA4B1520D2E789E16A90D8C8F6", "algorithm": "sha256" }, { - "id": "github_release/github.com/farcloser/limen/v0.24.0/limen_0.24.0_linux_arm64.tar.gz", - "checksum": "BDC58258E2B6280AFEF8AD7D8965D19B4AC3AB0C741C9FDC126403847F279E04", + "id": "github_release/github.com/farcloser/limen/v0.26.0/limen_0.26.0_linux_arm64.tar.gz", + "checksum": "AF2541BCCE26DFEEC8B62F802327E65EAC6C054D8647D251370E4072F668FB5A", "algorithm": "sha256" }, { - "id": "github_release/github.com/farcloser/limen/v0.24.0/limen_0.24.0_windows_amd64.tar.gz", - "checksum": "9B862D79FCBB33676F2304FDA902A39F7623BB543EB43693F1F8015B2531730B", + "id": "github_release/github.com/farcloser/limen/v0.26.0/limen_0.26.0_windows_amd64.tar.gz", + "checksum": "53F06B63777631B57F08FBDE8BD466AA456286D54701DFD04553AF06306C14A0", "algorithm": "sha256" }, { - "id": "github_release/github.com/farcloser/limen/v0.24.0/limen_0.24.0_windows_arm64.tar.gz", - "checksum": "05F751B5F5DB7FDB8544ACC055D9330A6CFDA64897FE31339B210A64C5C1CC49", + "id": "github_release/github.com/farcloser/limen/v0.26.0/limen_0.26.0_windows_arm64.tar.gz", + "checksum": "E83991B59F70E7DA0AB7A22FEAC93F6BF58768C683901C1B1D458BC4130E4879", "algorithm": "sha256" }, { @@ -156,28 +156,28 @@ "algorithm": "sha256" }, { - "id": "github_release/github.com/goreleaser/goreleaser/v2.19.0/goreleaser_Darwin_all.tar.gz", - "checksum": "21ADCEFF6E676EF63497FC129983F8C454E5A46EC0125B905CBA0F83E7879722", + "id": "github_release/github.com/goreleaser/goreleaser/v2.20.0/goreleaser_Darwin_all.tar.gz", + "checksum": "B4F0702BCB2AAD05BD13AF5AC69EC94D84270DCE59B917E7A8C446C974E29372", "algorithm": "sha256" }, { - "id": "github_release/github.com/goreleaser/goreleaser/v2.19.0/goreleaser_Linux_arm64.tar.gz", - "checksum": "EF33741B684C9F62D6A21E7A3C8B051F139EA7B1D301693B67CC819C46226D53", + "id": "github_release/github.com/goreleaser/goreleaser/v2.20.0/goreleaser_Linux_arm64.tar.gz", + "checksum": "2DADA0A6BBCD10F3A05228D98E77D25FB362EFB9E5BAB6362CF37E64C8A26CB9", "algorithm": "sha256" }, { - "id": "github_release/github.com/goreleaser/goreleaser/v2.19.0/goreleaser_Linux_x86_64.tar.gz", - "checksum": "EBC3194AD1D1B1787614405285A0039665CD4C5BD3305215A1B201600F90630B", + "id": "github_release/github.com/goreleaser/goreleaser/v2.20.0/goreleaser_Linux_x86_64.tar.gz", + "checksum": "D2483159E6007F814132CB56635AD30A70013DBEB813D6033A7E01ADF6AE108C", "algorithm": "sha256" }, { - "id": "github_release/github.com/goreleaser/goreleaser/v2.19.0/goreleaser_Windows_arm64.zip", - "checksum": "FF7A728EBDF86770D45C522F88B901E7FB3C06692B0D0C6A8A3A2C9BCF01B682", + "id": "github_release/github.com/goreleaser/goreleaser/v2.20.0/goreleaser_Windows_arm64.zip", + "checksum": "B7AE30D558DB74D67BD03E39D3309AABF47E1A18649EF4AC4429F329C357F496", "algorithm": "sha256" }, { - "id": "github_release/github.com/goreleaser/goreleaser/v2.19.0/goreleaser_Windows_x86_64.zip", - "checksum": "67807490E909A37F58EF40B67601896D8D4DA2411C9839221DAE55732C243FE9", + "id": "github_release/github.com/goreleaser/goreleaser/v2.20.0/goreleaser_Windows_x86_64.zip", + "checksum": "3C6A58F6941224A25EC28DE733554743E9B2517C40C76991EEF5474F8C1C2C1A", "algorithm": "sha256" }, { diff --git a/.limen/hermetic.yaml b/.limen/hermetic.yaml index f7f9f82..9dce0ba 100644 --- a/.limen/hermetic.yaml +++ b/.limen/hermetic.yaml @@ -32,10 +32,10 @@ packages: - name: casey/just@1.59.0 - name: koalaman/shellcheck@v0.11.0 - name: lycheeverse/lychee@lychee-v0.24.2 - - name: goreleaser/goreleaser@v2.19.0 + - name: goreleaser/goreleaser@v2.20.0 - name: sigstore/cosign@v3.1.4 # The SBOM generator the release lane runs over every archive (book/releasing.md). - - name: anchore/syft@v1.55.0 + - name: anchore/syft@v1.57.0 - name: jqlang/jq@jq-1.8.2 - name: cli/cli@v2.103.3 # --- spec tooling (local registry; see .limen/hermetic-registry.yaml) --- diff --git a/.limen/just/apple.just b/.limen/just/apple.just index c948041..1188c47 100644 --- a/.limen/just/apple.just +++ b/.limen/just/apple.just @@ -63,8 +63,8 @@ apple-verify-notarized bundle: echo "apple-verify-notarized: $bundle carries a valid stapled ticket" # Submit the signed bundle to Apple and staple the ticket. The verdict is -# notarytool's own "status: Accepted": --wait's exit status is not it. Without -# an identity (a local build) there is nothing to notarize and the recipe says +# notarytool's own "status: Accepted", never an exit status. Without an +# identity (a local build) there is nothing to notarize and the recipe says # so; with one and no credentials it fails, since a Developer ID build that # leaves here unnotarized would be refused on every install. [doc('Notarize a signed bundle with notarytool and staple the ticket')] @@ -84,17 +84,46 @@ apple-notarize bundle: rm -f "$archive" ditto -c -k --sequesterRsrc --keepParent "$bundle" "$archive" key=(--key "${APPLE_NOTARY_KEY:?}" --key-id "${APPLE_NOTARY_KEY_ID:?}" --issuer "${APPLE_NOTARY_ISSUER_ID:?}") - submission=$(xcrun notarytool submit "$archive" --wait "${key[@]}" 2>&1 | tee /dev/stderr) || true + # Submit, wait and the verdict are separate calls, each retried on its + # own: a connection that drops during the wait loses the verdict on an + # upload Apple already holds. Only a submit that exits 0 has finished its + # upload, so a failed one is submitted again; once one has, its id is + # waited on and asked about, never submitted again. + for attempt in 1 2 3; do + submission=$(xcrun notarytool submit "$archive" --no-wait "${key[@]}" 2>&1 | tee /dev/stderr) && break + [ "$attempt" -lt 3 ] || { echo "apple-notarize: $archive could not be submitted" >&2; exit 1; } + sleep $((attempt * 15)) + done id=$(printf '%s\n' "$submission" | sed -n 's/^ *id: \([0-9a-f-]*\)$/\1/p' | head -n 1) - if ! printf '%s\n' "$submission" | grep -q '^ *status: Accepted$'; then - echo "apple-notarize: Apple did not accept the submission${id:+ $id}" >&2 - [ -z "$id" ] || xcrun notarytool log "$id" "${key[@]}" >&2 || true + [ -n "$id" ] || { echo "apple-notarize: notarytool submit returned no submission id" >&2; exit 1; } + # A "status:" line is the end of processing, whatever wait exits with; + # anything else is a wait cut short, resumed on the same id. + for attempt in 1 2 3 4 5; do + waited=$(xcrun notarytool wait "$id" "${key[@]}" 2>&1 | tee /dev/stderr) && break + printf '%s\n' "$waited" | grep -q '^ *status: ' && break + [ "$attempt" -lt 5 ] || { echo "apple-notarize: submission $id did not finish processing" >&2; exit 1; } + sleep $((attempt * 15)) + done + for attempt in 1 2 3; do + info=$(xcrun notarytool info "$id" "${key[@]}" 2>&1 | tee /dev/stderr) && break + [ "$attempt" -lt 3 ] || { echo "apple-notarize: the status of submission $id could not be read" >&2; exit 1; } + sleep $((attempt * 10)) + done + if ! printf '%s\n' "$info" | grep -q '^ *status: Accepted$'; then + echo "apple-notarize: Apple did not accept the submission $id" >&2 + xcrun notarytool log "$id" "${key[@]}" >&2 || true exit 1 fi - # staple validates what it writes; a second validate only asks the - # network again. - xcrun stapler staple "$bundle" - echo "apple-notarize: $bundle notarized (submission ${id:-?}), ticket stapled" + # staple fetches the ticket from Apple's ticket service and validates + # what it writes: a connection that drops on the runner fails it with the + # submission accepted, so it is tried five times, further apart each time, + # before the release stops. + for attempt in 1 2 3 4 5; do + xcrun stapler staple "$bundle" && break + [ "$attempt" -lt 5 ] || { echo "apple-notarize: the ticket for submission $id could not be stapled" >&2; exit 1; } + sleep $((attempt * 15)) + done + echo "apple-notarize: $bundle notarized (submission $id), ticket stapled" # ditto, not zip: the archiver that keeps a bundle's extended attributes and # code signature intact, so what a user unzips is what was signed. diff --git a/.limen/just/release.just b/.limen/just/release.just index ddc5db6..b99bb4a 100644 --- a/.limen/just/release.just +++ b/.limen/just/release.just @@ -50,9 +50,13 @@ release *args: } # A fourth segment is a fork's rebuild of the same upstream version # (v10.6.1.2, book/forks.md): never a -suffix, which semver sorts before - # the release it rebuilds. + # the release it rebuilds. A rebuild carries no prerelease of its own: + # goreleaser reads no semver from it (--ci below), so a suffix would be + # published as a full release. + rebuild_tag_re='^v[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$' require_version_tag() { - if ! printf '%s' "$1" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(\.[0-9]+)?(-[0-9A-Za-z][0-9A-Za-z.-]*)?$'; then + if ! printf '%s' "$1" | grep -qE '^v[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z][0-9A-Za-z.-]*)?$' && + ! printf '%s' "$1" | grep -qE "$rebuild_tag_re"; then echo "'$1' is not a version tag (vX.Y.Z, vX.Y.Z-prerelease, or a fork's rebuild vX.Y.Z.N)." >&2 exit 2 fi @@ -154,7 +158,22 @@ release *args: echo "HEAD carries no tag — this lane only runs on a tag push." >&2 exit 1 fi - exec goreleaser release --config .release-go.yaml --clean + # goreleaser refuses a tag that is not semver, and a fork's + # rebuild tag is not: --skip=validate is its one way past, and it + # also drops goreleaser's dirty-tree and tag-at-HEAD checks, so + # the two are made here first, on the tag this run was pushed for. + opts=() + tag="${GITHUB_REF_NAME:-}" + if printf '%s' "$tag" | grep -qE "$rebuild_tag_re"; then + require_clean + if ! git describe --exact-match --tags --match "$tag" HEAD >/dev/null 2>&1; then + echo "$tag is not on HEAD — this lane releases the tag its run was pushed for." >&2 + exit 1 + fi + export GORELEASER_CURRENT_TAG="$tag" + opts+=(--skip=validate) + fi + exec goreleaser release --config .release-go.yaml --clean ${opts[@]+"${opts[@]}"} ;; --dry-run) echo "dry runs are a local concern: use 'just do release --local --dry-run'." >&2 @@ -218,3 +237,24 @@ release *args: fi ;; esac + +# goreleaser's sign command (.release-go.yaml `signs:`): one keyless +# signature over a release file, in CI. cosign gives up on Fulcio at the first +# dropped connection and retries Rekor once, so a reset on the runner fails +# the release with nothing wrong in it. Every attempt is a fresh key, a fresh +# certificate and a new log entry, so one that failed halfway cannot collide +# with the next; its partial bundle is removed first. +[doc("Sign a release file keyless with cosign into a Sigstore bundle (goreleaser's sign command)")] +[positional-arguments] +release-sign file bundle: + #!/usr/bin/env bash + set -euo pipefail + file="$1" bundle="$2" + for attempt in 1 2 3; do + rm -f "$bundle" + if cosign sign-blob --yes --bundle "$bundle" "$file" && [ -s "$bundle" ]; then + exit 0 + fi + [ "$attempt" -lt 3 ] || { echo "release-sign: $file could not be signed" >&2; exit 1; } + sleep $((attempt * 15)) + done diff --git a/.limen/renovate.json b/.limen/renovate.json index a24afd8..f133be6 100644 --- a/.limen/renovate.json +++ b/.limen/renovate.json @@ -19,6 +19,7 @@ "packageRules, golang/go, versioning: Go tags its releases go1.N.M, and the candidates golang/go offers are tags (it publishes no GitHub release). The regex managers' default versioning, semver-coerced, parses such a tag but calls every one unstable, since its stability check accepts only a bare or v-prefixed number; from a current version it holds unstable, Renovate lets through only a candidate with the same major, minor and patch, so no bump was ever proposed, silently. Regex versioning that carries the prefix parses the pin and the candidates alike, as lychee's does, and leaves the rc tags out by construction. Out of the aqua tools group: a toolchain patch is the standard-library fix the pin exists to receive without delay, in a pull request that names it.", "packageRules, lychee: releases are tagged lychee-vX.Y.Z next to lychee-lib-vX.Y.Z and nightly; regex versioning that carries the prefix parses the pin and the candidates alike and excludes the others by construction.", "packageRules, git-for-windows: releases are tagged vX.Y.Z.windows.N, and the N moves on its own (a Git for Windows rebuild of the same Git); a semver reading drops it and would never propose that bump. The build group carries it, and release candidates (vX.Y.Z-rcN.windows.N) fall outside the pattern.", + "packageRules, own releases, versioning: a fork's rebuild of the same upstream version is tagged with a fourth segment, vX.Y.Z.N (book/forks.md); the regex managers' default versioning, semver-coerced, reads v8.22.0.2 as 8.22.0 and so never proposes a rebuild (limen stayed on forkcloser/curl v8.22.0 through v8.22.0.1 and v8.22.0.2). The build group carries the fourth segment; absent, the release compares as the one its rebuilds follow, and a -suffix stays a prerelease. The rule claims a pin by its current value, a v-prefixed version, since a packageRule's versioning overrides the one a pins.yaml entry declares for itself: a release line of another shape (ossein-kernel's X.Y.Z-ossein.N, read by its own regex in the pin) keeps its own.", "packageRules, runner images: the github-actions manager, which config:recommended enables, also proposes the runs-on images (ubuntu-24.04 to 26.04, macos-15 to 26) from the github-runners datasource. Those are product targets, not dependencies: the matrix is the set of platforms the code and the commands are proven on, set by the canonical ci.yaml seed and moved deliberately, on purpose, as a reviewed change. Off for that datasource; the actions themselves keep moving.", "customManagers, pins.yaml: the artifacts a repository fetches by hand (a kernel tarball, a toolchain release, a source archive) live in one limen-owned file, each entry naming its own datasource and depName on its renovate: line (or `manual`, the one word, for a pin no datasource serves, which the regex below then leaves alone and a hand moves), optionally an extract-version regexp and a versioning scheme on the two lines after it, the version: line that moves, and for a commit pin (git-refs: the version is the branch) a commit: line after it, captured as the digest, so Renovate proposes the branch's new head. The digest follows in the same pull request: the checksum workflow runs `limen pins refresh`, which recomputes it through the verifier the entry declares. Watched here, once, for every repository; nobody writes a regex manager per pin.", "commitBody: `just do lint commits` enforces DCO on every PR range, bot commits included.", @@ -191,6 +192,20 @@ ], "versioning": "regex:^v(?\\d+)\\.(?\\d+)\\.(?\\d+)\\.windows\\.(?\\d+)$" }, + { + "matchManagers": [ + "custom.regex" + ], + "matchDatasources": [ + "github-releases", + "github-tags" + ], + "matchDepNames": [ + "/^(farcloser|forkcloser|mycophonic)/[^/]+$/" + ], + "matchCurrentValue": "/^v\\d+\\.\\d+\\.\\d+(\\.\\d+)?(-[0-9A-Za-z.-]+)?$/", + "versioning": "regex:^v(?\\d+)\\.(?\\d+)\\.(?\\d+)(?:\\.(?\\d+))?(?:-(?[0-9A-Za-z.-]+))?$" + }, { "matchDepNames": [ "golang/go" diff --git a/AGENTS.md b/AGENTS.md index 22de83f..db3e787 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -83,17 +83,22 @@ chapter; the procedure is limen's `skills/contribute`. private repository is never armed: its pull request is bound for the human, who merges by hand after approving. No review request, no review comments, no message at open. - **Your worktree goes when its pull request has merged.** Once `git status` in it is clean - and its head is on `main`, remove it with `~/.claude/bin/farclauder worktree remove `, - run as the whole Bash command: `git worktree remove` cannot finish inside the sandbox, and - the exclusion that runs farclauder outside it matches the call's text (the book's + and its head is on `main`, remove it with + `/Users/apostasie/.claude/bin/farclauder worktree remove `, run as the whole Bash + command and by that absolute path: `git worktree remove` cannot finish inside the sandbox, + and the exclusion that runs farclauder outside it matches the call's text, which the `~` + form does not (the book's [identity](https://github.com/farcloser/limen/blob/main/book/identity.md)). - **A native stack** is reviewed and opened layer by layer the same way; the project manager merges it from the top once every layer is approved, never from the middle. A lower layer merged alone comes back rebased and signed by GitHub, which `lint commits` rejects. -- **Not yours to do:** merge by hand, push to `main`, force-push a shared branch, tag a - release. A release waits for an empty queue: no tag while a pull request is open, a bot's - included, unless the human parks it by number for that tag (`PARKED_PRS`). +- **Not yours to do:** merge by hand, push to `main` (but for the empty `Birth` commit that + creates it on a new repository, the book's + [creating a repository](https://github.com/farcloser/limen/blob/main/book/github.md#creating-a-repository)), + force-push a shared branch, tag a release. A release waits for an empty queue: no tag + while a pull request is open, a bot's included, unless the human parks it by number for + that tag (`PARKED_PRS`). ## Scope