mirror of
https://github.com/norandom/OpenUltraSAST.git
synced 2026-10-16 03:49:26 +00:00
Add openultrasast.plane.manifests: frozen dataclasses and loaders for ax's Task, Workspace and Model kinds (ax.io/v1alpha1, ax's fields only) and the Run kind (openultrasast.io/v1alpha1: tasks, dependsOn, inputs, outputs, budget, serialize). Every violation raises ManifestError naming the kind, metadata.name and field path: unknown fields at any depth, wrong apiVersion or kind, a provider outside google/anthropic unless deepseek is declared via the openultrasast.io/provider-extension annotation, a Run with a dependency cycle, an input naming no task, and a Run task naming no loaded Task. load_manifests reads multi-document YAML files and indexes by kind and name. PyYAML becomes the one declared core dependency; the two zero-dependency guards now pin exactly that, and the module audit registers the plane package under the ai-service-plane spec. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01EmM1j46qgKMh3zqD1QMwEo
74 lines
2.9 KiB
Python
74 lines
2.9 KiB
Python
"""HarnessX optional-extra packaging + capability guard (Phase 3 task 5.2)."""
|
|
|
|
import re
|
|
import tomllib
|
|
from pathlib import Path
|
|
|
|
import pytest
|
|
|
|
from openultrasast.harness_ext import (
|
|
HARNESSX_EXTRA,
|
|
SUPPORTED_PROVIDERS,
|
|
HarnessXUnavailableError,
|
|
build_provider,
|
|
has_harnessx,
|
|
require_harnessx,
|
|
)
|
|
|
|
PYPROJECT = tomllib.loads(Path("pyproject.toml").read_text())
|
|
|
|
|
|
def test_core_dependencies_are_pyyaml_only() -> None:
|
|
assert PYPROJECT["project"]["dependencies"] == ["pyyaml>=6.0"] # ai-service-plane task 1: manifests are YAML; HarnessX stays an extra
|
|
|
|
|
|
def test_harnessx_is_a_sha_pinned_optional_extra() -> None:
|
|
extras = PYPROJECT["project"]["optional-dependencies"]["harnessx"]
|
|
assert len(extras) == 1
|
|
assert re.fullmatch(
|
|
r"harnessx @ git\+https://github\.com/Darwin-Agent/HarnessX\.git@[0-9a-f]{40}",
|
|
extras[0],
|
|
), extras[0]
|
|
|
|
|
|
def test_importing_openultrasast_does_not_import_harnessx(assert_cold_of_harnessx) -> None: # type: ignore[no-untyped-def]
|
|
# The big modules (cli, harness_ext) must not eagerly import the heavy extra.
|
|
assert_cold_of_harnessx("import openultrasast.cli\nimport openultrasast.harness_ext")
|
|
|
|
|
|
def test_has_harnessx_probes_without_importing(assert_cold_of_harnessx) -> None: # type: ignore[no-untyped-def]
|
|
assert isinstance(has_harnessx(), bool)
|
|
# find_spec must not import the module.
|
|
assert_cold_of_harnessx("from openultrasast.harness_ext import has_harnessx\nassert isinstance(has_harnessx(), bool)")
|
|
|
|
|
|
def test_require_harnessx_raises_with_install_guidance_when_absent() -> None:
|
|
if has_harnessx():
|
|
pytest.skip("HarnessX extra is installed in this environment")
|
|
with pytest.raises(HarnessXUnavailableError, match=re.escape(HARNESSX_EXTRA)):
|
|
require_harnessx()
|
|
|
|
|
|
def test_build_provider_rejects_unknown_provider_before_importing(assert_cold_of_harnessx) -> None: # type: ignore[no-untyped-def]
|
|
# Name is validated before any import, so this fails loudly even without the extra.
|
|
with pytest.raises(ValueError, match="unknown HarnessX provider"):
|
|
build_provider("gpt-4o", "bogus")
|
|
assert_cold_of_harnessx(
|
|
"from openultrasast.harness_ext import build_provider\n"
|
|
"try:\n build_provider('gpt-4o', 'bogus')\n"
|
|
"except ValueError:\n pass\n"
|
|
"else:\n raise SystemExit('expected ValueError')\n"
|
|
)
|
|
|
|
|
|
def test_supported_providers_cover_anthropic_and_openai() -> None:
|
|
assert {"anthropic", "openai"} <= set(SUPPORTED_PROVIDERS)
|
|
|
|
|
|
@pytest.mark.parametrize(("provider", "class_name"), [("anthropic", "AnthropicProvider"), ("openai", "OpenAIProvider")])
|
|
def test_build_provider_constructs_selected_provider(provider: str, class_name: str) -> None:
|
|
if not has_harnessx():
|
|
pytest.skip("HarnessX extra not installed in this environment")
|
|
built = build_provider("test-model", provider)
|
|
assert type(built).__name__ == class_name
|