diff --git a/pkg/manifest/anaconda_installer.go b/pkg/manifest/anaconda_installer.go index cdb13dabe1..9dee21a67b 100644 --- a/pkg/manifest/anaconda_installer.go +++ b/pkg/manifest/anaconda_installer.go @@ -256,9 +256,17 @@ func (p *AnacondaInstaller) serialize() (osbuild.Pipeline, error) { if p.InteractiveDefaults != nil { return osbuild.Pipeline{}, fmt.Errorf("anaconda installer type live does not support interactive defaults") } - pipeline.AddStages(p.liveStages()...) + liveStages, err := p.liveStages() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("live stages generation failed: %w", err) + } + pipeline.AddStages(liveStages...) case AnacondaInstallerTypePayload, AnacondaInstallerTypeNetinst: - pipeline.AddStages(p.payloadStages()...) + payloadStages, err := p.payloadStages() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("payload stages generation failed: %w", err) + } + pipeline.AddStages(payloadStages...) default: return osbuild.Pipeline{}, fmt.Errorf("invalid anaconda installer type") } @@ -273,7 +281,7 @@ func (p *AnacondaInstaller) serialize() (osbuild.Pipeline, error) { // - Generic initrd with support for the boot iso // - SELinux in permissive mode // - Default Anaconda kickstart (optional) -func (p *AnacondaInstaller) payloadStages() []*osbuild.Stage { +func (p *AnacondaInstaller) payloadStages() ([]*osbuild.Stage, error) { stages := make([]*osbuild.Stage, 0) installUID := 0 @@ -318,7 +326,10 @@ func (p *AnacondaInstaller) payloadStages() []*osbuild.Stage { })) // Create a generic initrd suitable for booting Anaconda and activating supported hardware - dracutOptions := p.dracutStageOptions() + dracutOptions, err := p.dracutStageOptions() + if err != nil { + return nil, fmt.Errorf("cannot get dracut stage options: %w", err) + } stages = append(stages, osbuild.NewDracutStage(dracutOptions)) stages = append(stages, osbuild.NewSELinuxConfigStage(&osbuild.SELinuxConfigStageOptions{State: osbuild.SELinuxStatePermissive})) @@ -327,7 +338,7 @@ func (p *AnacondaInstaller) payloadStages() []*osbuild.Stage { // stage setting SELinux to permissive. It's an error to set it to anything // that isn't an empty string if p.SELinux != "" { - panic("payload installers do not support SELinux policies") + return nil, fmt.Errorf("payload installers do not support SELinux policies (got policy %q)", p.SELinux) } if p.InteractiveDefaults != nil { @@ -345,13 +356,13 @@ func (p *AnacondaInstaller) payloadStages() []*osbuild.Stage { ) if err != nil { - panic(fmt.Sprintf("failed to create kickstart stage options for interactive defaults: %v", err)) + return nil, fmt.Errorf("failed to create kickstart stage options for interactive defaults: %w", err) } stages = append(stages, osbuild.NewKickstartStage(kickstartOptions)) } - return stages + return stages, nil } // liveStages creates the stages needed to boot a live image with Anaconda installed @@ -361,7 +372,7 @@ func (p *AnacondaInstaller) payloadStages() []*osbuild.Stage { // - Generic initrd with support for the boot iso // - SELinux in permissive mode // - Default Anaconda kickstart (optional) -func (p *AnacondaInstaller) liveStages() []*osbuild.Stage { +func (p *AnacondaInstaller) liveStages() ([]*osbuild.Stage, error) { stages := make([]*osbuild.Stage, 0) usersStageOptions := &osbuild.UsersStageOptions{ @@ -384,7 +395,7 @@ func (p *AnacondaInstaller) liveStages() []*osbuild.Stage { livesysFile, err := fsnode.NewFile("/etc/sysconfig/livesys", &livesysMode, "root", "root", []byte("livesys_session=\"gnome\"")) if err != nil { - panic(err) + return nil, err } p.Files = []*fsnode.File{livesysFile} @@ -392,7 +403,10 @@ func (p *AnacondaInstaller) liveStages() []*osbuild.Stage { stages = append(stages, osbuild.GenFileNodesStages(p.Files)...) // Create a generic initrd suitable for booting the live iso and activating supported hardware - dracutOptions := p.dracutStageOptions() + dracutOptions, err := p.dracutStageOptions() + if err != nil { + return nil, fmt.Errorf("cannot get dracut stage options: %w", err) + } stages = append(stages, osbuild.NewDracutStage(dracutOptions)) if p.SELinux != "" { @@ -401,7 +415,7 @@ func (p *AnacondaInstaller) liveStages() []*osbuild.Stage { })) } - return stages + return stages, nil } // dracutStageOptions returns the basic dracut setup with anaconda support @@ -412,7 +426,7 @@ func (p *AnacondaInstaller) liveStages() []*osbuild.Stage { // only add what is needed to support the boot iso and anaconda. When new // hardware support is needed in the inird it just needs to be added to dracut, // not everything that uses dracut (eg. anaconda, lorax, osbuild). -func (p *AnacondaInstaller) dracutStageOptions() *osbuild.DracutStageOptions { +func (p *AnacondaInstaller) dracutStageOptions() (*osbuild.DracutStageOptions, error) { // Common settings options := osbuild.DracutStageOptions{ Kernel: []string{p.kernelVer}, @@ -452,10 +466,10 @@ func (p *AnacondaInstaller) dracutStageOptions() *osbuild.DracutStageOptions { "convertfs", }...) default: - panic(fmt.Errorf("unknown AnacondaInstallerType %v in dracutStageOptions", p.Type)) + return nil, fmt.Errorf("unknown AnacondaInstallerType %v in dracutStageOptions", p.Type) } - return &options + return &options, nil } func (p *AnacondaInstaller) Platform() platform.Platform { diff --git a/pkg/manifest/anaconda_installer_iso_tree.go b/pkg/manifest/anaconda_installer_iso_tree.go index 26e06414b1..7f1b742f80 100644 --- a/pkg/manifest/anaconda_installer_iso_tree.go +++ b/pkg/manifest/anaconda_installer_iso_tree.go @@ -240,7 +240,7 @@ var installerBootExcludePaths = []string{ // NewSquashfsStage returns an osbuild stage configured to build // the squashfs root filesystem for the ISO. -func (p *AnacondaInstallerISOTree) NewSquashfsStage() *osbuild.Stage { +func (p *AnacondaInstallerISOTree) NewSquashfsStage() (*osbuild.Stage, error) { var squashfsOptions osbuild.SquashfsStageOptions switch p.anacondaPipeline.Type { @@ -254,7 +254,7 @@ func (p *AnacondaInstallerISOTree) NewSquashfsStage() *osbuild.Stage { } default: // Shouldn't be possible, but catch it anyway - panic(fmt.Errorf("unknown AnacondaInstallerType %v in NewSquashfsStage", p.anacondaPipeline.Type)) + return nil, fmt.Errorf("unknown AnacondaInstallerType %v in NewSquashfsStage", p.anacondaPipeline.Type) } if p.RootfsCompression != "" { @@ -276,14 +276,14 @@ func (p *AnacondaInstallerISOTree) NewSquashfsStage() *osbuild.Stage { // The iso's rootfs can either be an ext4 filesystem compressed with squashfs, or // a squashfs of the plain directory tree if p.RootfsType == SquashfsExt4Rootfs && p.rootfsPipeline != nil { - return osbuild.NewSquashfsStage(&squashfsOptions, p.rootfsPipeline.Name()) + return osbuild.NewSquashfsStage(&squashfsOptions, p.rootfsPipeline.Name()), nil } - return osbuild.NewSquashfsStage(&squashfsOptions, p.anacondaPipeline.Name()) + return osbuild.NewSquashfsStage(&squashfsOptions, p.anacondaPipeline.Name()), nil } // NewErofsStage returns an osbuild stage configured to build // the erofs root filesystem for the ISO. -func (p *AnacondaInstallerISOTree) NewErofsStage() *osbuild.Stage { +func (p *AnacondaInstallerISOTree) NewErofsStage() (*osbuild.Stage, error) { var erofsOptions osbuild.ErofsStageOptions switch p.anacondaPipeline.Type { @@ -297,7 +297,7 @@ func (p *AnacondaInstallerISOTree) NewErofsStage() *osbuild.Stage { } default: // Shouldn't be possible, but catch it anyway - panic(fmt.Errorf("unknown AnacondaInstallerType %v in NewErofsStage", p.anacondaPipeline.Type)) + return nil, fmt.Errorf("unknown AnacondaInstallerType %v in NewErofsStage", p.anacondaPipeline.Type) } var compression osbuild.ErofsCompression @@ -315,7 +315,7 @@ func (p *AnacondaInstallerISOTree) NewErofsStage() *osbuild.Stage { // Clean up the root filesystem's /boot to save space erofsOptions.ExcludePaths = installerBootExcludePaths - return osbuild.NewErofsStage(&erofsOptions, p.anacondaPipeline.Name()) + return osbuild.NewErofsStage(&erofsOptions, p.anacondaPipeline.Name()), nil } func (p *AnacondaInstallerISOTree) serializeStart(inputs Inputs) error { @@ -434,9 +434,17 @@ func (p *AnacondaInstallerISOTree) serialize() (osbuild.Pipeline, error) { // Add the selected roofs stage switch p.RootfsType { case SquashfsExt4Rootfs, SquashfsRootfs: - pipeline.AddStage(p.NewSquashfsStage()) + stage, err := p.NewSquashfsStage() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("cannot create squashfs stage: %w", err) + } + pipeline.AddStage(stage) case ErofsRootfs: - pipeline.AddStage(p.NewErofsStage()) + stage, err := p.NewErofsStage() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("cannot create erofs stage: %w", err) + } + pipeline.AddStage(stage) default: } @@ -516,11 +524,23 @@ func (p *AnacondaInstallerISOTree) serialize() (osbuild.Pipeline, error) { // the following pipelines are only relevant for payload installers switch { case p.ostreeCommitSpec != nil: - pipeline.AddStages(p.ostreeCommitStages()...) + ostreeCommitStages, err := p.ostreeCommitStages() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("cannot create ostree commit stages: %w", err) + } + pipeline.AddStages(ostreeCommitStages...) case p.containerSpec != nil: - pipeline.AddStages(p.ostreeContainerStages()...) + ostreeContainerStages, err := p.ostreeContainerStages() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("cannot create ostree container stages: %w", err) + } + pipeline.AddStages(ostreeContainerStages...) case p.OSPipeline != nil: - pipeline.AddStages(p.tarPayloadStages()...) + tarPayloadStages, err := p.tarPayloadStages() + if err != nil { + return osbuild.Pipeline{}, fmt.Errorf("cannot create ostree container stages: %w", err) + } + pipeline.AddStages(tarPayloadStages...) default: // this should have been caught at the top of the function, but // let's check again in case we refactor the function. @@ -536,7 +556,7 @@ func (p *AnacondaInstallerISOTree) serialize() (osbuild.Pipeline, error) { return pipeline, nil } -func (p *AnacondaInstallerISOTree) ostreeCommitStages() []*osbuild.Stage { +func (p *AnacondaInstallerISOTree) ostreeCommitStages() ([]*osbuild.Stage, error) { stages := make([]*osbuild.Stage, 0) // Set up the payload ostree repo @@ -547,11 +567,11 @@ func (p *AnacondaInstallerISOTree) ostreeCommitStages() []*osbuild.Stage { )) if p.Kickstart == nil { - panic(fmt.Sprintf("Kickstart options not set for %s pipeline", p.name)) + return nil, fmt.Errorf("Kickstart options not set for %s pipeline", p.name) } if p.Kickstart.OSTree == nil { - panic(fmt.Sprintf("Kickstart ostree options not set for %s pipeline", p.name)) + return nil, fmt.Errorf("Kickstart ostree options not set for %s pipeline", p.name) } // Configure the kickstart file with the payload and any user options kickstartOptions, err := osbuild.NewKickstartStageOptionsWithOSTreeCommit( @@ -564,15 +584,19 @@ func (p *AnacondaInstallerISOTree) ostreeCommitStages() []*osbuild.Stage { p.Kickstart.OSTree.OSName) if err != nil { - panic(fmt.Sprintf("failed to create kickstart stage options: %v", err)) + return nil, fmt.Errorf("failed to create kickstart stage options: %w", err) } - stages = append(stages, p.makeKickstartStages(kickstartOptions)...) + kickstartStages, err := p.makeKickstartStages(kickstartOptions) + if err != nil { + return nil, fmt.Errorf("cannot create kickstart stages: %w", err) + } + stages = append(stages, kickstartStages...) - return stages + return stages, nil } -func (p *AnacondaInstallerISOTree) ostreeContainerStages() []*osbuild.Stage { +func (p *AnacondaInstallerISOTree) ostreeContainerStages() ([]*osbuild.Stage, error) { stages := make([]*osbuild.Stage, 0) image := osbuild.NewContainersInputForSingleSource(*p.containerSpec) @@ -596,15 +620,19 @@ func (p *AnacondaInstallerISOTree) ostreeContainerStages() []*osbuild.Stage { } stages = append(stages, skopeoStage) - stages = append(stages, p.bootcInstallerKickstartStages()...) - return stages + kickstartStages, err := p.bootcInstallerKickstartStages() + if err != nil { + return nil, fmt.Errorf("cannot generate bootc installer kickstart stages: %w", err) + } + stages = append(stages, kickstartStages...) + return stages, nil } // bootcInstallerKickstartStages sets up kickstart-related stages for Anaconda // ISOs that install a bootc bootable container. -func (p *AnacondaInstallerISOTree) bootcInstallerKickstartStages() []*osbuild.Stage { +func (p *AnacondaInstallerISOTree) bootcInstallerKickstartStages() ([]*osbuild.Stage, error) { if p.Kickstart == nil { - panic(fmt.Sprintf("Kickstart options not set for %s pipeline", p.name)) + return nil, fmt.Errorf("Kickstart options not set for %s pipeline", p.name) } stages := make([]*osbuild.Stage, 0) @@ -619,7 +647,7 @@ func (p *AnacondaInstallerISOTree) bootcInstallerKickstartStages() []*osbuild.St "", "") if err != nil { - panic(fmt.Sprintf("failed to create kickstart stage options: %v", err)) + return nil, fmt.Errorf("failed to create kickstart stage options: %w", err) } // Workaround for lack of --target-imgref in Anaconda, xref https://github.com/osbuild/images/issues/380 @@ -638,7 +666,7 @@ func (p *AnacondaInstallerISOTree) bootcInstallerKickstartStages() []*osbuild.St // kickstart.New() already validates the options but they may have been // modified since then, so validate them before we create the stages if err := p.Kickstart.Validate(); err != nil { - panic(err) + return nil, err } if p.Kickstart.UserFile != nil { @@ -649,10 +677,10 @@ func (p *AnacondaInstallerISOTree) bootcInstallerKickstartStages() []*osbuild.St stages = append(stages, osbuild.NewKickstartStage(kickstartOptions)) kickstartFile, err := kickstartOptions.IncludeRaw(p.Kickstart.UserFile.Contents) if err != nil { - panic(err) + return nil, err } p.Files = append(p.Files, kickstartFile) - return append(stages, osbuild.GenFileNodesStages(p.Files)...) + return append(stages, osbuild.GenFileNodesStages(p.Files)...), nil } // create a fully unattended/automated kickstart @@ -723,14 +751,14 @@ reboot --eject kickstartFile, err := kickstartOptions.IncludeRaw(hardcodedKickstartBits) if err != nil { - panic(err) + return nil, err } p.Files = append(p.Files, kickstartFile) - return append(stages, osbuild.GenFileNodesStages(p.Files)...) + return append(stages, osbuild.GenFileNodesStages(p.Files)...), nil } -func (p *AnacondaInstallerISOTree) tarPayloadStages() []*osbuild.Stage { +func (p *AnacondaInstallerISOTree) tarPayloadStages() ([]*osbuild.Stage, error) { stages := make([]*osbuild.Stage, 0) // Create the payload tarball @@ -746,18 +774,22 @@ func (p *AnacondaInstallerISOTree) tarPayloadStages() []*osbuild.Stage { makeISORootPath(p.PayloadPath)) if err != nil { - panic(fmt.Sprintf("failed to create kickstart stage options: %v", err)) + return nil, fmt.Errorf("failed to create kickstart stage options: %w", err) } - stages = append(stages, p.makeKickstartStages(kickstartOptions)...) + kickstartStages, err := p.makeKickstartStages(kickstartOptions) + if err != nil { + return nil, fmt.Errorf("cannot create kickstart stages: %w", err) + } + stages = append(stages, kickstartStages...) } - return stages + return stages, nil } // Create the base kickstart stage with any options required for unattended // installation if set and with any extra file insertion stage required for // extra kickstart content. -func (p *AnacondaInstallerISOTree) makeKickstartStages(stageOptions *osbuild.KickstartStageOptions) []*osbuild.Stage { +func (p *AnacondaInstallerISOTree) makeKickstartStages(stageOptions *osbuild.KickstartStageOptions) ([]*osbuild.Stage, error) { kickstartOptions := p.Kickstart if kickstartOptions == nil { kickstartOptions = new(kickstart.Options) @@ -768,7 +800,7 @@ func (p *AnacondaInstallerISOTree) makeKickstartStages(stageOptions *osbuild.Kic // kickstart.New() already validates the options but they may have been // modified since then, so validate them before we create the stages if err := p.Kickstart.Validate(); err != nil { - panic(err) + return nil, err } if kickstartOptions.UserFile != nil { @@ -776,7 +808,7 @@ func (p *AnacondaInstallerISOTree) makeKickstartStages(stageOptions *osbuild.Kic if kickstartOptions.UserFile != nil { kickstartFile, err := stageOptions.IncludeRaw(kickstartOptions.UserFile.Contents) if err != nil { - panic(err) + return nil, err } p.Files = append(p.Files, kickstartFile) @@ -850,14 +882,14 @@ func (p *AnacondaInstallerISOTree) makeKickstartStages(stageOptions *osbuild.Kic This directory contains files necessary for registering the system on first boot after installation. These files are copied to the installed system and services are enabled to activate the subscription on boot.`), ) if err != nil { - panic(err) + return nil, err } p.Files = append(p.Files, subscriptionReadme) } stages = append(stages, osbuild.GenFileNodesStages(p.Files)...) - return stages + return stages, nil } // makeISORootPath return a path that can be used to address files and folders diff --git a/pkg/manifest/anaconda_installer_iso_tree_test.go b/pkg/manifest/anaconda_installer_iso_tree_test.go index 95c73e8e0e..47f201e9d4 100644 --- a/pkg/manifest/anaconda_installer_iso_tree_test.go +++ b/pkg/manifest/anaconda_installer_iso_tree_test.go @@ -446,8 +446,8 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { }, } pipeline.ISOBoot = manifest.SyslinuxISOBoot - // XXX: we should check the error instead - assert.Panics(t, func() { _, _ = manifest.SerializeWith(pipeline, manifest.Inputs{}) }) + _, err := manifest.SerializeWith(pipeline, manifest.Inputs{}) + assert.EqualError(t, err, "cannot create ostree container stages: cannot create kickstart stages: kickstart unattended options are not compatible with user-supplied kickstart content") }) t.Run("unhappy/user-kickstart-with-sudo-bits", func(t *testing.T) { @@ -462,8 +462,8 @@ func TestAnacondaISOTreeSerializeWithOS(t *testing.T) { }, } pipeline.ISOBoot = manifest.SyslinuxISOBoot - // XXX: we should check the error instead - assert.Panics(t, func() { _, _ = manifest.SerializeWith(pipeline, manifest.Inputs{}) }) + _, err := manifest.SerializeWith(pipeline, manifest.Inputs{}) + assert.EqualError(t, err, "cannot create ostree container stages: cannot create kickstart stages: kickstart sudo nopasswd drop-in file creation is not compatible with user-supplied kickstart content") }) t.Run("plain+squashfs-rootfs", func(t *testing.T) { @@ -583,10 +583,8 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOBoot = manifest.SyslinuxISOBoot - // XXX: we should check the error instead - assert.Panics(t, func() { - _, _ = manifest.SerializeWith(pipeline, manifest.Inputs{Commits: []ostree.CommitSpec{ostreeCommit}}) - }) + _, err := manifest.SerializeWith(pipeline, manifest.Inputs{Commits: []ostree.CommitSpec{ostreeCommit}}) + assert.EqualError(t, err, "cannot create ostree commit stages: cannot create kickstart stages: kickstart unattended options are not compatible with user-supplied kickstart content") }) t.Run("unhappy/user-kickstart-with-sudo-bits", func(t *testing.T) { @@ -602,10 +600,8 @@ func TestAnacondaISOTreeSerializeWithOSTree(t *testing.T) { OSTree: &kickstart.OSTree{}, } pipeline.ISOBoot = manifest.SyslinuxISOBoot - // XXX: we should check the error instead - assert.Panics(t, func() { - _, _ = manifest.SerializeWith(pipeline, manifest.Inputs{Commits: []ostree.CommitSpec{ostreeCommit}}) - }) + _, err := manifest.SerializeWith(pipeline, manifest.Inputs{Commits: []ostree.CommitSpec{ostreeCommit}}) + assert.EqualError(t, err, "cannot create ostree commit stages: cannot create kickstart stages: kickstart sudo nopasswd drop-in file creation is not compatible with user-supplied kickstart content") }) t.Run("plain+squashfs-rootfs", func(t *testing.T) { diff --git a/pkg/manifest/common.go b/pkg/manifest/common.go index 0461cdd6d2..6152cb9f67 100644 --- a/pkg/manifest/common.go +++ b/pkg/manifest/common.go @@ -24,6 +24,6 @@ func filesystemConfigStages(pt *disk.PartitionTable, mountConfiguration osbuild. case osbuild.MOUNT_CONFIGURATION_NONE: return []*osbuild.Stage{}, nil default: - panic(fmt.Sprintf("Unexpected mount configuration %d", mountConfiguration)) + return nil, fmt.Errorf("Unexpected mount configuration %d", mountConfiguration) } } diff --git a/pkg/manifest/manifest.go b/pkg/manifest/manifest.go index 8f8e90ce54..8a35a38888 100644 --- a/pkg/manifest/manifest.go +++ b/pkg/manifest/manifest.go @@ -201,7 +201,11 @@ func (m Manifest) Serialize(depsolvedSets map[string]depsolvednf.DepsolveResult, mergedInputs.Depsolved.Repos = append(mergedInputs.Depsolved.Repos, depsolvedSets[pipeline.Name()].Repos...) mergedInputs.Containers = append(mergedInputs.Containers, pipeline.getContainerSpecs()...) mergedInputs.InlineData = append(mergedInputs.InlineData, pipeline.getInline()...) - mergedInputs.FileRefs = append(mergedInputs.FileRefs, pipeline.fileRefs()...) + fileRefs, err := pipeline.fileRefs() + if err != nil { + return nil, fmt.Errorf("cannot get files ref from %q: %w", pipeline.Name(), err) + } + mergedInputs.FileRefs = append(mergedInputs.FileRefs, fileRefs...) } for _, pipeline := range m.pipelines { pipeline.serializeEnd() diff --git a/pkg/manifest/os.go b/pkg/manifest/os.go index dec2249381..d6e440cbec 100644 --- a/pkg/manifest/os.go +++ b/pkg/manifest/os.go @@ -1220,24 +1220,24 @@ func (p *OS) addStagesForAllFilesAndInlineData(pipeline *osbuild.Pipeline, files // (e.g. via the "uri" key in customizations) are added to the manifests "sources" // // Note that the actual copy/chmod/... stages are generated via addStagesForAllFilesAndInlineData -func (p *OS) fileRefs() []string { +func (p *OS) fileRefs() ([]string, error) { var fileRefs []string for _, file := range p.OSCustomizations.Files { if uriStr := file.URI(); uriStr != "" { uri, err := url.Parse(uriStr) if err != nil { - panic(fmt.Errorf("internal error: file customizations is not a valid URL: %w", err)) + return nil, fmt.Errorf("internal error: file customizations is not a valid URL: %w", err) } switch uri.Scheme { case "", "file": fileRefs = append(fileRefs, uri.Path) default: - panic(fmt.Errorf("internal error: unsupported schema for OSCustomizations.Files: %v", uriStr)) + return nil, fmt.Errorf("internal error: unsupported schema for OSCustomizations.Files: %v", uriStr) } } } - return fileRefs + return fileRefs, nil } diff --git a/pkg/manifest/pipeline.go b/pkg/manifest/pipeline.go index d8f1e5714b..b8d9ae5b4b 100644 --- a/pkg/manifest/pipeline.go +++ b/pkg/manifest/pipeline.go @@ -68,7 +68,7 @@ type Pipeline interface { getInline() []string // files generated from url references - fileRefs() []string + fileRefs() ([]string, error) } // ExportingPipeline is a pipeline that can export an artifact @@ -152,8 +152,8 @@ func (p Base) getInline() []string { return []string{} } -func (p Base) fileRefs() []string { - return nil +func (p Base) fileRefs() ([]string, error) { + return nil, nil } // NewBase returns a generic Pipeline object. The name is mandatory, immutable and must