Skip to content

Canonicalize URLs prior to Policy specifier matching

Currently policies preempt the resolution process entirely and work off of raw specifiers. If file:///app/component.cjs requires require("./util.js") or imports import("./util.js") policies only look for an exact match of "./util.js" in "dependencies". This was found as a usability issue by @giltayar while comparing with / looking at import maps compatibility. In particular, with import maps the specifiers are always canonicalized prior to performing matching, both the specifiers in the map that can be matched and the specifier from the call site. This allows a mapping table to cover all ways to get a hold of file:///app/util.js in a more concise manner.

Consider this as the source texts :

// `file:///app/component.cjs`
require('./dir/foo.cjs');
require('./bar.cjs');
 // `file:///app/dir/foo.cjs`
require('./bar.cjs');

and a policy at file:///policy.json containing:

{
  "scopes": {
    "file:": {
      "cascade": true,
      "integrity": true,
      "dependencies": {
         "./bar.cjs": "file:///app/bar.js"
      }
    }
  }
}

This policy will intercept both the loads from file:///app/dir/foo.cjs and file:///app/component.cjs. And have both resolve to file:///app/bar.js.

Canonicalizing early would mean that it only intercepts resolution that PRIOR TO NODE RESOLUTION would point to file:///bar.cjs regardless of the file containing the load. This actually is a breaking change to policies and one would have to alter some data as seen in the tests in this PR but it would greatly simplify some cases so that instead of needing to specify all routes to dependencies one only needs to specify the eventual target if resolved prior to node resolving. This must be done prior to node resolving so that things like fs and react are still properly able to be intercepted. Due to the number of closures this uses we likely should add a benchmark and migrate to be less closure heavy and pass around objects instead.

Merge request reports

Loading