github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/asserts/validation_set_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package asserts_test 21 22 import ( 23 "strings" 24 "time" 25 26 . "gopkg.in/check.v1" 27 28 "github.com/snapcore/snapd/asserts" 29 ) 30 31 type validationSetSuite struct { 32 ts time.Time 33 tsLine string 34 } 35 36 var _ = Suite(&validationSetSuite{}) 37 38 func (vss *validationSetSuite) SetUpSuite(c *C) { 39 vss.ts = time.Now().Truncate(time.Second).UTC() 40 vss.tsLine = "timestamp: " + vss.ts.Format(time.RFC3339) + "\n" 41 } 42 43 const ( 44 validationSetExample = `type: validation-set 45 authority-id: brand-id1 46 series: 16 47 account-id: brand-id1 48 name: baz-3000-good 49 sequence: 2 50 snaps: 51 - 52 name: baz-linux 53 id: bazlinuxidididididididididididid 54 presence: optional 55 revision: 99 56 OTHER` + "TSLINE" + 57 "body-length: 0\n" + 58 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 59 "\n\n" + 60 "AXNpZw==" 61 ) 62 63 func (vss *validationSetSuite) TestDecodeOK(c *C) { 64 encoded := strings.Replace(validationSetExample, "TSLINE", vss.tsLine, 1) 65 encoded = strings.Replace(encoded, "OTHER", "", 1) 66 67 a, err := asserts.Decode([]byte(encoded)) 68 c.Assert(err, IsNil) 69 c.Check(a.Type(), Equals, asserts.ValidationSetType) 70 _, ok := a.(asserts.SequenceMember) 71 c.Assert(ok, Equals, true) 72 valset := a.(*asserts.ValidationSet) 73 c.Check(valset.AuthorityID(), Equals, "brand-id1") 74 c.Check(valset.Timestamp(), Equals, vss.ts) 75 c.Check(valset.Series(), Equals, "16") 76 c.Check(valset.AccountID(), Equals, "brand-id1") 77 c.Check(valset.Name(), Equals, "baz-3000-good") 78 c.Check(valset.Sequence(), Equals, 2) 79 snaps := valset.Snaps() 80 c.Assert(snaps, DeepEquals, []*asserts.ValidationSetSnap{ 81 { 82 Name: "baz-linux", 83 SnapID: "bazlinuxidididididididididididid", 84 Presence: asserts.PresenceOptional, 85 Revision: 99, 86 }, 87 }) 88 c.Check(snaps[0].SnapName(), Equals, "baz-linux") 89 c.Check(snaps[0].ID(), Equals, "bazlinuxidididididididididididid") 90 } 91 92 func (vss *validationSetSuite) TestDecodeInvalid(c *C) { 93 const validationSetErrPrefix = "assertion validation-set: " 94 95 encoded := strings.Replace(validationSetExample, "TSLINE", vss.tsLine, 1) 96 97 snapsStanza := encoded[strings.Index(encoded, "snaps:"):strings.Index(encoded, "timestamp:")] 98 99 invalidTests := []struct{ original, invalid, expectedErr string }{ 100 {"series: 16\n", "", `"series" header is mandatory`}, 101 {"series: 16\n", "series: \n", `"series" header should not be empty`}, 102 {"account-id: brand-id1\n", "", `"account-id" header is mandatory`}, 103 {"account-id: brand-id1\n", "account-id: \n", `"account-id" header should not be empty`}, 104 {"account-id: brand-id1\n", "account-id: random\n", `authority-id and account-id must match, validation-set assertions are expected to be signed by the issuer account: "brand-id1" != "random"`}, 105 {"name: baz-3000-good\n", "", `"name" header is mandatory`}, 106 {"name: baz-3000-good\n", "name: \n", `"name" header should not be empty`}, 107 {"name: baz-3000-good\n", "name: baz/3000/good\n", `"name" primary key header cannot contain '/'`}, 108 {"name: baz-3000-good\n", "name: baz+3000+good\n", `"name" header contains invalid characters: "baz\+3000\+good"`}, 109 {vss.tsLine, "timestamp: 12:30\n", `"timestamp" header is not a RFC3339 date: .*`}, 110 {"sequence: 2\n", "", `"sequence" header is mandatory`}, 111 {"sequence: 2\n", "sequence: one\n", `"sequence" header is not an integer: one`}, 112 {"sequence: 2\n", "sequence: 0\n", `"sequence" must be >=1: 0`}, 113 {"sequence: 2\n", "sequence: -1\n", `"sequence" must be >=1: -1`}, 114 {"sequence: 2\n", "sequence: 00\n", `"sequence" header has invalid prefix zeros: 00`}, 115 {"sequence: 2\n", "sequence: 01\n", `"sequence" header has invalid prefix zeros: 01`}, 116 {"sequence: 2\n", "sequence: 010\n", `"sequence" header has invalid prefix zeros: 010`}, 117 {snapsStanza, "", `"snaps" header is mandatory`}, 118 {snapsStanza, "snaps: snap\n", `"snaps" header must be a list of maps`}, 119 {snapsStanza, "snaps:\n - snap\n", `"snaps" header must be a list of maps`}, 120 {"name: baz-linux\n", "other: 1\n", `"name" of snap is mandatory`}, 121 {"name: baz-linux\n", "name: linux_2\n", `invalid snap name "linux_2"`}, 122 {"id: bazlinuxidididididididididididid\n", "id: 2\n", `"id" of snap "baz-linux" contains invalid characters: "2"`}, 123 {" id: bazlinuxidididididididididididid\n", "", `"id" of snap "baz-linux" is mandatory`}, 124 {"OTHER", " -\n name: baz-linux\n id: bazlinuxidididididididididididid\n", `cannot list the same snap "baz-linux" multiple times`}, 125 {"OTHER", " -\n name: baz-linux2\n id: bazlinuxidididididididididididid\n", `cannot specify the same snap id "bazlinuxidididididididididididid" multiple times, specified for snaps "baz-linux" and "baz-linux2"`}, 126 {"presence: optional\n", "presence:\n - opt\n", `"presence" of snap "baz-linux" must be a string`}, 127 {"presence: optional\n", "presence: no\n", `"presence" of snap "baz-linux" must be one of must be one of required|optional|invalid`}, 128 {"revision: 99\n", "revision: 0\n", `"revision" of snap "baz-linux" must be >=1: 0`}, 129 {"presence: optional\n", "presence: invalid\n", `cannot specify revision of snap "baz-linux" at the same time as stating its presence is invalid`}, 130 } 131 132 for _, test := range invalidTests { 133 invalid := strings.Replace(encoded, test.original, test.invalid, 1) 134 invalid = strings.Replace(invalid, "OTHER", "", 1) 135 _, err := asserts.Decode([]byte(invalid)) 136 c.Check(err, ErrorMatches, validationSetErrPrefix+test.expectedErr) 137 } 138 139 } 140 141 func (vss *validationSetSuite) TestSnapPresenceOptionalDefaultRequired(c *C) { 142 encoded := strings.Replace(validationSetExample, "TSLINE", vss.tsLine, 1) 143 encoded = strings.Replace(encoded, "OTHER", "", 1) 144 encoded = strings.Replace(encoded, " presence: optional\n", "", 1) 145 146 a, err := asserts.Decode([]byte(encoded)) 147 c.Assert(err, IsNil) 148 c.Check(a.Type(), Equals, asserts.ValidationSetType) 149 valset := a.(*asserts.ValidationSet) 150 snaps := valset.Snaps() 151 c.Assert(snaps, HasLen, 1) 152 c.Check(snaps[0].Presence, Equals, asserts.PresenceRequired) 153 } 154 155 func (vss *validationSetSuite) TestSnapRevisionOptional(c *C) { 156 encoded := strings.Replace(validationSetExample, "TSLINE", vss.tsLine, 1) 157 encoded = strings.Replace(encoded, "OTHER", "", 1) 158 encoded = strings.Replace(encoded, " revision: 99\n", "", 1) 159 160 a, err := asserts.Decode([]byte(encoded)) 161 c.Assert(err, IsNil) 162 c.Check(a.Type(), Equals, asserts.ValidationSetType) 163 valset := a.(*asserts.ValidationSet) 164 snaps := valset.Snaps() 165 c.Assert(snaps, HasLen, 1) 166 // 0 means unset 167 c.Check(snaps[0].Revision, Equals, 0) 168 }