Skip to main content

Jentic OpenAPI Spectral Validator Backend

Project description

jentic-openapi-validator-spectral

A Spectral validator backend for the Jentic OpenAPI Tools ecosystem. This package provides OpenAPI document validation using Stoplight's Spectral CLI with comprehensive error reporting and flexible configuration options.

Features

  • Multiple input formats: Validate OpenAPI documents from file URIs or Python dictionaries
  • Custom rulesets: Use built-in rules or provide your own Spectral ruleset
  • Configurable timeouts: Control execution time limits for different use cases
  • Rich diagnostics: Detailed validation results with line/column information
  • Type-safe API: Full typing support with Literal types and comprehensive docstrings

Installation

pip install jentic-openapi-validator-spectral

Prerequisites:

  • Node.js and npm (for Spectral CLI)
  • Python 3.11+

The Spectral CLI will be automatically downloaded via npx on first use, or you can install it globally:

npm install -g @stoplight/spectral-cli

Quick Start

Basic Usage

from jentic.apitools.openapi.validator.backends.spectral import SpectralValidatorBackend

# Create validator with defaults
validator = SpectralValidatorBackend()

# Validate from file URI
result = validator.validate("file:///path/to/openapi.yaml")
print(f"Valid: {result.valid}")

# Check for validation issues
if not result.valid:
    for diagnostic in result.diagnostics:
        print(f"Error: {diagnostic.message}")

Validate Dictionary Documents

# Validate from dictionary
openapi_doc = {
    "openapi": "3.0.0",
    "info": {"title": "My API", "version": "1.0.0"},
    "paths": {}
}

result = validator.validate(openapi_doc)
print(f"Document is valid: {result.valid}")

Configuration Options

Custom Spectral CLI Path

# Use local Spectral installation
validator = SpectralValidatorBackend(spectral_path="/usr/local/bin/spectral")

# Use specific version via npx
validator = SpectralValidatorBackend(spectral_path="npx --yes @stoplight/spectral-cli@6.15.0")

Custom Rulesets

# Use custom ruleset file
validator = SpectralValidatorBackend(ruleset_path="/path/to/custom-rules.yaml")

# The validator automatically falls back to bundled rulesets if no custom path is provided

Timeout Configuration

# Short timeout for CI/CD (10 seconds)
validator = SpectralValidatorBackend(timeout=10.0)

# Extended timeout for large documents (2 minutes)
validator = SpectralValidatorBackend(timeout=120.0)

# Combined configuration (45 seconds)
validator = SpectralValidatorBackend(
    spectral_path="/usr/local/bin/spectral",
    ruleset_path="/path/to/strict-rules.yaml",
    timeout=45.0
)

Path Security

Use allowed_base_dir to restrict file access when processing untrusted input or running as a web service:

from jentic.apitools.openapi.common.path_security import (
    PathTraversalError,
    InvalidExtensionError,
)

# Restrict file access to /var/app/documents directory
validator = SpectralValidatorBackend(
    allowed_base_dir="/var/app/documents"
)

# Valid paths within allowed directory work normally
result = validator.validate("/var/app/documents/specs/openapi.yaml")

# Path traversal attempts are blocked
try:
    result = validator.validate("/var/app/documents/../../etc/passwd")
except PathTraversalError as e:
    print(f"Security violation: {e}")

# Invalid file extensions are rejected
try:
    result = validator.validate("/var/app/documents/malicious.exe")
except InvalidExtensionError as e:
    print(f"Invalid file type: {e}")

# HTTP(S) URLs bypass path validation (as expected)
result = validator.validate("https://example.com/openapi.yaml")

# Combined security configuration for web services
validator = SpectralValidatorBackend(
    allowed_base_dir="/var/app/uploads",
    ruleset_path="/var/app/config/custom-rules.yaml",  # Also validated
    timeout=600.0
)

Security Benefits:

  • Prevents path traversal attacks (../../etc/passwd)
  • Restricts access to allowed directories only (when allowed_base_dir is set)
  • Validates file extensions (.yaml, .yml, .json) - always enforced, even when allowed_base_dir=None
  • Checks symlinks don't escape boundaries (when allowed_base_dir is set)
  • Validates both document and ruleset paths

Note: File extension validation (.yaml, .yml, .json) is always performed for filesystem paths, regardless of whether allowed_base_dir is set. When allowed_base_dir=None, only the base directory containment check is skipped.

Advanced Usage

Error Handling

from jentic.apitools.openapi.common.subproc import SubprocessExecutionError

