Merge lp:~jdstrand/click-reviewers-tools/click-reviewers-tools.modern-yaml into lp:click-reviewers-tools

Proposed by Jamie Strandboge on 2015-05-11
Status: Merged
Merged at revision: 461
Proposed branch: lp:~jdstrand/click-reviewers-tools/click-reviewers-tools.modern-yaml
Merge into: lp:click-reviewers-tools
Diff against target: 1552 lines (+1312/-22)
8 files modified
clickreviews/cr_framework.py (+6/-7)
clickreviews/cr_lint.py (+32/-0)
clickreviews/cr_security.py (+464/-7)
clickreviews/cr_tests.py (+50/-5)
clickreviews/tests/test_cr_lint.py (+77/-0)
clickreviews/tests/test_cr_security.py (+675/-1)
debian/changelog (+2/-0)
run-pep8 (+6/-2)
To merge this branch: bzr merge lp:~jdstrand/click-reviewers-tools/click-reviewers-tools.modern-yaml
Reviewer Review Type Date Requested Status
Daniel Holbach (community) 2015-05-11 Approve on 2015-05-18
Review via email: mp+258791@code.launchpad.net

Description of the Change

  * add security yaml checks
  * cr_lint.py: don't allow same key in 'binaries' and 'services'

To post a comment you must log in.
Daniel Holbach (dholbach) wrote :

+1. Pinged Martin Albisetti to see if somebody on their team can give another review.

review: Approve
Ricardo Kirkner (ricardokirkner) wrote :

I didn't see anything obvious that would prevent from landing this branch, but I think it would be very beneficial to start spending some time improving the readability of this code base. I'd be happy to work on it provided Martin can approve of the time spent to do so.

449. By Jamie Strandboge on 2015-05-18

merge with trunk

450. By Jamie Strandboge on 2015-05-18

clickreviews/cr_security.py: implement feedback from MP review
- remove commented out code
- use more descriptive variable name

451. By Jamie Strandboge on 2015-05-18

update comment in check_security_caps()

452. By Jamie Strandboge on 2015-05-18

clickreviews/tests/test_cr_lint.py: update to include test on the error
string too

Jamie Strandboge (jdstrand) wrote :

