Skip to content

feat(amber): reject invalid dashboard pagination - #8146

Open
carloea2 wants to merge 1 commit into
apache:mainfrom
carloea2:fix/dashboard-negative-pagination
Open

feat(amber): reject invalid dashboard pagination#8146
carloea2 wants to merge 1 commit into
apache:mainfrom
carloea2:fix/dashboard-negative-pagination

Conversation

@carloea2

@carloea2 carloea2 commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

What changes were proposed in this PR?

Reject negative dashboard search start and count values, and reject counts above the largest value that can safely include the one-row lookahead. Define the lookahead and maximum count once, and cover both accepted boundaries.

Before: negative start returned 500, negative count returned an inconsistent 200 response, and Int.MaxValue overflowed the query limit.

After: invalid pagination returns 400, while zero and the maximum safe count remain valid.

Any related issues, documentation, discussions?

Closes #8145

How was this PR tested?

  • sbt "WorkflowExecutionService / Test / testOnly org.apache.texera.web.resource.dashboard.DashboardResourceSpec"
  • sbt scalafmtCheckAll
  • The focused suite is currently blocked before the spec by upstream JOOQ generation mismatches for DefaultViewEnum and LAKEKEEPER_WAREHOUSE_NAME.
  • Earlier live checks confirmed negative start and count return 400 while zero remains valid.

Was this PR authored or co-authored using generative AI tooling?

Generated-by: Codex

@Yicong-Huang Yicong-Huang added the release/v1.2 back porting to release/v1.2 label Aug 30, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Automated Reviewer Suggestions

Based on the git blame history of the changed files, we recommend the following reviewers:

  • Contributors with relevant context: @Neilk1021, @aglinxinyuan
    You can notify them by mentioning @Neilk1021, @aglinxinyuan in a comment.

@github-actions
github-actions Bot requested a review from xuang7 August 30, 2026 20:58
@github-actions

Copy link
Copy Markdown
Contributor

Backport auto-label report

