sourcecode 1.36.3__tar.gz → 1.36.5__tar.gz
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-1.36.3 → sourcecode-1.36.5}/PKG-INFO +33 -5
- {sourcecode-1.36.3 → sourcecode-1.36.5}/README.md +32 -4
- {sourcecode-1.36.3 → sourcecode-1.36.5}/pyproject.toml +1 -1
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/__init__.py +1 -1
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/repository_ir.py +86 -16
- {sourcecode-1.36.3 → sourcecode-1.36.5}/.github/workflows/build-windows.yml +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/.gitignore +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/.ruff.toml +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/CHANGELOG.md +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/CONTRIBUTING.md +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/LICENSE +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/SECURITY.md +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/raw +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/adaptive_scanner.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/architecture_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/architecture_summary.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/ast_extractor.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/cache.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/canonical_ir.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/cir_graphs.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/classifier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/cli.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/code_notes_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/confidence_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/context_scorer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/context_summarizer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/contract_model.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/contract_pipeline.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/coverage_parser.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/dependency_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/__init__.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/base.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/csproj_parser.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/dart.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/dotnet.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/elixir.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/go.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/heuristic.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/hybrid.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/java.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/jvm_ext.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/nodejs.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/parsers.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/php.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/project.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/python.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/ruby.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/rust.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/systems.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/terraform.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/detectors/tooling.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/doc_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/entrypoint_classifier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/env_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/error_schema.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/explain.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/file_chunker.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/file_classifier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/flow_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/fqn_utils.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/git_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/graph_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/license.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/__init__.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/onboarding/__init__.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/onboarding/applier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/onboarding/backup.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/onboarding/detector.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/onboarding/planner.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/orchestrator.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/registry.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/runner.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp/server.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/mcp_nudge.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/metrics_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/migrate_check.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/output_budget.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/path_filters.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/pr_comment_renderer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/pr_impact.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/prepare_context.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/progress.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/ranking_engine.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/redactor.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/relevance_scorer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/rename_refactor.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/repo_classifier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/ris.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/runtime_classifier.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/scanner.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/schema.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/security_config.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/semantic_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/serializer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_event_topology.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_findings.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_impact.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_model.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_security_audit.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_semantic.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/spring_tx_analyzer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/summarizer.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/__init__.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/config.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/consent.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/events.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/filters.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/telemetry/transport.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/tree_utils.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/version_check.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/src/sourcecode/workspace.py +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/.temp/cli-latest +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/functions/README.md +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/functions/get-license/index.ts +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/functions/lemonsqueezy-webhook/index.ts +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/functions/telemetry/index.ts +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/sql/license_event_ordering.sql +0 -0
- {sourcecode-1.36.3 → sourcecode-1.36.5}/supabase/sql/telemetry_events.sql +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.36.
|
|
3
|
+
Version: 1.36.5
|
|
4
4
|
Summary: Persistent structural context and ultra-fast repeated analysis for AI coding agents
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Keywords: agents,ai,codebase,context,developer-tools,llm
|
|
@@ -40,8 +40,8 @@ Description-Content-Type: text/markdown
|
|
|
40
40
|
|
|
41
41
|
**Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
|
|
42
42
|
|
|
43
|
-

|
|
44
|
+

