From d9127d7124806095ff5c87b7635173035f954d78 Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Fri, 4 Sep 2026 16:47:46 -0500 Subject: [PATCH 1/4] Add cua-driver-bin, the Cua computer-use driver, to the fast ring cua-driver ships prebuilt from the trycua/cua monorepo release feed. The declarative github provider reads a release feed as a single product and trips on the monorepo's foreign and hyphenated tags, so a bespoke .omarchy/upstream.sh selects the newest stable cua-driver-rs release by tag shape (upstream flags every driver release prerelease; nightlies are distinguished by tag prefix instead) and reads its checksums.txt manifest. The vendor tree stays together under /usr/lib/cua-driver with a /usr/bin symlink, matching upstream's own layout: the CLI resolves its cursor-theme compiler as a sibling of /proc/self/exe. Verified by installing the built package into a clean archlinux:base container and exercising the CLI. --- .../cua-driver-bin/.omarchy/package.json | 5 ++ pkgbuilds/cua-driver-bin/.omarchy/upstream.sh | 90 +++++++++++++++++++ pkgbuilds/cua-driver-bin/LICENSE | 21 +++++ pkgbuilds/cua-driver-bin/PKGBUILD | 61 +++++++++++++ 4 files changed, 177 insertions(+) create mode 100644 pkgbuilds/cua-driver-bin/.omarchy/package.json create mode 100644 pkgbuilds/cua-driver-bin/.omarchy/upstream.sh create mode 100644 pkgbuilds/cua-driver-bin/LICENSE create mode 100644 pkgbuilds/cua-driver-bin/PKGBUILD diff --git a/pkgbuilds/cua-driver-bin/.omarchy/package.json b/pkgbuilds/cua-driver-bin/.omarchy/package.json new file mode 100644 index 0000000..bbe9ae1 --- /dev/null +++ b/pkgbuilds/cua-driver-bin/.omarchy/package.json @@ -0,0 +1,5 @@ +{ + "source": "local", + "release_ring": "fast", + "min_release_age": "24h" +} diff --git a/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh new file mode 100644 index 0000000..2833d64 --- /dev/null +++ b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh @@ -0,0 +1,90 @@ +#!/bin/bash +# cua-driver ships from the trycua/cua monorepo, whose single release feed +# interleaves many products (cua-driver-rs-v*, fleet-v*, sandbox-v*, and +# nightly-* builds). The declarative github provider reads a feed as one +# product and stops on the first foreign tag, so this hook selects the newest +# stable cua-driver-rs release itself and reads its checksums.txt manifest. +set -euo pipefail + +REPO="trycua/cua" +TAG_PREFIX="cua-driver-rs-v" + +releases=$(curl -fsSL "https://api.github.com/repos/$REPO/releases?per_page=100") + +min_age="${MIN_RELEASE_AGE_SECONDS:-0}" +now=$(date +%s) +candidates=0 +best_pkgver="" best_tag="" best_published="" +while IFS=$'\t' read -r tag published_at; do + [[ "$tag" == "$TAG_PREFIX"* ]] || continue + pkgver=${tag#"$TAG_PREFIX"} + # Upstream marks every driver release "prerelease" so the monorepo's + # "latest" can point at another product; stability lives in the tag shape + # instead. Stable driver versions are plain dotted numbers -- nightlies + # carry a nightly- tag prefix and a -nightly.N version suffix, and both + # fall out here. + [[ "$pkgver" =~ ^[0-9]+(\.[0-9]+)*$ ]] || continue + + # Strict ISO 8601 before GNU date sees it, matching bin/sync-upstream's + # backstop: date alone also accepts relative expressions, which would let a + # malformed feed fabricate an age instead of failing closed. + if [[ ! "$published_at" =~ ^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(\.[0-9]+)?(Z|[+-][0-9]{2}:?[0-9]{2})$ ]] \ + || ! published_epoch=$(date --date="$published_at" +%s 2>/dev/null); then + echo "$REPO release $tag has an invalid published_at: ${published_at:-}" >&2 + exit 1 + fi + candidates=$((candidates + 1)) + + if (( now - published_epoch < min_age )); then + if [[ "${BYPASS_MIN_RELEASE_AGE:-}" == "1" ]]; then + echo "Bypassing release-age gate for $REPO $tag" >&2 + else + continue + fi + fi + + if [[ -z "$best_pkgver" ]] || [[ "$(vercmp "$pkgver" "$best_pkgver")" -gt 0 ]]; then + best_pkgver=$pkgver + best_tag=$tag + best_published=$published_at + fi +done < <(jq -r '.[] | select(.draft | not) | [.tag_name // "", .published_at // ""] | @tsv' <<<"$releases") + +# A feed page with no stable driver release at all is an anomaly worth a loud +# error; every candidate merely being inside the quarantine window is not. +if (( candidates == 0 )); then + echo "no stable $TAG_PREFIX releases in the feed for $REPO" >&2 + exit 1 +fi +if [[ -z "$best_tag" ]]; then + echo "every recent $TAG_PREFIX release is still inside the release-age quarantine; skipping" >&2 + echo '{}' + exit 0 +fi + +current=$(grep -m1 '^pkgver=' PKGBUILD | cut -d= -f2- | tr -d "\"'") +if [[ -n "$current" ]] && [[ "$(vercmp "$best_pkgver" "$current")" -le 0 ]]; then + echo '{}' + exit 0 +fi + +checksums=$(curl -fsSL "https://github.com/$REPO/releases/download/$best_tag/checksums.txt") + +sums_json='{}' +for arch in x86_64 aarch64; do + case "$arch" in + x86_64) platform="linux-x86_64" ;; + aarch64) platform="linux-arm64" ;; + esac + asset="cua-driver-rs-${best_pkgver}-${platform}.tar.gz" + sum=$(awk -v f="$asset" '$2 == f { print $1; exit }' <<<"$checksums") + if [[ ! "$sum" =~ ^[0-9a-f]{64}$ ]]; then + echo "no valid checksum for $asset in $REPO $best_tag checksums.txt" >&2 + exit 1 + fi + sums_json=$(jq -c --arg arch "$arch" --arg sum "$sum" '.[$arch] = [$sum]' <<<"$sums_json") +done + +jq -n --arg pkgver "$best_pkgver" --arg published_at "$best_published" \ + --argjson sums "$sums_json" \ + '{pkgver: $pkgver, published_at: $published_at, sha256sums: $sums}' diff --git a/pkgbuilds/cua-driver-bin/LICENSE b/pkgbuilds/cua-driver-bin/LICENSE new file mode 100644 index 0000000..b8b198c --- /dev/null +++ b/pkgbuilds/cua-driver-bin/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 Cua AI, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/pkgbuilds/cua-driver-bin/PKGBUILD b/pkgbuilds/cua-driver-bin/PKGBUILD new file mode 100644 index 0000000..d1ec04f --- /dev/null +++ b/pkgbuilds/cua-driver-bin/PKGBUILD @@ -0,0 +1,61 @@ +# Maintainer: Spencer Bull + +# cua-driver ships prebuilt from the trycua/cua monorepo release feed, so this +# repackages the vendor tarball. Upstream keeps the CLI, its cursor-theme +# compiler, and the SDK artifacts together in one directory and exposes the +# CLI through a symlink -- the binary resolves its helpers as siblings of +# /proc/self/exe -- so the whole tree lands under /usr/lib/cua-driver with a +# /usr/bin symlink. .omarchy/upstream.sh rewrites the version and checksums +# below from the release feed. + +pkgname=cua-driver-bin +pkgver=0.23.2 +pkgrel=1 +pkgdesc="Computer-use driver for native GUI apps: accessibility-tree snapshots and input injection" +arch=('x86_64' 'aarch64') +url="https://github.com/trycua/cua" +license=('MIT') +# at-spi2-core carries the AT-SPI accessibility bus the driver reads GUI +# trees through; the X libraries are linked, not dlopen'd. +depends=( + 'at-spi2-core' + 'gcc-libs' + 'glibc' + 'libx11' + 'libxcb' + 'libxext' + 'libxi' + 'libxkbcommon' +) +provides=("cua-driver=${pkgver}") +conflicts=('cua-driver') +# Prebuilt Rust binaries ship byte-exact: their build ids are what upstream +# symbolication matches. +options=('!strip' '!debug') +source=('LICENSE') +source_x86_64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-x86_64.tar.gz") +source_aarch64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-arm64.tar.gz") +sha256sums=('c0779290c1d4783169aa3dbfb55feb505e563ef8a004bbf55298ceffcfbda8d9') +sha256sums_x86_64=('478e010d2b0426de9d8a07eb839802daa92137b33cb8affb93b991e91d76ce7e') +sha256sums_aarch64=('3ad2d6c7ca7356a08e534baa2f4ca84ad02cebb2d27caef66cb268b6df71210d') + +package() { + local platform + case "${CARCH}" in + x86_64) platform="linux-x86_64" ;; + aarch64) platform="linux-arm64" ;; + esac + cd "${srcdir}/cua-driver-rs-${pkgver}-${platform}" + + # The vendor tree stays together: cua-driver execs cua-cursor-theme as a + # sibling of the resolved binary, and the SDK library, node runtime, ABI + # header, and the GNOME wayland-helper extension are versioned with it. + install -d "${pkgdir}/usr/lib/cua-driver" + cp -a . "${pkgdir}/usr/lib/cua-driver/" + chmod -R a+rX "${pkgdir}/usr/lib/cua-driver" + + install -d "${pkgdir}/usr/bin" + ln -s ../lib/cua-driver/cua-driver "${pkgdir}/usr/bin/cua-driver" + + install -Dm644 "${srcdir}/LICENSE" "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" +} From 8ac12ec7d6af878680ae6a2653c3c67e76714bd4 Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Fri, 4 Sep 2026 17:23:55 -0500 Subject: [PATCH 2/4] cua-driver-bin: point the binary's self-updater at pacman cua-driver update --apply pipes the vendor installer into bash, which installs a second copy under ~/.cua-driver and links it into ~/.local/bin, stepping around pacman and the repository's release gate. Upstream offers no switch for that path, and a /usr/bin wrapper would not cover it either: the MCP configurations the binary generates record the resolved executable. prepare() rewrites the installer URL inside the binary, in place and at equal length, to file:///usr/lib/cua-driver/pm.sh, a stand-in that declines and names pacman. The build asserts the URL appears exactly twice before the rewrite and not at all after it, so an upstream change to the updater stops the build instead of shipping a live self-updater. Verified in a clean archlinux:base container: pacman -Qkk is clean, the CLI and cursor-theme helper still run, and on the nightly channel update --apply prints the notice, exits 1, and creates nothing under ~/.cua-driver/packages or ~/.local/bin. --- pkgbuilds/cua-driver-bin/PKGBUILD | 72 ++++++++++++++++++++++++++----- pkgbuilds/cua-driver-bin/pm.sh | 12 ++++++ 2 files changed, 74 insertions(+), 10 deletions(-) create mode 100644 pkgbuilds/cua-driver-bin/pm.sh diff --git a/pkgbuilds/cua-driver-bin/PKGBUILD b/pkgbuilds/cua-driver-bin/PKGBUILD index d1ec04f..6af53aa 100644 --- a/pkgbuilds/cua-driver-bin/PKGBUILD +++ b/pkgbuilds/cua-driver-bin/PKGBUILD @@ -7,6 +7,15 @@ # /proc/self/exe -- so the whole tree lands under /usr/lib/cua-driver with a # /usr/bin symlink. .omarchy/upstream.sh rewrites the version and checksums # below from the release feed. +# +# The binary carries its own updater: `cua-driver update --apply` pipes the +# vendor installer into bash, which would install a second copy under +# ~/.cua-driver and link it into ~/.local/bin, stepping around pacman and +# this repository's release gate. Upstream offers no switch for that path, +# and a /usr/bin wrapper would not cover it either, since the MCP +# configurations the binary generates record the resolved executable. So +# prepare() rewrites the installer URL inside the binary to point at pm.sh, +# a stand-in that declines and names pacman instead. pkgname=cua-driver-bin pkgver=0.23.2 @@ -29,23 +38,63 @@ depends=( ) provides=("cua-driver=${pkgver}") conflicts=('cua-driver') -# Prebuilt Rust binaries ship byte-exact: their build ids are what upstream -# symbolication matches. +# Prebuilt Rust binaries ship byte-exact apart from the installer rewrite +# below: their build ids are what upstream symbolication matches. options=('!strip' '!debug') -source=('LICENSE') +source=('LICENSE' 'pm.sh') source_x86_64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-x86_64.tar.gz") source_aarch64=("https://github.com/trycua/cua/releases/download/cua-driver-rs-v${pkgver}/cua-driver-rs-${pkgver}-linux-arm64.tar.gz") -sha256sums=('c0779290c1d4783169aa3dbfb55feb505e563ef8a004bbf55298ceffcfbda8d9') +sha256sums=('c0779290c1d4783169aa3dbfb55feb505e563ef8a004bbf55298ceffcfbda8d9' + 'c76e251c3ed424200eac52bec35ba534336307fabd83a175ab0b47e2084ab0d8') sha256sums_x86_64=('478e010d2b0426de9d8a07eb839802daa92137b33cb8affb93b991e91d76ce7e') sha256sums_aarch64=('3ad2d6c7ca7356a08e534baa2f4ca84ad02cebb2d27caef66cb268b6df71210d') +case "${CARCH}" in + x86_64) _platform="linux-x86_64" ;; + aarch64) _platform="linux-arm64" ;; +esac +_vendor_tree="cua-driver-rs-${pkgver}-${_platform}" + +# Rust strings carry their length out of band, so the replacement has to be +# exactly as long as the original: 32 bytes, which is what fixes the +# stand-in's short name and location. +_vendor_installer='https://cua.ai/driver/install.sh' +_pacman_installer='file:///usr/lib/cua-driver/pm.sh' + +prepare() { + cd "${srcdir}/${_vendor_tree}" + + if (( ${#_vendor_installer} != ${#_pacman_installer} )); then + echo "installer URLs must be the same length to rewrite in place" >&2 + return 1 + fi + + # The URL appears twice: once in the updater and once in the printed + # reinstall one-liner. Any other count means upstream moved the updater + # and this rewrite needs another look, so the build stops rather than + # shipping a live self-updater. + local found + found=$(grep -obUaF "${_vendor_installer}" cua-driver | wc -l) + if (( found != 2 )); then + echo "expected the vendor installer URL twice in cua-driver, found ${found}" >&2 + return 1 + fi + + local size_before size_after + size_before=$(stat -c %s cua-driver) + sed -i "s|${_vendor_installer//./\\.}|${_pacman_installer}|g" cua-driver + size_after=$(stat -c %s cua-driver) + + if (( size_before != size_after )) \ + || grep -qUaF "${_vendor_installer}" cua-driver \ + || (( $(grep -obUaF "${_pacman_installer}" cua-driver | wc -l) != 2 )); then + echo "installer URL rewrite did not land cleanly in cua-driver" >&2 + return 1 + fi +} + package() { - local platform - case "${CARCH}" in - x86_64) platform="linux-x86_64" ;; - aarch64) platform="linux-arm64" ;; - esac - cd "${srcdir}/cua-driver-rs-${pkgver}-${platform}" + cd "${srcdir}/${_vendor_tree}" # The vendor tree stays together: cua-driver execs cua-cursor-theme as a # sibling of the resolved binary, and the SDK library, node runtime, ABI @@ -54,6 +103,9 @@ package() { cp -a . "${pkgdir}/usr/lib/cua-driver/" chmod -R a+rX "${pkgdir}/usr/lib/cua-driver" + # The path prepare() wrote into the binary. + install -Dm755 "${srcdir}/pm.sh" "${pkgdir}/usr/lib/cua-driver/pm.sh" + install -d "${pkgdir}/usr/bin" ln -s ../lib/cua-driver/cua-driver "${pkgdir}/usr/bin/cua-driver" diff --git a/pkgbuilds/cua-driver-bin/pm.sh b/pkgbuilds/cua-driver-bin/pm.sh new file mode 100644 index 0000000..e60fd6c --- /dev/null +++ b/pkgbuilds/cua-driver-bin/pm.sh @@ -0,0 +1,12 @@ +#!/bin/bash +# Stands in for the vendor installer. cua-driver-bin points the binary's +# `update --apply` here instead of https://cua.ai/driver/install.sh, which +# would otherwise install a second copy under ~/.cua-driver and link it into +# ~/.local/bin, stepping around pacman and the repository's release gate. The +# exit status is what `cua-driver update --apply` reports. +{ + echo "cua-driver is installed by pacman (cua-driver-bin), so the vendor installer is disabled." + echo "Upgrade it with pacman instead:" + echo " sudo pacman -Syu cua-driver-bin" +} >&2 +exit 1 From 2b2e880eed841266c4ae5d915386d415c3259f78 Mon Sep 17 00:00:00 2001 From: Francesco Bonacci <195596869+f-trycua@users.noreply.github.com> Date: Mon, 7 Sep 2026 17:57:46 -0500 Subject: [PATCH 3/4] fix: paginate Cua Driver release discovery Build on #306 without replacing its package or updater workaround. Exhaust the component feed before selecting a release and cover quarantine, version ordering, invalid input, and transport failures with offline fixtures. --- bin/sync-upstream | 4 + .../cua-driver-bin/.omarchy/upstream-test.sh | 146 ++++++++++++++++++ pkgbuilds/cua-driver-bin/.omarchy/upstream.sh | 27 +++- 3 files changed, 174 insertions(+), 3 deletions(-) create mode 100644 pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh diff --git a/bin/sync-upstream b/bin/sync-upstream index 04c7ac6..bc89160 100755 --- a/bin/sync-upstream +++ b/bin/sync-upstream @@ -834,6 +834,10 @@ EOF check "malformed upstream fails the sync instead of skipping" "1" "$((FAILED - prev_failed))" FAILED=0 + if ! bash "$BUILD_ROOT/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh"; then + failures=$((failures + 1)) + fi + echo "" if [[ "$failures" -eq 0 ]]; then print_success "Self-test passed" diff --git a/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh b/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh new file mode 100644 index 0000000..48f099c --- /dev/null +++ b/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh @@ -0,0 +1,146 @@ +#!/bin/bash +# Offline hook fixtures, also run by bin/sync-upstream self-test. Requires +# GNU date, jq, and pacman's vercmp, like the repository's other self-tests. +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")/.." + +failures=0 +check() { + if [[ "$2" == "$3" ]]; then + echo " ok: $1" + else + echo " FAIL: $1 (expected '$2', got '$3')" + failures=$((failures + 1)) + fi +} + +# Freeze time at the exact 24-hour boundary of the fixture's 0.24.0. +date() { + if [[ "$*" == '+%s' ]]; then + jq -nr '"2026-09-08T16:51:50Z" | fromdateiso8601' + else + command date "$@" + fi +} +curl() { + local url="${!#}" + case "$url" in + 'https://api.github.com/repos/trycua/cua/releases?per_page=100&page='*) + local page="${url##*=}" + [[ "$page" != "${FAIL_PAGE:-}" ]] || { echo 'fixture API failure' >&2; return 22; } + if [[ "${ENDLESS:-}" == 1 || "$page" == 1 ]]; then + printf '%s\n' "$PAGE1" + elif [[ "$page" == 2 ]]; then + printf '%s\n' "$PAGE2" + else + echo '[]' + fi + ;; + 'https://github.com/trycua/cua/releases/download/'*'/checksums.txt') + [[ "${FAIL_CHECKSUMS:-}" != 1 ]] || { echo 'fixture download failure' >&2; return 22; } + printf '%s\n' "$CHECKSUMS" + ;; + *) echo "unexpected fixture URL: $url" >&2; return 1 ;; + esac +} +export -f curl date +export PAGE1 PAGE2 CHECKSUMS FAIL_PAGE FAIL_CHECKSUMS ENDLESS +export MIN_RELEASE_AGE_SECONDS=86400 +export BYPASS_MIN_RELEASE_AGE='' +FAIL_PAGE='' FAIL_CHECKSUMS='' ENDLESS='' +PAGE2='[]' + +release() { + jq -cn --arg tag "$1" --arg published "${2:-2026-09-06T16:51:50Z}" \ + '{tag_name: $tag, published_at: $published, draft: false, prerelease: true}' +} +run_hook() { + status=0 + out=$(bash .omarchy/upstream.sh 2>&1) || status=$? +} +expect_failure() { + run_hook + check "$1 fails" yes "$([[ "$status" != 0 ]] && echo yes || echo no)" + check "$1 reports the reason" yes "$([[ "$out" == *"$2"* ]] && echo yes || echo no)" +} +sum_x=$(printf 'a%.0s' {1..64}) +sum_a=$(printf 'b%.0s' {1..64}) +CHECKSUMS=$(printf '%s\n' \ + "$sum_x cua-driver-rs-0.24.0-linux-x86_64.tar.gz" \ + "$sum_a cua-driver-rs-0.24.0-linux-arm64.tar.gz") +foreign_page=$(jq -cn '[range(100) | {tag_name: "fleet-v9.0.0", draft: false}]') +stable=$(release cua-driver-rs-v0.24.0 2026-09-07T16:51:50Z) + +echo 'Cua Driver release hook:' +PAGE1="$foreign_page" +PAGE2="[$stable]" +run_hook +check 'component found beyond the first 100 releases' 0 "$status" +check 'stable-shaped prerelease accepted at exactly 24h' 0.24.0 "$(jq -r '.pkgver' <<<"$out")" +check 'x86_64 checksum' "$sum_x" "$(jq -r '.sha256sums.x86_64[0]' <<<"$out")" +check 'ARM checksum' "$sum_a" "$(jq -r '.sha256sums.aarch64[0]' <<<"$out")" +check 'publication date preserved' 2026-09-07T16:51:50Z "$(jq -r '.published_at' <<<"$out")" + +# An eligible lower version on page one must not terminate the scan. +rebuilt=$(release cua-driver-rs-v0.23.3 2026-09-07T16:51:50Z) +PAGE1=$(jq -c --argjson rebuilt "$rebuilt" '.[0] = $rebuilt' <<<"$foreign_page") +PAGE2="[$(release cua-driver-rs-v0.24.0)]" +run_hook +check 'older page outranks recently rebuilt lower version' 0.24.0 "$(jq -r '.pkgver' <<<"$out")" + +draft=$(release cua-driver-rs-v99.0.0 | jq -c '.draft = true') +nightly=$(release nightly-cua-driver-rs-v99.0.0) +suffix=$(release cua-driver-rs-v99.0.0-nightly.1) +young=$(release cua-driver-rs-v0.25.0 2026-09-07T16:51:51Z) +PAGE1="[$draft,$nightly,$suffix,$young,$stable,$rebuilt]" +PAGE2='[]' +run_hook +check 'drafts/nightlies rejected and young release quarantined' 0.24.0 "$(jq -r '.pkgver' <<<"$out")" + +PAGE1="[$young]" +run_hook +check 'all candidates too young is a successful skip' 0 "$status" +check 'all young candidates emit empty JSON' '{}' "${out##*$'\n'}" +check 'quarantine reason is reported' yes "$([[ "$out" == *release-age* ]] && echo yes || echo no)" + +PAGE1="[$(release cua-driver-rs-v0.23.2)]" +run_hook +check 'current package version is unchanged' '{}' "$out" + +PAGE1="[$draft,$nightly,$suffix]" +expect_failure 'no stable component candidate' 'no stable cua-driver-rs-v' +PAGE1='[]' +expect_failure 'empty feed' 'no stable cua-driver-rs-v' +PAGE1="[$(release cua-driver-rs-v0.24.0 yesterday)]" +expect_failure 'relative publication date' 'invalid published_at' +PAGE1="[$(release cua-driver-rs-v0.24.0 2026-02-30T00:00:00Z)]" +expect_failure 'impossible publication date' 'invalid published_at' +PAGE1='[{"tag_name":"cua-driver-rs-v0.24.0","draft":false}]' +expect_failure 'missing publication date' 'invalid published_at' + +PAGE1="$foreign_page" +PAGE2='{"message":"API rate limit exceeded"}' +expect_failure 'API error object on later page' 'invalid release feed' +PAGE2='not json' +expect_failure 'malformed JSON on later page' 'invalid release feed' +PAGE2='[42]' +expect_failure 'malformed release entry' 'Cannot index' +PAGE2="[$stable]" +FAIL_PAGE=2 +expect_failure 'network failure after first page' 'fixture API failure' +FAIL_PAGE='' +ENDLESS=1 +expect_failure 'feed exceeds pagination bound' 'refusing incomplete selection' +ENDLESS='' + +PAGE1="[$stable]" +PAGE2='[]' +FAIL_CHECKSUMS=1 +expect_failure 'checksum download failure' 'fixture download failure' +FAIL_CHECKSUMS='' +CHECKSUMS="$sum_x cua-driver-rs-0.24.0-linux-x86_64.tar.gz" +expect_failure 'missing ARM checksum' 'no valid checksum' +CHECKSUMS='invalid cua-driver-rs-0.24.0-linux-x86_64.tar.gz' +expect_failure 'invalid checksum' 'no valid checksum' + +[[ "$failures" == 0 ]] diff --git a/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh index 2833d64..9c4a478 100644 --- a/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh +++ b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh @@ -9,7 +9,28 @@ set -euo pipefail REPO="trycua/cua" TAG_PREFIX="cua-driver-rs-v" -releases=$(curl -fsSL "https://api.github.com/repos/$REPO/releases?per_page=100") +# Publication order is not version order: older pages can contain a newer +# driver version than a recently rebuilt release. Exhaust the feed before +# selecting, and fail closed if the bounded scan cannot reach its end. +releases='[]' +max_pages=100 +for ((page = 1; page <= max_pages; page++)); do + release_page=$(curl --connect-timeout 10 --max-time 30 -fsSL \ + "https://api.github.com/repos/$REPO/releases?per_page=100&page=$page") + if ! page_size=$(jq -er 'if type == "array" and length <= 100 then length else error("expected release page of at most 100 entries") end' <<<"$release_page"); then + echo "invalid release feed for $REPO on page $page" >&2 + exit 1 + fi + releases=$(jq -c --argjson page "$release_page" '. + $page' <<<"$releases") + (( page_size == 100 )) || break +done +if (( page > max_pages )); then + echo "release feed for $REPO exceeds $max_pages pages; refusing incomplete selection" >&2 + exit 1 +fi + +# Keep jq failures in the main shell, where errexit can reject malformed data. +release_rows=$(jq -r '.[] | select(.draft | not) | [.tag_name // "", .published_at // ""] | @tsv' <<<"$releases") min_age="${MIN_RELEASE_AGE_SECONDS:-0}" now=$(date +%s) @@ -48,9 +69,9 @@ while IFS=$'\t' read -r tag published_at; do best_tag=$tag best_published=$published_at fi -done < <(jq -r '.[] | select(.draft | not) | [.tag_name // "", .published_at // ""] | @tsv' <<<"$releases") +done <<<"$release_rows" -# A feed page with no stable driver release at all is an anomaly worth a loud +# A feed with no stable driver release at all is an anomaly worth a loud # error; every candidate merely being inside the quarantine window is not. if (( candidates == 0 )); then echo "no stable $TAG_PREFIX releases in the feed for $REPO" >&2 From 9779715f163897e0b1ef0d14ceefaba896fc7c8b Mon Sep 17 00:00:00 2001 From: Spencer Bull Date: Wed, 9 Sep 2026 17:19:40 -0500 Subject: [PATCH 4/4] Fix large Cua release pages and isolate hook fixtures Feed GitHub release pages to jq through stdin so real pages do not exceed Linux argument limits. Generate an oversized fixture response in the curl mock, and run hook fixtures against a temporary pinned PKGBUILD so routine package updates do not break repository self-tests. Co-Authored-By: Codex GPT-6 XHigh --- .../cua-driver-bin/.omarchy/upstream-test.sh | 24 +++++++++++++++---- pkgbuilds/cua-driver-bin/.omarchy/upstream.sh | 2 +- 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh b/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh index 48f099c..dbb6f1a 100644 --- a/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh +++ b/pkgbuilds/cua-driver-bin/.omarchy/upstream-test.sh @@ -2,7 +2,11 @@ # Offline hook fixtures, also run by bin/sync-upstream self-test. Requires # GNU date, jq, and pacman's vercmp, like the repository's other self-tests. set -euo pipefail -cd "$(dirname "${BASH_SOURCE[0]}")/.." +hook="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/upstream.sh" +fixture_dir=$(mktemp -d) +trap 'rm -rf "$fixture_dir"' EXIT +printf 'pkgver=0.23.2\n' > "$fixture_dir/PKGBUILD" +cd "$fixture_dir" failures=0 check() { @@ -29,7 +33,11 @@ curl() { local page="${url##*=}" [[ "$page" != "${FAIL_PAGE:-}" ]] || { echo 'fixture API failure' >&2; return 22; } if [[ "${ENDLESS:-}" == 1 || "$page" == 1 ]]; then - printf '%s\n' "$PAGE1" + if [[ "${LARGE_PAGE:-}" == 1 ]]; then + jq -c '.[0].body = ("x" * 131072)' <<<"$PAGE1" + else + printf '%s\n' "$PAGE1" + fi elif [[ "$page" == 2 ]]; then printf '%s\n' "$PAGE2" else @@ -44,10 +52,10 @@ curl() { esac } export -f curl date -export PAGE1 PAGE2 CHECKSUMS FAIL_PAGE FAIL_CHECKSUMS ENDLESS +export PAGE1 PAGE2 CHECKSUMS FAIL_PAGE FAIL_CHECKSUMS ENDLESS LARGE_PAGE export MIN_RELEASE_AGE_SECONDS=86400 export BYPASS_MIN_RELEASE_AGE='' -FAIL_PAGE='' FAIL_CHECKSUMS='' ENDLESS='' +FAIL_PAGE='' FAIL_CHECKSUMS='' ENDLESS='' LARGE_PAGE='' PAGE2='[]' release() { @@ -56,7 +64,7 @@ release() { } run_hook() { status=0 - out=$(bash .omarchy/upstream.sh 2>&1) || status=$? + out=$(bash "$hook" 2>&1) || status=$? } expect_failure() { run_hook @@ -81,6 +89,12 @@ check 'x86_64 checksum' "$sum_x" "$(jq -r '.sha256sums.x86_64[0]' <<<"$out")" check 'ARM checksum' "$sum_a" "$(jq -r '.sha256sums.aarch64[0]' <<<"$out")" check 'publication date preserved' 2026-09-07T16:51:50Z "$(jq -r '.published_at' <<<"$out")" +LARGE_PAGE=1 +run_hook +check 'release page larger than the argument limit succeeds' 0 "$status" +check 'large release page preserves version selection' 0.24.0 "$(jq -r '.pkgver' <<<"$out")" +LARGE_PAGE='' + # An eligible lower version on page one must not terminate the scan. rebuilt=$(release cua-driver-rs-v0.23.3 2026-09-07T16:51:50Z) PAGE1=$(jq -c --argjson rebuilt "$rebuilt" '.[0] = $rebuilt' <<<"$foreign_page") diff --git a/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh index 9c4a478..e1e1428 100644 --- a/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh +++ b/pkgbuilds/cua-driver-bin/.omarchy/upstream.sh @@ -21,7 +21,7 @@ for ((page = 1; page <= max_pages; page++)); do echo "invalid release feed for $REPO on page $page" >&2 exit 1 fi - releases=$(jq -c --argjson page "$release_page" '. + $page' <<<"$releases") + releases=$(printf '%s\n' "$releases" "$release_page" | jq -cs 'add') (( page_size == 100 )) || break done if (( page > max_pages )); then