Skip to content

Conversation

@thozza
Copy link
Member

@thozza thozza commented Dec 4, 2025

Overview

This PR refactors the pkg/depsolvednf package to introduce an apiHandler interface that abstracts the osbuild-depsolve-dnf API implementation. The goal is to enable easier iteration on Solver API versions by cleanly separating API wire-format handling (request building and response parsing) from the core Solver logic. The current v1 API has been extracted into a dedicated v1Handler implementation. This is preparatory work for adding a v2 Solver API in a follow-up PR.

Architectural Changes

The key design decision is the introduction of the apiHandler interface that defines three pairs of methods for Request building and Response parsing.

A solverConfig struct is used to pass solver configuration to handlers without coupling them to the Solver type directly. The run() function now accepts raw []byte request data instead of a typed *Request struct, making it agnostic to the API version being used.

This architecture allows new API versions to be added by simply implementing the apiHandler interface, without modifying the Solver methods themselves.

Key Changes

  • New apiHandler interface (api.go): Defines the contract for API version handlers with methods for building requests and parsing responses
  • New v1Handler implementation (v1.go): Extracts all v1 API structs, request building, and response parsing logic from the main file
  • Migrated Solver methods: Depsolve(), FetchMetadata(), and SearchMetadata() now use activeHandler instead of inline API logic
  • Refactored run() function: Now accepts raw []byte instead of a typed request struct
  • Replaced Request.Hash() with hashRequest(): Caching now uses SHA256 of raw request bytes instead of custom field-based hashing
  • Extracted applyRHSMSecrets() helper: The RHSM secrets override logic is now a separate, testable function

Breaking Changes / Backward Compatibility

This PR is fully backward compatible. The external API surface of the depsolvednf package remains unchanged. Internal types have been moved/removed, but these were not exported. The cache hash computation has changed, which will cause a one-time cache invalidation for existing caches.

Testing

  • Added comprehensive unit tests for v1 handler request building methods (TestV1HandlerMakeDepsolveRequest, TestV1HandlerMakeDumpRequest, TestV1HandlerMakeSearchRequest) verifying JSON output matches expected format
  • Added unit tests for Solver.FetchMetadata() and Solver.SearchMetadata() to ensure the refactoring doesn't break existing behavior
  • Added unit tests for the newly extracted applyRHSMSecrets() function covering various RHSM/mTLS/plain repo combinations
  • Existing integration tests continue to pass, now indirectly testing the v1 handler's response parsing through the Solver methods

While working on the osbuild-depsolve-dnf parts, I realized that the
`BaseURL` information in this case comes from the repository metadata,
where it is almost never set. So in reality, the value would be almost
always empty. The baseurl value is and should be deduced from the
repository config that the package comes from.

Signed-off-by: Tomáš Hozza <[email protected]>
Add the NVR() helper. This property is used by the depsolvednf package
to sort list of packages, so let's implement it in a single place.

Signed-off-by: Tomáš Hozza <[email protected]>
The unit test verifies that the expected number of packages are in the
response and that the slice is sorted by package's NVR string.

Signed-off-by: Tomáš Hozza <[email protected]>
The unit test verifies that the expected list of packages is returned
for certain scenarios and that the list is sorted by package's NVR
string.

Signed-off-by: Tomáš Hozza <[email protected]>
The function is not used anywhere as far as I can tell. There is an
unexported version of the error parser, which is called by the `run()`
function.

Signed-off-by: Tomáš Hozza <[email protected]>
This moves a common and important validation logic from
makeDepsolveRequest() a level higher, before the depsolve request is
constructed. The goal is to keep only API wire-format specific code in
the makeDepsolveRequest() to make it easy to iterate on API versions.

Signed-off-by: Tomáš Hozza <[email protected]>
@thozza thozza requested a review from a team as a code owner December 4, 2025 12:26
@thozza thozza force-pushed the HMS-9062-refactoring-and-tests branch from 865468c to 04c4767 Compare December 4, 2025 12:27
@thozza thozza marked this pull request as draft December 4, 2025 13:15
thozza added 16 commits December 4, 2025 15:19
The goal is to later make reposFromRPMMD() specific to the API
implementation and not being a method of the Solver. This will make the
transition easier, because there would be less data that need to be
passed to the function that transforms the rpmmd.RepoConfig to the
wire-format.

Signed-off-by: Tomáš Hozza <[email protected]>
Extract the error parsing from the Solver request wire-format. This will
make adding a new API version easier, since no more changes would be
needed to adjust error parsing.

Also change the run() function to not return parsed error, but instead
return and error with the raw error message. This moves the task to
parser the actual error to the caller, which makes more sense since the
run() function should not care about the wire-format at all.

Signed-off-by: Tomáš Hozza <[email protected]>
The `rhsmMap` was previously constructed in `makeDepsolveRequest()`,
but not used at all and returned to the caller. The caller then used it
to interpret the Solver API response. Considering this, the
makeDepsolveRequest() is simply the wrong place to construct `rhsmMap`.

