Skip to content

feat(bakery): FCOS sysext catalog client for fedora-sysexts/community#720

Open
clubanderson wants to merge 2 commits into
projectbluefin:mainfrom
clubanderson:feat/fcos-catalog-641
Open

feat(bakery): FCOS sysext catalog client for fedora-sysexts/community#720
clubanderson wants to merge 2 commits into
projectbluefin:mainfrom
clubanderson:feat/fcos-catalog-641

Conversation

@clubanderson
Copy link
Copy Markdown
Contributor

@clubanderson clubanderson commented Jun 4, 2026

Closes #641

Summary

Implements all sub-scopes from issue #641 — adds the FCOS sysext catalog client for fedora-sysexts/community, including stream metadata fetching, tag name parsing, catalog pagination, curated descriptions, and wizard wiring.

Changes

A — FCOS stream metadata (internal/fcos/streams.go)

  • FetchStreamFedoraVersion(ctx, stream) fetches the Fedora major version from the FCOS stream JSON at builds.coreos.fedoraproject.org/streams/<stream>.json
  • Validates stream is stable, testing, or next; parses major version from release field

B — Tag name parsing (internal/bakery/fcos.go)

  • ParseFCOSTagName(tag) parses <name>-<version>-<fedoraVersion>-<arch> tags
  • Handles docker-ce, 1password-gui, tailscale-0-1.98.4-1, netbird-ui, cloud-hypervisor
  • Floating tags (tailscale, latest, vscode) rejected with descriptive error

C — Catalog URL + pagination (internal/bakery/fcos.go)

  • FCOSCatalogURL const; maxFCOSCatalogPages = 20 (covers ~1600 releases at 100/page)
  • slog.Warn emitted if cap hit while rel="next" still exists (soft failure)

D — HTTPClient.FetchCatalogFCOS (internal/bakery/fcos.go)

  • Filters releases by arch AND fedoraVersion before deduplication
  • SHA256SUMS best-effort; NewFCOSHTTPClient() factory
  • Asset URLs confirmed to be on github.com (not extensions.fcos.fr)

E — Curated descriptions (internal/bakery/fcos_descriptions.go)

  • FCOSLookup + TierFCOSCommunity constant
  • Covers: tailscale, docker-ce, vscode, vscodium, glab, cilium-cli, 1password-gui, bitwarden

** Dispatcher + wizard wiring**F

  • FCOSCatalogClient interface in dispatch.go (extends Client with FetchCatalogFCOS)
  • FetchCatalogForOS gains fedoraVersion int parameter
  • Wizard FetchSysexts dispatches via DispatchingClient, resolves fedoraVersion lazily on first use
  • Wizard.FetchFCOSStream pre-fetch helper called from main.go startup
  • main.go wired to DispatchingClient{Flatcar: NewHTTPClient(), FCOS: NewFCOSHTTPClient()}

Tests

  • internal/fcos/streams_test.go: httptest-based tests for stream version fetching
  • internal/bakery/fcos_test.go: table-driven ParseFCOSTagName + FetchCatalogFCOS integration tests
  • All go test ./... pass; go vet ./... and gofmt clean

Summary by CodeRabbit

  • New Features

    • Added Fedora CoreOS catalog support with automatic Fedora version detection from stream metadata.
    • Implemented Fedora version-aware filtering for CoreOS system extensions.
    • Introduced curated metadata for CoreOS community extensions, including categories and support tiers.
    • Extended catalog fetching to support multiple operating systems with separate configurations.
  • Tests

    • Added comprehensive test coverage for CoreOS catalog operations and stream version detection.

Implements all sub-scopes from issue projectbluefin#641:

- A: FCOS stream metadata client (internal/fcos/streams.go)
  FetchStreamFedoraVersion fetches the Fedora major version from the
  FCOS stream JSON at builds.coreos.fedoraproject.org/streams.

- B: ParseFCOSTagName (internal/bakery/fcos.go)
  Left-to-right scan for first '-<digit>' boundary correctly handles
  names like 'docker-ce', '1password-gui', and versions with epoch
  fields like 'tailscale-0-1.98.4-1'.

- C: FCOSCatalogURL + maxFCOSCatalogPages=20 (internal/bakery/fcos.go)
  fedora-sysexts/community has ~1600 releases; 20 pages at 100/page
  provides full coverage with headroom. Emits slog.Warn if truncated.

