Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packaging/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,11 @@ package carries no binaries and owes no `VERIFICATION.txt`. `chocolateybeforemod
releases the WinDivert driver before an upgrade or an uninstall, because the kernel
holds `WinDivert64.sys` open while it is loaded and an open file cannot be deleted.
Its package folder is read-only for plain users, which is one of the two reasons the
program stopped keeping user files in its own directory.
program stopped keeping user files in its own directory. Its `iconUrl` is a CDN address
pinned to the release tag, and both halves are load-bearing: moderation refuses
`github.com/<owner>/<repo>/raw/...` exactly as it refuses `raw.githubusercontent.com`,
and an icon pointing at a branch would keep changing under a package that is already
approved.

**WinGet.** `ArchiveBinariesDependOnPath: true` is the line that matters. The default
for a portable inside an archive is a symlink, and this executable cannot be reached
Expand Down
2 changes: 1 addition & 1 deletion packaging/chocolatey/bean-network-tester.nuspec.in
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
<title>{{APP_NAME}}</title>
<authors>{{PUBLISHER}}</authors>
<projectUrl>{{PROJECT_URL}}</projectUrl>
<iconUrl>{{REPO_URL}}/raw/master/bean.png</iconUrl>
<iconUrl>{{ICON_URL}}</iconUrl>
<copyright>{{COPYRIGHT}}</copyright>
<licenseUrl>{{LICENSE_URL}}</licenseUrl>
<requireLicenseAcceptance>false</requireLicenseAcceptance>
Expand Down
9 changes: 9 additions & 0 deletions tests/test_mutation_registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -2152,6 +2152,15 @@
"new": " pass",
"test": "test_the_converted_readout_appears_only_when_there_is_something_to_convert",
},
{
# The exact line Chocolatey's moderation refused, and the branch pin that
# came with it. One line carries both faults, so one mutation restores both.
"label": "packaging: the Chocolatey icon goes back to a branch on github.com",
"file": "packaging/chocolatey/bean-network-tester.nuspec.in",
"old": " <iconUrl>{{ICON_URL}}</iconUrl>",
"new": " <iconUrl>{{REPO_URL}}/raw/master/bean.png</iconUrl>",
"test": "test_the_chocolatey_icon_is_a_pinned_cdn_url",
},
]

# The runner's own check: a patch that cannot compile must be reported as BROKEN, not
Expand Down
19 changes: 19 additions & 0 deletions tests/test_packaging.py
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,25 @@ def test_the_download_is_checksummed(tmp_path, monkeypatch):
"-Checksum64 '94359ea6" in install and "-ChecksumType64 'sha256'" in install)


def test_the_chocolatey_icon_is_a_pinned_cdn_url(tmp_path, monkeypatch):
"""Not `github.com/.../raw/`, and not a branch. Both were wrong until 2026-09-05.

Chocolatey's moderation held 0.5.0 back over the first half: it treats
`github.com/<owner>/<repo>/raw/...` exactly as `raw.githubusercontent.com`, and
neither is a CDN. The second half is the one nobody had complained about, and it
is the one that bites later - an icon pinned to a BRANCH follows whatever that
branch does next, under a package that is already approved and out of reach.
"""
nuspec = _rendered(tmp_path, monkeypatch)["chocolatey/bean-network-tester.nuspec"]
found = re.search(r"<iconUrl>(.*?)</iconUrl>", nuspec)
check("the nuspec carries an icon at all", found is not None)
url = found.group(1) if found else ""
for host in ("raw.githubusercontent.com", "github.com"):
check(f"the icon is not served from {host}", host not in url, f"({url})")
check("the icon is pinned to the tag being packaged, not to a branch",
f"@v{appinfo.__version__}/" in url, f"({url})")


# -- the inputs that would look fine and be wrong ------------------------------- #
def test_the_binary_marker_never_reaches_the_url(tmp_path, monkeypatch):
"""`sha256sum` writes `<hash> *<file>`, and that star is not part of the name."""
Expand Down
9 changes: 9 additions & 0 deletions tools/build_packages.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def values(version, digest, asset):
home = _read_json("site", "pages", "home", "page.json")["languages"]["en"]
tagline = _read_json("site", "i18n", "en.json")["site.tagline"]
repo = site["repo_url"].rstrip("/")
slug = repo.split("github.com/", 1)[-1] # owner/name, which is what a CDN wants
tag = f"v{version}"
# Every entry here is used by a template, and a test keeps it that way in both
# directions: an unknown placeholder is a typo, a dead entry is a manifest that
Expand All @@ -123,6 +124,14 @@ def values(version, digest, asset):
"PROJECT_URL": site["base_url"].rstrip("/"),
"REPO_URL": repo,
"RELEASE_NOTES_URL": f"{repo}/releases/tag/{tag}",
# 馃敶 A CDN, and PINNED to the tag - Chocolatey's moderation held 0.5.0 back over
# this on 2026-09-05. `{repo}/raw/...` is treated as raw.githubusercontent.com,
# which is not a CDN; jsDelivr, Statically and the Githack variants are. The
# BRANCH was the second fault, and nobody had complained about it yet: an icon on
# `master` follows whatever the branch does next, under a package that is already
# approved. Same bytes either way (measured that day: 21 155 B, image/png, from
# both hosts), so this moves the address and not the picture.
"ICON_URL": f"https://cdn.jsdelivr.net/gh/{slug}@{tag}/bean.png",
"RELEASE_DATE": release_date(version),
"TAGLINE": tagline,
"DESCRIPTION": home["description"],
Expand Down
Loading