Merge ~jslarraz/review-tools:schema-add-layout into review-tools:master

Proposed by Jorge Sancho Larraz
Status: Merged
Merged at revision: 5934f2a041b7e784ab1bd332d7832536dfc1c5ce
Proposed branch: ~jslarraz/review-tools:schema-add-layout
Merge into: review-tools:master
Diff against target: 1025 lines (+180/-747)
6 files modified
check-names.list (+0/-3)
reviewtools/schemas/snap.json (+57/-0)
reviewtools/sr_lint.py (+0/-206)
reviewtools/tests/schemas/test_schema_snap.py (+123/-0)
reviewtools/tests/test_sr_lint.py (+0/-346)
tests/test.sh.expected (+0/-192)
Reviewer Review Type Date Requested Status
Alex Murray Approve
Review via email: mp+467096@code.launchpad.net

Commit message

many: validate snap.yaml::layout via schema

To post a comment you must log in.
Revision history for this message
Jorge Sancho Larraz (jslarraz) wrote :

reviewtools/tests/schemas/test_schema_against_store.py validates the current snap.yaml schema against all snaps in the store. No additional errors have been found in this version.

Revision history for this message
Jorge Sancho Larraz (jslarraz) wrote :

See inline comments

Revision history for this message
Alex Murray (alexmurray) wrote :

LGTM!

review: Approve
Revision history for this message
Jorge Sancho Larraz (jslarraz) wrote :

Current tests cases have a 100% coverage. Thus, passing all the existent cases indicates that the regular expression is fine