- D: HTTPClient.FetchCatalogFCOS (internal/bakery/fcos.go)
  Filters releases by arch AND fedoraVersion before deduplication.
  Fetches SHA256SUMS best-effort. Asset URLs are github.com (confirmed
  against live API; extensions.fcos.fr CDN is not used).

- E: FCOSLookup + fcos_descriptions.go curated catalog
  Covers tailscale, docker-ce, vscode, vscodium, glab, cilium-cli,
  1password-gui, bitwarden with category and TierFCOSCommunity tier.

- F: FCOSCatalogClient interface in dispatch.go
  DispatchingClient.FCOS is FCOSCatalogClient (not bare Client).
  FetchCatalogForOS gains a fedoraVersion int parameter.
  Wizard FetchSysexts dispatches via DispatchingClient when available,
  resolving fedoraVersion lazily from the current stream on first use.
  FetchFCOSStream is a pre-fetch helper called from main.go startup.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dosubot dosubot Bot added size:XL This PR changes 500-999 lines, ignoring generated files. domain:bakery Sysext catalog and Flatcar release fetching domain:sysext System extensions / bakery kind/feature New feature or enhancement labels Jun 4, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Jun 4, 2026

Review Change Stack

Warning

Review limit reached

@clubanderson, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 31 minutes and 13 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0eeb7cf3-d111-4674-ba44-755cba65ca7a

📥 Commits

Reviewing files that changed from the base of the PR and between 534fa63 and 8baa0e6.

📒 Files selected for processing (8)
  • cmd/knuckle/main.go
  • internal/bakery/bakery.go
  • internal/bakery/dispatch.go
  • internal/bakery/dispatch_test.go
  • internal/bakery/fcos.go
  • internal/bakery/fcos_descriptions.go
  • internal/bakery/fcos_test.go
  • internal/wizard/wizard.go
📝 Walkthrough

Walkthrough

This PR implements comprehensive FCOS (Fedora CoreOS) sysext catalog support by adding stream metadata fetching for runtime Fedora version resolution, a full-featured GitHub-backed catalog client with tag parsing and Fedora-version filtering, dispatching infrastructure to route FCOS and Flatcar requests separately, wizard integration with lazy version resolution, and application startup wiring.

Changes

FCOS Catalog Client Implementation

Layer / File(s) Summary
FCOS Stream Version Fetching
internal/fcos/streams.go, internal/fcos/streams_test.go
FetchStreamFedoraVersion validates stream names (stable, testing, next), fetches stream metadata JSON from coreos.fedoraproject.org with 30s timeout and 5MiB response limit, and extracts the Fedora major version from the first release component (e.g., 44 from 44.20260510.3.1). Five tests verify happy path, unsupported streams, HTTP errors, empty JSON, and graceful fallback when one artifact is malformed.
FCOS Catalog Fetching and Filtering
internal/bakery/fcos.go, internal/bakery/fcos_test.go
FetchCatalogFCOS constructs an HTTPClient with FCOS GitHub catalog URL and optional GitHub auth token. ParseFCOSTagName parses release tags to extract name, version, Fedora version, and arch, rejecting floating tags without recognized arch suffixes. The catalog client paginates through releases (capped at 10 pages with truncation warning), filters by requested arch and Fedora version, deduplicates by sysext name (keeping newest), selects *.raw assets and optional SHA256SUMS, and validates names. Eight tests cover tag parsing variants, basic filtering by arch/version, deduplication, skipped floating tags, curated vs. raw descriptions, unsupported arch rejection, HTTP errors, and multi-page pagination.
FCOS Extension Metadata
internal/bakery/fcos_descriptions.go
Hardcoded map of FCOS community extension metadata (name → category, support tier, short/long descriptions) with FCOSLookup function for enriching catalog entries with curated descriptions instead of raw GitHub body text.

Dispatcher and Bakery Integration

Layer / File(s) Summary
FCOSCatalogClient Interface and DispatchingClient Update
internal/bakery/dispatch.go
New FCOSCatalogClient interface requires FetchCatalogFCOS(ctx, arch, fedoraVersion) method. DispatchingClient.FCOS field now typed to this interface. FetchCatalogForOS signature updated to accept fedoraVersion parameter; FCOS branch validates non-nil FCOS client and calls FetchCatalogFCOS with version; Flatcar branch behavior unchanged.
MockClient and Test Updates
internal/bakery/bakery.go, internal/bakery/dispatch_test.go
MockClient.FetchCatalogFCOS implements the interface by forwarding to FetchCatalogArch (ignoring fedoraVersion). All five dispatcher tests updated to pass fedoraVersion argument (0 for Flatcar, 44 for FCOS).