Move the construction of the `rhsmMap` to the caller. This decouples the
request construction even more from the Solver implementation. This will
make decoupling the wire-format construction from the Solver
implementation much cleaner.

Signed-off-by: Tomáš Hozza <[email protected]>
Make optionalMetadataForDistro() a standalone function that takes
modulePlatformID as parameter. This will eventually enable API handler
implementation use it without Solver access.

Signed-off-by: Tomáš Hozza <[email protected]>
These will wrap the Solver command response in a similar way as
DepsolveResult does now for the 'depsolve' command. The structs are
not used yet. They will be used by the future API handler interface.

Signed-off-by: Tomáš Hozza <[email protected]>
The apiHandler describes methods that an osbuild-depsolve-dnf API
handler must implement. The code will be refactored to use the interface
later, which will make adding new API handlers much simpler thanks to
clear separation of responsibilities.

Signed-off-by: Tomáš Hozza <[email protected]>
Add a version of the current (v1) API implementation, which implements
the apiHandler interface. The implementation is not used yet. It will be
swapped with the current implementation that is coupled with the Solver,
in the following commits.

The goal is to keep the API as is, without any noticeable change.

Add unit tests for make*Request() methods, verifying that the produced
JSON is as expected. The parse*Result() will be tested indirectly by
the unit tests that verify the Solver methods, when they switch to use
API handler implementation.

Signed-off-by: Tomáš Hozza <[email protected]>
Add a helper method for the Solver, which returns the solverConfig
instance from the current Solver state. The return value will be then
passed to the API handler methods.

Signed-off-by: Tomáš Hozza <[email protected]>
This decouples the run() function from the API wire-format struct
implementation. Now it takes raw request as []byte and returns raw
response as []byte. The caller is responsible for (un)marshaling the
response/request from and to JSON.

Signed-off-by: Tomáš Hozza <[email protected]>
The caching for the dump and search commands depended on the API request
wire-format struct. To not need to complicate the API handler interface
with this specific aspect, replace the old way of calculating hash by
hashing the whole raw request. Although the new implementation will
produce different hashes than the old one, this is a one time cache
invalidation. The functionality is technically the same.

Signed-off-by: Tomáš Hozza <[email protected]>
Modify Solver.Depsolve() to use activeHandler instead. Remove methods
that are no longer needed.

Signed-off-by: Tomáš Hozza <[email protected]>
Modify Solver.FetchMetadata() to use activeHandler instead. Remove
methods that are no longer needed.

Signed-off-by: Tomáš Hozza <[email protected]>
Modify Solver.SearchMetadata() to use activeHandler instead. Remove
methods and structs that are no longer needed.

Signed-off-by: Tomáš Hozza <[email protected]>
Remove the remaining old types and methods that are no longer used
anywhere after migrating all Solver methods to use activeHandler.

Signed-off-by: Tomáš Hozza <[email protected]>
Extract the RHSM secrets override logic from Depsolve() into a separate
applyRHSMSecrets() function. This logic overrides Package.Secrets from
"org.osbuild.mtls" to "org.osbuild.rhsm" for packages coming from
repositories with RHSM=true.

This logic was previously untested.

Signed-off-by: Tomáš Hozza <[email protected]>
@thozza thozza force-pushed the HMS-9062-refactoring-and-tests branch from 04c4767 to b37aa65 Compare December 4, 2025 14:23
@thozza thozza marked this pull request as ready for review December 4, 2025 14:31
Copy link
Member

@achilleas-k achilleas-k left a comment

Choose a reason for hiding this comment

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

Wow, that's a lot! Very clean PR, couldn't find anything to complain about.

LGTM

Comment on lines +580 to +582
// optionalMetadataForDistro returns optional repository metadata types
// that should be downloaded for the given distro.
func optionalMetadataForDistro(modulePlatformID string) []string {
Copy link
Member

Choose a reason for hiding this comment

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

Could drop all mentions of Fedora here now.

Copy link
Member Author

Choose a reason for hiding this comment

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

Nice catch. I'll make this change in a follow-up.

Copy link
Contributor

@lzap lzap left a comment

Choose a reason for hiding this comment

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

Wow, 22 commits and I was able to find just one nit pick :-D

@supakeen supakeen added this pull request to the merge queue Dec 8, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Dec 8, 2025
@achilleas-k achilleas-k added this pull request to the merge queue Dec 8, 2025
@achilleas-k
Copy link
Member

Lots of rebuilds happening on the merge queue. I wonder if it's a manifest generation or caching issue. Looking into it.

@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Dec 8, 2025
@achilleas-k
Copy link
Member

Let's get #2075 merged first to stop the rebuilds on the merge queue.

@thozza thozza added this pull request to the merge queue Dec 10, 2025
Merged via the queue into osbuild:main with commit 7f89c21 Dec 10, 2025
23 checks passed
@thozza thozza deleted the HMS-9062-refactoring-and-tests branch December 10, 2025 09:39
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