See https://gist.github.com/jslarraz/9042092c83160a10af0985af716a382d

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
diff --git a/check-names.list b/check-names.list
index 5725ecf..687f33f 100644
--- a/check-names.list
+++ b/check-names.list
@@ -90,9 +90,6 @@ lint-snap-v2:icon_theme_size|
90lint-snap-v2:iffy_files|90lint-snap-v2:iffy_files|
91lint-snap-v2:install-mode|91lint-snap-v2:install-mode|
92lint-snap-v2:invalid_link|92lint-snap-v2:invalid_link|
93lint-snap-v2:layout_source|
94lint-snap-v2:layout_target|
95lint-snap-v2:layout|
96lint-snap-v2:meta_gui_desktop|93lint-snap-v2:meta_gui_desktop|
97lint-snap-v2:mpris_slot_name|94lint-snap-v2:mpris_slot_name|
98lint-snap-v2:personal-files_attrib_valid|95lint-snap-v2:personal-files_attrib_valid|
diff --git a/reviewtools/schemas/snap.json b/reviewtools/schemas/snap.json
index e8038b0..d45ddbf 100644
--- a/reviewtools/schemas/snap.json
+++ b/reviewtools/schemas/snap.json
@@ -89,6 +89,63 @@
89 }89 }
90 },90 },
91 "additionalProperties": false91 "additionalProperties": false
92 },
93 "layout": {
94 "description": "Modify the execution environment of a strictly-confined snap.",
95 "$comment": "See https://forum.snapcraft.io/t/why-are-snap-layouts-limited-to-15-entries/15337/3",
96 "type": "object",
97 "propertyNames": {
98 "not": {
99 "anyOf": [
100 {"pattern": "^/boot"},
101 {"pattern": "^/dev"},
102 {"pattern": "^/home"},
103 {"pattern": "^(/usr)?/lib/firmware"},
104 {"pattern": "^(/usr)?/lib/modules"},
105 {"pattern": "^/lost+found"},
106 {"pattern": "^/media"},
107 {"pattern": "^/proc"},
108 {"pattern": "^(/var)?/run"},
109 {"pattern": "^/sys"},
110 {"pattern": "^/tmp"},
111 {"pattern": "^/var/lib/snapd"},
112 {"pattern": "^/var/snap"}
113 ]
114 }
115 },
116 "patternProperties": {
117 "^(?:\\$(?:SNAP|SNAP_COMMON|SNAP_DATA))?(\\/(?![\\.]*\\/)[^\\/\\0]*)*[\\/]?$": {
118 "$comment": "The core of this regex, (\\/[^\\/\\0]*)*, is intended to match groups of (slash + file name), where file name does not contain slash or NULL characters. The negative lookahead (?![\\.]*\\/) is used to ensure that at least one character other than dots is present between two consecutive slashes, thus avoiding non-normalized paths but still allowing hidden files. Optionally the path may start with $SNAP, $SNAP_COMMON or $SNAP_DATA and may have a tailing slash",
119 "type": "object",
120 "patternProperties": {
121 "^bind|bind-file|symlink$": {
122 "type": "string",
123 "$comment": "This regex is identical to the previous one with the exception that it always must start with $SNAP, $SNAP_COMMON or $SNAP_DATA",
124 "pattern": "^\\$(SNAP|SNAP_COMMON|SNAP_DATA)(\\/(?![\\.]*\\/)[^\\/\\0]*)*[\\/]?$"
125 },
126 "^mode$": {
127 "type": "integer",
128 "minimum": 1,
129 "maximum": 511
130 },
131 "^type$": {
132 "type": "string",
133 "enum": ["tmpfs"]
134 },
135 "^user|group$": {
136 "type": "string",
137 "not": {
138 "pattern": "^[0-9]+$"
139 }
140 }
141 },
142 "minProperties": 1,
143 "additionalProperties": false
144 }
145 },
146 "minProperties": 1,
147 "maxProperties": 100,
148 "additionalProperties": false
92 }149 }
93 },150 },
94 "required": ["name", "version"]151 "required": ["name", "version"]
diff --git a/reviewtools/sr_lint.py b/reviewtools/sr_lint.py
index 8cad5e9..72d6691 100644
--- a/reviewtools/sr_lint.py
+++ b/reviewtools/sr_lint.py
@@ -2360,212 +2360,6 @@ class SnapReviewLint(SnapReview):
2360 s = "paths found in both read and write: %s" % ", ".join(both)2360 s = "paths found in both read and write: %s" % ", ".join(both)
2361 self._add_result(t, n, s)2361 self._add_result(t, n, s)
23622362
2363 def check_layout(self):
2364 """Check layout"""
2365 if "layout" not in self.snap_yaml:
2366 return
2367
2368 # snap/validate.go - ValidateLayout()
2369 snap_vars = ["$SNAP", "$SNAP_COMMON", "$SNAP_DATA"]
2370 target_bad_prefixes = [
2371 "/boot",
2372 "/dev",
2373 "/home",
2374 "(/usr)?/lib/firmware",
2375 "(/usr)?/lib/modules",
2376 "/lost+found",
2377 "/media",
2378 "/proc",
2379 "(/var)?/run",
2380 "/sys",
2381 "/tmp",
2382 "/var/lib/snapd",
2383 "/var/snap",
2384 ]
2385
2386 def _verify_layout_target(p, disallowed):
2387 if "\0" in p or os.path.normpath(p) != p:
2388 return False
2389
2390 # if the normalized path starts with snap_vars, then it is ok
2391 for prefix in snap_vars:
2392 if p.startswith("%s/" % prefix):
2393 return True
2394
2395 # otherwise it must be an absolute path
2396 if not p.startswith("/"):
2397 return False
2398
2399 # p is now guaranteed to start with '/' and not '//...'
2400 for dis in disallowed:
2401 if re.match(dis, p):
2402 return False
2403
2404 return True
2405
2406 def _verify_layout_source(p, allowed):
2407 if "\0" in p or os.path.normpath(p) != p or not p.startswith("$"):
2408 return False
2409
2410 # p is guaranteed to start with '$'
2411 top = p.split("/")[0]
2412 if top not in allowed:
2413 return False
2414
2415 return True
2416
2417 # arbitrary; 10 was agreed upon with snapd team (zyga) but found snaps
2418 # with 8, so bumped to 15. Unfortunately, others hit the ceiling, so
2419 # bumping to 30, then bumped to 100 since surely 100 layouts is enough
2420 # for anyone ;)
2421 # https://forum.snapcraft.io/t/why-are-snap-layouts-limited-to-15-entries/15337/3
2422 maximum_layouts = 100
2423
2424 key = "layout"
2425 t = "info"
2426 n = self._get_check_name(key)
2427 s = "OK"
2428 if not isinstance(self.snap_yaml[key], dict):
2429 t = "error"
2430 s = "invalid %s entry: %s (not a dict)" % (key, self.snap_yaml[key])
2431 self._add_result(t, n, s)
2432 return
2433 elif len(self.snap_yaml[key].keys()) < 1:
2434 t = "error"
2435 s = "invalid %s entry (empty)" % (key)
2436 self._add_result(t, n, s)
2437 return
2438 elif len(self.snap_yaml[key].keys()) > maximum_layouts:
2439 t = "error"
2440 s = "too many defined layouts (%d > %d)" % (
2441 len(self.snap_yaml[key].keys()),
2442 maximum_layouts,
2443 )
2444 self._add_result(t, n, s)
2445 return
2446 self._add_result(t, n, s)
2447
2448 for target in self.snap_yaml[key]:
2449 t = "info"
2450 n = self._get_check_name("%s_target" % key, app=target)
2451 s = "OK"
2452
2453 if not isinstance(self.snap_yaml[key][target], dict):
2454 t = "error"
2455 s = "invalid entry: %s (not a dict)" % (self.snap_yaml[key][target])
2456 self._add_result(t, n, s)
2457 continue
2458 elif len(self.snap_yaml[key][target].keys()) < 1:
2459 t = "error"
2460 s = "invalid target '%s' (empty)" % (target)
2461 self._add_result(t, n, s)
2462 continue
2463 elif not _verify_layout_target(target, target_bad_prefixes):
2464 t = "error"
2465 s = (
2466 "invalid mount target: '%s'" % target
2467 + " (should be "
2468 + "a legal path (ie, absolute path or one that starts "
2469 + "with: %s)" % ", ".join(snap_vars)
2470 + ". If absolute, "
2471 + "should not start with: %s" % ", ".join(target_bad_prefixes)
2472 )
2473 self._add_result(t, n, s)
2474 continue
2475 self._add_result(t, n, s)
2476
2477 # from snap/info_snap.go
2478 known = ["bind", "bind-file", "symlink", "type", "user", "group", "mode"]
2479 for ltype in self.snap_yaml[key][target]:
2480 t = "info"
2481 n = self._get_check_name("%s" % key, app=target, extra=ltype)
2482 s = "OK"
2483
2484 if ltype not in known:
2485 t = "error"
2486 s = "invalid layout: '%s' (should be one of %s)" % (
2487 ltype,
2488 ", ".join(known),
2489 )
2490 self._add_result(t, n, s)
2491 continue
2492
2493 if ltype in ["bind", "bind-file", "symlink"]:
2494 target = target
2495 source = self.snap_yaml[key][target][ltype]
2496 t = "info"
2497 n = self._get_check_name(
2498 "%s_source" % key, app=target, extra=source
2499 )
2500 s = "OK"
2501
2502 if not isinstance(source, str):
2503 t = "error"
2504 s = "invalid source: %s (not a str)" % source
2505 elif not _verify_layout_source(source, snap_vars):
2506 t = "error"
2507 s = (
2508 "invalid source mount: '%s' " % source
2509 + "(should be a legal path and start with one "
2510 + "of: %s" % ", ".join(snap_vars)
2511 )
2512 elif ltype == "mode":
2513 ltype = "mode"
2514 rdata = self.snap_yaml[key][target][ltype]
2515 if not isinstance(rdata, int) and not isinstance(rdata, str):
2516 t = "error"
2517 s = "invalid mode: should be an integer (eg, 0755)"
2518 self._add_result(t, n, s)
2519 continue
2520
2521 mode = None
2522 if isinstance(rdata, str):
2523 try:
2524 mode = int(rdata, 8)
2525 except Exception:
2526 t = "error"
2527 s = (
2528 "mode '%s' should be an integer " % rdata
2529 + "within 1-777 octal"
2530 )
2531 self._add_result(t, n, s)
2532 continue
2533 else:
2534 mode = rdata
2535
2536 if mode < 0o1 or mode > 0o777:
2537 t = "error"
2538 s = "mode '%s' must be within 1-777 octal" % format(mode, "o")
2539 elif ltype == "type":
2540 ltype = "type"
2541 rdata = self.snap_yaml[key][target][ltype]
2542 if not isinstance(rdata, str):
2543 t = "error"
2544 s = "invalid %s (not a str)" % ltype
2545 self._add_result(t, n, s)
2546 continue
2547
2548 if rdata != "tmpfs":
2549 t = "error"
2550 s = "invalid type: %s != tmpfs" % rdata
2551 elif ltype in ["user", "group"]:
2552 rdata = self.snap_yaml[key][target][ltype]
2553 if not isinstance(rdata, str):
2554 t = "error"
2555 s = "invalid %s (not a str)" % ltype
2556 self._add_result(t, n, s)
2557 continue
2558
2559 # Don't allow specifying uids
2560 try:
2561 int(self.snap_yaml[key][target][ltype])
2562 t = "error"
2563 s = "invalid %s (should not be a number)" % ltype
2564 except Exception:
2565 pass
2566
2567 self._add_result(t, n, s)
2568
2569 def check_apps_install_mode(self):2363 def check_apps_install_mode(self):
2570 """Check apps - install-mode"""2364 """Check apps - install-mode"""
2571 if "apps" not in self.snap_yaml:2365 if "apps" not in self.snap_yaml:
diff --git a/reviewtools/tests/schemas/test_schema_snap.py b/reviewtools/tests/schemas/test_schema_snap.py
index beed77e..96484d3 100644
--- a/reviewtools/tests/schemas/test_schema_snap.py
+++ b/reviewtools/tests/schemas/test_schema_snap.py
@@ -354,3 +354,126 @@ class TestSchemaSnap(TestSchemaBase):
354 with self.subTest(value=value):354 with self.subTest(value=value):
355 error = error.replace("{value}", str(value)) if error else error355 error = error.replace("{value}", str(value)) if error else error
356 self._test_value("environment", value, error)356 self._test_value("environment", value, error)
357
358 def test_layout(self):
359 for value, error in [
360 # test_check_layout
361 (
362 {
363 "/etc/demo": {"bind": "$SNAP_COMMON/etc/demo"},
364 "/etc/demo.cfg": {"symlink": "$SNAP_COMMON/etc/demo.conf"},
365 "/etc/demo.conf": {"bind-file": "$SNAP_COMMON/etc/demo.conf"},
366 "/opt/demo": {"bind": "$SNAP/opt/demo"},
367 "/usr/share/demo": {"bind": "$SNAP/usr/share/demo"},
368 "/var/cache/demo": {"bind": "$SNAP_DATA/var/cache/demo"},
369 "/var/lib/demo": {"bind": "$SNAP_DATA/var/lib/demo"},
370 "/var/lib/foo": {"type": "tmpfs", "mode": 0o755},
371 "/var/lib/bar": {
372 "type": "tmpfs",
373 "user": "username",
374 "group": "groupname",
375 "mode": 0o755,
376 },
377 },
378 None,
379 ),
380 # test_check_layout_bad - list
381 ([], "{value} is not of type 'object'"),
382 # test_check_layout_empty
383 ({}, "{value} does not have enough properties"),
384 # test_check_layout_source_target_use_snap_vars - source/target use $SNAP
385 ({"$SNAP/db": {"bind": "$SNAP_DATA/db"}}, None),
386 # test_check_layout_target_bad_snap_var - bad target (SNAP_USER_COMMON)
387 (
388 {"$SNAP_USER_COMMON/db": {"bind": "$SNAP_DATA/db"}},
389 "'$SNAP_USER_COMMON/db' does not match ",
390 ),
391 # test_check_layout_target_bad_val - bad target (list)
392 ({"/etc/demo": []}, "[] is not of type 'object'"),
393 # test_check_layout_target_bad_empty
394 ({"/etc/demo": {}}, "{} does not have enough properties"),
395 # test_check_layout_target_bad_too_many
396 (
397 dict.fromkeys(["/a/%s" % i for i in range(101)], {"bind": "$SNAP/db"}),
398 "{value} has too many properties",
399 ),
400 # test_check_layout_target_bad - bad target (normpath)
401 (
402 {"/etc/../demo": {"bind": "$SNAP_COMMON/etc/demo"}},
403 "'/etc/../demo' does not match ",
404 ),
405 # test_check_layout_target_bad_prefix - bad target (prefix)
406 (
407 {"/proc/cmdline": {"bind": "$SNAP_COMMON/etc/demo"}},
408 " is not allowed for '/proc/cmdline'",
409 ),
410 (
411 {"/lib/firmware/foo": {"bind": "$SNAP_COMMON/etc/demo"}},
412 "is not allowed for '/lib/firmware/foo'",
413 ),
414 (
415 {"/usr/lib/firmware": {"bind": "$SNAP_COMMON/etc/demo"}},
416 "is not allowed for '/usr/lib/firmware'",
417 ),
418 (
419 {"/run": {"bind": "$SNAP_COMMON/etc/demo"}},
420 "is not allowed for '/run'",
421 ),
422 (
423 {"/var/run": {"bind": "$SNAP_COMMON/etc/demo"}},
424 "is not allowed for '/var/run'",
425 ),
426 # test_check_layout_source_bad_prefix - bad source (prefix)
427 (
428 {"/etc/demo": {"bind": "/bad/etc/demo"}},
429 "'/bad/etc/demo' does not match ",
430 ),
431 # test_check_layout_source_bad_prefix_home - bad source (prefix $HOME)
432 (
433 {"/var/tmp/other": {"bind": "$HOME/snap/other"}},
434 "'$HOME/snap/other' does not match ",
435 ),
436 # test_check_layout_source_bad_val - bad source (list)
437 ({"/etc/demo": {"bind": []}}, "[] is not of type 'string'"),
438 # test_check_layout_source_bad - bad source (normpath)
439 (
440 {"/etc/demo": {"bind": "$SNAP_COMMON/etc/../demo"}},
441 "'$SNAP_COMMON/etc/../demo' does not match",
442 ),
443 # test_check_layout_source_bad_type - bad source (type)
444 (
445 {"/etc/demo": {"nonexistent": "$SNAP_COMMON/etc/demo"}},
446 "'nonexistent' does not match any of the regexes: ",
447 ),
448 # test_check_layout_mode_bad
449 (
450 {"/var/lib/foo": {"type": "tmpfs", "mode": []}},
451 "[] is not of type 'integer'",
452 ),
453 # test_check_layout_mode_range - mode range TODO: can we limit it to integers? why no 0?
454 (
455 {"/var/lib/foo": {"type": "tmpfs", "mode": 0}},
456 "0 is less than the minimum of 1",
457 ),
458 (
459 {"/var/lib/foo": {"type": "tmpfs", "mode": 512}},
460 "512 is greater than the maximum of 511",
461 ),
462 (
463 {"/var/lib/foo": {"type": "tmpfs", "mode": "778"}},
464 "'778' is not of type 'integer'",
465 ),
466 # test_check_layout_type_bad
467 ({"/var/lib/foo": {"type": []}}, "[] is not of type 'string'"),
468 # test_check_layout_type_nonexistent
469 ({"/var/lib/foo": {"type": "nonexistent"}}, "'nonexistent' is not one of "),
470 # test_check_layout_user_bad
471 ({"/var/lib/foo": {"user": []}}, "[] is not of type 'string'"),
472 # test_check_layout_user_invalid
473 ({"/var/lib/foo": {"user": "0"}}, " is not allowed for '0'"),
474 # test_check_layout_group_bad
475 ({"/var/lib/foo": {"group": []}}, "[] is not of type 'string'"),
476 ]:
477 with self.subTest(value=value):
478 error = error.replace("{value}", str(value)) if error else error
479 self._test_value("layout", value, error)
diff --git a/reviewtools/tests/test_sr_lint.py b/reviewtools/tests/test_sr_lint.py
index 44f88df..14d0a54 100644
--- a/reviewtools/tests/test_sr_lint.py
+++ b/reviewtools/tests/test_sr_lint.py
@@ -4448,352 +4448,6 @@ class TestSnapReviewLint(sr_tests.TestSnapReview):
4448 expected_counts = {"info": None, "warn": 0, "error": 1}4448 expected_counts = {"info": None, "warn": 0, "error": 1}
4449 self.check_results(r, expected_counts)4449 self.check_results(r, expected_counts)
44504450
4451 def test_check_layout(self):
4452 """Test check_layout()"""
4453 self.set_test_snap_yaml(
4454 "layout",
4455 {
4456 "/etc/demo": {"bind": "$SNAP_COMMON/etc/demo"},
4457 "/etc/demo.cfg": {"symlink": "$SNAP_COMMON/etc/demo.conf"},
4458 "/etc/demo.conf": {"bind-file": "$SNAP_COMMON/etc/demo.conf"},
4459 "/opt/demo": {"bind": "$SNAP/opt/demo"},
4460 "/usr/share/demo": {"bind": "$SNAP/usr/share/demo"},
4461 "/var/cache/demo": {"bind": "$SNAP_DATA/var/cache/demo"},
4462 "/var/lib/demo": {"bind": "$SNAP_DATA/var/lib/demo"},
4463 "/var/lib/foo": {"type": "tmpfs", "mode": "755"},
4464 "/var/lib/bar": {
4465 "type": "tmpfs",
4466 "user": "username",
4467 "group": "groupname",
4468 "mode": "0755",
4469 },
4470 },
4471 )
4472 c = SnapReviewLint(SnapContainer(self.test_name))
4473 c.check_layout()
4474 r = c.review_report
4475 expected_counts = {"info": 23, "warn": 0, "error": 0}
4476 self.check_results(r, expected_counts)
4477
4478 def test_check_layout_bad(self):
4479 """Test check_layout() - bad (list)"""
4480 self.set_test_snap_yaml("layout", [])
4481 c = SnapReviewLint(SnapContainer(self.test_name))
4482 c.check_layout()
4483 r = c.review_report
4484 expected_counts = {"info": None, "warn": 0, "error": 1}
4485 self.check_results(r, expected_counts)
4486
4487 def test_check_layout_empty(self):
4488 """Test check_layout() - bad (empty)"""
4489 self.set_test_snap_yaml("layout", {})
4490 c = SnapReviewLint(SnapContainer(self.test_name))
4491 c.check_layout()
4492 r = c.review_report
4493 expected_counts = {"info": None, "warn": 0, "error": 1}
4494 self.check_results(r, expected_counts)
4495
4496 def test_check_layout_source_target_use_snap_vars(self):
4497 """Test check_layout() - source/target use $SNAP..."""
4498 self.set_test_snap_yaml("layout", {"$SNAP/db": {"bind": "$SNAP_DATA/db"}})
4499 c = SnapReviewLint(SnapContainer(self.test_name))
4500 c.check_layout()
4501 r = c.review_report
4502 expected_counts = {"info": 3, "warn": 0, "error": 0}
4503 self.check_results(r, expected_counts)
4504
4505 def test_check_layout_target_bad_snap_var(self):
4506 """Test check_layout() - bad target (SNAP_USER_COMMON)"""
4507 self.set_test_snap_yaml(
4508 "layout", {"$SNAP_USER_COMMON/db": {"bind": "$SNAP_DATA/db"}}
4509 )
4510 c = SnapReviewLint(SnapContainer(self.test_name))
4511 c.check_layout()
4512 r = c.review_report
4513 expected_counts = {"info": None, "warn": 0, "error": 1}
4514 self.check_results(r, expected_counts)
4515
4516 def test_check_layout_target_bad_val(self):
4517 """Test check_layout() - bad target (list)"""
4518 self.set_test_snap_yaml("layout", {"/etc/demo": []})
4519 c = SnapReviewLint(SnapContainer(self.test_name))
4520 c.check_layout()
4521 r = c.review_report
4522 expected_counts = {"info": None, "warn": 0, "error": 1}
4523 self.check_results(r, expected_counts)
4524
4525 def test_check_layout_target_bad_empty(self):
4526 """Test check_layout() - bad target (empty)"""
4527 self.set_test_snap_yaml("layout", {"/etc/demo": {}})
4528 c = SnapReviewLint(SnapContainer(self.test_name))
4529 c.check_layout()
4530 r = c.review_report
4531 expected_counts = {"info": None, "warn": 0, "error": 1}
4532 self.check_results(r, expected_counts)
4533
4534 def test_check_layout_target_bad_too_many(self):
4535 """Test check_layout() - bad target (too many)"""
4536 self.set_test_snap_yaml(
4537 "layout",
4538 {
4539 "/a/1": {"bind": "$SNAP/1"},
4540 "/a/2": {"bind": "$SNAP/2"},
4541 "/a/3": {"bind": "$SNAP/3"},
4542 "/a/4": {"bind": "$SNAP/4"},
4543 "/a/5": {"bind": "$SNAP/5"},
4544 "/a/6": {"bind": "$SNAP/6"},
4545 "/a/7": {"bind": "$SNAP/7"},
4546 "/a/8": {"bind": "$SNAP/8"},
4547 "/a/9": {"bind": "$SNAP/9"},
4548 "/a/10": {"bind": "$SNAP/10"},
4549 "/a/11": {"bind": "$SNAP/11"},
4550 "/a/12": {"bind": "$SNAP/12"},
4551 "/a/13": {"bind": "$SNAP/13"},
4552 "/a/14": {"bind": "$SNAP/14"},
4553 "/a/15": {"bind": "$SNAP/15"},
4554 "/a/16": {"bind": "$SNAP/16"},
4555 "/a/17": {"bind": "$SNAP/17"},
4556 "/a/18": {"bind": "$SNAP/19"},
4557 "/a/19": {"bind": "$SNAP/19"},
4558 "/a/20": {"bind": "$SNAP/20"},
4559 "/a/21": {"bind": "$SNAP/21"},
4560 "/a/22": {"bind": "$SNAP/22"},
4561 "/a/23": {"bind": "$SNAP/23"},
4562 "/a/24": {"bind": "$SNAP/24"},
4563 "/a/25": {"bind": "$SNAP/25"},
4564 "/a/26": {"bind": "$SNAP/26"},
4565 "/a/27": {"bind": "$SNAP/27"},
4566 "/a/28": {"bind": "$SNAP/28"},
4567 "/a/29": {"bind": "$SNAP/29"},
4568 "/a/30": {"bind": "$SNAP/30"},
4569 "/a/31": {"bind": "$SNAP/31"},
4570 "/a/32": {"bind": "$SNAP/32"},
4571 "/a/33": {"bind": "$SNAP/33"},
4572 "/a/34": {"bind": "$SNAP/34"},
4573 "/a/35": {"bind": "$SNAP/35"},
4574 "/a/36": {"bind": "$SNAP/36"},
4575 "/a/37": {"bind": "$SNAP/37"},
4576 "/a/38": {"bind": "$SNAP/38"},
4577 "/a/39": {"bind": "$SNAP/39"},
4578 "/a/40": {"bind": "$SNAP/40"},
4579 "/a/41": {"bind": "$SNAP/41"},
4580 "/a/42": {"bind": "$SNAP/42"},
4581 "/a/43": {"bind": "$SNAP/43"},
4582 "/a/44": {"bind": "$SNAP/44"},
4583 "/a/45": {"bind": "$SNAP/45"},
4584 "/a/46": {"bind": "$SNAP/46"},
4585 "/a/47": {"bind": "$SNAP/47"},
4586 "/a/48": {"bind": "$SNAP/48"},
4587 "/a/49": {"bind": "$SNAP/49"},
4588 "/a/50": {"bind": "$SNAP/50"},
4589 "/a/51": {"bind": "$SNAP/51"},
4590 "/a/52": {"bind": "$SNAP/52"},
4591 "/a/53": {"bind": "$SNAP/53"},
4592 "/a/54": {"bind": "$SNAP/54"},
4593 "/a/55": {"bind": "$SNAP/55"},
4594 "/a/56": {"bind": "$SNAP/56"},
4595 "/a/57": {"bind": "$SNAP/57"},
4596 "/a/58": {"bind": "$SNAP/58"},
4597 "/a/59": {"bind": "$SNAP/59"},
4598 "/a/60": {"bind": "$SNAP/60"},
4599 "/a/61": {"bind": "$SNAP/61"},
4600 "/a/62": {"bind": "$SNAP/62"},
4601 "/a/63": {"bind": "$SNAP/63"},
4602 "/a/64": {"bind": "$SNAP/64"},
4603 "/a/65": {"bind": "$SNAP/65"},
4604 "/a/66": {"bind": "$SNAP/66"},
4605 "/a/67": {"bind": "$SNAP/67"},
4606 "/a/68": {"bind": "$SNAP/68"},
4607 "/a/69": {"bind": "$SNAP/69"},
4608 "/a/70": {"bind": "$SNAP/70"},
4609 "/a/71": {"bind": "$SNAP/71"},
4610 "/a/72": {"bind": "$SNAP/72"},
4611 "/a/73": {"bind": "$SNAP/73"},
4612 "/a/74": {"bind": "$SNAP/74"},
4613 "/a/75": {"bind": "$SNAP/75"},
4614 "/a/76": {"bind": "$SNAP/76"},
4615 "/a/77": {"bind": "$SNAP/77"},
4616 "/a/78": {"bind": "$SNAP/78"},
4617 "/a/79": {"bind": "$SNAP/79"},
4618 "/a/80": {"bind": "$SNAP/80"},
4619 "/a/81": {"bind": "$SNAP/81"},
4620 "/a/82": {"bind": "$SNAP/82"},
4621 "/a/83": {"bind": "$SNAP/83"},
4622 "/a/84": {"bind": "$SNAP/84"},
4623 "/a/85": {"bind": "$SNAP/85"},
4624 "/a/86": {"bind": "$SNAP/86"},
4625 "/a/87": {"bind": "$SNAP/87"},
4626 "/a/88": {"bind": "$SNAP/88"},
4627 "/a/89": {"bind": "$SNAP/89"},
4628 "/a/90": {"bind": "$SNAP/90"},
4629 "/a/91": {"bind": "$SNAP/91"},
4630 "/a/92": {"bind": "$SNAP/92"},
4631 "/a/93": {"bind": "$SNAP/93"},
4632 "/a/94": {"bind": "$SNAP/94"},
4633 "/a/95": {"bind": "$SNAP/95"},
4634 "/a/96": {"bind": "$SNAP/96"},
4635 "/a/97": {"bind": "$SNAP/97"},
4636 "/a/98": {"bind": "$SNAP/98"},
4637 "/a/99": {"bind": "$SNAP/99"},
4638 "/a/100": {"bind": "$SNAP/100"},
4639 "/a/101": {"bind": "$SNAP/101"},
4640 },
4641 )
4642 c = SnapReviewLint(SnapContainer(self.test_name))
4643 c.check_layout()
4644 r = c.review_report
4645 expected_counts = {"info": None, "warn": 0, "error": 1}
4646 self.check_results(r, expected_counts)
4647
4648 def test_check_layout_target_bad(self):
4649 """Test check_layout() - bad target (normpath)"""
4650 self.set_test_snap_yaml(
4651 "layout", {"/etc/../demo": {"bind": "$SNAP_COMMON/etc/demo"}}
4652 )
4653 c = SnapReviewLint(SnapContainer(self.test_name))
4654 c.check_layout()
4655 r = c.review_report
4656 expected_counts = {"info": None, "warn": 0, "error": 1}
4657 self.check_results(r, expected_counts)
4658
4659 def test_check_layout_target_bad_prefix(self):
4660 """Test check_layout() - bad target (prefix)"""
4661 for prefix in [
4662 "/proc/cmdline",
4663 "/lib/firmware/foo",
4664 "/usr/lib/firmware",
4665 "/run",
4666 "/var/run",
4667 ]:
4668 self.set_test_snap_yaml("layout", {prefix: {"bind": "$SNAP/etc/demo"}})
4669 c = SnapReviewLint(SnapContainer(self.test_name))
4670 c.check_layout()
4671 r = c.review_report
4672 expected_counts = {"info": None, "warn": 0, "error": 1}
4673 self.check_results(r, expected_counts)
4674
4675 def test_check_layout_source_bad_prefix(self):
4676 """Test check_layout() - bad source (prefix)"""
4677 self.set_test_snap_yaml("layout", {"/etc/demo": {"bind": "/bad/etc/demo"}})
4678 c = SnapReviewLint(SnapContainer(self.test_name))
4679 c.check_layout()
4680 r = c.review_report
4681 expected_counts = {"info": None, "warn": 0, "error": 1}
4682 self.check_results(r, expected_counts)
4683
4684 def test_check_layout_source_bad_prefix_home(self):
4685 """Test check_layout() - bad source (prefix $HOME)"""
4686 self.set_test_snap_yaml(
4687 "layout", {"/var/tmp/other": {"bind": "$HOME/snap/other"}}
4688 )
4689 c = SnapReviewLint(SnapContainer(self.test_name))
4690 c.check_layout()
4691 r = c.review_report
4692 expected_counts = {"info": None, "warn": 0, "error": 1}
4693 self.check_results(r, expected_counts)
4694
4695 def test_check_layout_source_bad_val(self):
4696 """Test check_layout() - bad source (list)"""
4697 self.set_test_snap_yaml("layout", {"/etc/demo": {"bind": []}})
4698 c = SnapReviewLint(SnapContainer(self.test_name))
4699 c.check_layout()
4700 r = c.review_report
4701 expected_counts = {"info": None, "warn": 0, "error": 1}
4702 self.check_results(r, expected_counts)
4703
4704 def test_check_layout_source_bad(self):
4705 """Test check_layout() - bad source (normpath)"""
4706 self.set_test_snap_yaml(
4707 "layout", {"/etc/demo": {"bind": "$SNAP_COMMON/etc/../demo"}}
4708 )
4709 c = SnapReviewLint(SnapContainer(self.test_name))
4710 c.check_layout()
4711 r = c.review_report
4712 expected_counts = {"info": None, "warn": 0, "error": 1}
4713 self.check_results(r, expected_counts)
4714
4715 def test_check_layout_source_bad_type(self):
4716 """Test check_layout() - bad source (type)"""
4717 self.set_test_snap_yaml(
4718 "layout", {"/etc/demo": {"nonexistent": "$SNAP_COMMON/etc/demo"}}
4719 )
4720 c = SnapReviewLint(SnapContainer(self.test_name))
4721 c.check_layout()
4722 r = c.review_report
4723 expected_counts = {"info": None, "warn": 0, "error": 1}
4724 self.check_results(r, expected_counts)
4725
4726 def test_check_layout_mode_bad(self):
4727 """Test check_layout() - mode bad"""
4728 self.set_test_snap_yaml(
4729 "layout", {"/var/lib/foo": {"type": "tmpfs", "mode": []}}
4730 )
4731 c = SnapReviewLint(SnapContainer(self.test_name))
4732 c.check_layout()
4733 r = c.review_report
4734 expected_counts = {"info": None, "warn": 0, "error": 1}
4735 self.check_results(r, expected_counts)
4736
4737 def test_check_layout_mode_range(self):
4738 """Test check_layout() - mode range"""
4739 self.set_test_snap_yaml(
4740 "layout",
4741 {
4742 "/var/lib/foo": {"type": "tmpfs", "mode": 0},
4743 "/var/lib/bar": {"type": "tmpfs", "mode": "778"},
4744 },
4745 )
4746 c = SnapReviewLint(SnapContainer(self.test_name))
4747 c.check_layout()
4748 r = c.review_report
4749 expected_counts = {"info": None, "warn": 0, "error": 2}
4750 self.check_results(r, expected_counts)
4751
4752 def test_check_layout_type_bad(self):
4753 """Test check_layout() - type bad"""
4754 self.set_test_snap_yaml("layout", {"/var/lib/foo": {"type": []}})
4755 c = SnapReviewLint(SnapContainer(self.test_name))
4756 c.check_layout()
4757 r = c.review_report
4758 expected_counts = {"info": None, "warn": 0, "error": 1}
4759 self.check_results(r, expected_counts)
4760
4761 def test_check_layout_type_nonexistent(self):
4762 """Test check_layout() - type nonexistent"""
4763 self.set_test_snap_yaml("layout", {"/var/lib/foo": {"type": "nonexistent"}})
4764 c = SnapReviewLint(SnapContainer(self.test_name))
4765 c.check_layout()
4766 r = c.review_report
4767 expected_counts = {"info": None, "warn": 0, "error": 1}
4768 self.check_results(r, expected_counts)
4769
4770 def test_check_layout_user_bad(self):
4771 """Test check_layout() - user bad"""
4772 self.set_test_snap_yaml("layout", {"/var/lib/foo": {"user": []}})
4773 c = SnapReviewLint(SnapContainer(self.test_name))
4774 c.check_layout()
4775 r = c.review_report
4776 expected_counts = {"info": None, "warn": 0, "error": 1}
4777 self.check_results(r, expected_counts)
4778
4779 def test_check_layout_user_invalid(self):
4780 """Test check_layout() - user invalid"""
4781 self.set_test_snap_yaml("layout", {"/var/lib/foo": {"user": "0"}})
4782 c = SnapReviewLint(SnapContainer(self.test_name))
4783 c.check_layout()
4784 r = c.review_report
4785 expected_counts = {"info": None, "warn": 0, "error": 1}
4786 self.check_results(r, expected_counts)
4787
4788 def test_check_layout_group_bad(self):
4789 """Test check_layout() - group bad"""
4790 self.set_test_snap_yaml("layout", {"/var/lib/foo": {"group": []}})
4791 c = SnapReviewLint(SnapContainer(self.test_name))
4792 c.check_layout()
4793 r = c.review_report
4794 expected_counts = {"info": None, "warn": 0, "error": 1}
4795 self.check_results(r, expected_counts)
4796
4797 def test_check_apps_install_mode(self):4451 def test_check_apps_install_mode(self):
4798 """Test check_apps_install_mode()"""4452 """Test check_apps_install_mode()"""
4799 self.set_test_snap_yaml("apps", {"foo": {"install-mode": "enable"}})4453 self.set_test_snap_yaml("apps", {"foo": {"install-mode": "enable"}})
diff --git a/tests/test.sh.expected b/tests/test.sh.expected
index 7e394ec..e74cc2c 100644
--- a/tests/test.sh.expected
+++ b/tests/test.sh.expected
@@ -4852,18 +4852,6 @@ nix-example-jormungandr_f7xva0vh9fzv20vhyr121yd6ahplqh9v_amd64.snap: pass
4852 "manual_review": false,4852 "manual_review": false,
4853 "text": "OK"4853 "text": "OK"
4854 },4854 },
4855 "lint-snap-v2:layout": {
4856 "manual_review": false,
4857 "text": "OK"
4858 },
4859 "lint-snap-v2:layout_source:/nix:$SNAP/nix": {
4860 "manual_review": false,
4861 "text": "OK"
4862 },
4863 "lint-snap-v2:layout_target:/nix": {
4864 "manual_review": false,
4865 "text": "OK"
4866 },
4867 "lint-snap-v2:snap_type_redflag": {4855 "lint-snap-v2:snap_type_redflag": {
4868 "manual_review": false,4856 "manual_review": false,
4869 "text": "OK"4857 "text": "OK"
@@ -5015,18 +5003,6 @@ nix-example-jormungandr_f7xva0vh9fzv20vhyr121yd6ahplqh9v_amd64.snap: pass
5015 "manual_review": false,5003 "manual_review": false,
5016 "text": "OK"5004 "text": "OK"
5017 },5005 },
5018 "lint-snap-v2:layout": {
5019 "manual_review": false,
5020 "text": "OK"
5021 },
5022 "lint-snap-v2:layout_source:/nix:$SNAP/nix": {
5023 "manual_review": false,
5024 "text": "OK"
5025 },
5026 "lint-snap-v2:layout_target:/nix": {
5027 "manual_review": false,
5028 "text": "OK"
5029 },
5030 "lint-snap-v2:snap_type_redflag": {5006 "lint-snap-v2:snap_type_redflag": {
5031 "manual_review": false,5007 "manual_review": false,
5032 "text": "OK"5008 "text": "OK"
@@ -5268,18 +5244,6 @@ nix-example_g7qmi8r4qwws6fhwschfb8aib5wl0x1q_amd64.snap: pass
5268 "manual_review": false,5244 "manual_review": false,
5269 "text": "OK"5245 "text": "OK"
5270 },5246 },
5271 "lint-snap-v2:layout": {
5272 "manual_review": false,
5273 "text": "OK"
5274 },
5275 "lint-snap-v2:layout_source:/nix:$SNAP/nix": {
5276 "manual_review": false,
5277 "text": "OK"
5278 },
5279 "lint-snap-v2:layout_target:/nix": {
5280 "manual_review": false,
5281 "text": "OK"
5282 },
5283 "lint-snap-v2:meta_gui_desktop": {5247 "lint-snap-v2:meta_gui_desktop": {
5284 "manual_review": false,5248 "manual_review": false,
5285 "text": "desktop interfaces (x11) specified without a corresponding meta/gui/*.desktop file. If your application does not require a desktop file, you may ignore this. Otherwise, if using snapcraft, please see https://snapcraft.io/docs/build-snaps/metadata#fixed-assets or provide a desktop file in meta/gui/*.desktop (it should reference one of the 'apps' from your snapcraft/snap.yaml)."5249 "text": "desktop interfaces (x11) specified without a corresponding meta/gui/*.desktop file. If your application does not require a desktop file, you may ignore this. Otherwise, if using snapcraft, please see https://snapcraft.io/docs/build-snaps/metadata#fixed-assets or provide a desktop file in meta/gui/*.desktop (it should reference one of the 'apps' from your snapcraft/snap.yaml)."
@@ -5516,18 +5480,6 @@ nix-example_g7qmi8r4qwws6fhwschfb8aib5wl0x1q_amd64.snap: pass
5516 "manual_review": false,5480 "manual_review": false,
5517 "text": "OK"5481 "text": "OK"
5518 },5482 },
5519 "lint-snap-v2:layout": {
5520 "manual_review": false,
5521 "text": "OK"
5522 },
5523 "lint-snap-v2:layout_source:/nix:$SNAP/nix": {
5524 "manual_review": false,
5525 "text": "OK"
5526 },
5527 "lint-snap-v2:layout_target:/nix": {
5528 "manual_review": false,
5529 "text": "OK"
5530 },
5531 "lint-snap-v2:meta_gui_desktop": {5483 "lint-snap-v2:meta_gui_desktop": {
5532 "manual_review": false,5484 "manual_review": false,
5533 "text": "desktop interfaces (x11) specified without a corresponding meta/gui/*.desktop file. If your application does not require a desktop file, you may ignore this. Otherwise, if using snapcraft, please see https://snapcraft.io/docs/build-snaps/metadata#fixed-assets or provide a desktop file in meta/gui/*.desktop (it should reference one of the 'apps' from your snapcraft/snap.yaml)."5485 "text": "desktop interfaces (x11) specified without a corresponding meta/gui/*.desktop file. If your application does not require a desktop file, you may ignore this. Otherwise, if using snapcraft, please see https://snapcraft.io/docs/build-snaps/metadata#fixed-assets or provide a desktop file in meta/gui/*.desktop (it should reference one of the 'apps' from your snapcraft/snap.yaml)."
@@ -35331,78 +35283,6 @@ test-snapd-layout_1.0_all.snap: pass
35331 "manual_review": false,35283 "manual_review": false,
35332 "text": "OK"35284 "text": "OK"
35333 },35285 },
35334 "lint-snap-v2:layout": {
35335 "manual_review": false,
35336 "text": "OK"
35337 },
35338 "lint-snap-v2:layout:/opt/foo:mode": {
35339 "manual_review": false,
35340 "text": "OK"
35341 },
35342 "lint-snap-v2:layout:/opt/foo:type": {
35343 "manual_review": false,
35344 "text": "OK"
35345 },
35346 "lint-snap-v2:layout_source:/etc/demo.cfg:$SNAP_COMMON/etc/demo.conf": {
35347 "manual_review": false,
35348 "text": "OK"
35349 },
35350 "lint-snap-v2:layout_source:/etc/demo.conf:$SNAP_COMMON/etc/demo.conf": {
35351 "manual_review": false,
35352 "text": "OK"
35353 },
35354 "lint-snap-v2:layout_source:/etc/demo:$SNAP_COMMON/etc/demo": {
35355 "manual_review": false,
35356 "text": "OK"
35357 },
35358 "lint-snap-v2:layout_source:/opt/demo:$SNAP/opt/demo": {
35359 "manual_review": false,
35360 "text": "OK"
35361 },
35362 "lint-snap-v2:layout_source:/usr/share/demo:$SNAP/usr/share/demo": {
35363 "manual_review": false,
35364 "text": "OK"
35365 },
35366 "lint-snap-v2:layout_source:/var/cache/demo:$SNAP_DATA/var/cache/demo": {
35367 "manual_review": false,
35368 "text": "OK"
35369 },
35370 "lint-snap-v2:layout_source:/var/lib/demo:$SNAP_DATA/var/lib/demo": {
35371 "manual_review": false,
35372 "text": "OK"
35373 },
35374 "lint-snap-v2:layout_target:/etc/demo": {
35375 "manual_review": false,
35376 "text": "OK"
35377 },
35378 "lint-snap-v2:layout_target:/etc/demo.cfg": {
35379 "manual_review": false,
35380 "text": "OK"
35381 },
35382 "lint-snap-v2:layout_target:/etc/demo.conf": {
35383 "manual_review": false,
35384 "text": "OK"
35385 },
35386 "lint-snap-v2:layout_target:/opt/demo": {
35387 "manual_review": false,
35388 "text": "OK"
35389 },
35390 "lint-snap-v2:layout_target:/opt/foo": {
35391 "manual_review": false,
35392 "text": "OK"
35393 },
35394 "lint-snap-v2:layout_target:/usr/share/demo": {
35395 "manual_review": false,
35396 "text": "OK"
35397 },
35398 "lint-snap-v2:layout_target:/var/cache/demo": {
35399 "manual_review": false,
35400 "text": "OK"
35401 },
35402 "lint-snap-v2:layout_target:/var/lib/demo": {
35403 "manual_review": false,
35404 "text": "OK"
35405 },
35406 "lint-snap-v2:snap_type_redflag": {35286 "lint-snap-v2:snap_type_redflag": {
35407 "manual_review": false,35287 "manual_review": false,
35408 "text": "OK"35288 "text": "OK"
@@ -35522,78 +35402,6 @@ test-snapd-layout_1.0_all.snap: pass
35522 "manual_review": false,35402 "manual_review": false,
35523 "text": "OK"35403 "text": "OK"
35524 },35404 },
35525 "lint-snap-v2:layout": {
35526 "manual_review": false,
35527 "text": "OK"
35528 },
35529 "lint-snap-v2:layout:/opt/foo:mode": {
35530 "manual_review": false,
35531 "text": "OK"
35532 },
35533 "lint-snap-v2:layout:/opt/foo:type": {
35534 "manual_review": false,
35535 "text": "OK"
35536 },
35537 "lint-snap-v2:layout_source:/etc/demo.cfg:$SNAP_COMMON/etc/demo.conf": {
35538 "manual_review": false,
35539 "text": "OK"
35540 },
35541 "lint-snap-v2:layout_source:/etc/demo.conf:$SNAP_COMMON/etc/demo.conf": {
35542 "manual_review": false,
35543 "text": "OK"
35544 },
35545 "lint-snap-v2:layout_source:/etc/demo:$SNAP_COMMON/etc/demo": {
35546 "manual_review": false,
35547 "text": "OK"
35548 },
35549 "lint-snap-v2:layout_source:/opt/demo:$SNAP/opt/demo": {
35550 "manual_review": false,
35551 "text": "OK"
35552 },
35553 "lint-snap-v2:layout_source:/usr/share/demo:$SNAP/usr/share/demo": {
35554 "manual_review": false,
35555 "text": "OK"
35556 },
35557 "lint-snap-v2:layout_source:/var/cache/demo:$SNAP_DATA/var/cache/demo": {
35558 "manual_review": false,
35559 "text": "OK"
35560 },
35561 "lint-snap-v2:layout_source:/var/lib/demo:$SNAP_DATA/var/lib/demo": {
35562 "manual_review": false,
35563 "text": "OK"
35564 },
35565 "lint-snap-v2:layout_target:/etc/demo": {
35566 "manual_review": false,
35567 "text": "OK"
35568 },
35569 "lint-snap-v2:layout_target:/etc/demo.cfg": {
35570 "manual_review": false,
35571 "text": "OK"
35572 },
35573 "lint-snap-v2:layout_target:/etc/demo.conf": {
35574 "manual_review": false,
35575 "text": "OK"
35576 },
35577 "lint-snap-v2:layout_target:/opt/demo": {
35578 "manual_review": false,
35579 "text": "OK"
35580 },
35581 "lint-snap-v2:layout_target:/opt/foo": {
35582 "manual_review": false,
35583 "text": "OK"
35584 },
35585 "lint-snap-v2:layout_target:/usr/share/demo": {
35586 "manual_review": false,
35587 "text": "OK"
35588 },
35589 "lint-snap-v2:layout_target:/var/cache/demo": {
35590 "manual_review": false,
35591 "text": "OK"
35592 },
35593 "lint-snap-v2:layout_target:/var/lib/demo": {
35594 "manual_review": false,
35595 "text": "OK"
35596 },
35597 "lint-snap-v2:snap_type_redflag": {35405 "lint-snap-v2:snap_type_redflag": {
35598 "manual_review": false,35406 "manual_review": false,
35599 "text": "OK"35407 "text": "OK"

Subscribers

People subscribed via source and target branches