DanielLeens commented on PR #11613:
URL: https://github.com/apache/seatunnel/pull/11613#issuecomment-5379366298

   # What Problem Does This PR Solve?
   
   - **User pain point**: the Zeta Web UI was mostly a read-only inspection 
console — operators could see jobs, metrics and checkpoints, but had to fall 
back to the CLI/REST directly for job submission, 
stopping/savepointing/cancelling a running job, restoring from a checkpoint, 
looking up a connector's option rules, checking whether 
HTTP/HTTPS/basic-auth/mTLS are actually enabled on a node, or updating a 
worker's tags.
   - **Fix approach**: this PR wires all of that into the UI — job submission 
(text or uploaded config, with an optional savepoint-restore via 
`restoreJobId`), running-job control (stop / savepoint-stop / force-cancel), a 
checkpoint detail/history view with a "Restore Latest State" shortcut, a 
connector option-rule lookup page, a new read-only `GET /http-service/status` 
page, and a local-worker tag editor — plus a safety check added to the existing 
`update-tags` endpoint.
   - **One-sentence summary**: turns the Zeta Web UI from a read-only console 
into a genuine operations surface, on top of already-existing REST job-control 
endpoints.
   
   I did a fresh, independent verification pass rather than reusing the 
extensive review history already on this PR: I pulled every backend file 
changed by this PR straight from the GitHub Contents/Files API at the current 
head (`37ca28b6e4139365ae7e9a45acbc6b10e3e446b8`) and re-derived the 
security-relevant conclusions below (auth coverage, sensitive-field leakage, 
backward compatibility of `update-tags`) directly from that source, plus a 
fresh live check of CI.
   
   # 1. Code Change Review
   
   ## 1.1 Core Logic Analysis
   
   This PR's backend footprint is small and additive relative to its UI 
footprint: `JettyService.java` (+6), `RestConstant.java` (+1), 
`BaseService.java` (+15/-1), `UpdateTagsService.java` (+71/-9), and one new 
file, `HttpServiceStatusServlet.java` (140 lines). Everything else is 
`seatunnel-engine-ui` (Vue/TSX) plus `docs/en|zh`.
   
   I read `HttpServiceStatusServlet.java` in full and checked every field it 
returns against what it must never leak:
   
   ```java
   JsonObject status = new JsonObject()
       .add("httpEnabled", httpConfig.isEnabled())
       .add("httpsEnabled", httpConfig.isEnableHttps())
       .add("configuredHttpPort", httpConfig.getPort())
       .add("configuredHttpsPort", httpConfig.getHttpsPort())
       .add("httpPort", findConnectorPort(false, httpConfig.getPort()))
       .add("httpsPort", findConnectorPort(true, httpConfig.getHttpsPort()))
       .add("contextPath", defaultContextPath(httpConfig.getContextPath()))
       .add("dynamicPortEnabled", httpConfig.isEnableDynamicPort())
       .add("portRange", httpConfig.getPortRange())
       .add("basicAuthEnabled", httpConfig.isEnableBasicAuth())
       .add("mutualTlsEnabled", hasText(httpConfig.getTrustStorePath()) && 
hasText(httpConfig.getTrustStorePassword()));
   ```
   
   Confirmed field by field: no `username`, `password`, `keyStorePath`, 
`keyStorePassword`, `trustStorePath`, or `trustStorePassword` value is ever put 
into the response — `mutualTlsEnabled` only exposes a derived boolean of 
whether those two fields are non-blank, never their contents. This is a 
genuinely well-designed "safe status" endpoint.
   
   I then checked the auth-coverage claim directly in `JettyService.java` 
rather than taking it on faith:
   ```java
   FilterHolder exceptionFilterHolder = new FilterHolder(new 
ExceptionHandlingFilter());
   context.addFilter(exceptionFilterHolder, "/*", 
EnumSet.of(DispatcherType.REQUEST));
   ...
   FilterHolder basicAuthFilterHolder = new FilterHolder(new 
BasicAuthFilter(httpConfig));
   context.addFilter(basicAuthFilterHolder, "/*", 
EnumSet.of(DispatcherType.REQUEST));
   ...
   context.addServlet(new ServletHolder(new 
HttpServiceStatusServlet(nodeEngine, seaTunnelConfig, server)), ...)
   ```
   Both filters are registered on the same Jetty `context` with a `"/*"` path 
