github.com/Lephar/snapd@v0.0.0-20210825215435-c7fba9cef4d2/seed/validate_test.go (about) 1 // -*- Mode: Go; indent-tabs-mode: t -*- 2 3 /* 4 * Copyright (C) 2019-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 seed_test 21 22 import ( 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 28 . "gopkg.in/check.v1" 29 30 "github.com/snapcore/snapd/asserts" 31 "github.com/snapcore/snapd/seed" 32 "github.com/snapcore/snapd/seed/seedtest" 33 "github.com/snapcore/snapd/snap" 34 "github.com/snapcore/snapd/snap/squashfs" 35 "github.com/snapcore/snapd/testutil" 36 ) 37 38 type validateSuite struct { 39 testutil.BaseTest 40 41 *seedtest.TestingSeed16 42 } 43 44 var _ = Suite(&validateSuite{}) 45 46 var coreYaml = `name: core 47 version: 1.0 48 type: os 49 ` 50 51 const snapdYaml = `name: snapd 52 version: 1.0 53 type: snapd 54 ` 55 56 const packageCore18 = ` 57 name: core18 58 version: 18.04 59 type: base 60 ` 61 62 func (s *validateSuite) SetUpTest(c *C) { 63 s.BaseTest.SetUpTest(c) 64 s.BaseTest.AddCleanup(snap.MockSanitizePlugsSlots(func(snapInfo *snap.Info) {})) 65 66 s.TestingSeed16 = &seedtest.TestingSeed16{} 67 s.SetupAssertSigning("canonical") 68 s.Brands.Register("my-brand", brandPrivKey, map[string]interface{}{ 69 "verification": "verified", 70 }) 71 72 s.SeedDir = c.MkDir() 73 74 s.AddCleanup(seed.MockTrusted(s.StoreSigning.Trusted)) 75 76 err := os.MkdirAll(s.SnapsDir(), 0755) 77 c.Assert(err, IsNil) 78 err = os.Mkdir(s.AssertsDir(), 0755) 79 c.Assert(err, IsNil) 80 81 modelChain := s.MakeModelAssertionChain("my-brand", "my-model", map[string]interface{}{ 82 "classic": "true", 83 }) 84 s.WriteAssertions("model.asserts", modelChain...) 85 } 86 87 func (s *validateSuite) makeSnapInSeed(c *C, snapYaml string) { 88 publisher := "canonical" 89 fname, decl, rev := s.MakeAssertedSnap(c, snapYaml, nil, snap.R(1), publisher) 90 err := os.Rename(filepath.Join(s.SnapsDir(), fname), filepath.Join(s.SnapsDir(), fmt.Sprintf("%s_%s.snap", decl.SnapName(), snap.R(1)))) 91 c.Assert(err, IsNil) 92 93 acct, err := s.StoreSigning.Find(asserts.AccountType, map[string]string{"account-id": publisher}) 94 c.Assert(err, IsNil) 95 s.WriteAssertions(fmt.Sprintf("%s.asserts", decl.SnapName()), rev, decl, acct) 96 } 97 98 func (s *validateSuite) makeSeedYaml(c *C, seedYaml string) string { 99 tmpf := filepath.Join(s.SeedDir, "seed.yaml") 100 err := ioutil.WriteFile(tmpf, []byte(seedYaml), 0644) 101 c.Assert(err, IsNil) 102 return tmpf 103 } 104 105 func (s *validateSuite) TestValidateFromYamlSnapHappy(c *C) { 106 s.makeSnapInSeed(c, coreYaml) 107 s.makeSnapInSeed(c, `name: gtk-common-themes 108 version: 19.04`) 109 seedFn := s.makeSeedYaml(c, ` 110 snaps: 111 - name: core 112 channel: stable 113 file: core_1.snap 114 - name: gtk-common-themes 115 channel: stable/ubuntu-19.04 116 file: gtk-common-themes_1.snap 117 `) 118 119 err := seed.ValidateFromYaml(seedFn) 120 c.Assert(err, IsNil) 121 } 122 123 func (s *validateSuite) TestValidateFromYamlSnapMissingBase(c *C) { 124 s.makeSnapInSeed(c, `name: need-base 125 base: some-base 126 version: 1.0`) 127 s.makeSnapInSeed(c, coreYaml) 128 seedFn := s.makeSeedYaml(c, ` 129 snaps: 130 - name: core 131 file: core_1.snap 132 - name: need-base 133 file: need-base_1.snap 134 `) 135 136 err := seed.ValidateFromYaml(seedFn) 137 c.Assert(err, ErrorMatches, `cannot validate seed: 138 - cannot use snap "need-base": base "some-base" is missing`) 139 } 140 141 func (s *validateSuite) TestValidateFromYamlSnapMissingDefaultProvider(c *C) { 142 s.makeSnapInSeed(c, coreYaml) 143 s.makeSnapInSeed(c, `name: need-df 144 version: 1.0 145 plugs: 146 gtk-3-themes: 147 interface: content 148 default-provider: gtk-common-themes 149 `) 150 seedFn := s.makeSeedYaml(c, ` 151 snaps: 152 - name: core 153 file: core_1.snap 154 - name: need-df 155 file: need-df_1.snap 156 `) 157 158 err := seed.ValidateFromYaml(seedFn) 159 c.Assert(err, ErrorMatches, `cannot validate seed: 160 - cannot use snap "need-df": default provider "gtk-common-themes" is missing`) 161 } 162 163 func (s *validateSuite) TestValidateFromYamlSnapSnapdHappy(c *C) { 164 s.makeSnapInSeed(c, snapdYaml) 165 s.makeSnapInSeed(c, packageCore18) 166 s.makeSnapInSeed(c, `name: some-snap 167 version: 1.0 168 base: core18 169 `) 170 seedFn := s.makeSeedYaml(c, ` 171 snaps: 172 - name: snapd 173 file: snapd_1.snap 174 - name: some-snap 175 file: some-snap_1.snap 176 - name: core18 177 file: core18_1.snap 178 `) 179 180 err := seed.ValidateFromYaml(seedFn) 181 c.Assert(err, IsNil) 182 } 183 184 func (s *validateSuite) TestValidateFromYamlSnapMissingCore(c *C) { 185 s.makeSnapInSeed(c, snapdYaml) 186 s.makeSnapInSeed(c, `name: some-snap 187 version: 1.0`) 188 seedFn := s.makeSeedYaml(c, ` 189 snaps: 190 - name: snapd 191 file: snapd_1.snap 192 - name: some-snap 193 file: some-snap_1.snap 194 `) 195 196 err := seed.ValidateFromYaml(seedFn) 197 c.Assert(err, ErrorMatches, `cannot validate seed: 198 - cannot use snap "some-snap": required snap "core" missing`) 199 } 200 201 func (s *validateSuite) TestValidateFromYamlSnapMissingSnapdOrCore(c *C) { 202 s.makeSnapInSeed(c, packageCore18) 203 s.makeSnapInSeed(c, `name: some-snap 204 version: 1.0 205 base: core18`) 206 seedFn := s.makeSeedYaml(c, ` 207 snaps: 208 - name: some-snap 209 file: some-snap_1.snap 210 - name: core18 211 file: core18_1.snap 212 `) 213 214 err := seed.ValidateFromYaml(seedFn) 215 c.Assert(err, ErrorMatches, `cannot validate seed: 216 - essential snap core or snapd must be part of the seed`) 217 } 218 219 func (s *validateSuite) TestValidateFromYamlSnapMissingSnapd(c *C) { 220 modelChain := s.MakeModelAssertionChain("my-brand", "my-model", map[string]interface{}{ 221 "classic": "true", 222 "required-snaps": []interface{}{"snapd"}, 223 }) 224 s.WriteAssertions("model.asserts", modelChain...) 225 226 s.makeSnapInSeed(c, packageCore18) 227 s.makeSnapInSeed(c, `name: some-snap 228 version: 1.0 229 base: core18`) 230 seedFn := s.makeSeedYaml(c, ` 231 snaps: 232 - name: some-snap 233 file: some-snap_1.snap 234 - name: core18 235 file: core18_1.snap 236 `) 237 238 err := seed.ValidateFromYaml(seedFn) 239 c.Assert(err, ErrorMatches, `cannot validate seed: 240 - essential snap "snapd" required by the model is missing in the seed`) 241 } 242 243 func (s *validateSuite) makeBrokenSnap(c *C, snapYaml string) (snapPath string) { 244 snapBuildDir := c.MkDir() 245 metaSnapYaml := filepath.Join(snapBuildDir, "meta", "snap.yaml") 246 err := os.MkdirAll(filepath.Dir(metaSnapYaml), 0755) 247 c.Assert(err, IsNil) 248 err = ioutil.WriteFile(metaSnapYaml, []byte(snapYaml), 0644) 249 c.Assert(err, IsNil) 250 251 // need to build the snap "manually" pack.Snap() will do validation 252 snapPath = filepath.Join(c.MkDir(), "broken.snap") 253 d := squashfs.New(snapPath) 254 err = d.Build(snapBuildDir, nil) 255 c.Assert(err, IsNil) 256 257 return snapPath 258 } 259 260 func (s *validateSuite) TestValidateFromYamlSnapSnapInvalid(c *C) { 261 s.makeSnapInSeed(c, coreYaml) 262 263 // "version" is missing in this yaml 264 snapYaml := `name: some-snap-invalid-yaml` 265 snapPath := s.makeBrokenSnap(c, snapYaml) 266 267 // put the broken snap in place 268 dst := filepath.Join(s.SnapsDir(), "some-snap-invalid-yaml_1.snap") 269 err := os.Rename(snapPath, dst) 270 c.Assert(err, IsNil) 271 272 seedFn := s.makeSeedYaml(c, ` 273 snaps: 274 - name: core 275 file: core_1.snap 276 - name: some-snap-invalid-yaml 277 unasserted: true 278 file: some-snap-invalid-yaml_1.snap 279 `) 280 281 err = seed.ValidateFromYaml(seedFn) 282 c.Assert(err, ErrorMatches, `cannot validate seed: 283 - cannot use snap "/.*/snaps/some-snap-invalid-yaml_1.snap": invalid snap version: cannot be empty`) 284 } 285 286 func (s *validateSuite) TestValidateFromYamlSnapMultipleErrors(c *C) { 287 s.makeSnapInSeed(c, coreYaml) 288 s.makeSnapInSeed(c, `name: need-df 289 version: 1.0 290 plugs: 291 gtk-3-themes: 292 interface: content 293 default-provider: gtk-common-themes 294 `) 295 296 // "version" is missing in this yaml 297 snapYaml := `name: some-snap-invalid-yaml` 298 snapPath := s.makeBrokenSnap(c, snapYaml) 299 300 // put the broken snap in place 301 dst := filepath.Join(s.SnapsDir(), "some-snap-invalid-yaml_1.snap") 302 err := os.Rename(snapPath, dst) 303 c.Assert(err, IsNil) 304 305 seedFn := s.makeSeedYaml(c, ` 306 snaps: 307 - name: core 308 file: core_1.snap 309 - name: need-df 310 file: need-df_1.snap 311 - name: some-snap-invalid-yaml 312 unasserted: true 313 file: some-snap-invalid-yaml_1.snap 314 `) 315 316 err = seed.ValidateFromYaml(seedFn) 317 c.Assert(err, ErrorMatches, `cannot validate seed: 318 - cannot use snap "/.*/snaps/some-snap-invalid-yaml_1.snap": invalid snap version: cannot be empty 319 - cannot use snap "need-df": default provider "gtk-common-themes" is missing`) 320 } 321 322 func (s *validateSuite) TestValidateFromYamlSnapSnapMissing(c *C) { 323 s.makeSnapInSeed(c, coreYaml) 324 seedFn := s.makeSeedYaml(c, ` 325 snaps: 326 - name: core 327 file: core_1.snap 328 - name: some-snap 329 file: some-snap_1.snap 330 `) 331 332 err := seed.ValidateFromYaml(seedFn) 333 c.Assert(err, ErrorMatches, `cannot validate seed: 334 - cannot compute snap "/.*/snaps/some-snap_1.snap" digest:.* no such file or directory`) 335 } 336 337 func (s *validateSuite) TestValidateFromYamlSnapMissingAssertions(c *C) { 338 s.makeSnapInSeed(c, snapdYaml) 339 s.makeSnapInSeed(c, packageCore18) 340 s.makeSnapInSeed(c, `name: some-snap 341 version: 1.0 342 base: core18 343 `) 344 seedFn := s.makeSeedYaml(c, ` 345 snaps: 346 - name: snapd 347 file: snapd_1.snap 348 - name: some-snap 349 file: some-snap_1.snap 350 - name: core18 351 file: core18_1.snap 352 `) 353 354 err := os.Remove(filepath.Join(s.AssertsDir(), "some-snap.asserts")) 355 c.Assert(err, IsNil) 356 357 err = seed.ValidateFromYaml(seedFn) 358 c.Assert(err, ErrorMatches, `cannot validate seed: 359 - cannot find signatures with metadata for snap "some-snap" .*`) 360 361 } 362 363 func (s *validateSuite) TestValidateFromYamlDuplicatedSnap(c *C) { 364 s.makeSnapInSeed(c, coreYaml) 365 s.makeSnapInSeed(c, `name: gtk-common-themes 366 version: 19.04`) 367 seedFn := s.makeSeedYaml(c, ` 368 snaps: 369 - name: core 370 channel: stable 371 file: core_1.snap 372 - name: gtk-common-themes 373 channel: stable/ubuntu-19.04 374 file: gtk-common-themes_1.snap 375 - name: gtk-common-themes 376 channel: stable/ubuntu-19.04 377 file: gtk-common-themes_1.snap 378 `) 379 380 err := seed.ValidateFromYaml(seedFn) 381 c.Assert(err, ErrorMatches, `cannot validate seed: 382 - cannot read seed yaml: snap name "gtk-common-themes" must be unique`) 383 } 384 385 func (s *validateSuite) TestValidateFromYamlRegressionLP1825437(c *C) { 386 s.makeSnapInSeed(c, coreYaml) 387 s.makeSnapInSeed(c, `name: gtk-common-themes 388 version: 19.04`) 389 seedFn := s.makeSeedYaml(c, ` 390 snaps: 391 - 392 name: core 393 channel: stable 394 file: core_1.snap 395 - 396 - 397 name: gtk-common-themes 398 channel: stable/ubuntu-19.04 399 file: gtk-common-themes_1.snap 400 `) 401 402 err := seed.ValidateFromYaml(seedFn) 403 c.Assert(err, ErrorMatches, `cannot validate seed: 404 - cannot read seed yaml: empty element in seed`) 405 }