2015-11-26 18:29:56 +01:00
// -*- Mode: Go; indent-tabs-mode: t -*-
/ *
2022-01-26 16:45:03 +01:00
* Copyright ( C ) 2015 - 2022 Canonical Ltd
2015-11-26 18:29:56 +01:00
*
* This program is free software : you can redistribute it and / or modify
* it under the terms of the GNU General Public License version 3 as
* published by the Free Software Foundation .
*
* This program is distributed in the hope that it will be useful ,
* but WITHOUT ANY WARRANTY ; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE . See the
* GNU General Public License for more details .
*
* You should have received a copy of the GNU General Public License
* along with this program . If not , see < http : //www.gnu.org/licenses/>.
*
* /
package asserts_test
import (
2016-08-21 14:28:03 +02:00
"encoding/base64"
2023-09-26 11:38:46 +01:00
"os"
2016-08-21 14:28:03 +02:00
"path/filepath"
2017-03-10 07:30:05 +00:00
"sort"
2015-11-26 18:29:56 +01:00
"strings"
"time"
2016-08-21 14:28:03 +02:00
"golang.org/x/crypto/sha3"
2015-11-26 18:29:56 +01:00
. "gopkg.in/check.v1"
2016-05-24 09:26:23 -03:00
"github.com/snapcore/snapd/asserts"
2016-07-07 18:32:57 +02:00
"github.com/snapcore/snapd/asserts/assertstest"
2015-11-26 18:29:56 +01:00
)
2016-02-15 19:11:57 +01:00
var (
_ = Suite ( & snapDeclSuite { } )
2016-08-21 14:28:03 +02:00
_ = Suite ( & snapFileDigestSuite { } )
2016-02-15 19:11:57 +01:00
_ = Suite ( & snapBuildSuite { } )
_ = Suite ( & snapRevSuite { } )
2016-08-23 19:10:24 -03:00
_ = Suite ( & validationSuite { } )
2016-09-30 23:26:36 +02:00
_ = Suite ( & baseDeclSuite { } )
2017-03-10 07:30:05 +00:00
_ = Suite ( & snapDevSuite { } )
2016-02-15 19:11:57 +01:00
)
type snapDeclSuite struct {
2015-11-26 18:29:56 +01:00
ts time . Time
tsLine string
}
2018-05-16 11:01:04 +02:00
type emptyAttrerObject struct { }
func ( o emptyAttrerObject ) Lookup ( path string ) ( interface { } , bool ) {
return nil , false
}
2016-02-15 19:11:57 +01:00
func ( sds * snapDeclSuite ) SetUpSuite ( c * C ) {
sds . ts = time . Now ( ) . Truncate ( time . Second ) . UTC ( )
sds . tsLine = "timestamp: " + sds . ts . Format ( time . RFC3339 ) + "\n"
}
func ( sds * snapDeclSuite ) TestDecodeOK ( c * C ) {
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
2016-09-02 12:22:50 -03:00
"refresh-control:\n - foo\n - bar\n" +
2016-12-01 19:48:03 +01:00
"auto-aliases:\n - cmd1\n - cmd_2\n - Cmd-3\n - CMD.4\n" +
2016-02-15 19:11:57 +01:00
sds . tsLine +
2017-03-17 12:14:13 +01:00
` aliases :
-
name : cmd1
target : cmd - 1
-
name : cmd_2
target : cmd - 2
-
name : Cmd - 3
target : cmd - 3
-
name : CMD .4
target : cmd - 4
` +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2016-02-15 19:11:57 +01:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2016-02-15 19:11:57 +01:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . SnapDeclarationType )
snapDecl := a . ( * asserts . SnapDeclaration )
c . Check ( snapDecl . AuthorityID ( ) , Equals , "canonical" )
c . Check ( snapDecl . Timestamp ( ) , Equals , sds . ts )
c . Check ( snapDecl . Series ( ) , Equals , "16" )
c . Check ( snapDecl . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( snapDecl . SnapName ( ) , Equals , "first" )
c . Check ( snapDecl . PublisherID ( ) , Equals , "dev-id1" )
2016-09-02 12:22:50 -03:00
c . Check ( snapDecl . RefreshControl ( ) , DeepEquals , [ ] string { "foo" , "bar" } )
2016-12-01 19:48:03 +01:00
c . Check ( snapDecl . AutoAliases ( ) , DeepEquals , [ ] string { "cmd1" , "cmd_2" , "Cmd-3" , "CMD.4" } )
2017-03-17 12:14:13 +01:00
c . Check ( snapDecl . Aliases ( ) , DeepEquals , map [ string ] string {
"cmd1" : "cmd-1" ,
"cmd_2" : "cmd-2" ,
"Cmd-3" : "cmd-3" ,
"CMD.4" : "cmd-4" ,
} )
2022-06-17 16:00:48 +02:00
c . Check ( snapDecl . RevisionAuthority ( "" ) , IsNil )
}
func ( sds * snapDeclSuite ) TestDecodeOKWithRevisionAuthority ( c * C ) {
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
"refresh-control:\n - foo\n - bar\n" +
sds . tsLine +
` revision - authority :
-
account - id : delegated - acc - id
provenance :
- prov1
- prov2
min - revision : 100
max - revision : 1000000
on - store :
- store1
` +
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . SnapDeclarationType )
snapDecl := a . ( * asserts . SnapDeclaration )
c . Check ( snapDecl . AuthorityID ( ) , Equals , "canonical" )
c . Check ( snapDecl . Timestamp ( ) , Equals , sds . ts )
c . Check ( snapDecl . Series ( ) , Equals , "16" )
c . Check ( snapDecl . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( snapDecl . SnapName ( ) , Equals , "first" )
c . Check ( snapDecl . PublisherID ( ) , Equals , "dev-id1" )
c . Check ( snapDecl . RefreshControl ( ) , DeepEquals , [ ] string { "foo" , "bar" } )
ras := snapDecl . RevisionAuthority ( "prov1" )
c . Check ( ras , DeepEquals , [ ] * asserts . RevisionAuthority {
{
AccountID : "delegated-acc-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 100 ,
MaxRevision : 1000000 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "store1" } ,
} ,
} ,
} )
}
func ( sds * snapDeclSuite ) TestDecodeOKWithRevisionAuthorityDefaults ( c * C ) {
initial := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
"refresh-control:\n - foo\n - bar\n" +
sds . tsLine +
` revision - authority :
-
account - id : delegated - acc - id
provenance :
- prov1
- prov2
min - revision : 100
` +
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
tests := [ ] struct {
original , replaced string
revAuth asserts . RevisionAuthority
} {
{ "min" , "min" , asserts . RevisionAuthority {
AccountID : "delegated-acc-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 100 ,
} } ,
{ "min" , "max" , asserts . RevisionAuthority {
AccountID : "delegated-acc-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
MaxRevision : 100 ,
} } ,
{ " min-revision: 100\n" , "" , asserts . RevisionAuthority {
AccountID : "delegated-acc-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
} } ,
}
for _ , t := range tests {
encoded := strings . Replace ( initial , t . original , t . replaced , 1 )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
snapDecl := a . ( * asserts . SnapDeclaration )
ras := snapDecl . RevisionAuthority ( "prov2" )
c . Check ( ras , HasLen , 1 )
c . Check ( * ras [ 0 ] , DeepEquals , t . revAuth )
}
2016-02-15 19:11:57 +01:00
}
2016-05-17 11:49:06 +01:00
func ( sds * snapDeclSuite ) TestEmptySnapName ( c * C ) {
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: \n" +
"publisher-id: dev-id1\n" +
sds . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2016-05-17 11:49:06 +01:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2016-05-17 11:49:06 +01:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
snapDecl := a . ( * asserts . SnapDeclaration )
c . Check ( snapDecl . SnapName ( ) , Equals , "" )
}
2016-12-01 19:48:03 +01:00
func ( sds * snapDeclSuite ) TestMissingRefreshControlAutoAliases ( c * C ) {
2016-09-02 12:22:50 -03:00
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: \n" +
"publisher-id: dev-id1\n" +
sds . tsLine +
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
snapDecl := a . ( * asserts . SnapDeclaration )
2016-09-13 14:11:06 -03:00
c . Check ( snapDecl . RefreshControl ( ) , HasLen , 0 )
2016-12-01 19:48:03 +01:00
c . Check ( snapDecl . AutoAliases ( ) , HasLen , 0 )
2016-09-02 12:22:50 -03:00
}
2016-02-15 19:11:57 +01:00
const (
snapDeclErrPrefix = "assertion snap-declaration: "
2015-12-10 13:12:03 +00:00
)
2015-11-26 18:29:56 +01:00
2016-02-15 19:11:57 +01:00
func ( sds * snapDeclSuite ) TestDecodeInvalid ( c * C ) {
2017-03-17 12:14:13 +01:00
aliases := ` aliases :
-
name : cmd_1
target : cmd - 1
`
2016-02-15 19:11:57 +01:00
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
2016-09-13 14:11:06 -03:00
"refresh-control:\n - foo\n - bar\n" +
2016-12-01 19:48:03 +01:00
"auto-aliases:\n - cmd1\n - cmd2\n" +
2017-03-17 12:14:13 +01:00
aliases +
2016-09-29 22:09:10 +02:00
"plugs:\n interface1: true\n" +
2016-09-30 20:15:52 +02:00
"slots:\n interface2: true\n" +
2016-02-15 19:11:57 +01:00
sds . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2016-02-15 19:11:57 +01:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2016-02-15 19:11:57 +01:00
invalidTests := [ ] struct { original , invalid , expectedErr string } {
2016-02-22 16:50:52 +01:00
{ "series: 16\n" , "" , ` "series" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "series: 16\n" , "series: \n" , ` "series" header should not be empty ` } ,
2016-02-15 19:11:57 +01:00
{ "snap-id: snap-id-1\n" , "" , ` "snap-id" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "snap-id: snap-id-1\n" , "snap-id: \n" , ` "snap-id" header should not be empty ` } ,
2016-02-15 19:11:57 +01:00
{ "snap-name: first\n" , "" , ` "snap-name" header is mandatory ` } ,
{ "publisher-id: dev-id1\n" , "" , ` "publisher-id" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "publisher-id: dev-id1\n" , "publisher-id: \n" , ` "publisher-id" header should not be empty ` } ,
2016-09-13 14:11:06 -03:00
{ "refresh-control:\n - foo\n - bar\n" , "refresh-control: foo\n" , ` "refresh-control" header must be a list of strings ` } ,
{ "refresh-control:\n - foo\n - bar\n" , "refresh-control:\n -\n - nested\n" , ` "refresh-control" header must be a list of strings ` } ,
2016-09-29 22:09:10 +02:00
{ "plugs:\n interface1: true\n" , "plugs: \n" , ` "plugs" header must be a map ` } ,
{ "plugs:\n interface1: true\n" , "plugs:\n intf1:\n foo: bar\n" , ` plug rule for interface "intf1" must specify at least one of.* ` } ,
2016-09-30 20:15:52 +02:00
{ "slots:\n interface2: true\n" , "slots: \n" , ` "slots" header must be a map ` } ,
{ "slots:\n interface2: true\n" , "slots:\n intf1:\n foo: bar\n" , ` slot rule for interface "intf1" must specify at least one of.* ` } ,
2016-12-01 19:48:03 +01:00
{ "auto-aliases:\n - cmd1\n - cmd2\n" , "auto-aliases: cmd0\n" , ` "auto-aliases" header must be a list of strings ` } ,
{ "auto-aliases:\n - cmd1\n - cmd2\n" , "auto-aliases:\n -\n - nested\n" , ` "auto-aliases" header must be a list of strings ` } ,
{ "auto-aliases:\n - cmd1\n - cmd2\n" , "auto-aliases:\n - _cmd-1\n - cmd2\n" , ` "auto-aliases" header contains an invalid element: "_cmd-1" ` } ,
2017-03-17 12:14:13 +01:00
{ aliases , "aliases: cmd0\n" , ` "aliases" header must be a list of alias maps ` } ,
{ aliases , "aliases:\n - cmd1\n" , ` "aliases" header must be a list of alias maps ` } ,
{ "name: cmd_1\n" , "name: .cmd1\n" , ` "name" in "aliases" item 1 contains invalid characters: ".cmd1" ` } ,
{ "target: cmd-1\n" , "target: -cmd-1\n" , ` "target" for alias "cmd_1" contains invalid characters: "-cmd-1" ` } ,
{ aliases , aliases + " -\n name: cmd_1\n target: foo\n" , ` duplicated definition in "aliases" for alias "cmd_1" ` } ,
2016-05-17 11:11:30 +01:00
{ sds . tsLine , "" , ` "timestamp" header is mandatory ` } ,
{ sds . tsLine , "timestamp: \n" , ` "timestamp" header should not be empty ` } ,
{ sds . tsLine , "timestamp: 12:30\n" , ` "timestamp" header is not a RFC3339 date: .* ` } ,
2016-02-15 19:11:57 +01:00
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , snapDeclErrPrefix + test . expectedErr )
}
}
2022-06-17 16:00:48 +02:00
func ( sds * snapDeclSuite ) TestDecodeInvalidWithRevisionAuthority ( c * C ) {
const revAuth = ` revision - authority :
-
account - id : delegated - acc - id
provenance :
- prov1
- prov2
min - revision : 100
max - revision : 1000000
on - store :
- store1
`
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
"refresh-control:\n - foo\n - bar\n" +
sds . tsLine +
revAuth +
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ revAuth , "revision-authority: x\n" , ` revision-authority stanza must be a list of maps ` } ,
{ revAuth , "revision-authority:\n - x\n" , ` revision-authority stanza must be a list of maps ` } ,
{ " account-id: delegated-acc-id\n" , "" , ` "account-id" in revision authority is mandatory ` } ,
{ "account-id: delegated-acc-id\n" , "account-id: *\n" , ` "account-id" in revision authority contains invalid characters: "\*" ` } ,
{ " provenance:\n - prov1\n - prov2\n" , " provenance: \n" , ` provenance in revision authority must be a list of strings ` } ,
2022-06-29 17:41:21 +02:00
{ "prov2\n" , "*\n" , ` provenance in revision authority contains an invalid element: "\*" ` } ,
2022-06-17 16:00:48 +02:00
{ " min-revision: 100\n" , " min-revision: 0\n" , ` "min-revision" in revision authority must be >=1: 0 ` } ,
{ " max-revision: 1000000\n" , " max-revision: 0\n" , ` "max-revision" in revision authority must be >=1: 0 ` } ,
2022-06-30 09:42:23 +02:00
{ " max-revision: 1000000\n" , " max-revision: 10\n" , ` optional max-revision cannot be less than min-revision in revision-authority ` } ,
2022-06-17 16:00:48 +02:00
{ " on-store:\n - store1\n" , " on-store: foo" , ` on-store in revision-authority must be a list of strings ` } ,
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , snapDeclErrPrefix + test . expectedErr )
}
}
2016-09-30 20:15:52 +02:00
func ( sds * snapDeclSuite ) TestDecodePlugsAndSlots ( c * C ) {
2016-09-29 22:09:10 +02:00
encoded := ` type : snap - declaration
2017-01-20 16:55:42 +01:00
format : 1
2016-09-29 22:09:10 +02:00
authority - id : canonical
series : 16
snap - id : snap - id - 1
snap - name : first
publisher - id : dev - id1
plugs :
interface1 :
deny - installation : false
allow - auto - connection :
slot - snap - type :
- app
slot - publisher - id :
- acme
slot - attributes :
a1 : / foo / . *
plug - attributes :
b1 : B1
deny - auto - connection :
slot - attributes :
a1 : ! A1
plug - attributes :
b1 : ! B1
interface2 :
allow - installation : true
allow - connection :
plug - attributes :
a2 : A2
slot - attributes :
b2 : B2
deny - connection :
slot - snap - id :
- snapidsnapidsnapidsnapidsnapid01
- snapidsnapidsnapidsnapidsnapid02
plug - attributes :
a2 : ! A2
slot - attributes :
b2 : ! B2
2016-09-30 20:15:52 +02:00
slots :
interface3 :
deny - installation : false
allow - auto - connection :
plug - snap - type :
- app
plug - publisher - id :
- acme
slot - attributes :
c1 : / foo / . *
plug - attributes :
d1 : C1
deny - auto - connection :
slot - attributes :
c1 : ! C1
plug - attributes :
d1 : ! D1
interface4 :
allow - connection :
plug - attributes :
c2 : C2
slot - attributes :
d2 : D2
deny - connection :
plug - snap - id :
- snapidsnapidsnapidsnapidsnapid01
- snapidsnapidsnapidsnapidsnapid02
plug - attributes :
c2 : ! D2
slot - attributes :
d2 : ! D2
allow - installation :
slot - snap - type :
- app
slot - attributes :
e1 : E1
2016-09-29 22:09:10 +02:00
TSLINE
body - length : 0
sign - key - sha3 - 384 : Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS - 3 VW7F_idjix7Ffn5qMxB21ZQuij
AXNpZw == `
encoded = strings . Replace ( encoded , "TSLINE\n" , sds . tsLine , 1 )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
2016-10-14 14:53:38 +02:00
c . Check ( a . SupportedFormat ( ) , Equals , true )
2016-09-29 22:09:10 +02:00
snapDecl := a . ( * asserts . SnapDeclaration )
c . Check ( snapDecl . Series ( ) , Equals , "16" )
c . Check ( snapDecl . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( snapDecl . PlugRule ( "interfaceX" ) , IsNil )
2016-09-30 20:15:52 +02:00
c . Check ( snapDecl . SlotRule ( "interfaceX" ) , IsNil )
2016-09-29 22:09:10 +02:00
plugRule1 := snapDecl . PlugRule ( "interface1" )
c . Assert ( plugRule1 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule1 . DenyInstallation , HasLen , 1 )
c . Check ( plugRule1 . DenyInstallation [ 0 ] . PlugAttributes , Equals , asserts . NeverMatchAttributes )
c . Assert ( plugRule1 . AllowAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
2018-05-16 11:01:04 +02:00
plug := emptyAttrerObject { }
slot := emptyAttrerObject { }
2018-01-29 10:25:27 +01:00
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "a1".* ` )
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "b1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotSnapTypes , DeepEquals , [ ] string { "app" } )
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotPublisherIDs , DeepEquals , [ ] string { "acme" } )
c . Assert ( plugRule1 . DenyAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule1 . DenyAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "a1".* ` )
c . Check ( plugRule1 . DenyAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "b1".* ` )
2016-09-29 22:09:10 +02:00
plugRule2 := snapDecl . PlugRule ( "interface2" )
c . Assert ( plugRule2 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule2 . AllowInstallation , HasLen , 1 )
c . Check ( plugRule2 . AllowInstallation [ 0 ] . PlugAttributes , Equals , asserts . AlwaysMatchAttributes )
c . Assert ( plugRule2 . AllowConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule2 . AllowConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "a2".* ` )
c . Check ( plugRule2 . AllowConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "b2".* ` )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule2 . DenyConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule2 . DenyConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "a2".* ` )
c . Check ( plugRule2 . DenyConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "b2".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( plugRule2 . DenyConnection [ 0 ] . SlotSnapIDs , DeepEquals , [ ] string { "snapidsnapidsnapidsnapidsnapid01" , "snapidsnapidsnapidsnapidsnapid02" } )
2016-09-30 20:15:52 +02:00
slotRule3 := snapDecl . SlotRule ( "interface3" )
c . Assert ( slotRule3 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule3 . DenyInstallation , HasLen , 1 )
c . Check ( slotRule3 . DenyInstallation [ 0 ] . SlotAttributes , Equals , asserts . NeverMatchAttributes )
c . Assert ( slotRule3 . AllowAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "c1".* ` )
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "d1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugSnapTypes , DeepEquals , [ ] string { "app" } )
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugPublisherIDs , DeepEquals , [ ] string { "acme" } )
c . Assert ( slotRule3 . DenyAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule3 . DenyAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "c1".* ` )
c . Check ( slotRule3 . DenyAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "d1".* ` )
2016-09-30 20:15:52 +02:00
slotRule4 := snapDecl . SlotRule ( "interface4" )
c . Assert ( slotRule4 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule4 . AllowAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . AllowConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "c2".* ` )
c . Check ( slotRule4 . AllowConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "d2".* ` )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule4 . DenyAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . DenyConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "c2".* ` )
c . Check ( slotRule4 . DenyConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "d2".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule4 . DenyConnection [ 0 ] . PlugSnapIDs , DeepEquals , [ ] string { "snapidsnapidsnapidsnapidsnapid01" , "snapidsnapidsnapidsnapidsnapid02" } )
c . Assert ( slotRule4 . AllowInstallation , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . AllowInstallation [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "e1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule4 . AllowInstallation [ 0 ] . SlotSnapTypes , DeepEquals , [ ] string { "app" } )
2016-09-29 22:09:10 +02:00
}
2017-01-20 16:55:42 +01:00
func ( sds * snapDeclSuite ) TestSuggestedFormat ( c * C ) {
fmtnum , err := asserts . SuggestFormat ( asserts . SnapDeclarationType , nil , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 0 )
headers := map [ string ] interface { } {
"plugs" : map [ string ] interface { } {
"interface1" : "true" ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 1 )
headers = map [ string ] interface { } {
"slots" : map [ string ] interface { } {
"interface2" : "true" ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 1 )
2017-02-01 20:56:02 +01:00
headers = map [ string ] interface { } {
"plugs" : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"plug-attributes" : map [ string ] interface { } {
"x" : "$SLOT(x)" ,
} ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 2 )
headers = map [ string ] interface { } {
"slots" : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"plug-attributes" : map [ string ] interface { } {
"x" : "$SLOT(x)" ,
} ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 2 )
2018-09-26 11:50:01 +02:00
// combinations with on-store/on-brand/on-model => format 3
for _ , side := range [ ] string { "plugs" , "slots" } {
for k , vals := range deviceScopeConstrs {
2018-09-14 13:53:46 +02:00
2018-09-26 11:50:01 +02:00
headers := map [ string ] interface { } {
side : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-installation" : map [ string ] interface { } {
k : vals ,
} ,
} ,
2018-09-14 13:53:46 +02:00
} ,
2018-09-26 11:50:01 +02:00
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 3 )
2018-09-14 13:53:46 +02:00
2018-09-26 11:50:01 +02:00
for _ , conn := range [ ] string { "connection" , "auto-connection" } {
headers = map [ string ] interface { } {
side : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-" + conn : map [ string ] interface { } {
k : vals ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 3 )
}
}
2018-09-14 13:53:46 +02:00
}
// higher format features win
headers = map [ string ] interface { } {
"plugs" : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"on-store" : [ ] interface { } { "store" } ,
} ,
} ,
} ,
"slots" : map [ string ] interface { } {
"interface4" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"plug-attributes" : map [ string ] interface { } {
"x" : "$SLOT(x)" ,
} ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 3 )
headers = map [ string ] interface { } {
"plugs" : map [ string ] interface { } {
"interface4" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"slot-attributes" : map [ string ] interface { } {
"x" : "$SLOT(x)" ,
} ,
} ,
} ,
} ,
"slots" : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
"on-store" : [ ] interface { } { "store" } ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 3 )
2017-02-01 20:56:02 +01:00
// errors
headers = map [ string ] interface { } {
"plugs" : "what" ,
}
_ , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , ErrorMatches , ` assertion snap-declaration: "plugs" header must be a map ` )
headers = map [ string ] interface { } {
"slots" : "what" ,
}
_ , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , ErrorMatches , ` assertion snap-declaration: "slots" header must be a map ` )
2019-11-27 17:29:30 +01:00
// plug-names/slot-names => format 4
for _ , sidePrefix := range [ ] string { "plug" , "slot" } {
side := sidePrefix + "s"
headers := map [ string ] interface { } {
side : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-installation" : map [ string ] interface { } {
sidePrefix + "-names" : [ ] interface { } { "foo" } ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 4 )
for _ , conn := range [ ] string { "connection" , "auto-connection" } {
headers = map [ string ] interface { } {
side : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-" + conn : map [ string ] interface { } {
sidePrefix + "-names" : [ ] interface { } { "foo" } ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 4 )
headers = map [ string ] interface { } {
side : map [ string ] interface { } {
"interface3" : map [ string ] interface { } {
"allow-" + conn : map [ string ] interface { } {
"plug-names" : [ ] interface { } { "Pfoo" } ,
"slot-names" : [ ] interface { } { "Sfoo" } ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 4 )
}
}
2021-05-28 09:44:22 +02:00
// alt matcher (so far unused) => format 5
for _ , sidePrefix := range [ ] string { "plug" , "slot" } {
headers = map [ string ] interface { } {
sidePrefix + "s" : map [ string ] interface { } {
"interface5" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
sidePrefix + "-attributes" : map [ string ] interface { } {
"x" : [ ] interface { } { "alt1" , "alt2" } , // alt matcher
} ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 5 )
}
2024-06-10 16:45:47 +01:00
for _ , cstr := range [ ] string { "$PLUG_PUBLISHER_ID" , "$SLOT_PUBLISHER_ID" } {
for _ , sidePrefix := range [ ] string { "plug" , "slot" } {
headers = map [ string ] interface { } {
sidePrefix + "s" : map [ string ] interface { } {
"interface6" : map [ string ] interface { } {
"allow-auto-connection" : map [ string ] interface { } {
sidePrefix + "-attributes" : map [ string ] interface { } {
"x" : cstr ,
} ,
} ,
} ,
} ,
}
fmtnum , err = asserts . SuggestFormat ( asserts . SnapDeclarationType , headers , nil )
c . Assert ( err , IsNil )
c . Check ( fmtnum , Equals , 6 )
}
}
2017-01-20 16:55:42 +01:00
}
2016-07-12 11:37:28 +02:00
func prereqDevAccount ( c * C , storeDB assertstest . SignerDB , db * asserts . Database ) {
2016-07-27 15:21:36 +02:00
dev1Acct := assertstest . NewAccount ( storeDB , "developer1" , map [ string ] interface { } {
2016-07-12 11:37:28 +02:00
"account-id" : "dev-id1" ,
} , "" )
err := db . Add ( dev1Acct )
c . Assert ( err , IsNil )
}
func ( sds * snapDeclSuite ) TestSnapDeclarationCheck ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
prereqDevAccount ( c , storeDB , db )
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-07-12 11:37:28 +02:00
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
}
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapDecl )
c . Assert ( err , IsNil )
}
func ( sds * snapDeclSuite ) TestSnapDeclarationCheckUntrustedAuthority ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
otherDB := setup3rdPartySigning ( c , "other" , storeDB , db )
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-07-12 11:37:28 +02:00
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
}
snapDecl , err := otherDB . Sign ( asserts . SnapDeclarationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapDecl )
c . Assert ( err , ErrorMatches , ` snap-declaration assertion for "foo" \(id "snap-id-1"\) is not signed by a directly trusted authority:.* ` )
}
2016-07-14 11:51:50 +02:00
func ( sds * snapDeclSuite ) TestSnapDeclarationCheckMissingPublisherAccount ( c * C ) {
2016-07-12 11:37:28 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-07-12 11:37:28 +02:00
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
}
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapDecl )
c . Assert ( err , ErrorMatches , ` snap-declaration assertion for "foo" \(id "snap-id-1"\) does not have a matching account assertion for the publisher "dev-id1" ` )
}
2016-08-21 14:28:03 +02:00
type snapFileDigestSuite struct { }
func ( s * snapFileDigestSuite ) TestSnapFileSHA3_384 ( c * C ) {
exData := [ ] byte ( "hashmeplease" )
tempdir := c . MkDir ( )
snapFn := filepath . Join ( tempdir , "ex.snap" )
2023-09-26 11:38:46 +01:00
err := os . WriteFile ( snapFn , exData , 0644 )
2016-08-21 14:28:03 +02:00
c . Assert ( err , IsNil )
encDgst , size , err := asserts . SnapFileSHA3_384 ( snapFn )
c . Assert ( err , IsNil )
c . Check ( size , Equals , uint64 ( len ( exData ) ) )
h3_384 := sha3 . Sum384 ( exData )
expected := base64 . RawURLEncoding . EncodeToString ( h3_384 [ : ] )
c . Check ( encDgst , DeepEquals , expected )
}
2016-02-15 19:11:57 +01:00
type snapBuildSuite struct {
ts time . Time
tsLine string
}
2016-07-15 12:17:49 +02:00
func ( sds * snapDeclSuite ) TestPrerequisites ( c * C ) {
encoded := "type: snap-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"snap-name: first\n" +
"publisher-id: dev-id1\n" +
sds . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2016-07-15 12:17:49 +02:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2016-07-15 12:17:49 +02:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := a . Prerequisites ( )
c . Assert ( prereqs , HasLen , 1 )
c . Check ( prereqs [ 0 ] , DeepEquals , & asserts . Ref {
Type : asserts . AccountType ,
PrimaryKey : [ ] string { "dev-id1" } ,
} )
}
2016-02-14 19:36:08 +01:00
func ( sbs * snapBuildSuite ) SetUpSuite ( c * C ) {
sbs . ts = time . Now ( ) . Truncate ( time . Second ) . UTC ( )
sbs . tsLine = "timestamp: " + sbs . ts . Format ( time . RFC3339 ) + "\n"
2015-11-26 18:29:56 +01:00
}
2016-07-28 18:30:08 +02:00
const (
blobSHA3_384 = "QlqR0uAWEAWF5Nwnzj5kqmmwFslYPu1IL16MKtLKhwhv0kpBv5wKZ_axf_nf_2cL"
)
2016-02-14 19:36:08 +01:00
func ( sbs * snapBuildSuite ) TestDecodeOK ( c * C ) {
2015-12-18 13:57:48 +01:00
encoded := "type: snap-build\n" +
2015-11-26 18:29:56 +01:00
"authority-id: dev-id1\n" +
2016-07-28 18:30:08 +02:00
"snap-sha3-384: " + blobSHA3_384 + "\n" +
2015-11-26 18:29:56 +01:00
"grade: stable\n" +
2016-07-28 18:30:08 +02:00
"snap-id: snap-id-1\n" +
2015-11-26 18:29:56 +01:00
"snap-size: 10000\n" +
2016-02-14 19:36:08 +01:00
sbs . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2015-11-26 18:29:56 +01:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2015-11-26 18:29:56 +01:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
2015-12-18 13:57:48 +01:00
c . Check ( a . Type ( ) , Equals , asserts . SnapBuildType )
snapBuild := a . ( * asserts . SnapBuild )
c . Check ( snapBuild . AuthorityID ( ) , Equals , "dev-id1" )
2016-02-14 19:36:08 +01:00
c . Check ( snapBuild . Timestamp ( ) , Equals , sbs . ts )
2015-12-18 13:57:48 +01:00
c . Check ( snapBuild . SnapID ( ) , Equals , "snap-id-1" )
2016-07-28 18:30:08 +02:00
c . Check ( snapBuild . SnapSHA3_384 ( ) , Equals , blobSHA3_384 )
2015-12-18 13:57:48 +01:00
c . Check ( snapBuild . SnapSize ( ) , Equals , uint64 ( 10000 ) )
c . Check ( snapBuild . Grade ( ) , Equals , "stable" )
2015-11-26 18:29:56 +01:00
}
const (
2015-12-18 13:57:48 +01:00
snapBuildErrPrefix = "assertion snap-build: "
2015-11-26 18:29:56 +01:00
)
2016-02-14 19:36:08 +01:00
func ( sbs * snapBuildSuite ) TestDecodeInvalid ( c * C ) {
2016-07-29 11:26:49 +02:00
digestHdr := "snap-sha3-384: " + blobSHA3_384 + "\n"
2016-07-28 18:30:08 +02:00
2015-12-18 13:57:48 +01:00
encoded := "type: snap-build\n" +
2015-11-26 18:29:56 +01:00
"authority-id: dev-id1\n" +
2016-07-29 11:26:49 +02:00
digestHdr +
2015-11-26 18:29:56 +01:00
"grade: stable\n" +
2016-07-28 18:30:08 +02:00
"snap-id: snap-id-1\n" +
2015-11-26 18:29:56 +01:00
"snap-size: 10000\n" +
2016-02-14 19:36:08 +01:00
sbs . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2015-11-26 18:29:56 +01:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2015-11-26 18:29:56 +01:00
2015-11-26 19:08:53 +01:00
invalidTests := [ ] struct { original , invalid , expectedErr string } {
2015-11-26 18:29:56 +01:00
{ "snap-id: snap-id-1\n" , "" , ` "snap-id" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "snap-id: snap-id-1\n" , "snap-id: \n" , ` "snap-id" header should not be empty ` } ,
2016-07-29 11:26:49 +02:00
{ digestHdr , "" , ` "snap-sha3-384" header is mandatory ` } ,
{ digestHdr , "snap-sha3-384: \n" , ` "snap-sha3-384" header should not be empty ` } ,
{ digestHdr , "snap-sha3-384: #\n" , ` "snap-sha3-384" header cannot be decoded:.* ` } ,
2015-11-26 18:29:56 +01:00
{ "snap-size: 10000\n" , "" , ` "snap-size" header is mandatory ` } ,
{ "snap-size: 10000\n" , "snap-size: -1\n" , ` "snap-size" header is not an unsigned integer: -1 ` } ,
{ "snap-size: 10000\n" , "snap-size: zzz\n" , ` "snap-size" header is not an unsigned integer: zzz ` } ,
2020-07-06 13:50:19 +02:00
{ "snap-size: 10000\n" , "snap-size: 010\n" , ` "snap-size" header has invalid prefix zeros: 010 ` } ,
2020-07-06 21:55:54 +02:00
{ "snap-size: 10000\n" , "snap-size: 99999999999999999999\n" , ` "snap-size" header is out of range: 99999999999999999999 ` } ,
2016-05-17 11:11:30 +01:00
{ "grade: stable\n" , "" , ` "grade" header is mandatory ` } ,
{ "grade: stable\n" , "grade: \n" , ` "grade" header should not be empty ` } ,
{ sbs . tsLine , "" , ` "timestamp" header is mandatory ` } ,
{ sbs . tsLine , "timestamp: \n" , ` "timestamp" header should not be empty ` } ,
2016-02-14 19:36:08 +01:00
{ sbs . tsLine , "timestamp: 12:30\n" , ` "timestamp" header is not a RFC3339 date: .* ` } ,
2015-11-26 18:29:56 +01:00
}
2015-11-26 19:08:53 +01:00
for _ , test := range invalidTests {
2015-11-26 18:29:56 +01:00
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
2015-12-18 13:57:48 +01:00
c . Check ( err , ErrorMatches , snapBuildErrPrefix + test . expectedErr )
2015-11-26 18:29:56 +01:00
}
}
2015-11-26 20:25:45 +01:00
2017-06-23 20:06:26 +02:00
func makeStoreAndCheckDB ( c * C ) ( store * assertstest . StoreStack , checkDB * asserts . Database ) {
2017-08-18 18:38:21 +02:00
store = assertstest . NewStoreStack ( "canonical" , nil )
2015-11-26 20:25:45 +01:00
cfg := & asserts . DatabaseConfig {
2017-06-23 20:06:26 +02:00
Backstore : asserts . NewMemoryBackstore ( ) ,
Trusted : store . Trusted ,
OtherPredefined : store . Generic ,
2015-11-26 20:25:45 +01:00
}
2016-07-07 18:32:57 +02:00
checkDB , err := asserts . OpenDatabase ( cfg )
2015-11-26 20:25:45 +01:00
c . Assert ( err , IsNil )
2016-07-07 18:32:57 +02:00
// add store key
2016-07-11 10:38:19 +02:00
err = checkDB . Add ( store . StoreAccountKey ( "" ) )
2016-07-07 18:32:57 +02:00
c . Assert ( err , IsNil )
2017-06-23 20:06:26 +02:00
// add generic key
err = checkDB . Add ( store . GenericKey )
c . Assert ( err , IsNil )
2016-07-07 18:32:57 +02:00
2017-06-23 20:06:26 +02:00
return store , checkDB
2016-07-07 18:32:57 +02:00
}
2017-06-23 20:06:26 +02:00
func setup3rdPartySigning ( c * C , username string , storeDB assertstest . SignerDB , checkDB * asserts . Database ) ( signingDB * assertstest . SigningDB ) {
2016-07-07 18:32:57 +02:00
privKey := testPrivKey2
2016-09-16 22:33:51 +02:00
acct := assertstest . NewAccount ( storeDB , username , map [ string ] interface { } {
"account-id" : username ,
} , "" )
2016-07-11 10:38:19 +02:00
accKey := assertstest . NewAccountKey ( storeDB , acct , nil , privKey . PublicKey ( ) , "" )
2016-07-07 18:32:57 +02:00
err := checkDB . Add ( acct )
c . Assert ( err , IsNil )
2015-12-01 14:28:54 +01:00
err = checkDB . Add ( accKey )
2015-11-26 20:25:45 +01:00
c . Assert ( err , IsNil )
2016-07-07 18:32:57 +02:00
return assertstest . NewSigningDB ( acct . AccountID ( ) , privKey )
2015-11-27 19:26:50 +01:00
}
2016-02-14 19:36:08 +01:00
func ( sbs * snapBuildSuite ) TestSnapBuildCheck ( c * C ) {
2016-07-07 18:32:57 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "devel1" , storeDB , db )
2015-11-27 19:26:50 +01:00
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-09-16 22:33:51 +02:00
"authority-id" : "devel1" ,
2016-07-28 18:30:08 +02:00
"snap-sha3-384" : blobSHA3_384 ,
"snap-id" : "snap-id-1" ,
"grade" : "devel" ,
"snap-size" : "1025" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
2015-11-26 20:25:45 +01:00
}
2016-07-07 18:32:57 +02:00
snapBuild , err := devDB . Sign ( asserts . SnapBuildType , headers , nil , "" )
2015-11-26 20:25:45 +01:00
c . Assert ( err , IsNil )
2015-12-18 13:57:48 +01:00
err = db . Check ( snapBuild )
2015-11-26 20:25:45 +01:00
c . Assert ( err , IsNil )
}
2015-11-27 19:26:50 +01:00
2016-02-14 19:36:08 +01:00
func ( sbs * snapBuildSuite ) TestSnapBuildCheckInconsistentTimestamp ( c * C ) {
2016-07-07 18:32:57 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "devel1" , storeDB , db )
2015-11-27 19:26:50 +01:00
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-07-28 18:30:08 +02:00
"snap-sha3-384" : blobSHA3_384 ,
"snap-id" : "snap-id-1" ,
"grade" : "devel" ,
"snap-size" : "1025" ,
"timestamp" : "2013-01-01T14:00:00Z" ,
2015-11-27 19:26:50 +01:00
}
2016-07-07 18:32:57 +02:00
snapBuild , err := devDB . Sign ( asserts . SnapBuildType , headers , nil , "" )
2015-11-27 19:26:50 +01:00
c . Assert ( err , IsNil )
2015-12-18 13:57:48 +01:00
err = db . Check ( snapBuild )
2021-02-25 11:42:27 +01:00
c . Assert ( err , ErrorMatches , ` snap-build assertion timestamp "2013-01-01 14:00:00 \+0000 UTC" outside of signing key validity \(key valid since.*\) ` )
2015-11-27 19:26:50 +01:00
}
2015-12-10 13:12:03 +00:00
2015-12-11 11:37:05 +00:00
type snapRevSuite struct {
2017-03-21 12:01:00 +00:00
ts time . Time
tsLine string
2015-12-10 13:12:03 +00:00
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) SetUpSuite ( c * C ) {
srs . ts = time . Now ( ) . Truncate ( time . Second ) . UTC ( )
srs . tsLine = "timestamp: " + srs . ts . Format ( time . RFC3339 ) + "\n"
2015-12-10 13:12:03 +00:00
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) makeValidEncoded ( ) string {
2015-12-11 11:37:05 +00:00
return "type: snap-revision\n" +
2015-12-10 13:12:03 +00:00
"authority-id: store-id1\n" +
2016-07-28 18:30:08 +02:00
"snap-sha3-384: " + blobSHA3_384 + "\n" +
2015-12-10 13:12:03 +00:00
"snap-id: snap-id-1\n" +
2016-03-16 12:59:26 +00:00
"snap-size: 123\n" +
2016-01-05 15:57:40 +00:00
"snap-revision: 1\n" +
2015-12-10 13:12:03 +00:00
"developer-id: dev-id1\n" +
"revision: 1\n" +
2016-02-14 19:36:08 +01:00
srs . tsLine +
2016-08-01 23:10:40 +02:00
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
2015-12-10 13:12:03 +00:00
"\n\n" +
2016-08-01 23:10:40 +02:00
"AXNpZw=="
2015-12-10 13:12:03 +00:00
}
2023-03-22 10:55:25 +07:00
func ( srs * snapRevSuite ) makeValidEncodedWithIntegrity ( ) string {
return "type: snap-revision\n" +
"authority-id: store-id1\n" +
"snap-sha3-384: " + blobSHA3_384 + "\n" +
"snap-id: snap-id-1\n" +
"snap-size: 123\n" +
"snap-revision: 1\n" +
"integrity:\n" +
" sha3-384: " + blobSHA3_384 + "\n" +
" size: 128\n" +
"developer-id: dev-id1\n" +
"revision: 1\n" +
srs . tsLine +
"body-length: 0\n" +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
}
2022-01-26 16:45:03 +01:00
func makeSnapRevisionHeaders ( overrides map [ string ] interface { } ) map [ string ] interface { } {
2016-07-27 15:21:36 +02:00
headers := map [ string ] interface { } {
2016-07-07 18:32:57 +02:00
"authority-id" : "canonical" ,
2016-07-28 18:30:08 +02:00
"snap-sha3-384" : blobSHA3_384 ,
2016-01-05 15:57:40 +00:00
"snap-id" : "snap-id-1" ,
2016-03-16 12:59:26 +00:00
"snap-size" : "123" ,
2016-01-05 15:57:40 +00:00
"snap-revision" : "1" ,
"developer-id" : "dev-id1" ,
"revision" : "1" ,
2016-07-07 18:32:57 +02:00
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
2015-12-10 13:12:03 +00:00
}
for k , v := range overrides {
headers [ k ] = v
}
return headers
}
2022-01-26 16:45:03 +01:00
func ( srs * snapRevSuite ) makeHeaders ( overrides map [ string ] interface { } ) map [ string ] interface { } {
return makeSnapRevisionHeaders ( overrides )
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) TestDecodeOK ( c * C ) {
encoded := srs . makeValidEncoded ( )
2015-12-10 13:12:03 +00:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
2015-12-11 11:37:05 +00:00
c . Check ( a . Type ( ) , Equals , asserts . SnapRevisionType )
snapRev := a . ( * asserts . SnapRevision )
c . Check ( snapRev . AuthorityID ( ) , Equals , "store-id1" )
2016-02-14 19:36:08 +01:00
c . Check ( snapRev . Timestamp ( ) , Equals , srs . ts )
2015-12-11 11:37:05 +00:00
c . Check ( snapRev . SnapID ( ) , Equals , "snap-id-1" )
2016-07-28 18:30:08 +02:00
c . Check ( snapRev . SnapSHA3_384 ( ) , Equals , blobSHA3_384 )
2016-03-16 12:59:26 +00:00
c . Check ( snapRev . SnapSize ( ) , Equals , uint64 ( 123 ) )
2016-07-15 14:05:36 +02:00
c . Check ( snapRev . SnapRevision ( ) , Equals , 1 )
2015-12-11 11:37:05 +00:00
c . Check ( snapRev . DeveloperID ( ) , Equals , "dev-id1" )
c . Check ( snapRev . Revision ( ) , Equals , 1 )
2022-06-17 13:36:26 +02:00
c . Check ( snapRev . Provenance ( ) , Equals , "global-upload" )
}
func ( srs * snapRevSuite ) TestDecodeOKWithProvenance ( c * C ) {
encoded := srs . makeValidEncoded ( )
encoded = strings . Replace ( encoded , "snap-id: snap-id-1" , "provenance: foo\nsnap-id: snap-id-1" , 1 )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . SnapRevisionType )
snapRev := a . ( * asserts . SnapRevision )
c . Check ( snapRev . AuthorityID ( ) , Equals , "store-id1" )
c . Check ( snapRev . Timestamp ( ) , Equals , srs . ts )
c . Check ( snapRev . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( snapRev . SnapSHA3_384 ( ) , Equals , blobSHA3_384 )
c . Check ( snapRev . SnapSize ( ) , Equals , uint64 ( 123 ) )
c . Check ( snapRev . SnapRevision ( ) , Equals , 1 )
c . Check ( snapRev . DeveloperID ( ) , Equals , "dev-id1" )
c . Check ( snapRev . Revision ( ) , Equals , 1 )
c . Check ( snapRev . Provenance ( ) , Equals , "foo" )
2015-12-10 13:12:03 +00:00
}
2023-03-22 10:55:25 +07:00
func ( srs * snapRevSuite ) TestDecodeOKWithIntegrity ( c * C ) {
encoded := srs . makeValidEncodedWithIntegrity ( )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . SnapRevisionType )
snapRev := a . ( * asserts . SnapRevision )
c . Check ( snapRev . AuthorityID ( ) , Equals , "store-id1" )
c . Check ( snapRev . Timestamp ( ) , Equals , srs . ts )
c . Check ( snapRev . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( snapRev . SnapSHA3_384 ( ) , Equals , blobSHA3_384 )
c . Check ( snapRev . SnapSize ( ) , Equals , uint64 ( 123 ) )
c . Check ( snapRev . SnapRevision ( ) , Equals , 1 )
c . Check ( snapRev . DeveloperID ( ) , Equals , "dev-id1" )
c . Check ( snapRev . Revision ( ) , Equals , 1 )
c . Check ( snapRev . Provenance ( ) , Equals , "global-upload" )
c . Check ( snapRev . SnapIntegrity ( ) . SHA3_384 , Equals , blobSHA3_384 )
c . Check ( snapRev . SnapIntegrity ( ) . Size , Equals , uint64 ( 128 ) )
}
2015-12-10 13:12:03 +00:00
const (
2015-12-11 11:37:05 +00:00
snapRevErrPrefix = "assertion snap-revision: "
2015-12-10 13:12:03 +00:00
)
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) TestDecodeInvalid ( c * C ) {
encoded := srs . makeValidEncoded ( )
2016-07-28 18:30:08 +02:00
2016-07-29 11:26:49 +02:00
digestHdr := "snap-sha3-384: " + blobSHA3_384 + "\n"
2015-12-10 13:12:03 +00:00
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ "snap-id: snap-id-1\n" , "" , ` "snap-id" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "snap-id: snap-id-1\n" , "snap-id: \n" , ` "snap-id" header should not be empty ` } ,
2016-07-29 11:26:49 +02:00
{ digestHdr , "" , ` "snap-sha3-384" header is mandatory ` } ,
{ digestHdr , "snap-sha3-384: \n" , ` "snap-sha3-384" header should not be empty ` } ,
{ digestHdr , "snap-sha3-384: #\n" , ` "snap-sha3-384" header cannot be decoded:.* ` } ,
{ digestHdr , "snap-sha3-384: eHl6\n" , ` "snap-sha3-384" header does not have the expected bit length: 24 ` } ,
2022-06-17 13:36:26 +02:00
{ "snap-id: snap-id-1\n" , "provenance: \nsnap-id: snap-id-1\n" , ` "provenance" header should not be empty ` } ,
2022-06-29 17:41:21 +02:00
{ "snap-id: snap-id-1\n" , "provenance: *\nsnap-id: snap-id-1\n" , ` "provenance" header contains invalid characters: "\*" ` } ,
2016-03-16 12:59:26 +00:00
{ "snap-size: 123\n" , "" , ` "snap-size" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "snap-size: 123\n" , "snap-size: \n" , ` "snap-size" header should not be empty ` } ,
2016-03-16 12:59:26 +00:00
{ "snap-size: 123\n" , "snap-size: -1\n" , ` "snap-size" header is not an unsigned integer: -1 ` } ,
{ "snap-size: 123\n" , "snap-size: zzz\n" , ` "snap-size" header is not an unsigned integer: zzz ` } ,
2016-01-05 15:57:40 +00:00
{ "snap-revision: 1\n" , "" , ` "snap-revision" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "snap-revision: 1\n" , "snap-revision: \n" , ` "snap-revision" header should not be empty ` } ,
2016-07-15 14:05:36 +02:00
{ "snap-revision: 1\n" , "snap-revision: -1\n" , ` "snap-revision" header must be >=1: -1 ` } ,
{ "snap-revision: 1\n" , "snap-revision: 0\n" , ` "snap-revision" header must be >=1: 0 ` } ,
{ "snap-revision: 1\n" , "snap-revision: zzz\n" , ` "snap-revision" header is not an integer: zzz ` } ,
2015-12-10 13:12:03 +00:00
{ "developer-id: dev-id1\n" , "" , ` "developer-id" header is mandatory ` } ,
2016-05-17 11:11:30 +01:00
{ "developer-id: dev-id1\n" , "developer-id: \n" , ` "developer-id" header should not be empty ` } ,
{ srs . tsLine , "" , ` "timestamp" header is mandatory ` } ,
{ srs . tsLine , "timestamp: \n" , ` "timestamp" header should not be empty ` } ,
2016-02-14 19:36:08 +01:00
{ srs . tsLine , "timestamp: 12:30\n" , ` "timestamp" header is not a RFC3339 date: .* ` } ,
2015-12-10 13:12:03 +00:00
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
2023-03-22 10:55:25 +07:00
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , snapRevErrPrefix + test . expectedErr )
}
}
func ( srs * snapRevSuite ) TestDecodeInvalidWithIntegrity ( c * C ) {
encoded := srs . makeValidEncodedWithIntegrity ( )
integrityHdr := "integrity:\n" +
" sha3-384: " + blobSHA3_384 + "\n" +
" size: 128\n"
integrityShaHdr := " sha3-384: " + blobSHA3_384 + "\n"
integritySizeHdr := " size: 128\n"
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ integrityHdr , "integrity: \n" , ` "integrity" header must be a map ` } ,
{ integrityShaHdr , " sha3-384: \n" , ` "sha3-384" of integrity header should not be empty ` } ,
{ integrityShaHdr , " sha3-384: #\n" , ` "sha3-384" of integrity header cannot be decoded:.* ` } ,
{ integrityShaHdr , " sha3-384: eHl6\n" , ` "sha3-384" of integrity header does not have the expected bit length: 24 ` } ,
{ integritySizeHdr , "" , ` "size" of integrity header is mandatory ` } ,
{ integritySizeHdr , " size: \n" , ` "size" of integrity header should not be empty ` } ,
{ integritySizeHdr , " size: -1\n" , ` "size" of integrity header is not an unsigned integer: -1 ` } ,
{ integritySizeHdr , " size: zzz\n" , ` "size" of integrity header is not an unsigned integer: zzz ` } ,
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
2015-12-10 13:12:03 +00:00
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
2015-12-11 11:37:05 +00:00
c . Check ( err , ErrorMatches , snapRevErrPrefix + test . expectedErr )
2015-12-10 13:12:03 +00:00
}
}
2016-07-12 11:49:20 +02:00
func prereqSnapDecl ( c * C , storeDB assertstest . SignerDB , db * asserts . Database ) {
2016-07-27 15:21:36 +02:00
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
2016-07-12 11:37:28 +02:00
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) TestSnapRevisionCheck ( c * C ) {
2016-07-07 18:32:57 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
2015-12-10 13:12:03 +00:00
2016-07-12 11:37:28 +02:00
prereqDevAccount ( c , storeDB , db )
2016-07-12 11:49:20 +02:00
prereqSnapDecl ( c , storeDB , db )
2016-07-12 11:37:28 +02:00
2016-02-14 19:36:08 +01:00
headers := srs . makeHeaders ( nil )
2016-07-07 18:32:57 +02:00
snapRev , err := storeDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
2015-12-10 13:12:03 +00:00
c . Assert ( err , IsNil )
2015-12-11 11:37:05 +00:00
err = db . Check ( snapRev )
2015-12-10 13:12:03 +00:00
c . Assert ( err , IsNil )
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) TestSnapRevisionCheckInconsistentTimestamp ( c * C ) {
2016-07-07 18:32:57 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
2015-12-10 13:12:03 +00:00
2016-07-27 15:21:36 +02:00
headers := srs . makeHeaders ( map [ string ] interface { } {
2015-12-10 13:12:03 +00:00
"timestamp" : "2013-01-01T14:00:00Z" ,
} )
2016-07-07 18:32:57 +02:00
snapRev , err := storeDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
2015-12-10 13:12:03 +00:00
c . Assert ( err , IsNil )
2015-12-11 11:37:05 +00:00
err = db . Check ( snapRev )
2021-02-25 11:42:27 +01:00
c . Assert ( err , ErrorMatches , ` snap-revision assertion timestamp "2013-01-01 14:00:00 \+0000 UTC" outside of signing key validity \(key valid since.*\) ` )
2015-12-10 13:12:03 +00:00
}
2015-12-11 09:20:28 +00:00
2016-07-12 11:37:28 +02:00
func ( srs * snapRevSuite ) TestSnapRevisionCheckUntrustedAuthority ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
otherDB := setup3rdPartySigning ( c , "other" , storeDB , db )
2017-08-10 14:52:21 +02:00
headers := srs . makeHeaders ( map [ string ] interface { } {
"authority-id" : "other" ,
} )
2016-07-12 11:37:28 +02:00
snapRev , err := otherDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapRev )
c . Assert ( err , ErrorMatches , ` snap-revision assertion for snap id "snap-id-1" is not signed by a store:.* ` )
}
2016-07-14 11:51:50 +02:00
func ( srs * snapRevSuite ) TestSnapRevisionCheckMissingDeveloperAccount ( c * C ) {
2016-07-12 11:37:28 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
headers := srs . makeHeaders ( nil )
snapRev , err := storeDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapRev )
c . Assert ( err , ErrorMatches , ` snap-revision assertion for snap id "snap-id-1" does not have a matching account assertion for the developer "dev-id1" ` )
}
func ( srs * snapRevSuite ) TestSnapRevisionCheckMissingDeclaration ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
prereqDevAccount ( c , storeDB , db )
headers := srs . makeHeaders ( nil )
snapRev , err := storeDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapRev )
c . Assert ( err , ErrorMatches , ` snap-revision assertion for snap id "snap-id-1" does not have a matching snap-declaration assertion ` )
}
2022-06-17 16:00:48 +02:00
func ( srs * snapRevSuite ) TestRevisionAuthorityCheck ( c * C ) {
2022-01-28 15:53:20 +01:00
storeDB , db := makeStoreAndCheckDB ( c )
2022-06-17 16:00:48 +02:00
delegatedDB := setup3rdPartySigning ( c , "delegated-id" , storeDB , db )
2022-01-28 15:53:20 +01:00
headers := srs . makeHeaders ( map [ string ] interface { } {
2022-06-17 16:00:48 +02:00
"authority-id" : "delegated-id" ,
"developer-id" : "delegated-id" ,
"snap-revision" : "200" ,
"provenance" : "prov1" ,
2022-01-28 15:53:20 +01:00
} )
2022-06-17 16:00:48 +02:00
a , err := delegatedDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
snapRev := a . ( * asserts . SnapRevision )
tests := [ ] struct {
revAuth asserts . RevisionAuthority
err string
} {
{ asserts . RevisionAuthority {
AccountID : "delegated-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
} , "" } ,
{ asserts . RevisionAuthority {
AccountID : "delegated-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
MaxRevision : 1000 ,
} , "" } ,
{ asserts . RevisionAuthority {
AccountID : "delegated-id" ,
Provenance : [ ] string { "prov2" } ,
MinRevision : 1 ,
MaxRevision : 1000 ,
} , "provenance mismatch" } ,
{ asserts . RevisionAuthority {
AccountID : "delegated-id-2" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
MaxRevision : 1000 ,
} , "authority-id mismatch" } ,
{ asserts . RevisionAuthority {
AccountID : "delegated-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1000 ,
} , "snap revision 200 is less than min-revision 1000" } ,
{ asserts . RevisionAuthority {
AccountID : "delegated-id" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 10 ,
MaxRevision : 110 ,
} , "snap revision 200 is greater than max-revision 110" } ,
}
for _ , t := range tests {
2022-07-04 11:21:57 +02:00
err := t . revAuth . Check ( snapRev , nil , nil )
if t . err == "" {
c . Check ( err , IsNil )
} else {
c . Check ( err , ErrorMatches , t . err )
}
}
}
func ( srs * snapRevSuite ) TestRevisionAuthorityCheckDeviceScope ( c * C ) {
a , err := asserts . Decode ( [ ] byte ( ` type : model
authority - id : my - brand
series : 16
brand - id : my - brand
model : my - model
store : substore
architecture : armhf
kernel : krnl
gadget : gadget
timestamp : 2018 - 0 9 - 12 T12 : 00 : 00 Z
sign - key - sha3 - 384 : Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS - 3 VW7F_idjix7Ffn5qMxB21ZQuij
AXNpZw == ` ) )
c . Assert ( err , IsNil )
myModel := a . ( * asserts . Model )
a , err = asserts . Decode ( [ ] byte ( ` type : store
store : substore
authority - id : canonical
operator - id : canonical
friendly - stores :
- a - store
- store1
- store2
timestamp : 2018 - 0 9 - 12 T12 : 00 : 00 Z
sign - key - sha3 - 384 : Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS - 3 VW7F_idjix7Ffn5qMxB21ZQuij
AXNpZw == ` ) )
c . Assert ( err , IsNil )
substore := a . ( * asserts . Store )
storeDB , db := makeStoreAndCheckDB ( c )
delegatedDB := setup3rdPartySigning ( c , "my-brand" , storeDB , db )
headers := srs . makeHeaders ( map [ string ] interface { } {
"authority-id" : "my-brand" ,
"developer-id" : "my-brand" ,
"snap-revision" : "200" ,
"provenance" : "prov1" ,
} )
a , err = delegatedDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
snapRev := a . ( * asserts . SnapRevision )
tests := [ ] struct {
revAuth asserts . RevisionAuthority
substore * asserts . Store
err string
} {
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
} , nil , "" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "other-store" } ,
} ,
} , nil , "on-store mismatch" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "substore" } ,
} ,
} , nil , "" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "substore" } ,
} ,
} , substore , "" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "a-store" } ,
} ,
} , substore , "" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "store1" } ,
} ,
} , nil , "on-store mismatch" } ,
{ asserts . RevisionAuthority {
AccountID : "my-brand" ,
Provenance : [ ] string { "prov1" , "prov2" } ,
MinRevision : 1 ,
DeviceScope : & asserts . DeviceScopeConstraint {
Store : [ ] string { "store1" , "other-store" } ,
} ,
} , substore , "" } ,
}
for _ , t := range tests {
err := t . revAuth . Check ( snapRev , myModel , t . substore )
2022-06-17 16:00:48 +02:00
if t . err == "" {
c . Check ( err , IsNil )
} else {
c . Check ( err , ErrorMatches , t . err )
}
}
}
func ( srs * snapRevSuite ) TestSnapRevisionDelegation ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
delegatedDB := setup3rdPartySigning ( c , "delegated-id" , storeDB , db )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "delegated-id" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
2022-01-28 15:53:20 +01:00
c . Assert ( err , IsNil )
2022-06-17 16:00:48 +02:00
headers := srs . makeHeaders ( map [ string ] interface { } {
"authority-id" : "delegated-id" ,
"developer-id" : "delegated-id" ,
"provenance" : "prov1" ,
} )
snapRev , err := delegatedDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapRev )
c . Check ( err , ErrorMatches , ` snap-revision assertion with provenance "prov1" for snap id "snap-id-1" is not signed by an authorized authority: delegated-id ` )
// establish delegation
snapDecl , err = storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "delegated-id" ,
"revision" : "1" ,
"revision-authority" : [ ] interface { } {
2022-01-28 15:53:20 +01:00
map [ string ] interface { } {
2022-06-17 16:00:48 +02:00
"account-id" : "delegated-id" ,
"provenance" : [ ] interface { } {
"prov1" ,
} ,
// present but not checked at this level
"on-store" : [ ] interface { } {
"store1" ,
2022-01-28 15:53:20 +01:00
} ,
} ,
} ,
2022-06-17 16:00:48 +02:00
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
2022-01-28 15:53:20 +01:00
c . Assert ( err , IsNil )
2022-06-17 16:00:48 +02:00
// now revision should be accepted
2022-01-28 15:53:20 +01:00
err = db . Check ( snapRev )
c . Check ( err , IsNil )
}
2022-06-17 16:00:48 +02:00
func ( srs * snapRevSuite ) TestSnapRevisionDelegationRevisionOutOfRange ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
delegatedDB := setup3rdPartySigning ( c , "delegated-id" , storeDB , db )
// establish delegation
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "foo" ,
"publisher-id" : "delegated-id" ,
"revision-authority" : [ ] interface { } {
map [ string ] interface { } {
"account-id" : "delegated-id" ,
"provenance" : [ ] interface { } {
"prov1" ,
} ,
// present but not checked at this level
"on-store" : [ ] interface { } {
"store1" ,
} ,
"max-revision" : "200" ,
} ,
} ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
headers := srs . makeHeaders ( map [ string ] interface { } {
"authority-id" : "delegated-id" ,
"developer-id" : "delegated-id" ,
"provenance" : "prov1" ,
"snap-revision" : "1000" ,
} )
snapRev , err := delegatedDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapRev )
c . Check ( err , ErrorMatches , ` snap-revision assertion with provenance "prov1" for snap id "snap-id-1" is not signed by an authorized authority: delegated-id ` )
}
2016-02-14 19:36:08 +01:00
func ( srs * snapRevSuite ) TestPrimaryKey ( c * C ) {
2016-07-07 18:32:57 +02:00
storeDB , db := makeStoreAndCheckDB ( c )
2016-07-11 20:36:54 +02:00
2016-07-12 11:37:28 +02:00
prereqDevAccount ( c , storeDB , db )
2016-07-12 11:49:20 +02:00
prereqSnapDecl ( c , storeDB , db )
2016-07-12 11:37:28 +02:00
2016-07-11 20:36:54 +02:00
headers := srs . makeHeaders ( nil )
2016-07-07 18:32:57 +02:00
snapRev , err := storeDB . Sign ( asserts . SnapRevisionType , headers , nil , "" )
2015-12-11 09:20:28 +00:00
c . Assert ( err , IsNil )
2015-12-11 11:37:05 +00:00
err = db . Add ( snapRev )
2015-12-11 09:20:28 +00:00
c . Assert ( err , IsNil )
2015-12-11 11:37:05 +00:00
_ , err = db . Find ( asserts . SnapRevisionType , map [ string ] string {
2016-07-28 18:30:08 +02:00
"snap-sha3-384" : headers [ "snap-sha3-384" ] . ( string ) ,
2015-12-11 09:20:28 +00:00
} )
c . Assert ( err , IsNil )
}
2016-07-15 12:17:49 +02:00
func ( srs * snapRevSuite ) TestPrerequisites ( c * C ) {
encoded := srs . makeValidEncoded ( )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := a . Prerequisites ( )
c . Assert ( prereqs , HasLen , 2 )
c . Check ( prereqs [ 0 ] , DeepEquals , & asserts . Ref {
Type : asserts . SnapDeclarationType ,
PrimaryKey : [ ] string { "16" , "snap-id-1" } ,
} )
c . Check ( prereqs [ 1 ] , DeepEquals , & asserts . Ref {
Type : asserts . AccountType ,
PrimaryKey : [ ] string { "dev-id1" } ,
} )
}
2016-08-23 19:10:24 -03:00
type validationSuite struct {
ts time . Time
tsLine string
}
func ( vs * validationSuite ) SetUpSuite ( c * C ) {
vs . ts = time . Now ( ) . Truncate ( time . Second ) . UTC ( )
vs . tsLine = "timestamp: " + vs . ts . Format ( time . RFC3339 ) + "\n"
}
func ( vs * validationSuite ) makeValidEncoded ( ) string {
return "type: validation\n" +
"authority-id: dev-id1\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"approved-snap-id: snap-id-2\n" +
"approved-snap-revision: 42\n" +
"revision: 1\n" +
vs . tsLine +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
}
func ( vs * validationSuite ) makeHeaders ( overrides map [ string ] interface { } ) map [ string ] interface { } {
headers := map [ string ] interface { } {
"authority-id" : "dev-id1" ,
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"approved-snap-id" : "snap-id-2" ,
"approved-snap-revision" : "42" ,
"revision" : "1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
}
for k , v := range overrides {
headers [ k ] = v
}
return headers
}
func ( vs * validationSuite ) TestDecodeOK ( c * C ) {
encoded := vs . makeValidEncoded ( )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . ValidationType )
validation := a . ( * asserts . Validation )
c . Check ( validation . AuthorityID ( ) , Equals , "dev-id1" )
c . Check ( validation . Timestamp ( ) , Equals , vs . ts )
c . Check ( validation . Series ( ) , Equals , "16" )
c . Check ( validation . SnapID ( ) , Equals , "snap-id-1" )
c . Check ( validation . ApprovedSnapID ( ) , Equals , "snap-id-2" )
2016-09-13 09:40:39 -03:00
c . Check ( validation . ApprovedSnapRevision ( ) , Equals , 42 )
2016-09-12 11:56:48 -03:00
c . Check ( validation . Revoked ( ) , Equals , false )
2016-08-23 19:10:24 -03:00
c . Check ( validation . Revision ( ) , Equals , 1 )
}
const (
validationErrPrefix = "assertion validation: "
)
func ( vs * validationSuite ) TestDecodeInvalid ( c * C ) {
encoded := vs . makeValidEncoded ( )
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ "series: 16\n" , "" , ` "series" header is mandatory ` } ,
{ "series: 16\n" , "series: \n" , ` "series" header should not be empty ` } ,
{ "snap-id: snap-id-1\n" , "" , ` "snap-id" header is mandatory ` } ,
{ "snap-id: snap-id-1\n" , "snap-id: \n" , ` "snap-id" header should not be empty ` } ,
{ "approved-snap-id: snap-id-2\n" , "" , ` "approved-snap-id" header is mandatory ` } ,
{ "approved-snap-id: snap-id-2\n" , "approved-snap-id: \n" , ` "approved-snap-id" header should not be empty ` } ,
{ "approved-snap-revision: 42\n" , "" , ` "approved-snap-revision" header is mandatory ` } ,
2016-09-14 11:41:33 +02:00
{ "approved-snap-revision: 42\n" , "approved-snap-revision: z\n" , ` "approved-snap-revision" header is not an integer: z ` } ,
2016-08-23 19:10:24 -03:00
{ "approved-snap-revision: 42\n" , "approved-snap-revision: 0\n" , ` "approved-snap-revision" header must be >=1: 0 ` } ,
{ "approved-snap-revision: 42\n" , "approved-snap-revision: -1\n" , ` "approved-snap-revision" header must be >=1: -1 ` } ,
{ vs . tsLine , "" , ` "timestamp" header is mandatory ` } ,
{ vs . tsLine , "timestamp: \n" , ` "timestamp" header should not be empty ` } ,
{ vs . tsLine , "timestamp: 12:30\n" , ` "timestamp" header is not a RFC3339 date: .* ` } ,
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , validationErrPrefix + test . expectedErr )
}
}
func prereqSnapDecl2 ( c * C , storeDB assertstest . SignerDB , db * asserts . Database ) {
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-2" ,
"snap-name" : "bar" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
}
func ( vs * validationSuite ) TestValidationCheck ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
2016-09-16 22:33:51 +02:00
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
prereqSnapDecl ( c , storeDB , db )
prereqSnapDecl2 ( c , storeDB , db )
headers := vs . makeHeaders ( nil )
validation , err := devDB . Sign ( asserts . ValidationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( validation )
c . Assert ( err , IsNil )
}
func ( vs * validationSuite ) TestValidationCheckWrongAuthority ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
2016-08-23 19:10:24 -03:00
prereqDevAccount ( c , storeDB , db )
prereqSnapDecl ( c , storeDB , db )
prereqSnapDecl2 ( c , storeDB , db )
2017-08-14 14:06:40 +02:00
headers := vs . makeHeaders ( map [ string ] interface { } {
"authority-id" : "canonical" , // not the publisher
} )
2016-08-23 19:10:24 -03:00
validation , err := storeDB . Sign ( asserts . ValidationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( validation )
2016-09-16 22:33:51 +02:00
c . Assert ( err , ErrorMatches , ` validation assertion by snap "foo" \(id "snap-id-1"\) not signed by its publisher ` )
2016-08-23 19:10:24 -03:00
}
2016-09-12 11:56:48 -03:00
func ( vs * validationSuite ) TestRevocation ( c * C ) {
encoded := "type: validation\n" +
"authority-id: dev-id1\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"approved-snap-id: snap-id-2\n" +
"approved-snap-revision: 42\n" +
"revoked: true\n" +
"revision: 1\n" +
vs . tsLine +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
validation := a . ( * asserts . Validation )
c . Check ( validation . Revoked ( ) , Equals , true )
}
2016-09-14 10:54:01 +02:00
func ( vs * validationSuite ) TestRevokedFalse ( c * C ) {
encoded := "type: validation\n" +
"authority-id: dev-id1\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"approved-snap-id: snap-id-2\n" +
"approved-snap-revision: 42\n" +
"revoked: false\n" +
"revision: 1\n" +
vs . tsLine +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
validation := a . ( * asserts . Validation )
c . Check ( validation . Revoked ( ) , Equals , false )
}
func ( vs * validationSuite ) TestRevokedInvalid ( c * C ) {
encoded := "type: validation\n" +
"authority-id: dev-id1\n" +
"series: 16\n" +
"snap-id: snap-id-1\n" +
"approved-snap-id: snap-id-2\n" +
"approved-snap-revision: 42\n" +
"revoked: foo\n" +
"revision: 1\n" +
vs . tsLine +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , ErrorMatches , ` .*: "revoked" header must be 'true' or 'false' ` )
}
func ( vs * validationSuite ) TestMissingGatedSnapDeclaration ( c * C ) {
2016-09-13 11:24:28 -03:00
storeDB , db := makeStoreAndCheckDB ( c )
2017-08-14 14:06:40 +02:00
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
2016-09-13 11:24:28 -03:00
headers := vs . makeHeaders ( nil )
2017-08-14 14:06:40 +02:00
a , err := devDB . Sign ( asserts . ValidationType , headers , nil , "" )
2016-09-13 11:24:28 -03:00
c . Assert ( err , IsNil )
err = db . Check ( a )
2016-09-14 11:15:53 +02:00
c . Assert ( err , ErrorMatches , ` validation assertion by snap-id "snap-id-1" does not have a matching snap-declaration assertion for approved-snap-id "snap-id-2" ` )
2016-09-14 10:54:01 +02:00
}
func ( vs * validationSuite ) TestMissingGatingSnapDeclaration ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
2017-08-14 14:06:40 +02:00
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
2016-09-14 10:54:01 +02:00
prereqSnapDecl2 ( c , storeDB , db )
headers := vs . makeHeaders ( nil )
2017-08-14 14:06:40 +02:00
a , err := devDB . Sign ( asserts . ValidationType , headers , nil , "" )
2016-09-14 10:54:01 +02:00
c . Assert ( err , IsNil )
err = db . Check ( a )
2016-09-14 11:15:53 +02:00
c . Assert ( err , ErrorMatches , ` validation assertion by snap-id "snap-id-1" does not have a matching snap-declaration assertion ` )
2016-09-13 11:24:28 -03:00
}
2016-08-23 19:10:24 -03:00
func ( vs * validationSuite ) TestPrerequisites ( c * C ) {
encoded := vs . makeValidEncoded ( )
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := a . Prerequisites ( )
c . Assert ( prereqs , HasLen , 2 )
c . Check ( prereqs [ 0 ] , DeepEquals , & asserts . Ref {
Type : asserts . SnapDeclarationType ,
PrimaryKey : [ ] string { "16" , "snap-id-1" } ,
} )
c . Check ( prereqs [ 1 ] , DeepEquals , & asserts . Ref {
Type : asserts . SnapDeclarationType ,
PrimaryKey : [ ] string { "16" , "snap-id-2" } ,
} )
2016-09-30 23:26:36 +02:00
}
type baseDeclSuite struct { }
func ( s * baseDeclSuite ) TestDecodeOK ( c * C ) {
encoded := ` type : base - declaration
authority - id : canonical
series : 16
plugs :
interface1 :
deny - installation : false
allow - auto - connection :
slot - snap - type :
- app
slot - publisher - id :
- acme
slot - attributes :
a1 : / foo / . *
plug - attributes :
b1 : B1
deny - auto - connection :
slot - attributes :
a1 : ! A1
plug - attributes :
b1 : ! B1
interface2 :
allow - installation : true
allow - connection :
plug - attributes :
a2 : A2
slot - attributes :
b2 : B2
deny - connection :
slot - snap - id :
- snapidsnapidsnapidsnapidsnapid01
- snapidsnapidsnapidsnapidsnapid02
plug - attributes :
a2 : ! A2
slot - attributes :
b2 : ! B2
slots :
interface3 :
deny - installation : false
allow - auto - connection :
plug - snap - type :
- app
plug - publisher - id :
- acme
slot - attributes :
c1 : / foo / . *
plug - attributes :
d1 : C1
deny - auto - connection :
slot - attributes :
c1 : ! C1
plug - attributes :
d1 : ! D1
interface4 :
allow - connection :
plug - attributes :
c2 : C2
slot - attributes :
d2 : D2
deny - connection :
plug - snap - id :
- snapidsnapidsnapidsnapidsnapid01
- snapidsnapidsnapidsnapidsnapid02
plug - attributes :
c2 : ! D2
slot - attributes :
d2 : ! D2
allow - installation :
slot - snap - type :
- app
slot - attributes :
e1 : E1
timestamp : 2016 - 0 9 - 29 T19 : 50 : 49 Z
sign - key - sha3 - 384 : Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS - 3 VW7F_idjix7Ffn5qMxB21ZQuij
2016-10-02 15:42:28 +02:00
AXNpZw == `
2016-09-30 23:26:36 +02:00
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
baseDecl := a . ( * asserts . BaseDeclaration )
c . Check ( baseDecl . Series ( ) , Equals , "16" )
ts , err := time . Parse ( time . RFC3339 , "2016-09-29T19:50:49Z" )
2016-11-22 15:03:24 +01:00
c . Assert ( err , IsNil )
2016-09-30 23:26:36 +02:00
c . Check ( baseDecl . Timestamp ( ) . Equal ( ts ) , Equals , true )
c . Check ( baseDecl . PlugRule ( "interfaceX" ) , IsNil )
c . Check ( baseDecl . SlotRule ( "interfaceX" ) , IsNil )
2018-05-16 11:01:04 +02:00
plug := emptyAttrerObject { }
slot := emptyAttrerObject { }
2018-01-29 10:25:27 +01:00
2016-09-30 23:26:36 +02:00
plugRule1 := baseDecl . PlugRule ( "interface1" )
c . Assert ( plugRule1 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule1 . DenyInstallation , HasLen , 1 )
c . Check ( plugRule1 . DenyInstallation [ 0 ] . PlugAttributes , Equals , asserts . NeverMatchAttributes )
c . Assert ( plugRule1 . AllowAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "a1".* ` )
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "b1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotSnapTypes , DeepEquals , [ ] string { "app" } )
c . Check ( plugRule1 . AllowAutoConnection [ 0 ] . SlotPublisherIDs , DeepEquals , [ ] string { "acme" } )
c . Assert ( plugRule1 . DenyAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule1 . DenyAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "a1".* ` )
c . Check ( plugRule1 . DenyAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "b1".* ` )
2016-09-30 23:26:36 +02:00
plugRule2 := baseDecl . PlugRule ( "interface2" )
c . Assert ( plugRule2 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule2 . AllowInstallation , HasLen , 1 )
c . Check ( plugRule2 . AllowInstallation [ 0 ] . PlugAttributes , Equals , asserts . AlwaysMatchAttributes )
c . Assert ( plugRule2 . AllowConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule2 . AllowConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "a2".* ` )
c . Check ( plugRule2 . AllowConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "b2".* ` )
2016-10-15 01:18:23 +02:00
c . Assert ( plugRule2 . DenyConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( plugRule2 . DenyConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "a2".* ` )
c . Check ( plugRule2 . DenyConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "b2".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( plugRule2 . DenyConnection [ 0 ] . SlotSnapIDs , DeepEquals , [ ] string { "snapidsnapidsnapidsnapidsnapid01" , "snapidsnapidsnapidsnapidsnapid02" } )
2016-09-30 23:26:36 +02:00
slotRule3 := baseDecl . SlotRule ( "interface3" )
c . Assert ( slotRule3 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule3 . DenyInstallation , HasLen , 1 )
c . Check ( slotRule3 . DenyInstallation [ 0 ] . SlotAttributes , Equals , asserts . NeverMatchAttributes )
c . Assert ( slotRule3 . AllowAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "c1".* ` )
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "d1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugSnapTypes , DeepEquals , [ ] string { "app" } )
c . Check ( slotRule3 . AllowAutoConnection [ 0 ] . PlugPublisherIDs , DeepEquals , [ ] string { "acme" } )
c . Assert ( slotRule3 . DenyAutoConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule3 . DenyAutoConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "c1".* ` )
c . Check ( slotRule3 . DenyAutoConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "d1".* ` )
2016-09-30 23:26:36 +02:00
slotRule4 := baseDecl . SlotRule ( "interface4" )
c . Assert ( slotRule4 , NotNil )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule4 . AllowConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . AllowConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "c2".* ` )
c . Check ( slotRule4 . AllowConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "d2".* ` )
2016-10-15 01:18:23 +02:00
c . Assert ( slotRule4 . DenyConnection , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . DenyConnection [ 0 ] . PlugAttributes . Check ( plug , nil ) , ErrorMatches , ` attribute "c2".* ` )
c . Check ( slotRule4 . DenyConnection [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "d2".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule4 . DenyConnection [ 0 ] . PlugSnapIDs , DeepEquals , [ ] string { "snapidsnapidsnapidsnapidsnapid01" , "snapidsnapidsnapidsnapidsnapid02" } )
c . Assert ( slotRule4 . AllowInstallation , HasLen , 1 )
2018-01-29 10:25:27 +01:00
c . Check ( slotRule4 . AllowInstallation [ 0 ] . SlotAttributes . Check ( slot , nil ) , ErrorMatches , ` attribute "e1".* ` )
2016-10-15 01:18:23 +02:00
c . Check ( slotRule4 . AllowInstallation [ 0 ] . SlotSnapTypes , DeepEquals , [ ] string { "app" } )
2016-08-23 19:10:24 -03:00
}
2016-09-30 23:26:36 +02:00
func ( s * baseDeclSuite ) TestBaseDeclarationCheckUntrustedAuthority ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
otherDB := setup3rdPartySigning ( c , "other" , storeDB , db )
headers := map [ string ] interface { } {
"series" : "16" ,
"timestamp" : time . Now ( ) . Format ( time . RFC3339 ) ,
}
baseDecl , err := otherDB . Sign ( asserts . BaseDeclarationType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( baseDecl )
c . Assert ( err , ErrorMatches , ` base-declaration assertion for series 16 is not signed by a directly trusted authority: other ` )
}
const (
baseDeclErrPrefix = "assertion base-declaration: "
)
func ( s * baseDeclSuite ) TestDecodeInvalid ( c * C ) {
tsLine := "timestamp: 2016-09-29T19:50:49Z\n"
encoded := "type: base-declaration\n" +
"authority-id: canonical\n" +
"series: 16\n" +
"plugs:\n interface1: true\n" +
"slots:\n interface2: true\n" +
tsLine +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
2016-10-02 15:42:28 +02:00
"AXNpZw=="
2016-09-30 23:26:36 +02:00
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ "series: 16\n" , "" , ` "series" header is mandatory ` } ,
{ "series: 16\n" , "series: \n" , ` "series" header should not be empty ` } ,
{ "plugs:\n interface1: true\n" , "plugs: \n" , ` "plugs" header must be a map ` } ,
{ "plugs:\n interface1: true\n" , "plugs:\n intf1:\n foo: bar\n" , ` plug rule for interface "intf1" must specify at least one of.* ` } ,
{ "slots:\n interface2: true\n" , "slots: \n" , ` "slots" header must be a map ` } ,
{ "slots:\n interface2: true\n" , "slots:\n intf1:\n foo: bar\n" , ` slot rule for interface "intf1" must specify at least one of.* ` } ,
{ tsLine , "" , ` "timestamp" header is mandatory ` } ,
{ tsLine , "timestamp: 12:30\n" , ` "timestamp" header is not a RFC3339 date: .* ` } ,
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , baseDeclErrPrefix + test . expectedErr )
}
}
func ( s * baseDeclSuite ) TestBuiltin ( c * C ) {
baseDecl := asserts . BuiltinBaseDeclaration ( )
c . Check ( baseDecl , IsNil )
defer asserts . InitBuiltinBaseDeclaration ( nil )
const headers = `
type : base - declaration
authority - id : canonical
series : 16
revision : 0
plugs :
network : true
slots :
network :
allow - installation :
slot - snap - type :
- core
`
err := asserts . InitBuiltinBaseDeclaration ( [ ] byte ( headers ) )
c . Assert ( err , IsNil )
baseDecl = asserts . BuiltinBaseDeclaration ( )
c . Assert ( baseDecl , NotNil )
cont , _ := baseDecl . Signature ( )
c . Check ( string ( cont ) , Equals , strings . TrimSpace ( headers ) )
c . Check ( baseDecl . AuthorityID ( ) , Equals , "canonical" )
c . Check ( baseDecl . Series ( ) , Equals , "16" )
2016-10-15 01:18:23 +02:00
c . Check ( baseDecl . PlugRule ( "network" ) . AllowAutoConnection [ 0 ] . SlotAttributes , Equals , asserts . AlwaysMatchAttributes )
c . Check ( baseDecl . SlotRule ( "network" ) . AllowInstallation [ 0 ] . SlotSnapTypes , DeepEquals , [ ] string { "core" } )
2016-09-30 23:26:36 +02:00
enc := asserts . Encode ( baseDecl )
// it's expected that it cannot be decoded
_ , err = asserts . Decode ( enc )
c . Check ( err , NotNil )
}
func ( s * baseDeclSuite ) TestBuiltinInitErrors ( c * C ) {
defer asserts . InitBuiltinBaseDeclaration ( nil )
tests := [ ] struct {
headers string
err string
} {
{ "" , ` header entry missing ':' separator: "" ` } ,
{ "type: foo\n" , ` the builtin base-declaration "type" header is not set to expected value "base-declaration" ` } ,
{ "type: base-declaration" , ` the builtin base-declaration "authority-id" header is not set to expected value "canonical" ` } ,
{ "type: base-declaration\nauthority-id: canonical" , ` the builtin base-declaration "series" header is not set to expected value "16" ` } ,
{ "type: base-declaration\nauthority-id: canonical\nseries: 16\nrevision: zzz" , ` cannot assemble the builtin-base declaration: "revision" header is not an integer: zzz ` } ,
{ "type: base-declaration\nauthority-id: canonical\nseries: 16\nplugs: foo" , ` cannot assemble the builtin base-declaration: "plugs" header must be a map ` } ,
}
for _ , t := range tests {
err := asserts . InitBuiltinBaseDeclaration ( [ ] byte ( t . headers ) )
c . Check ( err , ErrorMatches , t . err , Commentf ( t . headers ) )
}
}
2017-03-10 07:30:05 +00:00
type snapDevSuite struct {
developersLines string
validEncoded string
}
func ( sds * snapDevSuite ) SetUpSuite ( c * C ) {
sds . developersLines = "developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-02-01T00:00:00.0Z\n"
sds . validEncoded = "type: snap-developer\n" +
"authority-id: dev-id1\n" +
"snap-id: snap-id-1\n" +
"publisher-id: dev-id1\n" +
sds . developersLines +
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
"\n\n" +
"AXNpZw=="
}
func ( sds * snapDevSuite ) TestDecodeOK ( c * C ) {
encoded := sds . validEncoded
a , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
c . Check ( a . Type ( ) , Equals , asserts . SnapDeveloperType )
snapDev := a . ( * asserts . SnapDeveloper )
c . Check ( snapDev . AuthorityID ( ) , Equals , "dev-id1" )
c . Check ( snapDev . PublisherID ( ) , Equals , "dev-id1" )
c . Check ( snapDev . SnapID ( ) , Equals , "snap-id-1" )
}
func ( sds * snapDevSuite ) TestDevelopersOptional ( c * C ) {
encoded := strings . Replace ( sds . validEncoded , sds . developersLines , "" , 1 )
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , IsNil )
}
func ( sds * snapDevSuite ) TestDevelopersUntilOptional ( c * C ) {
encoded := strings . Replace (
sds . validEncoded , sds . developersLines ,
"developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n" , 1 )
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , IsNil )
}
func ( sds * snapDevSuite ) TestDevelopersRevoked ( c * C ) {
encoded := sds . validEncoded
encoded = strings . Replace (
encoded , sds . developersLines ,
"developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-01-01T00:00:00.0Z\n" , 1 )
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , IsNil )
// TODO(matt): check actually revoked rather than just parsed
}
const (
snapDevErrPrefix = "assertion snap-developer: "
)
func ( sds * snapDevSuite ) TestDecodeInvalid ( c * C ) {
encoded := sds . validEncoded
invalidTests := [ ] struct { original , invalid , expectedErr string } {
{ "publisher-id: dev-id1\n" , "" , ` "publisher-id" header is mandatory ` } ,
{ "publisher-id: dev-id1\n" , "publisher-id: \n" , ` "publisher-id" header should not be empty ` } ,
{ "snap-id: snap-id-1\n" , "" , ` "snap-id" header is mandatory ` } ,
{ "snap-id: snap-id-1\n" , "snap-id: \n" , ` "snap-id" header should not be empty ` } ,
{ sds . developersLines , "developers: \n" , ` "developers" must be a list of developer maps ` } ,
{ sds . developersLines , "developers: foo\n" , ` "developers" must be a list of developer maps ` } ,
{ sds . developersLines , "developers:\n foo: bar\n" , ` "developers" must be a list of developer maps ` } ,
{ sds . developersLines , "developers:\n - foo\n" , ` "developers" must be a list of developer maps ` } ,
{ sds . developersLines , "developers:\n -\n foo: bar\n" , ` "developer-id" in "developers" item 1 is mandatory ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: a\n" ,
` "developer-id" in "developers" item 1 contains invalid characters: "a" ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n" ,
` "since" in "developers" item 1 for developer "dev-id2" is mandatory ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: \n" ,
` "since" in "developers" item 1 for developer "dev-id2" should not be empty ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: foo\n" ,
` "since" in "developers" item 1 for developer "dev-id2" is not a RFC3339 date.* ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: \n" ,
` "until" in "developers" item 1 for developer "dev-id2" is not a RFC3339 date.* ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: foo\n" ,
` "until" in "developers" item 1 for developer "dev-id2" is not a RFC3339 date.* ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n -\n foo: bar\n" ,
` "developer-id" in "developers" item 2 is mandatory ` } ,
{ sds . developersLines , "developers:\n -\n developer-id: dev-id2\n since: 2017-01-02T00:00:00.0Z\n until: 2017-01-01T00:00:00.0Z\n" ,
` "since" in "developers" item 1 for developer "dev-id2" must be less than or equal to "until" ` } ,
}
for _ , test := range invalidTests {
invalid := strings . Replace ( encoded , test . original , test . invalid , 1 )
_ , err := asserts . Decode ( [ ] byte ( invalid ) )
c . Check ( err , ErrorMatches , snapDevErrPrefix + test . expectedErr )
}
}
2017-03-17 10:47:40 +00:00
func ( sds * snapDevSuite ) TestRevokedValidation ( c * C ) {
// Multiple non-revoking items are fine.
2017-03-17 15:15:29 +00:00
encoded := strings . Replace ( sds . validEncoded , sds . developersLines ,
2017-03-17 10:47:40 +00:00
"developers:\n" +
2017-03-17 15:15:29 +00:00
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-02-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id2\n since: 2017-03-01T00:00:00.0Z\n" ,
2017-03-17 10:47:40 +00:00
1 )
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , IsNil )
// Multiple revocations for different developers are fine.
2017-03-17 15:15:29 +00:00
encoded = strings . Replace ( sds . validEncoded , sds . developersLines ,
2017-03-17 10:47:40 +00:00
"developers:\n" +
2017-03-17 15:15:29 +00:00
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id3\n since: 2017-02-01T00:00:00.0Z\n until: 2017-02-01T00:00:00.0Z\n" ,
2017-03-17 10:47:40 +00:00
1 )
_ , err = asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , IsNil )
2017-03-17 15:15:29 +00:00
invalidTests := [ ] string {
// Multiple revocations.
"developers:\n" +
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id2\n since: 2017-02-01T00:00:00.0Z\n until: 2017-02-01T00:00:00.0Z\n" ,
// Revocation after non-revoking.
"developers:\n" +
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id2\n since: 2017-03-01T00:00:00.0Z\n until: 2017-03-01T00:00:00.0Z\n" ,
// Non-revoking after revocation.
"developers:\n" +
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n until: 2017-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id2\n since: 2017-02-01T00:00:00.0Z\n" ,
}
for _ , test := range invalidTests {
encoded := strings . Replace ( sds . validEncoded , sds . developersLines , test , 1 )
_ , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Check ( err , ErrorMatches , snapDevErrPrefix + ` revocation for developer "dev-id2" must be standalone but found other "developers" items ` )
}
2017-03-17 10:47:40 +00:00
}
2017-03-10 07:30:05 +00:00
func ( sds * snapDevSuite ) TestAuthorityIsPublisher ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "snap-name-1" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
snapDev , err := devDB . Sign ( asserts . SnapDeveloperType , map [ string ] interface { } {
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id1" ,
} , nil , "" )
c . Assert ( err , IsNil )
// Just to be super sure ...
c . Assert ( snapDev . HeaderString ( "authority-id" ) , Equals , "dev-id1" )
c . Assert ( snapDev . HeaderString ( "publisher-id" ) , Equals , "dev-id1" )
err = db . Check ( snapDev )
c . Assert ( err , IsNil )
}
func ( sds * snapDevSuite ) TestAuthorityIsNotPublisher ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "snap-name-1" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
snapDev , err := devDB . Sign ( asserts . SnapDeveloperType , map [ string ] interface { } {
"authority-id" : "dev-id1" ,
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id2" ,
} , nil , "" )
c . Assert ( err , IsNil )
// Just to be super sure ...
c . Assert ( snapDev . HeaderString ( "authority-id" ) , Equals , "dev-id1" )
c . Assert ( snapDev . HeaderString ( "publisher-id" ) , Equals , "dev-id2" )
err = db . Check ( snapDev )
c . Assert ( err , ErrorMatches , ` snap-developer must be signed by the publisher or a trusted authority but got authority "dev-id1" and publisher "dev-id2" ` )
}
func ( sds * snapDevSuite ) TestAuthorityIsNotPublisherButIsTrusted ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
account , err := storeDB . Sign ( asserts . AccountType , map [ string ] interface { } {
"account-id" : "dev-id1" ,
"display-name" : "dev-id1" ,
"validation" : "unknown" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( account )
c . Assert ( err , IsNil )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "snap-name-1" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
snapDev , err := storeDB . Sign ( asserts . SnapDeveloperType , map [ string ] interface { } {
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id1" ,
} , nil , "" )
c . Assert ( err , IsNil )
// Just to be super sure ...
c . Assert ( snapDev . HeaderString ( "authority-id" ) , Equals , "canonical" )
c . Assert ( snapDev . HeaderString ( "publisher-id" ) , Equals , "dev-id1" )
err = db . Check ( snapDev )
c . Assert ( err , IsNil )
}
func ( sds * snapDevSuite ) TestCheckNewPublisherAccountExists ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
account , err := storeDB . Sign ( asserts . AccountType , map [ string ] interface { } {
"account-id" : "dev-id1" ,
"display-name" : "dev-id1" ,
"validation" : "unknown" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( account )
c . Assert ( err , IsNil )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "snap-name-1" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
snapDev , err := storeDB . Sign ( asserts . SnapDeveloperType , map [ string ] interface { } {
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id2" ,
} , nil , "" )
c . Assert ( err , IsNil )
// Just to be super sure ...
c . Assert ( snapDev . HeaderString ( "authority-id" ) , Equals , "canonical" )
c . Assert ( snapDev . HeaderString ( "publisher-id" ) , Equals , "dev-id2" )
// There's no account for dev-id2 yet so it should fail.
err = db . Check ( snapDev )
c . Assert ( err , ErrorMatches , ` snap-developer assertion for snap-id "snap-id-1" does not have a matching account assertion for the publisher "dev-id2" ` )
// But once the dev-id2 account is added the snap-developer is ok.
account , err = storeDB . Sign ( asserts . AccountType , map [ string ] interface { } {
"account-id" : "dev-id2" ,
"display-name" : "dev-id2" ,
"validation" : "unknown" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( account )
c . Assert ( err , IsNil )
err = db . Check ( snapDev )
c . Assert ( err , IsNil )
}
func ( sds * snapDevSuite ) TestCheckDeveloperAccountExists ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
snapDecl , err := storeDB . Sign ( asserts . SnapDeclarationType , map [ string ] interface { } {
"series" : "16" ,
"snap-id" : "snap-id-1" ,
"snap-name" : "snap-name-1" ,
"publisher-id" : "dev-id1" ,
"timestamp" : time . Now ( ) . UTC ( ) . Format ( time . RFC3339 ) ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Add ( snapDecl )
c . Assert ( err , IsNil )
snapDev , err := devDB . Sign ( asserts . SnapDeveloperType , map [ string ] interface { } {
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id1" ,
"developers" : [ ] interface { } {
map [ string ] interface { } {
"developer-id" : "dev-id2" ,
"since" : "2017-01-01T00:00:00.0Z" ,
} ,
} ,
} , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapDev )
c . Assert ( err , ErrorMatches , ` snap-developer assertion for snap-id "snap-id-1" does not have a matching account assertion for the developer "dev-id2" ` )
}
func ( sds * snapDevSuite ) TestCheckMissingDeclaration ( c * C ) {
storeDB , db := makeStoreAndCheckDB ( c )
devDB := setup3rdPartySigning ( c , "dev-id1" , storeDB , db )
headers := map [ string ] interface { } {
"authority-id" : "dev-id1" ,
"snap-id" : "snap-id-1" ,
"publisher-id" : "dev-id1" ,
}
snapDev , err := devDB . Sign ( asserts . SnapDeveloperType , headers , nil , "" )
c . Assert ( err , IsNil )
err = db . Check ( snapDev )
c . Assert ( err , ErrorMatches , ` snap-developer assertion for snap id "snap-id-1" does not have a matching snap-declaration assertion ` )
}
func ( sds * snapDevSuite ) TestPrerequisitesNoDevelopers ( c * C ) {
encoded := strings . Replace ( sds . validEncoded , sds . developersLines , "" , 1 )
assert , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := assert . Prerequisites ( )
sort . Sort ( RefSlice ( prereqs ) )
c . Assert ( prereqs , DeepEquals , [ ] * asserts . Ref {
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id1" } } ,
{ Type : asserts . SnapDeclarationType , PrimaryKey : [ ] string { "16" , "snap-id-1" } } ,
} )
}
func ( sds * snapDevSuite ) TestPrerequisitesWithDevelopers ( c * C ) {
encoded := strings . Replace (
sds . validEncoded , sds . developersLines ,
"developers:\n" +
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id3\n since: 2017-01-01T00:00:00.0Z\n" ,
1 )
assert , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := assert . Prerequisites ( )
sort . Sort ( RefSlice ( prereqs ) )
c . Assert ( prereqs , DeepEquals , [ ] * asserts . Ref {
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id1" } } ,
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id2" } } ,
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id3" } } ,
{ Type : asserts . SnapDeclarationType , PrimaryKey : [ ] string { "16" , "snap-id-1" } } ,
} )
}
func ( sds * snapDevSuite ) TestPrerequisitesWithDeveloperRepeated ( c * C ) {
encoded := strings . Replace (
sds . validEncoded , sds . developersLines ,
"developers:\n" +
" -\n developer-id: dev-id2\n since: 2015-01-01T00:00:00.0Z\n until: 2016-01-01T00:00:00.0Z\n" +
" -\n developer-id: dev-id2\n since: 2017-01-01T00:00:00.0Z\n" ,
1 )
assert , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := assert . Prerequisites ( )
sort . Sort ( RefSlice ( prereqs ) )
c . Assert ( prereqs , DeepEquals , [ ] * asserts . Ref {
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id1" } } ,
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id2" } } ,
{ Type : asserts . SnapDeclarationType , PrimaryKey : [ ] string { "16" , "snap-id-1" } } ,
} )
}
func ( sds * snapDevSuite ) TestPrerequisitesWithPublisherAsDeveloper ( c * C ) {
encoded := strings . Replace (
sds . validEncoded , sds . developersLines ,
"developers:\n -\n developer-id: dev-id1\n since: 2017-01-01T00:00:00.0Z\n" ,
1 )
assert , err := asserts . Decode ( [ ] byte ( encoded ) )
c . Assert ( err , IsNil )
prereqs := assert . Prerequisites ( )
sort . Sort ( RefSlice ( prereqs ) )
c . Assert ( prereqs , DeepEquals , [ ] * asserts . Ref {
{ Type : asserts . AccountType , PrimaryKey : [ ] string { "dev-id1" } } ,
{ Type : asserts . SnapDeclarationType , PrimaryKey : [ ] string { "16" , "snap-id-1" } } ,
} )
}
type RefSlice [ ] * asserts . Ref
func ( s RefSlice ) Len ( ) int {
return len ( s )
}
func ( s RefSlice ) Less ( i , j int ) bool {
iref , jref := s [ i ] , s [ j ]
if v := strings . Compare ( iref . Type . Name , jref . Type . Name ) ; v != 0 {
return v == - 1
}
for n , ipk := range iref . PrimaryKey {
jpk := jref . PrimaryKey [ n ]
if v := strings . Compare ( ipk , jpk ) ; v != 0 {
return v == - 1
}
}
return false
}
func ( s RefSlice ) Swap ( i , j int ) {
s [ i ] , s [ j ] = s [ j ] , s [ i ]
}