github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/overlord/snapstate/check_snap_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016 Canonical Ltd
     5   *
     6   * This program is free software: you can redistribute it and/or modify
     7   * it under the terms of the GNU General Public License version 3 as
     8   * published by the Free Software Foundation.
     9   *
    10   * This program is distributed in the hope that it will be useful,
    11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
    12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13   * GNU General Public License for more details.
    14   *
    15   * You should have received a copy of the GNU General Public License
    16   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    17   *
    18   */
    19  
    20  package snapstate_test
    21  
    22  import (
    23  	"errors"
    24  	"fmt"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/arch"
    29  	"github.com/snapcore/snapd/dirs"
    30  	"github.com/snapcore/snapd/osutil"
    31  	"github.com/snapcore/snapd/overlord/state"
    32  	"github.com/snapcore/snapd/release"
    33  	seccomp_compiler "github.com/snapcore/snapd/sandbox/seccomp"
    34  	"github.com/snapcore/snapd/snap"
    35  	"github.com/snapcore/snapd/snap/snaptest"
    36  	"github.com/snapcore/snapd/snapdtool"
    37  	"github.com/snapcore/snapd/testutil"
    38  
    39  	"github.com/snapcore/snapd/overlord/snapstate"
    40  	"github.com/snapcore/snapd/overlord/snapstate/snapstatetest"
    41  )
    42  
    43  type checkSnapSuite struct {
    44  	testutil.BaseTest
    45  	st        *state.State
    46  	deviceCtx snapstate.DeviceContext
    47  }
    48  
    49  var _ = Suite(&checkSnapSuite{})
    50  
    51  func (s *checkSnapSuite) SetUpTest(c *C) {
    52  	s.BaseTest.SetUpTest(c)
    53  	dirs.SetRootDir(c.MkDir())
    54  	s.st = state.New(nil)
    55  	s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {}))
    56  	s.deviceCtx = &snapstatetest.TrivialDeviceContext{DeviceModel: MakeModel(map[string]interface{}{
    57  		"kernel": "kernel",
    58  		"gadget": "gadget",
    59  	})}
    60  }
    61  
    62  func (s *checkSnapSuite) TearDownTest(c *C) {
    63  	s.BaseTest.TearDownTest(c)
    64  	dirs.SetRootDir("")
    65  }
    66  
    67  func emptyContainer(c *C) snap.Container {
    68  	return snaptest.MockContainer(c, nil)
    69  }
    70  
    71  func (s *checkSnapSuite) TestCheckSnapErrorOnUnsupportedArchitecture(c *C) {
    72  	const yaml = `name: hello
    73  version: 1.10
    74  architectures:
    75      - yadayada
    76      - blahblah
    77  `
    78  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
    79  	c.Assert(err, IsNil)
    80  
    81  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
    82  		c.Check(path, Equals, "snap-path")
    83  		c.Check(si, IsNil)
    84  		return info, emptyContainer(c), nil
    85  	}
    86  	restore := snapstate.MockOpenSnapFile(openSnapFile)
    87  	defer restore()
    88  
    89  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
    90  
    91  	errorMsg := fmt.Sprintf(`snap "hello" supported architectures (yadayada, blahblah) are incompatible with this system (%s)`, arch.DpkgArchitecture())
    92  	c.Assert(err.Error(), Equals, errorMsg)
    93  }
    94  
    95  var assumesTests = []struct {
    96  	version string
    97  	assumes string
    98  	classic bool
    99  	error   string
   100  }{{
   101  	assumes: "[common-data-dir]",
   102  }, {
   103  	assumes: "[f1, f2]",
   104  	error:   `snap "foo" assumes unsupported features: f1, f2 \(try to refresh the core or snapd snaps\)`,
   105  }, {
   106  	assumes: "[f1, f2]",
   107  	classic: true,
   108  	error:   `snap "foo" assumes unsupported features: f1, f2 \(try to update snapd and refresh the core snap\)`,
   109  }, {
   110  	assumes: "[snapd2.15]",
   111  	version: "unknown",
   112  }, {
   113  	assumes: "[snapdnono]",
   114  	version: "unknown",
   115  	error:   `.* unsupported features: snapdnono .*`,
   116  }, {
   117  	assumes: "[snapd2.15nono]",
   118  	version: "unknown",
   119  	error:   `.* unsupported features: snapd2.15nono .*`,
   120  }, {
   121  	assumes: "[snapd2.15]",
   122  	version: "2.15",
   123  }, {
   124  	assumes: "[snapd2.15]",
   125  	version: "2.15.1",
   126  }, {
   127  	assumes: "[snapd2.15]",
   128  	version: "2.15+git",
   129  }, {
   130  	assumes: "[snapd2.15]",
   131  	version: "2.16",
   132  }, {
   133  	assumes: "[snapd2.15.1]",
   134  	version: "2.16",
   135  }, {
   136  	assumes: "[snapd2.15.2]",
   137  	version: "2.16.1",
   138  }, {
   139  	assumes: "[snapd3]",
   140  	version: "3.1",
   141  }, {
   142  	assumes: "[snapd2.16]",
   143  	version: "2.15",
   144  	error:   `.* unsupported features: snapd2\.16 .*`,
   145  }, {
   146  	assumes: "[snapd2.15.1]",
   147  	version: "2.15",
   148  	error:   `.* unsupported features: snapd2\.15\.1 .*`,
   149  }, {
   150  	assumes: "[snapd2.15.1]",
   151  	version: "2.15.0",
   152  	error:   `.* unsupported features: snapd2\.15\.1 .*`,
   153  }, {
   154  	// Note that this is different from how strconv.VersionCompare
   155  	// (dpkg version numbering) would behave - it would error here
   156  	assumes: "[snapd2.15]",
   157  	version: "2.15~pre1",
   158  }, {
   159  	assumes: "[command-chain]",
   160  }}
   161  
   162  func (s *checkSnapSuite) TestCheckSnapAssumes(c *C) {
   163  	restore := snapdtool.MockVersion("2.15")
   164  	defer restore()
   165  
   166  	restore = release.MockOnClassic(false)
   167  	defer restore()
   168  
   169  	for _, test := range assumesTests {
   170  		snapdtool.Version = test.version
   171  		if snapdtool.Version == "" {
   172  			snapdtool.Version = "2.15"
   173  		}
   174  		release.OnClassic = test.classic
   175  
   176  		yaml := fmt.Sprintf("name: foo\nversion: 1.0\nassumes: %s\n", test.assumes)
   177  
   178  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
   179  		c.Assert(err, IsNil)
   180  
   181  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   182  			return info, emptyContainer(c), nil
   183  		}
   184  		restore := snapstate.MockOpenSnapFile(openSnapFile)
   185  		defer restore()
   186  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
   187  		if test.error != "" {
   188  			c.Check(err, ErrorMatches, test.error)
   189  		} else {
   190  			c.Assert(err, IsNil)
   191  		}
   192  	}
   193  }
   194  
   195  func (s *checkSnapSuite) TestCheckSnapCheckCallbackOK(c *C) {
   196  	const yaml = `name: foo
   197  version: 1.0`
   198  
   199  	si := &snap.SideInfo{
   200  		SnapID: "snap-id",
   201  	}
   202  
   203  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   204  		info := snaptest.MockInfo(c, yaml, si)
   205  		cont := snaptest.MockContainer(c, [][]string{{"canary", "canary"}})
   206  		return info, cont, nil
   207  	}
   208  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   209  	defer r1()
   210  
   211  	checkCbCalled := false
   212  	checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   213  		c.Assert(sf, NotNil)
   214  		data, err := sf.ReadFile("canary")
   215  		c.Assert(err, IsNil)
   216  		c.Assert(data, DeepEquals, []byte("canary"))
   217  		c.Assert(s.InstanceName(), Equals, "foo")
   218  		c.Assert(s.SnapID, Equals, "snap-id")
   219  		checkCbCalled = true
   220  		return nil
   221  	}
   222  	r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb})
   223  	defer r2()
   224  
   225  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, nil, snapstate.Flags{}, nil)
   226  	c.Check(err, IsNil)
   227  
   228  	c.Check(checkCbCalled, Equals, true)
   229  }
   230  
   231  func (s *checkSnapSuite) TestCheckSnapCheckCallbackFail(c *C) {
   232  	const yaml = `name: foo
   233  version: 1.0`
   234  
   235  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   236  	c.Assert(err, IsNil)
   237  
   238  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   239  		return info, emptyContainer(c), nil
   240  	}
   241  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   242  	defer restore()
   243  
   244  	fail := errors.New("bad snap")
   245  	checkCb := func(st *state.State, s, cur *snap.Info, _ snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   246  		return fail
   247  	}
   248  	r2 := snapstate.MockCheckSnapCallbacks(nil)
   249  	defer r2()
   250  	snapstate.AddCheckSnapCallback(checkCb)
   251  
   252  	err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
   253  	c.Check(err, Equals, fail)
   254  }
   255  
   256  func (s *checkSnapSuite) TestCheckSnapGadgetUpdate(c *C) {
   257  	reset := release.MockOnClassic(false)
   258  	defer reset()
   259  
   260  	st := state.New(nil)
   261  	st.Lock()
   262  	defer st.Unlock()
   263  
   264  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   265  	snaptest.MockSnap(c, `
   266  name: gadget
   267  type: gadget
   268  version: 1
   269  `, si)
   270  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   271  		SnapType: "gadget",
   272  		Active:   true,
   273  		Sequence: []*snap.SideInfo{si},
   274  		Current:  si.Revision,
   275  	})
   276  
   277  	const yaml = `name: gadget
   278  type: gadget
   279  version: 2
   280  `
   281  
   282  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   283  	info.SnapID = "gadget-id"
   284  	c.Assert(err, IsNil)
   285  
   286  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   287  		return info, emptyContainer(c), nil
   288  	}
   289  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   290  	defer restore()
   291  
   292  	st.Unlock()
   293  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   294  	st.Lock()
   295  	c.Check(err, IsNil)
   296  }
   297  
   298  func (s *checkSnapSuite) TestCheckSnapGadgetUpdateLocal(c *C) {
   299  	reset := release.MockOnClassic(false)
   300  	defer reset()
   301  
   302  	st := state.New(nil)
   303  	st.Lock()
   304  	defer st.Unlock()
   305  
   306  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)}
   307  	snaptest.MockSnap(c, `
   308  name: gadget
   309  type: gadget
   310  version: 1
   311  `, si)
   312  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   313  		SnapType: "gadget",
   314  		Active:   true,
   315  		Sequence: []*snap.SideInfo{si},
   316  		Current:  si.Revision,
   317  	})
   318  
   319  	const yaml = `name: gadget
   320  type: gadget
   321  version: 2
   322  `
   323  
   324  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   325  	// no SnapID => local!
   326  	c.Assert(err, IsNil)
   327  
   328  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   329  		return info, emptyContainer(c), nil
   330  	}
   331  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   332  	defer restore()
   333  
   334  	st.Unlock()
   335  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   336  	st.Lock()
   337  	c.Check(err, IsNil)
   338  }
   339  
   340  func (s *checkSnapSuite) TestCheckSnapGadgetUpdateToUnassertedProhibited(c *C) {
   341  	reset := release.MockOnClassic(false)
   342  	defer reset()
   343  
   344  	st := state.New(nil)
   345  	st.Lock()
   346  	defer st.Unlock()
   347  
   348  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   349  	snaptest.MockSnap(c, `
   350  name: gadget
   351  type: gadget
   352  version: 1
   353  `, si)
   354  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   355  		SnapType: "gadget",
   356  		Active:   true,
   357  		Sequence: []*snap.SideInfo{si},
   358  		Current:  si.Revision,
   359  	})
   360  
   361  	const yaml = `name: gadget
   362  type: gadget
   363  version: 2
   364  `
   365  
   366  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   367  	c.Assert(err, IsNil)
   368  
   369  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   370  		return info, emptyContainer(c), nil
   371  	}
   372  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   373  	defer restore()
   374  
   375  	st.Unlock()
   376  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   377  	st.Lock()
   378  	c.Check(err, ErrorMatches, `cannot replace signed gadget snap with an unasserted one`)
   379  }
   380  
   381  func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibited(c *C) {
   382  	reset := release.MockOnClassic(false)
   383  	defer reset()
   384  
   385  	st := state.New(nil)
   386  	st.Lock()
   387  	defer st.Unlock()
   388  
   389  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2)}
   390  	snaptest.MockSnap(c, `
   391  name: gadget
   392  type: gadget
   393  version: 1
   394  `, si)
   395  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   396  		SnapType: "gadget",
   397  		Active:   true,
   398  		Sequence: []*snap.SideInfo{si},
   399  		Current:  si.Revision,
   400  	})
   401  
   402  	const yaml = `name: zgadget
   403  type: gadget
   404  version: 2
   405  `
   406  
   407  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   408  	c.Assert(err, IsNil)
   409  
   410  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   411  		return info, emptyContainer(c), nil
   412  	}
   413  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   414  	defer restore()
   415  
   416  	st.Unlock()
   417  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   418  	st.Lock()
   419  	c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one")
   420  }
   421  
   422  func (s *checkSnapSuite) TestCheckSnapGadgetAdditionProhibitedBySnapID(c *C) {
   423  	reset := release.MockOnClassic(false)
   424  	defer reset()
   425  
   426  	st := state.New(nil)
   427  	st.Lock()
   428  	defer st.Unlock()
   429  
   430  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
   431  	snaptest.MockSnap(c, `
   432  name: gadget
   433  type: gadget
   434  version: 1
   435  `, si)
   436  	snapstate.Set(st, "gadget", &snapstate.SnapState{
   437  		SnapType: "gadget",
   438  		Active:   true,
   439  		Sequence: []*snap.SideInfo{si},
   440  		Current:  si.Revision,
   441  	})
   442  
   443  	const yaml = `name: zgadget
   444  type: gadget
   445  version: 2
   446  `
   447  
   448  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   449  	info.SnapID = "zgadget-id"
   450  	c.Assert(err, IsNil)
   451  
   452  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   453  		return info, emptyContainer(c), nil
   454  	}
   455  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   456  	defer restore()
   457  
   458  	st.Unlock()
   459  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, s.deviceCtx)
   460  	st.Lock()
   461  	c.Check(err, ErrorMatches, "cannot replace gadget snap with a different one")
   462  }
   463  
   464  func (s *checkSnapSuite) TestCheckSnapGadgetNoPrior(c *C) {
   465  	reset := release.MockOnClassic(false)
   466  	defer reset()
   467  
   468  	st := state.New(nil)
   469  	st.Lock()
   470  	defer st.Unlock()
   471  	st.Set("seeded", true)
   472  
   473  	const yaml = `name: gadget
   474  type: gadget
   475  version: 1
   476  `
   477  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   478  	c.Assert(err, IsNil)
   479  
   480  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   481  		return info, emptyContainer(c), nil
   482  	}
   483  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   484  	defer restore()
   485  
   486  	st.Unlock()
   487  	err = snapstate.CheckSnap(st, "snap-path", "gadget", nil, nil, snapstate.Flags{}, nil)
   488  	st.Lock()
   489  	c.Check(err, IsNil)
   490  }
   491  
   492  func (s *checkSnapSuite) TestCheckSnapErrorOnDevModeDisallowed(c *C) {
   493  	const yaml = `name: hello
   494  version: 1.10
   495  confinement: devmode
   496  `
   497  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   498  	c.Assert(err, IsNil)
   499  
   500  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   501  		c.Check(path, Equals, "snap-path")
   502  		c.Check(si, IsNil)
   503  		return info, emptyContainer(c), nil
   504  	}
   505  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   506  	defer restore()
   507  
   508  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
   509  
   510  	c.Assert(err, ErrorMatches, ".* requires devmode or confinement override")
   511  }
   512  
   513  func (s *checkSnapSuite) TestCheckSnapErrorOnClassicDisallowed(c *C) {
   514  	const yaml = `name: hello
   515  version: 1.10
   516  confinement: classic
   517  `
   518  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   519  	c.Assert(err, IsNil)
   520  
   521  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   522  		c.Check(path, Equals, "snap-path")
   523  		c.Check(si, IsNil)
   524  		return info, emptyContainer(c), nil
   525  	}
   526  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   527  	defer restore()
   528  
   529  	restore = release.MockOnClassic(true)
   530  	defer restore()
   531  
   532  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{}, nil)
   533  
   534  	c.Assert(err, ErrorMatches, ".* requires classic confinement")
   535  }
   536  
   537  func (s *checkSnapSuite) TestCheckSnapErrorClassicOnCoreDisallowed(c *C) {
   538  	const yaml = `name: hello
   539  version: 1.10
   540  confinement: classic
   541  `
   542  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   543  	c.Assert(err, IsNil)
   544  
   545  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   546  		c.Check(path, Equals, "snap-path")
   547  		c.Check(si, IsNil)
   548  		return info, emptyContainer(c), nil
   549  	}
   550  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   551  	defer restore()
   552  
   553  	restore = release.MockOnClassic(false)
   554  	defer restore()
   555  
   556  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil)
   557  
   558  	c.Assert(err, ErrorMatches, ".* requires classic confinement which is only available on classic systems")
   559  }
   560  
   561  func (s *checkSnapSuite) TestCheckSnapErrorClassicModeForStrictOrDevmode(c *C) {
   562  	const yaml = `name: hello
   563  version: 1.10
   564  confinement: strict
   565  `
   566  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   567  	c.Assert(err, IsNil)
   568  
   569  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   570  		c.Check(path, Equals, "snap-path")
   571  		c.Check(si, IsNil)
   572  		return info, emptyContainer(c), nil
   573  	}
   574  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   575  	defer restore()
   576  
   577  	err = snapstate.CheckSnap(s.st, "snap-path", "hello", nil, nil, snapstate.Flags{Classic: true}, nil)
   578  
   579  	c.Assert(err, ErrorMatches, `snap "hello" is not a classic confined snap`)
   580  }
   581  
   582  func (s *checkSnapSuite) TestCheckSnapKernelUpdate(c *C) {
   583  	reset := release.MockOnClassic(false)
   584  	defer reset()
   585  
   586  	st := state.New(nil)
   587  	st.Lock()
   588  	defer st.Unlock()
   589  
   590  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   591  	snaptest.MockSnap(c, `
   592  name: kernel
   593  type: kernel
   594  version: 1
   595  `, si)
   596  	snapstate.Set(st, "kernel", &snapstate.SnapState{
   597  		SnapType: "kernel",
   598  		Active:   true,
   599  		Sequence: []*snap.SideInfo{si},
   600  		Current:  si.Revision,
   601  	})
   602  
   603  	const yaml = `name: kernel
   604  type: kernel
   605  version: 2
   606  `
   607  
   608  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   609  	info.SnapID = "kernel-id"
   610  	c.Assert(err, IsNil)
   611  
   612  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   613  		return info, emptyContainer(c), nil
   614  	}
   615  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   616  	defer restore()
   617  
   618  	st.Unlock()
   619  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   620  	st.Lock()
   621  	c.Check(err, IsNil)
   622  }
   623  
   624  func (s *checkSnapSuite) TestCheckSnapKernelAdditionProhibitedBySnapID(c *C) {
   625  	reset := release.MockOnClassic(false)
   626  	defer reset()
   627  
   628  	st := state.New(nil)
   629  	st.Lock()
   630  	defer st.Unlock()
   631  
   632  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   633  	snaptest.MockSnap(c, `
   634  name: kernel
   635  type: kernel
   636  version: 1
   637  `, si)
   638  	snapstate.Set(st, "kernel", &snapstate.SnapState{
   639  		SnapType: "kernel",
   640  		Active:   true,
   641  		Sequence: []*snap.SideInfo{si},
   642  		Current:  si.Revision,
   643  	})
   644  
   645  	const yaml = `name: zkernel
   646  type: kernel
   647  version: 2
   648  `
   649  
   650  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   651  	info.SnapID = "zkernel-id"
   652  	c.Assert(err, IsNil)
   653  
   654  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   655  		return info, emptyContainer(c), nil
   656  	}
   657  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   658  	defer restore()
   659  
   660  	st.Unlock()
   661  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   662  	st.Lock()
   663  	c.Check(err, ErrorMatches, "cannot replace kernel snap with a different one")
   664  }
   665  
   666  func (s *checkSnapSuite) TestCheckSnapNoStateInfoInternalError(c *C) {
   667  	reset := release.MockOnClassic(false)
   668  	defer reset()
   669  
   670  	st := state.New(nil)
   671  	st.Lock()
   672  	defer st.Unlock()
   673  
   674  	si := &snap.SideInfo{RealName: "other-kernel", Revision: snap.R(2), SnapID: "kernel-id"}
   675  	snaptest.MockSnap(c, `
   676  name: other-kernel
   677  type: kernel
   678  version: 1
   679  `, si)
   680  	// we have a state information for snap of type kernel, but it's a
   681  	// different snap
   682  	snapstate.Set(st, "other-kernel", &snapstate.SnapState{
   683  		SnapType: "kernel",
   684  		Active:   true,
   685  		Sequence: []*snap.SideInfo{si},
   686  		Current:  si.Revision,
   687  	})
   688  
   689  	const yaml = `name: kernel
   690  type: kernel
   691  version: 2
   692  `
   693  
   694  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   695  	info.SnapID = "kernel-id"
   696  	c.Assert(err, IsNil)
   697  
   698  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   699  		return info, emptyContainer(c), nil
   700  	}
   701  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   702  	defer restore()
   703  
   704  	st.Unlock()
   705  	err = snapstate.CheckSnap(st, "snap-path", "kernel", nil, nil, snapstate.Flags{}, s.deviceCtx)
   706  	st.Lock()
   707  	c.Check(err, ErrorMatches, "internal error: no state for kernel snap \"kernel\"")
   708  }
   709  
   710  func (s *checkSnapSuite) TestCheckSnapBasesErrorsIfMissing(c *C) {
   711  	st := state.New(nil)
   712  	st.Lock()
   713  	defer st.Unlock()
   714  
   715  	const yaml = `name: requires-base
   716  version: 1
   717  base: some-base
   718  `
   719  
   720  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   721  	c.Assert(err, IsNil)
   722  
   723  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   724  		return info, emptyContainer(c), nil
   725  	}
   726  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   727  	defer restore()
   728  
   729  	st.Unlock()
   730  	err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil)
   731  	st.Lock()
   732  	c.Check(err, ErrorMatches, "cannot find required base \"some-base\"")
   733  }
   734  
   735  func (s *checkSnapSuite) TestCheckSnapBasesNoneHappy(c *C) {
   736  	st := state.New(nil)
   737  	st.Lock()
   738  	defer st.Unlock()
   739  
   740  	const yaml = `name: use-base-none
   741  version: 1
   742  base: none
   743  `
   744  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   745  	c.Assert(err, IsNil)
   746  
   747  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   748  		return info, emptyContainer(c), nil
   749  	}
   750  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   751  	defer restore()
   752  
   753  	st.Unlock()
   754  	err = snapstate.CheckSnap(st, "snap-path", "use-base-none", nil, nil, snapstate.Flags{}, nil)
   755  	st.Lock()
   756  	c.Check(err, IsNil)
   757  }
   758  
   759  func (s *checkSnapSuite) TestCheckSnapBasesHappy(c *C) {
   760  	st := state.New(nil)
   761  	st.Lock()
   762  	defer st.Unlock()
   763  
   764  	si := &snap.SideInfo{RealName: "some-base", Revision: snap.R(1), SnapID: "some-base-id"}
   765  	snaptest.MockSnap(c, `
   766  name: some-base
   767  type: base
   768  version: 1
   769  `, si)
   770  	snapstate.Set(st, "some-base", &snapstate.SnapState{
   771  		SnapType: "base",
   772  		Active:   true,
   773  		Sequence: []*snap.SideInfo{si},
   774  		Current:  si.Revision,
   775  	})
   776  
   777  	const yaml = `name: requires-base
   778  version: 1
   779  base: some-base
   780  `
   781  
   782  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   783  	c.Assert(err, IsNil)
   784  
   785  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   786  		return info, emptyContainer(c), nil
   787  	}
   788  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   789  	defer restore()
   790  
   791  	st.Unlock()
   792  	err = snapstate.CheckSnap(st, "snap-path", "requires-base", nil, nil, snapstate.Flags{}, nil)
   793  	st.Lock()
   794  	c.Check(err, IsNil)
   795  }
   796  
   797  func (s *checkSnapSuite) TestCheckSnapInstanceName(c *C) {
   798  	st := state.New(nil)
   799  	st.Lock()
   800  	defer st.Unlock()
   801  
   802  	si := &snap.SideInfo{RealName: "foo", Revision: snap.R(1), SnapID: "some-base-id"}
   803  	info := snaptest.MockSnap(c, `
   804  name: foo
   805  version: 1
   806  `, si)
   807  	snapstate.Set(st, "foo", &snapstate.SnapState{
   808  		Active:   true,
   809  		Sequence: []*snap.SideInfo{si},
   810  		Current:  si.Revision,
   811  	})
   812  
   813  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   814  		return info, emptyContainer(c), nil
   815  	}
   816  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   817  	defer restore()
   818  
   819  	st.Unlock()
   820  	err := snapstate.CheckSnap(st, "snap-path", "foo_instance", nil, nil, snapstate.Flags{}, nil)
   821  	st.Lock()
   822  	c.Check(err, IsNil)
   823  
   824  	st.Unlock()
   825  	err = snapstate.CheckSnap(st, "snap-path", "bar_instance", nil, nil, snapstate.Flags{}, nil)
   826  	st.Lock()
   827  	c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "bar_instance"`)
   828  
   829  	st.Unlock()
   830  	err = snapstate.CheckSnap(st, "snap-path", "other-name", nil, nil, snapstate.Flags{}, nil)
   831  	st.Lock()
   832  	c.Check(err, ErrorMatches, `cannot install snap "foo" using instance name "other-name"`)
   833  }
   834  
   835  func (s *checkSnapSuite) TestCheckSnapCheckCallInstanceKeySet(c *C) {
   836  	const yaml = `name: foo
   837  version: 1.0`
   838  
   839  	si := &snap.SideInfo{
   840  		SnapID: "snap-id",
   841  	}
   842  
   843  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   844  		info := snaptest.MockInfo(c, yaml, si)
   845  		return info, emptyContainer(c), nil
   846  	}
   847  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   848  	defer r1()
   849  
   850  	checkCbCalled := false
   851  	checkCb := func(st *state.State, s, cur *snap.Info, sf snap.Container, flags snapstate.Flags, deviceCtx snapstate.DeviceContext) error {
   852  		c.Assert(sf, NotNil)
   853  		c.Assert(s.InstanceName(), Equals, "foo_instance")
   854  		c.Assert(s.SnapName(), Equals, "foo")
   855  		c.Assert(s.SnapID, Equals, "snap-id")
   856  		checkCbCalled = true
   857  		return nil
   858  	}
   859  	r2 := snapstate.MockCheckSnapCallbacks([]snapstate.CheckSnapCallback{checkCb})
   860  	defer r2()
   861  
   862  	err := snapstate.CheckSnap(s.st, "snap-path", "foo_instance", si, nil, snapstate.Flags{}, nil)
   863  	c.Check(err, IsNil)
   864  
   865  	c.Check(checkCbCalled, Equals, true)
   866  }
   867  
   868  func (s *checkSnapSuite) TestCheckSnapCheckEpochLocal(c *C) {
   869  	si := &snap.SideInfo{
   870  		SnapID: "snap-id",
   871  	}
   872  
   873  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   874  		info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si)
   875  		return info, emptyContainer(c), nil
   876  	}
   877  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   878  	defer r1()
   879  
   880  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil)
   881  	c.Check(err, ErrorMatches, `cannot refresh "foo" to local snap with epoch 13, because it can't read the current epoch of 0`)
   882  }
   883  
   884  func (s *checkSnapSuite) TestCheckSnapCheckEpochNonLocal(c *C) {
   885  	si := &snap.SideInfo{
   886  		SnapID:   "snap-id",
   887  		Revision: snap.R(42),
   888  	}
   889  
   890  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   891  		info := snaptest.MockInfo(c, "{name: foo, version: 1.0, epoch: 13}", si)
   892  		return info, emptyContainer(c), nil
   893  	}
   894  	r1 := snapstate.MockOpenSnapFile(openSnapFile)
   895  	defer r1()
   896  
   897  	err := snapstate.CheckSnap(s.st, "snap-path", "foo", si, &snap.Info{}, snapstate.Flags{}, nil)
   898  	c.Check(err, ErrorMatches, `cannot refresh "foo" to new revision 42 with epoch 13, because it can't read the current epoch of 0`)
   899  }
   900  
   901  func (s *checkSnapSuite) TestCheckSnapBasesCoreCanBeUsedAsCore16(c *C) {
   902  	st := state.New(nil)
   903  	st.Lock()
   904  	defer st.Unlock()
   905  
   906  	si := &snap.SideInfo{RealName: "core", Revision: snap.R(1), SnapID: "core-id"}
   907  	snaptest.MockSnap(c, `
   908  name: core
   909  type: os
   910  version: 1
   911  `, si)
   912  	snapstate.Set(st, "core", &snapstate.SnapState{
   913  		SnapType: "os",
   914  		Active:   true,
   915  		Sequence: []*snap.SideInfo{si},
   916  		Current:  si.Revision,
   917  	})
   918  
   919  	const yaml = `name: requires-core16
   920  version: 1
   921  base: core16
   922  `
   923  
   924  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
   925  	c.Assert(err, IsNil)
   926  
   927  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   928  		return info, emptyContainer(c), nil
   929  	}
   930  	restore := snapstate.MockOpenSnapFile(openSnapFile)
   931  	defer restore()
   932  
   933  	st.Unlock()
   934  	err = snapstate.CheckSnap(st, "snap-path", "requires-core16", nil, nil, snapstate.Flags{}, nil)
   935  	st.Lock()
   936  	c.Check(err, IsNil)
   937  }
   938  
   939  func (s *checkSnapSuite) TestCheckSnapdHappy(c *C) {
   940  	st := state.New(nil)
   941  	st.Lock()
   942  	defer st.Unlock()
   943  
   944  	for _, t := range []struct {
   945  		yaml   string
   946  		errStr string
   947  	}{
   948  		{"name: snapd\nversion: 1\ntype: snapd", ""},
   949  		{"name: some-snap\nversion: 1\ntype: snapd", `cannot install snap "some-snap" of type "snapd" with a name other than "snapd"`},
   950  		{"name: snapd_instance\nversion: 1\ntype: snapd", `cannot install snap "snapd_instance" of type "snapd" with a name other than "snapd"`},
   951  	} {
   952  		info, err := snap.InfoFromSnapYaml([]byte(t.yaml))
   953  		c.Assert(err, IsNil)
   954  
   955  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
   956  			return info, emptyContainer(c), nil
   957  		}
   958  		restore := snapstate.MockOpenSnapFile(openSnapFile)
   959  		defer restore()
   960  
   961  		st.Unlock()
   962  		err = snapstate.CheckSnap(st, "snap-path", "snapd", nil, nil, snapstate.Flags{}, nil)
   963  		st.Lock()
   964  		if t.errStr == "" {
   965  			c.Check(err, IsNil)
   966  		} else {
   967  			c.Check(err, ErrorMatches, t.errStr)
   968  		}
   969  	}
   970  }
   971  
   972  // Note, invalid usernames checked in snap/info_snap_yaml.go
   973  var systemUsernamesTests = []struct {
   974  	sysIDs      string
   975  	classic     bool
   976  	noRangeUser bool
   977  	noUser      bool
   978  	scVer       string
   979  	error       string
   980  }{{
   981  	sysIDs: "snap_daemon: shared",
   982  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   983  }, {
   984  	sysIDs: "snap_daemon:\n    scope: shared",
   985  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   986  }, {
   987  	sysIDs: "snap_daemon:\n    scope: private",
   988  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   989  	error:  `snap "foo" requires unsupported user scope "private" for this version of snapd`,
   990  }, {
   991  	sysIDs: "snap_daemon:\n    scope: external",
   992  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   993  	error:  `snap "foo" requires unsupported user scope "external" for this version of snapd`,
   994  }, {
   995  	sysIDs: "snap_daemon:\n    scope: other",
   996  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
   997  	error:  `snap "foo" requires unsupported user scope "other"`,
   998  }, {
   999  	sysIDs:  "snap_daemon: shared",
  1000  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1001  	classic: true,
  1002  }, {
  1003  	sysIDs:  "snap_daemon:\n    scope: shared",
  1004  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1005  	classic: true,
  1006  }, {
  1007  	sysIDs:  "snap_daemon:\n    scope: private",
  1008  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1009  	classic: true,
  1010  	error:   `snap "foo" requires unsupported user scope "private" for this version of snapd`,
  1011  }, {
  1012  	sysIDs:  "snap_daemon:\n    scope: external",
  1013  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1014  	classic: true,
  1015  	error:   `snap "foo" requires unsupported user scope "external" for this version of snapd`,
  1016  }, {
  1017  	sysIDs:  "snap_daemon:\n    scope: other",
  1018  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1019  	classic: true,
  1020  	error:   `snap "foo" requires unsupported user scope "other"`,
  1021  }, {
  1022  	sysIDs: "snap_daemon: shared\n  allowed-not: shared",
  1023  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
  1024  	error:  `snap "foo" requires unsupported system username "allowed-not"`,
  1025  }, {
  1026  	sysIDs:  "allowed-not: shared\n  snap_daemon: shared",
  1027  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1028  	classic: true,
  1029  	error:   `snap "foo" requires unsupported system username "allowed-not"`,
  1030  }, {
  1031  	sysIDs: "snap_daemon: shared",
  1032  	noUser: true,
  1033  	scVer:  "dead 2.4.1 deadbeef bpf-actlog",
  1034  	error:  `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`,
  1035  }, {
  1036  	sysIDs:  "snap_daemon: shared",
  1037  	classic: true,
  1038  	noUser:  true,
  1039  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1040  	error:   `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snap_daemon", group exists and user does not`,
  1041  }, {
  1042  	sysIDs: "snap_daemon: shared",
  1043  	scVer:  "dead 2.3.3 deadbeef bpf-actlog",
  1044  	error:  `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`,
  1045  }, {
  1046  	sysIDs:  "snap_daemon: shared",
  1047  	classic: true,
  1048  	scVer:   "dead 2.3.3 deadbeef bpf-actlog",
  1049  	error:   `snap "foo" system usernames require a snapd built against libseccomp >= 2.4`,
  1050  }, {
  1051  	sysIDs: "snap_daemon: shared",
  1052  	scVer:  "dead 3.0.0 deadbeef bpf-actlog",
  1053  }, {
  1054  	sysIDs:  "snap_daemon: shared",
  1055  	classic: true,
  1056  	scVer:   "dead 3.0.0 deadbeef bpf-actlog",
  1057  }, {
  1058  	sysIDs: "snap_daemon: shared",
  1059  	scVer:  "dead 2.4.1 deadbeef -",
  1060  	error:  `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`,
  1061  }, {
  1062  	sysIDs:  "snap_daemon: shared",
  1063  	classic: true,
  1064  	scVer:   "dead 2.4.1 deadbeef -",
  1065  	error:   `snap "foo" system usernames require a snapd built against golang-seccomp >= 0.9.1`,
  1066  }, {
  1067  	sysIDs:      "snap_daemon: shared",
  1068  	noRangeUser: true,
  1069  	scVer:       "dead 2.4.1 deadbeef bpf-actlog",
  1070  	error:       `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`,
  1071  }, {
  1072  	sysIDs:      "snap_daemon: shared",
  1073  	classic:     true,
  1074  	noRangeUser: true,
  1075  	scVer:       "dead 2.4.1 deadbeef bpf-actlog",
  1076  	error:       `cannot ensure users for snap "foo" required system username "snap_daemon": cannot add user/group "snapd-range-524288-root", group exists and user does not`,
  1077  }, {
  1078  	sysIDs:  "snap_daemon: shared\n  daemon: shared",
  1079  	classic: true,
  1080  	scVer:   "dead 2.4.1 deadbeef bpf-actlog",
  1081  	error:   `snap "foo" requires unsupported system username "daemon"`,
  1082  },
  1083  }
  1084  
  1085  func (s *checkSnapSuite) TestCheckSnapSystemUsernames(c *C) {
  1086  	for _, test := range systemUsernamesTests {
  1087  		restore := seccomp_compiler.MockCompilerVersionInfo(test.scVer)
  1088  		defer restore()
  1089  
  1090  		restore = release.MockOnClassic(test.classic)
  1091  		defer restore()
  1092  
  1093  		var osutilEnsureUserGroupCalls int
  1094  		if test.noRangeUser {
  1095  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1096  				return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name)
  1097  			})
  1098  		} else if test.noUser {
  1099  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1100  				if name == "snapd-range-524288-root" {
  1101  					return nil
  1102  				}
  1103  				return fmt.Errorf(`cannot add user/group "%s", group exists and user does not`, name)
  1104  			})
  1105  		} else {
  1106  			restore = snapstate.MockOsutilEnsureUserGroup(func(name string, id uint32, extraUsers bool) error {
  1107  				osutilEnsureUserGroupCalls++
  1108  				return nil
  1109  			})
  1110  		}
  1111  		defer restore()
  1112  
  1113  		yaml := fmt.Sprintf("name: foo\nsystem-usernames:\n  %s\n", test.sysIDs)
  1114  
  1115  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1116  		c.Assert(err, IsNil)
  1117  
  1118  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1119  			return info, emptyContainer(c), nil
  1120  		}
  1121  		restore = snapstate.MockOpenSnapFile(openSnapFile)
  1122  		defer restore()
  1123  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
  1124  		if test.error != "" {
  1125  			c.Check(err, ErrorMatches, test.error)
  1126  			c.Check(osutilEnsureUserGroupCalls, Equals, 0)
  1127  		} else {
  1128  			c.Assert(err, IsNil)
  1129  			// one call for the range user, one for the system user
  1130  			c.Check(osutilEnsureUserGroupCalls, Equals, 2)
  1131  		}
  1132  	}
  1133  }
  1134  
  1135  func (s *checkSnapSuite) TestCheckSnapSystemUsernamesCalls(c *C) {
  1136  	// FIXME: this test fails on machines where the user was already
  1137  	// created by the system snapd
  1138  	_, err := osutil.FindUid("snapd-range-524288-root")
  1139  	if err == nil {
  1140  		c.Skip("FIXME")
  1141  	}
  1142  	falsePath := osutil.LookPathDefault("false", "/bin/false")
  1143  	for _, classic := range []bool{false, true} {
  1144  		restore := release.MockOnClassic(classic)
  1145  		defer restore()
  1146  
  1147  		restore = seccomp_compiler.MockCompilerVersionInfo("dead 2.4.1 deadbeef bpf-actlog")
  1148  		defer restore()
  1149  
  1150  		const yaml = `name: foo
  1151  version: 1.0
  1152  system-usernames:
  1153    snap_daemon: shared`
  1154  
  1155  		info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1156  		c.Assert(err, IsNil)
  1157  
  1158  		var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1159  			return info, emptyContainer(c), nil
  1160  		}
  1161  		restore = snapstate.MockOpenSnapFile(openSnapFile)
  1162  		defer restore()
  1163  
  1164  		mockGroupAdd := testutil.MockCommand(c, "groupadd", "")
  1165  		defer mockGroupAdd.Restore()
  1166  
  1167  		mockUserAdd := testutil.MockCommand(c, "useradd", "")
  1168  		defer mockUserAdd.Restore()
  1169  
  1170  		err = snapstate.CheckSnap(s.st, "snap-path", "foo", nil, nil, snapstate.Flags{}, nil)
  1171  		c.Assert(err, IsNil)
  1172  		if classic {
  1173  			c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{
  1174  				{"groupadd", "--system", "--gid", "524288", "snapd-range-524288-root"},
  1175  				{"groupadd", "--system", "--gid", "584788", "snap_daemon"},
  1176  			})
  1177  			c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{
  1178  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "snapd-range-524288-root"},
  1179  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "snap_daemon"},
  1180  			})
  1181  		} else {
  1182  			c.Check(mockGroupAdd.Calls(), DeepEquals, [][]string{
  1183  				{"groupadd", "--system", "--gid", "524288", "--extrausers", "snapd-range-524288-root"},
  1184  				{"groupadd", "--system", "--gid", "584788", "--extrausers", "snap_daemon"},
  1185  			})
  1186  			c.Check(mockUserAdd.Calls(), DeepEquals, [][]string{
  1187  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "524288", "--no-user-group", "--uid", "524288", "--extrausers", "snapd-range-524288-root"},
  1188  				{"useradd", "--system", "--home-dir", "/nonexistent", "--no-create-home", "--shell", falsePath, "--gid", "584788", "--no-user-group", "--uid", "584788", "--extrausers", "snap_daemon"},
  1189  			})
  1190  
  1191  		}
  1192  	}
  1193  }
  1194  
  1195  func (s *checkSnapSuite) TestCheckSnapRemodelKernel(c *C) {
  1196  	reset := release.MockOnClassic(false)
  1197  	defer reset()
  1198  
  1199  	st := state.New(nil)
  1200  	st.Lock()
  1201  	defer st.Unlock()
  1202  
  1203  	si := &snap.SideInfo{RealName: "kernel", Revision: snap.R(2), SnapID: "kernel-id"}
  1204  	snaptest.MockSnap(c, `
  1205  name: kernel
  1206  type: kernel
  1207  version: 1
  1208  `, si)
  1209  	snapstate.Set(st, "kernel", &snapstate.SnapState{
  1210  		SnapType: "kernel",
  1211  		Active:   true,
  1212  		Sequence: []*snap.SideInfo{si},
  1213  		Current:  si.Revision,
  1214  	})
  1215  
  1216  	const yaml = `name: new-kernel
  1217  type: kernel
  1218  version: 2
  1219  `
  1220  
  1221  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1222  	info.SnapID = "new-kernel-id"
  1223  	c.Assert(err, IsNil)
  1224  
  1225  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1226  		return info, emptyContainer(c), nil
  1227  	}
  1228  	restore := snapstate.MockOpenSnapFile(openSnapFile)
  1229  	defer restore()
  1230  
  1231  	// happy case, the new-kernel matches the model
  1232  	deviceCtx := &snapstatetest.TrivialDeviceContext{
  1233  		Remodeling: true,
  1234  		DeviceModel: MakeModel(map[string]interface{}{
  1235  			"kernel": "new-kernel",
  1236  			"gadget": "gadget",
  1237  		}),
  1238  	}
  1239  
  1240  	st.Unlock()
  1241  	err = snapstate.CheckSnap(st, "snap-path", "new-kernel", nil, nil, snapstate.Flags{}, deviceCtx)
  1242  	st.Lock()
  1243  	c.Check(err, IsNil)
  1244  }
  1245  
  1246  func (s *checkSnapSuite) TestCheckSnapRemodelGadget(c *C) {
  1247  	reset := release.MockOnClassic(false)
  1248  	defer reset()
  1249  
  1250  	st := state.New(nil)
  1251  	st.Lock()
  1252  	defer st.Unlock()
  1253  
  1254  	si := &snap.SideInfo{RealName: "gadget", Revision: snap.R(2), SnapID: "gadget-id"}
  1255  	snaptest.MockSnap(c, `
  1256  name: gadget
  1257  type: gadget
  1258  version: 1
  1259  `, si)
  1260  	snapstate.Set(st, "gadget", &snapstate.SnapState{
  1261  		SnapType: "gadget",
  1262  		Active:   true,
  1263  		Sequence: []*snap.SideInfo{si},
  1264  		Current:  si.Revision,
  1265  	})
  1266  
  1267  	const yaml = `name: new-gadget
  1268  type: gadget
  1269  version: 2
  1270  `
  1271  
  1272  	info, err := snap.InfoFromSnapYaml([]byte(yaml))
  1273  	info.SnapID = "new-gadget-id"
  1274  	c.Assert(err, IsNil)
  1275  
  1276  	var openSnapFile = func(path string, si *snap.SideInfo) (*snap.Info, snap.Container, error) {
  1277  		return info, emptyContainer(c), nil
  1278  	}
  1279  	restore := snapstate.MockOpenSnapFile(openSnapFile)
  1280  	defer restore()
  1281  
  1282  	// happy case, the new-gadget matches the model but we do not
  1283  	// support this yet
  1284  	deviceCtx := &snapstatetest.TrivialDeviceContext{
  1285  		Remodeling: true,
  1286  		DeviceModel: MakeModel(map[string]interface{}{
  1287  			"kernel": "kernel",
  1288  			"gadget": "new-gadget",
  1289  		}),
  1290  	}
  1291  
  1292  	st.Unlock()
  1293  	err = snapstate.CheckSnap(st, "snap-path", "new-gadget", nil, nil, snapstate.Flags{}, deviceCtx)
  1294  	st.Lock()
  1295  	c.Check(err, IsNil)
  1296  }