From c77a53ef3ad44a4bc732d2c670eec5d7bd25b845 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 10:31:40 +0000 Subject: [PATCH 1/3] ci(deps): bump github/codeql-action init+analyze to 4.38.1 together Dependabot split the bump across #151 and #154; each alone fails every analyze job because init and analyze must run the same action version (same fix as #138). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013z24CKdETNZRqL7CKMur99 --- .github/workflows/codeql.yml | 4 ++-- vendor/glib-0.18.5-patched/.cargo-ok | 1 - 2 files changed, 2 insertions(+), 3 deletions(-) delete mode 100644 vendor/glib-0.18.5-patched/.cargo-ok diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1972b5f..ec1a222 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -33,13 +33,13 @@ jobs: build-mode: none steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - - uses: github/codeql-action/init@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + - uses: github/codeql-action/init@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1 with: languages: ${{ matrix.language }} build-mode: ${{ matrix.build-mode }} # Path and rule exclusions, each with its reason, live in the config # file so they are reviewable in one place. config-file: ./.github/codeql/codeql-config.yml - - uses: github/codeql-action/analyze@cdf488f595d80d6e07e03d4674febd5ab45fa938 # v4.37.9 + - uses: github/codeql-action/analyze@1c5b675653bb5c22dbe9b12b556ec555138e09fd # v4.38.1 with: category: "/language:${{ matrix.language }}" diff --git a/vendor/glib-0.18.5-patched/.cargo-ok b/vendor/glib-0.18.5-patched/.cargo-ok deleted file mode 100644 index 5f8b795..0000000 --- a/vendor/glib-0.18.5-patched/.cargo-ok +++ /dev/null @@ -1 +0,0 @@ -{"v":1} \ No newline at end of file From 288474797066d4ea5b7f90976d80e7dd903c199e Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 10:31:40 +0000 Subject: [PATCH 2/3] ci: verify vendored glib against the published crate (#71) Adds a vendor-provenance workflow that downloads glib 0.18.5 from crates.io, checks it against the checksum pinned in PROVENANCE.md, and diffs it against vendor/glib-0.18.5-patched/. Any difference other than the deltas pinned (with SHA-256) in PROVENANCE.md's provenance block fails, so editing a delta requires updating PROVENANCE.md too. The first run found an undocumented fourth delta: the .cargo-ok registry extraction marker copied along with the source. It is not crate content, so it is removed rather than documented. Closes #71 Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013z24CKdETNZRqL7CKMur99 --- .github/scripts/verify_glib_provenance.py | 160 ++++++++++++++++++++++ .github/workflows/vendor-provenance.yml | 31 +++++ vendor/glib-0.18.5-patched/PROVENANCE.md | 17 +++ 3 files changed, 208 insertions(+) create mode 100755 .github/scripts/verify_glib_provenance.py create mode 100644 .github/workflows/vendor-provenance.yml diff --git a/.github/scripts/verify_glib_provenance.py b/.github/scripts/verify_glib_provenance.py new file mode 100755 index 0000000..bb238fe --- /dev/null +++ b/.github/scripts/verify_glib_provenance.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Verify the vendored glib tree against the published crate (issue #71). + +`vendor/glib-0.18.5-patched/` compiles into every Linux desktop build, and its +PROVENANCE.md claims the directory is the published `glib` 0.18.5 source apart +from a small set of documented deltas. This script enforces that claim: + +1. Parse the pinned crate checksum and delta list from PROVENANCE.md (the + fenced "Pinned deltas" block — the one place a reviewer reads them). +2. Download the `.crate` from crates.io (or read `--crate `) and verify + it against the pinned checksum. +3. Diff the extracted source against the vendored tree. Fail unless every + difference is a documented delta whose file matches its pinned SHA-256, + and every documented delta is an actual difference. + +Editing a delta file therefore fails CI unless PROVENANCE.md is updated in the +same change; any other edit, addition, or removal fails outright. + +Usage: verify_glib_provenance.py [--crate ] + +Removal gate: delete this script and its workflow together with the vendored +directory when Tauri's Linux stack uses glib >= 0.20. +""" + +import argparse +import hashlib +import io +import os +import re +import sys +import tarfile +import urllib.request + +REPO_ROOT = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..")) +VENDOR_DIR = os.path.join(REPO_ROOT, "vendor", "glib-0.18.5-patched") +MANIFEST = "PROVENANCE.md" +CRATE_NAME, CRATE_VERSION = "glib", "0.18.5" +CRATE_URL = ( + f"https://static.crates.io/crates/{CRATE_NAME}/" + f"{CRATE_NAME}-{CRATE_VERSION}.crate" +) + +BLOCK_RE = re.compile(r"```provenance\n(.*?)```", re.S) +CRATE_LINE_RE = re.compile(r"^crate-sha256: ([0-9a-f]{64})$") +DELTA_LINE_RE = re.compile(r"^delta: (\S+) sha256=([0-9a-f]{64})$") + + +def sha256(data: bytes) -> str: + return hashlib.sha256(data).hexdigest() + + +def parse_manifest(text: str) -> tuple[str, dict[str, str]]: + """Return (pinned crate checksum, {relative path: pinned sha256}).""" + blocks = BLOCK_RE.findall(text) + if len(blocks) != 1: + sys.exit(f"{MANIFEST}: expected exactly one ```provenance block, found {len(blocks)}") + crate_sum, deltas = None, {} + for line in blocks[0].splitlines(): + line = line.strip() + if not line or line.startswith("#"): + continue + if m := CRATE_LINE_RE.match(line): + if crate_sum is not None: + sys.exit(f"{MANIFEST}: duplicate crate-sha256 line") + crate_sum = m.group(1) + elif m := DELTA_LINE_RE.match(line): + path, digest = m.groups() + if path == MANIFEST or path in deltas: + sys.exit(f"{MANIFEST}: invalid or duplicate delta {path!r}") + deltas[path] = digest + else: + sys.exit(f"{MANIFEST}: unrecognised provenance line {line!r}") + if crate_sum is None: + sys.exit(f"{MANIFEST}: missing crate-sha256 line") + return crate_sum, deltas + + +def upstream_files(crate_bytes: bytes) -> dict[str, bytes]: + """Map relative path -> content for every regular file in the .crate.""" + prefix = f"{CRATE_NAME}-{CRATE_VERSION}/" + files = {} + with tarfile.open(fileobj=io.BytesIO(crate_bytes), mode="r:gz") as tar: + for member in tar.getmembers(): + if member.isdir(): + continue + if not member.isfile() or not member.name.startswith(prefix): + sys.exit(f"unexpected entry in published crate: {member.name!r}") + files[member.name[len(prefix):]] = tar.extractfile(member).read() + return files + + +def vendored_files() -> dict[str, bytes]: + """Map relative path -> content for every file under the vendored tree.""" + files = {} + for root, dirs, names in os.walk(VENDOR_DIR, followlinks=False): + for name in dirs + names: + full = os.path.join(root, name) + rel = os.path.relpath(full, VENDOR_DIR).replace(os.sep, "/") + if os.path.islink(full): + sys.exit(f"vendored tree contains a symlink: {rel}") + if name in names: + with open(full, "rb") as f: + files[rel] = f.read() + return files + + +def main() -> None: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("--crate", help="read the .crate from this path instead of crates.io") + args = parser.parse_args() + + vendored = vendored_files() + if MANIFEST not in vendored: + sys.exit(f"{MANIFEST} missing from {VENDOR_DIR}") + crate_sum, deltas = parse_manifest(vendored.pop(MANIFEST).decode()) + + if args.crate: + with open(args.crate, "rb") as f: + crate_bytes = f.read() + else: + with urllib.request.urlopen(CRATE_URL, timeout=60) as resp: + crate_bytes = resp.read() + actual_sum = sha256(crate_bytes) + if actual_sum != crate_sum: + sys.exit(f"crate checksum mismatch: pinned {crate_sum}, downloaded {actual_sum}") + upstream = upstream_files(crate_bytes) + + errors = [] + for path in sorted(set(upstream) | set(vendored)): + if path not in vendored: + errors.append(f"removed from vendored tree: {path}") + elif path not in upstream: + errors.append(f"added to vendored tree (undocumented): {path}") + elif upstream[path] == vendored[path]: + if path in deltas: + errors.append(f"documented delta is identical to upstream: {path}") + elif path not in deltas: + errors.append(f"undocumented change: {path}") + elif sha256(vendored[path]) != deltas[path]: + errors.append( + f"delta {path} changed without updating {MANIFEST} " + f"(now sha256={sha256(vendored[path])})" + ) + for path in sorted(set(deltas) - set(upstream)): + errors.append(f"documented delta is not a published file: {path}") + + if errors: + print("vendored glib provenance check FAILED:", file=sys.stderr) + for e in errors: + print(f" - {e}", file=sys.stderr) + sys.exit(1) + print( + f"vendored glib {CRATE_VERSION} matches the published crate " + f"({crate_sum[:12]}…) apart from {len(deltas)} documented delta(s) " + f"and {MANIFEST}" + ) + + +if __name__ == "__main__": + main() diff --git a/.github/workflows/vendor-provenance.yml b/.github/workflows/vendor-provenance.yml new file mode 100644 index 0000000..0909bf4 --- /dev/null +++ b/.github/workflows/vendor-provenance.yml @@ -0,0 +1,31 @@ +name: vendor-provenance + +# Guards vendor/glib-0.18.5-patched/ against drift (issue #71): the vendored +# crate is product code, and its PROVENANCE.md claim — published source plus a +# pinned set of deltas — is enforced here rather than by review alone. Remove +# together with the vendored directory (glib >= 0.20 removal gate). +on: + push: + branches: [main] + paths: + - "vendor/glib-0.18.5-patched/**" + - ".github/scripts/verify_glib_provenance.py" + - ".github/workflows/vendor-provenance.yml" + pull_request: + paths: + - "vendor/glib-0.18.5-patched/**" + - ".github/scripts/verify_glib_provenance.py" + - ".github/workflows/vendor-provenance.yml" + workflow_dispatch: + +permissions: + contents: read + +jobs: + glib: + name: vendored glib matches published crate + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: verify vendored glib against crates.io + run: python3 .github/scripts/verify_glib_provenance.py diff --git a/vendor/glib-0.18.5-patched/PROVENANCE.md b/vendor/glib-0.18.5-patched/PROVENANCE.md index 22d8b9e..0fca757 100644 --- a/vendor/glib-0.18.5-patched/PROVENANCE.md +++ b/vendor/glib-0.18.5-patched/PROVENANCE.md @@ -17,5 +17,22 @@ copy is a path dependency; it does not change runtime behavior. `cargo audit` matches by package name and version, so the workflow must continue ignoring RUSTSEC-2024-0429 even though the runtime code is patched. +## Pinned deltas (machine-checked) + +CI (`.github/workflows/vendor-provenance.yml`, running +`.github/scripts/verify_glib_provenance.py`) downloads the published crate, +verifies it against `crate-sha256`, and diffs it against this directory. It +fails on any difference not listed below, and on any listed file whose content +no longer matches its pinned hash — so changing a delta requires updating its +hash here in the same change. This file itself is the only addition. + +```provenance +crate-sha256: 233daaf6e83ae6a12a52055f568f9d7cf4671dabb78ff9560ab6da230ce00ee5 +# RUSTSEC-2024-0429 backport (gtk-rs-core#1343) +delta: src/variant_iter.rs sha256=a0f5ee8acb8faa089bcdfbc9a57372609fce7654026ccef7d9a224d05a654ccc +# crate-level allow(warnings), reproducing Cargo's --cap-lints for registry deps +delta: src/lib.rs sha256=f118b6507cf8c7176a70963ec6ad890f5020559cf4e5a87131eddae61e4fcb3a +``` + Remove this directory, the workspace exclusion, the `[patch.crates-io]` entry, and the audit exception when Tauri's Linux stack uses `glib` 0.20 or newer. From fac28c3a62f4fc182768e0296a9f1826dae5a8b4 Mon Sep 17 00:00:00 2001 From: Claude Date: Thu, 24 Sep 2026 10:34:58 +0000 Subject: [PATCH 3/3] ci(deps): port #152's Cargo.lock (rustls 0.23.45, RUSTSEC-2026-0285) This PR touches vendor/glib-0.18.5-patched/, which triggers cargo audit, and main still carries rustls 0.23.43. Taking #152's lockfile verbatim keeps audit green here; it no-ops once #152 merges. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_013z24CKdETNZRqL7CKMur99 --- Cargo.lock | 86 +++++++++++++++++++++++++++--------------------------- 1 file changed, 43 insertions(+), 43 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8e4c47a..b1928f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,9 +204,9 @@ checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "aws-config" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a767267da9e2c2e189b2f9df8b5657e850ecf5352644734ba130d4a57095cf1b" +checksum = "b8d7b388a9fc3a6db15a5ec778c38b354eff1364882c94d08e0252f7a47dcaa4" dependencies = [ "aws-credential-types", "aws-runtime", @@ -270,9 +270,9 @@ dependencies = [ [[package]] name = "aws-runtime" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9007227e10b5fed2f3e0a2beff489211e2b5604c400b7a9d5d81ca9d64c24bb" +checksum = "ef47857a1d4488b528f4a5d5715fa7c3300820897824152234d3fa22b1426657" dependencies = [ "aws-credential-types", "aws-sigv4", @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "aws-sdk-s3" -version = "1.144.0" +version = "1.146.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30dc8bf6baaf7d46336a0ca2c69f223d9b90d7a801fb3e28f7ea17b00dc6b1de" +checksum = "2cd651b4400d4011b8927b83a9552bf90ff11e6e5da0b9f0a7583247aceec971" dependencies = [ "arc-swap", "aws-credential-types", @@ -335,9 +335,9 @@ dependencies = [ [[package]] name = "aws-sdk-sso" -version = "1.108.0" +version = "1.109.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c15301b04372832947916607983b114b3374b9db0be058a00fb7513800de1f05" +checksum = "c3cfe74df5d9ad2fedd691973ad3521ebf4f27a3c68c792556686aedb5519bab" dependencies = [ "arc-swap", "aws-credential-types", @@ -361,9 +361,9 @@ dependencies = [ [[package]] name = "aws-sdk-ssooidc" -version = "1.110.0" +version = "1.111.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72cc2c205cb27108183cf1856333f7d584c2ba0f505421b4209ca5828f9ea899" +checksum = "81b0ec31ed6191bd11350aae4b2004198f2db21350cb0a20c57e0a92e55dd161" dependencies = [ "arc-swap", "aws-credential-types", @@ -387,9 +387,9 @@ dependencies = [ [[package]] name = "aws-sdk-sts" -version = "1.113.0" +version = "1.114.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68182ecb449f7537db0f4d5d25917789cf41e32074a9fe47b6a0b847fe1d2032" +checksum = "ef45745026107ec30c4ef86bd8ae4b002e7e5f6a86e4225240bdf6b06a0b944a" dependencies = [ "arc-swap", "aws-credential-types", @@ -589,9 +589,9 @@ dependencies = [ [[package]] name = "aws-smithy-runtime-api" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "954c563ce84507722d2679f07a35d21b9c6466b3872d513020d0281fc8112ac9" +checksum = "3fbf162725183ec0df77a9dc82ce22d9ba0b6ea7f376e8ec4f6b695727c70698" dependencies = [ "aws-smithy-async", "aws-smithy-runtime-api-macros", @@ -629,9 +629,9 @@ dependencies = [ [[package]] name = "aws-smithy-types" -version = "1.6.2" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fce83ce9abbb198d25bc7131e468d0f9fe1257125e58c39f3f9fc9f5098c9647" +checksum = "16ecf7989e381d0cbb7ca06104140d940bf38d8eb9004bd3a12d23df03e3d363" dependencies = [ "base64-simd", "bytes", @@ -667,9 +667,9 @@ dependencies = [ [[package]] name = "aws-types" -version = "1.5.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eec1cd5469f328c782dc3e33d4153cf118a54e33cbb3356d60d16f89883e1f94" +checksum = "209f3a6d82a6e9e5f94abbed94c7a26e1c052341002bf57a5fb5481f625896fc" dependencies = [ "aws-credential-types", "aws-smithy-async", @@ -1044,9 +1044,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473c7e07f409a8d772161724aa8db6a765a2532a70f9667eeb7b49d3d02fbdca" +checksum = "aa8876b300ab35ba921adea3dfd70157a46249b33f95c9084ae5709785478946" dependencies = [ "clap_builder", "clap_derive", @@ -1054,9 +1054,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.6.6" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b48fea5a88e9ae728a2dcbedbfc0e730f7d60da42e1cb049a83c9fb8b789889" +checksum = "ec0797fb7aeb1406c84efac526901f7ec3ead2124f946b494e72879d4b54704d" dependencies = [ "anstream", "anstyle", @@ -1066,9 +1066,9 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.6.4" +version = "4.6.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d012d2b9d65aca7f18f4d9878a045bc17899bba951561ba5ec3c2ba1eed9a061" +checksum = "f9c751b79415d4e559e3d1fcf128e09e720eb673a06d26cf6f392d37d75b66e0" dependencies = [ "heck 0.5.0", "proc-macro2", @@ -1763,7 +1763,7 @@ dependencies = [ "cc", "memchr", "rustc_version", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", "vswhom", "winreg", ] @@ -5154,9 +5154,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.43" +version = "0.23.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0283386ce02abc0151e1761d08802dfe86c173b0b494af5cbc086574e453da06" +checksum = "0d41d731c7d2f962d1ccc364cec258de3c0e93b38c2fb3ba97ac74513048d634" dependencies = [ "aws-lc-rs", "log", @@ -5191,9 +5191,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.13" +version = "0.103.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c429a8649f110dddef65e2a5ad240f747e85f7758a6bccc7e5777bd33f756e" +checksum = "f3c3cf1d8b1e7d4927e2d154c3fcb02979afb9939629c62cd9048d4f07b60ac2" dependencies = [ "aws-lc-rs", "ring", @@ -5308,7 +5308,7 @@ dependencies = [ "scl-vfs", "serde", "serde_json", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", ] [[package]] @@ -5352,7 +5352,7 @@ dependencies = [ "tauri", "tauri-build", "tauri-plugin-dialog", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", ] [[package]] @@ -5392,7 +5392,7 @@ dependencies = [ "scl-vfs", "serde", "thiserror 2.0.20", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", ] [[package]] @@ -6016,9 +6016,9 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1" [[package]] name = "tauri" -version = "2.11.5" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "667b20e2726d572dea2de7370da16e188eb06008faf9a92fab7cdc46791190b5" +checksum = "6fa5bacdb9bbad5954af3d1bd6cf6ae9192cab1b2e270f4a07f904610b9e85f4" dependencies = [ "anyhow", "bytes", @@ -6145,9 +6145,9 @@ dependencies = [ [[package]] name = "tauri-plugin-dialog" -version = "2.7.2" +version = "2.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2d3c1dbe38037e7f590cdf2492594d5ceebe031e7bc7e827509b22a999d2940" +checksum = "61854a36651aa48381e5e209f69a01273b77f3f9f91f0c430b1b98d33bd47229" dependencies = [ "log", "raw-window-handle", @@ -6163,9 +6163,9 @@ dependencies = [ [[package]] name = "tauri-plugin-fs" -version = "2.5.1" +version = "2.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7ecc274121aca0c036a2b42d1cbe83d368d348f54e0bb8a735c2b1548e8f371" +checksum = "de22eef34fd78c0da050e748710edd50bf127e651d02ea1b2bfada1523cc5c51" dependencies = [ "anyhow", "dunce", @@ -6181,7 +6181,7 @@ dependencies = [ "tauri-plugin", "tauri-utils", "thiserror 2.0.20", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", "url", ] @@ -6267,7 +6267,7 @@ dependencies = [ "serde_with", "swift-rs", "thiserror 2.0.20", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", "url", "urlpattern", "uuid", @@ -6282,7 +6282,7 @@ checksum = "cc65d45c68858bfe420dd29e834b5d15dbecf8a07a8a16cf4d532c7b1f69d4b6" dependencies = [ "dunce", "embed-resource", - "toml 1.1.4+spec-1.1.0", + "toml 1.1.6+spec-1.1.0", ] [[package]] @@ -6469,9 +6469,9 @@ dependencies = [ [[package]] name = "toml" -version = "1.1.4+spec-1.1.0" +version = "1.1.6+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" +checksum = "920602543f0911ab71da12c50d59701da54c196d1a2bf5cb4b75667f137a406a" dependencies = [ "indexmap 2.14.0", "serde_core",