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