Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

interfaces/builtin: refine the content interface rules using $SLOT #2712

Merged
merged 4 commits into from
Jan 30, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 5 additions & 0 deletions interfaces/builtin/basedeclaration.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,14 @@ slots:
slot-snap-type:
- app
- gadget
allow-connection:
plug-attributes:
content: $SLOT(content)
allow-auto-connection:
plug-publisher-id:
- $SLOT_PUBLISHER_ID
plug-attributes:
content: $SLOT(content)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The updated base declaration changes without $MISSING LGTM.

core-support:
allow-installation:
slot-snap-type:
Expand Down
106 changes: 105 additions & 1 deletion interfaces/builtin/basedeclaration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,11 +220,58 @@ plugs:
}

func (s *baseDeclSuite) TestAutoConnectionContent(c *C) {
// content will also depend for now AutoConnect(plug, slot)
// random snaps cannot connect with content
// (Sanitize* will now also block this)
cand := s.connectCand(c, "content", "", "")
err := cand.CheckAutoConnect()
c.Check(err, NotNil)

slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")

// same publisher, same content
cand = s.connectCand(c, "stuff", `
name: slot-snap
slots:
stuff:
interface: content
content: mk1
`, `
name: plug-snap
plugs:
stuff:
interface: content
content: mk1
`)
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl1
err = cand.CheckAutoConnect()
c.Check(err, IsNil)

// different publisher, same content
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl2
err = cand.CheckAutoConnect()
c.Check(err, NotNil)

// same publisher, different content
cand = s.connectCand(c, "stuff", `name: slot-snap
slots:
stuff:
interface: content
content: mk1
`, `
name: plug-snap
plugs:
stuff:
interface: content
content: mk2
`)
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl1
err = cand.CheckAutoConnect()
c.Check(err, NotNil)
}