Wizard FCOS Integration

Layer / File(s) Summary
Wizard State and Test Injection
internal/wizard/wizard.go (imports, hook, state)
Import internal/fcos package. New package-level hook variable fetchFCOSStreamVersionFn allows tests to inject version lookup. Wizard.State gains FCOSFedoraVersion field to cache resolved Fedora major version.
FCOS-Aware Sysext Catalog Loading
internal/wizard/wizard.go (FetchSysexts, FetchFCOSStream)
FetchSysexts detects if bakery client is *DispatchingClient; for FCOS OS, lazily resolves FCOSFedoraVersion via hook before calling FetchCatalogForOS. New exported FetchFCOSStream(ctx) method resolves and stores stream version for FCOS only, returning wrapped error on failure.

Application Startup Wiring

Layer / File(s) Summary
DispatchingClient Initialization and Prefetch
cmd/knuckle/main.go
Replace single HTTP client with DispatchingClient wiring separate Flatcar and FCOS HTTP clients. Add non-fatal FetchFCOSStream(ctx) prefetch during non-demo startup with warning-level log on failure.

Sequence Diagram(s)

sequenceDiagram
  participant Wizard as Wizard (main startup)
  participant Prefetch as FetchFCOSStream
  participant StreamFetch as FetchStreamFedoraVersion
  participant StreamsAPI as FCOS Streams API
  participant FetchSysexts as FetchSysexts
  participant Dispatcher as DispatchingClient
  participant FCOSClient as FetchCatalogFCOS
  participant GitHubAPI as GitHub Releases API
  
  Wizard->>Prefetch: prefetch FCOS version (best-effort)
  Prefetch->>StreamFetch: FetchStreamFedoraVersion(stable)
  StreamFetch->>StreamsAPI: GET /stable.json
  StreamsAPI-->>StreamFetch: version 44.x.x
  StreamFetch-->>Prefetch: 44
  Prefetch->>Wizard: cached in State
  
  Wizard->>FetchSysexts: load catalog
  FetchSysexts->>Dispatcher: FetchCatalogForOS (FCOS, x86-64, fedoraVersion=44)
  Dispatcher->>FCOSClient: FetchCatalogFCOS(x86-64, 44)
  FCOSClient->>GitHubAPI: GET /repos/fedora-sysexts/community/releases (paginated)
  GitHubAPI-->>FCOSClient: releases (paginated)
  FCOSClient->>FCOSClient: filter by arch and Fedora 44
  FCOSClient-->>Dispatcher: []SysextEntry
  Dispatcher-->>FetchSysexts: filtered catalog
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

The PR adds substantial new functionality across multiple files: FCOS stream version fetching with HTTP handling and JSON parsing; a feature-rich catalog client with pagination, tag parsing, filtering, deduplication, and optional hash fetching; dispatcher interface updates affecting existing code paths; curated metadata catalog; and wizard state integration. High-density implementation logic, diverse file coordination, and multiple edge cases (pagination caps, truncation warnings, floating tags, malformed artifacts, best-effort hash fetching) require careful review across behavior, error handling, and test coverage.

Possibly related issues

  • #641: This PR directly implements the full scope of the FCOS sysext catalog client feature, including stream metadata fetching, tag parsing, filtered catalog retrieval, and wizard integration outlined in the issue.

Suggested labels

domain:bakery, domain:wizard, domain:ci, feature, fcos

Suggested reviewers

  • castrojo

Poem

🐰 Hopping through FCOS Streams

A baker hops through Fedora's streams so fine,
Parsing tags and Fedora versions divine,
With pagination and dedup by name,
The FCOS catalog's now in the game! 🎉
Communities sysexts, filtered just right,
Version forty-four burning bright!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 23.08% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding an FCOS sysext catalog client for fedora-sysexts/community.
Linked Issues check ✅ Passed All coding objectives from issue #641 are implemented: FCOS stream metadata (FetchStreamFedoraVersion), tag parsing (ParseFCOSTagName), catalog URL with pagination cap (FCOSCatalogURL and maxFCOSCatalogPages=20), FetchCatalogFCOS with arch/Fedora filtering, curated FCOS descriptions, and dispatcher/wizard wiring.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the FCOS catalog client as specified in issue #641. No unrelated modifications detected.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (1)
internal/bakery/bakery.go (1)

