Repository: osbuild/osbuild-composer
Pull request #2033 (2021-11-18 13:24:20)

osbuild2: selinux stage - introduce force_autorelabel option
This was added in osbuild: https://github.com/osbuild/osbuild/pull/875

Introduce the same option in composer and make it optional by specifying
it as a pointer to bool value. It would work the same even if it was
there every time, but as it should be an edge case, don't use it
everywhere. Also osbuild doesn't require it to be present, so it seems
like the right thing to do.


This pull request includes:

- [ ] adequate testing for the new functionality or fixed issue
- [ ] adequate documentation informing people about the change such as
  - [ ] submit a PR for the [guides](https://github.com/osbuild/guides) repository if this PR changed any behavior described there: https://www.osbuild.org/guides/

<!--
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`
-->



Patch:
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 7d3d2ab7b..e3258315c 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -137,6 +137,27 @@ Base:
       - "*.repo"
     when: always
 
+Manifests:
+  stage: test
+  extends: .terraform
+  rules:
+    - if: '$CI_PIPELINE_SOURCE != "schedule"'
+    - if: '$CI_PIPELINE_SOURCE == "schedule" && $RUNNER =~ /[\S]+rhel-9.0-[^ga][\S]+/ && $NIGHTLY == "true" && $RHEL_MAJOR == "9"'
+    - if: '$CI_PIPELINE_SOURCE == "schedule" && $RUNNER =~ /[\S]+rhel-8.6-[^ga][\S]+/ && $NIGHTLY == "true" && $RHEL_MAJOR == "8"'
+  script:
+    - schutzbot/deploy.sh
+    - /usr/libexec/tests/osbuild-composer/manifest_tests.sh
+  parallel:
+    matrix:
+      - RUNNER:
+          - aws/rhel-9.0-nightly-x86_64
+        INTERNAL_NETWORK: ["true"]
+  artifacts:
+    paths:
+      - journal-log.gpg
+      - "*.repo"
+    when: always
+
 Regression:
   stage: test
   extends: .terraform
@@ -295,9 +316,24 @@ API:
   parallel:
     matrix:
       - <<: *API_TESTS
+        RUNNER:
+          - aws/fedora-33-x86_64
+          # See COMPOSER-919
+          # - aws/fedora-34-x86_64
+          # See COMPOSER-1118
+          # - aws/centos-stream-8-x86_64
+      - TARGET:
+          - aws
+          - gcp
+          - aws.s3
         RUNNER:
           - aws/centos-stream-8-x86_64
+      - <<: *API_TESTS
+        RUNNER:
           - aws/rhel-8.4-ga-x86_64
+          - aws/rhel-8.6-nightly-x86_64
+          - aws/rhel-9.0-nightly-x86_64
+        INTERNAL_NETWORK: ["true"]
 
 libvirt:
   stage: test
diff --git a/Makefile b/Makefile
index f15810e04..6c8d23bf2 100644
--- a/Makefile
+++ b/Makefile
@@ -123,6 +123,7 @@ build:
 	go test -c -tags=integration -o bin/osbuild-auth-tests ./cmd/osbuild-auth-tests/
 	go test -c -tags=integration -o bin/osbuild-koji-tests ./cmd/osbuild-koji-tests/
 	go test -c -tags=integration -o bin/osbuild-composer-dbjobqueue-tests ./cmd/osbuild-composer-dbjobqueue-tests/
+	go test -c -tags=integration -o bin/osbuild-composer-manifest-tests ./cmd/osbuild-composer-manifest-tests/
 
 .PHONY: install
 install:
diff --git a/cmd/osbuild-composer/composer.go b/cmd/osbuild-composer/composer.go
index 90fea6109..49b0cf710 100644
--- a/cmd/osbuild-composer/composer.go
+++ b/cmd/osbuild-composer/composer.go
@@ -15,6 +15,8 @@ import (
 
 	"github.com/prometheus/client_golang/prometheus/promhttp"
 
+	logrus "github.com/sirupsen/logrus"
+
 	"github.com/osbuild/osbuild-composer/internal/auth"
 	"github.com/osbuild/osbuild-composer/internal/cloudapi"
 	"github.com/osbuild/osbuild-composer/internal/distroregistry"
@@ -25,7 +27,6 @@ import (
 	"github.com/osbuild/osbuild-composer/internal/rpmmd"
 	"github.com/osbuild/osbuild-composer/internal/weldr"
 	"github.com/osbuild/osbuild-composer/internal/worker"
-	logrus "github.com/sirupsen/logrus"
 )
 
 type Composer struct {
@@ -77,6 +78,11 @@ func NewComposer(config *ComposerConfigFile, stateDir, cacheDir string) (*Compos
 			config.Worker.PGDatabase,
 			config.Worker.PGSSLMode,
 		)
+
+		if config.Worker.PGMaxConns > 0 {
+			dbURL += fmt.Sprintf("&pool_max_conns=%d", config.Worker.PGMaxConns)
+		}
+
 		jobs, err = dbjobqueue.New(dbURL)
 		if err != nil {
 			return nil, fmt.Errorf("cannot create jobqueue: %v", err)
diff --git a/cmd/osbuild-composer/config.go b/cmd/osbuild-composer/config.go
index d162cb9e3..e37a6de07 100644
--- a/cmd/osbuild-composer/config.go
+++ b/cmd/osbuild-composer/config.go
@@ -5,6 +5,7 @@ import (
 	"io"
 	"os"
 	"reflect"
+	"strconv"
 
 	"github.com/BurntSushi/toml"
 )
@@ -44,6 +45,7 @@ type WorkerAPIConfig struct {
 	PGUser            string   `toml:"pg_user" env:"PGUSER"`
 	PGPassword        string   `toml:"pg_password" env:"PGPASSWORD"`
 	PGSSLMode         string   `toml:"pg_ssl_mode" env:"PGSSLMODE"`
+	PGMaxConns        int      `toml:"pg_max_conns" env:"PGMAXCONNS"`
 	EnableTLS         bool     `toml:"enable_tls"`
 	EnableMTLS        bool     `toml:"enable_mtls"`
 	EnableJWT         bool     `toml:"enable_jwt"`
@@ -143,6 +145,20 @@ func loadConfigFromEnv(intf interface{}) error {
 				continue
 			}
 			fieldV.SetString(confV)
+		case reflect.Int:
+			key, ok := fieldT.Tag.Lookup("env")
+			if !ok {
+				continue
+			}
+			confV, ok := os.LookupEnv(key)
+			if !ok {
+				continue
+			}
+			value, err := strconv.ParseInt(confV, 10, 64)
+			if err != nil {
+				return err
+			}
+			fieldV.SetInt(value)
 		case reflect.Bool:
 			// no-op
 			continue
diff --git a/internal/cloudapi/v2/openapi.v2.gen.go b/internal/cloudapi/v2/openapi.v2.gen.go
index 511c12839..d4c135623 100644
--- a/internal/cloudapi/v2/openapi.v2.gen.go
+++ b/internal/cloudapi/v2/openapi.v2.gen.go
@@ -207,6 +207,7 @@ const (
 	ImageTypes_aws            ImageTypes = "aws"
 	ImageTypes_azure          ImageTypes = "azure"
 	ImageTypes_edge_commit    ImageTypes = "edge-commit"
+	ImageTypes_edge_container ImageTypes = "edge-container"
 	ImageTypes_edge_installer ImageTypes = "edge-installer"
 	ImageTypes_gcp            ImageTypes = "gcp"
 )
@@ -511,32 +512,32 @@ var swaggerSpec = []string{
 	"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",
-	"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",
+	"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",
 }
 
 // GetSwagger returns the Swagger specification corresponding to the generated code
diff --git a/internal/cloudapi/v2/openapi.v2.yml b/internal/cloudapi/v2/openapi.v2.yml
index 9f4e435d8..1652008c5 100644
--- a/internal/cloudapi/v2/openapi.v2.yml
+++ b/internal/cloudapi/v2/openapi.v2.yml
@@ -510,6 +510,7 @@ components:
         - gcp
         - azure
         - edge-commit
+        - edge-container
         - edge-installer
     Repository:
       type: object
diff --git a/internal/cloudapi/v2/v2.go b/internal/cloudapi/v2/v2.go
index c044fd2a3..da252a991 100644
--- a/internal/cloudapi/v2/v2.go
+++ b/internal/cloudapi/v2/v2.go
@@ -280,6 +280,8 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 		irTarget = t
 	case ImageTypes_edge_installer:
 		fallthrough
+	case ImageTypes_edge_container:
+		fallthrough
 	case ImageTypes_edge_commit:
 		var awsS3UploadOptions AWSS3UploadOptions
 		jsonUploadOptions, err := json.Marshal(ir.UploadOptions)
@@ -372,6 +374,10 @@ func (h *apiHandlers) PostCompose(ctx echo.Context) error {
 	id, err := h.server.workers.EnqueueOSBuildAsDependency(arch.Name(), &worker.OSBuildJob{
 		Targets: []*target.Target{irTarget},
 		Exports: imageType.Exports(),
+		PipelineNames: &worker.PipelineNames{
+			Build:   imageType.BuildPipelines(),
+			Payload: imageType.PayloadPipelines(),
+		},
 	}, manifestJobID)
 	if err != nil {
 		return HTTPErrorWithInternal(ErrorEnqueueingJob, err)
@@ -478,6 +484,8 @@ func imageTypeFromApiImageType(it ImageTypes) string {
 		return "vhd"
 	case ImageTypes_edge_commit:
 		return "rhel-edge-commit"
+	case ImageTypes_edge_container:
+		return "rhel-edge-container"
 	case ImageTypes_edge_installer:
 		return "rhel-edge-installer"
 	}
diff --git a/internal/distro/rhel86/package_sets.go b/internal/distro/rhel86/package_sets.go
index 1c7793515..70c5ac1b0 100644
--- a/internal/distro/rhel86/package_sets.go
+++ b/internal/distro/rhel86/package_sets.go
@@ -498,7 +498,7 @@ func bareMetalPackageSet(t *imageType) rpmmd.PackageSet {
 			"subscription-manager-cockpit", "tar", "tcpdump", "yum",
 		},
 		Exclude: nil,
-	}.Append(bootPackageSet(t)).Append(distroBuildPackageSet(t))
+	}.Append(bootPackageSet(t)).Append(distroSpecificPackageSet(t))
 }
 
 // packages that are only in some (sub)-distributions
@@ -746,7 +746,6 @@ func edgeSimplifiedInstallerPackageSet(t *imageType) rpmmd.PackageSet {
 			"policycoreutils-python-utils",
 			"procps-ng",
 			"rootfiles",
-			"rdma-core",
 			"setools-console",
 			"sudo",
 			"traceroute",
diff --git a/internal/distro/rhel86/pipelines.go b/internal/distro/rhel86/pipelines.go
index 823073405..5f7aee836 100644
--- a/internal/distro/rhel86/pipelines.go
+++ b/internal/distro/rhel86/pipelines.go
@@ -1314,6 +1314,14 @@ func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec
 	p.AddStage(osbuild.NewLoraxScriptStage(loraxScriptStageOptions(arch)))
 	p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, arch, []string{
 		"anaconda",
+		"rdma",
+		"rngd",
+		"multipath",
+		"fcoe",
+		"fcoe-uefi",
+		"iscsi",
+		"lunmask",
+		"nfs",
 	})))
 
 	return p
diff --git a/internal/distro/rhel86/stage_options.go b/internal/distro/rhel86/stage_options.go
index be96ed451..7d242f9f4 100644
--- a/internal/distro/rhel86/stage_options.go
+++ b/internal/distro/rhel86/stage_options.go
@@ -197,8 +197,6 @@ func dracutStageOptions(kernelVer, arch string, additionalModules []string) *osb
 		"systemd-initrd",
 		"modsign",
 		"nss-softokn",
-		"rdma",
-		"rngd",
 		"i18n",
 		"convertfs",
 		"network-manager",
@@ -218,14 +216,8 @@ func dracutStageOptions(kernelVer, arch string, additionalModules []string) *osb
 		"livenet",
 		"lvm",
 		"mdraid",
-		"multipath",
 		"qemu",
 		"qemu-net",
-		"fcoe",
-		"fcoe-uefi",
-		"iscsi",
-		"lunmask",
-		"nfs",
 		"resume",
 		"rootfs-block",
 		"terminfo",
@@ -335,10 +327,6 @@ func grubISOStageOptions(installDevice, kernelVer, arch, vendor, product, osVers
 		Kernel: osbuild.ISOKernel{
 			Dir: "/images/pxeboot",
 			Opts: []string{"rd.neednet=1",
-				"console=tty0",
-				"console=ttyS0",
-				"systemd.log_target=console",
-				"systemd.journald.forward_to_console=1",
 				"coreos.inst.isoroot=" + isolabel,
 				"coreos.inst.install_dev=" + installDevice,
 				"coreos.inst.image_file=/run/media/iso/disk.img.xz",
diff --git a/internal/distro/rhel90/package_sets.go b/internal/distro/rhel90/package_sets.go
index 42e86bc76..021d4197e 100644
--- a/internal/distro/rhel90/package_sets.go
+++ b/internal/distro/rhel90/package_sets.go
@@ -381,7 +381,6 @@ func rhelEc2SapPackageSet(t *imageType) rpmmd.PackageSet {
 		"rhel-system-roles-sap",
 		// RHBZ#1959813
 		"bind-utils",
-		"compat-sap-c++-9",
 		"nfs-utils",
 		"tcsh",
 		// RHBZ#1959955
diff --git a/internal/distro/rhel90/pipelines.go b/internal/distro/rhel90/pipelines.go
index 383ca3248..39f8900d3 100644
--- a/internal/distro/rhel90/pipelines.go
+++ b/internal/distro/rhel90/pipelines.go
@@ -1306,6 +1306,14 @@ func anacondaTreePipeline(repos []rpmmd.RepoConfig, packages []rpmmd.PackageSpec
 	p.AddStage(osbuild.NewLoraxScriptStage(loraxScriptStageOptions(arch)))
 	p.AddStage(osbuild.NewDracutStage(dracutStageOptions(kernelVer, arch, []string{
 		"anaconda",
+		"rdma",
+		"rngd",
+		"multipath",
+		"fcoe",
+		"fcoe-uefi",
+		"iscsi",
+		"lunmask",
+		"nfs",
 	})))
 
 	return p
diff --git a/internal/distro/rhel90/stage_options.go b/internal/distro/rhel90/stage_options.go
index 0e2a88da2..5ed4434f6 100644
--- a/internal/distro/rhel90/stage_options.go
+++ b/internal/distro/rhel90/stage_options.go
@@ -183,8 +183,6 @@ func dracutStageOptions(kernelVer, arch string, additionalModules []string) *osb
 		"systemd-initrd",
 		"modsign",
 		"nss-softokn",
-		"rdma",
-		"rngd",
 		"i18n",
 		"convertfs",
 		"network-manager",
@@ -204,14 +202,8 @@ func dracutStageOptions(kernelVer, arch string, additionalModules []string) *osb
 		"livenet",
 		"lvm",
 		"mdraid",
-		"multipath",
 		"qemu",
 		"qemu-net",
-		"fcoe",
-		"fcoe-uefi",
-		"iscsi",
-		"lunmask",
-		"nfs",
 		"resume",
 		"rootfs-block",
 		"terminfo",
@@ -321,10 +313,6 @@ func grubISOStageOptions(installDevice, kernelVer, arch, vendor, product, osVers
 		Kernel: osbuild.ISOKernel{
 			Dir: "/images/pxeboot",
 			Opts: []string{"rd.neednet=1",
-				"console=tty0",
-				"console=ttyS0",
-				"systemd.log_target=console",
-				"systemd.journald.forward_to_console=1",
 				"edge.liveiso=" + isolabel,
 				"coreos.inst.install_dev=" + installDevice,
 				"coreos.inst.image_file=/run/media/iso/disk.img.xz",
diff --git a/internal/osbuild2/rhsm_stage.go b/internal/osbuild2/rhsm_stage.go
index 160e6529f..9f487ea95 100644
--- a/internal/osbuild2/rhsm_stage.go
+++ b/internal/osbuild2/rhsm_stage.go
@@ -6,6 +6,7 @@ package osbuild2
 // related components. Currently it allows only configuration of the enablement
 // state of DNF plugins used by the Subscription Manager.
 type RHSMStageOptions struct {
+	YumPlugins *RHSMStageOptionsDnfPlugins `json:"yum-plugins,omitempty"`
 	DnfPlugins *RHSMStageOptionsDnfPlugins `json:"dnf-plugins,omitempty"`
 	SubMan     *RHSMStageOptionsSubMan     `json:"subscription-manager,omitempty"`
 }
diff --git a/internal/osbuild2/selinux_stage.go b/internal/osbuild2/selinux_stage.go
index 37377d86f..4757283bc 100644
--- a/internal/osbuild2/selinux_stage.go
+++ b/internal/osbuild2/selinux_stage.go
@@ -5,8 +5,9 @@ package osbuild2
 // A file contexts configuration file is sepcified that describes
 // the filesystem labels to apply to the image.
 type SELinuxStageOptions struct {
-	FileContexts string            `json:"file_contexts"`
-	Labels       map[string]string `json:"labels,omitempty"`
+	FileContexts     string            `json:"file_contexts"`
+	Labels           map[string]string `json:"labels,omitempty"`
+	ForceAutorelabel *bool             `json:"force_autorelabel,omitempty"`
 }
 
 func (SELinuxStageOptions) isStageOptions() {}
diff --git a/internal/prometheus/http_metrics.go b/internal/prometheus/http_metrics.go
new file mode 100644
index 000000000..bcc5c21a2
--- /dev/null
+++ b/internal/prometheus/http_metrics.go
@@ -0,0 +1,49 @@
+package prometheus
+
+import (
+	"github.com/prometheus/client_golang/prometheus"
+	"github.com/prometheus/client_golang/prometheus/promauto"
+)
+
+const (
+	namespace = "image_builder"
+	subsystem = "composer"
+)
+
+var (
+	TotalRequests = promauto.NewCounter(prometheus.CounterOpts{
+		Name:      "total_requests",
+		Namespace: namespace,
+		Subsystem: subsystem,
+		Help:      "total number of http requests made to osbuild-composer",
+	})
+)
+
+var (
+	// update this to count all 500s
+	ComposeFailures = promauto.NewCounter(prometheus.CounterOpts{
+		Name:      "total_failed_compose_requests",
+		Namespace: namespace,
+		Subsystem: subsystem,
+		Help:      "total number of failed compose requests",
+	})
+)
+
+var (
+	ComposeRequests = promauto.NewCounter(prometheus.CounterOpts{
+		Name:      "total_compose_requests",
+		Namespace: namespace,
+		Subsystem: subsystem,
+		Help:      "total number of compose requests made to osbuild-composer",
+	})
+)
+
+var (
+	httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
+		Name:      "http_duration_seconds",
+		Namespace: namespace,
+		Subsystem: subsystem,
+		Help:      "Duration of HTTP requests.",
+		Buckets:   []float64{.025, .05, .075, .1, .2, .5, .75, 1, 1.5, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20},
+	}, []string{"path"})
+)
diff --git a/internal/prometheus/prometheus.go b/internal/prometheus/prometheus.go
deleted file mode 100644
index 8dbfd069e..000000000
--- a/internal/prometheus/prometheus.go
+++ /dev/null
@@ -1,42 +0,0 @@
-package prometheus
-
-import (
-	"github.com/prometheus/client_golang/prometheus"
-	"github.com/prometheus/client_golang/prometheus/promauto"
-)
-
-var (
-	TotalRequests = promauto.NewCounter(prometheus.CounterOpts{
-		Name: "composer_total_http_requests",
-		Help: "total number of http requests made to osbuild-composer",
-	})
-)
-
-var (
-	ComposeRequests = promauto.NewCounter(prometheus.CounterOpts{
-		Name: "total_compose_requests",
-		Help: "total number of compose requests made to osbuild-composer",
-	})
-)
-
-var (
-	ComposeSuccesses = promauto.NewCounter(prometheus.CounterOpts{
-		Name: "total_successful_compose_requests",
-		Help: "total number of successful compose requests",
-	})
-)
-
-var (
-	ComposeFailures = promauto.NewCounter(prometheus.CounterOpts{
-		Name: "total_failed_compose_requests",
-		Help: "total number of failed compose requests",
-	})
-)
-
-var (
-	httpDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
-		Name:    "composer_http_duration_seconds",
-		Help:    "Duration of HTTP requests.",
-		Buckets: []float64{.025, .05, .075, .1, .2, .5, .75, 1, 1.5, 2, 3, 4, 5, 6, 8, 10, 12, 14, 16, 20},
-	}, []string{"path"})
-)
diff --git a/internal/worker/server.go b/internal/worker/server.go
index c2c56e2e0..855296b3e 100644
--- a/internal/worker/server.go
+++ b/internal/worker/server.go
@@ -21,7 +21,6 @@ import (
 
 	"github.com/osbuild/osbuild-composer/internal/common"
 	"github.com/osbuild/osbuild-composer/internal/jobqueue"
-	"github.com/osbuild/osbuild-composer/internal/prometheus"
 	"github.com/osbuild/osbuild-composer/internal/worker/api"
 )
 
@@ -306,10 +305,6 @@ func (s *Server) FinishJob(token uuid.UUID, result json.RawMessage) error {
 		return fmt.Errorf("error finding job status: %v", err)
 	}
 
-	if jobResult.Success {
-		prometheus.ComposeSuccesses.Inc()
-	}
-
 	// Move artifacts from the temporary location to the final job
 	// location. Log any errors, but do not treat them as fatal. The job is
 	// already finished.
diff --git a/osbuild-composer.spec b/osbuild-composer.spec
index 87dde25aa..972dc6cf5 100644
--- a/osbuild-composer.spec
+++ b/osbuild-composer.spec
@@ -159,6 +159,7 @@ go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-image-te
 go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-auth-tests %{goipath}/cmd/osbuild-auth-tests
 go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-koji-tests %{goipath}/cmd/osbuild-koji-tests
 go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-composer-dbjobqueue-tests %{goipath}/cmd/osbuild-composer-dbjobqueue-tests
+go test -c -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-composer-manifest-tests %{goipath}/cmd/osbuild-composer-manifest-tests
 go build -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/cloud-cleaner %{goipath}/cmd/cloud-cleaner
 go build -tags=integration -ldflags="${TEST_LDFLAGS}" -o _bin/osbuild-mock-openid-provider %{goipath}/cmd/osbuild-mock-openid-provider
 
@@ -224,6 +225,7 @@ install -m 0755 -vp _bin/osbuild-image-tests                    %{buildroot}%{_l
 install -m 0755 -vp _bin/osbuild-auth-tests                     %{buildroot}%{_libexecdir}/osbuild-composer-test/
 install -m 0755 -vp _bin/osbuild-koji-tests                     %{buildroot}%{_libexecdir}/osbuild-composer-test/
 install -m 0755 -vp _bin/osbuild-composer-dbjobqueue-tests      %{buildroot}%{_libexecdir}/osbuild-composer-test/
+install -m 0755 -vp _bin/osbuild-composer-manifest-tests        %{buildroot}%{_libexecdir}/osbuild-composer-test/
 install -m 0755 -vp _bin/cloud-cleaner                          %{buildroot}%{_libexecdir}/osbuild-composer-test/
 install -m 0755 -vp _bin/osbuild-mock-openid-provider           %{buildroot}%{_libexecdir}/osbuild-composer-test/
 install -m 0755 -vp tools/define-compose-url.sh                 %{buildroot}%{_libexecdir}/osbuild-composer-test/
diff --git a/templates/composer.yml b/templates/composer.yml
index 032e91e3a..8fd025618 100644
--- a/templates/composer.yml
+++ b/templates/composer.yml
@@ -92,6 +92,8 @@ objects:
                 key: db.password
           - name: PGSSLMODE
             value: "${PGSSLMODE}"
+          - name: PGMAXCONNS
+            value: "${PGMAXCONNS}"
           ports:
           - name: composer-api
             protocol: TCP
@@ -229,6 +231,9 @@ parameters:
   - description: postgres sslmode to use when connecting to the db
     name: PGSSLMODE
     value: "require"
+  - description: postgres maximum connections per pod
+    name: PGMAXCONNS
+    value: "20"
   - description: base sso url
     name: SSO_BASE_URL
     required: true
diff --git a/templates/dashboards/grafana-dashboard-image-builder-composer-general.configmap.yml b/templates/dashboards/grafana-dashboard-image-builder-composer-general.configmap.yml
index ebe9cf19e..f61c4da70 100644
--- a/templates/dashboards/grafana-dashboard-image-builder-composer-general.configmap.yml
+++ b/templates/dashboards/grafana-dashboard-image-builder-composer-general.configmap.yml
@@ -130,7 +130,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "1 - sum(increase(total_failed_compose_requests[$__range]))/sum(increase(total_compose_requests[$__range]))",
+              "expr": "1 - sum(increase(image_builder_composer_total_failed_compose_requests[$__range]))/sum(increase(image_builder_composer_total_compose_requests[$__range]))",
               "interval": "",
               "legendFormat": "",
               "refId": "A"
@@ -187,7 +187,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "sum(increase(total_compose_requests[$__range]))",
+              "expr": "sum(increase(image_builder_composer_total_compose_requests[$__range]))",
               "interval": "",
               "legendFormat": "",
               "refId": "A"
@@ -267,7 +267,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "sum(increase(total_failed_compose_requests[$__range]))/sum(increase(total_compose_requests[$__range]))",
+              "expr": "sum(increase(image_builder_composer_total_failed_compose_requests[$__range]))/sum(increase(image_builder_composer_total_compose_requests[$__range]))",
               "interval": "",
               "legendFormat": "",
               "refId": "A"
@@ -361,7 +361,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "28 * 24 * (1 - $stability_slo) / ((sum(rate(total_failed_compose_requests[$__range]))/ sum(rate(total_compose_requests[$__range]))) + 0.001)",
+              "expr": "28 * 24 * (1 - $stability_slo) / ((sum(rate(image_builder_composer_total_failed_compose_requests[$__range]))/ sum(rate(image_builder_composer_total_compose_requests[$__range]))) + 0.001)",
               "format": "time_series",
               "interval": "",
               "intervalFactor": 1,
@@ -460,7 +460,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "1 - ((1 - sum(increase(total_failed_compose_requests[$__range]))/sum(increase(total_compose_requests[$__range]))) - $stability_slo)/ (1 - $stability_slo)",
+              "expr": "1 - ((1 - sum(increase(image_builder_composer_total_failed_compose_requests[$__range]))/sum(increase(image_builder_composer_total_compose_requests[$__range]))) - $stability_slo)/ (1 - $stability_slo)",
               "instant": false,
               "interval": "",
               "intervalFactor": 10,
@@ -566,7 +566,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "histogram_quantile(0.9, sum(rate(composer_http_duration_seconds_bucket[$__range])) by (le)) * 1000",
+              "expr": "histogram_quantile(0.9, sum(rate(image_builder_composer_http_duration_seconds_bucket[$__range])) by (le)) * 1000",
               "interval": "",
               "legendFormat": "",
               "refId": "A"
@@ -654,7 +654,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "histogram_quantile(0.9, sum(rate(composer_http_duration_seconds_bucket[$__range])) by (le)) * 1000",
+              "expr": "histogram_quantile(0.9, sum(rate(image_builder_composer_http_duration_seconds_bucket[$__range])) by (le)) * 1000",
               "interval": "",
               "legendFormat": "",
               "refId": "A"
@@ -748,7 +748,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "28 * 24 * (1 - $latency_slo) / (1 - sum(rate(composer_http_duration_seconds_bucket{le=\"0.2\"}[$__range]))/sum(rate(composer_http_duration_seconds_count[$__range])))",
+              "expr": "28 * 24 * (1 - $latency_slo) / (1 - sum(rate(image_builder_composer_http_duration_seconds_bucket{le=\"0.2\"}[$__range]))/sum(rate(image_builder_composer_http_duration_seconds_count[$__range])))",
               "format": "time_series",
               "interval": "",
               "intervalFactor": 1,
@@ -846,7 +846,7 @@ data:
           "targets": [
             {
               "exemplar": true,
-              "expr": "1 - ((sum(increase(composer_http_duration_seconds_bucket{le=\"0.2\"}[$__range]))/sum(increase(composer_http_duration_seconds_count[$__range]))) - $latency_slo)/ (1 - $latency_slo)",
+              "expr": "1 - ((sum(increase(image_builder_composer_http_duration_seconds_bucket{le=\"0.2\"}[$__range]))/sum(increase(image_builder_composer_http_duration_seconds_count[$__range]))) - $latency_slo)/ (1 - $latency_slo)",
               "instant": false,
               "interval": "",
               "intervalFactor": 10,


Test patch:
diff --git a/cmd/osbuild-composer-manifest-tests/main_test.go b/cmd/osbuild-composer-manifest-tests/main_test.go
new file mode 100644
index 000000000..850ba1689
--- /dev/null
+++ b/cmd/osbuild-composer-manifest-tests/main_test.go
@@ -0,0 +1,39 @@
+// +build integration
+
+package main
+
+import (
+	"flag"
+	"os"
+	"testing"
+
+	"github.com/osbuild/osbuild-composer/internal/distro/distro_test_common"
+	"github.com/osbuild/osbuild-composer/internal/distroregistry"
+	"github.com/stretchr/testify/require"
+)
+
+var manifestsPath string
+var dnfJsonPath string
+var testCaseGlob string
+
+func init() {
+	flag.StringVar(&manifestsPath, "manifests-path", "/usr/share/tests/osbuild-composer/manifests", "path to a directory with *.json files containing image test cases")
+	flag.StringVar(&dnfJsonPath, "dnf-json-path", "/usr/libexec/osbuild-composer/dnf-json", "path to the 'dnf-json' executable")
+	flag.StringVar(&testCaseGlob, "test-case-glob", "*", "glob pattern to select image test cases to verify")
+}
+
+func TestManifests(t *testing.T) {
+	cacheDirPath := "/var/tmp/osbuild-composer-manifest-tests/rpmmd"
+	err := os.MkdirAll(cacheDirPath, 0755)
+	require.Nilf(t, err, "failed to create RPMMD cache directory %q", cacheDirPath)
+
+	distro_test_common.TestDistro_Manifest(
+		t,
+		manifestsPath,
+		testCaseGlob,
+		distroregistry.NewDefault(),
+		true,
+		cacheDirPath,
+		dnfJsonPath,
+	)
+}
diff --git a/internal/distro/distro_test.go b/internal/distro/distro_test.go
index f2dcdcb35..be547ad58 100644
--- a/internal/distro/distro_test.go
+++ b/internal/distro/distro_test.go
@@ -16,6 +16,9 @@ func TestDistro_Manifest(t *testing.T) {
 		"../../test/data/manifests/",
 		"*",
 		distroregistry.NewDefault(),
+		false, // This test case does not check for changes in the imageType package sets!
+		"",
+		"",
 	)
 }
 
diff --git a/internal/distro/distro_test_common/distro_test_common.go b/internal/distro/distro_test_common/distro_test_common.go
index 295cf7947..6a1437be4 100644
--- a/internal/distro/distro_test_common/distro_test_common.go
+++ b/internal/distro/distro_test_common/distro_test_common.go
@@ -20,7 +20,7 @@ import (
 
 const RandomTestSeed = 0
 
-func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, registry *distroregistry.Registry) {
+func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, registry *distroregistry.Registry, depsolvePkgSets bool, dnfCacheDir, dnfJsonPath string) {
 	assert := assert.New(t)
 	fileNames, err := filepath.Glob(filepath.Join(pipelinePath, prefix))
 	assert.NoErrorf(err, "Could not read pipelines directory '%s': %v", pipelinePath, err)
@@ -41,9 +41,9 @@ func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, regis
 			Blueprint    *blueprint.Blueprint `json:"blueprint"`
 		}
 		var tt struct {
-			ComposeRequest *composeRequest                `json:"compose-request"`
-			PackageSets    map[string][]rpmmd.PackageSpec `json:"rpmmd"`
-			Manifest       distro.Manifest                `json:"manifest,omitempty"`
+			ComposeRequest  *composeRequest                `json:"compose-request"`
+			PackageSpecSets map[string][]rpmmd.PackageSpec `json:"rpmmd"`
+			Manifest        distro.Manifest                `json:"manifest,omitempty"`
 		}
 		file, err := ioutil.ReadFile(fileName)
 		assert.NoErrorf(err, "Could not read test-case '%s': %v", fileName, err)
@@ -82,6 +82,24 @@ func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, regis
 				t.Errorf("unknown image type: %v", tt.ComposeRequest.ImageType)
 				return
 			}
+
+			var imgPackageSpecSets map[string][]rpmmd.PackageSpec
+			// depsolve the image's package set to catch changes in the image's default package set.
+			// downside is that this takes long time
+			if depsolvePkgSets {
+				require.NotEmptyf(t, dnfCacheDir, "DNF cache directory path must be provided when chosen to depsolve image package sets")
+				require.NotEmptyf(t, dnfJsonPath, "path to 'dnf-json' must be provided when chosen to depsolve image package sets")
+				imgPackageSpecSets = getImageTypePkgSpecSets(
+					imageType,
+					*tt.ComposeRequest.Blueprint,
+					repos,
+					dnfCacheDir,
+					dnfJsonPath,
+				)
+			} else {
+				imgPackageSpecSets = tt.PackageSpecSets
+			}
+
 			got, err := imageType.Manifest(tt.ComposeRequest.Blueprint.Customizations,
 				distro.ImageOptions{
 					Size: imageType.Size(0),
@@ -90,7 +108,7 @@ func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, regis
 					},
 				},
 				repos,
-				tt.PackageSets,
+				imgPackageSpecSets,
 				RandomTestSeed)
 
 			if (err == nil && tt.Manifest == nil) || (err != nil && tt.Manifest != nil) {
@@ -111,6 +129,23 @@ func TestDistro_Manifest(t *testing.T, pipelinePath string, prefix string, regis
 	}
 }
 
+func getImageTypePkgSpecSets(imageType distro.ImageType, bp blueprint.Blueprint, repos []rpmmd.RepoConfig, cacheDir, dnfJsonPath string) map[string][]rpmmd.PackageSpec {
+	imgPackageSets := imageType.PackageSets(bp)
+
+	rpm_md := rpmmd.NewRPMMD(cacheDir, dnfJsonPath)
+
+	imgPackageSpecSets := make(map[string][]rpmmd.PackageSpec)
+	for name, packages := range imgPackageSets {
+		packageSpecs, _, err := rpm_md.Depsolve(packages, repos, imageType.Arch().Distro().ModulePlatformID(), imageType.Arch().Name(), imageType.Arch().Distro().Releasever())
+		if err != nil {
+			panic("Could not depsolve: " + err.Error())
+		}
+		imgPackageSpecSets[name] = packageSpecs
+	}
+
+	return imgPackageSpecSets
+}
+
 func isOSTree(imgType distro.ImageType) bool {
 	packageSets := imgType.PackageSets(blueprint.Blueprint{})
 	for _, pkg := range packageSets["build-packages"].Include {
diff --git a/internal/osbuild2/rhsm_stage_test.go b/internal/osbuild2/rhsm_stage_test.go
index 68867c763..49b8c9136 100644
--- a/internal/osbuild2/rhsm_stage_test.go
+++ b/internal/osbuild2/rhsm_stage_test.go
@@ -1,9 +1,12 @@
 package osbuild2
 
 import (
+	"encoding/json"
+	"reflect"
 	"testing"
 
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 )
 
 func TestNewRhsmStage(t *testing.T) {
@@ -14,3 +17,56 @@ func TestNewRhsmStage(t *testing.T) {
 	actualStage := NewRHSMStage(&RHSMStageOptions{})
 	assert.Equal(t, expectedStage, actualStage)
 }
+
+func TestRhsmStageJson(t *testing.T) {
+	tests := []struct {
+		Options    RHSMStageOptions
+		JsonString string
+	}{
+		{
+			Options: RHSMStageOptions{
+				YumPlugins: &RHSMStageOptionsDnfPlugins{
+					ProductID: &RHSMStageOptionsDnfPlugin{
+						Enabled: true,
+					},
+					SubscriptionManager: &RHSMStageOptionsDnfPlugin{
+						Enabled: false,
+					},
+				},
+			},
+			JsonString: `{"yum-plugins":{"product-id":{"enabled":true},"subscription-manager":{"enabled":false}}}`,
+		},
+		{
+			Options: RHSMStageOptions{
+				DnfPlugins: &RHSMStageOptionsDnfPlugins{
+					ProductID: &RHSMStageOptionsDnfPlugin{
+						Enabled: true,
+					},
+					SubscriptionManager: &RHSMStageOptionsDnfPlugin{
+						Enabled: false,
+					},
+				},
+			},
+			JsonString: `{"dnf-plugins":{"product-id":{"enabled":true},"subscription-manager":{"enabled":false}}}`,
+		},
+		{
+			Options: RHSMStageOptions{
+				SubMan: &RHSMStageOptionsSubMan{
+					Rhsm:      &SubManConfigRHSMSection{},
+					Rhsmcertd: &SubManConfigRHSMCERTDSection{},
+				},
+			},
+			JsonString: `{"subscription-manager":{"rhsm":{},"rhsmcertd":{}}}`,
+		},
+	}
+	for _, test := range tests {
+		marshaledJson, err := json.Marshal(test.Options)
+		require.NoError(t, err, "failed to marshal JSON")
+		require.Equal(t, string(marshaledJson), test.JsonString)
+
+		var jsonOptions RHSMStageOptions
+		err = json.Unmarshal([]byte(test.JsonString), &jsonOptions)
+		require.NoError(t, err, "failed to parse JSON")
+		require.True(t, reflect.DeepEqual(test.Options, jsonOptions))
+	}
+}
diff --git a/internal/osbuild2/stage_test.go b/internal/osbuild2/stage_test.go
index e31b96d5a..a9d8e3bfa 100644
--- a/internal/osbuild2/stage_test.go
+++ b/internal/osbuild2/stage_test.go
@@ -452,6 +452,18 @@ func TestStage_UnmarshalJSON(t *testing.T) {
 				data: []byte(`{"type":"org.osbuild.selinux","options":{"file_contexts":""}}`),
 			},
 		},
+		{
+			name: "selinux-force_autorelabel",
+			fields: fields{
+				Type: "org.osbuild.selinux",
+				Options: &SELinuxStageOptions{
+					ForceAutorelabel: common.BoolToPtr(true),
+				},
+			},
+			args: args{
+				data: []byte(`{"type":"org.osbuild.selinux","options":{"file_contexts":"","force_autorelabel":true}}`),
+			},
+		},
 		{
 			name: "selinux.config-empty",
 			fields: fields{
diff --git a/test/cases/api.sh b/test/cases/api.sh
index 6eed1240a..2b4bfdadb 100755
--- a/test/cases/api.sh
+++ b/test/cases/api.sh
@@ -79,6 +79,7 @@ pg_database = "osbuildcomposer"
 pg_user = "postgres"
 pg_password = "foobar"
 pg_ssl_mode = "disable"
+pg_max_conns = 10
 EOF
 
 sudo systemctl restart osbuild-composer
@@ -607,7 +608,7 @@ function collectMetrics(){
                           --cert /etc/osbuild-composer/client-crt.pem \
                           https://localhost/metrics)
 
-    echo "$METRICS_OUTPUT" | grep "^total_compose_requests" | cut -f2 -d' '
+    echo "$METRICS_OUTPUT" | grep "^image_builder_composer_total_compose_requests" | cut -f2 -d' '
 }
 
 function sendCompose() {
diff --git a/test/cases/manifest_tests.sh b/test/cases/manifest_tests.sh
new file mode 100755
index 000000000..da348af7b
--- /dev/null
+++ b/test/cases/manifest_tests.sh
@@ -0,0 +1,36 @@
+#!/bin/bash
+set -euo pipefail
+
+MANIFEST_TESTS_RUNNER="/usr/libexec/osbuild-composer-test/osbuild-composer-manifest-tests"
+DNF_JSON_PATH="/usr/libexec/osbuild-composer/dnf-json"
+IMAGE_TEST_CASES_PATH="/usr/share/tests/osbuild-composer/manifests"
+
+WORKING_DIRECTORY=/usr/libexec/osbuild-composer
+mkdir --parents /tmp/logs
+LOGS_DIRECTORY=$(mktemp --directory --tmpdir=/tmp/logs)
+
+# Print out a nice test divider so we know when tests stop and start.
+test_divider () {
+    printf "%0.s-" {1..78} && echo
+}
+
+# Provision the software under test.
+/usr/libexec/osbuild-composer-test/provision.sh
+
+# Change to the working directory.
+cd $WORKING_DIRECTORY
+
+# Run test case.
+TEST_NAME=$(basename "$MANIFEST_TESTS_RUNNER")
+echo
+test_divider
+echo "🏃🏻 Running test: ${TEST_NAME}"
+test_divider
+
+if sudo "$MANIFEST_TESTS_RUNNER" -test.v -manifests-path "$IMAGE_TEST_CASES_PATH" -dnf-json-path "$DNF_JSON_PATH" | tee "${LOGS_DIRECTORY}"/"${TEST_NAME}".log; then
+    echo "🎉  Test passed."
+    exit 0
+else
+    echo "🔥 Test failed."
+    exit 1
+fi
diff --git a/test/data/manifests/rhel_86-x86_64-image_installer-boot.json b/test/data/manifests/rhel_86-x86_64-image_installer-boot.json
index 954418837..467dd7ca7 100644
--- a/test/data/manifests/rhel_86-x86_64-image_installer-boot.json
+++ b/test/data/manifests/rhel_86-x86_64-image_installer-boot.json
@@ -683,6 +683,7 @@
                   "sha256:9b0634c2c2cedbd9072b0bc3a05f57b22bf3c7fe25fb414c0d140996ab3a2f59",
                   "sha256:fd9e5c379cd3482d32686fb13881827a39037e7a7afa92c62d58c1f05fcb797f",
                   "sha256:28ccf9ff472c824f6c5a3c2a0c076bfa221b8e48368e43de9b3c2e83d67e8b5d",
+                  "sha256:9fa50a4864795cfb8eba32bde7bc76abd2453d876c9884508d9d070e80c4cf09",
                   "sha256:6d7a41fb238610416349a53d024cc505ab7f3f6e9953cc2244abb663ec404dad",
                   "sha256:78b6dd926d2a1dadb07ca4513e017796a485f3ef64466d06037d4db07f797f10",
                   "sha256:62cea902bbf8da5f9ff08b186401f98b8d49779c74e7d93e511d3534f4c7fff0",
@@ -753,7 +754,6 @@
                   "sha256:5b1bc2ca63d563828a3a0968d42fb75ae0917366d06df8176d917f7c477f33b4",
                   "sha256:0fdeaf3c6214dd2c13aa75ef01198e7d792f9bb2fc447af013fc434cba94701d",
                   "sha256:6103a6b9eb69f8b79999371c124bdc21f1bedd64c8d67a73a06daf2f6307956f",
-                  "sha256:6ac86e716545bfde2c56ca9632aa35d211386a94251aecd44749f3998dbe4732",
                   "sha256:ca00963bae82fdd87827009ab2e1be386729f374f767ba40f9da1e4b4b2c71cb",
                   "sha256:1cffddb6923ef5fc16ff367f61fda1f25efeeee48707a5b775efd6606a0afee8",
                   "sha256:e53699b8142244c10df48394869ae2ff0f840db2403021a75d8d3d1f53a7c86d",
@@ -764,6 +764,7 @@
                   "sha256:d94ea399f82d4f9537af1098a588c5cc9a80454ba7c1de9b26dd11cb5c730d8a",
                   "sha256:b92bac878ce3117573c94a7f5e88eca3ba7765f40937e2540ee910fee7427d2e",
                   "sha256:db8bc154626bdd906a1f50104031a5042bbe91db7f5a1473657795eedd4158c6",
+                  "sha256:616b23d84d2c4f85463c1b72cf1fcc2c99eeac38e94ade7318a195072d139641",
                   "sha256:1ed3940c0466986fa38fe9d3bd5fc6370b5e62edba51f7a8359eab786b4b81ec",
                   "sha256:932cca0b2aa28d64538fca0401acc35bec34f14bfe99d3e22ea8452b79890eac",
                   "sha256:7f2436df92ce3dacaf5a52d988e65b2cbfc6af8be917bdc14119940480efd7bb",
@@ -809,6 +810,8 @@
                   "sha256:161ca65284b6051ed90bf8298c55f95e7ab17769eb29599a9bd4618d8eda8371",
                   "sha256:555925b62c734082a4a706ec44de44ada82e23f319472957ddc58ac5b1e9a2f3",
                   "sha256:176cd5cb58307c4a89ed986dbbcb765f306c08da3fa3fe2cb7b3e80076a3d7a9",
+                  "sha256:7f564d267644d0e24ea856599ab95dba3bbdd7a0fc6554c803185d771a12d8e6",
+                  "sha256:b4f1b695d96c86edffdc0996e2cfe78e343674ce3d8f42387412e34d5cb95fd8",
                   "sha256:ac0ee56d309e294b38d73e70715683e87779684f63d465ed9b01c1388571b753",
                   "sha256:a2dead854d6ba93925f9f8fe42ddc1a550a62a5c8873b16665a57f57cf3a104b",
                   "sha256:9cde9419c00e6f9f8904ee47b17c74136895f7735031ddc865406d08d6692078",
@@ -832,15 +835,17 @@
                   "sha256:c13683818b2e3f5a1bc0b4188c7680cadc9bc29e9ff3be6790b5adff632e666c",
                   "sha256:8450db29ac9604e8bd5ca8dfa2254138a933689bfb987f89d7faeeb5d49b22b5",
                   "sha256:43a4f1c39b2a8b212d50af73d0d510adfdc4ac61be8ecdc6bd718f6cab0e5afc",
+                  "sha256:aed1436b76055b10cc1f78fb6519687cdadf02bc53c440e792217986b7314eec",
                   "sha256:a842bbdfe4e3f24ef55acd0ed6930639ccaa5980a2774235bc4c6c2a95ab421c",
                   "sha256:468b540f98263d7b274c722a7b8f18ac1ab9d88783cfca6561c85e56b36afeee",
                   "sha256:2829ee7cd506bfadd391e04c6281fec277f2681e6b360bdbfc0305c48d429c3c",
                   "sha256:4e9ea2f28dc154e7b1f33e5be698ef2bb02991ca83927d88e9e8f813eb78c516",
                   "sha256:7d0bc4f2f78166013ef160ed10930a4902c7c5c6d6b7940fc900d36eaacc65a2",
                   "sha256:18fd9b2a61147367ad7d51798d33db38aedbaf761f3d0561c752f0048d1f4221",
+                  "sha256:8abcb3e48f4d92e1e311bf462968a3b9db429eca9fd70fbeae9222601b8dff93",
                   "sha256:19dba7cb30c3cb598886326df0ec1114c6e195a57c9ce3a8b78b83555e9e8648",
                   "sha256:c60aede8488f68a001f3495bd6e6d894fc3a44bb488f4550b5970ab5904d0a1e",
-                  "sha256:606a1f63731d99f3814dbcb232f63b4776d389c3301f702e2be15acac163be58",
+                  "sha256:b202816022b9cecdc4d34dc31f29146eee7de3a32d065be73e4c25adcd230484",
                   "sha256:2d3abde6a8de3e2b73933735daf067a57d627c43d90e65b7bb98cba4967bd2c5",
                   "sha256:15c69b314caf9b28ce6b50ab5d179448f8101b53839e01a34da0b3892d333af7",
                   "sha256:a260f793e49805b188908e2f30c4687abe4e023b20c28a85d10d2371556c3981",
@@ -860,8 +865,12 @@
                   "sha256:b3056b22b99fdf7a10647ab30a5c2af408216cf33c3be56653f51b85ca90cb86",
                   "sha256:995a5401cd86404d14d08c0aeafeaa8da3f540b1806f9d0e233d75dec9e45c74",
                   "sha256:2d7bb5cff7b7f741621d92e12e56d3a32143fee999ab96d4ce4b148bcb387a70",
+                  "sha256:a049cfb6609f54daf5413c44fa426a5bdc45c3f784a6c225924d70ae788c8bf0",
                   "sha256:39e6bc1e8101e536066554702d5d6b25f8cad359fb5e02ac598cfdad56eafb6d",
                   "sha256:25b13ea50e21233dc5fccf42da344fbf24605dde38db9b94e49739ae39faa072",
+                  "sha256:707db58b819782033d3480e945757601463b18804567ea6d6f3683742cf1e922",
+                  "sha256:a8a81d5523311634b3bb27a737c7646e5d9b464fff1c0e7b7d78994711b6301d",
+                  "sha256:a771c776f1e8bdf82bd2db42b39df6fc3f74ed92e37234a280441c44c1f48549",
                   "sha256:52aed1bbd2aa4041e599a453a9c4323775b26d2b1326ffb98ac6febbcab8c230",
                   "sha256:17b847a40817f2d3daead8c90aa4345c81964ca599c95abf02fbf91f7cd56612",
                   "sha256:594828a378b02e5cc08a4928382b54ec2b909098ae5bc084118e07bda873e6a4",
@@ -878,12 +887,19 @@
                   "sha256:8caac6d04fc98a82d17af56a8faacd1e1a019112ba207388fb82ffdd6df54301",
                   "sha256:4229196b5ea88c1133d5509a2ec326093a2c7ac5566ca4abb55c3d6fab47130a",
                   "sha256:59bf7b92f9eecb7868e960dc05c269a9df088d2dc71ce85cf77bfad68e206f0b",
+                  "sha256:4d1f1a45a34e3eab4b663c895b8378a3b672fd408b3d67a31c522f1661fc98f3",
+                  "sha256:58cf5aa3c5b3f7bed1433b33818fb6327ec4d6cebe3772c99249e19bb14a8c03",
+                  "sha256:e868499743c399baa6463fa64a2534a7d32f8e1cca7b1b47ec00c60b34250bfe",
+                  "sha256:53d3c15711e89c48416a7e134576b62abfb8bdbdfc5db0e65bd423f4bfa8e428",
                   "sha256:b50ed1c4095445fbb87d3f3b21abad7ace7fb2cbbac8f38e19b7f1e0caf28b4d",
+                  "sha256:e1382a5e1960353d613f453853e614ec9a66854119eefa0b3ddf19c5d9fcdce3",
                   "sha256:dc1ae7a1011705164487dae39f656665a6b18d8c36cd402bd9328825ba473c2b",
                   "sha256:fd75c594f871a3353d326833e630ea1d28e5f446f796b836dc628f8c9c039f88",
                   "sha256:534bbf990d0f0537715561c818c2b68f10e6ba0cc1252a32a0696f1e22fde1e3",
                   "sha256:3ded289944ae1be6daded7105456bcb8508f155cc7fd2807e546b2fe32f9b002",
+                  "sha256:ee2ba576f07f5cdd9cf24e788d60071869107aa313addbba0a311448bb32a86c",
                   "sha256:368acce07c86b55fc3966acdab9e553bbeab0e76945cbf7f2acdb95ea3a768d2",
+                  "sha256:e4e5b28586c8d57f26a6df5371310c19468145f0189ad97c72c55b425e696294",
                   "sha256:d304564f7e38550253add8e4ac68ebac32f7f0857b39e976df2a410c0cd2b7ef",
                   "sha256:c7b4850fa0c575c67d7a4a90dd78045c0de7b29045e9710d0a90dc7f028336d2",
                   "sha256:85593c98340382805a432f9ebac83f5e2d1e6737ed24f60f7889e5d79b1346ad",
@@ -2029,8 +2045,6 @@
                 "systemd-initrd",
                 "modsign",
                 "nss-softokn",
-                "rdma",
-                "rngd",
                 "i18n",
                 "convertfs",
                 "network-manager",
@@ -2050,14 +2064,8 @@
                 "livenet",
                 "lvm",
                 "mdraid",
-                "multipath",
                 "qemu",
                 "qemu-net",
-                "fcoe",
-                "fcoe-uefi",
-                "iscsi",
-                "lunmask",
-                "nfs",
                 "resume",
                 "rootfs-block",
                 "terminfo",
@@ -2071,7 +2079,15 @@
                 "shutdown",
                 "uefi-lib",
                 "biosdevname",
-                "anaconda"
+                "anaconda",
+                "rdma",
+                "rngd",
+                "multipath",
+                "fcoe",
+                "fcoe-uefi",
+                "iscsi",
+                "lunmask",
+                "nfs"
               ],
               "install": [
                 "/.buildstamp"
@@ -3238,9 +3254,6 @@
           "sha256:6050aeaf727c3cb9f43bbe2aeed45c946c2ceefe9531e035189f5b849610b82a": {
             "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-rpm-macros-3-41.el8.noarch.rpm"
           },
-          "sha256:606a1f63731d99f3814dbcb232f63b4776d389c3301f702e2be15acac163be58": {
-            "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/insights-client-3.1.5-1.el8.noarch.rpm"
-          },
           "sha256:60db56b8dd41774e97b9cd8cef8649493c576e3e9ea10fcfa73b8a8f16550ad8": {
             "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-cpio-0.1-29.el8.noarch.rpm"
           },
@@ -3349,9 +3362,6 @@
           "sha256:6aab23e22ca99314106df2068464bec8a2d78cf59cb1335ae9b63b3a06e808f8": {
             "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/openssl-1.1.1k-4.el8.x86_64.rpm"
           },
-          "sha256:6ac86e716545bfde2c56ca9632aa35d211386a94251aecd44749f3998dbe4732": {
-            "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/python3-magic-5.33-20.el8.noarch.rpm"
-          },
           "sha256:6b52102af0aab3b41a5d410b7717713aef3adc48c41015a745c9c5a2ba7b814f": {
             "url": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/libdb-utils-5.3.28-42.el8_4.x86_64.rpm"
           },
@@ -19123,6 +19133,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/mpfr-3.1.6-1.el8.x86_64.rpm",
         "checksum": "sha256:28ccf9ff472c824f6c5a3c2a0c076bfa221b8e48368e43de9b3c2e83d67e8b5d"
       },
+      {
+        "name": "mtools",
+        "epoch": 0,
+        "version": "4.0.18",
+        "release": "14.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/mtools-4.0.18-14.el8.x86_64.rpm",
+        "checksum": "sha256:9fa50a4864795cfb8eba32bde7bc76abd2453d876c9884508d9d070e80c4cf09"
+      },
       {
         "name": "ncurses",
         "epoch": 0,
@@ -19753,15 +19772,6 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/python3-linux-procfs-0.6.3-1.el8.noarch.rpm",
         "checksum": "sha256:6103a6b9eb69f8b79999371c124bdc21f1bedd64c8d67a73a06daf2f6307956f"
       },
-      {
-        "name": "python3-magic",
-        "epoch": 0,
-        "version": "5.33",
-        "release": "20.el8",
-        "arch": "noarch",
-        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/python3-magic-5.33-20.el8.noarch.rpm",
-        "checksum": "sha256:6ac86e716545bfde2c56ca9632aa35d211386a94251aecd44749f3998dbe4732"
-      },
       {
         "name": "python3-nftables",
         "epoch": 1,
@@ -19852,6 +19862,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/python3-setools-4.3.0-2.el8.x86_64.rpm",
         "checksum": "sha256:db8bc154626bdd906a1f50104031a5042bbe91db7f5a1473657795eedd4158c6"
       },
+      {
+        "name": "python3-setuptools",
+        "epoch": 0,
+        "version": "39.2.0",
+        "release": "6.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/python3-setuptools-39.2.0-6.el8.noarch.rpm",
+        "checksum": "sha256:616b23d84d2c4f85463c1b72cf1fcc2c99eeac38e94ade7318a195072d139641"
+      },
       {
         "name": "python3-setuptools-wheel",
         "epoch": 0,
@@ -20257,6 +20276,24 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/sudo-1.8.29-7.el8.x86_64.rpm",
         "checksum": "sha256:176cd5cb58307c4a89ed986dbbcb765f306c08da3fa3fe2cb7b3e80076a3d7a9"
       },
+      {
+        "name": "syslinux",
+        "epoch": 0,
+        "version": "6.04",
+        "release": "5.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/syslinux-6.04-5.el8.x86_64.rpm",
+        "checksum": "sha256:7f564d267644d0e24ea856599ab95dba3bbdd7a0fc6554c803185d771a12d8e6"
+      },
+      {
+        "name": "syslinux-nonlinux",
+        "epoch": 0,
+        "version": "6.04",
+        "release": "5.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/syslinux-nonlinux-6.04-5.el8.noarch.rpm",
+        "checksum": "sha256:b4f1b695d96c86edffdc0996e2cfe78e343674ce3d8f42387412e34d5cb95fd8"
+      },
       {
         "name": "systemd",
         "epoch": 0,
@@ -20464,6 +20501,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-baseos-n8.6-20210930/Packages/zlib-1.2.11-17.el8.x86_64.rpm",
         "checksum": "sha256:43a4f1c39b2a8b212d50af73d0d510adfdc4ac61be8ecdc6bd718f6cab0e5afc"
       },
+      {
+        "name": "GConf2",
+        "epoch": 0,
+        "version": "3.2.6",
+        "release": "22.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/GConf2-3.2.6-22.el8.x86_64.rpm",
+        "checksum": "sha256:aed1436b76055b10cc1f78fb6519687cdadf02bc53c440e792217986b7314eec"
+      },
       {
         "name": "PackageKit",
         "epoch": 0,
@@ -20518,6 +20564,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/cairo-gobject-1.15.12-3.el8.x86_64.rpm",
         "checksum": "sha256:18fd9b2a61147367ad7d51798d33db38aedbaf761f3d0561c752f0048d1f4221"
       },
+      {
+        "name": "genisoimage",
+        "epoch": 0,
+        "version": "1.1.11",
+        "release": "39.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/genisoimage-1.1.11-39.el8.x86_64.rpm",
+        "checksum": "sha256:8abcb3e48f4d92e1e311bf462968a3b9db429eca9fd70fbeae9222601b8dff93"
+      },
       {
         "name": "geolite2-city",
         "epoch": 0,
@@ -20537,13 +20592,13 @@
         "checksum": "sha256:c60aede8488f68a001f3495bd6e6d894fc3a44bb488f4550b5970ab5904d0a1e"
       },
       {
-        "name": "insights-client",
-        "epoch": 0,
-        "version": "3.1.5",
-        "release": "1.el8",
-        "arch": "noarch",
-        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/insights-client-3.1.5-1.el8.noarch.rpm",
-        "checksum": "sha256:606a1f63731d99f3814dbcb232f63b4776d389c3301f702e2be15acac163be58"
+        "name": "isomd5sum",
+        "epoch": 1,
+        "version": "1.2.3",
+        "release": "3.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/isomd5sum-1.2.3-3.el8.x86_64.rpm",
+        "checksum": "sha256:b202816022b9cecdc4d34dc31f29146eee7de3a32d065be73e4c25adcd230484"
       },
       {
         "name": "libX11",
@@ -20716,6 +20771,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/libudisks2-2.9.0-7.el8.x86_64.rpm",
         "checksum": "sha256:2d7bb5cff7b7f741621d92e12e56d3a32143fee999ab96d4ce4b148bcb387a70"
       },
+      {
+        "name": "libusal",
+        "epoch": 0,
+        "version": "1.1.11",
+        "release": "39.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/libusal-1.1.11-39.el8.x86_64.rpm",
+        "checksum": "sha256:a049cfb6609f54daf5413c44fa426a5bdc45c3f784a6c225924d70ae788c8bf0"
+      },
       {
         "name": "libxcb",
         "epoch": 0,
@@ -20734,6 +20798,33 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/libxkbcommon-0.9.1-1.el8.x86_64.rpm",
         "checksum": "sha256:25b13ea50e21233dc5fccf42da344fbf24605dde38db9b94e49739ae39faa072"
       },
+      {
+        "name": "lorax",
+        "epoch": 0,
+        "version": "28.14.62",
+        "release": "1.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/lorax-28.14.62-1.el8.x86_64.rpm",
+        "checksum": "sha256:707db58b819782033d3480e945757601463b18804567ea6d6f3683742cf1e922"
+      },
+      {
+        "name": "lorax-templates-generic",
+        "epoch": 0,
+        "version": "28.14.62",
+        "release": "1.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/lorax-templates-generic-28.14.62-1.el8.x86_64.rpm",
+        "checksum": "sha256:a8a81d5523311634b3bb27a737c7646e5d9b464fff1c0e7b7d78994711b6301d"
+      },
+      {
+        "name": "lorax-templates-rhel",
+        "epoch": 0,
+        "version": "8.5",
+        "release": "2.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/lorax-templates-rhel-8.5-2.el8.noarch.rpm",
+        "checksum": "sha256:a771c776f1e8bdf82bd2db42b39df6fc3f74ed92e37234a280441c44c1f48549"
+      },
       {
         "name": "nspr",
         "epoch": 0,
@@ -20878,6 +20969,42 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-jsonschema-2.6.0-4.el8.noarch.rpm",
         "checksum": "sha256:59bf7b92f9eecb7868e960dc05c269a9df088d2dc71ce85cf77bfad68e206f0b"
       },
+      {
+        "name": "python3-kickstart",
+        "epoch": 0,
+        "version": "3.16.14",
+        "release": "1.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-kickstart-3.16.14-1.el8.noarch.rpm",
+        "checksum": "sha256:4d1f1a45a34e3eab4b663c895b8378a3b672fd408b3d67a31c522f1661fc98f3"
+      },
+      {
+        "name": "python3-mako",
+        "epoch": 0,
+        "version": "1.0.6",
+        "release": "13.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-mako-1.0.6-13.el8.noarch.rpm",
+        "checksum": "sha256:58cf5aa3c5b3f7bed1433b33818fb6327ec4d6cebe3772c99249e19bb14a8c03"
+      },
+      {
+        "name": "python3-markupsafe",
+        "epoch": 0,
+        "version": "0.23",
+        "release": "19.el8",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-markupsafe-0.23-19.el8.x86_64.rpm",
+        "checksum": "sha256:e868499743c399baa6463fa64a2534a7d32f8e1cca7b1b47ec00c60b34250bfe"
+      },
+      {
+        "name": "python3-ordered-set",
+        "epoch": 0,
+        "version": "2.0.2",
+        "release": "4.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-ordered-set-2.0.2-4.el8.noarch.rpm",
+        "checksum": "sha256:53d3c15711e89c48416a7e134576b62abfb8bdbdfc5db0e65bd423f4bfa8e428"
+      },
       {
         "name": "python3-pexpect",
         "epoch": 0,
@@ -20887,6 +21014,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-pexpect-4.3.1-3.el8.noarch.rpm",
         "checksum": "sha256:b50ed1c4095445fbb87d3f3b21abad7ace7fb2cbbac8f38e19b7f1e0caf28b4d"
       },
+      {
+        "name": "python3-pip",
+        "epoch": 0,
+        "version": "9.0.3",
+        "release": "20.el8",
+        "arch": "noarch",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-pip-9.0.3-20.el8.noarch.rpm",
+        "checksum": "sha256:e1382a5e1960353d613f453853e614ec9a66854119eefa0b3ddf19c5d9fcdce3"
+      },
       {
         "name": "python3-ptyprocess",
         "epoch": 0,
@@ -20923,6 +21059,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python3-unbound-1.7.3-17.el8.x86_64.rpm",
         "checksum": "sha256:3ded289944ae1be6daded7105456bcb8508f155cc7fd2807e546b2fe32f9b002"
       },
+      {
+        "name": "python36",
+        "epoch": 0,
+        "version": "3.6.8",
+        "release": "38.module+el8.5.0+12207+5c5719bc",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/python36-3.6.8-38.module+el8.5.0+12207+5c5719bc.x86_64.rpm",
+        "checksum": "sha256:ee2ba576f07f5cdd9cf24e788d60071869107aa313addbba0a311448bb32a86c"
+      },
       {
         "name": "qemu-guest-agent",
         "epoch": 15,
@@ -20932,6 +21077,15 @@
         "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/qemu-guest-agent-6.1.0-1.module+el8.6.0+12648+6ede71a5.x86_64.rpm",
         "checksum": "sha256:368acce07c86b55fc3966acdab9e553bbeab0e76945cbf7f2acdb95ea3a768d2"
       },
+      {
+        "name": "qemu-img",
+        "epoch": 15,
+        "version": "6.1.0",
+        "release": "1.module+el8.6.0+12648+6ede71a5",
+        "arch": "x86_64",
+        "remote_location": "https://rpmrepo.osbuild.org/v2/mirror/rhvpn/el8/el8-x86_64-appstream-n8.6-20210930/Packages/qemu-img-6.1.0-1.module+el8.6.0+12648+6ede71a5.x86_64.rpm",
+        "checksum": "sha256:e4e5b28586c8d57f26a6df5371310c19468145f0189ad97c72c55b425e696294"
+      },
       {
         "name": "rhc",
         "epoch": 1,