Skip to content

Audit class#32

Merged
LinusWestling merged 3 commits intomainfrom
feature/audit
Apr 2, 2026
Merged

Audit class#32
LinusWestling merged 3 commits intomainfrom
feature/audit

Conversation

@LinusWestling
Copy link
Copy Markdown
Collaborator

@LinusWestling LinusWestling commented Apr 2, 2026

Closes #9

Summary by CodeRabbit

  • New Features

    • Full audit logging with rich event details and a UI + API to browse/filter by date, case ID, and page size (with sane clamping & pagination).
    • Role-based visibility: admins/managers see all; other roles see only authorized case events.
    • Request capture that never fails user requests and records actor, handler, client info, and case ID.
    • Automatic redaction of sensitive values in request payloads and query strings.
  • Tests

    • Integration test verifying audit event creation from UI requests.

@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 124fb1de-c5ff-4e9b-8724-35070b6cc4ed

📥 Commits

Reviewing files that changed from the base of the PR and between 5d27e44 and e88c768.

📒 Files selected for processing (2)
  • pom.xml
  • src/test/java/org/example/projektarendehantering/ProjektArendehanteringApplicationTests.java

📝 Walkthrough

Walkthrough

Adds a complete audit subsystem: JPA entity and repository, DTO and mapper, AuditService with recording/sanitization and role-filtered listing, WebMVC interceptor and config, REST/UI controllers and templates, Pom dependency for Jackson, and an integration test exercising UI-triggered audit persistence.

Changes

