github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/interfaces/builtin/bluez_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 builtin_test 21 22 import ( 23 . "gopkg.in/check.v1" 24 25 "github.com/snapcore/snapd/interfaces" 26 "github.com/snapcore/snapd/interfaces/apparmor" 27 "github.com/snapcore/snapd/interfaces/builtin" 28 "github.com/snapcore/snapd/interfaces/dbus" 29 "github.com/snapcore/snapd/interfaces/seccomp" 30 "github.com/snapcore/snapd/interfaces/udev" 31 "github.com/snapcore/snapd/release" 32 "github.com/snapcore/snapd/snap" 33 "github.com/snapcore/snapd/testutil" 34 ) 35 36 type BluezInterfaceSuite struct { 37 iface interfaces.Interface 38 appSlot *interfaces.ConnectedSlot 39 appSlotInfo *snap.SlotInfo 40 coreSlot *interfaces.ConnectedSlot 41 coreSlotInfo *snap.SlotInfo 42 plug *interfaces.ConnectedPlug 43 plugInfo *snap.PlugInfo 44 } 45 46 var _ = Suite(&BluezInterfaceSuite{ 47 iface: builtin.MustInterface("bluez"), 48 }) 49 50 const bluezConsumerYaml = `name: consumer 51 version: 0 52 apps: 53 app: 54 plugs: [bluez] 55 ` 56 57 const bluezConsumerTwoAppsYaml = `name: consumer 58 version: 0 59 apps: 60 app1: 61 plugs: [bluez] 62 app2: 63 plugs: [bluez] 64 ` 65 66 const bluezConsumerThreeAppsYaml = `name: consumer 67 version: 0 68 apps: 69 app1: 70 plugs: [bluez] 71 app2: 72 plugs: [bluez] 73 app3: 74 ` 75 76 const bluezProducerYaml = `name: producer 77 version: 0 78 apps: 79 app: 80 slots: [bluez] 81 ` 82 83 const bluezProducerTwoAppsYaml = `name: producer 84 version: 0 85 apps: 86 app1: 87 slots: [bluez] 88 app2: 89 slots: [bluez] 90 ` 91 92 const bluezProducerThreeAppsYaml = `name: producer 93 version: 0 94 apps: 95 app1: 96 slots: [bluez] 97 app2: 98 app3: 99 slots: [bluez] 100 ` 101 102 const bluezCoreYaml = `name: core 103 version: 0 104 slots: 105 bluez: 106 ` 107 108 func (s *BluezInterfaceSuite) SetUpTest(c *C) { 109 s.plug, s.plugInfo = MockConnectedPlug(c, bluezConsumerYaml, nil, "bluez") 110 s.appSlot, s.appSlotInfo = MockConnectedSlot(c, bluezProducerYaml, nil, "bluez") 111 s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, bluezCoreYaml, nil, "bluez") 112 } 113 114 func (s *BluezInterfaceSuite) TestName(c *C) { 115 c.Assert(s.iface.Name(), Equals, "bluez") 116 } 117 118 func (s *BluezInterfaceSuite) TestAppArmorSpec(c *C) { 119 // on a core system with bluez slot coming from a regular app snap. 120 restore := release.MockOnClassic(false) 121 defer restore() 122 123 // The label uses short form when exactly one app is bound to the bluez slot 124 spec := &apparmor.Specification{} 125 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 126 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 127 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`) 128 129 // The label glob when all apps are bound to the bluez slot 130 slot, _ := MockConnectedSlot(c, bluezProducerTwoAppsYaml, nil, "bluez") 131 spec = &apparmor.Specification{} 132 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil) 133 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 134 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.*"),`) 135 136 // The label uses alternation when some, but not all, apps is bound to the bluez slot 137 slot, _ = MockConnectedSlot(c, bluezProducerThreeAppsYaml, nil, "bluez") 138 spec = &apparmor.Specification{} 139 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil) 140 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 141 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.{app1,app3}"),`) 142 143 // The label uses short form when exactly one app is bound to the bluez plug 144 spec = &apparmor.Specification{} 145 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.appSlot), IsNil) 146 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 147 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.app"),`) 148 149 // The label glob when all apps are bound to the bluez plug 150 plug, _ := MockConnectedPlug(c, bluezConsumerTwoAppsYaml, nil, "bluez") 151 spec = &apparmor.Specification{} 152 c.Assert(spec.AddConnectedSlot(s.iface, plug, s.appSlot), IsNil) 153 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 154 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.*"),`) 155 156 // The label uses alternation when some, but not all, apps is bound to the bluez plug 157 plug, _ = MockConnectedPlug(c, bluezConsumerThreeAppsYaml, nil, "bluez") 158 spec = &apparmor.Specification{} 159 c.Assert(spec.AddConnectedSlot(s.iface, plug, s.appSlot), IsNil) 160 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 161 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.{app1,app2}"),`) 162 163 // permanent slot have a non-nil security snippet for apparmor 164 spec = &apparmor.Specification{} 165 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 166 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 167 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app", "snap.producer.app"}) 168 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`) 169 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label=unconfined),`) 170 171 // on a classic system with bluez slot coming from the core snap. 172 restore = release.MockOnClassic(true) 173 defer restore() 174 175 // connected plug to core slot 176 spec = &apparmor.Specification{} 177 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 178 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 179 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez, label=unconfined)") 180 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez.obex, label=unconfined)") 181 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez.mesh, label=unconfined)") 182 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=unconfined),") 183 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.DBus.ObjectManager`) 184 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.DBus.*`) 185 186 // connected core slot to plug 187 spec = &apparmor.Specification{} 188 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.coreSlot), IsNil) 189 c.Assert(spec.SecurityTags(), HasLen, 0) 190 191 // permanent core slot 192 spec = &apparmor.Specification{} 193 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 194 c.Assert(spec.SecurityTags(), HasLen, 0) 195 } 196 197 func (s *BluezInterfaceSuite) TestDBusSpec(c *C) { 198 // on a core system with bluez slot coming from a regular app snap. 199 restore := release.MockOnClassic(false) 200 defer restore() 201 202 spec := &dbus.Specification{} 203 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 204 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 205 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `<allow own="org.bluez"/>`) 206 207 // on a classic system with bluez slot coming from the core snap. 208 restore = release.MockOnClassic(true) 209 defer restore() 210 211 spec = &dbus.Specification{} 212 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 213 c.Assert(spec.SecurityTags(), HasLen, 0) 214 } 215 216 func (s *BluezInterfaceSuite) TestSecCompSpec(c *C) { 217 // on a core system with bluez slot coming from a regular app snap. 218 restore := release.MockOnClassic(false) 219 defer restore() 220 221 spec := &seccomp.Specification{} 222 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 223 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 224 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, "listen\n") 225 226 // on a classic system with bluez slot coming from the core snap. 227 restore = release.MockOnClassic(true) 228 defer restore() 229 230 spec = &seccomp.Specification{} 231 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 232 c.Assert(spec.SecurityTags(), HasLen, 0) 233 234 } 235 236 func (s *BluezInterfaceSuite) TestUDevSpec(c *C) { 237 // on a core system with bluez slot coming from a regular app snap. 238 restore := release.MockOnClassic(false) 239 defer restore() 240 241 spec := &udev.Specification{} 242 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 243 c.Assert(spec.Snippets(), HasLen, 2) 244 c.Assert(spec.Snippets(), testutil.Contains, `# bluez 245 KERNEL=="rfkill", TAG+="snap_consumer_app"`) 246 c.Assert(spec.Snippets(), testutil.Contains, `TAG=="snap_consumer_app", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_consumer_app $devpath $major:$minor"`) 247 248 // on a classic system with bluez slot coming from the core snap. 249 restore = release.MockOnClassic(true) 250 defer restore() 251 252 spec = &udev.Specification{} 253 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 254 c.Assert(spec.Snippets(), HasLen, 2) 255 c.Assert(spec.Snippets()[0], testutil.Contains, `KERNEL=="rfkill", TAG+="snap_consumer_app"`) 256 c.Assert(spec.Snippets(), testutil.Contains, `TAG=="snap_consumer_app", RUN+="/usr/lib/snapd/snap-device-helper $env{ACTION} snap_consumer_app $devpath $major:$minor"`) 257 258 } 259 260 func (s *BluezInterfaceSuite) TestStaticInfo(c *C) { 261 si := interfaces.StaticInfoOf(s.iface) 262 c.Assert(si.ImplicitOnCore, Equals, false) 263 c.Assert(si.ImplicitOnClassic, Equals, true) 264 c.Assert(si.Summary, Equals, `allows operating as the bluez service`) 265 c.Assert(si.BaseDeclarationSlots, testutil.Contains, "bluez") 266 } 267 268 func (s *BluezInterfaceSuite) TestAutoConnect(c *C) { 269 c.Assert(s.iface.AutoConnect(s.plugInfo, s.coreSlotInfo), Equals, true) 270 c.Assert(s.iface.AutoConnect(s.plugInfo, s.appSlotInfo), Equals, true) 271 } 272 273 func (s *BluezInterfaceSuite) TestInterfaces(c *C) { 274 c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface) 275 }