(node, parsed, failClosed)
| 135 | } |
| 136 | |
| 137 | const matchRegistry = (node, parsed, failClosed) => { |
| 138 | // If this node is not a registry dep, refuse the match. A registry-style |
| 139 | // key (`pkg`, `pkg@1`, `pkg@1 || 2`) must not match a tarball or git node |
| 140 | // even if their names happen to coincide. |
| 141 | if (!isRegistryNode(node)) { |
| 142 | return false |
| 143 | } |
| 144 | |
| 145 | // Derive the trusted name+version from the lockfile's resolved URL. |
| 146 | // Never use `node.packageName` / `node.version` here: those read from |
| 147 | // the tarball's own package.json and can be forged by a malicious |
| 148 | // publisher to bypass an allowScripts entry. |
| 149 | const trusted = getTrustedRegistryIdentity(node) |
| 150 | if (!trusted || trusted.name !== parsed.name) { |
| 151 | return false |
| 152 | } |
| 153 | |
| 154 | // `tag` covers `pkg@latest`. Rejected up front by validatePolicy in |
| 155 | // resolve-allow-scripts.js because tags look like a pin but can't be |
| 156 | // verified at install time. Defense-in-depth: if one slips through |
| 157 | // (e.g. arborist invoked directly without the resolver), don't match. |
| 158 | if (parsed.type === 'tag') { |
| 159 | /* istanbul ignore next: validatePolicy filters this; defensive */ |
| 160 | return false |
| 161 | } |
| 162 | |
| 163 | // `range` includes `pkg@^1`, `pkg@1 || 2`, `pkg@*`, `pkg@>=0`, and bare |
| 164 | // names like `pkg` (npa parses these as range with fetchSpec='*'). The |
| 165 | // RFC permits bare names (name-only allow) and exact versions joined by |
| 166 | // `||`; ranges like ^/~/>=/< are rejected because they would silently |
| 167 | // allow versions the user has never reviewed. |
| 168 | if (parsed.type === 'range') { |
| 169 | // Bare name or `pkg@*`: treat as name-only allow. |
| 170 | if (parsed.fetchSpec === '*' || parsed.rawSpec === '' || parsed.rawSpec === '*') { |
| 171 | return true |
| 172 | } |
| 173 | if (!isExactVersionDisjunction(parsed.fetchSpec)) { |
| 174 | return false |
| 175 | } |
| 176 | // Unverifiable version (omit-lockfile-registry-resolved): a deny blocks, |
| 177 | // an allow is refused. |
| 178 | if (!trusted.version) { |
| 179 | return failClosed |
| 180 | } |
| 181 | return semver.satisfies(trusted.version, parsed.fetchSpec, { loose: true }) |
| 182 | } |
| 183 | |
| 184 | // `version` is an exact pin like `pkg@1.2.3`. |
| 185 | /* istanbul ignore else: parsed.type at this point is always 'version'; |
| 186 | the istanbul-ignored fallback below handles the impossible case. */ |
| 187 | if (parsed.type === 'version') { |
| 188 | // Unverifiable version: a deny blocks, an allow is refused. |
| 189 | if (!trusted.version) { |
| 190 | return failClosed |
| 191 | } |
| 192 | return trusted.version === parsed.fetchSpec |
| 193 | } |
| 194 |
no test coverage detected