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