spec, and `HttpServiceStatusServlet` is registered on that same context. So 
when basic auth is enabled cluster-wide, this new endpoint requires it exactly 
like every other endpoint; when disabled, it's exactly as open as every other 
endpoint today. **No new unauthenticated attack surface.**
   
   `UpdateTagsService.java` — I read the full 116-line file. The new 
`validateTargetMember` check:
   ```java
   Object uuid = params.get("uuid");
   if (uuid != null && 
!localMember.getUuid().toString().equals(uuid.toString())) {
       throw new IllegalArgumentException(...);
   }
   ```
   is a real, net-positive scoping fix: it rejects a request whose explicit 
`uuid` doesn't match the node actually serving it, preventing an operator from 
silently mutating the wrong worker's tags via a stale UI selection. 
`extractTagParams` still falls back to treating the whole body (minus `uuid`) 
as the legacy flat tag map when no `tags` object is present, so the historical 
request shape keeps working.
   
   **New finding this round, not raised before**: `extractTagParams` (lines 
87-98) now does:
   ```java
   Object tags = params.get("tags");
   if (tags instanceof Map) { return (Map<String, Object>) tags; }
   if (tags != null) { throw new IllegalArgumentException("The tags field must 
be an object."); }
   Map<String, Object> legacyTags = new HashMap<>(params);
   legacyTags.remove("uuid");
   return legacyTags;
   ```
   Before this PR, a legacy-format request with a top-level key literally named 
`tags` whose value is a non-object (e.g. `{"tags": "some-value"}`, intending to 
set a tag *named* `tags`) would have been silently accepted as a flat tag map 
entry. After this PR, that exact request now throws 
`IllegalArgumentException("The tags field must be an object.")` instead. This 
is a narrow, low-probability compatibility edge case — a caller would need to 
have been using `tags` as a literal tag *key* under the old flat-map contract — 
but it is a real behavior change for that one input shape, not just an additive 
safety check, and it isn't mentioned in the PR's compatibility notes. I'm 
keeping this Low severity since the field name collision is unlikely in 
practice, but it should be called out explicitly.
   
   ## 1.2 Compatibility Impact
   
   **Mostly compatible, with one narrow caveat (see Issue 2 below).** 
`REST_URL_HTTP_SERVICE_STATUS = "/http-service/status"` is a brand-new, 
additive endpoint. `BaseService`'s monitoring-info JSON gains new fields 
additively (I confirmed no existing field is renamed or removed in the 
`BaseService.java` diff). `update-tags`'s legacy flat-map body still works for 
every input except the one edge case above. No SeaTunnel `Option`, default 
value, checkpoint/savepoint format, or job-state serialization is touched.
   
   ## 1.3 Performance / Side-Effect Analysis
   
   `HttpServiceStatusServlet` is read-only: it iterates 
`server.getConnectors()` (a small, bounded, in-memory list) and does no 
locking, no allocation beyond the JSON response, no I/O. No new concurrency, 
retry, or resource-release concerns introduced by the backend changes in this 
PR.
   
   ## 1.4 Error Handling and Logging
   
   No error-handling regression found in the backend files I read. The one 
carryover item from the review history (`JettyService.java` Spotless/Code-style 
failure) is confirmed **fixed and still green** at the current head — see the 
live CI section below for the up-to-date evidence.
   
   Formal issues, sorted by severity:
   
   **Issue 1 (Medium, carried over from the prior round, re-verified live): the 
`seatunnel-ui` CI job that actually exercises `jobs.spec.ts` still does not run 
on this branch's CI configuration.**
   - Location: `.github/workflows/backend.yml`'s `seatunnel-ui` job on this 
branch (104+ commits behind current `dev`, predating PR #11515's more granular 
UI-path routing).
   - I re-checked this live rather than trusting the previous round's claim: on 
