Skip to content

feat: resolve vendor Stable/Beta image tags from GHCR (studio#128) - #131

Merged
brettchien merged 2 commits into
mainfrom
feat/ghcr-vendor-image-tags-128
Aug 29, 2026
Merged

feat: resolve vendor Stable/Beta image tags from GHCR (studio#128)#131
brettchien merged 2 commits into
mainfrom
feat/ghcr-vendor-image-tags-128

Conversation

@brettchien

Copy link
Copy Markdown
Contributor

Summary

Item 7 of #128's runbook. Backs the New Fleet wizard's Vendor + Image tag fields — resolves a vendor name to real, currently-published ghcr.io/openabdev/openab image tags instead of the operator guessing a tag that might not exist.

Was blocked, now isn't: initially thought this needed a GitHub auth mechanism Studio doesn't have anywhere (GitHub's Packages REST API requires a read:packages-scoped token even for public packages). Brett pushed back that reading a public GHCR image shouldn't need auth — right: ghcr.io speaks the standard OCI Distribution API, not just GitHub's REST API, and supports the same anonymous pull-token flow docker pull uses with no login. Verified live before writing any code:

curl "https://ghcr.io/token?scope=repository:openabdev/openab:pull"   # anonymous, no credentials
curl -H "Authorization: Bearer <token>" "https://ghcr.io/v2/openabdev/openab/manifests/<tag>"

Change

  • oabctl: new vendor_images module. "Beta" = pre-beta-<vendor> (the hourly rolling build). "Stable" = the newest openab GitHub release whose matching <version>-<vendor> image is confirmed to actually exist — verified via a manifest HEAD request per candidate (cheap existence check, no image bytes transferred), not a bulk tag-list scan (this repo has thousands of tags across multiple pages, confirmed live). A release tag existing doesn't guarantee a matching image was ever published (build-images.yml is a manual workflow_dispatch, completely disconnected from cutting a release — confirmed by reading both workflows), so Stable is verified against GHCR directly, not inferred from the release list alone. Also needed a name-based filter alongside GitHub's prerelease flag: at least one real release (openab-0.10.0-beta.3) has prerelease: false despite its name — the flag alone isn't reliable.
  • studio-cp: thin resolve_vendor_image_tags wrapper.
  • oab-mcp: new resolve_vendor_image_tags tool. Never errors on a failed GHCR/GitHub call — leaves the corresponding field null, matching Brett's earlier confirmation that manual image tag entry stays available as a fallback either way. Tool-count test bumped 18→19.
  • src-tauri: bridge command, same shape as the other read-only wizard pickers (list_k8s_contexts etc).

Console wiring (actually using this in the Vendor select) lands with the rest of the wizard UI (#128's items 1/3/4/5), not this PR.

Verification

  • Not locally compiled — same pre-existing aws-sdk-ec2 OOM limitation as every other Rust PR this week.
  • The GHCR anonymous-access flow and the specific 404-on-missing-tag/200-on-existing-tag behavior were verified live against the real openabdev/openab package before writing the Rust code, not assumed.
  • reqwest (already a direct oabctl dependency, unchanged version/features) is the only dependency touched — no new crate added.
  • CI's build-test job is the real gate for compilation; this PR has no k8s/AWS-provisioning-path changes so bundle-macos risk is low, but it's still the real signal for src-tauri-adjacent correctness (none of this crate is on the src-tauri layer beyond the new bridge command, which mirrors an existing one closely).

Ref #128.

🤖 Generated with Claude Code

Adds a "Config folder" field to the Debug drawer's Config tab — a
user-picked local directory (native folder picker via tauri-plugin-dialog)
that later work will mirror each agent's generated config.toml into
(<folder>/<agent-name>/config.toml, alongside the existing S3 upload
provision_agent/provision_agent_k8s already do — unchanged) and that the
"view an agent's config" screen (also studio#128, separate follow-up) will
read from directly, no S3 round-trip.

This slice is just the setting itself: plugin registration + capability
grant (dialog:allow-open — the app's capabilities/default.json had no
dialog permission at all before this) + picker UI, persisted like the
existing theme/log-level settings (localStorage), not Tauri's hidden
app-config-dir — this setting points at other local files, so storing it
in the hidden config dir would just be an extra layer of indirection.
Wiring the wizard/view-screen to actually use it lands with those pieces.

Verification: npm run typecheck clean, npm test 106/106 passing, npm run
build succeeds. Rust side (plugin registration, Cargo.toml) not locally
compiled — same pre-existing limitation as every other Rust change this
week; tauri-plugin-dialog's exact API (invoke command name
"plugin:dialog|open", options shape, return type for directory+non-multiple
mode) was checked against the plugin's actual TypeScript source before
using it, not guessed.

Ref #128.
…image tags from GHCR (studio#128)

Item 7 of #128's runbook. Backs the New Fleet wizard's Vendor + Image tag
fields — resolves a vendor name to real, currently-published
ghcr.io/openabdev/openab image tags instead of the operator guessing a tag
that might not exist.

Initially thought this needed a GitHub auth mechanism Studio doesn't have
(GitHub's Packages REST API requires a read:packages-scoped token even for
public packages) — Brett pushed back that reading a public GHCR image
shouldn't need auth, which was right: ghcr.io itself speaks the standard
OCI Distribution API, not just GitHub's REST API, and a public package
supports the same anonymous pull-token flow `docker pull` uses with no
login (`GET /token?scope=repository:<repo>:pull`, verified live against
openabdev/openab before writing any code). Switched to that.

- oabctl: new `vendor_images` module. `pre-beta-<vendor>` (Beta, the
  hourly rolling build) and the newest openab GitHub release whose
  matching `<version>-<vendor>` image is confirmed to exist (Stable) —
  verified via a manifest HEAD request per candidate (existence check, no
  image bytes transferred), not a bulk tag-list scan (this repo has
  thousands of tags across multiple pages). A release tag existing doesn't
  guarantee a matching image was ever published (`build-images.yml` is a
  manual `workflow_dispatch`, disconnected from cutting a release), so
  Stable is verified against GHCR directly rather than inferred from the
  release list alone. GitHub's releases API also needed a name-based
  filter alongside `prerelease`: at least one real release
  (`openab-0.10.0-beta.3`) has `prerelease: false` despite its name.
- studio-cp: thin `resolve_vendor_image_tags` wrapper.
- oab-mcp: new `resolve_vendor_image_tags` tool. Never errors on a failed
  GHCR/GitHub call — leaves the corresponding field `None`, the console
  falls back to a plain editable text field either way (Brett already
  confirmed manual image tag entry stays available).
- src-tauri: bridge command, same shape as the other read-only wizard
  pickers (list_k8s_contexts etc).

Console wiring (actually using this in the Vendor select) lands with the
rest of the wizard UI (#128's items 1/3/4/5), not this PR.

Ref #128.
@brettchien
brettchien merged commit 7a5ef5e into main Aug 29, 2026
2 checks passed
@brettchien
brettchien deleted the feat/ghcr-vendor-image-tags-128 branch August 29, 2026 08:40
brettchien added a commit that referenced this pull request Aug 29, 2026
…write (studio#128) (#132)

Replaces the Template/Overlay compose-library step (empty on every fresh
install by design, blocking the whole deploy flow — the original #119
screenshot that started this) with the vendor + chat platform + ACP flow
confirmed with Brett across #128's design thread.

## Console (items 1-5 of the runbook, shipped together — all fields live
on the same new Step 2 screen)

- Vendor <select>: Claude/codex/agy/cursor/kiro. "agy" is only the display
  label — the option value is "antigravity" (the GHCR image variant /
  Dockerfile.package build-target name resolve_vendor_image_tags expects).
- Image tag: pre-filled from resolve_vendor_image_tags (#131) — Stable if
  GHCR confirms it exists, else Beta (pre-beta-<vendor>), else left for
  manual entry. Always editable — no lookup failure blocks the field.
- API key (optional): captured, stored as a secret server-side; not yet
  wired into config.toml (documented gap from #129, unchanged here).
- Chat platform (optional, default none — "use ACP directly"):
  Discord/Telegram/LINE, reveals the right token field(s) per platform.
  k8s deploys refuse a non-empty selection both client-side (clean
  validation message) and server-side (#129's existing refusal) — config.toml
  secret resolution needs AWS credentials a k8s pod doesn't have.
- Enable ACP checkbox: default checked, forced off + disabled for
  vendor=agy (its bridge bypasses openab-gateway's /acp route entirely).
- Agent name: pre-filled with a random Greek god name, shuffle button to
  re-roll, still freely editable.
- No separate "Preview bundle" step anymore — fill in the fields, Deploy.

## Backend: acp_enabled made caller-controlled (was hardcoded true in #127)

#127 hardcoded `acp_enabled: Some(true)` inside build_default_manifest /
build_default_k8s_manifest with no way for a caller to turn it off — fine
when nothing exposed a toggle, not fine once the wizard has an actual
checkbox (needed for the agy case above). Both functions, and
AgentWizardInput, now take `acp_enabled: bool` explicitly:
- studio-cp: build_default_manifest/build_default_k8s_manifest gained an
  `acp_enabled: bool` param — only generates the ACP auth secret when true.
  provision_from_library[_k8s] (the older compose-library path, unrelated
  to this wizard) pass `true` at their call sites, preserving #127's
  original unconditional-on behavior there unchanged.
- oab-mcp: deploy_provision_agent's schema gained `acp_enabled: boolean`,
  defaulting to true when the caller omits it (same default #127 had,
  now explicit and overridable instead of baked in).
- src-tauri: bridge command threads the new param through.

Ref #128.
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