Cohort / File(s) Summary
Persistence
src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventEntity.java, src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventRepository.java
New AuditEventEntity mapped to audit_events (UUID id, occurredAt, actor/request/response/client fields, indexes) and repository with paginated query methods ordered by occurredAt desc.
Application Service & Mapper
src/main/java/org/example/projektarendehantering/application/service/AuditService.java, src/main/java/org/example/projektarendehantering/application/service/AuditEventMapper.java
New AuditService.record() (null-safe, defaults timestamp, sanitizes query/json payloads, persists) and listEvents() (actor required, time normalization, role-based case filtering, maps results to DTO via AuditEventMapper).
Web / Interceptor / Config
src/main/java/org/example/projektarendehantering/infrastructure/web/AuditInterceptor.java, src/main/java/org/example/projektarendehantering/infrastructure/config/AuditWebMvcConfig.java
Interceptor captures request/response/actor/case info (extracts caseId from URI vars, client IP, handler, exception), builds AuditEventEntity, calls AuditService.record() while swallowing runtime exceptions; config registers interceptor for /ui/** and /api/** with exclusions.
Presentation — REST & UI
src/main/java/org/example/projektarendehantering/presentation/rest/AuditController.java, src/main/java/org/example/projektarendehantering/presentation/web/AuditUiController.java, src/main/resources/templates/audit/list.html, src/main/resources/templates/fragments/header.html
Added REST and MVC endpoints to list audit events (filters: from/to/caseId, pagination clamped), Thymeleaf template for listing, and header nav link to Audit UI.
DTO / Mapping
src/main/java/org/example/projektarendehantering/presentation/dto/AuditEventDTO.java
New DTO mirroring entity fields (id, occurredAt, actor fields, request/response metadata, caseId, client info) with getters/setters.
Build / Tests
pom.xml, src/test/java/.../ProjektArendehanteringApplicationTests.java
Added jackson-databind and test autoconfigure dependency; added integration-style test that performs a UI request and asserts audit event persistence increment.

Sequence Diagram(s)

sequenceDiagram
    participant Client as Client
    participant SpringMVC as Spring MVC
    participant AuditInterceptor as AuditInterceptor
    participant AuditService as AuditService
    participant Repo as AuditEventRepository

    Client->>SpringMVC: HTTP request (/ui/... or /api/...)
    SpringMVC->>AuditInterceptor: afterCompletion(request,response,handler,ex)
    AuditInterceptor->>AuditService: record(AuditEventEntity)
    AuditService->>AuditService: sanitize query / normalize timestamp / apply role filters (for list)
    AuditService->>Repo: save(entity) or query(...) for listEvents
    Repo-->>AuditService: persisted entity / page
    AuditService-->>SpringMVC: (for list) Page<AuditEventDTO>
    SpringMVC-->>Client: HTTP response (view or JSON)
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly Related PRs

  • New structure #13: Refactors/removes prior audit domain types and AuditLogPort; directly related to the new persistence-backed audit implementation here.

Poem

🐇 I hopped through headers, paths, and light,

I tucked each footprint safe and tight.
From user, IP, to handler name,
I log the trail — no blame, no shame.
A nibble of code, a carrot of trace.

🚥 Pre-merge checks | ✅ 3 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Audit class' is vague and generic; it fails to convey the specific changes being introduced (entity, service, mapper, controller, interceptor, and repository components). Use a more descriptive title that summarizes the main implementation, such as 'Implement audit logging system with entity, service, and REST API' or 'Add audit event recording and querying infrastructure'.
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues check ✅ Passed The PR implements comprehensive audit functionality (entity, service, mapper, controllers, interceptor, repository) that directly addresses issue #9's objective to establish audit-class workflows and structure.
Out of Scope Changes check ✅ Passed All changes are scoped to audit functionality: entity, service, mapper, controllers, interceptor, repository, template, and configuration. The header.html and pom.xml changes directly support the audit system.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/audit

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventRepository.java (1)

13-27: Use deterministic ordering for paginated audit queries.

Sorting only by occurredAt can produce unstable page boundaries when timestamps collide. Add a secondary key (e.g., id) to keep pagination deterministic.

💡 Proposed refactor
-    Page<AuditEventEntity> findAllByOccurredAtBetweenOrderByOccurredAtDesc(Instant from, Instant to, Pageable pageable);
+    Page<AuditEventEntity> findAllByOccurredAtBetweenOrderByOccurredAtDescIdDesc(Instant from, Instant to, Pageable pageable);
@@
-    Page<AuditEventEntity> findAllByCaseIdInAndOccurredAtBetweenOrderByOccurredAtDesc(
+    Page<AuditEventEntity> findAllByCaseIdInAndOccurredAtBetweenOrderByOccurredAtDescIdDesc(
             Collection<UUID> caseIds,
             Instant from,
             Instant to,
             Pageable pageable
     );
@@
-    Page<AuditEventEntity> findAllByCaseIdAndOccurredAtBetweenOrderByOccurredAtDesc(
+    Page<AuditEventEntity> findAllByCaseIdAndOccurredAtBetweenOrderByOccurredAtDescIdDesc(
             UUID caseId,
             Instant from,
             Instant to,
             Pageable pageable
     );
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventRepository.java`
around lines 13 - 27, The repository queries currently order only by occurredAt
which can yield non-deterministic pagination when timestamps are equal; update
the three methods in AuditEventRepository
(findAllByOccurredAtBetweenOrderByOccurredAtDesc,
findAllByCaseIdInAndOccurredAtBetweenOrderByOccurredAtDesc,
findAllByCaseIdAndOccurredAtBetweenOrderByOccurredAtDesc) to include a secondary
tie-breaker on the entity id (e.g., rename to OrderByOccurredAtDescIdDesc or
OrderByOccurredAtDescIdAsc consistently) so pagination becomes deterministic;
ensure all three signatures use the same id ordering direction.
src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventEntity.java (1)

35-37: Add explicit column mappings for audit String fields when audit recording is integrated.

While requestPath, queryString, and userAgent fields in this entity currently lack explicit @Column annotations (defaulting to VARCHAR(255)), note that AuditService is not currently integrated into any controller or business logic—no code invokes auditService.record(). When audit recording is actually wired up, add explicit column definitions to prevent truncation of long query strings and user agents. Use @Column(columnDefinition = "text") for variable-length fields and @Column(length = 45) for clientIp (IPv6 max).

Proposed fix (apply when audit is integrated)
+import jakarta.persistence.Column;
 import jakarta.persistence.Entity;
 import jakarta.persistence.GeneratedValue;
 import jakarta.persistence.GenerationType;
 import jakarta.persistence.Id;
 import jakarta.persistence.Index;
 import jakarta.persistence.Table;
@@
-    private String httpMethod;
-    private String requestPath;
-    private String queryString;
-    private String handler;
+    `@Column`(length = 16)
+    private String httpMethod;
+    `@Column`(columnDefinition = "text")
+    private String requestPath;
+    `@Column`(columnDefinition = "text")
+    private String queryString;
+    `@Column`(columnDefinition = "text")
+    private String handler;
@@
-    private String clientIp;
-    private String userAgent;
+    `@Column`(length = 45)
+    private String clientIp;
+    `@Column`(columnDefinition = "text")
+    private String userAgent;

Also applies to: 44-45

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventEntity.java`
around lines 35 - 37, The AuditEventEntity currently relies on default column
sizes which may truncate long values; update the entity by adding explicit
`@Column` mappings: annotate requestPath, queryString, and userAgent with
`@Column`(columnDefinition = "text") to allow variable-length content, and
annotate clientIp with `@Column`(length = 45) to safely store IPv6 addresses;
modify the AuditEventEntity class fields requestPath, queryString, userAgent,
and clientIp accordingly so the schema supports long query strings and user
agents when AuditService.record() is used.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/main/java/org/example/projektarendehantering/application/service/AuditService.java`:
- Around line 47-48: After computing safeFrom and safeTo in AuditService (use
the same logic: Instant safeFrom = from != null ? from : Instant.EPOCH; Instant
safeTo = to != null ? to : Instant.now();), validate the time-window order by
adding a check like if (safeFrom.isAfter(safeTo)) throw new
IllegalArgumentException("Invalid time range: 'from' must be <= 'to'"); so the
method fails fast when a caller supplies an inverted range instead of silently
returning empty results.
- Around line 36-42: AuditEventEntity currently persists raw payloads in
AuditService.record; before calling auditEventRepository.save(event) implement
payload sanitization: add a private sanitizeAuditPayload method in AuditService
that detects and redacts sensitive keys (e.g.,
"password","token","authorization","apiKey","access_token","secret","ssn","creditCard",
etc.) from the event payload (handle both Map/structured payloads and
JSON/string query strings by parsing, replacing values with "[REDACTED]" and
preserving structure), then set the sanitized payload back on the
AuditEventEntity (use event.getPayload()/setPayload(...) or appropriate
accessors) and only then call auditEventRepository.save(event); keep null checks
(event != null, occurredAt) intact.
- Around line 61-67: The current logic in AuditService returns
Page.empty(pageable) when allowedCaseIds.isEmpty() even if a caller passed an
explicit caseId, bypassing authorization; reorder the checks so that if (caseId
!= null) { if (!allowedCaseIds.contains(caseId)) throw new
NotAuthorizedException(...) } is executed before the allowedCaseIds.isEmpty()
check, ensuring the explicit caseId is rejected with NotAuthorizedException
rather than returning an empty Page; keep references to allowedCaseIds, caseId,
NotAuthorizedException and Page.empty(pageable) when making the change.

---

Nitpick comments:
In
`@src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventEntity.java`:
- Around line 35-37: The AuditEventEntity currently relies on default column
sizes which may truncate long values; update the entity by adding explicit
`@Column` mappings: annotate requestPath, queryString, and userAgent with
`@Column`(columnDefinition = "text") to allow variable-length content, and
annotate clientIp with `@Column`(length = 45) to safely store IPv6 addresses;
modify the AuditEventEntity class fields requestPath, queryString, userAgent,
and clientIp accordingly so the schema supports long query strings and user
agents when AuditService.record() is used.

In
`@src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventRepository.java`:
- Around line 13-27: The repository queries currently order only by occurredAt
which can yield non-deterministic pagination when timestamps are equal; update
the three methods in AuditEventRepository
(findAllByOccurredAtBetweenOrderByOccurredAtDesc,
findAllByCaseIdInAndOccurredAtBetweenOrderByOccurredAtDesc,
findAllByCaseIdAndOccurredAtBetweenOrderByOccurredAtDesc) to include a secondary
tie-breaker on the entity id (e.g., rename to OrderByOccurredAtDescIdDesc or
OrderByOccurredAtDescIdAsc consistently) so pagination becomes deterministic;
ensure all three signatures use the same id ordering direction.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: b57b16d4-71d5-40cc-9681-18eb9ffe2807

📥 Commits

Reviewing files that changed from the base of the PR and between 172d176 and f324ec9.

📒 Files selected for processing (5)
  • src/main/java/org/example/projektarendehantering/application/service/AuditEventMapper.java
  • src/main/java/org/example/projektarendehantering/application/service/AuditService.java
  • src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventEntity.java
  • src/main/java/org/example/projektarendehantering/infrastructure/persistence/AuditEventRepository.java
  • src/main/java/org/example/projektarendehantering/presentation/dto/AuditEventDTO.java

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (4)
pom.xml (1)

71-75: Redundant test dependency.

spring-boot-test-autoconfigure is already included transitively by spring-boot-starter-test. This explicit declaration is unnecessary.

🧹 Proposed fix
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-test-autoconfigure</artifactId>
-            <scope>test</scope>
-        </dependency>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@pom.xml` around lines 71 - 75, Remove the redundant explicit dependency
declaration for artifactId "spring-boot-test-autoconfigure" from the pom.xml
because it is provided transitively by "spring-boot-starter-test"; locate the
<dependency> block containing groupId org.springframework.boot and artifactId
spring-boot-test-autoconfigure and delete that entire dependency element so the
project relies on the existing spring-boot-starter-test transitive inclusion.
src/main/java/org/example/projektarendehantering/presentation/web/AuditUiController.java (1)

39-43: Consider extracting shared pagination logic.

The pagination clamping logic (Math.max(page, 0), Math.min(Math.max(size, 1), 200)) is duplicated in both AuditController and AuditUiController. This could be extracted to a shared utility method.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/presentation/web/AuditUiController.java`
around lines 39 - 43, Extract the duplicated pagination clamping into a shared
utility method and replace the inline logic in both AuditUiController and
AuditController with a call to it; specifically, create a helper (e.g.,
PaginationUtils.createPageRequest or PaginationHelper.getPageable) that accepts
page, size, and Sort and inside performs Math.max(page, 0) and
Math.min(Math.max(size, 1), 200) before returning PageRequest.of(...), then
update the Pageable construction in AuditUiController (the PageRequest.of(...)
usage) and the analogous code in AuditController to use this new helper.
src/main/java/org/example/projektarendehantering/infrastructure/web/AuditInterceptor.java (1)

90-97: Consider X-Forwarded-For spoofing risk.

The X-Forwarded-For header can be spoofed by clients. If accurate client IP tracking is important for security audit purposes, ensure your infrastructure (load balancer/reverse proxy) overwrites or sanitizes this header before it reaches the application.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/infrastructure/web/AuditInterceptor.java`
around lines 90 - 97, The clientIp method trusts the X-Forwarded-For header
which can be spoofed; change it to only use X-Forwarded-For when the immediate
peer is a trusted proxy. Modify AuditInterceptor.clientIp to consult a
configurable set/list of trusted proxy IPs (e.g., trustedProxies) and only parse
X-Forwarded-For if request.getRemoteAddr() is in that set; otherwise always
return request.getRemoteAddr(). Make the trustedProxies configurable
(constructor/config property) and ensure trimming/parsing of the first entry in
the header remains the same when allowed.
src/main/java/org/example/projektarendehantering/application/service/AuditService.java (1)

38-38: Consider injecting ObjectMapper instead of creating inline.

Creating a new ObjectMapper instance as a field prevents configuration sharing (e.g., custom serializers, modules) and makes testing harder. Spring Boot auto-configures an ObjectMapper bean that can be injected.

💡 Proposed change
-    private final ObjectMapper objectMapper = new ObjectMapper();
+    private final ObjectMapper objectMapper;

-    public AuditService(AuditEventRepository auditEventRepository, AuditEventMapper auditEventMapper, CaseRepository caseRepository) {
+    public AuditService(AuditEventRepository auditEventRepository, AuditEventMapper auditEventMapper, CaseRepository caseRepository, ObjectMapper objectMapper) {
         this.auditEventRepository = auditEventRepository;
         this.auditEventMapper = auditEventMapper;
         this.caseRepository = caseRepository;
+        this.objectMapper = objectMapper;
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/application/service/AuditService.java`
at line 38, The AuditService currently instantiates a new ObjectMapper inline
(private final ObjectMapper objectMapper = new ObjectMapper();) which prevents
shared configuration and makes testing harder; change AuditService to accept an
ObjectMapper as a dependency (constructor injection or `@Autowired`) and remove
the inline new ObjectMapper() so the class uses the Spring-configured
ObjectMapper bean; update any tests to provide a mocked or test-configured
ObjectMapper via the constructor or test configuration.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@pom.xml`:
- Around line 115-118: The POM contains a duplicate dependency declaration for
com.fasterxml.jackson.core:jackson-databind; remove the redundant <dependency>
block that declares groupId com.fasterxml.jackson.core and artifactId
jackson-databind (the second occurrence) so it only appears once (or remove both
and rely on the transitive jackson-databind from spring-boot-starter-web if you
prefer), ensuring the final pom only has a single jackson-databind declaration
or none if relying on the starter.

In
`@src/main/java/org/example/projektarendehantering/application/service/AuditService.java`:
- Around line 91-117: Remove the unused overload sanitizeAuditPayload(Object):
delete the private Object sanitizeAuditPayload(Object) method and ensure callers
use the existing sanitizeAuditPayload(String) and other type-specific logic;
update any recursive sanitization to be handled within the String overload
(sanitizeAuditPayload(String)) or by converting/dispatching callers to the
appropriate overload so there are no orphaned recursive calls like the ones that
referenced sanitizeAuditPayload(Object).

In
`@src/test/java/org/example/projektarendehantering/ProjektArendehanteringApplicationTests.java`:
- Around line 29-40: The MockMvc in uiRequest_createsAuditEvent is built without
the Spring Security filter chain so `@WithMockUser` isn't applied; update the
MockMvc construction (the webAppContextSetup(...) call that builds MockMvc) to
apply Spring Security before build — e.g., use
MockMvcBuilders.webAppContextSetup(webApplicationContext).apply(springSecurity()).build()
or enable filters via AutoConfigureMockMvc so that security filters are included
and the `@WithMockUser` security context is propagated during the request.

---

Nitpick comments:
In `@pom.xml`:
- Around line 71-75: Remove the redundant explicit dependency declaration for
artifactId "spring-boot-test-autoconfigure" from the pom.xml because it is
provided transitively by "spring-boot-starter-test"; locate the <dependency>
block containing groupId org.springframework.boot and artifactId
spring-boot-test-autoconfigure and delete that entire dependency element so the
project relies on the existing spring-boot-starter-test transitive inclusion.

In
`@src/main/java/org/example/projektarendehantering/application/service/AuditService.java`:
- Line 38: The AuditService currently instantiates a new ObjectMapper inline
(private final ObjectMapper objectMapper = new ObjectMapper();) which prevents
shared configuration and makes testing harder; change AuditService to accept an
ObjectMapper as a dependency (constructor injection or `@Autowired`) and remove
the inline new ObjectMapper() so the class uses the Spring-configured
ObjectMapper bean; update any tests to provide a mocked or test-configured
ObjectMapper via the constructor or test configuration.

In
`@src/main/java/org/example/projektarendehantering/infrastructure/web/AuditInterceptor.java`:
- Around line 90-97: The clientIp method trusts the X-Forwarded-For header which
can be spoofed; change it to only use X-Forwarded-For when the immediate peer is
a trusted proxy. Modify AuditInterceptor.clientIp to consult a configurable
set/list of trusted proxy IPs (e.g., trustedProxies) and only parse
X-Forwarded-For if request.getRemoteAddr() is in that set; otherwise always
return request.getRemoteAddr(). Make the trustedProxies configurable
(constructor/config property) and ensure trimming/parsing of the first entry in
the header remains the same when allowed.

In
`@src/main/java/org/example/projektarendehantering/presentation/web/AuditUiController.java`:
- Around line 39-43: Extract the duplicated pagination clamping into a shared
utility method and replace the inline logic in both AuditUiController and
AuditController with a call to it; specifically, create a helper (e.g.,
PaginationUtils.createPageRequest or PaginationHelper.getPageable) that accepts
page, size, and Sort and inside performs Math.max(page, 0) and
Math.min(Math.max(size, 1), 200) before returning PageRequest.of(...), then
update the Pageable construction in AuditUiController (the PageRequest.of(...)
usage) and the analogous code in AuditController to use this new helper.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 7dc96df7-b5c0-42f7-8cd4-24ed1347258f

📥 Commits

Reviewing files that changed from the base of the PR and between f324ec9 and 5d27e44.

📒 Files selected for processing (9)
  • pom.xml
  • src/main/java/org/example/projektarendehantering/application/service/AuditService.java
  • src/main/java/org/example/projektarendehantering/infrastructure/config/AuditWebMvcConfig.java
  • src/main/java/org/example/projektarendehantering/infrastructure/web/AuditInterceptor.java
  • src/main/java/org/example/projektarendehantering/presentation/rest/AuditController.java
  • src/main/java/org/example/projektarendehantering/presentation/web/AuditUiController.java
  • src/main/resources/templates/audit/list.html
  • src/main/resources/templates/fragments/header.html
  • src/test/java/org/example/projektarendehantering/ProjektArendehanteringApplicationTests.java
✅ Files skipped from review due to trivial changes (1)
  • src/main/resources/templates/fragments/header.html

Comment on lines +91 to +117
@SuppressWarnings("unchecked")
private Object sanitizeAuditPayload(Object payload) {
if (payload == null) return null;
if (payload instanceof String s) return sanitizeAuditPayload(s);

if (payload instanceof Map<?, ?> map) {
Map<String, Object> out = new LinkedHashMap<>();
for (Map.Entry<?, ?> e : map.entrySet()) {
String key = e.getKey() == null ? null : String.valueOf(e.getKey());
Object value = e.getValue();
if (key != null && isSensitiveKey(key)) {
out.put(key, REDACTED);
} else {
out.put(key, sanitizeAuditPayload(value));
}
}
return out;
}

if (payload instanceof Collection<?> col) {
List<Object> out = new ArrayList<>(col.size());
for (Object v : col) out.add(sanitizeAuditPayload(v));
return out;
}

return payload;
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that sanitizeAuditPayload(Object) is never called
rg -n 'sanitizeAuditPayload\s*\(' --type java | grep -v 'private.*sanitizeAuditPayload'

Repository: ithsjava25/project-backend-code-trauma-team

Length of output: 727


🏁 Script executed:

#!/bin/bash
# Find all sanitizeAuditPayload method signatures/definitions
rg -n 'private.*sanitizeAuditPayload' --type java -A 1

Repository: ithsjava25/project-backend-code-trauma-team

Length of output: 673


Remove unused method overload: sanitizeAuditPayload(Object).

The Object overload is never called. The only external call site (line 71) passes a String, which routes to the String overload (line 75). The Object overload's recursive calls (lines 104, 112) are only reachable if the Object overload itself were initially invoked, which never happens in practice. Remove this dead code.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@src/main/java/org/example/projektarendehantering/application/service/AuditService.java`
around lines 91 - 117, Remove the unused overload sanitizeAuditPayload(Object):
delete the private Object sanitizeAuditPayload(Object) method and ensure callers
use the existing sanitizeAuditPayload(String) and other type-specific logic;
update any recursive sanitization to be handled within the String overload
(sanitizeAuditPayload(String)) or by converting/dispatching callers to the
appropriate overload so there are no orphaned recursive calls like the ones that
referenced sanitizeAuditPayload(Object).

@LinusWestling LinusWestling merged commit 81b32ad into main Apr 2, 2026
1 of 2 checks passed
@LinusWestling LinusWestling deleted the feature/audit branch April 2, 2026 13:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make sense of the audit-classes and workflows

1 participant