github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/interfaces/policy/basedeclaration_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2018 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 policy_test
    21  
    22  import (
    23  	"fmt"
    24  	"strings"
    25  
    26  	. "gopkg.in/check.v1"
    27  
    28  	"github.com/snapcore/snapd/asserts"
    29  	"github.com/snapcore/snapd/interfaces"
    30  	"github.com/snapcore/snapd/interfaces/builtin"
    31  	"github.com/snapcore/snapd/interfaces/policy"
    32  	"github.com/snapcore/snapd/release"
    33  	"github.com/snapcore/snapd/snap"
    34  	"github.com/snapcore/snapd/snap/snaptest"
    35  	"github.com/snapcore/snapd/strutil"
    36  	"github.com/snapcore/snapd/testutil"
    37  )
    38  
    39  type baseDeclSuite struct {
    40  	baseDecl        *asserts.BaseDeclaration
    41  	restoreSanitize func()
    42  }
    43  
    44  var _ = Suite(&baseDeclSuite{})
    45  
    46  func (s *baseDeclSuite) SetUpSuite(c *C) {
    47  	s.restoreSanitize = snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})
    48  	s.baseDecl = asserts.BuiltinBaseDeclaration()
    49  }
    50  
    51  func (s *baseDeclSuite) TearDownSuite(c *C) {
    52  	s.restoreSanitize()
    53  }
    54  
    55  func (s *baseDeclSuite) connectCand(c *C, iface, slotYaml, plugYaml string) *policy.ConnectCandidate {
    56  	if slotYaml == "" {
    57  		slotYaml = fmt.Sprintf(`name: slot-snap
    58  version: 0
    59  slots:
    60    %s:
    61  `, iface)
    62  	}
    63  	if plugYaml == "" {
    64  		plugYaml = fmt.Sprintf(`name: plug-snap
    65  version: 0
    66  plugs:
    67    %s:
    68  `, iface)
    69  	}
    70  	slotSnap := snaptest.MockInfo(c, slotYaml, nil)
    71  	plugSnap := snaptest.MockInfo(c, plugYaml, nil)
    72  	return &policy.ConnectCandidate{
    73  		Plug:            interfaces.NewConnectedPlug(plugSnap.Plugs[iface], nil, nil),
    74  		Slot:            interfaces.NewConnectedSlot(slotSnap.Slots[iface], nil, nil),
    75  		BaseDeclaration: s.baseDecl,
    76  	}
    77  }
    78  
    79  func (s *baseDeclSuite) installSlotCand(c *C, iface string, snapType snap.Type, yaml string) *policy.InstallCandidate {
    80  	if yaml == "" {
    81  		yaml = fmt.Sprintf(`name: install-slot-snap
    82  version: 0
    83  type: %s
    84  slots:
    85    %s:
    86  `, snapType, iface)
    87  	}
    88  	snap := snaptest.MockInfo(c, yaml, nil)
    89  	return &policy.InstallCandidate{
    90  		Snap:            snap,
    91  		BaseDeclaration: s.baseDecl,
    92  	}
    93  }
    94  
    95  func (s *baseDeclSuite) installPlugCand(c *C, iface string, snapType snap.Type, yaml string) *policy.InstallCandidate {
    96  	if yaml == "" {
    97  		yaml = fmt.Sprintf(`name: install-plug-snap
    98  version: 0
    99  type: %s
   100  plugs:
   101    %s:
   102  `, snapType, iface)
   103  	}
   104  	snap := snaptest.MockInfo(c, yaml, nil)
   105  	return &policy.InstallCandidate{
   106  		Snap:            snap,
   107  		BaseDeclaration: s.baseDecl,
   108  	}
   109  }
   110  
   111  const declTempl = `type: snap-declaration
   112  authority-id: canonical
   113  series: 16
   114  snap-name: @name@
   115  snap-id: @snapid@
   116  publisher-id: @publisher@
   117  @plugsSlots@
   118  timestamp: 2016-09-30T12:00:00Z
   119  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
   120  
   121  AXNpZw==`
   122  
   123  func (s *baseDeclSuite) mockSnapDecl(c *C, name, snapID, publisher string, plugsSlots string) *asserts.SnapDeclaration {
   124  	encoded := strings.Replace(declTempl, "@name@", name, 1)
   125  	encoded = strings.Replace(encoded, "@snapid@", snapID, 1)
   126  	encoded = strings.Replace(encoded, "@publisher@", publisher, 1)
   127  	if plugsSlots != "" {
   128  		encoded = strings.Replace(encoded, "@plugsSlots@", strings.TrimSpace(plugsSlots), 1)
   129  	} else {
   130  		encoded = strings.Replace(encoded, "@plugsSlots@\n", "", 1)
   131  	}
   132  	a, err := asserts.Decode([]byte(encoded))
   133  	c.Assert(err, IsNil)
   134  	return a.(*asserts.SnapDeclaration)
   135  }
   136  
   137  func (s *baseDeclSuite) TestAutoConnection(c *C) {
   138  	all := builtin.Interfaces()
   139  
   140  	// these have more complex or in flux policies and have their
   141  	// own separate tests
   142  	snowflakes := map[string]bool{
   143  		"content":            true,
   144  		"core-support":       true,
   145  		"home":               true,
   146  		"lxd-support":        true,
   147  		"multipass-support":  true,
   148  		"packagekit-control": true,
   149  		"snapd-control":      true,
   150  		"dummy":              true,
   151  	}
   152  
   153  	// these simply auto-connect, anything else doesn't
   154  	autoconnect := map[string]bool{
   155  		"audio-playback":          true,
   156  		"browser-support":         true,
   157  		"desktop":                 true,
   158  		"desktop-legacy":          true,
   159  		"gsettings":               true,
   160  		"media-hub":               true,
   161  		"mir":                     true,
   162  		"network":                 true,
   163  		"network-bind":            true,
   164  		"network-status":          true,
   165  		"online-accounts-service": true,
   166  		"opengl":                  true,
   167  		"optical-drive":           true,
   168  		"screen-inhibit-control":  true,
   169  		"ubuntu-download-manager": true,
   170  		"unity7":                  true,
   171  		"unity8":                  true,
   172  		"upower-observe":          true,
   173  		"wayland":                 true,
   174  		"x11":                     true,
   175  	}
   176  
   177  	for _, iface := range all {
   178  		if snowflakes[iface.Name()] {
   179  			continue
   180  		}
   181  		expected := autoconnect[iface.Name()]
   182  		comm := Commentf(iface.Name())
   183  
   184  		// check base declaration
   185  		cand := s.connectCand(c, iface.Name(), "", "")
   186  		arity, err := cand.CheckAutoConnect()
   187  		if expected {
   188  			c.Check(err, IsNil, comm)
   189  			c.Check(arity.SlotsPerPlugAny(), Equals, false)
   190  		} else {
   191  			c.Check(err, NotNil, comm)
   192  		}
   193  	}
   194  }
   195  
   196  func (s *baseDeclSuite) TestAutoConnectPlugSlot(c *C) {
   197  	all := builtin.Interfaces()
   198  
   199  	// these have more complex or in flux policies and have their
   200  	// own separate tests
   201  	snowflakes := map[string]bool{
   202  		"classic-support": true,
   203  		"content":         true,
   204  		"home":            true,
   205  		"lxd-support":     true,
   206  		// netlink-driver needs the family-name attributes to match
   207  		"netlink-driver": true,
   208  	}
   209  
   210  	for _, iface := range all {
   211  		if snowflakes[iface.Name()] {
   212  			continue
   213  		}
   214  		c.Check(iface.AutoConnect(nil, nil), Equals, true)
   215  	}
   216  }
   217  
   218  func (s *baseDeclSuite) TestInterimAutoConnectionHome(c *C) {
   219  	restore := release.MockOnClassic(true)
   220  	defer restore()
   221  	cand := s.connectCand(c, "home", "", "")
   222  	arity, err := cand.CheckAutoConnect()
   223  	c.Check(err, IsNil)
   224  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   225  
   226  	release.OnClassic = false
   227  	_, err = cand.CheckAutoConnect()
   228  	c.Check(err, ErrorMatches, `auto-connection denied by slot rule of interface \"home\"`)
   229  }
   230  
   231  func (s *baseDeclSuite) TestHomeReadAll(c *C) {
   232  	const plugYaml = `name: plug-snap
   233  version: 0
   234  plugs:
   235    home:
   236      read: all
   237  `
   238  	restore := release.MockOnClassic(true)
   239  	defer restore()
   240  	cand := s.connectCand(c, "home", "", plugYaml)
   241  	err := cand.Check()
   242  	c.Check(err, NotNil)
   243  
   244  	_, err = cand.CheckAutoConnect()
   245  	c.Check(err, NotNil)
   246  
   247  	release.OnClassic = false
   248  	err = cand.Check()
   249  	c.Check(err, NotNil)
   250  
   251  	_, err = cand.CheckAutoConnect()
   252  	c.Check(err, NotNil)
   253  }
   254  
   255  func (s *baseDeclSuite) TestHomeReadDefault(c *C) {
   256  	const plugYaml = `name: plug-snap
   257  version: 0
   258  plugs:
   259    home: null
   260  `
   261  	restore := release.MockOnClassic(true)
   262  	defer restore()
   263  	cand := s.connectCand(c, "home", "", plugYaml)
   264  	err := cand.Check()
   265  	c.Check(err, IsNil)
   266  
   267  	// Same as TestInterimAutoConnectionHome()
   268  	arity, err := cand.CheckAutoConnect()
   269  	c.Check(err, IsNil)
   270  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   271  
   272  	release.OnClassic = false
   273  	err = cand.Check()
   274  	c.Check(err, IsNil)
   275  
   276  	// Same as TestInterimAutoConnectionHome()
   277  	_, err = cand.CheckAutoConnect()
   278  	c.Check(err, NotNil)
   279  }
   280  
   281  func (s *baseDeclSuite) TestAutoConnectionSnapdControl(c *C) {
   282  	cand := s.connectCand(c, "snapd-control", "", "")
   283  	_, err := cand.CheckAutoConnect()
   284  	c.Check(err, NotNil)
   285  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"snapd-control\"")
   286  
   287  	plugsSlots := `
   288  plugs:
   289    snapd-control:
   290      allow-auto-connection: true
   291  `
   292  
   293  	lxdDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   294  	cand.PlugSnapDeclaration = lxdDecl
   295  	arity, err := cand.CheckAutoConnect()
   296  	c.Check(err, IsNil)
   297  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   298  }
   299  
   300  func (s *baseDeclSuite) TestAutoConnectionContent(c *C) {
   301  	// random snaps cannot connect with content
   302  	// (Sanitize* will now also block this)
   303  	cand := s.connectCand(c, "content", "", "")
   304  	_, err := cand.CheckAutoConnect()
   305  	c.Check(err, NotNil)
   306  
   307  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
   308  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
   309  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
   310  
   311  	// same publisher, same content
   312  	cand = s.connectCand(c, "stuff", `
   313  name: slot-snap
   314  version: 0
   315  slots:
   316    stuff:
   317      interface: content
   318      content: mk1
   319  `, `
   320  name: plug-snap
   321  version: 0
   322  plugs:
   323    stuff:
   324      interface: content
   325      content: mk1
   326  `)
   327  	cand.SlotSnapDeclaration = slotDecl1
   328  	cand.PlugSnapDeclaration = plugDecl1
   329  	arity, err := cand.CheckAutoConnect()
   330  	c.Check(err, IsNil)
   331  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   332  
   333  	// different publisher, same content
   334  	cand.SlotSnapDeclaration = slotDecl1
   335  	cand.PlugSnapDeclaration = plugDecl2
   336  	_, err = cand.CheckAutoConnect()
   337  	c.Check(err, NotNil)
   338  
   339  	// same publisher, different content
   340  	cand = s.connectCand(c, "stuff", `name: slot-snap
   341  version: 0
   342  slots:
   343    stuff:
   344      interface: content
   345      content: mk1
   346  `, `
   347  name: plug-snap
   348  version: 0
   349  plugs:
   350    stuff:
   351      interface: content
   352      content: mk2
   353  `)
   354  	cand.SlotSnapDeclaration = slotDecl1
   355  	cand.PlugSnapDeclaration = plugDecl1
   356  	_, err = cand.CheckAutoConnect()
   357  	c.Check(err, NotNil)
   358  }
   359  
   360  func (s *baseDeclSuite) TestAutoConnectionLxdSupportOverride(c *C) {
   361  	// by default, don't auto-connect
   362  	cand := s.connectCand(c, "lxd-support", "", "")
   363  	_, err := cand.CheckAutoConnect()
   364  	c.Check(err, NotNil)
   365  
   366  	plugsSlots := `
   367  plugs:
   368    lxd-support:
   369      allow-auto-connection: true
   370  `
   371  
   372  	lxdDecl := s.mockSnapDecl(c, "lxd", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   373  	cand.PlugSnapDeclaration = lxdDecl
   374  	_, err = cand.CheckAutoConnect()
   375  	c.Check(err, IsNil)
   376  }
   377  
   378  func (s *baseDeclSuite) TestAutoConnectionLxdSupportOverrideRevoke(c *C) {
   379  	cand := s.connectCand(c, "lxd-support", "", "")
   380  	plugsSlots := `
   381  plugs:
   382    lxd-support:
   383      allow-auto-connection: false
   384  `
   385  
   386  	lxdDecl := s.mockSnapDecl(c, "notlxd", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   387  	cand.PlugSnapDeclaration = lxdDecl
   388  	_, err := cand.CheckAutoConnect()
   389  	c.Check(err, NotNil)
   390  	c.Assert(err, ErrorMatches, "auto-connection not allowed by plug rule of interface \"lxd-support\" for \"notlxd\" snap")
   391  }
   392  
   393  func (s *baseDeclSuite) TestAutoConnectionKernelModuleControlOverride(c *C) {
   394  	cand := s.connectCand(c, "kernel-module-control", "", "")
   395  	_, err := cand.CheckAutoConnect()
   396  	c.Check(err, NotNil)
   397  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"kernel-module-control\"")
   398  
   399  	plugsSlots := `
   400  plugs:
   401    kernel-module-control:
   402      allow-auto-connection: true
   403  `
   404  
   405  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   406  	cand.PlugSnapDeclaration = snapDecl
   407  	_, err = cand.CheckAutoConnect()
   408  	c.Check(err, IsNil)
   409  }
   410  
   411  func (s *baseDeclSuite) TestAutoConnectionDockerSupportOverride(c *C) {
   412  	cand := s.connectCand(c, "docker-support", "", "")
   413  	_, err := cand.CheckAutoConnect()
   414  	c.Check(err, NotNil)
   415  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"docker-support\"")
   416  
   417  	plugsSlots := `
   418  plugs:
   419    docker-support:
   420      allow-auto-connection: true
   421  `
   422  
   423  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   424  	cand.PlugSnapDeclaration = snapDecl
   425  	_, err = cand.CheckAutoConnect()
   426  	c.Check(err, IsNil)
   427  }
   428  
   429  func (s *baseDeclSuite) TestAutoConnectionClassicSupportOverride(c *C) {
   430  	cand := s.connectCand(c, "classic-support", "", "")
   431  	_, err := cand.CheckAutoConnect()
   432  	c.Check(err, NotNil)
   433  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"classic-support\"")
   434  
   435  	plugsSlots := `
   436  plugs:
   437    classic-support:
   438      allow-auto-connection: true
   439  `
   440  
   441  	snapDecl := s.mockSnapDecl(c, "classic", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   442  	cand.PlugSnapDeclaration = snapDecl
   443  	_, err = cand.CheckAutoConnect()
   444  	c.Check(err, IsNil)
   445  }
   446  
   447  func (s *baseDeclSuite) TestAutoConnectionKubernetesSupportOverride(c *C) {
   448  	cand := s.connectCand(c, "kubernetes-support", "", "")
   449  	_, err := cand.CheckAutoConnect()
   450  	c.Check(err, NotNil)
   451  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"kubernetes-support\"")
   452  
   453  	plugsSlots := `
   454  plugs:
   455    kubernetes-support:
   456      allow-auto-connection: true
   457  `
   458  
   459  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   460  	cand.PlugSnapDeclaration = snapDecl
   461  	_, err = cand.CheckAutoConnect()
   462  	c.Check(err, IsNil)
   463  }
   464  
   465  func (s *baseDeclSuite) TestAutoConnectionGreengrassSupportOverride(c *C) {
   466  	cand := s.connectCand(c, "greengrass-support", "", "")
   467  	_, err := cand.CheckAutoConnect()
   468  	c.Check(err, NotNil)
   469  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"greengrass-support\"")
   470  
   471  	plugsSlots := `
   472  plugs:
   473    greengrass-support:
   474      allow-auto-connection: true
   475  `
   476  
   477  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   478  	cand.PlugSnapDeclaration = snapDecl
   479  	_, err = cand.CheckAutoConnect()
   480  	c.Check(err, IsNil)
   481  }
   482  
   483  func (s *baseDeclSuite) TestAutoConnectionMultipassSupportOverride(c *C) {
   484  	cand := s.connectCand(c, "multipass-support", "", "")
   485  	_, err := cand.CheckAutoConnect()
   486  	c.Check(err, NotNil)
   487  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"multipass-support\"")
   488  
   489  	plugsSlots := `
   490  plugs:
   491    multipass-support:
   492      allow-auto-connection: true
   493  `
   494  
   495  	snapDecl := s.mockSnapDecl(c, "multipass-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   496  	cand.PlugSnapDeclaration = snapDecl
   497  	_, err = cand.CheckAutoConnect()
   498  	c.Check(err, IsNil)
   499  }
   500  
   501  func (s *baseDeclSuite) TestAutoConnectionBlockDevicesOverride(c *C) {
   502  	cand := s.connectCand(c, "block-devices", "", "")
   503  	_, err := cand.CheckAutoConnect()
   504  	c.Check(err, NotNil)
   505  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"block-devices\"")
   506  
   507  	plugsSlots := `
   508  plugs:
   509    block-devices:
   510      allow-auto-connection: true
   511  `
   512  
   513  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   514  	cand.PlugSnapDeclaration = snapDecl
   515  	_, err = cand.CheckAutoConnect()
   516  	c.Check(err, IsNil)
   517  }
   518  
   519  func (s *baseDeclSuite) TestAutoConnectionPackagekitControlOverride(c *C) {
   520  	cand := s.connectCand(c, "packagekit-control", "", "")
   521  	_, err := cand.CheckAutoConnect()
   522  	c.Check(err, NotNil)
   523  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"packagekit-control\"")
   524  
   525  	plugsSlots := `
   526  plugs:
   527    packagekit-control:
   528      allow-auto-connection: true
   529  `
   530  
   531  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   532  	cand.PlugSnapDeclaration = snapDecl
   533  	_, err = cand.CheckAutoConnect()
   534  	c.Check(err, IsNil)
   535  }
   536  
   537  func (s *baseDeclSuite) TestAutoConnectionOverrideMultiple(c *C) {
   538  	plugsSlots := `
   539  plugs:
   540    network-bind:
   541      allow-auto-connection: true
   542    network-control:
   543      allow-auto-connection: true
   544    kernel-module-control:
   545      allow-auto-connection: true
   546    system-observe:
   547      allow-auto-connection: true
   548    hardware-observe:
   549      allow-auto-connection: true
   550  `
   551  
   552  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   553  
   554  	all := builtin.Interfaces()
   555  	// these are a mixture interfaces that the snap plugs
   556  	plugged := map[string]bool{
   557  		"network-bind":          true,
   558  		"network-control":       true,
   559  		"kernel-module-control": true,
   560  		"system-observe":        true,
   561  		"hardware-observe":      true,
   562  	}
   563  	for _, iface := range all {
   564  		if !plugged[iface.Name()] {
   565  			continue
   566  		}
   567  
   568  		cand := s.connectCand(c, iface.Name(), "", "")
   569  		cand.PlugSnapDeclaration = snapDecl
   570  		arity, err := cand.CheckAutoConnect()
   571  		c.Check(err, IsNil)
   572  		c.Check(arity.SlotsPerPlugAny(), Equals, false)
   573  	}
   574  }
   575  
   576  // describe installation rules for slots succinctly for cross-checking,
   577  // if an interface is not mentioned here a slot of its type can only
   578  // be installed by a core snap (and this was taken care by
   579  // BeforePrepareSlot),
   580  // otherwise the entry for the interface is the list of snap types it
   581  // can be installed by (using the declaration naming);
   582  // ATM a nil entry means even stricter rules that would need be tested
   583  // separately and whose implementation is in flux for now
   584  var (
   585  	slotInstallation = map[string][]string{
   586  		// other
   587  		"adb-support":               {"core"},
   588  		"audio-playback":            {"app", "core"},
   589  		"audio-record":              {"app", "core"},
   590  		"autopilot-introspection":   {"core"},
   591  		"avahi-control":             {"app", "core"},
   592  		"avahi-observe":             {"app", "core"},
   593  		"bluez":                     {"app", "core"},
   594  		"bool-file":                 {"core", "gadget"},
   595  		"browser-support":           {"core"},
   596  		"content":                   {"app", "gadget"},
   597  		"core-support":              {"core"},
   598  		"cups":                      {"app"},
   599  		"cups-control":              {"app", "core"},
   600  		"dbus":                      {"app"},
   601  		"docker-support":            {"core"},
   602  		"desktop-launch":            {"core"},
   603  		"dsp":                       {"core", "gadget"},
   604  		"dummy":                     {"app"},
   605  		"fwupd":                     {"app", "core"},
   606  		"gpio":                      {"core", "gadget"},
   607  		"gpio-control":              {"core"},
   608  		"greengrass-support":        {"core"},
   609  		"hidraw":                    {"core", "gadget"},
   610  		"i2c":                       {"core", "gadget"},
   611  		"iio":                       {"core", "gadget"},
   612  		"kubernetes-support":        {"core"},
   613  		"location-control":          {"app"},
   614  		"location-observe":          {"app"},
   615  		"lxd-support":               {"core"},
   616  		"maliit":                    {"app"},
   617  		"media-hub":                 {"app", "core"},
   618  		"mir":                       {"app"},
   619  		"modem-manager":             {"app", "core"},
   620  		"mpris":                     {"app"},
   621  		"netlink-driver":            {"core", "gadget"},
   622  		"network-manager":           {"app", "core"},
   623  		"network-manager-observe":   {"app", "core"},
   624  		"network-status":            {"core"},
   625  		"ofono":                     {"app", "core"},
   626  		"online-accounts-service":   {"app"},
   627  		"power-control":             {"core"},
   628  		"ppp":                       {"core"},
   629  		"pulseaudio":                {"app", "core"},
   630  		"pwm":                       {"core", "gadget"},
   631  		"raw-volume":                {"core", "gadget"},
   632  		"sd-control":                {"core"},
   633  		"serial-port":               {"core", "gadget"},
   634  		"spi":                       {"core", "gadget"},
   635  		"storage-framework-service": {"app"},
   636  		"thumbnailer-service":       {"app"},
   637  		"ubuntu-download-manager":   {"app"},
   638  		"udisks2":                   {"app", "core"},
   639  		"uhid":                      {"core"},
   640  		"uio":                       {"core", "gadget"},
   641  		"unity8":                    {"app"},
   642  		"unity8-calendar":           {"app"},
   643  		"unity8-contacts":           {"app"},
   644  		"upower-observe":            {"app", "core"},
   645  		"wayland":                   {"app", "core"},
   646  		"x11":                       {"app", "core"},
   647  		// snowflakes
   648  		"classic-support": nil,
   649  		"docker":          nil,
   650  		"lxd":             nil,
   651  	}
   652  
   653  	restrictedPlugInstallation = map[string][]string{
   654  		"core-support": {"core"},
   655  	}
   656  
   657  	snapTypeMap = map[string]snap.Type{
   658  		"core":   snap.TypeOS,
   659  		"app":    snap.TypeApp,
   660  		"kernel": snap.TypeKernel,
   661  		"gadget": snap.TypeGadget,
   662  	}
   663  )
   664  
   665  func (s *baseDeclSuite) TestSlotInstallation(c *C) {
   666  	all := builtin.Interfaces()
   667  
   668  	for _, iface := range all {
   669  		types, ok := slotInstallation[iface.Name()]
   670  		if !ok { // common ones, only core can install them,
   671  			types = []string{"core"}
   672  		}
   673  
   674  		if types == nil {
   675  			// snowflake needs to be tested specially
   676  			continue
   677  		}
   678  		for name, snapType := range snapTypeMap {
   679  			ok := strutil.ListContains(types, name)
   680  			ic := s.installSlotCand(c, iface.Name(), snapType, ``)
   681  			err := ic.Check()
   682  			comm := Commentf("%s by %s snap", iface.Name(), name)
   683  			if ok {
   684  				c.Check(err, IsNil, comm)
   685  			} else {
   686  				c.Check(err, NotNil, comm)
   687  			}
   688  		}
   689  	}
   690  
   691  	// test docker specially
   692  	ic := s.installSlotCand(c, "docker", snap.TypeApp, ``)
   693  	err := ic.Check()
   694  	c.Assert(err, Not(IsNil))
   695  	c.Assert(err, ErrorMatches, "installation not allowed by \"docker\" slot rule of interface \"docker\"")
   696  
   697  	// test lxd specially
   698  	ic = s.installSlotCand(c, "lxd", snap.TypeApp, ``)
   699  	err = ic.Check()
   700  	c.Assert(err, Not(IsNil))
   701  	c.Assert(err, ErrorMatches, "installation not allowed by \"lxd\" slot rule of interface \"lxd\"")
   702  }
   703  
   704  func (s *baseDeclSuite) TestPlugInstallation(c *C) {
   705  	all := builtin.Interfaces()
   706  
   707  	restricted := map[string]bool{
   708  		"block-devices":         true,
   709  		"classic-support":       true,
   710  		"desktop-launch":        true,
   711  		"dm-crypt":              true,
   712  		"docker-support":        true,
   713  		"greengrass-support":    true,
   714  		"gpio-control":          true,
   715  		"kernel-module-control": true,
   716  		"kubernetes-support":    true,
   717  		"lxd-support":           true,
   718  		"multipass-support":     true,
   719  		"packagekit-control":    true,
   720  		"personal-files":        true,
   721  		"sd-control":            true,
   722  		"snapd-control":         true,
   723  		"system-files":          true,
   724  		"tee":                   true,
   725  		"uinput":                true,
   726  		"unity8":                true,
   727  	}
   728  
   729  	for _, iface := range all {
   730  		types, ok := restrictedPlugInstallation[iface.Name()]
   731  		// If plug installation is restricted to specific snap types we
   732  		// need to make sure this is really the case here. If that is not
   733  		// the case we continue as normal.
   734  		if ok {
   735  			for name, snapType := range snapTypeMap {
   736  				ok := strutil.ListContains(types, name)
   737  				ic := s.installPlugCand(c, iface.Name(), snapType, ``)
   738  				err := ic.Check()
   739  				comm := Commentf("%s by %s snap", iface.Name(), name)
   740  				if ok {
   741  					c.Check(err, IsNil, comm)
   742  				} else {
   743  					c.Check(err, NotNil, comm)
   744  				}
   745  			}
   746  		} else {
   747  			ic := s.installPlugCand(c, iface.Name(), snap.TypeApp, ``)
   748  			err := ic.Check()
   749  			comm := Commentf("%s", iface.Name())
   750  			if restricted[iface.Name()] {
   751  				c.Check(err, NotNil, comm)
   752  			} else {
   753  				c.Check(err, IsNil, comm)
   754  			}
   755  		}
   756  	}
   757  }
   758  
   759  func (s *baseDeclSuite) TestConnection(c *C) {
   760  	all := builtin.Interfaces()
   761  
   762  	// connecting with these interfaces needs to be allowed on
   763  	// case-by-case basis
   764  	noconnect := map[string]bool{
   765  		"content":                   true,
   766  		"cups":                      true,
   767  		"docker":                    true,
   768  		"fwupd":                     true,
   769  		"location-control":          true,
   770  		"location-observe":          true,
   771  		"lxd":                       true,
   772  		"maliit":                    true,
   773  		"mir":                       true,
   774  		"online-accounts-service":   true,
   775  		"raw-volume":                true,
   776  		"storage-framework-service": true,
   777  		"thumbnailer-service":       true,
   778  		"ubuntu-download-manager":   true,
   779  		"unity8-calendar":           true,
   780  		"unity8-contacts":           true,
   781  	}
   782  
   783  	for _, iface := range all {
   784  		expected := !noconnect[iface.Name()]
   785  		comm := Commentf(iface.Name())
   786  
   787  		// check base declaration
   788  		cand := s.connectCand(c, iface.Name(), "", "")
   789  		err := cand.Check()
   790  
   791  		if expected {
   792  			c.Check(err, IsNil, comm)
   793  		} else {
   794  			c.Check(err, NotNil, comm)
   795  		}
   796  	}
   797  }
   798  
   799  func (s *baseDeclSuite) TestConnectionOnClassic(c *C) {
   800  	restore := release.MockOnClassic(false)
   801  	defer restore()
   802  
   803  	all := builtin.Interfaces()
   804  
   805  	// connecting with these interfaces needs to be allowed on
   806  	// case-by-case basis when not on classic
   807  	noconnect := map[string]bool{
   808  		"audio-record":    true,
   809  		"modem-manager":   true,
   810  		"network-manager": true,
   811  		"ofono":           true,
   812  		"pulseaudio":      true,
   813  		"upower-observe":  true,
   814  	}
   815  
   816  	for _, onClassic := range []bool{true, false} {
   817  		release.OnClassic = onClassic
   818  		for _, iface := range all {
   819  			if !noconnect[iface.Name()] {
   820  				continue
   821  			}
   822  			expected := onClassic
   823  			comm := Commentf(iface.Name())
   824  
   825  			// check base declaration
   826  			cand := s.connectCand(c, iface.Name(), "", "")
   827  			err := cand.Check()
   828  
   829  			if expected {
   830  				c.Check(err, IsNil, comm)
   831  			} else {
   832  				c.Check(err, NotNil, comm)
   833  			}
   834  		}
   835  	}
   836  }
   837  
   838  func (s *baseDeclSuite) TestConnectionImplicitOnClassicOrAppSnap(c *C) {
   839  	restore := release.MockOnClassic(false)
   840  	defer restore()
   841  
   842  	all := builtin.Interfaces()
   843  
   844  	// These interfaces represent when the interface might be implicit on
   845  	// classic or when the interface is provided via an app snap. As such,
   846  	// they all share the following:
   847  	//
   848  	// - implicitOnCore: false
   849  	// - implicitOnClassis: true
   850  	// - base declaration uses:
   851  	//     allow-installation:
   852  	//       slot-snap-type:
   853  	//         - app
   854  	//         - core
   855  	//     deny-connection:
   856  	//       on-classic: false
   857  	//     deny-auto-connection: true|false|unspecified
   858  	//
   859  	// connecting with these interfaces needs to be allowed on
   860  	// case-by-case basis when not on classic
   861  	ifaces := map[string]bool{
   862  		"audio-playback":  true,
   863  		"audio-record":    true,
   864  		"cups-control":    true,
   865  		"modem-manager":   true,
   866  		"network-manager": true,
   867  		"ofono":           true,
   868  		"pulseaudio":      true,
   869  		"upower-observe":  true,
   870  	}
   871  
   872  	for _, iface := range all {
   873  		if !ifaces[iface.Name()] {
   874  			continue
   875  		}
   876  		comm := Commentf(iface.Name())
   877  
   878  		// verify the interface is setup as expected wrt
   879  		// implicitOnCore, implicitOnClassic, no plugs and has
   880  		// expected slots (ignoring AutoConnection)
   881  		si := interfaces.StaticInfoOf(iface)
   882  		c.Assert(si.ImplicitOnCore, Equals, false)
   883  		c.Assert(si.ImplicitOnClassic, Equals, true)
   884  
   885  		c.Assert(s.baseDecl.PlugRule(iface.Name()), IsNil)
   886  
   887  		sr := s.baseDecl.SlotRule(iface.Name())
   888  		c.Assert(sr, Not(IsNil))
   889  		c.Assert(sr.AllowInstallation, HasLen, 1)
   890  		c.Check(sr.AllowInstallation[0].SlotSnapTypes, DeepEquals, []string{"app", "core"}, comm)
   891  		c.Assert(sr.DenyConnection, HasLen, 1)
   892  		c.Check(sr.DenyConnection[0].OnClassic, DeepEquals, &asserts.OnClassicConstraint{Classic: false}, comm)
   893  
   894  		for _, onClassic := range []bool{true, false} {
   895  			release.OnClassic = onClassic
   896  
   897  			for _, implicit := range []bool{true, false} {
   898  				// When implicitOnCore is false, there is
   899  				// nothing to test on Core
   900  				if implicit && !onClassic {
   901  					continue
   902  				}
   903  
   904  				snapType := "app"
   905  				if implicit {
   906  					snapType = "os"
   907  				}
   908  				slotYaml := fmt.Sprintf(`name: slot-snap
   909  version: 0
   910  type: %s
   911  slots:
   912    %s:
   913  `, snapType, iface.Name())
   914  
   915  				// XXX: eventually 'onClassic && !implicit' but
   916  				// the current declaration allows connection on
   917  				// Core when 'type: app'. See:
   918  				// https://github.com/snapcore/snapd/pull/8920/files#r471678529
   919  				expected := onClassic
   920  
   921  				// check base declaration
   922  				cand := s.connectCand(c, iface.Name(), slotYaml, "")
   923  				err := cand.Check()
   924  
   925  				if expected {
   926  					c.Check(err, IsNil, comm)
   927  				} else {
   928  					c.Check(err, NotNil, comm)
   929  				}
   930  			}
   931  		}
   932  	}
   933  }
   934  
   935  func (s *baseDeclSuite) TestSanity(c *C) {
   936  	all := builtin.Interfaces()
   937  
   938  	// these interfaces have rules both for the slots and plugs side
   939  	// given how the rules work this can be delicate,
   940  	// listed here to make sure that was a conscious decision
   941  	bothSides := map[string]bool{
   942  		"block-devices":         true,
   943  		"audio-playback":        true,
   944  		"classic-support":       true,
   945  		"core-support":          true,
   946  		"desktop-launch":        true,
   947  		"dm-crypt":              true,
   948  		"docker-support":        true,
   949  		"greengrass-support":    true,
   950  		"gpio-control":          true,
   951  		"kernel-module-control": true,
   952  		"kubernetes-support":    true,
   953  		"lxd-support":           true,
   954  		"multipass-support":     true,
   955  		"packagekit-control":    true,
   956  		"personal-files":        true,
   957  		"sd-control":            true,
   958  		"snapd-control":         true,
   959  		"system-files":          true,
   960  		"tee":                   true,
   961  		"udisks2":               true,
   962  		"uinput":                true,
   963  		"unity8":                true,
   964  		"wayland":               true,
   965  	}
   966  
   967  	for _, iface := range all {
   968  		plugRule := s.baseDecl.PlugRule(iface.Name())
   969  		slotRule := s.baseDecl.SlotRule(iface.Name())
   970  		if plugRule == nil && slotRule == nil {
   971  			c.Logf("%s is not considered in the base declaration", iface.Name())
   972  			c.Fail()
   973  		}
   974  		if plugRule != nil && slotRule != nil {
   975  			if !bothSides[iface.Name()] {
   976  				c.Logf("%s have both a base declaration slot rule and plug rule, make sure that's intended and correct", iface.Name())
   977  				c.Fail()
   978  			}
   979  		}
   980  	}
   981  }
   982  
   983  func (s *baseDeclSuite) TestConnectionContent(c *C) {
   984  	// we let connect explicitly as long as content matches (or is absent on both sides)
   985  
   986  	// random (Sanitize* will now also block this)
   987  	cand := s.connectCand(c, "content", "", "")
   988  	err := cand.Check()
   989  	c.Check(err, NotNil)
   990  
   991  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
   992  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
   993  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
   994  
   995  	// same publisher, same content
   996  	cand = s.connectCand(c, "stuff", `name: slot-snap
   997  version: 0
   998  slots:
   999    stuff:
  1000      interface: content
  1001      content: mk1
  1002  `, `
  1003  name: plug-snap
  1004  version: 0
  1005  plugs:
  1006    stuff:
  1007      interface: content
  1008      content: mk1
  1009  `)
  1010  	cand.SlotSnapDeclaration = slotDecl1
  1011  	cand.PlugSnapDeclaration = plugDecl1
  1012  	err = cand.Check()
  1013  	c.Check(err, IsNil)
  1014  
  1015  	// different publisher, same content
  1016  	cand.SlotSnapDeclaration = slotDecl1
  1017  	cand.PlugSnapDeclaration = plugDecl2
  1018  	err = cand.Check()
  1019  	c.Check(err, IsNil)
  1020  
  1021  	// same publisher, different content
  1022  	cand = s.connectCand(c, "stuff", `
  1023  name: slot-snap
  1024  version: 0
  1025  slots:
  1026    stuff:
  1027      interface: content
  1028      content: mk1
  1029  `, `
  1030  name: plug-snap
  1031  version: 0
  1032  plugs:
  1033    stuff:
  1034      interface: content
  1035      content: mk2
  1036  `)
  1037  	cand.SlotSnapDeclaration = slotDecl1
  1038  	cand.PlugSnapDeclaration = plugDecl1
  1039  	err = cand.Check()
  1040  	c.Check(err, NotNil)
  1041  }
  1042  
  1043  func (s *baseDeclSuite) TestComposeBaseDeclaration(c *C) {
  1044  	decl, err := policy.ComposeBaseDeclaration(nil)
  1045  	c.Assert(err, IsNil)
  1046  	c.Assert(string(decl), testutil.Contains, `
  1047  type: base-declaration
  1048  authority-id: canonical
  1049  series: 16
  1050  revision: 0
  1051  `)
  1052  }
  1053  
  1054  func (s *baseDeclSuite) TestDoesNotPanic(c *C) {
  1055  	// In case there are any issues in the actual interfaces we'd get a panic
  1056  	// on snapd startup. This test prevents this from happing unnoticed.
  1057  	_, err := policy.ComposeBaseDeclaration(builtin.Interfaces())
  1058  	c.Assert(err, IsNil)
  1059  }
  1060  
  1061  func (s *baseDeclSuite) TestBrowserSupportAllowSandbox(c *C) {
  1062  	const plugYaml = `name: plug-snap
  1063  version: 0
  1064  plugs:
  1065    browser-support:
  1066     allow-sandbox: true
  1067  `
  1068  	cand := s.connectCand(c, "browser-support", "", plugYaml)
  1069  	err := cand.Check()
  1070  	c.Check(err, NotNil)
  1071  
  1072  	_, err = cand.CheckAutoConnect()
  1073  	c.Check(err, NotNil)
  1074  }
  1075  
  1076  func (s *baseDeclSuite) TestOpticalDriveWrite(c *C) {
  1077  	type options struct {
  1078  		readonlyYamls []string
  1079  		writableYamls []string
  1080  	}
  1081  
  1082  	opts := &options{
  1083  		readonlyYamls: []string{
  1084  			// Non-specified "write" attribute
  1085  			`name: plug-snap
  1086  version: 0
  1087  plugs:
  1088    optical-drive: null
  1089  `,
  1090  			// Undefined "write" attribute
  1091  			`name: plug-snap
  1092  version: 0
  1093  plugs:
  1094    optical-drive: {}
  1095  `,
  1096  			// False "write" attribute
  1097  			`name: plug-snap
  1098  version: 0
  1099  plugs:
  1100    optical-drive:
  1101      write: false
  1102  `,
  1103  		},
  1104  		writableYamls: []string{
  1105  			// True "write" attribute
  1106  			`name: plug-snap
  1107  version: 0
  1108  plugs:
  1109    optical-drive:
  1110      write: true
  1111  `,
  1112  		},
  1113  	}
  1114  
  1115  	checkOpticalDriveAutoConnect := func(plugYaml string, checker Checker) {
  1116  		cand := s.connectCand(c, "optical-drive", "", plugYaml)
  1117  		err := cand.Check()
  1118  		c.Check(err, checker)
  1119  		_, err = cand.CheckAutoConnect()
  1120  		c.Check(err, checker)
  1121  	}
  1122  
  1123  	for _, plugYaml := range opts.readonlyYamls {
  1124  		checkOpticalDriveAutoConnect(plugYaml, IsNil)
  1125  	}
  1126  	for _, plugYaml := range opts.writableYamls {
  1127  		checkOpticalDriveAutoConnect(plugYaml, NotNil)
  1128  	}
  1129  }
  1130  
  1131  func (s *baseDeclSuite) TestRawVolumeOverride(c *C) {
  1132  	slotYaml := `name: slot-snap
  1133  type: gadget
  1134  version: 0
  1135  slots:
  1136    raw-volume:
  1137      path: /dev/mmcblk0p1
  1138  `
  1139  	slotSnap := snaptest.MockInfo(c, slotYaml, nil)
  1140  	// mock a well-formed slot snap decl with SnapID
  1141  	slotSnapDecl := s.mockSnapDecl(c, "slot-snap", "slotsnapidididididididididididid", "canonical", "")
  1142  
  1143  	plugYaml := `name: plug-snap
  1144  version: 0
  1145  plugs:
  1146    raw-volume:
  1147  `
  1148  	plugSnap := snaptest.MockInfo(c, plugYaml, nil)
  1149  
  1150  	// no plug-side declaration
  1151  	cand := &policy.ConnectCandidate{
  1152  		Plug:                interfaces.NewConnectedPlug(plugSnap.Plugs["raw-volume"], nil, nil),
  1153  		Slot:                interfaces.NewConnectedSlot(slotSnap.Slots["raw-volume"], nil, nil),
  1154  		SlotSnapDeclaration: slotSnapDecl,
  1155  		BaseDeclaration:     s.baseDecl,
  1156  	}
  1157  
  1158  	err := cand.Check()
  1159  	c.Check(err, NotNil)
  1160  	c.Assert(err, ErrorMatches, "connection denied by slot rule of interface \"raw-volume\"")
  1161  	_, err = cand.CheckAutoConnect()
  1162  	c.Check(err, NotNil)
  1163  	c.Assert(err, ErrorMatches, "auto-connection denied by slot rule of interface \"raw-volume\"")
  1164  
  1165  	// specific plug-side declaration for connection only
  1166  	plugsOverride := `
  1167  plugs:
  1168    raw-volume:
  1169      allow-connection:
  1170        slot-snap-id:
  1171          - slotsnapidididididididididididid
  1172      allow-auto-connection: false
  1173  `
  1174  	plugSnapDecl := s.mockSnapDecl(c, "plug-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1175  	cand.PlugSnapDeclaration = plugSnapDecl
  1176  	err = cand.Check()
  1177  	c.Check(err, IsNil)
  1178  	_, err = cand.CheckAutoConnect()
  1179  	c.Check(err, NotNil)
  1180  	c.Assert(err, ErrorMatches, "auto-connection not allowed by plug rule of interface \"raw-volume\" for \"plug-snap\" snap")
  1181  
  1182  	// specific plug-side declaration for connection and auto-connection
  1183  	plugsOverride = `
  1184  plugs:
  1185    raw-volume:
  1186      allow-connection:
  1187        slot-snap-id:
  1188          - slotsnapidididididididididididid
  1189      allow-auto-connection:
  1190        slot-snap-id:
  1191          - slotsnapidididididididididididid
  1192  `
  1193  	plugSnapDecl = s.mockSnapDecl(c, "plug-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1194  	cand.PlugSnapDeclaration = plugSnapDecl
  1195  	err = cand.Check()
  1196  	c.Check(err, IsNil)
  1197  	arity, err := cand.CheckAutoConnect()
  1198  	c.Check(err, IsNil)
  1199  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
  1200  
  1201  	// blanket allow for connection and auto-connection to any slotting snap
  1202  	plugsOverride = `
  1203  plugs:
  1204    raw-volume:
  1205      allow-connection: true
  1206      allow-auto-connection: true
  1207  `
  1208  	plugSnapDecl = s.mockSnapDecl(c, "some-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1209  	cand.PlugSnapDeclaration = plugSnapDecl
  1210  	err = cand.Check()
  1211  	c.Check(err, IsNil)
  1212  	arity, err = cand.CheckAutoConnect()
  1213  	c.Check(err, IsNil)
  1214  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
  1215  }
  1216  
  1217  func (s *baseDeclSuite) TestAutoConnectionDesktopLaunchOverride(c *C) {
  1218  	cand := s.connectCand(c, "desktop-launch", "", "")
  1219  	_, err := cand.CheckAutoConnect()
  1220  	c.Check(err, NotNil)
  1221  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"desktop-launch\"")
  1222  
  1223  	plugsSlots := `
  1224  plugs:
  1225    desktop-launch:
  1226      allow-auto-connection: true
  1227  `
  1228  
  1229  	snapDecl := s.mockSnapDecl(c, "some-snap", "some-snap-with-desktop-launch-id", "canonical", plugsSlots)
  1230  	cand.PlugSnapDeclaration = snapDecl
  1231  	_, err = cand.CheckAutoConnect()
  1232  	c.Check(err, IsNil)
  1233  }