Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,11 @@ FROM from clause
[ORDER BY fields2]
[UNION SELECT...]

UP TO (Default max rows) ROWS added at end of query if omitted
You could force select without limits by adding UP TO 0 ROWS
UP TO (Default max rows) ROWS is applied if omitted.
Every multirow SELECT is limited to 1-10,000 rows. `UP TO 0 ROWS`, invalid
limits, and explicit values above 10,000 are rejected before execution. A saved
default of zero or a negative value safely falls back to 100; a larger saved
default is capped at 10,000.

COUNT, AVG, MAX, MIN, SUM are managed
DO NOT FORGET SPACE in ( ) of aggregat
Expand Down
2 changes: 1 addition & 1 deletion docs/baseline-findings.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ Priority meanings: **P0** blocks the requested test workflow or is an immediate
| BASE-RUN-006 | P1 | After `STATUS010` dispatch, ZTOAD queued desktop-only editor population/selection, tree refresh, history refresh, and splitter operations in WebGUI. Automatic PBO flush then terminated with CNDP 006; result-only changes could not repair the poisoned queue. SAP's standard TextEdit diagnostic is green, and an isolated empty TextEdit/stream-read/ALV spike executed the sanitized query successfully. | Pure frontend-capability Unit tests; preserve desktop behavior; exact-candidate syntax/Unit/ATC/object state; fresh A4H query result plus ST22 delta. | Fixed: capability tests pass on both releases; A4H last-statement ALV smoke and clean exit are green with no new ST22 dump; NPL UI is not applicable |
| BASE-RUN-002 | P1 | Generated-program failures crossed directly into report orchestration, while raw compiler text could expose query details. | Deterministic runtime containment, sanitized synthetic detail, preserved success, empty partial output, exact two-release gates, and a read-only WebGUI/ST22 delta. | Fixed candidate `92946fe`: 109/109 on both releases; exact activation/state and complete ATC accounting recorded; failure UI is generic, normal result is green, and ST22 is unchanged |
| BASE-RUN-003 | P1 | The generated subroutine-pool approach has a finite per-session pool budget and encourages session restart behavior instead of bounded execution objects. | Pure logical stress across the documented maximum, explicit reserve/accounting tests, exact two-release gates, and a read-only WebGUI/ST22 smoke; never exhaust undeletable live pools merely to test the limit. | Fixed candidate `4b37b69`: ZTOAD owns at most 30 pools with six slots reserved; only successful real generation charges the budget and cancelled DML allocates none. Both releases pass 113/113 Unit, ATC totals do not regress, A4H smoke is green, and ST22 is unchanged. |
| BASE-RUN-004 | P1 | `UP TO 0 ROWS` means unlimited results. A user can accidentally run an unbounded query or expensive aggregation in an interactive tool. | Row-limit policy tests, explicit unlimited confirmation/policy test, timeout/load test on disposable data. | Open |
| BASE-RUN-004 | P1 | `UP TO 0 ROWS` means effectively unlimited results, and zero in the saved default reached the same generator sentinel. Literal-zero strict-mode protection is newer than the supported 7.50 floor. | Central bounded policy; zero/invalid/overflow/exact-max/above-max/default-recovery tests; non-set and set-path regressions; exact two-release gates; real rejection and two-row WebGUI smoke; full ST22 delta. | Fixed candidate `832d057`: every executable multirow SELECT resolves to 1-10,000 rows; unsafe explicit values stop before generation, invalid defaults recover safely, both releases pass 120/120 Unit, Cloud ATC improves by three findings, the browser boundary is green, and ST22 is unchanged. A result cap is not represented as a generic database-work timeout. |
| BASE-RUN-005 | P1 | INSERT parsing is quote- and whitespace-sensitive and relies on dynamic component assignment/conversion. Truncation, missing fields, and conversion failures need a defined result. | Values/SET variants, embedded quotes, numeric/date conversion, too-long values, missing/duplicate fields; isolated Z table only. | Open |
| BASE-ARCH-001 | P2 | The report is over 5,000 lines with 37 lint findings for procedural-size reduction. GUI, parser, authorization, generator, and execution responsibilities are coupled. | Preserve characterization tests; extract one pure parser/generator class per fixed issue without a big-bang rewrite. | Open |
| BASE-ARCH-002 | P2 | GUI-bound globals and `FORM` routines prevent headless tests for startup, editor selection, authorization, and execution orchestration. | Introduce narrow editor/auth/executor interfaces; test factories and orchestration with doubles. | Open |
Expand Down
10 changes: 9 additions & 1 deletion docs/development.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,12 @@ Current ARC-1 TABL `dryRun` requests can still create an inactive draft. After a
3. Add the smallest test, replay the original production code, and record the intended red failure.
4. Write and review a plan under `docs/plans/` covering implementation, ABAP 7.50, Clean ABAP/Clean Core, local/live tests, rollback, browser smoke, and ST22. A security plan must separately state actor prerequisites, proven entry-point reachability, demonstrated sink behavior, and the invariant enforced by the patch so a sink-level proof is not presented as an end-to-end exploit without evidence.
5. Edit source locally and make the smallest production change that turns the test green. For a frontend or other environment-dependent assumption, keep the candidate classified as a spike until live integration evidence accepts it. Keep serializer XML unchanged for a source-only fix. At any external-text-to-code boundary, state the representation invariant explicitly. Treat every allow-list exception as grammar: prove its context, add an adversarial lookalike regression, and fail closed when the parser cannot distinguish data from source syntax.

