github.com/chipaca/snappy@v0.0.0-20210104084008-1f06296fe8ad/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 type: os 104 version: 0 105 slots: 106 bluez: 107 ` 108 109 func (s *BluezInterfaceSuite) SetUpTest(c *C) { 110 s.plug, s.plugInfo = MockConnectedPlug(c, bluezConsumerYaml, nil, "bluez") 111 s.appSlot, s.appSlotInfo = MockConnectedSlot(c, bluezProducerYaml, nil, "bluez") 112 s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, bluezCoreYaml, nil, "bluez") 113 } 114 115 func (s *BluezInterfaceSuite) TestName(c *C) { 116 c.Assert(s.iface.Name(), Equals, "bluez") 117 } 118 119 func (s *BluezInterfaceSuite) TestAppArmorSpec(c *C) { 120 // on a core system with bluez slot coming from a regular app snap. 121 restore := release.MockOnClassic(false) 122 defer restore() 123 124 // The label uses short form when exactly one app is bound to the bluez slot 125 spec := &apparmor.Specification{} 126 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 127 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 128 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`) 129 130 // The label glob when all apps are bound to the bluez slot 131 slot, _ := MockConnectedSlot(c, bluezProducerTwoAppsYaml, nil, "bluez") 132 spec = &apparmor.Specification{} 133 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil) 134 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 135 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.*"),`) 136 137 // The label uses alternation when some, but not all, apps is bound to the bluez slot 138 slot, _ = MockConnectedSlot(c, bluezProducerThreeAppsYaml, nil, "bluez") 139 spec = &apparmor.Specification{} 140 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil) 141 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 142 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.{app1,app3}"),`) 143 144 // The label uses short form when exactly one app is bound to the bluez plug 145 spec = &apparmor.Specification{} 146 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.appSlot), IsNil) 147 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 148 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.app"),`) 149 150 // The label glob when all apps are bound to the bluez plug 151 plug, _ := MockConnectedPlug(c, bluezConsumerTwoAppsYaml, nil, "bluez") 152 spec = &apparmor.Specification{} 153 c.Assert(spec.AddConnectedSlot(s.iface, plug, s.appSlot), IsNil) 154 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 155 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.*"),`) 156 157 // The label uses alternation when some, but not all, apps is bound to the bluez plug 158 plug, _ = MockConnectedPlug(c, bluezConsumerThreeAppsYaml, nil, "bluez") 159 spec = &apparmor.Specification{} 160 c.Assert(spec.AddConnectedSlot(s.iface, plug, s.appSlot), IsNil) 161 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 162 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.{app1,app2}"),`) 163 164 // permanent slot have a non-nil security snippet for apparmor 165 spec = &apparmor.Specification{} 166 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 167 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 168 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app", "snap.producer.app"}) 169 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`) 170 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label=unconfined),`) 171 172 // on a classic system with bluez slot coming from the core snap. 173 restore = release.MockOnClassic(true) 174 defer restore() 175 176 // connected plug to core slot 177 spec = &apparmor.Specification{} 178 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 179 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"}) 180 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez, label=unconfined)") 181 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez.obex, label=unconfined)") 182 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(name=org.bluez.mesh, label=unconfined)") 183 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=unconfined),") 184 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.DBus.ObjectManager`) 185 c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.DBus.*`) 186 187 // connected core slot to plug 188 spec = &apparmor.Specification{} 189 c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.coreSlot), IsNil) 190 c.Assert(spec.SecurityTags(), HasLen, 0) 191 192 // permanent core slot 193 spec = &apparmor.Specification{} 194 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 195 c.Assert(spec.SecurityTags(), HasLen, 0) 196 } 197 198 func (s *BluezInterfaceSuite) TestDBusSpec(c *C) { 199 // on a core system with bluez slot coming from a regular app snap. 200 restore := release.MockOnClassic(false) 201 defer restore() 202 203 spec := &dbus.Specification{} 204 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 205 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 206 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `<allow own="org.bluez"/>`) 207 208 // on a classic system with bluez slot coming from the core snap. 209 restore = release.MockOnClassic(true) 210 defer restore() 211 212 spec = &dbus.Specification{} 213 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 214 c.Assert(spec.SecurityTags(), HasLen, 0) 215 } 216 217 func (s *BluezInterfaceSuite) TestSecCompSpec(c *C) { 218 // on a core system with bluez slot coming from a regular app snap. 219 restore := release.MockOnClassic(false) 220 defer restore() 221 222 spec := &seccomp.Specification{} 223 c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil) 224 c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"}) 225 c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, "listen\n") 226 227 // on a classic system with bluez slot coming from the core snap. 228 restore = release.MockOnClassic(true) 229 defer restore() 230 231 spec = &seccomp.Specification{} 232 c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil) 233 c.Assert(spec.SecurityTags(), HasLen, 0) 234 235 } 236 237 func (s *BluezInterfaceSuite) TestUDevSpec(c *C) { 238 // on a core system with bluez slot coming from a regular app snap. 239 restore := release.MockOnClassic(false) 240 defer restore() 241 242 spec := &udev.Specification{} 243 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil) 244 c.Assert(spec.Snippets(), HasLen, 2) 245 c.Assert(spec.Snippets(), testutil.Contains, `# bluez 246 KERNEL=="rfkill", TAG+="snap_consumer_app"`) 247 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"`) 248 249 // on a classic system with bluez slot coming from the core snap. 250 restore = release.MockOnClassic(true) 251 defer restore() 252 253 spec = &udev.Specification{} 254 c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil) 255 c.Assert(spec.Snippets(), HasLen, 2) 256 c.Assert(spec.Snippets()[0], testutil.Contains, `KERNEL=="rfkill", TAG+="snap_consumer_app"`) 257 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"`) 258 259 } 260 261 func (s *BluezInterfaceSuite) TestStaticInfo(c *C) { 262 si := interfaces.StaticInfoOf(s.iface) 263 c.Assert(si.ImplicitOnCore, Equals, false) 264 c.Assert(si.ImplicitOnClassic, Equals, true) 265 c.Assert(si.Summary, Equals, `allows operating as the bluez service`) 266 c.Assert(si.BaseDeclarationSlots, testutil.Contains, "bluez") 267 } 268 269 func (s *BluezInterfaceSuite) TestAutoConnect(c *C) { 270 c.Assert(s.iface.AutoConnect(s.plugInfo, s.coreSlotInfo), Equals, true) 271 c.Assert(s.iface.AutoConnect(s.plugInfo, s.appSlotInfo), Equals, true) 272 } 273 274 func (s *BluezInterfaceSuite) TestInterfaces(c *C) { 275 c.Check(builtin.Interfaces(), testutil.DeepContains, s.iface) 276 }