From 4a860aa049a04745f4fa1dbfb55d3a8317396f3b Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Fri, 21 Aug 2026 13:29:33 -0400 Subject: [PATCH 01/11] fix(security): bump Jackson to 2.21 LTS line Remediates CVE-2026-59889 (JsonView authorization bypass) in jackson-databind. Targets the 2.21 LTS line rather than the latest 2.22.x release for long-term stability in this client library. jackson-annotations no longer publishes patch-level versions past 2.20, so it now has its own jackson-annotations-version property separate from the shared jackson-version used by jackson-core and jackson-databind. --- CHANGELOG.md | 6 ++++++ pom.xml | 8 +++++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0c6bf7da..810d3311 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 1.0.4 + +### Chore & Maintenance + +- Update `jackson-databind`, `jackson-core`, and `jackson-annotations` dependencies to the 2.21 LTS line due to vulnerability + ## 1.0.3 ### Chore & Maintenance diff --git a/pom.xml b/pom.xml index 87300363..e6c98935 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ lf-repository-api-client-v2 jar Laserfiche Repository API Client V2 - 1.0.0 + 1.0.4 https://github.com/Laserfiche/lf-repository-api-client-java The Java Laserfiche Repository API Client library for accessing the v2 Laserfiche Repository APIs. @@ -240,7 +240,7 @@ com.fasterxml.jackson.core jackson-annotations - ${jackson-version} + ${jackson-annotations-version} com.fasterxml.jackson.core @@ -309,7 +309,9 @@ ${java.version} 1.8.0 2.0.0 - 2.18.2 + + 2.21.6 + 2.21 2.9.0 1.3.5 1.0.2 From e787136ef4ecab2b789a66991c7745831f4fad1d Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 25 Aug 2026 19:12:58 -0400 Subject: [PATCH 02/11] chore: bump lf-api-client-core dependency to 2.2.5 Picks up the newly published lf-api-client-core 2.2.5, which includes the Jackson 2.21 LTS bump, keeping both packages on a consistent Jackson version. --- CHANGELOG.md | 1 + pom.xml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 810d3311..b1728374 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,7 @@ ### Chore & Maintenance - Update `jackson-databind`, `jackson-core`, and `jackson-annotations` dependencies to the 2.21 LTS line due to vulnerability +- Update `lf-api-client-core` dependency to 2.2.5 ## 1.0.3 diff --git a/pom.xml b/pom.xml index e6c98935..5c45260f 100644 --- a/pom.xml +++ b/pom.xml @@ -270,7 +270,7 @@ com.laserfiche lf-api-client-core - 2.2.4 + 2.2.5 From 45c8e90b997f691b32680c2bbf83c8ffc12439b7 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 25 Aug 2026 19:19:06 -0400 Subject: [PATCH 03/11] fix: set published version via VERSION_PREFIX instead of pom.xml CI overrides the checked-in pom.xml version via mvn versions:set using VERSION_PREFIX from main.yml, so bumping pom.xml's directly had no effect on the published artifact. Reverted pom.xml to its 1.0.0 placeholder and bumped VERSION_PREFIX to 1.0.4 instead, matching the fix applied in lf-api-client-core-java (PR #89). --- .github/workflows/main.yml | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 32a6c6d3..f63e42e9 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -12,7 +12,7 @@ on: env: API_VERSION: 'v2' - VERSION_PREFIX: '1.0.3' + VERSION_PREFIX: '1.0.4' GITHUB_PAGES_BRANCH: 'gh-pages' jobs: diff --git a/pom.xml b/pom.xml index 5c45260f..81c1a76b 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ lf-repository-api-client-v2 jar Laserfiche Repository API Client V2 - 1.0.4 + 1.0.0 https://github.com/Laserfiche/lf-repository-api-client-java The Java Laserfiche Repository API Client library for accessing the v2 Laserfiche Repository APIs. From f17dd8fdc30cf82210cdb9807229624fa8b4fc4d Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Wed, 26 Aug 2026 09:55:14 -0400 Subject: [PATCH 04/11] ci: grant checks:write and pull-requests:write to build-n-test Default GITHUB_TOKEN permissions are read-only, so EnricoMi/publish-unit-test-result-action was failing with 403 Resource not accessible by integration when creating check runs (and would also fail posting its PR comment). Same fix already worked out on an earlier abandoned branch, carried over here. --- .github/workflows/main.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f63e42e9..332eb069 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -19,6 +19,11 @@ jobs: build-n-test: runs-on: ubuntu-latest + permissions: + contents: read + checks: write + pull-requests: write + steps: - uses: actions/checkout@v4 From 0beb23aba8f22dadf896c6dc0641f9d16a66be20 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Wed, 26 Aug 2026 13:50:44 -0400 Subject: [PATCH 05/11] dummy commit needed to trigger build From dfb6b3a71ec506cba27bf7e8d19ba5ac4242cee1 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 1 Sep 2026 17:59:27 -0400 Subject: [PATCH 06/11] try using standard repo --- .github/workflows/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 332eb069..160a5e06 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -54,7 +54,7 @@ jobs: env: ACCESS_KEY: ${{ secrets.DEV_CA_PUBLIC_USE_INTEGRATION_TEST_ACCESS_KEY }} SERVICE_PRINCIPAL_KEY: ${{ secrets.DEV_CA_PUBLIC_USE_TESTOAUTHSERVICEPRINCIPAL_SERVICE_PRINCIPAL_KEY }} - REPOSITORY_ID: ${{ secrets.DEV_CA_PUBLIC_USE_REPOSITORY_ID_2 }} + REPOSITORY_ID: ${{ secrets.DEV_CA_PUBLIC_USE_REPOSITORY_ID_1 }} AUTHORIZATION_TYPE: ${{ secrets.AUTHORIZATION_TYPE }} TEST_HEADER: ${{ secrets.TEST_HEADER }} READONLY_TEST_FOLDER_ID: ${{ secrets.DEV_CA_READONLY_TEST_FOLDER_ID }} From 6687eb10f1e0141ad1b3d80fb5192c414c4c4dad Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 1 Sep 2026 18:06:54 -0400 Subject: [PATCH 07/11] empty commit to trigger build From 18608d2a19181e73ef40cfefc6e049d75764bbde Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Tue, 1 Sep 2026 19:03:37 -0400 Subject: [PATCH 08/11] test: assert delete task completed before checking entry is gone startDeleteEntryCanDeleteFolder only waited for the task to leave IN_PROGRESS, which is also true when a task fails, then asserted getEntry throws 404. A failed delete (e.g. a required audit reason not set) would silently look identical to "not deleted yet" in the old assertion. Now asserts TaskStatus.COMPLETED first and prints the ProblemDetails on failure, matching the pattern already used in ImportUploadedPartsApiTest. --- .../repository/api/integration/EntriesClientTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java b/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java index fbcefa9d..b403e5f3 100644 --- a/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java +++ b/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java @@ -426,6 +426,15 @@ void startDeleteEntryCanDeleteFolder() { waitUntilTaskEnds(deleteEntryResponse.getTaskId()); + TaskCollectionResponse tasks = repositoryApiClient + .getTasksClient() + .listTasks(new ParametersForListTasks().setRepositoryId(repositoryId).setTaskIds(taskId)); + TaskProgress taskProgress = tasks.getValue().get(0); + if (taskProgress.getStatus() == TaskStatus.FAILED) { + printProblemDetails(taskProgress.getErrors().get(0)); + } + assertEquals(TaskStatus.COMPLETED, taskProgress.getStatus()); + ApiException apiException = Assertions.assertThrows( ApiException.class, () -> client.getEntry(new ParametersForGetEntry().setRepositoryId(repositoryId) From 56390bdbce69e5b56f95586d8cda493347a919db Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Wed, 2 Sep 2026 10:39:29 -0400 Subject: [PATCH 09/11] test: supply required audit reason on DeleteEntry calls REPOSITORY_ID_1 requires an audit reason for DeleteEntry (ErrorCode 216: "Need to provide correct audit reason for DeleteEntry"), confirmed via the ProblemDetails now printed by startDeleteEntryCanDeleteFolder. Every StartDeleteEntryRequest in the suite was missing one, including BaseTest.deleteEntry(), the shared @AfterAll cleanup helper used by nearly every test class, which was silently failing and leaving orphaned test folders behind. Added findAuditReasonForDelete()/newDeleteEntryRequest() to BaseTest, mirroring the existing findAuditReasonForExport() pattern in ImportUploadedPartsApiTest, and switched all four delete call sites to use it. --- .../repository/api/integration/BaseTest.java | 29 ++++++++++++++++++- .../api/integration/EntriesClientTest.java | 2 +- .../api/integration/TasksClientTest.java | 4 +-- 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/src/test/java/com/laserfiche/repository/api/integration/BaseTest.java b/src/test/java/com/laserfiche/repository/api/integration/BaseTest.java index 280a568a..e4c3044d 100644 --- a/src/test/java/com/laserfiche/repository/api/integration/BaseTest.java +++ b/src/test/java/com/laserfiche/repository/api/integration/BaseTest.java @@ -8,6 +8,7 @@ import com.laserfiche.repository.api.RepositoryApiClientImpl; import com.laserfiche.repository.api.clients.impl.model.*; import com.laserfiche.repository.api.clients.params.ParametersForCreateEntry; +import com.laserfiche.repository.api.clients.params.ParametersForListAuditReasons; import com.laserfiche.repository.api.clients.params.ParametersForListTasks; import com.laserfiche.repository.api.clients.params.ParametersForStartDeleteEntry; import io.github.cdimascio.dotenv.Dotenv; @@ -23,6 +24,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.concurrent.TimeUnit; enum AuthorizationType { @@ -55,6 +57,8 @@ public class BaseTest { protected static final String SMALL_JPEG_FILE_PATH = "src/test/java/com/laserfiche/repository/api/integration/testFiles/test.jpg"; protected static int readonlyTestFolderId = -1; + protected static int deleteAuditReasonId = -1; + protected static String deleteAuditReasonComment; @BeforeAll public static void setUp() { @@ -87,6 +91,29 @@ public static void setUp() { testHeaders = new HashMap<>(); testHeaders.put(testHeaderName, "true"); createRepositoryApiClient(); + findAuditReasonForDelete(); + } + + private static void findAuditReasonForDelete() { + AuditReasonCollectionResponse auditReasons = repositoryApiClient + .getAuditReasonsClient() + .listAuditReasons(new ParametersForListAuditReasons().setRepositoryId(repositoryId)); + Optional deleteAuditReason = auditReasons.getValue().stream() + .filter(auditReason -> auditReason.getAuditEventType() == AuditEventType.DELETE_ENTRY) + .findFirst(); + if (deleteAuditReason.isPresent()) { + deleteAuditReasonId = deleteAuditReason.get().getId(); + deleteAuditReasonComment = deleteAuditReason.get().getName(); + } + } + + protected static StartDeleteEntryRequest newDeleteEntryRequest() { + StartDeleteEntryRequest request = new StartDeleteEntryRequest(); + if (deleteAuditReasonId != -1) { + request.setAuditReasonId(deleteAuditReasonId); + request.setAuditReasonComment(deleteAuditReasonComment); + } + return request; } protected static String getEnvironmentVariable(String environmentVariableName) { @@ -175,7 +202,7 @@ public static void deleteEntry(int entryId) { .startDeleteEntry(new ParametersForStartDeleteEntry() .setRepositoryId(repositoryId) .setEntryId(entryId) - .setRequestBody(new StartDeleteEntryRequest())); + .setRequestBody(newDeleteEntryRequest())); waitUntilTaskEnds(startTaskResponse.getTaskId()); } } diff --git a/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java b/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java index b403e5f3..fb45fe40 100644 --- a/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java +++ b/src/test/java/com/laserfiche/repository/api/integration/EntriesClientTest.java @@ -420,7 +420,7 @@ void startDeleteEntryCanDeleteFolder() { StartTaskResponse deleteEntryResponse = client.startDeleteEntry(new ParametersForStartDeleteEntry() .setRepositoryId(repositoryId) .setEntryId(entryToDelete.getId()) - .setRequestBody(new StartDeleteEntryRequest())); + .setRequestBody(newDeleteEntryRequest())); String taskId = deleteEntryResponse.getTaskId(); assertNotNull(taskId); diff --git a/src/test/java/com/laserfiche/repository/api/integration/TasksClientTest.java b/src/test/java/com/laserfiche/repository/api/integration/TasksClientTest.java index 597bfad0..24f047e7 100644 --- a/src/test/java/com/laserfiche/repository/api/integration/TasksClientTest.java +++ b/src/test/java/com/laserfiche/repository/api/integration/TasksClientTest.java @@ -30,7 +30,7 @@ void cancelTasksDoesNotReturnErrorWhenCancellingACompletedTask() { .startDeleteEntry(new ParametersForStartDeleteEntry() .setRepositoryId(repositoryId) .setEntryId(deleteEntry.getId()) - .setRequestBody(new StartDeleteEntryRequest())); + .setRequestBody(newDeleteEntryRequest())); String taskId = result.getTaskId(); assertNotNull(taskId); @@ -58,7 +58,7 @@ void listTasksWorksAndAcceptsMultipleTaskIdsAndCanBeCalledWithNoTaskIdsAndIgnore .startDeleteEntry(new ParametersForStartDeleteEntry() .setRepositoryId(repositoryId) .setEntryId(entry.getId()) - .setRequestBody(new StartDeleteEntryRequest())); + .setRequestBody(newDeleteEntryRequest())); assertNotNull(startTaskResponse); taskIds[i] = startTaskResponse.getTaskId(); } From 8d07892f3ed82d9d3c637abcbdf21b69885dfcd6 Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Wed, 2 Sep 2026 10:46:07 -0400 Subject: [PATCH 10/11] dummy commit to trigger build From d30e9a96d2203dcaa714f15496b414033628270b Mon Sep 17 00:00:00 2001 From: "alexandria.gomez" Date: Wed, 2 Sep 2026 12:50:52 -0400 Subject: [PATCH 11/11] chore: remove AI-Generated marker comment from pom.xml --- pom.xml | 1 - 1 file changed, 1 deletion(-) diff --git a/pom.xml b/pom.xml index 81c1a76b..d9b472b8 100644 --- a/pom.xml +++ b/pom.xml @@ -309,7 +309,6 @@ ${java.version} 1.8.0 2.0.0 - 2.21.6 2.21 2.9.0