When zero or an initial value has product meaning, do not also use it as an
"omit the policy" sentinel. Validate explicit input and persisted/default
configuration separately, normalize invalid stored values at their boundary,
and test every downstream representation so later generation cannot silently
restore the bypass.
6. Run `npm ci`, `npm test`, `git diff --check`, and the final local/security review. Reconcile the review inventory with `git diff --name-only`; generic extension classifiers can omit `.abap`, so every changed ABAP source must be added explicitly and reviewed. For generated or otherwise transformed input, compare pre- and post-transformation semantics, especially comments, quoting, escaping, length limits, and inserted line/token boundaries. Commit and freeze the exact source/object candidate before the expensive live gates, and record its commit plus source hash. Any later `src/` or serialized-object change invalidates the affected live evidence and must be redeployed and rechecked.
7. Deploy the exact candidate source to SAP_BASIS 750 first through ARC-1/ADT when its real dependencies exist; record any missing ADT prerequisite as blocked. Keep the A4H native-abapGit link on `master` and record an unmerged candidate as a direct deployment. Follow every write with an explicit activation call, active/inactive main-object comparison, and an inactive-child-part query for affected composite objects; a write response, activation option, or equal main-source hash alone does not prove that screens, statuses, texts, and includes are active.
8. On NPL, activate only the intended object and run active syntax, all ABAP Unit tests, and complete ATC variants through ARC-1. On A4H/SAP_BASIS 758, repeat those checks and additionally start a fresh browser session for safe smoke and ST22 delta. Verify required dynpros/GUI statuses before attributing an end-to-end failure to the source candidate.
Expand Down Expand Up @@ -208,7 +214,9 @@ For every relevant change, verify:
- values are bound or safely quoted instead of concatenated where possible;
- comments, aliases, nested expressions, subqueries, and unions cannot hide additional statements;
- wrapping, splitting, generated-source layout, or other representation changes do not alter comment/quote boundaries or resume hidden input as executable code; generated lines split only at a grammar-safe boundary, and a hard length cut, split inside a literal, or continuation that moves `*` into ABAP source column one must fail closed;
- row limits remain enforced unless the user explicitly requests the documented override;
- every executable multirow SELECT keeps a positive bounded row limit; zero,
invalid, overflowed, saved-default, and transformed representations cannot
turn the limit into an omitted clause;
- Native SQL remains unconditionally rejected and forbidden sinks such as `C_DB_EXECUTE` do not return;
- error/generated-code displays do not leak credentials or confidential values.

Expand Down
149 changes: 149 additions & 0 deletions docs/plans/finished/base-run-004.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
# BASE-RUN-004 — enforce bounded SELECT results

_Date: 2026-08-07 · branch: `codex/base-run-004`_