This fix: PR was checked against each actively-supported release branch. release/* labels drive the post-merge backport, so add or remove one to change where this fix lands.

Release branch Analysis
⚠️ release/v1.3 Not labeled automatically — none of the files this PR modifies exist on this branch (amber/src/main/scala/org/apache/texera/web/resource/dashboard/DashboardResource.scala, amber/src/test/scala/org/apache/texera/web/resource/dashboard/DashboardResourceSpec.scala). The fix may target code that isn't on this release, or the files were moved/renamed after the branch was cut. Please check and add release/v1.3 by hand if this fix should be backported here.
release/v1.2 Change detected on this branch — label added; this fix is queued to backport here. Requested review from @xuang7.

Auto-label run.

@github-actions

github-actions Bot commented Aug 30, 2026

Copy link
Copy Markdown
Contributor

⚠️ Benchmark changes need a look

🟢 0 better · 🔴 3 worse · ⚪ 12 noise (<±5%) · 0 without baseline

Compared against main b28faee benchmarked on this same runner, so the delta is largely free of cross-runner hardware noise. The "7d avg" column still reflects the gh-pages dashboard. Treat <±5% as noise unless repeated.

Dashboard · Run

config throughput MB/s latency max Δ latest / 7d
🔴 bs=10 sw=10 sl=64 512 0.313 19,114/24,588/24,588 us 🔴 -9.7% / 🔴 +54.6%
bs=100 sw=10 sl=64 1,212 0.74 82,808/88,918/88,918 us ⚪ within ±5% / 🟢 -26.4%
bs=1000 sw=10 sl=64 1,404 0.857 709,738/788,183/788,183 us ⚪ within ±5% / 🟢 +41.4%
Baseline details

Latest main b28faee from same runner

config metric PR latest main 7d avg Δ latest Δ 7d
bs=10 sw=10 sl=64 throughput 512 tuples/sec 567 tuples/sec 750.65 tuples/sec -9.7% -31.8%
bs=10 sw=10 sl=64 MB/s 0.313 MB/s 0.346 MB/s 0.458 MB/s -9.5% -31.7%
bs=10 sw=10 sl=64 p50 19,114 us 17,679 us 13,049 us +8.1% +46.5%
bs=10 sw=10 sl=64 p95 24,588 us 24,152 us 15,902 us +1.8% +54.6%
bs=10 sw=10 sl=64 p99 24,588 us 24,152 us 19,184 us +1.8% +28.2%
bs=100 sw=10 sl=64 throughput 1,212 tuples/sec 1,252 tuples/sec 960.3 tuples/sec -3.2% +26.2%
bs=100 sw=10 sl=64 MB/s 0.74 MB/s 0.764 MB/s 0.586 MB/s -3.1% +26.3%
bs=100 sw=10 sl=64 p50 82,808 us 80,565 us 104,199 us +2.8% -20.5%
bs=100 sw=10 sl=64 p95 88,918 us 91,531 us 110,645 us -2.9% -19.6%
bs=100 sw=10 sl=64 p99 88,918 us 91,531 us 120,888 us -2.9% -26.4%
bs=1000 sw=10 sl=64 throughput 1,404 tuples/sec 1,395 tuples/sec 993.27 tuples/sec +0.6% +41.4%
bs=1000 sw=10 sl=64 MB/s 0.857 MB/s 0.851 MB/s 0.606 MB/s +0.7% +41.4%
bs=1000 sw=10 sl=64 p50 709,738 us 711,606 us 1,012,191 us -0.3% -29.9%
bs=1000 sw=10 sl=64 p95 788,183 us 821,195 us 1,054,057 us -4.0% -25.2%
bs=1000 sw=10 sl=64 p99 788,183 us 821,195 us 1,081,313 us -4.0% -27.1%
Raw CSV
config_idx,batch_size,schema_width,string_len,num_batches,total_ms,total_tuples,total_bytes,tuples_per_sec,mb_per_sec,lat_p50_us,lat_p95_us,lat_p99_us
0,10,10,64,20,390.55,200,128000,512,0.313,19114.21,24587.67,24587.67
1,100,10,64,20,1649.78,2000,1280000,1212,0.740,82807.75,88918.48,88918.48
2,1000,10,64,20,14245.71,20000,12800000,1404,0.857,709737.81,788183.44,788183.44

@codecov-commenter

codecov-commenter commented Aug 30, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 94.07%. Comparing base (b28faee) to head (2ccf517).
✅ All tests successful. No failed tests found.

Additional details and impacted files
@@             Coverage Diff              @@
##               main    #8146      +/-   ##
============================================
- Coverage     94.07%   94.07%   -0.01%     
+ Complexity     4811     4810       -1     
============================================
  Files          1193     1193              
  Lines         48573    48581       +8     
  Branches       5854     5855       +1     
============================================
+ Hits          45696    45703       +7     
  Misses         1428     1428              
- Partials       1449     1450       +1     
Flag Coverage Δ *Carryforward flag
access-control-service 81.00% <ø> (ø) Carriedforward from b28faee
agent-service 99.32% <ø> (ø) Carriedforward from b28faee
amber 90.11% <100.00%> (-0.01%) ⬇️
computing-unit-managing-service 73.67% <ø> (ø) Carriedforward from b28faee
config-service 87.00% <ø> (ø) Carriedforward from b28faee
file-service 87.91% <ø> (ø) Carriedforward from b28faee
frontend 96.82% <ø> (ø) Carriedforward from b28faee
notebook-migration-service 79.31% <ø> (ø) Carriedforward from b28faee
pyamber 98.18% <ø> (ø) Carriedforward from b28faee
workflow-compiling-service 77.19% <ø> (ø) Carriedforward from b28faee

*This pull request uses carry forward flags. Click here to find out more.

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@Yicong-Huang
Yicong-Huang self-requested a review August 30, 2026 22:35

@Yicong-Huang Yicong-Huang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 0 must-fix · 2 advisory · 1 polish — the guard is clean and covers every reader of offset/count; nothing here blocks it.

Correctness (1)

  • DashboardResource.scala:95count = Int.MaxValue overflows in the + 1 one line below the guard, so the arithmetic path may still 500 where this establishes a 400 (advisory, question, see inline)

Simplifications (1)

  • DashboardResourceSpec.scala:135 — nothing pins the "zero remains valid" boundary the description promises; < 0<= 0 would keep CI green (advisory, see inline)

Polish: 1 quick touch-up (see inline comment).

Verification trace

Checked that the guard actually dominates the values it protects rather than assuming placement: all four readers of offset/count sit below it, it covers both HTTP entry points plus the internal ProjectResource caller, and it keeps zero valid. The exception type matches the 11-site amber BadRequestException pattern rather than introducing a new one.

On the overflow: I verified the wrap itself — Scala Int wraps, and the + 1 is at :113 — but not the end-to-end response, which needs a build and a live database. That is why it is posted as a question and marked advisory rather than must-fix, and it is pre-existing on main: this diff does not touch that line.

@carloea2

Copy link
Copy Markdown
Contributor Author

Feedback is addressed and CI is green. Ready for another review.

@carloea2 carloea2 changed the title fix(amber): reject negative dashboard pagination feat(amber): reject negative dashboard pagination Aug 31, 2026
@mengw15 mengw15 removed the release/v1.2 back porting to release/v1.2 label Aug 31, 2026

@Yicong-Huang Yicong-Huang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 3 resolved · 0 open · 6 new (6 new = 6 newly introduced · 0 late catches)

All three round-2 findings are genuinely fixed — I checked each against the tree rather than the replies. The only blocker is the title.

Conventions (2)

  • Retitle → fix(amber): reject invalid dashboard paginationfeat contradicts the fix label, both commit subjects, and #8145's HTTP 500 reproduction; "negative" also no longer covers the Int.MaxValue rejection (must-fix)
  • Description: the body and the testing list still promise only that negatives return 400, but ?count=2147483647 now does too (advisory)

Design & architecture (1)

  • DashboardResource.scala:94 — the max-count bound lives in three unlinked places and is documented in none of them (advisory, see inline)

Simplifications (1)

  • DashboardResourceSpec.scala:145 — the accepted end of the new range has no case, unlike the zero end (advisory, see inline)

Polish: 2 quick touch-ups (see inline comments).

Verification trace

Two claims were load-bearing here. First, that count == Int.MaxValue closes the overflow completely: params.count feeds exactly one arithmetic expression in amber/src/main, the params.count + 1 at :115, and for a Scala Int that wraps on exactly one input — so the new clause covers it, and params.offset needs no upper bound because it feeds no arithmetic at all.

Second, that the new zero-boundary case actually discriminates rather than passing by luck. I extracted javax.ws.rs-api and parsed the class files instead of trusting recall: BadRequestExceptionClientErrorExceptionWebApplicationExceptionRuntimeException. It is not an IllegalArgumentException, so tightening < 0 to <= 0 really would fail that test.

I also traced every consumer of the newly rejected value: both HTTP entry points through search.service.ts, and ProjectResource.scala:173. None sends a large-count sentinel, so the new upper bound breaks no caller.

@xuang7 xuang7 removed the fix label Sep 1, 2026
@xuang7
xuang7 removed their request for review September 1, 2026 01:47
@carloea2
carloea2 force-pushed the fix/dashboard-negative-pagination branch from fe0e232 to 2ccf517 Compare September 1, 2026 17:35
@carloea2 carloea2 changed the title feat(amber): reject negative dashboard pagination feat(amber): reject invalid dashboard pagination Sep 1, 2026
@carloea2

carloea2 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

I kept this as feat after checking the history against the definition you shared. Invalid pagination has been accepted since this endpoint was introduced, so this adds validation rather than restoring previously working behavior. I also broadened the title to cover both bounds.

@github-actions github-actions Bot added the fix label Sep 1, 2026
@carloea2

carloea2 commented Sep 1, 2026

Copy link
Copy Markdown
Contributor Author

@Yicong-Huang, all review comments are addressed and CI is green. Could you take another look?

@Yicong-Huang Yicong-Huang left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔴 5 resolved · 1 open · 0 new (0 new = 0 newly introduced · 0 late catches)

Every code finding from the last three rounds is closed, and I checked each against the tree rather than the replies. Only the title is left.

Conventions (1)

  • Retitle → fix(amber): reject invalid dashboard paginationfeat claims a new capability, but no client can do anything it could not before; three broken responses became correct 400s (must-fix)

Thanks for engaging the definition rather than just retitling. Squashing the branch retired my commit-subject evidence, so here is what replaces it:

  • The head branch is fix/dashboard-negative-pagination, and AGENTS.md:134 asks for the same shape on branch and commit subject — the two now disagree.
  • #8083 fix(amber): reject duplicate worker initialization merged 2026-08-31: a guard that never existed, rejecting previously-accepted invalid input, same module, shipped as fix.
  • backport-auto-label.yml:110 gates release backports on /^fix(...)/i against the title, so feat quietly removes this from every release branch.

"Support never existed" reads on user-facing capability, and no endpoint, parameter or option is added here. A 500 on client input and a 200 carrying more=true are what §5 of the review standards calls defects.

Verification trace

Two claims were load-bearing. First, that this round changes no behavior: params.count is an Int (:86), so count > MaxSearchCount and the previous count == Int.MaxValue have identical truth sets — the accept/reject partition is byte-for-byte the one already traced to all three callers and to search.service.ts, so nothing needed re-tracing downstream.

Second, that the extraction closes the overflow rather than renaming it. params.count feeds exactly one arithmetic expression in amber/src/mainparams.count + SearchResultLookahead at :121 — and the guard admits at most Int.MaxValue - SearchResultLookahead, so the sum cannot wrap for any lookahead, not just 1. That is the part worth having: the guard now derives from the probe, so widening the probe moves the bound and the message with it. I also checked the val initialization order, since MaxSearchCount reads SearchResultLookahead — it is declared first at :53, and the spec's literal at :71 would render 2147483647 otherwise.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Dashboard search accepts negative pagination values

5 participants