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