Skip to content

feat(gh): release-asset uploads, the Gemini extension archive, and a coverage push to 98% - #352

Merged
totollygeek merged 11 commits into
masterfrom
claude/marketplace-codex-gemini-setup-ksau6v
Aug 13, 2026
Merged

feat(gh): release-asset uploads, the Gemini extension archive, and a coverage push to 98%#352
totollygeek merged 11 commits into
masterfrom
claude/marketplace-codex-gemini-setup-ksau6v

Conversation

@totollygeek

Copy link
Copy Markdown
Contributor

What & why

Two related deliverables on the multi-harness skills work, plus a repo-wide test-coverage push.

1. Releases now carry a Gemini CLI extension archive. gemini extensions install https://github.com/zuke-build/zuke resolves the repo's latest release and prefers a release asset over cloning; without one it downloads the whole monorepo source tarball to install two skill folders. The release target now builds a minimal, deterministic tar.gz (gemini-extension.json + LICENSE + skills/) and attaches it to the latest release under three platform-prefixed names (darwin.zuke.tar.gz, linux.zuke.tar.gz, win32.zuke.tar.gz) — the shape Gemini's findReleaseAsset matches deterministically regardless of what else the release carries (a single generic asset silently degrades to the source tarball as soon as any second file is attached; verified against the gemini-cli source).

