sourcecode 2.5.17__py3-none-any.whl → 2.5.18__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.
- sourcecode/__init__.py +1 -1
- sourcecode/validation_surface.py +128 -0
- {sourcecode-2.5.17.dist-info → sourcecode-2.5.18.dist-info}/METADATA +1 -1
- {sourcecode-2.5.17.dist-info → sourcecode-2.5.18.dist-info}/RECORD +7 -7
- {sourcecode-2.5.17.dist-info → sourcecode-2.5.18.dist-info}/WHEEL +0 -0
- {sourcecode-2.5.17.dist-info → sourcecode-2.5.18.dist-info}/entry_points.txt +0 -0
- {sourcecode-2.5.17.dist-info → sourcecode-2.5.18.dist-info}/licenses/LICENSE +0 -0
sourcecode/__init__.py
CHANGED
sourcecode/validation_surface.py
CHANGED
|
@@ -363,6 +363,98 @@ def _recover_source_endpoints(
|
|
|
363
363
|
return routes, total
|
|
364
364
|
|
|
365
365
|
|
|
366
|
+
def _recover_spec_endpoints(
|
|
367
|
+
root: Path,
|
|
368
|
+
existing_keys: "set[tuple[Any, Any]]",
|
|
369
|
+
catalog: "dict[str, Any]",
|
|
370
|
+
custom_used: "set[str]",
|
|
371
|
+
) -> "tuple[Optional[str], list[dict[str, Any]], int]":
|
|
372
|
+
"""Recover validation routes from a standalone OpenAPI spec on disk.
|
|
373
|
+
|
|
374
|
+
F1: ``extract_java_endpoints`` only links a spec when an openapi-generator
|
|
375
|
+
interface-controller (``@RestController implements XxxApi``) matches it. A
|
|
376
|
+
repo that ships a plain ``openapi.yml`` with no such controller therefore
|
|
377
|
+
reported "No OpenAPI spec found" — a confirmed false negative. This consults
|
|
378
|
+
the existing :func:`build_openapi_surface` producer directly so a discovered
|
|
379
|
+
spec's body operations contribute their declared constraints and flip the
|
|
380
|
+
"no spec" claim.
|
|
381
|
+
|
|
382
|
+
Returns ``(spec_path, routes, validated_field_count)``; ``spec_path`` is None
|
|
383
|
+
when no parseable spec with operations is present.
|
|
384
|
+
"""
|
|
385
|
+
from sourcecode.openapi_surface import build_openapi_surface
|
|
386
|
+
|
|
387
|
+
surface = build_openapi_surface(root)
|
|
388
|
+
if surface is None or not surface.operations:
|
|
389
|
+
return None, [], 0
|
|
390
|
+
|
|
391
|
+
routes: "list[dict[str, Any]]" = []
|
|
392
|
+
total = 0
|
|
393
|
+
for op in surface.operations:
|
|
394
|
+
if str(op.method).upper() not in ("POST", "PUT", "PATCH"):
|
|
395
|
+
continue
|
|
396
|
+
key = (op.method, op.path)
|
|
397
|
+
if key in existing_keys:
|
|
398
|
+
continue # already surfaced from source — dedupe by method+path
|
|
399
|
+
schema = surface.schemas.get(op.request_body_schema) if op.request_body_schema else None
|
|
400
|
+
constraints = [f.to_dict() for f in schema.fields] if schema is not None else []
|
|
401
|
+
validated = _validated_fields_from_constraints(constraints, catalog, custom_used)
|
|
402
|
+
total += len(validated)
|
|
403
|
+
route: "dict[str, Any]" = {
|
|
404
|
+
"method": op.method,
|
|
405
|
+
"path": op.path,
|
|
406
|
+
"controller": None,
|
|
407
|
+
"handler": op.operation_id or "(operation)",
|
|
408
|
+
"schema": op.request_body_schema,
|
|
409
|
+
"source": "openapi-spec",
|
|
410
|
+
"confidence": "high",
|
|
411
|
+
"validatedFields": validated,
|
|
412
|
+
}
|
|
413
|
+
routes.append(route)
|
|
414
|
+
existing_keys.add(key)
|
|
415
|
+
return surface.spec_path, routes, total
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def _validated_fields_from_constraints(
|
|
419
|
+
constraints: "list[Any]",
|
|
420
|
+
catalog: "dict[str, Any]",
|
|
421
|
+
custom_used: "set[str]",
|
|
422
|
+
) -> "list[dict[str, Any]]":
|
|
423
|
+
"""Render a schema's constraint dicts into ``validatedFields`` entries.
|
|
424
|
+
|
|
425
|
+
Mirrors the built-in-rule + custom-validator linkage the main loop applies to
|
|
426
|
+
OpenAPI request bodies; shared so the standalone-spec path (F1) stays byte-
|
|
427
|
+
consistent with the interface-controller path."""
|
|
428
|
+
out: "list[dict[str, Any]]" = []
|
|
429
|
+
for fc in constraints:
|
|
430
|
+
if not isinstance(fc, dict):
|
|
431
|
+
continue
|
|
432
|
+
rules = _field_rules(fc)
|
|
433
|
+
customs: "list[dict[str, Any]]" = []
|
|
434
|
+
for ann in fc.get("extraAnnotations", []) or []:
|
|
435
|
+
cc = catalog.get(ann)
|
|
436
|
+
entry: "dict[str, Any]" = {"annotation": ann}
|
|
437
|
+
if cc is not None:
|
|
438
|
+
custom_used.add(ann)
|
|
439
|
+
if cc.validators:
|
|
440
|
+
entry["validators"] = cc.validators
|
|
441
|
+
if cc.message is not None:
|
|
442
|
+
entry["message"] = cc.message
|
|
443
|
+
entry["resolved"] = True
|
|
444
|
+
else:
|
|
445
|
+
entry["resolved"] = False
|
|
446
|
+
customs.append(entry)
|
|
447
|
+
if not rules and not customs:
|
|
448
|
+
continue
|
|
449
|
+
field_entry: "dict[str, Any]" = {"name": fc.get("name")}
|
|
450
|
+
if rules:
|
|
451
|
+
field_entry["rules"] = rules
|
|
452
|
+
if customs:
|
|
453
|
+
field_entry["customValidators"] = customs
|
|
454
|
+
out.append(field_entry)
|
|
455
|
+
return out
|
|
456
|
+
|
|
457
|
+
|
|
366
458
|
def _field_rules(fieldc: "dict[str, Any]") -> "list[dict[str, Any]]":
|
|
367
459
|
"""Render a constraint dict's built-in rules as a list of {kind, value}."""
|
|
368
460
|
rules: "list[dict[str, Any]]" = []
|
|
@@ -491,6 +583,36 @@ def build_validation_surface(
|
|
|
491
583
|
if spec_path:
|
|
492
584
|
result["openapi_spec"] = spec_path
|
|
493
585
|
else:
|
|
586
|
+
# No spec linked by extract_java_endpoints (no openapi-generator
|
|
587
|
+
# interface-controller matched). F1: consult the standalone-spec
|
|
588
|
+
# producer directly — a plain openapi.yml shipped in the repo is a real
|
|
589
|
+
# spec, so its body operations contribute constraints and flip the
|
|
590
|
+
# "no spec found" claim instead of reporting a false negative.
|
|
591
|
+
existing_keys = {(r.get("method"), r.get("path")) for r in out_endpoints}
|
|
592
|
+
spec_path2, spec_routes, spec_fields = _recover_spec_endpoints(
|
|
593
|
+
root, existing_keys, catalog, custom_used
|
|
594
|
+
)
|
|
595
|
+
if spec_path2 is not None:
|
|
596
|
+
result["openapi_spec"] = spec_path2
|
|
597
|
+
out_endpoints.extend(spec_routes)
|
|
598
|
+
total_validated_fields += spec_fields
|
|
599
|
+
spec_keys = {(r.get("method"), r.get("path")) for r in spec_routes}
|
|
600
|
+
gaps = [g for g in gaps if (g.get("method"), g.get("path")) not in spec_keys]
|
|
601
|
+
result["endpoints"] = out_endpoints
|
|
602
|
+
result["gaps"] = gaps
|
|
603
|
+
result["custom_validators"] = [catalog[k].to_dict() for k in sorted(catalog)]
|
|
604
|
+
result["summary"]["endpoints_with_body"] = len(out_endpoints)
|
|
605
|
+
result["summary"]["validated_fields"] = total_validated_fields
|
|
606
|
+
result["summary"]["custom_validators_linked"] = len(custom_used)
|
|
607
|
+
result["summary"]["gaps"] = len(gaps)
|
|
608
|
+
result["summary"]["spec_derived_routes"] = len(spec_routes)
|
|
609
|
+
result["note"] = (
|
|
610
|
+
"OpenAPI spec discovered on disk (standalone, not linked to a "
|
|
611
|
+
"generated interface-controller); body operations contributed "
|
|
612
|
+
"their declared constraints. Response shapes and non-body "
|
|
613
|
+
"operations are not modeled here."
|
|
614
|
+
)
|
|
615
|
+
return result
|
|
494
616
|
# No OpenAPI spec on disk / under target/generated-sources. Recover
|
|
495
617
|
# declarative constraints from the graph's DTO field nodes (bean-
|
|
496
618
|
# validation annotations on @Valid/@Validated handler bodies), so a
|
|
@@ -525,6 +647,12 @@ def build_validation_surface(
|
|
|
525
647
|
"partial; OpenAPI-carried constraints would be more complete."
|
|
526
648
|
)
|
|
527
649
|
else:
|
|
650
|
+
# Genuine absence — no spec on disk AND no in-repo DTO constraints.
|
|
651
|
+
# Emit a machine-readable zero_result_reason (F1) so a consumer can
|
|
652
|
+
# tell "we looked and found nothing" from "we did not look": an empty
|
|
653
|
+
# surface here is an attested negative, not a missing-validation
|
|
654
|
+
# finding.
|
|
655
|
+
result["zero_result_reason"] = "no_openapi_spec_and_no_source_dto_constraints"
|
|
528
656
|
result["note"] = (
|
|
529
657
|
"No OpenAPI spec found and no source DTO constraints recovered "
|
|
530
658
|
"(no handler validates an in-repo DTO via @Valid/@Validated, or "
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
sourcecode/__init__.py,sha256=
|
|
1
|
+
sourcecode/__init__.py,sha256=wslvpdjMsUV-sx7b3v1cpnzhBqIUNoLGcCwm8IheiSM,309
|
|
2
2
|
sourcecode/adaptive_scanner.py,sha256=yJBKjNpkY6bpueYJ2YnRezen3sYZDecEt7WaaNWdqug,9466
|
|
3
3
|
sourcecode/archetype.py,sha256=d7yoN6Tj4OBj-VgSMPEKg4WF9H8FypnZ5A6AkUh5oIE,34484
|
|
4
4
|
sourcecode/architecture_analyzer.py,sha256=GFc4ek-s1IHWM7pl-0L32WahZ93AmDgrAMcOuBKA5Dk,61463
|
|
@@ -80,7 +80,7 @@ sourcecode/summarizer.py,sha256=sr0-tfecFKCr-fSkPPWbl-t9HC7SY2ZxkjnnXX8DB2A,2662
|
|
|
80
80
|
sourcecode/tree_utils.py,sha256=8GAkIfQAsvtEudIeW1l4ooH_oRtrWR8cpJQJsEa_Pfw,2093
|
|
81
81
|
sourcecode/type_usage_surface.py,sha256=51IrKRQoIoRnlsiDjHnqpJBn2rc6E59aRhgS0HTzAF0,4428
|
|
82
82
|
sourcecode/validation_inference.py,sha256=UtmYv-d4TEzT1ihGEipAhtXDrwq0XtVtjMpb3i7NsNc,10815
|
|
83
|
-
sourcecode/validation_surface.py,sha256=
|
|
83
|
+
sourcecode/validation_surface.py,sha256=A0-FVswL__XOcw92wvIwghwLq5AWtIm2kzO3RjEb1b4,27325
|
|
84
84
|
sourcecode/version_check.py,sha256=CHp6ZxTIfo8kyHPCBgJA1uFC0xQCoXMuuOfrW8QTL8o,4942
|
|
85
85
|
sourcecode/workspace.py,sha256=X_6NmNnitvT3_38V-JDChydo_sR68s249hLFlrQskU0,8271
|
|
86
86
|
sourcecode/detectors/__init__.py,sha256=A0AACJFF6HWf_RgatNtWu3PUzstcKtIGM9f1PoFcJug,1987
|
|
@@ -138,8 +138,8 @@ sourcecode/telemetry/consent.py,sha256=LIAO9ohJZF8OuZwM4u1VWtALlYfTCCKq4wV3Vwc7i
|
|
|
138
138
|
sourcecode/telemetry/events.py,sha256=LtzYfaX9Ilckj5PTvAcTpDa9mLqDsYPDUiDkRa58piY,2580
|
|
139
139
|
sourcecode/telemetry/filters.py,sha256=NHa5T-6DaZduQPFuC34jOqHWQgSizM-Ygq8aZ4j19ng,5834
|
|
140
140
|
sourcecode/telemetry/transport.py,sha256=4gGHsq0WeY9VywEZXA3vUxykfiYnw9uuqfjAAec7F8o,1681
|
|
141
|
-
sourcecode-2.5.
|
|
142
|
-
sourcecode-2.5.
|
|
143
|
-
sourcecode-2.5.
|
|
144
|
-
sourcecode-2.5.
|
|
145
|
-
sourcecode-2.5.
|
|
141
|
+
sourcecode-2.5.18.dist-info/METADATA,sha256=Er3B54p5axMRW7yoIsZmmGYvVCH_uILX7C4ge3mMQj0,10852
|
|
142
|
+
sourcecode-2.5.18.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
143
|
+
sourcecode-2.5.18.dist-info/entry_points.txt,sha256=-JEAdChrK5We51kZcb7OaDcyil-dHBjBPL-NhuO-QY8,89
|
|
144
|
+
sourcecode-2.5.18.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
|
|
145
|
+
sourcecode-2.5.18.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|