the fork's current run for this exact head (`danielnadean/seatunnel` run 
`32327632157`), `Run / Build SeaTunnel UI` is still `skipped`. So the last 
commit's test-only fix to `jobs.spec.ts` (see below) has still never actually 
been executed by CI on this branch.
   - Best improvement: rebase onto current `dev` to pick up #11515's routing, 
or have the author run `npm run test:unit` locally and report the result.
   - Severity: Medium (verification-confidence gap; my own reading of the diff, 
described below, is that the fix is correct). Raised by another reviewer: No 
(carried over from Daniel's own prior round, now re-verified independently).
   
   **Issue 2 (Low, new this round): `update-tags` legacy flat-map compatibility 
has one narrow edge case**
   - Location: `UpdateTagsService.java:87-98` (`extractTagParams`).
   - A legacy request using a top-level key literally named `tags` with a 
non-object value now throws `IllegalArgumentException` instead of being 
silently accepted as before. Worth a one-line mention in the PR 
description/docs since it's a real (if unlikely) compatibility edge case, not 
purely additive.
   - Raised by another reviewer: No.
   
   **Issue 3 (Low, informational, live-verified): current CI is red, but the 
failure is unrelated to this PR's diff.**
   - I checked this myself rather than trusting the `FAILURE` status label at 
face value. The apache-side `Build` pointer check for this head is `failure`, 
backed by fork run `32327632157`. Of 82 check runs in that fork run, exactly 
one failed: `Run / unit-test (8, ubuntu-latest)`. I pulled that job's full log 
and the actual failure is:
     ```
     [ERROR] MessageDelayedEventLimiterTest.testAcquire:48 expected: <true> but 
was: <false>
     ... in module connector-cdc-base 
(seatunnel-connectors-v2/connector-cdc/connector-cdc-base)
     ```
     This PR touches only `seatunnel-engine-server`, `seatunnel-engine-ui`, and 
docs — it does not touch `connector-cdc-base` or anything CDC-related at all. A 
rate-limiter `testAcquire` boundary assertion failing after a 10-second wait 
window is a classic CI-load timing flake, not something this diff could have 
caused. `Run / Code style` on the same run is green (confirms Issue 1's earlier 
Spotless blocker is genuinely still fixed). This is not a blocker; it needs a 
rerun of the failed job (or a rebase, given how far behind `dev` this branch 
is), not any code change here.
   - Raised by another reviewer: No.
   
   # 2. Code Quality Assessment
   
   ## 2.1 Coding Standards
   
   Consistent with the rest of the module; ASF headers present; new Java 
classes (`HttpServiceStatusServlet`) carry class- and method-level Javadoc, 
including an explicit "must not include passwords/keystore paths" contract 
comment that I confirmed the implementation actually honors.
   
   ## 2.2 Test Coverage and Test Stability
   
   I checked the last commit specifically, since it's the only change since the 
prior full review round: it modifies only 
`seatunnel-engine-ui/src/tests/jobs.spec.ts` (+9/-3), replacing a zero-arg 
`onPositiveClick()` invocation with a helper that passes a synthetic 
`MouseEvent`, to satisfy `NPopconfirm`'s typed prop signature under stricter 
type-checking. The three assertions on `stopJobSpy`'s call arguments are 
unchanged — this reads as a real, narrowly-scoped type-check fix, not a 
behavior or coverage change. However, per Issue 1, this fix has never actually 
been executed by CI on this branch (the `seatunnel-ui` job is skipped), so 
"fixed" here is my own static read of the diff, not a CI-confirmed result.
   
   The other UI test files added by this PR (`checkpoints.spec.ts`, 
`operations.spec.ts`, `managers.spec.ts` additions, `detail.spec.ts` additions) 
are mock-based with `flushPromises()`, no fixed sleeps, no real network 
dependency, no shared mutable global state, no order-sensitive or 
floating-point assertions.
   
   **Stability rating: Stable** for what's written; the open item is 
verification confidence (Issue 1), not flakiness.
   
   ## 2.3 Documentation Updates
   
   `docs/en/engines/zeta/rest-api-v2.md` and `web-ui.md`, plus their `zh` 
counterparts, are all updated with matching line counts (+55/-2 and +28/-9 
respectively in both languages) — no en/zh drift in the file list. I did not do 
a full line-by-line bilingual diff of prose content, but the structural 
symmetry (identical +/- counts per language pair) is a good sign of parity.
   
   # 3. Architectural Soundness
   
   ## 3.1 Elegance of the Solution
   
   **Precise fix, well-scoped.** This PR wires UI controls on top of 
already-existing, already-shipped job-control REST endpoints (`stopJob`, 
savepoint-stop, cancel) rather than reimplementing any state-machine or 
coordinator logic — I confirmed `BaseService.handleStopJob()` and the 
coordinator-side cancel/savepoint/stop methods are not touched by this diff at 
all. The two backend changes it does make (a read-only status servlet, and a 
safety check on an existing mutation endpoint) are minimal and consistent with 
the existing filter/auth architecture, not a parallel one.
   
   ## 3.2 Maintainability
   
   Small, focused new classes; the `validateTargetMember` addition is a clear, 
single-purpose guard. No connector/plugin/SPI registration is touched, so the 
full "registration matrix" check (factory/mapper/dist packaging) doesn't apply 
to this PR.
   
   ## 3.3 Extensibility
   
   The option-rule lookup page and status page both follow existing 
servlet/service patterns, so future endpoints in the same family should be easy 
to add consistently.
   
   ## 3.4 Historical-Version Compatibility
   
   No REST contract, config option, or serialized/checkpoint state is broken. 
The one real (if narrow) behavior change is Issue 2 above; everything else is 
additive.
   
   # 4. Issue Summary
   
   | # | Issue | Location | Severity | Raised by another reviewer |
   | --- | --- | --- | --- | --- |
   | 1 | `seatunnel-ui` CI job still skipped for this head; the last commit's 
test fix has never actually run in CI | `.github/workflows/backend.yml`, 
`jobs.spec.ts` | Medium | No (carried over from Daniel's own prior round, 
re-verified live this round) |
   | 2 | `update-tags` legacy flat-map body now rejects a literal `tags` key 
with a non-object value (narrow compat edge case) | 
`UpdateTagsService.java:87-98` | Low | No |
   | 3 | Current CI failure is a pre-existing, unrelated flaky test 
(`connector-cdc-base`), not caused by this diff | live CI, fork run 
`32327632157` | Low, informational | No |
   
   # 5. Merge Recommendation
   
   ### Conclusion: Ready to merge after fixes
   
   **1. Blockers — must be fixed before merge:**
   - Issue 1 — get the `seatunnel-ui` job to actually execute against this 
exact head (rebase onto current `dev` to pick up #11515's routing, or have the 
author report a local `npm run test:unit` run) before treating the last 
commit's test fix as CI-confirmed rather than statically-read.
   
   **2. Recommended fixes — non-blocking:**
   - Issue 2 — document (or adjust) the narrow `tags`-key-collision edge case 
in `extractTagParams`.
   - Issue 3 — rerun the failed `unit-test (8, ubuntu-latest)` job (or rely on 
the rebase in Issue 1 picking up a healthier base); no code change needed on 
this PR's side.
   - Non-blocking test/doc suggestion carried from earlier rounds: a small 
backend test locking in the "`/http-service/status` never returns a sensitive 
field" contract would be a nice belt-and-suspenders addition, though I verified 
that contract holds today by reading the servlet in full.
   
   **Overall assessment.** I independently re-verified the two things that 
matter most for a PR that adds job-control and a new status endpoint to the Web 
UI: (1) the new endpoint cannot leak credentials or bypass the existing auth 
filter chain — confirmed field-by-field and via the actual filter registration 
code, not by trusting the description; and (2) the hardening added to 
`update-tags` is a real, backward-compatible-in-the-common-case safety 
improvement, with one narrow edge case now flagged as Issue 2 that wasn't 
called out in earlier rounds. Live CI is currently red, but I traced the actual 
failure to an unrelated pre-existing flaky test in `connector-cdc-base` that 
this diff cannot have caused — the real gate is still Issue 1 (get the UI test 
job to actually run against this head). This is my own PR, and GitHub blocks 
self-approval on this account, so I'm posting this as a plain comment; a 
maintainer with approval rights is the remaining gate once Issue 1 is resolved.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to