gitee.com/mysnapcore/mysnapd@v0.1.0/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  	"gitee.com/mysnapcore/mysnapd/asserts"
    29  	"gitee.com/mysnapcore/mysnapd/interfaces"
    30  	"gitee.com/mysnapcore/mysnapd/interfaces/builtin"
    31  	"gitee.com/mysnapcore/mysnapd/interfaces/policy"
    32  	"gitee.com/mysnapcore/mysnapd/release"
    33  	"gitee.com/mysnapcore/mysnapd/snap"
    34  	"gitee.com/mysnapcore/mysnapd/snap/snaptest"
    35  	"gitee.com/mysnapcore/mysnapd/strutil"
    36  	"gitee.com/mysnapcore/mysnapd/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  		"pkcs11":             true,
   151  		"snapd-control":      true,
   152  		"empty":              true,
   153  	}
   154  
   155  	// these simply auto-connect, anything else doesn't
   156  	autoconnect := map[string]bool{
   157  		"audio-playback":          true,
   158  		"browser-support":         true,
   159  		"desktop":                 true,
   160  		"desktop-legacy":          true,
   161  		"gsettings":               true,
   162  		"media-hub":               true,
   163  		"mir":                     true,
   164  		"network":                 true,
   165  		"network-bind":            true,
   166  		"network-status":          true,
   167  		"online-accounts-service": true,
   168  		"opengl":                  true,
   169  		"optical-drive":           true,
   170  		"screen-inhibit-control":  true,
   171  		"ubuntu-download-manager": true,
   172  		"unity7":                  true,
   173  		"unity8":                  true,
   174  		"upower-observe":          true,
   175  		"wayland":                 true,
   176  		"x11":                     true,
   177  	}
   178  
   179  	for _, iface := range all {
   180  		if snowflakes[iface.Name()] {
   181  			continue
   182  		}
   183  		expected := autoconnect[iface.Name()]
   184  		comm := Commentf(iface.Name())
   185  
   186  		// check base declaration
   187  		cand := s.connectCand(c, iface.Name(), "", "")
   188  		arity, err := cand.CheckAutoConnect()
   189  		if expected {
   190  			c.Check(err, IsNil, comm)
   191  			c.Check(arity.SlotsPerPlugAny(), Equals, false)
   192  		} else {
   193  			c.Check(err, NotNil, comm)
   194  		}
   195  	}
   196  }
   197  
   198  func (s *baseDeclSuite) TestAutoConnectPlugSlot(c *C) {
   199  	all := builtin.Interfaces()
   200  
   201  	// these have more complex or in flux policies and have their
   202  	// own separate tests
   203  	snowflakes := map[string]bool{
   204  		"classic-support": true,
   205  		"content":         true,
   206  		"home":            true,
   207  		"lxd-support":     true,
   208  		// netlink-driver needs the family-name attributes to match
   209  		"netlink-driver": true,
   210  	}
   211  
   212  	for _, iface := range all {
   213  		if snowflakes[iface.Name()] {
   214  			continue
   215  		}
   216  		c.Check(iface.AutoConnect(nil, nil), Equals, true)
   217  	}
   218  }
   219  
   220  func (s *baseDeclSuite) TestInterimAutoConnectionHome(c *C) {
   221  	restore := release.MockOnClassic(true)
   222  	defer restore()
   223  	cand := s.connectCand(c, "home", "", "")
   224  	arity, err := cand.CheckAutoConnect()
   225  	c.Check(err, IsNil)
   226  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   227  
   228  	release.OnClassic = false
   229  	_, err = cand.CheckAutoConnect()
   230  	c.Check(err, ErrorMatches, `auto-connection denied by slot rule of interface \"home\"`)
   231  }
   232  
   233  func (s *baseDeclSuite) TestHomeReadAll(c *C) {
   234  	const plugYaml = `name: plug-snap
   235  version: 0
   236  plugs:
   237    home:
   238      read: all
   239  `
   240  	restore := release.MockOnClassic(true)
   241  	defer restore()
   242  	cand := s.connectCand(c, "home", "", plugYaml)
   243  	err := cand.Check()
   244  	c.Check(err, NotNil)
   245  
   246  	_, err = cand.CheckAutoConnect()
   247  	c.Check(err, NotNil)
   248  
   249  	release.OnClassic = false
   250  	err = cand.Check()
   251  	c.Check(err, NotNil)
   252  
   253  	_, err = cand.CheckAutoConnect()
   254  	c.Check(err, NotNil)
   255  }
   256  
   257  func (s *baseDeclSuite) TestHomeReadDefault(c *C) {
   258  	const plugYaml = `name: plug-snap
   259  version: 0
   260  plugs:
   261    home: null
   262  `
   263  	restore := release.MockOnClassic(true)
   264  	defer restore()
   265  	cand := s.connectCand(c, "home", "", plugYaml)
   266  	err := cand.Check()
   267  	c.Check(err, IsNil)
   268  
   269  	// Same as TestInterimAutoConnectionHome()
   270  	arity, err := cand.CheckAutoConnect()
   271  	c.Check(err, IsNil)
   272  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   273  
   274  	release.OnClassic = false
   275  	err = cand.Check()
   276  	c.Check(err, IsNil)
   277  
   278  	// Same as TestInterimAutoConnectionHome()
   279  	_, err = cand.CheckAutoConnect()
   280  	c.Check(err, NotNil)
   281  }
   282  
   283  func (s *baseDeclSuite) TestAutoConnectionSnapdControl(c *C) {
   284  	cand := s.connectCand(c, "snapd-control", "", "")
   285  	_, err := cand.CheckAutoConnect()
   286  	c.Check(err, NotNil)
   287  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"snapd-control\"")
   288  
   289  	plugsSlots := `
   290  plugs:
   291    snapd-control:
   292      allow-auto-connection: true
   293  `
   294  
   295  	lxdDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   296  	cand.PlugSnapDeclaration = lxdDecl
   297  	arity, err := cand.CheckAutoConnect()
   298  	c.Check(err, IsNil)
   299  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   300  }
   301  
   302  func (s *baseDeclSuite) TestAutoConnectionContent(c *C) {
   303  	// random snaps cannot connect with content
   304  	// (Sanitize* will now also block this)
   305  	cand := s.connectCand(c, "content", "", "")
   306  	_, err := cand.CheckAutoConnect()
   307  	c.Check(err, NotNil)
   308  
   309  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
   310  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
   311  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
   312  
   313  	// same publisher, same content
   314  	cand = s.connectCand(c, "stuff", `
   315  name: slot-snap
   316  version: 0
   317  slots:
   318    stuff:
   319      interface: content
   320      content: mk1
   321  `, `
   322  name: plug-snap
   323  version: 0
   324  plugs:
   325    stuff:
   326      interface: content
   327      content: mk1
   328  `)
   329  	cand.SlotSnapDeclaration = slotDecl1
   330  	cand.PlugSnapDeclaration = plugDecl1
   331  	arity, err := cand.CheckAutoConnect()
   332  	c.Check(err, IsNil)
   333  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   334  
   335  	// different publisher, same content
   336  	cand.SlotSnapDeclaration = slotDecl1
   337  	cand.PlugSnapDeclaration = plugDecl2
   338  	_, err = cand.CheckAutoConnect()
   339  	c.Check(err, NotNil)
   340  
   341  	// same publisher, different content
   342  	cand = s.connectCand(c, "stuff", `name: slot-snap
   343  version: 0
   344  slots:
   345    stuff:
   346      interface: content
   347      content: mk1
   348  `, `
   349  name: plug-snap
   350  version: 0
   351  plugs:
   352    stuff:
   353      interface: content
   354      content: mk2
   355  `)
   356  	cand.SlotSnapDeclaration = slotDecl1
   357  	cand.PlugSnapDeclaration = plugDecl1
   358  	_, err = cand.CheckAutoConnect()
   359  	c.Check(err, NotNil)
   360  }
   361  
   362  func (s *baseDeclSuite) TestAutoConnectionSharedMemory(c *C) {
   363  	// random snaps cannot connect with shared-memory
   364  	// (Sanitize* will now also block this)
   365  	cand := s.connectCand(c, "shared-memory", "", "")
   366  	_, err := cand.CheckAutoConnect()
   367  	c.Check(err, NotNil)
   368  
   369  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
   370  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
   371  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
   372  
   373  	// same publisher, same shared-memory
   374  	cand = s.connectCand(c, "stuff", `
   375  name: slot-snap
   376  version: 0
   377  slots:
   378    stuff:
   379      interface: shared-memory
   380      shared-memory: mk1
   381  `, `
   382  name: plug-snap
   383  version: 0
   384  plugs:
   385    stuff:
   386      interface: shared-memory
   387      private: false
   388      shared-memory: mk1
   389  `)
   390  	cand.SlotSnapDeclaration = slotDecl1
   391  	cand.PlugSnapDeclaration = plugDecl1
   392  	arity, err := cand.CheckAutoConnect()
   393  	c.Check(err, IsNil)
   394  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   395  
   396  	// different publisher, same shared-memory
   397  	cand.SlotSnapDeclaration = slotDecl1
   398  	cand.PlugSnapDeclaration = plugDecl2
   399  	_, err = cand.CheckAutoConnect()
   400  	c.Check(err, NotNil)
   401  
   402  	// same publisher, different shared-memory
   403  	cand = s.connectCand(c, "stuff", `name: slot-snap
   404  version: 0
   405  slots:
   406    stuff:
   407      interface: shared-memory
   408      shared-memory: mk1
   409  `, `
   410  name: plug-snap
   411  version: 0
   412  plugs:
   413    stuff:
   414      interface: shared-memory
   415      private: false
   416      shared-memory: mk2
   417  `)
   418  	cand.SlotSnapDeclaration = slotDecl1
   419  	cand.PlugSnapDeclaration = plugDecl1
   420  	_, err = cand.CheckAutoConnect()
   421  	c.Check(err, NotNil)
   422  }
   423  
   424  func (s *baseDeclSuite) TestAutoConnectionSharedMemoryPrivate(c *C) {
   425  	slotDecl := s.mockSnapDecl(c, "snapd", "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4", "canonical", "")
   426  	appSlotDecl := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
   427  	plugDecl := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
   428  
   429  	// private shm plug, implicit slot
   430  	cand := s.connectCand(c, "shared-memory", `
   431  name: snapd
   432  type: snapd
   433  version: 0
   434  slots:
   435    shared-memory:
   436  `, `
   437  name: plug-snap
   438  version: 0
   439  plugs:
   440    shared-memory:
   441      private: true
   442  `)
   443  	cand.SlotSnapDeclaration = slotDecl
   444  	cand.PlugSnapDeclaration = plugDecl
   445  	arity, err := cand.CheckAutoConnect()
   446  	c.Check(err, IsNil)
   447  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
   448  
   449  	// private shm plug, regular app slot
   450  	cand = s.connectCand(c, "shared-memory", `
   451  name: slot-snap
   452  version: 0
   453  slots:
   454    shared-memory:
   455  `, `
   456  name: plug-snap
   457  version: 0
   458  plugs:
   459    shared-memory:
   460      private: true
   461  `)
   462  	cand.SlotSnapDeclaration = appSlotDecl
   463  	cand.PlugSnapDeclaration = plugDecl
   464  	_, err = cand.CheckAutoConnect()
   465  	c.Check(err, NotNil)
   466  
   467  	// regular shm plug, implicit slot
   468  	cand = s.connectCand(c, "shared-memory", `
   469  name: snapd
   470  type: snapd
   471  version: 0
   472  slots:
   473    shared-memory:
   474  `, `
   475  name: plug-snap
   476  version: 0
   477  plugs:
   478    shared-memory:
   479      private: false
   480  `)
   481  	cand.SlotSnapDeclaration = slotDecl
   482  	cand.PlugSnapDeclaration = plugDecl
   483  	_, err = cand.CheckAutoConnect()
   484  	c.Check(err, NotNil)
   485  }
   486  
   487  func (s *baseDeclSuite) TestAutoConnectionLxdSupportOverride(c *C) {
   488  	// by default, don't auto-connect
   489  	cand := s.connectCand(c, "lxd-support", "", "")
   490  	_, err := cand.CheckAutoConnect()
   491  	c.Check(err, NotNil)
   492  
   493  	plugsSlots := `
   494  plugs:
   495    lxd-support:
   496      allow-auto-connection: true
   497  `
   498  
   499  	lxdDecl := s.mockSnapDecl(c, "lxd", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   500  	cand.PlugSnapDeclaration = lxdDecl
   501  	_, err = cand.CheckAutoConnect()
   502  	c.Check(err, IsNil)
   503  }
   504  
   505  func (s *baseDeclSuite) TestAutoConnectionLxdSupportOverrideRevoke(c *C) {
   506  	cand := s.connectCand(c, "lxd-support", "", "")
   507  	plugsSlots := `
   508  plugs:
   509    lxd-support:
   510      allow-auto-connection: false
   511  `
   512  
   513  	lxdDecl := s.mockSnapDecl(c, "notlxd", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   514  	cand.PlugSnapDeclaration = lxdDecl
   515  	_, err := cand.CheckAutoConnect()
   516  	c.Check(err, NotNil)
   517  	c.Assert(err, ErrorMatches, "auto-connection not allowed by plug rule of interface \"lxd-support\" for \"notlxd\" snap")
   518  }
   519  
   520  func (s *baseDeclSuite) TestAutoConnectionKernelModuleControlOverride(c *C) {
   521  	cand := s.connectCand(c, "kernel-module-control", "", "")
   522  	_, err := cand.CheckAutoConnect()
   523  	c.Check(err, NotNil)
   524  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"kernel-module-control\"")
   525  
   526  	plugsSlots := `
   527  plugs:
   528    kernel-module-control:
   529      allow-auto-connection: true
   530  `
   531  
   532  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   533  	cand.PlugSnapDeclaration = snapDecl
   534  	_, err = cand.CheckAutoConnect()
   535  	c.Check(err, IsNil)
   536  }
   537  
   538  func (s *baseDeclSuite) TestAutoConnectionDockerSupportOverride(c *C) {
   539  	cand := s.connectCand(c, "docker-support", "", "")
   540  	_, err := cand.CheckAutoConnect()
   541  	c.Check(err, NotNil)
   542  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"docker-support\"")
   543  
   544  	plugsSlots := `
   545  plugs:
   546    docker-support:
   547      allow-auto-connection: true
   548  `
   549  
   550  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   551  	cand.PlugSnapDeclaration = snapDecl
   552  	_, err = cand.CheckAutoConnect()
   553  	c.Check(err, IsNil)
   554  }
   555  
   556  func (s *baseDeclSuite) TestAutoConnectionClassicSupportOverride(c *C) {
   557  	cand := s.connectCand(c, "classic-support", "", "")
   558  	_, err := cand.CheckAutoConnect()
   559  	c.Check(err, NotNil)
   560  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"classic-support\"")
   561  
   562  	plugsSlots := `
   563  plugs:
   564    classic-support:
   565      allow-auto-connection: true
   566  `
   567  
   568  	snapDecl := s.mockSnapDecl(c, "classic", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   569  	cand.PlugSnapDeclaration = snapDecl
   570  	_, err = cand.CheckAutoConnect()
   571  	c.Check(err, IsNil)
   572  }
   573  
   574  func (s *baseDeclSuite) TestAutoConnectionKubernetesSupportOverride(c *C) {
   575  	cand := s.connectCand(c, "kubernetes-support", "", "")
   576  	_, err := cand.CheckAutoConnect()
   577  	c.Check(err, NotNil)
   578  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"kubernetes-support\"")
   579  
   580  	plugsSlots := `
   581  plugs:
   582    kubernetes-support:
   583      allow-auto-connection: true
   584  `
   585  
   586  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   587  	cand.PlugSnapDeclaration = snapDecl
   588  	_, err = cand.CheckAutoConnect()
   589  	c.Check(err, IsNil)
   590  }
   591  
   592  func (s *baseDeclSuite) TestAutoConnectionMicroStackSupportOverride(c *C) {
   593  	cand := s.connectCand(c, "microstack-support", "", "")
   594  	_, err := cand.CheckAutoConnect()
   595  	c.Check(err, NotNil)
   596  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"microstack-support\"")
   597  
   598  	plugsSlots := `
   599  plugs:
   600    microstack-support:
   601      allow-auto-connection: true
   602  `
   603  
   604  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   605  	cand.PlugSnapDeclaration = snapDecl
   606  	_, err = cand.CheckAutoConnect()
   607  	c.Check(err, IsNil)
   608  }
   609  func (s *baseDeclSuite) TestAutoConnectionGreengrassSupportOverride(c *C) {
   610  	cand := s.connectCand(c, "greengrass-support", "", "")
   611  	_, err := cand.CheckAutoConnect()
   612  	c.Check(err, NotNil)
   613  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"greengrass-support\"")
   614  
   615  	plugsSlots := `
   616  plugs:
   617    greengrass-support:
   618      allow-auto-connection: true
   619  `
   620  
   621  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   622  	cand.PlugSnapDeclaration = snapDecl
   623  	_, err = cand.CheckAutoConnect()
   624  	c.Check(err, IsNil)
   625  }
   626  
   627  func (s *baseDeclSuite) TestAutoConnectionMultipassSupportOverride(c *C) {
   628  	cand := s.connectCand(c, "multipass-support", "", "")
   629  	_, err := cand.CheckAutoConnect()
   630  	c.Check(err, NotNil)
   631  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"multipass-support\"")
   632  
   633  	plugsSlots := `
   634  plugs:
   635    multipass-support:
   636      allow-auto-connection: true
   637  `
   638  
   639  	snapDecl := s.mockSnapDecl(c, "multipass-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   640  	cand.PlugSnapDeclaration = snapDecl
   641  	_, err = cand.CheckAutoConnect()
   642  	c.Check(err, IsNil)
   643  }
   644  
   645  func (s *baseDeclSuite) TestAutoConnectionBlockDevicesOverride(c *C) {
   646  	cand := s.connectCand(c, "block-devices", "", "")
   647  	_, err := cand.CheckAutoConnect()
   648  	c.Check(err, NotNil)
   649  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"block-devices\"")
   650  
   651  	plugsSlots := `
   652  plugs:
   653    block-devices:
   654      allow-auto-connection: true
   655  `
   656  
   657  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   658  	cand.PlugSnapDeclaration = snapDecl
   659  	_, err = cand.CheckAutoConnect()
   660  	c.Check(err, IsNil)
   661  }
   662  
   663  func (s *baseDeclSuite) TestAutoConnectionPackagekitControlOverride(c *C) {
   664  	cand := s.connectCand(c, "packagekit-control", "", "")
   665  	_, err := cand.CheckAutoConnect()
   666  	c.Check(err, NotNil)
   667  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"packagekit-control\"")
   668  
   669  	plugsSlots := `
   670  plugs:
   671    packagekit-control:
   672      allow-auto-connection: true
   673  `
   674  
   675  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   676  	cand.PlugSnapDeclaration = snapDecl
   677  	_, err = cand.CheckAutoConnect()
   678  	c.Check(err, IsNil)
   679  }
   680  
   681  func (s *baseDeclSuite) TestAutoConnectionPosixMQOverride(c *C) {
   682  	cand := s.connectCand(c, "posix-mq", "", "")
   683  	_, err := cand.CheckAutoConnect()
   684  	c.Check(err, NotNil)
   685  	c.Assert(err, ErrorMatches, "auto-connection not allowed by plug rule of interface \"posix-mq\"")
   686  
   687  	plugsSlots := `
   688  plugs:
   689    posix-mq:
   690      allow-auto-connection: true
   691  `
   692  
   693  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   694  	cand.PlugSnapDeclaration = snapDecl
   695  	_, err = cand.CheckAutoConnect()
   696  	c.Check(err, IsNil)
   697  }
   698  
   699  func (s *baseDeclSuite) TestAutoConnectionSteamSupportOverride(c *C) {
   700  	cand := s.connectCand(c, "steam-support", "", "")
   701  	_, err := cand.CheckAutoConnect()
   702  	c.Check(err, NotNil)
   703  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"steam-support\"")
   704  
   705  	plugsSlots := `
   706  plugs:
   707    steam-support:
   708      allow-auto-connection: true
   709  `
   710  
   711  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   712  	cand.PlugSnapDeclaration = snapDecl
   713  	_, err = cand.CheckAutoConnect()
   714  	c.Check(err, IsNil)
   715  }
   716  
   717  func (s *baseDeclSuite) TestAutoConnectionOverrideMultiple(c *C) {
   718  	plugsSlots := `
   719  plugs:
   720    network-bind:
   721      allow-auto-connection: true
   722    network-control:
   723      allow-auto-connection: true
   724    kernel-module-control:
   725      allow-auto-connection: true
   726    system-observe:
   727      allow-auto-connection: true
   728    hardware-observe:
   729      allow-auto-connection: true
   730  `
   731  
   732  	snapDecl := s.mockSnapDecl(c, "some-snap", "J60k4JY0HppjwOjW8dZdYc8obXKxujRu", "canonical", plugsSlots)
   733  
   734  	all := builtin.Interfaces()
   735  	// these are a mixture interfaces that the snap plugs
   736  	plugged := map[string]bool{
   737  		"network-bind":          true,
   738  		"network-control":       true,
   739  		"kernel-module-control": true,
   740  		"system-observe":        true,
   741  		"hardware-observe":      true,
   742  	}
   743  	for _, iface := range all {
   744  		if !plugged[iface.Name()] {
   745  			continue
   746  		}
   747  
   748  		cand := s.connectCand(c, iface.Name(), "", "")
   749  		cand.PlugSnapDeclaration = snapDecl
   750  		arity, err := cand.CheckAutoConnect()
   751  		c.Check(err, IsNil)
   752  		c.Check(arity.SlotsPerPlugAny(), Equals, false)
   753  	}
   754  }
   755  
   756  // describe installation rules for slots succinctly for cross-checking,
   757  // if an interface is not mentioned here a slot of its type can only
   758  // be installed by a core snap (and this was taken care by
   759  // BeforePrepareSlot),
   760  // otherwise the entry for the interface is the list of snap types it
   761  // can be installed by (using the declaration naming);
   762  // ATM a nil entry means even stricter rules that would need be tested
   763  // separately and whose implementation is in flux for now
   764  var (
   765  	slotInstallation = map[string][]string{
   766  		// other
   767  		"adb-support":               {"core"},
   768  		"audio-playback":            {"app", "core"},
   769  		"audio-record":              {"app", "core"},
   770  		"autopilot-introspection":   {"core"},
   771  		"avahi-control":             {"app", "core"},
   772  		"avahi-observe":             {"app", "core"},
   773  		"bluez":                     {"app", "core"},
   774  		"bool-file":                 {"core", "gadget"},
   775  		"browser-support":           {"core"},
   776  		"content":                   {"app", "gadget"},
   777  		"core-support":              {"core"},
   778  		"cups":                      {"app"},
   779  		"cups-control":              {"app", "core"},
   780  		"dbus":                      {"app"},
   781  		"docker-support":            {"core"},
   782  		"desktop-launch":            {"core"},
   783  		"dsp":                       {"core", "gadget"},
   784  		"empty":                     {"app"},
   785  		"fwupd":                     {"app", "core"},
   786  		"gpio":                      {"core", "gadget"},
   787  		"gpio-control":              {"core"},
   788  		"greengrass-support":        {"core"},
   789  		"hidraw":                    {"core", "gadget"},
   790  		"i2c":                       {"core", "gadget"},
   791  		"iio":                       {"core", "gadget"},
   792  		"kernel-module-load":        {"core"},
   793  		"kubernetes-support":        {"core"},
   794  		"location-control":          {"app"},
   795  		"location-observe":          {"app"},
   796  		"lxd-support":               {"core"},
   797  		"maliit":                    {"app"},
   798  		"media-hub":                 {"app", "core"},
   799  		"mir":                       {"app"},
   800  		"microstack-support":        {"core"},
   801  		"modem-manager":             {"app", "core"},
   802  		"mount-control":             {"core"},
   803  		"mpris":                     {"app"},
   804  		"netlink-driver":            {"core", "gadget"},
   805  		"network-manager":           {"app", "core"},
   806  		"network-manager-observe":   {"app", "core"},
   807  		"network-status":            {"core"},
   808  		"ofono":                     {"app", "core"},
   809  		"online-accounts-service":   {"app"},
   810  		"power-control":             {"core"},
   811  		"ppp":                       {"core"},
   812  		"pulseaudio":                {"app", "core"},
   813  		"pwm":                       {"core", "gadget"},
   814  		"qualcomm-ipc-router":       {"core"},
   815  		"raw-volume":                {"core", "gadget"},
   816  		"scsi-generic":              {"core"},
   817  		"sd-control":                {"core"},
   818  		"serial-port":               {"core", "gadget"},
   819  		"spi":                       {"core", "gadget"},
   820  		"steam-support":             {"core"},
   821  		"storage-framework-service": {"app"},
   822  		"thumbnailer-service":       {"app"},
   823  		"ubuntu-download-manager":   {"app"},
   824  		"udisks2":                   {"app", "core"},
   825  		"uhid":                      {"core"},
   826  		"uio":                       {"core", "gadget"},
   827  		"unity8":                    {"app"},
   828  		"unity8-calendar":           {"app"},
   829  		"unity8-contacts":           {"app"},
   830  		"upower-observe":            {"app", "core"},
   831  		"wayland":                   {"app", "core"},
   832  		"x11":                       {"app", "core"},
   833  		// snowflakes
   834  		"classic-support": nil,
   835  		"custom-device":   nil,
   836  		"docker":          nil,
   837  		"lxd":             nil,
   838  		"microceph":       nil,
   839  		"pkcs11":          nil,
   840  		"posix-mq":        nil,
   841  		"shared-memory":   nil,
   842  	}
   843  
   844  	restrictedPlugInstallation = map[string][]string{
   845  		"core-support": {"core"},
   846  	}
   847  
   848  	snapTypeMap = map[string]snap.Type{
   849  		"core":   snap.TypeOS,
   850  		"app":    snap.TypeApp,
   851  		"kernel": snap.TypeKernel,
   852  		"gadget": snap.TypeGadget,
   853  	}
   854  )
   855  
   856  func (s *baseDeclSuite) TestSlotInstallation(c *C) {
   857  	all := builtin.Interfaces()
   858  
   859  	for _, iface := range all {
   860  		types, ok := slotInstallation[iface.Name()]
   861  		if !ok { // common ones, only core can install them,
   862  			types = []string{"core"}
   863  		}
   864  
   865  		if types == nil {
   866  			// snowflake needs to be tested specially
   867  			continue
   868  		}
   869  		for name, snapType := range snapTypeMap {
   870  			ok := strutil.ListContains(types, name)
   871  			ic := s.installSlotCand(c, iface.Name(), snapType, ``)
   872  			err := ic.Check()
   873  			comm := Commentf("%s by %s snap", iface.Name(), name)
   874  			if ok {
   875  				c.Check(err, IsNil, comm)
   876  			} else {
   877  				c.Check(err, NotNil, comm)
   878  			}
   879  		}
   880  	}
   881  
   882  	// test docker specially
   883  	ic := s.installSlotCand(c, "docker", snap.TypeApp, ``)
   884  	err := ic.Check()
   885  	c.Assert(err, Not(IsNil))
   886  	c.Assert(err, ErrorMatches, "installation not allowed by \"docker\" slot rule of interface \"docker\"")
   887  
   888  	// test lxd specially
   889  	ic = s.installSlotCand(c, "lxd", snap.TypeApp, ``)
   890  	err = ic.Check()
   891  	c.Assert(err, Not(IsNil))
   892  	c.Assert(err, ErrorMatches, "installation not allowed by \"lxd\" slot rule of interface \"lxd\"")
   893  
   894  	// test microceph specially
   895  	ic = s.installSlotCand(c, "microceph", snap.TypeApp, ``)
   896  	err = ic.Check()
   897  	c.Assert(err, Not(IsNil))
   898  	c.Assert(err, ErrorMatches, "installation not allowed by \"microceph\" slot rule of interface \"microceph\"")
   899  
   900  	// test shared-memory specially
   901  	ic = s.installSlotCand(c, "shared-memory", snap.TypeApp, ``)
   902  	err = ic.Check()
   903  	c.Assert(err, Not(IsNil))
   904  	c.Assert(err, ErrorMatches, "installation not allowed by \"shared-memory\" slot rule of interface \"shared-memory\"")
   905  
   906  	// The core and snapd snaps may provide a shared-memory slot
   907  	ic = s.installSlotCand(c, "shared-memory", snap.TypeOS, `name: core
   908  version: 0
   909  type: os
   910  slots:
   911    shared-memory:
   912  `)
   913  	ic.SnapDeclaration = s.mockSnapDecl(c, "core", "99T7MUlRhtI3U0QFgl5mXXESAiSwt776", "canonical", "")
   914  	c.Assert(ic.Check(), IsNil)
   915  
   916  	ic = s.installSlotCand(c, "shared-memory", snap.TypeSnapd, `name: snapd
   917  version: 0
   918  type: snapd
   919  slots:
   920    shared-memory:
   921  `)
   922  	ic.SnapDeclaration = s.mockSnapDecl(c, "snapd", "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4", "canonical", "")
   923  	c.Assert(ic.Check(), IsNil)
   924  }
   925  
   926  func (s *baseDeclSuite) TestPlugInstallation(c *C) {
   927  	all := builtin.Interfaces()
   928  
   929  	restricted := map[string]bool{
   930  		"block-devices":         true,
   931  		"classic-support":       true,
   932  		"desktop-launch":        true,
   933  		"dm-crypt":              true,
   934  		"docker-support":        true,
   935  		"greengrass-support":    true,
   936  		"gpio-control":          true,
   937  		"ion-memory-control":    true,
   938  		"kernel-module-control": true,
   939  		"kernel-module-load":    true,
   940  		"kubernetes-support":    true,
   941  		"lxd-support":           true,
   942  		"microstack-support":    true,
   943  		"mount-control":         true,
   944  		"multipass-support":     true,
   945  		"packagekit-control":    true,
   946  		"personal-files":        true,
   947  		"polkit":                true,
   948  		"sd-control":            true,
   949  		"snap-refresh-control":  true,
   950  		"snap-themes-control":   true,
   951  		"snapd-control":         true,
   952  		"steam-support":         true,
   953  		"system-files":          true,
   954  		"tee":                   true,
   955  		"uinput":                true,
   956  		"unity8":                true,
   957  		"xilinx-dma":            true,
   958  	}
   959  
   960  	for _, iface := range all {
   961  		types, ok := restrictedPlugInstallation[iface.Name()]
   962  		// If plug installation is restricted to specific snap types we
   963  		// need to make sure this is really the case here. If that is not
   964  		// the case we continue as normal.
   965  		if ok {
   966  			for name, snapType := range snapTypeMap {
   967  				ok := strutil.ListContains(types, name)
   968  				ic := s.installPlugCand(c, iface.Name(), snapType, ``)
   969  				err := ic.Check()
   970  				comm := Commentf("%s by %s snap", iface.Name(), name)
   971  				if ok {
   972  					c.Check(err, IsNil, comm)
   973  				} else {
   974  					c.Check(err, NotNil, comm)
   975  				}
   976  			}
   977  		} else {
   978  			ic := s.installPlugCand(c, iface.Name(), snap.TypeApp, ``)
   979  			err := ic.Check()
   980  			comm := Commentf("%s", iface.Name())
   981  			if restricted[iface.Name()] {
   982  				c.Check(err, NotNil, comm)
   983  			} else {
   984  				c.Check(err, IsNil, comm)
   985  			}
   986  		}
   987  	}
   988  }
   989  
   990  func (s *baseDeclSuite) TestConnection(c *C) {
   991  	all := builtin.Interfaces()
   992  
   993  	// connecting with these interfaces needs to be allowed on
   994  	// case-by-case basis
   995  	noconnect := map[string]bool{
   996  		"content":                   true,
   997  		"cups":                      true,
   998  		"custom-device":             true,
   999  		"docker":                    true,
  1000  		"fwupd":                     true,
  1001  		"location-control":          true,
  1002  		"location-observe":          true,
  1003  		"lxd":                       true,
  1004  		"maliit":                    true,
  1005  		"microceph":                 true,
  1006  		"mir":                       true,
  1007  		"online-accounts-service":   true,
  1008  		"posix-mq":                  true,
  1009  		"raw-volume":                true,
  1010  		"shared-memory":             true,
  1011  		"storage-framework-service": true,
  1012  		"thumbnailer-service":       true,
  1013  		"ubuntu-download-manager":   true,
  1014  		"unity8-calendar":           true,
  1015  		"unity8-contacts":           true,
  1016  	}
  1017  
  1018  	for _, iface := range all {
  1019  		expected := !noconnect[iface.Name()]
  1020  		comm := Commentf(iface.Name())
  1021  
  1022  		// check base declaration
  1023  		cand := s.connectCand(c, iface.Name(), "", "")
  1024  		err := cand.Check()
  1025  
  1026  		if expected {
  1027  			c.Check(err, IsNil, comm)
  1028  		} else {
  1029  			c.Check(err, NotNil, comm)
  1030  		}
  1031  	}
  1032  }
  1033  
  1034  func (s *baseDeclSuite) TestConnectionOnClassic(c *C) {
  1035  	restore := release.MockOnClassic(false)
  1036  	defer restore()
  1037  
  1038  	all := builtin.Interfaces()
  1039  
  1040  	// connecting with these interfaces needs to be allowed on
  1041  	// case-by-case basis when not on classic
  1042  	noconnect := map[string]bool{
  1043  		"audio-record":    true,
  1044  		"modem-manager":   true,
  1045  		"network-manager": true,
  1046  		"ofono":           true,
  1047  		"pulseaudio":      true,
  1048  		"upower-observe":  true,
  1049  	}
  1050  
  1051  	for _, onClassic := range []bool{true, false} {
  1052  		release.OnClassic = onClassic
  1053  		for _, iface := range all {
  1054  			if !noconnect[iface.Name()] {
  1055  				continue
  1056  			}
  1057  			expected := onClassic
  1058  			comm := Commentf(iface.Name())
  1059  
  1060  			// check base declaration
  1061  			cand := s.connectCand(c, iface.Name(), "", "")
  1062  			err := cand.Check()
  1063  
  1064  			if expected {
  1065  				c.Check(err, IsNil, comm)
  1066  			} else {
  1067  				c.Check(err, NotNil, comm)
  1068  			}
  1069  		}
  1070  	}
  1071  }
  1072  
  1073  func (s *baseDeclSuite) TestConnectionImplicitOnClassicOrAppSnap(c *C) {
  1074  	restore := release.MockOnClassic(false)
  1075  	defer restore()
  1076  
  1077  	all := builtin.Interfaces()
  1078  
  1079  	// These interfaces represent when the interface might be implicit on
  1080  	// classic or when the interface is provided via an app snap. As such,
  1081  	// they all share the following:
  1082  	//
  1083  	// - implicitOnCore: false
  1084  	// - implicitOnClassis: true
  1085  	// - base declaration uses:
  1086  	//     allow-installation:
  1087  	//       slot-snap-type:
  1088  	//         - app
  1089  	//         - core
  1090  	//     deny-connection:
  1091  	//       on-classic: false
  1092  	//     deny-auto-connection: true|false|unspecified
  1093  	//
  1094  	// connecting with these interfaces needs to be allowed on
  1095  	// case-by-case basis when not on classic
  1096  	ifaces := map[string]bool{
  1097  		"audio-playback":  true,
  1098  		"audio-record":    true,
  1099  		"cups-control":    true,
  1100  		"modem-manager":   true,
  1101  		"network-manager": true,
  1102  		"ofono":           true,
  1103  		"pulseaudio":      true,
  1104  		"upower-observe":  true,
  1105  	}
  1106  
  1107  	for _, iface := range all {
  1108  		if !ifaces[iface.Name()] {
  1109  			continue
  1110  		}
  1111  		comm := Commentf(iface.Name())
  1112  
  1113  		// verify the interface is setup as expected wrt
  1114  		// implicitOnCore, implicitOnClassic, no plugs and has
  1115  		// expected slots (ignoring AutoConnection)
  1116  		si := interfaces.StaticInfoOf(iface)
  1117  		c.Assert(si.ImplicitOnCore, Equals, false)
  1118  		c.Assert(si.ImplicitOnClassic, Equals, true)
  1119  
  1120  		c.Assert(s.baseDecl.PlugRule(iface.Name()), IsNil)
  1121  
  1122  		sr := s.baseDecl.SlotRule(iface.Name())
  1123  		c.Assert(sr, Not(IsNil))
  1124  		c.Assert(sr.AllowInstallation, HasLen, 1)
  1125  		c.Check(sr.AllowInstallation[0].SlotSnapTypes, DeepEquals, []string{"app", "core"}, comm)
  1126  		c.Assert(sr.DenyConnection, HasLen, 1)
  1127  		c.Check(sr.DenyConnection[0].OnClassic, DeepEquals, &asserts.OnClassicConstraint{Classic: false}, comm)
  1128  
  1129  		for _, onClassic := range []bool{true, false} {
  1130  			release.OnClassic = onClassic
  1131  
  1132  			for _, implicit := range []bool{true, false} {
  1133  				// When implicitOnCore is false, there is
  1134  				// nothing to test on Core
  1135  				if implicit && !onClassic {
  1136  					continue
  1137  				}
  1138  
  1139  				snapType := "app"
  1140  				if implicit {
  1141  					snapType = "os"
  1142  				}
  1143  				slotYaml := fmt.Sprintf(`name: slot-snap
  1144  version: 0
  1145  type: %s
  1146  slots:
  1147    %s:
  1148  `, snapType, iface.Name())
  1149  
  1150  				// XXX: eventually 'onClassic && !implicit' but
  1151  				// the current declaration allows connection on
  1152  				// Core when 'type: app'. See:
  1153  				// https://github.com/snapcore/snapd/pull/8920/files#r471678529
  1154  				expected := onClassic
  1155  
  1156  				// check base declaration
  1157  				cand := s.connectCand(c, iface.Name(), slotYaml, "")
  1158  				err := cand.Check()
  1159  
  1160  				if expected {
  1161  					c.Check(err, IsNil, comm)
  1162  				} else {
  1163  					c.Check(err, NotNil, comm)
  1164  				}
  1165  			}
  1166  		}
  1167  	}
  1168  }
  1169  
  1170  func (s *baseDeclSuite) TestValidity(c *C) {
  1171  	all := builtin.Interfaces()
  1172  
  1173  	// these interfaces have rules both for the slots and plugs side
  1174  	// given how the rules work this can be delicate,
  1175  	// listed here to make sure that was a conscious decision
  1176  	bothSides := map[string]bool{
  1177  		"block-devices":         true,
  1178  		"audio-playback":        true,
  1179  		"classic-support":       true,
  1180  		"core-support":          true,
  1181  		"custom-device":         true,
  1182  		"desktop-launch":        true,
  1183  		"dm-crypt":              true,
  1184  		"docker-support":        true,
  1185  		"greengrass-support":    true,
  1186  		"gpio-control":          true,
  1187  		"ion-memory-control":    true,
  1188  		"kernel-module-control": true,
  1189  		"kernel-module-load":    true,
  1190  		"kubernetes-support":    true,
  1191  		"lxd-support":           true,
  1192  		"microstack-support":    true,
  1193  		"mount-control":         true,
  1194  		"multipass-support":     true,
  1195  		"packagekit-control":    true,
  1196  		"personal-files":        true,
  1197  		"pkcs11":                true,
  1198  		"posix-mq":              true,
  1199  		"polkit":                true,
  1200  		"sd-control":            true,
  1201  		"shared-memory":         true,
  1202  		"snap-refresh-control":  true,
  1203  		"snap-themes-control":   true,
  1204  		"snapd-control":         true,
  1205  		"steam-support":         true,
  1206  		"system-files":          true,
  1207  		"tee":                   true,
  1208  		"udisks2":               true,
  1209  		"uinput":                true,
  1210  		"unity8":                true,
  1211  		"wayland":               true,
  1212  		"xilinx-dma":            true,
  1213  	}
  1214  
  1215  	for _, iface := range all {
  1216  		plugRule := s.baseDecl.PlugRule(iface.Name())
  1217  		slotRule := s.baseDecl.SlotRule(iface.Name())
  1218  		if plugRule == nil && slotRule == nil {
  1219  			c.Logf("%s is not considered in the base declaration", iface.Name())
  1220  			c.Fail()
  1221  		}
  1222  		if plugRule != nil && slotRule != nil {
  1223  			if !bothSides[iface.Name()] {
  1224  				c.Logf("%s have both a base declaration slot rule and plug rule, make sure that's intended and correct", iface.Name())
  1225  				c.Fail()
  1226  			}
  1227  		}
  1228  	}
  1229  }
  1230  
  1231  func (s *baseDeclSuite) TestConnectionContent(c *C) {
  1232  	// we let connect explicitly as long as content matches (or is absent on both sides)
  1233  
  1234  	// random (Sanitize* will now also block this)
  1235  	cand := s.connectCand(c, "content", "", "")
  1236  	err := cand.Check()
  1237  	c.Check(err, NotNil)
  1238  
  1239  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
  1240  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
  1241  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
  1242  
  1243  	// same publisher, same content
  1244  	cand = s.connectCand(c, "stuff", `name: slot-snap
  1245  version: 0
  1246  slots:
  1247    stuff:
  1248      interface: content
  1249      content: mk1
  1250  `, `
  1251  name: plug-snap
  1252  version: 0
  1253  plugs:
  1254    stuff:
  1255      interface: content
  1256      content: mk1
  1257  `)
  1258  	cand.SlotSnapDeclaration = slotDecl1
  1259  	cand.PlugSnapDeclaration = plugDecl1
  1260  	err = cand.Check()
  1261  	c.Check(err, IsNil)
  1262  
  1263  	// different publisher, same content
  1264  	cand.SlotSnapDeclaration = slotDecl1
  1265  	cand.PlugSnapDeclaration = plugDecl2
  1266  	err = cand.Check()
  1267  	c.Check(err, IsNil)
  1268  
  1269  	// same publisher, different content
  1270  	cand = s.connectCand(c, "stuff", `
  1271  name: slot-snap
  1272  version: 0
  1273  slots:
  1274    stuff:
  1275      interface: content
  1276      content: mk1
  1277  `, `
  1278  name: plug-snap
  1279  version: 0
  1280  plugs:
  1281    stuff:
  1282      interface: content
  1283      content: mk2
  1284  `)
  1285  	cand.SlotSnapDeclaration = slotDecl1
  1286  	cand.PlugSnapDeclaration = plugDecl1
  1287  	err = cand.Check()
  1288  	c.Check(err, NotNil)
  1289  }
  1290  
  1291  func (s *baseDeclSuite) TestConnectionSharedMemory(c *C) {
  1292  	// we let connect explicitly as long as shared-memory matches
  1293  
  1294  	// random (Sanitize* will now also block this)
  1295  	cand := s.connectCand(c, "shared-memory", "", "")
  1296  	err := cand.Check()
  1297  	c.Check(err, NotNil)
  1298  
  1299  	slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
  1300  	plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
  1301  	plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")
  1302  
  1303  	// same publisher, same shared-memory
  1304  	cand = s.connectCand(c, "stuff", `name: slot-snap
  1305  version: 0
  1306  slots:
  1307    stuff:
  1308      interface: shared-memory
  1309      shared-memory: mk1
  1310  `, `
  1311  name: plug-snap
  1312  version: 0
  1313  plugs:
  1314    stuff:
  1315      interface: shared-memory
  1316      private: false
  1317      shared-memory: mk1
  1318  `)
  1319  	cand.SlotSnapDeclaration = slotDecl1
  1320  	cand.PlugSnapDeclaration = plugDecl1
  1321  	err = cand.Check()
  1322  	c.Check(err, IsNil)
  1323  
  1324  	// different publisher, same shared-memory
  1325  	cand.SlotSnapDeclaration = slotDecl1
  1326  	cand.PlugSnapDeclaration = plugDecl2
  1327  	err = cand.Check()
  1328  	c.Check(err, IsNil)
  1329  
  1330  	// same publisher, different shared-memory
  1331  	cand = s.connectCand(c, "stuff", `
  1332  name: slot-snap
  1333  version: 0
  1334  slots:
  1335    stuff:
  1336      interface: shared-memory
  1337      shared-memory: mk1
  1338  `, `
  1339  name: plug-snap
  1340  version: 0
  1341  plugs:
  1342    stuff:
  1343      interface: shared-memory
  1344      private: false
  1345      shared-memory: mk2
  1346  `)
  1347  	cand.SlotSnapDeclaration = slotDecl1
  1348  	cand.PlugSnapDeclaration = plugDecl1
  1349  	err = cand.Check()
  1350  	c.Check(err, NotNil)
  1351  }
  1352  
  1353  func (s *baseDeclSuite) TestConnectionSharedMemoryPrivate(c *C) {
  1354  	slotDecl := s.mockSnapDecl(c, "snapd", "PMrrV4ml8uWuEUDBT8dSGnKUYbevVhc4", "canonical", "")
  1355  	appSlotDecl := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
  1356  	plugDecl := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
  1357  
  1358  	// private shm plug, implicit slot
  1359  	cand := s.connectCand(c, "shared-memory", `name: snapd
  1360  type: snapd
  1361  version: 0
  1362  slots:
  1363    shared-memory:
  1364  `, `
  1365  name: plug-snap
  1366  version: 0
  1367  plugs:
  1368    shared-memory:
  1369      private: true
  1370  `)
  1371  	cand.SlotSnapDeclaration = slotDecl
  1372  	cand.PlugSnapDeclaration = plugDecl
  1373  	err := cand.Check()
  1374  	c.Check(err, IsNil)
  1375  
  1376  	// private shm plug, regular app slot
  1377  	cand = s.connectCand(c, "shared-memory", `name: slot-snap
  1378  version: 0
  1379  slots:
  1380    shared-memory:
  1381      shared-memory: mk1
  1382  `, `
  1383  name: plug-snap
  1384  version: 0
  1385  plugs:
  1386    shared-memory:
  1387      private: true
  1388  `)
  1389  	cand.SlotSnapDeclaration = appSlotDecl
  1390  	cand.PlugSnapDeclaration = plugDecl
  1391  	err = cand.Check()
  1392  	c.Check(err, NotNil)
  1393  
  1394  	// regular shm plug, implicit slot
  1395  	cand = s.connectCand(c, "shared-memory", `name: snapd
  1396  type: snapd
  1397  version: 0
  1398  slots:
  1399    shared-memory:
  1400  `, `
  1401  name: plug-snap
  1402  version: 0
  1403  plugs:
  1404    shared-memory:
  1405      shared-memory: mk1
  1406      private: false
  1407  `)
  1408  	cand.SlotSnapDeclaration = slotDecl
  1409  	cand.PlugSnapDeclaration = plugDecl
  1410  	err = cand.Check()
  1411  	c.Check(err, NotNil)
  1412  }
  1413  
  1414  func (s *baseDeclSuite) TestComposeBaseDeclaration(c *C) {
  1415  	decl, err := policy.ComposeBaseDeclaration(nil)
  1416  	c.Assert(err, IsNil)
  1417  	c.Assert(string(decl), testutil.Contains, `
  1418  type: base-declaration
  1419  authority-id: canonical
  1420  series: 16
  1421  revision: 0
  1422  `)
  1423  }
  1424  
  1425  func (s *baseDeclSuite) TestDoesNotPanic(c *C) {
  1426  	// In case there are any issues in the actual interfaces we'd get a panic
  1427  	// on snapd startup. This test prevents this from happing unnoticed.
  1428  	_, err := policy.ComposeBaseDeclaration(builtin.Interfaces())
  1429  	c.Assert(err, IsNil)
  1430  }
  1431  
  1432  func (s *baseDeclSuite) TestBrowserSupportAllowSandbox(c *C) {
  1433  	const plugYaml = `name: plug-snap
  1434  version: 0
  1435  plugs:
  1436    browser-support:
  1437     allow-sandbox: true
  1438  `
  1439  	cand := s.connectCand(c, "browser-support", "", plugYaml)
  1440  	err := cand.Check()
  1441  	c.Check(err, NotNil)
  1442  
  1443  	_, err = cand.CheckAutoConnect()
  1444  	c.Check(err, NotNil)
  1445  }
  1446  
  1447  func (s *baseDeclSuite) TestOpticalDriveWrite(c *C) {
  1448  	type options struct {
  1449  		readonlyYamls []string
  1450  		writableYamls []string
  1451  	}
  1452  
  1453  	opts := &options{
  1454  		readonlyYamls: []string{
  1455  			// Non-specified "write" attribute
  1456  			`name: plug-snap
  1457  version: 0
  1458  plugs:
  1459    optical-drive: null
  1460  `,
  1461  			// Undefined "write" attribute
  1462  			`name: plug-snap
  1463  version: 0
  1464  plugs:
  1465    optical-drive: {}
  1466  `,
  1467  			// False "write" attribute
  1468  			`name: plug-snap
  1469  version: 0
  1470  plugs:
  1471    optical-drive:
  1472      write: false
  1473  `,
  1474  		},
  1475  		writableYamls: []string{
  1476  			// True "write" attribute
  1477  			`name: plug-snap
  1478  version: 0
  1479  plugs:
  1480    optical-drive:
  1481      write: true
  1482  `,
  1483  		},
  1484  	}
  1485  
  1486  	checkOpticalDriveAutoConnect := func(plugYaml string, checker Checker) {
  1487  		cand := s.connectCand(c, "optical-drive", "", plugYaml)
  1488  		err := cand.Check()
  1489  		c.Check(err, checker)
  1490  		_, err = cand.CheckAutoConnect()
  1491  		c.Check(err, checker)
  1492  	}
  1493  
  1494  	for _, plugYaml := range opts.readonlyYamls {
  1495  		checkOpticalDriveAutoConnect(plugYaml, IsNil)
  1496  	}
  1497  	for _, plugYaml := range opts.writableYamls {
  1498  		checkOpticalDriveAutoConnect(plugYaml, NotNil)
  1499  	}
  1500  }
  1501  
  1502  func (s *baseDeclSuite) TestRawVolumeOverride(c *C) {
  1503  	slotYaml := `name: slot-snap
  1504  type: gadget
  1505  version: 0
  1506  slots:
  1507    raw-volume:
  1508      path: /dev/mmcblk0p1
  1509  `
  1510  	slotSnap := snaptest.MockInfo(c, slotYaml, nil)
  1511  	// mock a well-formed slot snap decl with SnapID
  1512  	slotSnapDecl := s.mockSnapDecl(c, "slot-snap", "slotsnapidididididididididididid", "canonical", "")
  1513  
  1514  	plugYaml := `name: plug-snap
  1515  version: 0
  1516  plugs:
  1517    raw-volume:
  1518  `
  1519  	plugSnap := snaptest.MockInfo(c, plugYaml, nil)
  1520  
  1521  	// no plug-side declaration
  1522  	cand := &policy.ConnectCandidate{
  1523  		Plug:                interfaces.NewConnectedPlug(plugSnap.Plugs["raw-volume"], nil, nil),
  1524  		Slot:                interfaces.NewConnectedSlot(slotSnap.Slots["raw-volume"], nil, nil),
  1525  		SlotSnapDeclaration: slotSnapDecl,
  1526  		BaseDeclaration:     s.baseDecl,
  1527  	}
  1528  
  1529  	err := cand.Check()
  1530  	c.Check(err, NotNil)
  1531  	c.Assert(err, ErrorMatches, "connection denied by slot rule of interface \"raw-volume\"")
  1532  	_, err = cand.CheckAutoConnect()
  1533  	c.Check(err, NotNil)
  1534  	c.Assert(err, ErrorMatches, "auto-connection denied by slot rule of interface \"raw-volume\"")
  1535  
  1536  	// specific plug-side declaration for connection only
  1537  	plugsOverride := `
  1538  plugs:
  1539    raw-volume:
  1540      allow-connection:
  1541        slot-snap-id:
  1542          - slotsnapidididididididididididid
  1543      allow-auto-connection: false
  1544  `
  1545  	plugSnapDecl := s.mockSnapDecl(c, "plug-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1546  	cand.PlugSnapDeclaration = plugSnapDecl
  1547  	err = cand.Check()
  1548  	c.Check(err, IsNil)
  1549  	_, err = cand.CheckAutoConnect()
  1550  	c.Check(err, NotNil)
  1551  	c.Assert(err, ErrorMatches, "auto-connection not allowed by plug rule of interface \"raw-volume\" for \"plug-snap\" snap")
  1552  
  1553  	// specific plug-side declaration for connection and auto-connection
  1554  	plugsOverride = `
  1555  plugs:
  1556    raw-volume:
  1557      allow-connection:
  1558        slot-snap-id:
  1559          - slotsnapidididididididididididid
  1560      allow-auto-connection:
  1561        slot-snap-id:
  1562          - slotsnapidididididididididididid
  1563  `
  1564  	plugSnapDecl = s.mockSnapDecl(c, "plug-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1565  	cand.PlugSnapDeclaration = plugSnapDecl
  1566  	err = cand.Check()
  1567  	c.Check(err, IsNil)
  1568  	arity, err := cand.CheckAutoConnect()
  1569  	c.Check(err, IsNil)
  1570  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
  1571  
  1572  	// blanket allow for connection and auto-connection to any slotting snap
  1573  	plugsOverride = `
  1574  plugs:
  1575    raw-volume:
  1576      allow-connection: true
  1577      allow-auto-connection: true
  1578  `
  1579  	plugSnapDecl = s.mockSnapDecl(c, "some-snap", "plugsnapidididididididididididid", "canonical", plugsOverride)
  1580  	cand.PlugSnapDeclaration = plugSnapDecl
  1581  	err = cand.Check()
  1582  	c.Check(err, IsNil)
  1583  	arity, err = cand.CheckAutoConnect()
  1584  	c.Check(err, IsNil)
  1585  	c.Check(arity.SlotsPerPlugAny(), Equals, false)
  1586  }
  1587  
  1588  func (s *baseDeclSuite) TestAutoConnectionDesktopLaunchOverride(c *C) {
  1589  	cand := s.connectCand(c, "desktop-launch", "", "")
  1590  	_, err := cand.CheckAutoConnect()
  1591  	c.Check(err, NotNil)
  1592  	c.Assert(err, ErrorMatches, "auto-connection denied by plug rule of interface \"desktop-launch\"")
  1593  
  1594  	plugsSlots := `
  1595  plugs:
  1596    desktop-launch:
  1597      allow-auto-connection: true
  1598  `
  1599  
  1600  	snapDecl := s.mockSnapDecl(c, "some-snap", "some-snap-with-desktop-launch-id", "canonical", plugsSlots)
  1601  	cand.PlugSnapDeclaration = snapDecl
  1602  	_, err = cand.CheckAutoConnect()
  1603  	c.Check(err, IsNil)
  1604  }