From 3e03914dab2cee434703f457bf23faf147a7c440 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Sat, 15 Aug 2026 14:08:26 -0400 Subject: [PATCH 01/10] fix(ci): agy reviewer must fall back on GitHub's FILES limit, not just lines Synced from RustyNES, where this was found and fixed (PR #374). The `review` check fails on a wide PR with `gh pr diff failed:` and an empty reason, which reads like a lapsed OAuth session on the self-hosted runner. It is neither -- the script has a bug. GitHub refuses an oversized PR diff two ways, both HTTP 406, with different wording: over 20,000 LINES, and over 300 FILES. The local-diff fallback was gated on grep -qi 'diff exceeded the maximum number of lines' so only the lines variant reached it. A wide-but-shallow PR -- hundreds of files, well under the line limit, which is what a bulk regeneration of test baselines produces -- took the `else` branch and exited 1. That is the one outcome the fallback exists to prevent; the comment directly above it says "a large PR is exactly the one worth reviewing". Verified on RustyNES rather than assumed: fetching the PR head and the base into the private `refs/agy/*` namespace and diffing against the merge base produced 12,002 lines / 586,010 bytes for a 487-file PR, well inside the 5 MB `MAX_DIFF_BYTES` cap, so the review proceeds normally once the grep matches. Includes the two review findings from that PR: the log line now names whichever limit actually fired (reporting "20,000-line" for a file-count refusal is the same misleading signal that caused the wrong diagnosis), and the explanatory comment carries no cross-repo issue number, which would mean nothing here. Note this cannot take effect on the PR that carries it: the workflow checks out the DEFAULT BRANCH for the reviewer scripts by design, so a PR cannot rewrite its own reviewer. --- scripts/agy-review.sh | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 9b273dea..82495695 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -221,13 +221,28 @@ esac # ($diff_err was allocated alongside $diff_file / $meta_file above, so the cleanup # trap never references it before it exists.) if ! gh pr diff "$PR" --repo "$REPO" > "$diff_file" 2>"$diff_err"; then - if grep -qi 'diff exceeded the maximum number of lines' "$diff_err"; then + # GitHub refuses an oversized diff TWO ways, with different wording: over + # 20,000 lines, and over 300 FILES. Both are HTTP 406 and both mean the same + # thing here -- the PR is too big for the API, not that anything went wrong -- + # so both must reach the local fallback. Matching only the `lines` variant made + # a wide-but-shallow PR -- hundreds of files, well under the line limit, as a + # bulk regeneration of test baselines produces -- fail the review outright + # instead of falling back. + if grep -qiE 'diff exceeded the maximum number of (lines|files)' "$diff_err"; then base_ref="$(jq -r '.baseRefName // empty' "$meta_file")" if [ -z "$base_ref" ] || [ "$base_ref" = "null" ]; then log "diff exceeds the API limit and the base branch is unknown; cannot fall back" exit 1 fi - log "diff exceeds GitHub's 20,000-line API limit; falling back to a local git diff" + # Name the limit that actually fired. Reporting "20,000-line" for a + # file-count refusal is the same class of misleading triage signal that + # made this bug look like a runner auth failure in the first place. + if grep -qi 'maximum number of files' "$diff_err"; then + hit="300-file" + else + hit="20,000-line" + fi + log "diff exceeds GitHub's ${hit} API limit; falling back to a local git diff" pr_ref="refs/agy/pr-${PR}" base_local="refs/agy/base-${PR}" agy_refs_created=1 From 7a2b98e6840d0b17f31f90aeeef4ba14917409ef Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Sat, 15 Aug 2026 14:29:03 -0400 Subject: [PATCH 02/10] fix(ci): the agy local-diff fallback cannot merge-base in a shallow clone Synced from RustyNES (PR #375), stacked on the file-count fix in this same branch. That fix alone is not enough: it gets the fallback started, and then the run dies one step later. [agy-review] diff exceeds GitHub's 300-file API limit; falling back to a local git diff [agy-review] fetched PR refs using git's ambient credentials [agy-review] could not compute the merge base for PR #373 The workflow checks out with `fetch-depth: 1`, deliberately -- the comment says the fallback "fetches exactly the two refs it needs on demand, so a full history clone would be paid on every run for a path most runs never take". But two refs fetched into a shallow repository arrive as DISCONNECTED shallow histories, with no common ancestor for `git merge-base` to find, so it fails even though both fetches succeeded. Asks the compare API for the merge base and fetches that single commit instead of unshallowing. Diffing two commits needs both trees, not the history between them, so a shallow fetch of the merge base suffices, and a repo with a large history does not pay a full clone on a path that exists only because the PR is already unusually big. `--deepen=250` covers a server that refuses a bare-SHA fetch. Verified upstream against a genuinely shallow clone -- the earlier attempt was checked in a full clone, where `git merge-base` succeeds and the bug cannot be seen. Reproduced the runner's exact failure at `--depth 1`, then confirmed the fix in that same clone: merge base resolved via the API (identical to a full clone's `git merge-base`), SHA fetch accepted, resulting diff 12,021 lines / 586,242 bytes. --- scripts/agy-review.sh | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 82495695..a312b8d7 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -175,7 +175,7 @@ trap cleanup EXIT # but is NOT harmless now that isCrossRepository gates whether an untrusted diff # reaches agy: a lookup failure must never be indistinguishable from "same-repo". diff_file="$(mktemp)"; meta_file="$(mktemp)"; diff_err="$(mktemp)" -gh pr view "$PR" --repo "$REPO" --json title,isCrossRepository,baseRefName > "$meta_file" \ +gh pr view "$PR" --repo "$REPO" --json title,isCrossRepository,baseRefName,headRefOid > "$meta_file" \ || { log "gh pr view failed; refusing to review without knowing the PR's head repo"; exit 1; } # THE FORK GATE (see the trust model at the agy invocation below). The workflow `if:` @@ -260,8 +260,32 @@ if ! gh pr diff "$PR" --repo "$REPO" > "$diff_file" 2>"$diff_err"; then log "could not fetch PR #${PR} refs for the local diff fallback" exit 1 fi - merge_base="$(git merge-base "$base_local" "$pr_ref")" || { - log "could not compute the merge base for PR #${PR}"; exit 1; } + # The workflow clones with `fetch-depth: 1`, so the two refs above arrive as + # DISCONNECTED shallow histories -- there is no common ancestor for + # `git merge-base` to find, and it fails even though both refs fetched fine. + # (A full local clone hides this completely, which is how it got missed.) + # + # Ask the API for the merge base and fetch that one commit, rather than + # unshallowing: a repo with a large history would pay a full clone on a path + # that only exists because the PR is already unusually big. Diffing two + # commits needs both trees, not the history between them, so a shallow fetch + # of the merge base is enough. + merge_base="$(git merge-base "$base_local" "$pr_ref" 2>/dev/null || true)" + if [ -z "$merge_base" ]; then + head_sha="$(jq -r '.headRefOid // empty' "$meta_file")" + api_base="$(gh api "repos/${REPO}/compare/${base_ref}...${head_sha}" \ + --jq '.merge_base_commit.sha' 2>/dev/null || true)" + if [ -n "$api_base" ] && [ "$api_base" != "null" ]; then + if git fetch --no-tags --quiet origin "$api_base" 2>/dev/null \ + || git fetch --no-tags --quiet --deepen=250 origin "${fetch_refspecs[@]}" 2>/dev/null; then + merge_base="$(git merge-base "$base_local" "$pr_ref" 2>/dev/null || echo "$api_base")" + log "shallow clone: merge base ${merge_base} resolved via the compare API" + fi + fi + fi + if [ -z "$merge_base" ]; then + log "could not compute the merge base for PR #${PR}"; exit 1 + fi git diff "$merge_base" "$pr_ref" > "$diff_file" || { log "local git diff failed for PR #${PR}"; exit 1; } log "local diff: $(wc -l < "$diff_file") lines, $(wc -c < "$diff_file") bytes" From 83bf7f4ba481128035b66c505aca3f1788132632 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Sat, 15 Aug 2026 14:31:29 -0400 Subject: [PATCH 03/10] fix(ci): percent-encode the base ref in the compare-API URL Copilot flagged the raw `${base_ref}` interpolation, predicting that a `/` branch would make the path ambiguous and fail. That specific case does NOT reproduce -- checked against a real slashed branch, GitHub's compare endpoint accepts `fix/agy-review-shallow-merge-base...main` raw and returns the same SHA as the encoded form. So the stated failure is not the bug. The finding still points at a real one, for different characters. Git permits `%` and `#` in a ref name and a URL path does not survive either: `%` starts an escape sequence, `#` truncates at the fragment. Both would fail silently into the `|| true` and leave the merge base unresolved, which is exactly the failure mode this whole fallback exists to avoid. Encoding with jq's `@uri`. Verified both shapes still resolve: a plain `main` and a slashed branch encoded to `fix%2F...` both return the correct merge base. --- scripts/agy-review.sh | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index a312b8d7..104517b5 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -273,7 +273,14 @@ if ! gh pr diff "$PR" --repo "$REPO" > "$diff_file" 2>"$diff_err"; then merge_base="$(git merge-base "$base_local" "$pr_ref" 2>/dev/null || true)" if [ -z "$merge_base" ]; then head_sha="$(jq -r '.headRefOid // empty' "$meta_file")" - api_base="$(gh api "repos/${REPO}/compare/${base_ref}...${head_sha}" \ + # Percent-encode the branch name for the URL path. NOT for the `/` in a + # `/` branch -- GitHub's compare endpoint accepts those + # raw, verified against a real slashed branch, returning the same SHA + # either way. It is for `%` and `#`, which git permits in a ref name and + # which a URL does not survive: `%` starts an escape and `#` truncates the + # path at the fragment. Both would fail silently into the `|| true`. + base_enc="$(jq -rn --arg v "$base_ref" '$v|@uri')" + api_base="$(gh api "repos/${REPO}/compare/${base_enc}...${head_sha}" \ --jq '.merge_base_commit.sha' 2>/dev/null || true)" if [ -n "$api_base" ] && [ "$api_base" != "null" ]; then if git fetch --no-tags --quiet origin "$api_base" 2>/dev/null \ From 5fe46cb5def926e783325c465c2814d7b924e7f1 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 11:24:27 -0400 Subject: [PATCH 04/10] ci(agy): the reviewer appends its rounds instead of destroying them The Antigravity reviewer posted a fresh comment each round and DELETED the previous one. That kept the PR tidy and destroyed the record: a round nobody had read before the next push was gone, with nothing on the PR indicating it had ever existed. Unlike a CodeRabbit or Copilot review thread, an unaddressed finding left no trace -- so a clean comment list was not evidence that nothing had been raised. Observed on RustyNES PR #428. Round 1 posted at 13:37:57Z and round 2 at 14:21:35Z; afterwards the issue-comments endpoint returned exactly ONE bot comment, with created_at equal to updated_at equal to 14:21:35Z. The first was gone -- not edited, since the timestamps would differ, and not appended to. Both rounds raised a blocking issue and both were correct, one of them a data-loss defect, so losing a round is not a hypothetical cost. There is now ONE comment per PR, edited in place: the newest round on top, every earlier round folded into a collapsed
block beneath it. Same tidiness, nothing destroyed. The script issues no DELETE at all, and the selftest asserts the absence of one so the behaviour cannot return unnoticed. The archive is bounded by MAX_BODY_BYTES (60000, under GitHub's 65536 hard limit), because a PR with many pushes would otherwise grow it until an EDIT starts failing -- stranding the comment at whatever round last fit, which is the worst failure available since the newest review is the one that cannot post. Oldest rounds drop first, and the drop is ANNOUNCED: a silent truncation would look exactly like a PR reviewed only once, which is the confusion this change exists to remove. Every failure path falls back to a plain post; a duplicate is noise, failing to publish a review is not. THE FORMAT LIVES IN ITS OWN FILE, AND THAT IS THE POINT scripts/_agy_comment_body.sh holds the sentinels and the split/trim helpers and is sourced by both the reviewer and its selftest. agy-review.sh does its work at top level and cannot be sourced, which is exactly how a test ends up reimplementing its subject -- and that happened. The first version of these checks inlined its own copy of the awk pipeline, so a mutation deleting the marker strip came back NOT CAUGHT. A test that reimplements what it tests agrees with itself forever. The fixture changed for the same reason: it had our own bot's comment first, so `first` selected it whether or not the author filter was present, leaving the control that stops any user pasting the marker into a comment and having the bot edit it untestable. A User comment carrying the marker now sorts ahead of ours. Eight mutations, all caught: the author filter, empty-versus-null, oldest-versus- newest selection, a reintroduced DELETE, the marker strip, the archive split's sentinel ordering, dropping the newest round instead of the oldest, and a drop that succeeds on an empty archive (which would spin the trim loop). Verified end to end by simulating four rounds through the real functions: all four findings present in the final body, newest first, marker appearing exactly once. ALSO IN THIS SWEEP actions/checkout is SHA-pinned. This job runs on a SELF-HOSTED runner -- the maintainer's own machine, holding the agy CLI's OAuth session -- so a compromised tag executes there rather than in a disposable VM. Verified rather than copied: tag v7 resolves to 3d3c42e5aac5ba805825da76410c181273ba90b1, the v7.0.1 commit of 2026-07-17. The trailing `# v7` is what Dependabot reads to keep the pin current. .github/actionlint.yaml declares the self-hosted `agy` label. Without it actionlint reported an error on EVERY run in this repo, and a linter that always reports something is a linter that stops being read. Created only when absent, so a repo with its own actionlint config keeps it. _agy_comment_body.sh is REQUIRED, not optional -- agy-review.sh sources it at startup, so an install without it fails at runtime rather than degrading. The installer copies it and the selftest, the workflow chmods it, and both temporaries the archive path creates are pre-declared so the cleanup trap frees them on every exit including the early one after a successful edit. THIS DOES NOT TAKE EFFECT UNTIL IT REACHES MAIN The workflow checks out the DEFAULT BRANCH to run the scripts, so a change to agy-review.sh has no effect on any PR -- not even the PR that makes it. Swept from the canonical template at Local_Only-Projects/antigravity-pr-review/, which carries all of the above for future installs. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- .github/actionlint.yaml | 25 ++++ .github/workflows/antigravity-review.yml | 14 +- scripts/_agy_comment_body.sh | 61 ++++++++ scripts/agy-review-selftest.sh | 120 +++++++++++---- scripts/agy-review.sh | 179 ++++++++++++++--------- 5 files changed, 300 insertions(+), 99 deletions(-) create mode 100644 .github/actionlint.yaml create mode 100755 scripts/_agy_comment_body.sh diff --git a/.github/actionlint.yaml b/.github/actionlint.yaml new file mode 100644 index 00000000..06b9ec70 --- /dev/null +++ b/.github/actionlint.yaml @@ -0,0 +1,25 @@ +# actionlint configuration. +# +# actionlint validates `runs-on:` against GitHub's list of hosted-runner labels +# and reports anything else as unknown, because a typo'd label is a job that +# queues forever rather than failing. Self-hosted labels therefore have to be +# declared here — that is the mechanism actionlint's own diagnostic points at. +# +# Without this file, `actionlint` reports an error on EVERY run in a repo that +# has the reviewer installed. That is not a harmless false positive: a linter +# that always reports something is a linter people stop reading, and the real +# findings go with it. +# +# Run it over the whole tree with: +# +# actionlint +# +# (no arguments — it discovers `.github/workflows/*.yml` and reads this file.) + +self-hosted-runner: + labels: + # The maintainer's self-hosted runner for the Antigravity PR reviewer + # (`.github/workflows/antigravity-review.yml`, `runs-on: [self-hosted, agy]`). + # It is a personal machine holding the `agy` CLI's Google AI Ultra OAuth + # session, which is why that workflow cannot run on a hosted runner. + - agy diff --git a/.github/workflows/antigravity-review.yml b/.github/workflows/antigravity-review.yml index 32ba8cf4..d500f69f 100644 --- a/.github/workflows/antigravity-review.yml +++ b/.github/workflows/antigravity-review.yml @@ -53,6 +53,10 @@ jobs: group: agy-review-${{ github.event.pull_request.number || github.event.issue.number }} cancel-in-progress: false runs-on: [self-hosted, agy] + # Bounded harder than the hosted jobs, not softer: this runs on the + # maintainer's own hardware, so a hung run holds a real machine rather than + # a disposable VM. Observed runtime is 1-3 minutes. + timeout-minutes: 30 steps: # Check out the DEFAULT BRANCH, never the PR head. This job runs the checked-out # `scripts/agy-review.sh` on a self-hosted runner with a token in the environment, @@ -63,6 +67,12 @@ jobs: # branch throughout. Consequence worth knowing: a PR that edits the reviewer or the # style guide is reviewed by the version already on the default branch until it merges. - name: Check out repo (for the style guide + scripts) + # SHA-pinned, not `@v7`: this job runs on a SELF-HOSTED runner -- the + # maintainer's own machine -- so a compromised tag would execute there + # rather than in a disposable VM. Verified to be exactly what `v7` + # resolves to (v7.0.1, 2026-07-17). The trailing `# v7` is the form + # Dependabot's github-actions ecosystem reads to keep the pin current. + # Adopted FROM RustySNES and SLAC, which had it while the template did not. uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 with: ref: ${{ github.event.repository.default_branch }} @@ -91,5 +101,7 @@ jobs: # MAX_PROMPT_BYTES: "125000" # inline/file threshold + hard backstop on the argv prompt # STYLE_GUIDE: .github/agy-review.md # style guide, loaded if present run: | - chmod +x scripts/agy-review.sh scripts/_agy_print.sh + # `_agy_comment_body.sh` is sourced by the reviewer at startup, so a + # missing or non-executable copy fails the run rather than degrading it. + chmod +x scripts/agy-review.sh scripts/_agy_print.sh scripts/_agy_comment_body.sh scripts/agy-review.sh diff --git a/scripts/_agy_comment_body.sh b/scripts/_agy_comment_body.sh new file mode 100755 index 00000000..4997864f --- /dev/null +++ b/scripts/_agy_comment_body.sh @@ -0,0 +1,61 @@ +#!/usr/bin/env bash +# +# _agy_comment_body.sh -- the review comment's body format, as sourceable functions. +# +# Sourced by `agy-review.sh` (which uses them) and by `agy-review-selftest.sh` (which tests +# them). It exists as a separate file for one reason: `agy-review.sh` does its work at TOP +# LEVEL, so it cannot be sourced without running a review, and a test that cannot call the +# real implementation ends up reimplementing it. That failure is not hypothetical here -- the +# first version of the archive test inlined its own copy of the `awk` pipeline, so a mutation +# deleting the marker strip from the script came back NOT CAUGHT. A test that reimplements its +# subject agrees with itself forever. +# +# Defines no state and runs nothing on source. + +# The sentinels delimiting the archive of earlier review rounds inside the comment body. +# +# The reviewer used to POST a fresh comment each round and DELETE the previous one. That kept +# the PR tidy and destroyed the record: a round nobody read before the next push was gone, with +# nothing on the PR indicating it had existed -- and unlike a CodeRabbit or Copilot thread, an +# unaddressed finding left no trace. Observed on a real PR where two consecutive rounds each +# raised a blocking issue and only the second survived. +# +# Now there is ONE comment per PR, edited in place: newest round on top, earlier rounds folded +# into a collapsed `
` below. Same tidiness, no destruction. +AGY_ARCHIVE_START='' +AGY_ARCHIVE_END='' + +# The newest round of a comment body: everything after the marker, before the archive. +# +# `awk` matching WHOLE LINES rather than `sed` with a pattern, because a review body +# legitimately contains regex metacharacters, backslashes and HTML, and the sentinels must not +# match a line that merely mentions one. +agy_body_head() { + local marker="$1" + awk -v s="$AGY_ARCHIVE_START" '$0 == s { exit } { print }' \ + | grep -v -F -x "$marker" || true +} + +# The archived rounds of a comment body: everything strictly between the sentinels. +# +# The `$0 == e` test comes FIRST so a body whose archive is empty yields nothing rather than +# emitting its own end sentinel. +agy_body_archive() { + awk -v s="$AGY_ARCHIVE_START" -v e="$AGY_ARCHIVE_END" ' + $0 == e { inside = 0 } + inside { print } + $0 == s { inside = 1 }' || true +} + +# Drop the OLDEST archived round -- the last `
` block. Exits non-zero when there is +# none left to drop, so a caller trimming to a size limit terminates rather than spinning. +agy_drop_oldest_round() { + awk ' + /^
$/ { starts[++n] = NR } + { line[NR] = $0 } + END { + cut = (n > 0) ? starts[n] : 0 + if (cut == 0) exit 1 + for (i = 1; i < cut; i++) print line[i] + }' +} diff --git a/scripts/agy-review-selftest.sh b/scripts/agy-review-selftest.sh index db684954..0a4153a6 100755 --- a/scripts/agy-review-selftest.sh +++ b/scripts/agy-review-selftest.sh @@ -31,15 +31,33 @@ extract_marker() { sed -n 's/^MARKER="\(.*\)"$/\1/p' "$SCRIPT_DIR/agy-review.sh" | head -n 1 } extract_filter() { - sed -n "/^SELECT_STALE_JQ='/,/'\$/p" "$SCRIPT_DIR/agy-review.sh" \ - | sed "1s/^SELECT_STALE_JQ='//; \$s/'\$//" + sed -n "/^SELECT_OURS_JQ='/,/'\$/p" "$SCRIPT_DIR/agy-review.sh" \ + | sed "1s/^SELECT_OURS_JQ='//; \$s/'\$//" } MARKER="$(extract_marker)" FILTER="$(extract_filter)" [ -n "$MARKER" ] || { echo "FAIL: could not extract MARKER from agy-review.sh" >&2; exit 1; } -[ -n "$FILTER" ] || { echo "FAIL: could not extract SELECT_STALE_JQ from agy-review.sh" >&2; exit 1; } +[ -n "$FILTER" ] || { echo "FAIL: could not extract SELECT_OURS_JQ from agy-review.sh" >&2; exit 1; } + +# The REAL body-format implementation, sourced rather than reimplemented. The first version of +# these checks inlined its own copy of the `awk` pipeline, and a mutation deleting the marker +# strip from the script came back NOT CAUGHT -- a test that reimplements its subject agrees with +# itself forever. `agy-review.sh` cannot be sourced (it works at top level), which is exactly +# why the format lives in its own file. +# shellcheck source=scripts/_agy_comment_body.sh +. "$SCRIPT_DIR/_agy_comment_body.sh" +[ -n "${AGY_ARCHIVE_START:-}" ] || { echo "FAIL: _agy_comment_body.sh defined no AGY_ARCHIVE_START" >&2; exit 1; } +[ -n "${AGY_ARCHIVE_END:-}" ] || { echo "FAIL: _agy_comment_body.sh defined no AGY_ARCHIVE_END" >&2; exit 1; } + +# The script must actually USE the shared helper, or these checks test a file nothing runs. +grep -q '_agy_comment_body.sh' "$SCRIPT_DIR/agy-review.sh" \ + || { echo "FAIL: agy-review.sh does not source _agy_comment_body.sh" >&2; exit 1; } +for fn in agy_body_head agy_body_archive agy_drop_oldest_round; do + grep -q "$fn" "$SCRIPT_DIR/agy-review.sh" \ + || { echo "FAIL: agy-review.sh does not call $fn" >&2; exit 1; } +done # A non-empty extraction is not the same as a COMPLETE one. The `sed` range above ends at the # first line closing with a quote, so a filter whose body ever ends a line that way would be @@ -51,14 +69,14 @@ FILTER="$(extract_filter)" # prefix of one. # The named args must be supplied here too: the filter references `$marker`/`$new_id`, and jq # rejects an undefined variable at COMPILE time — so omitting them fails a perfectly good program. -if ! printf '[]' | jq --arg marker x --argjson new_id 0 "$FILTER" >/dev/null 2>&1; then - echo "FAIL: extracted SELECT_STALE_JQ is not a valid jq program (truncated?):" >&2 +if ! printf '[]' | jq --arg marker x "$FILTER" >/dev/null 2>&1; then + echo "FAIL: extracted SELECT_OURS_JQ is not a valid jq program (truncated?):" >&2 printf '%s\n' "$FILTER" >&2 exit 1 fi case "$(printf '%s' "$FILTER" | tr -d '[:space:]')" in - *'|.id') : ;; - *) echo "FAIL: extracted SELECT_STALE_JQ does not end in '| .id'; extraction truncated" >&2 + *'|.id//empty') : ;; + *) echo "FAIL: extracted SELECT_OURS_JQ does not end in '| .id // empty'; extraction truncated" >&2 printf '%s\n' "$FILTER" >&2 exit 1 ;; esac @@ -66,20 +84,19 @@ esac fixture() { cat <\nOLDER ROUND\n
')" "$archive_part" + +# A body with NO archive yet (the first round) must split to a head and an empty archive, not to +# an empty head -- the first re-review is exactly when this path runs for the first time. +first_body="$(printf '%s\nFIRST ROUND\n' "$MARKER")" +check "a body with no archive still yields its head" "FIRST ROUND" \ + "$(printf '%s\n' "$first_body" | agy_body_head "$MARKER")" +check "a body with no archive yields an empty archive" "" \ + "$(printf '%s\n' "$first_body" | agy_body_archive)" + +# The head must NOT carry the marker forward: an archived round that still contains it would +# make every future run's `contains($marker)` match inside the archive, and the split would +# then cut at the wrong place. A mutation removing the strip must fail here. +check "the head never carries the marker into the archive" "" \ + "$(printf '%s\nX\n' "$MARKER" | agy_body_head "$MARKER" | grep -F -x "$MARKER" || true)" + +# Trimming must terminate: with no `
` left, dropping fails rather than looping. +check "dropping from an empty archive fails rather than spinning" "1" \ + "$(printf 'no rounds here\n' | agy_drop_oldest_round >/dev/null 2>&1; echo $?)" +check "dropping removes the OLDEST round, keeping the newest" \ + "$(printf '
\nNEW\n
')" \ + "$(printf '
\nNEW\n
\n
\nOLD\n
\n' | agy_drop_oldest_round)" + +# The script must not delete comments any more. A reintroduced DELETE is the regression that +# would silently restore the destructive behaviour this design replaced. +if grep -qE 'gh api +-X +DELETE' "$SCRIPT_DIR/agy-review.sh"; then + echo " FAIL agy-review.sh deletes comments again; the archive design forbids it" + fails=$((fails + 1)) +else + echo " ok agy-review.sh never deletes a comment" +fi # Regression #2, pinned: `--arg`/`--argjson` belong to jq. If they are ever moved onto `gh api` # again, that command exits non-zero — assert the flags are not passed to `gh api` in the script. diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 104517b5..5728b9bd 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -100,21 +100,31 @@ AGY_RETRIES="${AGY_RETRIES:-3}" # attempts to get a usable agy respon AGY_RETRY_DELAY="${AGY_RETRY_DELAY:-15}" # base backoff seconds between retries (grows per attempt) MARKER="" -# The jq program that picks which prior review comments to delete. Named, and exercised directly -# by `scripts/agy-review-selftest.sh`, because this filter has now been wrong TWICE in ways -# nothing observed: first the just-posted comment was not excluded (so it deleted itself), then -# jq's `--arg` was handed to `gh api`, which has no such flag (so the whole step died silently and -# stale comments accumulated). Both were invisible from the outside — the review still posted. +# The comment body's format -- sentinels plus the split/trim helpers -- lives in a sourceable +# file so `agy-review-selftest.sh` can test the REAL implementation rather than a copy of it. +# This script does its work at top level and so cannot itself be sourced. +# shellcheck source=scripts/_agy_comment_body.sh +. "$(dirname -- "${BASH_SOURCE[0]}")/_agy_comment_body.sh" + +MAX_BODY_BYTES="${MAX_BODY_BYTES:-60000}" + +# The jq program that finds THIS bot's existing review comment on the PR, so it can be edited +# rather than replaced. Named, and exercised directly by `scripts/agy-review-selftest.sh`, +# because its predecessor (which selected comments to DELETE) was wrong twice in ways nothing +# observed: first the just-posted comment was not excluded, so a run deleted its own review; +# then jq's `--arg` was handed to `gh api`, which has no such flag, so the step died silently. +# Both were invisible from the outside — the review still posted. # -# The two `select`s that matter: the AUTHOR filter (without it, any user could put the marker in a -# comment and have this bot delete arbitrary comments) and the ID exclusion (without it, the run -# deletes the comment it just published). -SELECT_STALE_JQ='.[] +# The AUTHOR filter is load-bearing, not cosmetic: without it, any user could put the marker +# (an HTML comment, invisible when rendered) in a PR comment and have this bot edit it. Only +# ever touch our own bot's comments. `first` picks the OLDEST match, so if duplicates exist +# from an older version of this script, the canonical thread is the one that keeps growing. +SELECT_OURS_JQ='[ .[] | select(.user.type == "Bot" and .user.login == "github-actions[bot]") - | select(.body | contains($marker)) - | select(.id != $new_id) - | .id' -readonly SELECT_STALE_JQ + | select(.body | contains($marker)) ] + | first + | .id // empty' +readonly SELECT_OURS_JQ REPO="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY not set}" @@ -600,65 +610,94 @@ if oauth_url_present "$body_file"; then exit 1 fi -# --- post fresh, THEN replace any prior review comment -------------------------- -# Publish-before-delete, deliberately: if this ordering were reversed and posting failed -# afterward (a transient gh/API error), the PR would be left with NO review comment at all -# instead of the still-valid prior one. Posting first means a failure here can only ever -# leave a harmless duplicate, never a silent loss of the last review. -# The posted comment's id comes from the POST itself, not from a read-back. `gh pr comment` -# prints the new comment's URL, whose trailing `#issuecomment-` is authoritative the instant -# it returns. Re-querying the comment list to find "the newest one with our marker" raced with -# GitHub's own read replication: right after posting, the list can still omit it, and then the -# exclusion below matched nothing and the script deleted the comment it had just published -- -# turning publish-before-delete into publish-then-destroy, the exact failure the ordering exists -# to prevent. +# --- edit our existing comment, appending the previous round to its archive ------ +# One comment per PR, edited in place: newest round on top, earlier rounds folded into a +# collapsed `
` below. NOTHING IS DELETED. The previous design posted fresh and +# deleted the prior comment, which kept the PR tidy at the cost of destroying any round +# nobody had read yet — and left no evidence a round had happened at all. +# +# Fail-closed in the direction that matters: every step below falls back to a plain POST of +# the new review. A duplicate comment is noise; failing to publish a review, or losing one, is +# not. The lookup happens BEFORE the post so a PATCH is possible at all, but a failed lookup +# costs only the archive, never the review. +prior_id="" +prior_body_file="$(mktemp)" +if prior_json="$(gh api "repos/${REPO}/issues/${PR}/comments" --paginate 2>/dev/null)"; then + prior_id="$(printf '%s' "$prior_json" | jq -r --arg marker "$MARKER" "$SELECT_OURS_JQ" 2>/dev/null || true)" + if [ -n "$prior_id" ] && [ "$prior_id" != "null" ]; then + printf '%s' "$prior_json" \ + | jq -r --argjson id "$prior_id" '.[] | select(.id == $id) | .body' > "$prior_body_file" 2>/dev/null \ + || : > "$prior_body_file" + else + prior_id="" + fi +else + log "warning: could not list PR comments; posting a fresh review without the archive" +fi + +if [ -n "$prior_id" ] && [ -s "$prior_body_file" ]; then + # Split the prior body into its newest round (everything after the marker, before the + # archive) and the archive's existing inner rounds. `awk` rather than `sed`, because the + # sentinels must match whole lines and a review body legitimately contains regex + # metacharacters, backslashes and HTML. + prior_head="$(agy_body_head "$MARKER" < "$prior_body_file")" + prior_archive="$(agy_body_archive < "$prior_body_file")" + + archived_file="$(mktemp)" + { + printf '
\nRound reviewed at %s\n\n' \ + "$(date -u +'%Y-%m-%d %H:%M UTC')" + printf '%s\n' "$prior_head" + printf '\n
\n' + printf '%s\n' "$prior_archive" + } > "$archived_file" + + # Drop the oldest rounds until the whole comment fits, and SAY SO. A silent truncation + # here would look identical to "there were never any earlier rounds", which is the exact + # confusion this whole change exists to remove. + dropped=0 + while :; do + combined_size=$(( $(wc -c < "$body_file") + $(wc -c < "$archived_file") + 200 )) + [ "$combined_size" -le "$MAX_BODY_BYTES" ] && break + # Remove the LAST `
` block (the oldest round) from the archive. + trimmed="$(mktemp)" + agy_drop_oldest_round < "$archived_file" > "$trimmed" || { rm -f "$trimmed"; break; } + mv "$trimmed" "$archived_file" + dropped=$(( dropped + 1 )) + done + + { + printf '\n%s\n' "$AGY_ARCHIVE_START" + if [ "$dropped" -gt 0 ]; then + printf '%d earlier round(s) dropped to stay under GitHub'"'"'s comment size limit.\n\n' "$dropped" + fi + printf '
\nEarlier review rounds (newest first)\n\n' + cat "$archived_file" + printf '\n
\n' + printf '%s\n' "$AGY_ARCHIVE_END" + } >> "$body_file" + rm -f "$archived_file" + + # Re-run the OAuth guard on the ASSEMBLED body. The archive is text this script published + # earlier and so has already passed the guard once, but the body is what gets published now + # and the guard's contract is that it runs on exactly that. + if oauth_url_present "$body_file"; then + log "refusing to post: the assembled comment body contains a live OAuth authorization URL." + exit 1 + fi + + if gh api -X PATCH "repos/${REPO}/issues/comments/${prior_id}" \ + -f body="$(cat "$body_file")" >/dev/null 2>&1; then + log "updated review comment ${prior_id} on ${REPO}#${PR} (earlier rounds archived in place)" + rm -f "$prior_body_file" + exit 0 + fi + log "warning: could not edit comment ${prior_id}; posting a fresh review instead" +fi +rm -f "$prior_body_file" + if ! post_output="$(gh pr comment "$PR" --repo "$REPO" --body-file "$body_file" 2>&1)"; then - # Nothing is deleted when the post fails: the prior review comment is still the best - # information the PR has, and removing it would leave no review at all. log "failed to post review to ${REPO}#${PR}: ${post_output}" exit 1 fi log "posted review to ${REPO}#${PR}" -new_comment_id="$(printf '%s\n' "$post_output" | sed -n 's/.*#issuecomment-\([0-9][0-9]*\).*/\1/p' | tail -n 1)" - -# A failed delete is logged, not swallowed: silently ignoring it would let a transient API/perms -# error leave the old comment in place alongside the new one, so runs accumulate duplicates. -# The author filter is load-bearing, not cosmetic: without it, ANY user could put the -# marker (an HTML comment) in a PR comment and have this bot delete arbitrary comments on -# the next run. Only ever delete OUR OWN bot's prior review comments -- and only ones from -# BEFORE this run (the just-posted comment's own id is excluded so it can never delete itself). -if [ -z "$new_comment_id" ]; then - # FAIL CLOSED. Without a known id there is no way to tell the new comment from the old ones, - # and the safe direction is unambiguous: a leftover duplicate is noise, deleting the review - # that was just posted is data loss. - log "warning: could not determine the posted comment id; leaving prior review comments in place" -else - # `--arg`/`--argjson` rather than shell interpolation into the filter: the marker is an HTML - # comment today, but a quote or a backslash in it would otherwise break the jq program itself - # rather than simply not matching. - # - # Those are JQ flags, so the JSON is fetched raw and piped into a real `jq` — `gh api` has no - # `--arg`/`--argjson` of its own and rejects them. Handing them to `gh api --jq` made it exit - # non-zero on every run; with the old `2>/dev/null` swallowing the message and `set -o pipefail` - # in force, the script then died *after* posting, so the stale comments were never deleted and - # the job went red for a reason nothing printed. stderr is kept this time for exactly that - # reason. (`--paginate` without `--jq` emits one JSON array per page; `jq` reads that stream - # fine, applying `.[]` to each.) - stale_ids="$( - gh api "repos/${REPO}/issues/${PR}/comments" --paginate \ - | jq -r --arg marker "$MARKER" --argjson new_id "$new_comment_id" "$SELECT_STALE_JQ" - )" || { - log "warning: could not list prior review comments; leaving them in place" - stale_ids="" - } - while read -r cid; do - [ -n "$cid" ] || continue - if ! gh api -X DELETE "repos/${REPO}/issues/comments/${cid}" >/dev/null 2>&1; then - log "warning: could not delete prior review comment ${cid}; a duplicate may result" - fi - done <<< "$stale_ids" -fi - -# The delete loop above is the last real work; end on a defined status so a stray non-zero from -# it can never be mistaken for "the review failed" once the comment is already published. -exit 0 From c6ac098db8d93811b7af2d1901b14593165d82d1 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 11:30:09 -0400 Subject: [PATCH 05/10] ci(agy): adopt SLAC's backend-error guard and marker-based test extraction Two mechanisms existed in exactly one of the five installs. Both belong in all of them, and the sweep that unified the comment-archive behaviour is the right moment to say so. A BACKEND OUTAGE POSTED AS A PASSING REVIEW When agy's upstream is down it prints an error rather than a review: Error: Eligibility check failed: UNAVAILABLE (code 503): The service is currently unavailable. That text is non-empty, so have_text() treated it as a valid review, POSTed it as the review comment, and the job exited 0 -- a green check for a review that never ran. Observed twice on SLAC PR #14, where the check passed in seven seconds with that string as its entire body. A control that cannot fail is worse than no control. The match is deliberately ANCHORED to the start of the capture rather than being a substring search, and it is bounded by size. A genuine review may quote a 503 or an UNAVAILABLE constant while reviewing retry logic, and aborting on that would be the false positive the OAuth guard's design notes warn about. A backend failure IS the whole capture and begins with `Error:`, so requiring the error on line one, in a capture short enough to contain nothing else, separates the two without a content heuristic. A backend error is transient, so it retries like empty output rather than aborting the way a lapsed session does -- but the capture is blanked so no later path can post it. The tally is a COUNTER, not a per-attempt flag: a boolean reset each attempt reflects only the last one, so a 503 on attempt 1 followed by empty output on attempt 3 would report the wrong cause. Both exit non-zero, so nothing unsafe -- but the log line is the only thing telling a human which outage they are looking at. MARKER-BASED EXTRACTION, AND WHY IT IS BETTER The selftest lifted the jq filter out of the reviewer by matching the declaration's own syntax: a sed range ending at the first line closing with a quote. A filter whose body ever ended a line that way would be SILENTLY TRUNCATED, and a truncated jq program can still compile and still return ids -- the exact silent-wrong-answer that file exists to prevent. Explicit `SELFTEST-EXTRACT` markers replace it. They also let a guard be several statements rather than one assignment, which is what makes the OAuth and service-error guards testable at all. Every marked block is now asserted to exist, to be valid shell, and to be sourceable, because a renamed marker would extract EMPTY -- and an empty guard sources fine and asserts nothing. WHAT THE MUTATIONS CHANGED Three of six came back NOT CAUGHT on the first pass, and two were real. The anchor could be deleted with every check still passing, because the fixture for "a review discussing a 503" put the error on line 3, where `head -n 1` already excluded it. A fixture whose FIRST line contains the error text mid-line -- which only `^` can reject -- now covers it. The persistent-outage abort was checked by grepping the script for its condition, which `if false && [ ... ]` still satisfies. That decision is now a named function, `backend_outage_should_fail`, called by the test rather than grepped for; three mutations of it are caught where the grep caught none. `have_text` moved inside the marked block so the block is self-contained -- the marker is a comment, so nothing about where the function is defined changed. The third, removing the `[ -s ]` empty-file check, is an EQUIVALENT mutant and is recorded as such rather than papered over with a test: an empty capture yields no grep match either way, so the check is defensive and its removal is unobservable. Superset verified rather than assumed: every non-comment line SLAC had before this sweep is either present in the template or is old delete machinery this design removes, plus a large-diff fallback the template supersedes -- SLAC's copy handled GitHub's 20,000-line limit only, the template's handles the 300-FILE limit too. All five installs now run one implementation. Selftest passes and actionlint is clean in each. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- scripts/agy-review-selftest.sh | 72 +++++++++++++++++++++++++++- scripts/agy-review.sh | 86 ++++++++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+), 1 deletion(-) diff --git a/scripts/agy-review-selftest.sh b/scripts/agy-review-selftest.sh index 0a4153a6..9851e416 100755 --- a/scripts/agy-review-selftest.sh +++ b/scripts/agy-review-selftest.sh @@ -30,11 +30,33 @@ SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" extract_marker() { sed -n 's/^MARKER="\(.*\)"$/\1/p' "$SCRIPT_DIR/agy-review.sh" | head -n 1 } +# Extraction is delimited by explicit `SELFTEST-EXTRACT` markers rather than by matching the +# declaration's own syntax. Adopted FROM SLAC, and it is the better mechanism: the `sed` range +# it replaced ended at the first line closing with a quote, so a filter whose body ever ended a +# line that way would be silently TRUNCATED -- and a truncated jq program can still compile and +# still return ids, which is exactly the silent-wrong-answer this file exists to prevent. +# Markers also let a guard be several statements rather than one assignment, which is what makes +# the OAuth and service-error guards testable at all. +extract_block() { + sed -n "/^# >>> SELFTEST-EXTRACT: $1\$/,/^# <<< SELFTEST-EXTRACT\$/p" "$SCRIPT_DIR/agy-review.sh" +} extract_filter() { - sed -n "/^SELECT_OURS_JQ='/,/'\$/p" "$SCRIPT_DIR/agy-review.sh" \ + extract_block "ours-comment filter" \ + | sed -n "/^SELECT_OURS_JQ='/,/'\$/p" \ | sed "1s/^SELECT_OURS_JQ='//; \$s/'\$//" } +# Every marked block must exist and be sourceable. A renamed or unbalanced marker would +# otherwise extract EMPTY, and an empty guard sources fine and asserts nothing -- the same +# absence-reads-as-agreement failure the markers were adopted to prevent. +for guard in "service-error guard" "oauth guard" "ours-comment filter"; do + blk="$(extract_block "$guard")" + [ -n "$blk" ] || { echo "FAIL: SELFTEST-EXTRACT block '$guard' is missing or empty" >&2; exit 1; } + printf '%s\n' "$blk" | bash -n - 2>/dev/null \ + || { echo "FAIL: extracted block '$guard' is not valid shell (unbalanced markers?)" >&2; exit 1; } + eval "$blk" +done + MARKER="$(extract_marker)" FILTER="$(extract_filter)" @@ -192,6 +214,54 @@ else echo " ok --arg/--argjson are not passed to \`gh api\`" fi +# --- the service-error guard --------------------------------------------------- +# When agy's upstream is down it prints an error, not a review. That text is non-empty, so +# `have_text` alone treats it as a valid review and POSTs it -- a green check for a review that +# never ran. Observed twice on SLAC PR #14, where the check passed in 7 seconds with the error +# string as its entire body. A control that cannot fail is worse than no control. +se() { printf '%s' "$1" > "$TMPD/cap"; service_error_present "$TMPD/cap" && echo MATCH || echo NOMATCH; } +TMPD="$(mktemp -d)" +trap 'rm -rf "$TMPD"' EXIT + +check "a bare backend 503 is caught" "MATCH" \ + "$(se 'Error: Eligibility check failed: UNAVAILABLE (code 503): The service is currently unavailable.')" +check "RESOURCE_EXHAUSTED is caught" "MATCH" "$(se 'Error: RESOURCE_EXHAUSTED')" + +# The false positives the anchoring exists to avoid. A genuine review may quote a 503 while +# reviewing retry logic, and aborting on that would be the very failure the OAuth guard's design +# notes warn about. +check "a review DISCUSSING a 503 is not caught" "NOMATCH" \ + "$(se "$(printf '## Review\n\nThe retry path should handle Error: UNAVAILABLE (code 503) here.\n')")" +check "an error on line 3 is not caught (only line 1 counts)" "NOMATCH" \ + "$(se "$(printf '## Review\n\nError: UNAVAILABLE (code 503)\n')")" +check "an empty capture is not caught" "NOMATCH" "$(se '')" + +# The ANCHOR, tested where it is the only thing that matters: the error text is on LINE ONE but +# not at its start. `head -n 1` cannot exclude this; only `^` can. Without this fixture the +# anchor could be deleted and every other check still passed. +check "a heading MENTIONING an error mid-line is not caught" "NOMATCH" \ + "$(se '## Review of the Error: UNAVAILABLE (code 503) retry path')" + +# ...and the anchored form still matches with leading whitespace, which the regex allows. +check "a leading-whitespace error is still caught" "MATCH" \ + "$(se ' Error: UNAVAILABLE (code 503)')" + +# The size cap is what separates "the error IS the whole capture" from "a review mentions one". +long="Error: UNAVAILABLE (code 503) $(head -c 3000 /dev/zero | tr '\0' 'x')" +check "a long capture opening with an error is not caught" "NOMATCH" "$(se "$long")" + +# The script must FAIL rather than post when the backend errored and nothing was produced. +# Called, not grepped for: `if false && [ "${service_errors:-0}" -gt 0 ]` still contains what a +# structural grep looks for, and that mutation came back NOT CAUGHT. +: > "$TMPD/empty" +printf 'a real review\n' > "$TMPD/review" +check "outage + no review -> fail the job" "0" \ + "$(backend_outage_should_fail 2 "$TMPD/empty"; echo $?)" +check "outage + a review -> do not fail" "1" \ + "$(backend_outage_should_fail 2 "$TMPD/review"; echo $?)" +check "no outage + no review -> not THIS guard's job" "1" \ + "$(backend_outage_should_fail 0 "$TMPD/empty"; echo $?)" + if [ "$fails" -ne 0 ]; then echo "$fails check(s) failed" >&2 exit 1 diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 5728b9bd..0af20131 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -17,7 +17,60 @@ set -euo pipefail # clamp, so log() must already exist. (Defined later, a clamp that fires would die with # `log: command not found` under set -e instead of warning — a latent misconfiguration trap.) log() { printf '[agy-review] %s\n' "$*" >&2; } + +# A capture that is only a BACKEND ERROR, not a review. When agy's upstream is down it prints +# something like: +# +# Error: Eligibility check failed: UNAVAILABLE (code 503): The service is currently unavailable. +# +# That text is non-empty, so have_text() alone treats it as a valid review, POSTs it as the +# review comment, and the job exits 0 -- a green check for a review that never happened. Observed +# on SLAC PR #14: the `review` check passed in 7 seconds with that string as its entire body, +# twice. A control that cannot fail is worse than no control. +# +# The match is deliberately ANCHORED to the start of the capture rather than being a substring +# search. A genuine review may legitimately quote a 503, an "UNAVAILABLE" constant, or an +# eligibility check while reviewing retry logic -- and aborting on that would be the +# false-positive the OAuth guard's design notes warn about. agy's backend failures occupy the +# WHOLE capture and begin with `Error:`, so requiring the error at the top, in a capture short +# enough to contain nothing else, separates the two without a content heuristic. +# +# Adopted FROM SLAC, which had it while the template and the other installs did not. +# >>> SELFTEST-EXTRACT: service-error guard +# `have_text` lives INSIDE this block, not above it: `backend_outage_should_fail` calls it, so +# an extracted block without it is not self-contained and the selftest cannot run it. It is a +# general helper used throughout the script -- the marker is a comment, so its position +# changes nothing about where the function is defined. have_text() { [ -s "$1" ] && grep -q '[^[:space:]]' "$1"; } +AGY_ERROR_RE='^[[:space:]]*Error:.*(Eligibility check failed|UNAVAILABLE|unavailable|RESOURCE_EXHAUSTED|INTERNAL|DEADLINE_EXCEEDED|code [45][0-9]{2})' +# Captures longer than this are assumed to be real reviews even if they open with an error line: +# a genuine review is thousands of bytes, a bare backend error is a couple of hundred. +AGY_ERROR_MAX_BYTES="${AGY_ERROR_MAX_BYTES:-2000}" +# `head -n 1`, not `head -n 5`. grep matches line-by-line, so scanning five lines +# means "any of the first five lines is an error line" -- which would discard a short, +# genuine review whose heading is on line 1 and which happens to discuss `Error: ... +# UNAVAILABLE` on line 3. That is the false positive the anchoring was supposed to +# prevent, reintroduced by the very check meant to enforce it. The invariant is that a +# backend failure IS the whole capture, so only the first line can carry it. +service_error_present() { + [ -s "$1" ] || return 1 + [ "$(wc -c < "$1")" -le "$AGY_ERROR_MAX_BYTES" ] || return 1 + head -n 1 "$1" | grep -qE "$AGY_ERROR_RE" +} + +# True when the run must FAIL rather than post: the backend errored at least once and no review +# survived. A separate named function rather than an inline condition, because a structural grep +# for the condition is too weak to notice it being disabled -- `if false && [ ... ]` still +# contains the text a grep looks for, and that mutation came back NOT CAUGHT. +# +# The `have_text` half is redundant today (the retry loop truncates the capture whenever it +# counts a backend error) and is kept deliberately: it makes the "post nothing" guarantee +# independent of that truncation surviving a future edit. +backend_outage_should_fail() { + [ "${1:-0}" -gt 0 ] || return 1 + ! have_text "$2" +} +# <<< SELFTEST-EXTRACT # Guarding against a leak of agy's interactive Google OAuth login flow. When agy's cached # session lapses on the runner, `--print` emits the login prompt (a live OAuth URL + "paste the # authorization code here") instead of a review; that text is non-empty, so have_text() alone @@ -44,6 +97,7 @@ have_text() { [ -s "$1" ] && grep -q '[^[:space:]]' "$1"; } # would miss a URL emitted as `.../o/oauth2?client_id=…` or bare `.../o/oauth2` (a leak). The # scheme is what keeps a review's bare-pattern quote from matching, so dropping the trailing # slash loses no safety. +# >>> SELFTEST-EXTRACT: oauth guard OAUTH_URL_RE='https?://accounts\.google\.com/o/oauth2' # The single guard, used at BOTH the retry-loop capture (Layer 1) and the assembled body before @@ -54,6 +108,7 @@ OAUTH_URL_RE='https?://accounts\.google\.com/o/oauth2' # URL is always present in a real login flow, so it alone is both necessary and sufficient; a # lapse is detected AND a leak is blocked by the same unconditional check. oauth_url_present() { [ -s "$1" ] && grep -qiE "$OAUTH_URL_RE" "$1"; } +# <<< SELFTEST-EXTRACT # --- configuration (all env-overridable from the workflow) --------------------- AGY_BIN="${AGY_BIN:-agy}" @@ -119,12 +174,14 @@ MAX_BODY_BYTES="${MAX_BODY_BYTES:-60000}" # (an HTML comment, invisible when rendered) in a PR comment and have this bot edit it. Only # ever touch our own bot's comments. `first` picks the OLDEST match, so if duplicates exist # from an older version of this script, the canonical thread is the one that keeps growing. +# >>> SELFTEST-EXTRACT: ours-comment filter SELECT_OURS_JQ='[ .[] | select(.user.type == "Bot" and .user.login == "github-actions[bot]") | select(.body | contains($marker)) ] | first | .id // empty' readonly SELECT_OURS_JQ +# <<< SELFTEST-EXTRACT REPO="${GITHUB_REPOSITORY:?GITHUB_REPOSITORY not set}" @@ -165,6 +222,9 @@ diff_file= diff_err= meta_file= prompt_file= out_file= raw= body_file= agy_diff_ # Set to 1 if agy printed its interactive OAuth login flow instead of a review (lapsed session); # gates the no-post abort below. Pre-declared so `${auth_failed:-0}` is set-u-safe on every path. auth_failed=0 +# Counts backend-error captures across attempts; see `service_error_present`. Pre-declared so +# `${service_errors:-0}` is set-u-safe even on paths that never enter the retry loop. +service_errors=0 # Set when the large-diff fallback below creates refs/agy/* so the trap can remove them. agy_refs_created= cleanup() { @@ -554,6 +614,21 @@ for (( attempt=1; attempt<=AGY_RETRIES; attempt++ )); do # reading it would post that session's output into a public PR comment (data # leak). The PTY path above plus the retry loop cover agy issue #76 without it. + # A backend error is TRANSIENT, so it retries like empty output rather than aborting the way a + # lapsed session does -- but it must never be mistaken for a review. Blank the capture so no + # later path can post it, and let the loop try again. + # + # A COUNTER, not a per-attempt flag. A boolean reset each attempt reflects only the last one, + # so a 503 on attempt 1 followed by empty output on attempt 3 would report the generic "no + # output" cause, and the reverse would claim the backend was down on every attempt when it was + # down on one. Both exit non-zero, so nothing unsafe -- but the log line is the only thing + # telling a human which outage they are looking at. + if service_error_present "$out_file"; then + log "agy returned a backend error rather than a review (attempt ${attempt}/${AGY_RETRIES}): $(head -n 1 "$out_file")" + : > "$out_file" + service_errors=$(( ${service_errors:-0} + 1 )) + fi + have_text "$out_file" && break if [ "$attempt" -lt "$AGY_RETRIES" ]; then delay=$(( AGY_RETRY_DELAY * attempt )) @@ -571,6 +646,17 @@ if [ "${auth_failed:-0}" = "1" ]; then exit 1 fi +# A persistent backend failure is reported as its own cause, and it FAILS THE JOB. Posting the +# error as a review comment (the previous behaviour) produced a passing check for a review that +# never ran; posting nothing and exiting non-zero makes the outage visible where it matters. +# The `! have_text` is redundant today -- the loop truncates $out_file whenever it counts a +# backend error -- and is kept deliberately: it makes the "post nothing" guarantee independent +# of that truncation surviving a future edit. +if backend_outage_should_fail "${service_errors:-0}" "$out_file"; then + log "agy's backend returned an error on ${service_errors} of ${AGY_RETRIES} attempt(s) and no review was produced. Failing the check rather than posting the error as a review. Re-run with '/agy-review' once the service recovers." + exit 1 +fi + if ! have_text "$out_file"; then log "no review output after ${AGY_RETRIES} attempt(s). Check $LOG and confirm 'agy -p \"hi\"' works for this user." # Surface agy's stderr into the job log. RUNNER_TEMP is wiped between jobs, so a bare From 02787c1ee22d8c8ee0ddcfb74bbcd49d10302813 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 11:49:46 -0400 Subject: [PATCH 06/10] fix(ci): the reviewer workflow must tolerate the script set on the default branch The reviewer workflow checks out the DEFAULT BRANCH to get its scripts -- that is deliberate and documented, so a fork's code never executes on the self-hosted runner. But for a `pull_request` event GitHub runs the workflow YAML itself from the PR BRANCH. The two halves therefore come from different refs, and a change spanning both breaks its own PR. The preceding commit added `scripts/_agy_comment_body.sh` and added it to the workflow's chmod; on RustyNES the job died with chmod: cannot access 'scripts/_agy_comment_body.sh': No such file or directory because the checkout was of `main`, which does not have the file yet. Every repo in this sweep would have hit the identical failure on its next run. The surprising half is the inversion. The default-branch rule is documented for the scripts -- a change to agy-review.sh has no effect until it merges -- and its corollary is that the workflow moves IMMEDIATELY while the scripts do not, which runs against the usual intuition that a PR is self-consistent. The workflow half now tolerates both script sets: the two required files are chmod'd unconditionally, anything added later only if present, with a trailing `true` so a false `[ -f ]` cannot fail the step under `bash -e`. A genuinely missing required file still fails loudly, because agy-review.sh sources it and dies -- the tolerance belongs in the workflow, not in the contract. actionlint clean. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- .github/workflows/antigravity-review.yml | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/antigravity-review.yml b/.github/workflows/antigravity-review.yml index d500f69f..4a5abbbc 100644 --- a/.github/workflows/antigravity-review.yml +++ b/.github/workflows/antigravity-review.yml @@ -101,7 +101,21 @@ jobs: # MAX_PROMPT_BYTES: "125000" # inline/file threshold + hard backstop on the argv prompt # STYLE_GUIDE: .github/agy-review.md # style guide, loaded if present run: | - # `_agy_comment_body.sh` is sourced by the reviewer at startup, so a - # missing or non-executable copy fails the run rather than degrading it. - chmod +x scripts/agy-review.sh scripts/_agy_print.sh scripts/_agy_comment_body.sh + # The workflow and the scripts come from DIFFERENT REFS: for a `pull_request` + # event GitHub runs this YAML from the PR branch, while the checkout step + # above deliberately fetches the DEFAULT branch to get the scripts. So a + # change that adds a script file breaks its own PR -- the new workflow + # chmods a file the default branch does not have yet. Observed exactly + # once, on the PR that introduced `_agy_comment_body.sh`. + # + # The two required files are chmod'd unconditionally; anything added later + # is chmod'd only if present, so the workflow stays compatible with both + # the old and the new script set. A genuinely missing required file still + # fails loudly -- `agy-review.sh` sources it and dies -- rather than being + # papered over here. + chmod +x scripts/agy-review.sh scripts/_agy_print.sh + for opt in scripts/_agy_comment_body.sh; do + [ -f "$opt" ] && chmod +x "$opt" + done + true scripts/agy-review.sh From 552b1ef178e115e099f4da6387ed5391774ca4d2 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 12:12:38 -0400 Subject: [PATCH 07/10] fix(ci): the review comment no longer goes through argv `gh api -f body="$(cat "$body_file")"` passed the whole comment as a single execve argument. At MAX_BODY_BYTES the archived comment approaches 60 KB against a MAX_ARG_STRLEN of 128 KB on Linux -- close enough that raising the bound later would start failing with E2BIG, and the failure would read as a GitHub API error rather than a local limit. It is now `jq -n --rawfile b "$body_file" '{body: $b}'` piped into `gh api ... --input -`. Nothing traverses argv, and `--rawfile` makes the value a JSON string by construction, so neither shell quoting nor `-F` type-coercion can reinterpret a body that happens to look like a number or a boolean. Selftest passes. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- scripts/agy-review.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 0af20131..14b0686d 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -772,8 +772,15 @@ if [ -n "$prior_id" ] && [ -s "$prior_body_file" ]; then exit 1 fi - if gh api -X PATCH "repos/${REPO}/issues/comments/${prior_id}" \ - -f body="$(cat "$body_file")" >/dev/null 2>&1; then + # The body goes through STDIN as JSON, never through argv. At `MAX_BODY_BYTES` + # the comment can approach 60 KB, and a single execve argument is capped at + # `MAX_ARG_STRLEN` (128 KB on Linux) -- close enough that a future raise of that + # bound would start failing with E2BIG, and the failure would look like a + # GitHub error rather than a local limit. `--rawfile` also makes the value a + # JSON string by construction, so no shell quoting or `-F` type-coercion can + # reinterpret a body that happens to look like a number or a boolean. + if jq -n --rawfile b "$body_file" '{body: $b}' \ + | gh api -X PATCH "repos/${REPO}/issues/comments/${prior_id}" --input - >/dev/null 2>&1; then log "updated review comment ${prior_id} on ${REPO}#${PR} (earlier rounds archived in place)" rm -f "$prior_body_file" exit 0 From 5a1932952b1c63426a5274a225b40adcdc8a9116 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 12:33:06 -0400 Subject: [PATCH 08/10] fix(ci): a
in a review body could tear the round it lives in `agy_drop_oldest_round` located the oldest archived round by matching `/^
$/` -- the tag itself. A review body legitimately contains `
` blocks: folded logs, collapsed code, another bot's summary, and the archived rounds are themselves nested `
`. So the cut could land INSIDE a round, leaving torn HTML and half a review in a comment nobody would think to check. It is now delimited by `AGY_ROUND_MARK`, an HTML comment the writer emits ahead of each round. Invisible when rendered, and it cannot occur by accident in prose the way a tag can. Same mechanism the archive boundaries already used -- markers for the outer boundaries and a naive regex for the inner ones was the kind of half-application that reads as consistent until someone tries it with real content. An archive written by the previous version has no round markers. With none present the function exits non-zero and NOTHING is dropped, so the edit fails on size -- recoverable, visible, repaired by the next round -- rather than the archive being silently mangled. Three checks and two mutations. The nested case is the one that matters: a round carrying its own `
` must survive the oldest being dropped, and restoring the tag-matching form fails it. Also asserted: the writer actually emits the sentinel, because otherwise every archive looks legacy-shaped, the trim silently never fires, and the comment grows until the edit fails. Selftest passes. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- scripts/_agy_comment_body.sh | 22 ++++++++++++++++++---- scripts/agy-review-selftest.sh | 32 ++++++++++++++++++++++++++++++-- scripts/agy-review.sh | 1 + 3 files changed, 49 insertions(+), 6 deletions(-) diff --git a/scripts/_agy_comment_body.sh b/scripts/_agy_comment_body.sh index 4997864f..5668f9ce 100755 --- a/scripts/_agy_comment_body.sh +++ b/scripts/_agy_comment_body.sh @@ -47,11 +47,25 @@ agy_body_archive() { $0 == s { inside = 1 }' || true } -# Drop the OLDEST archived round -- the last `
` block. Exits non-zero when there is -# none left to drop, so a caller trimming to a size limit terminates rather than spinning. +# Delimits one archived round. Emitted by the caller ahead of each round's `
`. +# +# A dedicated sentinel, NOT the `
` tag itself. Matching `/^
$/` looked +# equivalent and was a data-corruption bug: a review body legitimately contains `
` +# blocks -- folded logs, collapsed code, another bot's summary, and the archived rounds are +# themselves nested `
` -- so the cut could land INSIDE a round and leave torn HTML +# plus half a review. The sentinel is an HTML comment, so it is invisible when rendered and +# cannot occur by accident in prose the way a tag can. Found in review. +AGY_ROUND_MARK='' + +# Drop the OLDEST archived round -- everything from the last round marker onward. +# +# Exits non-zero when there is no marker to cut at, so a caller trimming to a size limit +# terminates rather than spinning. That is also the fail-safe direction for an archive written +# by an older version of this script: with no markers present, nothing is dropped and the edit +# simply fails on size, rather than the archive being silently mangled. agy_drop_oldest_round() { - awk ' - /^
$/ { starts[++n] = NR } + awk -v m="$AGY_ROUND_MARK" ' + $0 == m { starts[++n] = NR } { line[NR] = $0 } END { cut = (n > 0) ? starts[n] : 0 diff --git a/scripts/agy-review-selftest.sh b/scripts/agy-review-selftest.sh index 9851e416..decbda30 100755 --- a/scripts/agy-review-selftest.sh +++ b/scripts/agy-review-selftest.sh @@ -188,9 +188,37 @@ check "the head never carries the marker into the archive" "" \ # Trimming must terminate: with no `
` left, dropping fails rather than looping. check "dropping from an empty archive fails rather than spinning" "1" \ "$(printf 'no rounds here\n' | agy_drop_oldest_round >/dev/null 2>&1; echo $?)" + +# An archive written by an OLDER version has no round markers. Nothing must be dropped: +# the edit then fails on size, which is recoverable, rather than the archive being mangled. +check "an unmarked (legacy) archive drops nothing" "1" \ + "$(printf '
\nNEW\n
\n
\nOLD\n
\n' \ + | agy_drop_oldest_round >/dev/null 2>&1; echo $?)" + +marked_archive="$(printf '%s\n
\nNEW\n
\n%s\n
\nOLD\n
\n' \ + "$AGY_ROUND_MARK" "$AGY_ROUND_MARK")" check "dropping removes the OLDEST round, keeping the newest" \ - "$(printf '
\nNEW\n
')" \ - "$(printf '
\nNEW\n
\n
\nOLD\n
\n' | agy_drop_oldest_round)" + "$(printf '%s\n
\nNEW\n
' "$AGY_ROUND_MARK")" \ + "$(printf '%s\n' "$marked_archive" | agy_drop_oldest_round)" + +# THE BUG THIS SENTINEL EXISTS FOR. A review body legitimately contains `
` blocks +# -- folded logs, collapsed code, another bot's summary -- and matching the tag itself cut +# INSIDE a round, leaving torn HTML and half a review. The newest round below carries its own +# `
`; dropping the oldest must not touch it. +nested="$(printf '%s\n
\nRound\n
\nfolded log\n
\nfinding\n
\n%s\n
\nOLD\n
\n' \ + "$AGY_ROUND_MARK" "$AGY_ROUND_MARK")" +check "a
INSIDE a round is not mistaken for a round boundary" \ + "$(printf '%s\n
\nRound\n
\nfolded log\n
\nfinding\n
' "$AGY_ROUND_MARK")" \ + "$(printf '%s\n' "$nested" | agy_drop_oldest_round)" + +# The writer must actually EMIT the sentinel, or every archive is legacy-shaped and the trim +# silently never fires -- the comment would then grow until the edit fails. +if grep -q 'AGY_ROUND_MARK' "$SCRIPT_DIR/agy-review.sh"; then + echo " ok agy-review.sh emits the round sentinel" +else + echo " FAIL agy-review.sh never emits AGY_ROUND_MARK; the archive would never trim" + fails=$((fails + 1)) +fi # The script must not delete comments any more. A reintroduced DELETE is the regression that # would silently restore the destructive behaviour this design replaced. diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index 14b0686d..fb7fc862 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -731,6 +731,7 @@ if [ -n "$prior_id" ] && [ -s "$prior_body_file" ]; then archived_file="$(mktemp)" { + printf '%s\n' "$AGY_ROUND_MARK" printf '
\nRound reviewed at %s\n\n' \ "$(date -u +'%Y-%m-%d %H:%M UTC')" printf '%s\n' "$prior_head" From fe61fdceda7b47afeacfec932df0f8cbcdaa7f6e Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 14:09:30 -0400 Subject: [PATCH 09/10] fix(ci): en-US spelling in the shared reviewer scripts RustyN64 enforces en-US spelling through `scripts/check_en_us.sh`, and two of my comment lines carried "behaviour". The check passes on that repo's `main` and failed on the PR, so this was mine rather than pre-existing. Fixed in the canonical template rather than in the one repo that complained. The five installs are byte-identical by design -- that is what makes the sync a copy instead of a re-derivation -- so a spelling fix applied locally would have made RustyN64 the odd one out and the next template sync would have reverted it. en-US is the safe common denominator: the repos that do not enforce it do not care, and the one that does now passes. Verified by running RustyN64's own checker against the template's scripts rather than by eye: it reported the same two lines before and reports none after. Not touched: `docs/provenance.md` in RustyN64 also trips the checker locally, but it is UNTRACKED there -- a stray working-tree file, not part of any PR, which is why CI counted two findings where a local run counts three. Deleting or editing another repo's untracked file to quiet a checker would be the wrong fix for a problem CI does not have. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- scripts/agy-review-selftest.sh | 2 +- scripts/agy-review.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/agy-review-selftest.sh b/scripts/agy-review-selftest.sh index decbda30..491f8a5f 100755 --- a/scripts/agy-review-selftest.sh +++ b/scripts/agy-review-selftest.sh @@ -221,7 +221,7 @@ else fi # The script must not delete comments any more. A reintroduced DELETE is the regression that -# would silently restore the destructive behaviour this design replaced. +# would silently restore the destructive behavior this design replaced. if grep -qE 'gh api +-X +DELETE' "$SCRIPT_DIR/agy-review.sh"; then echo " FAIL agy-review.sh deletes comments again; the archive design forbids it" fails=$((fails + 1)) diff --git a/scripts/agy-review.sh b/scripts/agy-review.sh index fb7fc862..656e760a 100755 --- a/scripts/agy-review.sh +++ b/scripts/agy-review.sh @@ -647,7 +647,7 @@ if [ "${auth_failed:-0}" = "1" ]; then fi # A persistent backend failure is reported as its own cause, and it FAILS THE JOB. Posting the -# error as a review comment (the previous behaviour) produced a passing check for a review that +# error as a review comment (the previous behavior) produced a passing check for a review that # never ran; posting nothing and exiting non-zero makes the outage visible where it matters. # The `! have_text` is redundant today -- the loop truncates $out_file whenever it counts a # backend error -- and is kept deliberately: it makes the "post nothing" guarantee independent From 9ee67138876db295af2d98b005d15f45f18ed9b2 Mon Sep 17 00:00:00 2001 From: DoubleGate Date: Thu, 20 Aug 2026 15:10:31 -0400 Subject: [PATCH 10/10] fix(deps): close RUSTSEC-2026-0257 and bring every dependency current `Cargo Deny Check` and `Dependency Audit` were failing on `main`, not merely on a branch, so the vulnerability had been shipping. RUSTSEC-2026-0257 -- `BROWSER` argument injection on Unix, reached transitively through `egui-winit` -> `webbrowser` 1.2.1. On Unix the affected versions substituted the caller's URL into the `BROWSER` template BEFORE tokenizing the result with `split_ascii_whitespace()`, so a URL that retains spaces could break out into additional browser arguments. Upstream reproduced it against Chromium with `--remote-debugging-port`, exposing a local DevTools endpoint, and `--proxy-server`, redirecting traffic through an attacker-controlled proxy. Fixed in 1.2.2 by tokenizing the template first; this lands 1.2.4. EVERY DEPENDENCY, NOT JUST THE VULNERABLE ONE 141 packages moved to their latest semver-compatible versions. A targeted patch of the one crate would have cleared the gate while leaving the rest of the graph wherever it happened to be; a current graph is the state a security gate can meaningfully assert against, and it is cheaper to verify once than to re-verify per advisory. Verified rather than assumed. `cargo deny check` reports advisories ok, bans ok, licenses ok, sources ok. The workspace is green at 66 suites / 897 tests / 0 failures, with `cargo fmt --all --check`, `cargo clippy --workspace --all-targets -- -D warnings` and a full `cargo build --workspace` all passing. That test run is the point of the exercise: a green `cargo deny` says nothing about whether 141 package updates changed emulator behaviour, and the suite is the only thing that can answer it. TWO IGNORES RETIRED ON THEIR OWN STATED CONDITION `deny.toml` ignored the `quick-xml 0.39.4` pair (RUSTSEC-2026-0194 and RUSTSEC-2026-0195) with the note that no upgrade path existed -- the fixes live in quick-xml >= 0.40, `wayland-scanner` 0.31.10 pinned ^0.39, and the entry said to revisit on the next wayland-scanner / smithay-client-toolkit release. That release arrived in this update: wayland-scanner 0.31.10 -> 0.31.11 pulls quick-xml 0.39.4 -> 0.41.0. `cargo deny` flagged both ignores as matching no crate, which is the signal that an ignore has outlived its reason, and the check stays green with them removed. The `ttf-parser` ignore (RUSTSEC-2026-0192) is KEPT and still matches: an informational "unmaintained" advisory, not a vulnerability, on a transitive dep of winit's Wayland decoration stack with no upgrade available. NOT TOUCHED `## [1.21.0] "Touchstone"` carries two sibling `### Changed` headings, which trips MD024 under this repo's `siblings_only` config. It predates this change by many releases -- confirmed against HEAD -- and quietly folding an unrelated lint fix into a security bump would make both harder to review. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_014qfTKi2M3swo7qnwvYCkDj --- CHANGELOG.md | 36 +++ Cargo.lock | 900 ++++++++++++++++++++++++++++----------------------- deny.toml | 10 - 3 files changed, 528 insertions(+), 418 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6903721e..81b05136 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,42 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Security + +- **`webbrowser` 1.2.1 → 1.2.4, closing RUSTSEC-2026-0257** (`BROWSER` argument + injection on Unix). Reached transitively through `egui-winit`: on Unix the + affected versions substituted the URL into the `BROWSER` template *before* + tokenizing with `split_ascii_whitespace()`, so a URL retaining spaces could + become extra browser arguments — reproduced upstream against Chromium with + `--remote-debugging-port` and `--proxy-server`. + + The advisory was failing `Cargo Deny Check` and `Dependency Audit` on `main`, + not only on a branch, so this had been shipping. + +### Changed + +- **Every dependency moved to its latest semver-compatible version** — 141 + packages, `cargo update`. Not a targeted patch of the one vulnerable crate: + the whole graph is now current, which is the state a security gate can + meaningfully assert against. + + Verified rather than assumed: `cargo deny check` reports **advisories ok, bans + ok, licenses ok, sources ok**, and the workspace is green at **66 suites / 897 + tests / 0 failures** with `fmt`, `clippy --workspace -D warnings` and a full + `build` all passing. + +- **Two `deny.toml` advisory ignores retired on their own stated condition.** The + `quick-xml 0.39.4` pair (RUSTSEC-2026-0194 / RUSTSEC-2026-0195) was ignored with + the note *"no upgrade path exists … revisit on the next wayland-scanner / + smithay-client-toolkit release"*. That release arrived: + `wayland-scanner 0.31.10 → 0.31.11` pulls `quick-xml 0.39.4 → 0.41.0`, past the + `>= 0.40` the fixes live in. `cargo deny` flagged both as matching no crate, and + it stays green with them removed. + + The `ttf-parser` ignore (RUSTSEC-2026-0192) still matches and is kept — it is an + informational *unmaintained* advisory on a transitive dep of `winit`'s + decoration stack, with no upgrade available. + ## [1.31.1] "Firewall" - 2026-08-04 ### Added diff --git a/Cargo.lock b/Cargo.lock index c1187973..b880685e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,9 +52,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.4" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +checksum = "c982642fa9e8606056828ee9a8505737230110bb1099153c79efe865c59d12ba" dependencies = [ "memchr", ] @@ -72,7 +72,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "812947049edcd670a82cd5c73c3661d2e58468577ba8489de58e1a73c04cbd5d" dependencies = [ "alsa-sys", - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "libc", ] @@ -94,7 +94,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f2a1bb052857d5dd49572219344a7332b31b76405648eabac5bc68978251bcd" dependencies = [ "android-properties", - "bitflags 2.13.0", + "bitflags 2.13.1", "cc", "jni 0.22.4", "libc", @@ -103,7 +103,7 @@ dependencies = [ "ndk-context", "ndk-sys", "num_enum", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -131,9 +131,9 @@ dependencies = [ [[package]] name = "android_system_properties" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +checksum = "ae221649c9976a6f6c56ae1facf410f3ddb33cc661c4b7b61020a912d4237fbc" dependencies = [ "libc", ] @@ -196,9 +196,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.103" +version = "1.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" +checksum = "330a5ed07fa54e4702c9d6c4174f74427fc0ef6e214bbd677ae50a5099946470" [[package]] name = "approx" @@ -225,7 +225,7 @@ dependencies = [ "objc2-foundation 0.3.2", "parking_lot", "percent-encoding", - "windows-sys 0.59.0", + "windows-sys 0.60.2", "x11rb", ] @@ -237,9 +237,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" [[package]] name = "as-raw-xcb-connection" @@ -280,10 +280,10 @@ dependencies = [ "memchr", "proc-macro2", "quote", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "serde_derive", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -325,6 +325,12 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" +[[package]] +name = "base64" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac07cdecf99051d9a5238b80f35af32cdeba5b336e55d957b318b50137e18da5" + [[package]] name = "basic-toml" version = "0.1.10" @@ -394,9 +400,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.13.0" +version = "2.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" +checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da" [[package]] name = "block-buffer" @@ -427,9 +433,9 @@ dependencies = [ [[package]] name = "bstr" -version = "1.12.3" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cee35f73844aa3014bb606320a6c1f010249dbdf43342fe54b5a4f6a8ed4b79" +checksum = "6bb31b46c14244e20ee9984b11bf5c992b91fb6939fea616e3512c8baecdbe5f" dependencies = [ "memchr", "serde_core", @@ -449,22 +455,22 @@ checksum = "64fa3c856b712db6612c019f14756e64e4bcea13337a6b33b696333a9eaa2d06" [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "95832e849adfb21180ccb6826a99da14e5d266ae5c2e668e1602cf234f153797" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.2" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +checksum = "fc0e56a716f1e132ff6bf4bdac1c944a3fcdc1cae65f70a4a2a1ac3b401d2d1f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -475,9 +481,9 @@ checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" [[package]] name = "bytes" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae3f5d315924270530207e2a68396c3cc547f6dca3fbdca317cfb1a51edb593" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" [[package]] name = "calloop" @@ -485,7 +491,7 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "log", "polling", "rustix 0.38.44", @@ -507,9 +513,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.4" +version = "1.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" +checksum = "bb1307f12aa967b5a58416e87b3653360e0fd614a016b6e970db08fecbb1b80d" dependencies = [ "serde_core", ] @@ -534,7 +540,7 @@ dependencies = [ "semver", "serde", "serde_json", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -554,9 +560,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.65" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +checksum = "509591b7bcd67f4ef775afad7662703b4935daaa6ec0e5605cfb1090b32a2b6d" dependencies = [ "find-msvc-tools", "jobserver", @@ -587,9 +593,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527" [[package]] name = "ciborium" @@ -620,9 +626,9 @@ dependencies = [ [[package]] name = "clang-sys" -version = "1.8.1" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +checksum = "157a8ba7b480713b56f4c09fd13fc3e0a22a5dfab8097ba61cbc5feef950788a" dependencies = [ "glob", "libc", @@ -631,9 +637,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.1" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" dependencies = [ "clap_builder", "clap_derive", @@ -641,9 +647,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.0" +version = "4.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" dependencies = [ "anstream", "anstyle", @@ -653,23 +659,23 @@ dependencies = [ [[package]] name = "clap_complete" -version = "4.6.5" +version = "4.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a7a9bfdb35811f9e59832f0f05975114d2251b415fb534108e6f34060fd772" +checksum = "3be2ad0423bdbbb0e25bc89add796f3559706d4a95e1bc98e4d9662a957b6a19" dependencies = [ "clap", ] [[package]] name = "clap_derive" -version = "4.6.1" +version = "4.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2ce8604710f6733aa641a2b3731eaa1e8b3d9973d5e3565da11800813f997a9" +checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -748,9 +754,9 @@ dependencies = [ [[package]] name = "console" -version = "0.16.3" +version = "0.16.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" dependencies = [ "encode_unicode", "libc", @@ -792,16 +798,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -815,7 +811,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "core-graphics-types", "foreign-types", "libc", @@ -828,7 +824,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "libc", ] @@ -838,7 +834,7 @@ version = "0.14.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d5d7dca3ebcf65a035582c9ad4385371a9d9ee6537474d2a278f4e1e475bb58" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2-audio-toolbox", "objc2-core-audio", @@ -848,9 +844,9 @@ dependencies = [ [[package]] name = "cpal" -version = "0.18.1" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f77b11176c37874be37e8d691c946e31b2b8c357abce9526f6a99eb469e1028" +checksum = "6f02e8d0327b42d3e2e4ab2119af397344eb9fc54a34bf0ddeaa1277af8681f1" dependencies = [ "alsa", "block2 0.6.2", @@ -954,9 +950,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crossterm" @@ -964,7 +960,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b9f2e4c67f833b660cdb0a3523065869fb35570177239812ed4c905aeff87b" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crossterm_winapi", "derive_more", "document-features", @@ -1019,9 +1015,9 @@ checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" [[package]] name = "darling" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +checksum = "ed17f5901b6630b993ca003def43f2f8ef4014fc13b047b57aad617ff32bc2ec" dependencies = [ "darling_core", "darling_macro", @@ -1029,26 +1025,26 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +checksum = "6837e2cf7485aaae18f86181d2f0e9a7ed297a025e220aeabf63fdebd3a2ddff" dependencies = [ "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "darling_macro" -version = "0.23.0" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +checksum = "2ac7135c3ef02b2f7833bbeb1be5ba7f966dcde8a87c6b87f65a778d71a02785" dependencies = [ "darling_core", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1088,7 +1084,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -1134,7 +1130,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e0e367e4e7da84520dedcac1901e4da967309406d1e51017ae1abfb97adbd38" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -1142,13 +1138,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.6" +version = "0.2.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +checksum = "c6232dd377dcc64799954cbd3a9bb882e9cdc1308ccd87b1c098f1fb2eaf82a8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1199,7 +1195,7 @@ checksum = "2796c98d50b79631281d516343a6f6e93c0666462ca36e2c93b39f25d7793325" dependencies = [ "accesskit", "ahash", - "bitflags 2.13.0", + "bitflags 2.13.1", "emath", "epaint", "itertools 0.14.0", @@ -1222,7 +1218,7 @@ dependencies = [ "epaint", "log", "profiling", - "thiserror 2.0.18", + "thiserror 2.0.20", "type-map", "web-time", "wgpu", @@ -1249,9 +1245,9 @@ dependencies = [ [[package]] name = "either" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" +checksum = "9e5e8f6c15a24b9a3ee5efec809ccd006d3b30e8b3bb63c39af737c7f87daa1d" [[package]] name = "emath" @@ -1327,9 +1323,9 @@ dependencies = [ [[package]] name = "error-code" -version = "3.3.2" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" +checksum = "0b5343afd4a8365a643ac588dab4cf234a190c7f6c88c9f6dd6ffe00837661b7" [[package]] name = "euclid" @@ -1350,17 +1346,11 @@ dependencies = [ "regex", ] -[[package]] -name = "fast-srgb8" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd2e7510819d6fbf51a5545c8f922716ecfb14df168a3242f7d33e0239efe6a1" - [[package]] name = "fastrand" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" +checksum = "da7c62ceae207dd37ea5b845da6a0696c799f85e97da1ab5b7910be3c1c80223" [[package]] name = "fax" @@ -1396,9 +1386,9 @@ dependencies = [ [[package]] name = "find-msvc-tools" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" +checksum = "d45db016d36b838f563236e9193d0ee6ce38f3f68b6c94e914b4929c96bbb890" [[package]] name = "finl_unicode" @@ -1462,13 +1452,13 @@ dependencies = [ [[package]] name = "foreign-types-macros" -version = "0.2.3" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +checksum = "ea5190182e6915eb873ddbc16e23b711b6eb1f9c00a0d0a3a91b5f6228475225" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -1497,21 +1487,21 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" +checksum = "92d699e522242e69e3003b94ecc1f960f3a5e015aa7c5d7486e65ad01dd94f5e" [[package]] name = "futures-task" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" +checksum = "cd417de3d1d015fc3bfd2b1ea46dfc7bab72ef86f1cc7cc9c78e728b34a6d1fd" [[package]] name = "futures-util" -version = "0.3.32" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +checksum = "0d50a92467f8ba5dd6e3ee5d4bd04d73ab2e4e1c44474a0674821dfce14b79bc" dependencies = [ "futures-core", "futures-task", @@ -1636,9 +1626,9 @@ dependencies = [ [[package]] name = "glob" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" +checksum = "e4eba85ea1d0a966a983acd07deee566e67395d2d96b6fb39e62b5a833f1eb0b" [[package]] name = "glow" @@ -1682,7 +1672,7 @@ dependencies = [ "hashbrown 0.16.1", "log", "presser", - "thiserror 2.0.18", + "thiserror 2.0.20", "windows", ] @@ -1692,7 +1682,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "gpu-descriptor-types", "hashbrown 0.15.5", ] @@ -1703,7 +1693,7 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -1733,7 +1723,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0431e8e389aa0f1e72bb9d1c2db8957a1a7a3580e8ed97db819c14837aac9b3e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "read-fonts", "smallvec", @@ -1805,9 +1795,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" dependencies = [ "bytes", "itoa", @@ -1821,9 +1811,9 @@ checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] name = "icu_collections" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +checksum = "fa68d21081c4a05d5a901a1c62add574c77048b6a1c67be3b50ce0b60d4ca513" dependencies = [ "displaydoc", "potential_utf", @@ -1835,9 +1825,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +checksum = "d56e28588da92eee5c3201a6eff33fabdd49b62269c8938d4ff050ce4d900deb" dependencies = [ "displaydoc", "litemap", @@ -1848,9 +1838,9 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +checksum = "12f9cf5f235641ed274641dd81c3f28d870e276763d0797aeeab72317b1c646f" dependencies = [ "icu_collections", "icu_normalizer_data", @@ -1862,16 +1852,17 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" +checksum = "1563da1ed3e0b3bf3d74c9b85917ac9c56464d2f57242270c09c9e752f8021a0" [[package]] name = "icu_properties" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +checksum = "7e7ca276ad3145661a65914e6daf131ca5120cd3dcee8f8f3214b8875184a148" dependencies = [ + "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", @@ -1882,15 +1873,15 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" +checksum = "e590f038c1464a96894fd6d10127e90a8be4509f56ff7ecef851b15cee0b7caa" [[package]] name = "icu_provider" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +checksum = "92a7ed671a6aad807a8651a2e1782a6598fda9ce5185dd8158549e95a91c6428" dependencies = [ "displaydoc", "icu_locale_core", @@ -1963,20 +1954,20 @@ dependencies = [ [[package]] name = "inotify" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533e68a5842e734946fe159fb03fc9bbbb254f590dd0d8ad321ae5ff7beca2c1" +checksum = "4cc00ea907cab49550b7da656f80ebb97be1b997d931fbcd28d39734e17ce592" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "inotify-sys", "libc", ] [[package]] name = "inotify-sys" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05c02b5e89bff3b946cedeca278abc628fe811e604f027c45a8aa3cf793d0eb" +checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d" dependencies = [ "libc", ] @@ -1995,15 +1986,15 @@ dependencies = [ [[package]] name = "instability" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eb2d60ef19920a3a9193c3e371f726ec1dafc045dac788d0fb3704272458971" +checksum = "2bf84e73fa6f27f299dec58e13223cf70db80da872eb921d4f6138342a0eabc8" dependencies = [ "darling", "indoc", "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -2064,7 +2055,7 @@ dependencies = [ "jni-sys 0.4.1", "log", "simd_cesu8", - "thiserror 2.0.18", + "thiserror 2.0.20", "walkdir", "windows-link", ] @@ -2079,7 +2070,7 @@ dependencies = [ "quote", "rustc_version", "simd_cesu8", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2107,24 +2098,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" dependencies = [ "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" +checksum = "0e0c1080212aad755ea003d18543e8768dd432c48819efd73a7bf1e39b7a5a3a" dependencies = [ "cfg-if", "futures-util", @@ -2139,7 +2130,7 @@ checksum = "bde5057d6143cc94e861d90f591b9303d6716c6b9602309150bd068853c10899" dependencies = [ "hashbrown 0.16.1", "portable-atomic", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -2191,9 +2182,9 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.186" +version = "0.2.189" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" +checksum = "3eaf3ede3fee6db1a4c2ee091bf8a8b4dccdc6d17f656fb07896ee72867612f2" [[package]] name = "libloading" @@ -2213,14 +2204,14 @@ checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.17" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f02ab6bace2054fb888a3c16f990117b579d14a3088e472d63c6011fa185c9d3" +checksum = "28d0a00925a9f930d679b6789b721e3a7f9ed110f41b86d2497caa780c3a070a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "plain", - "redox_syscall 0.8.1", + "redox_syscall 0.9.2", ] [[package]] @@ -2235,11 +2226,11 @@ dependencies = [ [[package]] name = "line-clipping" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f50e8f47623268b5407192d26876c4d7f89d686ca130fdc53bced4814cd29f8" +checksum = "e752191d037c44ad111a8caa762921926658402f01cc1253f7bef2020ece4f5e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -2262,9 +2253,9 @@ checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" +checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" [[package]] name = "litrs" @@ -2289,9 +2280,9 @@ checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" -version = "0.18.0" +version = "0.18.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9" +checksum = "5d2f2f9b4ba7e6b24d95e7e899329d35be83bcded72c8540cdd5368932d1d90a" dependencies = [ "hashbrown 0.17.1", ] @@ -2312,7 +2303,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "920cf654b23d217c550ceea57c32cd2a413ea27b6d47ed77b5ee0cf655adefa6" dependencies = [ "cc", - "which 8.0.4", + "which 8.0.5", ] [[package]] @@ -2333,9 +2324,9 @@ checksum = "dae608c151f68243f2b000364e1f7b186d9c29845f7d2d85bd31b9ad77ad552b" [[package]] name = "memchr" -version = "2.8.2" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmap2" @@ -2379,9 +2370,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" +checksum = "30d65c71f1ce40ab09135ce117d742b9f8a19ff91a41a8b57ed50bc2de59c427" dependencies = [ "libc", "log", @@ -2401,7 +2392,7 @@ dependencies = [ "mlua-sys", "num-traits", "parking_lot", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", ] [[package]] @@ -2430,13 +2421,13 @@ dependencies = [ [[package]] name = "naga" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dd91265cc2454558f659b3b4b9640f0ddb8cc6521277f166b8a8c181c898079" +checksum = "b2bf919621e7975acb27d881bae2fb993e0d45c8e0446e85e6272971e00dc8df" dependencies = [ "arrayvec", "bit-set 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "codespan-reporting", @@ -2451,7 +2442,7 @@ dependencies = [ "pp-rs", "rustc-hash 1.1.0", "spirv", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-ident", ] @@ -2461,7 +2452,7 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "jni-sys 0.3.1", "log", "ndk-sys", @@ -2491,7 +2482,7 @@ version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", @@ -2504,7 +2495,7 @@ version = "0.31.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cfg-if", "cfg_aliases", "libc", @@ -2540,7 +2531,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2572,7 +2563,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -2615,7 +2606,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "libc", "objc2 0.5.2", @@ -2631,7 +2622,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-core-graphics", @@ -2644,7 +2635,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6948501a91121d6399b79abaa33a8aa4ea7857fe019f341b8c23ad6e81b79b08" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2 0.6.4", "objc2-core-audio", @@ -2659,7 +2650,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13a380031deed8e99db00065c45937da434ca987c034e13b87e4441f9e4090be" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-foundation 0.3.2", ] @@ -2670,7 +2661,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -2707,7 +2698,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a89f2ec274a0cf4a32642b2991e8b351a404d290da87bb6a9a9d8632490bd1c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", ] @@ -2717,7 +2708,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2729,7 +2720,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "dispatch2", "libc", @@ -2742,7 +2733,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dispatch2", "objc2 0.6.4", "objc2-core-foundation", @@ -2785,7 +2776,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "dispatch", "libc", @@ -2798,7 +2789,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "libc", "objc2 0.6.4", @@ -2811,7 +2802,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "33fafba39597d6dc1fb709123dfa8289d39406734be322956a69f0931c73bb15" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "libc", "objc2-core-foundation", ] @@ -2822,7 +2813,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", ] @@ -2845,7 +2836,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2857,7 +2848,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0125f776a10d00af4152d74616409f0d4a2053a6f57fa5b7d6aa2854ac04794" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "objc2 0.6.4", "objc2-foundation 0.3.2", @@ -2869,7 +2860,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-foundation 0.2.2", @@ -2882,7 +2873,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c1358452b371bf9f104e21ec536d37a650eb10f7ee379fff67d2e08d537f1f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -2905,7 +2896,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-cloud-kit", @@ -2926,7 +2917,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d87d638e33c06f577498cbcc50491496a3ed4246998a7fbba7ccb98b1e7eab22" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "objc2 0.6.4", "objc2-core-foundation", "objc2-foundation 0.3.2", @@ -2949,7 +2940,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "objc2 0.5.2", "objc2-core-location", @@ -3019,26 +3010,35 @@ dependencies = [ [[package]] name = "palette" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cbf71184cc5ecc2e4e1baccdb21026c20e5fc3dcf63028a086131b3ab00b6e6" +checksum = "ddeed8580d347d2abf3dcf06a5f0b3dc020258338526b277847cd4248a70fc64" dependencies = [ "approx", - "fast-srgb8", "libm", "palette_derive", + "palette_math", ] [[package]] name = "palette_derive" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5030daf005bface118c096f510ffb781fc28f9ab6a32ab224d8631be6851d30" +checksum = "88537020289b719d81be994ccf1bbf4990f477e2f69ee52fe3e45f43a02e56be" dependencies = [ "by_address", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", +] + +[[package]] +name = "palette_math" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e6eb142958d64335fb0e345c5b9ead2ecd6fc438c307e9d7d3c4fd428dbaf12" +dependencies = [ + "libm", ] [[package]] @@ -3091,9 +3091,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "5a07a60cc7a4d00c91f95c685609d1d2f79050e6804b70ebedd7650f0b839bcf" dependencies = [ "memchr", "ucd-trie", @@ -3101,9 +3101,9 @@ dependencies = [ [[package]] name = "pest_derive" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11f486f1ea21e6c10ed15d5a7c77165d0ee443402f0780849d1768e7d9d6fe77" +checksum = "b3a83744a5c8455b8b3e0dc5031362780a347c878bdd11584d1a8984228cc88d" dependencies = [ "pest", "pest_generator", @@ -3111,25 +3111,24 @@ dependencies = [ [[package]] name = "pest_generator" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8040c4647b13b210a963c1ed407c1ff4fdfa01c31d6d2a098218702e6664f94f" +checksum = "e0cd3451aa3de60d4b9a1e736885e4dea6b31617598026f12256ad566d63304a" dependencies = [ "pest", "pest_meta", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "pest_meta" -version = "2.8.6" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89815c69d36021a140146f26659a81d6c2afa33d216d736dd4be5381a7362220" +checksum = "e04d3a0849e241d7dfce834c83b1c5edc8622009e8dd51a12ba1927c32f05496" dependencies = [ "pest", - "sha2", ] [[package]] @@ -3172,7 +3171,7 @@ dependencies = [ "phf_shared", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3201,7 +3200,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -3212,9 +3211,9 @@ checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkg-config" -version = "0.3.33" +version = "0.3.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" +checksum = "f6b464fbc74e149a392436b17d523f769e057cb6877f6a5c4618bc6f11800548" [[package]] name = "plain" @@ -3256,7 +3255,7 @@ version = "0.18.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "crc32fast", "fdeflate", "flate2", @@ -3294,9 +3293,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +checksum = "05c8b63e8d9609db387f0324918f81d68fe27748f084ef092fb35954d0539a85" [[package]] name = "portable-atomic-util" @@ -3309,9 +3308,9 @@ dependencies = [ [[package]] name = "potential_utf" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +checksum = "d83eb9bc6d8e5cf568e7a1101d60ee05e81ed50ea106026f3d18deeb046d7661" dependencies = [ "zerovec", ] @@ -3348,9 +3347,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.106" +version = "1.0.107" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +checksum = "985e7ec9bb745e6ce6535b544d84d6cd6f7ad8bd711c398938ae983b91a766d9" dependencies = [ "unicode-ident", ] @@ -3375,18 +3374,18 @@ checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" [[package]] name = "quick-xml" -version = "0.39.4" +version = "0.41.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e" +checksum = "e660451e55124f798a69a5af3f49ccfbefbd41910eefd25caf2393e1f3473ec1" dependencies = [ "memchr", ] [[package]] name = "quote" -version = "1.0.46" +version = "1.0.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +checksum = "1fbf4db142a473a8d80c26bbf18454ed458bf8d26c8219c331daecfdbd079001" dependencies = [ "proc-macro2", ] @@ -3405,9 +3404,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] name = "rand" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ca0ecfa931c29007047d1bc58e623ab12e5590e8c7cc53200d5202b69266d8a" +checksum = "22f6172bdec972074665ed81ed53b71da00bfc44b65a753cfde883ec4c702a1a" dependencies = [ "rand_core", ] @@ -3446,7 +3445,7 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cbb175c433c8e28a809d1f5773a2ae96e68c0ce40db865cbab1020bf33ae479c" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "compact_str", "critical-section", "hashbrown 0.17.1", @@ -3456,7 +3455,7 @@ dependencies = [ "palette", "serde", "strum", - "thiserror 2.0.18", + "thiserror 2.0.20", "unicode-segmentation", "unicode-truncate", "unicode-width", @@ -3511,7 +3510,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "66e3d19bcc9130ca376277d93b60767ff121ace3be06f5f95f81dd68956407d1" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "hashbrown 0.17.1", "indoc", "instability", @@ -3588,16 +3587,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] name = "redox_syscall" -version = "0.8.1" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7" +checksum = "f1c93da5bb2c5d4e6c0ef7abeead62c89169a0a4882bfb83ac892f2423aea2fe" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -3608,14 +3607,14 @@ checksum = "a4e608c6638b9c18977b00b475ac1f28d14e84b27d8d42f70e0bf1e3dec127ac" dependencies = [ "getrandom 0.2.17", "libredox", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] name = "regex" -version = "1.12.4" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +checksum = "f020237b6c8eed93db2e2cb53c00c60a8e1bc73da7d073199a1180401450218d" dependencies = [ "aho-corasick", "memchr", @@ -3625,9 +3624,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "ad8553b9b26413251cbf30e620595c7a41b3887f03da04579c0e6b0d6a06b4b2" dependencies = [ "aho-corasick", "memchr", @@ -3743,9 +3742,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc_version" @@ -3762,7 +3761,7 @@ version = "0.38.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.4.15", @@ -3775,7 +3774,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "errno", "libc", "linux-raw-sys 0.12.1", @@ -3784,9 +3783,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.41" +version = "0.23.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" +checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" dependencies = [ "log", "once_cell", @@ -3799,18 +3798,18 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.15.0" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" +checksum = "2f4925028c7eb5d1fcdaf196971378ed9d2c1c4efc7dc5d011256f76c99c0a96" dependencies = [ "zeroize", ] [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "0527518605e68109d875e248ea259b6758801cf165e4b2c2733ae3b51f12535a" dependencies = [ "ring", "rustls-pki-types", @@ -3819,9 +3818,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rustysnes-android" @@ -3843,7 +3842,7 @@ dependencies = [ name = "rustysnes-apu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", ] @@ -3851,9 +3850,9 @@ dependencies = [ name = "rustysnes-cart" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -3875,7 +3874,7 @@ dependencies = [ "rustysnes-ppu", "rustysnes-savestate", "sha2", - "thiserror 2.0.18", + "thiserror 2.0.20", "zip", ] @@ -3883,7 +3882,7 @@ dependencies = [ name = "rustysnes-cpu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-savestate", ] @@ -3918,8 +3917,8 @@ dependencies = [ "rustysnes-savestate", "rustysnes-script", "serde", - "thiserror 2.0.18", - "toml 1.1.2+spec-1.1.0", + "thiserror 2.0.20", + "toml 1.1.4+spec-1.1.0", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", @@ -3961,7 +3960,7 @@ version = "1.25.0" dependencies = [ "rustysnes-cart", "rustysnes-core", - "thiserror 2.0.18", + "thiserror 2.0.20", "uniffi", ] @@ -3972,7 +3971,7 @@ dependencies = [ "js-sys", "rustysnes-core", "rustysnes-savestate", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "web-sys", ] @@ -3981,7 +3980,7 @@ dependencies = [ name = "rustysnes-ppu" version = "1.25.0" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustysnes-cart", "rustysnes-savestate", "xxhash-rust", @@ -3991,7 +3990,7 @@ dependencies = [ name = "rustysnes-savestate" version = "1.25.0" dependencies = [ - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -4000,7 +3999,7 @@ version = "1.25.0" dependencies = [ "mlua", "rustysnes-core", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -4059,7 +4058,7 @@ checksum = "1783eabc414609e28a5ba76aee5ddd52199f7107a0b24c2e9746a1ecc34a683d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4077,9 +4076,9 @@ dependencies = [ [[package]] name = "self_cell" -version = "1.2.2" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b12e76d157a900eb52e81bc6e9f3069344290341720e9178cde2407113ac8d89" +checksum = "2ab42ca02749e120097e328d91d415325bdf43b1c72c4c8badf37375fe40a813" [[package]] name = "semver" @@ -4093,9 +4092,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba" dependencies = [ "serde_core", "serde_derive", @@ -4103,29 +4102,29 @@ dependencies = [ [[package]] name = "serde_core" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.228" +version = "1.0.229" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] name = "serde_json" -version = "1.0.150" +version = "1.0.151" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14" dependencies = [ "itoa", "memchr", @@ -4199,15 +4198,15 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" +checksum = "3a219298ac11a56ea9a6d2120044824d6f01aeb034955e7af7bc16858527deea" [[package]] name = "simd_cesu8" -version = "1.1.1" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f90157bb87cddf702797c5dadfa0be7d266cdf49e22da2fcaa32eff75b2c33" +checksum = "11031e251abf8611c80f460e19dbdeb54a66db918e49c65a7065b46ac7aec520" dependencies = [ "rustc_version", "simdutf8", @@ -4280,7 +4279,7 @@ version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "calloop", "calloop-wayland-source", "cursor-icon", @@ -4314,7 +4313,7 @@ version = "0.4.0+sdk-1.4.341.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9571ea910ebd84c86af4b3ed27f9dbdc6ad06f17c5f96146b2b671e2976744f" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", ] [[package]] @@ -4359,7 +4358,7 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4381,9 +4380,20 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.118" +version = "2.0.119" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +checksum = "53e9bae58849f64dfa4f5d5ae372c8341f7305f82a3868709269343628b659a3" dependencies = [ "proc-macro2", "quote", @@ -4398,7 +4408,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4429,7 +4439,7 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9048a889effe34a5cddee0af7f53285198b16dca3be510858d38dfdb3e62a04e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "parking_lot", "rustix 1.1.4", "signal-hook", @@ -4464,8 +4474,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4676b37242ccbd1aabf56edb093a4827dc49086c0ffd764a5705899e0f35f8f7" dependencies = [ "anyhow", - "base64", - "bitflags 2.13.0", + "base64 0.22.1", + "bitflags 2.13.1", "fancy-regex", "filedescriptor", "finl_unicode", @@ -4519,11 +4529,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +checksum = "ec86235f5fcc2a73650310756d2ac5b138a5780bbbdfae3eeccec992c435ba4f" dependencies = [ - "thiserror-impl 2.0.18", + "thiserror-impl 2.0.20", ] [[package]] @@ -4534,18 +4544,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] name = "thiserror-impl" -version = "2.0.18" +version = "2.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +checksum = "bc04cd3e1236dd4a98afca4569f2deb3f120e5422a4023be2cb683f8486292af" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -4564,9 +4574,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.51" +version = "0.3.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85c17d80feb7334b40c484e45ed1a5273dfd8bfda537c3be2e74a06a6686f327" +checksum = "cdb87b95ec50ddfa440816d227a17b2ccbdda963a316a727fda0fc4334f7d134" dependencies = [ "deranged", "libc", @@ -4610,9 +4620,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +checksum = "b1e27c91459209c2986af3dcf603a5a74a4368754ce37414f59acc971167f643" dependencies = [ "displaydoc", "zerovec", @@ -4639,9 +4649,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.2+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81f3d15e84cbcd896376e6730314d59fb5a87f31e4b038454184435cd57defee" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap", "serde_core", @@ -4649,7 +4659,7 @@ dependencies = [ "toml_datetime", "toml_parser", "toml_writer", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] @@ -4663,30 +4673,30 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.12+spec-1.1.0" +version = "0.25.13+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" +checksum = "6975367e4d2ef766d86af01ffad14b622fecc8d4357a998fbc4deb6e9bacaf9b" dependencies = [ "indexmap", "toml_datetime", "toml_parser", - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_parser" -version = "1.1.2+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ - "winnow 1.0.3", + "winnow 1.0.4", ] [[package]] name = "toml_writer" -version = "1.1.1+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "756daf9b1013ebe47a8776667b466417e2d4c5679d441c26230efd9ef78692db" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tracing" @@ -4716,7 +4726,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" dependencies = [ - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", ] [[package]] @@ -4842,7 +4852,7 @@ dependencies = [ "indexmap", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -4857,7 +4867,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.118", + "syn 2.0.119", "toml 0.5.11", "uniffi_meta", ] @@ -4907,11 +4917,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0" +checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d" dependencies = [ - "base64", + "base64 0.23.1", "log", "percent-encoding", "rustls", @@ -4923,11 +4933,11 @@ dependencies = [ [[package]] name = "ureq-proto" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c" +checksum = "da5f78b09e6941e1a0f2e30e695e4b120377b54d5e0aec11b594bb57b3971613" dependencies = [ - "base64", + "base64 0.23.1", "http", "httparse", "log", @@ -4965,9 +4975,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.4" +version = "1.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" +checksum = "2cefc03fd367c0c6d4305de1b312cf00248c4114f4a0418ce6a6af769e3b0bd9" dependencies = [ "atomic", "getrandom 0.4.3", @@ -4994,7 +5004,7 @@ dependencies = [ "log", "peniko", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", ] [[package]] @@ -5051,9 +5061,9 @@ dependencies = [ [[package]] name = "wasm-bindgen" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" +checksum = "1b70935747edd64d89de3efa29d73789b806c15798f8e7dca4d8ac356b50ce70" dependencies = [ "cfg-if", "once_cell", @@ -5064,9 +5074,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.76" +version = "0.4.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" +checksum = "6b7777d5cc23d0e91404e53ce2d5e8ec7acae3026b16233dba62cd3246457950" dependencies = [ "js-sys", "wasm-bindgen", @@ -5074,9 +5084,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" +checksum = "77775f8f3f7217702089053b94958f8f54061a3f663417df76e19cbdcca29bc1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5084,31 +5094,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" +checksum = "e11d33f857dc2fb11b8bc75aee111aa9cbeb12cd9f25efd3d4c2a3dd4e235284" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.126" +version = "0.2.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" +checksum = "7ef64dbcc55df09c7e5a46182d181c2cfa3e925f3da937ea764728b4bbb9dcbf" dependencies = [ "unicode-ident", ] [[package]] name = "wayland-backend" -version = "0.3.15" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d" +checksum = "38a91b4eaddff87b1cd1074985e3713da4af2c49742d1b356b2c01670a67a078" dependencies = [ "cc", "downcast-rs", @@ -5120,11 +5130,11 @@ dependencies = [ [[package]] name = "wayland-client" -version = "0.31.14" +version = "0.31.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144" +checksum = "e3c36a0f861ad76d0901f2800b46321410d9f73f2ea88aac0650d86c32688073" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "rustix 1.1.4", "wayland-backend", "wayland-scanner", @@ -5136,7 +5146,7 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "cursor-icon", "wayland-backend", ] @@ -5158,7 +5168,7 @@ version = "0.32.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-scanner", @@ -5170,7 +5180,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b6d8cf1eb2c1c31ed1f5643c88a6e53538129d4af80030c8cabd1f9fa884d91" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5183,7 +5193,7 @@ version = "0.3.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "wayland-backend", "wayland-client", "wayland-protocols", @@ -5192,9 +5202,9 @@ dependencies = [ [[package]] name = "wayland-scanner" -version = "0.31.10" +version = "0.31.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a" +checksum = "338e30461b3a2b67d70eb30a6d89f8e0c93a833e07d2ae89085cd070c4a00ac0" dependencies = [ "proc-macro2", "quick-xml", @@ -5215,9 +5225,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.103" +version = "0.3.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" +checksum = "c435338968042f4f59a557f690a253676d47ce13ceb55d70100e7facf6620a30" dependencies = [ "js-sys", "wasm-bindgen", @@ -5235,15 +5245,15 @@ dependencies = [ [[package]] name = "webbrowser" -version = "1.2.1" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc95580916af1e68ff6a7be07446fc5db73ebf71cf092de939bbf5f7e189f72" +checksum = "62c35be770821a214dbc362fc26908c853e776c0004294d0b10b8a6bad582f94" dependencies = [ - "core-foundation 0.10.1", "jni 0.22.4", "log", "ndk-context", "objc2 0.6.4", + "objc2-app-kit 0.3.2", "objc2-foundation 0.3.2", "url", "web-sys", @@ -5251,9 +5261,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.8" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" +checksum = "7dcd9d09a39985f5344844e66b0c530a33843579125f23e21e9f0f220850f22a" dependencies = [ "rustls-pki-types", ] @@ -5347,12 +5357,12 @@ dependencies = [ [[package]] name = "wgpu" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb3feacc458f7bee8bc1737149b42b6c731aa461039a4264a67bb6681646b250" +checksum = "76e8840e1ba2881d4cbb18d2147627a56af426ff064c0401eb0c8410c6325d07" dependencies = [ "arrayvec", - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "cfg-if", "cfg_aliases", @@ -5377,14 +5387,14 @@ dependencies = [ [[package]] name = "wgpu-core" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02da3ad1b568337f25513b317870960ef87073ea0945502e44b864b67a8c77b7" +checksum = "2f519832254e56965a9940c4af57dcb75f702b6f6fa4a0b172f685395843a4d7" dependencies = [ "arrayvec", "bit-set 0.9.1", "bit-vec 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "cfg_aliases", "document-features", @@ -5399,7 +5409,7 @@ dependencies = [ "raw-window-handle", "rustc-hash 1.1.0", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wgpu-core-deps-apple", "wgpu-core-deps-emscripten", "wgpu-core-deps-wasm", @@ -5411,51 +5421,51 @@ dependencies = [ [[package]] name = "wgpu-core-deps-apple" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62e51b5447e144b3dbba4feb01f80f4fa21696fa0cd99afb2c3df1affd6fdb28" +checksum = "f5e39e26c4c0e07589e67d18546cf79ff45383659fc72fca4dd293358a0347f3" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-emscripten" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3487cd6293a963bc5c0c0396f6a2192043c50003c07f4efdccbad3d90ec9d819" +checksum = "01e09be551dc939498bdd5f6b2c66e55ab275dad25825267a08605a80fc9f0af" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-wasm" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c2f2fb042f36920771deb0b966543c5751b18f3d327760ffc90f74e20b2dcd4" +checksum = "af1fb1798be2a912497d4c224f72d39bb0cb34af50e8bcc29865bc339c943059" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-core-deps-windows-linux-android" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb01076d0aa08b0ba9bd741e178b5cc440f5abe99d9581323a4c8b5d1a1916" +checksum = "4e592c1bbef6ad047647ae6e666ebd8cee7a32bb4544d9700ec96cbf73230257" dependencies = [ "wgpu-hal", ] [[package]] name = "wgpu-hal" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f8e1a9e7a8512f276f7c62e018c7fa8d60954303fed2e5750114332049193f" +checksum = "97ace1c17727311c22a46e4e3faf56ea6de81af99dcc839bdfb54857b94d448d" dependencies = [ "android_system_properties", "arrayvec", "ash", "bit-set 0.9.1", - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.6.2", "bytemuck", "cfg-if", @@ -5488,7 +5498,7 @@ dependencies = [ "raw-window-metal", "renderdoc-sys", "smallvec", - "thiserror 2.0.18", + "thiserror 2.0.20", "wasm-bindgen", "wayland-sys", "web-sys", @@ -5501,9 +5511,9 @@ dependencies = [ [[package]] name = "wgpu-naga-bridge" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c654c483f058800972c3645e95388a7eca31bf9fe1933bc20e036588a0be02" +checksum = "95226013f547544b223281cd16a4fb549aa9dcb562adbda0faae4c73ffbbc161" dependencies = [ "naga", "wgpu-types", @@ -5511,11 +5521,11 @@ dependencies = [ [[package]] name = "wgpu-types" -version = "29.0.3" +version = "29.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9bcc31518a0e9735aefebedb5f7a9ef3ed1c42549c9f4c882fa9060ceaac639" +checksum = "84bf84cd9ca8ca45e2b223a3868f1adf9bfc0c66aeac212e76ee7e40fdadf8f5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "bytemuck", "js-sys", "log", @@ -5537,9 +5547,9 @@ dependencies = [ [[package]] name = "which" -version = "8.0.4" +version = "8.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48d7cd18d4acb58fb3cdfe9ea54e6cd96a4e7d4cc45c56338b236e82dad47248" +checksum = "8f3ef584124b911bcc3875c2f1472e80f24361ceb789bd1c62b3e9a3df9ff43c" dependencies = [ "libc", ] @@ -5628,7 +5638,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5639,7 +5649,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -5703,6 +5713,15 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + [[package]] name = "windows-sys" version = "0.61.2" @@ -5736,13 +5755,30 @@ dependencies = [ "windows_aarch64_gnullvm 0.52.6", "windows_aarch64_msvc 0.52.6", "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm", + "windows_i686_gnullvm 0.52.6", "windows_i686_msvc 0.52.6", "windows_x86_64_gnu 0.52.6", "windows_x86_64_gnullvm 0.52.6", "windows_x86_64_msvc 0.52.6", ] +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + [[package]] name = "windows-threading" version = "0.2.1" @@ -5764,6 +5800,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + [[package]] name = "windows_aarch64_msvc" version = "0.42.2" @@ -5776,6 +5818,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + [[package]] name = "windows_i686_gnu" version = "0.42.2" @@ -5788,12 +5836,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + [[package]] name = "windows_i686_msvc" version = "0.42.2" @@ -5806,6 +5866,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + [[package]] name = "windows_x86_64_gnu" version = "0.42.2" @@ -5818,6 +5884,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + [[package]] name = "windows_x86_64_gnullvm" version = "0.42.2" @@ -5830,6 +5902,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + [[package]] name = "windows_x86_64_msvc" version = "0.42.2" @@ -5842,6 +5920,12 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + [[package]] name = "winit" version = "0.30.13" @@ -5851,13 +5935,13 @@ dependencies = [ "ahash", "android-activity", "atomic-waker", - "bitflags 2.13.0", + "bitflags 2.13.1", "block2 0.5.1", "bytemuck", "calloop", "cfg_aliases", "concurrent-queue", - "core-foundation 0.9.4", + "core-foundation", "core-graphics", "cursor-icon", "dpi", @@ -5905,9 +5989,9 @@ dependencies = [ [[package]] name = "winnow" -version = "1.0.3" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0592e1c9d151f854e6fd382574c3a0855250e1d9b2f99d9281c6e6391af352f1" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" dependencies = [ "memchr", ] @@ -5920,9 +6004,9 @@ checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" [[package]] name = "writeable" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" +checksum = "3ad82d2a33cdc9674dc7465672f271e096168fcdbe0f799d9e6db8c5892679dc" [[package]] name = "x11-dl" @@ -5958,9 +6042,9 @@ checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" [[package]] name = "xcursor" -version = "0.3.10" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" +checksum = "163b33ed8786455e2fa5d72f554057ce3f3182425434f756cd39c99839d88e23" [[package]] name = "xkbcommon-dl" @@ -5968,7 +6052,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" dependencies = [ - "bitflags 2.13.0", + "bitflags 2.13.1", "dlib", "log", "once_cell", @@ -5983,15 +6067,15 @@ checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" [[package]] name = "xml-rs" -version = "0.8.28" +version = "0.8.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" +checksum = "e450f9b2ed1dff33c94c12589a87338689467b9c4f5d8a5710bd09a847d2c8a7" [[package]] name = "xxhash-rust" -version = "0.8.16" +version = "0.8.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d93c89cdc2d3a63c3ec48ffe926931bdc069eafa8e4402fe6d8f790c9d1e576" +checksum = "aee1b19627c7c60102ab80d3a9cbe18de90bfe03bfa6c3715447681f0e8c8af6" [[package]] name = "yoke" @@ -6012,28 +6096,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.52" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce1022995ff5ff5d841ad7d994facc23098cd40152f2c1d11cd607c6f530653f" +checksum = "556764e583adb45a9f8d413c2a147fa7e8d821e48e12b14fd560b607998b75eb" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.52" +version = "0.8.56" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ae7f38b72ec2a254e2b87ef277cf2cd4fb97cbebf944faa6f33354da0867930" +checksum = "f2ab42fc20575779bd240faa45f94a74256f755c0fa9e89f0ede20d91d0cdfc1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", ] [[package]] @@ -6053,7 +6137,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 2.0.119", "synstructure", ] @@ -6065,9 +6149,9 @@ checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" [[package]] name = "zerotrie" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +checksum = "4ea269c3bd32f0a32c321907a2ae912ba6f4649bb0fc764a15627e99a7095a3f" dependencies = [ "displaydoc", "yoke", @@ -6076,9 +6160,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.6" +version = "0.11.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +checksum = "bb0464e17806c1d976d5cba29399c7f08e516e279e2ba493f63123b5fca67dd8" dependencies = [ "yoke", "zerofrom", @@ -6087,13 +6171,13 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.3" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +checksum = "9f212a141d820099d57ffafb9569be9617a6f27d3dc881fbee8fb56642f917a9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.118", + "syn 3.0.3", ] [[package]] @@ -6112,15 +6196,15 @@ dependencies = [ [[package]] name = "zlib-rs" -version = "0.6.5" +version = "0.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5431d5661c32445236631278f27946e444ddafe4684cac70b185272d4f9c52d5" +checksum = "34b31d188d9d685a4f9c7b46d6e36631b07058d2cfe190267adce54dc230bf12" [[package]] name = "zmij" -version = "1.0.21" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" +checksum = "29666d0abbfad1e3dc4dcf6144730dd3a3ab225bbbdac83319345b1b44ccfc1b" [[package]] name = "zopfli" @@ -6136,9 +6220,9 @@ dependencies = [ [[package]] name = "zune-core" -version = "0.5.1" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb8a0807f7c01457d0379ba880ba6322660448ddebc890ce29bb64da71fb40f9" +checksum = "d56377fd46368984a170bc5aac5567e52ca5da874caa60bea39fcbca78fb658b" [[package]] name = "zune-jpeg" diff --git a/deny.toml b/deny.toml index 6528806c..cadec380 100644 --- a/deny.toml +++ b/deny.toml @@ -21,16 +21,6 @@ ignore = [ # sctk-adwaita -> ab_glyph -> owned_ttf_parser -> ttf-parser 0.25.1 (already the latest # release). No safe upgrade exists until winit's decoration stack moves off ab_glyph. "RUSTSEC-2026-0192", - # `quick-xml 0.39.4` -- two real advisories (quadratic duplicate-attribute scan; unbounded - # NsReader namespace allocation), BOTH requiring attacker-controlled XML input. The only - # consumer here is `wayland-scanner` 0.31.10, a PROC-MACRO that parses the vendored Wayland - # protocol XML files at COMPILE TIME -- no runtime code path in this project parses XML at - # all, and the inputs are trusted files shipped inside the wayland-protocols crates, never - # external data. No upgrade path exists: 0.39.4 is the max of its line, the fixes live in - # quick-xml >= 0.40, and wayland-scanner 0.31.10 (its own max version) pins ^0.39. Revisit on - # the next wayland-scanner / smithay-client-toolkit release. - "RUSTSEC-2026-0194", - "RUSTSEC-2026-0195", ] [licenses]