github.com/hugh712/snapd@v0.0.0-20200910133618-1a99902bd583/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  }