Skip to content

Do not fail a release because Chocolatey is still moderating - #122

Merged
ralyodio merged 1 commit into
mainfrom
fix/chocolatey-moderation
Sep 24, 2026
Merged

ralyodio merged 1 commit into
mainfrom
fix/chocolatey-moderation

Conversation

@ralyodio

Copy link
Copy Markdown
Contributor

v3.16.0's release went red on a Chocolatey 403 Forbidden.

The same API key pushed 3.15.1 an hour earlier, so it isn't the credential: tronbrowser is a brand-new package whose first submission is still with their moderators, and Chocolatey won't queue a second unapproved version behind it. That's a state to wait out — but until a human moderator gets to it, every release run goes red on a job behaving exactly as designed.

Not by swallowing the 403

Blanket-swallowing it would be the same mistake that let this pipeline spend three months publishing nothing while reporting success. The two cases are told apart instead:

  • Chocolatey's public OData feed lists approved versions only
  • no approved version → the package has never cleared moderation → a refusal is the moderation gate, so the run continues with an explanation
  • listed and still refusing → wrong key, or someone else owns the id → still fails loudly

Verified against the live feed, both directions

package approved versions a 403 would mean
tronbrowser 0 moderation — wait, don't fail
7zip 40 real failure
vlc 40 real failure
pairux (ours) 17 real failure

Proving the positive case mattered more than the negative one: a parser that always returned empty would have silently swallowed every 403, which is precisely the failure being avoided.

🤖 Generated with Claude Code

v3.16.0's release went red on a Chocolatey 403. The same API key had pushed
3.15.1 an hour earlier, so it is not the credential: tronbrowser is a brand-new
package whose first submission is still with their moderators, and Chocolatey
will not queue a second unapproved version behind it. That is a state to wait
out, and until a human gets to it every release run goes red on a job that is
behaving exactly as designed.

Swallowing a 403 outright would be the wrong fix, and the same mistake that let
this pipeline spend three months publishing nothing while reporting success. So
the two cases are told apart rather than merged. Chocolatey's public feed lists
approved versions only. No approved version means the package has never cleared
moderation, so a refusal is the moderation gate and the run continues with an
explanation. A package that IS listed and still refuses is a wrong key or someone
else owning the id, and that still fails loudly.

Checked against the live feed both ways before trusting it: tronbrowser returns
zero approved versions, while 7zip returns 40, vlc 40 and our own pairux 17. A
parser that always returned empty would have silently swallowed every 403, which
is precisely the failure being avoided, so proving the positive case mattered
more than proving the negative one.
@github-actions

Copy link
Copy Markdown
Contributor

ThreatCrush Security Scan

52 finding(s)

HIGH/CRITICAL: 3 | MEDIUM: 28 | LOW: 21

Severity Rule Location
HIGH py-ssrf-outbound-request apps/desktop/launcher/tron-tor-helper:303
HIGH py-ssrf-outbound-request apps/desktop/launcher/tron-tor-helper:437
HIGH sh-remote-script-execution apps/web/public/install.sh:757
MEDIUM js-open-redirect apps/desktop/extensions/ai-sidebar/install-helper.js:156
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/media.js:34
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/media.js:57
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:237
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:266
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/newtab.js:336
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/options.js:306
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/sidepanel.js:78
MEDIUM js-unescaped-html-sink apps/desktop/extensions/ai-sidebar/sidepanel.js:166
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:77
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:227
MEDIUM js-unescaped-html-sink apps/extensions/public/store.js:569
MEDIUM js-unescaped-html-sink apps/web/public/app.js:29
MEDIUM js-unescaped-html-sink apps/web/public/dns.js:54
MEDIUM sh-remote-script-execution apps/web/public/install.sh:164
MEDIUM sh-remote-script-execution apps/web/public/install.sh:169
MEDIUM sh-remote-script-execution apps/web/public/install.sh:282
MEDIUM sh-remote-script-execution apps/web/public/install.sh:300
MEDIUM sh-remote-script-execution apps/web/public/install.sh:813
MEDIUM sh-remote-script-execution apps/web/public/install.sh:864
MEDIUM js-unescaped-html-sink apps/web/public/settings.js:96
MEDIUM js-unescaped-html-sink apps/web/public/settings.js:168
MEDIUM js-dynamic-code-execution packages/sdk/src/mcp/tools.ts:125
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:68
MEDIUM js-dynamic-code-execution packages/sdk/src/page.ts:73
MEDIUM sql-template-interpolation services/api/src/store/db.ts:116
MEDIUM js-dynamic-code-execution services/api/src/store/scanner.ts:44
MEDIUM sh-predictable-temp-path start.sh:25
LOW js-dynamic-code-execution apps/desktop/extensions/ai-sidebar/pit-proxy.test.js:8
LOW js-dynamic-code-execution packages/agent-runtime/src/analyze/form-script.test.ts:6
LOW js-unescaped-html-sink packages/agent-runtime/src/analyze/form-script.test.ts:26
LOW js-unescaped-html-sink packages/agent-runtime/src/analyze/form-script.test.ts:49
LOW js-dynamic-code-execution packages/browser-core/src/automation/extract-script.test.ts:6
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:16
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:45
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:57
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:80
LOW js-unescaped-html-sink packages/browser-core/src/automation/extract-script.test.ts:99
LOW js-dynamic-code-execution packages/browser-core/src/automation/snapshot-script.test.ts:11
LOW js-unescaped-html-sink packages/browser-core/src/automation/snapshot-script.test.ts:62
LOW js-unescaped-html-sink packages/browser-core/src/automation/snapshot-script.test.ts:101
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:47
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:170
LOW js-unescaped-html-sink packages/provenance/src/scan.test.ts:216
LOW js-dynamic-code-execution packages/sdk/src/mcp/automate.test.ts:261
LOW secret-generic-api-key packages/storage/src/config.ts:51
LOW secret-generic-credential packages/storage/src/config.ts:51

…and 2 more. Full results in the Security tab.

Snippets are redacted; ThreatCrush never prints matched credential material.

@ralyodio
ralyodio merged commit 762b527 into main Sep 24, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant