Description
Test suites already support an auth property (currently type: basic + username/
password) that can be declared either on a test case's own request block, or suite-wide on
a rest-client / rest-clients entry (RestClientConfig.auth()). PureJavaTestEngine
already resolves and applies this precedence when sending the HTTP request (request-level
overrides suite-level), but the resulting Authorization header is never recorded anywhere
that reaches the HTML report — ExecutedRequestInfo has no auth field at all today.
The report should show that authentication was used (its type), without ever leaking the real
username/password. This is purely a reporting/visibility feature — no new YAML property, no
new auth type.
Design decision: the real username/password values ARE captured into
ExecutedRequestInfo (reusing the existing RequestAuth record as-is), and masking to the
literal string "*****" happens only at report-render time, inside HtmlReportGenerator. Raw
credentials must never be written into the map that feeds the Thymeleaf template.
Implementation Plan
1. Model — reuse RequestAuth, no new class
Add a field to ExecutedRequestInfo (model/ExecutedRequestInfo.java):
public record ExecutedRequestInfo(
HttpMethod method,
String url,
@Nullable Map<String, String> headers,
@Nullable String body,
@Nullable RequestAuth auth) {}
No new record is needed — RequestAuth(AuthType type, String username, String password)
already has exactly the right shape. Update the class javadoc to describe the new field and
note it holds the real (unmasked) credentials, so masking is a report-rendering concern, not a
model concern.
2. Engine — resolve effective auth in PureJavaTestEngine
In executeSingleTest (service/PureJavaTestEngine.java), before constructing
ExecutedRequestInfo (~line 432), resolve which auth actually applies to this request and
pass it as the new constructor argument. Add a private helper that mirrors the precedence
already implemented across buildRestClient (suite-level default header) and
buildRequestSpec (request-level override):
private @Nullable RequestAuth resolveEffectiveAuth(TestSuite testSuite, TestCase config) {
RequestAuth requestAuth = config.request().auth();
if (requestAuth != null && !hasAuthorizationHeader(config.request().headers())) {
return requestAuth;
}
String id = config.request().restClient();
RestClientConfig restClientConfig = testSuite.restClientsById()
.getOrDefault(id, testSuite.restClientsById().get(TestSuite.DEFAULT_REST_CLIENT_ID));
return restClientConfig != null ? restClientConfig.auth() : null;
}
Notes:
- Reuses the existing
hasAuthorizationHeader helper so the captured auth matches reality: if
the test case declares an explicit Authorization header, request-level auth is never
actually applied (per buildRequestSpec), so it must not be reported either.
- Falls back to the suite's default rest-client the same way
selectRestClient does, when the
request's restClient() id is null or unknown.
- Give this method full JavaDoc per project convention.
3. Report generator — mask at render time
In HtmlReportGenerator.toTestMap() (service/HtmlReportGenerator.java), add a masked
representation without ever putting the raw values in the map:
private static final String MASKED_VALUE = "*****";
...
RequestAuth auth = tc.requestInfo() != null ? tc.requestInfo().auth() : null;
map.put("hasAuth", auth != null);
map.put("authType", auth != null ? auth.type().name() : null);
map.put("authUsername", auth != null ? MASKED_VALUE : null);
map.put("authPassword", auth != null ? MASKED_VALUE : null);
4. Template — new Authentication block
In src/main/resources/templates/suite-report.html, inside the existing Request
<details> block (near the current headers-grid), add an auth block guarded by
th:if="${t.hasAuth}", following the same headers-grid/header-row markup pattern already
used for headers:
<div th:if="${t.hasAuth}">
<p class="section-label">Authentication</p>
<div class="headers-grid">
<div class="header-row">
<span class="header-name">Type</span>
<span class="header-value" th:text="${t.authType}">BASIC</span>
</div>
<div class="header-row">
<span class="header-name">Username</span>
<span class="header-value" th:text="${t.authUsername}">*****</span>
</div>
<div class="header-row">
<span class="header-name">Password</span>
<span class="header-value" th:text="${t.authPassword}">*****</span>
</div>
</div>
</div>
5. Fix existing call sites (compile breakage)
Adding a field to the ExecutedRequestInfo record breaks every existing constructor call.
Only two call sites exist today (grep -rn "new ExecutedRequestInfo(" src):
service/PureJavaTestEngine.java — updated as part of step 2.
src/test/java/.../service/HtmlReportGeneratorTest.java — add null (or a RequestAuth
fixture, for the new masking tests) as the 5th argument at each call site.
6. Tests to add
PureJavaTestEngineTest / PureJavaTestEngineAdditionalTest:
- Request declares
auth → result.requestInfo().auth() equals the declared RequestAuth.
- Suite/rest-client declares
auth, request declares none → suite-level auth is captured.
- Both declared → request-level auth wins (matches existing header-precedence behavior).
- Request declares
auth AND an explicit Authorization header → captured auth is null
(header wins, per hasAuthorizationHeader check — matches what's actually sent).
- Neither declares
auth → auth is null.
HtmlReportGeneratorTest:
- Build a
TestCaseResult whose requestInfo().auth() has a real username/password fixture
(e.g. "realuser" / "s3cr3t") and assert the generated HTML contains "*****" for both
fields and does not contain the raw "realuser"/"s3cr3t" strings anywhere.
- Assert no Authentication block renders when
auth is null (hasAuth false).
7. Docs
Update docs/html-report.md, in the #### Request bullet list, to add a line describing the
new Authentication block (type shown in full, username/password always shown as *****).
Files to Change
src/main/java/io/github/snytkine/apitester/api_tester_cli/model/ExecutedRequestInfo.java
src/main/java/io/github/snytkine/apitester/api_tester_cli/service/PureJavaTestEngine.java
src/main/java/io/github/snytkine/apitester/api_tester_cli/service/HtmlReportGenerator.java
src/main/resources/templates/suite-report.html
src/test/java/io/github/snytkine/apitester/api_tester_cli/service/HtmlReportGeneratorTest.java
src/test/java/io/github/snytkine/apitester/api_tester_cli/service/PureJavaTestEngineTest.java (and/or PureJavaTestEngineAdditionalTest.java)
docs/html-report.md
Description
Test suites already support an
authproperty (currentlytype: basic+username/password) that can be declared either on a test case's ownrequestblock, or suite-wide ona
rest-client/rest-clientsentry (RestClientConfig.auth()).PureJavaTestEnginealready resolves and applies this precedence when sending the HTTP request (request-level
overrides suite-level), but the resulting
Authorizationheader is never recorded anywherethat reaches the HTML report —
ExecutedRequestInfohas noauthfield at all today.The report should show that authentication was used (its type), without ever leaking the real
username/password. This is purely a reporting/visibility feature — no new YAML property, no
new auth type.
Design decision: the real
username/passwordvalues ARE captured intoExecutedRequestInfo(reusing the existingRequestAuthrecord as-is), and masking to theliteral string
"*****"happens only at report-render time, insideHtmlReportGenerator. Rawcredentials must never be written into the map that feeds the Thymeleaf template.
Implementation Plan
1. Model — reuse
RequestAuth, no new classAdd a field to
ExecutedRequestInfo(model/ExecutedRequestInfo.java):No new record is needed —
RequestAuth(AuthType type, String username, String password)already has exactly the right shape. Update the class javadoc to describe the new field and
note it holds the real (unmasked) credentials, so masking is a report-rendering concern, not a
model concern.
2. Engine — resolve effective auth in
PureJavaTestEngineIn
executeSingleTest(service/PureJavaTestEngine.java), before constructingExecutedRequestInfo(~line 432), resolve which auth actually applies to this request andpass it as the new constructor argument. Add a private helper that mirrors the precedence
already implemented across
buildRestClient(suite-level default header) andbuildRequestSpec(request-level override):Notes:
hasAuthorizationHeaderhelper so the captured auth matches reality: ifthe test case declares an explicit
Authorizationheader, request-levelauthis neveractually applied (per
buildRequestSpec), so it must not be reported either.selectRestClientdoes, when therequest's
restClient()id is null or unknown.3. Report generator — mask at render time
In
HtmlReportGenerator.toTestMap()(service/HtmlReportGenerator.java), add a maskedrepresentation without ever putting the raw values in the map:
4. Template — new Authentication block
In
src/main/resources/templates/suite-report.html, inside the existingRequest<details>block (near the current headers-grid), add an auth block guarded byth:if="${t.hasAuth}", following the sameheaders-grid/header-rowmarkup pattern alreadyused for headers:
5. Fix existing call sites (compile breakage)
Adding a field to the
ExecutedRequestInforecord breaks every existing constructor call.Only two call sites exist today (
grep -rn "new ExecutedRequestInfo(" src):service/PureJavaTestEngine.java— updated as part of step 2.src/test/java/.../service/HtmlReportGeneratorTest.java— addnull(or aRequestAuthfixture, for the new masking tests) as the 5th argument at each call site.
6. Tests to add
PureJavaTestEngineTest/PureJavaTestEngineAdditionalTest:auth→result.requestInfo().auth()equals the declaredRequestAuth.auth, request declares none → suite-level auth is captured.authAND an explicitAuthorizationheader → capturedauthisnull(header wins, per
hasAuthorizationHeadercheck — matches what's actually sent).auth→authisnull.HtmlReportGeneratorTest:TestCaseResultwhoserequestInfo().auth()has a real username/password fixture(e.g.
"realuser"/"s3cr3t") and assert the generated HTML contains"*****"for bothfields and does not contain the raw
"realuser"/"s3cr3t"strings anywhere.authisnull(hasAuthfalse).7. Docs
Update
docs/html-report.md, in the#### Requestbullet list, to add a line describing thenew Authentication block (type shown in full, username/password always shown as
*****).Files to Change
src/main/java/io/github/snytkine/apitester/api_tester_cli/model/ExecutedRequestInfo.javasrc/main/java/io/github/snytkine/apitester/api_tester_cli/service/PureJavaTestEngine.javasrc/main/java/io/github/snytkine/apitester/api_tester_cli/service/HtmlReportGenerator.javasrc/main/resources/templates/suite-report.htmlsrc/test/java/io/github/snytkine/apitester/api_tester_cli/service/HtmlReportGeneratorTest.javasrc/test/java/io/github/snytkine/apitester/api_tester_cli/service/PureJavaTestEngineTest.java(and/orPureJavaTestEngineAdditionalTest.java)docs/html-report.md