test(geschichte): GeschichteServiceTest — list_withDraftRequest_returnsPublished_whenCallerLacksBlogWrite #808

Open
opened 2026-06-12 07:37:18 +02:00 by marcel · 0 comments
Owner

Context

Identified during review of #794 (annotate GET /api/geschichten OpenAPI params). This is the most security-sensitive unguarded behaviour in the Geschichte domain.

GeschichteService.java:81 silently overrides any status=DRAFT request from a caller lacking BLOG_WRITE to PUBLISHED. There is currently no automated regression test for this behaviour — if the guard is removed in a future refactor, no test will catch it.

What needs to be done

Add a @ExtendWith(MockitoExtension.class) unit test to GeschichteServiceTest:

@Test
void list_withDraftRequest_returnsPublished_whenCallerLacksBlogWrite() {
    // caller has READ_ALL but not BLOG_WRITE
    AppUser reader = makeUser(Set.of("READ_ALL"));
    when(geschichteRepository.findAll(any(Specification.class)))
            .thenReturn(List.of());

    geschichteService.list(GeschichteStatus.DRAFT, List.of(), null, 10, reader);

    // verify the repository was called with PUBLISHED, not DRAFT
    // (exact assertion depends on how the Specification is inspected — may require
    //  ArgumentCaptor or a spy on the service; adjust to match the actual implementation)
}

The exact assertion approach (ArgumentCaptor, spy, or refactor to make the override testable) should be decided when implementing. The key invariant: a READ_ALL-only caller passing DRAFT must receive PUBLISHED results.

Acceptance Criteria

  • GeschichteServiceTest contains list_withDraftRequest_returnsPublished_whenCallerLacksBlogWrite
  • Test is a @ExtendWith(MockitoExtension.class) unit test — no Spring context
  • Test fails (red) before any code change and passes (green) after asserting the override

Why this matters

This is the only regression guard for the READ_ALL-caller status-override security behaviour documented in GeschichteService.java:81. Without it, the permission-gated logic can be silently removed in a refactor and no CI signal will catch it.

## Context Identified during review of #794 (annotate GET /api/geschichten OpenAPI params). This is the most security-sensitive unguarded behaviour in the Geschichte domain. `GeschichteService.java:81` silently overrides any `status=DRAFT` request from a caller lacking `BLOG_WRITE` to `PUBLISHED`. There is currently no automated regression test for this behaviour — if the guard is removed in a future refactor, no test will catch it. ## What needs to be done Add a `@ExtendWith(MockitoExtension.class)` unit test to `GeschichteServiceTest`: ```java @Test void list_withDraftRequest_returnsPublished_whenCallerLacksBlogWrite() { // caller has READ_ALL but not BLOG_WRITE AppUser reader = makeUser(Set.of("READ_ALL")); when(geschichteRepository.findAll(any(Specification.class))) .thenReturn(List.of()); geschichteService.list(GeschichteStatus.DRAFT, List.of(), null, 10, reader); // verify the repository was called with PUBLISHED, not DRAFT // (exact assertion depends on how the Specification is inspected — may require // ArgumentCaptor or a spy on the service; adjust to match the actual implementation) } ``` > The exact assertion approach (ArgumentCaptor, spy, or refactor to make the override testable) should be decided when implementing. The key invariant: a `READ_ALL`-only caller passing `DRAFT` must receive `PUBLISHED` results. ## Acceptance Criteria - [ ] `GeschichteServiceTest` contains `list_withDraftRequest_returnsPublished_whenCallerLacksBlogWrite` - [ ] Test is a `@ExtendWith(MockitoExtension.class)` unit test — no Spring context - [ ] Test fails (red) before any code change and passes (green) after asserting the override ## Why this matters This is the only regression guard for the `READ_ALL`-caller status-override security behaviour documented in `GeschichteService.java:81`. Without it, the permission-gated logic can be silently removed in a refactor and no CI signal will catch it.
marcel added the P2-mediumtest labels 2026-06-12 07:37:33 +02:00
Sign in to join this conversation.
No Label P2-medium test
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: marcel/familienarchiv#808