summaryrefslogtreecommitdiff
diff options
authorMichael Vogt <mvo@ubuntu.com>2019-06-07 13:21:10 +0200
committerGitHub <noreply@github.com>2019-06-07 13:21:10 +0200
commit47a007b51438e63f9aec020de90d6c9d07c54d38 (patch)
tree15143136f333872d22481b4fbfe482f600343244
parent9d4e5903d00c24fb7a08aa7c0081e4b88af7fbfe (diff)
parent2159125f423998f1f440c07214f3174fabb637a2 (diff)
Merge pull request #6325 from kubiko/avahi-on-classic
Allowing avahi-observer/control slots from app snap also on classic
-rw-r--r--interfaces/builtin/avahi_control.go23
-rw-r--r--interfaces/builtin/avahi_control_test.go99
-rw-r--r--interfaces/builtin/avahi_observe.go23
-rw-r--r--interfaces/builtin/avahi_observe_test.go99
-rw-r--r--interfaces/builtin/export_test.go2
-rw-r--r--interfaces/builtin/utils.go24
-rw-r--r--interfaces/builtin/utils_test.go38
7 files changed, 224 insertions, 84 deletions
diff --git a/interfaces/builtin/avahi_control.go b/interfaces/builtin/avahi_control.go
index d20f85acfb..3b91439ce8 100644
--- a/interfaces/builtin/avahi_control.go
+++ b/interfaces/builtin/avahi_control.go
@@ -25,7 +25,6 @@ import (
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/dbus"
- "github.com/snapcore/snapd/release"
"github.com/snapcore/snapd/snap"
)
@@ -119,10 +118,12 @@ func (iface *avahiControlInterface) StaticInfo() interfaces.StaticInfo {
func (iface *avahiControlInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
old := "###SLOT_SECURITY_TAGS###"
var new string
- if release.OnClassic {
- // If we're running on classic Avahi will be part
- // of the OS snap and will run unconfined.
- new = "unconfined"
+ // If we're running on classic, Avahi may be installed either as a snap of
+ // as part of the OS. If it is part of the OS, it will not have a security
+ // label like it would when installed as a snap.
+ if implicitSystemConnectedSlot(slot) {
+ // avahi from the OS is typically unconfined but known to sometimes be confined
+ new = "\"{unconfined,/usr/sbin/avahi-daemon}\""
} else {
new = slotAppLabelExpr(slot)
}
@@ -135,7 +136,9 @@ func (iface *avahiControlInterface) AppArmorConnectedPlug(spec *apparmor.Specifi
}
func (iface *avahiControlInterface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemPermanentSlot(slot) {
// NOTE: this is using avahi-observe permanent slot as it contains
// base declarations for running as the avahi service.
spec.AddSnippet(avahiObservePermanentSlotAppArmor)
@@ -144,7 +147,9 @@ func (iface *avahiControlInterface) AppArmorPermanentSlot(spec *apparmor.Specifi
}
func (iface *avahiControlInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemConnectedSlot(slot) {
old := "###PLUG_SECURITY_TAGS###"
new := plugAppLabelExpr(plug)
// avahi-control implies avahi-observe, so add snippets for both here
@@ -157,7 +162,9 @@ func (iface *avahiControlInterface) AppArmorConnectedSlot(spec *apparmor.Specifi
}
func (iface *avahiControlInterface) DBusPermanentSlot(spec *dbus.Specification, slot *snap.SlotInfo) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemPermanentSlot(slot) {
// NOTE: this is using avahi-observe permanent slot as it contains
// base declarations for running as the avahi service.
spec.AddSnippet(avahiObservePermanentSlotDBus)
diff --git a/interfaces/builtin/avahi_control_test.go b/interfaces/builtin/avahi_control_test.go
index 71f4c3cec0..ae42bd62b7 100644
--- a/interfaces/builtin/avahi_control_test.go
+++ b/interfaces/builtin/avahi_control_test.go
@@ -32,13 +32,15 @@ import (
)
type AvahiControlInterfaceSuite struct {
- iface interfaces.Interface
- plug *interfaces.ConnectedPlug
- plugInfo *snap.PlugInfo
- appSlot *interfaces.ConnectedSlot
- appSlotInfo *snap.SlotInfo
- coreSlot *interfaces.ConnectedSlot
- coreSlotInfo *snap.SlotInfo
+ iface interfaces.Interface
+ plug *interfaces.ConnectedPlug
+ plugInfo *snap.PlugInfo
+ appSlot *interfaces.ConnectedSlot
+ appSlotInfo *snap.SlotInfo
+ coreSlot *interfaces.ConnectedSlot
+ coreSlotInfo *snap.SlotInfo
+ snapdSlot *interfaces.ConnectedSlot
+ snapdSlotInfo *snap.SlotInfo
}
var _ = Suite(&AvahiControlInterfaceSuite{
@@ -61,6 +63,14 @@ apps:
const avahiControlCoreYaml = `name: core
version: 0
+type: os
+slots:
+ avahi-control:
+`
+
+const avahiControlSnapdYaml = `name: snapd
+version: 0
+type: snapd
slots:
avahi-control:
`
@@ -69,6 +79,7 @@ func (s *AvahiControlInterfaceSuite) SetUpTest(c *C) {
s.plug, s.plugInfo = MockConnectedPlug(c, avahiControlConsumerYaml, nil, "avahi-control")
s.appSlot, s.appSlotInfo = MockConnectedSlot(c, avahiControlProducerYaml, nil, "avahi-control")
s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, avahiControlCoreYaml, nil, "avahi-control")
+ s.snapdSlot, s.snapdSlotInfo = MockConnectedSlot(c, avahiControlSnapdYaml, nil, "avahi-control")
}
func (s *AvahiControlInterfaceSuite) TestName(c *C) {
@@ -91,14 +102,11 @@ func (s *AvahiControlInterfaceSuite) TestSanitizePlug(c *C) {
c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
}
-func (s *AvahiControlInterfaceSuite) TestAppArmorSpec(c *C) {
- // on a core system with avahi slot coming from a regular app snap.
- restore := release.MockOnClassic(false)
- defer restore()
-
+func (s *AvahiControlInterfaceSuite) testAppArmorSpecWithProducer(c *C,
+ slot *interfaces.ConnectedSlot, slotInfo *snap.SlotInfo) {
// connected plug to app slot
spec := &apparmor.Specification{}
- c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil)
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "name=org.freedesktop.Avahi")
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`)
@@ -114,7 +122,7 @@ func (s *AvahiControlInterfaceSuite) TestAppArmorSpec(c *C) {
// connected app slot to plug
spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.appSlot), IsNil)
+ c.Assert(spec.AddConnectedSlot(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `interface=org.freedesktop.Avahi`)
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.app"),`)
@@ -128,22 +136,21 @@ func (s *AvahiControlInterfaceSuite) TestAppArmorSpec(c *C) {
// permanent app slot
spec = &apparmor.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil)
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `dbus (bind)
bus=system
name="org.freedesktop.Avahi",`)
+}
- // on a classic system with avahi slot coming from the core snap.
- restore = release.MockOnClassic(true)
- defer restore()
-
+func (s *AvahiControlInterfaceSuite) testAppArmorSpecFromSystem(c *C,
+ slot *interfaces.ConnectedSlot, slotInfo *snap.SlotInfo) {
// connected plug to core slot
- spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil)
+ spec := &apparmor.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "name=org.freedesktop.Avahi")
- c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=unconfined),")
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=\"{unconfined,/usr/sbin/avahi-daemon}\"),")
// make sure control includes also observe capabilities
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.Avahi.AddressResolver`)
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.Avahi.HostNameResolver`)
@@ -155,34 +162,68 @@ func (s *AvahiControlInterfaceSuite) TestAppArmorSpec(c *C) {
// connected core slot to plug
spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.coreSlot), IsNil)
+ c.Assert(spec.AddConnectedSlot(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
// permanent core slot
spec = &apparmor.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
}
-func (s *AvahiControlInterfaceSuite) TestDBusSpec(c *C) {
+func (s *AvahiControlInterfaceSuite) TestAppArmorSpec(c *C) {
// on a core system with avahi slot coming from a regular app snap.
restore := release.MockOnClassic(false)
defer restore()
+ s.testAppArmorSpecWithProducer(c, s.appSlot, s.appSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by core snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecWithProducer(c, s.appSlot, s.appSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by core snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecFromSystem(c, s.coreSlot, s.coreSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by snapd snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecFromSystem(c, s.snapdSlot, s.snapdSlotInfo)
+}
+
+func (s *AvahiControlInterfaceSuite) testDBusSpecSlotByApp(c *C, classic bool) {
+ restore := release.MockOnClassic(classic)
+ defer restore()
spec := &dbus.Specification{}
c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `<allow own="org.freedesktop.Avahi"/>`)
+}
- // on a classic system with avahi slot coming from the core snap.
- restore = release.MockOnClassic(true)
+func (s *AvahiControlInterfaceSuite) testDBusSpecSlotBySystem(c *C, slotInfo *snap.SlotInfo) {
+ restore := release.MockOnClassic(true)
defer restore()
- spec = &dbus.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
+ spec := &dbus.Specification{}
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
}
+func (s *AvahiControlInterfaceSuite) TestDBusSpecSlot(c *C) {
+ // on a core system with avahi slot coming from a regular app snap.
+ s.testDBusSpecSlotByApp(c, false)
+ // on a classic system with avahi slot coming from a regular app snap.
+ s.testDBusSpecSlotByApp(c, true)
+
+ // on a classic system with avahi slot coming from the core snap.
+ s.testDBusSpecSlotBySystem(c, s.coreSlotInfo)
+ // on a classic system with avahi slot coming from the snapd snap.
+ s.testDBusSpecSlotBySystem(c, s.snapdSlotInfo)
+}
+
func (s *AvahiControlInterfaceSuite) TestStaticInfo(c *C) {
si := interfaces.StaticInfoOf(s.iface)
c.Assert(si.ImplicitOnCore, Equals, false)
diff --git a/interfaces/builtin/avahi_observe.go b/interfaces/builtin/avahi_observe.go
index c767d7e68f..362109b763 100644
--- a/interfaces/builtin/avahi_observe.go
+++ b/interfaces/builtin/avahi_observe.go
@@ -25,7 +25,6 @@ import (
"github.com/snapcore/snapd/interfaces"
"github.com/snapcore/snapd/interfaces/apparmor"
"github.com/snapcore/snapd/interfaces/dbus"
- "github.com/snapcore/snapd/release"
"github.com/snapcore/snapd/snap"
)
@@ -430,10 +429,12 @@ func (iface *avahiObserveInterface) StaticInfo() interfaces.StaticInfo {
func (iface *avahiObserveInterface) AppArmorConnectedPlug(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
old := "###SLOT_SECURITY_TAGS###"
var new string
- if release.OnClassic {
- // If we're running on classic Avahi will be part
- // of the OS snap and will run unconfined.
- new = "unconfined"
+ // If we're running on classic, Avahi may be installed either as a snap of
+ // as part of the OS. If it is part of the OS, it will not have a security
+ // label like it would when installed as a snap.
+ if implicitSystemConnectedSlot(slot) {
+ // avahi from the OS is typically unconfined but known to sometimes be confined
+ new = "\"{unconfined,/usr/sbin/avahi-daemon}\""
} else {
new = slotAppLabelExpr(slot)
}
@@ -443,14 +444,18 @@ func (iface *avahiObserveInterface) AppArmorConnectedPlug(spec *apparmor.Specifi
}
func (iface *avahiObserveInterface) AppArmorPermanentSlot(spec *apparmor.Specification, slot *snap.SlotInfo) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemPermanentSlot(slot) {
spec.AddSnippet(avahiObservePermanentSlotAppArmor)
}
return nil
}
func (iface *avahiObserveInterface) AppArmorConnectedSlot(spec *apparmor.Specification, plug *interfaces.ConnectedPlug, slot *interfaces.ConnectedSlot) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemConnectedSlot(slot) {
old := "###PLUG_SECURITY_TAGS###"
new := plugAppLabelExpr(plug)
snippet := strings.Replace(avahiObserveConnectedSlotAppArmor, old, new, -1)
@@ -460,7 +465,9 @@ func (iface *avahiObserveInterface) AppArmorConnectedSlot(spec *apparmor.Specifi
}
func (iface *avahiObserveInterface) DBusPermanentSlot(spec *dbus.Specification, slot *snap.SlotInfo) error {
- if !release.OnClassic {
+ // Only apply slot snippet when running as application snap
+ // on classic, slot side can be system or application
+ if !implicitSystemPermanentSlot(slot) {
spec.AddSnippet(avahiObservePermanentSlotDBus)
}
return nil
diff --git a/interfaces/builtin/avahi_observe_test.go b/interfaces/builtin/avahi_observe_test.go
index 650e25e7ed..d428558651 100644
--- a/interfaces/builtin/avahi_observe_test.go
+++ b/interfaces/builtin/avahi_observe_test.go
@@ -32,13 +32,15 @@ import (
)
type AvahiObserveInterfaceSuite struct {
- iface interfaces.Interface
- plug *interfaces.ConnectedPlug
- plugInfo *snap.PlugInfo
- appSlot *interfaces.ConnectedSlot
- appSlotInfo *snap.SlotInfo
- coreSlot *interfaces.ConnectedSlot
- coreSlotInfo *snap.SlotInfo
+ iface interfaces.Interface
+ plug *interfaces.ConnectedPlug
+ plugInfo *snap.PlugInfo
+ appSlot *interfaces.ConnectedSlot
+ appSlotInfo *snap.SlotInfo
+ coreSlot *interfaces.ConnectedSlot
+ coreSlotInfo *snap.SlotInfo
+ snapdSlot *interfaces.ConnectedSlot
+ snapdSlotInfo *snap.SlotInfo
}
var _ = Suite(&AvahiObserveInterfaceSuite{
@@ -61,6 +63,14 @@ apps:
const avahiObserveCoreYaml = `name: core
version: 0
+type: os
+slots:
+ avahi-observe:
+`
+
+const avahiObserveSnapdYaml = `name: snapd
+version: 0
+type: snapd
slots:
avahi-observe:
`
@@ -69,6 +79,7 @@ func (s *AvahiObserveInterfaceSuite) SetUpTest(c *C) {
s.plug, s.plugInfo = MockConnectedPlug(c, avahiObserveConsumerYaml, nil, "avahi-observe")
s.appSlot, s.appSlotInfo = MockConnectedSlot(c, avahiObserveProducerYaml, nil, "avahi-observe")
s.coreSlot, s.coreSlotInfo = MockConnectedSlot(c, avahiObserveCoreYaml, nil, "avahi-observe")
+ s.snapdSlot, s.snapdSlotInfo = MockConnectedSlot(c, avahiObserveSnapdYaml, nil, "avahi-observe")
}
func (s *AvahiObserveInterfaceSuite) TestName(c *C) {
@@ -91,14 +102,11 @@ func (s *AvahiObserveInterfaceSuite) TestSanitizePlug(c *C) {
c.Assert(interfaces.BeforePreparePlug(s.iface, s.plugInfo), IsNil)
}
-func (s *AvahiObserveInterfaceSuite) TestAppArmorSpec(c *C) {
- // on a core system with avahi slot coming from a regular app snap.
- restore := release.MockOnClassic(false)
- defer restore()
-
+func (s *AvahiObserveInterfaceSuite) testAppArmorSpecWithProducer(c *C,
+ slot *interfaces.ConnectedSlot, slotInfo *snap.SlotInfo) {
// connected plug to app slot
spec := &apparmor.Specification{}
- c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.appSlot), IsNil)
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "name=org.freedesktop.Avahi")
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `peer=(label="snap.producer.app"),`)
@@ -114,7 +122,7 @@ func (s *AvahiObserveInterfaceSuite) TestAppArmorSpec(c *C) {
// connected app slot to plug
spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.appSlot), IsNil)
+ c.Assert(spec.AddConnectedSlot(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `interface=org.freedesktop.Avahi`)
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `peer=(label="snap.consumer.app"),`)
@@ -128,22 +136,21 @@ func (s *AvahiObserveInterfaceSuite) TestAppArmorSpec(c *C) {
// permanent app slot
spec = &apparmor.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil)
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `dbus (bind)
bus=system
name="org.freedesktop.Avahi",`)
+}
- // on a classic system with avahi slot coming from the core snap.
- restore = release.MockOnClassic(true)
- defer restore()
-
+func (s *AvahiObserveInterfaceSuite) testAppArmorSpecFromSystem(c *C,
+ slot *interfaces.ConnectedSlot, slotInfo *snap.SlotInfo) {
// connected plug to core slot
- spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedPlug(s.iface, s.plug, s.coreSlot), IsNil)
+ spec := &apparmor.Specification{}
+ c.Assert(spec.AddConnectedPlug(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.consumer.app"})
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "name=org.freedesktop.Avahi")
- c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=unconfined),")
+ c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, "peer=(label=\"{unconfined,/usr/sbin/avahi-daemon}\"),")
// make sure observe does have observe but not control capabilities
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.Avahi.AddressResolver`)
c.Assert(spec.SnippetForTag("snap.consumer.app"), testutil.Contains, `interface=org.freedesktop.Avahi.HostNameResolver`)
@@ -155,34 +162,68 @@ func (s *AvahiObserveInterfaceSuite) TestAppArmorSpec(c *C) {
// connected core slot to plug
spec = &apparmor.Specification{}
- c.Assert(spec.AddConnectedSlot(s.iface, s.plug, s.coreSlot), IsNil)
+ c.Assert(spec.AddConnectedSlot(s.iface, s.plug, slot), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
// permanent core slot
spec = &apparmor.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
}
-func (s *AvahiObserveInterfaceSuite) TestDBusSpec(c *C) {
+func (s *AvahiObserveInterfaceSuite) TestAppArmorSpec(c *C) {
// on a core system with avahi slot coming from a regular app snap.
restore := release.MockOnClassic(false)
defer restore()
+ s.testAppArmorSpecWithProducer(c, s.appSlot, s.appSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by core snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecWithProducer(c, s.appSlot, s.appSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by core snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecFromSystem(c, s.coreSlot, s.coreSlotInfo)
+
+ // on a classic system with avahi slot coming from the system by snapd snap.
+ restore = release.MockOnClassic(true)
+ defer restore()
+ s.testAppArmorSpecFromSystem(c, s.snapdSlot, s.snapdSlotInfo)
+}
+
+func (s *AvahiObserveInterfaceSuite) testDBusSpecSlotByApp(c *C, classic bool) {
+ restore := release.MockOnClassic(classic)
+ defer restore()
spec := &dbus.Specification{}
c.Assert(spec.AddPermanentSlot(s.iface, s.appSlotInfo), IsNil)
c.Assert(spec.SecurityTags(), DeepEquals, []string{"snap.producer.app"})
c.Assert(spec.SnippetForTag("snap.producer.app"), testutil.Contains, `<allow own="org.freedesktop.Avahi"/>`)
+}
- // on a classic system with avahi slot coming from the core snap.
- restore = release.MockOnClassic(true)
+func (s *AvahiObserveInterfaceSuite) testDBusSpecSlotBySystem(c *C, slotInfo *snap.SlotInfo) {
+ restore := release.MockOnClassic(true)
defer restore()
- spec = &dbus.Specification{}
- c.Assert(spec.AddPermanentSlot(s.iface, s.coreSlotInfo), IsNil)
+ spec := &dbus.Specification{}
+ c.Assert(spec.AddPermanentSlot(s.iface, slotInfo), IsNil)
c.Assert(spec.SecurityTags(), HasLen, 0)
}
+func (s *AvahiObserveInterfaceSuite) TestDBusSpecSlot(c *C) {
+ // on a core system with avahi slot coming from a regular app snap.
+ s.testDBusSpecSlotByApp(c, false)
+ // on a classic system with avahi slot coming from a regular app snap.
+ s.testDBusSpecSlotByApp(c, true)
+
+ // on a classic system with avahi slot coming from the core snap.
+ s.testDBusSpecSlotBySystem(c, s.coreSlotInfo)
+ // on a classic system with avahi slot coming from the snapd snap.
+ s.testDBusSpecSlotBySystem(c, s.snapdSlotInfo)
+}
+
func (s *AvahiObserveInterfaceSuite) TestStaticInfo(c *C) {
si := interfaces.StaticInfoOf(s.iface)
c.Assert(si.ImplicitOnCore, Equals, false)
diff --git a/interfaces/builtin/export_test.go b/interfaces/builtin/export_test.go
index 2315e924be..756016504b 100644
--- a/interfaces/builtin/export_test.go
+++ b/interfaces/builtin/export_test.go
@@ -35,6 +35,8 @@ var (
SanitizeSlotReservedForOS = sanitizeSlotReservedForOS
SanitizeSlotReservedForOSOrGadget = sanitizeSlotReservedForOSOrGadget
SanitizeSlotReservedForOSOrApp = sanitizeSlotReservedForOSOrApp
+ ImplicitSystemPermanentSlot = implicitSystemPermanentSlot
+ ImplicitSystemConnectedSlot = implicitSystemConnectedSlot
)
func MprisGetName(iface interfaces.Interface, attribs map[string]interface{}) (string, error) {
diff --git a/interfaces/builtin/utils.go b/interfaces/builtin/utils.go
index ae690a3292..b071964824 100644
--- a/interfaces/builtin/utils.go
+++ b/interfaces/builtin/utils.go
@@ -25,6 +25,7 @@ import (
"sort"
"github.com/snapcore/snapd/interfaces"
+ "github.com/snapcore/snapd/release"
"github.com/snapcore/snapd/snap"
)
@@ -96,3 +97,26 @@ func sanitizeSlotReservedForOSOrApp(iface interfaces.Interface, slot *snap.SlotI
}
return nil
}
+
+// determine if permanent slot side is provided by the system
+// on classic system some implicit slots can be provided by system or by
+// application snap e.g. avahi (it can be installed as deb or snap)
+// - slot owned by the system (core,snapd snap) usually requires no action
+// - slot owned by application snap typically requires rules update
+func implicitSystemPermanentSlot(slot *snap.SlotInfo) bool {
+ if release.OnClassic &&
+ (slot.Snap.Type == snap.TypeOS || slot.Snap.Type == snap.TypeSnapd) {
+ return true
+ }
+ return false
+}
+
+// determine if connected slot side is provided by the system
+// as for isPermanentSlotSystemSlot() slot can be owned by app or system
+func implicitSystemConnectedSlot(slot *interfaces.ConnectedSlot) bool {
+ if release.OnClassic &&
+ (slot.Snap().Type == snap.TypeOS || slot.Snap().Type == snap.TypeSnapd) {
+ return true
+ }
+ return false
+}
diff --git a/interfaces/builtin/utils_test.go b/interfaces/builtin/utils_test.go
index 4f6fb556c0..17958f7923 100644
--- a/interfaces/builtin/utils_test.go
+++ b/interfaces/builtin/utils_test.go
@@ -32,19 +32,25 @@ import (
)
type utilsSuite struct {
- iface interfaces.Interface
- slotOS *snap.SlotInfo
- slotApp *snap.SlotInfo
- slotSnapd *snap.SlotInfo
- slotGadget *snap.SlotInfo
+ iface interfaces.Interface
+ slotOS *snap.SlotInfo
+ slotApp *snap.SlotInfo
+ slotSnapd *snap.SlotInfo
+ slotGadget *snap.SlotInfo
+ conSlotOS *interfaces.ConnectedSlot
+ conSlotSnapd *interfaces.ConnectedSlot
+ conSlotApp *interfaces.ConnectedSlot
}
var _ = Suite(&utilsSuite{
- iface: &ifacetest.TestInterface{InterfaceName: "iface"},
- slotOS: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeOS}},
- slotApp: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeApp}},
- slotSnapd: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeApp, SuggestedName: "snapd"}},
- slotGadget: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeGadget}},
+ iface: &ifacetest.TestInterface{InterfaceName: "iface"},
+ slotOS: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeOS}},
+ slotApp: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeApp}},
+ slotSnapd: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeSnapd, SuggestedName: "snapd"}},
+ slotGadget: &snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeGadget}},
+ conSlotOS: interfaces.NewConnectedSlot(&snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeOS}}, nil, nil),
+ conSlotSnapd: interfaces.NewConnectedSlot(&snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeSnapd}}, nil, nil),
+ conSlotApp: interfaces.NewConnectedSlot(&snap.SlotInfo{Snap: &snap.Info{Type: snap.TypeApp}}, nil, nil),
})
func (s *utilsSuite) TestSanitizeSlotReservedForOS(c *C) {
@@ -70,6 +76,18 @@ func (s *utilsSuite) TestSanitizeSlotReservedForOSOrApp(c *C) {
c.Assert(builtin.SanitizeSlotReservedForOSOrApp(s.iface, s.slotGadget), ErrorMatches, errmsg)
}
+func (s *utilsSuite) TestIsSlotSystemSlot(c *C) {
+ c.Assert(builtin.ImplicitSystemPermanentSlot(s.slotApp), Equals, false)
+ c.Assert(builtin.ImplicitSystemPermanentSlot(s.slotOS), Equals, true)
+ c.Assert(builtin.ImplicitSystemPermanentSlot(s.slotSnapd), Equals, true)
+}
+
+func (s *utilsSuite) TestImplicitSystemConnectedSlot(c *C) {
+ c.Assert(builtin.ImplicitSystemConnectedSlot(s.conSlotApp), Equals, false)
+ c.Assert(builtin.ImplicitSystemConnectedSlot(s.conSlotOS), Equals, true)
+ c.Assert(builtin.ImplicitSystemConnectedSlot(s.conSlotSnapd), Equals, true)
+}
+
func MockPlug(c *C, yaml string, si *snap.SideInfo, plugName string) *snap.PlugInfo {
return builtin.MockPlug(c, yaml, si, plugName)
}