From 45bfed9ab41a25b937215883a56e2b211ace144c Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Wed, 11 Feb 2026 11:13:33 +0100 Subject: [PATCH 1/2] Improve veraPDF Java version error message --- src/tools/impl/verapdf.ts | 11 +++++++++-- src/tools/tools.ts | 5 ++++- src/tools/types.ts | 2 +- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/tools/impl/verapdf.ts b/src/tools/impl/verapdf.ts index cdf64233839..b885f586f80 100644 --- a/src/tools/impl/verapdf.ts +++ b/src/tools/impl/verapdf.ts @@ -40,8 +40,15 @@ export const verapdfInstallable: InstallableTool = { kSupportedJavaVersions.includes(javaVersion); }, os: ["darwin", "linux", "windows"], - message: - `Java is not installed or version is not supported. veraPDF requires Java 8, 11, 17, or 21.`, + message: async () => { + const javaVersion = await getJavaVersion(); + const supportedVersions = kSupportedJavaVersions.join(", "); + if (javaVersion === undefined) { + return `Java is not installed. veraPDF requires Java ${supportedVersions}.`; + } else { + return `Java ${javaVersion} is installed but not supported. veraPDF requires Java ${supportedVersions}.`; + } + }, }], installed, installDir, diff --git a/src/tools/tools.ts b/src/tools/tools.ts index b8c59d6abed..b15f482ead8 100644 --- a/src/tools/tools.ts +++ b/src/tools/tools.ts @@ -136,7 +136,10 @@ export async function installTool(name: string, updatePath?: boolean) { for (const prereq of platformPrereqs) { const met = await prereq.check(context); if (!met) { - context.error(prereq.message); + const message = typeof prereq.message === "function" + ? await prereq.message(context) + : prereq.message; + context.error(message); Deno.exit(1); } } diff --git a/src/tools/types.ts b/src/tools/types.ts index f6e23c2d384..6a1d9fcddaf 100644 --- a/src/tools/types.ts +++ b/src/tools/types.ts @@ -30,7 +30,7 @@ export interface InstallableTool { export interface InstallPreReq { check: (context: InstallContext) => Promise; os: string[]; - message: string; + message: string | ((context: InstallContext) => Promise); } // Locally accessible Package information From b0f6d2ea0edf13330cbe1bcb092dbaf0f6611e09 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Wed, 11 Feb 2026 11:27:00 +0100 Subject: [PATCH 2/2] Cache Java version to avoid redundant subprocess call The check and message functions were both calling getJavaVersion(), spawning the subprocess twice. This created inefficiency and a TOCTOU risk where the Java environment could change between calls. Now check caches the detected version in context.props.javaVersion, and message reads from the cache. The message function is now synchronous since it only reads from context. The InstallPreReq.message type was updated to allow both sync and async functions for flexibility. Co-Authored-By: Claude Opus 4.6 --- src/tools/impl/verapdf.ts | 7 ++++--- src/tools/types.ts | 2 +- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/tools/impl/verapdf.ts b/src/tools/impl/verapdf.ts index b885f586f80..d45f1b95e84 100644 --- a/src/tools/impl/verapdf.ts +++ b/src/tools/impl/verapdf.ts @@ -34,14 +34,15 @@ const kVersionFileName = "version"; export const verapdfInstallable: InstallableTool = { name: "VeraPDF", prereqs: [{ - check: async () => { + check: async (context) => { const javaVersion = await getJavaVersion(); + context.props.javaVersion = javaVersion; return javaVersion !== undefined && kSupportedJavaVersions.includes(javaVersion); }, os: ["darwin", "linux", "windows"], - message: async () => { - const javaVersion = await getJavaVersion(); + message: (context) => { + const javaVersion = context.props.javaVersion as number | undefined; const supportedVersions = kSupportedJavaVersions.join(", "); if (javaVersion === undefined) { return `Java is not installed. veraPDF requires Java ${supportedVersions}.`; diff --git a/src/tools/types.ts b/src/tools/types.ts index 6a1d9fcddaf..265d47465d3 100644 --- a/src/tools/types.ts +++ b/src/tools/types.ts @@ -30,7 +30,7 @@ export interface InstallableTool { export interface InstallPreReq { check: (context: InstallContext) => Promise; os: string[]; - message: string | ((context: InstallContext) => Promise); + message: string | ((context: InstallContext) => string | Promise); } // Locally accessible Package information