try:
    result = validator.validate("file:///path/to/openapi.yaml")

    if result.valid:
        print("✅ Document is valid")
    else:
        print("❌ Validation failed:")
        for diagnostic in result.diagnostics:
            severity = diagnostic.severity.name
            line = diagnostic.range.start.line + 1
            print(f"  {severity}: {diagnostic.message} (line {line})")

except FileNotFoundError as e:
    print(f"Ruleset file not found: {e}")
except SubprocessExecutionError as e:
    print(f"Spectral execution failed: {e}")
except TypeError as e:
    print(f"Invalid document type: {e}")

Supported Document Formats

# Check what formats the validator supports
formats = validator.accepts()
print(formats)  # ['uri', 'dict']

# Validate different input types
if "uri" in validator.accepts():
    result = validator.validate("file:///path/to/spec.yaml")

if "dict" in validator.accepts():
    result = validator.validate({"openapi": "3.0.0", ...})

Custom Rulesets

Create a custom Spectral ruleset file:

# custom-rules.yaml
extends: [ "spectral:oas" ]

rules:
  info-contact: error
  info-description: error
  operation-description: error
  operation-summary: warn
  path-params: error

  # Custom rule
  no-empty-paths:
    description: "Paths object should not be empty"
    given: "$.paths"
    then:
      function: truthy
    severity: error

Use it with the validator:

validator = SpectralValidatorBackend(ruleset_path="./custom-rules.yaml")
result = validator.validate("file:///path/to/openapi.yaml")

Testing

Integration Tests

The integration tests require Spectral CLI to be available. They will be automatically skipped if Spectral is not installed.

Run the integration test:

uv run --package jentic-openapi-validator-spectral pytest packages/jentic-openapi-validator-spectral -v

API Reference

SpectralValidator

class SpectralValidatorBackend(BaseValidatorBackend):
    def __init__(
            self,
            spectral_path: str = "npx --yes @stoplight/spectral-cli@6.15.0",
            ruleset_path: str | None = None,
            timeout: float = 600.0,
            allowed_base_dir: str | Path | None = None,
    ) -> None

Parameters:

  • spectral_path: Path to Spectral CLI executable
  • ruleset_path: Path to a custom ruleset file (optional)
  • timeout: Maximum execution time in seconds
  • allowed_base_dir: Optional base directory for path security validation. When set, all document and ruleset paths are validated to be within this directory, providing defense against path traversal attacks. When None (default), only file extension validation is performed (no base directory containment check). Recommended for web services or untrusted input (optional)

Methods:

  • accepts() -> list[Literal["uri", "dict"]]: Returns supported document format identifiers
  • validate(document: str | dict) -> ValidationResult: Validates an OpenAPI document

Exceptions:

  • FileNotFoundError: Custom ruleset file doesn't exist
  • RuntimeError: Spectral execution fails
  • SubprocessExecutionError: Spectral times out or fails to start
  • TypeError: Unsupported document type
  • PathTraversalError: Document or ruleset path attempts to escape allowed_base_dir (only when allowed_base_dir is set)
  • InvalidExtensionError: Document or ruleset path has disallowed file extension (always checked for filesystem paths)

Project details


Release history Release notifications | RSS feed

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

jentic_openapi_validator_spectral-1.0.0a36.tar.gz (12.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file jentic_openapi_validator_spectral-1.0.0a36.tar.gz.

File metadata

File hashes

Hashes for jentic_openapi_validator_spectral-1.0.0a36.tar.gz
Algorithm Hash digest
SHA256 975e26e18187c447916d4d90ce38b894d699b226f859acd00b8ccbd2c06bb4fe
MD5 109b503c8fcb16fed8449d0d560f4958
BLAKE2b-256 03b197ffb31578815bdd1c5317007536b62baf91eb2c3fd1f9362404431e4072

See more details on using hashes here.

Provenance

The following attestation bundles were made for jentic_openapi_validator_spectral-1.0.0a36.tar.gz:

Publisher: release.yml on jentic/jentic-openapi-tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file jentic_openapi_validator_spectral-1.0.0a36-py3-none-any.whl.

File metadata

File hashes

Hashes for jentic_openapi_validator_spectral-1.0.0a36-py3-none-any.whl
Algorithm Hash digest
SHA256 0a4c588d31283147f9fbefed72e85790817a4bb0b8fbbcbebe184dac8ffac0b4
MD5 713e1c6af9c6642ae2a3bba54cd5092b
BLAKE2b-256 bde67116f3ac12ee6a93c72a6b6f699fa1027ee15a4c9f4db3dd57348dfb8540

See more details on using hashes here.

Provenance

The following attestation bundles were made for jentic_openapi_validator_spectral-1.0.0a36-py3-none-any.whl:

Publisher: release.yml on jentic/jentic-openapi-tools

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page