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