## Goal

Remove the `UP TO 0 ROWS` unlimited-result bypass, centralize a positive row-
limit policy for every generated SELECT representation, preserve valid bounded
queries, and keep the SAP_BASIS 750 compatibility floor.

## Proven root cause and red evidence

Official SAP documentation defines a runtime value of zero as up to
2,147,483,647 rows. ZTOAD removes the user's clause and represents zero as an
initial `fw_rows`; legacy SELECT, strict SELECT, and set-cursor generation then
all omit their cap. A saved default of zero reaches the same sentinel.

Red commit `ccea89741a3317de361c54b081c657def4ee9899` is syntax-valid on
NPL and runs 113 tests: 112 pass and only the focused zero-limit assertion
fails. The reproduction performs no SELECT. Full analysis is in the linked
research note.

## Reviewed implementation plan

1. **Baseline and research — complete.** Align both systems to merged master,
verify the 113-test baseline and exact object state, trace parser and all
generator representations, and confirm zero semantics through official SAP
documentation.
2. **Focused red test — complete.** Change the existing zero-limit
characterization into a fail-closed regression and replay it against
unchanged production behavior on SAP_BASIS 750.
3. **Central policy.** Add one pure local row-limit policy with fallback 100 and
maximum 10,000. Resolve explicit text before numeric assignment; reject zero,
invalid, overflow, and above-maximum explicit values. Normalize missing or
invalid saved defaults to 100 and cap oversized saved defaults at 10,000.
4. **Parser integration.** Recognize the complete top-level row token, pass it
through the policy before removing the clause, and return `fw_error` for an
unsafe explicit request. Ensure the parser always supplies a positive value
to generation for an executable multirow SELECT.
5. **Regression/refactor.** Add pure cases for exact maximum, above maximum,
invalid/negative/overflow tokens, leading zeros, zero and oversized saved
defaults, literal lookalikes, and normal positive/default behavior. Replace
the set-query unlimited test with a fail-closed full-path regression while
retaining strict, legacy, aggregate, and positive UNION generation tests.
6. **Documentation.** Remove the advertised unlimited mode from embedded help
and README, document the 1–10,000 policy and safe default recovery, and state
honestly that a result cap is not a database statement timeout.
7. **Local gates and review.** Run `npm ci`, `npm test`, the diagnostic quality
profile, `git diff --check`, a complete diff review, and focused checks for
parser/generator consistency, authorization, generated-fragment validation,
overflow, aggregate semantics, and both set/non-set representations.
8. **Freeze exact candidate.** Commit source and documentation, record the
commit and source SHA-256, and invalidate affected live evidence after any
later `src/` change.
9. **NPL gate first.** Directly deploy the exact candidate, explicitly activate,
and require active syntax, every ABAP Unit test, complete DEFAULT ATC,
active/inactive equality, zero inactive ZTOAD child parts, and no new dump.
NPL UI remains not applicable.
10. **A4H gate.** Repeat activation, syntax, Unit, complete Cloud ATC, object
state, and inactive-child checks. In a fresh browser session, submit a safe
`UP TO 0 ROWS` query and prove rejection without a result, then submit a
small positive-limit read-only query and prove the bound. Compare the full
ST22 set client-side with the pre-smoke marker.
11. **Restore and PR.** Restore both shared systems to intended merged master,
verify activation/state/tests, perform the final review, update the finding,
push, open the PR, and wait for required green CI.
12. **Post-green audit.** Audit plan fidelity, evidence, ARC-1 behavior, PR diff,
and CI. Add useful durable workflow improvements to the same PR, archive
this plan under `docs/plans/finished/`, wait for green CI again, then squash
merge and synchronize local master.

## Execution record

