diff --git a/scripts/Android.bp b/scripts/Android.bp index 9367ff06a..97f6ab424 100644 --- a/scripts/Android.bp +++ b/scripts/Android.bp @@ -237,3 +237,20 @@ sh_binary_host { name: "jars-to-module-info-java", src: "jars-to-module-info-java.sh", } + +python_binary_host { + name: "modify_permissions_allowlist", + main: "modify_permissions_allowlist.py", + srcs: [ + "modify_permissions_allowlist.py", + ], +} + +python_test_host { + name: "modify_permissions_allowlist_test", + main: "modify_permissions_allowlist_test.py", + srcs: [ + "modify_permissions_allowlist_test.py", + "modify_permissions_allowlist.py", + ], +} diff --git a/scripts/modify_permissions_allowlist.py b/scripts/modify_permissions_allowlist.py new file mode 100755 index 000000000..38ec7ec86 --- /dev/null +++ b/scripts/modify_permissions_allowlist.py @@ -0,0 +1,70 @@ +#!/usr/bin/env python +# +# Copyright (C) 2022 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""A tool for modifying privileged permission allowlists.""" + +from __future__ import print_function + +import argparse +import sys +from xml.dom import minidom + + +class InvalidRootNodeException(Exception): + pass + + +class InvalidNumberOfPrivappPermissionChildren(Exception): + pass + + +def modify_allowlist(allowlist_dom, package_name): + if allowlist_dom.documentElement.tagName != 'permissions': + raise InvalidRootNodeException + nodes = allowlist_dom.getElementsByTagName('privapp-permissions') + if nodes.length != 1: + raise InvalidNumberOfPrivappPermissionChildren + privapp_permissions = nodes[0] + privapp_permissions.setAttribute('package', package_name) + + +def parse_args(): + """Parse commandline arguments.""" + + parser = argparse.ArgumentParser() + parser.add_argument('input', help='input allowlist template file') + parser.add_argument( + 'package_name', help='package name to use in the allowlist' + ) + parser.add_argument('output', help='output allowlist file') + + return parser.parse_args() + + +def main(): + try: + args = parse_args() + doc = minidom.parse(args.input) + modify_allowlist(doc, args.package_name) + with open(args.output, 'w') as output_file: + doc.writexml(output_file, encoding='utf-8') + except Exception as err: + print('error: ' + str(err), file=sys.stderr) + sys.exit(-1) + + +if __name__ == '__main__': + main() diff --git a/scripts/modify_permissions_allowlist_test.py b/scripts/modify_permissions_allowlist_test.py new file mode 100755 index 000000000..ee8b12cc8 --- /dev/null +++ b/scripts/modify_permissions_allowlist_test.py @@ -0,0 +1,76 @@ +#!/usr/bin/env python +# +# Copyright (C) 2022 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +"""Unit tests for modify_permissions_allowlist.py.""" + +from __future__ import print_function + +import unittest + +from xml.dom import minidom + +from modify_permissions_allowlist import InvalidRootNodeException, InvalidNumberOfPrivappPermissionChildren, modify_allowlist + + +class ModifyPermissionsAllowlistTest(unittest.TestCase): + + def test_invalid_root(self): + xml_data = '' + xml_dom = minidom.parseString(xml_data) + self.assertRaises(InvalidRootNodeException, modify_allowlist, xml_dom, 'x') + + def test_no_packages(self): + xml_data = '' + xml_dom = minidom.parseString(xml_data) + self.assertRaises( + InvalidNumberOfPrivappPermissionChildren, modify_allowlist, xml_dom, 'x' + ) + + def test_multiple_packages(self): + xml_data = ( + '' + ' ' + ' ' + '' + ) + xml_dom = minidom.parseString(xml_data) + self.assertRaises( + InvalidNumberOfPrivappPermissionChildren, modify_allowlist, xml_dom, 'x' + ) + + def test_modify_package_name(self): + xml_data = ( + '' + ' ' + ' ' + ' ' + '' + ) + xml_dom = minidom.parseString(xml_data) + modify_allowlist(xml_dom, 'bar.baz') + expected_data = ( + '' + '' + ' ' + ' ' + ' ' + '' + ) + self.assertEqual(expected_data, xml_dom.toxml()) + + +if __name__ == '__main__': + unittest.main(verbosity=2)