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