github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/asserts/fsbackstore_test.go (about)

     1  // -*- Mode: Go; indent-tabs-mode: t -*-
     2  
     3  /*
     4   * Copyright (C) 2016-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  	"os"
    24  	"path/filepath"
    25  	"syscall"
    26  
    27  	. "gopkg.in/check.v1"
    28  
    29  	"github.com/snapcore/snapd/asserts"
    30  )
    31  
    32  type fsBackstoreSuite struct{}
    33  
    34  var _ = Suite(&fsBackstoreSuite{})
    35  
    36  func (fsbss *fsBackstoreSuite) TestOpenOK(c *C) {
    37  	// ensure umask is clean when creating the DB dir
    38  	oldUmask := syscall.Umask(0)
    39  	defer syscall.Umask(oldUmask)
    40  
    41  	topDir := filepath.Join(c.MkDir(), "asserts-db")
    42  
    43  	bs, err := asserts.OpenFSBackstore(topDir)
    44  	c.Check(err, IsNil)
    45  	c.Check(bs, NotNil)
    46  
    47  	info, err := os.Stat(filepath.Join(topDir, "asserts-v0"))
    48  	c.Assert(err, IsNil)
    49  	c.Assert(info.IsDir(), Equals, true)
    50  	c.Check(info.Mode().Perm(), Equals, os.FileMode(0775))
    51  }
    52  
    53  func (fsbss *fsBackstoreSuite) TestOpenCreateFail(c *C) {
    54  	parent := filepath.Join(c.MkDir(), "var")
    55  	topDir := filepath.Join(parent, "asserts-db")
    56  	// make it not writable
    57  	err := os.Mkdir(parent, 0555)
    58  	c.Assert(err, IsNil)
    59  
    60  	bs, err := asserts.OpenFSBackstore(topDir)
    61  	c.Assert(err, ErrorMatches, "cannot create assert storage root: .*")
    62  	c.Check(bs, IsNil)
    63  }
    64  
    65  func (fsbss *fsBackstoreSuite) TestOpenWorldWritableFail(c *C) {
    66  	topDir := filepath.Join(c.MkDir(), "asserts-db")
    67  	// make it world-writable
    68  	oldUmask := syscall.Umask(0)
    69  	os.MkdirAll(filepath.Join(topDir, "asserts-v0"), 0777)
    70  	syscall.Umask(oldUmask)
    71  
    72  	bs, err := asserts.OpenFSBackstore(topDir)
    73  	c.Assert(err, ErrorMatches, "assert storage root unexpectedly world-writable: .*")
    74  	c.Check(bs, IsNil)
    75  }
    76  
    77  func (fsbss *fsBackstoreSuite) TestPutOldRevision(c *C) {
    78  	topDir := filepath.Join(c.MkDir(), "asserts-db")
    79  	bs, err := asserts.OpenFSBackstore(topDir)
    80  	c.Assert(err, IsNil)
    81  
    82  	// Create two revisions of assertion.
    83  	a0, err := asserts.Decode([]byte("type: test-only\n" +
    84  		"authority-id: auth-id1\n" +
    85  		"primary-key: foo\n" +
    86  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
    87  		"\n\n" +
    88  		"AXNpZw=="))
    89  	c.Assert(err, IsNil)
    90  	a1, err := asserts.Decode([]byte("type: test-only\n" +
    91  		"authority-id: auth-id1\n" +
    92  		"primary-key: foo\n" +
    93  		"revision: 1\n" +
    94  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
    95  		"\n\n" +
    96  		"AXNpZw=="))
    97  	c.Assert(err, IsNil)
    98  
    99  	// Put newer revision, follwed by old revision.
   100  	err = bs.Put(asserts.TestOnlyType, a1)
   101  	c.Assert(err, IsNil)
   102  	err = bs.Put(asserts.TestOnlyType, a0)
   103  
   104  	c.Check(err, ErrorMatches, `revision 0 is older than current revision 1`)
   105  	c.Check(err, DeepEquals, &asserts.RevisionError{Current: 1, Used: 0})
   106  }
   107  
   108  func (fsbss *fsBackstoreSuite) TestGetFormat(c *C) {
   109  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   110  	bs, err := asserts.OpenFSBackstore(topDir)
   111  	c.Assert(err, IsNil)
   112  
   113  	af0, err := asserts.Decode([]byte("type: test-only\n" +
   114  		"authority-id: auth-id1\n" +
   115  		"primary-key: foo\n" +
   116  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   117  		"\n\n" +
   118  		"AXNpZw=="))
   119  	c.Assert(err, IsNil)
   120  	af1, err := asserts.Decode([]byte("type: test-only\n" +
   121  		"authority-id: auth-id1\n" +
   122  		"primary-key: foo\n" +
   123  		"format: 1\n" +
   124  		"revision: 1\n" +
   125  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   126  		"\n\n" +
   127  		"AXNpZw=="))
   128  	c.Assert(err, IsNil)
   129  	af2, err := asserts.Decode([]byte("type: test-only\n" +
   130  		"authority-id: auth-id1\n" +
   131  		"primary-key: zoo\n" +
   132  		"format: 2\n" +
   133  		"revision: 22\n" +
   134  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   135  		"\n\n" +
   136  		"AXNpZw=="))
   137  	c.Assert(err, IsNil)
   138  
   139  	err = bs.Put(asserts.TestOnlyType, af0)
   140  	c.Assert(err, IsNil)
   141  	err = bs.Put(asserts.TestOnlyType, af1)
   142  	c.Assert(err, IsNil)
   143  
   144  	a, err := bs.Get(asserts.TestOnlyType, []string{"foo"}, 1)
   145  	c.Assert(err, IsNil)
   146  	c.Check(a.Revision(), Equals, 1)
   147  
   148  	a, err = bs.Get(asserts.TestOnlyType, []string{"foo"}, 0)
   149  	c.Assert(err, IsNil)
   150  	c.Check(a.Revision(), Equals, 0)
   151  
   152  	a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 0)
   153  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   154  		Type: asserts.TestOnlyType,
   155  		// Headers can be omitted by Backstores
   156  	})
   157  	c.Check(a, IsNil)
   158  
   159  	err = bs.Put(asserts.TestOnlyType, af2)
   160  	c.Assert(err, IsNil)
   161  
   162  	a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 1)
   163  	c.Assert(err, DeepEquals, &asserts.NotFoundError{
   164  		Type: asserts.TestOnlyType,
   165  	})
   166  	c.Check(a, IsNil)
   167  
   168  	a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 2)
   169  	c.Assert(err, IsNil)
   170  	c.Check(a.Revision(), Equals, 22)
   171  }
   172  
   173  func (fsbss *fsBackstoreSuite) TestSearchFormat(c *C) {
   174  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   175  	bs, err := asserts.OpenFSBackstore(topDir)
   176  	c.Assert(err, IsNil)
   177  
   178  	af0, err := asserts.Decode([]byte("type: test-only-2\n" +
   179  		"authority-id: auth-id1\n" +
   180  		"pk1: foo\n" +
   181  		"pk2: bar\n" +
   182  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   183  		"\n\n" +
   184  		"AXNpZw=="))
   185  	c.Assert(err, IsNil)
   186  	af1, err := asserts.Decode([]byte("type: test-only-2\n" +
   187  		"authority-id: auth-id1\n" +
   188  		"pk1: foo\n" +
   189  		"pk2: bar\n" +
   190  		"format: 1\n" +
   191  		"revision: 1\n" +
   192  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   193  		"\n\n" +
   194  		"AXNpZw=="))
   195  	c.Assert(err, IsNil)
   196  
   197  	af2, err := asserts.Decode([]byte("type: test-only-2\n" +
   198  		"authority-id: auth-id1\n" +
   199  		"pk1: foo\n" +
   200  		"pk2: baz\n" +
   201  		"format: 2\n" +
   202  		"revision: 1\n" +
   203  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   204  		"\n\n" +
   205  		"AXNpZw=="))
   206  	c.Assert(err, IsNil)
   207  
   208  	err = bs.Put(asserts.TestOnly2Type, af0)
   209  	c.Assert(err, IsNil)
   210  
   211  	queries := []map[string]string{
   212  		{"pk1": "foo", "pk2": "bar"},
   213  		{"pk1": "foo"},
   214  		{"pk2": "bar"},
   215  	}
   216  
   217  	for _, q := range queries {
   218  		var a asserts.Assertion
   219  		foundCb := func(a1 asserts.Assertion) {
   220  			a = a1
   221  		}
   222  		err := bs.Search(asserts.TestOnly2Type, q, foundCb, 1)
   223  		c.Assert(err, IsNil)
   224  		c.Check(a.Revision(), Equals, 0)
   225  	}
   226  
   227  	err = bs.Put(asserts.TestOnly2Type, af1)
   228  	c.Assert(err, IsNil)
   229  
   230  	for _, q := range queries {
   231  		var a asserts.Assertion
   232  		foundCb := func(a1 asserts.Assertion) {
   233  			a = a1
   234  		}
   235  		err := bs.Search(asserts.TestOnly2Type, q, foundCb, 1)
   236  		c.Assert(err, IsNil)
   237  		c.Check(a.Revision(), Equals, 1)
   238  
   239  		err = bs.Search(asserts.TestOnly2Type, q, foundCb, 0)
   240  		c.Assert(err, IsNil)
   241  		c.Check(a.Revision(), Equals, 0)
   242  	}
   243  
   244  	err = bs.Put(asserts.TestOnly2Type, af2)
   245  	c.Assert(err, IsNil)
   246  
   247  	var as []asserts.Assertion
   248  	foundCb := func(a1 asserts.Assertion) {
   249  		as = append(as, a1)
   250  	}
   251  	err = bs.Search(asserts.TestOnly2Type, map[string]string{
   252  		"pk1": "foo",
   253  	}, foundCb, 1) // will not find af2
   254  	c.Assert(err, IsNil)
   255  	c.Check(as, HasLen, 1)
   256  	c.Check(as[0].Revision(), Equals, 1)
   257  
   258  }
   259  
   260  func (fsbss *fsBackstoreSuite) TestSequenceMemberAfter(c *C) {
   261  	topDir := filepath.Join(c.MkDir(), "asserts-db")
   262  	bs, err := asserts.OpenFSBackstore(topDir)
   263  	c.Assert(err, IsNil)
   264  
   265  	other1, err := asserts.Decode([]byte("type: test-only-seq\n" +
   266  		"authority-id: auth-id1\n" +
   267  		"n: other\n" +
   268  		"sequence: 1\n" +
   269  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   270  		"\n\n" +
   271  		"AXNpZw=="))
   272  	c.Assert(err, IsNil)
   273  
   274  	sq1f0, err := asserts.Decode([]byte("type: test-only-seq\n" +
   275  		"authority-id: auth-id1\n" +
   276  		"n: s1\n" +
   277  		"sequence: 1\n" +
   278  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   279  		"\n\n" +
   280  		"AXNpZw=="))
   281  	c.Assert(err, IsNil)
   282  
   283  	sq2f0, err := asserts.Decode([]byte("type: test-only-seq\n" +
   284  		"authority-id: auth-id1\n" +
   285  		"n: s1\n" +
   286  		"sequence: 2\n" +
   287  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   288  		"\n\n" +
   289  		"AXNpZw=="))
   290  	c.Assert(err, IsNil)
   291  
   292  	sq2f1, err := asserts.Decode([]byte("type: test-only-seq\n" +
   293  		"authority-id: auth-id1\n" +
   294  		"format: 1\n" +
   295  		"n: s1\n" +
   296  		"sequence: 2\n" +
   297  		"revision: 1\n" +
   298  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   299  		"\n\n" +
   300  		"AXNpZw=="))
   301  	c.Assert(err, IsNil)
   302  
   303  	sq3f1, err := asserts.Decode([]byte("type: test-only-seq\n" +
   304  		"authority-id: auth-id1\n" +
   305  		"format: 1\n" +
   306  		"n: s1\n" +
   307  		"sequence: 3\n" +
   308  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   309  		"\n\n" +
   310  		"AXNpZw=="))
   311  	c.Assert(err, IsNil)
   312  
   313  	sq3f2, err := asserts.Decode([]byte("type: test-only-seq\n" +
   314  		"authority-id: auth-id1\n" +
   315  		"format: 2\n" +
   316  		"n: s1\n" +
   317  		"sequence: 3\n" +
   318  		"revision: 1\n" +
   319  		"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
   320  		"\n\n" +
   321  		"AXNpZw=="))
   322  	c.Assert(err, IsNil)
   323  
   324  	for _, a := range []asserts.Assertion{other1, sq1f0, sq2f0, sq2f1, sq3f1, sq3f2} {
   325  		err = bs.Put(asserts.TestOnlySeqType, a)
   326  		c.Assert(err, IsNil)
   327  	}
   328  
   329  	seqKey := []string{"s1"}
   330  	tests := []struct {
   331  		after     int
   332  		maxFormat int
   333  		sequence  int
   334  		format    int
   335  		revision  int
   336  	}{
   337  		{after: 0, maxFormat: 0, sequence: 1, format: 0, revision: 0},
   338  		{after: 0, maxFormat: 2, sequence: 1, format: 0, revision: 0},
   339  		{after: 1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
   340  		{after: 1, maxFormat: 1, sequence: 2, format: 1, revision: 1},
   341  		{after: 1, maxFormat: 2, sequence: 2, format: 1, revision: 1},
   342  		{after: 2, maxFormat: 0, sequence: -1},
   343  		{after: 2, maxFormat: 1, sequence: 3, format: 1, revision: 0},
   344  		{after: 2, maxFormat: 2, sequence: 3, format: 2, revision: 1},
   345  		{after: 3, maxFormat: 0, sequence: -1},
   346  		{after: 3, maxFormat: 2, sequence: -1},
   347  		{after: 4, maxFormat: 2, sequence: -1},
   348  		{after: -1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
   349  		{after: -1, maxFormat: 1, sequence: 3, format: 1, revision: 0},
   350  		{after: -1, maxFormat: 2, sequence: 3, format: 2, revision: 1},
   351  	}
   352  
   353  	for _, t := range tests {
   354  		a, err := bs.SequenceMemberAfter(asserts.TestOnlySeqType, seqKey, t.after, t.maxFormat)
   355  		if t.sequence == -1 {
   356  			c.Check(err, DeepEquals, &asserts.NotFoundError{
   357  				Type: asserts.TestOnlySeqType,
   358  			})
   359  		} else {
   360  			c.Assert(err, IsNil)
   361  			c.Assert(a.HeaderString("n"), Equals, "s1")
   362  			c.Check(a.Sequence(), Equals, t.sequence)
   363  			c.Check(a.Format(), Equals, t.format)
   364  			c.Check(a.Revision(), Equals, t.revision)
   365  		}
   366  	}
   367  
   368  	_, err = bs.SequenceMemberAfter(asserts.TestOnlySeqType, []string{"s2"}, -1, 2)
   369  	c.Check(err, DeepEquals, &asserts.NotFoundError{
   370  		Type: asserts.TestOnlySeqType,
   371  	})
   372  }