Thanks for the reviews, I've updated the branch based on Ricardo's feedback.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'clickreviews/cr_framework.py'
2--- clickreviews/cr_framework.py 2015-04-03 20:51:02 +0000
3+++ clickreviews/cr_framework.py 2015-05-18 21:07:49 +0000
4@@ -66,12 +66,12 @@
5 def _extract_framework_policy(self):
6 '''Get framework policy files'''
7 policy_dict = dict()
8- unknown_dict = dict()
9+ unknown = []
10 fpdir = os.path.join(self.unpack_dir, "meta", "framework-policy")
11 for i in glob.glob("%s/*" % fpdir):
12 rel_i = os.path.basename(i)
13 if not os.path.isdir(i) or rel_i not in self.framework_policy_dirs:
14- unknown_dict.append(os.path.relpath(i, self.unpack_dir))
15+ unknown.append(os.path.relpath(i, self.unpack_dir))
16 continue
17
18 policy_dict[rel_i] = dict()
19@@ -79,21 +79,20 @@
20 rel_j = os.path.basename(j)
21 if not os.path.isdir(j) or \
22 rel_j not in self.framework_policy_subdirs:
23- unknown_dict.append(os.path.relpath(j, self.unpack_dir))
24+ unknown.append(os.path.relpath(j, self.unpack_dir))
25 continue
26
27 policy_dict[rel_i][rel_j] = dict()
28 for k in glob.glob("%s/*" % j):
29 rel_k = os.path.basename(k)
30 if not os.path.isfile(k):
31- unknown_dict.append(os.path.relpath(k,
32- self.unpack_dir))
33+ unknown.append(os.path.relpath(k, self.unpack_dir))
34 continue
35
36 fh = open_file_read(k)
37 policy_dict[rel_i][rel_j][rel_k] = fh.read()
38 fh.close()
39- return (policy_dict, unknown_dict)
40+ return (policy_dict, unknown)
41
42 def _has_framework_in_metadir(self):
43 '''Check if snap has meta/<name>.framework'''
44@@ -223,7 +222,7 @@
45 if j not in self.framework_policy[other] or \
46 k not in self.framework_policy[other][j]:
47 t = 'error'
48- s = "Could not find mathcing '%s/%s/%s'" % (other,
49+ s = "Could not find matching '%s/%s/%s'" % (other,
50 j, k)
51 self._add_result(t, n, s)
52
53
54=== modified file 'clickreviews/cr_lint.py'
55--- clickreviews/cr_lint.py 2015-05-01 15:18:50 +0000
56+++ clickreviews/cr_lint.py 2015-05-18 21:07:49 +0000
57@@ -1055,3 +1055,35 @@
58 t = 'warn'
59 s = "meta/readme.md is too short"
60 self._add_result(t, n, s)
61+
62+ def check_snappy_services_and_binaries(self):
63+ '''Services and binaries should not overlap'''
64+ if not self.is_snap:
65+ return
66+ for exe_t in ['binaries', 'services']:
67+ if exe_t not in self.pkg_yaml:
68+ break
69+ if exe_t == 'binaries':
70+ other_exe_t = 'services'
71+ else:
72+ other_exe_t = 'binaries'
73+
74+ if other_exe_t not in self.pkg_yaml:
75+ break
76+
77+ for a in self.pkg_yaml[exe_t]:
78+ if 'name' not in a:
79+ continue
80+ # handle 'exec' in binaries
81+ app = os.path.basename(a['name'])
82+
83+ t = 'info'
84+ n = 'snappy_%s_in_%s' % (app, other_exe_t)
85+ s = 'OK'
86+ for other_a in self.pkg_yaml[other_exe_t]:
87+ other_app = os.path.basename(other_a['name'])
88+ if app == other_app:
89+ t = 'error'
90+ s = "'%s' in both 'services' and 'binaries'" % app
91+ break
92+ self._add_result(t, n, s)
93
94=== modified file 'clickreviews/cr_security.py'
95--- clickreviews/cr_security.py 2015-05-04 18:29:04 +0000
96+++ clickreviews/cr_security.py 2015-05-18 21:07:49 +0000
97@@ -19,6 +19,7 @@
98 from clickreviews.cr_common import ClickReview, error, open_file_read
99 import clickreviews.cr_common as cr_common
100 import clickreviews.apparmor_policy as apparmor_policy
101+import copy
102 import json
103 import os
104
105@@ -68,8 +69,7 @@
106 'comment',
107 'copyright',
108 'name']
109- self.required_fields = ['policy_groups',
110- 'policy_version']
111+ self.required_fields = ['policy_version']
112 self.redflag_fields = ['abstractions',
113 'binary',
114 'read_path',
115@@ -147,6 +147,9 @@
116 self._extract_security_profile(app)
117 self.security_apps_profiles.append(app)
118
119+ # snappy
120+ self.sec_skipped_types = ['oem'] # these don't need security items
121+
122 def _override_framework_policies(self, overrides):
123 # override major framework policies
124 self.major_framework_policy.update(overrides)
125@@ -464,7 +467,27 @@
126 continue
127 self._add_result(t, n, s)
128
129- if m['template'] not in self._get_templates(vendor, version):
130+ found = False
131+ if m['template'] in self._get_templates(vendor, version):
132+ found = True
133+ elif self.is_snap:
134+ frameworks = []
135+ if 'framework' in self.pkg_yaml:
136+ frameworks = [x.strip() for x in
137+ self.pkg_yaml['framework'].split(',')]
138+ elif 'frameworks' in self.pkg_yaml:
139+ frameworks = self.pkg_yaml['frameworks']
140+ elif 'type' in self.pkg_yaml and \
141+ self.pkg_yaml['type'] == 'framework':
142+ # frameworks may reference their own policy groups
143+ frameworks.append(self.pkg_yaml['name'])
144+
145+ for f in frameworks:
146+ if m['template'].startswith("%s_" % f):
147+ found = True
148+ break
149+
150+ if not found:
151 t = 'error'
152 s = "specified unsupported template '%s'" % m['template']
153
154@@ -590,7 +613,7 @@
155 n = 'policy_groups_exists_%s (%s)' % (app, f)
156 if 'policy_groups' not in m:
157 # If template not specified, we just use the default
158- self._add_result('warn', n, 'no policy groups specified')
159+ self._add_result('info', n, 'no policy groups specified')
160 continue
161 elif 'policy_version' not in m:
162 self._add_result('error', n,
163@@ -625,6 +648,18 @@
164 s = 'duplicate policy groups found: %s' % ", ".join(tmp)
165 self._add_result(t, n, s)
166
167+ frameworks = []
168+ if self.is_snap:
169+ if 'framework' in self.pkg_yaml:
170+ frameworks = [x.strip() for x in
171+ self.pkg_yaml['framework'].split(',')]
172+ elif 'frameworks' in self.pkg_yaml:
173+ frameworks = self.pkg_yaml['frameworks']
174+ elif 'type' in self.pkg_yaml and \
175+ self.pkg_yaml['type'] == 'framework':
176+ # frameworks may reference their own policy groups
177+ frameworks.append(self.pkg_yaml['name'])
178+
179 # If we got here, we can see if valid policy groups were specified
180 for i in m['policy_groups']:
181 t = 'info'
182@@ -640,10 +675,20 @@
183 continue
184
185 found = False
186+ framework_found = False
187 for j in policy_groups:
188 if i == os.path.basename(j):
189 found = True
190 break
191+ else:
192+ for f in frameworks:
193+ if i.startswith("%s_" % f):
194+ framework_found = True
195+ break
196+ if framework_found:
197+ found = True
198+ break
199+
200 if not found:
201 t = 'error'
202 s = "unsupported policy_group '%s'" % i
203@@ -656,7 +701,11 @@
204 l = None
205 manual_review = False
206
207- aa_type = self._get_policy_group_type(vendor, version, i)
208+ if framework_found:
209+ aa_type = 'framework'
210+ else:
211+ aa_type = self._get_policy_group_type(vendor, version,
212+ i)
213 if i == "debug":
214 t = 'error'
215 s = "(REJECT) %s policy group " % aa_type + \
216@@ -668,9 +717,11 @@
217 if i == "debug":
218 l = 'http://askubuntu.com/a/562123/94326'
219 manual_review = True
220+ elif aa_type == 'framework':
221+ s = "OK (matches '%s' framework)" % i.split('_')[0]
222 elif aa_type != "common":
223 t = 'error'
224- s = "policy group '%s' has" % i + \
225+ s = "policy group '%s' has " % i + \
226 "unknown type '%s'" % (aa_type)
227 self._add_result(t, n, s, l, manual_review=manual_review)
228
229@@ -720,7 +771,7 @@
230 (f, m) = self._get_security_manifest(app)
231
232 t = 'info'
233- n = 'ignored_fields (%s)' % f
234+ n = 'required_fields (%s)' % f
235 s = "OK"
236 not_found = []
237 for i in self.required_fields:
238@@ -751,3 +802,409 @@
239 "could not find '%s' in profile" % v)
240 continue
241 self._add_result(t, n, s)
242+
243+ # This will be really nice to get rid of when the click compat manifest
244+ # is gone
245+ def _compare_security_yamls(self, yaml, click_m):
246+ '''Compare two security yamls'''
247+ def find_match(name, key, value, my_dict):
248+ if 'name' in my_dict and my_dict['name'] == name and \
249+ key in my_dict and my_dict[key] == value:
250+ return True
251+ return False
252+
253+ for first in [yaml, click_m]:
254+ if first == yaml:
255+ second = click_m
256+ second_m = "click-manifest"
257+ first_m = "package.yaml"
258+ else:
259+ second = yaml
260+ first_m = "click-manifest"
261+ second_m = "package.yaml"
262+ for exe_t in ['binaries', 'services']:
263+ t = 'info'
264+ n = 'yaml_%s' % exe_t
265+ s = 'OK'
266+ if exe_t in first and exe_t not in second:
267+ t = 'error'
268+ s = "%s missing '%s'" % (second_m, exe_t)
269+ elif exe_t not in first and exe_t in second:
270+ t = 'error'
271+ s = "%s has extra '%s'" % (second_m, exe_t)
272+ self._add_result(t, n, s)
273+
274+ if t == 'error':
275+ continue
276+ elif exe_t not in first and exe_t not in second:
277+ continue
278+
279+ t = 'info'
280+ n = 'yaml_%s_entries' % exe_t
281+ s = 'OK'
282+ if len(first[exe_t]) < len(second[exe_t]):
283+ t = 'error'
284+ s = "%s has extra '%s' entries" % (second_m, exe_t)
285+ self._add_result(t, n, s)
286+
287+ for fapp in first[exe_t]:
288+ t = 'info'
289+ n = 'yaml_%s_%s' % (exe_t, fapp['name'])
290+ s = 'OK'
291+ sapp = None
292+ for tmp in second[exe_t]:
293+ if tmp['name'] == fapp['name']:
294+ sapp = tmp
295+ if sapp is None:
296+ t = 'error'
297+ s = "%s missing '%s'" % (second_m, fapp['name'])
298+ self._add_result(t, n, s)
299+ continue
300+ elif first == yaml and "security-override" in fapp or \
301+ second == yaml and "security-override" in sapp:
302+ # no reason to check security-override since apparmor
303+ # hook entry will point to this file
304+ continue
305+ elif first == yaml and "security-policy" in fapp or \
306+ second == yaml and "security-policy" in sapp:
307+ # no reason to check security-policy since apparmor
308+ # profile hook is used instead
309+ continue
310+ elif 'caps' not in fapp and 'caps' not in sapp and \
311+ second == yaml and 'security-template' not in sapp:
312+ # no caps in yaml, policy_groups is empty in click
313+ # manifest, unless security-template is in yaml
314+ t = 'error'
315+ s = "'policy_groups' not found in click manifest " + \
316+ "(should default to ['networking'])"
317+ self._add_result(t, n, s)
318+ continue
319+ self._add_result(t, n, s)
320+
321+ for key in ['security-template', 'caps']:
322+ t = 'info'
323+ n = 'yaml_%s_%s' % (exe_t, second_m)
324+ s = 'OK'
325+
326+ if key not in fapp:
327+ continue
328+
329+ if key == 'caps':
330+ fapp['caps'] = set(fapp['caps'])
331+ if 'caps' in sapp:
332+ sapp['caps'] = set(sapp['caps'])
333+
334+ if not find_match(fapp['name'], key, fapp[key], sapp):
335+ # handle snappy defaults for security-template
336+ # and caps
337+ if key == 'security-template' and \
338+ second == yaml and key not in sapp and \
339+ key in fapp and fapp[key] == 'default':
340+ # if yaml missing security-template, click may
341+ # specify 'default'
342+ self._add_result(t, n, s)
343+ continue
344+ elif key == 'caps' and second == yaml and \
345+ 'security-template' in sapp and \
346+ key not in sapp and \
347+ (key not in fapp or key in fapp and
348+ fapp[key] == set([])):
349+ # when security-template is specified, then
350+ # caps won't default to 'networking' when
351+ # missing, so click manifest can omit or be []
352+ self._add_result(t, n, s)
353+ continue
354+ elif key == 'caps' and second == yaml and \
355+ 'security-template' not in sapp and \
356+ key not in sapp and key in fapp and \
357+ fapp[key] == set(['networking']):
358+ # no caps in yaml, policy_groups is networking
359+ # in click manifest wen security-template not
360+ # specified in yaml
361+ self._add_result(t, n, s)
362+ continue
363+ elif key == 'caps' and second == click_m and \
364+ key not in sapp and key in fapp and \
365+ fapp[key] == set([]):
366+ # no caps in click manifest, caps is [] in yaml
367+ self._add_result(t, n, s)
368+ continue
369+ t = 'error'
370+ s = "%s has different '%s' for '%s'" % \
371+ (second_m, key, fapp['name']) + \
372+ " - '%s:%s' vs '%s:%s'" % (first_m, fapp,
373+ second_m, sapp)
374+ self._add_result(t, n, s)
375+
376+ def _convert_click_security_to_yaml(self):
377+ '''Convert click manifest to yaml'''
378+ converted = dict()
379+ for app in sorted(self.security_apps):
380+ if 'snappy-systemd' in self.manifest['hooks'][app]:
381+ key = 'services'
382+ elif 'bin-path' in self.manifest['hooks'][app]:
383+ key = 'binaries'
384+ else:
385+ t = 'error'
386+ n = 'yaml_click_%s' % app
387+ s = "click manifest missing 'snappy-systemd/bin-path' for " + \
388+ "'%s'" % app
389+ self._add_result(t, n, s)
390+ continue
391+
392+ if key not in converted:
393+ converted[key] = []
394+ tmp = dict()
395+ tmp['name'] = app
396+
397+ (f, m) = self._get_security_manifest(app)
398+ if 'template' in m:
399+ tmp['security-template'] = m['template']
400+
401+ if 'policy_groups' in m:
402+ tmp['caps'] = m['policy_groups']
403+
404+ converted[key].append(copy.deepcopy(tmp))
405+
406+ for app in sorted(self.security_apps_profiles):
407+ if 'snappy-systemd' in self.manifest['hooks'][app]:
408+ key = 'services'
409+ elif 'bin-path' in self.manifest['hooks'][app]:
410+ key = 'binaries'
411+ else:
412+ t = 'error'
413+ n = 'yaml_click_%s' % app
414+ s = "click manifest missing 'snappy-systemd/bin-path' for " + \
415+ "'%s'" % app
416+ self._add_result(t, n, s)
417+ continue
418+
419+ if key not in converted:
420+ converted[key] = []
421+ tmp = dict()
422+ tmp['name'] = app
423+
424+ (f, p) = self._get_security_profile(app)
425+ tmp['security-policy'] = {'apparmor': f}
426+
427+ converted[key].append(copy.deepcopy(tmp))
428+
429+ return copy.deepcopy(converted)
430+
431+ def check_security_yaml_and_click(self):
432+ '''Verify click and security yaml are in sync (not including
433+ override)
434+ '''
435+ if not self.is_snap or self.pkg_yaml['type'] in self.sec_skipped_types:
436+ return
437+
438+ # setup a small dict that is a subset of self.pkg_yaml
439+ yml = dict()
440+ for exe_t in ['binaries', 'services']:
441+ if exe_t not in self.pkg_yaml:
442+ continue
443+ yml[exe_t] = copy.deepcopy(self.pkg_yaml[exe_t])
444+ for item in yml[exe_t]:
445+ # account for binaries doing different things with 'name/exec'
446+ if exe_t == 'binaries' and 'exec' not in item and \
447+ '/' in item['name']:
448+ item['name'] = os.path.basename(item['name'])
449+
450+ converted = self._convert_click_security_to_yaml()
451+ self._compare_security_yamls(yml, converted)
452+
453+ def check_security_yaml_override_and_click(self):
454+ '''Verify click and security yaml override are in sync'''
455+ if not self.is_snap or self.pkg_yaml['type'] in self.sec_skipped_types:
456+ return
457+
458+ for exe_t in ['services', 'binaries']:
459+ if exe_t not in self.pkg_yaml:
460+ continue
461+
462+ for item in self.pkg_yaml[exe_t]:
463+ if 'name' not in item:
464+ t = 'error'
465+ n = 'yaml_override_click_name'
466+ s = "package.yaml malformed. Could not find 'name' " + \
467+ "for entry in '%s'" % item
468+ self._add_result(t, n, s)
469+ continue
470+
471+ app = item['name']
472+ t = 'info'
473+ n = 'yaml_override_click_%s' % app
474+ s = "OK"
475+ if 'security-override' not in item:
476+ s = "OK (skipping unspecified override)"
477+ elif 'apparmor' not in item['security-override']:
478+ t = 'error'
479+ s = "'apparmor' not specified in 'security-override' " + \
480+ "for '%s'" % app
481+ elif item['security-override']['apparmor'] not in \
482+ self.security_manifests:
483+ t = 'error'
484+ s = "'%s' not found in click manifest for '%s'" % \
485+ (item['security-override']['apparmor'], app)
486+ # NOTE: we skip 'seccomp' because there isn't currently a
487+ # click hook for it
488+ self._add_result(t, n, s)
489+
490+ def check_security_yaml_override(self):
491+ '''Verify security yaml override'''
492+ for exe_t in ['services', 'binaries']:
493+ if exe_t not in self.pkg_yaml:
494+ continue
495+
496+ for item in self.pkg_yaml[exe_t]:
497+ if 'name' not in item:
498+ t = 'error'
499+ n = 'yaml_override_name'
500+ s = "package.yaml malformed. Could not find 'name' " + \
501+ "for entry in '%s'" % item
502+ self._add_result(t, n, s)
503+ continue
504+
505+ app = item['name']
506+ t = 'info'
507+ n = 'yaml_override_format_%s' % app
508+ s = "OK"
509+ if 'security-override' not in item:
510+ s = "OK (skipping unspecified override)"
511+ elif 'apparmor' not in item['security-override']:
512+ t = 'error'
513+ s = "'apparmor' not specified in 'security-override' " + \
514+ "for '%s'" % app
515+ elif 'seccomp' not in item['security-override']:
516+ t = 'error'
517+ s = "'seccomp' not specified in 'security-override' " + \
518+ "for '%s'" % app
519+ self._add_result(t, n, s)
520+
521+ def check_security_yaml_policy(self):
522+ '''Verify security yaml policy'''
523+ for exe_t in ['services', 'binaries']:
524+ if exe_t not in self.pkg_yaml:
525+ continue
526+
527+ for item in self.pkg_yaml[exe_t]:
528+ if 'name' not in item:
529+ t = 'error'
530+ n = 'yaml_policy_name'
531+ s = "package.yaml malformed. Could not find 'name' " + \
532+ "for entry in '%s'" % item
533+ self._add_result(t, n, s)
534+ continue
535+
536+ app = item['name']
537+ t = 'info'
538+ n = 'yaml_policy_format_%s' % app
539+ s = "OK"
540+ if 'security-policy' not in item:
541+ s = "OK (skipping unspecified policy)"
542+ elif 'apparmor' not in item['security-policy']:
543+ t = 'error'
544+ s = "'apparmor' not specified in 'security-policy' " + \
545+ "for '%s'" % app
546+ elif 'seccomp' not in item['security-policy']:
547+ t = 'error'
548+ s = "'seccomp' not specified in 'security-policy' for " + \
549+ "'%s'" % app
550+ self._add_result(t, n, s)
551+
552+ # TODO: error if specified
553+
554+ def check_security_yaml_combinations(self):
555+ '''Verify security yaml uses valid combinations'''
556+ if not self.is_snap or self.pkg_yaml['type'] in self.sec_skipped_types:
557+ return
558+
559+ for exe_t in ['services', 'binaries']:
560+ if exe_t not in self.pkg_yaml:
561+ continue
562+ for item in self.pkg_yaml[exe_t]:
563+ if 'name' not in item:
564+ t = 'error'
565+ n = 'yaml_combinations_name'
566+ s = "package.yaml malformed. Could not find 'name' " + \
567+ "for entry in '%s'" % item
568+ self._add_result(t, n, s)
569+ continue
570+
571+ app = item['name']
572+
573+ t = 'info'
574+ n = 'yaml_combinations_%s' % app
575+ s = "OK"
576+ if "security-policy" in item:
577+ for i in ['security-override', 'security-template',
578+ 'caps']:
579+ if i in item:
580+ t = 'error'
581+ s = "Found '%s' with 'security-policy'" % (i)
582+ break
583+ elif "security-override" in item:
584+ for i in ['security-policy', 'security-template', 'caps']:
585+ if i in item:
586+ t = 'error'
587+ s = "Found '%s' with 'security-override'" % (i)
588+ break
589+ self._add_result(t, n, s)
590+
591+ def check_security_template(self):
592+ '''Check snap security-template'''
593+ if not self.is_snap or self.pkg_yaml['type'] in self.sec_skipped_types:
594+ return
595+
596+ for exe_t in ['services', 'binaries']:
597+ if exe_t not in self.pkg_yaml:
598+ continue
599+ for item in self.pkg_yaml[exe_t]:
600+ if 'security-template' not in item:
601+ tmpl = ""
602+ else:
603+ tmpl = item['security-template']
604+
605+ if 'name' not in item:
606+ t = 'error'
607+ n = 'yaml_security-template_name'
608+ s = "package.yaml malformed. Could not find 'name' " + \
609+ "for entry in '%s'" % item
610+ self._add_result(t, n, s)
611+ continue
612+
613+ # Handle bin/exec concept with bianries
614+ app = os.path.basename(item['name'])
615+
616+ t = 'info'
617+ n = 'yaml_security-template_%s' % app
618+ s = "OK"
619+ if not isinstance(tmpl, str):
620+ t = 'error'
621+ s = "'%s/%s' malformed: '%s' is not str" % (exe_t, app,
622+ tmpl)
623+ self._add_result(t, n, s)
624+ continue
625+ self._add_result(t, n, s)
626+
627+ t = 'info'
628+ n = 'yaml_security-template_in_manifest_%s' % app
629+ s = "OK"
630+ if app not in self.manifest['hooks']:
631+ t = 'error'
632+ s = "'%s' not found in click manifest" % app
633+ self._add_result(t, n, s)
634+ continue
635+ elif 'apparmor' not in self.manifest['hooks'][app] and \
636+ 'apparmor-profile' not in self.manifest['hooks'][app]:
637+ t = 'error'
638+ s = "'apparmor' not found in click manifest for '%s'" % app
639+ self._add_result(t, n, s)
640+ continue
641+
642+ # TODO: error if not 'common' or is 'unconfined'
643+
644+ def check_security_caps(self):
645+ '''Check snap caps'''
646+ # TODO - check caps on their own instead of just via compat click
647+ # manifest
648
649=== modified file 'clickreviews/cr_tests.py'
650--- clickreviews/cr_tests.py 2015-04-03 22:17:04 +0000
651+++ clickreviews/cr_tests.py 2015-05-18 21:07:49 +0000
652@@ -745,12 +745,57 @@
653 self._update_test_readme_md()
654
655 def set_test_security_manifest(self, app, key, value):
656- '''Set key in security manifest to value. If value is None, remove
657- key'''
658+ '''Set key in security manifest and package.yaml to value. If value is
659+ None, remove key, if key is None, remove app.
660+ '''
661+ # package.yaml - we don't know if it is a service or a binary with
662+ # these values, so just use 'binaries'
663+ if key is None:
664+ if 'binaries' in self.test_pkg_yaml:
665+ for b in self.test_pkg_yaml['binaries']:
666+ if 'name' in b and b['name'] == app:
667+ self.test_pkg_yaml['binaries'].remove(b)
668+ break
669+ elif value is None:
670+ if 'binaries' in self.test_pkg_yaml:
671+ found = False
672+ for b in self.test_pkg_yaml['binaries']:
673+ if 'name' in b and b['name'] == app:
674+ if key in b:
675+ b.remove(key)
676+ found = True
677+ break
678+ else:
679+ found = False
680+ k = key
681+ if key == 'template':
682+ k = 'security-template'
683+ elif key == 'policy_groups':
684+ k = 'caps'
685+ if 'binaries' in self.test_pkg_yaml:
686+ for b in self.test_pkg_yaml['binaries']:
687+ if 'name' in b and b['name'] == app:
688+ # Found the entry, so update key/value
689+ b[k] = value
690+ found = True
691+ break
692+ # Did not find the entry, so create one
693+ if not found:
694+ if 'binaries' not in self.test_pkg_yaml:
695+ self.test_pkg_yaml['binaries'] = []
696+ self.test_pkg_yaml['binaries'].append({'name': app,
697+ k: value})
698+ self._update_test_pkg_yaml()
699+
700+ # click manifest
701 if app not in self.test_security_manifests:
702 self.test_security_manifests[app] = dict()
703
704- if value is None:
705+ if key is None:
706+ if app in self.test_security_manifests:
707+ del self.test_security_manifests[app]
708+ del self.test_manifest["hooks"][app]
709+ elif value is None:
710 if key in self.test_security_manifests[app]:
711 self.test_security_manifests[app].pop(key, None)
712 else:
713@@ -973,8 +1018,8 @@
714 self._update_test_framework_policy_unknown()
715
716 def set_test_systemd(self, app, key, value):
717- '''Set systemd entries. If key is None, snappy-systemd from manifest
718- and yaml.
719+ '''Set systemd entries. If key is None, remove snappy-systemd from
720+ manifest and yaml.
721
722 Note the click manifest and the package.yaml use different
723 storage types. pkg_yaml['services'] is a list of dictionaries where
724
725=== modified file 'clickreviews/tests/test_cr_lint.py'
726--- clickreviews/tests/test_cr_lint.py 2015-05-01 15:18:50 +0000
727+++ clickreviews/tests/test_cr_lint.py 2015-05-18 21:07:49 +0000
728@@ -1357,3 +1357,80 @@
729 r = c.click_report
730 expected_counts = {'info': None, 'warn': 0, 'error': 1}
731 self.check_results(r, expected_counts)
732+
733+ def test_check_snappy_services_and_binaries1(self):
734+ '''Test check_snappy_services_and_binaries() - different'''
735+ self.set_test_pkg_yaml("name", self.test_name.split('_')[0])
736+ self.set_test_pkg_yaml("services", [{"name": "foo",
737+ "start": "bin/foo"}])
738+ self.set_test_pkg_yaml("binaries", [{"name": "bar"}])
739+ c = ClickReviewLint(self.test_name)
740+ c.check_snappy_services_and_binaries()
741+ r = c.click_report
742+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
743+ self.check_results(r, expected_counts)
744+
745+ def test_check_snappy_services_and_binaries2(self):
746+ '''Test check_snappy_services_and_binaries() - different (exec)'''
747+ self.set_test_pkg_yaml("name", self.test_name.split('_')[0])
748+ self.set_test_pkg_yaml("services", [{"name": "foo",
749+ "start": "bin/foo"}])
750+ self.set_test_pkg_yaml("binaries", [{"name": "bar",
751+ "exec": "bin/foo"}])
752+ c = ClickReviewLint(self.test_name)
753+ c.check_snappy_services_and_binaries()
754+ r = c.click_report
755+ expected_counts = {'info': 2, 'warn': 0, 'error': 0}
756+ self.check_results(r, expected_counts)
757+
758+ def test_check_snappy_services_and_binaries3(self):
759+ '''Test check_snappy_services_and_binaries() - same'''
760+ self.set_test_pkg_yaml("name", self.test_name.split('_')[0])
761+ self.set_test_pkg_yaml("services", [{"name": "foo",
762+ "start": "bin/foo"}])
763+ self.set_test_pkg_yaml("binaries", [{"name": "foo"}])
764+ c = ClickReviewLint(self.test_name)
765+ c.check_snappy_services_and_binaries()
766+ r = c.click_report
767+ expected_counts = {'info': 0, 'warn': 0, 'error': 2}
768+ self.check_results(r, expected_counts)
769+
770+ m = r['error']['lint_snappy_foo_in_services']['text']
771+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
772+ m = r['error']['lint_snappy_foo_in_binaries']['text']
773+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
774+
775+ def test_check_snappy_services_and_binaries4(self):
776+ '''Test check_snappy_services_and_binaries() - same (subdir)'''
777+ self.set_test_pkg_yaml("name", self.test_name.split('_')[0])
778+ self.set_test_pkg_yaml("services", [{"name": "foo",
779+ "start": "bin/foo"}])
780+ self.set_test_pkg_yaml("binaries", [{"name": "bin/foo"}])
781+ c = ClickReviewLint(self.test_name)
782+ c.check_snappy_services_and_binaries()
783+ r = c.click_report
784+ expected_counts = {'info': 0, 'warn': 0, 'error': 2}
785+ self.check_results(r, expected_counts)
786+
787+ m = r['error']['lint_snappy_foo_in_services']['text']
788+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
789+ m = r['error']['lint_snappy_foo_in_binaries']['text']
790+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
791+
792+ def test_check_snappy_services_and_binaries5(self):
793+ '''Test check_snappy_services_and_binaries() - same (exec, subdir)'''
794+ self.set_test_pkg_yaml("name", self.test_name.split('_')[0])
795+ self.set_test_pkg_yaml("services", [{"name": "foo",
796+ "start": "bin/foo"}])
797+ self.set_test_pkg_yaml("binaries", [{"name": "foo",
798+ "exec": "bin/foo"}])
799+ c = ClickReviewLint(self.test_name)
800+ c.check_snappy_services_and_binaries()
801+ r = c.click_report
802+ expected_counts = {'info': 0, 'warn': 0, 'error': 2}
803+ self.check_results(r, expected_counts)
804+
805+ m = r['error']['lint_snappy_foo_in_services']['text']
806+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
807+ m = r['error']['lint_snappy_foo_in_binaries']['text']
808+ self.assertIn("'foo' in both 'services' and 'binaries'", m)
809
810=== modified file 'clickreviews/tests/test_cr_security.py'
811--- clickreviews/tests/test_cr_security.py 2015-05-01 15:03:57 +0000
812+++ clickreviews/tests/test_cr_security.py 2015-05-18 21:07:49 +0000
813@@ -32,6 +32,16 @@
814 self.default_security_json = "%s.apparmor" % \
815 self.default_appname
816
817+ def _set_yaml_binary(self, entries, name=None):
818+ d = dict()
819+ if name is None:
820+ d['name'] = self.default_appname
821+ else:
822+ d['name'] = name
823+ for (key, value) in entries:
824+ d[key] = value
825+ self.set_test_pkg_yaml("binaries", [d])
826+
827 def test_check_policy_version_vendor(self):
828 '''Test check_policy_version() - valid'''
829 for v in [1.0]: # update when have more vendor policy
830@@ -482,6 +492,52 @@
831 expected_counts = {'info': None, 'warn': 0, 'error': 1}
832 self.check_results(report, expected_counts)
833
834+ def test_check_template_snappy_framework_deprecated(self):
835+ '''Test check_template() - in deprecated framework declaration'''
836+ self.set_test_pkg_yaml("framework", "fwk")
837+ c = ClickReviewSecurity(self.test_name)
838+ self.set_test_security_manifest(self.default_appname,
839+ "template", "fwk_foo")
840+ c.check_template()
841+ report = c.click_report
842+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
843+ self.check_results(report, expected_counts)
844+
845+ def test_check_template_snappy_framework_deprecated2(self):
846+ '''Test check_template() - in deprecated framework declaration list'''
847+ self.set_test_pkg_yaml("framework", "fwk, somethingelse")
848+ c = ClickReviewSecurity(self.test_name)
849+ self.set_test_security_manifest(self.default_appname,
850+ "template", "fwk_foo")
851+ c.check_template()
852+ report = c.click_report
853+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
854+ self.check_results(report, expected_counts)
855+
856+ def test_check_template_snappy_frameworks(self):
857+ '''Test check_template() - in frameworks declaration'''
858+ self.set_test_pkg_yaml("frameworks", ["fwk"])
859+ c = ClickReviewSecurity(self.test_name)
860+ self.set_test_security_manifest(self.default_appname,
861+ "template", "fwk_foo")
862+ c.check_template()
863+ report = c.click_report
864+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
865+ self.check_results(report, expected_counts)
866+
867+ def test_check_template_snappy_framework_type(self):
868+ '''Test check_template() - type framework'''
869+ self.set_test_pkg_yaml("type", "framework")
870+ c = ClickReviewSecurity(self.test_name)
871+ self.set_test_security_manifest(self.default_appname,
872+ "template",
873+ "%s_foo" %
874+ self.test_name.split('_')[0])
875+ c.check_template()
876+ report = c.click_report
877+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
878+ self.check_results(report, expected_counts)
879+
880 def test_check_template_webapp(self):
881 '''Test check_template() - webapp'''
882 c = ClickReviewSecurity(self.test_name)
883@@ -762,7 +818,7 @@
884 c = ClickReviewSecurity(self.test_name)
885 c.check_policy_groups()
886 report = c.click_report
887- expected_counts = {'info': 0, 'warn': 1, 'error': 0}
888+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
889 self.check_results(report, expected_counts)
890
891 def test_check_policy_groups_bad_policy_version(self):
892@@ -833,6 +889,54 @@
893 expected_counts = {'info': None, 'warn': 0, 'error': 1}
894 self.check_results(report, expected_counts)
895
896+ def test_check_policy_groups_snappy_framework_deprecated(self):
897+ '''Test check_policy_groups() - in deprecated framework declaration'''
898+ self.set_test_pkg_yaml("framework", "fwk")
899+ c = ClickReviewSecurity(self.test_name)
900+ self.set_test_security_manifest(self.default_appname,
901+ "policy_groups", ["fwk_foo"])
902+ c.check_policy_groups()
903+ report = c.click_report
904+ expected_counts = {'info': 4, 'warn': 0, 'error': 0}
905+ self.check_results(report, expected_counts)
906+
907+ def test_check_policy_groups_snappy_framework_deprecated2(self):
908+ '''Test check_policy_groups() - in deprecated framework declaration
909+ list
910+ '''
911+ self.set_test_pkg_yaml("framework", "fwk, somethingelse")
912+ c = ClickReviewSecurity(self.test_name)
913+ self.set_test_security_manifest(self.default_appname,
914+ "policy_groups", ["fwk_foo"])
915+ c.check_policy_groups()
916+ report = c.click_report
917+ expected_counts = {'info': 4, 'warn': 0, 'error': 0}
918+ self.check_results(report, expected_counts)
919+
920+ def test_check_policy_groups_snappy_frameworks(self):
921+ '''Test check_policy_groups() - in frameworks declaration'''
922+ self.set_test_pkg_yaml("frameworks", ["fwk"])
923+ c = ClickReviewSecurity(self.test_name)
924+ self.set_test_security_manifest(self.default_appname,
925+ "policy_groups", ["fwk_foo"])
926+ c.check_policy_groups()
927+ report = c.click_report
928+ expected_counts = {'info': 4, 'warn': 0, 'error': 0}
929+ self.check_results(report, expected_counts)
930+
931+ def test_check_policy_groups_snappy_framework_type(self):
932+ '''Test check_policy_groups() - type framework'''
933+ self.set_test_pkg_yaml("type", "framework")
934+ c = ClickReviewSecurity(self.test_name)
935+ self.set_test_security_manifest(self.default_appname,
936+ "policy_groups",
937+ ["%s_foo" %
938+ self.test_name.split('_')[0]])
939+ c.check_policy_groups()
940+ report = c.click_report
941+ expected_counts = {'info': 4, 'warn': 0, 'error': 0}
942+ self.check_results(report, expected_counts)
943+
944 def test_check_policy_groups_pushhelper_no_hook(self):
945 '''Test check_policy_groups_pushhelper() - no hook'''
946 c = ClickReviewSecurity(self.test_name)
947@@ -1154,3 +1258,573 @@
948 report = c.click_report
949 expected_counts = {'info': None, 'warn': 1, 'error': 0}
950 self.check_results(report, expected_counts)
951+
952+ def test_check_security_template_default(self):
953+ '''Test check_security_template() - default'''
954+ self.set_test_security_manifest(self.default_appname, "template", None)
955+ self._set_yaml_binary([])
956+ c = ClickReviewSecurity(self.test_name)
957+ c.check_security_template()
958+ report = c.click_report
959+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
960+ self.check_results(report, expected_counts)
961+
962+ def test_check_security_template_default_with_exec(self):
963+ '''Test check_security_template() - default with exec'''
964+ self.set_test_security_manifest(self.default_appname, "template", None)
965+ self._set_yaml_binary([('exec', 'bin/%s' % self.default_appname)])
966+ c = ClickReviewSecurity(self.test_name)
967+ c.check_security_template()
968+ report = c.click_report
969+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
970+ self.check_results(report, expected_counts)
971+
972+ def test_check_security_template_nondefault(self):
973+ '''Test check_security_template() - nondefault'''
974+ self.set_test_security_manifest(self.default_appname,
975+ "template", "nondefault")
976+ self._set_yaml_binary([('security-template', 'nondefault')])
977+ c = ClickReviewSecurity(self.test_name)
978+ c.check_security_template()
979+ report = c.click_report
980+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
981+ self.check_results(report, expected_counts)
982+
983+ def test_check_security_template_bad(self):
984+ '''Test check_security_template() - {}'''
985+ self._set_yaml_binary([('security-template', {})])
986+ c = ClickReviewSecurity(self.test_name)
987+ c.check_security_template()
988+ report = c.click_report
989+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
990+ self.check_results(report, expected_counts)
991+
992+ def test_check_security_yaml_and_click_name_relative(self):
993+ '''Test check_security_yaml_and_click() - relative path'''
994+ self._set_yaml_binary([('caps', ['networking'])],
995+ name="bin/%s" % self.default_appname)
996+ c = ClickReviewSecurity(self.test_name)
997+
998+ # update the manifest and test_manifest
999+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1000+
1001+ c.check_security_yaml_and_click()
1002+ report = c.click_report
1003+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
1004+ self.check_results(report, expected_counts)
1005+
1006+ def test_check_security_yaml_and_click_name_exec(self):
1007+ '''Test check_security_yaml_and_click() - uses exec'''
1008+ self._set_yaml_binary([('caps', ['networking']),
1009+ ('exec', "bin/%s" % self.default_appname)],
1010+ name=self.default_appname)
1011+ c = ClickReviewSecurity(self.test_name)
1012+
1013+ # update the manifest and test_manifest
1014+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1015+
1016+ c.check_security_yaml_and_click()
1017+ report = c.click_report
1018+ expected_counts = {'info': 6, 'warn': 0, 'error': 0}
1019+ self.check_results(report, expected_counts)
1020+
1021+ def test_check_security_yaml_and_click_matching_template(self):
1022+ '''Test check_security_yaml_and_click() - matching default template'''
1023+ self._set_yaml_binary([('caps', ['networking'])])
1024+ self.set_test_security_manifest(self.default_appname,
1025+ "template", "default")
1026+ c = ClickReviewSecurity(self.test_name)
1027+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1028+ del c.pkg_yaml['binaries'][0]['security-template']
1029+ c.check_security_yaml_and_click()
1030+ report = c.click_report
1031+ expected_counts = {'info': 6, 'warn': 0, 'error': 0}
1032+ self.check_results(report, expected_counts)
1033+
1034+ def test_check_security_yaml_and_click_security_override(self):
1035+ '''Test check_security_yaml_and_click() - security-override'''
1036+ self._set_yaml_binary([('security-template', 'default')])
1037+ self._set_yaml_binary([('security-override', {})])
1038+ self.set_test_security_manifest(self.default_appname,
1039+ "template", "default")
1040+ c = ClickReviewSecurity(self.test_name)
1041+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1042+ c.check_security_yaml_and_click()
1043+ report = c.click_report
1044+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
1045+ self.check_results(report, expected_counts)
1046+
1047+ def test_check_security_yaml_and_click_security_policy(self):
1048+ '''Test check_security_yaml_and_click() - security-policy'''
1049+ self._set_yaml_binary([('security-template', 'default')])
1050+ self._set_yaml_binary([('security-policy', {})])
1051+ self.set_test_security_manifest(self.default_appname,
1052+ "template", "default")
1053+ c = ClickReviewSecurity(self.test_name)
1054+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1055+ c.check_security_yaml_and_click()
1056+ report = c.click_report
1057+ expected_counts = {'info': 3, 'warn': 0, 'error': 0}
1058+ self.check_results(report, expected_counts)
1059+
1060+ def test_check_security_yaml_and_click_matching_caps(self):
1061+ '''Test check_security_yaml_and_click() - matching default caps'''
1062+ self._set_yaml_binary([('caps', [])])
1063+ self.set_test_security_manifest(self.default_appname,
1064+ "policy_groups", ['networking'])
1065+ c = ClickReviewSecurity(self.test_name)
1066+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1067+ del c.pkg_yaml['binaries'][0]['caps']
1068+ c.check_security_yaml_and_click()
1069+ report = c.click_report
1070+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
1071+ self.check_results(report, expected_counts)
1072+
1073+ def test_check_security_yaml_and_click_matching_no_caps(self):
1074+ '''Test check_security_yaml_and_click() - matching no caps'''
1075+ self._set_yaml_binary([('caps', [])])
1076+ self.set_test_security_manifest(self.default_appname,
1077+ "policy_groups", None)
1078+ c = ClickReviewSecurity(self.test_name)
1079+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1080+ c.check_security_yaml_and_click()
1081+ report = c.click_report
1082+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
1083+ self.check_results(report, expected_counts)
1084+
1085+ def test_check_security_yaml_and_click_matching_no_caps_template(self):
1086+ '''Test check_security_yaml_and_click() - matching no caps with
1087+ template
1088+ '''
1089+ self._set_yaml_binary([('security-template', 'nondefault')])
1090+ self.set_test_security_manifest(self.default_appname,
1091+ "policy_groups", None)
1092+ self.set_test_security_manifest(self.default_appname,
1093+ "template", "nondefault")
1094+ c = ClickReviewSecurity(self.test_name)
1095+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1096+ c.check_security_yaml_and_click()
1097+ report = c.click_report
1098+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
1099+ self.check_results(report, expected_counts)
1100+
1101+ def test_check_security_yaml_and_click_mismatch0(self):
1102+ '''Test check_security_yaml_and_click() - missing app in hooks'''
1103+ self._set_yaml_binary([])
1104+ self.set_test_security_manifest(self.default_appname,
1105+ "template", None)
1106+ c = ClickReviewSecurity(self.test_name)
1107+
1108+ del c.manifest["hooks"][self.default_appname]
1109+ self._update_test_manifest()
1110+ c.security_apps.remove(self.default_appname)
1111+
1112+ c.check_security_yaml_and_click()
1113+ report = c.click_report
1114+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1115+ self.check_results(report, expected_counts)
1116+
1117+ def test_check_security_yaml_and_click_mismatch1(self):
1118+ '''Test check_security_yaml_and_click() - missing bin-path in hooks'''
1119+ self._set_yaml_binary([])
1120+ c = ClickReviewSecurity(self.test_name)
1121+
1122+ c.check_security_yaml_and_click()
1123+ report = c.click_report
1124+ expected_counts = {'info': None, 'warn': 0, 'error': 2}
1125+ self.check_results(report, expected_counts)
1126+
1127+ def test_check_security_yaml_and_click_mismatch2(self):
1128+ '''Test check_security_yaml_and_click() - missing apparmor in hooks'''
1129+ self._set_yaml_binary([])
1130+ c = ClickReviewSecurity(self.test_name)
1131+
1132+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1133+ del c.manifest["hooks"][self.default_appname]['apparmor']
1134+ c.security_apps.remove(self.default_appname)
1135+ self._update_test_manifest()
1136+
1137+ c.check_security_yaml_and_click()
1138+ report = c.click_report
1139+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1140+ self.check_results(report, expected_counts)
1141+
1142+ def test_check_security_yaml_and_click_mismatch3(self):
1143+ '''Test check_security_yaml_and_click() - missing security-template'''
1144+ self._set_yaml_binary([('caps', ['networking'])])
1145+ self.set_test_security_manifest(self.default_appname,
1146+ "template", "nondefault")
1147+ c = ClickReviewSecurity(self.test_name)
1148+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1149+ del c.pkg_yaml['binaries'][0]['security-template']
1150+ c.check_security_yaml_and_click()
1151+ report = c.click_report
1152+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1153+ self.check_results(report, expected_counts)
1154+
1155+ def test_check_security_yaml_and_click_mismatch4(self):
1156+ '''Test check_security_yaml_and_click() - missing click template'''
1157+ self._set_yaml_binary([("security-template", "nondefault"),
1158+ ('caps', ['networking'])],
1159+ name=self.default_appname)
1160+ self.set_test_security_manifest(self.default_appname,
1161+ "template", None)
1162+ c = ClickReviewSecurity(self.test_name)
1163+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1164+ c.check_security_yaml_and_click()
1165+ report = c.click_report
1166+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1167+ self.check_results(report, expected_counts)
1168+
1169+ def test_check_security_yaml_and_click_mismatch5(self):
1170+ '''Test check_security_yaml_and_click() - different templates'''
1171+ self.set_test_security_manifest(self.default_appname,
1172+ "template", "other")
1173+ self._set_yaml_binary([("security-template", "nondefault"),
1174+ ('caps', ['networking'])],
1175+ name=self.default_appname)
1176+ c = ClickReviewSecurity(self.test_name)
1177+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1178+ c.check_security_yaml_and_click()
1179+ report = c.click_report
1180+ expected_counts = {'info': None, 'warn': 0, 'error': 2}
1181+ self.check_results(report, expected_counts)
1182+
1183+ def test_check_security_yaml_and_click_mismatch6(self):
1184+ '''Test check_security_yaml_and_click() - missing caps in yaml'''
1185+ self._set_yaml_binary([('caps', [])])
1186+ self.set_test_security_manifest(self.default_appname,
1187+ "policy_groups", ["1", "2"])
1188+ c = ClickReviewSecurity(self.test_name)
1189+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1190+ del c.pkg_yaml['binaries'][0]['caps']
1191+ c.check_security_yaml_and_click()
1192+ report = c.click_report
1193+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1194+ self.check_results(report, expected_counts)
1195+
1196+ def test_check_security_yaml_and_click_mismatch7(self):
1197+ '''Test check_security_yaml_and_click() - missing policy_groups'''
1198+ self._set_yaml_binary([('caps', ['networking'])],
1199+ name=self.default_appname)
1200+ self.set_test_security_manifest(self.default_appname,
1201+ "policy_groups", None)
1202+ c = ClickReviewSecurity(self.test_name)
1203+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1204+ c.check_security_yaml_and_click()
1205+ report = c.click_report
1206+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1207+ self.check_results(report, expected_counts)
1208+
1209+ def test_check_security_yaml_and_click_mismatch8(self):
1210+ '''Test check_security_yaml_and_click() - different caps/groups'''
1211+ self.set_test_security_manifest(self.default_appname,
1212+ "policy_groups", ["1", "2"])
1213+ self._set_yaml_binary([('caps', ["3"])],
1214+ name=self.default_appname)
1215+ c = ClickReviewSecurity(self.test_name)
1216+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1217+ c.check_security_yaml_and_click()
1218+ report = c.click_report
1219+ expected_counts = {'info': None, 'warn': 0, 'error': 2}
1220+ self.check_results(report, expected_counts)
1221+
1222+ def test_check_security_yaml_and_click_mismatch9(self):
1223+ '''Test check_security_yaml_and_click() - unordered caps/groups'''
1224+ self.set_test_security_manifest(self.default_appname,
1225+ "policy_groups", ["1", "2"])
1226+ self._set_yaml_binary([('caps', ["2", "1"])],
1227+ name=self.default_appname)
1228+ c = ClickReviewSecurity(self.test_name)
1229+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1230+ c.check_security_yaml_and_click()
1231+ report = c.click_report
1232+ expected_counts = {'info': 5, 'warn': 0, 'error': 0}
1233+ self.check_results(report, expected_counts)
1234+
1235+ def test_check_security_yaml_and_click_mismatch10(self):
1236+ '''Test check_security_yaml_and_click() - missing caps in both'''
1237+ self._set_yaml_binary([('caps', [])])
1238+ self.set_test_security_manifest(self.default_appname,
1239+ "policy_groups", None)
1240+ c = ClickReviewSecurity(self.test_name)
1241+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1242+ del c.pkg_yaml['binaries'][0]['caps']
1243+ c.check_security_yaml_and_click()
1244+ report = c.click_report
1245+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1246+ self.check_results(report, expected_counts)
1247+
1248+ def test_check_security_yaml_and_click_mismatch11(self):
1249+ '''Test check_security_yaml_and_click() - default caps with template'''
1250+ self._set_yaml_binary([('security-template', 'nondefault')])
1251+ self.set_test_security_manifest(self.default_appname,
1252+ "policy_groups", ['networking'])
1253+ self.set_test_security_manifest(self.default_appname,
1254+ "template", "nondefault")
1255+ c = ClickReviewSecurity(self.test_name)
1256+ c.manifest["hooks"][self.default_appname]['bin-path'] = "bin/path"
1257+ del c.pkg_yaml['binaries'][0]['caps']
1258+ c.check_security_yaml_and_click()
1259+ report = c.click_report
1260+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1261+ self.check_results(report, expected_counts)
1262+
1263+ def test_check_security_yaml_combinations(self):
1264+ '''Test check_security_yaml_combinations()'''
1265+ self._set_yaml_binary([], name=self.default_appname)
1266+ c = ClickReviewSecurity(self.test_name)
1267+ c.check_security_yaml_combinations()
1268+ report = c.click_report
1269+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1270+ self.check_results(report, expected_counts)
1271+
1272+ def test_check_security_yaml_combinations1(self):
1273+ '''Test check_security_yaml_combinations() - template'''
1274+ self._set_yaml_binary([('security-template', 'foo')],
1275+ name=self.default_appname)
1276+ c = ClickReviewSecurity(self.test_name)
1277+ c.check_security_yaml_combinations()
1278+ report = c.click_report
1279+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1280+ self.check_results(report, expected_counts)
1281+
1282+ def test_check_security_yaml_combinations2(self):
1283+ '''Test check_security_yaml_combinations() - caps'''
1284+ self._set_yaml_binary([('caps', ['networking'])],
1285+ name=self.default_appname)
1286+ c = ClickReviewSecurity(self.test_name)
1287+ c.check_security_yaml_combinations()
1288+ report = c.click_report
1289+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1290+ self.check_results(report, expected_counts)
1291+
1292+ def test_check_security_yaml_combinations3(self):
1293+ '''Test check_security_yaml_combinations() - template,caps'''
1294+ self._set_yaml_binary([('security-template', 'foo'),
1295+ ('caps', ['networking'])],
1296+ name=self.default_appname)
1297+ c = ClickReviewSecurity(self.test_name)
1298+ c.check_security_yaml_combinations()
1299+ report = c.click_report
1300+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1301+ self.check_results(report, expected_counts)
1302+
1303+ def test_check_security_yaml_combinations4(self):
1304+ '''Test check_security_yaml_combinations() - override'''
1305+ self._set_yaml_binary([('security-override', {'apparmor': 'foo.aa',
1306+ 'seccomp': 'foo.sc'})],
1307+ name=self.default_appname)
1308+ c = ClickReviewSecurity(self.test_name)
1309+ c.check_security_yaml_combinations()
1310+ report = c.click_report
1311+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1312+ self.check_results(report, expected_counts)
1313+
1314+ def test_check_security_yaml_combinations5(self):
1315+ '''Test check_security_yaml_combinations() - override, template'''
1316+ self._set_yaml_binary([('security-template', 'foo'),
1317+ ('security-override', {'apparmor': 'foo.aa',
1318+ 'seccomp': 'foo.sc'})],
1319+ name=self.default_appname)
1320+ c = ClickReviewSecurity(self.test_name)
1321+ c.check_security_yaml_combinations()
1322+ report = c.click_report
1323+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1324+ self.check_results(report, expected_counts)
1325+
1326+ def test_check_security_yaml_combinations6(self):
1327+ '''Test check_security_yaml_combinations() - override, caps'''
1328+ self._set_yaml_binary([('caps', ['networking']),
1329+ ('security-override', {'apparmor': 'foo.aa',
1330+ 'seccomp': 'foo.sc'})],
1331+ name=self.default_appname)
1332+ c = ClickReviewSecurity(self.test_name)
1333+ c.check_security_yaml_combinations()
1334+ report = c.click_report
1335+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1336+ self.check_results(report, expected_counts)
1337+
1338+ def test_check_security_yaml_combinations7(self):
1339+ '''Test check_security_yaml_combinations() - override, caps, template
1340+ '''
1341+ self._set_yaml_binary([('security-template', 'foo'),
1342+ ('caps', ['networking']),
1343+ ('security-override', {'apparmor': 'foo.aa',
1344+ 'seccomp': 'foo.sc'})],
1345+ name=self.default_appname)
1346+ c = ClickReviewSecurity(self.test_name)
1347+ c.check_security_yaml_combinations()
1348+ report = c.click_report
1349+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1350+ self.check_results(report, expected_counts)
1351+
1352+ def test_check_security_yaml_combinations8(self):
1353+ '''Test check_security_yaml_combinations() - override, caps, template,
1354+ policy
1355+ '''
1356+ self._set_yaml_binary([('security-template', 'foo'),
1357+ ('caps', ['networking']),
1358+ ('security-policy', {'apparmor': 'foo.aa',
1359+ 'seccomp': 'foo.sc'}),
1360+ ('security-override', {'apparmor': 'foo.aa',
1361+ 'seccomp': 'foo.sc'})],
1362+ name=self.default_appname)
1363+ c = ClickReviewSecurity(self.test_name)
1364+ c.check_security_yaml_combinations()
1365+ report = c.click_report
1366+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1367+ self.check_results(report, expected_counts)
1368+
1369+ def test_check_security_yaml_combinations9(self):
1370+ '''Test check_security_yaml_combinations() - policy'''
1371+ self._set_yaml_binary([('security-policy', {'apparmor': 'foo.aa',
1372+ 'seccomp': 'foo.sc'})],
1373+ name=self.default_appname)
1374+ c = ClickReviewSecurity(self.test_name)
1375+ c.check_security_yaml_combinations()
1376+ report = c.click_report
1377+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1378+ self.check_results(report, expected_counts)
1379+
1380+ def test_check_security_yaml_combinations10(self):
1381+ '''Test check_security_yaml_combinations() - policy, template'''
1382+ self._set_yaml_binary([('security-template', 'foo'),
1383+ ('security-policy', {'apparmor': 'foo.aa',
1384+ 'seccomp': 'foo.sc'})],
1385+ name=self.default_appname)
1386+ c = ClickReviewSecurity(self.test_name)
1387+ c.check_security_yaml_combinations()
1388+ report = c.click_report
1389+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1390+ self.check_results(report, expected_counts)
1391+
1392+ def test_check_security_yaml_combinations11(self):
1393+ '''Test check_security_yaml_combinations() - policy, caps'''
1394+ self._set_yaml_binary([('caps', ['networking']),
1395+ ('security-policy', {'apparmor': 'foo.aa',
1396+ 'seccomp': 'foo.sc'})],
1397+ name=self.default_appname)
1398+ c = ClickReviewSecurity(self.test_name)
1399+ c.check_security_yaml_combinations()
1400+ report = c.click_report
1401+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1402+ self.check_results(report, expected_counts)
1403+
1404+ def test_check_security_yaml_combinations12(self):
1405+ '''Test check_security_yaml_combinations() - policy, caps, template
1406+ '''
1407+ self._set_yaml_binary([('security-template', 'foo'),
1408+ ('caps', ['networking']),
1409+ ('security-policy', {'apparmor': 'foo.aa',
1410+ 'seccomp': 'foo.sc'})],
1411+ name=self.default_appname)
1412+ c = ClickReviewSecurity(self.test_name)
1413+ c.check_security_yaml_combinations()
1414+ report = c.click_report
1415+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1416+ self.check_results(report, expected_counts)
1417+
1418+ def test_check_security_yaml_override_and_click(self):
1419+ '''Test check_security_yaml_override_and_click()'''
1420+ self.set_test_security_manifest(self.default_appname, "template", None)
1421+ self._set_yaml_binary([])
1422+ c = ClickReviewSecurity(self.test_name)
1423+ c.check_security_yaml_override_and_click()
1424+ report = c.click_report
1425+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1426+ self.check_results(report, expected_counts)
1427+
1428+ def test_check_security_yaml_override_and_click_bad(self):
1429+ '''Test check_security_yaml_override_and_click() - bad'''
1430+ self.set_test_security_manifest(self.default_appname, "template", None)
1431+ self._set_yaml_binary([('security-override', {'apparmor':
1432+ 'something.else'})],
1433+ name=self.default_appname)
1434+ c = ClickReviewSecurity(self.test_name)
1435+ c.check_security_yaml_override_and_click()
1436+ report = c.click_report
1437+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1438+ self.check_results(report, expected_counts)
1439+
1440+ def test_check_security_yaml_override(self):
1441+ '''Test check_security_yaml_override()'''
1442+ self.set_test_security_manifest(self.default_appname, "template", None)
1443+ self._set_yaml_binary([])
1444+ c = ClickReviewSecurity(self.test_name)
1445+ c.check_security_yaml_override()
1446+ report = c.click_report
1447+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1448+ self.check_results(report, expected_counts)
1449+
1450+ def test_check_security_yaml_override2(self):
1451+ '''Test check_security_yaml_override() - seccomp/apparmor specified'''
1452+ self._set_yaml_binary([('security-override', {'apparmor': 'aa',
1453+ 'seccomp': 'sc'})],
1454+ name=self.default_appname)
1455+ c = ClickReviewSecurity(self.test_name)
1456+ c.check_security_yaml_override()
1457+ report = c.click_report
1458+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1459+ self.check_results(report, expected_counts)
1460+
1461+ def test_check_security_yaml_override_missing1(self):
1462+ '''Test check_security_yaml_override() - missing apparmor'''
1463+ self._set_yaml_binary([('security-override', {'seccomp': 'sc'})],
1464+ name=self.default_appname)
1465+ c = ClickReviewSecurity(self.test_name)
1466+ c.check_security_yaml_override()
1467+ report = c.click_report
1468+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1469+ self.check_results(report, expected_counts)
1470+
1471+ def test_check_security_yaml_override_missing2(self):
1472+ '''Test check_security_yaml_override() - missing seccomp'''
1473+ self._set_yaml_binary([('security-override', {'apparmor': 'aa'})],
1474+ name=self.default_appname)
1475+ c = ClickReviewSecurity(self.test_name)
1476+ c.check_security_yaml_override()
1477+ report = c.click_report
1478+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1479+ self.check_results(report, expected_counts)
1480+
1481+ def test_check_security_yaml_policy(self):
1482+ '''Test check_security_yaml_policy()'''
1483+ self.set_test_security_manifest(self.default_appname, "template", None)
1484+ self._set_yaml_binary([])
1485+ c = ClickReviewSecurity(self.test_name)
1486+ c.check_security_yaml_policy()
1487+ report = c.click_report
1488+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1489+ self.check_results(report, expected_counts)
1490+
1491+ def test_check_security_yaml_policy2(self):
1492+ '''Test check_security_yaml_policy() - seccomp/apparmor specified'''
1493+ self._set_yaml_binary([('security-policy', {'apparmor': 'aa',
1494+ 'seccomp': 'sc'})],
1495+ name=self.default_appname)
1496+ c = ClickReviewSecurity(self.test_name)
1497+ c.check_security_yaml_policy()
1498+ report = c.click_report
1499+ expected_counts = {'info': 1, 'warn': 0, 'error': 0}
1500+ self.check_results(report, expected_counts)
1501+
1502+ def test_check_security_yaml_policy_missing1(self):
1503+ '''Test check_security_yaml_policy() - missing apparmor'''
1504+ self._set_yaml_binary([('security-policy', {'seccomp': 'sc'})],
1505+ name=self.default_appname)
1506+ c = ClickReviewSecurity(self.test_name)
1507+ c.check_security_yaml_policy()
1508+ report = c.click_report
1509+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1510+ self.check_results(report, expected_counts)
1511+
1512+ def test_check_security_yaml_policy_missing2(self):
1513+ '''Test check_security_yaml_policy() - missing seccomp'''
1514+ self._set_yaml_binary([('security-policy', {'apparmor': 'aa'})],
1515+ name=self.default_appname)
1516+ c = ClickReviewSecurity(self.test_name)
1517+ c.check_security_yaml_policy()
1518+ report = c.click_report
1519+ expected_counts = {'info': None, 'warn': 0, 'error': 1}
1520+ self.check_results(report, expected_counts)
1521
1522=== modified file 'debian/changelog'
1523--- debian/changelog 2015-05-14 14:42:37 +0000
1524+++ debian/changelog 2015-05-18 21:07:49 +0000
1525@@ -3,6 +3,8 @@
1526 [ Jamie Strandboge ]
1527 * Makefile: perform run-pyflakes in check target
1528 * cr_systemd.py: add bus-name checks and update testsuite
1529+ * add security yaml checks
1530+ * cr_lint.py: don't allow same key in 'binaries' and 'services'
1531
1532 [ Marcus Tomlinson ]
1533 * cr_scope.py: add "keywords" to the list of optional scope .ini keys
1534
1535=== modified file 'run-pep8'
1536--- run-pep8 2014-08-22 13:22:48 +0000
1537+++ run-pep8 2015-05-18 21:07:49 +0000
1538@@ -2,8 +2,12 @@
1539 set -e
1540
1541 echo "= pep8 ="
1542-for i in ./bin/update-* ./bin/click-check-* ./bin/click-show-files ./bin/click-review \
1543- ./clickreviews/*py ./clickreviews/tests/*py ; do
1544+for i in ./clickreviews/*py \
1545+ ./clickreviews/tests/*py \
1546+ ./bin/update-* \
1547+ ./bin/click-check-* \
1548+ ./bin/click-show-files \
1549+ ./bin/click-review ; do
1550 echo "Checking $i"
1551 pep8 $i
1552 done

Subscribers

People subscribed via source and target branches