Skip to content

Commit

Permalink
o/hookstate: allow snapctl model command for kernel snaps
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsosanchezbeato committed Nov 7, 2024
1 parent 74d2d93 commit e99a881
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 11 deletions.
7 changes: 4 additions & 3 deletions overlord/hookstate/ctlcmd/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,11 +153,12 @@ func (c *modelCommand) getSnapInfoWithPublisher(st *state.State, snapName string
// checkPermissions verifies that the snap described by snapInfo is allowed to
// read the model assertion of deviceCtx.
// We allow the usage of this command if one of the following is true
// 1. The requesting snap must be a gadget
// 1. The requesting snap must be of gadget or kernel type
// 2. Come from the same brand as the device model assertion
// 3. Have the snapd-control plug
func (c *modelCommand) checkPermissions(st *state.State, deviceCtx snapstate.DeviceContext, snapInfo *snap.Info) error {
if snapType := snapInfo.Type(); snapType == snap.TypeGadget {
switch snapInfo.Type() {
case snap.TypeGadget, snap.TypeKernel:
return nil
}
if snapInfo.Publisher.ID == deviceCtx.Model().BrandID() {
Expand All @@ -170,7 +171,7 @@ func (c *modelCommand) checkPermissions(st *state.State, deviceCtx snapstate.Dev
}

c.reportError("cannot get model assertion for snap %q: "+
"must be either a gadget snap, from the same publisher as the model "+
"must be either a gadget or a kernel snap, from the same publisher as the model "+
"or have the snapd-control interface\n", snapInfo.SnapName())
return fmt.Errorf("insufficient permissions to get model assertion for snap %q", snapInfo.SnapName())
}
Expand Down
29 changes: 21 additions & 8 deletions overlord/hookstate/ctlcmd/model_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,11 @@ type: base
version: 1
`

const snapKernelYaml = `name: kernel1
type: kernel
version: 1
`

const snapYaml = `name: snap1
base: snap1-base
version: 1
Expand Down Expand Up @@ -239,7 +244,7 @@ func (s *modelSuite) TestUnhappyModelCommandInsufficientPermissions(c *C) {
stdout, stderr, err := ctlcmd.Run(mockContext, []string{"model"}, 0)
c.Check(err, ErrorMatches, "insufficient permissions to get model assertion for snap \"snap1\"")
c.Check(string(stdout), Equals, "")
c.Check(string(stderr), Equals, "cannot get model assertion for snap \"snap1\": must be either a gadget snap, from the same publisher as the model or have the snapd-control interface\n")
c.Check(string(stderr), Equals, "cannot get model assertion for snap \"snap1\": must be either a gadget or a kernel snap, from the same publisher as the model or have the snapd-control interface\n")
}

func (s *modelSuite) TestHappyModelCommandIdenticalPublisher(c *C) {
Expand Down Expand Up @@ -365,15 +370,23 @@ timestamp: %s
c.Check(string(stderr), Equals, "")
}

func (s *modelSuite) TestHappyModelCommandGadgetYaml(c *C) {
func (s *modelSuite) TestHappyModelCommandGadget(c *C) {
s.testHappyModelCommandForSnap(c, "gadget1", snapGadgetYaml)
}

func (s *modelSuite) TestHappyModelCommandKernel(c *C) {
s.testHappyModelCommandForSnap(c, "kernel1", snapKernelYaml)
}

func (s *modelSuite) testHappyModelCommandForSnap(c *C, snapName, snapYaml string) {
// This tests verifies that a snap that is a gadget can be used to
// get the model assertion, even if from a different publisher
s.addSnapDeclaration(c, "gadget1-id", "canonical", "gadget1")
s.addSnapDeclaration(c, snapName+"-id", "canonical", snapName)
s.setupBrands()

// set a model assertion
s.state.Lock()
current := s.brands.Model("canonical", "pc-model", map[string]interface{}{
current := s.brands.Model("my-brand", "pc-model", map[string]interface{}{
"architecture": "amd64",
"kernel": "pc-kernel",
"gadget": "pc",
Expand All @@ -382,21 +395,21 @@ func (s *modelSuite) TestHappyModelCommandGadgetYaml(c *C) {
err := assertstate.Add(s.state, current)
c.Assert(err, IsNil)
devicestatetest.SetDevice(s.state, &auth.DeviceState{
Brand: "canonical",
Brand: "my-brand",
Model: "pc-model",
})

c.Assert(err, IsNil)
task := s.state.NewTask("test-task", "my test task")
setup := &hookstate.HookSetup{Snap: "gadget1", Revision: snap.R(1), Hook: "test-hook"}
setup := &hookstate.HookSetup{Snap: snapName, Revision: snap.R(1), Hook: "test-hook"}
mockContext, err := hookstate.NewContext(task, s.state, setup, s.mockHandler, "")
c.Assert(err, IsNil)
mockInstalledSnap(c, s.state, snapGadgetYaml, "")
mockInstalledSnap(c, s.state, snapYaml, "")
s.state.Unlock()

stdout, stderr, err := ctlcmd.Run(mockContext, []string{"model"}, 0)
c.Check(err, IsNil)
c.Check(string(stdout), Equals, fmt.Sprintf(`brand-id: canonical
c.Check(string(stdout), Equals, fmt.Sprintf(`brand-id: my-brand
model: pc-model
serial: -- (device not registered yet)
architecture: amd64
Expand Down

0 comments on commit e99a881

Please sign in to comment.