github.com/meulengracht/snapd@v0.0.0-20210719210640-8bde69bcc84e/asserts/fsbackstore_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 asserts_test 21 22 import ( 23 "os" 24 "path/filepath" 25 "syscall" 26 27 . "gopkg.in/check.v1" 28 29 "github.com/snapcore/snapd/asserts" 30 ) 31 32 type fsBackstoreSuite struct{} 33 34 var _ = Suite(&fsBackstoreSuite{}) 35 36 func (fsbss *fsBackstoreSuite) TestOpenOK(c *C) { 37 // ensure umask is clean when creating the DB dir 38 oldUmask := syscall.Umask(0) 39 defer syscall.Umask(oldUmask) 40 41 topDir := filepath.Join(c.MkDir(), "asserts-db") 42 43 bs, err := asserts.OpenFSBackstore(topDir) 44 c.Check(err, IsNil) 45 c.Check(bs, NotNil) 46 47 info, err := os.Stat(filepath.Join(topDir, "asserts-v0")) 48 c.Assert(err, IsNil) 49 c.Assert(info.IsDir(), Equals, true) 50 c.Check(info.Mode().Perm(), Equals, os.FileMode(0775)) 51 } 52 53 func (fsbss *fsBackstoreSuite) TestOpenCreateFail(c *C) { 54 parent := filepath.Join(c.MkDir(), "var") 55 topDir := filepath.Join(parent, "asserts-db") 56 // make it not writable 57 err := os.Mkdir(parent, 0555) 58 c.Assert(err, IsNil) 59 60 bs, err := asserts.OpenFSBackstore(topDir) 61 c.Assert(err, ErrorMatches, "cannot create assert storage root: .*") 62 c.Check(bs, IsNil) 63 } 64 65 func (fsbss *fsBackstoreSuite) TestOpenWorldWritableFail(c *C) { 66 topDir := filepath.Join(c.MkDir(), "asserts-db") 67 // make it world-writable 68 oldUmask := syscall.Umask(0) 69 os.MkdirAll(filepath.Join(topDir, "asserts-v0"), 0777) 70 syscall.Umask(oldUmask) 71 72 bs, err := asserts.OpenFSBackstore(topDir) 73 c.Assert(err, ErrorMatches, "assert storage root unexpectedly world-writable: .*") 74 c.Check(bs, IsNil) 75 } 76 77 func (fsbss *fsBackstoreSuite) TestPutOldRevision(c *C) { 78 topDir := filepath.Join(c.MkDir(), "asserts-db") 79 bs, err := asserts.OpenFSBackstore(topDir) 80 c.Assert(err, IsNil) 81 82 // Create two revisions of assertion. 83 a0, err := asserts.Decode([]byte("type: test-only\n" + 84 "authority-id: auth-id1\n" + 85 "primary-key: foo\n" + 86 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 87 "\n\n" + 88 "AXNpZw==")) 89 c.Assert(err, IsNil) 90 a1, err := asserts.Decode([]byte("type: test-only\n" + 91 "authority-id: auth-id1\n" + 92 "primary-key: foo\n" + 93 "revision: 1\n" + 94 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 95 "\n\n" + 96 "AXNpZw==")) 97 c.Assert(err, IsNil) 98 99 // Put newer revision, follwed by old revision. 100 err = bs.Put(asserts.TestOnlyType, a1) 101 c.Assert(err, IsNil) 102 err = bs.Put(asserts.TestOnlyType, a0) 103 104 c.Check(err, ErrorMatches, `revision 0 is older than current revision 1`) 105 c.Check(err, DeepEquals, &asserts.RevisionError{Current: 1, Used: 0}) 106 } 107 108 func (fsbss *fsBackstoreSuite) TestGetFormat(c *C) { 109 topDir := filepath.Join(c.MkDir(), "asserts-db") 110 bs, err := asserts.OpenFSBackstore(topDir) 111 c.Assert(err, IsNil) 112 113 af0, err := asserts.Decode([]byte("type: test-only\n" + 114 "authority-id: auth-id1\n" + 115 "primary-key: foo\n" + 116 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 117 "\n\n" + 118 "AXNpZw==")) 119 c.Assert(err, IsNil) 120 af1, err := asserts.Decode([]byte("type: test-only\n" + 121 "authority-id: auth-id1\n" + 122 "primary-key: foo\n" + 123 "format: 1\n" + 124 "revision: 1\n" + 125 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 126 "\n\n" + 127 "AXNpZw==")) 128 c.Assert(err, IsNil) 129 af2, err := asserts.Decode([]byte("type: test-only\n" + 130 "authority-id: auth-id1\n" + 131 "primary-key: zoo\n" + 132 "format: 2\n" + 133 "revision: 22\n" + 134 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 135 "\n\n" + 136 "AXNpZw==")) 137 c.Assert(err, IsNil) 138 139 err = bs.Put(asserts.TestOnlyType, af0) 140 c.Assert(err, IsNil) 141 err = bs.Put(asserts.TestOnlyType, af1) 142 c.Assert(err, IsNil) 143 144 a, err := bs.Get(asserts.TestOnlyType, []string{"foo"}, 1) 145 c.Assert(err, IsNil) 146 c.Check(a.Revision(), Equals, 1) 147 148 a, err = bs.Get(asserts.TestOnlyType, []string{"foo"}, 0) 149 c.Assert(err, IsNil) 150 c.Check(a.Revision(), Equals, 0) 151 152 a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 0) 153 c.Assert(err, DeepEquals, &asserts.NotFoundError{ 154 Type: asserts.TestOnlyType, 155 // Headers can be omitted by Backstores 156 }) 157 c.Check(a, IsNil) 158 159 err = bs.Put(asserts.TestOnlyType, af2) 160 c.Assert(err, IsNil) 161 162 a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 1) 163 c.Assert(err, DeepEquals, &asserts.NotFoundError{ 164 Type: asserts.TestOnlyType, 165 }) 166 c.Check(a, IsNil) 167 168 a, err = bs.Get(asserts.TestOnlyType, []string{"zoo"}, 2) 169 c.Assert(err, IsNil) 170 c.Check(a.Revision(), Equals, 22) 171 } 172 173 func (fsbss *fsBackstoreSuite) TestSearchFormat(c *C) { 174 topDir := filepath.Join(c.MkDir(), "asserts-db") 175 bs, err := asserts.OpenFSBackstore(topDir) 176 c.Assert(err, IsNil) 177 178 af0, err := asserts.Decode([]byte("type: test-only-2\n" + 179 "authority-id: auth-id1\n" + 180 "pk1: foo\n" + 181 "pk2: bar\n" + 182 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 183 "\n\n" + 184 "AXNpZw==")) 185 c.Assert(err, IsNil) 186 af1, err := asserts.Decode([]byte("type: test-only-2\n" + 187 "authority-id: auth-id1\n" + 188 "pk1: foo\n" + 189 "pk2: bar\n" + 190 "format: 1\n" + 191 "revision: 1\n" + 192 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 193 "\n\n" + 194 "AXNpZw==")) 195 c.Assert(err, IsNil) 196 197 af2, err := asserts.Decode([]byte("type: test-only-2\n" + 198 "authority-id: auth-id1\n" + 199 "pk1: foo\n" + 200 "pk2: baz\n" + 201 "format: 2\n" + 202 "revision: 1\n" + 203 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 204 "\n\n" + 205 "AXNpZw==")) 206 c.Assert(err, IsNil) 207 208 err = bs.Put(asserts.TestOnly2Type, af0) 209 c.Assert(err, IsNil) 210 211 queries := []map[string]string{ 212 {"pk1": "foo", "pk2": "bar"}, 213 {"pk1": "foo"}, 214 {"pk2": "bar"}, 215 } 216 217 for _, q := range queries { 218 var a asserts.Assertion 219 foundCb := func(a1 asserts.Assertion) { 220 a = a1 221 } 222 err := bs.Search(asserts.TestOnly2Type, q, foundCb, 1) 223 c.Assert(err, IsNil) 224 c.Check(a.Revision(), Equals, 0) 225 } 226 227 err = bs.Put(asserts.TestOnly2Type, af1) 228 c.Assert(err, IsNil) 229 230 for _, q := range queries { 231 var a asserts.Assertion 232 foundCb := func(a1 asserts.Assertion) { 233 a = a1 234 } 235 err := bs.Search(asserts.TestOnly2Type, q, foundCb, 1) 236 c.Assert(err, IsNil) 237 c.Check(a.Revision(), Equals, 1) 238 239 err = bs.Search(asserts.TestOnly2Type, q, foundCb, 0) 240 c.Assert(err, IsNil) 241 c.Check(a.Revision(), Equals, 0) 242 } 243 244 err = bs.Put(asserts.TestOnly2Type, af2) 245 c.Assert(err, IsNil) 246 247 var as []asserts.Assertion 248 foundCb := func(a1 asserts.Assertion) { 249 as = append(as, a1) 250 } 251 err = bs.Search(asserts.TestOnly2Type, map[string]string{ 252 "pk1": "foo", 253 }, foundCb, 1) // will not find af2 254 c.Assert(err, IsNil) 255 c.Check(as, HasLen, 1) 256 c.Check(as[0].Revision(), Equals, 1) 257 258 } 259 260 func (fsbss *fsBackstoreSuite) TestSequenceMemberAfter(c *C) { 261 topDir := filepath.Join(c.MkDir(), "asserts-db") 262 bs, err := asserts.OpenFSBackstore(topDir) 263 c.Assert(err, IsNil) 264 265 other1, err := asserts.Decode([]byte("type: test-only-seq\n" + 266 "authority-id: auth-id1\n" + 267 "n: other\n" + 268 "sequence: 1\n" + 269 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 270 "\n\n" + 271 "AXNpZw==")) 272 c.Assert(err, IsNil) 273 274 sq1f0, err := asserts.Decode([]byte("type: test-only-seq\n" + 275 "authority-id: auth-id1\n" + 276 "n: s1\n" + 277 "sequence: 1\n" + 278 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 279 "\n\n" + 280 "AXNpZw==")) 281 c.Assert(err, IsNil) 282 283 sq2f0, err := asserts.Decode([]byte("type: test-only-seq\n" + 284 "authority-id: auth-id1\n" + 285 "n: s1\n" + 286 "sequence: 2\n" + 287 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 288 "\n\n" + 289 "AXNpZw==")) 290 c.Assert(err, IsNil) 291 292 sq2f1, err := asserts.Decode([]byte("type: test-only-seq\n" + 293 "authority-id: auth-id1\n" + 294 "format: 1\n" + 295 "n: s1\n" + 296 "sequence: 2\n" + 297 "revision: 1\n" + 298 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 299 "\n\n" + 300 "AXNpZw==")) 301 c.Assert(err, IsNil) 302 303 sq3f1, err := asserts.Decode([]byte("type: test-only-seq\n" + 304 "authority-id: auth-id1\n" + 305 "format: 1\n" + 306 "n: s1\n" + 307 "sequence: 3\n" + 308 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 309 "\n\n" + 310 "AXNpZw==")) 311 c.Assert(err, IsNil) 312 313 sq3f2, err := asserts.Decode([]byte("type: test-only-seq\n" + 314 "authority-id: auth-id1\n" + 315 "format: 2\n" + 316 "n: s1\n" + 317 "sequence: 3\n" + 318 "revision: 1\n" + 319 "sign-key-sha3-384: Jv8_JiHiIzJVcO9M55pPdqSDWUvuhfDIBJUS-3VW7F_idjix7Ffn5qMxB21ZQuij" + 320 "\n\n" + 321 "AXNpZw==")) 322 c.Assert(err, IsNil) 323 324 for _, a := range []asserts.Assertion{other1, sq1f0, sq2f0, sq2f1, sq3f1, sq3f2} { 325 err = bs.Put(asserts.TestOnlySeqType, a) 326 c.Assert(err, IsNil) 327 } 328 329 seqKey := []string{"s1"} 330 tests := []struct { 331 after int 332 maxFormat int 333 sequence int 334 format int 335 revision int 336 }{ 337 {after: 0, maxFormat: 0, sequence: 1, format: 0, revision: 0}, 338 {after: 0, maxFormat: 2, sequence: 1, format: 0, revision: 0}, 339 {after: 1, maxFormat: 0, sequence: 2, format: 0, revision: 0}, 340 {after: 1, maxFormat: 1, sequence: 2, format: 1, revision: 1}, 341 {after: 1, maxFormat: 2, sequence: 2, format: 1, revision: 1}, 342 {after: 2, maxFormat: 0, sequence: -1}, 343 {after: 2, maxFormat: 1, sequence: 3, format: 1, revision: 0}, 344 {after: 2, maxFormat: 2, sequence: 3, format: 2, revision: 1}, 345 {after: 3, maxFormat: 0, sequence: -1}, 346 {after: 3, maxFormat: 2, sequence: -1}, 347 {after: 4, maxFormat: 2, sequence: -1}, 348 {after: -1, maxFormat: 0, sequence: 2, format: 0, revision: 0}, 349 {after: -1, maxFormat: 1, sequence: 3, format: 1, revision: 0}, 350 {after: -1, maxFormat: 2, sequence: 3, format: 2, revision: 1}, 351 } 352 353 for _, t := range tests { 354 a, err := bs.SequenceMemberAfter(asserts.TestOnlySeqType, seqKey, t.after, t.maxFormat) 355 if t.sequence == -1 { 356 c.Check(err, DeepEquals, &asserts.NotFoundError{ 357 Type: asserts.TestOnlySeqType, 358 }) 359 } else { 360 c.Assert(err, IsNil) 361 c.Assert(a.HeaderString("n"), Equals, "s1") 362 c.Check(a.Sequence(), Equals, t.sequence) 363 c.Check(a.Format(), Equals, t.format) 364 c.Check(a.Revision(), Equals, t.revision) 365 } 366 } 367 368 _, err = bs.SequenceMemberAfter(asserts.TestOnlySeqType, []string{"s2"}, -1, 2) 369 c.Check(err, DeepEquals, &asserts.NotFoundError{ 370 Type: asserts.TestOnlySeqType, 371 }) 372 }