390-392: ⚡ Quick win

Make the mock observe fedoraVersion.

This implementation drops the new FCOS parameter, so the dispatch tests still pass even if the caller forwards 0 or the wrong stream version. Record the argument on MockClient, or use an FCOS-specific stub in tests that asserts the expected Fedora version.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@internal/bakery/bakery.go` around lines 390 - 392,
MockClient.FetchCatalogFCOS currently ignores the fedoraVersion parameter which
lets callers pass wrong versions unnoticed; update FetchCatalogFCOS to record or
assert the fedoraVersion before delegating to FetchCatalogArch. Add a field on
MockClient (e.g., LastFedoraVersion or ReceivedFedoraVersion) and set it inside
FetchCatalogFCOS (or implement an FCOS-specific stub callback on MockClient) so
tests can verify the forwarded version, then keep the existing call to
m.FetchCatalogArch(ctx, arch). Ensure tests are updated to inspect the new field
or use the stub to assert the expected Fedora version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@cmd/knuckle/main.go`:
- Around line 154-158: Move the FCOS stream prefetch so it runs before the
sysexts/catalog lazy-resolve: call w.FetchFCOSStream(ctx) prior to invoking
w.FetchSysexts(...) (and before the catalog fetch that triggers lazy resolution
of State.FCOSFedoraVersion). This avoids duplicate stream requests by ensuring
FetchFCOSStream executes as the true prewarm step before Wizard.FetchSysexts can
lazily request the same stream.

In `@internal/bakery/dispatch.go`:
- Around line 39-45: In FetchCatalogForOS (method
DispatchingClient.FetchCatalogForOS) add a validation in the FCOS branch to
reject a missing/zero fedoraVersion: if fedoraVersion == 0 return a descriptive
error (e.g. "fedoraVersion required for FCOS") instead of forwarding 0 into
FetchCatalogFCOS; keep the existing nil-check for d.FCOS and only call
d.FCOS.FetchCatalogFCOS when fedoraVersion is non-zero.

In `@internal/bakery/fcos_descriptions.go`:
- Around line 12-69: fcosCatalog is missing curated entries for "kubernetes" and
"1password-cli", so add two map entries in the fcosCatalog variable (same
structure as existing entries like "tailscale" and "1password-gui"): keys
"kubernetes" and "1password-cli" with fields Category (e.g., "Orchestration" for
kubernetes, "Security" for 1password-cli), SupportTier set to TierFCOSCommunity,
Short and Long descriptive strings, and Caveats (nil or list) as appropriate so
they no longer fall back to raw release text; follow the exact ExtensionMeta
field names used in fcos_descriptions.go.

In `@internal/bakery/fcos_test.go`:
- Around line 131-134: The unit test fixture in internal/bakery/fcos_test.go
includes a SHA256SUMS asset that causes FetchCatalogFCOS to perform an outbound
fetch; update the test to remain hermetic by either removing the fcosAsset entry
with Name "SHA256SUMS" from the Assets slice or changing its BrowserDownloadURL
to point at the httptest server URL used in this test; locate the test data
where Assets: []fcosAsset is defined (the entries with Name "tailscale-..." and
"SHA256SUMS") and modify that SHA256SUMS entry so FetchCatalogFCOS only fetches
from the local test server (or omit the entry entirely) to prevent network calls
during tests.

In `@internal/bakery/fcos.go`:
- Around line 238-245: The code currently permits empty Sha256 when
c.fetchSHA256ForAsset fails (sha256sumsURL, downloadURL, sha256Hash), which
weakens integrity checks; change the logic so that if c.fetchSHA256ForAsset(ctx,
sha256sumsURL, rawFilename) returns an error you do not produce a catalog entry
— either return the error up from the enclosing method or skip the asset and log
a clear error instead of setting sha256Hash="". Additionally implement mandatory
DIGESTS and GPG verification: call a helper that fetches the
.DIGESTS/.DIGESTS.sig and verifies the GPG signature using the embedded Flatcar
key, then verify the asset's SHA512 against the DIGESTS before accepting the
asset (introduce descriptive helper names like fetchAndVerifyDIGESTS(ctx,
digestsURL) and verifySHA512AgainstDIGESTS(rawFilename, digests) and invoke them
in the same code path so failures hard-fail and prevent the entry from being
returned).