The upload is a new GhTasks.uploadReleaseAsset task in @zuke/gh, API-based like uploadSarif: it resolves the latest release (or a named tag), skips an asset the release already carries, deletes-and-resends an asset stuck in a non-uploaded state (GitHub's documented recovery for interrupted uploads), and reports a repo with no releases as an ordinary outcome. In zuke.ts the attach step is best-effort — a transient upload failure must not redden the release job after releases exist, which would skip the JSR publish behind it. Both failure modes were found by the pre-PR adversarial review and carry regression tests.

2. Coverage raised from 96.8%/95.0% to 98.4% lines / 97.5% branches (3,151 tests, 0 failed). Targeted, behavior-asserting tests for the weakest files: the AI reviewer/fixer/hosts plumbing, the MCP run-tools/registry/hardening surface, the executor (scheduler, cancel, resume, reap, execute-plan), core cli/ci/ci_schedule/describe, core state serialization/stores, and the gh package (now 96–100% per file). Residual uncovered branches are justified in the test files — unreachable defensive guards or paths that would require real network/ambient tools to hit.

Drive-by: README.md documents that the Gemini extension installs from releases; test fixture wording made dictionary-safe for the spell gate.

Related issues

Follow-up to #351 (multi-harness skills distribution) — closes the "Gemini installs the whole monorepo" gap noted there.

Checklist

  • The PR title is a Conventional Commit (type(scope): summary).
  • deno task ci passes locally (lint, fmt, type-check, tests, spell — security verified except zizmor's advisories lookup, which the sandbox proxy blocks).
  • Tests were added or updated; coverage stays at 95%+ (lines and branches) — now 98.4% / 97.5%.
  • Docs updated in the same PR (README.md, JSDoc) when behaviour changed.
  • Public API changes were regenerated with ./zuke apiDocs (llms.txt, llms-full.txt, package README ## API).
  • No any, no as casts or ! non-null assertions in src/ (narrow with type guards instead).
  • A new package was wired into all seven places — not applicable, no new package.
  • The code is written using AI assisted coding.

🤖 Generated with Claude Code

https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk


Generated by Claude Code

claude added 10 commits August 13, 2026 11:45
Gemini CLI installs a GitHub extension from the repository's latest
release, preferring a release asset over the source tarball — and for
this monorepo the tarball means downloading 50+ packages to obtain two
skill folders. The release target now builds a minimal, deterministic
archive of the extension manifest, license, and skills tree, and
attaches it to the latest release under the three platform-prefixed
names Gemini matches deterministically regardless of what else the
release carries.

The upload itself is a new GhTasks.uploadReleaseAsset task in @zuke/gh,
API-based like uploadSarif: it resolves the latest release or a named
tag, leaves an already-attached asset untouched so republishing is
idempotent, and reports a repository with no releases as an ordinary
outcome rather than an error.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
…effort

Adversarial review found two real failure modes: an errored upload
reserves the asset name in a non-uploaded state, and the skip-by-name
idempotence check would step past that corpse forever, so a re-run now
deletes the stuck asset and re-sends it. And a transient upload failure
used to redden the release job after the releases already existed,
which skipped the JSR publish behind it — the attach step is now
best-effort with a warning, since the next release run tops the assets
up anyway. The archive builder also refuses symlinks instead of
silently dropping them and names the fix when the manifest, license,
or skills tree is missing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
…ites

Checkpoint of the coverage push toward 98%: meaningful branch tests for
the AI reviewer plumbing, CI schedule/generation, build description,
and the GitHub workflow trigger, all against the existing fakes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
Further checkpoint of the coverage push: branch tests for CLI flag
parsing and state serialization edge paths, against existing fixtures.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
Coverage-push checkpoint: meaningful branch tests for the AI fixer,
dedup, hosts, comment/gate/report modules, the executor plan and
cancellation paths, the scheduler, resume, reap, and the MCP servers.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
Coverage-push checkpoint: null-payload signal delivery, authorization
refusals, and registry lookup edge paths through the fake transports.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
Coverage-push checkpoint from the executor cluster.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
…eduler

Coverage-push checkpoint: CAS-conflict give-up paths, parked-time
timeout credit, and effect re-drive semantics, all against fake stores.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Zuke AI review

🔎 security review — review

Score: 0/10 · Severity: none · 0 finding(s)

Tokens: 44832 in · 345 out · 45177 total

Budget: 82,465 tokens of 500,000 tokens

Refuted by verification (not reported):

Finding Reason
Archive builder follows arbitrary nested paths without rejecting traversal-like roots The new archive walk only recurses through entries under the supplied root and explicitly rejects non-file/non-directory entries like symlinks, so the code does not follow arbitrary nested paths outside the tree.
Release-asset upload needs an explicit scope check at call sites that may run on untrusted PR contexts The change only adds the uploadReleaseAsset API and its docs/tests; the reviewer’s claim about untrusted-PR gating is speculative and no call-site or implementation path in the shown diff indicates an introduced authorization bypass.

The change mostly adds archive-building and GitHub release asset support, but it introduces one plausible path-traversal exposure in archive creation and one authorization-risk area if release uploads are reachable without a sufficiently scoped token.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Zuke AI review

🔎 generic review — review

Score: 0/10 · Severity: none · 0 finding(s)

Tokens: 30780 in · 330 out · 31110 total

Budget: 136,828 tokens of 500,000 tokens

Refuted by verification (not reported):

Finding Reason
Type-unsafe fetch stubs are cast with as typeof fetch, violating the repo's strict no-as rule The new tests use as typeof fetch, but the repo already contains many existing tests with the same cast, so this change does not introduce a new no-as violation and the candidate’s failure path is pre-existing rather than introduced here.
Release-asset upload is documented and exposed, but there are no visible regression tests for the new GitHub release path The diff does add build/gemini_archive.ts and related docs, but it also adds focused tests for the new archive behavior in packages/ai/tests/comment_test.ts and packages/ai/tests/agent_fixer_test.ts, so the claim that there are no visible regression tests is false.

The patch adds substantial new Gemini/GitHub release-asset and AI-review behavior, but it also introduces a couple of high-confidence type-safety and runtime robustness issues in the new test/support code.

Comment thread packages/gh/tests/release_asset_test.ts Fixed
Comment thread packages/gh/tests/release_asset_test.ts Fixed
Comment thread packages/gh/tests/release_asset_test.ts Fixed
Comment thread packages/gh/tests/release_asset_test.ts Fixed
Comment thread packages/gh/tests/release_asset_test.ts Fixed
CodeQL flags substring URL checks as incomplete sanitization. These are
hermetic test fakes routing canned responses, not a security boundary,
but a parsed-hostname comparison is just as readable and keeps the
scanner quiet without a dismissal trail.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019As9A3ugixLQiAvcat1ZKk
@github-actions

Copy link
Copy Markdown
Contributor

🤖 Zuke AI review

🔎 security review — review

Score: 0/10 · Severity: none · 0 finding(s)

Tokens: 44832 in · 40 out · 44872 total

Budget: 44,872 tokens of 500,000 tokens

No security-relevant regressions were introduced by the reviewed diff.

@github-actions

Copy link
Copy Markdown
Contributor

🤖 Zuke AI review

🔎 generic review — review

Score: 0/10 · Severity: none · 0 finding(s)

Tokens: 30780 in · 443 out · 31223 total

Budget: 99,524 tokens of 500,000 tokens

Refuted by verification (not reported):

Finding Reason
Release asset upload can silently degrade to the wrong release without validating the target tag The new API explicitly documents that a missing tag selects the latest release and returns a non-error no-release state, so the behavior is intentional rather than an unvalidated misupload path.
Gemini archive builder now hard-fails on any non-regular file in skills/ walk() only throws on non-file/non-directory entries after Deno.readDir, and geminiArchiveFiles() separately catches missing skills/, so the claimed symlink failure is a deliberate guard, not an introduced regression.
Tests introduce runtime-only type assertions that bypass the project's no-as rule The casts are confined to test fakes that are intentionally shaped as typeof fetch seams, and the tests verify the exact runtime behavior those seams need, so this does not expose a production type-safety bug in the change.

The change adds release-asset upload and a Gemini release archive, but several new tests and helper code rely on unsafe type assertions and insecure fallbacks that could mask real failures or expose incorrect behavior.

@totollygeek
totollygeek merged commit a678f35 into master Aug 13, 2026
12 checks passed
@totollygeek
totollygeek deleted the claude/marketplace-codex-gemini-setup-ksau6v branch August 13, 2026 12:43
@github-actions github-actions Bot mentioned this pull request Aug 13, 2026
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.

3 participants