diff --git a/overlord/snapstate/snapstate_install_test.go b/overlord/snapstate/snapstate_install_test.go index 8eddb32ed61..454eb9d19fd 100644 --- a/overlord/snapstate/snapstate_install_test.go +++ b/overlord/snapstate/snapstate_install_test.go @@ -6874,3 +6874,87 @@ func printTasks(ts []*state.Task) string { } return b.String() } + +func (s *snapmgrTestSuite) TestInstallComponentsFromPathInvalidComponentFile(c *C) { + s.state.Lock() + defer s.state.Unlock() + + // use the real thing for this one + snapstate.MockOpenSnapFile(backend.OpenSnapFile) + + const ( + snapID = "test-snap-id" + snapName = "test-snap" + componentName = "test-component" + ) + snapRevision := snap.R(11) + + csi := snap.ComponentSideInfo{ + Component: naming.NewComponentRef(snapName, componentName), + Revision: snap.R(1), + } + + compPath := filepath.Join(c.MkDir(), "invalid-component") + err := os.WriteFile(compPath, []byte("invalid-component"), 0644) + c.Assert(err, IsNil) + + components := map[*snap.ComponentSideInfo]string{ + &csi: compPath, + } + + snapPath := makeTestSnap(c, `name: test-snap +version: 1.0 +components: + test-component: + type: test +`) + si := &snap.SideInfo{ + RealName: snapName, + SnapID: snapID, + Revision: snapRevision, + } + + goal := snapstate.PathInstallGoal(snapName, snapPath, si, components, snapstate.RevisionOptions{}) + _, _, err = snapstate.InstallOne(context.Background(), s.state, goal, snapstate.Options{}) + c.Assert(err, ErrorMatches, fmt.Sprintf(`.*cannot process snap or snapdir: file "%s" is invalid.*`, compPath)) +} + +func (s *snapmgrTestSuite) TestInstallComponentsFromPathInvalidComponentName(c *C) { + s.state.Lock() + defer s.state.Unlock() + + // use the real thing for this one + snapstate.MockOpenSnapFile(backend.OpenSnapFile) + + const ( + snapID = "test-snap-id" + snapName = "test-snap" + componentName = "Bad-component" + ) + snapRevision := snap.R(11) + + csi := snap.ComponentSideInfo{ + Component: naming.NewComponentRef(snapName, componentName), + Revision: snap.R(1), + } + + components := map[*snap.ComponentSideInfo]string{ + &csi: "", + } + + snapPath := makeTestSnap(c, `name: test-snap +version: 1.0 +components: + test-component: + type: test +`) + si := &snap.SideInfo{ + RealName: snapName, + SnapID: snapID, + Revision: snapRevision, + } + + goal := snapstate.PathInstallGoal(snapName, snapPath, si, components, snapstate.RevisionOptions{}) + _, _, err := snapstate.InstallOne(context.Background(), s.state, goal, snapstate.Options{}) + c.Assert(err, ErrorMatches, fmt.Sprintf(`invalid snap name: "%s"`, componentName)) +} diff --git a/overlord/snapstate/target.go b/overlord/snapstate/target.go index c04c4c12c9a..02f6586e479 100644 --- a/overlord/snapstate/target.go +++ b/overlord/snapstate/target.go @@ -27,6 +27,7 @@ import ( "github.com/snapcore/snapd/asserts/snapasserts" "github.com/snapcore/snapd/client" + "github.com/snapcore/snapd/logger" "github.com/snapcore/snapd/overlord/snapstate/backend" "github.com/snapcore/snapd/overlord/state" "github.com/snapcore/snapd/snap" @@ -682,7 +683,7 @@ func (p *pathInstallGoal) toInstall(ctx context.Context, st *state.State, opts O return nil, err } - comps, err := installableComponentsFromPaths(info, p.components) + comps, err := componentSetupsFromPaths(info, p.components) if err != nil { return nil, err } @@ -701,10 +702,10 @@ func (p *pathInstallGoal) toInstall(ctx context.Context, st *state.State, opts O return []target{inst}, nil } -func installableComponentsFromPaths(info *snap.Info, components map[*snap.ComponentSideInfo]string) ([]ComponentSetup, error) { +func componentSetupsFromPaths(snapInfo *snap.Info, components map[*snap.ComponentSideInfo]string) ([]ComponentSetup, error) { setups := make([]ComponentSetup, 0, len(components)) for csi, path := range components { - compInfo, _, err := backend.OpenComponentFile(path, info, csi) + compInfo, err := validatedComponentInfo(path, csi, snapInfo) if err != nil { return nil, err } @@ -718,3 +719,17 @@ func installableComponentsFromPaths(info *snap.Info, components map[*snap.Compon return setups, nil } + +func validatedComponentInfo(path string, csi *snap.ComponentSideInfo, si *snap.Info) (*snap.ComponentInfo, error) { + if err := csi.Component.Validate(); err != nil { + return nil, err + } + componentInfo, cont, err := backend.OpenComponentFile(path, si, csi) + if err != nil { + return nil, fmt.Errorf("cannot open snap file: %v", err) + } + if err := snap.ValidateComponentContainer(cont, csi.Component.String(), logger.Noticef); err != nil { + return nil, err + } + return componentInfo, nil +}