Commit c8a6abe1 authored by Kris Maglione's avatar Kris Maglione
Browse files

Bug 1442931: Part 1 - Forbid web-visible interfaces outside of WebIDL root. r=mystor

Web-visible WebIDL interfaces require DOM peer review with every change, which
is enforced by a commit hook. ChromeOnly interfaces are not exposed to the
web, and therefore don't require the same strictures.

The current commit hook enforces the review requirement for changes to any
(non-Servo) WebIDL file, and is not smart enough to determine if the change is
web-visible. In order to loosen that restriction, we need the build system to
enforce the requirement that only WebIDL files in certain locations may
contain web-visible interfaces, so that the commit hook can restrict itself to
checking only those directories.

This change restricts the location of web-visible WebIDL interfaces to the
dom/webidl/ and dom/bindings/ roots (along with the corresponding objdir root
for generated interfaces). A follow-up will change the commit hook to only
enforce review requirements on these directories.

MozReview-Commit-ID: CiDxXxN4oO4

--HG--
extra : source : 6cb20ada1a0aa1f6d621ba3c85ce9946a6f9841f
extra : histedit_source : 1f02888264a936db3e77134c0a7203e911707312%2C6ea38c077b8a7dfaf358bc819d150a20db9bd6b7
parent 27f4fb5a
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -18,12 +18,17 @@ class DescriptorProvider:
        pass


def isChildPath(path, basePath):
    path = os.path.normpath(path)
    return os.path.commonprefix((path, basePath)) == basePath


class Configuration(DescriptorProvider):
    """
    Represents global configuration state based on IDL parse data and
    the configuration file.
    """
    def __init__(self, filename, parseData, generatedEvents=[]):
    def __init__(self, filename, webRoots, parseData, generatedEvents=[]):
        DescriptorProvider.__init__(self)

        # Read the configuration file.
@@ -31,6 +36,10 @@ class Configuration(DescriptorProvider):
        execfile(filename, glbl)
        config = glbl['DOMInterfaces']

        webRoots = tuple(map(os.path.normpath, webRoots))
        def isInWebIDLRoot(path):
            return any(isChildPath(path, root) for root in webRoots)

        # Build descriptors for all the interfaces we have in the parse data.
        # This allows callers to specify a subset of interfaces by filtering
        # |parseData|.
@@ -94,6 +103,17 @@ class Configuration(DescriptorProvider):
                            "%s\n"
                            "%s" %
                            (partialIface.location, iface.location))
                if not (iface.getExtendedAttribute("ChromeOnly") or
                        not (iface.hasInterfaceObject() or
                             iface.isNavigatorProperty()) or
                        isInWebIDLRoot(iface.filename())):
                    raise TypeError(
                        "Interfaces which are exposed to the web may only be "
                        "defined in a DOM WebIDL root %r. Consider marking "
                        "the interface [ChromeOnly] if you do not want it "
                        "exposed to the web.\n"
                        "%s" %
                        (webRoots, iface.location))
            self.interfaces[iface.identifier.name] = iface
            if iface.identifier.name not in config:
                # Completely skip consequential interfaces with no descriptor
+23 −2
Original line number Diff line number Diff line
@@ -150,7 +150,7 @@ class WebIDLCodegenManager(LoggingMixin):
        'PrototypeList.cpp',
    }

    def __init__(self, config_path, inputs, exported_header_dir,
    def __init__(self, config_path, webidl_root, inputs, exported_header_dir,
                 codegen_dir, state_path, cache_dir=None, make_deps_path=None,
                 make_deps_target=None):
        """Create an instance that manages WebIDLs in the build system.
@@ -176,6 +176,7 @@ class WebIDLCodegenManager(LoggingMixin):
        input_paths, exported_stems, generated_events_stems, example_interfaces = inputs

        self._config_path = config_path
        self._webidl_root = webidl_root
        self._input_paths = set(input_paths)
        self._exported_stems = set(exported_stems)
        self._generated_events_stems = set(generated_events_stems)
@@ -332,8 +333,26 @@ class WebIDLCodegenManager(LoggingMixin):
                hashes[path] = hashlib.sha1(data).hexdigest()
                parser.parse(data, path)

        # Only these directories may contain WebIDL files with interfaces
        # which are exposed to the web. WebIDL files in these roots may not
        # be changed without DOM peer review.
        #
        # Other directories may contain WebIDL files as long as they only
        # contain ChromeOnly interfaces. These are not subject to mandatory
        # DOM peer review.
        web_roots = (
            # The main WebIDL root.
            self._webidl_root,
            # The binding config root, which contains some test-only
            # interfaces.
            os.path.dirname(self._config_path),
            # The objdir sub-directory which contains generated WebIDL files.
            self._codegen_dir,
        )

        self._parser_results = parser.finish()
        self._config = Configuration(self._config_path, self._parser_results,
        self._config = Configuration(self._config_path, web_roots,
                                     self._parser_results,
                                     self._generated_events_stems_as_array)
        self._input_hashes = hashes

@@ -546,6 +565,7 @@ def create_build_system_manager(topsrcdir, topobjdir, dist_dir):
    """Create a WebIDLCodegenManager for use by the build system."""
    src_dir = os.path.join(topsrcdir, 'dom', 'bindings')
    obj_dir = os.path.join(topobjdir, 'dom', 'bindings')
    webidl_root = os.path.join(topsrcdir, 'dom', 'webidl')

    with open(os.path.join(obj_dir, 'file-lists.json'), 'rb') as fh:
        files = json.load(fh)
@@ -562,6 +582,7 @@ def create_build_system_manager(topsrcdir, topobjdir, dist_dir):

    return WebIDLCodegenManager(
        os.path.join(src_dir, 'Bindings.conf'),
        webidl_root,
        inputs,
        os.path.join(dist_dir, 'include', 'mozilla', 'dom'),
        obj_dir,
+1 −0
Original line number Diff line number Diff line
@@ -71,6 +71,7 @@ class TestWebIDLCodegenManager(unittest.TestCase):

        return dict(
            config_path=self._config_path,
            webidl_root='/',
            inputs=inputs,
            exported_header_dir=mozpath.join(tmp, 'exports'),
            codegen_dir=mozpath.join(tmp, 'codegen'),