sourcecode 1.31.26__py3-none-any.whl → 1.31.27__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/canonical_ir.py +2 -0
- sourcecode/cli.py +4 -0
- sourcecode/mcp/server.py +6 -3
- sourcecode/repository_ir.py +71 -2
- {sourcecode-1.31.26.dist-info → sourcecode-1.31.27.dist-info}/METADATA +3 -3
- {sourcecode-1.31.26.dist-info → sourcecode-1.31.27.dist-info}/RECORD +10 -10
- {sourcecode-1.31.26.dist-info → sourcecode-1.31.27.dist-info}/WHEEL +0 -0
- {sourcecode-1.31.26.dist-info → sourcecode-1.31.27.dist-info}/entry_points.txt +0 -0
- {sourcecode-1.31.26.dist-info → sourcecode-1.31.27.dist-info}/licenses/LICENSE +0 -0
sourcecode/__init__.py
CHANGED
sourcecode/canonical_ir.py
CHANGED
|
@@ -332,6 +332,7 @@ def ir_dict_to_canonical(
|
|
|
332
332
|
"spring_events": ir.get("spring_events") or {},
|
|
333
333
|
"score_basis": (ir.get("impact") or {}).get("score_basis", "none"),
|
|
334
334
|
"reverse_graph_size": len(ir.get("reverse_graph") or {}),
|
|
335
|
+
"security_model": ir.get("security_model", "unknown"),
|
|
335
336
|
}
|
|
336
337
|
|
|
337
338
|
cir_hash = _compute_cir_hash(
|
|
@@ -452,6 +453,7 @@ def project_endpoint_surface(cir: CanonicalRepositoryIR) -> dict:
|
|
|
452
453
|
"endpoints": endpoints,
|
|
453
454
|
"total": len(endpoints),
|
|
454
455
|
"no_security_signal": no_security_signal,
|
|
456
|
+
"security_model": cir.metadata.get("security_model", "unknown"),
|
|
455
457
|
# Legacy field alias — same count, kept for backward compat
|
|
456
458
|
"undocumented": no_security_signal,
|
|
457
459
|
}
|
sourcecode/cli.py
CHANGED
|
@@ -1127,10 +1127,14 @@ def main(
|
|
|
1127
1127
|
|
|
1128
1128
|
# --compact implicitly enables lightweight analysis passes so that
|
|
1129
1129
|
# dependency_summary, env_summary and code_notes_summary are never null.
|
|
1130
|
+
# architecture=True is also enabled so that architecture.confidence is
|
|
1131
|
+
# consistent with --agent (which auto-enables architecture). The
|
|
1132
|
+
# ArchitectureAnalyzer is path-based and adds negligible latency.
|
|
1130
1133
|
if compact:
|
|
1131
1134
|
dependencies = True
|
|
1132
1135
|
env_map = True
|
|
1133
1136
|
code_notes = True
|
|
1137
|
+
architecture = True
|
|
1134
1138
|
|
|
1135
1139
|
dependency_analyzer = DependencyAnalyzer() if dependencies else None
|
|
1136
1140
|
graph_analyzer = GraphAnalyzer() if graph_modules else None
|
sourcecode/mcp/server.py
CHANGED
|
@@ -158,9 +158,12 @@ def get_endpoints(repo_path: str = ".") -> dict:
|
|
|
158
158
|
Returns: endpoints list with method, path, controller, handler fields;
|
|
159
159
|
security dict when authorization annotations are present
|
|
160
160
|
(policy: roles_allowed|permit_all|deny_all|authenticated|...);
|
|
161
|
-
total (int)
|
|
162
|
-
no_security_signal counts endpoints with no recognized auth annotation
|
|
163
|
-
|
|
161
|
+
total (int), no_security_signal (int), and security_model (str) fields.
|
|
162
|
+
no_security_signal counts endpoints with no recognized auth annotation.
|
|
163
|
+
security_model values: "filter_based" (centralized Spring Security config —
|
|
164
|
+
high no_security_signal is expected and does NOT mean endpoints are unprotected),
|
|
165
|
+
"annotation_based" (per-endpoint annotations only), "mixed" (both),
|
|
166
|
+
"unknown" (no security signals detected).
|
|
164
167
|
Supports Spring MVC (@GetMapping etc.) and JAX-RS (@GET/@POST etc.).
|
|
165
168
|
Security annotations detected: @RolesAllowed, @PermitAll, @DenyAll,
|
|
166
169
|
@Authenticated, @PreAuthorize, @Secured, @SecurityRequirement, @M3FiltroSeguridad.
|
sourcecode/repository_ir.py
CHANGED
|
@@ -192,6 +192,15 @@ _SECURITY_MARKER_ANNOTATIONS: frozenset[str] = frozenset({
|
|
|
192
192
|
"@PermitAll", "@DenyAll", "@Authenticated",
|
|
193
193
|
})
|
|
194
194
|
|
|
195
|
+
# Annotations on config classes that indicate a centralized security filter chain
|
|
196
|
+
# (Spring Security / Spring Boot). When present, per-endpoint no_security_signal
|
|
197
|
+
# is expected and does NOT mean endpoints are unprotected.
|
|
198
|
+
_FILTER_SECURITY_ANNOTATIONS: frozenset[str] = frozenset({
|
|
199
|
+
"@EnableWebSecurity",
|
|
200
|
+
"@EnableMethodSecurity",
|
|
201
|
+
"@EnableGlobalMethodSecurity",
|
|
202
|
+
})
|
|
203
|
+
|
|
195
204
|
_MODIFIER_WORDS: frozenset[str] = frozenset({
|
|
196
205
|
"public", "private", "protected", "static", "final", "abstract",
|
|
197
206
|
"synchronized", "native", "strictfp", "transient", "volatile", "default",
|
|
@@ -1711,6 +1720,7 @@ def _detect_subsystems(all_fqns: list[str], relations: list[RelationEdge]) -> li
|
|
|
1711
1720
|
"label": label,
|
|
1712
1721
|
"package_prefix": pkg_prefix,
|
|
1713
1722
|
"member_count": len(members),
|
|
1723
|
+
"members": members,
|
|
1714
1724
|
"summary": summary,
|
|
1715
1725
|
})
|
|
1716
1726
|
return result
|
|
@@ -2132,17 +2142,47 @@ def _assemble(
|
|
|
2132
2142
|
"change_set": change_set_out,
|
|
2133
2143
|
}
|
|
2134
2144
|
|
|
2135
|
-
|
|
2145
|
+
_extends_map = {
|
|
2136
2146
|
e.from_symbol: e.to_symbol.split(".")[-1]
|
|
2137
2147
|
for e in sorted_rels if e.type == "extends"
|
|
2138
|
-
}
|
|
2148
|
+
}
|
|
2149
|
+
_route_surface = _build_route_surface(sorted_syms, route_diffs, extends_map=_extends_map)
|
|
2139
2150
|
_analysis_gaps = _compute_analysis_gaps(sorted_syms, spring_summary, _route_surface, sorted_rels)
|
|
2140
2151
|
|
|
2152
|
+
# Detect filter-based security model for the assembled IR.
|
|
2153
|
+
# Stored here so CIR projections (project_endpoint_surface) can read it without
|
|
2154
|
+
# re-parsing symbols.
|
|
2155
|
+
_class_syms_asm = [s for s in sorted_syms if s.type in ("class", "interface")]
|
|
2156
|
+
_filter_based_asm = (
|
|
2157
|
+
any(
|
|
2158
|
+
ann in _FILTER_SECURITY_ANNOTATIONS
|
|
2159
|
+
for sym in _class_syms_asm
|
|
2160
|
+
for ann in sym.annotations
|
|
2161
|
+
)
|
|
2162
|
+
or any(
|
|
2163
|
+
_extends_map.get(sym.symbol, "") == "WebSecurityConfigurerAdapter"
|
|
2164
|
+
for sym in _class_syms_asm
|
|
2165
|
+
)
|
|
2166
|
+
)
|
|
2167
|
+
_has_ann_sec_asm = any(
|
|
2168
|
+
r.get("security_annotations") for r in _route_surface
|
|
2169
|
+
if isinstance(r, dict)
|
|
2170
|
+
)
|
|
2171
|
+
if _filter_based_asm and _has_ann_sec_asm:
|
|
2172
|
+
_security_model_asm = "mixed"
|
|
2173
|
+
elif _filter_based_asm:
|
|
2174
|
+
_security_model_asm = "filter_based"
|
|
2175
|
+
elif _has_ann_sec_asm:
|
|
2176
|
+
_security_model_asm = "annotation_based"
|
|
2177
|
+
else:
|
|
2178
|
+
_security_model_asm = "unknown"
|
|
2179
|
+
|
|
2141
2180
|
return {
|
|
2142
2181
|
**_base,
|
|
2143
2182
|
"route_surface": _route_surface,
|
|
2144
2183
|
"spring_events": _spring_events,
|
|
2145
2184
|
"analysis_gaps": _analysis_gaps,
|
|
2185
|
+
"security_model": _security_model_asm,
|
|
2146
2186
|
"audit": {
|
|
2147
2187
|
"dropped_fields": dropped_fields,
|
|
2148
2188
|
},
|
|
@@ -2908,10 +2948,39 @@ def extract_java_endpoints(root: Path) -> "dict[str, Any]":
|
|
|
2908
2948
|
# Note: repos may use framework-level security (e.g. Keycloak itself) with no
|
|
2909
2949
|
# per-endpoint annotations — this count reflects annotation-based coverage only.
|
|
2910
2950
|
no_security_signal = sum(1 for e in endpoints if "security" not in e)
|
|
2951
|
+
|
|
2952
|
+
# Detect filter-based security: centralized Spring Security config class.
|
|
2953
|
+
# When present, high no_security_signal is expected — security is enforced by
|
|
2954
|
+
# the filter chain, not per-endpoint annotations.
|
|
2955
|
+
_class_syms = [s for s in all_symbols if s.type in ("class", "interface")]
|
|
2956
|
+
_filter_based = (
|
|
2957
|
+
# Config class annotated with EnableWebSecurity / EnableMethodSecurity
|
|
2958
|
+
any(
|
|
2959
|
+
ann in _FILTER_SECURITY_ANNOTATIONS
|
|
2960
|
+
for sym in _class_syms
|
|
2961
|
+
for ann in sym.annotations
|
|
2962
|
+
)
|
|
2963
|
+
# Class extends WebSecurityConfigurerAdapter (pre-Spring 5.7 style)
|
|
2964
|
+
or any(
|
|
2965
|
+
extends_map.get(sym.symbol, "") == "WebSecurityConfigurerAdapter"
|
|
2966
|
+
for sym in _class_syms
|
|
2967
|
+
)
|
|
2968
|
+
)
|
|
2969
|
+
_has_annotation_security = any("security" in e for e in endpoints)
|
|
2970
|
+
if _filter_based and _has_annotation_security:
|
|
2971
|
+
security_model = "mixed"
|
|
2972
|
+
elif _filter_based:
|
|
2973
|
+
security_model = "filter_based"
|
|
2974
|
+
elif _has_annotation_security:
|
|
2975
|
+
security_model = "annotation_based"
|
|
2976
|
+
else:
|
|
2977
|
+
security_model = "unknown"
|
|
2978
|
+
|
|
2911
2979
|
return {
|
|
2912
2980
|
"endpoints": endpoints,
|
|
2913
2981
|
"total": len(endpoints),
|
|
2914
2982
|
"no_security_signal": no_security_signal,
|
|
2983
|
+
"security_model": security_model,
|
|
2915
2984
|
# Keep legacy field name for backward compat, now means same as no_security_signal
|
|
2916
2985
|
"undocumented": no_security_signal,
|
|
2917
2986
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sourcecode
|
|
3
|
-
Version: 1.31.
|
|
3
|
+
Version: 1.31.27
|
|
4
4
|
Summary: Deterministic codebase context for AI coding agents
|
|
5
5
|
License: Apache License
|
|
6
6
|
Version 2.0, January 2004
|
|
@@ -225,7 +225,7 @@ Description-Content-Type: text/markdown
|
|
|
225
225
|
|
|
226
226
|
**AI-ready change intelligence for Java/Spring enterprise monoliths.**
|
|
227
227
|
|
|
228
|
-

|
|
229
229
|

|
|
230
230
|
|
|
231
231
|
---
|
|
@@ -263,7 +263,7 @@ pipx install sourcecode
|
|
|
263
263
|
|
|
264
264
|
```bash
|
|
265
265
|
sourcecode version
|
|
266
|
-
# sourcecode 1.31.
|
|
266
|
+
# sourcecode 1.31.27
|
|
267
267
|
```
|
|
268
268
|
|
|
269
269
|
---
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
sourcecode/__init__.py,sha256=
|
|
1
|
+
sourcecode/__init__.py,sha256=VXhPMdJM6x_WGp7qMeGlW63Lz-PmJxDFOdXqGhLNfm4,104
|
|
2
2
|
sourcecode/adaptive_scanner.py,sha256=XffluXKzJUXrMtjEiAOnSNPZnztdIcts17T9ouHeID0,10521
|
|
3
3
|
sourcecode/architecture_analyzer.py,sha256=Ry3aYT9dc7XuLmWLT5IZ93RkCf_P14Qtew0nGPvUl_8,42184
|
|
4
4
|
sourcecode/architecture_summary.py,sha256=z34_6v7cSwy98cof2UVciGho7SCrZ93tiqMmq5WNzRQ,20405
|
|
5
5
|
sourcecode/ast_extractor.py,sha256=_btmeOJIe3t-NicF94D5ZAesa2YIJ0_QNExGnbHxGFE,50578
|
|
6
6
|
sourcecode/cache.py,sha256=TiYa3ECjBKtvlfCk7GvQ9v6gZkAITpH3ow9PubA7sUo,22946
|
|
7
|
-
sourcecode/canonical_ir.py,sha256=
|
|
7
|
+
sourcecode/canonical_ir.py,sha256=_HM3AUmKSdna9u4dCoU6rpgSA6HdF8gzOKZykIUCNGY,23277
|
|
8
8
|
sourcecode/classifier.py,sha256=yWeq6agTjkFa3zuNa-gdVIHtjoBoPoVlJnX-b7tdVJs,7851
|
|
9
|
-
sourcecode/cli.py,sha256=
|
|
9
|
+
sourcecode/cli.py,sha256=8qcr6G5RF17EqtLsM7Weu3G6Pb3GbfgudK-Knx01-0w,151980
|
|
10
10
|
sourcecode/code_notes_analyzer.py,sha256=EJemNCNc9Dn-1RZYu-aNbK0ELzmsyC4s6FdHi3XyNEI,9392
|
|
11
11
|
sourcecode/confidence_analyzer.py,sha256=_jckZSxksV-OU38vbkxfVNBnWCtlCq8Vwfg23x1uspA,19054
|
|
12
12
|
sourcecode/context_scorer.py,sha256=QpChSpsmaAYz91rXA4Ue5xzQmNz_ZboZN09YOHScq1U,14679
|
|
@@ -32,7 +32,7 @@ sourcecode/ranking_engine.py,sha256=ZAucq_YX2KkWUuAZf4P0lhtQ_38vEFnUhuGtSZd1S0E,
|
|
|
32
32
|
sourcecode/redactor.py,sha256=xuGcadGEHaPw4qZXlMDvzMCsr4VOkdp3oBQptHyJk8c,2884
|
|
33
33
|
sourcecode/relevance_scorer.py,sha256=MYF4FFkveAQps9SmTeTlh6ODiBz2F--_hWNeHMLtUHQ,8405
|
|
34
34
|
sourcecode/repo_classifier.py,sha256=FG1vaWKdWXsWdl-S8hjVMiTqcwgaRXkDyvK4rPcOGtQ,22681
|
|
35
|
-
sourcecode/repository_ir.py,sha256=
|
|
35
|
+
sourcecode/repository_ir.py,sha256=gzgveIWxgT77JwUxS2dxEuLp6UbVnrHEkVo4a8x4QfY,151066
|
|
36
36
|
sourcecode/runtime_classifier.py,sha256=uTAD6BDCiBLUZEDRfqk718kM4RTT_vAbfkcOI2_Xx58,18432
|
|
37
37
|
sourcecode/scanner.py,sha256=WdOQ78mMzjR1NjmKTlbxdgwinnCTfAhxCVLBEFQiFHU,8899
|
|
38
38
|
sourcecode/schema.py,sha256=aHNXDf8LGyUC8ZDE_VS9kiskC2-Oswhi_WnpdGy6HDw,24897
|
|
@@ -64,7 +64,7 @@ sourcecode/detectors/terraform.py,sha256=cxORPR_zVLOJpHlh4e9JnFpkQsn_UnqMMom5yG6
|
|
|
64
64
|
sourcecode/detectors/tooling.py,sha256=8CKbtxwQoABP-WyBRNmdAmHDOvAH57AR1cF4UKuWEdQ,2074
|
|
65
65
|
sourcecode/mcp/__init__.py,sha256=XU4HfRGbdid8wdUA0x_4f7uKZD1z3mv_XUY_WU_T9Mw,179
|
|
66
66
|
sourcecode/mcp/runner.py,sha256=7PnFjKYbgxFeDnqVeSntXHxZX7ZtK3-krDkEuVjI24M,1386
|
|
67
|
-
sourcecode/mcp/server.py,sha256=
|
|
67
|
+
sourcecode/mcp/server.py,sha256=BqoXi2Ncu7huGVie9AbsUNAxq9cbASLJ_Zgf68aZWsI,20122
|
|
68
68
|
sourcecode/mcp/onboarding/__init__.py,sha256=sj2PWqEBmMc4zBNkomg89WtL0M6S7A9yb7_wAuSWNP4,66
|
|
69
69
|
sourcecode/mcp/onboarding/applier.py,sha256=yfSMT0NKdZsjavtLkC8yQ7OtkfepOl5IXGByqg6bdEY,1894
|
|
70
70
|
sourcecode/mcp/onboarding/backup.py,sha256=ihqGOR8QTX8HASRSEDyfFyXr5bkXrygPHamv4p9KTmk,1452
|
|
@@ -76,8 +76,8 @@ sourcecode/telemetry/consent.py,sha256=wLMvGNJeSSyZoNkQXpoUioY6mMv4Qdvuw7S9jAEWn
|
|
|
76
76
|
sourcecode/telemetry/events.py,sha256=oEvvulfsv5GIDWG2174gSS6tNB95w38AIYiYeifGKlE,2294
|
|
77
77
|
sourcecode/telemetry/filters.py,sha256=Asa71oRl7q3Wt_FMwuufIZJFzSYdgRNKS8LHCIyFeYE,4805
|
|
78
78
|
sourcecode/telemetry/transport.py,sha256=KJeIPCPWMdmbCP3ySGs2iUlia34U6vWne2dZsUezesw,1560
|
|
79
|
-
sourcecode-1.31.
|
|
80
|
-
sourcecode-1.31.
|
|
81
|
-
sourcecode-1.31.
|
|
82
|
-
sourcecode-1.31.
|
|
83
|
-
sourcecode-1.31.
|
|
79
|
+
sourcecode-1.31.27.dist-info/METADATA,sha256=yC3wqkw7X5sccpT8RShxa7uR2_fQsik7FCAJJZ33yY0,31103
|
|
80
|
+
sourcecode-1.31.27.dist-info/WHEEL,sha256=QccIxa26bgl1E6uMy58deGWi-0aeIkkangHcxk2kWfw,87
|
|
81
|
+
sourcecode-1.31.27.dist-info/entry_points.txt,sha256=ex3F9rmbXeyDIoFQHtkEqTsKSaJow8F0LrVu8XfIktQ,57
|
|
82
|
+
sourcecode-1.31.27.dist-info/licenses/LICENSE,sha256=7DdHrU9Z_3e7dSvq4ISijZNjnuHo5NIHNiHDouMQ9JU,10491
|
|
83
|
+
sourcecode-1.31.27.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|