github.com/rigado/snapd@v2.42.5-go-mod+incompatible/interfaces/policy/policy_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-2017 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  	"strings"
    24  	"testing"
    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/policy"
    31  	"github.com/snapcore/snapd/release"
    32  	"github.com/snapcore/snapd/snap"
    33  	"github.com/snapcore/snapd/snap/snaptest"
    34  )
    35  
    36  func TestPolicy(t *testing.T) { TestingT(t) }
    37  
    38  type policySuite struct {
    39  	baseDecl *asserts.BaseDeclaration
    40  
    41  	plugSnap *snap.Info
    42  	slotSnap *snap.Info
    43  
    44  	plugDecl *asserts.SnapDeclaration
    45  	slotDecl *asserts.SnapDeclaration
    46  
    47  	randomSnap *snap.Info
    48  	randomDecl *asserts.SnapDeclaration
    49  
    50  	restoreSanitize func()
    51  }
    52  
    53  var _ = Suite(&policySuite{})
    54  
    55  func (s *policySuite) SetUpSuite(c *C) {
    56  	s.restoreSanitize = snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})
    57  	a, err := asserts.Decode([]byte(`type: base-declaration
    58  authority-id: canonical
    59  series: 16
    60  plugs:
    61    base-plug-allow: true
    62    base-plug-not-allow:
    63      allow-connection: false
    64    base-plug-not-allow-slots:
    65      allow-connection:
    66        slot-attributes:
    67          s: S
    68    base-plug-not-allow-plugs:
    69      allow-connection:
    70        plug-attributes:
    71          p: P
    72    base-plug-deny:
    73      deny-connection: true
    74    same-plug-publisher-id:
    75      allow-connection:
    76        slot-publisher-id:
    77          - $PLUG_PUBLISHER_ID
    78    plug-plug-attr:
    79      allow-connection:
    80        slot-attributes:
    81          c: $PLUG(c)
    82    plug-slot-attr:
    83      allow-connection:
    84        plug-attributes:
    85          c: $SLOT(c)
    86    plug-or:
    87      allow-connection:
    88        -
    89          slot-attributes:
    90            s: S1
    91          plug-attributes:
    92            p: P1
    93        -
    94          slot-attributes:
    95            s: S2
    96          plug-attributes:
    97            p: P2
    98    plug-on-classic-true:
    99      allow-connection:
   100        on-classic: true
   101    plug-on-classic-distros:
   102      allow-connection:
   103        on-classic:
   104          - ubuntu
   105          - debian
   106    plug-on-classic-false:
   107      allow-connection:
   108        on-classic: false
   109    auto-base-plug-allow: true
   110    auto-base-plug-not-allow:
   111      allow-auto-connection: false
   112    auto-base-plug-not-allow-slots:
   113      allow-auto-connection:
   114        slot-attributes:
   115          s: S
   116    auto-base-plug-not-allow-plugs:
   117      allow-auto-connection:
   118        plug-attributes:
   119          p: P
   120    auto-base-plug-deny:
   121      deny-auto-connection: true
   122    auto-plug-or:
   123      allow-auto-connection:
   124        -
   125          slot-attributes:
   126            s: S1
   127          plug-attributes:
   128            p: P1
   129        -
   130          slot-attributes:
   131            s: S2
   132          plug-attributes:
   133            p: P2
   134    auto-plug-on-store1:
   135      allow-auto-connection: false
   136    auto-plug-on-my-brand:
   137      allow-auto-connection: false
   138    auto-plug-on-my-model2:
   139      allow-auto-connection: false
   140    auto-plug-on-multi:
   141      allow-auto-connection: false
   142    install-plug-attr-ok:
   143      allow-installation:
   144        plug-attributes:
   145          attr: ok
   146    install-plug-gadget-only:
   147      allow-installation:
   148        plug-snap-type:
   149          - gadget
   150    install-plug-base-deny-snap-allow:
   151      deny-installation:
   152        plug-attributes:
   153          attr: attrvalue
   154    install-plug-or:
   155      deny-installation:
   156        -
   157          plug-attributes:
   158            p: P1
   159        -
   160          plug-snap-type:
   161            - gadget
   162          plug-attributes:
   163            p: P2
   164    install-plug-on-classic-distros:
   165      allow-installation:
   166        on-classic:
   167          - ubuntu
   168          - debian
   169    install-plug-device-scope:
   170      allow-installation: false
   171  slots:
   172    base-slot-allow: true
   173    base-slot-not-allow:
   174      allow-connection: false
   175    base-slot-not-allow-slots:
   176      allow-connection:
   177        slot-attributes:
   178          s: S
   179    base-slot-not-allow-plugs:
   180      allow-connection:
   181        plug-attributes:
   182          p: P
   183    base-slot-deny:
   184      deny-connection: true
   185    base-deny-snap-slot-allow: false
   186    base-deny-snap-plug-allow: false
   187    base-allow-snap-slot-not-allow: true
   188    gadgethelp:
   189      allow-connection:
   190        plug-snap-type:
   191          - gadget
   192    same-slot-publisher-id:
   193      allow-connection:
   194        plug-publisher-id:
   195          - $SLOT_PUBLISHER_ID
   196    slot-slot-attr:
   197      allow-connection:
   198        plug-attributes:
   199          a:
   200            b: $SLOT(a.b)
   201    slot-plug-attr:
   202      allow-connection:
   203        slot-attributes:
   204          c: $PLUG(c)
   205    slot-plug-missing:
   206      allow-connection:
   207        plug-attributes:
   208          x: $MISSING
   209    slot-or:
   210      allow-connection:
   211        -
   212          slot-attributes:
   213            s: S1
   214          plug-attributes:
   215            p: P1
   216        -
   217          slot-attributes:
   218            s: S2
   219          plug-attributes:
   220            p: P2
   221    slot-on-classic-true:
   222      allow-connection:
   223        on-classic: true
   224    slot-on-classic-distros:
   225      allow-connection:
   226        on-classic:
   227          - ubuntu
   228          - debian
   229    slot-on-classic-false:
   230      allow-connection:
   231        on-classic: false
   232    auto-base-slot-allow: true
   233    auto-base-slot-not-allow:
   234      allow-auto-connection: false
   235    auto-base-slot-not-allow-slots:
   236      allow-auto-connection:
   237        slot-attributes:
   238          s: S
   239    auto-base-slot-not-allow-plugs:
   240      allow-auto-connection:
   241        plug-attributes:
   242          p: P
   243    auto-base-slot-deny:
   244      deny-auto-connection: true
   245    auto-base-deny-snap-slot-allow: false
   246    auto-base-deny-snap-plug-allow: false
   247    auto-base-allow-snap-slot-not-allow: true
   248    auto-slot-or:
   249      allow-auto-connection:
   250        -
   251          slot-attributes:
   252            s: S1
   253          plug-attributes:
   254            p: P1
   255        -
   256          slot-attributes:
   257            s: S2
   258          plug-attributes:
   259            p: P2
   260    auto-slot-on-store1:
   261      allow-auto-connection: false
   262    auto-slot-on-my-brand:
   263      allow-auto-connection: false
   264    auto-slot-on-my-model2:
   265      allow-auto-connection: false
   266    auto-slot-on-multi:
   267      allow-auto-connection: false
   268    install-slot-coreonly:
   269      allow-installation:
   270        slot-snap-type:
   271          - core
   272    install-slot-attr-ok:
   273      allow-installation:
   274        slot-attributes:
   275          attr: ok
   276    install-slot-attr-deny:
   277      deny-installation:
   278        slot-attributes:
   279          trust: trusted
   280    install-slot-base-deny-snap-allow:
   281      deny-installation:
   282        slot-attributes:
   283          have: true
   284    install-slot-or:
   285      deny-installation:
   286        -
   287          slot-attributes:
   288            p: P1
   289        -
   290          slot-snap-type:
   291            - gadget
   292          slot-attributes:
   293            p: P2
   294    install-slot-on-classic-distros:
   295      allow-installation:
   296        on-classic:
   297          - ubuntu
   298          - debian
   299    install-slot-device-scope:
   300      allow-installation: false
   301  timestamp: 2016-09-30T12:00:00Z
   302  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
   303  
   304  AXNpZw==`))
   305  	c.Assert(err, IsNil)
   306  	s.baseDecl = a.(*asserts.BaseDeclaration)
   307  
   308  	s.plugSnap = snaptest.MockInfo(c, `
   309  name: plug-snap
   310  version: 0
   311  plugs:
   312     random:
   313     mismatchy:
   314       interface: bar
   315  
   316     base-plug-allow:
   317     base-plug-not-allow:
   318     base-plug-not-allow-slots:
   319     base-plug-not-allow-plugs:
   320     base-plug-deny:
   321  
   322     base-slot-allow:
   323     base-slot-not-allow:
   324     base-slot-not-allow-slots:
   325     base-slot-not-allow-plugs:
   326     base-slot-deny:
   327  
   328     auto-base-plug-allow:
   329     auto-base-plug-not-allow:
   330     auto-base-plug-not-allow-slots:
   331     auto-base-plug-not-allow-plugs:
   332     auto-base-plug-deny:
   333  
   334     auto-base-slot-allow:
   335     auto-base-slot-not-allow:
   336     auto-base-slot-not-allow-slots:
   337     auto-base-slot-not-allow-plugs:
   338     auto-base-slot-deny:
   339  
   340     snap-plug-allow:
   341     snap-plug-not-allow:
   342     snap-plug-deny:
   343  
   344     snap-slot-allow:
   345     snap-slot-not-allow:
   346     snap-slot-deny:
   347  
   348     base-deny-snap-slot-allow:
   349     base-deny-snap-plug-allow:
   350     base-allow-snap-slot-not-allow:
   351  
   352     snap-slot-deny-snap-plug-allow:
   353  
   354     auto-snap-plug-allow:
   355     auto-snap-plug-not-allow:
   356     auto-snap-plug-deny:
   357  
   358     auto-snap-slot-allow:
   359     auto-snap-slot-not-allow:
   360     auto-snap-slot-deny:
   361  
   362     auto-base-deny-snap-slot-allow:
   363     auto-base-deny-snap-plug-allow:
   364     auto-base-allow-snap-slot-not-allow:
   365  
   366     auto-snap-slot-deny-snap-plug-allow:
   367  
   368     gadgethelp:
   369     trustedhelp:
   370  
   371     precise-plug-snap-id:
   372     precise-slot-snap-id:
   373  
   374     checked-plug-publisher-id:
   375     checked-slot-publisher-id:
   376  
   377     same-plug-publisher-id:
   378  
   379     slot-slot-attr-mismatch:
   380       interface: slot-slot-attr
   381       a:
   382         b: []
   383  
   384     slot-slot-attr-match:
   385       interface: slot-slot-attr
   386       a:
   387         b: ["x", "y"]
   388  
   389     slot-plug-attr-mismatch:
   390       interface: slot-plug-attr
   391       c: "Z"
   392  
   393     slot-plug-attr-dynamic:
   394       interface: slot-plug-attr
   395  
   396     slot-plug-attr-match:
   397       interface: slot-plug-attr
   398       c: "C"
   399  
   400     slot-plug-missing-mismatch:
   401       interface: slot-plug-missing
   402       x: 1
   403       z: 2
   404  
   405     slot-plug-missing-match:
   406       interface: slot-plug-missing
   407       z: 2
   408  
   409     plug-plug-attr:
   410       c: "C"
   411  
   412     plug-slot-attr:
   413       c: "C"
   414  
   415     plug-or-p1-s1:
   416       interface: plug-or
   417       p: P1
   418  
   419     plug-or-p2-s2:
   420       interface: plug-or
   421       p: P2
   422  
   423     plug-or-p1-s2:
   424       interface: plug-or
   425       p: P1
   426  
   427     auto-plug-or-p1-s1:
   428       interface: auto-plug-or
   429       p: P1
   430  
   431     auto-plug-or-p2-s2:
   432       interface: auto-plug-or
   433       p: P2
   434  
   435     auto-plug-or-p2-s1:
   436       interface: auto-plug-or
   437       p: P2
   438  
   439     auto-plug-on-store1:
   440     auto-plug-on-my-brand:
   441     auto-plug-on-my-model2:
   442     auto-plug-on-multi:
   443  
   444     slot-or-p1-s1:
   445       interface: slot-or
   446       p: P1
   447  
   448     slot-or-p2-s2:
   449       interface: slot-or
   450       p: P2
   451  
   452     slot-or-p1-s2:
   453       interface: slot-or
   454       p: P1
   455  
   456     auto-slot-or-p1-s1:
   457       interface: auto-slot-or
   458       p: P1
   459  
   460     auto-slot-or-p2-s2:
   461       interface: auto-slot-or
   462       p: P2
   463  
   464     auto-slot-or-p2-s1:
   465       interface: auto-slot-or
   466       p: P2
   467  
   468     auto-slot-on-store1:
   469     auto-slot-on-my-brand:
   470     auto-slot-on-my-model2:
   471     auto-slot-on-multi:
   472  
   473     slot-on-classic-true:
   474     slot-on-classic-distros:
   475     slot-on-classic-false:
   476  
   477     plug-on-classic-true:
   478     plug-on-classic-distros:
   479     plug-on-classic-false:
   480  `, nil)
   481  
   482  	s.slotSnap = snaptest.MockInfo(c, `
   483  name: slot-snap
   484  version: 0
   485  slots:
   486     random:
   487     mismatchy:
   488       interface: baz
   489  
   490     base-plug-allow:
   491     base-plug-not-allow:
   492     base-plug-not-allow-slots:
   493     base-plug-not-allow-plugs:
   494     base-plug-deny:
   495  
   496     base-slot-allow:
   497     base-slot-not-allow:
   498     base-slot-not-allow-slots:
   499     base-slot-not-allow-plugs:
   500     base-slot-deny:
   501  
   502     auto-base-plug-allow:
   503     auto-base-plug-not-allow:
   504     auto-base-plug-not-allow-slots:
   505     auto-base-plug-not-allow-plugs:
   506     auto-base-plug-deny:
   507  
   508     auto-base-slot-allow:
   509     auto-base-slot-not-allow:
   510     auto-base-slot-not-allow-slots:
   511     auto-base-slot-not-allow-plugs:
   512     auto-base-slot-deny:
   513  
   514     snap-plug-allow:
   515     snap-plug-not-allow:
   516     snap-plug-deny:
   517  
   518     snap-slot-allow:
   519     snap-slot-not-allow:
   520     snap-slot-deny:
   521  
   522     base-deny-snap-slot-allow:
   523     base-deny-snap-plug-allow:
   524     base-allow-snap-slot-not-allow:
   525  
   526     snap-slot-deny-snap-plug-allow:
   527  
   528     auto-snap-plug-allow:
   529     auto-snap-plug-not-allow:
   530     auto-snap-plug-deny:
   531  
   532     auto-snap-slot-allow:
   533     auto-snap-slot-not-allow:
   534     auto-snap-slot-deny:
   535  
   536     auto-base-deny-snap-slot-allow:
   537     auto-base-deny-snap-plug-allow:
   538     auto-base-allow-snap-slot-not-allow:
   539  
   540     auto-snap-slot-deny-snap-plug-allow:
   541  
   542     trustedhelp:
   543  
   544     precise-plug-snap-id:
   545     precise-slot-snap-id:
   546  
   547     checked-plug-publisher-id:
   548     checked-slot-publisher-id:
   549  
   550     same-slot-publisher-id:
   551  
   552     slot-slot-attr:
   553       a:
   554         b: ["x", "y"]
   555  
   556     slot-plug-attr:
   557       c: "C"
   558  
   559     slot-plug-missing:
   560  
   561     plug-plug-attr-mismatch:
   562       interface: plug-plug-attr
   563       c: "Z"
   564  
   565     plug-plug-attr-match:
   566       interface: plug-plug-attr
   567       c: "C"
   568  
   569     plug-plug-attr-dynamic:
   570       interface: plug-plug-attr
   571  
   572     plug-slot-attr-mismatch:
   573       interface: plug-slot-attr
   574       c: "Z"
   575  
   576     plug-slot-attr-match:
   577       interface: plug-slot-attr
   578       c: "C"
   579  
   580     plug-or-p1-s1:
   581       interface: plug-or
   582       s: S1
   583  
   584     plug-or-p2-s2:
   585       interface: plug-or
   586       s: S2
   587  
   588     plug-or-p1-s2:
   589       interface: plug-or
   590       s: S2
   591  
   592     auto-plug-or-p1-s1:
   593       interface: auto-plug-or
   594       s: S1
   595  
   596     auto-plug-or-p2-s2:
   597       interface: auto-plug-or
   598       s: S2
   599  
   600     auto-plug-or-p2-s1:
   601       interface: auto-plug-or
   602       s: S1
   603  
   604     auto-plug-on-store1:
   605     auto-plug-on-my-brand:
   606     auto-plug-on-my-model2:
   607     auto-plug-on-multi:
   608  
   609     slot-or-p1-s1:
   610       interface: slot-or
   611       s: S1
   612  
   613     slot-or-p2-s2:
   614       interface: slot-or
   615       s: S2
   616  
   617     slot-or-p1-s2:
   618       interface: slot-or
   619       s: S2
   620  
   621     auto-slot-or-p1-s1:
   622       interface: auto-slot-or
   623       s: S1
   624  
   625     auto-slot-or-p2-s2:
   626       interface: auto-slot-or
   627       s: S2
   628  
   629     auto-slot-or-p2-s1:
   630       interface: auto-slot-or
   631       s: S1
   632  
   633     auto-slot-on-store1:
   634     auto-slot-on-my-brand:
   635     auto-slot-on-my-model2:
   636     auto-slot-on-multi:
   637  
   638     slot-on-classic-true:
   639     slot-on-classic-distros:
   640     slot-on-classic-false:
   641  
   642     plug-on-classic-true:
   643     plug-on-classic-distros:
   644     plug-on-classic-false:
   645  `, nil)
   646  
   647  	a, err = asserts.Decode([]byte(`type: snap-declaration
   648  authority-id: canonical
   649  series: 16
   650  snap-name: plug-snap
   651  snap-id: plugsnapidididididididididididid
   652  publisher-id: plug-publisher
   653  plugs:
   654    snap-plug-allow: true
   655    snap-plug-deny: false
   656    snap-plug-not-allow:
   657      allow-connection: false
   658    base-deny-snap-plug-allow: true
   659    snap-slot-deny-snap-plug-allow:
   660      deny-connection: false
   661    trustedhelp:
   662      allow-connection:
   663        slot-snap-type:
   664          - core
   665          - gadget
   666    precise-slot-snap-id:
   667      allow-connection:
   668        slot-snap-id:
   669          - slotsnapidididididididididididid
   670    checked-slot-publisher-id:
   671      allow-connection:
   672        slot-publisher-id:
   673          - slot-publisher
   674          - $PLUG_PUBLISHER_ID
   675    auto-snap-plug-allow: true
   676    auto-snap-plug-deny: false
   677    auto-snap-plug-not-allow:
   678      allow-auto-connection: false
   679    auto-snap-slot-deny-snap-plug-allow:
   680      deny-auto-connection: false
   681    auto-base-deny-snap-plug-allow: true
   682    auto-plug-on-store1:
   683      allow-auto-connection:
   684        on-store:
   685          - store1
   686    auto-plug-on-my-brand:
   687      allow-auto-connection:
   688        on-brand:
   689          - my-brand
   690          - my-brand-subbrand
   691    auto-plug-on-my-model2:
   692      allow-auto-connection:
   693        on-model:
   694          - my-brand-subbrand/my-model2
   695    auto-plug-on-multi:
   696      allow-auto-connection:
   697        on-brand:
   698          - my-brand
   699          - my-brand-subbrand
   700        on-store:
   701          - store1
   702          - other-store
   703        on-model:
   704          - my-brand/my-model1
   705          - my-brand-subbrand/my-model2
   706  timestamp: 2016-09-30T12:00:00Z
   707  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
   708  
   709  AXNpZw==`))
   710  	c.Assert(err, IsNil)
   711  	s.plugDecl = a.(*asserts.SnapDeclaration)
   712  
   713  	a, err = asserts.Decode([]byte(`type: snap-declaration
   714  authority-id: canonical
   715  series: 16
   716  snap-name: slot-snap
   717  snap-id: slotsnapidididididididididididid
   718  publisher-id: slot-publisher
   719  slots:
   720    snap-slot-allow: true
   721    snap-slot-deny: false
   722    snap-slot-not-allow:
   723      allow-connection: false
   724    base-deny-snap-slot-allow: true
   725    snap-slot-deny-snap-plug-allow:
   726      deny-connection: true
   727    base-allow-snap-slot-not-allow:
   728      allow-connection: false
   729    precise-plug-snap-id:
   730      allow-connection:
   731        plug-snap-id:
   732          - plugsnapidididididididididididid
   733    checked-plug-publisher-id:
   734      allow-connection:
   735        plug-publisher-id:
   736          - plug-publisher
   737    auto-snap-slot-allow: true
   738    auto-snap-slot-deny: false
   739    auto-snap-slot-not-allow:
   740      allow-auto-connection: false
   741    auto-base-deny-snap-slot-allow: true
   742    auto-snap-slot-deny-snap-plug-allow:
   743      deny-auto-connection: true
   744    auto-base-allow-snap-slot-not-allow:
   745      allow-auto-connection: false
   746    auto-slot-on-store1:
   747      allow-auto-connection:
   748        on-store:
   749          - store1
   750    auto-slot-on-my-brand:
   751      allow-auto-connection:
   752        on-brand:
   753          - my-brand
   754          - my-brand-subbrand
   755    auto-slot-on-my-model2:
   756      allow-auto-connection:
   757        on-model:
   758          - my-brand-subbrand/my-model2
   759    auto-slot-on-multi:
   760      allow-auto-connection:
   761        on-brand:
   762          - my-brand
   763          - my-brand-subbrand
   764        on-store:
   765          - store1
   766          - other-store
   767        on-model:
   768          - my-brand/my-model1
   769          - my-brand-subbrand/my-model2
   770  timestamp: 2016-09-30T12:00:00Z
   771  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
   772  
   773  AXNpZw==`))
   774  	c.Assert(err, IsNil)
   775  	s.slotDecl = a.(*asserts.SnapDeclaration)
   776  
   777  	s.randomSnap = snaptest.MockInfo(c, `
   778  name: random-snap
   779  version: 0
   780  plugs:
   781    precise-plug-snap-id:
   782    checked-plug-publisher-id:
   783    same-slot-publisher-id:
   784    slot-slot-attr:
   785  slots:
   786    precise-slot-snap-id:
   787    checked-slot-publisher-id:
   788    same-plug-publisher-id:
   789  `, nil)
   790  
   791  	a, err = asserts.Decode([]byte(`type: snap-declaration
   792  authority-id: canonical
   793  series: 16
   794  snap-name: random-snap
   795  snap-id: randomsnapididididididididid
   796  publisher-id: random-publisher
   797  timestamp: 2016-09-30T12:00:00Z
   798  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
   799  
   800  AXNpZw==`))
   801  	c.Assert(err, IsNil)
   802  	s.randomDecl = a.(*asserts.SnapDeclaration)
   803  }
   804  
   805  func (s *policySuite) TearDownSuite(c *C) {
   806  	s.restoreSanitize()
   807  }
   808  
   809  func (s *policySuite) TestBaselineDefaultIsAllow(c *C) {
   810  	cand := policy.ConnectCandidate{
   811  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["random"], nil, nil),
   812  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["random"], nil, nil),
   813  		BaseDeclaration: s.baseDecl,
   814  	}
   815  
   816  	c.Check(cand.Check(), IsNil)
   817  	c.Check(cand.CheckAutoConnect(), IsNil)
   818  }
   819  
   820  func (s *policySuite) TestInterfaceMismatch(c *C) {
   821  	cand := policy.ConnectCandidate{
   822  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["mismatchy"], nil, nil),
   823  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["mismatchy"], nil, nil),
   824  		BaseDeclaration: s.baseDecl,
   825  	}
   826  
   827  	c.Check(cand.Check(), ErrorMatches, `cannot connect mismatched plug interface "bar" to slot interface "baz"`)
   828  }
   829  
   830  func (s *policySuite) TestBaseDeclAllowDenyConnection(c *C) {
   831  	tests := []struct {
   832  		iface    string
   833  		expected string // "" => no error
   834  	}{
   835  		{"base-plug-allow", ""},
   836  		{"base-plug-deny", `connection denied by plug rule of interface "base-plug-deny"`},
   837  		{"base-plug-not-allow", `connection not allowed by plug rule of interface "base-plug-not-allow"`},
   838  		{"base-slot-allow", ""},
   839  		{"base-slot-deny", `connection denied by slot rule of interface "base-slot-deny"`},
   840  		{"base-slot-not-allow", `connection not allowed by slot rule of interface "base-slot-not-allow"`},
   841  		{"base-plug-not-allow-slots", `connection not allowed.*`},
   842  		{"base-slot-not-allow-slots", `connection not allowed.*`},
   843  		{"base-plug-not-allow-plugs", `connection not allowed.*`},
   844  		{"base-slot-not-allow-plugs", `connection not allowed.*`},
   845  		{"plug-or-p1-s1", ""},
   846  		{"plug-or-p2-s2", ""},
   847  		{"plug-or-p1-s2", "connection not allowed by plug rule.*"},
   848  		{"slot-or-p1-s1", ""},
   849  		{"slot-or-p2-s2", ""},
   850  		{"slot-or-p1-s2", "connection not allowed by slot rule.*"},
   851  	}
   852  
   853  	for _, t := range tests {
   854  		cand := policy.ConnectCandidate{
   855  			Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
   856  			Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
   857  			BaseDeclaration: s.baseDecl,
   858  		}
   859  
   860  		err := cand.Check()
   861  		if t.expected == "" {
   862  			c.Check(err, IsNil)
   863  		} else {
   864  			c.Check(err, ErrorMatches, t.expected)
   865  		}
   866  	}
   867  }
   868  
   869  func (s *policySuite) TestBaseDeclAllowDenyAutoConnection(c *C) {
   870  	tests := []struct {
   871  		iface    string
   872  		expected string // "" => no error
   873  	}{
   874  		{"auto-base-plug-allow", ""},
   875  		{"auto-base-plug-deny", `auto-connection denied by plug rule of interface "auto-base-plug-deny"`},
   876  		{"auto-base-plug-not-allow", `auto-connection not allowed by plug rule of interface "auto-base-plug-not-allow"`},
   877  		{"auto-base-slot-allow", ""},
   878  		{"auto-base-slot-deny", `auto-connection denied by slot rule of interface "auto-base-slot-deny"`},
   879  		{"auto-base-slot-not-allow", `auto-connection not allowed by slot rule of interface "auto-base-slot-not-allow"`},
   880  		{"auto-base-plug-not-allow-slots", `auto-connection not allowed.*`},
   881  		{"auto-base-slot-not-allow-slots", `auto-connection not allowed.*`},
   882  		{"auto-base-plug-not-allow-plugs", `auto-connection not allowed.*`},
   883  		{"auto-base-slot-not-allow-plugs", `auto-connection not allowed.*`},
   884  		{"auto-plug-or-p1-s1", ""},
   885  		{"auto-plug-or-p2-s2", ""},
   886  		{"auto-plug-or-p2-s1", "auto-connection not allowed by plug rule.*"},
   887  		{"auto-slot-or-p1-s1", ""},
   888  		{"auto-slot-or-p2-s2", ""},
   889  		{"auto-slot-or-p2-s1", "auto-connection not allowed by slot rule.*"},
   890  	}
   891  
   892  	for _, t := range tests {
   893  		cand := policy.ConnectCandidate{
   894  			Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
   895  			Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
   896  			BaseDeclaration: s.baseDecl,
   897  		}
   898  
   899  		err := cand.CheckAutoConnect()
   900  		if t.expected == "" {
   901  			c.Check(err, IsNil)
   902  		} else {
   903  			c.Check(err, ErrorMatches, t.expected)
   904  		}
   905  	}
   906  }
   907  
   908  func (s *policySuite) TestSnapDeclAllowDenyConnection(c *C) {
   909  	tests := []struct {
   910  		iface    string
   911  		expected string // "" => no error
   912  	}{
   913  		{"random", ""},
   914  		{"snap-plug-allow", ""},
   915  		{"snap-plug-deny", `connection denied by plug rule of interface "snap-plug-deny" for "plug-snap" snap`},
   916  		{"snap-plug-not-allow", `connection not allowed by plug rule of interface "snap-plug-not-allow" for "plug-snap" snap`},
   917  		{"snap-slot-allow", ""},
   918  		{"snap-slot-deny", `connection denied by slot rule of interface "snap-slot-deny" for "slot-snap" snap`},
   919  		{"snap-slot-not-allow", `connection not allowed by slot rule of interface "snap-slot-not-allow" for "slot-snap" snap`},
   920  		{"base-deny-snap-slot-allow", ""},
   921  		{"base-deny-snap-plug-allow", ""},
   922  		{"snap-slot-deny-snap-plug-allow", ""},
   923  		{"base-allow-snap-slot-not-allow", `connection not allowed.*`},
   924  	}
   925  
   926  	for _, t := range tests {
   927  		cand := policy.ConnectCandidate{
   928  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
   929  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
   930  			PlugSnapDeclaration: s.plugDecl,
   931  			SlotSnapDeclaration: s.slotDecl,
   932  			BaseDeclaration:     s.baseDecl,
   933  		}
   934  
   935  		err := cand.Check()
   936  		if t.expected == "" {
   937  			c.Check(err, IsNil)
   938  		} else {
   939  			c.Check(err, ErrorMatches, t.expected)
   940  		}
   941  	}
   942  }
   943  
   944  func (s *policySuite) TestSnapDeclAllowDenyAutoConnection(c *C) {
   945  	tests := []struct {
   946  		iface    string
   947  		expected string // "" => no error
   948  	}{
   949  		{"random", ""},
   950  		{"auto-snap-plug-allow", ""},
   951  		{"auto-snap-plug-deny", `auto-connection denied by plug rule of interface "auto-snap-plug-deny" for "plug-snap" snap`},
   952  		{"auto-snap-plug-not-allow", `auto-connection not allowed by plug rule of interface "auto-snap-plug-not-allow" for "plug-snap" snap`},
   953  		{"auto-snap-slot-allow", ""},
   954  		{"auto-snap-slot-deny", `auto-connection denied by slot rule of interface "auto-snap-slot-deny" for "slot-snap" snap`},
   955  		{"auto-snap-slot-not-allow", `auto-connection not allowed by slot rule of interface "auto-snap-slot-not-allow" for "slot-snap" snap`},
   956  		{"auto-base-deny-snap-slot-allow", ""},
   957  		{"auto-base-deny-snap-plug-allow", ""},
   958  		{"auto-snap-slot-deny-snap-plug-allow", ""},
   959  		{"auto-base-allow-snap-slot-not-allow", `auto-connection not allowed.*`},
   960  	}
   961  
   962  	for _, t := range tests {
   963  		cand := policy.ConnectCandidate{
   964  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
   965  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
   966  			PlugSnapDeclaration: s.plugDecl,
   967  			SlotSnapDeclaration: s.slotDecl,
   968  			BaseDeclaration:     s.baseDecl,
   969  		}
   970  
   971  		err := cand.CheckAutoConnect()
   972  		if t.expected == "" {
   973  			c.Check(err, IsNil)
   974  		} else {
   975  			c.Check(err, ErrorMatches, t.expected)
   976  		}
   977  	}
   978  }
   979  
   980  func (s *policySuite) TestSnapTypeCheckConnection(c *C) {
   981  	gadgetSnap := snaptest.MockInfo(c, `
   982  name: gadget
   983  version: 0
   984  type: gadget
   985  plugs:
   986     gadgethelp:
   987  slots:
   988     trustedhelp:
   989  `, nil)
   990  
   991  	coreSnap := snaptest.MockInfo(c, `
   992  name: core
   993  version: 0
   994  type: os
   995  slots:
   996     gadgethelp:
   997     trustedhelp:
   998  `, nil)
   999  
  1000  	cand := policy.ConnectCandidate{
  1001  		Plug:            interfaces.NewConnectedPlug(gadgetSnap.Plugs["gadgethelp"], nil, nil),
  1002  		Slot:            interfaces.NewConnectedSlot(coreSnap.Slots["gadgethelp"], nil, nil),
  1003  		BaseDeclaration: s.baseDecl,
  1004  	}
  1005  	c.Check(cand.Check(), IsNil)
  1006  
  1007  	cand = policy.ConnectCandidate{
  1008  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["gadgethelp"], nil, nil),
  1009  		Slot:            interfaces.NewConnectedSlot(coreSnap.Slots["gadgethelp"], nil, nil),
  1010  		BaseDeclaration: s.baseDecl,
  1011  	}
  1012  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1013  
  1014  	for _, trustedSide := range []*snap.Info{coreSnap, gadgetSnap} {
  1015  		cand = policy.ConnectCandidate{
  1016  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["trustedhelp"], nil, nil),
  1017  			PlugSnapDeclaration: s.plugDecl,
  1018  			Slot:                interfaces.NewConnectedSlot(trustedSide.Slots["trustedhelp"], nil, nil),
  1019  			BaseDeclaration:     s.baseDecl,
  1020  		}
  1021  		c.Check(cand.Check(), IsNil)
  1022  	}
  1023  
  1024  	cand = policy.ConnectCandidate{
  1025  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["trustedhelp"], nil, nil),
  1026  		PlugSnapDeclaration: s.plugDecl,
  1027  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["trustedhelp"], nil, nil),
  1028  		BaseDeclaration:     s.baseDecl,
  1029  	}
  1030  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1031  }
  1032  
  1033  func (s *policySuite) TestPlugSnapIDCheckConnection(c *C) {
  1034  	// no plug-side declaration
  1035  	cand := policy.ConnectCandidate{
  1036  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["precise-plug-snap-id"], nil, nil),
  1037  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["precise-plug-snap-id"], nil, nil),
  1038  		SlotSnapDeclaration: s.slotDecl,
  1039  		BaseDeclaration:     s.baseDecl,
  1040  	}
  1041  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1042  
  1043  	// plug-side declaration, wrong snap-id
  1044  	cand = policy.ConnectCandidate{
  1045  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["precise-plug-snap-id"], nil, nil),
  1046  		PlugSnapDeclaration: s.randomDecl,
  1047  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["precise-plug-snap-id"], nil, nil),
  1048  		SlotSnapDeclaration: s.slotDecl,
  1049  		BaseDeclaration:     s.baseDecl,
  1050  	}
  1051  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1052  
  1053  	// right snap-id
  1054  	cand = policy.ConnectCandidate{
  1055  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["precise-plug-snap-id"], nil, nil),
  1056  		PlugSnapDeclaration: s.plugDecl,
  1057  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["precise-plug-snap-id"], nil, nil),
  1058  		SlotSnapDeclaration: s.slotDecl,
  1059  		BaseDeclaration:     s.baseDecl,
  1060  	}
  1061  	c.Check(cand.Check(), IsNil)
  1062  }
  1063  
  1064  func (s *policySuite) TestSlotSnapIDCheckConnection(c *C) {
  1065  	// no slot-side declaration
  1066  	cand := policy.ConnectCandidate{
  1067  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["precise-slot-snap-id"], nil, nil),
  1068  		PlugSnapDeclaration: s.plugDecl,
  1069  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["precise-slot-snap-id"], nil, nil),
  1070  		BaseDeclaration:     s.baseDecl,
  1071  	}
  1072  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1073  
  1074  	// slot-side declaration, wrong snap-id
  1075  	cand = policy.ConnectCandidate{
  1076  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["precise-slot-snap-id"], nil, nil),
  1077  		PlugSnapDeclaration: s.plugDecl,
  1078  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["precise-slot-snap-id"], nil, nil),
  1079  		SlotSnapDeclaration: s.randomDecl,
  1080  		BaseDeclaration:     s.baseDecl,
  1081  	}
  1082  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1083  
  1084  	// right snap-id
  1085  	cand = policy.ConnectCandidate{
  1086  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["precise-slot-snap-id"], nil, nil),
  1087  		PlugSnapDeclaration: s.plugDecl,
  1088  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["precise-slot-snap-id"], nil, nil),
  1089  		SlotSnapDeclaration: s.slotDecl,
  1090  		BaseDeclaration:     s.baseDecl,
  1091  	}
  1092  	c.Check(cand.Check(), IsNil)
  1093  }
  1094  
  1095  func (s *policySuite) TestPlugPublisherIDCheckConnection(c *C) {
  1096  	// no plug-side declaration
  1097  	cand := policy.ConnectCandidate{
  1098  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["checked-plug-publisher-id"], nil, nil),
  1099  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["checked-plug-publisher-id"], nil, nil),
  1100  		SlotSnapDeclaration: s.slotDecl,
  1101  		BaseDeclaration:     s.baseDecl,
  1102  	}
  1103  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1104  
  1105  	// plug-side declaration, wrong publisher-id
  1106  	cand = policy.ConnectCandidate{
  1107  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["checked-plug-publisher-id"], nil, nil),
  1108  		PlugSnapDeclaration: s.randomDecl,
  1109  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["checked-plug-publisher-id"], nil, nil),
  1110  		SlotSnapDeclaration: s.slotDecl,
  1111  		BaseDeclaration:     s.baseDecl,
  1112  	}
  1113  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1114  
  1115  	// right publisher-id
  1116  	cand = policy.ConnectCandidate{
  1117  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["checked-plug-publisher-id"], nil, nil),
  1118  		PlugSnapDeclaration: s.plugDecl,
  1119  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["checked-plug-publisher-id"], nil, nil),
  1120  		SlotSnapDeclaration: s.slotDecl,
  1121  		BaseDeclaration:     s.baseDecl,
  1122  	}
  1123  	c.Check(cand.Check(), IsNil)
  1124  }
  1125  
  1126  func (s *policySuite) TestSlotPublisherIDCheckConnection(c *C) {
  1127  	// no slot-side declaration
  1128  	cand := policy.ConnectCandidate{
  1129  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["checked-slot-publisher-id"], nil, nil),
  1130  		PlugSnapDeclaration: s.plugDecl,
  1131  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["checked-slot-publisher-id"], nil, nil),
  1132  		BaseDeclaration:     s.baseDecl,
  1133  	}
  1134  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1135  
  1136  	// slot-side declaration, wrong publisher-id
  1137  	cand = policy.ConnectCandidate{
  1138  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["checked-slot-publisher-id"], nil, nil),
  1139  		PlugSnapDeclaration: s.plugDecl,
  1140  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["checked-slot-publisher-id"], nil, nil),
  1141  		SlotSnapDeclaration: s.randomDecl,
  1142  		BaseDeclaration:     s.baseDecl,
  1143  	}
  1144  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1145  
  1146  	// right publisher-id
  1147  	cand = policy.ConnectCandidate{
  1148  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["checked-slot-publisher-id"], nil, nil),
  1149  		PlugSnapDeclaration: s.plugDecl,
  1150  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["checked-slot-publisher-id"], nil, nil),
  1151  		SlotSnapDeclaration: s.slotDecl,
  1152  		BaseDeclaration:     s.baseDecl,
  1153  	}
  1154  	c.Check(cand.Check(), IsNil)
  1155  }
  1156  
  1157  func (s *policySuite) TestDollarPlugPublisherIDCheckConnection(c *C) {
  1158  	// no known publishers
  1159  	cand := policy.ConnectCandidate{
  1160  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["same-plug-publisher-id"], nil, nil),
  1161  		Slot:            interfaces.NewConnectedSlot(s.randomSnap.Slots["same-plug-publisher-id"], nil, nil),
  1162  		BaseDeclaration: s.baseDecl,
  1163  	}
  1164  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1165  
  1166  	// no slot-side declaration
  1167  	cand = policy.ConnectCandidate{
  1168  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["same-plug-publisher-id"], nil, nil),
  1169  		PlugSnapDeclaration: s.plugDecl,
  1170  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["same-plug-publisher-id"], nil, nil),
  1171  		BaseDeclaration:     s.baseDecl,
  1172  	}
  1173  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1174  
  1175  	// slot-side declaration, wrong publisher-id
  1176  	cand = policy.ConnectCandidate{
  1177  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["same-plug-publisher-id"], nil, nil),
  1178  		PlugSnapDeclaration: s.plugDecl,
  1179  		Slot:                interfaces.NewConnectedSlot(s.randomSnap.Slots["same-plug-publisher-id"], nil, nil),
  1180  		SlotSnapDeclaration: s.randomDecl,
  1181  		BaseDeclaration:     s.baseDecl,
  1182  	}
  1183  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1184  
  1185  	// slot publisher id == plug publisher id
  1186  	samePubSlotSnap := snaptest.MockInfo(c, `
  1187  name: same-pub-slot-snap
  1188  version: 0
  1189  slots:
  1190    same-plug-publisher-id:
  1191  `, nil)
  1192  
  1193  	a, err := asserts.Decode([]byte(`type: snap-declaration
  1194  authority-id: canonical
  1195  series: 16
  1196  snap-name: same-pub-slot-snap
  1197  snap-id: samepublslotsnapidididididididid
  1198  publisher-id: plug-publisher
  1199  timestamp: 2016-09-30T12:00:00Z
  1200  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1201  
  1202  AXNpZw==`))
  1203  	c.Assert(err, IsNil)
  1204  	samePubSlotDecl := a.(*asserts.SnapDeclaration)
  1205  
  1206  	cand = policy.ConnectCandidate{
  1207  		Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs["same-plug-publisher-id"], nil, nil),
  1208  		PlugSnapDeclaration: s.plugDecl,
  1209  		Slot:                interfaces.NewConnectedSlot(samePubSlotSnap.Slots["same-plug-publisher-id"], nil, nil),
  1210  		SlotSnapDeclaration: samePubSlotDecl,
  1211  		BaseDeclaration:     s.baseDecl,
  1212  	}
  1213  	c.Check(cand.Check(), IsNil)
  1214  }
  1215  
  1216  func (s *policySuite) TestDollarSlotPublisherIDCheckConnection(c *C) {
  1217  	// no known publishers
  1218  	cand := policy.ConnectCandidate{
  1219  		Plug:            interfaces.NewConnectedPlug(s.randomSnap.Plugs["same-slot-publisher-id"], nil, nil),
  1220  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["same-slot-publisher-id"], nil, nil),
  1221  		BaseDeclaration: s.baseDecl,
  1222  	}
  1223  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1224  
  1225  	// no plug-side declaration
  1226  	cand = policy.ConnectCandidate{
  1227  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["same-slot-publisher-id"], nil, nil),
  1228  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["same-slot-publisher-id"], nil, nil),
  1229  		SlotSnapDeclaration: s.slotDecl,
  1230  		BaseDeclaration:     s.baseDecl,
  1231  	}
  1232  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1233  
  1234  	// plug-side declaration, wrong publisher-id
  1235  	cand = policy.ConnectCandidate{
  1236  		Plug:                interfaces.NewConnectedPlug(s.randomSnap.Plugs["same-slot-publisher-id"], nil, nil),
  1237  		PlugSnapDeclaration: s.randomDecl,
  1238  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["same-slot-publisher-id"], nil, nil),
  1239  		SlotSnapDeclaration: s.slotDecl,
  1240  		BaseDeclaration:     s.baseDecl,
  1241  	}
  1242  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  1243  
  1244  	// plug publisher id == slot publisher id
  1245  	samePubPlugSnap := snaptest.MockInfo(c, `
  1246  name: same-pub-plug-snap
  1247  version: 0
  1248  plugs:
  1249    same-slot-publisher-id:
  1250  `, nil)
  1251  
  1252  	a, err := asserts.Decode([]byte(`type: snap-declaration
  1253  authority-id: canonical
  1254  series: 16
  1255  snap-name: same-pub-plug-snap
  1256  snap-id: samepublplugsnapidididididididid
  1257  publisher-id: slot-publisher
  1258  timestamp: 2016-09-30T12:00:00Z
  1259  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1260  
  1261  AXNpZw==`))
  1262  	c.Assert(err, IsNil)
  1263  	samePubPlugDecl := a.(*asserts.SnapDeclaration)
  1264  
  1265  	cand = policy.ConnectCandidate{
  1266  		Plug:                interfaces.NewConnectedPlug(samePubPlugSnap.Plugs["same-slot-publisher-id"], nil, nil),
  1267  		PlugSnapDeclaration: samePubPlugDecl,
  1268  		Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots["same-slot-publisher-id"], nil, nil),
  1269  		SlotSnapDeclaration: s.slotDecl,
  1270  		BaseDeclaration:     s.baseDecl,
  1271  	}
  1272  	c.Check(cand.Check(), IsNil)
  1273  }
  1274  
  1275  func (s *policySuite) TestBaselineDefaultIsAllowInstallation(c *C) {
  1276  	installSnap := snaptest.MockInfo(c, `
  1277  name: install-slot-snap
  1278  version: 0
  1279  slots:
  1280    random1:
  1281  plugs:
  1282    random2:
  1283  `, nil)
  1284  
  1285  	cand := policy.InstallCandidate{
  1286  		Snap:            installSnap,
  1287  		BaseDeclaration: s.baseDecl,
  1288  	}
  1289  
  1290  	c.Check(cand.Check(), IsNil)
  1291  }
  1292  
  1293  func (s *policySuite) TestBaseDeclAllowDenyInstallation(c *C) {
  1294  
  1295  	tests := []struct {
  1296  		installYaml string
  1297  		expected    string // "" => no error
  1298  	}{
  1299  		{`name: install-snap
  1300  version: 0
  1301  slots:
  1302    innocuous:
  1303    install-slot-coreonly:
  1304  `, `installation not allowed by "install-slot-coreonly" slot rule of interface "install-slot-coreonly"`},
  1305  		{`name: install-snap
  1306  version: 0
  1307  slots:
  1308    install-slot-attr-ok:
  1309      attr: ok
  1310  `, ""},
  1311  		{`name: install-snap
  1312  version: 0
  1313  slots:
  1314    install-slot-attr-deny:
  1315      trust: trusted
  1316  `, `installation denied by "install-slot-attr-deny" slot rule of interface "install-slot-attr-deny"`},
  1317  		{`name: install-snap
  1318  version: 0
  1319  plugs:
  1320    install-plug-attr-ok:
  1321      attr: ok
  1322  `, ""},
  1323  		{`name: install-snap
  1324  version: 0
  1325  plugs:
  1326    install-plug-attr-ok:
  1327      attr: not-ok
  1328  `, `installation not allowed by "install-plug-attr-ok" plug rule of interface "install-plug-attr-ok"`},
  1329  		{`name: install-snap
  1330  version: 0
  1331  plugs:
  1332    install-plug-gadget-only:
  1333  `, `installation not allowed by "install-plug-gadget-only" plug rule of interface "install-plug-gadget-only"`},
  1334  		{`name: install-gadget
  1335  version: 0
  1336  type: gadget
  1337  plugs:
  1338    install-plug-gadget-only:
  1339  `, ""},
  1340  		{`name: install-gadget
  1341  version: 0
  1342  type: gadget
  1343  plugs:
  1344    install-plug-or:
  1345       p: P2`, `installation denied by "install-plug-or" plug rule.*`},
  1346  		{`name: install-snap
  1347  version: 0
  1348  plugs:
  1349    install-plug-or:
  1350       p: P1`, `installation denied by "install-plug-or" plug rule.*`},
  1351  		{`name: install-snap
  1352  version: 0
  1353  plugs:
  1354    install-plug-or:
  1355       p: P3`, ""},
  1356  		{`name: install-gadget
  1357  version: 0
  1358  type: gadget
  1359  slots:
  1360    install-slot-or:
  1361       p: P2`, `installation denied by "install-slot-or" slot rule.*`},
  1362  		{`name: install-snap
  1363  version: 0
  1364  slots:
  1365    install-slot-or:
  1366       p: P1`, `installation denied by "install-slot-or" slot rule.*`},
  1367  		{`name: install-snap
  1368  version: 0
  1369  slots:
  1370    install-slot-or:
  1371       p: P3`, ""},
  1372  	}
  1373  
  1374  	for _, t := range tests {
  1375  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  1376  
  1377  		cand := policy.InstallCandidate{
  1378  			Snap:            installSnap,
  1379  			BaseDeclaration: s.baseDecl,
  1380  		}
  1381  
  1382  		err := cand.Check()
  1383  		if t.expected == "" {
  1384  			c.Check(err, IsNil)
  1385  		} else {
  1386  			c.Check(err, ErrorMatches, t.expected)
  1387  		}
  1388  	}
  1389  }
  1390  
  1391  func (s *policySuite) TestSnapDeclAllowDenyInstallation(c *C) {
  1392  
  1393  	tests := []struct {
  1394  		installYaml string
  1395  		plugsSlots  string
  1396  		expected    string // "" => no error
  1397  	}{
  1398  		{`name: install-snap
  1399  version: 0
  1400  slots:
  1401    install-slot-base-allow-snap-deny:
  1402      have: yes # bool
  1403  `, `slots:
  1404    install-slot-base-allow-snap-deny:
  1405      deny-installation:
  1406        slot-attributes:
  1407          have: true
  1408  `, `installation denied by "install-slot-base-allow-snap-deny" slot rule of interface "install-slot-base-allow-snap-deny" for "install-snap" snap`},
  1409  		{`name: install-snap
  1410  version: 0
  1411  slots:
  1412    install-slot-base-allow-snap-not-allow:
  1413      have: yes # bool
  1414  `, `slots:
  1415    install-slot-base-allow-snap-not-allow:
  1416      allow-installation:
  1417        slot-attributes:
  1418          have: false
  1419  `, `installation not allowed by "install-slot-base-allow-snap-not-allow" slot rule of interface "install-slot-base-allow-snap-not-allow" for "install-snap" snap`},
  1420  		{`name: install-snap
  1421  version: 0
  1422  slots:
  1423    install-slot-base-deny-snap-allow:
  1424      have: yes
  1425  `, `slots:
  1426    install-slot-base-deny-snap-allow:
  1427      allow-installation: true
  1428  `, ""},
  1429  		{`name: install-snap
  1430  version: 0
  1431  plugs:
  1432    install-plug-base-allow-snap-deny:
  1433      attr: give-me
  1434  `, `plugs:
  1435    install-plug-base-allow-snap-deny:
  1436      deny-installation:
  1437        plug-attributes:
  1438          attr: .*
  1439  `, `installation denied by "install-plug-base-allow-snap-deny" plug rule of interface "install-plug-base-allow-snap-deny" for "install-snap" snap`},
  1440  		{`name: install-snap
  1441  version: 0
  1442  plugs:
  1443    install-plug-base-allow-snap-not-allow:
  1444      attr: give-me
  1445  `, `plugs:
  1446    install-plug-base-allow-snap-not-allow:
  1447      allow-installation:
  1448        plug-attributes:
  1449          attr: minimal
  1450  `, `installation not allowed by "install-plug-base-allow-snap-not-allow" plug rule of interface "install-plug-base-allow-snap-not-allow" for "install-snap" snap`},
  1451  		{`name: install-snap
  1452  version: 0
  1453  plugs:
  1454    install-plug-base-deny-snap-allow:
  1455      attr: attrvalue
  1456  `, `plugs:
  1457    install-plug-base-deny-snap-allow:
  1458      allow-installation:
  1459        plug-attributes:
  1460          attr: attrvalue
  1461  `, ""},
  1462  	}
  1463  
  1464  	for _, t := range tests {
  1465  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  1466  
  1467  		a, err := asserts.Decode([]byte(strings.Replace(`type: snap-declaration
  1468  authority-id: canonical
  1469  series: 16
  1470  snap-name: install-snap
  1471  snap-id: installsnap6idididididididididid
  1472  publisher-id: publisher
  1473  @plugsSlots@
  1474  timestamp: 2016-09-30T12:00:00Z
  1475  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1476  
  1477  AXNpZw==`, "@plugsSlots@", strings.TrimSpace(t.plugsSlots), 1)))
  1478  		c.Assert(err, IsNil)
  1479  		snapDecl := a.(*asserts.SnapDeclaration)
  1480  
  1481  		cand := policy.InstallCandidate{
  1482  			Snap:            installSnap,
  1483  			SnapDeclaration: snapDecl,
  1484  			BaseDeclaration: s.baseDecl,
  1485  		}
  1486  
  1487  		err = cand.Check()
  1488  		if t.expected == "" {
  1489  			c.Check(err, IsNil)
  1490  		} else {
  1491  			c.Check(err, ErrorMatches, t.expected)
  1492  		}
  1493  	}
  1494  }
  1495  
  1496  func (s *policySuite) TestBaseDeclAllowDenyInstallationMinimalCheck(c *C) {
  1497  	tests := []struct {
  1498  		installYaml string
  1499  		expected    string // "" => no error
  1500  	}{
  1501  		{`name: install-snap
  1502  version: 0
  1503  slots:
  1504    innocuous:
  1505    install-slot-coreonly:
  1506  `, `installation not allowed by "install-slot-coreonly" slot rule of interface "install-slot-coreonly"`},
  1507  		{`name: install-gadget
  1508  version: 0
  1509  type: gadget
  1510  slots:
  1511    install-slot-or:
  1512  `, `installation denied by "install-slot-or" slot rule.*`},
  1513  		{`name: install-snap
  1514  version: 0
  1515  slots:
  1516    install-slot-or:
  1517  `, ""},
  1518  		{`name: install-snap
  1519  version: 0
  1520  plugs:
  1521    install-plug-gadget-only:
  1522  `, ``}, // plug is not validated with minimal installation check
  1523  	}
  1524  
  1525  	for _, t := range tests {
  1526  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  1527  
  1528  		cand := policy.InstallCandidateMinimalCheck{
  1529  			Snap:            installSnap,
  1530  			BaseDeclaration: s.baseDecl,
  1531  		}
  1532  
  1533  		err := cand.Check()
  1534  		if t.expected == "" {
  1535  			c.Check(err, IsNil)
  1536  		} else {
  1537  			c.Check(err, ErrorMatches, t.expected)
  1538  		}
  1539  	}
  1540  }
  1541  
  1542  func (s *policySuite) TestOnClassicMinimalInstallationCheck(c *C) {
  1543  	r1 := release.MockOnClassic(false)
  1544  	defer r1()
  1545  	r2 := release.MockReleaseInfo(&release.ReleaseInfo)
  1546  	defer r2()
  1547  
  1548  	tests := []struct {
  1549  		distro      string // "" => not classic
  1550  		installYaml string
  1551  		err         string // "" => no error
  1552  	}{
  1553  		{"", `name: install-snap
  1554  version: 0
  1555  slots:
  1556    install-slot-on-classic-distros:`, `installation not allowed by "install-slot-on-classic-distros" slot rule.*`},
  1557  		{"debian", `name: install-snap
  1558  version: 0
  1559  slots:
  1560    install-slot-on-classic-distros:`, ""},
  1561  		{"", `name: install-snap
  1562  version: 0
  1563  plugs:
  1564    install-plug-on-classic-distros:`, ""}, // plug is not validated with minimal installation check
  1565  		{"debian", `name: install-snap
  1566  version: 0
  1567  plugs:
  1568    install-plug-on-classic-distros:`, ""},
  1569  	}
  1570  
  1571  	for _, t := range tests {
  1572  		if t.distro == "" {
  1573  			release.OnClassic = false
  1574  		} else {
  1575  			release.OnClassic = true
  1576  			release.ReleaseInfo = release.OS{
  1577  				ID: t.distro,
  1578  			}
  1579  		}
  1580  
  1581  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  1582  
  1583  		cand := policy.InstallCandidateMinimalCheck{
  1584  			Snap:            installSnap,
  1585  			BaseDeclaration: s.baseDecl,
  1586  		}
  1587  		err := cand.Check()
  1588  		if t.err == "" {
  1589  			c.Check(err, IsNil)
  1590  		} else {
  1591  			c.Check(err, ErrorMatches, t.err)
  1592  		}
  1593  	}
  1594  }
  1595  
  1596  func (s *policySuite) TestPlugOnClassicCheckConnection(c *C) {
  1597  	r1 := release.MockOnClassic(false)
  1598  	defer r1()
  1599  	r2 := release.MockReleaseInfo(&release.ReleaseInfo)
  1600  	defer r2()
  1601  
  1602  	tests := []struct {
  1603  		distro string // "" => not classic
  1604  		iface  string
  1605  		err    string // "" => no error
  1606  	}{
  1607  		{"ubuntu", "plug-on-classic-true", ""},
  1608  		{"", "plug-on-classic-true", `connection not allowed by plug rule of interface "plug-on-classic-true"`},
  1609  		{"", "plug-on-classic-false", ""},
  1610  		{"ubuntu", "plug-on-classic-false", "connection not allowed.*"},
  1611  		{"ubuntu", "plug-on-classic-distros", ""},
  1612  		{"debian", "plug-on-classic-distros", ""},
  1613  		{"", "plug-on-classic-distros", "connection not allowed.*"},
  1614  		{"other", "plug-on-classic-distros", "connection not allowed.*"},
  1615  	}
  1616  
  1617  	for _, t := range tests {
  1618  		if t.distro == "" {
  1619  			release.OnClassic = false
  1620  		} else {
  1621  			release.OnClassic = true
  1622  			release.ReleaseInfo = release.OS{
  1623  				ID: t.distro,
  1624  			}
  1625  		}
  1626  		cand := policy.ConnectCandidate{
  1627  			Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1628  			Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1629  			BaseDeclaration: s.baseDecl,
  1630  		}
  1631  		err := cand.Check()
  1632  		if t.err == "" {
  1633  			c.Check(err, IsNil)
  1634  		} else {
  1635  			c.Check(err, ErrorMatches, t.err)
  1636  		}
  1637  	}
  1638  }
  1639  
  1640  func (s *policySuite) TestSlotOnClassicCheckConnection(c *C) {
  1641  	r1 := release.MockOnClassic(false)
  1642  	defer r1()
  1643  	r2 := release.MockReleaseInfo(&release.ReleaseInfo)
  1644  	defer r2()
  1645  
  1646  	tests := []struct {
  1647  		distro string // "" => not classic
  1648  		iface  string
  1649  		err    string // "" => no error
  1650  	}{
  1651  		{"ubuntu", "slot-on-classic-true", ""},
  1652  		{"", "slot-on-classic-true", `connection not allowed by slot rule of interface "slot-on-classic-true"`},
  1653  		{"", "slot-on-classic-false", ""},
  1654  		{"ubuntu", "slot-on-classic-false", "connection not allowed.*"},
  1655  		{"ubuntu", "slot-on-classic-distros", ""},
  1656  		{"debian", "slot-on-classic-distros", ""},
  1657  		{"", "slot-on-classic-distros", "connection not allowed.*"},
  1658  		{"other", "slot-on-classic-distros", "connection not allowed.*"},
  1659  	}
  1660  
  1661  	for _, t := range tests {
  1662  		if t.distro == "" {
  1663  			release.OnClassic = false
  1664  		} else {
  1665  			release.OnClassic = true
  1666  			release.ReleaseInfo = release.OS{
  1667  				ID: t.distro,
  1668  			}
  1669  		}
  1670  		cand := policy.ConnectCandidate{
  1671  			Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1672  			Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1673  			BaseDeclaration: s.baseDecl,
  1674  		}
  1675  		err := cand.Check()
  1676  		if t.err == "" {
  1677  			c.Check(err, IsNil)
  1678  		} else {
  1679  			c.Check(err, ErrorMatches, t.err)
  1680  		}
  1681  	}
  1682  }
  1683  
  1684  func (s *policySuite) TestOnClassicInstallation(c *C) {
  1685  	r1 := release.MockOnClassic(false)
  1686  	defer r1()
  1687  	r2 := release.MockReleaseInfo(&release.ReleaseInfo)
  1688  	defer r2()
  1689  
  1690  	tests := []struct {
  1691  		distro      string // "" => not classic
  1692  		installYaml string
  1693  		err         string // "" => no error
  1694  	}{
  1695  		{"", `name: install-snap
  1696  version: 0
  1697  slots:
  1698    install-slot-on-classic-distros:`, `installation not allowed by "install-slot-on-classic-distros" slot rule.*`},
  1699  		{"debian", `name: install-snap
  1700  version: 0
  1701  slots:
  1702    install-slot-on-classic-distros:`, ""},
  1703  		{"", `name: install-snap
  1704  version: 0
  1705  plugs:
  1706    install-plug-on-classic-distros:`, `installation not allowed by "install-plug-on-classic-distros" plug rule.*`},
  1707  		{"debian", `name: install-snap
  1708  version: 0
  1709  plugs:
  1710    install-plug-on-classic-distros:`, ""},
  1711  	}
  1712  
  1713  	for _, t := range tests {
  1714  		if t.distro == "" {
  1715  			release.OnClassic = false
  1716  		} else {
  1717  			release.OnClassic = true
  1718  			release.ReleaseInfo = release.OS{
  1719  				ID: t.distro,
  1720  			}
  1721  		}
  1722  
  1723  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  1724  
  1725  		cand := policy.InstallCandidate{
  1726  			Snap:            installSnap,
  1727  			BaseDeclaration: s.baseDecl,
  1728  		}
  1729  		err := cand.Check()
  1730  		if t.err == "" {
  1731  			c.Check(err, IsNil)
  1732  		} else {
  1733  			c.Check(err, ErrorMatches, t.err)
  1734  		}
  1735  	}
  1736  }
  1737  
  1738  var (
  1739  	otherModel *asserts.Model
  1740  	myModel1   *asserts.Model
  1741  	myModel2   *asserts.Model
  1742  	myModel3   *asserts.Model
  1743  
  1744  	substore1 *asserts.Store
  1745  )
  1746  
  1747  func init() {
  1748  	a, err := asserts.Decode([]byte(`type: model
  1749  authority-id: other-brand
  1750  series: 16
  1751  brand-id: other-brand
  1752  model: other-model
  1753  classic: true
  1754  gadget: gadget
  1755  timestamp: 2018-09-12T12:00:00Z
  1756  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1757  
  1758  AXNpZw==`))
  1759  	if err != nil {
  1760  		panic(err)
  1761  	}
  1762  	otherModel = a.(*asserts.Model)
  1763  
  1764  	a, err = asserts.Decode([]byte(`type: model
  1765  authority-id: my-brand
  1766  series: 16
  1767  brand-id: my-brand
  1768  model: my-model1
  1769  store: store1
  1770  architecture: armhf
  1771  kernel: krnl
  1772  gadget: gadget
  1773  timestamp: 2018-09-12T12:00:00Z
  1774  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1775  
  1776  AXNpZw==`))
  1777  	if err != nil {
  1778  		panic(err)
  1779  	}
  1780  	myModel1 = a.(*asserts.Model)
  1781  
  1782  	a, err = asserts.Decode([]byte(`type: model
  1783  authority-id: my-brand-subbrand
  1784  series: 16
  1785  brand-id: my-brand-subbrand
  1786  model: my-model2
  1787  store: store2
  1788  architecture: armhf
  1789  kernel: krnl
  1790  gadget: gadget
  1791  timestamp: 2018-09-12T12:00:00Z
  1792  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1793  
  1794  AXNpZw==`))
  1795  	if err != nil {
  1796  		panic(err)
  1797  	}
  1798  	myModel2 = a.(*asserts.Model)
  1799  
  1800  	a, err = asserts.Decode([]byte(`type: model
  1801  authority-id: my-brand
  1802  series: 16
  1803  brand-id: my-brand
  1804  model: my-model3
  1805  store: substore1
  1806  architecture: armhf
  1807  kernel: krnl
  1808  gadget: gadget
  1809  timestamp: 2018-09-12T12:00:00Z
  1810  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1811  
  1812  AXNpZw==`))
  1813  	if err != nil {
  1814  		panic(err)
  1815  	}
  1816  	myModel3 = a.(*asserts.Model)
  1817  
  1818  	a, err = asserts.Decode([]byte(`type: store
  1819  store: substore1
  1820  authority-id: canonical
  1821  operator-id: canonical
  1822  friendly-stores:
  1823    - a-store
  1824    - store1
  1825    - store2
  1826  timestamp: 2018-09-12T12:00:00Z
  1827  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  1828  
  1829  AXNpZw==`))
  1830  	if err != nil {
  1831  		panic(err)
  1832  	}
  1833  	substore1 = a.(*asserts.Store)
  1834  }
  1835  
  1836  func (s *policySuite) TestPlugDeviceScopeCheckAutoConnection(c *C) {
  1837  	tests := []struct {
  1838  		model *asserts.Model
  1839  		iface string
  1840  		err   string // "" => no error
  1841  	}{
  1842  		{nil, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1843  		{otherModel, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1844  		{myModel1, "auto-plug-on-store1", ""},
  1845  		{myModel2, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1846  		{otherModel, "auto-plug-on-my-brand", `auto-connection not allowed by plug rule of interface "auto-plug-on-my-brand" for "plug-snap" snap`},
  1847  		{myModel1, "auto-plug-on-my-brand", ""},
  1848  		{myModel2, "auto-plug-on-my-brand", ""},
  1849  		{otherModel, "auto-plug-on-my-model2", `auto-connection not allowed by plug rule of interface "auto-plug-on-my-model2" for "plug-snap" snap`},
  1850  		{myModel1, "auto-plug-on-my-model2", `auto-connection not allowed by plug rule of interface "auto-plug-on-my-model2" for "plug-snap" snap`},
  1851  		{myModel2, "auto-plug-on-my-model2", ""},
  1852  		// on-store/on-brand/on-model are ANDed for consistency!
  1853  		{otherModel, "auto-plug-on-multi", `auto-connection not allowed by plug rule of interface "auto-plug-on-multi" for "plug-snap" snap`},
  1854  		{myModel1, "auto-plug-on-multi", ""},
  1855  		{myModel2, "auto-plug-on-multi", `auto-connection not allowed by plug rule of interface "auto-plug-on-multi" for "plug-snap" snap`},
  1856  	}
  1857  
  1858  	for _, t := range tests {
  1859  		cand := policy.ConnectCandidate{
  1860  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1861  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1862  			PlugSnapDeclaration: s.plugDecl,
  1863  			SlotSnapDeclaration: s.slotDecl,
  1864  
  1865  			BaseDeclaration: s.baseDecl,
  1866  
  1867  			Model: t.model,
  1868  		}
  1869  		err := cand.CheckAutoConnect()
  1870  		if t.err == "" {
  1871  			c.Check(err, IsNil)
  1872  		} else {
  1873  			c.Check(err, ErrorMatches, t.err)
  1874  		}
  1875  	}
  1876  }
  1877  
  1878  func (s *policySuite) TestPlugDeviceScopeFriendlyStoreCheckAutoConnection(c *C) {
  1879  	tests := []struct {
  1880  		model *asserts.Model
  1881  		store *asserts.Store
  1882  		iface string
  1883  		err   string // "" => no error
  1884  	}{
  1885  		{nil, nil, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1886  		{myModel3, nil, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1887  		{myModel3, substore1, "auto-plug-on-store1", ""},
  1888  		{myModel2, substore1, "auto-plug-on-store1", `auto-connection not allowed by plug rule of interface "auto-plug-on-store1" for "plug-snap" snap`},
  1889  	}
  1890  
  1891  	for _, t := range tests {
  1892  		cand := policy.ConnectCandidate{
  1893  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1894  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1895  			PlugSnapDeclaration: s.plugDecl,
  1896  			SlotSnapDeclaration: s.slotDecl,
  1897  
  1898  			BaseDeclaration: s.baseDecl,
  1899  
  1900  			Model: t.model,
  1901  			Store: t.store,
  1902  		}
  1903  		err := cand.CheckAutoConnect()
  1904  		if t.err == "" {
  1905  			c.Check(err, IsNil)
  1906  		} else {
  1907  			c.Check(err, ErrorMatches, t.err)
  1908  		}
  1909  	}
  1910  }
  1911  
  1912  func (s *policySuite) TestSlotDeviceScopeCheckAutoConnection(c *C) {
  1913  	tests := []struct {
  1914  		model *asserts.Model
  1915  		iface string
  1916  		err   string // "" => no error
  1917  	}{
  1918  		{nil, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1919  		{otherModel, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1920  		{myModel1, "auto-slot-on-store1", ""},
  1921  		{myModel2, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1922  		{otherModel, "auto-slot-on-my-brand", `auto-connection not allowed by slot rule of interface "auto-slot-on-my-brand" for "slot-snap" snap`},
  1923  		{myModel1, "auto-slot-on-my-brand", ""},
  1924  		{myModel2, "auto-slot-on-my-brand", ""},
  1925  		{otherModel, "auto-slot-on-my-model2", `auto-connection not allowed by slot rule of interface "auto-slot-on-my-model2" for "slot-snap" snap`},
  1926  		{myModel1, "auto-slot-on-my-model2", `auto-connection not allowed by slot rule of interface "auto-slot-on-my-model2" for "slot-snap" snap`},
  1927  		{myModel2, "auto-slot-on-my-model2", ""},
  1928  		// on-store/on-brand/on-model are ANDed for consistency!
  1929  		{otherModel, "auto-slot-on-multi", `auto-connection not allowed by slot rule of interface "auto-slot-on-multi" for "slot-snap" snap`},
  1930  		{myModel1, "auto-slot-on-multi", ""},
  1931  		{myModel2, "auto-slot-on-multi", `auto-connection not allowed by slot rule of interface "auto-slot-on-multi" for "slot-snap" snap`},
  1932  	}
  1933  
  1934  	for _, t := range tests {
  1935  		cand := policy.ConnectCandidate{
  1936  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1937  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1938  			PlugSnapDeclaration: s.plugDecl,
  1939  			SlotSnapDeclaration: s.slotDecl,
  1940  
  1941  			BaseDeclaration: s.baseDecl,
  1942  
  1943  			Model: t.model,
  1944  		}
  1945  		err := cand.CheckAutoConnect()
  1946  		if t.err == "" {
  1947  			c.Check(err, IsNil)
  1948  		} else {
  1949  			c.Check(err, ErrorMatches, t.err)
  1950  		}
  1951  	}
  1952  }
  1953  
  1954  func (s *policySuite) TestSlotDeviceScopeFriendlyStoreCheckAutoConnection(c *C) {
  1955  	tests := []struct {
  1956  		model *asserts.Model
  1957  		store *asserts.Store
  1958  		iface string
  1959  		err   string // "" => no error
  1960  	}{
  1961  		{nil, nil, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1962  		{myModel3, nil, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1963  		{myModel3, substore1, "auto-slot-on-store1", ""},
  1964  		{myModel2, substore1, "auto-slot-on-store1", `auto-connection not allowed by slot rule of interface "auto-slot-on-store1" for "slot-snap" snap`},
  1965  	}
  1966  
  1967  	for _, t := range tests {
  1968  		cand := policy.ConnectCandidate{
  1969  			Plug:                interfaces.NewConnectedPlug(s.plugSnap.Plugs[t.iface], nil, nil),
  1970  			Slot:                interfaces.NewConnectedSlot(s.slotSnap.Slots[t.iface], nil, nil),
  1971  			PlugSnapDeclaration: s.plugDecl,
  1972  			SlotSnapDeclaration: s.slotDecl,
  1973  
  1974  			BaseDeclaration: s.baseDecl,
  1975  
  1976  			Model: t.model,
  1977  			Store: t.store,
  1978  		}
  1979  		err := cand.CheckAutoConnect()
  1980  		if t.err == "" {
  1981  			c.Check(err, IsNil)
  1982  		} else {
  1983  			c.Check(err, ErrorMatches, t.err)
  1984  		}
  1985  	}
  1986  }
  1987  
  1988  func (s *policySuite) TestDeviceScopeInstallation(c *C) {
  1989  	const plugSnap = `name: install-snap
  1990  version: 0
  1991  plugs:
  1992    install-plug-device-scope:`
  1993  
  1994  	const slotSnap = `name: install-snap
  1995  version: 0
  1996  slots:
  1997    install-slot-device-scope:`
  1998  
  1999  	const plugOnStore1 = `plugs:
  2000    install-plug-device-scope:
  2001      allow-installation:
  2002        on-store:
  2003          - store1
  2004  `
  2005  	const plugOnMulti = `plugs:
  2006    install-plug-device-scope:
  2007      allow-installation:
  2008        on-brand:
  2009          - my-brand
  2010          - my-brand-subbrand
  2011        on-store:
  2012          - store1
  2013          - other-store
  2014        on-model:
  2015          - my-brand/my-model1
  2016          - my-brand-subbrand/my-model2
  2017  `
  2018  	const slotOnStore2 = `slots:
  2019    install-slot-device-scope:
  2020      allow-installation:
  2021        on-store:
  2022          - store2
  2023  `
  2024  
  2025  	tests := []struct {
  2026  		model       *asserts.Model
  2027  		store       *asserts.Store
  2028  		installYaml string
  2029  		plugsSlots  string
  2030  		err         string // "" => no error
  2031  	}{
  2032  		{nil, nil, plugSnap, plugOnStore1, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2033  		{otherModel, nil, plugSnap, plugOnStore1, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2034  		{myModel1, nil, plugSnap, plugOnStore1, ""},
  2035  		{myModel2, nil, plugSnap, plugOnStore1, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2036  		{otherModel, nil, plugSnap, plugOnMulti, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2037  		{myModel1, nil, plugSnap, plugOnMulti, ""},
  2038  		{myModel2, nil, plugSnap, plugOnMulti, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2039  		{otherModel, nil, slotSnap, slotOnStore2, `installation not allowed by "install-slot-device-scope" slot rule of interface "install-slot-device-scope" for "install-snap" snap`},
  2040  		{myModel1, nil, slotSnap, slotOnStore2, `installation not allowed by "install-slot-device-scope" slot rule of interface "install-slot-device-scope" for "install-snap" snap`},
  2041  		{myModel2, nil, slotSnap, slotOnStore2, ""},
  2042  		// friendly-stores
  2043  		{myModel3, nil, plugSnap, plugOnStore1, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2044  		{myModel3, substore1, plugSnap, plugOnStore1, ""},
  2045  		{myModel2, substore1, plugSnap, plugOnStore1, `installation not allowed by "install-plug-device-scope" plug rule of interface "install-plug-device-scope" for "install-snap" snap`},
  2046  		{myModel3, nil, slotSnap, slotOnStore2, `installation not allowed by "install-slot-device-scope" slot rule of interface "install-slot-device-scope" for \"install-snap\" snap`},
  2047  		{myModel3, substore1, slotSnap, slotOnStore2, ""},
  2048  		{myModel2, substore1, slotSnap, slotOnStore2, `installation not allowed by "install-slot-device-scope" slot rule of interface "install-slot-device-scope" for \"install-snap\" snap`},
  2049  	}
  2050  
  2051  	for _, t := range tests {
  2052  		installSnap := snaptest.MockInfo(c, t.installYaml, nil)
  2053  
  2054  		a, err := asserts.Decode([]byte(strings.Replace(`type: snap-declaration
  2055  authority-id: canonical
  2056  series: 16
  2057  snap-name: install-snap
  2058  snap-id: installsnap6idididididididididid
  2059  publisher-id: publisher
  2060  @plugsSlots@
  2061  timestamp: 2016-09-30T12:00:00Z
  2062  sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij
  2063  
  2064  AXNpZw==`, "@plugsSlots@", strings.TrimSpace(t.plugsSlots), 1)))
  2065  		c.Assert(err, IsNil)
  2066  		snapDecl := a.(*asserts.SnapDeclaration)
  2067  
  2068  		cand := policy.InstallCandidate{
  2069  			Snap:            installSnap,
  2070  			SnapDeclaration: snapDecl,
  2071  			BaseDeclaration: s.baseDecl,
  2072  			Model:           t.model,
  2073  			Store:           t.store,
  2074  		}
  2075  		err = cand.Check()
  2076  		if t.err == "" {
  2077  			c.Check(err, IsNil)
  2078  		} else {
  2079  			c.Check(err, ErrorMatches, t.err)
  2080  		}
  2081  	}
  2082  }
  2083  
  2084  func (s *policySuite) TestSlotDollarSlotAttrConnection(c *C) {
  2085  	// no corresponding attr
  2086  	cand := policy.ConnectCandidate{
  2087  		Plug:            interfaces.NewConnectedPlug(s.randomSnap.Plugs["slot-slot-attr"], nil, nil),
  2088  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-slot-attr"], nil, nil),
  2089  		BaseDeclaration: s.baseDecl,
  2090  	}
  2091  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2092  
  2093  	// different attr values
  2094  	cand = policy.ConnectCandidate{
  2095  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-slot-attr-mismatch"], nil, nil),
  2096  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-slot-attr"], nil, nil),
  2097  		BaseDeclaration: s.baseDecl,
  2098  	}
  2099  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2100  
  2101  	// plug attr == slot attr
  2102  	cand = policy.ConnectCandidate{
  2103  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-slot-attr-match"], nil, nil),
  2104  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-slot-attr"], nil, nil),
  2105  		BaseDeclaration: s.baseDecl,
  2106  	}
  2107  	c.Check(cand.Check(), IsNil)
  2108  }
  2109  
  2110  func (s *policySuite) TestSlotDollarPlugAttrConnection(c *C) {
  2111  	// different attr values
  2112  	cand := policy.ConnectCandidate{
  2113  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-attr-mismatch"], nil, nil),
  2114  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-attr"], nil, nil),
  2115  		BaseDeclaration: s.baseDecl,
  2116  	}
  2117  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2118  
  2119  	// plug attr == slot attr
  2120  	cand = policy.ConnectCandidate{
  2121  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-attr-match"], nil, nil),
  2122  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-attr"], nil, nil),
  2123  		BaseDeclaration: s.baseDecl,
  2124  	}
  2125  	c.Check(cand.Check(), IsNil)
  2126  }
  2127  
  2128  func (s *policySuite) TestPlugDollarPlugAttrConnection(c *C) {
  2129  	// different attr values
  2130  	cand := policy.ConnectCandidate{
  2131  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-plug-attr"], nil, nil),
  2132  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-plug-attr-mismatch"], nil, nil),
  2133  		BaseDeclaration: s.baseDecl,
  2134  	}
  2135  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2136  
  2137  	// plug attr == slot attr
  2138  	cand = policy.ConnectCandidate{
  2139  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-plug-attr"], nil, nil),
  2140  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-plug-attr-match"], nil, nil),
  2141  		BaseDeclaration: s.baseDecl,
  2142  	}
  2143  	c.Check(cand.Check(), IsNil)
  2144  }
  2145  
  2146  func (s *policySuite) TestPlugDollarSlotAttrConnection(c *C) {
  2147  	// different attr values
  2148  	cand := policy.ConnectCandidate{
  2149  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-slot-attr"], nil, nil),
  2150  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-slot-attr-mismatch"], nil, nil),
  2151  		BaseDeclaration: s.baseDecl,
  2152  	}
  2153  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2154  
  2155  	// plug attr == slot attr
  2156  	cand = policy.ConnectCandidate{
  2157  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-slot-attr"], nil, nil),
  2158  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-slot-attr-match"], nil, nil),
  2159  		BaseDeclaration: s.baseDecl,
  2160  	}
  2161  	c.Check(cand.Check(), IsNil)
  2162  }
  2163  
  2164  func (s *policySuite) TestDollarMissingConnection(c *C) {
  2165  	// not missing
  2166  	cand := policy.ConnectCandidate{
  2167  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-missing-mismatch"], nil, nil),
  2168  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-missing"], nil, nil),
  2169  		BaseDeclaration: s.baseDecl,
  2170  	}
  2171  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2172  
  2173  	// missing
  2174  	cand = policy.ConnectCandidate{
  2175  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-missing-match"], nil, nil),
  2176  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-missing"], nil, nil),
  2177  		BaseDeclaration: s.baseDecl,
  2178  	}
  2179  	c.Check(cand.Check(), IsNil)
  2180  }
  2181  
  2182  func (s *policySuite) TestSlotDollarPlugDynamicAttrConnection(c *C) {
  2183  	// "c" attribute of the plug missing
  2184  	cand := policy.ConnectCandidate{
  2185  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-attr-dynamic"], nil, map[string]interface{}{}),
  2186  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-attr"], nil, nil),
  2187  		BaseDeclaration: s.baseDecl,
  2188  	}
  2189  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2190  
  2191  	// plug attr == slot attr, "c" attribute of the plug provided by dynamic attribute
  2192  	cand = policy.ConnectCandidate{
  2193  		Plug: interfaces.NewConnectedPlug(s.plugSnap.Plugs["slot-plug-attr-dynamic"], nil, map[string]interface{}{
  2194  			"c": "C",
  2195  		}),
  2196  
  2197  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["slot-plug-attr"], nil, nil),
  2198  		BaseDeclaration: s.baseDecl,
  2199  	}
  2200  	c.Check(cand.Check(), IsNil)
  2201  }
  2202  
  2203  func (s *policySuite) TestPlugDollarSlotDynamicAttrConnection(c *C) {
  2204  	// "c" attribute of the slot missing
  2205  	cand := policy.ConnectCandidate{
  2206  		Plug:            interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-plug-attr"], nil, nil),
  2207  		Slot:            interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-plug-attr-dynamic"], nil, map[string]interface{}{}),
  2208  		BaseDeclaration: s.baseDecl,
  2209  	}
  2210  	c.Check(cand.Check(), ErrorMatches, "connection not allowed.*")
  2211  
  2212  	// plug attr == slot attr, "c" attribute of the slot provided by dynamic attribute
  2213  	cand = policy.ConnectCandidate{
  2214  		Plug: interfaces.NewConnectedPlug(s.plugSnap.Plugs["plug-plug-attr"], nil, nil),
  2215  		Slot: interfaces.NewConnectedSlot(s.slotSnap.Slots["plug-plug-attr-dynamic"], nil, map[string]interface{}{
  2216  			"c": "C",
  2217  		}),
  2218  
  2219  		BaseDeclaration: s.baseDecl,
  2220  	}
  2221  	c.Check(cand.Check(), IsNil)
  2222  }