- Steps 1–11 through shared-system restoration are complete for frozen source
commit `832d057656dc2923e79b87eff5016b718dad42fe`; local source
SHA-256 is
`b8d5d7807e42832b105deabe4d55f142ee10408a4f1ef975cf9530d17cf2ebb4`.
Both candidate deployments reported normalized active/inactive SHA-256
`1e93f56cd0575ca73a1cc2c5b270ee07436db9839e3412ddd73448a8cc771264`.
- The focused NPL red replay at commit `ccea897` passed 112/113 Unit and
failed only `LTC_QUERY_PARSER->REJECTS_ZERO_LIMIT`; no SELECT was executed.
- `npm ci`, configured abaplint, repository and installation contracts,
`git diff --check`, both server-side dry syntax checks, and the complete diff
review are green. The diagnostic quality inventory is 2,524 findings across
62 rules and remains outside the merge gate.
- NPL is green at 120/120 Unit with clean active syntax, equal source state,
zero inactive ZTOAD parts, and complete DEFAULT ATC unchanged at 85 findings
(P1 3, P2 4, P3 78). Its four-dump result set and latest marker remained
unchanged across the candidate checks.
- A4H is green at 120/120 Unit with the known seven POSIX warnings, equal
source state, and zero inactive ZTOAD parts. Complete
ABAP_CLOUD_READINESS improved from 709 to 706 findings (P1 487, P2 219): a
stable-signature comparison shows only two fewer restricted-form errors and
one fewer generic restricted-syntax error, with no new signature.
`S4HANA_READINESS_2023` again returned zero displayed findings without
proving its unavailable prerequisites and remains explicitly incomplete.
- A fresh authenticated Chrome/WebGUI session entered both queries with
editor-scoped click, real typing, and blur. The zero-limit query
`SELECT mandt FROM t000 UP TO 0 ROWS` stopped with `Cannot parse the query`
and an empty grid. A following
`SELECT tabname FROM dd02l UP TO 2 ROWS` returned exactly two rows and the
success message reported two entries. The complete 49-ID ST22 set retained
its latest `2026-08-07T06:26:10Z` marker and gained no ID.
- Both shared targets were restored to merged master `ef54657`, explicitly
activated, and verified at 113/113 Unit, expected syntax, equal active and
inactive SHA-256
`736c93b341c8a14cd40f88522b6b542fa14b82bceaea5a34b0bedcfdab2699b8`,
and zero inactive ZTOAD part.
- Draft PR #33 opened from the recorded candidate and its first Quality run
`31196346909` passed `npm ci`, configured abaplint with zero findings, the
repository contract, and the installation contract. The external abaplint
observation check was neutral by design; both required checks passed.
- The post-green audit reconciled all six changed files with the PR diff,
reviewed the complete CI log, found no review comments or unresolved threads,
and confirmed the PR was cleanly mergeable. It found one stale security-
checklist reference to a documented unlimited override; the checklist now
states the bounded invariant instead.
- The workflow now explicitly requires separate validation of explicit input
and persisted/default configuration whenever zero or initial values could
act as an omit-policy sentinel. This plan is archived after that durable
improvement; the second green run and merge are recorded on the PR so they do
not require an evidence-only commit.

## Plan review

- **Compatibility:** no syntax or API newer than SAP_BASIS 750 is planned.
- **Clean ABAP/readability:** one named pure class owns fallback, ceiling,
conversion, and invalid-state decisions; the parser remains an adapter.
- **Clean Core:** this remains a classic on-premise report. The change adds no
unreleased dependency and makes no false ABAP Cloud claim.
- **Security and safety:** unsafe values fail before generated source or a
database request. Authorization, source scanning, fragment validation,
runtime containment, DML policy, and subroutine-pool budgeting remain intact.
- **Representation boundary:** tests must prove the policy at parsing and the
final strict/legacy/set representations; an initial value must never regain
its old "omit the cap" meaning downstream.
- **Testing:** permanent tests are harmless and data-in/data-out. Live smoke is
read-only and deliberately small; no load test materializes a large result.
- **Functional tradeoff:** unlimited results are intentionally removed. Users
must paginate/refine a query rather than risk dialog-session memory.
- **Rollback:** revert the candidate, redeploy and explicitly activate reviewed
master on both targets, then rerun syntax, Unit, state, and inactive-child
checks. No structural object or persistent data is introduced.

## References

- [Root-cause research](../../research/2026-08-07-base-run-004-row-limit-policy.md)
- [Development playbook](../../development.md)
- [Test strategy](../../test-strategy.md)
Loading