Leave the seeded Classification policy unowned rather than naming a service account

This commit is contained in:
Anthony Stirling
2026-08-19 22:41:14 +01:00
parent ae26756a0a
commit 12a4ffa963
2 changed files with 13 additions and 14 deletions
@@ -13,7 +13,6 @@ import org.springframework.transaction.event.TransactionalEventListener;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import stirling.software.common.model.enumeration.Role;
import stirling.software.proprietary.model.TeamCreatedEvent;
import stirling.software.proprietary.policy.model.OutputSpec;
import stirling.software.proprietary.policy.model.PipelineStep;
@@ -79,18 +78,17 @@ public class DefaultClassificationPolicySeeder {
}
/**
* Move a policy seeded before the owner was a real identity onto the internal API user. Left
* alone otherwise, so an owner someone deliberately changed is never overwritten.
* Clear an owner seeded as a placeholder name. An owner someone deliberately set is left alone.
*/
private void repairOwner(Policy policy) {
if (!LEGACY_OWNER.equals(policy.owner())) {
return;
}
policyStore.save(policy.withOwner(Role.INTERNAL_API_USER.getRoleId()));
policyStore.save(policy.withOwner(null));
log.info(
"Re-owned Classification policy {} from '{}' to the internal API user",
policy.id(),
LEGACY_OWNER);
"Cleared placeholder owner '{}' on Classification policy {}",
LEGACY_OWNER,
policy.id());
}
private static boolean isClassification(Policy policy) {
@@ -110,7 +108,9 @@ public class DefaultClassificationPolicySeeder {
return new Policy(
null,
POLICY_NAME,
Role.INTERNAL_API_USER.getRoleId(),
// Nobody created this - it is seeded. A name here would have to be a real user, and
// every consumer of owner already handles its absence.
null,
true,
List.of(),
List.of(new PipelineStep(CLASSIFY_ENDPOINT, Map.of())),
@@ -17,7 +17,6 @@ import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import stirling.software.common.model.enumeration.Role;
import stirling.software.proprietary.model.Team;
import stirling.software.proprietary.model.TeamCreatedEvent;
import stirling.software.proprietary.policy.model.OutputSpec;
@@ -37,7 +36,7 @@ class DefaultClassificationPolicySeederTest {
}
private static Policy classificationPolicy(Long teamId) {
return classificationPolicy(teamId, Role.INTERNAL_API_USER.getRoleId());
return classificationPolicy(teamId, null);
}
private static Policy classificationPolicy(Long teamId, String owner) {
@@ -83,16 +82,16 @@ class DefaultClassificationPolicySeederTest {
}
@Test
void reOwnsAPolicySeededUnderThePlaceholderName() {
void clearsAPlaceholderOwnerSeededBeforeOwnersHadToBeReal() {
when(policyStore.findByTeam(7L)).thenReturn(List.of(classificationPolicy(7L, "system")));
seeder().onTeamCreated(new TeamCreatedEvent(7L, "Acme"));
// "system" was never a user row: a sweep-fired run would fall back to it for output
// ownership, and a step dispatch would authenticate as it. Both need a real identity.
// "system" was never a user row, and a step dispatch authenticates as the owner. Absence
// is handled everywhere; a placeholder name is not.
ArgumentCaptor<Policy> saved = ArgumentCaptor.forClass(Policy.class);
verify(policyStore).save(saved.capture());
assertThat(saved.getValue().owner()).isEqualTo(Role.INTERNAL_API_USER.getRoleId());
assertThat(saved.getValue().owner()).isNull();
assertThat(saved.getValue().id()).isEqualTo("p1");
}