sourcecode 5.8.13__py3-none-any.whl → 5.8.15__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/_docs/DEFECT-LEDGER.md +85 -10
- sourcecode/_docs/USER_GUIDE.md +57 -11
- sourcecode/archetype.py +5 -0
- sourcecode/breaking_changes.py +41 -1
- sourcecode/cache_model.py +7 -0
- sourcecode/change_plan.py +8 -1
- sourcecode/ci_output.py +73 -0
- sourcecode/cli.py +585 -45
- sourcecode/compare.py +7 -1
- sourcecode/context_cache.py +17 -0
- sourcecode/data_labels.py +63 -0
- sourcecode/execution_plan.py +19 -0
- sourcecode/format_contract.py +5 -4
- sourcecode/github_diff.py +34 -0
- sourcecode/migrate_check.py +16 -7
- sourcecode/migration_apply.py +241 -0
- sourcecode/phased_run.py +6 -0
- sourcecode/posture.py +52 -9
- sourcecode/prepare_context.py +7 -0
- sourcecode/readonly.py +32 -8
- sourcecode/rename_refactor.py +14 -4
- sourcecode/repository_ir.py +88 -17
- sourcecode/retrieval/steps_impact.py +1 -1
- sourcecode/risk.py +13 -0
- sourcecode/schema.py +6 -3
- sourcecode/schema_registry.py +5 -0
- sourcecode/security_posture.py +9 -1
- sourcecode/selftest.py +46 -7
- sourcecode/serializer.py +27 -8
- sourcecode/spring_model.py +13 -0
- sourcecode/summarizer.py +54 -12
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/METADATA +29 -16
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/RECORD +38 -35
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/WHEEL +0 -0
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/entry_points.txt +0 -0
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/licenses/LICENSE +0 -0
- {sourcecode-5.8.13.dist-info → sourcecode-5.8.15.dist-info}/licenses/NOTICE +0 -0
sourcecode/__init__.py
CHANGED
|
@@ -16,24 +16,99 @@ The facts these rows are keyed to are published: `ask schema facts-v1` prints th
|
|
|
16
16
|
|
|
17
17
|
## Current Synchronization
|
|
18
18
|
|
|
19
|
-
**
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
**Latest attached audit of release `5.8.14`; correction battery targets `5.8.15`:** score **93/100**, coverage **53/61
|
|
20
|
+
invocables (87%)**, byte-identical CIR across five versions, and no functional-result
|
|
21
|
+
regression. One reproducible performance regression is now the primary release concern;
|
|
22
|
+
the historical `risk` P0 remains open because five successful runs do not disprove two
|
|
23
|
+
earlier exit-0/no-output failures. Only the fifth-pass section below declares present
|
|
24
|
+
state; older audit rounds remain below for traceability.
|
|
25
|
+
|
|
26
|
+
**Release status:** entries marked “pending `5.8.14`” in their historical wording are
|
|
27
|
+
shipped in `5.8.14`; the correction battery fixes listed above are included in `5.8.15`.
|
|
28
|
+
|
|
29
|
+
The battery also closed the following reproducible contract defects in `5.8.15`:
|
|
30
|
+
`migrate-apply` is registered across help, progress, path-admission, output-purity,
|
|
31
|
+
cache and schema authorities (`1d00ba2`); endpoint census output distinguishes excluded
|
|
32
|
+
test modules from retained test-fixture routes (`f65336d`, `014dec7`, `1c6cd0b`);
|
|
33
|
+
and compact posture output retains counts while omitting unresolved bodies (`dad5dad`).
|
|
34
|
+
|
|
35
|
+
### Fifth Audit Pass: `5.8.14` / `saint-server` / 2026-08-20
|
|
36
|
+
|
|
37
|
+
| ID | Severity | Current status | Required direction |
|
|
38
|
+
|---|---|---|---|
|
|
39
|
+
| `BUG-1` / `AUD-511-R02`, `AUD-589-B02`, `AUD-513-N06` | P1 | **not reproduced locally; external closure pending**: isolated/interleaved controls did not reproduce the reported slowdown. | Repeat the six-run protocol on the audit host and compare 5.8.13/5.8.15 with byte-equivalent output. |
|
|
40
|
+
| `BUG-2` / `AUD-588-B01`, `AUD-589-B01`, `C3-122` | P0 | **open, not reproduced in five runs**: all five current `risk` runs produced exit 0 and a ~311 KB artifact; historical failures remain material. | Keep the real-entry-point output invariant. Treat `b5acc63` and the existing working-set/timing instrumentation as hardening, not field closure. |
|
|
41
|
+
| `BUG-3` / `AUD-511-R02`, `AUD-589-B02`, `AUD-513-N06` | P1 | **implemented in 5.8.15; numeric external remeasurement pending**: labelled runs now reuse shared CIR (`443b345`). | Re-run the controlled external benchmark; do not infer a speedup from a different host. |
|
|
42
|
+
| `BUG-4a` / `AUD-588-B11` residual | P2 | **closed in 5.8.15** (`24b4185`): `onboard` and `archetype` publish explicit source-file population units and totals. | Keep parity tests on both payloads. |
|
|
43
|
+
| `BUG-4b` / `AUD-588-B11` residual | P2 | **closed in 5.8.15** (`0376350`): help, tier table and docs agree that `risk` is supported. | Keep the single `COMMAND_TIERS` authority. |
|
|
44
|
+
| `BUG-4c` / `SEC-009` calibration | P2 / product decision | **by-design in 5.8.15** (`fb7632a`): medium is retained and pinned; active/profile evidence supplies context. | Reopen only with a new product-risk decision, not from the same observation. |
|
|
45
|
+
| `BUG-5` / `AUD-588-B12`, `AUD-588-F03` | P2 | **open, measurement improved but not portable yet**: local six-run `risk` converged at 6.56s (clean control, Broadleaf, 5.8.14); this is not comparable to the historical Windows anchor. | Add a provenance-bearing, cross-host anchor before changing the operational model. |
|
|
46
|
+
| `AUD-588-F05` | Validation gap | **locally verified only**: dirty-tree `verify-edit` and eight mutating/denied invocables remain unexercised externally. | Clone the repository into scratch space, edit the clone and run the dirty-tree protocol; do not use an archive without `.git`. |
|
|
47
|
+
|
|
48
|
+
**Fifth-pass anchor correction:** `posture.summary` now reports the Spring IoC population
|
|
49
|
+
(`population_total: 1904`, `conditional: 5`, `active: 3`, `inactive: 2`, `unconditional:
|
|
50
|
+
1899`) instead of the former type count (`6667`). This is an intentional correction with
|
|
51
|
+
explicit units, not a regression. The audit remains static: it did not start the application.
|
|
52
|
+
|
|
53
|
+
**Recommended order:** BUG-1 measurement/isolation → `risk` phase-cost investigation →
|
|
54
|
+
BUG-3 reuse comparison → BUG-4 contract cleanup → BUG-5 calibration. Keep EclipseLink
|
|
55
|
+
automation deferred; provider non-coverage is the honest current behavior. `F02` remains
|
|
56
|
+
partial, `F03` open, `F04` explicit opt-in and `F05` locally verified only.
|
|
57
|
+
|
|
58
|
+
### Historical Execution Queue: `5.8.14` Intake
|
|
59
|
+
|
|
60
|
+
| ID | Severity | Current status | Required direction |
|
|
61
|
+
|---|---|---|---|
|
|
62
|
+
| `R-1` | High | **closed by `424fb1c`** | Delivery timing now publishes current elapsed time plus cache and phase provenance. |
|
|
63
|
+
| `R-2` | Medium | **closed by `5158b92`** | `BC-004` declares removed fields, replacements and effective version. |
|
|
64
|
+
| `R-3` | Medium | **closed by `88aec04`** | Global cache purge now clears parse and Shared CIR stores. |
|
|
65
|
+
| `R-4` | Medium | **closed by `04fd04f`** | Payload layers are homonymous with their authorities: `cir`, `parse_store`, `snapshot`, `ris`. |
|
|
66
|
+
| `N-6` | Medium | **not reproduced after cache fixes** | Isolated cold `openmrs-core`: 5.18 s wall / 4.76 s internal, all four layers cold. Retain the field report as an environment-specific reproduction request. |
|
|
67
|
+
| `B-3` | Medium, core/supported | **closed by `773268d`** | Help no longer claims maximum signal; `sibling_view` points to compact. |
|
|
68
|
+
| `B-6` | Medium, core | **closed by `17c6e06`** | Partial answers publish `overrun_bound` and its wall-clock basis. |
|
|
69
|
+
| `B-8` | Low | **closed by `52593b6`** | Compact posture retains one unresolved sample when the total is non-zero. |
|
|
70
|
+
| `N-5` | Low, core | **closed by `c68083f`** | Progress and payload name the Java population. |
|
|
71
|
+
| `N-7` | Low, core | **closed by `082e9de`** | Bounded fuzzy candidates and matching message hints handle close typos. |
|
|
72
|
+
|
|
73
|
+
**Recommended features/hardening:** response timing provenance and root cache-layer
|
|
74
|
+
disclosure; a single cache reset/state authority; compact/agent parity or sibling-view
|
|
75
|
+
metadata; a partial-budget exit contract; shared population/units authority; reusable fuzzy
|
|
76
|
+
symbol suggestions; and a release gate for `breaking-changes-v1` whenever core or supported
|
|
77
|
+
fields are removed. These extend `AUD-588-F02` and `AUD-588-F03`. `AUD-588-F01` EclipseLink
|
|
78
|
+
automation remains deferred; provider non-coverage is the current product behavior.
|
|
24
79
|
|
|
25
80
|
| Rows | Current status | Evidence |
|
|
26
81
|
|---|---|---|
|
|
27
|
-
| `AUD-588-B01
|
|
82
|
+
| `AUD-588-B01` / `AUD-589-B01`, `C3-122` | **open, P0 for `risk`; `audit-report` corrected** | `9884488` corrected `audit-report` to refuse with typed `OUTPUT_TOO_LARGE` and produce its requested artifact. `risk` nevertheless exited 0 twice on the first shared-cache invocations with 0 bytes and no `-o` file, then succeeded seven times. `5cfa9ba` now publishes the source, audit-finding, candidate-defect and composed-defect working set, including partial answers. Repeat the real entry-point protocol before closure. |
|
|
28
83
|
| `AUD-511-R01` / `AUD-588-B03` | **implemented in 5.8.12** | `13362ec` makes SEC-009 read comment-blanked Java, so a Javadoc profile cannot override the live `@Profile("!m3")` declaration. |
|
|
29
84
|
| `AUD-588-B04` | **retracted audit premise** | `data-exposure` correctly preserves `chain_decision`; the reported `coverage_unknown` routes were custom-gate annotations whose application was not configured. `fd34eb1` remains a valid additive disclosure, but no further B04 fix is due. |
|
|
30
85
|
| `AUD-588-B05` | **closed** | `c15f5b6`; changed container-wired components block a false `unaffected` disposition. |
|
|
31
|
-
| `AUD-511-R03` / `AUD-588-B07` | **implemented
|
|
86
|
+
| `AUD-511-R03` / `AUD-588-B07` | **implemented, pending 5.8.14 re-audit** | `f613df9` makes ASK-09 parse the typed document from stdout or stderr, including a progress-prefixed stderr stream, and removes the four inherited variables that change its precondition. The regression exercises the real typed refusal shape. The prior claim that the payload premise was false remains retracted as an environment-contamination artifact. |
|
|
32
87
|
| `AUD-588-B08` | **closed** | `c084555`; `impact` publishes its independent stdout-byte budget. |
|
|
33
88
|
| `MCP-001` | **closed 5.8.13** | Deep corpus testing reproduced concurrent `CliRunner` stream capture leaking a tool response to the host stdout. `b2c9660` serializes the narrow process-global capture seam; concurrent real MCP calls and a regression test verify response isolation. |
|
|
34
|
-
| `AUD-
|
|
35
|
-
| `AUD-
|
|
36
|
-
| `AUD-
|
|
89
|
+
| `AUD-513-N01` (`N-1`) | **closed in 5.8.14** | `rename-class` rewrote three Petclinic files under both `ASK_READONLY=1` and `--no-write`, then exited 0. The audit restored the tree; this is a write-policy breach, not an artifact-directory exception. `readonly.guard_mutation()` now refuses before any planned source write or physical rename; help names the command as mutating and regressions cover both readonly controls plus `--dry-run`. |
|
|
90
|
+
| `AUD-513-N02` / `B-4` / `N-5` | **N02/B-4 implemented in 5.8.14; N-5 open** | `posture.summary.unconditional` counted 1,697 on a non-Spring Struts tree and 1,573 on Mall, and `security` was `0/0/0` with no population. The posture projection now uses the canonical Spring IoC bean population, publishes its population/unit and separates unconditional security beans. Regressions cover non-Spring, mixed-bean and conditional/unconditional security fixtures. Progress/advice still use incompatible “Java files” scopes (`N-5`), so the `AUD-588-F02` family remains open. |
|
|
91
|
+
| `AUD-513-B01` / `B-3` / `B-5` | **B01/B-5 implemented in 5.8.14; B-3 closed as revalidated** | A MyBatis XML paired with a `*Mapper.java` interface now takes precedence over an absent `@Mapper` annotation, preserving XML-backed/`@MapperScan` interfaces in `mapper_interfaces` rather than misclassifying them as DTO mappers. `imports_found` now contains only actual Java imports; code, XML and build matches are emitted as `evidence`, including in compact output. `B-3` was stale against the current source: both views consume `JAVA_SPRING_SECTIONS`; a real MyBatis Mapper/XML regression proves the section is retained by `--agent`. |
|
|
92
|
+
| `AUD-513-N03/N04/N07/N08/N09`, `B-6/B-7/B-8`, `D-09` | **N03/N04/N07/N08/N09 implemented in 5.8.14; remainder open** | `impact` now always publishes the `candidates` field its not-found message names, including `[]` when no close symbol exists. Budget advice no longer calls partial snapshot/RIS evidence a warm cache: it identifies that presence and says context/parse are unknown before analysis, whose payload then reports all four actual layers. README operational sections (`clone`, install, build, getting started, troubleshooting and related headings) are never promoted into a project summary; with no descriptive prose compact output publishes `project_summary: null` and `summary_basis`. `security_posture.limitations` is now cache-state invariant; dynamic execution advice travels in `security_posture.operational_hints`. Every numeric output bound rejects negative values at parse time with a structured `INVALID_INPUT` envelope (`flag`, `value`, `expected`); `--limit 0` still means no cap wherever that behavior was published. Budgets overrun, timing coverage is inconsistent, compact hides unresolved identities and cost anchors remain stale. |
|
|
93
|
+
| `AUD-588-B11` (container/units subset) | **partially implemented in 5.8.14** | `d745d31` discovers nested Maven modules; `273ae8e` suppresses unsupported `pr-impact.unaffected_basis`. `e53507d` separates direct impact matches from analysis seeds and implementation classes; `8386744` carries the established container-wiring fact into plan checklists and compare cost dimensions. Source population units and risk-tier wording remain open. |
|
|
94
|
+
| `AUD-511-R02` / `AUD-589-B02` / `AUD-513-N06` | **partially corrected; `data-exposure` open, P1** | Nine of ten measured commands recovered, many to their best historical timings. `data-exposure --config` did not: 42.7 s versus 16.2 s in 5.8.8 and a 28.9 s model, with byte-equivalent output. Measure it with the idle-host, isolated-cache, interleaved-control protocol before changing code, then compare its reuse path with `validation`. |
|
|
95
|
+
| `AUD-588-B02`, `B06`, B11 residuals, `B12` | **B02/B06 closed; B11/B12 open, P2** | `3869c87` excludes explicit EclipseLink from Hibernate applicability and effort; `037223e` publishes provider non-coverage. The re-audit verifies both and the payload reduction; `cf57457` makes aggregate wording name only applicable dimensions. Complete B11 consumer parity and calibrate B12 only from provenance-bearing controlled samples. |
|
|
96
|
+
|
|
97
|
+
### Fourth Re-audit: 5.8.13
|
|
98
|
+
|
|
99
|
+
The fourth pass verifies the current facts that supersede the prior intake. There is no
|
|
100
|
+
crash/traceback and no regression in the published anchors. `B-2/D-05` remains a retracted
|
|
101
|
+
servlet premise, and the audit additionally verifies EclipseLink applicability/non-coverage,
|
|
102
|
+
typed `audit-report` refusal, nested Maven discovery and the `unaffected_basis` correction.
|
|
103
|
+
It leaves the following concrete queue rather than reopening closed facts.
|
|
104
|
+
|
|
105
|
+
| Recommendation | Status and direction |
|
|
106
|
+
|---|---|
|
|
107
|
+
| `AUD-588-F02` shared answer contracts | **Partial.** Reuse the existing authorities for exact target versus implementation cone, named source populations and container reach in plan/compare; do not add a parallel detector. |
|
|
108
|
+
| `AUD-588-F03` versioned cost calibration | **Open.** Capture repository, cache state, sample count and host provenance. The immediately actionable measurement is `data-exposure --config`; clean data is required before recalibration. |
|
|
109
|
+
| Risk cache observability | **Recommended hardening.** Publish working-set unit counts under progress or in the envelope to distinguish an empty compositor from a present-but-incomplete cache. |
|
|
110
|
+
| `AUD-588-F05` coverage expansion | **Locally verified only.** Dirty-tree `verify-edit` and the eight mutating/denied invocables remain unexercised in all four external rounds. |
|
|
111
|
+
| EclipseLink migration automation | **Deferred product feature.** The current applicability and non-coverage facts are verified; provider-specific migration automation is not a corrective fix. |
|
|
37
112
|
|
|
38
113
|
### Re-audit Intake: 5.8.11
|
|
39
114
|
|
sourcecode/_docs/USER_GUIDE.md
CHANGED
|
@@ -6,7 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
## What is it
|
|
8
8
|
|
|
9
|
-
A local CLI.
|
|
9
|
+
A local CLI. Source analysis runs on your machine; it does not need an API key or
|
|
10
|
+
an account. Anonymous telemetry is enabled by default and may send operational
|
|
11
|
+
event metadata, never source content, paths, secrets, or command output. Disable
|
|
12
|
+
it with `ask telemetry disable`, `SOURCECODE_TELEMETRY=0`, or `DO_NOT_TRACK=1`
|
|
13
|
+
before a run when policy requires it. See [privacy.md](privacy.md).
|
|
10
14
|
|
|
11
15
|
It builds a deterministic symbol graph (classes, annotations, injection edges, HTTP routes) from your repository's source files and answers structural questions about that graph. All analysis is static — it reads code, not runtime behavior.
|
|
12
16
|
|
|
@@ -42,7 +46,7 @@ CLI commands — impact, endpoints, spring-audit, explain, … each a pro
|
|
|
42
46
|
The key idea: the extraction is **content-addressed**. Commands reuse the parse cache and,
|
|
43
47
|
where their analysed scope matches, the shared Canonical IR; `ask cache model` names what a
|
|
44
48
|
warm buys for each command rather than implying that every projection costs the same. In
|
|
45
|
-
5.8.
|
|
49
|
+
5.8.15, `validation` enters through that shared CIR and `data-exposure` reuses one semantic
|
|
46
50
|
model across all declared label seeds. (The extraction and consumption contract is fixed in
|
|
47
51
|
the architecture ADRs 0001–0004 under `docs/architecture/`.)
|
|
48
52
|
|
|
@@ -138,16 +142,20 @@ pipx install sourcecode # isolated install, no venv needed
|
|
|
138
142
|
|
|
139
143
|
# Verify
|
|
140
144
|
ask version
|
|
141
|
-
# ask 5.8.
|
|
145
|
+
# ask 5.8.15
|
|
142
146
|
```
|
|
143
147
|
|
|
144
148
|
Requires Python 3.9+.
|
|
145
149
|
|
|
146
150
|
---
|
|
147
151
|
|
|
148
|
-
##
|
|
152
|
+
## Entitlement and activation
|
|
149
153
|
|
|
150
|
-
|
|
154
|
+
Base analysis works immediately after install. The effective entitlement is a runtime
|
|
155
|
+
fact, not a command list in this document: use `ask auth status` to see what runs,
|
|
156
|
+
why it runs, and when that source changes. During the current early-adoption period
|
|
157
|
+
the Pro entitlement may be unlocked without a key; an activated key remains the
|
|
158
|
+
explicit way to establish an entitlement when one is required.
|
|
151
159
|
|
|
152
160
|
```bash
|
|
153
161
|
ask activate SC-XXXX-XXXX-XXXX
|
|
@@ -179,7 +187,7 @@ estimate scaled by file count would be wrong in the direction that costs you a s
|
|
|
179
187
|
and an anchor printed without its release goes on recommending a nightly job for a command
|
|
180
188
|
that has come to finish in seconds (C3-97).
|
|
181
189
|
|
|
182
|
-
|
|
190
|
+
41 commands and six command groups exist. Four of them carry most of the measured
|
|
183
191
|
value in field use, and they are the ones to learn first:
|
|
184
192
|
|
|
185
193
|
| Start with | Because |
|
|
@@ -256,6 +264,9 @@ ask onboard . --output onboard.json
|
|
|
256
264
|
```
|
|
257
265
|
|
|
258
266
|
Output: architecture summary, subsystems, key entry points, hotspots, tech-debt signals, analysis gaps.
|
|
267
|
+
The payload also publishes `population`, `population_unit` and `population_total`; these
|
|
268
|
+
describe the non-test source-file universe behind the onboarding ranking, not every file
|
|
269
|
+
in the repository.
|
|
259
270
|
|
|
260
271
|
### `ask endpoints` *(core)*
|
|
261
272
|
|
|
@@ -342,6 +353,7 @@ ask spring-audit . --output audit.json
|
|
|
342
353
|
ask spring-audit . --since origin/main --fail-on-new # gate on what THIS change added
|
|
343
354
|
ask spring-audit . --remediation-diff # the patches a reviewer applies
|
|
344
355
|
ask spring-audit . --clusters # the work items behind the findings
|
|
356
|
+
ask spring-audit . --ci --format github-actions # native CI annotation plus ASK_CI summary
|
|
345
357
|
```
|
|
346
358
|
|
|
347
359
|
**`--since <ref>` / `--fail-on-new` — the gate a repository with debt can turn on.**
|
|
@@ -379,7 +391,7 @@ disabled changes runtime behaviour nobody measured; a diff is how a person makes
|
|
|
379
391
|
call with the evidence in front of them.
|
|
380
392
|
|
|
381
393
|
**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.
|
|
382
|
-
**SEC patterns (SEC-001..SEC-
|
|
394
|
+
**SEC patterns (SEC-001..SEC-009):** 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, and anonymous request-chain exceptions. **DEAD-001** reports a security control that is present only in comments and therefore disabled.
|
|
383
395
|
**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.
|
|
384
396
|
|
|
385
397
|
Each finding includes `severity`, `confidence`, `symbol`, `source_file`, `evidence`, `explanation`, and `fix_hint`. JAVA/SPRING ONLY.
|
|
@@ -656,6 +668,22 @@ cannot be reviewed as one change (on openmrs-core, including it takes the popula
|
|
|
656
668
|
— its own, and `migrate-check`'s narrower headline `blocking_count` — because two
|
|
657
669
|
populations under one name is the defect this project keeps finding in its own output.
|
|
658
670
|
|
|
671
|
+
### `ask migrate-apply` *(supported)*
|
|
672
|
+
|
|
673
|
+
```bash
|
|
674
|
+
ask migrate-apply . # plan only; no mutation
|
|
675
|
+
ask migrate-apply . --write --rewrite-version X.Y.Z
|
|
676
|
+
ask migrate-apply . --write --rewrite-version X.Y.Z --compile
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
The default is read-only. `--write` requires a clean Git tree and runs the measured
|
|
680
|
+
recipe in a separate branch/worktree with a pinned OpenRewrite version. The main tree
|
|
681
|
+
is not modified and ASK does not commit or merge. Maven and Gradle are supported
|
|
682
|
+
executors; Gradle uses a temporary OpenRewrite init script and does not modify the
|
|
683
|
+
project build files. After rewriting, ASK runs `migrate-check` on the
|
|
684
|
+
isolated result. `--compile` adds a build with tests skipped and a timeout; network access
|
|
685
|
+
requires `--allow-network`. Any failed stage removes the temporary branch/worktree.
|
|
686
|
+
|
|
659
687
|
### `ask data-exposure` *(supported)*
|
|
660
688
|
|
|
661
689
|
**Which routes can carry the data you called sensitive, and who reaches them.** Nothing
|
|
@@ -673,9 +701,15 @@ engine never branches on a name. Declare it once, in `sourcecode.config.json`:
|
|
|
673
701
|
```bash
|
|
674
702
|
ask data-exposure . # every route that can carry a declared label
|
|
675
703
|
ask data-exposure . --profile prod # …and what THAT deployment leaves reachable
|
|
704
|
+
ask data-exposure . --init --dry-run # suggest candidates, write nothing
|
|
705
|
+
ask data-exposure . --init # write proposed_only candidates under .ask/
|
|
676
706
|
ask data-exposure /path/to/repo -o exposure.json
|
|
677
707
|
```
|
|
678
708
|
|
|
709
|
+
`--init` never infers or activates a label. It writes only
|
|
710
|
+
`.ask/data-label-candidates-v1.json`; approved labels still require a human declaration
|
|
711
|
+
in `sourcecode.config.json`.
|
|
712
|
+
|
|
679
713
|
Everything after the declaration is measured, over authorities that already exist: the
|
|
680
714
|
call reach `impact-chain` walks, the endpoint security surface `risk` weighs, and the
|
|
681
715
|
profile resolution `posture` publishes. Two evidence classes, published apart and **never
|
|
@@ -1059,6 +1093,7 @@ ask verify # gate: only NEW violations block (--fail-on
|
|
|
1059
1093
|
ask verify --capture-baseline # accept today's debt, once
|
|
1060
1094
|
ask verify --fail-on any # gate on every violation, debt included
|
|
1061
1095
|
ask verify --fail-on never # report without gating
|
|
1096
|
+
ask verify --format github-actions # native CI annotation; exit contract is unchanged
|
|
1062
1097
|
```
|
|
1063
1098
|
|
|
1064
1099
|
**Start with `--init`.** Nobody hand-writes contracts for a 3 000-file monolith, and a gate
|
|
@@ -1130,6 +1165,10 @@ The same blast radius, scoped to a diff, with gating exit codes.
|
|
|
1130
1165
|
git diff --name-only origin/main | ask pr-impact . --files -
|
|
1131
1166
|
ask pr-impact . --files changed_files.txt --fail-on high
|
|
1132
1167
|
ask pr-impact . --files A.java,B.java
|
|
1168
|
+
ask pr-impact . # local git diff HEAD
|
|
1169
|
+
ask pr-impact . --since origin/main # local diff from a base ref
|
|
1170
|
+
ask pr-impact . --pr 123 # opt-in GitHub CLI adapter
|
|
1171
|
+
ask pr-impact . --format github-actions # CI annotations, JSON remains the default
|
|
1133
1172
|
```
|
|
1134
1173
|
|
|
1135
1174
|
Reports modified classes, the REST endpoints reachable through their call chains, direct
|
|
@@ -1137,6 +1176,10 @@ callers, event publishers and consumers, `@Transactional` methods in the changed
|
|
|
1137
1176
|
a consolidated risk level. **A changed Java file that maps to no class caps the verdict at
|
|
1138
1177
|
`UNKNOWN`** — a partial blast radius is never reported as a low one.
|
|
1139
1178
|
|
|
1179
|
+
`--pr NUMBER` invokes the local `gh` CLI to obtain the changed paths. It is opt-in, does not
|
|
1180
|
+
fetch or modify the repository, and requires local GitHub authentication. It cannot be
|
|
1181
|
+
combined with `--files` or `--since`; those modes remain fully offline.
|
|
1182
|
+
|
|
1140
1183
|
---
|
|
1141
1184
|
|
|
1142
1185
|
## Measuring a change, before and after
|
|
@@ -1293,7 +1336,9 @@ The MCP server exposes structural analysis tools to AI agents without requiring
|
|
|
1293
1336
|
|
|
1294
1337
|
## Output schema
|
|
1295
1338
|
|
|
1296
|
-
|
|
1339
|
+
Analysis and report commands output structured JSON to stdout unless `--output` is
|
|
1340
|
+
specified. Status and management commands intentionally return concise text, and
|
|
1341
|
+
`ask explain` defaults to text; each command's `--help` names its supported formats.
|
|
1297
1342
|
|
|
1298
1343
|
Common fields:
|
|
1299
1344
|
- `schema_version` — format version
|
|
@@ -1574,11 +1619,12 @@ Allowed formats per command (the first is the default):
|
|
|
1574
1619
|
| `endpoints` | `json`, `yaml` | `json` |
|
|
1575
1620
|
| `validation` | `json`, `yaml` | `json` |
|
|
1576
1621
|
| `impact-chain` | `json`, `yaml` | `json` |
|
|
1577
|
-
| `spring-audit` | `json`, `yaml`, `github-comment` | `json` |
|
|
1622
|
+
| `spring-audit` | `json`, `yaml`, `github-comment`, `github-actions` | `json` |
|
|
1578
1623
|
| `prepare-context` | `json`, `github-comment` | `json` |
|
|
1579
|
-
| `migrate-check` | `json`, `text` | `json` |
|
|
1624
|
+
| `migrate-check` | `json`, `text`, `github-actions` | `json` |
|
|
1580
1625
|
| `explain` | `text`, `json` | `text` |
|
|
1581
|
-
| `pr-impact` | `json`, `text` | `json` |
|
|
1626
|
+
| `pr-impact` | `json`, `text`, `github-actions` | `json` |
|
|
1627
|
+
| `verify` | `json`, `yaml`, `github-actions` | `json` |
|
|
1582
1628
|
|
|
1583
1629
|
`explain` defaults to a human-readable `text` view; pass `-f json` for
|
|
1584
1630
|
programmatic consumption. `pr-impact` defaults to `json` like every other
|
sourcecode/archetype.py
CHANGED
|
@@ -134,12 +134,16 @@ class ArchetypeAnalysis:
|
|
|
134
134
|
signals_used: list[str]
|
|
135
135
|
signals_missing: list[str]
|
|
136
136
|
generated_from: str
|
|
137
|
+
total_files: int
|
|
137
138
|
graph_metrics: dict[str, float] = field(default_factory=dict)
|
|
138
139
|
|
|
139
140
|
def to_dict(self) -> dict[str, Any]:
|
|
140
141
|
return {
|
|
141
142
|
"schema_version": "0.1-experimental",
|
|
142
143
|
"note": "Parallel/experimental model. Legacy architecture pattern is unchanged.",
|
|
144
|
+
"population": "source files",
|
|
145
|
+
"population_unit": "source files in the scanned repository tree",
|
|
146
|
+
"population_total": self.total_files,
|
|
143
147
|
"dimensions": {
|
|
144
148
|
dim: {
|
|
145
149
|
"primary": r.primary,
|
|
@@ -269,6 +273,7 @@ class ArchetypeClassifier:
|
|
|
269
273
|
else "endpoint surface not measured"
|
|
270
274
|
)
|
|
271
275
|
),
|
|
276
|
+
total_files=f.total_files,
|
|
272
277
|
graph_metrics=f.graph_metrics,
|
|
273
278
|
)
|
|
274
279
|
|
sourcecode/breaking_changes.py
CHANGED
|
@@ -273,11 +273,51 @@ DEPRECATED_FIELD_REMOVAL = BreakingChange(
|
|
|
273
273
|
)
|
|
274
274
|
|
|
275
275
|
|
|
276
|
+
def _released_schema_removals() -> "list[dict[str, object]]":
|
|
277
|
+
"""Fields removed in 5.8.14, kept as an explicit migration record."""
|
|
278
|
+
return [
|
|
279
|
+
{
|
|
280
|
+
"identifier": identifier,
|
|
281
|
+
"becomes": replacement,
|
|
282
|
+
"removed_in": "5.8.14",
|
|
283
|
+
}
|
|
284
|
+
for identifier, replacement in (
|
|
285
|
+
("migrate-check.findings[].imports_found", "use findings[].evidence"),
|
|
286
|
+
("ask.mybatis.dto_mappers", "use the compact sibling view or full output"),
|
|
287
|
+
("ask.mybatis.dto_mappers_total", "use mybatis.mapper_interfaces"),
|
|
288
|
+
("ask.mybatis.dto_mappers_truncated", "use the view cap metadata"),
|
|
289
|
+
)
|
|
290
|
+
]
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
RELEASED_SCHEMA_REMOVALS = BreakingChange(
|
|
294
|
+
id="BC-004",
|
|
295
|
+
kind=KIND_CONTRACT,
|
|
296
|
+
released_in="5.8.14",
|
|
297
|
+
takes_effect_in="5.8.14",
|
|
298
|
+
title="core and supported payload fields removed in a patch release",
|
|
299
|
+
what_changed=(
|
|
300
|
+
"The 5.8.14 payload no longer emits the fields listed in "
|
|
301
|
+
"affected_values. This is a contract change even where the replacement "
|
|
302
|
+
"is a better signal, because consumers must be able to schedule the "
|
|
303
|
+
"migration rather than discover a missing key at runtime."
|
|
304
|
+
),
|
|
305
|
+
trigger="a consumer reads one of the removed fields from migrate-check or the root ask payload",
|
|
306
|
+
compatibility=(
|
|
307
|
+
"pin 5.8.13 while migrating, or treat each affected field as optional "
|
|
308
|
+
"and read the replacement named beside it"
|
|
309
|
+
),
|
|
310
|
+
remedy="dispatch on the replacement and gate on its presence before upgrading",
|
|
311
|
+
affected=_released_schema_removals,
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
|
|
276
315
|
#: Every declared breaking change, newest first. A release that breaks a caller
|
|
277
316
|
#: and does not add a row here fails `tests/test_breaking_change_
|
|
278
317
|
#: disclosure_ask11.py` — the policy is enforced, not remembered.
|
|
279
318
|
BREAKING_CHANGES: tuple[BreakingChange, ...] = (
|
|
280
|
-
|
|
319
|
+
RELEASED_SCHEMA_REMOVALS, DEPRECATED_FIELD_REMOVAL,
|
|
320
|
+
SCHEMA_VERSION_RENAMES, OUTPUT_CEILING,
|
|
281
321
|
)
|
|
282
322
|
|
|
283
323
|
|
sourcecode/cache_model.py
CHANGED
|
@@ -297,6 +297,13 @@ COMMANDS: tuple[CommandCache, ...] = (
|
|
|
297
297
|
"the parse, not the rule pass.",
|
|
298
298
|
"not measured on the battery yet — bounded by `migrate-check` on the same "
|
|
299
299
|
"repository (openmrs-core ~2 s)", analysis_class="repo-wide"),
|
|
300
|
+
CommandCache("migrate-apply", ("parse",), "shared", False,
|
|
301
|
+
"Plan mode reads the same migration findings as `migrate-check`; apply mode "
|
|
302
|
+
"then uses an isolated worktree and never mutates the main tree. A warm can "
|
|
303
|
+
"remove shared parse work, but it does not cache the generated plan or the "
|
|
304
|
+
"optional rewrite/compile execution.",
|
|
305
|
+
"not measured on the battery yet — bounded by `migrate-check` plus the "
|
|
306
|
+
"optional OpenRewrite execution", analysis_class="repo-wide"),
|
|
300
307
|
CommandCache("data-exposure", ("cir", "parse"), "shared", False,
|
|
301
308
|
"Walks the same call reach as `impact-chain` once per declared type and "
|
|
302
309
|
"reads the endpoint security surface, both over the shared CIR a warm "
|
sourcecode/change_plan.py
CHANGED
|
@@ -139,7 +139,9 @@ def build_change_plan(
|
|
|
139
139
|
),
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
|
|
142
|
+
# The user-facing match names the requested target; planning must retain the
|
|
143
|
+
# subtype-expanded seeds that the blast-radius authority actually analysed.
|
|
144
|
+
seeds = list(blast.get("analysis_seed_fqns") or blast["matched_fqns"])
|
|
143
145
|
container_wired = [w.to_dict() for w in detect_classes(cir, seeds)]
|
|
144
146
|
meta = _node_meta(cir)
|
|
145
147
|
affected = _dependents_closure(cir.reverse_graph or {}, seeds, max_depth, _NODE_CAP)
|
|
@@ -210,6 +212,11 @@ def build_change_plan(
|
|
|
210
212
|
checklist.append(
|
|
211
213
|
f"{len(sec)} secured endpoint(s) in scope — re-check authorization."
|
|
212
214
|
)
|
|
215
|
+
if container_wired:
|
|
216
|
+
checklist.append(
|
|
217
|
+
f"{len(container_wired)} container-wired component(s) are in scope — "
|
|
218
|
+
"review their declared framework wiring because fan-in does not measure it."
|
|
219
|
+
)
|
|
213
220
|
txn = blast.get("transactional_boundaries_touched") or []
|
|
214
221
|
if txn:
|
|
215
222
|
checklist.append(f"{len(txn)} transactional boundary/boundaries in scope.")
|
sourcecode/ci_output.py
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"""Small, dependency-free renderers for CI workflow commands."""
|
|
2
|
+
from __future__ import annotations
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def _escape(value: object) -> str:
|
|
6
|
+
"""Escape values for GitHub Actions command properties and messages."""
|
|
7
|
+
return (
|
|
8
|
+
str(value)
|
|
9
|
+
.replace("%", "%25")
|
|
10
|
+
.replace("\r", "%0D")
|
|
11
|
+
.replace("\n", "%0A")
|
|
12
|
+
.replace(":", "%3A")
|
|
13
|
+
.replace(",", "%2C")
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def render_risk_annotation(
|
|
18
|
+
risk_level: str,
|
|
19
|
+
*,
|
|
20
|
+
reason: str = "",
|
|
21
|
+
unresolved: int = 0,
|
|
22
|
+
) -> str:
|
|
23
|
+
"""Render one annotation and a stable summary for a risk report."""
|
|
24
|
+
level = str(risk_level or "UNKNOWN").upper()
|
|
25
|
+
command = {
|
|
26
|
+
"CRITICAL": "error",
|
|
27
|
+
"HIGH": "error",
|
|
28
|
+
"MEDIUM": "warning",
|
|
29
|
+
"LOW": "notice",
|
|
30
|
+
"UNKNOWN": "warning",
|
|
31
|
+
}.get(level, "warning")
|
|
32
|
+
message = f"risk={level}"
|
|
33
|
+
if reason:
|
|
34
|
+
message += f"; {reason}"
|
|
35
|
+
if unresolved:
|
|
36
|
+
message += f"; unresolved_files={unresolved}"
|
|
37
|
+
return f"::{command} title=ASK PR impact::{_escape(message)}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def render_risk_summary(risk_level: str, *, unresolved: int = 0) -> str:
|
|
41
|
+
"""Render a short machine-readable summary line for CI logs."""
|
|
42
|
+
suffix = f" unresolved_files={unresolved}" if unresolved else ""
|
|
43
|
+
return f"ASK_PR_IMPACT risk={str(risk_level or 'UNKNOWN').upper()}{suffix}"
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def render_ci_result(
|
|
47
|
+
command: str,
|
|
48
|
+
*,
|
|
49
|
+
status: str,
|
|
50
|
+
severity: str = "unknown",
|
|
51
|
+
count: int = 0,
|
|
52
|
+
reason: str = "",
|
|
53
|
+
partial: bool = False,
|
|
54
|
+
) -> str:
|
|
55
|
+
"""Render one GitHub Actions annotation plus a stable CI summary line."""
|
|
56
|
+
normalized_status = str(status or "unknown").lower()
|
|
57
|
+
level = str(severity or "unknown").upper()
|
|
58
|
+
if partial or normalized_status in {"unverified", "unknown", "partial"}:
|
|
59
|
+
annotation = "warning"
|
|
60
|
+
elif normalized_status in {"fail", "failed", "findings"} or level in {"CRITICAL", "HIGH"}:
|
|
61
|
+
annotation = "error"
|
|
62
|
+
elif level == "MEDIUM":
|
|
63
|
+
annotation = "warning"
|
|
64
|
+
else:
|
|
65
|
+
annotation = "notice"
|
|
66
|
+
message = f"status={normalized_status}; severity={level}; findings={int(count)}"
|
|
67
|
+
if partial:
|
|
68
|
+
message += "; partial=true"
|
|
69
|
+
if reason:
|
|
70
|
+
message += f"; {reason}"
|
|
71
|
+
annotation_line = f"::{annotation} title=ASK {command}::{_escape(message)}"
|
|
72
|
+
summary = f"ASK_CI command={_escape(command)} status={_escape(normalized_status)} severity={_escape(level)} findings={int(count)}"
|
|
73
|
+
return f"{annotation_line}\n{summary}"
|