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 }