github.com/kubiko/snapd@v0.0.0-20201013125620-d4f3094d9ddf/overlord/assertstate/assertstate_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2016-2020 Canonical Ltd 5 * 6 * This program is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 3 as 8 * published by the Free Software Foundation. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program. If not, see <http://www.gnu.org/licenses/>. 17 * 18 */ 19 20 package assertstate_test 21 22 import ( 23 "bytes" 24 "context" 25 "crypto" 26 "errors" 27 "fmt" 28 "io/ioutil" 29 "path/filepath" 30 "sort" 31 "strings" 32 "testing" 33 "time" 34 35 "golang.org/x/crypto/sha3" 36 37 . "gopkg.in/check.v1" 38 39 "github.com/snapcore/snapd/asserts" 40 "github.com/snapcore/snapd/asserts/assertstest" 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 dev1Signing *assertstest.SigningDB 71 72 fakeStore snapstate.StoreService 73 trivialDeviceCtx snapstate.DeviceContext 74 } 75 76 var _ = Suite(&assertMgrSuite{}) 77 78 type fakeStore struct { 79 storetest.Store 80 state *state.State 81 db asserts.RODatabase 82 maxDeclSupportedFormat int 83 84 requestedTypes [][]string 85 86 snapActionErr error 87 downloadAssertionsErr error 88 } 89 90 func (sto *fakeStore) pokeStateLock() { 91 // the store should be called without the state lock held. Try 92 // to acquire it. 93 sto.state.Lock() 94 sto.state.Unlock() 95 } 96 97 func (sto *fakeStore) Assertion(assertType *asserts.AssertionType, key []string, _ *auth.UserState) (asserts.Assertion, error) { 98 sto.pokeStateLock() 99 100 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat) 101 defer restore() 102 103 ref := &asserts.Ref{Type: assertType, PrimaryKey: key} 104 return ref.Resolve(sto.db.Find) 105 } 106 107 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) { 108 sto.pokeStateLock() 109 110 if len(currentSnaps) != 0 || len(actions) != 0 { 111 panic("only assertion query supported") 112 } 113 114 toResolve, err := assertQuery.ToResolve() 115 if err != nil { 116 return nil, nil, err 117 } 118 119 if sto.snapActionErr != nil { 120 return nil, nil, sto.snapActionErr 121 } 122 123 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat) 124 defer restore() 125 126 reqTypes := make(map[string]bool) 127 ares := make([]store.AssertionResult, 0, len(toResolve)) 128 for g, ats := range toResolve { 129 urls := make([]string, 0, len(ats)) 130 for _, at := range ats { 131 reqTypes[at.Ref.Type.Name] = true 132 a, err := at.Ref.Resolve(sto.db.Find) 133 if err != nil { 134 assertQuery.AddError(err, &at.Ref) 135 continue 136 } 137 if a.Revision() > at.Revision { 138 urls = append(urls, fmt.Sprintf("/assertions/%s", at.Unique())) 139 } 140 } 141 ares = append(ares, store.AssertionResult{ 142 Grouping: asserts.Grouping(g), 143 StreamURLs: urls, 144 }) 145 } 146 // behave like the actual SnapAction if there are no results 147 if len(ares) == 0 { 148 return nil, ares, &store.SnapActionError{ 149 NoResults: true, 150 } 151 } 152 153 typeNames := make([]string, 0, len(reqTypes)) 154 for k := range reqTypes { 155 typeNames = append(typeNames, k) 156 } 157 sort.Strings(typeNames) 158 sto.requestedTypes = append(sto.requestedTypes, typeNames) 159 160 return nil, ares, nil 161 } 162 163 func (sto *fakeStore) DownloadAssertions(urls []string, b *asserts.Batch, user *auth.UserState) error { 164 sto.pokeStateLock() 165 166 if sto.downloadAssertionsErr != nil { 167 return sto.downloadAssertionsErr 168 } 169 170 resolve := func(ref *asserts.Ref) (asserts.Assertion, error) { 171 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, sto.maxDeclSupportedFormat) 172 defer restore() 173 return ref.Resolve(sto.db.Find) 174 } 175 176 for _, u := range urls { 177 comps := strings.Split(u, "/") 178 179 if len(comps) < 4 { 180 return fmt.Errorf("cannot use URL: %s", u) 181 } 182 183 assertType := asserts.Type(comps[2]) 184 key := comps[3:] 185 ref := &asserts.Ref{Type: assertType, PrimaryKey: key} 186 a, err := resolve(ref) 187 if err != nil { 188 return err 189 } 190 if err := b.Add(a); err != nil { 191 return err 192 } 193 } 194 195 return nil 196 } 197 198 var ( 199 dev1PrivKey, _ = assertstest.GenerateKey(752) 200 ) 201 202 func (s *assertMgrSuite) SetUpTest(c *C) { 203 dirs.SetRootDir(c.MkDir()) 204 205 s.storeSigning = assertstest.NewStoreStack("can0nical", nil) 206 s.AddCleanup(sysdb.InjectTrusted(s.storeSigning.Trusted)) 207 208 s.dev1Acct = assertstest.NewAccount(s.storeSigning, "developer1", nil, "") 209 err := s.storeSigning.Add(s.dev1Acct) 210 c.Assert(err, IsNil) 211 212 // developer signing 213 dev1AcctKey := assertstest.NewAccountKey(s.storeSigning, s.dev1Acct, nil, dev1PrivKey.PublicKey(), "") 214 err = s.storeSigning.Add(dev1AcctKey) 215 c.Assert(err, IsNil) 216 217 s.dev1Signing = assertstest.NewSigningDB(s.dev1Acct.AccountID(), dev1PrivKey) 218 219 s.o = overlord.Mock() 220 s.state = s.o.State() 221 s.se = s.o.StateEngine() 222 mgr, err := assertstate.Manager(s.state, s.o.TaskRunner()) 223 c.Assert(err, IsNil) 224 s.mgr = mgr 225 s.o.AddManager(s.mgr) 226 227 s.o.AddManager(s.o.TaskRunner()) 228 229 s.fakeStore = &fakeStore{ 230 state: s.state, 231 db: s.storeSigning, 232 maxDeclSupportedFormat: asserts.SnapDeclarationType.MaxSupportedFormat(), 233 } 234 s.trivialDeviceCtx = &snapstatetest.TrivialDeviceContext{ 235 CtxStore: s.fakeStore, 236 } 237 } 238 239 func (s *assertMgrSuite) TestDB(c *C) { 240 s.state.Lock() 241 defer s.state.Unlock() 242 243 db := assertstate.DB(s.state) 244 c.Check(db, FitsTypeOf, (*asserts.Database)(nil)) 245 } 246 247 func (s *assertMgrSuite) TestAdd(c *C) { 248 s.state.Lock() 249 defer s.state.Unlock() 250 251 // prereq store key 252 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 253 c.Assert(err, IsNil) 254 255 err = assertstate.Add(s.state, s.dev1Acct) 256 c.Assert(err, IsNil) 257 258 db := assertstate.DB(s.state) 259 devAcct, err := db.Find(asserts.AccountType, map[string]string{ 260 "account-id": s.dev1Acct.AccountID(), 261 }) 262 c.Assert(err, IsNil) 263 c.Check(devAcct.(*asserts.Account).Username(), Equals, "developer1") 264 } 265 266 func (s *assertMgrSuite) TestAddBatch(c *C) { 267 s.state.Lock() 268 defer s.state.Unlock() 269 270 b := &bytes.Buffer{} 271 enc := asserts.NewEncoder(b) 272 // wrong order is ok 273 err := enc.Encode(s.dev1Acct) 274 c.Assert(err, IsNil) 275 enc.Encode(s.storeSigning.StoreAccountKey("")) 276 c.Assert(err, IsNil) 277 278 batch := asserts.NewBatch(nil) 279 refs, err := batch.AddStream(b) 280 c.Assert(err, IsNil) 281 c.Check(refs, DeepEquals, []*asserts.Ref{ 282 {Type: asserts.AccountType, PrimaryKey: []string{s.dev1Acct.AccountID()}}, 283 {Type: asserts.AccountKeyType, PrimaryKey: []string{s.storeSigning.StoreAccountKey("").PublicKeyID()}}, 284 }) 285 286 // noop 287 err = batch.Add(s.storeSigning.StoreAccountKey("")) 288 c.Assert(err, IsNil) 289 290 err = assertstate.AddBatch(s.state, batch, nil) 291 c.Assert(err, IsNil) 292 293 db := assertstate.DB(s.state) 294 devAcct, err := db.Find(asserts.AccountType, map[string]string{ 295 "account-id": s.dev1Acct.AccountID(), 296 }) 297 c.Assert(err, IsNil) 298 c.Check(devAcct.(*asserts.Account).Username(), Equals, "developer1") 299 } 300 301 func (s *assertMgrSuite) TestAddBatchPartial(c *C) { 302 // Commit does add any successful assertion until the first error 303 s.state.Lock() 304 defer s.state.Unlock() 305 306 // store key already present 307 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 308 c.Assert(err, IsNil) 309 310 batch := asserts.NewBatch(nil) 311 312 snapDeclFoo := s.snapDecl(c, "foo", nil) 313 314 err = batch.Add(snapDeclFoo) 315 c.Assert(err, IsNil) 316 err = batch.Add(s.dev1Acct) 317 c.Assert(err, IsNil) 318 319 // too old 320 rev := 1 321 headers := map[string]interface{}{ 322 "snap-id": "foo-id", 323 "snap-sha3-384": makeDigest(rev), 324 "snap-size": fmt.Sprintf("%d", len(fakeSnap(rev))), 325 "snap-revision": fmt.Sprintf("%d", rev), 326 "developer-id": s.dev1Acct.AccountID(), 327 "timestamp": time.Time{}.Format(time.RFC3339), 328 } 329 snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "") 330 c.Assert(err, IsNil) 331 332 err = batch.Add(snapRev) 333 c.Assert(err, IsNil) 334 335 err = assertstate.AddBatch(s.state, batch, nil) 336 c.Check(err, ErrorMatches, `(?ms).*validity.*`) 337 338 // snap-declaration was added anyway 339 _, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 340 "series": "16", 341 "snap-id": "foo-id", 342 }) 343 c.Assert(err, IsNil) 344 } 345 346 func (s *assertMgrSuite) TestAddBatchPrecheckPartial(c *C) { 347 s.state.Lock() 348 defer s.state.Unlock() 349 350 // store key already present 351 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 352 c.Assert(err, IsNil) 353 354 batch := asserts.NewBatch(nil) 355 356 snapDeclFoo := s.snapDecl(c, "foo", nil) 357 358 err = batch.Add(snapDeclFoo) 359 c.Assert(err, IsNil) 360 err = batch.Add(s.dev1Acct) 361 c.Assert(err, IsNil) 362 363 // too old 364 rev := 1 365 headers := map[string]interface{}{ 366 "snap-id": "foo-id", 367 "snap-sha3-384": makeDigest(rev), 368 "snap-size": fmt.Sprintf("%d", len(fakeSnap(rev))), 369 "snap-revision": fmt.Sprintf("%d", rev), 370 "developer-id": s.dev1Acct.AccountID(), 371 "timestamp": time.Time{}.Format(time.RFC3339), 372 } 373 snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "") 374 c.Assert(err, IsNil) 375 376 err = batch.Add(snapRev) 377 c.Assert(err, IsNil) 378 379 err = assertstate.AddBatch(s.state, batch, &asserts.CommitOptions{ 380 Precheck: true, 381 }) 382 c.Check(err, ErrorMatches, `(?ms).*validity.*`) 383 384 // nothing was added 385 _, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 386 "series": "16", 387 "snap-id": "foo-id", 388 }) 389 c.Assert(asserts.IsNotFound(err), Equals, true) 390 } 391 392 func (s *assertMgrSuite) TestAddBatchPrecheckHappy(c *C) { 393 s.state.Lock() 394 defer s.state.Unlock() 395 396 // store key already present 397 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 398 c.Assert(err, IsNil) 399 400 batch := asserts.NewBatch(nil) 401 402 snapDeclFoo := s.snapDecl(c, "foo", nil) 403 404 err = batch.Add(snapDeclFoo) 405 c.Assert(err, IsNil) 406 err = batch.Add(s.dev1Acct) 407 c.Assert(err, IsNil) 408 409 rev := 1 410 revDigest := makeDigest(rev) 411 headers := map[string]interface{}{ 412 "snap-id": "foo-id", 413 "snap-sha3-384": revDigest, 414 "snap-size": fmt.Sprintf("%d", len(fakeSnap(rev))), 415 "snap-revision": fmt.Sprintf("%d", rev), 416 "developer-id": s.dev1Acct.AccountID(), 417 "timestamp": time.Now().Format(time.RFC3339), 418 } 419 snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "") 420 c.Assert(err, IsNil) 421 422 err = batch.Add(snapRev) 423 c.Assert(err, IsNil) 424 425 err = assertstate.AddBatch(s.state, batch, &asserts.CommitOptions{ 426 Precheck: true, 427 }) 428 c.Assert(err, IsNil) 429 430 _, err = assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{ 431 "snap-sha3-384": revDigest, 432 }) 433 c.Check(err, IsNil) 434 } 435 436 func fakeSnap(rev int) []byte { 437 fake := fmt.Sprintf("hsqs________________%d", rev) 438 return []byte(fake) 439 } 440 441 func fakeHash(rev int) []byte { 442 h := sha3.Sum384(fakeSnap(rev)) 443 return h[:] 444 } 445 446 func makeDigest(rev int) string { 447 d, err := asserts.EncodeDigest(crypto.SHA3_384, fakeHash(rev)) 448 if err != nil { 449 panic(err) 450 } 451 return string(d) 452 } 453 454 func (s *assertMgrSuite) prereqSnapAssertions(c *C, revisions ...int) { 455 headers := map[string]interface{}{ 456 "series": "16", 457 "snap-id": "snap-id-1", 458 "snap-name": "foo", 459 "publisher-id": s.dev1Acct.AccountID(), 460 "timestamp": time.Now().Format(time.RFC3339), 461 } 462 snapDecl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 463 c.Assert(err, IsNil) 464 err = s.storeSigning.Add(snapDecl) 465 c.Assert(err, IsNil) 466 467 for _, rev := range revisions { 468 headers = map[string]interface{}{ 469 "snap-id": "snap-id-1", 470 "snap-sha3-384": makeDigest(rev), 471 "snap-size": fmt.Sprintf("%d", len(fakeSnap(rev))), 472 "snap-revision": fmt.Sprintf("%d", rev), 473 "developer-id": s.dev1Acct.AccountID(), 474 "timestamp": time.Now().Format(time.RFC3339), 475 } 476 snapRev, err := s.storeSigning.Sign(asserts.SnapRevisionType, headers, nil, "") 477 c.Assert(err, IsNil) 478 err = s.storeSigning.Add(snapRev) 479 c.Assert(err, IsNil) 480 } 481 } 482 483 func (s *assertMgrSuite) TestDoFetch(c *C) { 484 s.prereqSnapAssertions(c, 10) 485 486 s.state.Lock() 487 defer s.state.Unlock() 488 489 ref := &asserts.Ref{ 490 Type: asserts.SnapRevisionType, 491 PrimaryKey: []string{makeDigest(10)}, 492 } 493 494 err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, func(f asserts.Fetcher) error { 495 return f.Fetch(ref) 496 }) 497 c.Assert(err, IsNil) 498 499 snapRev, err := ref.Resolve(assertstate.DB(s.state).Find) 500 c.Assert(err, IsNil) 501 c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10) 502 } 503 504 func (s *assertMgrSuite) TestFetchIdempotent(c *C) { 505 s.prereqSnapAssertions(c, 10, 11) 506 507 s.state.Lock() 508 defer s.state.Unlock() 509 510 ref := &asserts.Ref{ 511 Type: asserts.SnapRevisionType, 512 PrimaryKey: []string{makeDigest(10)}, 513 } 514 fetching := func(f asserts.Fetcher) error { 515 return f.Fetch(ref) 516 } 517 518 err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching) 519 c.Assert(err, IsNil) 520 521 ref = &asserts.Ref{ 522 Type: asserts.SnapRevisionType, 523 PrimaryKey: []string{makeDigest(11)}, 524 } 525 526 err = assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching) 527 c.Assert(err, IsNil) 528 529 snapRev, err := ref.Resolve(assertstate.DB(s.state).Find) 530 c.Assert(err, IsNil) 531 c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 11) 532 } 533 534 func (s *assertMgrSuite) settle(c *C) { 535 err := s.o.Settle(5 * time.Second) 536 c.Assert(err, IsNil) 537 } 538 539 func (s *assertMgrSuite) TestFetchUnsupportedUpdateIgnored(c *C) { 540 // ATM in principle we ignore updated assertions with unsupported formats 541 // NB: this scenario can only happen if there is a bug 542 // we ask the store to filter what is returned by max supported format! 543 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 111) 544 defer restore() 545 546 logbuf, restore := logger.MockLogger() 547 defer restore() 548 549 snapDeclFoo0 := s.snapDecl(c, "foo", nil) 550 551 s.state.Lock() 552 defer s.state.Unlock() 553 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 554 c.Assert(err, IsNil) 555 556 err = assertstate.Add(s.state, s.dev1Acct) 557 c.Assert(err, IsNil) 558 err = assertstate.Add(s.state, snapDeclFoo0) 559 c.Assert(err, IsNil) 560 561 var snapDeclFoo1 *asserts.SnapDeclaration 562 (func() { 563 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999) 564 defer restore() 565 snapDeclFoo1 = s.snapDecl(c, "foo", map[string]interface{}{ 566 "format": "999", 567 "revision": "1", 568 }) 569 })() 570 c.Check(snapDeclFoo1.Revision(), Equals, 1) 571 572 ref := &asserts.Ref{ 573 Type: asserts.SnapDeclarationType, 574 PrimaryKey: []string{"16", "foo-id"}, 575 } 576 fetching := func(f asserts.Fetcher) error { 577 return f.Fetch(ref) 578 } 579 580 s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999 581 err = assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching) 582 // no error and the old one was kept 583 c.Assert(err, IsNil) 584 snapDecl, err := ref.Resolve(assertstate.DB(s.state).Find) 585 c.Assert(err, IsNil) 586 c.Check(snapDecl.Revision(), Equals, 0) 587 588 // we log the issue 589 c.Check(logbuf.String(), testutil.Contains, `Cannot update assertion snap-declaration (foo-id;`) 590 } 591 592 func (s *assertMgrSuite) TestFetchUnsupportedError(c *C) { 593 // NB: this scenario can only happen if there is a bug 594 // we ask the store to filter what is returned by max supported format! 595 596 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 111) 597 defer restore() 598 599 s.state.Lock() 600 defer s.state.Unlock() 601 602 var snapDeclFoo1 *asserts.SnapDeclaration 603 (func() { 604 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999) 605 defer restore() 606 snapDeclFoo1 = s.snapDecl(c, "foo", map[string]interface{}{ 607 "format": "999", 608 "revision": "1", 609 }) 610 })() 611 c.Check(snapDeclFoo1.Revision(), Equals, 1) 612 613 ref := &asserts.Ref{ 614 Type: asserts.SnapDeclarationType, 615 PrimaryKey: []string{"16", "foo-id"}, 616 } 617 fetching := func(f asserts.Fetcher) error { 618 return f.Fetch(ref) 619 } 620 621 s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999 622 err := assertstate.DoFetch(s.state, 0, s.trivialDeviceCtx, fetching) 623 c.Check(err, ErrorMatches, `(?s).*proposed "snap-declaration" assertion has format 999 but 111 is latest supported.*`) 624 } 625 626 func (s *assertMgrSuite) setModel(model *asserts.Model) { 627 deviceCtx := &snapstatetest.TrivialDeviceContext{ 628 DeviceModel: model, 629 CtxStore: s.fakeStore, 630 } 631 s.AddCleanup(snapstatetest.MockDeviceContext(deviceCtx)) 632 s.state.Set("seeded", true) 633 } 634 635 func (s *assertMgrSuite) setupModelAndStore(c *C) *asserts.Store { 636 // setup a model and store assertion 637 a := assertstest.FakeAssertion(map[string]interface{}{ 638 "type": "model", 639 "authority-id": "my-brand", 640 "series": "16", 641 "brand-id": "my-brand", 642 "model": "my-model", 643 "architecture": "amd64", 644 "store": "my-brand-store", 645 "gadget": "gadget", 646 "kernel": "krnl", 647 }) 648 s.setModel(a.(*asserts.Model)) 649 650 a, err := s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{ 651 "authority-id": s.storeSigning.AuthorityID, 652 "operator-id": s.storeSigning.AuthorityID, 653 "store": "my-brand-store", 654 "timestamp": time.Now().Format(time.RFC3339), 655 }, nil, "") 656 c.Assert(err, IsNil) 657 return a.(*asserts.Store) 658 } 659 660 func (s *assertMgrSuite) TestValidateSnap(c *C) { 661 s.prereqSnapAssertions(c, 10) 662 663 tempdir := c.MkDir() 664 snapPath := filepath.Join(tempdir, "foo.snap") 665 err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644) 666 c.Assert(err, IsNil) 667 668 s.state.Lock() 669 defer s.state.Unlock() 670 671 // have a model and the store assertion available 672 storeAs := s.setupModelAndStore(c) 673 err = s.storeSigning.Add(storeAs) 674 c.Assert(err, IsNil) 675 676 chg := s.state.NewChange("install", "...") 677 t := s.state.NewTask("validate-snap", "Fetch and check snap assertions") 678 snapsup := snapstate.SnapSetup{ 679 SnapPath: snapPath, 680 UserID: 0, 681 SideInfo: &snap.SideInfo{ 682 RealName: "foo", 683 SnapID: "snap-id-1", 684 Revision: snap.R(10), 685 }, 686 } 687 t.Set("snap-setup", snapsup) 688 chg.AddTask(t) 689 690 s.state.Unlock() 691 defer s.se.Stop() 692 s.settle(c) 693 s.state.Lock() 694 695 c.Assert(chg.Err(), IsNil) 696 697 snapRev, err := assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{ 698 "snap-id": "snap-id-1", 699 "snap-sha3-384": makeDigest(10), 700 }) 701 c.Assert(err, IsNil) 702 c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10) 703 704 // store assertion was also fetched 705 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 706 "store": "my-brand-store", 707 }) 708 c.Assert(err, IsNil) 709 } 710 711 func (s *assertMgrSuite) TestValidateSnapStoreNotFound(c *C) { 712 s.prereqSnapAssertions(c, 10) 713 714 tempdir := c.MkDir() 715 snapPath := filepath.Join(tempdir, "foo.snap") 716 err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644) 717 c.Assert(err, IsNil) 718 719 s.state.Lock() 720 defer s.state.Unlock() 721 722 // have a model and store but store assertion is not made available 723 s.setupModelAndStore(c) 724 725 chg := s.state.NewChange("install", "...") 726 t := s.state.NewTask("validate-snap", "Fetch and check snap assertions") 727 snapsup := snapstate.SnapSetup{ 728 SnapPath: snapPath, 729 UserID: 0, 730 SideInfo: &snap.SideInfo{ 731 RealName: "foo", 732 SnapID: "snap-id-1", 733 Revision: snap.R(10), 734 }, 735 } 736 t.Set("snap-setup", snapsup) 737 chg.AddTask(t) 738 739 s.state.Unlock() 740 defer s.se.Stop() 741 s.settle(c) 742 s.state.Lock() 743 744 c.Assert(chg.Err(), IsNil) 745 746 snapRev, err := assertstate.DB(s.state).Find(asserts.SnapRevisionType, map[string]string{ 747 "snap-id": "snap-id-1", 748 "snap-sha3-384": makeDigest(10), 749 }) 750 c.Assert(err, IsNil) 751 c.Check(snapRev.(*asserts.SnapRevision).SnapRevision(), Equals, 10) 752 753 // store assertion was not found and ignored 754 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 755 "store": "my-brand-store", 756 }) 757 c.Assert(asserts.IsNotFound(err), Equals, true) 758 } 759 760 func (s *assertMgrSuite) TestValidateSnapMissingSnapSetup(c *C) { 761 s.state.Lock() 762 defer s.state.Unlock() 763 764 chg := s.state.NewChange("install", "...") 765 t := s.state.NewTask("validate-snap", "Fetch and check snap assertions") 766 chg.AddTask(t) 767 768 s.state.Unlock() 769 defer s.se.Stop() 770 s.settle(c) 771 s.state.Lock() 772 773 c.Assert(chg.Err(), ErrorMatches, `(?s).*internal error: cannot obtain snap setup: no state entry for key.*`) 774 } 775 776 func (s *assertMgrSuite) TestValidateSnapNotFound(c *C) { 777 tempdir := c.MkDir() 778 snapPath := filepath.Join(tempdir, "foo.snap") 779 err := ioutil.WriteFile(snapPath, fakeSnap(33), 0644) 780 c.Assert(err, IsNil) 781 782 s.state.Lock() 783 defer s.state.Unlock() 784 785 s.setModel(sysdb.GenericClassicModel()) 786 787 chg := s.state.NewChange("install", "...") 788 t := s.state.NewTask("validate-snap", "Fetch and check snap assertions") 789 snapsup := snapstate.SnapSetup{ 790 SnapPath: snapPath, 791 UserID: 0, 792 SideInfo: &snap.SideInfo{ 793 RealName: "foo", 794 SnapID: "snap-id-1", 795 Revision: snap.R(33), 796 }, 797 } 798 t.Set("snap-setup", snapsup) 799 chg.AddTask(t) 800 801 s.state.Unlock() 802 defer s.se.Stop() 803 s.settle(c) 804 s.state.Lock() 805 806 c.Assert(chg.Err(), ErrorMatches, `(?s).*cannot verify snap "foo", no matching signatures found.*`) 807 } 808 809 func (s *assertMgrSuite) TestValidateSnapCrossCheckFail(c *C) { 810 s.prereqSnapAssertions(c, 10) 811 812 tempdir := c.MkDir() 813 snapPath := filepath.Join(tempdir, "foo.snap") 814 err := ioutil.WriteFile(snapPath, fakeSnap(10), 0644) 815 c.Assert(err, IsNil) 816 817 s.state.Lock() 818 defer s.state.Unlock() 819 820 s.setModel(sysdb.GenericClassicModel()) 821 822 chg := s.state.NewChange("install", "...") 823 t := s.state.NewTask("validate-snap", "Fetch and check snap assertions") 824 snapsup := snapstate.SnapSetup{ 825 SnapPath: snapPath, 826 UserID: 0, 827 SideInfo: &snap.SideInfo{ 828 RealName: "f", 829 SnapID: "snap-id-1", 830 Revision: snap.R(10), 831 }, 832 } 833 t.Set("snap-setup", snapsup) 834 chg.AddTask(t) 835 836 s.state.Unlock() 837 defer s.se.Stop() 838 s.settle(c) 839 s.state.Lock() 840 841 c.Assert(chg.Err(), ErrorMatches, `(?s).*cannot install "f", snap "f" is undergoing a rename to "foo".*`) 842 } 843 844 func (s *assertMgrSuite) snapDecl(c *C, name string, extraHeaders map[string]interface{}) *asserts.SnapDeclaration { 845 headers := map[string]interface{}{ 846 "series": "16", 847 "snap-id": name + "-id", 848 "snap-name": name, 849 "publisher-id": s.dev1Acct.AccountID(), 850 "timestamp": time.Now().Format(time.RFC3339), 851 } 852 for h, v := range extraHeaders { 853 headers[h] = v 854 } 855 decl, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 856 c.Assert(err, IsNil) 857 err = s.storeSigning.Add(decl) 858 c.Assert(err, IsNil) 859 return decl.(*asserts.SnapDeclaration) 860 } 861 862 func (s *assertMgrSuite) stateFromDecl(c *C, decl *asserts.SnapDeclaration, instanceName string, revno snap.Revision) { 863 snapName, instanceKey := snap.SplitInstanceName(instanceName) 864 if snapName == "" { 865 snapName = decl.SnapName() 866 instanceName = snapName 867 } 868 869 c.Assert(snapName, Equals, decl.SnapName()) 870 871 snapID := decl.SnapID() 872 snapstate.Set(s.state, instanceName, &snapstate.SnapState{ 873 Active: true, 874 Sequence: []*snap.SideInfo{ 875 {RealName: snapName, SnapID: snapID, Revision: revno}, 876 }, 877 Current: revno, 878 InstanceKey: instanceKey, 879 }) 880 } 881 882 func (s *assertMgrSuite) TestRefreshSnapDeclarationsTooEarly(c *C) { 883 s.state.Lock() 884 defer s.state.Unlock() 885 886 r := snapstatetest.MockDeviceModel(nil) 887 defer r() 888 889 err := assertstate.RefreshSnapDeclarations(s.state, 0) 890 c.Check(err, FitsTypeOf, &snapstate.ChangeConflictError{}) 891 } 892 893 func (s *assertMgrSuite) TestRefreshSnapDeclarationsNop(c *C) { 894 s.state.Lock() 895 defer s.state.Unlock() 896 897 s.setModel(sysdb.GenericClassicModel()) 898 899 err := assertstate.RefreshSnapDeclarations(s.state, 0) 900 c.Assert(err, IsNil) 901 } 902 903 func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStore(c *C) { 904 s.state.Lock() 905 defer s.state.Unlock() 906 907 s.setModel(sysdb.GenericClassicModel()) 908 909 snapDeclFoo := s.snapDecl(c, "foo", nil) 910 snapDeclBar := s.snapDecl(c, "bar", nil) 911 912 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 913 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 914 snapstate.Set(s.state, "local", &snapstate.SnapState{ 915 Active: false, 916 Sequence: []*snap.SideInfo{ 917 {RealName: "local", Revision: snap.R(-1)}, 918 }, 919 Current: snap.R(-1), 920 }) 921 922 // previous state 923 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 924 c.Assert(err, IsNil) 925 err = assertstate.Add(s.state, s.dev1Acct) 926 c.Assert(err, IsNil) 927 err = assertstate.Add(s.state, snapDeclFoo) 928 c.Assert(err, IsNil) 929 err = assertstate.Add(s.state, snapDeclBar) 930 c.Assert(err, IsNil) 931 932 // one changed assertion 933 headers := map[string]interface{}{ 934 "series": "16", 935 "snap-id": "foo-id", 936 "snap-name": "fo-o", 937 "publisher-id": s.dev1Acct.AccountID(), 938 "timestamp": time.Now().Format(time.RFC3339), 939 "revision": "1", 940 } 941 snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 942 c.Assert(err, IsNil) 943 err = s.storeSigning.Add(snapDeclFoo1) 944 c.Assert(err, IsNil) 945 946 err = assertstate.RefreshSnapDeclarations(s.state, 0) 947 c.Assert(err, IsNil) 948 949 a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 950 "series": "16", 951 "snap-id": "foo-id", 952 }) 953 c.Assert(err, IsNil) 954 c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o") 955 956 // another one 957 // one changed assertion 958 headers = s.dev1Acct.Headers() 959 headers["display-name"] = "Dev 1 edited display-name" 960 headers["revision"] = "1" 961 dev1Acct1, err := s.storeSigning.Sign(asserts.AccountType, headers, nil, "") 962 c.Assert(err, IsNil) 963 err = s.storeSigning.Add(dev1Acct1) 964 c.Assert(err, IsNil) 965 966 err = assertstate.RefreshSnapDeclarations(s.state, 0) 967 c.Assert(err, IsNil) 968 969 a, err = assertstate.DB(s.state).Find(asserts.AccountType, map[string]string{ 970 "account-id": s.dev1Acct.AccountID(), 971 }) 972 c.Assert(err, IsNil) 973 c.Check(a.(*asserts.Account).DisplayName(), Equals, "Dev 1 edited display-name") 974 975 // change snap decl to something that has a too new format 976 s.fakeStore.(*fakeStore).maxDeclSupportedFormat = 999 977 (func() { 978 restore := asserts.MockMaxSupportedFormat(asserts.SnapDeclarationType, 999) 979 defer restore() 980 981 headers := map[string]interface{}{ 982 "format": "999", 983 "series": "16", 984 "snap-id": "foo-id", 985 "snap-name": "foo", 986 "publisher-id": s.dev1Acct.AccountID(), 987 "timestamp": time.Now().Format(time.RFC3339), 988 "revision": "2", 989 } 990 991 snapDeclFoo2, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 992 c.Assert(err, IsNil) 993 err = s.storeSigning.Add(snapDeclFoo2) 994 c.Assert(err, IsNil) 995 })() 996 997 // no error, kept the old one 998 err = assertstate.RefreshSnapDeclarations(s.state, 0) 999 c.Assert(err, IsNil) 1000 1001 a, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 1002 "series": "16", 1003 "snap-id": "foo-id", 1004 }) 1005 c.Assert(err, IsNil) 1006 c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o") 1007 c.Check(a.(*asserts.SnapDeclaration).Revision(), Equals, 1) 1008 } 1009 1010 func (s *assertMgrSuite) TestRefreshSnapDeclarationsChangingKey(c *C) { 1011 s.state.Lock() 1012 defer s.state.Unlock() 1013 1014 s.setModel(sysdb.GenericClassicModel()) 1015 1016 snapDeclFoo := s.snapDecl(c, "foo", nil) 1017 1018 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1019 1020 // previous state 1021 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1022 c.Assert(err, IsNil) 1023 err = assertstate.Add(s.state, s.dev1Acct) 1024 c.Assert(err, IsNil) 1025 err = assertstate.Add(s.state, snapDeclFoo) 1026 c.Assert(err, IsNil) 1027 1028 storePrivKey2, _ := assertstest.GenerateKey(752) 1029 err = s.storeSigning.ImportKey(storePrivKey2) 1030 c.Assert(err, IsNil) 1031 storeKey2 := assertstest.NewAccountKey(s.storeSigning.RootSigning, s.storeSigning.TrustedAccount, map[string]interface{}{ 1032 "name": "store2", 1033 }, storePrivKey2.PublicKey(), "") 1034 err = s.storeSigning.Add(storeKey2) 1035 c.Assert(err, IsNil) 1036 1037 // one changed assertion signed with different key 1038 headers := map[string]interface{}{ 1039 "series": "16", 1040 "snap-id": "foo-id", 1041 "snap-name": "foo", 1042 "publisher-id": s.dev1Acct.AccountID(), 1043 "timestamp": time.Now().Format(time.RFC3339), 1044 "revision": "1", 1045 } 1046 storeKey2ID := storePrivKey2.PublicKey().ID() 1047 snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, storeKey2ID) 1048 c.Assert(err, IsNil) 1049 c.Check(snapDeclFoo1.SignKeyID(), Not(Equals), snapDeclFoo.SignKeyID()) 1050 err = s.storeSigning.Add(snapDeclFoo1) 1051 c.Assert(err, IsNil) 1052 1053 _, err = storeKey2.Ref().Resolve(assertstate.DB(s.state).Find) 1054 c.Check(asserts.IsNotFound(err), Equals, true) 1055 1056 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1057 c.Assert(err, IsNil) 1058 1059 a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 1060 "series": "16", 1061 "snap-id": "foo-id", 1062 }) 1063 c.Assert(err, IsNil) 1064 c.Check(a.Revision(), Equals, 1) 1065 c.Check(a.SignKeyID(), Equals, storeKey2ID) 1066 1067 // key was fetched as well 1068 _, err = storeKey2.Ref().Resolve(assertstate.DB(s.state).Find) 1069 c.Check(err, IsNil) 1070 } 1071 1072 func (s *assertMgrSuite) TestRefreshSnapDeclarationsWithStore(c *C) { 1073 s.state.Lock() 1074 defer s.state.Unlock() 1075 1076 storeAs := s.setupModelAndStore(c) 1077 1078 snapDeclFoo := s.snapDecl(c, "foo", nil) 1079 1080 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1081 1082 // previous state 1083 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1084 c.Assert(err, IsNil) 1085 err = assertstate.Add(s.state, s.dev1Acct) 1086 c.Assert(err, IsNil) 1087 err = assertstate.Add(s.state, snapDeclFoo) 1088 c.Assert(err, IsNil) 1089 1090 // one changed assertion 1091 headers := map[string]interface{}{ 1092 "series": "16", 1093 "snap-id": "foo-id", 1094 "snap-name": "fo-o", 1095 "publisher-id": s.dev1Acct.AccountID(), 1096 "timestamp": time.Now().Format(time.RFC3339), 1097 "revision": "1", 1098 } 1099 snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 1100 c.Assert(err, IsNil) 1101 err = s.storeSigning.Add(snapDeclFoo1) 1102 c.Assert(err, IsNil) 1103 1104 // store assertion is missing 1105 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1106 c.Assert(err, IsNil) 1107 1108 a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 1109 "series": "16", 1110 "snap-id": "foo-id", 1111 }) 1112 c.Assert(err, IsNil) 1113 c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "fo-o") 1114 1115 // changed again 1116 headers = map[string]interface{}{ 1117 "series": "16", 1118 "snap-id": "foo-id", 1119 "snap-name": "f-oo", 1120 "publisher-id": s.dev1Acct.AccountID(), 1121 "timestamp": time.Now().Format(time.RFC3339), 1122 "revision": "2", 1123 } 1124 snapDeclFoo2, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 1125 c.Assert(err, IsNil) 1126 err = s.storeSigning.Add(snapDeclFoo2) 1127 c.Assert(err, IsNil) 1128 1129 // store assertion is available 1130 err = s.storeSigning.Add(storeAs) 1131 c.Assert(err, IsNil) 1132 1133 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1134 c.Assert(err, IsNil) 1135 1136 a, err = assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 1137 "series": "16", 1138 "snap-id": "foo-id", 1139 }) 1140 c.Assert(err, IsNil) 1141 c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, "f-oo") 1142 1143 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 1144 "store": "my-brand-store", 1145 }) 1146 c.Assert(err, IsNil) 1147 1148 // store assertion has changed 1149 a, err = s.storeSigning.Sign(asserts.StoreType, map[string]interface{}{ 1150 "authority-id": s.storeSigning.AuthorityID, 1151 "operator-id": s.storeSigning.AuthorityID, 1152 "store": "my-brand-store", 1153 "location": "the-cloud", 1154 "revision": "1", 1155 "timestamp": time.Now().Format(time.RFC3339), 1156 }, nil, "") 1157 c.Assert(err, IsNil) 1158 storeAs = a.(*asserts.Store) 1159 err = s.storeSigning.Add(storeAs) 1160 c.Assert(err, IsNil) 1161 1162 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1163 c.Assert(err, IsNil) 1164 a, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 1165 "store": "my-brand-store", 1166 }) 1167 c.Assert(err, IsNil) 1168 c.Check(a.(*asserts.Store).Location(), Equals, "the-cloud") 1169 } 1170 1171 func (s *assertMgrSuite) TestRefreshSnapDeclarationsDownloadError(c *C) { 1172 s.state.Lock() 1173 defer s.state.Unlock() 1174 1175 s.setModel(sysdb.GenericClassicModel()) 1176 1177 snapDeclFoo := s.snapDecl(c, "foo", nil) 1178 1179 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1180 1181 // previous state 1182 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1183 c.Assert(err, IsNil) 1184 err = assertstate.Add(s.state, s.dev1Acct) 1185 c.Assert(err, IsNil) 1186 err = assertstate.Add(s.state, snapDeclFoo) 1187 c.Assert(err, IsNil) 1188 1189 // one changed assertion 1190 headers := map[string]interface{}{ 1191 "series": "16", 1192 "snap-id": "foo-id", 1193 "snap-name": "fo-o", 1194 "publisher-id": s.dev1Acct.AccountID(), 1195 "timestamp": time.Now().Format(time.RFC3339), 1196 "revision": "1", 1197 } 1198 snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 1199 c.Assert(err, IsNil) 1200 err = s.storeSigning.Add(snapDeclFoo1) 1201 c.Assert(err, IsNil) 1202 1203 s.fakeStore.(*fakeStore).downloadAssertionsErr = errors.New("download error") 1204 1205 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1206 c.Assert(err, ErrorMatches, `cannot refresh snap-declarations for snaps: 1207 - foo: download error`) 1208 } 1209 1210 func (s *assertMgrSuite) TestRefreshSnapDeclarationsPersistentNetworkError(c *C) { 1211 s.state.Lock() 1212 defer s.state.Unlock() 1213 1214 s.setModel(sysdb.GenericClassicModel()) 1215 1216 snapDeclFoo := s.snapDecl(c, "foo", nil) 1217 1218 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1219 1220 // previous state 1221 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1222 c.Assert(err, IsNil) 1223 err = assertstate.Add(s.state, s.dev1Acct) 1224 c.Assert(err, IsNil) 1225 err = assertstate.Add(s.state, snapDeclFoo) 1226 c.Assert(err, IsNil) 1227 1228 // one changed assertion 1229 headers := map[string]interface{}{ 1230 "series": "16", 1231 "snap-id": "foo-id", 1232 "snap-name": "fo-o", 1233 "publisher-id": s.dev1Acct.AccountID(), 1234 "timestamp": time.Now().Format(time.RFC3339), 1235 "revision": "1", 1236 } 1237 snapDeclFoo1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 1238 c.Assert(err, IsNil) 1239 err = s.storeSigning.Add(snapDeclFoo1) 1240 c.Assert(err, IsNil) 1241 1242 pne := new(httputil.PersistentNetworkError) 1243 s.fakeStore.(*fakeStore).snapActionErr = pne 1244 1245 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1246 c.Assert(err, Equals, pne) 1247 } 1248 1249 func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStoreFallback(c *C) { 1250 // test that if we get a 4xx or 500 error from the store trying bulk 1251 // assertion refresh we fall back to the old logic 1252 s.fakeStore.(*fakeStore).snapActionErr = &store.UnexpectedHTTPStatusError{StatusCode: 400} 1253 1254 logbuf, restore := logger.MockLogger() 1255 defer restore() 1256 1257 s.TestRefreshSnapDeclarationsNoStore(c) 1258 1259 c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*HTTP status code 400.*") 1260 } 1261 1262 func (s *assertMgrSuite) TestRefreshSnapDeclarationsNoStoreFallbackUnexpectedSnapActionError(c *C) { 1263 // test that if we get an unexpected SnapAction error from the 1264 // store trying bulk assertion refresh we fall back to the old 1265 // logic 1266 s.fakeStore.(*fakeStore).snapActionErr = &store.SnapActionError{ 1267 NoResults: true, 1268 Other: []error{errors.New("unexpected error")}, 1269 } 1270 1271 logbuf, restore := logger.MockLogger() 1272 defer restore() 1273 1274 s.TestRefreshSnapDeclarationsNoStore(c) 1275 1276 c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*unexpected error.*") 1277 } 1278 1279 func (s *assertMgrSuite) TestRefreshSnapDeclarationsWithStoreFallback(c *C) { 1280 // test that if we get a 4xx or 500 error from the store trying bulk 1281 // assertion refresh we fall back to the old logic 1282 s.fakeStore.(*fakeStore).snapActionErr = &store.UnexpectedHTTPStatusError{StatusCode: 500} 1283 1284 logbuf, restore := logger.MockLogger() 1285 defer restore() 1286 1287 s.TestRefreshSnapDeclarationsWithStore(c) 1288 1289 c.Check(logbuf.String(), Matches, "(?m).*bulk refresh of snap-declarations failed, falling back to one-by-one assertion fetching:.*HTTP status code 500.*") 1290 } 1291 1292 // the following tests cover what happens when refreshing snap-declarations 1293 // need to support overflowing the chosen asserts.Pool maximum groups 1294 1295 func (s *assertMgrSuite) testRefreshSnapDeclarationsMany(c *C, n int) error { 1296 // reduce maxGroups to test and stress the logic that deals 1297 // with overflowing it 1298 s.AddCleanup(assertstate.MockMaxGroups(16)) 1299 1300 // previous state 1301 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1302 c.Assert(err, IsNil) 1303 err = assertstate.Add(s.state, s.dev1Acct) 1304 c.Assert(err, IsNil) 1305 1306 for i := 1; i <= n; i++ { 1307 name := fmt.Sprintf("foo%d", i) 1308 snapDeclFooX := s.snapDecl(c, name, nil) 1309 1310 s.stateFromDecl(c, snapDeclFooX, "", snap.R(7+i)) 1311 1312 // previous state 1313 err = assertstate.Add(s.state, snapDeclFooX) 1314 c.Assert(err, IsNil) 1315 1316 // make an update on top 1317 headers := map[string]interface{}{ 1318 "series": "16", 1319 "snap-id": name + "-id", 1320 "snap-name": fmt.Sprintf("fo-o-%d", i), 1321 "publisher-id": s.dev1Acct.AccountID(), 1322 "timestamp": time.Now().Format(time.RFC3339), 1323 "revision": "1", 1324 } 1325 snapDeclFooX1, err := s.storeSigning.Sign(asserts.SnapDeclarationType, headers, nil, "") 1326 c.Assert(err, IsNil) 1327 err = s.storeSigning.Add(snapDeclFooX1) 1328 c.Assert(err, IsNil) 1329 } 1330 1331 err = assertstate.RefreshSnapDeclarations(s.state, 0) 1332 if err != nil { 1333 // fot the caller to check 1334 return err 1335 } 1336 1337 // check we got the updates 1338 for i := 1; i <= n; i++ { 1339 name := fmt.Sprintf("foo%d", i) 1340 a, err := assertstate.DB(s.state).Find(asserts.SnapDeclarationType, map[string]string{ 1341 "series": "16", 1342 "snap-id": name + "-id", 1343 }) 1344 c.Assert(err, IsNil) 1345 c.Check(a.(*asserts.SnapDeclaration).SnapName(), Equals, fmt.Sprintf("fo-o-%d", i)) 1346 } 1347 1348 return nil 1349 } 1350 1351 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany14NoStore(c *C) { 1352 s.state.Lock() 1353 defer s.state.Unlock() 1354 s.setModel(sysdb.GenericClassicModel()) 1355 1356 err := s.testRefreshSnapDeclarationsMany(c, 14) 1357 c.Assert(err, IsNil) 1358 1359 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1360 {"account", "account-key", "snap-declaration"}, 1361 }) 1362 } 1363 1364 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany16NoStore(c *C) { 1365 s.state.Lock() 1366 defer s.state.Unlock() 1367 s.setModel(sysdb.GenericClassicModel()) 1368 1369 err := s.testRefreshSnapDeclarationsMany(c, 16) 1370 c.Assert(err, IsNil) 1371 1372 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1373 {"account", "account-key", "snap-declaration"}, 1374 }) 1375 } 1376 1377 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany16WithStore(c *C) { 1378 s.state.Lock() 1379 defer s.state.Unlock() 1380 // have a model and the store assertion available 1381 storeAs := s.setupModelAndStore(c) 1382 err := s.storeSigning.Add(storeAs) 1383 c.Assert(err, IsNil) 1384 1385 err = s.testRefreshSnapDeclarationsMany(c, 16) 1386 c.Assert(err, IsNil) 1387 1388 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1389 // first 16 groups request 1390 {"account", "account-key", "snap-declaration"}, 1391 // final separate request covering store only 1392 {"store"}, 1393 }) 1394 1395 // store assertion was also fetched 1396 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 1397 "store": "my-brand-store", 1398 }) 1399 c.Assert(err, IsNil) 1400 } 1401 1402 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany17NoStore(c *C) { 1403 s.state.Lock() 1404 defer s.state.Unlock() 1405 s.setModel(sysdb.GenericClassicModel()) 1406 1407 err := s.testRefreshSnapDeclarationsMany(c, 17) 1408 c.Assert(err, IsNil) 1409 1410 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1411 // first 16 groups request 1412 {"account", "account-key", "snap-declaration"}, 1413 // final separate request for the rest 1414 {"snap-declaration"}, 1415 }) 1416 } 1417 1418 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany17NoStoreMergeErrors(c *C) { 1419 s.state.Lock() 1420 defer s.state.Unlock() 1421 s.setModel(sysdb.GenericClassicModel()) 1422 1423 s.fakeStore.(*fakeStore).downloadAssertionsErr = errors.New("download error") 1424 1425 err := s.testRefreshSnapDeclarationsMany(c, 17) 1426 c.Check(err, ErrorMatches, `(?s)cannot refresh snap-declarations for snaps: 1427 - foo1: download error.* - foo9: download error`) 1428 // all foo* snaps accounted for 1429 c.Check(strings.Count(err.Error(), "foo"), Equals, 17) 1430 1431 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1432 // first 16 groups request 1433 {"account", "account-key", "snap-declaration"}, 1434 // final separate request for the rest 1435 {"snap-declaration"}, 1436 }) 1437 } 1438 1439 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany31WithStore(c *C) { 1440 s.state.Lock() 1441 defer s.state.Unlock() 1442 // have a model and the store assertion available 1443 storeAs := s.setupModelAndStore(c) 1444 err := s.storeSigning.Add(storeAs) 1445 c.Assert(err, IsNil) 1446 1447 err = s.testRefreshSnapDeclarationsMany(c, 31) 1448 c.Assert(err, IsNil) 1449 1450 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1451 // first 16 groups request 1452 {"account", "account-key", "snap-declaration"}, 1453 // final separate request for the rest and store 1454 {"snap-declaration", "store"}, 1455 }) 1456 1457 // store assertion was also fetched 1458 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 1459 "store": "my-brand-store", 1460 }) 1461 c.Assert(err, IsNil) 1462 } 1463 1464 func (s *assertMgrSuite) TestRefreshSnapDeclarationsMany32WithStore(c *C) { 1465 s.state.Lock() 1466 defer s.state.Unlock() 1467 // have a model and the store assertion available 1468 storeAs := s.setupModelAndStore(c) 1469 err := s.storeSigning.Add(storeAs) 1470 c.Assert(err, IsNil) 1471 1472 err = s.testRefreshSnapDeclarationsMany(c, 32) 1473 c.Assert(err, IsNil) 1474 1475 c.Check(s.fakeStore.(*fakeStore).requestedTypes, DeepEquals, [][]string{ 1476 // first 16 groups request 1477 {"account", "account-key", "snap-declaration"}, 1478 // 2nd round request 1479 {"snap-declaration"}, 1480 // final separate request covering store 1481 {"store"}, 1482 }) 1483 1484 // store assertion was also fetched 1485 _, err = assertstate.DB(s.state).Find(asserts.StoreType, map[string]string{ 1486 "store": "my-brand-store", 1487 }) 1488 c.Assert(err, IsNil) 1489 } 1490 1491 func (s *assertMgrSuite) TestValidateRefreshesNothing(c *C) { 1492 s.state.Lock() 1493 defer s.state.Unlock() 1494 1495 validated, err := assertstate.ValidateRefreshes(s.state, nil, nil, 0, s.trivialDeviceCtx) 1496 c.Assert(err, IsNil) 1497 c.Check(validated, HasLen, 0) 1498 } 1499 1500 func (s *assertMgrSuite) TestValidateRefreshesNoControl(c *C) { 1501 s.state.Lock() 1502 defer s.state.Unlock() 1503 1504 snapDeclFoo := s.snapDecl(c, "foo", nil) 1505 snapDeclBar := s.snapDecl(c, "bar", nil) 1506 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1507 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1508 1509 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1510 c.Assert(err, IsNil) 1511 err = assertstate.Add(s.state, s.dev1Acct) 1512 c.Assert(err, IsNil) 1513 err = assertstate.Add(s.state, snapDeclFoo) 1514 c.Assert(err, IsNil) 1515 err = assertstate.Add(s.state, snapDeclBar) 1516 c.Assert(err, IsNil) 1517 1518 fooRefresh := &snap.Info{ 1519 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1520 } 1521 1522 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx) 1523 c.Assert(err, IsNil) 1524 c.Check(validated, DeepEquals, []*snap.Info{fooRefresh}) 1525 } 1526 1527 func (s *assertMgrSuite) TestValidateRefreshesMissingValidation(c *C) { 1528 s.state.Lock() 1529 defer s.state.Unlock() 1530 1531 snapDeclFoo := s.snapDecl(c, "foo", nil) 1532 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1533 "refresh-control": []interface{}{"foo-id"}, 1534 }) 1535 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1536 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1537 1538 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1539 c.Assert(err, IsNil) 1540 err = assertstate.Add(s.state, s.dev1Acct) 1541 c.Assert(err, IsNil) 1542 err = assertstate.Add(s.state, snapDeclFoo) 1543 c.Assert(err, IsNil) 1544 err = assertstate.Add(s.state, snapDeclBar) 1545 c.Assert(err, IsNil) 1546 1547 fooRefresh := &snap.Info{ 1548 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1549 } 1550 1551 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx) 1552 c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`) 1553 c.Check(validated, HasLen, 0) 1554 } 1555 1556 func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidation(c *C) { 1557 s.state.Lock() 1558 defer s.state.Unlock() 1559 1560 snapDeclFoo := s.snapDecl(c, "foo", nil) 1561 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1562 "refresh-control": []interface{}{"foo-id"}, 1563 }) 1564 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1565 s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7)) 1566 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1567 1568 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1569 c.Assert(err, IsNil) 1570 err = assertstate.Add(s.state, s.dev1Acct) 1571 c.Assert(err, IsNil) 1572 err = assertstate.Add(s.state, snapDeclFoo) 1573 c.Assert(err, IsNil) 1574 err = assertstate.Add(s.state, snapDeclBar) 1575 c.Assert(err, IsNil) 1576 1577 fooInstanceRefresh := &snap.Info{ 1578 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1579 InstanceKey: "instance", 1580 } 1581 1582 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooInstanceRefresh}, nil, 0, s.trivialDeviceCtx) 1583 c.Assert(err, ErrorMatches, `cannot refresh "foo_instance" to revision 9: no validation by "bar"`) 1584 c.Check(validated, HasLen, 0) 1585 } 1586 1587 func (s *assertMgrSuite) TestValidateRefreshesMissingValidationButIgnore(c *C) { 1588 s.state.Lock() 1589 defer s.state.Unlock() 1590 1591 snapDeclFoo := s.snapDecl(c, "foo", nil) 1592 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1593 "refresh-control": []interface{}{"foo-id"}, 1594 }) 1595 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1596 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1597 1598 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1599 c.Assert(err, IsNil) 1600 err = assertstate.Add(s.state, s.dev1Acct) 1601 c.Assert(err, IsNil) 1602 err = assertstate.Add(s.state, snapDeclFoo) 1603 c.Assert(err, IsNil) 1604 err = assertstate.Add(s.state, snapDeclBar) 1605 c.Assert(err, IsNil) 1606 1607 fooRefresh := &snap.Info{ 1608 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1609 } 1610 1611 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, map[string]bool{"foo": true}, 0, s.trivialDeviceCtx) 1612 c.Assert(err, IsNil) 1613 c.Check(validated, DeepEquals, []*snap.Info{fooRefresh}) 1614 } 1615 1616 func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnore(c *C) { 1617 s.state.Lock() 1618 defer s.state.Unlock() 1619 1620 snapDeclFoo := s.snapDecl(c, "foo", nil) 1621 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1622 "refresh-control": []interface{}{"foo-id"}, 1623 }) 1624 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1625 s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7)) 1626 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1627 1628 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1629 c.Assert(err, IsNil) 1630 err = assertstate.Add(s.state, s.dev1Acct) 1631 c.Assert(err, IsNil) 1632 err = assertstate.Add(s.state, snapDeclFoo) 1633 c.Assert(err, IsNil) 1634 err = assertstate.Add(s.state, snapDeclBar) 1635 c.Assert(err, IsNil) 1636 1637 fooRefresh := &snap.Info{ 1638 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1639 } 1640 fooInstanceRefresh := &snap.Info{ 1641 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1642 InstanceKey: "instance", 1643 } 1644 1645 // validation is ignore for foo_instance but not for foo 1646 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx) 1647 c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`) 1648 c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh}) 1649 } 1650 1651 func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnoreInstanceKeyed(c *C) { 1652 s.state.Lock() 1653 defer s.state.Unlock() 1654 1655 snapDeclFoo := s.snapDecl(c, "foo", nil) 1656 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1657 "refresh-control": []interface{}{"foo-id"}, 1658 }) 1659 s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7)) 1660 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1661 1662 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1663 c.Assert(err, IsNil) 1664 err = assertstate.Add(s.state, s.dev1Acct) 1665 c.Assert(err, IsNil) 1666 err = assertstate.Add(s.state, snapDeclFoo) 1667 c.Assert(err, IsNil) 1668 err = assertstate.Add(s.state, snapDeclBar) 1669 c.Assert(err, IsNil) 1670 1671 fooInstanceRefresh := &snap.Info{ 1672 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1673 InstanceKey: "instance", 1674 } 1675 1676 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx) 1677 c.Assert(err, IsNil) 1678 c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh}) 1679 } 1680 1681 func (s *assertMgrSuite) TestParallelInstanceValidateRefreshesMissingValidationButIgnoreBothOneIgnored(c *C) { 1682 s.state.Lock() 1683 defer s.state.Unlock() 1684 1685 snapDeclFoo := s.snapDecl(c, "foo", nil) 1686 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1687 "refresh-control": []interface{}{"foo-id"}, 1688 }) 1689 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1690 s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7)) 1691 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1692 1693 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1694 c.Assert(err, IsNil) 1695 err = assertstate.Add(s.state, s.dev1Acct) 1696 c.Assert(err, IsNil) 1697 err = assertstate.Add(s.state, snapDeclFoo) 1698 c.Assert(err, IsNil) 1699 err = assertstate.Add(s.state, snapDeclBar) 1700 c.Assert(err, IsNil) 1701 1702 fooRefresh := &snap.Info{ 1703 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1704 } 1705 fooInstanceRefresh := &snap.Info{ 1706 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1707 InstanceKey: "instance", 1708 } 1709 1710 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, map[string]bool{"foo_instance": true}, 0, s.trivialDeviceCtx) 1711 c.Assert(err, ErrorMatches, `cannot refresh "foo" to revision 9: no validation by "bar"`) 1712 c.Check(validated, DeepEquals, []*snap.Info{fooInstanceRefresh}) 1713 } 1714 1715 func (s *assertMgrSuite) TestValidateRefreshesValidationOK(c *C) { 1716 s.state.Lock() 1717 defer s.state.Unlock() 1718 1719 snapDeclFoo := s.snapDecl(c, "foo", nil) 1720 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1721 "refresh-control": []interface{}{"foo-id"}, 1722 }) 1723 snapDeclBaz := s.snapDecl(c, "baz", map[string]interface{}{ 1724 "refresh-control": []interface{}{"foo-id"}, 1725 }) 1726 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1727 s.stateFromDecl(c, snapDeclFoo, "foo_instance", snap.R(7)) 1728 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1729 s.stateFromDecl(c, snapDeclBaz, "", snap.R(1)) 1730 snapstate.Set(s.state, "local", &snapstate.SnapState{ 1731 Active: false, 1732 Sequence: []*snap.SideInfo{ 1733 {RealName: "local", Revision: snap.R(-1)}, 1734 }, 1735 Current: snap.R(-1), 1736 }) 1737 1738 // validation by bar 1739 headers := map[string]interface{}{ 1740 "series": "16", 1741 "snap-id": "bar-id", 1742 "approved-snap-id": "foo-id", 1743 "approved-snap-revision": "9", 1744 "timestamp": time.Now().Format(time.RFC3339), 1745 } 1746 barValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "") 1747 c.Assert(err, IsNil) 1748 err = s.storeSigning.Add(barValidation) 1749 c.Assert(err, IsNil) 1750 1751 // validation by baz 1752 headers = map[string]interface{}{ 1753 "series": "16", 1754 "snap-id": "baz-id", 1755 "approved-snap-id": "foo-id", 1756 "approved-snap-revision": "9", 1757 "timestamp": time.Now().Format(time.RFC3339), 1758 } 1759 bazValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "") 1760 c.Assert(err, IsNil) 1761 err = s.storeSigning.Add(bazValidation) 1762 c.Assert(err, IsNil) 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 err = assertstate.Add(s.state, snapDeclBaz) 1773 c.Assert(err, IsNil) 1774 1775 fooRefresh := &snap.Info{ 1776 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1777 } 1778 fooInstanceRefresh := &snap.Info{ 1779 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1780 InstanceKey: "instance", 1781 } 1782 1783 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh, fooInstanceRefresh}, nil, 0, s.trivialDeviceCtx) 1784 c.Assert(err, IsNil) 1785 c.Check(validated, DeepEquals, []*snap.Info{fooRefresh, fooInstanceRefresh}) 1786 } 1787 1788 func (s *assertMgrSuite) TestValidateRefreshesRevokedValidation(c *C) { 1789 s.state.Lock() 1790 defer s.state.Unlock() 1791 1792 snapDeclFoo := s.snapDecl(c, "foo", nil) 1793 snapDeclBar := s.snapDecl(c, "bar", map[string]interface{}{ 1794 "refresh-control": []interface{}{"foo-id"}, 1795 }) 1796 snapDeclBaz := s.snapDecl(c, "baz", map[string]interface{}{ 1797 "refresh-control": []interface{}{"foo-id"}, 1798 }) 1799 s.stateFromDecl(c, snapDeclFoo, "", snap.R(7)) 1800 s.stateFromDecl(c, snapDeclBar, "", snap.R(3)) 1801 s.stateFromDecl(c, snapDeclBaz, "", snap.R(1)) 1802 snapstate.Set(s.state, "local", &snapstate.SnapState{ 1803 Active: false, 1804 Sequence: []*snap.SideInfo{ 1805 {RealName: "local", Revision: snap.R(-1)}, 1806 }, 1807 Current: snap.R(-1), 1808 }) 1809 1810 // validation by bar 1811 headers := map[string]interface{}{ 1812 "series": "16", 1813 "snap-id": "bar-id", 1814 "approved-snap-id": "foo-id", 1815 "approved-snap-revision": "9", 1816 "timestamp": time.Now().Format(time.RFC3339), 1817 } 1818 barValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "") 1819 c.Assert(err, IsNil) 1820 err = s.storeSigning.Add(barValidation) 1821 c.Assert(err, IsNil) 1822 1823 // revoked validation by baz 1824 headers = map[string]interface{}{ 1825 "series": "16", 1826 "snap-id": "baz-id", 1827 "approved-snap-id": "foo-id", 1828 "approved-snap-revision": "9", 1829 "revoked": "true", 1830 "timestamp": time.Now().Format(time.RFC3339), 1831 } 1832 bazValidation, err := s.dev1Signing.Sign(asserts.ValidationType, headers, nil, "") 1833 c.Assert(err, IsNil) 1834 err = s.storeSigning.Add(bazValidation) 1835 c.Assert(err, IsNil) 1836 1837 err = assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1838 c.Assert(err, IsNil) 1839 err = assertstate.Add(s.state, s.dev1Acct) 1840 c.Assert(err, IsNil) 1841 err = assertstate.Add(s.state, snapDeclFoo) 1842 c.Assert(err, IsNil) 1843 err = assertstate.Add(s.state, snapDeclBar) 1844 c.Assert(err, IsNil) 1845 err = assertstate.Add(s.state, snapDeclBaz) 1846 c.Assert(err, IsNil) 1847 1848 fooRefresh := &snap.Info{ 1849 SideInfo: snap.SideInfo{RealName: "foo", SnapID: "foo-id", Revision: snap.R(9)}, 1850 } 1851 1852 validated, err := assertstate.ValidateRefreshes(s.state, []*snap.Info{fooRefresh}, nil, 0, s.trivialDeviceCtx) 1853 c.Assert(err, ErrorMatches, `(?s).*cannot refresh "foo" to revision 9: validation by "baz" \(id "baz-id"\) revoked.*`) 1854 c.Check(validated, HasLen, 0) 1855 } 1856 1857 func (s *assertMgrSuite) TestBaseSnapDeclaration(c *C) { 1858 s.state.Lock() 1859 defer s.state.Unlock() 1860 1861 r1 := assertstest.MockBuiltinBaseDeclaration(nil) 1862 defer r1() 1863 1864 baseDecl, err := assertstate.BaseDeclaration(s.state) 1865 c.Assert(asserts.IsNotFound(err), Equals, true) 1866 c.Check(baseDecl, IsNil) 1867 1868 r2 := assertstest.MockBuiltinBaseDeclaration([]byte(` 1869 type: base-declaration 1870 authority-id: canonical 1871 series: 16 1872 plugs: 1873 iface: true 1874 `)) 1875 defer r2() 1876 1877 baseDecl, err = assertstate.BaseDeclaration(s.state) 1878 c.Assert(err, IsNil) 1879 c.Check(baseDecl, NotNil) 1880 c.Check(baseDecl.PlugRule("iface"), NotNil) 1881 } 1882 1883 func (s *assertMgrSuite) TestSnapDeclaration(c *C) { 1884 s.state.Lock() 1885 defer s.state.Unlock() 1886 1887 // have a declaration in the system db 1888 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1889 c.Assert(err, IsNil) 1890 err = assertstate.Add(s.state, s.dev1Acct) 1891 c.Assert(err, IsNil) 1892 snapDeclFoo := s.snapDecl(c, "foo", nil) 1893 err = assertstate.Add(s.state, snapDeclFoo) 1894 c.Assert(err, IsNil) 1895 1896 _, err = assertstate.SnapDeclaration(s.state, "snap-id-other") 1897 c.Check(asserts.IsNotFound(err), Equals, true) 1898 1899 snapDecl, err := assertstate.SnapDeclaration(s.state, "foo-id") 1900 c.Assert(err, IsNil) 1901 c.Check(snapDecl.SnapName(), Equals, "foo") 1902 } 1903 1904 func (s *assertMgrSuite) TestAutoAliasesTemporaryFallback(c *C) { 1905 s.state.Lock() 1906 defer s.state.Unlock() 1907 1908 // prereqs for developer assertions in the system db 1909 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1910 c.Assert(err, IsNil) 1911 err = assertstate.Add(s.state, s.dev1Acct) 1912 c.Assert(err, IsNil) 1913 1914 // not from the store 1915 aliases, err := assertstate.AutoAliases(s.state, &snap.Info{SuggestedName: "local"}) 1916 c.Assert(err, IsNil) 1917 c.Check(aliases, HasLen, 0) 1918 1919 // missing 1920 _, err = assertstate.AutoAliases(s.state, &snap.Info{ 1921 SideInfo: snap.SideInfo{ 1922 RealName: "baz", 1923 SnapID: "baz-id", 1924 }, 1925 }) 1926 c.Check(err, ErrorMatches, `internal error: cannot find snap-declaration for installed snap "baz": snap-declaration \(baz-id; series:16\) not found`) 1927 1928 info := snaptest.MockInfo(c, ` 1929 name: foo 1930 version: 0 1931 apps: 1932 cmd1: 1933 aliases: [alias1] 1934 cmd2: 1935 aliases: [alias2] 1936 `, &snap.SideInfo{ 1937 RealName: "foo", 1938 SnapID: "foo-id", 1939 }) 1940 1941 // empty list 1942 // have a declaration in the system db 1943 snapDeclFoo := s.snapDecl(c, "foo", nil) 1944 err = assertstate.Add(s.state, snapDeclFoo) 1945 c.Assert(err, IsNil) 1946 aliases, err = assertstate.AutoAliases(s.state, info) 1947 c.Assert(err, IsNil) 1948 c.Check(aliases, HasLen, 0) 1949 1950 // some aliases 1951 snapDeclFoo = s.snapDecl(c, "foo", map[string]interface{}{ 1952 "auto-aliases": []interface{}{"alias1", "alias2", "alias3"}, 1953 "revision": "1", 1954 }) 1955 err = assertstate.Add(s.state, snapDeclFoo) 1956 c.Assert(err, IsNil) 1957 aliases, err = assertstate.AutoAliases(s.state, info) 1958 c.Assert(err, IsNil) 1959 c.Check(aliases, DeepEquals, map[string]string{ 1960 "alias1": "cmd1", 1961 "alias2": "cmd2", 1962 }) 1963 } 1964 1965 func (s *assertMgrSuite) TestAutoAliasesExplicit(c *C) { 1966 s.state.Lock() 1967 defer s.state.Unlock() 1968 1969 // prereqs for developer assertions in the system db 1970 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 1971 c.Assert(err, IsNil) 1972 err = assertstate.Add(s.state, s.dev1Acct) 1973 c.Assert(err, IsNil) 1974 1975 // not from the store 1976 aliases, err := assertstate.AutoAliases(s.state, &snap.Info{SuggestedName: "local"}) 1977 c.Assert(err, IsNil) 1978 c.Check(aliases, HasLen, 0) 1979 1980 // missing 1981 _, err = assertstate.AutoAliases(s.state, &snap.Info{ 1982 SideInfo: snap.SideInfo{ 1983 RealName: "baz", 1984 SnapID: "baz-id", 1985 }, 1986 }) 1987 c.Check(err, ErrorMatches, `internal error: cannot find snap-declaration for installed snap "baz": snap-declaration \(baz-id; series:16\) not found`) 1988 1989 // empty list 1990 // have a declaration in the system db 1991 snapDeclFoo := s.snapDecl(c, "foo", nil) 1992 err = assertstate.Add(s.state, snapDeclFoo) 1993 c.Assert(err, IsNil) 1994 aliases, err = assertstate.AutoAliases(s.state, &snap.Info{ 1995 SideInfo: snap.SideInfo{ 1996 RealName: "foo", 1997 SnapID: "foo-id", 1998 }, 1999 }) 2000 c.Assert(err, IsNil) 2001 c.Check(aliases, HasLen, 0) 2002 2003 // some aliases 2004 snapDeclFoo = s.snapDecl(c, "foo", map[string]interface{}{ 2005 "aliases": []interface{}{ 2006 map[string]interface{}{ 2007 "name": "alias1", 2008 "target": "cmd1", 2009 }, 2010 map[string]interface{}{ 2011 "name": "alias2", 2012 "target": "cmd2", 2013 }, 2014 }, 2015 "revision": "1", 2016 }) 2017 err = assertstate.Add(s.state, snapDeclFoo) 2018 c.Assert(err, IsNil) 2019 aliases, err = assertstate.AutoAliases(s.state, &snap.Info{ 2020 SideInfo: snap.SideInfo{ 2021 RealName: "foo", 2022 SnapID: "foo-id", 2023 }, 2024 }) 2025 c.Assert(err, IsNil) 2026 c.Check(aliases, DeepEquals, map[string]string{ 2027 "alias1": "cmd1", 2028 "alias2": "cmd2", 2029 }) 2030 } 2031 2032 func (s *assertMgrSuite) TestPublisher(c *C) { 2033 s.state.Lock() 2034 defer s.state.Unlock() 2035 2036 // have a declaration in the system db 2037 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 2038 c.Assert(err, IsNil) 2039 err = assertstate.Add(s.state, s.dev1Acct) 2040 c.Assert(err, IsNil) 2041 snapDeclFoo := s.snapDecl(c, "foo", nil) 2042 err = assertstate.Add(s.state, snapDeclFoo) 2043 c.Assert(err, IsNil) 2044 2045 _, err = assertstate.SnapDeclaration(s.state, "snap-id-other") 2046 c.Check(asserts.IsNotFound(err), Equals, true) 2047 2048 acct, err := assertstate.Publisher(s.state, "foo-id") 2049 c.Assert(err, IsNil) 2050 c.Check(acct.AccountID(), Equals, s.dev1Acct.AccountID()) 2051 c.Check(acct.Username(), Equals, "developer1") 2052 } 2053 2054 func (s *assertMgrSuite) TestStore(c *C) { 2055 s.state.Lock() 2056 defer s.state.Unlock() 2057 2058 err := assertstate.Add(s.state, s.storeSigning.StoreAccountKey("")) 2059 c.Assert(err, IsNil) 2060 err = assertstate.Add(s.state, s.dev1Acct) 2061 c.Assert(err, IsNil) 2062 storeHeaders := map[string]interface{}{ 2063 "store": "foo", 2064 "operator-id": s.dev1Acct.AccountID(), 2065 "timestamp": time.Now().Format(time.RFC3339), 2066 } 2067 fooStore, err := s.storeSigning.Sign(asserts.StoreType, storeHeaders, nil, "") 2068 c.Assert(err, IsNil) 2069 err = assertstate.Add(s.state, fooStore) 2070 c.Assert(err, IsNil) 2071 2072 _, err = assertstate.Store(s.state, "bar") 2073 c.Check(asserts.IsNotFound(err), Equals, true) 2074 2075 store, err := assertstate.Store(s.state, "foo") 2076 c.Assert(err, IsNil) 2077 c.Check(store.Store(), Equals, "foo") 2078 }