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