Merge lp:~sergiusens/snapcraft/appamor into lp:~snappy-dev/snapcraft/core

Proposed by Sergio Schvezov
Status: Merged
Approved by: John Lenton
Approved revision: 168
Merged at revision: 169
Proposed branch: lp:~sergiusens/snapcraft/appamor
Merge into: lp:~snappy-dev/snapcraft/core
Diff against target: 325 lines (+130/-36)
4 files modified
schema/snapcraft.yaml (+27/-5)
snapcraft/meta.py (+22/-10)
snapcraft/tests/test_meta.py (+80/-21)
snapcraft/yaml.py (+1/-0)
To merge this branch: bzr merge lp:~sergiusens/snapcraft/appamor
Reviewer Review Type Date Requested Status
John Lenton (community) Approve
Review via email: mp+271363@code.launchpad.net

Commit message

apparmor and seccomp

To post a comment you must log in.
Revision history for this message
John Lenton (chipaca) wrote :

Ok.

I maintain my reservations around using yaml-encoded jsonschema. But if it works for you... :-/

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'schema/snapcraft.yaml'
2--- schema/snapcraft.yaml 2015-09-15 01:06:18 +0000
3+++ schema/snapcraft.yaml 2015-09-16 19:34:11 +0000
4@@ -1,5 +1,19 @@
5 $schema: http://json-schema.org/draft-04/schema#
6
7+definitions:
8+ security:
9+ type: object
10+ required:
11+ - apparmor
12+ - seccomp
13+ properties:
14+ apparmor:
15+ type: string
16+ format: file-path
17+ seccomp:
18+ type: string
19+ format: file-path
20+
21 title: snapcraft schema
22 type: object
23 properties:
24@@ -45,6 +59,9 @@
25 type: array
26 items:
27 - type: object
28+ required:
29+ - name
30+ - start
31 properties:
32 name:
33 type: string
34@@ -55,13 +72,16 @@
35 stop:
36 type: string
37 description: command executed to stop the service
38- required:
39- - name
40- - start
41+ security-policy:
42+ $ref: "#definitions/security"
43+ security-override:
44+ $ref: "#definitions/security"
45 binaries:
46 type: array
47 items:
48 - type: object
49+ required:
50+ - name
51 properties:
52 name:
53 type: string
54@@ -69,8 +89,10 @@
55 exec:
56 type: string
57 description: command executed to start the service
58- required:
59- - name
60+ security-policy:
61+ $ref: "#definitions/security"
62+ security-override:
63+ $ref: "#definitions/security"
64 parts:
65 type: object
66 minProperties: 1
67
68=== modified file 'snapcraft/meta.py'
69--- snapcraft/meta.py 2015-09-15 05:17:14 +0000
70+++ snapcraft/meta.py 2015-09-16 19:34:11 +0000
71@@ -52,7 +52,7 @@
72 meta_dir = os.path.join(common.get_snapdir(), 'meta')
73 os.makedirs(meta_dir, exist_ok=True)
74
75- config_data['icon'] = _copy_icon(meta_dir, config_data['icon'])
76+ config_data['icon'] = _copy(meta_dir, config_data['icon'])
77
78 _write_package_yaml(meta_dir, config_data, arches)
79 _write_readme_md(meta_dir, config_data)
80@@ -65,7 +65,7 @@
81
82 def _write_package_yaml(meta_dir, config_data, arches):
83 package_yaml_path = os.path.join(meta_dir, 'package.yaml')
84- package_yaml = _compose_package_yaml(config_data, arches)
85+ package_yaml = _compose_package_yaml(meta_dir, config_data, arches)
86
87 with open(package_yaml_path, 'w') as f:
88 yaml.dump(package_yaml, stream=f, default_flow_style=False)
89@@ -91,14 +91,24 @@
90 _write_wrap_exe(execparts[0], config_hook_path, args=args, cwd='$SNAP_APP_PATH')
91
92
93-def _copy_icon(meta_dir, icon_path):
94- new_icon_path = os.path.join(meta_dir, os.path.basename(icon_path))
95- shutil.copyfile(icon_path, new_icon_path)
96-
97- return os.path.join('meta', os.path.basename(icon_path))
98-
99-
100-def _compose_package_yaml(config_data, arches):
101+def _copy(meta_dir, relpath):
102+ new_relpath = os.path.join(meta_dir, os.path.basename(relpath))
103+ shutil.copyfile(relpath, new_relpath)
104+
105+ return os.path.join('meta', os.path.basename(relpath))
106+
107+
108+def _copy_security_profiles(meta_dir, runnables):
109+ for runnable in runnables:
110+ for entry in ('security-policy', 'security-override'):
111+ if entry in runnable:
112+ runnable[entry]['apparmor'] = _copy(meta_dir, runnable[entry]['apparmor'])
113+ runnable[entry]['seccomp'] = _copy(meta_dir, runnable[entry]['seccomp'])
114+
115+ return runnables
116+
117+
118+def _compose_package_yaml(meta_dir, config_data, arches):
119 '''
120 Creates a dictionary that can be used to yaml.dump a package.yaml using
121 config_data.
122@@ -121,9 +131,11 @@
123
124 if 'binaries' in config_data:
125 package_yaml['binaries'] = _wrap_binaries(config_data['binaries'])
126+ package_yaml['binaries'] = _copy_security_profiles(meta_dir, config_data['binaries'])
127
128 if 'services' in config_data:
129 package_yaml['services'] = _wrap_services(config_data['services'])
130+ package_yaml['services'] = _copy_security_profiles(meta_dir, config_data['services'])
131
132 return package_yaml
133
134
135=== modified file 'snapcraft/tests/test_meta.py'
136--- snapcraft/tests/test_meta.py 2015-09-15 05:17:14 +0000
137+++ snapcraft/tests/test_meta.py 2015-09-16 19:34:11 +0000
138@@ -44,7 +44,7 @@
139 }
140
141 def test_plain_no_binaries_or_services(self):
142- y = meta._compose_package_yaml(self.config_data, ['armhf', 'amd64'])
143+ y = meta._compose_package_yaml('meta', self.config_data, ['armhf', 'amd64'])
144
145 expected = {
146 'name': 'my-package',
147@@ -57,7 +57,7 @@
148 self.assertEqual(y, expected)
149
150 def test_plain_no_binaries_or_services_or_arches(self):
151- y = meta._compose_package_yaml(self.config_data, None)
152+ y = meta._compose_package_yaml('meta', self.config_data, None)
153
154 expected = {
155 'name': 'my-package',
156@@ -79,7 +79,7 @@
157 },
158 ]
159
160- y = meta._compose_package_yaml(self.config_data, ['armhf', 'amd64'])
161+ y = meta._compose_package_yaml('meta', self.config_data, ['armhf', 'amd64'])
162
163 expected = {
164 'name': 'my-package',
165@@ -117,7 +117,7 @@
166 },
167 ]
168
169- y = meta._compose_package_yaml(self.config_data, ['armhf', 'amd64'])
170+ y = meta._compose_package_yaml('meta', self.config_data, ['armhf', 'amd64'])
171
172 expected = {
173 'name': 'my-package',
174@@ -146,7 +146,7 @@
175 def test_plain_no_binaries_or_services_with_optionals(self):
176 self.config_data['frameworks'] = ['mir', ]
177
178- y = meta._compose_package_yaml(self.config_data, ['armhf', 'amd64'])
179+ y = meta._compose_package_yaml('meta', self.config_data, ['armhf', 'amd64'])
180
181 expected = {
182 'name': 'my-package',
183@@ -199,10 +199,21 @@
184 'description': 'my description',
185 'summary': 'my summary',
186 'icon': 'my-icon.png',
187- 'config': 'bin/config'
188+ 'config': 'bin/config',
189+ 'binaries': [
190+ {
191+ 'name': 'bash',
192+ 'exec': 'bin/bash',
193+ 'security-policy': {
194+ 'apparmor': 'file.apparmor',
195+ 'seccomp': 'file.seccomp',
196+ },
197+ }
198+ ]
199 }
200
201 self.meta_dir = os.path.join(os.path.abspath(os.curdir), 'snap', 'meta')
202+ self.hooks_dir = os.path.join(self.meta_dir, 'hooks')
203
204 self.expected_open_calls = [
205 call(os.path.join(self.meta_dir, 'package.yaml'), 'w'),
206@@ -214,6 +225,38 @@
207 call().__enter__().write(' '),
208 call().__enter__().write('amd64'),
209 call().__enter__().write('\n'),
210+ call().__enter__().write('binaries'),
211+ call().__enter__().write(':'),
212+ call().__enter__().write('\n'),
213+ call().__enter__().write('-'),
214+ call().__enter__().write(' '),
215+ call().__enter__().write('exec'),
216+ call().__enter__().write(':'),
217+ call().__enter__().write(' '),
218+ call().__enter__().write('bin/bash.wrapper'),
219+ call().__enter__().write('\n'),
220+ call().__enter__().write(' '),
221+ call().__enter__().write('name'),
222+ call().__enter__().write(':'),
223+ call().__enter__().write(' '),
224+ call().__enter__().write('bash'),
225+ call().__enter__().write('\n'),
226+ call().__enter__().write(' '),
227+ call().__enter__().write('security-policy'),
228+ call().__enter__().write(':'),
229+ call().__enter__().write('\n'),
230+ call().__enter__().write(' '),
231+ call().__enter__().write('apparmor'),
232+ call().__enter__().write(':'),
233+ call().__enter__().write(' '),
234+ call().__enter__().write('meta/file.apparmor'),
235+ call().__enter__().write('\n'),
236+ call().__enter__().write(' '),
237+ call().__enter__().write('seccomp'),
238+ call().__enter__().write(':'),
239+ call().__enter__().write(' '),
240+ call().__enter__().write('meta/file.seccomp'),
241+ call().__enter__().write('\n'),
242 call().__enter__().write('icon'),
243 call().__enter__().write(':'),
244 call().__enter__().write(' '),
245@@ -248,8 +291,6 @@
246 call().__exit__(None, None, None),
247 ]
248
249- self.hooks_dir = os.path.join(self.meta_dir, 'hooks')
250-
251 @patch('snapcraft.meta._write_wrap_exe')
252 @patch('snapcraft.meta.open', create=True)
253 def test_create_meta(self, mock_the_open, mock_wrap_exe):
254@@ -261,12 +302,23 @@
255 ])
256
257 mock_the_open.assert_has_calls(self.expected_open_calls)
258- mock_wrap_exe.assert_called_once_with(
259- 'bin/config',
260- os.path.join(os.path.abspath(os.curdir), 'snap', 'meta', 'hooks', 'config'),
261- args=[],
262- cwd='$SNAP_APP_PATH',
263- )
264+ mock_wrap_exe.assert_has_calls([
265+ call(
266+ '$SNAP_APP_PATH/bin/bash',
267+ os.path.join(os.path.abspath(os.curdir), 'snap/bin/bash.wrapper'),
268+ ),
269+ call(
270+ 'bin/config',
271+ os.path.join(self.hooks_dir, 'config'),
272+ args=[],
273+ cwd='$SNAP_APP_PATH',
274+ ),
275+ ])
276+ self.mock_copyfile.assert_has_calls([
277+ call('my-icon.png', os.path.join(self.meta_dir, 'my-icon.png')),
278+ call('file.apparmor', os.path.join(self.meta_dir, 'file.apparmor')),
279+ call('file.seccomp', os.path.join(self.meta_dir, 'file.seccomp')),
280+ ])
281
282 @patch('snapcraft.meta._write_wrap_exe')
283 @patch('snapcraft.meta.open', create=True)
284@@ -281,15 +333,22 @@
285 ])
286
287 mock_the_open.assert_has_calls(self.expected_open_calls)
288- mock_wrap_exe.assert_called_once_with(
289- 'python3',
290- os.path.join(os.path.abspath(os.curdir), 'snap', 'meta', 'hooks', 'config'),
291- args=['my.py', '--config'],
292- cwd='$SNAP_APP_PATH',
293- )
294+ mock_wrap_exe.assert_has_calls([
295+ call(
296+ '$SNAP_APP_PATH/bin/bash',
297+ os.path.join(os.path.abspath(os.curdir), 'snap/bin/bash.wrapper'),
298+ ),
299+ call(
300+ 'python3',
301+ os.path.join(self.hooks_dir, 'config'),
302+ args=['my.py', '--config'],
303+ cwd='$SNAP_APP_PATH',
304+ ),
305+ ])
306
307+ @patch('snapcraft.meta._write_wrap_exe')
308 @patch('snapcraft.meta.open', create=True)
309- def test_create_meta_without_config(self, mock_the_open):
310+ def test_create_meta_without_config(self, mock_the_open, mock_wrap_exe):
311 del self.config_data['config']
312
313 meta.create(self.config_data, ['amd64'])
314
315=== modified file 'snapcraft/yaml.py'
316--- snapcraft/yaml.py 2015-09-15 14:45:57 +0000
317+++ snapcraft/yaml.py 2015-09-16 19:34:11 +0000
318@@ -29,6 +29,7 @@
319 logger = logging.getLogger(__name__)
320
321
322+@jsonschema.FormatChecker.cls_checks('file-path')
323 @jsonschema.FormatChecker.cls_checks('icon-path')
324 def _validate_file_exists(instance):
325 return os.path.exists(instance)

Subscribers

People subscribed via source and target branches