github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/overlord/assertstate/assertstate_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 assertstate_test
    21  
    22  import (
    23  	"bytes"
    24  	"context"
    25  	"crypto"
    26  	"errors"
    27  	"fmt"
    28  	"io/ioutil"
    29  	"path/filepath"
    30  	"sort"
    31  	"strings"
    32  	"testing"
    33  	"time"
    34  
    35  	"golang.org/x/crypto/sha3"
    36  
    37  	. "gopkg.in/check.v1"
    38  
    39  	"github.com/snapcore/snapd/asserts"
    40  	"github.com/snapcore/snapd/asserts/assertstest"
    41  	"github.com/snapcore/snapd/asserts/sysdb"
    42  	"github.com/snapcore/snapd/dirs"
    43  	"github.com/snapcore/snapd/httputil"
    44  	"github.com/snapcore/snapd/logger"
    45  	"github.com/snapcore/snapd/overlord"
    46  	"github.com/snapcore/snapd/overlord/assertstate"
    47  	"github.com/snapcore/snapd/overlord/auth"
    48  	"github.com/snapcore/snapd/overlord/snapstate"
    49  	"github.com/snapcore/snapd/overlord/snapstate/snapstatetest"
    50  	"github.com/snapcore/snapd/overlord/state"
    51  	"github.com/snapcore/snapd/snap"
    52  	"github.com/snapcore/snapd/snap/snaptest"
    53  	"github.com/snapcore/snapd/store"
    54  	"github.com/snapcore/snapd/store/storetest"
    55  	"github.com/snapcore/snapd/testutil"
    56  )
    57  
    58  func TestAssertManager(t *testing.T) { TestingT(t) }
    59  
    60  type assertMgrSuite struct {
    61  	testutil.BaseTest
    62  
    63  	o     *overlord.Overlord
    64  	state *state.State
    65  	se    *overlord.StateEngine
    66  	mgr   *assertstate.AssertManager
    67  
    68  	storeSigning *assertstest.StoreStack
    69  	dev1Acct     *asserts.Account
    70  	dev1Signing  *assertstest.SigningDB
    71  
    72  	fakeStore        snapstate.StoreService
    73  	trivialDeviceCtx snapstate.DeviceContext
    74  }
    75  
    76  var _ = Suite(&assertMgrSuite{})
    77  
    78  type fakeStore struct {
    79  	storetest.Store
    80  	state                  *state.State
    81  	db                     asserts.RODatabase
    82  	maxDeclSupportedFormat int
    83  
    84  	requestedTypes [][]string
    85  
    86  	snapActionErr         error
    87  	downloadAssertionsErr error
    88  }
    89  
    90  func (sto *fakeStore) pokeStateLock() {
    91  	// the store should be called without the state lock held. Try
    92  	// to acquire it.
    93  	sto.state.Lock()
    94  	sto.state.Unlock()
    95  }
    96  
    97  func (sto *fakeStore) Assertion(assertType *asserts.AssertionType, key []string, _ *auth.UserState) (asserts.Assertion, error) {
    98  	sto.pokeStateLock()
    99  
   100  	restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat)
   101  	defer restore()
   102  
   103  	ref := &asserts.Ref{Type: assertType, PrimaryKey: key}
   104  	return ref.Resolve(sto.db.Find)
   105  }
   106  
   107  func (sto *fakeStore) SnapAction(_ context.Context, currentSnaps []*store.CurrentSnap, actions []*store.SnapAction, assertQuery store.AssertionQuery, user *auth.UserState, opts *store.RefreshOptions) ([]store.SnapActionResult, []store.AssertionResult, error) {
   108  	sto.pokeStateLock()
   109  
   110  	if len(currentSnaps) != 0 || len(actions) != 0 {
   111  		panic("only assertion query supported")
   112  	}
   113  
   114  	toResolve, err := assertQuery.ToResolve()
   115  	if err != nil {
   116  		return nil, nil, err
   117  	}
   118  
   119  	if sto.snapActionErr != nil {
   120  		return nil, nil, sto.snapActionErr
   121  	}
   122  
   123  	restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat)
   124  	defer restore()
   125  
   126  	reqTypes := make(map[string]bool)
   127  	ares := make([]store.AssertionResult, 0, len(toResolve))
   128  	for g, ats := range toResolve {
   129  		urls := make([]string, 0, len(ats))
   130  		for _, at := range ats {
   131  			reqTypes[at.Ref.Type.Name] = true
   132  			a, err := at.Ref.Resolve(sto.db.Find)
   133  			if err != nil {
   134  				assertQuery.AddError(err, &at.Ref)
   135  				continue
   136  			}
   137  			if a.Revision() > at.Revision {
   138  				urls = append(urls, fmt.Sprintf("/assertions/%s", at.Unique()))
   139  			}
   140  		}
   141  		ares = append(ares, store.AssertionResult{
   142  			Grouping:   asserts.Grouping(g),
   143  			StreamURLs: urls,
   144  		})
   145  	}
   146  	// behave like the actual SnapAction if there are no results
   147  	if len(ares) == 0 {
   148  		return nil, ares, &store.SnapActionError{
   149  			NoResults: true,
   150  		}
   151  	}
   152  
   153  	typeNames := make([]string, 0, len(reqTypes))
   154  	for k := range reqTypes {
   155  		typeNames = append(typeNames, k)
   156  	}
   157  	sort.Strings(typeNames)
   158  	sto.requestedTypes = append(sto.requestedTypes, typeNames)
   159  
   160  	return nil, ares, nil
   161  }
   162  
   163  func (sto *fakeStore) DownloadAssertions(urls []string, b *asserts.Batch, user *auth.UserState) error {
   164  	sto.pokeStateLock()
   165  
   166  	if sto.downloadAssertionsErr != nil {
   167  		return sto.downloadAssertionsErr
   168  	}
   169  
   170  	resolve := func(ref *asserts.Ref) (asserts.Assertion, error) {
   171  		restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat)
   172  		defer restore()
   173  		return ref.Resolve(sto.db.Find)
   174  	}
   175  
   176  	for _, u := range urls {
   177  		comps := strings.Split(u, "/")
   178  
   179  		if len(comps) < 4 {
   180  			return fmt.Errorf("cannot use URL: %s", u)
   181  		}
   182  
   183  		assertType := asserts.Type(comps[2])
   184  		key := comps[3:]
   185  		ref := &asserts.Ref{Type: assertType, PrimaryKey: key}
   186  		a, err := resolve(ref)
   187  		if err != nil {
   188  			return err
   189  		}
   190  		if err := b.Add(a); err != nil {
   191  			return err
   192  		}
   193  	}
   194  
   195  	return nil
   196  }
   197  
   198  var (
   199  	dev1PrivKey, _ = assertstest.GenerateKey(752)
   200  )
   201  
   202  func (s *assertMgrSuite) SetUpTest(c *C) {
   203  	dirs.SetRootDir(c.MkDir())
   204  
   205  	s.storeSigning = assertstest.NewStoreStack("can0nical", nil)
   206  	s.AddCleanup(sysdb.InjectTrusted(s.storeSigning.Trusted))
   207  
   208  	s.dev1Acct = assertstest.NewAccount(s.storeSigning, "developer1", nil, "")
   209  	err := s.storeSigning.Add(s.dev1Acct)
   210  	c.Assert(err, IsNil)
   211  
   212  	// developer signing
   213  	dev1AcctKey := assertstest.NewAccountKey(s.storeSigning, s.dev1Acct, nil, dev1PrivKey.PublicKey(), "")
   214  	err = s.storeSigning.Add(dev1AcctKey)
   215  	c.Assert(err, IsNil)
   216  
   217  	s.dev1Signing = assertstest.NewSigningDB(s.dev1Acct.AccountID(), dev1PrivKey)
   218  
   219  	s.o = overlord.Mock()
   220  	s.state = s.o.State()
   221  	s.se = s.o.StateEngine()
   222  	mgr, err := assertstate.Manager(s.state, s.o.TaskRunner())
   223  	c.Assert(err, IsNil)
   224  	s.mgr = mgr
   225  	s.o.AddManager(s.mgr)
   226  
   227  	s.o.AddManager(s.o.TaskRunner())
   228  
   229  	s.fakeStore = &fakeStore{
   230  		state: s.state,
   231  		db:    s.storeSigning,
   232  		maxDeclSupportedFormat: asserts.SnapDeclarationType.MaxSupportedFormat(),
   233  	}
   234  	s.trivialDeviceCtx = &snapstatetest.TrivialDeviceContext{
   235  		CtxStore: s.fakeStore,
   236  	}
   237  }
   238  
   239  func (s *assertMgrSuite) TestDB(c *C) {
   240  	s.state.Lock()
   241  	defer s.state.Unlock()
   242  
   243  	db := assertstate.DB(s.state)
   244  	c.Check(db, FitsTypeOf, (*asserts.Database)(nil))
   245  }
   246  
   247  func (s *assertMgrSuite) TestAdd(c *C) {
   248  	s.state.Lock()
   249  	defer s.state.Unlock()
   250  
   251  	// prereq store key
   252  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   253  	c.Assert(err, IsNil)
   254  
   255  	err = assertstate.Add(s.state, s.dev1Acct)
   256  	c.Assert(err, IsNil)
   257  
   258  	db := assertstate.DB(s.state)
   259  	devAcct, err := db.Find(asserts.AccountType, map[string]string{
   260  		"account-id": s.dev1Acct.AccountID(),
   261  	})
   262  	c.Assert(err, IsNil)
   263  	c.Check(devAcct.(*asserts.Account).Username(), Equals, "developer1")
   264  }
   265  
   266  func (s *assertMgrSuite) TestAddBatch(c *C) {
   267  	s.state.Lock()
   268  	defer s.state.Unlock()
   269  
   270  	b := &bytes.Buffer{}
   271  	enc := asserts.NewEncoder(b)
   272  	// wrong order is ok
   273  	err := enc.Encode(s.dev1Acct)
   274  	c.Assert(err, IsNil)
   275  	enc.Encode(s.storeSigning.StoreAccountKey(""))
   276  	c.Assert(err, IsNil)
   277  
   278  	batch := asserts.NewBatch(nil)
   279  	refs, err := batch.AddStream(b)
   280  	c.Assert(err, IsNil)
   281  	c.Check(refs, DeepEquals, []*asserts.Ref{
   282  		{Type: asserts.AccountType, PrimaryKey: []string{s.dev1Acct.AccountID()}},
   283  		{Type: asserts.AccountKeyType, PrimaryKey: []string{s.storeSigning.StoreAccountKey("").PublicKeyID()}},
   284  	})
   285  
   286  	// noop
   287  	err = batch.Add(s.storeSigning.StoreAccountKey(""))
   288  	c.Assert(err, IsNil)
   289  
   290  	err = assertstate.AddBatch(s.state, batch, nil)
   291  	c.Assert(err, IsNil)
   292  
   293  	db := assertstate.DB(s.state)
   294  	devAcct, err := db.Find(asserts.AccountType, map[string]string{
   295  		"account-id": s.dev1Acct.AccountID(),
   296  	})
   297  	c.Assert(err, IsNil)
   298  	c.Check(devAcct.(*asserts.Account).Username(), Equals, "developer1")
   299  }
   300  
   301  func (s *assertMgrSuite) TestAddBatchPartial(c *C) {
   302  	// Commit does add any successful assertion until the first error
   303  	s.state.Lock()
   304  	defer s.state.Unlock()
   305  
   306  	// store key already present
   307  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   308  	c.Assert(err, IsNil)
   309  
   310  	batch := asserts.NewBatch(nil)
   311  
   312  	snapDeclFoo := s.snapDecl(c, "foo", nil)
   313  
   314  	err = batch.Add(snapDeclFoo)
   315  	c.Assert(err, IsNil)
   316  	err = batch.Add(s.dev1Acct)
   317  	c.Assert(err, IsNil)
   318  
   319  	// too old
   320  	rev := 1
   321  	headers := map[string]interface{}{
   322  		"snap-id":       "foo-id",
   323  		"snap-sha3-384": makeDigest(rev),
   324  		"snap-size":     fmt.Sprintf("%d", len(fakeSnap(rev))),
   325  		"snap-revision": fmt.Sprintf("%d", rev),
   326  		"developer-id":  s.dev1Acct.AccountID(),
   327  		"timestamp":     time.Time{}.Format(time.RFC3339),
   328  	}
   329  	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
   330  	c.Assert(err, IsNil)
   331  
   332  	err = batch.Add(snapRev)
   333  	c.Assert(err, IsNil)
   334  
   335  	err = assertstate.AddBatch(s.state, batch, nil)
   336  	c.Check(err, ErrorMatches, `(?ms).*validity.*`)
   337  
   338  	// snap-declaration was added anyway
   339  	_, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
   340  		"series":  "16",
   341  		"snap-id": "foo-id",
   342  	})
   343  	c.Assert(err, IsNil)
   344  }
   345  
   346  func (s *assertMgrSuite) TestAddBatchPrecheckPartial(c *C) {
   347  	s.state.Lock()
   348  	defer s.state.Unlock()
   349  
   350  	// store key already present
   351  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   352  	c.Assert(err, IsNil)
   353  
   354  	batch := asserts.NewBatch(nil)
   355  
   356  	snapDeclFoo := s.snapDecl(c, "foo", nil)
   357  
   358  	err = batch.Add(snapDeclFoo)
   359  	c.Assert(err, IsNil)
   360  	err = batch.Add(s.dev1Acct)
   361  	c.Assert(err, IsNil)
   362  
   363  	// too old
   364  	rev := 1
   365  	headers := map[string]interface{}{
   366  		"snap-id":       "foo-id",
   367  		"snap-sha3-384": makeDigest(rev),
   368  		"snap-size":     fmt.Sprintf("%d", len(fakeSnap(rev))),
   369  		"snap-revision": fmt.Sprintf("%d", rev),
   370  		"developer-id":  s.dev1Acct.AccountID(),
   371  		"timestamp":     time.Time{}.Format(time.RFC3339),
   372  	}
   373  	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
   374  	c.Assert(err, IsNil)
   375  
   376  	err = batch.Add(snapRev)
   377  	c.Assert(err, IsNil)
   378  
   379  	err = assertstate.AddBatch(s.state, batch, &asserts.CommitOptions{
   380  		Precheck: true,
   381  	})
   382  	c.Check(err, ErrorMatches, `(?ms).*validity.*`)
   383  
   384  	// nothing was added
   385  	_, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
   386  		"series":  "16",
   387  		"snap-id": "foo-id",
   388  	})
   389  	c.Assert(asserts.IsNotFound(err), Equals, true)
   390  }
   391  
   392  func (s *assertMgrSuite) TestAddBatchPrecheckHappy(c *C) {
   393  	s.state.Lock()
   394  	defer s.state.Unlock()
   395  
   396  	// store key already present
   397  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   398  	c.Assert(err, IsNil)
   399  
   400  	batch := asserts.NewBatch(nil)
   401  
   402  	snapDeclFoo := s.snapDecl(c, "foo", nil)
   403  
   404  	err = batch.Add(snapDeclFoo)
   405  	c.Assert(err, IsNil)
   406  	err = batch.Add(s.dev1Acct)
   407  	c.Assert(err, IsNil)
   408  
   409  	rev := 1
   410  	revDigest := makeDigest(rev)
   411  	headers := map[string]interface{}{
   412  		"snap-id":       "foo-id",
   413  		"snap-sha3-384": revDigest,
   414  		"snap-size":     fmt.Sprintf("%d", len(fakeSnap(rev))),
   415  		"snap-revision": fmt.Sprintf("%d", rev),
   416  		"developer-id":  s.dev1Acct.AccountID(),
   417  		"timestamp":     time.Now().Format(time.RFC3339),
   418  	}
   419  	snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
   420  	c.Assert(err, IsNil)
   421  
   422  	err = batch.Add(snapRev)
   423  	c.Assert(err, IsNil)
   424  
   425  	err = assertstate.AddBatch(s.state, batch, &asserts.CommitOptions{
   426  		Precheck: true,
   427  	})
   428  	c.Assert(err, IsNil)
   429  
   430  	_, err = assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{
   431  		"snap-sha3-384": revDigest,
   432  	})
   433  	c.Check(err, IsNil)
   434  }
   435  
   436  func fakeSnap(rev int) []byte {
   437  	fake := fmt.Sprintf("hsqs________________%d", rev)
   438  	return []byte(fake)
   439  }
   440  
   441  func fakeHash(rev int) []byte {
   442  	h := sha3.Sum384(fakeSnap(rev))
   443  	return h[:]
   444  }
   445  
   446  func makeDigest(rev int) string {
   447  	d, err := asserts.EncodeDigest(crypto.SHA3_384, fakeHash(rev))
   448  	if err != nil {
   449  		panic(err)
   450  	}
   451  	return string(d)
   452  }
   453  
   454  func (s *assertMgrSuite) prereqSnapAssertions(c *C, revisions ...int) {
   455  	headers := map[string]interface{}{
   456  		"series":       "16",
   457  		"snap-id":      "snap-id-1",
   458  		"snap-name":    "foo",
   459  		"publisher-id": s.dev1Acct.AccountID(),
   460  		"timestamp":    time.Now().Format(time.RFC3339),
   461  	}
   462  	snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
   463  	c.Assert(err, IsNil)
   464  	err = s.storeSigning.Add(snapDecl)
   465  	c.Assert(err, IsNil)
   466  
   467  	for _, rev := range revisions {
   468  		headers = map[string]interface{}{
   469  			"snap-id":       "snap-id-1",
   470  			"snap-sha3-384": makeDigest(rev),
   471  			"snap-size":     fmt.Sprintf("%d", len(fakeSnap(rev))),
   472  			"snap-revision": fmt.Sprintf("%d", rev),
   473  			"developer-id":  s.dev1Acct.AccountID(),
   474  			"timestamp":     time.Now().Format(time.RFC3339),
   475  		}
   476  		snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "")
   477  		c.Assert(err, IsNil)
   478  		err = s.storeSigning.Add(snapRev)
   479  		c.Assert(err, IsNil)
   480  	}
   481  }
   482  
   483  func (s *assertMgrSuite) TestDoFetch(c *C) {
   484  	s.prereqSnapAssertions(c, 10)
   485  
   486  	s.state.Lock()
   487  	defer s.state.Unlock()
   488  
   489  	ref := &asserts.Ref{
   490  		Type:       asserts.SnapRevisionType,
   491  		PrimaryKey: []string{makeDigest(10)},
   492  	}
   493  
   494  	err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, func(f asserts.Fetcher) error {
   495  		return f.Fetch(ref)
   496  	})
   497  	c.Assert(err, IsNil)
   498  
   499  	snapRev, err := ref.Resolve(assertstate.DB(s.state).Find)
   500  	c.Assert(err, IsNil)
   501  	c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10)
   502  }
   503  
   504  func (s *assertMgrSuite) TestFetchIdempotent(c *C) {
   505  	s.prereqSnapAssertions(c, 10, 11)
   506  
   507  	s.state.Lock()
   508  	defer s.state.Unlock()
   509  
   510  	ref := &asserts.Ref{
   511  		Type:       asserts.SnapRevisionType,
   512  		PrimaryKey: []string{makeDigest(10)},
   513  	}
   514  	fetching := func(f asserts.Fetcher) error {
   515  		return f.Fetch(ref)
   516  	}
   517  
   518  	err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching)
   519  	c.Assert(err, IsNil)
   520  
   521  	ref = &asserts.Ref{
   522  		Type:       asserts.SnapRevisionType,
   523  		PrimaryKey: []string{makeDigest(11)},
   524  	}
   525  
   526  	err = assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching)
   527  	c.Assert(err, IsNil)
   528  
   529  	snapRev, err := ref.Resolve(assertstate.DB(s.state).Find)
   530  	c.Assert(err, IsNil)
   531  	c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 11)
   532  }
   533  
   534  func (s *assertMgrSuite) settle(c *C) {
   535  	err := s.o.Settle(5 * time.Second)
   536  	c.Assert(err, IsNil)
   537  }
   538  
   539  func (s *assertMgrSuite) TestFetchUnsupportedUpdateIgnored(c *C) {
   540  	// ATM in principle we ignore updated assertions with unsupported formats
   541  	// NB: this scenario can only happen if there is a bug
   542  	// we ask the store to filter what is returned by max supported format!
   543  	restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 111)
   544  	defer restore()
   545  
   546  	logbuf, restore := logger.MockLogger()
   547  	defer restore()
   548  
   549  	snapDeclFoo0 := s.snapDecl(c, "foo", nil)
   550  
   551  	s.state.Lock()
   552  	defer s.state.Unlock()
   553  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   554  	c.Assert(err, IsNil)
   555  
   556  	err = assertstate.Add(s.state, s.dev1Acct)
   557  	c.Assert(err, IsNil)
   558  	err = assertstate.Add(s.state, snapDeclFoo0)
   559  	c.Assert(err, IsNil)
   560  
   561  	var snapDeclFoo1 *asserts.SnapDeclaration
   562  	(func() {
   563  		restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999)
   564  		defer restore()
   565  		snapDeclFoo1 = s.snapDecl(c, "foo", map[string]interface{}{
   566  			"format":   "999",
   567  			"revision": "1",
   568  		})
   569  	})()
   570  	c.Check(snapDeclFoo1.Revision(), Equals, 1)
   571  
   572  	ref := &asserts.Ref{
   573  		Type:       asserts.SnapDeclarationType,
   574  		PrimaryKey: []string{"16", "foo-id"},
   575  	}
   576  	fetching := func(f asserts.Fetcher) error {
   577  		return f.Fetch(ref)
   578  	}
   579  
   580  	s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999
   581  	err = assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching)
   582  	// no error and the old one was kept
   583  	c.Assert(err, IsNil)
   584  	snapDecl, err := ref.Resolve(assertstate.DB(s.state).Find)
   585  	c.Assert(err, IsNil)
   586  	c.Check(snapDecl.Revision(), Equals, 0)
   587  
   588  	// we log the issue
   589  	c.Check(logbuf.String(), testutil.Contains, `Cannot update assertion snap-declaration (foo-id;`)
   590  }
   591  
   592  func (s *assertMgrSuite) TestFetchUnsupportedError(c *C) {
   593  	// NB: this scenario can only happen if there is a bug
   594  	// we ask the store to filter what is returned by max supported format!
   595  
   596  	restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 111)
   597  	defer restore()
   598  
   599  	s.state.Lock()
   600  	defer s.state.Unlock()
   601  
   602  	var snapDeclFoo1 *asserts.SnapDeclaration
   603  	(func() {
   604  		restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999)
   605  		defer restore()
   606  		snapDeclFoo1 = s.snapDecl(c, "foo", map[string]interface{}{
   607  			"format":   "999",
   608  			"revision": "1",
   609  		})
   610  	})()
   611  	c.Check(snapDeclFoo1.Revision(), Equals, 1)
   612  
   613  	ref := &asserts.Ref{
   614  		Type:       asserts.SnapDeclarationType,
   615  		PrimaryKey: []string{"16", "foo-id"},
   616  	}
   617  	fetching := func(f asserts.Fetcher) error {
   618  		return f.Fetch(ref)
   619  	}
   620  
   621  	s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999
   622  	err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching)
   623  	c.Check(err, ErrorMatches, `(?s).*proposed "snap-declaration" assertion has format 999 but 111 is latest supported.*`)
   624  }
   625  
   626  func (s *assertMgrSuite) setModel(model *asserts.Model) {
   627  	deviceCtx := &snapstatetest.TrivialDeviceContext{
   628  		DeviceModel: model,
   629  		CtxStore:    s.fakeStore,
   630  	}
   631  	s.AddCleanup(snapstatetest.MockDeviceContext(deviceCtx))
   632  	s.state.Set("seeded", true)
   633  }
   634  
   635  func (s *assertMgrSuite) setupModelAndStore(c *C) *asserts.Store {
   636  	// setup a model and store assertion
   637  	a := assertstest.FakeAssertion(map[string]interface{}{
   638  		"type":         "model",
   639  		"authority-id": "my-brand",
   640  		"series":       "16",
   641  		"brand-id":     "my-brand",
   642  		"model":        "my-model",
   643  		"architecture": "amd64",
   644  		"store":        "my-brand-store",
   645  		"gadget":       "gadget",
   646  		"kernel":       "krnl",
   647  	})
   648  	s.setModel(a.(*asserts.Model))
   649  
   650  	a, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{
   651  		"authority-id": s.storeSigning.AuthorityID,
   652  		"operator-id":  s.storeSigning.AuthorityID,
   653  		"store":        "my-brand-store",
   654  		"timestamp":    time.Now().Format(time.RFC3339),
   655  	}, nil, "")
   656  	c.Assert(err, IsNil)
   657  	return a.(*asserts.Store)
   658  }
   659  
   660  func (s *assertMgrSuite) TestValidateSnap(c *C) {
   661  	s.prereqSnapAssertions(c, 10)
   662  
   663  	tempdir := c.MkDir()
   664  	snapPath := filepath.Join(tempdir, "foo.snap")
   665  	err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644)
   666  	c.Assert(err, IsNil)
   667  
   668  	s.state.Lock()
   669  	defer s.state.Unlock()
   670  
   671  	// have a model and the store assertion available
   672  	storeAs := s.setupModelAndStore(c)
   673  	err = s.storeSigning.Add(storeAs)
   674  	c.Assert(err, IsNil)
   675  
   676  	chg := s.state.NewChange("install", "...")
   677  	t := s.state.NewTask("validate-snap", "Fetch and check snap assertions")
   678  	snapsup := snapstate.SnapSetup{
   679  		SnapPath: snapPath,
   680  		UserID:   0,
   681  		SideInfo: &snap.SideInfo{
   682  			RealName: "foo",
   683  			SnapID:   "snap-id-1",
   684  			Revision: snap.R(10),
   685  		},
   686  	}
   687  	t.Set("snap-setup", snapsup)
   688  	chg.AddTask(t)
   689  
   690  	s.state.Unlock()
   691  	defer s.se.Stop()
   692  	s.settle(c)
   693  	s.state.Lock()
   694  
   695  	c.Assert(chg.Err(), IsNil)
   696  
   697  	snapRev, err := assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{
   698  		"snap-id":       "snap-id-1",
   699  		"snap-sha3-384": makeDigest(10),
   700  	})
   701  	c.Assert(err, IsNil)
   702  	c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10)
   703  
   704  	// store assertion was also fetched
   705  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
   706  		"store": "my-brand-store",
   707  	})
   708  	c.Assert(err, IsNil)
   709  }
   710  
   711  func (s *assertMgrSuite) TestValidateSnapStoreNotFound(c *C) {
   712  	s.prereqSnapAssertions(c, 10)
   713  
   714  	tempdir := c.MkDir()
   715  	snapPath := filepath.Join(tempdir, "foo.snap")
   716  	err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644)
   717  	c.Assert(err, IsNil)
   718  
   719  	s.state.Lock()
   720  	defer s.state.Unlock()
   721  
   722  	// have a model and store but store assertion is not made available
   723  	s.setupModelAndStore(c)
   724  
   725  	chg := s.state.NewChange("install", "...")
   726  	t := s.state.NewTask("validate-snap", "Fetch and check snap assertions")
   727  	snapsup := snapstate.SnapSetup{
   728  		SnapPath: snapPath,
   729  		UserID:   0,
   730  		SideInfo: &snap.SideInfo{
   731  			RealName: "foo",
   732  			SnapID:   "snap-id-1",
   733  			Revision: snap.R(10),
   734  		},
   735  	}
   736  	t.Set("snap-setup", snapsup)
   737  	chg.AddTask(t)
   738  
   739  	s.state.Unlock()
   740  	defer s.se.Stop()
   741  	s.settle(c)
   742  	s.state.Lock()
   743  
   744  	c.Assert(chg.Err(), IsNil)
   745  
   746  	snapRev, err := assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{
   747  		"snap-id":       "snap-id-1",
   748  		"snap-sha3-384": makeDigest(10),
   749  	})
   750  	c.Assert(err, IsNil)
   751  	c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10)
   752  
   753  	// store assertion was not found and ignored
   754  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
   755  		"store": "my-brand-store",
   756  	})
   757  	c.Assert(asserts.IsNotFound(err), Equals, true)
   758  }
   759  
   760  func (s *assertMgrSuite) TestValidateSnapMissingSnapSetup(c *C) {
   761  	s.state.Lock()
   762  	defer s.state.Unlock()
   763  
   764  	chg := s.state.NewChange("install", "...")
   765  	t := s.state.NewTask("validate-snap", "Fetch and check snap assertions")
   766  	chg.AddTask(t)
   767  
   768  	s.state.Unlock()
   769  	defer s.se.Stop()
   770  	s.settle(c)
   771  	s.state.Lock()
   772  
   773  	c.Assert(chg.Err(), ErrorMatches, `(?s).*internal error: cannot obtain snap setup: no state entry for key.*`)
   774  }
   775  
   776  func (s *assertMgrSuite) TestValidateSnapNotFound(c *C) {
   777  	tempdir := c.MkDir()
   778  	snapPath := filepath.Join(tempdir, "foo.snap")
   779  	err := ioutil.WriteFile(snapPath, fakeSnap(33), 0644)
   780  	c.Assert(err, IsNil)
   781  
   782  	s.state.Lock()
   783  	defer s.state.Unlock()
   784  
   785  	s.setModel(sysdb.GenericClassicModel())
   786  
   787  	chg := s.state.NewChange("install", "...")
   788  	t := s.state.NewTask("validate-snap", "Fetch and check snap assertions")
   789  	snapsup := snapstate.SnapSetup{
   790  		SnapPath: snapPath,
   791  		UserID:   0,
   792  		SideInfo: &snap.SideInfo{
   793  			RealName: "foo",
   794  			SnapID:   "snap-id-1",
   795  			Revision: snap.R(33),
   796  		},
   797  	}
   798  	t.Set("snap-setup", snapsup)
   799  	chg.AddTask(t)
   800  
   801  	s.state.Unlock()
   802  	defer s.se.Stop()
   803  	s.settle(c)
   804  	s.state.Lock()
   805  
   806  	c.Assert(chg.Err(), ErrorMatches, `(?s).*cannot verify snap "foo", no matching signatures found.*`)
   807  }
   808  
   809  func (s *assertMgrSuite) TestValidateSnapCrossCheckFail(c *C) {
   810  	s.prereqSnapAssertions(c, 10)
   811  
   812  	tempdir := c.MkDir()
   813  	snapPath := filepath.Join(tempdir, "foo.snap")
   814  	err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644)
   815  	c.Assert(err, IsNil)
   816  
   817  	s.state.Lock()
   818  	defer s.state.Unlock()
   819  
   820  	s.setModel(sysdb.GenericClassicModel())
   821  
   822  	chg := s.state.NewChange("install", "...")
   823  	t := s.state.NewTask("validate-snap", "Fetch and check snap assertions")
   824  	snapsup := snapstate.SnapSetup{
   825  		SnapPath: snapPath,
   826  		UserID:   0,
   827  		SideInfo: &snap.SideInfo{
   828  			RealName: "f",
   829  			SnapID:   "snap-id-1",
   830  			Revision: snap.R(10),
   831  		},
   832  	}
   833  	t.Set("snap-setup", snapsup)
   834  	chg.AddTask(t)
   835  
   836  	s.state.Unlock()
   837  	defer s.se.Stop()
   838  	s.settle(c)
   839  	s.state.Lock()
   840  
   841  	c.Assert(chg.Err(), ErrorMatches, `(?s).*cannot install "f", snap "f" is undergoing a rename to "foo".*`)
   842  }
   843  
   844  func (s *assertMgrSuite) snapDecl(c *C, name string, extraHeaders map[string]interface{}) *asserts.SnapDeclaration {
   845  	headers := map[string]interface{}{
   846  		"series":       "16",
   847  		"snap-id":      name + "-id",
   848  		"snap-name":    name,
   849  		"publisher-id": s.dev1Acct.AccountID(),
   850  		"timestamp":    time.Now().Format(time.RFC3339),
   851  	}
   852  	for h, v := range extraHeaders {
   853  		headers[h] = v
   854  	}
   855  	decl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
   856  	c.Assert(err, IsNil)
   857  	err = s.storeSigning.Add(decl)
   858  	c.Assert(err, IsNil)
   859  	return decl.(*asserts.SnapDeclaration)
   860  }
   861  
   862  func (s *assertMgrSuite) stateFromDecl(c *C, decl *asserts.SnapDeclaration, instanceName string, revno snap.Revision) {
   863  	snapName, instanceKey := snap.SplitInstanceName(instanceName)
   864  	if snapName == "" {
   865  		snapName = decl.SnapName()
   866  		instanceName = snapName
   867  	}
   868  
   869  	c.Assert(snapName, Equals, decl.SnapName())
   870  
   871  	snapID := decl.SnapID()
   872  	snapstate.Set(s.state, instanceName, &snapstate.SnapState{
   873  		Active: true,
   874  		Sequence: []*snap.SideInfo{
   875  			{RealName: snapName, SnapID: snapID, Revision: revno},
   876  		},
   877  		Current:     revno,
   878  		InstanceKey: instanceKey,
   879  	})
   880  }
   881  
   882  func (s *assertMgrSuite) TestRefreshSnapDeclarationsTooEarly(c *C) {
   883  	s.state.Lock()
   884  	defer s.state.Unlock()
   885  
   886  	r := snapstatetest.MockDeviceModel(nil)
   887  	defer r()
   888  
   889  	err := assertstate.RefreshSnapDeclarations(s.state, 0)
   890  	c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{})
   891  }
   892  
   893  func (s *assertMgrSuite) TestRefreshSnapDeclarationsNop(c *C) {
   894  	s.state.Lock()
   895  	defer s.state.Unlock()
   896  
   897  	s.setModel(sysdb.GenericClassicModel())
   898  
   899  	err := assertstate.RefreshSnapDeclarations(s.state, 0)
   900  	c.Assert(err, IsNil)
   901  }
   902  
   903  func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStore(c *C) {
   904  	s.state.Lock()
   905  	defer s.state.Unlock()
   906  
   907  	s.setModel(sysdb.GenericClassicModel())
   908  
   909  	snapDeclFoo := s.snapDecl(c, "foo", nil)
   910  	snapDeclBar := s.snapDecl(c, "bar", nil)
   911  
   912  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
   913  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
   914  	snapstate.Set(s.state, "local", &snapstate.SnapState{
   915  		Active: false,
   916  		Sequence: []*snap.SideInfo{
   917  			{RealName: "local", Revision: snap.R(-1)},
   918  		},
   919  		Current: snap.R(-1),
   920  	})
   921  
   922  	// previous state
   923  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
   924  	c.Assert(err, IsNil)
   925  	err = assertstate.Add(s.state, s.dev1Acct)
   926  	c.Assert(err, IsNil)
   927  	err = assertstate.Add(s.state, snapDeclFoo)
   928  	c.Assert(err, IsNil)
   929  	err = assertstate.Add(s.state, snapDeclBar)
   930  	c.Assert(err, IsNil)
   931  
   932  	// one changed assertion
   933  	headers := map[string]interface{}{
   934  		"series":       "16",
   935  		"snap-id":      "foo-id",
   936  		"snap-name":    "fo-o",
   937  		"publisher-id": s.dev1Acct.AccountID(),
   938  		"timestamp":    time.Now().Format(time.RFC3339),
   939  		"revision":     "1",
   940  	}
   941  	snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
   942  	c.Assert(err, IsNil)
   943  	err = s.storeSigning.Add(snapDeclFoo1)
   944  	c.Assert(err, IsNil)
   945  
   946  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
   947  	c.Assert(err, IsNil)
   948  
   949  	a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
   950  		"series":  "16",
   951  		"snap-id": "foo-id",
   952  	})
   953  	c.Assert(err, IsNil)
   954  	c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o")
   955  
   956  	// another one
   957  	// one changed assertion
   958  	headers = s.dev1Acct.Headers()
   959  	headers["display-name"] = "Dev 1 edited display-name"
   960  	headers["revision"] = "1"
   961  	dev1Acct1, err := s.storeSigning.Sign(asserts.AccountType, headers, nil, "")
   962  	c.Assert(err, IsNil)
   963  	err = s.storeSigning.Add(dev1Acct1)
   964  	c.Assert(err, IsNil)
   965  
   966  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
   967  	c.Assert(err, IsNil)
   968  
   969  	a, err = assertstate.DB(s.state).Find(asserts.AccountType, map[string]string{
   970  		"account-id": s.dev1Acct.AccountID(),
   971  	})
   972  	c.Assert(err, IsNil)
   973  	c.Check(a.(*asserts.Account).DisplayName(), Equals, "Dev 1 edited display-name")
   974  
   975  	// change snap decl to something that has a too new format
   976  	s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999
   977  	(func() {
   978  		restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999)
   979  		defer restore()
   980  
   981  		headers := map[string]interface{}{
   982  			"format":       "999",
   983  			"series":       "16",
   984  			"snap-id":      "foo-id",
   985  			"snap-name":    "foo",
   986  			"publisher-id": s.dev1Acct.AccountID(),
   987  			"timestamp":    time.Now().Format(time.RFC3339),
   988  			"revision":     "2",
   989  		}
   990  
   991  		snapDeclFoo2, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
   992  		c.Assert(err, IsNil)
   993  		err = s.storeSigning.Add(snapDeclFoo2)
   994  		c.Assert(err, IsNil)
   995  	})()
   996  
   997  	// no error, kept the old one
   998  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
   999  	c.Assert(err, IsNil)
  1000  
  1001  	a, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
  1002  		"series":  "16",
  1003  		"snap-id": "foo-id",
  1004  	})
  1005  	c.Assert(err, IsNil)
  1006  	c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o")
  1007  	c.Check(a.(*asserts.SnapDeclaration).Revision(), Equals, 1)
  1008  }
  1009  
  1010  func (s *assertMgrSuite) TestRefreshSnapDeclarationsChangingKey(c *C) {
  1011  	s.state.Lock()
  1012  	defer s.state.Unlock()
  1013  
  1014  	s.setModel(sysdb.GenericClassicModel())
  1015  
  1016  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1017  
  1018  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1019  
  1020  	// previous state
  1021  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1022  	c.Assert(err, IsNil)
  1023  	err = assertstate.Add(s.state, s.dev1Acct)
  1024  	c.Assert(err, IsNil)
  1025  	err = assertstate.Add(s.state, snapDeclFoo)
  1026  	c.Assert(err, IsNil)
  1027  
  1028  	storePrivKey2, _ := assertstest.GenerateKey(752)
  1029  	err = s.storeSigning.ImportKey(storePrivKey2)
  1030  	c.Assert(err, IsNil)
  1031  	storeKey2 := assertstest.NewAccountKey(s.storeSigning.RootSigning, s.storeSigning.TrustedAccount, map[string]interface{}{
  1032  		"name": "store2",
  1033  	}, storePrivKey2.PublicKey(), "")
  1034  	err = s.storeSigning.Add(storeKey2)
  1035  	c.Assert(err, IsNil)
  1036  
  1037  	// one changed assertion signed with different key
  1038  	headers := map[string]interface{}{
  1039  		"series":       "16",
  1040  		"snap-id":      "foo-id",
  1041  		"snap-name":    "foo",
  1042  		"publisher-id": s.dev1Acct.AccountID(),
  1043  		"timestamp":    time.Now().Format(time.RFC3339),
  1044  		"revision":     "1",
  1045  	}
  1046  	storeKey2ID := storePrivKey2.PublicKey().ID()
  1047  	snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, storeKey2ID)
  1048  	c.Assert(err, IsNil)
  1049  	c.Check(snapDeclFoo1.SignKeyID(), Not(Equals), snapDeclFoo.SignKeyID())
  1050  	err = s.storeSigning.Add(snapDeclFoo1)
  1051  	c.Assert(err, IsNil)
  1052  
  1053  	_, err = storeKey2.Ref().Resolve(assertstate.DB(s.state).Find)
  1054  	c.Check(asserts.IsNotFound(err), Equals, true)
  1055  
  1056  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1057  	c.Assert(err, IsNil)
  1058  
  1059  	a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
  1060  		"series":  "16",
  1061  		"snap-id": "foo-id",
  1062  	})
  1063  	c.Assert(err, IsNil)
  1064  	c.Check(a.Revision(), Equals, 1)
  1065  	c.Check(a.SignKeyID(), Equals, storeKey2ID)
  1066  
  1067  	// key was fetched as well
  1068  	_, err = storeKey2.Ref().Resolve(assertstate.DB(s.state).Find)
  1069  	c.Check(err, IsNil)
  1070  }
  1071  
  1072  func (s *assertMgrSuite) TestRefreshSnapDeclarationsWithStore(c *C) {
  1073  	s.state.Lock()
  1074  	defer s.state.Unlock()
  1075  
  1076  	storeAs := s.setupModelAndStore(c)
  1077  
  1078  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1079  
  1080  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1081  
  1082  	// previous state
  1083  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1084  	c.Assert(err, IsNil)
  1085  	err = assertstate.Add(s.state, s.dev1Acct)
  1086  	c.Assert(err, IsNil)
  1087  	err = assertstate.Add(s.state, snapDeclFoo)
  1088  	c.Assert(err, IsNil)
  1089  
  1090  	// one changed assertion
  1091  	headers := map[string]interface{}{
  1092  		"series":       "16",
  1093  		"snap-id":      "foo-id",
  1094  		"snap-name":    "fo-o",
  1095  		"publisher-id": s.dev1Acct.AccountID(),
  1096  		"timestamp":    time.Now().Format(time.RFC3339),
  1097  		"revision":     "1",
  1098  	}
  1099  	snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
  1100  	c.Assert(err, IsNil)
  1101  	err = s.storeSigning.Add(snapDeclFoo1)
  1102  	c.Assert(err, IsNil)
  1103  
  1104  	// store assertion is missing
  1105  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1106  	c.Assert(err, IsNil)
  1107  
  1108  	a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
  1109  		"series":  "16",
  1110  		"snap-id": "foo-id",
  1111  	})
  1112  	c.Assert(err, IsNil)
  1113  	c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o")
  1114  
  1115  	// changed again
  1116  	headers = map[string]interface{}{
  1117  		"series":       "16",
  1118  		"snap-id":      "foo-id",
  1119  		"snap-name":    "f-oo",
  1120  		"publisher-id": s.dev1Acct.AccountID(),
  1121  		"timestamp":    time.Now().Format(time.RFC3339),
  1122  		"revision":     "2",
  1123  	}
  1124  	snapDeclFoo2, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
  1125  	c.Assert(err, IsNil)
  1126  	err = s.storeSigning.Add(snapDeclFoo2)
  1127  	c.Assert(err, IsNil)
  1128  
  1129  	// store assertion is available
  1130  	err = s.storeSigning.Add(storeAs)
  1131  	c.Assert(err, IsNil)
  1132  
  1133  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1134  	c.Assert(err, IsNil)
  1135  
  1136  	a, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
  1137  		"series":  "16",
  1138  		"snap-id": "foo-id",
  1139  	})
  1140  	c.Assert(err, IsNil)
  1141  	c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "f-oo")
  1142  
  1143  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
  1144  		"store": "my-brand-store",
  1145  	})
  1146  	c.Assert(err, IsNil)
  1147  
  1148  	// store assertion has changed
  1149  	a, err = s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{
  1150  		"authority-id": s.storeSigning.AuthorityID,
  1151  		"operator-id":  s.storeSigning.AuthorityID,
  1152  		"store":        "my-brand-store",
  1153  		"location":     "the-cloud",
  1154  		"revision":     "1",
  1155  		"timestamp":    time.Now().Format(time.RFC3339),
  1156  	}, nil, "")
  1157  	c.Assert(err, IsNil)
  1158  	storeAs = a.(*asserts.Store)
  1159  	err = s.storeSigning.Add(storeAs)
  1160  	c.Assert(err, IsNil)
  1161  
  1162  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1163  	c.Assert(err, IsNil)
  1164  	a, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
  1165  		"store": "my-brand-store",
  1166  	})
  1167  	c.Assert(err, IsNil)
  1168  	c.Check(a.(*asserts.Store).Location(), Equals, "the-cloud")
  1169  }
  1170  
  1171  func (s *assertMgrSuite) TestRefreshSnapDeclarationsDownloadError(c *C) {
  1172  	s.state.Lock()
  1173  	defer s.state.Unlock()
  1174  
  1175  	s.setModel(sysdb.GenericClassicModel())
  1176  
  1177  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1178  
  1179  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1180  
  1181  	// previous state
  1182  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1183  	c.Assert(err, IsNil)
  1184  	err = assertstate.Add(s.state, s.dev1Acct)
  1185  	c.Assert(err, IsNil)
  1186  	err = assertstate.Add(s.state, snapDeclFoo)
  1187  	c.Assert(err, IsNil)
  1188  
  1189  	// one changed assertion
  1190  	headers := map[string]interface{}{
  1191  		"series":       "16",
  1192  		"snap-id":      "foo-id",
  1193  		"snap-name":    "fo-o",
  1194  		"publisher-id": s.dev1Acct.AccountID(),
  1195  		"timestamp":    time.Now().Format(time.RFC3339),
  1196  		"revision":     "1",
  1197  	}
  1198  	snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
  1199  	c.Assert(err, IsNil)
  1200  	err = s.storeSigning.Add(snapDeclFoo1)
  1201  	c.Assert(err, IsNil)
  1202  
  1203  	s.fakeStore.(*fakeStore).downloadAssertionsErr = errors.New("download error")
  1204  
  1205  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1206  	c.Assert(err, ErrorMatches, `cannot refresh snap-declarations for snaps:
  1207   - foo: download error`)
  1208  }
  1209  
  1210  func (s *assertMgrSuite) TestRefreshSnapDeclarationsPersistentNetworkError(c *C) {
  1211  	s.state.Lock()
  1212  	defer s.state.Unlock()
  1213  
  1214  	s.setModel(sysdb.GenericClassicModel())
  1215  
  1216  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1217  
  1218  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1219  
  1220  	// previous state
  1221  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1222  	c.Assert(err, IsNil)
  1223  	err = assertstate.Add(s.state, s.dev1Acct)
  1224  	c.Assert(err, IsNil)
  1225  	err = assertstate.Add(s.state, snapDeclFoo)
  1226  	c.Assert(err, IsNil)
  1227  
  1228  	// one changed assertion
  1229  	headers := map[string]interface{}{
  1230  		"series":       "16",
  1231  		"snap-id":      "foo-id",
  1232  		"snap-name":    "fo-o",
  1233  		"publisher-id": s.dev1Acct.AccountID(),
  1234  		"timestamp":    time.Now().Format(time.RFC3339),
  1235  		"revision":     "1",
  1236  	}
  1237  	snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
  1238  	c.Assert(err, IsNil)
  1239  	err = s.storeSigning.Add(snapDeclFoo1)
  1240  	c.Assert(err, IsNil)
  1241  
  1242  	pne := new(httputil.PersistentNetworkError)
  1243  	s.fakeStore.(*fakeStore).snapActionErr = pne
  1244  
  1245  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1246  	c.Assert(err, Equals, pne)
  1247  }
  1248  
  1249  func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStoreFallback(c *C) {
  1250  	// test that if we get a 4xx or 500 error from the store trying bulk
  1251  	// assertion refresh we fall back to the old logic
  1252  	s.fakeStore.(*fakeStore).snapActionErr = &store.UnexpectedHTTPStatusError{StatusCode: 400}
  1253  
  1254  	logbuf, restore := logger.MockLogger()
  1255  	defer restore()
  1256  
  1257  	s.TestRefreshSnapDeclarationsNoStore(c)
  1258  
  1259  	c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*HTTP status code 400.*")
  1260  }
  1261  
  1262  func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStoreFallbackUnexpectedSnapActionError(c *C) {
  1263  	// test that if we get an unexpected SnapAction error from the
  1264  	// store trying bulk assertion refresh we fall back to the old
  1265  	// logic
  1266  	s.fakeStore.(*fakeStore).snapActionErr = &store.SnapActionError{
  1267  		NoResults: true,
  1268  		Other:     []error{errors.New("unexpected error")},
  1269  	}
  1270  
  1271  	logbuf, restore := logger.MockLogger()
  1272  	defer restore()
  1273  
  1274  	s.TestRefreshSnapDeclarationsNoStore(c)
  1275  
  1276  	c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*unexpected error.*")
  1277  }
  1278  
  1279  func (s *assertMgrSuite) TestRefreshSnapDeclarationsWithStoreFallback(c *C) {
  1280  	// test that if we get a 4xx or 500 error from the store trying bulk
  1281  	// assertion refresh we fall back to the old logic
  1282  	s.fakeStore.(*fakeStore).snapActionErr = &store.UnexpectedHTTPStatusError{StatusCode: 500}
  1283  
  1284  	logbuf, restore := logger.MockLogger()
  1285  	defer restore()
  1286  
  1287  	s.TestRefreshSnapDeclarationsWithStore(c)
  1288  
  1289  	c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*HTTP status code 500.*")
  1290  }
  1291  
  1292  // the following tests cover what happens when refreshing snap-declarations
  1293  // need to support overflowing the chosen asserts.Pool maximum groups
  1294  
  1295  func (s *assertMgrSuite) testRefreshSnapDeclarationsMany(c *C, n int) error {
  1296  	// reduce maxGroups to test and stress the logic that deals
  1297  	// with overflowing it
  1298  	s.AddCleanup(assertstate.MockMaxGroups(16))
  1299  
  1300  	// previous state
  1301  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1302  	c.Assert(err, IsNil)
  1303  	err = assertstate.Add(s.state, s.dev1Acct)
  1304  	c.Assert(err, IsNil)
  1305  
  1306  	for i := 1; i <= n; i++ {
  1307  		name := fmt.Sprintf("foo%d", i)
  1308  		snapDeclFooX := s.snapDecl(c, name, nil)
  1309  
  1310  		s.stateFromDecl(c, snapDeclFooX, "", snap.R(7+i))
  1311  
  1312  		// previous state
  1313  		err = assertstate.Add(s.state, snapDeclFooX)
  1314  		c.Assert(err, IsNil)
  1315  
  1316  		// make an update on top
  1317  		headers := map[string]interface{}{
  1318  			"series":       "16",
  1319  			"snap-id":      name + "-id",
  1320  			"snap-name":    fmt.Sprintf("fo-o-%d", i),
  1321  			"publisher-id": s.dev1Acct.AccountID(),
  1322  			"timestamp":    time.Now().Format(time.RFC3339),
  1323  			"revision":     "1",
  1324  		}
  1325  		snapDeclFooX1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "")
  1326  		c.Assert(err, IsNil)
  1327  		err = s.storeSigning.Add(snapDeclFooX1)
  1328  		c.Assert(err, IsNil)
  1329  	}
  1330  
  1331  	err = assertstate.RefreshSnapDeclarations(s.state, 0)
  1332  	if err != nil {
  1333  		// fot the caller to check
  1334  		return err
  1335  	}
  1336  
  1337  	// check we got the updates
  1338  	for i := 1; i <= n; i++ {
  1339  		name := fmt.Sprintf("foo%d", i)
  1340  		a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{
  1341  			"series":  "16",
  1342  			"snap-id": name + "-id",
  1343  		})
  1344  		c.Assert(err, IsNil)
  1345  		c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, fmt.Sprintf("fo-o-%d", i))
  1346  	}
  1347  
  1348  	return nil
  1349  }
  1350  
  1351  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany14NoStore(c *C) {
  1352  	s.state.Lock()
  1353  	defer s.state.Unlock()
  1354  	s.setModel(sysdb.GenericClassicModel())
  1355  
  1356  	err := s.testRefreshSnapDeclarationsMany(c, 14)
  1357  	c.Assert(err, IsNil)
  1358  
  1359  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1360  		{"account", "account-key", "snap-declaration"},
  1361  	})
  1362  }
  1363  
  1364  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany16NoStore(c *C) {
  1365  	s.state.Lock()
  1366  	defer s.state.Unlock()
  1367  	s.setModel(sysdb.GenericClassicModel())
  1368  
  1369  	err := s.testRefreshSnapDeclarationsMany(c, 16)
  1370  	c.Assert(err, IsNil)
  1371  
  1372  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1373  		{"account", "account-key", "snap-declaration"},
  1374  	})
  1375  }
  1376  
  1377  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany16WithStore(c *C) {
  1378  	s.state.Lock()
  1379  	defer s.state.Unlock()
  1380  	// have a model and the store assertion available
  1381  	storeAs := s.setupModelAndStore(c)
  1382  	err := s.storeSigning.Add(storeAs)
  1383  	c.Assert(err, IsNil)
  1384  
  1385  	err = s.testRefreshSnapDeclarationsMany(c, 16)
  1386  	c.Assert(err, IsNil)
  1387  
  1388  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1389  		// first 16 groups request
  1390  		{"account", "account-key", "snap-declaration"},
  1391  		// final separate request covering store only
  1392  		{"store"},
  1393  	})
  1394  
  1395  	// store assertion was also fetched
  1396  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
  1397  		"store": "my-brand-store",
  1398  	})
  1399  	c.Assert(err, IsNil)
  1400  }
  1401  
  1402  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany17NoStore(c *C) {
  1403  	s.state.Lock()
  1404  	defer s.state.Unlock()
  1405  	s.setModel(sysdb.GenericClassicModel())
  1406  
  1407  	err := s.testRefreshSnapDeclarationsMany(c, 17)
  1408  	c.Assert(err, IsNil)
  1409  
  1410  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1411  		// first 16 groups request
  1412  		{"account", "account-key", "snap-declaration"},
  1413  		// final separate request for the rest
  1414  		{"snap-declaration"},
  1415  	})
  1416  }
  1417  
  1418  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany17NoStoreMergeErrors(c *C) {
  1419  	s.state.Lock()
  1420  	defer s.state.Unlock()
  1421  	s.setModel(sysdb.GenericClassicModel())
  1422  
  1423  	s.fakeStore.(*fakeStore).downloadAssertionsErr = errors.New("download error")
  1424  
  1425  	err := s.testRefreshSnapDeclarationsMany(c, 17)
  1426  	c.Check(err, ErrorMatches, `(?s)cannot refresh snap-declarations for snaps:
  1427   - foo1: download error.* - foo9: download error`)
  1428  	// all foo* snaps accounted for
  1429  	c.Check(strings.Count(err.Error(), "foo"), Equals, 17)
  1430  
  1431  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1432  		// first 16 groups request
  1433  		{"account", "account-key", "snap-declaration"},
  1434  		// final separate request for the rest
  1435  		{"snap-declaration"},
  1436  	})
  1437  }
  1438  
  1439  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany31WithStore(c *C) {
  1440  	s.state.Lock()
  1441  	defer s.state.Unlock()
  1442  	// have a model and the store assertion available
  1443  	storeAs := s.setupModelAndStore(c)
  1444  	err := s.storeSigning.Add(storeAs)
  1445  	c.Assert(err, IsNil)
  1446  
  1447  	err = s.testRefreshSnapDeclarationsMany(c, 31)
  1448  	c.Assert(err, IsNil)
  1449  
  1450  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1451  		// first 16 groups request
  1452  		{"account", "account-key", "snap-declaration"},
  1453  		// final separate request for the rest and store
  1454  		{"snap-declaration", "store"},
  1455  	})
  1456  
  1457  	// store assertion was also fetched
  1458  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
  1459  		"store": "my-brand-store",
  1460  	})
  1461  	c.Assert(err, IsNil)
  1462  }
  1463  
  1464  func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany32WithStore(c *C) {
  1465  	s.state.Lock()
  1466  	defer s.state.Unlock()
  1467  	// have a model and the store assertion available
  1468  	storeAs := s.setupModelAndStore(c)
  1469  	err := s.storeSigning.Add(storeAs)
  1470  	c.Assert(err, IsNil)
  1471  
  1472  	err = s.testRefreshSnapDeclarationsMany(c, 32)
  1473  	c.Assert(err, IsNil)
  1474  
  1475  	c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{
  1476  		// first 16 groups request
  1477  		{"account", "account-key", "snap-declaration"},
  1478  		// 2nd round request
  1479  		{"snap-declaration"},
  1480  		// final separate request covering store
  1481  		{"store"},
  1482  	})
  1483  
  1484  	// store assertion was also fetched
  1485  	_, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{
  1486  		"store": "my-brand-store",
  1487  	})
  1488  	c.Assert(err, IsNil)
  1489  }
  1490  
  1491  func (s *assertMgrSuite) TestValidateRefreshesNothing(c *C) {
  1492  	s.state.Lock()
  1493  	defer s.state.Unlock()
  1494  
  1495  	validated, err := assertstate.ValidateRefreshes(s.state, nil, nil, 0, s.trivialDeviceCtx)
  1496  	c.Assert(err, IsNil)
  1497  	c.Check(validated, HasLen, 0)
  1498  }
  1499  
  1500  func (s *assertMgrSuite) TestValidateRefreshesNoControl(c *C) {
  1501  	s.state.Lock()
  1502  	defer s.state.Unlock()
  1503  
  1504  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1505  	snapDeclBar := s.snapDecl(c, "bar", nil)
  1506  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1507  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1508  
  1509  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1510  	c.Assert(err, IsNil)
  1511  	err = assertstate.Add(s.state, s.dev1Acct)
  1512  	c.Assert(err, IsNil)
  1513  	err = assertstate.Add(s.state, snapDeclFoo)
  1514  	c.Assert(err, IsNil)
  1515  	err = assertstate.Add(s.state, snapDeclBar)
  1516  	c.Assert(err, IsNil)
  1517  
  1518  	fooRefresh := &snap.Info{
  1519  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1520  	}
  1521  
  1522  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx)
  1523  	c.Assert(err, IsNil)
  1524  	c.Check(validated, DeepEquals, []*snap.Info{fooRefresh})
  1525  }
  1526  
  1527  func (s *assertMgrSuite) TestValidateRefreshesMissingValidation(c *C) {
  1528  	s.state.Lock()
  1529  	defer s.state.Unlock()
  1530  
  1531  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1532  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1533  		"refresh-control": []interface{}{"foo-id"},
  1534  	})
  1535  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1536  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1537  
  1538  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1539  	c.Assert(err, IsNil)
  1540  	err = assertstate.Add(s.state, s.dev1Acct)
  1541  	c.Assert(err, IsNil)
  1542  	err = assertstate.Add(s.state, snapDeclFoo)
  1543  	c.Assert(err, IsNil)
  1544  	err = assertstate.Add(s.state, snapDeclBar)
  1545  	c.Assert(err, IsNil)
  1546  
  1547  	fooRefresh := &snap.Info{
  1548  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1549  	}
  1550  
  1551  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx)
  1552  	c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`)
  1553  	c.Check(validated, HasLen, 0)
  1554  }
  1555  
  1556  func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidation(c *C) {
  1557  	s.state.Lock()
  1558  	defer s.state.Unlock()
  1559  
  1560  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1561  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1562  		"refresh-control": []interface{}{"foo-id"},
  1563  	})
  1564  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1565  	s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7))
  1566  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1567  
  1568  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1569  	c.Assert(err, IsNil)
  1570  	err = assertstate.Add(s.state, s.dev1Acct)
  1571  	c.Assert(err, IsNil)
  1572  	err = assertstate.Add(s.state, snapDeclFoo)
  1573  	c.Assert(err, IsNil)
  1574  	err = assertstate.Add(s.state, snapDeclBar)
  1575  	c.Assert(err, IsNil)
  1576  
  1577  	fooInstanceRefresh := &snap.Info{
  1578  		SideInfo:    snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1579  		InstanceKey: "instance",
  1580  	}
  1581  
  1582  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooInstanceRefresh}, nil, 0, s.trivialDeviceCtx)
  1583  	c.Assert(err, ErrorMatches, `cannot refresh "foo_instance" to revision 9: no validation by "bar"`)
  1584  	c.Check(validated, HasLen, 0)
  1585  }
  1586  
  1587  func (s *assertMgrSuite) TestValidateRefreshesMissingValidationButIgnore(c *C) {
  1588  	s.state.Lock()
  1589  	defer s.state.Unlock()
  1590  
  1591  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1592  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1593  		"refresh-control": []interface{}{"foo-id"},
  1594  	})
  1595  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1596  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1597  
  1598  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1599  	c.Assert(err, IsNil)
  1600  	err = assertstate.Add(s.state, s.dev1Acct)
  1601  	c.Assert(err, IsNil)
  1602  	err = assertstate.Add(s.state, snapDeclFoo)
  1603  	c.Assert(err, IsNil)
  1604  	err = assertstate.Add(s.state, snapDeclBar)
  1605  	c.Assert(err, IsNil)
  1606  
  1607  	fooRefresh := &snap.Info{
  1608  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1609  	}
  1610  
  1611  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, map[string]bool{"foo": true}, 0, s.trivialDeviceCtx)
  1612  	c.Assert(err, IsNil)
  1613  	c.Check(validated, DeepEquals, []*snap.Info{fooRefresh})
  1614  }
  1615  
  1616  func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnore(c *C) {
  1617  	s.state.Lock()
  1618  	defer s.state.Unlock()
  1619  
  1620  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1621  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1622  		"refresh-control": []interface{}{"foo-id"},
  1623  	})
  1624  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1625  	s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7))
  1626  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1627  
  1628  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1629  	c.Assert(err, IsNil)
  1630  	err = assertstate.Add(s.state, s.dev1Acct)
  1631  	c.Assert(err, IsNil)
  1632  	err = assertstate.Add(s.state, snapDeclFoo)
  1633  	c.Assert(err, IsNil)
  1634  	err = assertstate.Add(s.state, snapDeclBar)
  1635  	c.Assert(err, IsNil)
  1636  
  1637  	fooRefresh := &snap.Info{
  1638  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1639  	}
  1640  	fooInstanceRefresh := &snap.Info{
  1641  		SideInfo:    snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1642  		InstanceKey: "instance",
  1643  	}
  1644  
  1645  	// validation is ignore for foo_instance but not for foo
  1646  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx)
  1647  	c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`)
  1648  	c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh})
  1649  }
  1650  
  1651  func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnoreInstanceKeyed(c *C) {
  1652  	s.state.Lock()
  1653  	defer s.state.Unlock()
  1654  
  1655  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1656  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1657  		"refresh-control": []interface{}{"foo-id"},
  1658  	})
  1659  	s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7))
  1660  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1661  
  1662  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1663  	c.Assert(err, IsNil)
  1664  	err = assertstate.Add(s.state, s.dev1Acct)
  1665  	c.Assert(err, IsNil)
  1666  	err = assertstate.Add(s.state, snapDeclFoo)
  1667  	c.Assert(err, IsNil)
  1668  	err = assertstate.Add(s.state, snapDeclBar)
  1669  	c.Assert(err, IsNil)
  1670  
  1671  	fooInstanceRefresh := &snap.Info{
  1672  		SideInfo:    snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1673  		InstanceKey: "instance",
  1674  	}
  1675  
  1676  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx)
  1677  	c.Assert(err, IsNil)
  1678  	c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh})
  1679  }
  1680  
  1681  func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnoreBothOneIgnored(c *C) {
  1682  	s.state.Lock()
  1683  	defer s.state.Unlock()
  1684  
  1685  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1686  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1687  		"refresh-control": []interface{}{"foo-id"},
  1688  	})
  1689  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1690  	s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7))
  1691  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1692  
  1693  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1694  	c.Assert(err, IsNil)
  1695  	err = assertstate.Add(s.state, s.dev1Acct)
  1696  	c.Assert(err, IsNil)
  1697  	err = assertstate.Add(s.state, snapDeclFoo)
  1698  	c.Assert(err, IsNil)
  1699  	err = assertstate.Add(s.state, snapDeclBar)
  1700  	c.Assert(err, IsNil)
  1701  
  1702  	fooRefresh := &snap.Info{
  1703  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1704  	}
  1705  	fooInstanceRefresh := &snap.Info{
  1706  		SideInfo:    snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1707  		InstanceKey: "instance",
  1708  	}
  1709  
  1710  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx)
  1711  	c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`)
  1712  	c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh})
  1713  }
  1714  
  1715  func (s *assertMgrSuite) TestValidateRefreshesValidationOK(c *C) {
  1716  	s.state.Lock()
  1717  	defer s.state.Unlock()
  1718  
  1719  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1720  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1721  		"refresh-control": []interface{}{"foo-id"},
  1722  	})
  1723  	snapDeclBaz := s.snapDecl(c, "baz", map[string]interface{}{
  1724  		"refresh-control": []interface{}{"foo-id"},
  1725  	})
  1726  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1727  	s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7))
  1728  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1729  	s.stateFromDecl(c, snapDeclBaz, "", snap.R(1))
  1730  	snapstate.Set(s.state, "local", &snapstate.SnapState{
  1731  		Active: false,
  1732  		Sequence: []*snap.SideInfo{
  1733  			{RealName: "local", Revision: snap.R(-1)},
  1734  		},
  1735  		Current: snap.R(-1),
  1736  	})
  1737  
  1738  	// validation by bar
  1739  	headers := map[string]interface{}{
  1740  		"series":                 "16",
  1741  		"snap-id":                "bar-id",
  1742  		"approved-snap-id":       "foo-id",
  1743  		"approved-snap-revision": "9",
  1744  		"timestamp":              time.Now().Format(time.RFC3339),
  1745  	}
  1746  	barValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "")
  1747  	c.Assert(err, IsNil)
  1748  	err = s.storeSigning.Add(barValidation)
  1749  	c.Assert(err, IsNil)
  1750  
  1751  	// validation by baz
  1752  	headers = map[string]interface{}{
  1753  		"series":                 "16",
  1754  		"snap-id":                "baz-id",
  1755  		"approved-snap-id":       "foo-id",
  1756  		"approved-snap-revision": "9",
  1757  		"timestamp":              time.Now().Format(time.RFC3339),
  1758  	}
  1759  	bazValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "")
  1760  	c.Assert(err, IsNil)
  1761  	err = s.storeSigning.Add(bazValidation)
  1762  	c.Assert(err, IsNil)
  1763  
  1764  	err = assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1765  	c.Assert(err, IsNil)
  1766  	err = assertstate.Add(s.state, s.dev1Acct)
  1767  	c.Assert(err, IsNil)
  1768  	err = assertstate.Add(s.state, snapDeclFoo)
  1769  	c.Assert(err, IsNil)
  1770  	err = assertstate.Add(s.state, snapDeclBar)
  1771  	c.Assert(err, IsNil)
  1772  	err = assertstate.Add(s.state, snapDeclBaz)
  1773  	c.Assert(err, IsNil)
  1774  
  1775  	fooRefresh := &snap.Info{
  1776  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1777  	}
  1778  	fooInstanceRefresh := &snap.Info{
  1779  		SideInfo:    snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1780  		InstanceKey: "instance",
  1781  	}
  1782  
  1783  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, nil, 0, s.trivialDeviceCtx)
  1784  	c.Assert(err, IsNil)
  1785  	c.Check(validated, DeepEquals, []*snap.Info{fooRefresh, fooInstanceRefresh})
  1786  }
  1787  
  1788  func (s *assertMgrSuite) TestValidateRefreshesRevokedValidation(c *C) {
  1789  	s.state.Lock()
  1790  	defer s.state.Unlock()
  1791  
  1792  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1793  	snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{
  1794  		"refresh-control": []interface{}{"foo-id"},
  1795  	})
  1796  	snapDeclBaz := s.snapDecl(c, "baz", map[string]interface{}{
  1797  		"refresh-control": []interface{}{"foo-id"},
  1798  	})
  1799  	s.stateFromDecl(c, snapDeclFoo, "", snap.R(7))
  1800  	s.stateFromDecl(c, snapDeclBar, "", snap.R(3))
  1801  	s.stateFromDecl(c, snapDeclBaz, "", snap.R(1))
  1802  	snapstate.Set(s.state, "local", &snapstate.SnapState{
  1803  		Active: false,
  1804  		Sequence: []*snap.SideInfo{
  1805  			{RealName: "local", Revision: snap.R(-1)},
  1806  		},
  1807  		Current: snap.R(-1),
  1808  	})
  1809  
  1810  	// validation by bar
  1811  	headers := map[string]interface{}{
  1812  		"series":                 "16",
  1813  		"snap-id":                "bar-id",
  1814  		"approved-snap-id":       "foo-id",
  1815  		"approved-snap-revision": "9",
  1816  		"timestamp":              time.Now().Format(time.RFC3339),
  1817  	}
  1818  	barValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "")
  1819  	c.Assert(err, IsNil)
  1820  	err = s.storeSigning.Add(barValidation)
  1821  	c.Assert(err, IsNil)
  1822  
  1823  	// revoked validation by baz
  1824  	headers = map[string]interface{}{
  1825  		"series":                 "16",
  1826  		"snap-id":                "baz-id",
  1827  		"approved-snap-id":       "foo-id",
  1828  		"approved-snap-revision": "9",
  1829  		"revoked":                "true",
  1830  		"timestamp":              time.Now().Format(time.RFC3339),
  1831  	}
  1832  	bazValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "")
  1833  	c.Assert(err, IsNil)
  1834  	err = s.storeSigning.Add(bazValidation)
  1835  	c.Assert(err, IsNil)
  1836  
  1837  	err = assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1838  	c.Assert(err, IsNil)
  1839  	err = assertstate.Add(s.state, s.dev1Acct)
  1840  	c.Assert(err, IsNil)
  1841  	err = assertstate.Add(s.state, snapDeclFoo)
  1842  	c.Assert(err, IsNil)
  1843  	err = assertstate.Add(s.state, snapDeclBar)
  1844  	c.Assert(err, IsNil)
  1845  	err = assertstate.Add(s.state, snapDeclBaz)
  1846  	c.Assert(err, IsNil)
  1847  
  1848  	fooRefresh := &snap.Info{
  1849  		SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)},
  1850  	}
  1851  
  1852  	validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx)
  1853  	c.Assert(err, ErrorMatches, `(?s).*cannot refresh "foo" to revision 9: validation by "baz" \(id "baz-id"\) revoked.*`)
  1854  	c.Check(validated, HasLen, 0)
  1855  }
  1856  
  1857  func (s *assertMgrSuite) TestBaseSnapDeclaration(c *C) {
  1858  	s.state.Lock()
  1859  	defer s.state.Unlock()
  1860  
  1861  	r1 := assertstest.MockBuiltinBaseDeclaration(nil)
  1862  	defer r1()
  1863  
  1864  	baseDecl, err := assertstate.BaseDeclaration(s.state)
  1865  	c.Assert(asserts.IsNotFound(err), Equals, true)
  1866  	c.Check(baseDecl, IsNil)
  1867  
  1868  	r2 := assertstest.MockBuiltinBaseDeclaration([]byte(`
  1869  type: base-declaration
  1870  authority-id: canonical
  1871  series: 16
  1872  plugs:
  1873    iface: true
  1874  `))
  1875  	defer r2()
  1876  
  1877  	baseDecl, err = assertstate.BaseDeclaration(s.state)
  1878  	c.Assert(err, IsNil)
  1879  	c.Check(baseDecl, NotNil)
  1880  	c.Check(baseDecl.PlugRule("iface"), NotNil)
  1881  }
  1882  
  1883  func (s *assertMgrSuite) TestSnapDeclaration(c *C) {
  1884  	s.state.Lock()
  1885  	defer s.state.Unlock()
  1886  
  1887  	// have a declaration in the system db
  1888  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1889  	c.Assert(err, IsNil)
  1890  	err = assertstate.Add(s.state, s.dev1Acct)
  1891  	c.Assert(err, IsNil)
  1892  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1893  	err = assertstate.Add(s.state, snapDeclFoo)
  1894  	c.Assert(err, IsNil)
  1895  
  1896  	_, err = assertstate.SnapDeclaration(s.state, "snap-id-other")
  1897  	c.Check(asserts.IsNotFound(err), Equals, true)
  1898  
  1899  	snapDecl, err := assertstate.SnapDeclaration(s.state, "foo-id")
  1900  	c.Assert(err, IsNil)
  1901  	c.Check(snapDecl.SnapName(), Equals, "foo")
  1902  }
  1903  
  1904  func (s *assertMgrSuite) TestAutoAliasesTemporaryFallback(c *C) {
  1905  	s.state.Lock()
  1906  	defer s.state.Unlock()
  1907  
  1908  	// prereqs for developer assertions in the system db
  1909  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1910  	c.Assert(err, IsNil)
  1911  	err = assertstate.Add(s.state, s.dev1Acct)
  1912  	c.Assert(err, IsNil)
  1913  
  1914  	// not from the store
  1915  	aliases, err := assertstate.AutoAliases(s.state, &snap.Info{SuggestedName: "local"})
  1916  	c.Assert(err, IsNil)
  1917  	c.Check(aliases, HasLen, 0)
  1918  
  1919  	// missing
  1920  	_, err = assertstate.AutoAliases(s.state, &snap.Info{
  1921  		SideInfo: snap.SideInfo{
  1922  			RealName: "baz",
  1923  			SnapID:   "baz-id",
  1924  		},
  1925  	})
  1926  	c.Check(err, ErrorMatches, `internal error: cannot find snap-declaration for installed snap "baz": snap-declaration \(baz-id; series:16\) not found`)
  1927  
  1928  	info := snaptest.MockInfo(c, `
  1929  name: foo
  1930  version: 0
  1931  apps:
  1932     cmd1:
  1933       aliases: [alias1]
  1934     cmd2:
  1935       aliases: [alias2]
  1936  `, &snap.SideInfo{
  1937  		RealName: "foo",
  1938  		SnapID:   "foo-id",
  1939  	})
  1940  
  1941  	// empty list
  1942  	// have a declaration in the system db
  1943  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1944  	err = assertstate.Add(s.state, snapDeclFoo)
  1945  	c.Assert(err, IsNil)
  1946  	aliases, err = assertstate.AutoAliases(s.state, info)
  1947  	c.Assert(err, IsNil)
  1948  	c.Check(aliases, HasLen, 0)
  1949  
  1950  	// some aliases
  1951  	snapDeclFoo = s.snapDecl(c, "foo", map[string]interface{}{
  1952  		"auto-aliases": []interface{}{"alias1", "alias2", "alias3"},
  1953  		"revision":     "1",
  1954  	})
  1955  	err = assertstate.Add(s.state, snapDeclFoo)
  1956  	c.Assert(err, IsNil)
  1957  	aliases, err = assertstate.AutoAliases(s.state, info)
  1958  	c.Assert(err, IsNil)
  1959  	c.Check(aliases, DeepEquals, map[string]string{
  1960  		"alias1": "cmd1",
  1961  		"alias2": "cmd2",
  1962  	})
  1963  }
  1964  
  1965  func (s *assertMgrSuite) TestAutoAliasesExplicit(c *C) {
  1966  	s.state.Lock()
  1967  	defer s.state.Unlock()
  1968  
  1969  	// prereqs for developer assertions in the system db
  1970  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  1971  	c.Assert(err, IsNil)
  1972  	err = assertstate.Add(s.state, s.dev1Acct)
  1973  	c.Assert(err, IsNil)
  1974  
  1975  	// not from the store
  1976  	aliases, err := assertstate.AutoAliases(s.state, &snap.Info{SuggestedName: "local"})
  1977  	c.Assert(err, IsNil)
  1978  	c.Check(aliases, HasLen, 0)
  1979  
  1980  	// missing
  1981  	_, err = assertstate.AutoAliases(s.state, &snap.Info{
  1982  		SideInfo: snap.SideInfo{
  1983  			RealName: "baz",
  1984  			SnapID:   "baz-id",
  1985  		},
  1986  	})
  1987  	c.Check(err, ErrorMatches, `internal error: cannot find snap-declaration for installed snap "baz": snap-declaration \(baz-id; series:16\) not found`)
  1988  
  1989  	// empty list
  1990  	// have a declaration in the system db
  1991  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  1992  	err = assertstate.Add(s.state, snapDeclFoo)
  1993  	c.Assert(err, IsNil)
  1994  	aliases, err = assertstate.AutoAliases(s.state, &snap.Info{
  1995  		SideInfo: snap.SideInfo{
  1996  			RealName: "foo",
  1997  			SnapID:   "foo-id",
  1998  		},
  1999  	})
  2000  	c.Assert(err, IsNil)
  2001  	c.Check(aliases, HasLen, 0)
  2002  
  2003  	// some aliases
  2004  	snapDeclFoo = s.snapDecl(c, "foo", map[string]interface{}{
  2005  		"aliases": []interface{}{
  2006  			map[string]interface{}{
  2007  				"name":   "alias1",
  2008  				"target": "cmd1",
  2009  			},
  2010  			map[string]interface{}{
  2011  				"name":   "alias2",
  2012  				"target": "cmd2",
  2013  			},
  2014  		},
  2015  		"revision": "1",
  2016  	})
  2017  	err = assertstate.Add(s.state, snapDeclFoo)
  2018  	c.Assert(err, IsNil)
  2019  	aliases, err = assertstate.AutoAliases(s.state, &snap.Info{
  2020  		SideInfo: snap.SideInfo{
  2021  			RealName: "foo",
  2022  			SnapID:   "foo-id",
  2023  		},
  2024  	})
  2025  	c.Assert(err, IsNil)
  2026  	c.Check(aliases, DeepEquals, map[string]string{
  2027  		"alias1": "cmd1",
  2028  		"alias2": "cmd2",
  2029  	})
  2030  }
  2031  
  2032  func (s *assertMgrSuite) TestPublisher(c *C) {
  2033  	s.state.Lock()
  2034  	defer s.state.Unlock()
  2035  
  2036  	// have a declaration in the system db
  2037  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  2038  	c.Assert(err, IsNil)
  2039  	err = assertstate.Add(s.state, s.dev1Acct)
  2040  	c.Assert(err, IsNil)
  2041  	snapDeclFoo := s.snapDecl(c, "foo", nil)
  2042  	err = assertstate.Add(s.state, snapDeclFoo)
  2043  	c.Assert(err, IsNil)
  2044  
  2045  	_, err = assertstate.SnapDeclaration(s.state, "snap-id-other")
  2046  	c.Check(asserts.IsNotFound(err), Equals, true)
  2047  
  2048  	acct, err := assertstate.Publisher(s.state, "foo-id")
  2049  	c.Assert(err, IsNil)
  2050  	c.Check(acct.AccountID(), Equals, s.dev1Acct.AccountID())
  2051  	c.Check(acct.Username(), Equals, "developer1")
  2052  }
  2053  
  2054  func (s *assertMgrSuite) TestStore(c *C) {
  2055  	s.state.Lock()
  2056  	defer s.state.Unlock()
  2057  
  2058  	err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey(""))
  2059  	c.Assert(err, IsNil)
  2060  	err = assertstate.Add(s.state, s.dev1Acct)
  2061  	c.Assert(err, IsNil)
  2062  	storeHeaders := map[string]interface{}{
  2063  		"store":       "foo",
  2064  		"operator-id": s.dev1Acct.AccountID(),
  2065  		"timestamp":   time.Now().Format(time.RFC3339),
  2066  	}
  2067  	fooStore, err := s.storeSigning.Sign(asserts.StoreType, storeHeaders, nil, "")
  2068  	c.Assert(err, IsNil)
  2069  	err = assertstate.Add(s.state, fooStore)
  2070  	c.Assert(err, IsNil)
  2071  
  2072  	_, err = assertstate.Store(s.state, "bar")
  2073  	c.Check(asserts.IsNotFound(err), Equals, true)
  2074  
  2075  	store, err := assertstate.Store(s.state, "foo")
  2076  	c.Assert(err, IsNil)
  2077  	c.Check(store.Store(), Equals, "foo")
  2078  }