technical-debt-engine-runtime 1.0.0rc3__tar.gz → 1.0.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/PKG-INFO +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/pyproject.toml +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_cli/main.py +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/dependency_health.py +64 -18
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/execution.py +2 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/policies/generation-1.json +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/runtime.py +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/PKG-INFO +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_cli.py +2 -2
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_coverage.py +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_dependency_health.py +31 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_public_policy_configuration.py +2 -2
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_release_bundle.py +2 -2
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_release_publication.py +7 -7
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_runtime.py +1 -1
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/README.md +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/setup.cfg +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_cli/__init__.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/__init__.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/analyzer_discovery.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/assessment.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/baseline.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/code_size.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/complexity.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/configuration.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/coverage.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/differential.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/docker_artifact.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/evidence_store.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/maintainability.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/models.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/policies/__init__.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/policy.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/profiles/__init__.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/profiles/minimal.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/profiles/standard.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/query.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/registries.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/release_bundle.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/release_candidate.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/release_certification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/release_publication.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/release_qualification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/repository_qualification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/runtime_qualification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/__init__.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/assessment-decision-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/assessment-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/capability-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/common.schema.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/differential-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/policy-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/schemas/repository-qualification-evidence.json +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/software_assurance.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/trend.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_runtime/trusted_delivery.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/SOURCES.txt +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/dependency_links.txt +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/entry_points.txt +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/requires.txt +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/technical_debt_engine_runtime.egg-info/top_level.txt +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_baseline.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_build_reproducibility.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_capability_platform.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_code_size.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_complexity.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_docker_artifact.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_evidence_store.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_execution.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_policy.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_public_artifacts.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_query.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_release_candidate.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_release_certification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_release_qualification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_runtime_qualification.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_software_assurance.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_trend.py +0 -0
- {technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_trusted_delivery.py +0 -0
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/src/tde_cli/main.py
RENAMED
|
@@ -29,7 +29,7 @@ from tde_runtime.repository_qualification import (QualificationRegistry,
|
|
|
29
29
|
from tde_runtime.differential import AssessmentBaselineRegistry, DifferentialEngine, DifferentialError
|
|
30
30
|
|
|
31
31
|
|
|
32
|
-
CLI_VERSION = "1.0.
|
|
32
|
+
CLI_VERSION = "1.0.2"
|
|
33
33
|
GENERATION = "1"
|
|
34
34
|
|
|
35
35
|
|
|
@@ -11,7 +11,7 @@ import re
|
|
|
11
11
|
import shutil
|
|
12
12
|
import subprocess
|
|
13
13
|
import tomllib
|
|
14
|
-
from typing import Any
|
|
14
|
+
from typing import Any, Mapping
|
|
15
15
|
import xml.etree.ElementTree as ET
|
|
16
16
|
|
|
17
17
|
|
|
@@ -21,13 +21,13 @@ CAPABILITY_ID = "dependency_health"
|
|
|
21
21
|
CAPABILITY_VERSION = "1.0.0"
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
def analyze(root: Path, timeout: int) -> dict[str, Any]:
|
|
24
|
+
def analyze(root: Path, timeout: int, settings: Mapping[str, Any] | None = None) -> dict[str, Any]:
|
|
25
25
|
"""Normalize only package ecosystems actually present in a repository."""
|
|
26
26
|
records = []
|
|
27
27
|
if (root / "package.json").is_file(): records.append(_npm(root, timeout))
|
|
28
28
|
python = _python(root, timeout)
|
|
29
29
|
if python is not None: records.append(python)
|
|
30
|
-
nuget = _nuget(root, timeout)
|
|
30
|
+
nuget = _nuget(root, timeout, settings)
|
|
31
31
|
if nuget is not None: records.append(nuget)
|
|
32
32
|
if (root / "platformio.ini").is_file(): records.append(_platformio(root, timeout))
|
|
33
33
|
if (root / "Package.swift").is_file(): records.append(_swift(root, timeout))
|
|
@@ -88,35 +88,70 @@ def _python(root: Path, timeout: int) -> dict[str, Any] | None:
|
|
|
88
88
|
return _record("PyPI", "pip", sorted(direct), None, None, outdated, {"id": "pip", "version": version}, "".join(raw), limitations)
|
|
89
89
|
|
|
90
90
|
|
|
91
|
-
def _nuget(root: Path, timeout: int) -> dict[str, Any] | None:
|
|
91
|
+
def _nuget(root: Path, timeout: int, settings: Mapping[str, Any] | None = None) -> dict[str, Any] | None:
|
|
92
92
|
projects = _manifest_files(root, "*.csproj")
|
|
93
93
|
if not projects: return None
|
|
94
|
-
direct = []
|
|
95
94
|
for project in projects:
|
|
96
|
-
try:
|
|
95
|
+
try: _project_frameworks(project)
|
|
97
96
|
except (ET.ParseError, OSError) as error: return _blocked("NuGet", "dotnet", str(error))
|
|
97
|
+
direct = _nuget_direct_dependencies(projects)
|
|
98
98
|
dotnet = shutil.which("dotnet")
|
|
99
99
|
if not dotnet: return _record("NuGet", "dotnet", sorted(set(direct)), None, None, None, {"id": "dotnet", "version": "UNAVAILABLE"}, "", [_limitation("dependency_health.dotnet.unavailable", "dotnet was not found on PATH")])
|
|
100
|
+
try: selected_framework = _nuget_framework(settings)
|
|
101
|
+
except ValueError as error: return _configuration_failed("NuGet", "dotnet", str(error))
|
|
102
|
+
if selected_framework and not any(selected_framework in _project_frameworks(project) for project in projects):
|
|
103
|
+
return _configuration_failed("NuGet", "dotnet", f"configured nugetFramework '{selected_framework}' is not declared by any project")
|
|
100
104
|
raw, outdated, transitive, limitations = [], [], [], []
|
|
101
105
|
for project in projects:
|
|
102
106
|
try:
|
|
103
|
-
|
|
104
|
-
raw.append(
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
return _analysis_failed("NuGet", "dotnet", f"{project}: {detail}")
|
|
110
|
-
for project_data in payload.get("projects", []):
|
|
111
|
-
for framework in project_data.get("frameworks", []):
|
|
112
|
-
outdated.extend(item["id"] for item in framework.get("topLevelPackages", []) if item.get("latestVersion"))
|
|
113
|
-
outdated.extend(item["id"] for item in framework.get("transitivePackages", []) if item.get("latestVersion"))
|
|
114
|
-
transitive.extend(item["id"] for item in framework.get("transitivePackages", []) if item.get("id"))
|
|
107
|
+
output, project_outdated, project_transitive = _nuget_project(dotnet, root, project, selected_framework, timeout)
|
|
108
|
+
raw.append(output); outdated.extend(project_outdated); transitive.extend(project_transitive)
|
|
109
|
+
except ValueError as error:
|
|
110
|
+
return _configuration_failed("NuGet", "dotnet", str(error))
|
|
111
|
+
except _NugetAnalysisError as error:
|
|
112
|
+
return _analysis_failed("NuGet", "dotnet", f"{project}: {error}")
|
|
115
113
|
except (OSError, subprocess.SubprocessError, json.JSONDecodeError) as error:
|
|
116
114
|
outdated = None; transitive = None; limitations.append(_limitation("dependency_health.nuget.outdated.unavailable", str(error)))
|
|
117
115
|
return _record("NuGet", "dotnet", sorted(set(direct)), None if transitive is None else sorted(set(transitive) - set(direct)), None, None if outdated is None else sorted(set(outdated)), {"id": "dotnet", "version": _version(dotnet, root, timeout)}, "".join(raw), limitations)
|
|
118
116
|
|
|
119
117
|
|
|
118
|
+
class _NugetAnalysisError(Exception):
|
|
119
|
+
"""Native package-manager output cannot provide canonical evidence."""
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def _nuget_direct_dependencies(projects: list[Path]) -> list[str]:
|
|
123
|
+
return [item.attrib["Include"] for project in projects for item in ET.parse(project).iter()
|
|
124
|
+
if item.tag.endswith("PackageReference") and "Include" in item.attrib]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def _nuget_framework(settings: Mapping[str, Any] | None) -> str | None:
|
|
128
|
+
value = (settings or {}).get("nugetFramework")
|
|
129
|
+
if value is None: return None
|
|
130
|
+
if not isinstance(value, str) or not value.strip():
|
|
131
|
+
raise ValueError("dependency_health.nugetFramework must be a non-empty string")
|
|
132
|
+
return value.strip()
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def _nuget_project(dotnet: str, root: Path, project: Path, framework: str | None, timeout: int) -> tuple[str, list[str], list[str]]:
|
|
136
|
+
framework = framework if framework in _project_frameworks(project) else None
|
|
137
|
+
command = [dotnet, "package", "list", "--project", str(project), "--outdated", "--include-transitive", "--format", "json"]
|
|
138
|
+
if framework: command.extend(["--framework", framework])
|
|
139
|
+
completed = subprocess.run(command, cwd=root, capture_output=True, text=True, timeout=timeout, check=False)
|
|
140
|
+
payload = json.loads(completed.stdout or "{}")
|
|
141
|
+
errors = [item.get("text", "NuGet analysis failed") for item in payload.get("problems", []) if item.get("level") == "error"]
|
|
142
|
+
if completed.returncode != 0 or errors:
|
|
143
|
+
raise _NugetAnalysisError("; ".join(errors) or completed.stderr.strip() or f"dotnet exited with status {completed.returncode}")
|
|
144
|
+
return completed.stdout, *_nuget_packages(payload)
|
|
145
|
+
|
|
146
|
+
|
|
147
|
+
def _nuget_packages(payload: Mapping[str, Any]) -> tuple[list[str], list[str]]:
|
|
148
|
+
frameworks = [framework for project in payload.get("projects", []) for framework in project.get("frameworks", [])]
|
|
149
|
+
outdated = [item["id"] for framework in frameworks for key in ("topLevelPackages", "transitivePackages")
|
|
150
|
+
for item in framework.get(key, []) if item.get("latestVersion")]
|
|
151
|
+
transitive = [item["id"] for framework in frameworks for item in framework.get("transitivePackages", []) if item.get("id")]
|
|
152
|
+
return outdated, transitive
|
|
153
|
+
|
|
154
|
+
|
|
120
155
|
def _platformio(root: Path, timeout: int) -> dict[str, Any]:
|
|
121
156
|
direct = []
|
|
122
157
|
lines = (root / "platformio.ini").read_text(encoding="utf-8").splitlines(); in_deps = False
|
|
@@ -148,6 +183,7 @@ def _record(ecosystem: str, manager: str, direct: list[str], transitive: list[st
|
|
|
148
183
|
|
|
149
184
|
def _blocked(ecosystem: str, manager: str, reason: str) -> dict[str, Any]: return _record(ecosystem, manager, [], None, None, None, {"id": manager, "version": "UNAVAILABLE"}, "", [_limitation("dependency_health.manifest.invalid", reason, True)])
|
|
150
185
|
def _analysis_failed(ecosystem: str, manager: str, reason: str) -> dict[str, Any]: return _record(ecosystem, manager, [], None, None, None, {"id": manager, "version": "UNAVAILABLE"}, "", [_limitation(f"dependency_health.{manager}.analysis.failed", reason, True)])
|
|
186
|
+
def _configuration_failed(ecosystem: str, manager: str, reason: str) -> dict[str, Any]: return _record(ecosystem, manager, [], None, None, None, {"id": manager, "version": "UNAVAILABLE"}, "", [_limitation("dependency_health.nuget.configuration.invalid", reason, True)])
|
|
151
187
|
def _unavailable(reason: str) -> dict[str, Any]: return {"status": "VALID", "ecosystems": [], "rawOutput": "", "rawOutputHash": "sha256:" + sha256(b"").hexdigest(), "limitations": [_limitation("dependency_health.ecosystem.unavailable", reason)] , "available": False}
|
|
152
188
|
def _limitation(identifier: str, description: str, blocking: bool = False) -> dict[str, Any]: return {"id": identifier, "description": description, "cause": "dependency health", "blocking": blocking}
|
|
153
189
|
def _version(executable: str, root: Path, timeout: int) -> str:
|
|
@@ -169,5 +205,15 @@ def _manifest_files(root: Path, pattern: str) -> list[Path]:
|
|
|
169
205
|
return sorted(manifests)
|
|
170
206
|
|
|
171
207
|
|
|
208
|
+
def _project_frameworks(project: Path) -> set[str]:
|
|
209
|
+
"""Return target frameworks declared by a project without evaluating it."""
|
|
210
|
+
document = ET.parse(project)
|
|
211
|
+
values = []
|
|
212
|
+
for element in document.iter():
|
|
213
|
+
if element.tag.endswith(("TargetFramework", "TargetFrameworks")) and element.text:
|
|
214
|
+
values.extend(item.strip() for item in element.text.split(";") if item.strip())
|
|
215
|
+
return set(values)
|
|
216
|
+
|
|
217
|
+
|
|
172
218
|
def _ignored_directory(name: str) -> bool:
|
|
173
219
|
return name in {".git", "node_modules", "dist", "build", ".venv", "venv", ".build", ".swiftpm", ".pio", ".release", ".public-release"} or name.startswith(".xcode-derived")
|
|
@@ -121,7 +121,8 @@ class CapabilityExecutionEngine:
|
|
|
121
121
|
return self._blocked(COVERAGE_CAPABILITY_ID, COVERAGE_CAPABILITY_VERSION, [COVERAGE_ADAPTER_ID], result["limitations"], duration, result["status"])
|
|
122
122
|
return self._coverage_result(context, result, duration)
|
|
123
123
|
if identifier == DEPENDENCY_CAPABILITY_ID and selected_adapter == DEPENDENCY_ADAPTER_ID:
|
|
124
|
-
|
|
124
|
+
settings = context.execution_options.get("capabilities", {}).get(DEPENDENCY_CAPABILITY_ID, {})
|
|
125
|
+
result = analyze_dependencies(context.repository_root, timeout, settings)
|
|
125
126
|
duration = int((perf_counter() - started) * 1000)
|
|
126
127
|
if result["status"] != "VALID":
|
|
127
128
|
return self._blocked(DEPENDENCY_CAPABILITY_ID, DEPENDENCY_CAPABILITY_VERSION, [DEPENDENCY_ADAPTER_ID], result["limitations"], duration)
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Default, language-independent Generation 1 qualification policy.",
|
|
7
7
|
"supportedCapabilities": ["code_size", "complexity", "coverage", "dependency_health"],
|
|
8
8
|
"supportedSchemas": ["1.0.0"],
|
|
9
|
-
"supportedRuntimeVersions": ["0.2.0", "1.0.0rc1", "1.0.0rc2", "1.0.0rc3"],
|
|
9
|
+
"supportedRuntimeVersions": ["0.2.0", "1.0.0rc1", "1.0.0rc2", "1.0.0rc3", "1.0.0", "1.0.1", "1.0.2"],
|
|
10
10
|
"rules": [
|
|
11
11
|
{"id": "code_size.repository_lines", "type": "threshold", "capability": "code_size", "metric": "code_size.code_lines", "operator": "greater_than", "threshold": {"warning": 25000, "blocking": 50000}, "severity": {"warning": "WARNING", "blocking": "BLOCKING"}, "enabled": true, "rationale": "Large repositories require deliberate decomposition without treating established product repositories as a blocking condition."},
|
|
12
12
|
{"id": "complexity.maximum", "type": "threshold", "capability": "complexity", "metric": "complexity.cyclomatic.maximum", "operator": "greater_than", "threshold": {"warning": 15, "blocking": 30}, "severity": {"warning": "WARNING", "blocking": "BLOCKING"}, "enabled": true, "rationale": "High cyclomatic complexity impedes safe change; the blocking threshold accommodates the current measured maximum while retaining a warning signal."},
|
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_cli.py
RENAMED
|
@@ -41,8 +41,8 @@ class CliFoundationTests(unittest.TestCase):
|
|
|
41
41
|
code, output = self.invoke("--format", "json", "--version")
|
|
42
42
|
self.assertEqual(ExitCode.SUCCESS, code)
|
|
43
43
|
version = json.loads(output)
|
|
44
|
-
self.assertEqual("1.0.
|
|
45
|
-
self.assertEqual("1.0.
|
|
44
|
+
self.assertEqual("1.0.2", version["cliVersion"])
|
|
45
|
+
self.assertEqual("1.0.2", version["runtimeVersion"])
|
|
46
46
|
self.assertEqual("1.0.0", version["schemaVersion"])
|
|
47
47
|
self.assertEqual("1", version["generation"])
|
|
48
48
|
|
|
@@ -101,7 +101,7 @@ class CoverageBlackBoxTests(unittest.TestCase):
|
|
|
101
101
|
|
|
102
102
|
def test_policy_threshold_uses_coverage_without_runtime_specific_policy_logic(self) -> None:
|
|
103
103
|
(self.root / "coverage.xml").write_text(COBERTURA, encoding="utf-8")
|
|
104
|
-
policy = {"identifier": "coverage-policy", "version": "1.0.0", "scope": "repository", "owner": "tests", "description": "coverage threshold", "supportedCapabilities": ["coverage"], "supportedSchemas": ["1.0.0"], "supportedRuntimeVersions": ["1.0.
|
|
104
|
+
policy = {"identifier": "coverage-policy", "version": "1.0.0", "scope": "repository", "owner": "tests", "description": "coverage threshold", "supportedCapabilities": ["coverage"], "supportedSchemas": ["1.0.0"], "supportedRuntimeVersions": ["1.0.2"], "rules": [{"id": "minimum-line-coverage", "type": "threshold", "capability": "coverage", "metric": "coverage.line_coverage", "operator": "less_than", "threshold": {"warning": 80, "blocking": 60}, "severity": {"warning": "WARNING", "blocking": "BLOCKING"}, "enabled": True, "rationale": "coverage floor"}]}
|
|
105
105
|
path = self.root / "policy.json"; path.write_text(json.dumps(policy), encoding="utf-8")
|
|
106
106
|
code, result = self.invoke("--policy", str(path), "assess", "--capability", "coverage", str(self.root))
|
|
107
107
|
self.assertEqual(ExitCode.FAILED, code)
|
|
@@ -71,7 +71,7 @@ class DependencyHealthBlackBoxTests(unittest.TestCase):
|
|
|
71
71
|
|
|
72
72
|
def test_unknown_dependency_and_policy_are_evaluated(self) -> None:
|
|
73
73
|
self.project(missing=True); self.npm({})
|
|
74
|
-
policy = {"identifier": "dependency-policy", "version": "1.0.0", "scope": "repository", "owner": "tests", "description": "dependency threshold", "supportedCapabilities": ["dependency_health"], "supportedSchemas": ["1.0.0"], "supportedRuntimeVersions": ["1.0.
|
|
74
|
+
policy = {"identifier": "dependency-policy", "version": "1.0.0", "scope": "repository", "owner": "tests", "description": "dependency threshold", "supportedCapabilities": ["dependency_health"], "supportedSchemas": ["1.0.0"], "supportedRuntimeVersions": ["1.0.2"], "rules": [{"id": "unknown", "type": "threshold", "capability": "dependency_health", "metric": "dependency_health.unknown_dependencies", "operator": "greater_than", "threshold": {"warning": 1, "blocking": 1}, "severity": {"warning": "WARNING", "blocking": "BLOCKING"}, "enabled": True, "rationale": "unknown dependencies"}]}
|
|
75
75
|
path = self.root / "policy.json"; path.write_text(json.dumps(policy), encoding="utf-8")
|
|
76
76
|
code, result = self.invoke("--policy", str(path), "assess", "--capability", "dependency_health", str(self.root))
|
|
77
77
|
self.assertEqual(ExitCode.FAILED, code)
|
|
@@ -105,6 +105,36 @@ class DependencyHealthBlackBoxTests(unittest.TestCase):
|
|
|
105
105
|
self.assertEqual("NuGet", ecosystem["ecosystem"])
|
|
106
106
|
self.assertEqual(["Example", "Transit"], ecosystem["outdatedDependencies"])
|
|
107
107
|
|
|
108
|
+
def test_nuget_uses_configured_declared_target_framework(self) -> None:
|
|
109
|
+
project = self.root / "app.csproj"
|
|
110
|
+
project.write_text('<Project><PropertyGroup><TargetFrameworks>net10.0-maccatalyst;net10.0-windows10.0.19041.0</TargetFrameworks></PropertyGroup><ItemGroup><PackageReference Include="Example" Version="1.0.0" /></ItemGroup></Project>', encoding="utf-8")
|
|
111
|
+
(self.root / ".tde.yml").write_text("capabilities:\n dependency_health:\n nugetFramework: net10.0-windows10.0.19041.0\n", encoding="utf-8")
|
|
112
|
+
payload = {"projects": [{"frameworks": [{"topLevelPackages": [{"id": "Example", "latestVersion": "2.0.0"}], "transitivePackages": []}]}]}
|
|
113
|
+
self.tool("dotnet", 'if [ "$1" = "--version" ]; then echo "10.0"; else case "$*" in *"--framework net10.0-windows10.0.19041.0"*) printf "%s\\n" \'' + json.dumps(payload) + '\';; *) echo "wrong framework command: $*" >&2; exit 1;; esac; fi\n')
|
|
114
|
+
code, result = self.assess()
|
|
115
|
+
self.assertEqual(ExitCode.SUCCESS, code)
|
|
116
|
+
ecosystem = result["evidence"]["adapterResults"][0]["evidence"]["ecosystems"][0]
|
|
117
|
+
self.assertEqual(["Example"], ecosystem["outdatedDependencies"])
|
|
118
|
+
|
|
119
|
+
def test_nuget_framework_is_scoped_to_projects_that_declare_it(self) -> None:
|
|
120
|
+
app = self.root / "app.csproj"; tests = self.root / "tests.csproj"
|
|
121
|
+
app.write_text('<Project><PropertyGroup><TargetFrameworks>net10.0-maccatalyst;net10.0-windows10.0.19041.0</TargetFrameworks></PropertyGroup><ItemGroup><PackageReference Include="App" Version="1.0.0" /></ItemGroup></Project>', encoding="utf-8")
|
|
122
|
+
tests.write_text('<Project><PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Tests" Version="1.0.0" /></ItemGroup></Project>', encoding="utf-8")
|
|
123
|
+
(self.root / ".tde.yml").write_text("capabilities:\n dependency_health:\n nugetFramework: net10.0-windows10.0.19041.0\n", encoding="utf-8")
|
|
124
|
+
payload = {"projects": [{"frameworks": [{"topLevelPackages": [], "transitivePackages": []}]}]}
|
|
125
|
+
self.tool("dotnet", 'if [ "$1" = "--version" ]; then echo "10.0"; else case "$*" in *app.csproj*--framework\ net10.0-windows10.0.19041.0*) printf "%s\\n" \'' + json.dumps(payload) + '\';; *tests.csproj*) case "$*" in *--framework*) exit 1;; *) printf "%s\\n" \'' + json.dumps(payload) + '\';; esac;; *) exit 1;; esac; fi\n')
|
|
126
|
+
code, _ = self.assess()
|
|
127
|
+
self.assertEqual(ExitCode.SUCCESS, code)
|
|
128
|
+
|
|
129
|
+
def test_nuget_rejects_framework_not_declared_by_project(self) -> None:
|
|
130
|
+
(self.root / "app.csproj").write_text('<Project><PropertyGroup><TargetFramework>net10.0</TargetFramework></PropertyGroup><ItemGroup><PackageReference Include="Example" Version="1.0.0" /></ItemGroup></Project>', encoding="utf-8")
|
|
131
|
+
(self.root / ".tde.yml").write_text("capabilities:\n dependency_health:\n nugetFramework: net10.0-windows10.0.19041.0\n", encoding="utf-8")
|
|
132
|
+
self.tool("dotnet", 'if [ "$1" = "--version" ]; then echo "10.0"; else exit 99; fi\n')
|
|
133
|
+
code, result = self.assess()
|
|
134
|
+
self.assertEqual(ExitCode.BLOCKED, code)
|
|
135
|
+
self.assertEqual("BLOCKED", result["status"])
|
|
136
|
+
self.assertIn("validated canonical evidence", result["reason"])
|
|
137
|
+
|
|
108
138
|
def test_nuget_restore_failure_fails_closed(self) -> None:
|
|
109
139
|
(self.root / "app.csproj").write_text('<Project><ItemGroup><PackageReference Include="Example" Version="1.0.0" /></ItemGroup></Project>', encoding="utf-8")
|
|
110
140
|
payload = {"version": 1, "problems": [{"text": "Restore failed", "level": "error"}]}
|
|
@@ -51,7 +51,7 @@ class PublicPolicyConfigurationTests(unittest.TestCase):
|
|
|
51
51
|
"identifier": "example.code-size", "version": "2026.1", "scope": "repository",
|
|
52
52
|
"owner": "example", "description": "Example organization policy.",
|
|
53
53
|
"supportedCapabilities": ["code_size"], "supportedSchemas": ["1.0.0"],
|
|
54
|
-
"supportedRuntimeVersions": ["1.0.
|
|
54
|
+
"supportedRuntimeVersions": ["1.0.2"],
|
|
55
55
|
"rules": [{"id": "example.code-size.lines", "type": "threshold", "capability": "code_size",
|
|
56
56
|
"metric": "code_size.code_lines", "operator": "greater_than",
|
|
57
57
|
"threshold": {"warning": threshold, "blocking": threshold + 1000},
|
|
@@ -93,7 +93,7 @@ class PublicPolicyConfigurationTests(unittest.TestCase):
|
|
|
93
93
|
*evidence["assessment"]["capabilityExecutions"]]:
|
|
94
94
|
self.assertEqual("1.0.0", item["schema"]["version"])
|
|
95
95
|
self.assertEqual("1", item["schema"]["compatibilityVersion"])
|
|
96
|
-
self.assertEqual("1.0.
|
|
96
|
+
self.assertEqual("1.0.2", item["schema"]["runtimeVersion"])
|
|
97
97
|
record = next((location / "evidence").glob("*.json"))
|
|
98
98
|
persisted = json.loads(record.read_text(encoding="utf-8"))
|
|
99
99
|
persisted["evidence"]["policyEvidence"]["schema"]["version"] = "999.0.0"
|
|
@@ -15,13 +15,13 @@ class ReleaseBundleTests(unittest.TestCase):
|
|
|
15
15
|
"manifest.json": b"{}", "qualification.json": b"{}", "certification.json": b"{}", "evidence.json": b"{}"}
|
|
16
16
|
for name, value in files.items(): (inputs / name).write_bytes(value)
|
|
17
17
|
output = root / "bundle"
|
|
18
|
-
command = ["python", "tools/assemble_release_bundle.py", "--candidate-sha", "a" * 40, "--release-version", "1.0.
|
|
18
|
+
command = ["python", "tools/assemble_release_bundle.py", "--candidate-sha", "a" * 40, "--release-version", "1.0.0", "--output", str(output),
|
|
19
19
|
"--wheel", str(inputs / "wheel.whl"), "--sdist", str(inputs / "source.tar.gz"), "--oci-archive", str(inputs / "image.tar"),
|
|
20
20
|
"--docker-provenance", str(inputs / "docker-provenance.json"), "--release-manifest", str(inputs / "manifest.json"),
|
|
21
21
|
"--release-qualification", str(inputs / "qualification.json"), "--release-certification", str(inputs / "certification.json"), "--release-evidence", str(inputs / "evidence.json")]
|
|
22
22
|
subprocess.run(command, check=True, env={**__import__("os").environ, "PYTHONPATH": "src"}, capture_output=True)
|
|
23
23
|
self.assertTrue(verify(output)["integrity"])
|
|
24
|
-
self.assertEqual("1.0.
|
|
24
|
+
self.assertEqual("1.0.0", verify(output)["bundle"]["bundleVersion"])
|
|
25
25
|
(output / "wheel.whl").write_bytes(b"tampered")
|
|
26
26
|
self.assertFalse(verify(output)["integrity"])
|
|
27
27
|
|
|
@@ -22,7 +22,7 @@ class ReleasePublicationTests(unittest.TestCase):
|
|
|
22
22
|
files["qualification.json"] = json.dumps(qualification).encode(); files["certification.json"] = json.dumps(certification).encode()
|
|
23
23
|
for name, value in files.items(): (inputs / name).write_bytes(value)
|
|
24
24
|
output = root / "bundle"
|
|
25
|
-
command = ["python", "tools/assemble_release_bundle.py", "--candidate-sha", self.candidate, "--release-version", "1.0.
|
|
25
|
+
command = ["python", "tools/assemble_release_bundle.py", "--candidate-sha", self.candidate, "--release-version", "1.0.0", "--output", str(output),
|
|
26
26
|
"--wheel", str(inputs / "wheel.whl"), "--sdist", str(inputs / "source.tar.gz"), "--oci-archive", str(inputs / "image.tar"),
|
|
27
27
|
"--docker-provenance", str(inputs / "docker-provenance.json"), "--release-manifest", str(inputs / "manifest.json"),
|
|
28
28
|
"--release-qualification", str(inputs / "qualification.json"), "--release-certification", str(inputs / "certification.json"), "--release-evidence", str(inputs / "evidence.json")]
|
|
@@ -32,13 +32,13 @@ class ReleasePublicationTests(unittest.TestCase):
|
|
|
32
32
|
def authorization(self, bundle):
|
|
33
33
|
manifest = json.loads((bundle / "bundle-manifest.json").read_text())
|
|
34
34
|
return {"authorizedBy": "release-reviewer", "authorizedAt": "2026-07-16T00:00:00Z", "candidateSha": self.candidate,
|
|
35
|
-
"releaseVersion": "1.0.
|
|
35
|
+
"releaseVersion": "1.0.0", "bundleId": manifest["bundleId"], "bundleChecksum": manifest["bundleChecksum"],
|
|
36
36
|
"targets": ["github_release", "pypi", "docker_hub"]}
|
|
37
37
|
|
|
38
38
|
def test_preflight_reads_existing_bundle_and_writes_no_bundle_content(self):
|
|
39
39
|
with tempfile.TemporaryDirectory() as temporary:
|
|
40
40
|
root = Path(temporary); bundle = self.bundle(root); before = sorted(item.name for item in bundle.iterdir())
|
|
41
|
-
result = verify_publication_bundle(bundle, self.candidate, "1.0.
|
|
41
|
+
result = verify_publication_bundle(bundle, self.candidate, "1.0.0", self.authorization(bundle))
|
|
42
42
|
self.assertEqual("PUBLICATION_PREFLIGHT_READY", result["decision"])
|
|
43
43
|
self.assertEqual(before, sorted(item.name for item in bundle.iterdir()))
|
|
44
44
|
|
|
@@ -52,13 +52,13 @@ class ReleasePublicationTests(unittest.TestCase):
|
|
|
52
52
|
with tempfile.TemporaryDirectory() as temporary:
|
|
53
53
|
bundle = self.bundle(Path(temporary)); record = self.authorization(bundle)
|
|
54
54
|
record.update({"schemaId": "tde.internal-release-authorization",
|
|
55
|
-
"approvedGitTag": "1.0.
|
|
56
|
-
"approvedDockerHub": "docker.io/pcvantol/technical-debt-engine:1.0.
|
|
55
|
+
"approvedGitTag": "1.0.0", "approvedGitHubRelease": "1.0.0", "approvedPyPI": "1.0.0",
|
|
56
|
+
"approvedDockerHub": "docker.io/pcvantol/technical-debt-engine:1.0.0", "protectedEnvironment": "internal-release",
|
|
57
57
|
"publicationWorkflow": ".github/workflows/internal-release-publish.yml", "targetApprovals": {"github_release": True, "pypi": True, "docker_hub": True}})
|
|
58
58
|
record["authorizationId"] = "authorization.sha256." + sha256(canonical(record)).hexdigest()
|
|
59
|
-
self.assertFalse(validate_authorization_record(record, self.candidate, "1.0.
|
|
59
|
+
self.assertFalse(validate_authorization_record(record, self.candidate, "1.0.0", record["bundleId"], record["bundleChecksum"]))
|
|
60
60
|
record["targetApprovals"]["pypi"] = False
|
|
61
|
-
self.assertTrue(validate_authorization_record(record, self.candidate, "1.0.
|
|
61
|
+
self.assertTrue(validate_authorization_record(record, self.candidate, "1.0.0", record["bundleId"], record["bundleChecksum"]))
|
|
62
62
|
|
|
63
63
|
def test_workflow_is_manual_dry_run_and_never_rebuilds(self):
|
|
64
64
|
workflow = Path(".github/workflows/internal-release-publish.yml").read_text(encoding="utf-8")
|
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_runtime.py
RENAMED
|
@@ -61,7 +61,7 @@ class RuntimeFoundationTests(unittest.TestCase):
|
|
|
61
61
|
|
|
62
62
|
def test_context_contains_canonical_runtime_values(self) -> None:
|
|
63
63
|
result = Runtime().execute(self.root)
|
|
64
|
-
self.assertEqual("1.0.
|
|
64
|
+
self.assertEqual("1.0.2", result.context.runtime_version)
|
|
65
65
|
self.assertEqual("1.0.0", result.context.schema_version)
|
|
66
66
|
self.assertTrue(result.context.execution_id.startswith("execution."))
|
|
67
67
|
self.assertEqual("content_digest", result.context.candidate["identityType"])
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_policy.py
RENAMED
|
File without changes
|
|
File without changes
|
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_query.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{technical_debt_engine_runtime-1.0.0rc3 → technical_debt_engine_runtime-1.0.2}/tests/test_trend.py
RENAMED
|
File without changes
|
|
File without changes
|