2626logger = logging .getLogger (__name__ )
2727
2828_TARBALL_NAME = "jentic-openapi-validator-speclynx-0.1.0.tgz"
29- _DEFAULT_SPECLYNX_PATH = f"npx --yes { _TARBALL_NAME } "
3029
3130resources_dir = files ("jentic.apitools.openapi.validator.backends.speclynx.resources" )
3231tarball_file = resources_dir .joinpath (_TARBALL_NAME )
3534class SpeclynxValidatorBackend (BaseValidatorBackend ):
3635 def __init__ (
3736 self ,
38- speclynx_path : str = _DEFAULT_SPECLYNX_PATH ,
37+ speclynx_path : str | None = None ,
3938 timeout : float = 600.0 ,
4039 allowed_base_dir : str | Path | None = None ,
4140 plugins_dir : str | Path | None = None ,
@@ -44,9 +43,9 @@ def __init__(
4443 Initialize the SpeclynxValidatorBackend.
4544
4645 Args:
47- speclynx_path: Path to the speclynx CLI executable (default: uses bundled npm tarball via npx).
48- Can be a custom path like "/usr/local/bin/speclynx" or an npx command.
49- Uses shell-safe parsing to handle quoted arguments properly.
46+ speclynx_path: Path to the speclynx CLI executable. If None (default), uses the
47+ bundled npm tarball via npx. Can be a custom path like "/usr/local/bin/speclynx"
48+ or an npx command. Uses shell-safe parsing to handle quoted arguments properly.
5049 timeout: Maximum time in seconds to wait for validation execution (default: 600.0)
5150 allowed_base_dir: Optional base directory for path security validation.
5251 When set, all document paths will be validated to ensure they
@@ -147,25 +146,26 @@ def _validate_uri(
147146 output_path = tmp_output .name
148147
149148 try :
150- cmd = [
151- * shlex .split (self .speclynx_path ),
149+ args = [
152150 validated_doc_path ,
153151 "-o" ,
154152 output_path ,
155153 ]
156154 if base_url :
157- cmd .extend (["--base-uri" , base_url ])
155+ args .extend (["--base-uri" , base_url ])
158156 if self .plugins_dir :
159- cmd .extend (["--plugins" , str (self .plugins_dir )])
157+ args .extend (["--plugins" , str (self .plugins_dir )])
160158 if self .allowed_base_dir :
161- cmd .extend (["--allowed-base-dir" , str (self .allowed_base_dir )])
159+ args .extend (["--allowed-base-dir" , str (self .allowed_base_dir )])
162160
163- # npx with bundled tarball requires cwd set to resources directory
164- if self .speclynx_path == _DEFAULT_SPECLYNX_PATH :
161+ # npx with bundled tarball: pass absolute path so npm doesn't
162+ # resolve the bare filename relative to its global prefix.
163+ if self .speclynx_path is None :
165164 with as_file (tarball_file ) as tarball_path :
166- resources_path = tarball_path .parent
167- result = run_subprocess (cmd , timeout = self .timeout , cwd = str ( resources_path ) )
165+ cmd = [ "npx" , "--yes" , f"file: { tarball_path .as_posix () } " , * args ]
166+ result = run_subprocess (cmd , timeout = self .timeout )
168167 else :
168+ cmd = [* shlex .split (self .speclynx_path ), * args ]
169169 result = run_subprocess (cmd , timeout = self .timeout )
170170
171171 if result is None :
0 commit comments