Skip to content

Commit 7719563

Browse files
authored
Merge pull request #1651 from DeusData/fix/checksums-and-license-gate
fix(release,ci): cover ui-* aliases in checksums.txt, and stop the licence gate depending on a live fetch
2 parents 6a701b5 + 22de979 commit 7719563

3 files changed

Lines changed: 84 additions & 5 deletions

File tree

‎.github/workflows/release.yml‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,14 @@ jobs:
164164
release-selection.tsv \
165165
> checksums.txt
166166
167+
# The legacy ui-* aliases are byte-identical copies published after verify
168+
# (scripts/ci/publish-legacy-aliases.sh), so they were absent from
169+
# checksums.txt and 0.9.x updaters refused to install them (#1134). Their
170+
# digests are added here, BEFORE attestation, so the attested artifact
171+
# covers both names.
172+
- name: Cover legacy ui-* aliases in checksums
173+
run: scripts/ci/append-legacy-alias-checksums.sh checksums.txt
174+
167175
- name: Attest checksum provenance
168176
uses: actions/attest-build-provenance@0f67c3f4856b2e3261c31976d6725780e5e4c373 # v4.1.1
169177
with:

‎scripts/audit-license-provenance.py‎

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
ERROR upstream fetch failed
1111
"""
1212
import base64
13+
import hashlib
1314
import json
1415
import os
1516
import re
@@ -159,13 +160,24 @@ def check_upstream(key, dirpath, repo, pinned=None, exact_path=None):
159160
check_upstream(rel, os.path.join(ROOT, rel), repo, exact_path=exact)
160161

161162
# Special: nomic = canonical Apache-2.0 text; sqlite3 = first-party notice
163+
#
164+
# This used to `curl` https://www.apache.org/licenses/LICENSE-2.0.txt at
165+
# gate time and byte-compare. A gating verdict must not depend on a live
166+
# HTTP request: any fetch failure yielded an empty string, compared unequal,
167+
# and reported DIFFERS -- indistinguishable from a real licence change. That
168+
# is what reddened `security / license-gate` on PR #1337 for over two weeks,
169+
# on a branch touching three CLI files and no licence at all.
170+
#
171+
# The canonical Apache-2.0 text is immutable and versioned, so it is pinned
172+
# by digest instead. Verified byte-identical to the upstream text at the time
173+
# of pinning (11358 bytes). A mismatch now means our vendored copy changed --
174+
# which is exactly, and only, what this audit is meant to detect.
175+
APACHE_2_0_SHA256 = "cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30"
162176
fname, ours = local_license(os.path.join(ROOT, "vendored/nomic"))
163-
apache = subprocess.run(
164-
["curl", "-fsSL", "https://www.apache.org/licenses/LICENSE-2.0.txt"],
165-
capture_output=True, text=True).stdout
177+
ours_digest = hashlib.sha256(ours.encode("utf-8")).hexdigest() if ours is not None else None
166178
results["vendored/nomic"] = (
167-
"IDENTICAL" if ours == apache else "DIFFERS",
168-
"apache.org canonical LICENSE-2.0.txt")
179+
"IDENTICAL" if ours_digest == APACHE_2_0_SHA256 else "DIFFERS",
180+
"canonical Apache-2.0 text, pinned by sha256")
169181
results["vendored/sqlite3"] = ("FIRST-PARTY-NOTICE",
170182
"own public-domain notice (sqlite has no upstream LICENSE)")
171183

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#!/usr/bin/env bash
2+
# Add the legacy ui-* names to checksums.txt, carrying the canonical digest.
3+
#
4+
# publish-legacy-aliases.sh publishes byte-identical ui-*-named copies of the
5+
# release archives so already-released 0.9.x updaters stop 404ing (#1538). It
6+
# runs after verify, so those copies inherit the hash-bound VirusTotal verdicts
7+
# — and it therefore left them out of checksums.txt entirely, on the reasoning
8+
# that the file "covers the canonical names current installers request".
9+
#
10+
# That reasoning has a hole. The aliases exist ONLY for 0.9.x updaters, and
11+
# those verify the NAME they asked for. So the alias fixed the 404 and moved the
12+
# failure one step later: the updater downloads the archive, cannot find its name
13+
# in checksums.txt, and refuses to install it (#1134):
14+
#
15+
# warning: codebase-memory-mcp-ui-darwin-arm64.tar.gz not found in checksums.txt
16+
# error: refusing to install an unverified download
17+
#
18+
# An alias is a copy, so its sha256 is by construction the digest already
19+
# computed for the canonical archive. Emitting that digest under the legacy name
20+
# introduces no new bytes and no new scan surface. This runs BEFORE the
21+
# attestation step so the attested artifact covers both names.
22+
#
23+
# The alias rule MUST stay in step with publish-legacy-aliases.sh: .tar.gz and
24+
# .zip only, never an already-ui-* name. A name here with no published asset is
25+
# as broken as an asset with no name, so this fails closed when it matches
26+
# nothing.
27+
#
28+
# Usage: append-legacy-alias-checksums.sh <checksums-file>
29+
set -euo pipefail
30+
31+
CHECKSUMS="${1:?usage: append-legacy-alias-checksums.sh <checksums-file>}"
32+
33+
if [ ! -s "$CHECKSUMS" ]; then
34+
echo "error: $CHECKSUMS is missing or empty" >&2
35+
exit 1
36+
fi
37+
38+
aliases="$(mktemp)"
39+
trap 'rm -f "$aliases"' EXIT
40+
41+
awk '
42+
$2 ~ /^codebase-memory-mcp-/ &&
43+
$2 !~ /^codebase-memory-mcp-ui-/ &&
44+
($2 ~ /\.tar\.gz$/ || $2 ~ /\.zip$/) {
45+
alias = $2
46+
sub(/^codebase-memory-mcp-/, "codebase-memory-mcp-ui-", alias)
47+
print $1 " " alias
48+
}
49+
' "$CHECKSUMS" > "$aliases"
50+
51+
if [ ! -s "$aliases" ]; then
52+
echo "error: no canonical archives matched the ui-* alias rule in $CHECKSUMS;" >&2
53+
echo " publish-legacy-aliases.sh would then publish assets that" >&2
54+
echo " checksums.txt does not cover (#1134)." >&2
55+
exit 1
56+
fi
57+
58+
cat "$aliases" >> "$CHECKSUMS"
59+
echo "added $(wc -l < "$aliases" | tr -d ' ') legacy alias checksum line(s); $CHECKSUMS now covers $(wc -l < "$CHECKSUMS" | tr -d ' ') names"

0 commit comments

Comments
 (0)