Repository: osbuild/osbuild-composer (go)

Issue:
Fedora IoT Rawhide compose is failing with  "Received empty package specs" (from compose-status.json)
**Describe the bug**
Fedora Rawhide compose is failing with the error (from compose-status.json):

reason  "Received empty package specs"
reason  "Manifest dependency failed"

Koji Task:
https://koji.fedoraproject.org/koji/taskinfo?taskID=93976262

Full compose logs:
https://kojipkgs.fedoraproject.org/compose/iot/Fedora-IoT-38-20221108.0/

**Environment**
 *  Fedora Koji
 
**To Reproduce**
Steps to reproduce the behavior:

To manually reproduce the error:
koji osbuild-image Fedora-IoT 38 fedora-38 f38-candidate x86_64 --repo='https://kojipkgs.fedoraproject.org/compose/rawhide/Fedora-Rawhide-20221109.n.0/compose/Everything/x86_64/os/' --ostree-url='http://kojipkgs.fedoraproject.org/compose/iot/repo/' --ostree-ref='fedora/devel/$arch/iot' --image-type iot-installer --release 38.20221109.1 --skip-tag

https://koji.fedoraproject.org/koji/taskinfo?taskID=93978382

**Expected behavior**
Completed task in koji. 



Pull request:
Fix iot-installer build via the cloud API
8fdd1587997dbf091dd69a426bb44ef1c9abcfd1 modified the Cloud API to resolve
ostree commits using a separate job. This change caused the API handler
to call PackageSets without any ostree options (because they are not resolved
yet).

Unfortunately, the new implementation of PackageSets initializes the manifest.
The initialization checks the options and if the type is iot-installer and
it doesn't have the fetch checksum for IoT, it just returns an error.

To work around this (we need an initialized manifest to create the chains),
this commit just gives the initialization method a dummy checksum. The ostree
options currently don't have any effect on the package sets, so this should
be fine.

In order to make this workaround at least slightly sane, a warning is printed,
there's a new test just for this behaviour and a long comment to remember to
delete these lines.

Fixes #3125 

This pull request includes:

- [x] adequate testing for the new functionality or fixed issue

<!--
Thanks for proposing a change to osbuild-composer!

Please don't remove the above check list. These are things that each pull
request must have before it is merged. It helps maintainers to not forget
anything.

If the reason for ticking any of the boxes is ambiguous, please add a short
note explaining why.

In addition, if this pull request fixes a downstream issue, please refer to
test/README.md and add these additional items:

- [ ] 1st commit of any `rhbz#` related PR contains bug reproducer; CI reports FAIL or
- [ ] PR contains automated tests for new functionality and
- [ ] QE has approved reproducer/new tests and
- [ ] Subsequent commits provide bug fixes without modifying the reproducer; CI reports PASS and
- [ ] QE approves this PR; RHBZ status is set to `MODIFIED + Verified=Tested`

Information regarding our GitLab pipeline (Schutzbot):

CI will not be ran automatically if WIP label is applied or the PR is in DRAFT state, instead only
a link will be provided to the pipeline which can then be triggered manually if desired. To run the
CI automatically either switch the PR to ready or apply WIP+test label.

Outside contributors need manual approval from one of the osbuild-composer maintainers.

Schutzbot will only be triggered if all Tests jobs in GitHub workflow succeed.
-->


Patch:
diff --git a/internal/distro/fedora/distro.go b/internal/distro/fedora/distro.go
index 20e0d16d0..c141f61eb 100644
--- a/internal/distro/fedora/distro.go
+++ b/internal/distro/fedora/distro.go
@@ -8,6 +8,8 @@ import (
 	"strconv"
 	"strings"
 
+	"github.com/sirupsen/logrus"
+
 	"github.com/osbuild/osbuild-composer/internal/blueprint"
 	"github.com/osbuild/osbuild-composer/internal/common"
 	"github.com/osbuild/osbuild-composer/internal/container"
@@ -536,11 +538,30 @@ func (t *imageType) PackageSets(bp blueprint.Blueprint, options distro.ImageOpti
 		}
 	}
 
+	// In case of Cloud API, this method is called before the ostree commit
+	// is resolved. Unfortunately, initializeManifest when called for
+	// an ostree installer returns an error.
+	//
+	// Work around this by providing a dummy FetchChecksum to convince the
+	// method that it's fine to initialize the manifest. Note that the ostree
+	// content has no effect on the package sets, so this is fine.
+	//
+	// See: https://github.com/osbuild/osbuild-composer/issues/3125
+	//
+	// TODO: Remove me when it's possible the get the package set chain without
+	//       resolving the ostree reference before. Also remove the test for
+	//       this workaround
+	if t.rpmOstree && t.bootISO && options.OSTree.FetchChecksum == "" {
+		options.OSTree.FetchChecksum = "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+		logrus.Warn("FIXME: Requesting package sets for iot-installer without a resolved ostree ref. Faking one.")
+	}
+
 	// create a manifest object and instantiate it with the computed packageSetChains
 	manifest, err := t.initializeManifest(&bp, options, globalRepos, packageSets, nil, 0)
 	if err != nil {
 		// TODO: handle manifest initialization errors more gracefully, we
 		// refuse to initialize manifests with invalid config.
+		logrus.Errorf("Initializing the manifest failed for %s (%s/%s): %v", t.Name(), t.arch.distro.Name(), t.arch.Name(), err)
 		return nil
 	}
 


Test patch:
diff --git a/internal/distro/fedora/distro_test.go b/internal/distro/fedora/distro_test.go
index eb368ba54..0729c763c 100644
--- a/internal/distro/fedora/distro_test.go
+++ b/internal/distro/fedora/distro_test.go
@@ -730,3 +730,24 @@ func TestDistro_CustomUsrPartitionNotLargeEnough(t *testing.T) {
 		}
 	}
 }
+
+func TestIotInstallerWithoutOStreeRefs(t *testing.T) {
+	// Regression test for https://github.com/osbuild/osbuild-composer/issues/3125
+
+	// TODO: Remove when the ugly workaround is gone
+	d := fedora.NewF38()
+	arch, err := d.GetArch("x86_64")
+	require.NoError(t, err)
+
+	imgType, err := arch.GetImageType("iot-installer")
+	require.NoError(t, err)
+
+	bp := blueprint.Blueprint{
+		Name: "fish",
+	}
+	err = bp.Initialize()
+	require.NoError(t, err)
+
+	sets := imgType.PackageSets(bp, distro.ImageOptions{}, nil)
+	require.NotZero(t, len(sets))
+}