build(deps): bump org.verapdf:validation-model from 1.28.2 to 1.30.2 in /app/core (#6836)

Bumps
[org.verapdf:validation-model](https://github.com/veraPDF/veraPDF-validation)
from 1.28.2 to 1.30.2.
<details>
<summary>Commits</summary>
<ul>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/94caa46c1a594512247fbd46c808edae39469542"><code>94caa46</code></a>
Improve security of the DocumentBuilder</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/ae243fc06775ef79495accd2165e5262e31dcf67"><code>ae243fc</code></a>
Fix typo</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/f89130de3b97f19ef4030e5fc84345c4463cd867"><code>f89130d</code></a>
Fix getAlt in GFPDAnnot</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/11ad0c577853a658d11370277196c12e34b5fd81"><code>11ad0c5</code></a>
Proposed SECURITY.md file for veraPDF projects</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/59f9cd4c97799dd87d738ce847c066530bcf2ed1"><code>59f9cd4</code></a>
Use non static isCircularMappingExist</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/7494455aa44fd322fa7bd900456a3cb8f0602f18"><code>7494455</code></a>
REL - v1.30</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/ecd191d3d796dfdfa13970a114920530627a25bb"><code>ecd191d</code></a>
Fix glyph name detection for symbolic TrueType font</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/32e21ce19a478a4e8e47c4a090674cbb2cb58026"><code>32e21ce</code></a>
Update fixRevProperty method (<a
href="https://redirect.github.com/veraPDF/veraPDF-validation/issues/726">#726</a>)</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/ddfee10116d45cc37750a988ff4385dad0c8510a"><code>ddfee10</code></a>
PDF/UA. Fix Table validation</li>
<li><a
href="https://github.com/veraPDF/veraPDF-validation/commit/22ea95799bb98b50a2063c542de50de4aeb4ce9e"><code>22ea957</code></a>
RC - v1.30</li>
<li>Additional commits viewable in <a
href="https://github.com/veraPDF/veraPDF-validation/compare/v1.28.2...v1.30.2">compare
view</a></li>
</ul>
</details>
<br />


> **Note**
> Automatic rebases have been disabled on this pull request as it has
been open for over 30 days.

---------

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Anthony Stirling <77850077+Frooodle@users.noreply.github.com>
This commit is contained in:
dependabot[bot]
2026-08-01 23:39:20 +01:00
committed by GitHub
co-authored by Anthony Stirling
parent 53086a12c2
commit e4c9b0410c
6 changed files with 214 additions and 5 deletions
+1 -1
View File
@@ -50,7 +50,7 @@ dependencies {
implementation "org.apache.pdfbox:preflight:$pdfboxVersion"
implementation "org.apache.pdfbox:xmpbox:$pdfboxVersion"
implementation 'org.verapdf:validation-model:1.28.2'
implementation 'org.verapdf:validation-model:1.30.2'
// CVE-2025-66453: Explicit rhino 1.7.15 to override verapdf's 1.7.13
implementation "org.mozilla:rhino:${rhinoVersion}"
@@ -200,8 +200,8 @@ public class VeraPDFService {
try (PDFAParser detectionParser =
Foundries.defaultInstance().createParser(new ByteArrayInputStream(pdfBytes))) {
declaredFlavour = detectionParser.getFlavour();
detectedFlavours = detectionParser.getFlavours();
detectedFlavours = detectedFlavours(detectionParser);
declaredFlavour = firstFlavour(detectedFlavours);
}
// For PDF/A flavours, we need to validate first to check if PDF/A identification exists in
@@ -299,7 +299,7 @@ public class VeraPDFService {
Foundries.defaultInstance()
.createParser(new ByteArrayInputStream(pdfBytes), flavour)) {
PDFAFlavour parserDeclared = parser.getFlavour();
PDFAFlavour parserDeclared = firstFlavour(detectedFlavours(parser));
PDFAValidator validator =
Foundries.defaultInstance().createValidator(flavour, false);
ValidationResult result = validator.validate(parser);
@@ -322,7 +322,19 @@ public class VeraPDFService {
}
private static boolean isPdfaFlavour(PDFAFlavour flavour) {
return PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A);
return flavour != null
&& PDFFlavours.isFlavourFamily(flavour, PDFAFlavour.SpecificationFamily.PDF_A);
}
// veraPDF 1.30+ returns an empty flavour list for non-PDF/A files, where getFlavour() throws
private static List<PDFAFlavour> detectedFlavours(PDFAParser parser) {
List<PDFAFlavour> flavours = parser.getFlavours();
return flavours != null ? flavours : List.of();
}
// null means "no PDF/A flavour detected" rather than an error
private static PDFAFlavour firstFlavour(List<PDFAFlavour> flavours) {
return flavours.isEmpty() ? null : flavours.get(0);
}
private static String formatStandardDisplay(
@@ -0,0 +1,197 @@
package stirling.software.SPDF.service;
import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.List;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.verapdf.gf.foundry.VeraGreenfieldFoundryProvider;
import org.verapdf.pdfa.Foundries;
import org.verapdf.pdfa.PDFAParser;
import org.verapdf.pdfa.PDFAValidator;
import org.verapdf.pdfa.flavours.PDFAFlavour;
import org.verapdf.pdfa.results.ValidationResult;
import stirling.software.SPDF.model.api.security.PDFVerificationResult;
/**
* Exercises {@link VeraPDFService} against real PDF/A files. Fixtures were produced by Ghostscript
* with the same flags as ConvertPDFToPDFA and independently confirmed conformant by veraPDF.
*/
class VeraPDFServicePdfaFixtureTest {
private static final String VALID_1B = "valid-pdfa-1b.pdf";
private static final String VALID_2B = "valid-pdfa-2b.pdf";
private static final String DECLARED_BUT_INVALID_1B = "declared-pdfa-1b-no-outputintent.pdf";
private VeraPDFService service;
@BeforeEach
void setUp() {
service = new VeraPDFService();
service.initialize();
}
@Test
void fixtures_areGenuinePdfaAccordingToVeraPdfItself() throws Exception {
assertVeraPdfVerdict(VALID_1B, PDFAFlavour.PDFA_1_B, true);
assertVeraPdfVerdict(VALID_2B, PDFAFlavour.PDFA_2_B, true);
assertVeraPdfVerdict(DECLARED_BUT_INVALID_1B, PDFAFlavour.PDFA_1_B, false);
}
@Test
void validatePDF_realPdfa1b_reportsCompliantPdfa1b() throws Exception {
PDFVerificationResult result = onlyResult(fixture(VALID_1B));
assertEquals("1b", result.getStandard());
assertEquals("1b", result.getValidationProfile());
assertTrue(result.isDeclaredPdfa(), "Genuine PDF/A-1b must be reported as declared PDF/A");
assertTrue(result.isCompliant(), "Genuine PDF/A-1b must validate as compliant");
assertEquals(
0, result.getTotalFailures(), () -> "Unexpected failures: " + messages(result));
assertTrue(
result.getStandardName().startsWith("PDF/A-"),
"Display name should name the PDF/A standard, got: " + result.getStandardName());
assertTrue(
result.getStandardName().endsWith(" compliant"),
"Display name should read as compliant, got: " + result.getStandardName());
assertEquals(result.getStandardName(), result.getComplianceSummary());
}
@Test
void validatePDF_realPdfa2b_reportsPdfa2bAndNotPdfa1b() throws Exception {
PDFVerificationResult result = onlyResult(fixture(VALID_2B));
// Proves firstFlavour() returns the flavour actually declared, not just a non-null one
assertEquals("2b", result.getStandard());
assertEquals("2b", result.getValidationProfile());
assertNotEquals("1b", result.getStandard());
assertTrue(result.isDeclaredPdfa());
assertTrue(result.isCompliant(), () -> "Unexpected failures: " + messages(result));
assertEquals(0, result.getTotalFailures());
}
@Test
void validatePDF_plainPdf_reportsNotPdfaAndDoesNotThrowIndexOutOfBounds() throws Exception {
byte[] pdfBytes = createSimplePdf();
// veraPDF 1.30 returns an empty flavour list here where 1.28 returned [1b]; get(0) threw
List<PDFVerificationResult> results =
assertDoesNotThrow(
() -> service.validatePDF(new ByteArrayInputStream(pdfBytes)),
"Empty veraPDF flavour list must not surface as IndexOutOfBoundsException");
assertEquals(1, results.size());
PDFVerificationResult result = results.get(0);
assertEquals("not-pdfa", result.getStandard());
assertFalse(result.isDeclaredPdfa());
assertFalse(result.isCompliant());
assertEquals("Not PDF/A (no PDF/A identification metadata)", result.getStandardName());
}
@Test
void validatePDF_declaresPdfaButNotConformant_reportsFlavourWithFailures() throws Exception {
PDFVerificationResult result = onlyResult(fixture(DECLARED_BUT_INVALID_1B));
// "declares PDF/A but broken" must stay distinct from "not PDF/A at all"
assertEquals("1b", result.getStandard());
assertNotEquals("not-pdfa", result.getStandard());
assertTrue(result.isDeclaredPdfa(), "XMP still declares pdfaid:part=1");
assertFalse(result.isCompliant(), "Stripped OutputIntent must fail conformance");
assertTrue(result.getTotalFailures() > 0, "Non-conformance must be reported as issues");
assertTrue(
result.getStandardName().endsWith(" with errors"),
"Display name should flag errors, got: " + result.getStandardName());
assertTrue(
messages(result).contains("OutputIntent"),
"Expected the missing OutputIntent to be reported, got: " + messages(result));
}
@Test
void firstFlavour_withEmptyList_returnsNullInsteadOfThrowing() throws Exception {
Method method = VeraPDFService.class.getDeclaredMethod("firstFlavour", List.class);
method.setAccessible(true);
assertNull(method.invoke(null, List.of()));
assertEquals(PDFAFlavour.PDFA_2_B, method.invoke(null, List.of(PDFAFlavour.PDFA_2_B)));
}
@Test
void detectedFlavours_withNullFlavourList_returnsEmptyList() throws Exception {
Method method =
VeraPDFService.class.getDeclaredMethod("detectedFlavours", PDFAParser.class);
method.setAccessible(true);
PDFAParser parser = mock(PDFAParser.class);
when(parser.getFlavours()).thenReturn(null);
assertEquals(List.of(), method.invoke(null, parser));
}
private static void assertVeraPdfVerdict(
String fixtureName, PDFAFlavour expectedFlavour, boolean expectedCompliant)
throws Exception {
VeraGreenfieldFoundryProvider.initialise();
byte[] bytes = fixture(fixtureName);
List<PDFAFlavour> flavours;
try (PDFAParser parser =
Foundries.defaultInstance().createParser(new ByteArrayInputStream(bytes))) {
flavours = parser.getFlavours();
}
assertEquals(List.of(expectedFlavour), flavours, fixtureName + " declared flavours");
try (PDFAParser parser =
Foundries.defaultInstance()
.createParser(new ByteArrayInputStream(bytes), expectedFlavour)) {
PDFAValidator validator =
Foundries.defaultInstance().createValidator(expectedFlavour, false);
ValidationResult result = validator.validate(parser);
assertEquals(
expectedCompliant, result.isCompliant(), fixtureName + " veraPDF compliance");
}
}
private PDFVerificationResult onlyResult(byte[] pdfBytes) throws Exception {
List<PDFVerificationResult> results =
service.validatePDF(new ByteArrayInputStream(pdfBytes));
assertNotNull(results);
assertEquals(1, results.size(), () -> "Expected a single result, got: " + results);
return results.get(0);
}
private static String messages(PDFVerificationResult result) {
StringBuilder builder = new StringBuilder();
for (PDFVerificationResult.ValidationIssue issue : result.getFailures()) {
builder.append(issue.getMessage()).append(" | ");
}
return builder.toString();
}
private static byte[] fixture(String name) throws IOException {
try (InputStream in =
VeraPDFServicePdfaFixtureTest.class.getResourceAsStream("/pdfa/" + name)) {
assertNotNull(in, "Missing test fixture /pdfa/" + name);
return in.readAllBytes();
}
}
private static byte[] createSimplePdf() throws IOException {
try (PDDocument document = new PDDocument()) {
document.addPage(new PDPage());
ByteArrayOutputStream baos = new ByteArrayOutputStream();
document.save(baos);
return baos.toByteArray();
}
}
}
Binary file not shown.
Binary file not shown.