In `@internal/wizard/wizard.go`:
- Around line 390-395: The code only fetches FCOSFedoraVersion when it's zero,
so if the user changes w.State.Config.Channel we must invalidate the cached
version; modify the logic around w.State.FCOSFedoraVersion and
fetchFCOSStreamVersionFn to track the channel used for the last fetch (e.g., add
or use a w.State.FCOSChannel field) and if w.State.Config.Channel !=
w.State.FCOSChannel then set w.State.FCOSFedoraVersion = 0 (or otherwise force
refetch) and update w.State.FCOSChannel; ensure this change is applied wherever
the fetch logic runs (the block using model.OSFCOS, w.State.FCOSFedoraVersion,
and fetchFCOSStreamVersionFn) so the Fedora major is re-resolved when the
stream/channel changes.
- Around line 390-397: The code silently ignores failures from
fetchFCOSStreamVersionFn and proceeds to call dc.FetchCatalogForOS with
w.State.FCOSFedoraVersion == 0; change the logic in the block that checks
w.State.Config.OS == model.OSFCOS so that if fetchFCOSStreamVersionFn(ctx,
w.State.Config.Channel) returns a non-nil error (ferr) you propagate that error
(e.g., return or wrap and return the error) instead of continuing, otherwise set
w.State.FCOSFedoraVersion = ver as now; ensure this prevents calling
dc.FetchCatalogForOS with an invalid FCOSFedoraVersion and references the same
symbols (w.State.Config.OS, model.OSFCOS, w.State.FCOSFedoraVersion,
fetchFCOSStreamVersionFn, dc.FetchCatalogForOS).

---

Nitpick comments:
In `@internal/bakery/bakery.go`:
- Around line 390-392: MockClient.FetchCatalogFCOS currently ignores the
fedoraVersion parameter which lets callers pass wrong versions unnoticed; update
FetchCatalogFCOS to record or assert the fedoraVersion before delegating to
FetchCatalogArch. Add a field on MockClient (e.g., LastFedoraVersion or
ReceivedFedoraVersion) and set it inside FetchCatalogFCOS (or implement an
FCOS-specific stub callback on MockClient) so tests can verify the forwarded
version, then keep the existing call to m.FetchCatalogArch(ctx, arch). Ensure
tests are updated to inspect the new field or use the stub to assert the
expected Fedora version.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 2f7687fe-5a00-4e18-855d-af9bc1f4cb5c

📥 Commits

Reviewing files that changed from the base of the PR and between d4cfb3b and 534fa63.

📒 Files selected for processing (10)
  • cmd/knuckle/main.go
  • internal/bakery/bakery.go
  • internal/bakery/dispatch.go
  • internal/bakery/dispatch_test.go
  • internal/bakery/fcos.go
  • internal/bakery/fcos_descriptions.go
  • internal/bakery/fcos_test.go
  • internal/fcos/streams.go
  • internal/fcos/streams_test.go
  • internal/wizard/wizard.go

Comment thread cmd/knuckle/main.go
Comment thread internal/bakery/dispatch.go
Comment thread internal/bakery/fcos_descriptions.go
Comment thread internal/bakery/fcos_test.go
Comment thread internal/bakery/fcos.go Outdated
Comment thread internal/wizard/wizard.go Outdated
Comment thread internal/wizard/wizard.go Outdated
- dispatch.go: reject fedoraVersion <= 0 for FCOS (hard error)
- wizard.go: propagate stream-version fetch errors; add FCOSFedoraStream
  for cache invalidation when channel changes
- main.go: move FetchFCOSStream before FetchSysexts
- fcos.go: hard-fail when SHA256SUMS present but unresolvable
- fcos_descriptions.go: add curated entries for kubernetes and 1password-cli
- fcos_test.go: remove SHA256SUMS asset from test fixture
- bakery.go: add LastFedoraVersion to MockClient; record fedoraVersion param
- dispatch_test.go: add test for FCOS fedoraVersion=0 guard

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain:bakery Sysext catalog and Flatcar release fetching domain:sysext System extensions / bakery kind/feature New feature or enhancement size:XL This PR changes 500-999 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat(bakery): FCOS sysext catalog client for fedora-sysexts/community

2 participants