func (s *baseDeclSuite) TestAutoConnectionLxdSupportOverride(c *C) {
Expand Down Expand Up @@ -499,6 +546,7 @@ func (s *baseDeclSuite) TestConnection(c *C) {
// case-by-case basis
noconnect := map[string]bool{
"bluez": true,
"content": true,
"docker": true,
"fwupd": true,
"location-control": true,
Expand Down Expand Up @@ -594,3 +642,59 @@ func (s *baseDeclSuite) TestSanity(c *C) {
}
}
}

func (s *baseDeclSuite) TestConnectionContent(c *C) {
// we let connect explicitly as long as content matches (or is absent on both sides)

// random (Sanitize* will now also block this)
cand := s.connectCand(c, "content", "", "")
err := cand.Check()
c.Check(err, NotNil)

slotDecl1 := s.mockSnapDecl(c, "slot-snap", "slot-snap-id", "pub1", "")
plugDecl1 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub1", "")
plugDecl2 := s.mockSnapDecl(c, "plug-snap", "plug-snap-id", "pub2", "")

// same publisher, same content
cand = s.connectCand(c, "stuff", `name: slot-snap
slots:
stuff:
interface: content
content: mk1
`, `
name: plug-snap
plugs:
stuff:
interface: content
content: mk1
`)
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl1
err = cand.Check()
c.Check(err, IsNil)

// different publisher, same content
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl2
err = cand.Check()
c.Check(err, IsNil)

// same publisher, different content
cand = s.connectCand(c, "stuff", `
name: slot-snap
slots:
stuff:
interface: content
content: mk1
`, `
name: plug-snap
plugs:
stuff:
interface: content
content: mk2
`)
cand.SlotSnapDeclaration = slotDecl1
cand.PlugSnapDeclaration = plugDecl1
err = cand.Check()
c.Check(err, NotNil)
}
11 changes: 10 additions & 1 deletion interfaces/builtin/content.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ func (iface *ContentInterface) SanitizeSlot(slot *interfaces.Slot) error {
if iface.Name() != slot.Interface {
panic(fmt.Sprintf("slot is not of interface %q", iface))
}
content, ok := slot.Attrs["content"].(string)
if !ok || len(content) == 0 {
return fmt.Errorf("content slot must have a content attribute set")
}

// check that we have either a read or write path
rpath := iface.path(slot, "read")
Expand All @@ -68,6 +72,10 @@ func (iface *ContentInterface) SanitizePlug(plug *interfaces.Plug) error {
if iface.Name() != plug.Interface {
panic(fmt.Sprintf("plug is not of interface %q", iface))
}
content, ok := plug.Attrs["content"].(string)
if !ok || len(content) == 0 {
return fmt.Errorf("content plug must have a content attribute set")
}
target, ok := plug.Attrs["target"].(string)
if !ok || len(target) == 0 {
return fmt.Errorf("content plug must contain target path")
Expand Down Expand Up @@ -184,5 +192,6 @@ func (iface *ContentInterface) PermanentPlugSnippet(plug *interfaces.Plug, secur
}

func (iface *ContentInterface) AutoConnect(plug *interfaces.Plug, slot *interfaces.Slot) bool {
return plug.Attrs["content"] == slot.Attrs["content"]
// allow what declarations allowed
return true
}
38 changes: 37 additions & 1 deletion interfaces/builtin/content_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ version: 1.0
slots:
content-slot:
interface: content
content: mycont
read:
- shared/read
`
Expand All @@ -55,12 +56,28 @@ slots:
c.Assert(err, IsNil)
}

func (s *ContentSuite) TestSanitizeSlotNoContentLabel(c *C) {
const mockSnapYaml = `name: content-slot-snap
version: 1.0
slots:
content-slot:
interface: content
read:
- shared/read
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
slot := &interfaces.Slot{SlotInfo: info.Slots["content-slot"]}
err := s.iface.SanitizeSlot(slot)
c.Assert(err, ErrorMatches, `content slot must have a content attribute set`)
}

func (s *ContentSuite) TestSanitizeSlotNoPaths(c *C) {
const mockSnapYaml = `name: content-slot-snap
version: 1.0
slots:
content-slot:
interface: content
content: mycont
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
slot := &interfaces.Slot{SlotInfo: info.Slots["content-slot"]}
Expand All @@ -74,6 +91,7 @@ version: 1.0
slots:
content-slot:
interface: content
content: mycont
read: []
write: []
`
Expand All @@ -83,12 +101,13 @@ slots:
c.Assert(err, ErrorMatches, "read or write path must be set")
}

func (s *ContentSuite) TestSanitizeSlotHasRealtivePath(c *C) {
func (s *ContentSuite) TestSanitizeSlotHasRelativePath(c *C) {
const mockSnapYaml = `name: content-slot-snap
version: 1.0
slots:
content-slot:
interface: content
content: mycont
`
for _, rw := range []string{"read: [../foo]", "write: [../bar]"} {
info := snaptest.MockInfo(c, mockSnapYaml+" "+rw, nil)
Expand All @@ -104,6 +123,7 @@ version: 1.0
plugs:
content-plug:
interface: content
content: mycont
target: import
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
Expand All @@ -112,12 +132,27 @@ plugs:
c.Assert(err, IsNil)
}

func (s *ContentSuite) TestSanitizePlugNoContentLabel(c *C) {
const mockSnapYaml = `name: content-slot-snap
version: 1.0
plugs:
content-plug:
interface: content
target: import
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
plug := &interfaces.Plug{PlugInfo: info.Plugs["content-plug"]}
err := s.iface.SanitizePlug(plug)
c.Assert(err, ErrorMatches, `content plug must have a content attribute set`)
}

func (s *ContentSuite) TestSanitizePlugSimpleNoTarget(c *C) {
const mockSnapYaml = `name: content-slot-snap
version: 1.0
plugs:
content-plug:
interface: content
content: mycont
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
plug := &interfaces.Plug{PlugInfo: info.Plugs["content-plug"]}
Expand All @@ -131,6 +166,7 @@ version: 1.0
plugs:
content-plug:
interface: content
content: mycont
target: ../foo
`
info := snaptest.MockInfo(c, mockSnapYaml, nil)
Expand Down