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