fix(chocolatey): handle first-submission moderation - #32
Conversation
Findings
Reference: Chocolatey common 403 causes include invalid key, ownership conflicts, and moderation state: https://docs.chocolatey.org/en-us/community-repository/maintainers/common-errors/ |
FindingsNo findings. The updated diff addresses the prior major: credential/ownership-looking The moderation exception remains narrow: only generic |
|
The branch matrix is mostly there, but I would not call this fully proven yet.
|
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: e837cbd
Summary
| Reviewer | Findings |
|---|---|
| database:database-reviewer | 1 |
| harness-engineering:harness-enforcement-reviewer | 2 |
| harness-engineering:harness-self-documenting-code-reviewer | 2 |
database:database-reviewer (1 findings)
💡 Suggestion - actions/chocolatey-push/chocolatey_push.py:122
OData filter is constructed by direct interpolation of package_id without escaping: f"Id eq '{package_id}'". A package ID containing a single quote produces a malformed query, causing probe_package_state to receive an unexpected response and raising a misleading ProbeError. In practice Chocolatey IDs are alphanumeric-with-hyphens, but the fix is trivial: escape embedded single quotes by doubling them (package_id.replace("'", "''")).
harness-engineering:harness-enforcement-reviewer (2 findings)
actions/chocolatey-push/action.yml:24
Direct ${{ inputs.package-id }} and ${{ inputs.working-directory }} interpolation inside a bash run: step is a known GitHub Actions shell-injection vector. Values containing shell metacharacters or
$() substitution syntax will be evaluated by the shell. Map both inputs to env vars (e.g., PACKAGE_ID: $ {{ inputs.package-id }}) and reference them as "$PACKAGE_ID" in the script — matching the existing secure pattern already used for CHOCO_API_KEY.
💡 Suggestion - actions/chocolatey-push/chocolatey_push.py:7
Uses xml.etree.ElementTree to parse the external Chocolatey API response instead of defusedxml. Every other action in this repo that parses external XML (identity-check, winget-submit, release-preflight) takes a defusedxml==0.7.1 dependency; chocolatey-push is the only exception. While CPython's expat backend is not vulnerable to XXE, defusedxml also guards against XML-bomb DoS. Replace the import and add defusedxml to the pytest install line in test-actions.yml to align with the repo's established XML-parsing policy.
harness-engineering:harness-self-documenting-code-reviewer (2 findings)
actions/chocolatey-push/test_chocolatey_push.py:116
The parametrized matrix for the credential/owner 403 guard covers only a subset of patterns in _looks_like_credential_or_owner_failure. Missing coverage includes "invalid apikey", "api key is invalid", "not authorized", "not owned", "not the owner", and "package owner". A regression on any uncovered pattern would allow a credential or ownership 403 to bypass the hard-fail path and be misclassified as a green first-submission moderation state. This gap is flagged as an open concern in the PR discussion.
actions/chocolatey-push/chocolatey_push.py:79
pack_and_push tests only assert command names, not the exact choco push argv (source URL, --key value, resolved .nupkg filename) or cwd. Tests would pass if the action used the wrong API key, pointed at the wrong source registry, or ran in the wrong working directory. Tighten assertions to cover the full command list and cwd, mirroring the pattern used in winget-submit. Raised as an open concern in the PR discussion.
5 info-level observations excluded. Run with --verbose to include.
3 PR discussion threads considered.
Completed in 7m 59s | $1.80 | sonnet | daemon 0.2.121 | Glorfindel
| Field | Value |
|---|---|
| Model | sonnet |
| Reviewers | hybrid-synthesis, database:database-reviewer, harness-engineering:harness-architecture-reviewer, harness-engineering:harness-enforcement-reviewer, harness-engineering:harness-knowledge-reviewer, harness-engineering:harness-self-documenting-code-reviewer, security:security-code-auditor |
| Engine | claude · sonnet |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 7m 59s wall · 18m 54s compute (Reviewers: 5m 39s · Synthesis: 2m 18s) |
| Cost | $1.80 |
| Tokens | 302.5k in / 72.4k out |
| Turns | 15 |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost |
|---|---|---|---|---|---|---|
| hybrid-synthesis | sonnet | 32.0k | 9.0k | 17.4k | 14.6k (1h) | $0.20 |
| database:database-reviewer | sonnet | 28.3k | 1.6k | 7.1k | 21.2k (1h) | $0.11 |
| harness-engineering:harness-architecture-reviewer | sonnet | 52.4k | 17.9k | 7.1k | 45.4k (1h) | $0.45 |
| harness-engineering:harness-enforcement-reviewer | sonnet | 41.4k | 6.7k | 7.1k | 34.3k (1h) | $0.24 |
| harness-engineering:harness-knowledge-reviewer | sonnet | 55.1k | 20.2k | 7.1k | 48.0k (1h) | $0.49 |
| harness-engineering:harness-self-documenting-code-reviewer | sonnet | 76.8k | 8.9k | 54.6k | 22.2k (1h) | $0.24 |
| security:security-code-auditor | haiku | 16.4k | 8.1k | 0 | 16.4k (1h) | $0.07 |
Re-reviews only run when @monit-reviewer is re-requested as a reviewer — push as many commits as you need, then re-request when ready. PRs targeting branches other than main, master are skipped, even when @monit-reviewer is re-requested.
monit-reviewer
left a comment
There was a problem hiding this comment.
Automated PR Review
Reviewed commit: 956cee5 | Previous: e837cbd (incremental)
Approved with 1 non-blocking suggestion below. Address at your discretion.
Summary
| Reviewer | Findings |
|---|---|
| harness-engineering:harness-self-documenting-code-reviewer | 1 |
harness-engineering:harness-self-documenting-code-reviewer (1 findings)
💡 Suggestion - actions/chocolatey-push/chocolatey_push.py:158
_parse_atom_entries only catches ET.ParseError, but defusedxml raises a separate exception hierarchy (DefusedXmlException and subclasses like DTDForbidden, EntitiesForbidden) that does NOT inherit from xml.etree.ElementTree.ParseError. If the Chocolatey API returns XML with a DTD or entity references, those exceptions escape uncaught, bypass the except (PushError, ProbeError) handler in main, and surface as a raw traceback. The release still fails correctly, but the error output is unhelpful. Broaden the catch to include the defusedxml base exception class and re-raise as ProbeError.
8 PR discussion threads considered.
Completed in 2m 33s | $0.99 | sonnet | daemon 0.2.121 | Glorfindel
| Field | Value |
|---|---|
| Model | sonnet |
| Mode | Re-review · Cycle 2 · Session resumed |
| Reviewers | hybrid-synthesis, database:database-reviewer, harness-engineering:harness-architecture-reviewer, harness-engineering:harness-enforcement-reviewer, harness-engineering:harness-knowledge-reviewer, harness-engineering:harness-self-documenting-code-reviewer, security:security-code-auditor |
| Engine | claude · sonnet |
| Reviewed by | pr-review-daemon · monit-pr-reviewer |
| Duration | 2m 33s wall · 3m 10s compute (Reviewers: 1m 52s · Synthesis: 15s) |
| Cost | $0.99 |
| Tokens | 304.4k in / 12.1k out |
| Turns | 7 |
Per-workstream usage
| Workstream | Model | In | Out | Cache read | Cache create | Cost |
|---|---|---|---|---|---|---|
| hybrid-synthesis | sonnet | 45.2k | 906 | 17.4k | 27.8k (1h) | $0.12 |
| database:database-reviewer | sonnet | 20.0k | 67 | 4.1k | 15.9k (1h) | $0.06 |
| harness-engineering:harness-architecture-reviewer | sonnet | 45.4k | 92 | 4.1k | 41.2k (1h) | $0.16 |
| harness-engineering:harness-enforcement-reviewer | sonnet | 34.1k | 89 | 4.1k | 30.0k (1h) | $0.12 |
| harness-engineering:harness-knowledge-reviewer | sonnet | 47.7k | 117 | 4.1k | 43.5k (1h) | $0.17 |
| harness-engineering:harness-self-documenting-code-reviewer | sonnet | 27.4k | 7.1k | 4.1k | 23.2k (1h) | $0.19 |
| security:security-code-auditor | haiku | 33.7k | 2.9k | 4.2k | 29.6k (1h) | $0.05 |
| discussion-summarizer | — | 50.9k | 820 | 36.9k | 9.3k (1h) | $0.12 |
Re-reviews only run when @monit-reviewer is re-requested as a reviewer — push as many commits as you need, then re-request when ready. PRs targeting branches other than main, master are skipped, even when @monit-reviewer is re-requested.
| def _parse_atom_entries(body: str) -> int: | ||
| try: | ||
| root = ET.fromstring(body) | ||
| except ET.ParseError as exc: |
There was a problem hiding this comment.
🔵 Low (harness-engineering:harness-self-documenting-code-reviewer): _parse_atom_entries only catches ET.ParseError, but defusedxml raises a separate exception hierarchy (DefusedXmlException and subclasses like DTDForbidden, EntitiesForbidden) that does NOT inherit from xml.etree.ElementTree.ParseError. If the Chocolatey API returns XML with a DTD or entity references, those exceptions escape uncaught, bypass the except (PushError, ProbeError) handler in main, and surface as a raw traceback. The release still fails correctly, but the error output is unhelpful. Broaden the catch to include the defusedxml base exception class and re-raise as ProbeError.
Reply to this thread when addressed.
Summary
chocolatey-pushaction for Chocolatey pack/push behavior403state as a green pending stateCloses #31
Verification
uv run --with pytest>=8,<9 python -m pytest -qinactions/chocolatey-pushuv run --with PyYAML==6.0.2 --with pytest>=8,<9 python -m pytest -qinactions/winget-submituv run --with PyYAML==6.0.2 --with pytest>=8,<9 python -m pytest -qinactions/release-preflightuv run --with PyYAML==6.0.2 --with pytest>=8,<9 --with defusedxml==0.7.1 python -m pytest -qinactions/identity-checkactionlint