|
|
45
45
|
|
|
46
46
|
---
|
|
47
47
|
|
|
@@ -114,7 +114,7 @@ pipx install sourcecode
|
|
|
114
114
|
|
|
115
115
|
```bash
|
|
116
116
|
sourcecode version
|
|
117
|
-
# sourcecode 1.36.
|
|
117
|
+
# sourcecode 1.36.5
|
|
118
118
|
```
|
|
119
119
|
|
|
120
120
|
---
|
|
@@ -283,7 +283,7 @@ Specifically:
|
|
|
283
283
|
- Architecture pattern detection best for Spring MVC layered apps; SPI/plugin architectures (e.g. Quarkus extension model) may be misclassified
|
|
284
284
|
- Endpoint recall for JAX-RS subresource locator pattern is ~65%
|
|
285
285
|
- `impact` on implementation classes (e.g. `OrderServiceImpl`) returns 0 callers in Spring Boot — callers inject the interface via `@Autowired`. Always target the interface. When `direct_callers: []` with `confidence_level: high` for a `@Service` class, re-query the interface.
|
|
286
|
-
- `no_security_signal` on endpoints means no method-level
|
|
286
|
+
- `no_security_signal` on endpoints means no recognized method-level annotation found — does **not** mean the endpoint is unsecured. Projects using Spring Security filter chains show 100% `no_security_signal` even when fully secured. Projects using a custom authorization annotation can teach the scanner via [`sourcecode.config.json`](#sourcecodeconfigjson-repo-root).
|
|
287
287
|
- `spring-audit` and `impact-chain` are **Java/Spring only** — non-Java repos return `spring_detected: false`
|
|
288
288
|
- Event topology via `--type events` does not resolve Kafka/RabbitMQ/Redis message routes — only Spring ApplicationEvent and `@EventListener` chains
|
|
289
289
|
- Self-invocation TX bypass (calling `@Transactional` method from the same class without going through the proxy) is not detected
|
|
@@ -411,6 +411,8 @@ Detects structural Spring anomalies that survive code review and tests, but caus
|
|
|
411
411
|
|
|
412
412
|
Returns structured findings with `severity`, `confidence`, `symbol`, `source_file`, `evidence`, `explanation`, and `fix_hint`. JAVA/SPRING ONLY.
|
|
413
413
|
|
|
414
|
+
Endpoints guarded by a project-specific authorization annotation are treated as secured (not flagged `SEC-001`) once declared in [`sourcecode.config.json`](#sourcecodeconfigjson-repo-root).
|
|
415
|
+
|
|
414
416
|
### `impact-chain` — systemic blast radius with TX/SEC enrichment [free]
|
|
415
417
|
|
|
416
418
|
```bash
|
|
@@ -716,3 +718,29 @@ Or: `export SOURCECODE_TELEMETRY=0`
|
|
|
716
718
|
```bash
|
|
717
719
|
sourcecode config # show version, config file path, telemetry status
|
|
718
720
|
```
|
|
721
|
+
|
|
722
|
+
### `sourcecode.config.json` (repo root)
|
|
723
|
+
|
|
724
|
+
Optional, per-repo. Loaded from the root of the repo being analyzed. Absent or
|
|
725
|
+
malformed config is ignored — the tool behaves exactly as without it.
|
|
726
|
+
|
|
727
|
+
**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain`
|
|
728
|
+
about project-specific authorization annotations (otherwise reported as
|
|
729
|
+
`policy: "none_detected"`):
|
|
730
|
+
|
|
731
|
+
```json
|
|
732
|
+
{
|
|
733
|
+
"customSecurityAnnotations": [
|
|
734
|
+
{
|
|
735
|
+
"fullyQualifiedName": "com.example.security.M3FiltroSeguridad",
|
|
736
|
+
"shortName": "M3FiltroSeguridad",
|
|
737
|
+
"resourceParam": "nombreRecurso",
|
|
738
|
+
"levelParam": "nivelRequerido"
|
|
739
|
+
}
|
|
740
|
+
]
|
|
741
|
+
}
|
|
742
|
+
```
|
|
743
|
+
|
|
744
|
+
`resourceParam` / `levelParam` are optional and name the annotation attributes to
|
|
745
|
+
surface as `resourceName` / `requiredLevel`. Matching endpoints report
|
|
746
|
+
`policy: "custom"` and drop out of the `no_security_signal` count.
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
**Persistent structural context and ultra-fast repeated analysis for AI coding agents.**
|
|
4
4
|
|
|
5
|
-

|
|
6
|
+

|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
|
@@ -76,7 +76,7 @@ pipx install sourcecode
|
|
|
76
76
|
|
|
77
77
|
```bash
|
|
78
78
|
sourcecode version
|
|
79
|
-
# sourcecode 1.36.
|
|
79
|
+
# sourcecode 1.36.5
|
|
80
80
|
```
|
|
81
81
|
|
|
82
82
|
---
|
|
@@ -245,7 +245,7 @@ Specifically:
|
|
|
245
245
|
- Architecture pattern detection best for Spring MVC layered apps; SPI/plugin architectures (e.g. Quarkus extension model) may be misclassified
|
|
246
246
|
- Endpoint recall for JAX-RS subresource locator pattern is ~65%
|
|
247
247
|
- `impact` on implementation classes (e.g. `OrderServiceImpl`) returns 0 callers in Spring Boot — callers inject the interface via `@Autowired`. Always target the interface. When `direct_callers: []` with `confidence_level: high` for a `@Service` class, re-query the interface.
|
|
248
|
-
- `no_security_signal` on endpoints means no method-level
|
|
248
|
+
- `no_security_signal` on endpoints means no recognized method-level annotation found — does **not** mean the endpoint is unsecured. Projects using Spring Security filter chains show 100% `no_security_signal` even when fully secured. Projects using a custom authorization annotation can teach the scanner via [`sourcecode.config.json`](#sourcecodeconfigjson-repo-root).
|
|
249
249
|
- `spring-audit` and `impact-chain` are **Java/Spring only** — non-Java repos return `spring_detected: false`
|
|
250
250
|
- Event topology via `--type events` does not resolve Kafka/RabbitMQ/Redis message routes — only Spring ApplicationEvent and `@EventListener` chains
|
|
251
251
|
- Self-invocation TX bypass (calling `@Transactional` method from the same class without going through the proxy) is not detected
|
|
@@ -373,6 +373,8 @@ Detects structural Spring anomalies that survive code review and tests, but caus
|
|
|
373
373
|
|
|
374
374
|
Returns structured findings with `severity`, `confidence`, `symbol`, `source_file`, `evidence`, `explanation`, and `fix_hint`. JAVA/SPRING ONLY.
|
|
375
375
|
|
|
376
|
+
Endpoints guarded by a project-specific authorization annotation are treated as secured (not flagged `SEC-001`) once declared in [`sourcecode.config.json`](#sourcecodeconfigjson-repo-root).
|
|
377
|
+
|
|
376
378
|
### `impact-chain` — systemic blast radius with TX/SEC enrichment [free]
|
|
377
379
|
|
|
378
380
|
```bash
|
|
@@ -678,3 +680,29 @@ Or: `export SOURCECODE_TELEMETRY=0`
|
|
|
678
680
|
```bash
|
|
679
681
|
sourcecode config # show version, config file path, telemetry status
|
|
680
682
|
```
|
|
683
|
+
|
|
684
|
+
### `sourcecode.config.json` (repo root)
|
|
685
|
+
|
|
686
|
+
Optional, per-repo. Loaded from the root of the repo being analyzed. Absent or
|
|
687
|
+
malformed config is ignored — the tool behaves exactly as without it.
|
|
688
|
+
|
|
689
|
+
**Custom security annotations.** Teach `endpoints`, `spring-audit`, and `explain`
|
|
690
|
+
about project-specific authorization annotations (otherwise reported as
|
|
691
|
+
`policy: "none_detected"`):
|
|
692
|
+
|
|
693
|
+
```json
|
|
694
|
+
{
|
|
695
|
+
"customSecurityAnnotations": [
|
|
696
|
+
{
|
|
697
|
+
"fullyQualifiedName": "com.example.security.M3FiltroSeguridad",
|
|
698
|
+
"shortName": "M3FiltroSeguridad",
|
|
699
|
+
"resourceParam": "nombreRecurso",
|
|
700
|
+
"levelParam": "nivelRequerido"
|
|
701
|
+
}
|
|
702
|
+
]
|
|
703
|
+
}
|
|
704
|
+
```
|
|
705
|
+
|
|
706
|
+
`resourceParam` / `levelParam` are optional and name the annotation attributes to
|
|
707
|
+
surface as `resourceName` / `requiredLevel`. Matching endpoints report
|
|
708
|
+
`policy: "custom"` and drop out of the `no_security_signal` count.
|
|
@@ -486,6 +486,31 @@ def _normalize_type_name(raw: str) -> str:
|
|
|
486
486
|
return raw.strip()
|
|
487
487
|
|
|
488
488
|
|
|
489
|
+
def _split_supertype_list(raw: str) -> list[str]:
|
|
490
|
+
"""Split an ``extends``/``implements`` clause into individual base type names.
|
|
491
|
+
|
|
492
|
+
Handles multiple supertypes (interfaces may extend several) and strips generic
|
|
493
|
+
type arguments *before* splitting so that commas inside ``<...>`` do not corrupt
|
|
494
|
+
the result. e.g. ``"VetRepository, Repository<Vet, Integer>"`` → ``["VetRepository",
|
|
495
|
+
"Repository"]``.
|
|
496
|
+
"""
|
|
497
|
+
if not raw or not raw.strip():
|
|
498
|
+
return []
|
|
499
|
+
# Iteratively remove (possibly nested) generic parameters so any commas they
|
|
500
|
+
# contain are gone before we split on the top-level commas.
|
|
501
|
+
prev = None
|
|
502
|
+
stripped = raw
|
|
503
|
+
while prev != stripped:
|
|
504
|
+
prev = stripped
|
|
505
|
+
stripped = re.sub(r'<[^<>]*>', '', stripped)
|
|
506
|
+
bases: list[str] = []
|
|
507
|
+
for piece in stripped.split(","):
|
|
508
|
+
base = re.sub(r'<.*', '', piece).strip()
|
|
509
|
+
if base:
|
|
510
|
+
bases.append(base)
|
|
511
|
+
return bases
|
|
512
|
+
|
|
513
|
+
|
|
489
514
|
def _parse_param_types(params_str: str) -> list[str]:
|
|
490
515
|
"""Parse "(Long id, @Valid String name)" → ["Long", "String"].
|
|
491
516
|
|
|
@@ -1166,29 +1191,29 @@ def _build_relations(
|
|
|
1166
1191
|
class_fqn = f"{package}.{name}" if package else name
|
|
1167
1192
|
|
|
1168
1193
|
if extends_str:
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1194
|
+
# An interface may extend multiple interfaces (e.g.
|
|
1195
|
+
# `extends VetRepository, Repository<Vet, Integer>`); split on top-level
|
|
1196
|
+
# commas so each base produces its own edge and the reverse graph sees
|
|
1197
|
+
# every supertype (not a single mangled token).
|
|
1198
|
+
for base in _split_supertype_list(extends_str):
|
|
1199
|
+
to = import_map.get(base, base)
|
|
1200
|
+
edges.append(RelationEdge(
|
|
1201
|
+
from_symbol=class_fqn,
|
|
1202
|
+
to_symbol=to,
|
|
1203
|
+
type="extends",
|
|
1204
|
+
confidence="high",
|
|
1205
|
+
evidence={"type": "signature", "value": f"extends {extends_str}"},
|
|
1206
|
+
))
|
|
1178
1207
|
|
|
1179
1208
|
if implements_str:
|
|
1180
|
-
for
|
|
1181
|
-
iface = iface.strip()
|
|
1182
|
-
base = re.sub(r'<.*', '', iface).strip()
|
|
1183
|
-
if not base:
|
|
1184
|
-
continue
|
|
1209
|
+
for base in _split_supertype_list(implements_str):
|
|
1185
1210
|
to = import_map.get(base, base)
|
|
1186
1211
|
edges.append(RelationEdge(
|
|
1187
1212
|
from_symbol=class_fqn,
|
|
1188
1213
|
to_symbol=to,
|
|
1189
1214
|
type="implements",
|
|
1190
1215
|
confidence="high",
|
|
1191
|
-
evidence={"type": "signature", "value": f"implements {
|
|
1216
|
+
evidence={"type": "signature", "value": f"implements {base}"},
|
|
1192
1217
|
))
|
|
1193
1218
|
|
|
1194
1219
|
# mapped_to edges: controller class → class-level @RequestMapping path prefix.
|
|
@@ -2973,6 +2998,11 @@ def build_repo_ir(
|
|
|
2973
2998
|
'@Aspect', '@Aggregate', '@Document',
|
|
2974
2999
|
# Spring Data
|
|
2975
3000
|
'@Query', '@NamedQuery',
|
|
3001
|
+
# Profile-gated beans/interfaces (e.g. Spring Data repository specializations
|
|
3002
|
+
# like `@Profile("spring-data-jpa") interface FooRepo extends FooRepository`).
|
|
3003
|
+
# Without this marker such interfaces are pre-scan-skipped and their
|
|
3004
|
+
# extends/implements edges are lost — making them invisible to impact analysis.
|
|
3005
|
+
'@Profile',
|
|
2976
3006
|
)
|
|
2977
3007
|
# Pre-pass: collect custom meta-annotation names from @interface definitions
|
|
2978
3008
|
# that compose known Spring stereotypes (e.g. @DomainService = @Service + @Transactional).
|
|
@@ -3517,6 +3547,40 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
3517
3547
|
"note": "interface-based Spring MVC controller — URL mapped via XML",
|
|
3518
3548
|
})
|
|
3519
3549
|
|
|
3550
|
+
# Detect controllers whose HTTP mappings live on an IMPLEMENTED interface that is
|
|
3551
|
+
# not part of the scanned source surface. The dominant case is openapi-generator
|
|
3552
|
+
# "interface-only" output (e.g. PetV2Api, VetsApi) emitted under
|
|
3553
|
+
# target/generated-sources, which the scanner excludes. Such a controller carries
|
|
3554
|
+
# @RestController/@Controller and an `implements XxxApi` clause but contributes no
|
|
3555
|
+
# method-level routes, so its endpoints are invisible. Emit an explicit warning so
|
|
3556
|
+
# an empty/partial surface is not silently misread as "no endpoints / no security".
|
|
3557
|
+
_CONTROLLER_ANNS = {"@RestController", "@Controller"}
|
|
3558
|
+
_IMPLEMENTS_RE = _re.compile(r'\bimplements\s+(.+)$')
|
|
3559
|
+
_routed_fqns = {route.get("effective_class") for route in routes}
|
|
3560
|
+
interface_defined_controllers: list[str] = []
|
|
3561
|
+
endpoint_warnings: list[str] = []
|
|
3562
|
+
for sym in all_symbols:
|
|
3563
|
+
if sym.type != "class":
|
|
3564
|
+
continue
|
|
3565
|
+
if not (_CONTROLLER_ANNS & set(sym.annotations)):
|
|
3566
|
+
continue
|
|
3567
|
+
if sym.symbol in _routed_fqns:
|
|
3568
|
+
continue # already contributes routes — surface is captured
|
|
3569
|
+
m = _IMPLEMENTS_RE.search(sym.signature or "")
|
|
3570
|
+
if not m:
|
|
3571
|
+
continue
|
|
3572
|
+
ifaces = _split_supertype_list(m.group(1))
|
|
3573
|
+
api_ifaces = [i for i in ifaces if i.endswith("Api")]
|
|
3574
|
+
if not api_ifaces:
|
|
3575
|
+
continue
|
|
3576
|
+
interface_defined_controllers.append(sym.symbol)
|
|
3577
|
+
endpoint_warnings.append(
|
|
3578
|
+
f"{sym.symbol.split('.')[-1]} implements {', '.join(api_ifaces)}: HTTP "
|
|
3579
|
+
"mappings are declared on the implemented interface (commonly generated by "
|
|
3580
|
+
"openapi-generator under target/generated-sources, which is not scanned). "
|
|
3581
|
+
"Endpoint surface for this controller is NOT captured."
|
|
3582
|
+
)
|
|
3583
|
+
|
|
3520
3584
|
endpoints: list[dict] = []
|
|
3521
3585
|
for route in routes:
|
|
3522
3586
|
handler = (
|
|
@@ -3643,7 +3707,7 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
3643
3707
|
if e.get("security", {}).get("policy") == "none_detected"
|
|
3644
3708
|
)
|
|
3645
3709
|
|
|
3646
|
-
|
|
3710
|
+
result: dict[str, Any] = {
|
|
3647
3711
|
"endpoints": endpoints,
|
|
3648
3712
|
"total": len(endpoints),
|
|
3649
3713
|
"no_security_signal": no_security_signal,
|
|
@@ -3651,6 +3715,12 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
3651
3715
|
# Keep legacy field name for backward compat, now means same as no_security_signal
|
|
3652
3716
|
"undocumented": no_security_signal,
|
|
3653
3717
|
}
|
|
3718
|
+
# Surface incomplete-endpoint warnings (interface-defined controllers) only when
|
|
3719
|
+
# present, to keep output backward-compatible for the common case.
|
|
3720
|
+
if endpoint_warnings:
|
|
3721
|
+
result["warnings"] = endpoint_warnings
|
|
3722
|
+
result["interface_defined_controllers"] = interface_defined_controllers
|
|
3723
|
+
return result
|
|
3654
3724
|
|
|
3655
3725
|
|
|
3656
3726
|
def find_java_files(root: Path, *, max_files: int = 8000, limitations: list[str] | None = None) -> list[str]:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|