sourcecode 3.1.1__py3-none-any.whl → 3.2.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of sourcecode might be problematic. Click here for more details.

sourcecode/__init__.py CHANGED
@@ -4,4 +4,4 @@ ASK Engine is the product. ``ask`` is the canonical CLI command; ``sourcecode``
4
4
  the legacy compatibility alias and the Python/PyPI package name. See
5
5
  docs/PRODUCT_IDENTITY.md (normative)."""
6
6
 
7
- __version__ = "3.1.1"
7
+ __version__ = "3.2.1"
sourcecode/chain_rules.py CHANGED
@@ -274,16 +274,57 @@ def rule_matches(rule: AccessRule, method: str, path: str) -> bool:
274
274
  return any(ant_matches(pattern, path) for pattern in rule.patterns)
275
275
 
276
276
 
277
- def first_matching_rule(
278
- rules: "list[AccessRule]", method: str, path: str
279
- ) -> "Optional[AccessRule]":
280
- """The rule Spring would apply: the first declared one that matches."""
277
+ #: Matchers that see the DispatcherServlet path. An ant matcher matches the URL
278
+ #: the filter chain receives — servlet path included, servlet CONTEXT path never,
279
+ #: because the container has already stripped it. An mvc matcher matches the path
280
+ #: relative to the servlet mapping, so the servlet path is not part of it.
281
+ #: `requestMatchers` is either one depending on the Spring Security version and
282
+ #: what is on the classpath — undecidable from source, so both readings are tried
283
+ #: and the pattern is honoured if it covers the request under either.
284
+ _SERVLET_PATH_MATCHERS = ("antMatchers", "regexMatchers", "requestMatchers")
285
+ _SERVLET_RELATIVE_MATCHERS = ("mvcMatchers", "requestMatchers")
286
+
287
+
288
+ def candidate_paths(rule: AccessRule, path: str, servlet_prefix: str = "") -> "tuple[str, ...]":
289
+ """The path(s) `rule`'s matcher compares against a mapping-relative `path`.
290
+
291
+ Without a declared servlet path the two readings coincide and this is just
292
+ `(path,)` — which is every repository that never set `spring.mvc.servlet.path`.
293
+ """
294
+ if not servlet_prefix or rule.is_any_request:
295
+ return (path,)
296
+ prefixed = f"{servlet_prefix.rstrip('/')}/{path.lstrip('/')}".rstrip("/") or "/"
297
+ out: list[str] = []
298
+ if rule.matcher in _SERVLET_PATH_MATCHERS:
299
+ out.append(prefixed)
300
+ if rule.matcher in _SERVLET_RELATIVE_MATCHERS or not out:
301
+ out.append(path)
302
+ return tuple(dict.fromkeys(out))
303
+
304
+
305
+ def first_match(
306
+ rules: "list[AccessRule]", method: str, path: str, servlet_prefix: str = ""
307
+ ) -> "tuple[Optional[AccessRule], str]":
308
+ """`(rule Spring would apply, the path it matched)` — first declared wins.
309
+
310
+ The matched path is returned because with a servlet path declared it is not
311
+ the mapping-relative path the endpoint is keyed by, and a reader checking the
312
+ claim against the source line needs to see the URL the rule actually covers.
313
+ """
281
314
  for rule in rules:
282
315
  if rule.paths_unknown:
283
316
  # A rule whose paths could not be read may cover this request, and
284
317
  # everything after it is only reachable if it does not. Stopping here
285
318
  # is what keeps a later `permitAll` from being reported as the answer.
286
- return rule
287
- if rule_matches(rule, method, path):
288
- return rule
289
- return None
319
+ return rule, path
320
+ for candidate in candidate_paths(rule, path, servlet_prefix):
321
+ if rule_matches(rule, method, candidate):
322
+ return rule, candidate
323
+ return None, path
324
+
325
+
326
+ def first_matching_rule(
327
+ rules: "list[AccessRule]", method: str, path: str, servlet_prefix: str = ""
328
+ ) -> "Optional[AccessRule]":
329
+ """The rule Spring would apply: the first declared one that matches."""
330
+ return first_match(rules, method, path, servlet_prefix)[0]