btlqql opened a new pull request, #5351:
URL: https://github.com/apache/rocketmq-dashboard/pull/5351
### Which Issue(s) This PR Fixes
- Fixes #5169
### Brief Description
The ACL users tab had no export surface: `AclController` offered only `GET
/api/acl/users`, `GET /api/acl/users/page` and `GET
/api/acl/users/{id}/credentials`
(`server/src/main/java/org/apache/rocketmq/studio/instance/acl/AclController.java:89-110`),
so an access review of "which accounts exist, which are admin, which clusters
can each reach, which have IP whitelists" could only be transcribed from a
20-row paginated table.
This PR adds `GET /api/acl/users/export`, which streams the account
inventory as CSV (`text/csv;charset=UTF-8`, `Content-Disposition: attachment;
filename="acl-users.csv"`, BOM-prefixed header) with columns: user id,
username, masked access key, admin flag, cluster bindings (`;`-joined),
read/write permission, IP whitelist pattern and created time.
`AclUserCsvExporter` renders the document and the endpoint returns
`ResponseEntity<byte[]>`.
Two properties worth calling out:
- **No secret can leak.** The rows come from the page query the users table
reads, which already masks both credentials in `AclService` for both the Apache
and the Tencent path, so the export repeats only what the list already shows.
`secretKey` has no column at all, and the regression test asserts the raw
secret values never appear in the CSV.
- **The export matches the filtered view.** Instead of re-deriving the
keyword filter, the endpoint walks the *same* page query
(`AclService.pageUsers`, 100 rows per request — the service's own page-size
cap) so the file is exactly the filtered inventory the reviewer saw on screen,
including the repository-side `LIKE` pagination on the Apache path and the
provider list on the Tencent path. The whole inventory is materialized, so the
row count is bounded: above 10,000 records the endpoint returns `400` naming
the limit, following `CloudCredentialService.exportMaskedCsv`.
Scope note: the issue also asks for an **Export users** button on the users
tab. This PR is the server side only — the web application is outside the files
I own for this change — so the remaining follow-up is the button wired to this
endpoint through the shared blob download path. Nothing else about the users
tab changes; list, page, create, update, delete and credentials-reveal
behaviour are untouched, and `AclService` is not modified.
### How Did You Test This Change?
`AclControllerTest` (the controller slice, only `AclService` is mocked)
gained three tests: the filtered export with the CSV contract and the masking
regression, the multi-page walk, and the export bound.
Before the fix — the endpoint does not exist, so the three new tests fail
with 404 while the 27 pre-existing tests keep passing:
```
$ cd server && mvn -B -ntp test -Dtest=AclControllerTest
[ERROR] Tests run: 30, Failures: 3, Errors: 0, Skipped: 0, Time elapsed:
9.513 s <<< FAILURE! -- in
org.apache.rocketmq.studio.instance.acl.AclControllerTest
java.lang.AssertionError: Status expected:<200> but was:<404> <-
exportUsersShouldStreamTheMaskedInventoryForTheFilteredInstanceTest:376
java.lang.AssertionError: Status expected:<400> but was:<404> <-
exportUsersShouldRejectAnInventoryBeyondTheExportBoundTest:416
java.lang.AssertionError: Status expected:<200> but was:<404> <-
exportUsersShouldWalkEveryPageOfTheFilteredResultTest:401
[ERROR] Tests run: 30, Failures: 3, Errors: 0, Skipped: 0
[INFO] BUILD FAILURE
```
After the fix:
```
$ cd server && mvn -B -ntp test -Dtest=AclControllerTest
[INFO] You have 0 Checkstyle violations.
[INFO] Tests run: 30, Failures: 0, Errors: 0, Skipped: 0, Time elapsed:
9.335 s -- in org.apache.rocketmq.studio.instance.acl.AclControllerTest
[INFO] Tests run: 30, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
The new tests assert the response headers (`text/csv;charset=UTF-8`,
`attachment; filename="acl-users.csv"`), the BOM-prefixed header row, the
masked access key and the cluster/permission/whitelist/created columns, that
the raw secret values and any secret column are absent, that all 150 rows of a
two-page result are exported in one document, and that 10,001 records produce a
400 naming the limit.
Neighbouring suites, to show the controller change does not disturb the
package or the authorization matrix:
```
$ cd server && mvn -B -ntp test
-Dtest=AclControllerTest,AclServiceTest,AclUserVOTest,AuthInterceptorTest,AuthCredentialAuthorizationIntegrationTest,MybatisPlusAclRepositoryTest,ApacheAclReadServiceTest
[INFO] Tests run: 192, Failures: 0, Errors: 0, Skipped: 0
[INFO] BUILD SUCCESS
```
### Checklist
- [x] One coherent change; unrelated modifications are not bundled in
- [x] Commit subject follows Conventional Commits
- [x] Tests added or updated for non-trivial changes
- [ ] New UI text has both Chinese and English entries under `web/src/i18n/`
— not applicable: no UI change in this PR (server-side endpoint only, see the
scope note)
- [x] Architecture constraints stay green (`mvn test` runs the ArchUnit
checks) — the new endpoint reuses existing service/repository APIs, no new
package or dependency edge
- [x] New source files carry the ASF license header
- [ ] Documentation touched where behaviour changed (README / `docs/` /
in-app help) — not touched: the endpoint follows the existing export
conventions and the users tab that would surface it is a follow-up outside this
PR
--
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]