sourcecode 5.9.19__py3-none-any.whl → 5.9.23__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 +1 -1
- sourcecode/_build_commit.py +1 -1
- sourcecode/_docs/DEFECT-LEDGER.md +26 -0
- sourcecode/_docs/USER_GUIDE.md +9 -6
- sourcecode/answer_bounds.py +10 -0
- sourcecode/canonical_ir.py +12 -4
- sourcecode/cli.py +113 -23
- sourcecode/context_graph.py +24 -18
- sourcecode/jvm_inventory.py +294 -0
- sourcecode/migrate_check.py +21 -0
- sourcecode/non_coverage.py +17 -0
- sourcecode/output_budget.py +18 -4
- sourcecode/parallel.py +3 -11
- sourcecode/repository_ir.py +139 -21
- sourcecode/resource_budget.py +10 -5
- sourcecode/risk.py +3 -2
- sourcecode/rule_catalog.py +1 -0
- sourcecode/schema_registry.py +2 -0
- sourcecode/spring_findings.py +4 -3
- sourcecode/spring_security_audit.py +57 -0
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/METADATA +16 -8
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/RECORD +26 -25
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/WHEEL +0 -0
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/entry_points.txt +0 -0
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/licenses/LICENSE +0 -0
- {sourcecode-5.9.19.dist-info → sourcecode-5.9.23.dist-info}/licenses/NOTICE +0 -0
sourcecode/__init__.py
CHANGED
sourcecode/_build_commit.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""Generated at build time by hatch_build.py. Do not edit (AUD-592-D04)."""
|
|
2
2
|
|
|
3
|
-
BUILD_COMMIT = '
|
|
3
|
+
BUILD_COMMIT = '75c2f78dd8e2c7945e8a034f4f3c4fc8f9c40fc8'
|
|
4
4
|
CLOSURE_PROVENANCE = {'AUD-611-B05': {'commit': '', 'status': 'uncited'}, 'AUD-611-B06': {'commit': '', 'status': 'uncited'}, 'AUD-611-B07': {'commit': '', 'status': 'uncited'}, 'AUD-611-B08': {'commit': '', 'status': 'uncited'}, 'AUD-611-B09': {'commit': '', 'status': 'uncited'}, 'AUD-611-B10': {'commit': '', 'status': 'uncited'}, 'AUD-611-B11': {'commit': '', 'status': 'uncited'}, 'AUD-612-07': {'commit': '', 'status': 'uncited'}, 'AUD-612-09': {'commit': '', 'status': 'uncited'}, 'AUD-612-14': {'commit': '', 'status': 'uncited'}, 'AUD-612-B03': {'commit': '', 'status': 'uncited'}, 'AUD-612-B07': {'commit': '', 'status': 'uncited'}, 'AUD-612-B13': {'commit': '', 'status': 'uncited'}, 'AUD-612-E': {'commit': '', 'status': 'uncited'}, 'AUD-612-G': {'commit': '', 'status': 'uncited'}, 'AUD-612-I': {'commit': '', 'status': 'uncited'}, 'AUD-612-K': {'commit': '', 'status': 'uncited'}, 'AUD-612-M': {'commit': '', 'status': 'uncited'}, 'AUD-612-R': {'commit': '', 'status': 'uncited'}, 'AUD-613-ROOT': {'commit': '', 'status': 'uncited'}, 'AUD-614-07': {'commit': '', 'status': 'uncited'}, 'AUD-614-E': {'commit': '', 'status': 'uncited'}, 'AUD-614-F': {'commit': '', 'status': 'uncited'}, 'AUD-614-G': {'commit': '', 'status': 'uncited'}, 'AUD-614-I': {'commit': '', 'status': 'uncited'}, 'AUD-614-INTENT-TIE': {'commit': '', 'status': 'uncited'}, 'AUD-614-JUNIT4': {'commit': '', 'status': 'uncited'}, 'AUD-614-RISK-L0': {'commit': '', 'status': 'uncited'}, 'AUD-614-SELFTEST-TIMEOUT': {'commit': '', 'status': 'uncited'}, 'AUD-615-07': {'commit': '', 'status': 'uncited'}, 'AUD-615-COLD-COMPACT': {'commit': '', 'status': 'uncited'}, 'AUD-615-DRIFT': {'commit': '', 'status': 'uncited'}, 'AUD-615-E': {'commit': '', 'status': 'uncited'}, 'AUD-615-F': {'commit': '', 'status': 'uncited'}, 'AUD-615-INTENT-TIE': {'commit': '', 'status': 'uncited'}, 'AUD-615-JUNIT4': {'commit': '', 'status': 'uncited'}, 'AUD-615-RISK-L0': {'commit': '', 'status': 'uncited'}, 'AUD-615-SELFTEST-TIMEOUT': {'commit': '', 'status': 'uncited'}, 'AUD-616-E-PROV': {'commit': '', 'status': 'uncited'}, 'AUD-616-F, -RISK-L0, -SELFTEST-TIMEOUT, -INTENT-TIE, -DRIFT, -COLD-COMPACT, -E, -07': {'commit': '', 'status': 'uncited'}, 'AUD-616-INTENT-TIE-COV': {'commit': '', 'status': 'uncited'}, 'AUD-616-JUNIT4-SELF': {'commit': '', 'status': 'uncited'}, 'AUD-616-KOTLIN': {'commit': '', 'status': 'uncited'}, 'AUD-616-O': {'commit': '', 'status': 'uncited'}, 'AUD-616-P': {'commit': '', 'status': 'uncited'}, 'Window': {'commit': '', 'status': 'uncited'}, '`ASK-FIELD-01`': {'commit': '829f9fa', 'status': 'present'}, '`ASK-FIELD-02`': {'commit': '6a659fa', 'status': 'present'}, '`ASK-FIELD-03`': {'commit': '55b0d51', 'status': 'present'}, '`AUD-588-F05`': {'commit': '470e4a4', 'status': 'present'}, '`AUD-590-B01` / `B-01`, `F-01`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B02` / `B-02`, `F-02`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B03` / `B-03`, `F-03`': {'commit': '', 'status': 'uncited'}, '`AUD-590-B04` / `B-04`, `F-04`': {'commit': '', 'status': 'uncited'}, '`AUD-590-R01` / `R-01`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A01` / `A-1`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A02` / `A-2`, `A-4`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A03` / `A-3`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A05` / `A-5`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A06` / `A-6`, `A-7`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A08` / `A-8`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A09` / `A-9`': {'commit': '', 'status': 'uncited'}, '`AUD-591-A10` / `A-10`': {'commit': '', 'status': 'uncited'}, '`AUD-592-A02` / `A-1` second half, `§12.5`': {'commit': '63f3d61', 'status': 'present'}, '`AUD-592-B01` / `B-8`': {'commit': '8329614', 'status': 'present'}, '`AUD-592-D01` / `D-1`': {'commit': '0f8e03f', 'status': 'present'}, '`AUD-592-D02` / `D-2`': {'commit': '1d3db4d', 'status': 'present'}, '`AUD-592-D03` / `D-3`': {'commit': 'f28fe40', 'status': 'present'}, '`AUD-592-R01` / `A-1`': {'commit': '216025f', 'status': 'present'}, '`AUD-592-R02` / `N-4`, reopens `AUD-513-N04`': {'commit': 'ec3050d', 'status': 'present'}, '`AUD-593-N01` / `N-01`': {'commit': 'dd6a706', 'status': 'present'}, '`AUD-593-N02` / `N-02`': {'commit': 'f539787', 'status': 'present'}, '`AUD-593-N03` / `N-03`': {'commit': '1dd0b1c', 'status': 'present'}, '`AUD-593-N05` / `N-05`': {'commit': 'aa89388', 'status': 'present'}, '`AUD-593-N06` / `N-06`': {'commit': 'aa584a6', 'status': 'present'}, '`AUD-594-N04` / `D-5`, disclosure half of `B-3`': {'commit': 'a0060b7', 'status': 'present'}, '`AUD-594-X01` / `A-1`, residual of `AUD-593-N03`': {'commit': 'dd222b9', 'status': 'present'}, '`AUD-594-X02` / `A-1` second half': {'commit': '1193937', 'status': 'present'}, '`AUD-594-X03` / `X-03`, residual of `AUD-593-N01`': {'commit': 'e89e8f0', 'status': 'present'}, '`AUD-594-X04`': {'commit': '05b8cc9', 'status': 'present'}, '`AUD-595-A02` / `N-5`, advisory half of `AUD-588-B11`': {'commit': '3e15227', 'status': 'present'}, '`AUD-595-A03` / `B-6` exit-code half': {'commit': 'ab7285f', 'status': 'present'}, '`AUD-595-A05`': {'commit': 'e0b3d10', 'status': 'present'}, '`AUD-595-A07`, narrow half of `AUD-592-A02`': {'commit': 'cc15177', 'status': 'present'}, '`AUD-595-B01` / §B': {'commit': 'b77a1ad', 'status': 'present'}, '`AUD-595-Q01`': {'commit': '91a6566', 'status': 'present'}, '`AUD-596-A01` / `ASK-DET-001`': {'commit': 'fa508b4', 'status': 'present'}, '`AUD-596-A02` / `ASK-SELF-001`': {'commit': '4dfadc8', 'status': 'present'}, '`AUD-596-A03` / `ASK-C1-001`': {'commit': 'bffa3a6', 'status': 'present'}, '`AUD-596-A04` / `ASK-UX-003` + `ASK-UX-004`': {'commit': 'f0aac3c', 'status': 'present'}, '`AUD-596-B01` / `B-01`, harder witness for `BUG-6`': {'commit': '567d09d', 'status': 'present'}, '`AUD-596-B02` / `B-02`, class residual of `R2`': {'commit': '', 'status': 'uncited'}, '`AUD-596-B03` / `B-03`': {'commit': 'a8cb814', 'status': 'present'}, '`AUD-596-B06` / `B-06`': {'commit': '8107927', 'status': 'present'}, '`AUD-596-B07` / `B-07`, class residual of `AUD-592-R02`': {'commit': 'e060485', 'status': 'present'}, '`AUD-596-B09` / `B-09`': {'commit': '5b8146c', 'status': 'present'}, '`AUD-596-B10` / `B-10`': {'commit': '5cb994d', 'status': 'present'}, '`AUD-596-B16` / `B-16`': {'commit': '1507f69', 'status': 'present'}, '`AUD-596-D01` / `B-13` + `B-14`': {'commit': '0b1bdf0', 'status': 'present'}, '`AUD-596-D02` / `B-08`, residual of `AUD-594-N04`': {'commit': 'e7f73c3', 'status': 'present'}, '`AUD-596-D03` / `ASK-AGT-001`': {'commit': '8c46967', 'status': 'present'}, '`AUD-596-D04` / `B-18`': {'commit': '040f027', 'status': 'present'}, '`AUD-596-D05` / `B-19`': {'commit': 'fd2bf68', 'status': 'present'}, '`AUD-596-D06` / `B-20`': {'commit': '784cd83', 'status': 'present'}, '`AUD-596-D07` / `B-17`, half refuted': {'commit': 'c3ff822', 'status': 'present'}, '`AUD-596-D08` / `B-22`, class residual of `AUD-591-A06`': {'commit': 'b396c6a', 'status': 'present'}, '`AUD-596-D09` / `B-23`, surviving half of `B26`': {'commit': 'fd3d63f', 'status': 'present'}, '`AUD-596-D10` / `B-29`': {'commit': '', 'status': 'uncited'}, '`AUD-596-D11` / `ASK-UX-005`': {'commit': 'f4b4f77', 'status': 'present'}, '`AUD-596-D12` — six hints that send the reader back to the error': {'commit': '498df44', 'status': 'present'}, '`AUD-596-D13` / `B-28`': {'commit': '1014c72', 'status': 'present'}, '`AUD-596-D14` / `B-15`, narrow half of `B20`': {'commit': '10f2827', 'status': 'present'}, '`AUD-596-R01` / `B-05`': {'commit': '', 'status': 'uncited'}, '`AUD-596-X01` / `ASK-GATE-001`, gating half of `B24`': {'commit': 'e59c655', 'status': 'present'}, '`AUD-596-X02` / `ASK-UX-001` + `ASK-UX-002` + `B-21`': {'commit': 'f6ebf50', 'status': 'present'}, '`AUD-597-A01` / `ASK-UX-001` + `N-01`': {'commit': 'f8cf061', 'status': 'present'}, '`AUD-597-A02` / `ASK-UX-008` + `ASK-DOC-002`': {'commit': '9d47a4c', 'status': 'present'}, '`AUD-597-A03` / `ASK-DET-001`': {'commit': '4c7622a', 'status': 'present'}, '`AUD-597-A04` / `ASK-LEDGER-001`': {'commit': '46fb870', 'status': 'present'}, '`AUD-597-D01` / `B-04`': {'commit': '1094e6a', 'status': 'present'}, '`AUD-597-D02` / `ASK-DOC-001`': {'commit': 'ecb1bb7', 'status': 'present'}, '`AUD-597-D03` / `N-06`': {'commit': '9784333', 'status': 'present'}, '`AUD-597-D04` / `N-05`': {'commit': 'e51c087', 'status': 'present'}, '`AUD-597-D05` / `N-04`, fourth appearance of `C4-27`': {'commit': '9cccc15', 'status': 'present'}, '`AUD-597-D06` / `ASK-CLI-001`': {'commit': '178aa6d', 'status': 'present'}, '`AUD-597-D07` / `N-03`': {'commit': '9245e35', 'status': 'present'}, '`AUD-597-R01` / `ASK-PERF-001`': {'commit': '6910054', 'status': 'present'}, '`AUD-597-R02` / `ASK-ENC-001`': {'commit': 'ce6dac1', 'status': 'present'}, '`AUD-597-R03` / `ASK-UX-002`': {'commit': 'c57e50b', 'status': 'present'}, '`AUD-597-X01` / `ASK-BUILD-001` + `ASK-META-001` / `B-12`': {'commit': '354338b', 'status': 'present'}, '`AUD-598-B01` / `ASK-META-001`': {'commit': 'b2f7c65', 'status': 'present'}, '`AUD-598-B02` / `ASK-UX-002`': {'commit': '56a4bf7', 'status': 'present'}, '`AUD-598-B03` / `B-11`': {'commit': 'c63cb24', 'status': 'present'}, '`AUD-598-B04` / `N-02`': {'commit': '187937f', 'status': 'present'}, '`AUD-598-R01` / `ASK-PERF-002`': {'commit': '', 'status': 'uncited'}, '`AUD-598-X01` / `N-01` + `B-13` + `B-14` + `B-29` + `N-06`': {'commit': '6f2f5a4', 'status': 'present'}, '`AUD-600-B01` / `P-01`': {'commit': '366ffed', 'status': 'present'}, '`AUD-600-B02` / `P-02` + `ASK-PACK-002`': {'commit': '2a814c3', 'status': 'present'}, '`AUD-600-B03` / `ASK-PACK-001`': {'commit': '452f2a0', 'status': 'present'}, '`AUD-600-D01`': {'commit': '1224e1b', 'status': 'present'}, '`AUD-600-D02`': {'commit': 'eab8172', 'status': 'present'}, '`AUD-600-R01` / `R-01`': {'commit': '88add64', 'status': 'present'}, '`AUD-601-B01` / `N-02`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-B02` / `ASK-PACK-004`': {'commit': '', 'status': 'uncited'}, '`AUD-601-D01` / `N-01`, `ASK-UX-001`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-D02` / `B-13`, `B-14`, 5th round': {'commit': '', 'status': 'uncited'}, '`AUD-601-M01` / `B-26`, `B-27` retracted': {'commit': '', 'status': 'uncited'}, '`AUD-601-R01` / `R-02`': {'commit': '', 'status': 'uncited'}, '`AUD-619-WATCH`': {'commit': '', 'status': 'uncited'}, '`AUD-620-COMMAND-SURFACE`': {'commit': '', 'status': 'uncited'}, '`AUD-620-REVIEW-PR`': {'commit': '', 'status': 'uncited'}, '`AUD-621-REVIEW-PR`': {'commit': '', 'status': 'uncited'}, '`B-3`': {'commit': '773268d', 'status': 'present'}, '`B-6`': {'commit': '17c6e06', 'status': 'present'}, '`B-8`': {'commit': '8329614', 'status': 'present'}, '`BUG-3` / `443b345`': {'commit': '', 'status': 'uncited'}, '`BUG-4a` / `AUD-588-B11` residual': {'commit': '24b4185', 'status': 'present'}, '`BUG-4b` / `AUD-588-B11` residual': {'commit': '0376350', 'status': 'present'}, '`E-39`, class residual of `AUD-593-N06`': {'commit': '25fc11f', 'status': 'present'}, '`N-5`': {'commit': 'c68083f', 'status': 'present'}, '`N-7`': {'commit': '082e9de', 'status': 'present'}, '`R-1`': {'commit': '424fb1c', 'status': 'present'}, '`R-2`': {'commit': '5158b92', 'status': 'present'}, '`R-3`': {'commit': '88aec04', 'status': 'present'}, '`R-4`': {'commit': '04fd04f', 'status': 'present'}}
|
|
5
5
|
CLOSURE_COVERAGE = {'closed_rows': 165, 'present': 91, 'absent': 0, 'unresolved': 0, 'uncited': 74, 'unknown': 0}
|
|
@@ -14,6 +14,32 @@ Status values: `open` · `in-progress` · `closed <version>` · `by-design` (wit
|
|
|
14
14
|
The facts these rows are keyed to are published: `ask schema facts-v1` prints the registry
|
|
15
15
|
(authority, definition, consumers, parity test) that the release battery enforces.
|
|
16
16
|
|
|
17
|
+
## Current Synchronization — External Audit `5.9.22` (2026-09-01)
|
|
18
|
+
|
|
19
|
+
The external audit confirms strong precision, determinism and uncertainty
|
|
20
|
+
disclosure, but opens a P0/P1 cluster around silent success, incomplete
|
|
21
|
+
population disclosure, large-run memory and compact-output contracts. Full
|
|
22
|
+
evidence: [`AUDIT-2026-09-01-EXTERNAL-5.9.22.md`](AUDIT-2026-09-01-EXTERNAL-5.9.22.md).
|
|
23
|
+
|
|
24
|
+
| ID | Severity | Status | Evidence and required closure |
|
|
25
|
+
|---|---:|---|---|
|
|
26
|
+
| `BUG-01` | Critical maximum | **open, P0** | Full Markdown `audit-report` reproduced with `rc=0` and empty stdout. Add a global non-empty-answer invariant and renderer coverage. |
|
|
27
|
+
| `BUG-02` | Critical maximum | **open, P0** | Large `risk` ended `rc=127` with no output or structured failure. Add fail-fast resource/process handling and durable partial checkpoints. |
|
|
28
|
+
| `BUG-12` | Critical maximum | **open, P0** | Deep `--agent` output construction reaches multi-gigabyte RSS before a small answer. Bound projection while building. |
|
|
29
|
+
| `BUG-03` | High | **open, P1** | `content_id` changes between cold and warm because cache state is hashed into identity. Separate execution metadata from answer identity. |
|
|
30
|
+
| `BUG-04` | High | **open, P1** | `selftest` publishes `complete=true` with five error rows. Derive bounds from actual results. |
|
|
31
|
+
| `BUG-05` | High | **open, P1** | Overloaded endpoint handlers can receive the wrong declaration line. Resolve by mapping annotation or publish ambiguity. |
|
|
32
|
+
| `BUG-07` | High | **open, P1** | `--compact` remains oversized on `migrate-check` and `spring-audit`. Apply bounded projections with omission metadata. |
|
|
33
|
+
| `BUG-10` | High | **open, P1** | Unsupported routing styles can produce empty coverage gaps. Publish detected-but-unmodeled routing gaps. |
|
|
34
|
+
| `BUG-11` | High | **open, P1** | Default `pack assessment` can fail on a small Spring repository. Use a bounded default or explicit full mode. |
|
|
35
|
+
| `BUG-13` | High | **open, P1** | Unscoped `selftest` starts over nested repositories after warning. Refuse and require an explicit path. |
|
|
36
|
+
| `BUG-16` | High | **open, P1** | Context-cache growth has no published budget or eviction contract; about 1.5 GB was measured. |
|
|
37
|
+
| `BUG-22` | High | **open, P1** | RSS ceilings are checked post-hoc. Add periodic sampling and orderly abort. |
|
|
38
|
+
|
|
39
|
+
The remaining `BUG-04b`, `BUG-06`, `BUG-08`, `BUG-09`, `BUG-15`, `BUG-19`,
|
|
40
|
+
`BUG-20`, `BUG-21` and `BUG-23` findings are open P2/coverage follow-ups in
|
|
41
|
+
the audit document. None is closed by documentation alone.
|
|
42
|
+
|
|
17
43
|
## Current Synchronization — External Audit `AUD-621`
|
|
18
44
|
|
|
19
45
|
**Release `5.9.19` remediation.** The stderr-decoding fix for `AUD-621-PACK-STDERR` remains in code, and the distinct `pack gate --since` crash found by the post-remediation re-audit is corrected with a Python 3.9–3.11-compatible tar extraction path. `AUD-621-R` has a second Windows barrier at process-pool construction, complementing the sequential fallback. The broader findings remain open until their required native Windows evidence is recorded; `AUD-621-CONTEXT` and `AUD-621-WIN-PROC` are unchanged.
|
sourcecode/_docs/USER_GUIDE.md
CHANGED
|
@@ -332,7 +332,7 @@ value in field use, and they are the ones to learn first:
|
|
|
332
332
|
| `ask posture . --diff dev:prod` | The only command that answers *"what changes about effective access between two profile sets, across every endpoint at once"*. Experimental, and the most differentiated capability in the product. |
|
|
333
333
|
| `ask endpoints .` | Every REST endpoint with its **effective path** (context-path + `spring.mvc.servlet.path` resolved), inferred security policy and per-endpoint confidence. Turns "audit the API" into a list. |
|
|
334
334
|
| `ask spring-audit .` | Transactional anomalies that a compiler cannot see — `@Transactional` on a private method is a silent CGLIB no-op — plus the security surface. |
|
|
335
|
-
| `ask migrate-check . --compact` | Boot 2→3 readiness plus Java LTS/licensing inventory: blockers, effort, target JDK evidence and explicit licensing-review signals. |
|
|
335
|
+
| `ask migrate-check . --compact` | Boot 2→3 readiness plus Java LTS/licensing and local JVM ecosystem inventory: blockers, effort, target JDK evidence, framework/runtime signals and explicit licensing-review signals. |
|
|
336
336
|
|
|
337
337
|
Everything else is either a projection of the same model (`impact`, `export`, `explain`) or an
|
|
338
338
|
agent-facing packaging of it (`--compact`, `--agent`, `prepare-context`). The full surface is
|
|
@@ -382,6 +382,9 @@ Output: detected stacks, entry points, dependencies, transactional boundaries (S
|
|
|
382
382
|
### `ask --agent`
|
|
383
383
|
|
|
384
384
|
More structured version of `--compact`. Designed for AI agent system prompt injection.
|
|
385
|
+
It is bounded to 40 KB on stdout and admits repositories up to 10,000 Java files;
|
|
386
|
+
larger repositories return `AGENT_SCOPE_TOO_LARGE` before expensive analysis. Use
|
|
387
|
+
`--compact` or narrow the path in that case.
|
|
385
388
|
|
|
386
389
|
```bash
|
|
387
390
|
ask /repo --agent --output context.json
|
|
@@ -528,7 +531,7 @@ disabled changes runtime behaviour nobody measured; a diff is how a person makes
|
|
|
528
531
|
call with the evidence in front of them.
|
|
529
532
|
|
|
530
533
|
**TX patterns (TX-001..TX-006):** proxy bypass, nested transactions, readOnly propagation, NOT_SUPPORTED in active TX, exception swallowing, self-invocation of a `@Transactional` sibling.
|
|
531
|
-
**SEC patterns (SEC-001..SEC-
|
|
534
|
+
**SEC patterns (SEC-001..SEC-010):** unsecured endpoints, CVE-2025-41248 `@PreAuthorize` inheritance bypass, `@Transactional` on controllers, passwords stored under a fast unsalted digest, CSRF disabled under session-bearing authentication, cookies created without the Secure attribute, credentials stored in a deployment descriptor, SQL built by MyBatis string interpolation, anonymous request-chain exceptions, and HTTP input reaching a concatenated known query sink through bounded positional in-repository calls. **DEAD-001** reports a security control that is present only in comments and therefore disabled.
|
|
532
535
|
**GATE patterns (GATE-001..GATE-004):** custom AOP/security-gate risks over the same custom-gate authority published in `security_posture`: proxy bypass (`private`/`final`/self-invocation), advice that appears to fail open, disabled or tautological annotation attributes, and fragile `args[0]`/reflection binding.
|
|
533
536
|
|
|
534
537
|
Each finding includes `severity`, `confidence`, `symbol`, `source_file`, `evidence`, `explanation`, and `fix_hint`. JAVA/SPRING ONLY.
|
|
@@ -1812,10 +1815,10 @@ stops at 1 408 files inside the `SEC-004` group and ends at 5.1s.
|
|
|
1812
1815
|
**Memory budget.** Repository-scoped JSON answers include `_meta.memory` with
|
|
1813
1816
|
`unit: "MB"`, the observed `peak_rss_mb`, the `peak_rss_basis` it was sampled
|
|
1814
1817
|
from, `configured_max_rss_mb`, and `ceiling_enforceable`. To bound long analyses
|
|
1815
|
-
on a CI or supervised runner, set `ASK_MAX_RSS_MB=<megabytes>`.
|
|
1816
|
-
ceiling produces exit code `1`
|
|
1817
|
-
|
|
1818
|
-
|
|
1818
|
+
on a CI or supervised runner, set `ASK_MAX_RSS_MB=<megabytes>`. `--agent` uses
|
|
1819
|
+
1,536 MB when the variable is unset. Exceeding the ceiling produces exit code `1`
|
|
1820
|
+
and a structured `MEMORY_TOO_LARGE` error with the peak and configured limit; no
|
|
1821
|
+
partial answer is published. Set the variable to `0` to disable this ceiling.
|
|
1819
1822
|
|
|
1820
1823
|
Where the platform exposes no footprint sample, `peak_rss_mb` is `null` and
|
|
1821
1824
|
`peak_rss_basis` says why — never `0`, which would read as a measured floor. A
|
sourcecode/answer_bounds.py
CHANGED
|
@@ -99,6 +99,16 @@ def _gaps(payload: "dict[str, Any]") -> "list[dict[str, Any]]":
|
|
|
99
99
|
found.append({"field": "non_coverage", "what": _summarise(entry)})
|
|
100
100
|
elif non_coverage:
|
|
101
101
|
found.append({"field": "non_coverage", "what": _summarise(non_coverage)})
|
|
102
|
+
populations = [payload.get("population")]
|
|
103
|
+
metadata = payload.get("metadata")
|
|
104
|
+
if isinstance(metadata, dict):
|
|
105
|
+
populations.append(metadata.get("population"))
|
|
106
|
+
for population in populations:
|
|
107
|
+
if not isinstance(population, dict):
|
|
108
|
+
continue
|
|
109
|
+
for failure in _as_list(population.get("parse_failures")):
|
|
110
|
+
if failure:
|
|
111
|
+
found.append({"field": "population.parse_failures", "what": _summarise(failure)})
|
|
102
112
|
for prefix, block in _blocks(payload):
|
|
103
113
|
for field in _GAP_FIELDS:
|
|
104
114
|
value = block.get(field)
|
sourcecode/canonical_ir.py
CHANGED
|
@@ -528,10 +528,17 @@ def ir_dict_to_canonical(
|
|
|
528
528
|
files = sorted(file_set)
|
|
529
529
|
|
|
530
530
|
# Sorted call graph edges — stable ordering: from, type, to
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
)
|
|
531
|
+
# The raw graph is owned by this CIR conversion and its edge order is not
|
|
532
|
+
# observable until after conversion. Sort in place instead of creating a
|
|
533
|
+
# second repository-sized list during the raw/CIR overlap peak.
|
|
534
|
+
if isinstance(edges, list):
|
|
535
|
+
edges.sort(key=lambda e: (e.get("from", ""), e.get("type", ""), e.get("to", "")))
|
|
536
|
+
call_graph = edges
|
|
537
|
+
else:
|
|
538
|
+
call_graph = sorted(
|
|
539
|
+
edges,
|
|
540
|
+
key=lambda e: (e.get("from", ""), e.get("type", ""), e.get("to", "")),
|
|
541
|
+
)
|
|
535
542
|
|
|
536
543
|
# Dependency edges (structural subset of call_graph)
|
|
537
544
|
_dep_types = frozenset({"imports", "extends", "implements", "injects"})
|
|
@@ -587,6 +594,7 @@ def ir_dict_to_canonical(
|
|
|
587
594
|
"edge_count": len(call_graph),
|
|
588
595
|
"subsystems": ir.get("subsystems") or [],
|
|
589
596
|
"analysis_gaps": ir.get("analysis_gaps") or [],
|
|
597
|
+
"population": ir.get("population") or {},
|
|
590
598
|
"spring_events": ir.get("spring_events") or {},
|
|
591
599
|
"score_basis": (ir.get("impact") or {}).get("score_basis", "none"),
|
|
592
600
|
"reverse_graph_size": len(ir.get("reverse_graph") or {}),
|
sourcecode/cli.py
CHANGED
|
@@ -513,6 +513,28 @@ _START_HERE: "tuple[tuple[str, str], ...]" = (
|
|
|
513
513
|
)
|
|
514
514
|
|
|
515
515
|
|
|
516
|
+
def _start_here_entries(root: "Optional[Path]") -> "tuple[tuple[str, str], ...]":
|
|
517
|
+
"""Return pasteable first steps that the measured repository can accept."""
|
|
518
|
+
if root is None:
|
|
519
|
+
return _START_HERE
|
|
520
|
+
try:
|
|
521
|
+
from sourcecode.spring_profiles import profile_population
|
|
522
|
+
|
|
523
|
+
profiles = profile_population(root).names
|
|
524
|
+
except Exception:
|
|
525
|
+
# Help must remain available if a repository cannot be read.
|
|
526
|
+
return _START_HERE
|
|
527
|
+
if len(profiles) < 2:
|
|
528
|
+
# `posture --diff` rejects undeclared profile names. Do not publish an
|
|
529
|
+
# example that cannot run on this repository.
|
|
530
|
+
return tuple(entry for entry in _START_HERE if not entry[0].startswith("posture "))
|
|
531
|
+
diff = f"posture . --diff {profiles[0]}:{profiles[1]}"
|
|
532
|
+
return tuple(
|
|
533
|
+
(diff, answers) if invocation.startswith("posture ") else (invocation, answers)
|
|
534
|
+
for invocation, answers in _START_HERE
|
|
535
|
+
)
|
|
536
|
+
|
|
537
|
+
|
|
516
538
|
#: Resolved bounding flags, by invocation. Deliberately **not** an `lru_cache`:
|
|
517
539
|
#: only a resolution that found the command is stored. AUD-601-D01 — the front
|
|
518
540
|
#: page is composed while this module is still being imported, so the first
|
|
@@ -637,6 +659,8 @@ def _start_here_block(scope: "Optional[Any]" = None) -> str:
|
|
|
637
659
|
BUCKET_ORDER, BUCKET_TITLE, BUDGETED, DETACH, RUNS_NOW, UNKNOWN, plan,
|
|
638
660
|
)
|
|
639
661
|
|
|
662
|
+
root = getattr(scope, "root", None) if scope is not None else None
|
|
663
|
+
entries = _start_here_entries(root)
|
|
640
664
|
if scope is None or not scope.measured:
|
|
641
665
|
# AUD-601-D01. The ceiling is a property of the **command**, not of the
|
|
642
666
|
# repository, so the bounding flag must not depend on measuring one.
|
|
@@ -647,13 +671,13 @@ def _start_here_block(scope: "Optional[Any]" = None) -> str:
|
|
|
647
671
|
# the generator covers them, and this rendering never called it.
|
|
648
672
|
static = [
|
|
649
673
|
(_bounded_invocation(invocation), answers)
|
|
650
|
-
for invocation, answers in
|
|
674
|
+
for invocation, answers in entries
|
|
651
675
|
]
|
|
652
676
|
width = max([29] + [len(invocation) + 1 for invocation, _ in static])
|
|
653
677
|
lines = ["[bold]Start here — Java/Spring analysis:[/bold]"]
|
|
654
678
|
for invocation, answers in static:
|
|
655
679
|
lines.append(f" {invocation:<{width}}[dim]# {answers}[/dim]")
|
|
656
|
-
if any(bounded != raw for (bounded, _), (raw, _) in zip(static,
|
|
680
|
+
if any(bounded != raw for (bounded, _), (raw, _) in zip(static, entries)):
|
|
657
681
|
lines.append(
|
|
658
682
|
" [dim]Bounded for a first look: each line above carries the "
|
|
659
683
|
"flag its command declares against the output ceiling. Drop it, "
|
|
@@ -661,7 +685,7 @@ def _start_here_block(scope: "Optional[Any]" = None) -> str:
|
|
|
661
685
|
)
|
|
662
686
|
return "\n".join(lines)
|
|
663
687
|
|
|
664
|
-
answers = dict(
|
|
688
|
+
answers = dict(entries)
|
|
665
689
|
# AUD-596-X02: this block sold three commands under "Runs now" and two of
|
|
666
690
|
# them exited 1 here, both with `OUTPUT_TOO_LARGE` — `posture . --diff
|
|
667
691
|
# dev:prod` at ~71K estimated tokens over a 50K ceiling, and `endpoints .`
|
|
@@ -672,12 +696,12 @@ def _start_here_block(scope: "Optional[Any]" = None) -> str:
|
|
|
672
696
|
# it from an error.
|
|
673
697
|
bounded = {
|
|
674
698
|
invocation: _bounded_invocation(invocation)
|
|
675
|
-
for invocation, _ in
|
|
699
|
+
for invocation, _ in entries
|
|
676
700
|
}
|
|
677
701
|
for invocation, bounded_form in bounded.items():
|
|
678
702
|
if bounded_form != invocation:
|
|
679
703
|
answers[bounded_form] = answers[invocation]
|
|
680
|
-
grouped = plan([bounded[invocation] for invocation, _ in
|
|
704
|
+
grouped = plan([bounded[invocation] for invocation, _ in entries], scope)
|
|
681
705
|
|
|
682
706
|
# AUD-597-A01. The plan orders by *time* and the ceiling refuses by *size*,
|
|
683
707
|
# so a command that is seconds away from an answer it cannot print is not a
|
|
@@ -729,7 +753,7 @@ def _start_here_block(scope: "Optional[Any]" = None) -> str:
|
|
|
729
753
|
" [dim]…each of these answers into a file and survives the shell:"
|
|
730
754
|
" add --output <file> --detach[/dim]"
|
|
731
755
|
)
|
|
732
|
-
if any(bounded[invocation] != invocation for invocation, _ in
|
|
756
|
+
if any(bounded[invocation] != invocation for invocation, _ in entries):
|
|
733
757
|
lines.append(
|
|
734
758
|
" [dim]Bounded for a first look: each line above carries the flag "
|
|
735
759
|
"its command declares against the output ceiling. Drop it, or add "
|
|
@@ -888,12 +912,12 @@ scope matches; `ask cache model` says exactly what a warm buys per command.
|
|
|
888
912
|
data-exposure . [dim]# one semantic model is shared across declared label seeds[/dim]
|
|
889
913
|
repo-ir . --since main --budget-tokens 12000 [dim]# bounded agent context[/dim]
|
|
890
914
|
migrate-check . --format sarif -o migration.sarif [dim]# located migration findings[/dim]
|
|
891
|
-
[dim]
|
|
892
|
-
|
|
915
|
+
[dim]Repository paths are normally positional. Commands that publish --path, --repo
|
|
916
|
+
or --dir accept that documented spelling; use each command's --help for its grammar.[/dim]
|
|
893
917
|
|
|
894
918
|
ASK_MAX_ANALYSIS_SECONDS=N [dim]# deadline for {_budget_tiers_phrase()}[/dim]
|
|
895
919
|
[dim]Other commands do not consume this budget; use `--progress` or `--detach` where offered.[/dim]
|
|
896
|
-
ASK_MAX_RSS_MB=N [dim]# peak resident-memory ceiling
|
|
920
|
+
ASK_MAX_RSS_MB=N [dim]# peak resident-memory ceiling; --agent defaults to 1536 MB, 0 disables[/dim]
|
|
897
921
|
[dim]Repository JSON answers publish `_meta.memory.peak_rss_mb` with its basis; exceeding the ceiling
|
|
898
922
|
returns MEMORY_TOO_LARGE, and a platform that exposes no sample returns MEMORY_CEILING_UNAVAILABLE
|
|
899
923
|
rather than passing a ceiling nothing measured.[/dim]
|
|
@@ -1796,7 +1820,12 @@ def _apply_budget(
|
|
|
1796
1820
|
|
|
1797
1821
|
to_file = output_path is not None
|
|
1798
1822
|
return _trim(
|
|
1799
|
-
data,
|
|
1823
|
+
data,
|
|
1824
|
+
budget_bytes,
|
|
1825
|
+
label=label,
|
|
1826
|
+
skip=to_file,
|
|
1827
|
+
warn_stderr=not to_file,
|
|
1828
|
+
strict=(label in {"agent", "compact"}),
|
|
1800
1829
|
)
|
|
1801
1830
|
|
|
1802
1831
|
|
|
@@ -3140,6 +3169,18 @@ def _emit_command_output(
|
|
|
3140
3169
|
not about the encoding. A command that already serialized its own YAML passes
|
|
3141
3170
|
the default and is untouched: the conversion only fires on a JSON object.
|
|
3142
3171
|
"""
|
|
3172
|
+
# A completed analysis with no payload is never a successful answer. The
|
|
3173
|
+
# process-level guard also catches this for the production entry point, but
|
|
3174
|
+
# rejecting it here protects every direct Typer invocation and prevents an
|
|
3175
|
+
# empty file from being published as an artefact.
|
|
3176
|
+
if not content.strip():
|
|
3177
|
+
_emit_error_json(
|
|
3178
|
+
EXECUTION_FAILED_CODE,
|
|
3179
|
+
"The command finished without publishing an answer.",
|
|
3180
|
+
command=_ANSWER_REQUIRED_BY or "unknown",
|
|
3181
|
+
expected="a non-empty parseable answer or report",
|
|
3182
|
+
)
|
|
3183
|
+
raise typer.Exit(code=1)
|
|
3143
3184
|
if stamp_envelope:
|
|
3144
3185
|
content = _stamp_envelope(content)
|
|
3145
3186
|
if fmt == "yaml":
|
|
@@ -4404,7 +4445,9 @@ app = typer.Typer(
|
|
|
4404
4445
|
name="ask",
|
|
4405
4446
|
help=_HELP,
|
|
4406
4447
|
add_completion=False,
|
|
4407
|
-
|
|
4448
|
+
# Rich's Windows help renderer can drop options from long command panels;
|
|
4449
|
+
# plain Click help keeps the complete option contract visible there.
|
|
4450
|
+
rich_markup_mode=None if os.name == "nt" else "rich",
|
|
4408
4451
|
no_args_is_help=False,
|
|
4409
4452
|
)
|
|
4410
4453
|
|
|
@@ -4904,6 +4947,24 @@ DOCS_DEPTH_CHOICES = ["module", "symbols", "full"]
|
|
|
4904
4947
|
_FREE_TIER_NODE_CAP: int = 50 # graph/semantic node cap — applies only to large repos on free tier
|
|
4905
4948
|
_JAVA_MIN_SCAN_DEPTH: int = 12 # Maven src/main/java/<pkg>/<module>/File depth floor
|
|
4906
4949
|
_LARGE_REPO_ADVISORY_FILES: int = 3000 # cold-scan advisory threshold (files); honest expectation-setting, not a speed claim
|
|
4950
|
+
_AGENT_JAVA_FILE_CAP: int = 10_000
|
|
4951
|
+
|
|
4952
|
+
|
|
4953
|
+
def _agent_scope_error(root: Path) -> "Optional[dict[str, Any]]":
|
|
4954
|
+
"""Refuse an agent run that cannot stay inside its memory contract."""
|
|
4955
|
+
try:
|
|
4956
|
+
java_files = sum(1 for _ in root.rglob("*.java"))
|
|
4957
|
+
except OSError:
|
|
4958
|
+
return None
|
|
4959
|
+
if java_files <= _AGENT_JAVA_FILE_CAP:
|
|
4960
|
+
return None
|
|
4961
|
+
return {
|
|
4962
|
+
"code": "AGENT_SCOPE_TOO_LARGE",
|
|
4963
|
+
"message": f"--agent is limited to {_AGENT_JAVA_FILE_CAP:,} Java files by default; this repository has {java_files:,}.",
|
|
4964
|
+
"hint": "Use --compact for the bounded summary, or narrow the repository path.",
|
|
4965
|
+
"java_files": java_files,
|
|
4966
|
+
"max_java_files": _AGENT_JAVA_FILE_CAP,
|
|
4967
|
+
}
|
|
4907
4968
|
|
|
4908
4969
|
#: What one Java file costs in serialized `repo-ir` output, measured across five
|
|
4909
4970
|
#: repositories (C3-18): spring-petclinic 30 files/318 KB (10.8 KB/file),
|
|
@@ -5767,7 +5828,14 @@ def main(
|
|
|
5767
5828
|
code_notes = True
|
|
5768
5829
|
no_tree = True # agents never need the raw file tree
|
|
5769
5830
|
architecture = True # agents need full architectural signal (M4)
|
|
5770
|
-
|
|
5831
|
+
# Module graphs are quadratic on large import populations and are not
|
|
5832
|
+
# required by agent_view. Keep them opt-in via --graph-modules.
|
|
5833
|
+
_agent_error = _agent_scope_error(target)
|
|
5834
|
+
if _agent_error is not None:
|
|
5835
|
+
_emit_error_json(
|
|
5836
|
+
_agent_error.pop("code"), _agent_error.pop("message"), **_agent_error
|
|
5837
|
+
)
|
|
5838
|
+
raise typer.Exit(code=2)
|
|
5771
5839
|
|
|
5772
5840
|
# --compact implicitly enables lightweight analysis passes so that
|
|
5773
5841
|
# dependency_summary, env_summary and code_notes_summary are never null.
|
|
@@ -6349,6 +6417,7 @@ def main(
|
|
|
6349
6417
|
"""Close a phase and stop the run if the operator's budget is spent."""
|
|
6350
6418
|
_root_run.completed.append(phase)
|
|
6351
6419
|
if not _root_run.exhausted():
|
|
6420
|
+
_root_memory_seam()
|
|
6352
6421
|
return
|
|
6353
6422
|
_progress.stop()
|
|
6354
6423
|
_block = _root_run.status(_WHY_BUDGET)
|
|
@@ -6360,6 +6429,26 @@ def main(
|
|
|
6360
6429
|
_emit_command_output(_serialize_dict(_block, format), output, copy)
|
|
6361
6430
|
raise typer.Exit(code=_exit)
|
|
6362
6431
|
|
|
6432
|
+
def _root_memory_seam() -> None:
|
|
6433
|
+
"""Enforce the agent's protective RSS ceiling at every root boundary."""
|
|
6434
|
+
if not agent:
|
|
6435
|
+
return
|
|
6436
|
+
from sourcecode import resource_budget
|
|
6437
|
+
|
|
6438
|
+
memory_error = resource_budget.exceeded(
|
|
6439
|
+
"ask --agent",
|
|
6440
|
+
default_ceiling_mb=resource_budget.DEFAULT_AGENT_RSS_CEILING_MB,
|
|
6441
|
+
)
|
|
6442
|
+
if memory_error is None:
|
|
6443
|
+
return
|
|
6444
|
+
_progress.stop()
|
|
6445
|
+
_emit_error_json(
|
|
6446
|
+
memory_error.pop("code"),
|
|
6447
|
+
memory_error.pop("message"),
|
|
6448
|
+
**memory_error,
|
|
6449
|
+
)
|
|
6450
|
+
raise typer.Exit(code=1)
|
|
6451
|
+
|
|
6363
6452
|
_perf_discovery = perf.start()
|
|
6364
6453
|
scanner = AdaptiveScanner(target, topology=_topology, base_depth=effective_depth,
|
|
6365
6454
|
extra_excludes=_extra_excludes)
|
|
@@ -7097,7 +7186,7 @@ def main(
|
|
|
7097
7186
|
_root_timing.setdefault("ris_ms", 0.0)
|
|
7098
7187
|
_root_timing.setdefault("snapshot_ms", 0.0)
|
|
7099
7188
|
# 4. Serialize
|
|
7100
|
-
_progress.update("serializing output")
|
|
7189
|
+
_progress.update("building bounded agent context" if agent else "serializing output")
|
|
7101
7190
|
_perf_serialize = perf.start()
|
|
7102
7191
|
if _is_contract_mode and not agent:
|
|
7103
7192
|
from sourcecode.serializer import contract_view as _contract_view
|
|
@@ -7154,6 +7243,7 @@ def main(
|
|
|
7154
7243
|
content = _serialize_dict(data, format)
|
|
7155
7244
|
|
|
7156
7245
|
perf.stop("serialize", _perf_serialize)
|
|
7246
|
+
_root_seam("serialize")
|
|
7157
7247
|
perf.flush_recorder()
|
|
7158
7248
|
|
|
7159
7249
|
# 5. Write output (CLI-04)
|
|
@@ -7531,6 +7621,7 @@ def prepare_context_cmd(
|
|
|
7531
7621
|
Path("."),
|
|
7532
7622
|
help="Repository path to analyze (default: current directory)",
|
|
7533
7623
|
),
|
|
7624
|
+
jobs: Optional[int] = _jobs_option(),
|
|
7534
7625
|
since: Optional[str] = typer.Option(
|
|
7535
7626
|
None,
|
|
7536
7627
|
"--since",
|
|
@@ -7605,7 +7696,6 @@ def prepare_context_cmd(
|
|
|
7605
7696
|
),
|
|
7606
7697
|
),
|
|
7607
7698
|
progress_mode: Optional[str] = _progress_option(),
|
|
7608
|
-
jobs: Optional[int] = _jobs_option(),
|
|
7609
7699
|
) -> None:
|
|
7610
7700
|
"""Task-specific context for AI coding agents.
|
|
7611
7701
|
|
|
@@ -8426,6 +8516,7 @@ def repo_ir_cmd(
|
|
|
8426
8516
|
Path("."),
|
|
8427
8517
|
help="Repository root to analyze (default: current directory)",
|
|
8428
8518
|
),
|
|
8519
|
+
jobs: Optional[int] = _jobs_option(),
|
|
8429
8520
|
since: Optional[str] = typer.Option(
|
|
8430
8521
|
None,
|
|
8431
8522
|
"--since",
|
|
@@ -8491,7 +8582,6 @@ def repo_ir_cmd(
|
|
|
8491
8582
|
help="Compress output with gzip. Requires --output. Reduces large IR files by ~70-80%.",
|
|
8492
8583
|
),
|
|
8493
8584
|
progress_mode: Optional[str] = _progress_option(),
|
|
8494
|
-
jobs: Optional[int] = _jobs_option(),
|
|
8495
8585
|
) -> None:
|
|
8496
8586
|
"""Deterministic symbol-level IR for Java repositories.
|
|
8497
8587
|
|
|
@@ -9185,6 +9275,7 @@ def endpoints_cmd(
|
|
|
9185
9275
|
Path("."),
|
|
9186
9276
|
help="Repository path to scan for REST endpoints (default: current directory)",
|
|
9187
9277
|
),
|
|
9278
|
+
jobs: Optional[int] = _jobs_option(),
|
|
9188
9279
|
output_path: Optional[Path] = typer.Option(
|
|
9189
9280
|
None, "--output", "-o",
|
|
9190
9281
|
help="Write output to a file instead of stdout.",
|
|
@@ -9251,7 +9342,6 @@ def endpoints_cmd(
|
|
|
9251
9342
|
"than protect).",
|
|
9252
9343
|
),
|
|
9253
9344
|
progress_mode: Optional[str] = _progress_option(),
|
|
9254
|
-
jobs: Optional[int] = _jobs_option(),
|
|
9255
9345
|
) -> None:
|
|
9256
9346
|
"""Extract REST API endpoint surface from Java source files.
|
|
9257
9347
|
|
|
@@ -9806,6 +9896,7 @@ def export_cmd(
|
|
|
9806
9896
|
Path("."),
|
|
9807
9897
|
help="Repository path to export (default: current directory)",
|
|
9808
9898
|
),
|
|
9899
|
+
jobs: Optional[int] = _jobs_option(),
|
|
9809
9900
|
output_path: Optional[Path] = typer.Option(
|
|
9810
9901
|
None, "--output", "-o",
|
|
9811
9902
|
help="Write output to a file instead of stdout.",
|
|
@@ -9848,7 +9939,6 @@ def export_cmd(
|
|
|
9848
9939
|
"written on the diagram whenever it bites.",
|
|
9849
9940
|
),
|
|
9850
9941
|
progress_mode: Optional[str] = _progress_option(),
|
|
9851
|
-
jobs: Optional[int] = _jobs_option(),
|
|
9852
9942
|
) -> None:
|
|
9853
9943
|
"""Export structured, tool-agnostic codebase views for downstream tooling.
|
|
9854
9944
|
|
|
@@ -10015,6 +10105,7 @@ def validation_cmd(
|
|
|
10015
10105
|
Path("."),
|
|
10016
10106
|
help="Repository path to scan for request-body validation (default: current directory)",
|
|
10017
10107
|
),
|
|
10108
|
+
jobs: Optional[int] = _jobs_option(),
|
|
10018
10109
|
output_path: Optional[Path] = typer.Option(
|
|
10019
10110
|
None, "--output", "-o",
|
|
10020
10111
|
help="Write output to a file instead of stdout.",
|
|
@@ -10045,7 +10136,6 @@ def validation_cmd(
|
|
|
10045
10136
|
help=_NO_CACHE_SUBCOMMAND_HELP,
|
|
10046
10137
|
),
|
|
10047
10138
|
progress_mode: Optional[str] = _progress_option(),
|
|
10048
|
-
jobs: Optional[int] = _jobs_option(),
|
|
10049
10139
|
) -> None:
|
|
10050
10140
|
"""Map request-body validation per endpoint (constraints + custom validators).
|
|
10051
10141
|
|
|
@@ -12173,6 +12263,7 @@ def spring_audit_cmd(
|
|
|
12173
12263
|
Path("."),
|
|
12174
12264
|
help="Repository path to audit (default: current directory)",
|
|
12175
12265
|
),
|
|
12266
|
+
jobs: Optional[int] = _jobs_option(),
|
|
12176
12267
|
output_path: Optional[Path] = typer.Option(
|
|
12177
12268
|
None, "--output", "-o",
|
|
12178
12269
|
help="Write output to a file instead of stdout.",
|
|
@@ -12304,7 +12395,6 @@ def spring_audit_cmd(
|
|
|
12304
12395
|
),
|
|
12305
12396
|
detach: bool = _detach_option(),
|
|
12306
12397
|
progress_mode: Optional[str] = _progress_option(),
|
|
12307
|
-
jobs: Optional[int] = _jobs_option(),
|
|
12308
12398
|
) -> None:
|
|
12309
12399
|
"""Spring semantic audit: {{RULE_SUMMARY}}.
|
|
12310
12400
|
|
|
@@ -13483,6 +13573,7 @@ def risk_cmd(
|
|
|
13483
13573
|
Path("."),
|
|
13484
13574
|
help="Repository path (default: current directory).",
|
|
13485
13575
|
),
|
|
13576
|
+
jobs: Optional[int] = _jobs_option(),
|
|
13486
13577
|
limit: int = typer.Option(
|
|
13487
13578
|
50, "--limit", help="How many composed risks to publish (highest first).", min=0,
|
|
13488
13579
|
),
|
|
@@ -13542,7 +13633,6 @@ def risk_cmd(
|
|
|
13542
13633
|
allow_partial: bool = _allow_partial_option(),
|
|
13543
13634
|
detach: bool = _detach_option(),
|
|
13544
13635
|
progress_mode: Optional[str] = _progress_option(),
|
|
13545
|
-
jobs: Optional[int] = _jobs_option(),
|
|
13546
13636
|
) -> None:
|
|
13547
13637
|
"""What each defect actually costs, once reach and access are in it.
|
|
13548
13638
|
|
|
@@ -14796,6 +14886,7 @@ def posture_cmd(
|
|
|
14796
14886
|
Path("."),
|
|
14797
14887
|
help="Repository path (default: current directory).",
|
|
14798
14888
|
),
|
|
14889
|
+
jobs: Optional[int] = _jobs_option(),
|
|
14799
14890
|
profile: Optional[str] = typer.Option(
|
|
14800
14891
|
None,
|
|
14801
14892
|
"--profile",
|
|
@@ -14877,7 +14968,6 @@ def posture_cmd(
|
|
|
14877
14968
|
format: str = _format_option(help="Output format: json or yaml."),
|
|
14878
14969
|
copy: bool = _copy_option(),
|
|
14879
14970
|
progress_mode: Optional[str] = _progress_option(),
|
|
14880
|
-
jobs: Optional[int] = _jobs_option(),
|
|
14881
14971
|
) -> None:
|
|
14882
14972
|
"""Which beans are wired under a profile set — and which cannot be decided.
|
|
14883
14973
|
|
|
@@ -15300,6 +15390,7 @@ def migrate_check_cmd(
|
|
|
15300
15390
|
Path("."),
|
|
15301
15391
|
help="Repository path to scan (default: current directory)",
|
|
15302
15392
|
),
|
|
15393
|
+
jobs: Optional[int] = _jobs_option(),
|
|
15303
15394
|
output_path: Optional[Path] = typer.Option(
|
|
15304
15395
|
None, "--output", "-o",
|
|
15305
15396
|
help="Write output to a file instead of stdout.",
|
|
@@ -15441,7 +15532,6 @@ def migrate_check_cmd(
|
|
|
15441
15532
|
),
|
|
15442
15533
|
detach: bool = _detach_option(),
|
|
15443
15534
|
progress_mode: Optional[str] = _progress_option(),
|
|
15444
|
-
jobs: Optional[int] = _jobs_option(),
|
|
15445
15535
|
) -> None:
|
|
15446
15536
|
"""Spring Boot 2→3 migration readiness + Java LTS/licensing inventory.
|
|
15447
15537
|
|
|
@@ -15847,6 +15937,7 @@ def impact_chain_cmd(
|
|
|
15847
15937
|
Path("."),
|
|
15848
15938
|
help="Repository root (default: current directory)",
|
|
15849
15939
|
),
|
|
15940
|
+
jobs: Optional[int] = _jobs_option(),
|
|
15850
15941
|
depth: int = typer.Option(
|
|
15851
15942
|
4,
|
|
15852
15943
|
"--depth",
|
|
@@ -15886,7 +15977,6 @@ def impact_chain_cmd(
|
|
|
15886
15977
|
),
|
|
15887
15978
|
),
|
|
15888
15979
|
progress_mode: Optional[str] = _progress_option(),
|
|
15889
|
-
jobs: Optional[int] = _jobs_option(),
|
|
15890
15980
|
) -> None:
|
|
15891
15981
|
"""Spring impact-chain: systemic blast radius of a symbol; TX/SEC findings are opt-in.
|
|
15892
15982
|
|