gitee.com/mysnapcore/mysnapd@v0.1.0/interfaces/builtin/all_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package builtin_test 21 22 import ( 23 "fmt" 24 "reflect" 25 "strings" 26 27 . "gopkg.in/check.v1" 28 29 "gitee.com/mysnapcore/mysnapd/interfaces" 30 "gitee.com/mysnapcore/mysnapd/interfaces/apparmor" 31 "gitee.com/mysnapcore/mysnapd/interfaces/builtin" 32 "gitee.com/mysnapcore/mysnapd/interfaces/dbus" 33 "gitee.com/mysnapcore/mysnapd/interfaces/ifacetest" 34 "gitee.com/mysnapcore/mysnapd/interfaces/kmod" 35 "gitee.com/mysnapcore/mysnapd/interfaces/mount" 36 "gitee.com/mysnapcore/mysnapd/interfaces/polkit" 37 "gitee.com/mysnapcore/mysnapd/interfaces/seccomp" 38 "gitee.com/mysnapcore/mysnapd/interfaces/systemd" 39 "gitee.com/mysnapcore/mysnapd/interfaces/udev" 40 "gitee.com/mysnapcore/mysnapd/snap" 41 "gitee.com/mysnapcore/mysnapd/snap/snaptest" 42 ) 43 44 type AllSuite struct{} 45 46 var _ = Suite(&AllSuite{}) 47 48 // This section contains a list of *valid* defines that represent methods that 49 // backends recognize and call. They are in individual interfaces as each snapd 50 // interface can define a subset that it is interested in providing. Those are, 51 // essentially, the only valid methods that a snapd interface can have, apart 52 // from what is defined in the Interface golang interface. 53 type apparmorDefiner1 interface { 54 AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 55 } 56 type apparmorDefiner2 interface { 57 AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 58 } 59 type apparmorDefiner3 interface { 60 AppArmorPermanentPlug(spec *apparmor.Specification, plug *snap.PlugInfo) error 61 } 62 type apparmorDefiner4 interface { 63 AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error 64 } 65 66 type dbusDefiner1 interface { 67 DBusConnectedPlug(spec *dbus.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 68 } 69 type dbusDefiner2 interface { 70 DBusConnectedSlot(spec *dbus.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 71 } 72 type dbusDefiner3 interface { 73 DBusPermanentPlug(spec *dbus.Specification, plug *snap.PlugInfo) error 74 } 75 type dbusDefiner4 interface { 76 DBusPermanentSlot(spec *dbus.Specification, slot *snap.SlotInfo) error 77 } 78 79 type kmodDefiner1 interface { 80 KModConnectedPlug(spec *kmod.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 81 } 82 type kmodDefiner2 interface { 83 KModConnectedSlot(spec *kmod.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 84 } 85 type kmodDefiner3 interface { 86 KModPermanentPlug(spec *kmod.Specification, plug *snap.PlugInfo) error 87 } 88 type kmodDefiner4 interface { 89 KModPermanentSlot(spec *kmod.Specification, slot *snap.SlotInfo) error 90 } 91 92 type mountDefiner1 interface { 93 MountConnectedPlug(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 94 } 95 type mountDefiner2 interface { 96 MountConnectedSlot(spec *mount.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 97 } 98 type mountDefiner3 interface { 99 MountPermanentPlug(spec *mount.Specification, plug *snap.PlugInfo) error 100 } 101 type mountDefiner4 interface { 102 MountPermanentSlot(spec *mount.Specification, slot *snap.SlotInfo) error 103 } 104 105 type polkitDefiner1 interface { 106 PolkitConnectedPlug(spec *polkit.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 107 } 108 type polkitDefiner2 interface { 109 PolkitConnectedSlot(spec *polkit.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 110 } 111 type polkitDefiner3 interface { 112 PolkitPermanentPlug(spec *polkit.Specification, plug *snap.PlugInfo) error 113 } 114 type polkitDefiner4 interface { 115 PolkitPermanentSlot(spec *polkit.Specification, slot *snap.SlotInfo) error 116 } 117 118 type seccompDefiner1 interface { 119 SecCompConnectedPlug(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 120 } 121 type seccompDefiner2 interface { 122 SecCompConnectedSlot(spec *seccomp.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 123 } 124 type seccompDefiner3 interface { 125 SecCompPermanentPlug(spec *seccomp.Specification, plug *snap.PlugInfo) error 126 } 127 type seccompDefiner4 interface { 128 SecCompPermanentSlot(spec *seccomp.Specification, slot *snap.SlotInfo) error 129 } 130 131 type systemdDefiner1 interface { 132 SystemdConnectedPlug(spec *systemd.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 133 } 134 type systemdDefiner2 interface { 135 SystemdConnectedSlot(spec *systemd.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 136 } 137 type systemdDefiner3 interface { 138 SystemdPermanentPlug(spec *systemd.Specification, plug *snap.PlugInfo) error 139 } 140 type systemdDefiner4 interface { 141 SystemdPermanentSlot(spec *systemd.Specification, slot *snap.SlotInfo) error 142 } 143 144 type udevDefiner1 interface { 145 UDevConnectedPlug(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 146 } 147 type udevDefiner2 interface { 148 UDevConnectedSlot(spec *udev.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error 149 } 150 type udevDefiner3 interface { 151 UDevPermanentPlug(spec *udev.Specification, plug *snap.PlugInfo) error 152 } 153 type udevDefiner4 interface { 154 UDevPermanentSlot(spec *udev.Specification, slot *snap.SlotInfo) error 155 } 156 157 // allGoodDefiners contains all valid specification definers for all known backends. 158 var allGoodDefiners = []reflect.Type{ 159 // apparmor 160 reflect.TypeOf((*apparmorDefiner1)(nil)).Elem(), 161 reflect.TypeOf((*apparmorDefiner2)(nil)).Elem(), 162 reflect.TypeOf((*apparmorDefiner3)(nil)).Elem(), 163 reflect.TypeOf((*apparmorDefiner4)(nil)).Elem(), 164 // dbus 165 reflect.TypeOf((*dbusDefiner1)(nil)).Elem(), 166 reflect.TypeOf((*dbusDefiner2)(nil)).Elem(), 167 reflect.TypeOf((*dbusDefiner3)(nil)).Elem(), 168 reflect.TypeOf((*dbusDefiner4)(nil)).Elem(), 169 // kmod 170 reflect.TypeOf((*kmodDefiner1)(nil)).Elem(), 171 reflect.TypeOf((*kmodDefiner2)(nil)).Elem(), 172 reflect.TypeOf((*kmodDefiner3)(nil)).Elem(), 173 reflect.TypeOf((*kmodDefiner4)(nil)).Elem(), 174 // mount 175 reflect.TypeOf((*mountDefiner1)(nil)).Elem(), 176 reflect.TypeOf((*mountDefiner2)(nil)).Elem(), 177 reflect.TypeOf((*mountDefiner3)(nil)).Elem(), 178 reflect.TypeOf((*mountDefiner4)(nil)).Elem(), 179 // polkit 180 reflect.TypeOf((*polkitDefiner1)(nil)).Elem(), 181 reflect.TypeOf((*polkitDefiner2)(nil)).Elem(), 182 reflect.TypeOf((*polkitDefiner3)(nil)).Elem(), 183 reflect.TypeOf((*polkitDefiner4)(nil)).Elem(), 184 // seccomp 185 reflect.TypeOf((*seccompDefiner1)(nil)).Elem(), 186 reflect.TypeOf((*seccompDefiner2)(nil)).Elem(), 187 reflect.TypeOf((*seccompDefiner3)(nil)).Elem(), 188 reflect.TypeOf((*seccompDefiner4)(nil)).Elem(), 189 // systemd 190 reflect.TypeOf((*systemdDefiner1)(nil)).Elem(), 191 reflect.TypeOf((*systemdDefiner2)(nil)).Elem(), 192 reflect.TypeOf((*systemdDefiner3)(nil)).Elem(), 193 reflect.TypeOf((*systemdDefiner4)(nil)).Elem(), 194 // udev 195 reflect.TypeOf((*udevDefiner1)(nil)).Elem(), 196 reflect.TypeOf((*udevDefiner2)(nil)).Elem(), 197 reflect.TypeOf((*udevDefiner3)(nil)).Elem(), 198 reflect.TypeOf((*udevDefiner4)(nil)).Elem(), 199 } 200 201 // Check that each interface defines at least one definer method we recognize. 202 func (s *AllSuite) TestEachInterfaceImplementsSomeBackendMethods(c *C) { 203 for _, iface := range builtin.Interfaces() { 204 bogus := true 205 for _, definer := range allGoodDefiners { 206 if reflect.TypeOf(iface).Implements(definer) { 207 bogus = false 208 break 209 } 210 } 211 c.Assert(bogus, Equals, false, 212 Commentf("interface %q does not implement any specification methods", iface.Name())) 213 } 214 } 215 216 // pre-specification snippet functions 217 type snippetDefiner1 interface { 218 PermanentPlugSnippet(plug *snap.PlugInfo, sec interfaces.SecuritySystem) error 219 } 220 type snippetDefiner2 interface { 221 PermanentSlotSnippet(slot *snap.SlotInfo, sec interfaces.SecuritySystem) error 222 } 223 224 // old auto-connect function 225 type legacyAutoConnect interface { 226 LegacyAutoConnect() bool 227 } 228 229 type oldSanitizePlug1 interface { 230 SanitizePlug(plug *snap.PlugInfo) error 231 } 232 type oldSanitizeSlot1 interface { 233 SanitizeSlot(slot *snap.SlotInfo) error 234 } 235 236 // allBadDefiners contains all old/unused specification definers for all known backends. 237 var allBadDefiners = []reflect.Type{ 238 // pre-specification snippet methods 239 reflect.TypeOf((*snippetDefiner1)(nil)).Elem(), 240 reflect.TypeOf((*snippetDefiner2)(nil)).Elem(), 241 // old auto-connect function 242 reflect.TypeOf((*legacyAutoConnect)(nil)).Elem(), 243 // old sanitize methods 244 reflect.TypeOf((*oldSanitizePlug1)(nil)).Elem(), 245 reflect.TypeOf((*oldSanitizeSlot1)(nil)).Elem(), 246 } 247 248 // Check that no interface defines older definer methods. 249 func (s *AllSuite) TestNoInterfaceImplementsOldBackendMethods(c *C) { 250 for _, iface := range builtin.Interfaces() { 251 for _, definer := range allBadDefiners { 252 c.Assert(reflect.TypeOf(iface).Implements(definer), Equals, false, 253 Commentf("interface %q implements old/unused methods %s", iface.Name(), definer)) 254 } 255 } 256 } 257 258 func (s *AllSuite) TestRegisterIface(c *C) { 259 restore := builtin.MockInterfaces(nil) 260 defer restore() 261 262 // Registering an interface works correctly. 263 iface := &ifacetest.TestInterface{InterfaceName: "foo"} 264 builtin.RegisterIface(iface) 265 c.Assert(builtin.Interface("foo"), DeepEquals, iface) 266 267 // Duplicates are detected. 268 c.Assert(func() { builtin.RegisterIface(iface) }, PanicMatches, `cannot register duplicate interface "foo"`) 269 } 270 271 const testConsumerInvalidSlotNameYaml = ` 272 name: consumer 273 version: 0 274 slots: 275 ttyS5: 276 interface: iface 277 apps: 278 app: 279 slots: [iface] 280 ` 281 282 const testConsumerInvalidPlugNameYaml = ` 283 name: consumer 284 version: 0 285 plugs: 286 ttyS3: 287 interface: iface 288 apps: 289 app: 290 plugs: [iface] 291 ` 292 293 const testInvalidSlotInterfaceYaml = ` 294 name: testsnap 295 version: 0 296 slots: 297 iface: 298 interface: iface 299 apps: 300 app: 301 slots: [iface] 302 activates-on: [iface] 303 hooks: 304 install: 305 slots: [iface] 306 ` 307 308 const testInvalidPlugInterfaceYaml = ` 309 name: testsnap 310 version: 0 311 plugs: 312 iface: 313 interface: iface 314 apps: 315 app: 316 plugs: [iface] 317 hooks: 318 install: 319 plugs: [iface] 320 ` 321 322 func (s *AllSuite) TestSanitizeErrorsOnInvalidSlotNames(c *C) { 323 restore := builtin.MockInterfaces(map[string]interfaces.Interface{ 324 "iface": &ifacetest.TestInterface{InterfaceName: "iface"}, 325 }) 326 defer restore() 327 328 snapInfo := snaptest.MockInvalidInfo(c, testConsumerInvalidSlotNameYaml, nil) 329 snap.SanitizePlugsSlots(snapInfo) 330 c.Assert(snapInfo.BadInterfaces, HasLen, 1) 331 c.Check(snap.BadInterfacesSummary(snapInfo), Matches, `snap "consumer" has bad plugs or slots: ttyS5 \(invalid slot name: "ttyS5"\)`) 332 } 333 334 func (s *AllSuite) TestSanitizeErrorsOnInvalidPlugNames(c *C) { 335 restore := builtin.MockInterfaces(map[string]interfaces.Interface{ 336 "iface": &ifacetest.TestInterface{InterfaceName: "iface"}, 337 }) 338 defer restore() 339 340 snapInfo := snaptest.MockInvalidInfo(c, testConsumerInvalidPlugNameYaml, nil) 341 snap.SanitizePlugsSlots(snapInfo) 342 c.Assert(snapInfo.BadInterfaces, HasLen, 1) 343 c.Check(snap.BadInterfacesSummary(snapInfo), Matches, `snap "consumer" has bad plugs or slots: ttyS3 \(invalid plug name: "ttyS3"\)`) 344 } 345 346 func (s *AllSuite) TestSanitizeErrorsOnInvalidSlotInterface(c *C) { 347 snapInfo := snaptest.MockInvalidInfo(c, testInvalidSlotInterfaceYaml, nil) 348 c.Check(snapInfo.Apps["app"].Slots, HasLen, 1) 349 c.Check(snapInfo.Apps["app"].ActivatesOn, HasLen, 1) 350 c.Check(snapInfo.Hooks["install"].Slots, HasLen, 1) 351 c.Check(snapInfo.Slots, HasLen, 1) 352 snap.SanitizePlugsSlots(snapInfo) 353 c.Check(snapInfo.Apps["app"].Slots, HasLen, 0) 354 c.Check(snapInfo.Apps["app"].ActivatesOn, HasLen, 0) 355 c.Check(snapInfo.Hooks["install"].Slots, HasLen, 0) 356 c.Assert(snapInfo.BadInterfaces, HasLen, 1) 357 c.Check(snap.BadInterfacesSummary(snapInfo), Matches, `snap "testsnap" has bad plugs or slots: iface \(unknown interface "iface"\)`) 358 c.Assert(snapInfo.Plugs, HasLen, 0) 359 c.Assert(snapInfo.Slots, HasLen, 0) 360 } 361 362 func (s *AllSuite) TestSanitizeErrorsOnInvalidPlugInterface(c *C) { 363 snapInfo := snaptest.MockInfo(c, testInvalidPlugInterfaceYaml, nil) 364 c.Check(snapInfo.Apps["app"].Plugs, HasLen, 1) 365 c.Check(snapInfo.Hooks["install"].Plugs, HasLen, 1) 366 c.Assert(snapInfo.Plugs, HasLen, 1) 367 snap.SanitizePlugsSlots(snapInfo) 368 c.Assert(snapInfo.Apps["app"].Plugs, HasLen, 0) 369 c.Check(snapInfo.Hooks["install"].Plugs, HasLen, 0) 370 c.Assert(snapInfo.BadInterfaces, HasLen, 1) 371 c.Assert(snap.BadInterfacesSummary(snapInfo), Matches, `snap "testsnap" has bad plugs or slots: iface \(unknown interface "iface"\)`) 372 c.Assert(snapInfo.Plugs, HasLen, 0) 373 c.Assert(snapInfo.Slots, HasLen, 0) 374 } 375 376 func (s *AllSuite) TestUnexpectedSpecSignatures(c *C) { 377 type funcSig struct { 378 name string 379 in []string 380 out []string 381 } 382 var sigs []funcSig 383 384 // All the valid signatures from all the specification definers from all the backends. 385 for _, backend := range []string{"AppArmor", "SecComp", "UDev", "DBus", "Systemd", "KMod", "Polkit"} { 386 backendLower := strings.ToLower(backend) 387 sigs = append(sigs, []funcSig{{ 388 name: fmt.Sprintf("%sPermanentPlug", backend), 389 in: []string{ 390 fmt.Sprintf("*%s.Specification", backendLower), 391 "*snap.PlugInfo", 392 }, 393 out: []string{"error"}, 394 }, { 395 name: fmt.Sprintf("%sPermanentSlot", backend), 396 in: []string{ 397 fmt.Sprintf("*%s.Specification", backendLower), 398 "*snap.SlotInfo", 399 }, 400 out: []string{"error"}, 401 }, { 402 name: fmt.Sprintf("%sConnectedPlug", backend), 403 in: []string{ 404 fmt.Sprintf("*%s.Specification", backendLower), 405 "*interfaces.ConnectedPlug", 406 "*interfaces.ConnectedSlot", 407 }, 408 out: []string{"error"}, 409 }, { 410 name: fmt.Sprintf("%sConnectedSlot", backend), 411 in: []string{ 412 fmt.Sprintf("*%s.Specification", backendLower), 413 "*interfaces.ConnectedPlug", 414 "*interfaces.ConnectedSlot", 415 }, 416 out: []string{"error"}, 417 }}...) 418 } 419 for _, iface := range builtin.Interfaces() { 420 ifaceVal := reflect.ValueOf(iface) 421 ifaceType := ifaceVal.Type() 422 for _, sig := range sigs { 423 meth, ok := ifaceType.MethodByName(sig.name) 424 if !ok { 425 // all specification methods are optional. 426 continue 427 } 428 methType := meth.Type 429 // Check that the signature matches our expectation. The -1 and +1 below is for the receiver type. 430 c.Assert(methType.NumIn()-1, Equals, len(sig.in), Commentf("expected %s's %s method to take %d arguments", ifaceType, meth.Name, len(sig.in))) 431 for i, expected := range sig.in { 432 c.Assert(methType.In(i+1).String(), Equals, expected, Commentf("expected %s's %s method %dth argument type to be different", ifaceType, meth.Name, i)) 433 } 434 c.Assert(methType.NumOut(), Equals, len(sig.out), Commentf("expected %s's %s method to return %d values", ifaceType, meth.Name, len(sig.out))) 435 for i, expected := range sig.out { 436 c.Assert(methType.Out(i).String(), Equals, expected, Commentf("expected %s's %s method %dth return value type to be different", ifaceType, meth.Name, i)) 437 } 438 } 439 } 440 }