mirror of
https://github.com/token2/snapd.git
synced 2026-03-13 11:15:47 -07:00
1628 lines
49 KiB
Go
1628 lines
49 KiB
Go
// -*- Mode: Go; indent-tabs-mode: t -*-
|
|
|
|
/*
|
|
* Copyright (C) 2015-2022 Canonical Ltd
|
|
*
|
|
* This program is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 3 as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
package asserts_test
|
|
|
|
import (
|
|
"bytes"
|
|
"crypto"
|
|
"encoding/base64"
|
|
"errors"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"testing"
|
|
"time"
|
|
|
|
"golang.org/x/crypto/openpgp/packet"
|
|
"golang.org/x/crypto/sha3"
|
|
. "gopkg.in/check.v1"
|
|
|
|
"github.com/snapcore/snapd/asserts"
|
|
"github.com/snapcore/snapd/asserts/assertstest"
|
|
"github.com/snapcore/snapd/testutil"
|
|
)
|
|
|
|
func Test(t *testing.T) { TestingT(t) }
|
|
|
|
var _ = Suite(&openSuite{})
|
|
var _ = Suite(&revisionErrorSuite{})
|
|
var _ = Suite(&isUnacceptedUpdateSuite{})
|
|
|
|
type openSuite struct{}
|
|
|
|
func (opens *openSuite) TestOpenDatabaseOK(c *C) {
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: asserts.NewMemoryBackstore(),
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
c.Assert(db, NotNil)
|
|
}
|
|
|
|
func (opens *openSuite) TestOpenDatabaseTrustedAccount(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"account-id": "trusted",
|
|
"display-name": "Trusted",
|
|
"validation": "verified",
|
|
"timestamp": "2015-01-01T14:00:00Z",
|
|
}
|
|
acct, err := asserts.AssembleAndSignInTest(asserts.AccountType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: asserts.NewMemoryBackstore(),
|
|
Trusted: []asserts.Assertion{acct},
|
|
}
|
|
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
a, err := db.Find(asserts.AccountType, map[string]string{
|
|
"account-id": "trusted",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
acct1 := a.(*asserts.Account)
|
|
c.Check(acct1.AccountID(), Equals, "trusted")
|
|
c.Check(acct1.DisplayName(), Equals, "Trusted")
|
|
|
|
c.Check(db.IsTrustedAccount("trusted"), Equals, true)
|
|
|
|
// empty account id (invalid) is not trusted
|
|
c.Check(db.IsTrustedAccount(""), Equals, false)
|
|
}
|
|
|
|
func (opens *openSuite) TestOpenDatabaseTrustedWrongType(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "0",
|
|
}
|
|
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Trusted: []asserts.Assertion{a},
|
|
}
|
|
|
|
_, err = asserts.OpenDatabase(cfg)
|
|
c.Assert(err, ErrorMatches, "cannot predefine trusted assertions that are not account-key or account: test-only")
|
|
}
|
|
|
|
type databaseSuite struct {
|
|
topDir string
|
|
db *asserts.Database
|
|
}
|
|
|
|
var _ = Suite(&databaseSuite{})
|
|
|
|
func (dbs *databaseSuite) SetUpTest(c *C) {
|
|
dbs.topDir = filepath.Join(c.MkDir(), "asserts-db")
|
|
fsKeypairMgr, err := asserts.OpenFSKeypairManager(dbs.topDir)
|
|
c.Assert(err, IsNil)
|
|
cfg := &asserts.DatabaseConfig{
|
|
KeypairManager: fsKeypairMgr,
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
dbs.db = db
|
|
}
|
|
|
|
func (dbs *databaseSuite) TestImportKey(c *C) {
|
|
err := dbs.db.ImportKey(testPrivKey1)
|
|
c.Assert(err, IsNil)
|
|
|
|
keyPath := filepath.Join(dbs.topDir, "private-keys-v1", testPrivKey1SHA3_384)
|
|
info, err := os.Stat(keyPath)
|
|
c.Assert(err, IsNil)
|
|
c.Check(info.Mode().Perm(), Equals, os.FileMode(0600)) // secret
|
|
// too much "clear box" testing? ok at least until we have
|
|
// more functionality
|
|
privKey, err := ioutil.ReadFile(keyPath)
|
|
c.Assert(err, IsNil)
|
|
|
|
privKeyFromDisk, err := asserts.DecodePrivateKeyInTest(privKey)
|
|
c.Assert(err, IsNil)
|
|
|
|
c.Check(privKeyFromDisk.PublicKey().ID(), Equals, testPrivKey1SHA3_384)
|
|
}
|
|
|
|
func (dbs *databaseSuite) TestImportKeyAlreadyExists(c *C) {
|
|
err := dbs.db.ImportKey(testPrivKey1)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = dbs.db.ImportKey(testPrivKey1)
|
|
c.Check(err, ErrorMatches, "key pair with given key id already exists")
|
|
}
|
|
|
|
func (dbs *databaseSuite) TestPublicKey(c *C) {
|
|
pk := testPrivKey1
|
|
keyID := pk.PublicKey().ID()
|
|
err := dbs.db.ImportKey(pk)
|
|
c.Assert(err, IsNil)
|
|
|
|
pubk, err := dbs.db.PublicKey(keyID)
|
|
c.Assert(err, IsNil)
|
|
c.Check(pubk.ID(), Equals, keyID)
|
|
|
|
// usual pattern is to then encode it
|
|
encoded, err := asserts.EncodePublicKey(pubk)
|
|
c.Assert(err, IsNil)
|
|
data, err := base64.StdEncoding.DecodeString(string(encoded))
|
|
c.Assert(err, IsNil)
|
|
c.Check(data[0], Equals, uint8(1)) // v1
|
|
|
|
// check details of packet
|
|
const newHeaderBits = 0x80 | 0x40
|
|
c.Check(data[1]&newHeaderBits, Equals, uint8(newHeaderBits))
|
|
c.Check(data[2] < 192, Equals, true) // small packet, 1 byte length
|
|
c.Check(data[3], Equals, uint8(4)) // openpgp v4
|
|
pkt, err := packet.Read(bytes.NewBuffer(data[1:]))
|
|
c.Assert(err, IsNil)
|
|
pubKey, ok := pkt.(*packet.PublicKey)
|
|
c.Assert(ok, Equals, true)
|
|
c.Check(pubKey.PubKeyAlgo, Equals, packet.PubKeyAlgoRSA)
|
|
c.Check(pubKey.IsSubkey, Equals, false)
|
|
fixedTimestamp := time.Date(2016, time.January, 1, 0, 0, 0, 0, time.UTC)
|
|
c.Check(pubKey.CreationTime.Equal(fixedTimestamp), Equals, true)
|
|
// hash of blob content == hash of key
|
|
h384 := sha3.Sum384(data)
|
|
encHash := base64.RawURLEncoding.EncodeToString(h384[:])
|
|
c.Check(encHash, DeepEquals, testPrivKey1SHA3_384)
|
|
}
|
|
|
|
func (dbs *databaseSuite) TestPublicKeyNotFound(c *C) {
|
|
pk := testPrivKey1
|
|
keyID := pk.PublicKey().ID()
|
|
|
|
_, err := dbs.db.PublicKey(keyID)
|
|
c.Check(err, ErrorMatches, "cannot find key pair")
|
|
|
|
err = dbs.db.ImportKey(pk)
|
|
c.Assert(err, IsNil)
|
|
|
|
_, err = dbs.db.PublicKey("ff" + keyID)
|
|
c.Check(err, ErrorMatches, "cannot find key pair")
|
|
}
|
|
|
|
func (dbs *databaseSuite) TestNotFoundErrorIs(c *C) {
|
|
this := &asserts.NotFoundError{
|
|
Headers: map[string]string{"a": "a"},
|
|
Type: asserts.ValidationSetType,
|
|
}
|
|
that := &asserts.NotFoundError{
|
|
Headers: map[string]string{"b": "b"},
|
|
Type: asserts.RepairType,
|
|
}
|
|
c.Check(this, testutil.ErrorIs, that)
|
|
}
|
|
|
|
type checkSuite struct {
|
|
bs asserts.Backstore
|
|
a asserts.Assertion
|
|
}
|
|
|
|
var _ = Suite(&checkSuite{})
|
|
|
|
func (chks *checkSuite) SetUpTest(c *C) {
|
|
var err error
|
|
|
|
topDir := filepath.Join(c.MkDir(), "asserts-db")
|
|
chks.bs, err = asserts.OpenFSBackstore(topDir)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "0",
|
|
}
|
|
chks.a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckNoPubKey(c *C) {
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = db.Check(chks.a)
|
|
c.Assert(err, ErrorMatches, `no matching public key "[[:alnum:]_-]+" for signature by "canonical"`)
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckExpiredPubKey(c *C) {
|
|
fixedTimeStr := "0003-01-01T00:00:00Z"
|
|
fixedTime, err := time.Parse(time.RFC3339, fixedTimeStr)
|
|
c.Assert(err, IsNil)
|
|
|
|
restore := asserts.MockTimeNow(fixedTime)
|
|
defer restore()
|
|
|
|
trustedKey := testPrivKey0
|
|
|
|
expiredAccKey := asserts.ExpiredAccountKeyForTest("canonical", trustedKey.PublicKey())
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{expiredAccKey},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
expSince := regexp.QuoteMeta(expiredAccKey.Since().Format(time.RFC3339))
|
|
expUntil := regexp.QuoteMeta(expiredAccKey.Until().Format(time.RFC3339))
|
|
curTime := regexp.QuoteMeta(fixedTimeStr)
|
|
err = db.Check(chks.a)
|
|
c.Assert(err, ErrorMatches, fmt.Sprintf(`assertion is signed with expired public key "[[:alnum:]_-]+" from "canonical": current time is %s but key is valid during \[%s, %s\)`, curTime, expSince, expUntil))
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckExpiredPubKeyNoUntil(c *C) {
|
|
curTimeStr := "0002-01-01T00:00:00Z"
|
|
curTime, err := time.Parse(time.RFC3339, curTimeStr)
|
|
c.Assert(err, IsNil)
|
|
|
|
restore := asserts.MockTimeNow(curTime)
|
|
defer restore()
|
|
|
|
trustedKey := testPrivKey0
|
|
|
|
keyTimeStr := "0003-01-01T00:00:00Z"
|
|
keyTime, err := time.Parse(time.RFC3339, keyTimeStr)
|
|
c.Assert(err, IsNil)
|
|
expiredAccKey := asserts.MakeAccountKeyForTestWithUntil("canonical", trustedKey.PublicKey(), keyTime, time.Time{}, 1)
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{expiredAccKey},
|
|
}
|
|
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = db.Check(chks.a)
|
|
c.Assert(err, ErrorMatches, fmt.Sprintf(`assertion is signed with expired public key "[[:alnum:]_-]+" from "canonical": current time is %s but key is valid from %s`, regexp.QuoteMeta(curTimeStr), regexp.QuoteMeta(keyTimeStr)))
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckForgery(c *C) {
|
|
trustedKey := testPrivKey0
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
encoded := asserts.Encode(chks.a)
|
|
content, encodedSig := chks.a.Signature()
|
|
// forgery
|
|
forgedSig := new(packet.Signature)
|
|
forgedSig.PubKeyAlgo = packet.PubKeyAlgoRSA
|
|
forgedSig.Hash = crypto.SHA512
|
|
forgedSig.CreationTime = time.Now()
|
|
h := crypto.SHA512.New()
|
|
h.Write(content)
|
|
pk1 := packet.NewRSAPrivateKey(time.Unix(1, 0), testPrivKey1RSA)
|
|
err = forgedSig.Sign(h, pk1, &packet.Config{DefaultHash: crypto.SHA512})
|
|
c.Assert(err, IsNil)
|
|
buf := new(bytes.Buffer)
|
|
forgedSig.Serialize(buf)
|
|
b := append([]byte{0x1}, buf.Bytes()...)
|
|
forgedSigEncoded := base64.StdEncoding.EncodeToString(b)
|
|
forgedEncoded := bytes.Replace(encoded, encodedSig, []byte(forgedSigEncoded), 1)
|
|
c.Assert(forgedEncoded, Not(DeepEquals), encoded)
|
|
|
|
forgedAssert, err := asserts.Decode(forgedEncoded)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = db.Check(forgedAssert)
|
|
c.Assert(err, ErrorMatches, "failed signature verification: .*")
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckUnsupportedFormat(c *C) {
|
|
trustedKey := testPrivKey0
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
var a asserts.Assertion
|
|
(func() {
|
|
restore := asserts.MockMaxSupportedFormat(asserts.TestOnlyType, 77)
|
|
defer restore()
|
|
var err error
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "0",
|
|
"format": "77",
|
|
}
|
|
a, err = asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
|
|
c.Assert(err, IsNil)
|
|
})()
|
|
|
|
err = db.Check(a)
|
|
c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
|
|
c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported`)
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckMismatchedAccountIDandKey(c *C) {
|
|
trustedKey := testPrivKey0
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey())},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "random",
|
|
"primary-key": "0",
|
|
}
|
|
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = db.Check(a)
|
|
c.Check(err, ErrorMatches, `error finding matching public key for signature: found public key ".*" from "canonical" but expected it from: random`)
|
|
|
|
err = asserts.CheckSignature(a, cfg.Trusted[0].(*asserts.AccountKey), db, time.Time{}, time.Time{})
|
|
c.Check(err, ErrorMatches, `assertion authority "random" does not match public key from "canonical"`)
|
|
}
|
|
|
|
func (chks *checkSuite) TestCheckAndSetEarliestTime(c *C) {
|
|
trustedKey := testPrivKey0
|
|
|
|
ak := asserts.MakeAccountKeyForTest("canonical", trustedKey.PublicKey(), time.Date(2016, 1, 1, 0, 0, 0, 0, time.UTC), 2)
|
|
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: chks.bs,
|
|
Trusted: []asserts.Assertion{ak},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "0",
|
|
}
|
|
a, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, trustedKey)
|
|
c.Assert(err, IsNil)
|
|
|
|
// now is since + 1 year, key is valid
|
|
r := asserts.MockTimeNow(ak.Since().AddDate(1, 0, 0))
|
|
defer r()
|
|
|
|
err = db.Check(a)
|
|
c.Check(err, IsNil)
|
|
|
|
// now is since - 1 year, key is invalid
|
|
pastTime := ak.Since().AddDate(-1, 0, 0)
|
|
asserts.MockTimeNow(pastTime)
|
|
|
|
err = db.Check(a)
|
|
c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
|
|
|
|
// now is ignored but known to be at least >= pastTime
|
|
// key is considered valid
|
|
db.SetEarliestTime(pastTime)
|
|
err = db.Check(a)
|
|
c.Check(err, IsNil)
|
|
|
|
// move earliest after until
|
|
db.SetEarliestTime(ak.Until().AddDate(0, 0, 1))
|
|
err = db.Check(a)
|
|
c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
|
|
|
|
// check using now = since - 1 year again
|
|
db.SetEarliestTime(time.Time{})
|
|
err = db.Check(a)
|
|
c.Check(err, ErrorMatches, `assertion is signed with expired public key .*`)
|
|
|
|
// now is since + 1 month, key is valid
|
|
asserts.MockTimeNow(ak.Since().AddDate(0, 1, 0))
|
|
err = db.Check(a)
|
|
c.Check(err, IsNil)
|
|
}
|
|
|
|
type signAddFindSuite struct {
|
|
signingDB *asserts.Database
|
|
signingKeyID string
|
|
db *asserts.Database
|
|
}
|
|
|
|
var _ = Suite(&signAddFindSuite{})
|
|
|
|
func (safs *signAddFindSuite) SetUpTest(c *C) {
|
|
cfg0 := &asserts.DatabaseConfig{}
|
|
db0, err := asserts.OpenDatabase(cfg0)
|
|
c.Assert(err, IsNil)
|
|
safs.signingDB = db0
|
|
|
|
pk := testPrivKey0
|
|
err = db0.ImportKey(pk)
|
|
c.Assert(err, IsNil)
|
|
safs.signingKeyID = pk.PublicKey().ID()
|
|
|
|
topDir := filepath.Join(c.MkDir(), "asserts-db")
|
|
bs, err := asserts.OpenFSBackstore(topDir)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers := map[string]interface{}{
|
|
"type": "account",
|
|
"authority-id": "canonical",
|
|
"account-id": "predefined",
|
|
"validation": "verified",
|
|
"display-name": "Predef",
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
}
|
|
predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
trustedKey := testPrivKey0
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: bs,
|
|
Trusted: []asserts.Assertion{
|
|
asserts.BootstrapAccountForTest("canonical"),
|
|
asserts.BootstrapAccountKeyForTest("canonical", trustedKey.PublicKey()),
|
|
},
|
|
OtherPredefined: []asserts.Assertion{
|
|
predefAcct,
|
|
},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
safs.db = db
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSign(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Check(a1)
|
|
c.Check(err, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignEmptyKeyID(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "")
|
|
c.Assert(err, ErrorMatches, "key id is empty")
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignMissingAuthorityId(c *C) {
|
|
headers := map[string]interface{}{
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `"authority-id" header is mandatory`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignMissingPrimaryKey(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `"primary-key" header is mandatory`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignPrimaryKeyWithSlash(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "baz/9000",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `"primary-key" primary key header cannot contain '/'`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignNoPrivateKey(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, "abcd")
|
|
c.Assert(err, ErrorMatches, "cannot find key pair")
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignUnknownType(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}
|
|
a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "xyz", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `internal error: unknown assertion type: "xyz"`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignNonPredefinedType(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}
|
|
a1, err := safs.signingDB.Sign(&asserts.AssertionType{Name: "test-only", PrimaryKey: nil}, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `internal error: unpredefined assertion type for name "test-only" used.*`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignBadRevision(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"revision": "zzz",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `"revision" header is not an integer: zzz`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignBadFormat(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"format": "zzz",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `"format" header is not an integer: zzz`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignHeadersCheck(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"extra": []interface{}{1, 2},
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignHeadersCheckMap(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"extra": map[string]interface{}{"a": "a", "b": 1},
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Check(err, ErrorMatches, `header "extra": header values must be strings or nested lists or maps with strings as the only scalars: 1`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignAssemblerError(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"count": "zzz",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `cannot assemble assertion test-only: "count" header is not an integer: zzz`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignUnsupportedFormat(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"format": "77",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format 77 higher than max supported format 1`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestSignInadequateFormat(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"format-1-feature": "true",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, ErrorMatches, `cannot sign "test-only" assertion with format set to 0 lower than min format 1 covering included features`)
|
|
c.Check(a1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestAddRefusesSelfSignedKey(c *C) {
|
|
aKey := testPrivKey2
|
|
|
|
aKeyEncoded, err := asserts.EncodePublicKey(aKey.PublicKey())
|
|
c.Assert(err, IsNil)
|
|
|
|
now := time.Now().UTC()
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": aKey.PublicKey().ID(),
|
|
"name": "default",
|
|
"since": now.Format(time.RFC3339),
|
|
}
|
|
acctKey, err := asserts.AssembleAndSignInTest(asserts.AccountKeyType, headers, aKeyEncoded, aKey)
|
|
c.Assert(err, IsNil)
|
|
|
|
// this must fail
|
|
err = safs.db.Add(acctKey)
|
|
c.Check(err, ErrorMatches, `no matching public key.*`)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestAddSuperseding(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "a",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Check(retrieved1, NotNil)
|
|
c.Check(retrieved1.Revision(), Equals, 0)
|
|
|
|
headers["revision"] = "1"
|
|
a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a2)
|
|
c.Assert(err, IsNil)
|
|
|
|
retrieved2, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "a",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Check(retrieved2, NotNil)
|
|
c.Check(retrieved2.Revision(), Equals, 1)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Check(err, ErrorMatches, "revision 0 is older than current revision 1")
|
|
c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestAddNoAuthorityNoPrimaryKey(c *C) {
|
|
headers := map[string]interface{}{
|
|
"hdr": "FOO",
|
|
}
|
|
a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a)
|
|
c.Assert(err, ErrorMatches, `internal error: assertion type "test-only-no-authority" has no primary key`)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestAddNoAuthorityButPrimaryKey(c *C) {
|
|
headers := map[string]interface{}{
|
|
"pk": "primary",
|
|
}
|
|
a, err := asserts.SignWithoutAuthority(asserts.TestOnlyNoAuthorityPKType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a)
|
|
c.Assert(err, ErrorMatches, `cannot check no-authority assertion type "test-only-no-authority-pk"`)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestAddUnsupportedFormat(c *C) {
|
|
const unsupported = "type: test-only\n" +
|
|
"format: 77\n" +
|
|
"authority-id: canonical\n" +
|
|
"primary-key: a\n" +
|
|
"payload: unsupported\n" +
|
|
"sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" +
|
|
"\n\n" +
|
|
"AXNpZw=="
|
|
aUnsupp, err := asserts.Decode([]byte(unsupported))
|
|
c.Assert(err, IsNil)
|
|
c.Assert(aUnsupp.SupportedFormat(), Equals, false)
|
|
|
|
err = safs.db.Add(aUnsupp)
|
|
c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
|
|
c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, false)
|
|
c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported`)
|
|
c.Check(asserts.IsUnaccceptedUpdate(err), Equals, false)
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"format": "1",
|
|
"payload": "supported",
|
|
}
|
|
aSupp, err := asserts.AssembleAndSignInTest(asserts.TestOnlyType, headers, nil, testPrivKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(aSupp)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(aUnsupp)
|
|
c.Assert(err, FitsTypeOf, &asserts.UnsupportedFormatError{})
|
|
c.Check(err.(*asserts.UnsupportedFormatError).Update, Equals, true)
|
|
c.Check(err, ErrorMatches, `proposed "test-only" assertion has format 77 but 1 is latest supported \(current not updated\)`)
|
|
c.Check(asserts.IsUnaccceptedUpdate(err), Equals, true)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestNotFoundError(c *C) {
|
|
err1 := &asserts.NotFoundError{
|
|
Type: asserts.SnapDeclarationType,
|
|
Headers: map[string]string{
|
|
"series": "16",
|
|
"snap-id": "snap-id",
|
|
},
|
|
}
|
|
c.Check(errors.Is(err1, &asserts.NotFoundError{}), Equals, true)
|
|
c.Check(err1.Error(), Equals, "snap-declaration (snap-id; series:16) not found")
|
|
|
|
err2 := &asserts.NotFoundError{
|
|
Type: asserts.SnapRevisionType,
|
|
}
|
|
c.Check(errors.Is(err2, &asserts.NotFoundError{}), Equals, true)
|
|
c.Check(err2.Error(), Equals, "snap-revision assertion not found")
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindNotFound(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
hdrs := map[string]string{
|
|
"primary-key": "b",
|
|
}
|
|
retrieved1, err := safs.db.Find(asserts.TestOnlyType, hdrs)
|
|
c.Assert(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: hdrs,
|
|
})
|
|
c.Check(retrieved1, IsNil)
|
|
|
|
// checking also extra headers
|
|
hdrs = map[string]string{
|
|
"primary-key": "a",
|
|
"authority-id": "other-auth-id",
|
|
}
|
|
retrieved1, err = safs.db.Find(asserts.TestOnlyType, hdrs)
|
|
c.Assert(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: hdrs,
|
|
})
|
|
c.Check(retrieved1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindPrimaryLeftOut(c *C) {
|
|
retrieved1, err := safs.db.Find(asserts.TestOnlyType, map[string]string{})
|
|
c.Assert(err, ErrorMatches, "must provide primary key: primary-key")
|
|
c.Check(retrieved1, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindMany(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "a",
|
|
"other": "other-x",
|
|
}
|
|
aa, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(aa)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "b",
|
|
"other": "other-y",
|
|
}
|
|
ab, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(ab)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "c",
|
|
"other": "other-x",
|
|
}
|
|
ac, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(ac)
|
|
c.Assert(err, IsNil)
|
|
|
|
res, err := safs.db.FindMany(asserts.TestOnlyType, map[string]string{
|
|
"other": "other-x",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(res, HasLen, 2)
|
|
primKeys := []string{res[0].HeaderString("primary-key"), res[1].HeaderString("primary-key")}
|
|
sort.Strings(primKeys)
|
|
c.Check(primKeys, DeepEquals, []string{"a", "c"})
|
|
|
|
res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
|
|
"other": "other-y",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(res, HasLen, 1)
|
|
c.Check(res[0].Header("primary-key"), Equals, "b")
|
|
|
|
res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(res, HasLen, 3)
|
|
|
|
res, err = safs.db.FindMany(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "b",
|
|
"other": "other-y",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(res, HasLen, 1)
|
|
|
|
hdrs := map[string]string{
|
|
"primary-key": "b",
|
|
"other": "other-x",
|
|
}
|
|
res, err = safs.db.FindMany(asserts.TestOnlyType, hdrs)
|
|
c.Assert(res, HasLen, 0)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: hdrs,
|
|
})
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindFindsPredefined(c *C) {
|
|
pk1 := testPrivKey1
|
|
|
|
acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, safs.signingKeyID)
|
|
|
|
acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, pk1.PublicKey(), safs.signingKeyID)
|
|
|
|
err := safs.db.Add(acct1)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(acct1Key)
|
|
c.Assert(err, IsNil)
|
|
|
|
// find the trusted key as well
|
|
tKey, err := safs.db.Find(asserts.AccountKeyType, map[string]string{
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
|
|
c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
|
|
|
|
// find predefined account as well
|
|
predefAcct, err := safs.db.Find(asserts.AccountType, map[string]string{
|
|
"account-id": "predefined",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
|
|
c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
|
|
|
|
// find trusted and indirectly trusted
|
|
accKeys, err := safs.db.FindMany(asserts.AccountKeyType, nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(accKeys, HasLen, 2)
|
|
|
|
accts, err := safs.db.FindMany(asserts.AccountType, nil)
|
|
c.Assert(err, IsNil)
|
|
c.Check(accts, HasLen, 3)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindTrusted(c *C) {
|
|
pk1 := testPrivKey1
|
|
|
|
acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, safs.signingKeyID)
|
|
|
|
acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, pk1.PublicKey(), safs.signingKeyID)
|
|
|
|
err := safs.db.Add(acct1)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(acct1Key)
|
|
c.Assert(err, IsNil)
|
|
|
|
// find the trusted account
|
|
tAcct, err := safs.db.FindTrusted(asserts.AccountType, map[string]string{
|
|
"account-id": "canonical",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
|
|
|
|
// find the trusted key
|
|
tKey, err := safs.db.FindTrusted(asserts.AccountKeyType, map[string]string{
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
|
|
c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
|
|
|
|
// doesn't find not trusted assertions
|
|
hdrs := map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
}
|
|
_, err = safs.db.FindTrusted(asserts.AccountType, hdrs)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.AccountType,
|
|
Headers: hdrs,
|
|
})
|
|
|
|
hdrs = map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
"public-key-sha3-384": acct1Key.PublicKeyID(),
|
|
}
|
|
_, err = safs.db.FindTrusted(asserts.AccountKeyType, hdrs)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.AccountKeyType,
|
|
Headers: hdrs,
|
|
})
|
|
|
|
_, err = safs.db.FindTrusted(asserts.AccountType, map[string]string{
|
|
"account-id": "predefined",
|
|
})
|
|
c.Check(errors.Is(err, &asserts.NotFoundError{}), Equals, true)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindPredefined(c *C) {
|
|
pk1 := testPrivKey1
|
|
|
|
acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, safs.signingKeyID)
|
|
|
|
acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, pk1.PublicKey(), safs.signingKeyID)
|
|
|
|
err := safs.db.Add(acct1)
|
|
c.Assert(err, IsNil)
|
|
err = safs.db.Add(acct1Key)
|
|
c.Assert(err, IsNil)
|
|
|
|
// find the trusted account
|
|
tAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
|
|
"account-id": "canonical",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tAcct.(*asserts.Account).AccountID(), Equals, "canonical")
|
|
|
|
// find the trusted key
|
|
tKey, err := safs.db.FindPredefined(asserts.AccountKeyType, map[string]string{
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tKey.(*asserts.AccountKey).AccountID(), Equals, "canonical")
|
|
c.Assert(tKey.(*asserts.AccountKey).PublicKeyID(), Equals, safs.signingKeyID)
|
|
|
|
// find predefined account as well
|
|
predefAcct, err := safs.db.FindPredefined(asserts.AccountType, map[string]string{
|
|
"account-id": "predefined",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(predefAcct.(*asserts.Account).AccountID(), Equals, "predefined")
|
|
c.Assert(predefAcct.(*asserts.Account).DisplayName(), Equals, "Predef")
|
|
|
|
// doesn't find not trusted or predefined assertions
|
|
hdrs := map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
}
|
|
_, err = safs.db.FindPredefined(asserts.AccountType, hdrs)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.AccountType,
|
|
Headers: hdrs,
|
|
})
|
|
|
|
hdrs = map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
"public-key-sha3-384": acct1Key.PublicKeyID(),
|
|
}
|
|
_, err = safs.db.FindPredefined(asserts.AccountKeyType, hdrs)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.AccountKeyType,
|
|
Headers: hdrs,
|
|
})
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindManyPredefined(c *C) {
|
|
headers := map[string]interface{}{
|
|
"type": "account",
|
|
"authority-id": "canonical",
|
|
"account-id": "predefined",
|
|
"validation": "verified",
|
|
"display-name": "Predef",
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
}
|
|
predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
trustedKey0 := testPrivKey0
|
|
trustedKey1 := testPrivKey1
|
|
cfg := &asserts.DatabaseConfig{
|
|
Backstore: asserts.NewMemoryBackstore(),
|
|
Trusted: []asserts.Assertion{
|
|
asserts.BootstrapAccountForTest("canonical"),
|
|
asserts.BootstrapAccountKeyForTest("canonical", trustedKey0.PublicKey()),
|
|
asserts.BootstrapAccountKeyForTest("canonical", trustedKey1.PublicKey()),
|
|
},
|
|
OtherPredefined: []asserts.Assertion{
|
|
predefAcct,
|
|
},
|
|
}
|
|
db, err := asserts.OpenDatabase(cfg)
|
|
c.Assert(err, IsNil)
|
|
|
|
pk1 := testPrivKey2
|
|
|
|
acct1 := assertstest.NewAccount(safs.signingDB, "acc-id1", map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, safs.signingKeyID)
|
|
|
|
acct1Key := assertstest.NewAccountKey(safs.signingDB, acct1, map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
}, pk1.PublicKey(), safs.signingKeyID)
|
|
|
|
err = db.Add(acct1)
|
|
c.Assert(err, IsNil)
|
|
err = db.Add(acct1Key)
|
|
c.Assert(err, IsNil)
|
|
|
|
// find the trusted account
|
|
tAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
|
|
"account-id": "canonical",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tAccts, HasLen, 1)
|
|
c.Assert(tAccts[0].(*asserts.Account).AccountID(), Equals, "canonical")
|
|
|
|
// find the predefined account
|
|
pAccts, err := db.FindManyPredefined(asserts.AccountType, map[string]string{
|
|
"account-id": "predefined",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(pAccts, HasLen, 1)
|
|
c.Assert(pAccts[0].(*asserts.Account).AccountID(), Equals, "predefined")
|
|
|
|
// find the multiple trusted keys
|
|
tKeys, err := db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
|
|
"account-id": "canonical",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Assert(tKeys, HasLen, 2)
|
|
got := make(map[string]string)
|
|
for _, a := range tKeys {
|
|
acctKey := a.(*asserts.AccountKey)
|
|
got[acctKey.PublicKeyID()] = acctKey.AccountID()
|
|
}
|
|
c.Check(got, DeepEquals, map[string]string{
|
|
trustedKey0.PublicKey().ID(): "canonical",
|
|
trustedKey1.PublicKey().ID(): "canonical",
|
|
})
|
|
|
|
// doesn't find not predefined assertions
|
|
hdrs := map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
}
|
|
_, err = db.FindManyPredefined(asserts.AccountType, hdrs)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.AccountType,
|
|
Headers: hdrs,
|
|
})
|
|
|
|
_, err = db.FindManyPredefined(asserts.AccountKeyType, map[string]string{
|
|
"account-id": acct1.AccountID(),
|
|
"public-key-sha3-384": acct1Key.PublicKeyID(),
|
|
})
|
|
c.Check(errors.Is(err, &asserts.NotFoundError{}), Equals, true)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithTrustedOnes(c *C) {
|
|
// trusted
|
|
pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
now := time.Now().UTC()
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
"name": "default",
|
|
"since": now.Format(time.RFC3339),
|
|
"until": now.AddDate(1, 0, 0).Format(time.RFC3339),
|
|
}
|
|
tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(tKey)
|
|
c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestDontLetAddConfusinglyAssertionClashingWithPredefinedOnes(c *C) {
|
|
headers := map[string]interface{}{
|
|
"type": "account",
|
|
"authority-id": "canonical",
|
|
"account-id": "predefined",
|
|
"validation": "verified",
|
|
"display-name": "Predef",
|
|
"timestamp": time.Now().Format(time.RFC3339),
|
|
}
|
|
predefAcct, err := safs.signingDB.Sign(asserts.AccountType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(predefAcct)
|
|
c.Check(err, ErrorMatches, `cannot add "account" assertion with primary key clashing with a predefined assertion: .*`)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindAndRefResolve(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"pk1": "ka",
|
|
"pk2": "kb",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnly2Type, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
ref := &asserts.Ref{
|
|
Type: asserts.TestOnly2Type,
|
|
PrimaryKey: []string{"ka", "kb"},
|
|
}
|
|
|
|
resolved, err := ref.Resolve(safs.db.Find)
|
|
c.Assert(err, IsNil)
|
|
c.Check(resolved.Headers(), DeepEquals, map[string]interface{}{
|
|
"type": "test-only-2",
|
|
"authority-id": "canonical",
|
|
"pk1": "ka",
|
|
"pk2": "kb",
|
|
"sign-key-sha3-384": resolved.SignKeyID(),
|
|
})
|
|
|
|
ref = &asserts.Ref{
|
|
Type: asserts.TestOnly2Type,
|
|
PrimaryKey: []string{"kb", "ka"},
|
|
}
|
|
_, err = ref.Resolve(safs.db.Find)
|
|
c.Assert(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: ref.Type,
|
|
Headers: map[string]string{
|
|
"pk1": "kb",
|
|
"pk2": "ka",
|
|
},
|
|
})
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindMaxFormat(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "foo",
|
|
}
|
|
af0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(af0)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "foo",
|
|
"format": "1",
|
|
"revision": "1",
|
|
}
|
|
af1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(af1)
|
|
c.Assert(err, IsNil)
|
|
|
|
a, err := safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "foo",
|
|
}, 1)
|
|
c.Assert(err, IsNil)
|
|
c.Check(a.Revision(), Equals, 1)
|
|
|
|
a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "foo",
|
|
}, 0)
|
|
c.Assert(err, IsNil)
|
|
c.Check(a.Revision(), Equals, 0)
|
|
|
|
a, err = safs.db.FindMaxFormat(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "foo",
|
|
}, 3)
|
|
c.Check(err, ErrorMatches, `cannot find "test-only" assertions for format 3 higher than supported format 1`)
|
|
c.Check(a, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindOptionalPrimaryKeys(c *C) {
|
|
r := asserts.MockOptionalPrimaryKey(asserts.TestOnlyType, "opt1", "o1-defl")
|
|
defer r()
|
|
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "k1",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "k2",
|
|
"opt1": "A",
|
|
}
|
|
a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a2)
|
|
c.Assert(err, IsNil)
|
|
|
|
a, err := safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k1",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Check(a.HeaderString("primary-key"), Equals, "k1")
|
|
c.Check(a.HeaderString("opt1"), Equals, "o1-defl")
|
|
|
|
a, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k1",
|
|
"opt1": "o1-defl",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Check(a.HeaderString("primary-key"), Equals, "k1")
|
|
c.Check(a.HeaderString("opt1"), Equals, "o1-defl")
|
|
|
|
a, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k2",
|
|
"opt1": "A",
|
|
})
|
|
c.Assert(err, IsNil)
|
|
c.Check(a.HeaderString("primary-key"), Equals, "k2")
|
|
c.Check(a.HeaderString("opt1"), Equals, "A")
|
|
|
|
_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k3",
|
|
})
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: map[string]string{
|
|
"primary-key": "k3",
|
|
},
|
|
})
|
|
|
|
_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k2",
|
|
})
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: map[string]string{
|
|
"primary-key": "k2",
|
|
},
|
|
})
|
|
|
|
_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k2",
|
|
"opt1": "B",
|
|
})
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: map[string]string{
|
|
"primary-key": "k2",
|
|
"opt1": "B",
|
|
},
|
|
})
|
|
|
|
_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "k1",
|
|
"opt1": "B",
|
|
})
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlyType,
|
|
Headers: map[string]string{
|
|
"primary-key": "k1",
|
|
"opt1": "B",
|
|
},
|
|
})
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestWithStackedBackstore(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "one",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "two",
|
|
}
|
|
a2, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
bs := asserts.NewMemoryBackstore()
|
|
stacked := safs.db.WithStackedBackstore(bs)
|
|
|
|
err = stacked.Add(a2)
|
|
c.Assert(err, IsNil)
|
|
|
|
_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "one",
|
|
})
|
|
c.Check(err, IsNil)
|
|
|
|
_, err = stacked.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "two",
|
|
})
|
|
c.Check(err, IsNil)
|
|
|
|
_, err = safs.db.Find(asserts.TestOnlyType, map[string]string{
|
|
"primary-key": "two",
|
|
})
|
|
c.Check(errors.Is(err, &asserts.NotFoundError{}), Equals, true)
|
|
|
|
_, err = stacked.Find(asserts.AccountKeyType, map[string]string{
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
})
|
|
c.Check(err, IsNil)
|
|
|
|
// stored in backstore
|
|
_, err = bs.Get(asserts.TestOnlyType, []string{"two"}, 0)
|
|
c.Check(err, IsNil)
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestWithStackedBackstoreSafety(c *C) {
|
|
stacked := safs.db.WithStackedBackstore(asserts.NewMemoryBackstore())
|
|
|
|
// usual add safety
|
|
pubKey0, err := safs.signingDB.PublicKey(safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
pubKey0Encoded, err := asserts.EncodePublicKey(pubKey0)
|
|
c.Assert(err, IsNil)
|
|
|
|
now := time.Now().UTC()
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"account-id": "canonical",
|
|
"public-key-sha3-384": safs.signingKeyID,
|
|
"name": "default",
|
|
"since": now.Format(time.RFC3339),
|
|
"until": now.AddDate(1, 0, 0).Format(time.RFC3339),
|
|
}
|
|
tKey, err := safs.signingDB.Sign(asserts.AccountKeyType, headers, []byte(pubKey0Encoded), safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = stacked.Add(tKey)
|
|
c.Check(err, ErrorMatches, `cannot add "account-key" assertion with primary key clashing with a trusted assertion: .*`)
|
|
|
|
// cannot go back to old revisions
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "one",
|
|
}
|
|
a0, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"primary-key": "one",
|
|
"revision": "1",
|
|
}
|
|
a1, err := safs.signingDB.Sign(asserts.TestOnlyType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = safs.db.Add(a1)
|
|
c.Assert(err, IsNil)
|
|
|
|
err = stacked.Add(a0)
|
|
c.Assert(err, DeepEquals, &asserts.RevisionError{
|
|
Used: 0,
|
|
Current: 1,
|
|
})
|
|
}
|
|
|
|
func (safs *signAddFindSuite) TestFindSequence(c *C) {
|
|
headers := map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"n": "s1",
|
|
"sequence": "1",
|
|
}
|
|
sq1f0, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"n": "s1",
|
|
"sequence": "2",
|
|
}
|
|
sq2f0, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"format": "1",
|
|
"n": "s1",
|
|
"sequence": "2",
|
|
"revision": "1",
|
|
}
|
|
sq2f1, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"format": "1",
|
|
"n": "s1",
|
|
"sequence": "3",
|
|
}
|
|
sq3f1, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
headers = map[string]interface{}{
|
|
"authority-id": "canonical",
|
|
"format": "2",
|
|
"n": "s1",
|
|
"sequence": "3",
|
|
"revision": "1",
|
|
}
|
|
sq3f2, err := safs.signingDB.Sign(asserts.TestOnlySeqType, headers, nil, safs.signingKeyID)
|
|
c.Assert(err, IsNil)
|
|
|
|
for _, a := range []asserts.Assertion{sq1f0, sq2f0, sq2f1, sq3f1} {
|
|
|
|
err = safs.db.Add(a)
|
|
c.Assert(err, IsNil)
|
|
}
|
|
|
|
// stack a backstore, for test completeness, this is an unlikely
|
|
// scenario atm
|
|
bs := asserts.NewMemoryBackstore()
|
|
db := safs.db.WithStackedBackstore(bs)
|
|
err = db.Add(sq3f2)
|
|
c.Assert(err, IsNil)
|
|
|
|
seqHeaders := map[string]string{
|
|
"n": "s1",
|
|
}
|
|
tests := []struct {
|
|
after int
|
|
maxFormat int
|
|
sequence int
|
|
format int
|
|
revision int
|
|
}{
|
|
{after: 0, maxFormat: 0, sequence: 1, format: 0, revision: 0},
|
|
{after: 0, maxFormat: 2, sequence: 1, format: 0, revision: 0},
|
|
{after: 1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
|
|
{after: 1, maxFormat: 1, sequence: 2, format: 1, revision: 1},
|
|
{after: 1, maxFormat: 2, sequence: 2, format: 1, revision: 1},
|
|
{after: 2, maxFormat: 0, sequence: -1},
|
|
{after: 2, maxFormat: 1, sequence: 3, format: 1, revision: 0},
|
|
{after: 2, maxFormat: 2, sequence: 3, format: 2, revision: 1},
|
|
{after: 3, maxFormat: 0, sequence: -1},
|
|
{after: 3, maxFormat: 2, sequence: -1},
|
|
{after: 4, maxFormat: 2, sequence: -1},
|
|
{after: -1, maxFormat: 0, sequence: 2, format: 0, revision: 0},
|
|
{after: -1, maxFormat: 1, sequence: 3, format: 1, revision: 0},
|
|
{after: -1, maxFormat: 2, sequence: 3, format: 2, revision: 1},
|
|
}
|
|
|
|
for _, t := range tests {
|
|
a, err := db.FindSequence(asserts.TestOnlySeqType, seqHeaders, t.after, t.maxFormat)
|
|
if t.sequence == -1 {
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlySeqType,
|
|
Headers: seqHeaders,
|
|
})
|
|
} else {
|
|
c.Assert(err, IsNil)
|
|
c.Assert(a.HeaderString("n"), Equals, "s1")
|
|
c.Check(a.Sequence(), Equals, t.sequence)
|
|
c.Check(a.Format(), Equals, t.format)
|
|
c.Check(a.Revision(), Equals, t.revision)
|
|
}
|
|
}
|
|
|
|
seqHeaders = map[string]string{
|
|
"n": "s2",
|
|
}
|
|
_, err = db.FindSequence(asserts.TestOnlySeqType, seqHeaders, -1, 2)
|
|
c.Check(err, DeepEquals, &asserts.NotFoundError{
|
|
Type: asserts.TestOnlySeqType, Headers: seqHeaders,
|
|
})
|
|
|
|
}
|
|
|
|
type revisionErrorSuite struct{}
|
|
|
|
func (res *revisionErrorSuite) TestErrorText(c *C) {
|
|
tests := []struct {
|
|
err error
|
|
expected string
|
|
}{
|
|
// Invalid revisions.
|
|
{&asserts.RevisionError{Used: -1}, "assertion revision is unknown"},
|
|
{&asserts.RevisionError{Used: -100}, "assertion revision is unknown"},
|
|
{&asserts.RevisionError{Current: -1}, "assertion revision is unknown"},
|
|
{&asserts.RevisionError{Current: -100}, "assertion revision is unknown"},
|
|
{&asserts.RevisionError{Used: -1, Current: -1}, "assertion revision is unknown"},
|
|
// Used == Current.
|
|
{&asserts.RevisionError{}, "revision 0 is already the current revision"},
|
|
{&asserts.RevisionError{Used: 100, Current: 100}, "revision 100 is already the current revision"},
|
|
// Used < Current.
|
|
{&asserts.RevisionError{Used: 1, Current: 2}, "revision 1 is older than current revision 2"},
|
|
{&asserts.RevisionError{Used: 2, Current: 100}, "revision 2 is older than current revision 100"},
|
|
// Used > Current.
|
|
{&asserts.RevisionError{Current: 1, Used: 2}, "revision 2 is more recent than current revision 1"},
|
|
{&asserts.RevisionError{Current: 2, Used: 100}, "revision 100 is more recent than current revision 2"},
|
|
}
|
|
|
|
for _, test := range tests {
|
|
c.Check(test.err, ErrorMatches, test.expected)
|
|
}
|
|
}
|
|
|
|
type isUnacceptedUpdateSuite struct{}
|
|
|
|
func (s *isUnacceptedUpdateSuite) TestIsUnacceptedUpdate(c *C) {
|
|
tests := []struct {
|
|
err error
|
|
keptCurrent bool
|
|
}{
|
|
{&asserts.UnsupportedFormatError{}, false},
|
|
{&asserts.UnsupportedFormatError{Update: true}, true},
|
|
{&asserts.RevisionError{Used: 1, Current: 1}, true},
|
|
{&asserts.RevisionError{Used: 1, Current: 5}, true},
|
|
{&asserts.RevisionError{Used: 3, Current: 1}, false},
|
|
{errors.New("other error"), false},
|
|
{&asserts.NotFoundError{Type: asserts.TestOnlyType}, false},
|
|
}
|
|
|
|
for _, t := range tests {
|
|
c.Check(asserts.IsUnaccceptedUpdate(t.err), Equals, t.keptCurrent, Commentf("%v", t.err))
|
|
}
|
|
}
|