technical-debt-engine-runtime 0.1.0__py3-none-any.whl

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.
@@ -0,0 +1,183 @@
1
+ """Canonical, fail-closed operational Software Assurance evidence."""
2
+ from __future__ import annotations
3
+
4
+ from hashlib import sha256
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+ import re
9
+ import subprocess
10
+ from typing import Any, Iterable
11
+
12
+ from .configuration import RuntimeConfiguration
13
+
14
+ ASSURANCE_SCHEMA_VERSION = "1.0.0"
15
+ _USES_KEY = re.compile(r"^\s*(?:-\s+)?uses:\s*(?P<reference>.*)$")
16
+ _ACTION_REFERENCE = re.compile(
17
+ r"^(?P<owner>[A-Za-z0-9][A-Za-z0-9-]*)/"
18
+ r"(?P<repository>[A-Za-z0-9_.-]+)"
19
+ r"(?P<path>(?:/[A-Za-z0-9_.-]+)*)@(?P<revision>[^\s#]+)$"
20
+ )
21
+ _COMMIT_SHA = re.compile(r"^[0-9a-fA-F]{40}$")
22
+
23
+
24
+ def _canonical(value: object) -> bytes:
25
+ return (json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + "\n").encode("utf-8")
26
+
27
+
28
+ def _digest(path: Path) -> str:
29
+ hasher = sha256()
30
+ with path.open("rb") as stream:
31
+ for block in iter(lambda: stream.read(1024 * 1024), b""):
32
+ hasher.update(block)
33
+ return "sha256:" + hasher.hexdigest()
34
+
35
+
36
+ def _git(root: Path, *arguments: str) -> tuple[bool, str]:
37
+ completed = subprocess.run(["git", "-C", str(root), *arguments], text=True, capture_output=True, check=False)
38
+ return completed.returncode == 0, completed.stdout.strip()
39
+
40
+
41
+ def parse_action_reference(reference: str) -> dict[str, Any]:
42
+ """Normalize a GitHub Action reference and classify its immutability.
43
+
44
+ GitHub accepts ``owner/repository[/path]@revision`` for both step-level
45
+ actions and job-level reusable workflows. Only a complete commit SHA is
46
+ immutable; malformed, local, expression, and mutable references remain
47
+ explicitly untrusted.
48
+ """
49
+ reference = reference.split("#", 1)[0].strip()
50
+ match = _ACTION_REFERENCE.fullmatch(reference)
51
+ if not match:
52
+ return {"owner": None, "repository": None, "path": None, "commitSha": None, "immutable": False}
53
+ values = match.groupdict()
54
+ revision = values["revision"]
55
+ immutable = bool(_COMMIT_SHA.fullmatch(revision))
56
+ return {
57
+ "owner": values["owner"].lower(),
58
+ "repository": values["repository"].lower(),
59
+ "path": values["path"] or None,
60
+ "commitSha": revision.lower() if immutable else None,
61
+ "immutable": immutable,
62
+ }
63
+
64
+
65
+ class SoftwareAssurance:
66
+ """Evaluate repository and candidate artifacts without delivery or release behavior."""
67
+
68
+ def assure(self, root: str | Path, artifact_directories: Iterable[str | Path] = (), docker_artifact_directory: str | Path | None = None) -> dict[str, Any]:
69
+ root = Path(root).resolve(); limitations: list[str] = []
70
+ repository = self._repository(root, limitations); dependencies = self._dependencies(root, limitations)
71
+ workflows = self._workflows(root, limitations); configuration = self._configuration(root, limitations)
72
+ documentation = self._documentation(root, limitations)
73
+ artifacts = self._artifacts(tuple(Path(item).resolve() for item in artifact_directories), limitations)
74
+ if docker_artifact_directory is not None:
75
+ from .docker_artifact import validate as validate_docker
76
+ candidate = repository["candidateIdentity"].removeprefix("candidate.git.") if repository.get("candidateIdentity") else ""
77
+ docker = validate_docker(docker_artifact_directory, candidate)
78
+ artifacts["docker"] = docker
79
+ artifacts["records"].append({"directory": str(Path(docker_artifact_directory).resolve()), "artifactCount": 1,
80
+ "verified": docker["verified"], "artifacts": [{key: docker[key] for key in ("filename", "digest")} ]})
81
+ artifacts["integrity"] = artifacts["integrity"] and docker["verified"]
82
+ if not docker["verified"]:
83
+ limitations.append("candidate Docker archive or provenance is invalid")
84
+ checks = {"repositoryIntegrity": repository["integrity"], "dependencyIntegrity": dependencies["integrity"],
85
+ "artifactIntegrity": artifacts["integrity"], "workflowIntegrity": workflows["integrity"],
86
+ "configurationIntegrity": configuration["integrity"], "documentationIntegrity": documentation["integrity"],
87
+ "buildProvenanceVerification": artifacts["provenanceVerified"]}
88
+ required = ("repositoryIntegrity", "dependencyIntegrity", "workflowIntegrity", "configurationIntegrity", "documentationIntegrity")
89
+ failed = not all(checks[name] for name in required) or (bool(artifacts["directories"]) and not checks["artifactIntegrity"])
90
+ decision = "FAIL" if failed else "PASS_WITH_WARNINGS" if limitations else "PASS"
91
+ evidence = {"schemaId": "tde.software-assurance", "schemaVersion": ASSURANCE_SCHEMA_VERSION,
92
+ "repository": repository, "dependencies": dependencies, "artifacts": artifacts, "workflows": workflows,
93
+ "configuration": configuration, "documentation": documentation, "checks": checks,
94
+ "limitations": limitations, "decision": decision}
95
+ evidence["assuranceId"] = "assurance.sha256." + sha256(_canonical(evidence)).hexdigest()
96
+ evidence["qualification"] = decision
97
+ return evidence
98
+
99
+ @staticmethod
100
+ def _repository(root: Path, limitations: list[str]) -> dict[str, Any]:
101
+ valid, candidate = _git(root, "rev-parse", "HEAD"); _, branch = _git(root, "branch", "--show-current")
102
+ branch = branch or os.environ.get("TDE_CANDIDATE_SOURCE_BRANCH", "")
103
+ _, remote = _git(root, "config", "--get", "remote.origin.url"); status_ok, dirty = _git(root, "status", "--porcelain")
104
+ integrity = valid and status_ok and not dirty and bool(branch)
105
+ if not valid: limitations.append("repository identity is unavailable")
106
+ if not branch: limitations.append("candidate is detached from a branch")
107
+ if dirty: limitations.append("working tree is not clean")
108
+ return {"identity": remote or "local", "candidateIdentity": "candidate.git." + candidate if candidate else None,
109
+ "branch": branch or None, "workingTreeClean": not bool(dirty), "integrity": integrity}
110
+
111
+ @staticmethod
112
+ def _dependencies(root: Path, limitations: list[str]) -> dict[str, Any]:
113
+ project = root / "pyproject.toml"; build_tools = root / "requirements" / "build-tools.txt"; pinned = hashes = False
114
+ if project.is_file():
115
+ match = re.search(r"requires\s*=\s*\[([^]]*)\]", project.read_text(encoding="utf-8"), re.DOTALL)
116
+ pinned = bool(match and re.findall(r'"[^"\n]+==[^"\n]+"', match.group(1)))
117
+ if build_tools.is_file():
118
+ content = build_tools.read_text(encoding="utf-8"); hashes = "--hash=sha256:" in content and "Generated with:" in content
119
+ integrity = project.is_file() and pinned and build_tools.is_file() and hashes
120
+ if not integrity: limitations.append("dependency declarations, exact versions, and hash-locked build provenance are incomplete")
121
+ return {"declaration": str(project.relative_to(root)), "buildTools": str(build_tools.relative_to(root)),
122
+ "exactVersions": pinned, "reproducible": hashes, "provenance": hashes, "integrity": integrity}
123
+
124
+ @staticmethod
125
+ def _workflows(root: Path, limitations: list[str]) -> dict[str, Any]:
126
+ directory = root / ".github" / "workflows"; files = sorted(directory.glob("*.y*ml")) if directory.is_dir() else []
127
+ contents = [item.read_text(encoding="utf-8") for item in files]
128
+ action_references = [parse_action_reference(match.group("reference"))
129
+ for content in contents for line in content.splitlines()
130
+ if (match := _USES_KEY.match(line))]
131
+ immutable = bool(action_references) and all(reference["immutable"] for reference in action_references)
132
+ least_privilege = any(re.search(r"^permissions:\s*\n\s+contents:\s+read\s*$", content, re.MULTILINE) for content in contents)
133
+ package_build = any(item.name == "package-build.yml" and "tools/package_build.py" in content and "--require-hashes" in content for item, content in zip(files, contents))
134
+ integrity = bool(files) and immutable and least_privilege and package_build
135
+ if not integrity: limitations.append("workflow immutability, least privilege, or reproducible-build coverage is incomplete")
136
+ return {"workflowCount": len(files), "immutableActions": immutable, "actionReferences": action_references,
137
+ "leastPrivilege": least_privilege,
138
+ "buildReproducibility": package_build, "integrity": integrity}
139
+
140
+ @staticmethod
141
+ def _configuration(root: Path, limitations: list[str]) -> dict[str, Any]:
142
+ schema = root / "schemas" / "configuration.schema.json"; project = root / "pyproject.toml"; config = root / ".tde.yml"
143
+ compatible = False; provenance = None
144
+ try:
145
+ compatible = schema.is_file() and json.loads(schema.read_text(encoding="utf-8"))["properties"]["schemaVersion"]["const"] == "1.0.0"
146
+ if config.is_file(): provenance = RuntimeConfiguration.discover(root).digest()
147
+ except (KeyError, ValueError, json.JSONDecodeError): pass
148
+ integrity = schema.is_file() and project.is_file() and compatible
149
+ if not integrity: limitations.append("configuration schema compatibility or provenance is unavailable")
150
+ return {"schema": str(schema.relative_to(root)), "schemaCompatible": compatible, "configurationDigest": provenance, "integrity": integrity}
151
+
152
+ @staticmethod
153
+ def _documentation(root: Path, limitations: list[str]) -> dict[str, Any]:
154
+ required = ("README.md", "ENGINEERING_METHOD.md", "RUNTIME_ARCHITECTURE.md", "INTEGRATION_MODEL.md", "PACKAGING.md")
155
+ missing = [item for item in required if not (root / item).is_file()]
156
+ if missing: limitations.append("canonical documentation is missing: " + ", ".join(missing))
157
+ return {"required": list(required), "missing": missing, "architectureConsistent": not missing,
158
+ "governanceConsistent": not missing, "integrity": not missing}
159
+
160
+ @staticmethod
161
+ def _artifacts(directories: tuple[Path, ...], limitations: list[str]) -> dict[str, Any]:
162
+ if not directories:
163
+ limitations.append("no candidate artifact directory was supplied; artifact integrity and reproducibility were not evaluated")
164
+ return {"directories": [], "records": [], "checksumsVerified": False, "identityVerified": False,
165
+ "reproducible": False, "provenanceVerified": False, "integrity": False}
166
+ records: list[dict[str, Any]] = []; valid = True; identities: list[list[tuple[str, str]]] = []
167
+ for directory in directories:
168
+ manifest = directory / "SHA256SUMS"; provenance = directory / "build-provenance.json"
169
+ artifacts = sorted([*directory.glob("*.whl"), *directory.glob("*.tar.gz")]) if directory.is_dir() else []
170
+ try:
171
+ expected = {line.split(maxsplit=1)[1]: "sha256:" + line.split(maxsplit=1)[0] for line in manifest.read_text(encoding="utf-8").splitlines() if line.strip()}
172
+ source = json.loads(provenance.read_text(encoding="utf-8")); recorded = {item["filename"]: item["digest"] for item in source["artifacts"]}
173
+ current = {item.name: _digest(item) for item in artifacts}; directory_valid = len(artifacts) == 2 and current == expected == recorded and bool(source.get("candidateSha"))
174
+ except (OSError, ValueError, KeyError, IndexError, json.JSONDecodeError): directory_valid = False; current = {}
175
+ valid = valid and directory_valid; identities.append(sorted(current.items()))
176
+ records.append({"directory": str(directory), "artifactCount": len(artifacts), "verified": directory_valid,
177
+ "artifacts": [{"filename": name, "digest": digest} for name, digest in sorted(current.items())]})
178
+ reproducible = valid and len(identities) > 1 and all(identity == identities[0] for identity in identities[1:])
179
+ if not valid: limitations.append("candidate artifact checksums, identities, or build provenance are invalid")
180
+ if len(directories) == 1: limitations.append("one candidate artifact directory was supplied; reproducibility requires an independent second candidate")
181
+ elif not reproducible: limitations.append("candidate artifacts are not byte-identical across independent builds")
182
+ return {"directories": [str(item) for item in directories], "records": records, "checksumsVerified": valid,
183
+ "identityVerified": valid, "reproducible": reproducible, "provenanceVerified": valid, "integrity": valid and reproducible}
tde_runtime/trend.py ADDED
@@ -0,0 +1,73 @@
1
+ """Normalized, read-only trends over validated baseline evidence."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from hashlib import sha256
6
+ from pathlib import Path
7
+ from typing import Any, Mapping
8
+
9
+ from .baseline import BaselineRepository
10
+
11
+
12
+ class TrendEngine:
13
+ """Aggregates canonical evidence history and deliberately makes no policy decision."""
14
+
15
+ def build(self, current: Mapping[str, Any], location: str | Path, history_depth: int | None = None) -> dict[str, Any]:
16
+ BaselineRepository._validate_evidence(current)
17
+ repository = BaselineRepository(location)
18
+ history = []
19
+ for path in sorted(Path(location).glob("*.json")) if Path(location).is_dir() else []:
20
+ history.append(repository.load(path))
21
+ history.sort(key=lambda item: item["createdAt"])
22
+ if history_depth is not None:
23
+ history = history[-history_depth:]
24
+ evidence = [item["evidence"] for item in history] + [current]
25
+ metric_trends = self._metrics(evidence)
26
+ capability_trends = self._capabilities(evidence)
27
+ finding_trends = self._findings(evidence)
28
+ qualification_history = [item.get("policyEvidence", {}).get("decision", "NOT_APPLICABLE") for item in evidence]
29
+ return {"trendId": "trend." + sha256("|".join(item["integrity"]["contentDigest"] for item in evidence).encode()).hexdigest()[:16],
30
+ "repositoryId": current["repository"]["id"], "history": [{"baselineId": item["baselineId"], "createdAt": item["createdAt"], "evidenceId": item["sourceEvidenceId"]} for item in history],
31
+ "comparisonReferences": [item["baselineId"] for item in history], "repositoryTrend": self._repository(metric_trends),
32
+ "capabilityTrends": capability_trends, "metricTrends": metric_trends, "findingTrends": finding_trends,
33
+ "qualificationTrend": {"history": qualification_history, "direction": self._direction(qualification_history)},
34
+ "window": "latest" if not history else "rolling", "limitations": []}
35
+
36
+ @staticmethod
37
+ def _metrics(evidence: list[Mapping[str, Any]]) -> list[dict[str, Any]]:
38
+ series: dict[str, list[float]] = {}
39
+ for snapshot in evidence:
40
+ for metric in snapshot.get("measurements", []):
41
+ if isinstance(metric.get("value"), (int, float)):
42
+ series.setdefault(metric["metricKey"], []).append(metric["value"])
43
+ return [{"metricKey": key, "timeSeries": values, "delta": values[-1] - values[0],
44
+ "movingAverage": sum(values) / len(values), "direction": TrendEngine._numeric_direction(values)} for key, values in sorted(series.items())]
45
+
46
+ @staticmethod
47
+ def _capabilities(evidence: list[Mapping[str, Any]]) -> list[dict[str, Any]]:
48
+ states: dict[str, list[str]] = {}
49
+ for snapshot in evidence:
50
+ for result in snapshot.get("capabilityResults", []):
51
+ states.setdefault(result["capabilityId"], []).append(result.get("status", "UNKNOWN"))
52
+ return [{"capabilityId": key, "history": values, "direction": "STABLE" if len(set(values)) == 1 else "CHANGED"} for key, values in sorted(states.items())]
53
+
54
+ @staticmethod
55
+ def _findings(evidence: list[Mapping[str, Any]]) -> list[dict[str, Any]]:
56
+ seen: dict[str, int] = {}
57
+ for snapshot in evidence:
58
+ for finding in snapshot.get("findings", []):
59
+ seen[finding["findingId"]] = seen.get(finding["findingId"], 0) + 1
60
+ return [{"findingId": key, "occurrences": count, "state": "PERSISTENT" if count > 1 else "INTRODUCED"} for key, count in sorted(seen.items())]
61
+
62
+ @staticmethod
63
+ def _repository(metrics: list[Mapping[str, Any]]) -> dict[str, Any]:
64
+ size = next((item for item in metrics if item["metricKey"] == "code_size.code_lines"), None)
65
+ return {"growth": size["delta"] if size else None, "direction": size["direction"] if size else "NOT_APPLICABLE"}
66
+
67
+ @staticmethod
68
+ def _numeric_direction(values: list[float]) -> str:
69
+ return "INCREASING" if values[-1] > values[0] else "DECREASING" if values[-1] < values[0] else "STABLE"
70
+
71
+ @staticmethod
72
+ def _direction(values: list[str]) -> str:
73
+ return "STABLE" if len(set(values)) <= 1 else "CHANGED"
@@ -0,0 +1,137 @@
1
+ """Canonical, evidence-only Trusted Delivery validation."""
2
+ from __future__ import annotations
3
+
4
+ from hashlib import sha256
5
+ import json
6
+ import os
7
+ from pathlib import Path
8
+ import re
9
+ import subprocess
10
+ from typing import Any, Mapping
11
+
12
+ MANIFEST_SCHEMA_ID = "tde.trusted-delivery-manifest"
13
+ MANIFEST_SCHEMA_VERSION = "1.0.0"
14
+ _SHA256 = re.compile(r"^sha256:[0-9a-f]{64}$")
15
+ _GIT_SHA = re.compile(r"^[0-9a-f]{40}$")
16
+
17
+
18
+ def _canonical(value: object) -> bytes:
19
+ return (json.dumps(value, sort_keys=True, separators=(",", ":"), ensure_ascii=True) + "\n").encode("utf-8")
20
+
21
+
22
+ def _git(root: Path, *arguments: str) -> tuple[bool, str]:
23
+ completed = subprocess.run(["git", "-C", str(root), *arguments], text=True, capture_output=True, check=False)
24
+ return completed.returncode == 0, completed.stdout.strip()
25
+
26
+
27
+ class TrustedDelivery:
28
+ """Bind a candidate to assurance, artifact, manifest, and workflow evidence.
29
+
30
+ This layer deliberately consumes Software Assurance evidence instead of
31
+ re-evaluating assurance rules or making a release/publication decision.
32
+ """
33
+
34
+ def validate(self, root: str | Path, runtime_evidence: Mapping[str, Any] | None,
35
+ assurance_evidence: Mapping[str, Any] | None = None, manifest: str | Path | None = None) -> dict[str, Any]:
36
+ root = Path(root).resolve(); limitations: list[str] = []
37
+ candidate = self._candidate(root, limitations)
38
+ manifest_evidence = self._manifest(Path(manifest).resolve() if manifest else None, candidate, limitations)
39
+ assurance = self._assurance(assurance_evidence, limitations)
40
+ artifacts = self._artifacts(manifest_evidence, assurance, limitations)
41
+ workflow = self._workflow(root, assurance, limitations)
42
+ runtime_ok = runtime_evidence is not None and runtime_evidence.get("validation", {}).get("status") == "VALID"
43
+ if not runtime_ok:
44
+ limitations.append("validated Runtime evidence is unavailable")
45
+ checks = {
46
+ "candidateIntegrity": candidate["integrity"],
47
+ "manifestIntegrity": manifest_evidence["integrity"],
48
+ "artifactIntegrity": artifacts["integrity"],
49
+ "workflowIntegrity": workflow["integrity"],
50
+ "softwareAssuranceIntegrity": assurance["integrity"],
51
+ "runtimeEvidenceIntegrity": runtime_ok,
52
+ "buildProvenanceValidation": artifacts["provenanceValidated"],
53
+ }
54
+ # An omitted external delivery manifest/artifact is a bounded
55
+ # pre-release limitation. An explicitly supplied invalid input fails
56
+ # closed; candidate, Runtime, and assurance failures always fail.
57
+ required = ("candidateIntegrity", "softwareAssuranceIntegrity", "runtimeEvidenceIntegrity")
58
+ invalid_input = manifest is not None and (not checks["manifestIntegrity"] or not checks["artifactIntegrity"])
59
+ decision = "FAIL" if not all(checks[name] for name in required) or invalid_input else "PASS_WITH_WARNINGS" if limitations else "PASS"
60
+ evidence = {
61
+ "schemaId": "tde.trusted-delivery", "schemaVersion": "1.0.0", "candidate": candidate,
62
+ "manifest": manifest_evidence, "artifacts": artifacts, "workflow": workflow,
63
+ "softwareAssurance": {"assuranceId": assurance.get("assuranceId"), "decision": assurance.get("decision")},
64
+ "runtimeEvidenceId": runtime_evidence.get("integrity", {}).get("contentDigest") if runtime_evidence else None,
65
+ "checks": checks, "limitations": limitations, "decision": decision, "qualification": decision,
66
+ }
67
+ evidence["trustedDeliveryId"] = "trusted-delivery.sha256." + sha256(_canonical(evidence)).hexdigest()
68
+ return evidence
69
+
70
+ @staticmethod
71
+ def _candidate(root: Path, limitations: list[str]) -> dict[str, Any]:
72
+ sha_ok, sha = _git(root, "rev-parse", "HEAD"); _, branch = _git(root, "branch", "--show-current")
73
+ branch = branch or os.environ.get("TDE_CANDIDATE_SOURCE_BRANCH", "")
74
+ _, repository = _git(root, "config", "--get", "remote.origin.url"); status_ok, dirty = _git(root, "status", "--porcelain")
75
+ integrity = sha_ok and bool(_GIT_SHA.fullmatch(sha)) and bool(branch) and status_ok and not dirty
76
+ if not integrity:
77
+ limitations.append("candidate SHA, repository branch, or clean working tree is invalid")
78
+ return {"sha": sha or None, "candidateIdentity": "candidate.git." + sha if sha else None,
79
+ "repository": repository or "local", "branch": branch or None, "workingTreeClean": not bool(dirty),
80
+ "integrity": integrity}
81
+
82
+ @staticmethod
83
+ def _manifest(path: Path | None, candidate: Mapping[str, Any], limitations: list[str]) -> dict[str, Any]:
84
+ if path is None:
85
+ limitations.append("no delivery manifest was supplied; manifest and artifact references were not evaluated")
86
+ return {"path": None, "identity": None, "integrity": False, "supplied": False, "artifacts": []}
87
+ try:
88
+ raw = path.read_bytes(); value = json.loads(raw)
89
+ items = value["artifacts"]
90
+ valid = (value.get("schemaId") == MANIFEST_SCHEMA_ID and value.get("schemaVersion") == MANIFEST_SCHEMA_VERSION
91
+ and value.get("candidate", {}).get("sha") == candidate["sha"]
92
+ and value.get("candidate", {}).get("repository") == candidate["repository"]
93
+ and value.get("candidate", {}).get("branch") == candidate["branch"]
94
+ and isinstance(items, list) and bool(items)
95
+ and all(isinstance(item, dict) and isinstance(item.get("filename"), str) and _SHA256.fullmatch(item.get("digest", "")) for item in items))
96
+ except (OSError, ValueError, KeyError, TypeError, json.JSONDecodeError):
97
+ raw = b""; value = {}; items = []; valid = False
98
+ if not valid:
99
+ limitations.append("supplied delivery manifest does not meet the canonical schema, candidate, or checksum requirements")
100
+ return {"path": str(path), "identity": "manifest.sha256." + sha256(raw).hexdigest() if raw else None,
101
+ "schemaId": value.get("schemaId"), "schemaVersion": value.get("schemaVersion"), "supplied": True,
102
+ "candidate": value.get("candidate"), "artifacts": items, "integrity": valid}
103
+
104
+ @staticmethod
105
+ def _assurance(evidence: Mapping[str, Any] | None, limitations: list[str]) -> Mapping[str, Any]:
106
+ valid = (evidence is not None and evidence.get("schemaId") == "tde.software-assurance"
107
+ and isinstance(evidence.get("assuranceId"), str) and evidence.get("decision") != "FAIL")
108
+ if not valid:
109
+ limitations.append("canonical Software Assurance evidence is unavailable or failed")
110
+ return {"integrity": False}
111
+ return {**evidence, "integrity": True}
112
+
113
+ @staticmethod
114
+ def _artifacts(manifest: Mapping[str, Any], assurance: Mapping[str, Any], limitations: list[str]) -> dict[str, Any]:
115
+ records = [artifact for directory in assurance.get("artifacts", {}).get("records", []) for artifact in directory.get("artifacts", [])]
116
+ supplied = bool(manifest.get("supplied"))
117
+ if not supplied:
118
+ return {"records": [], "integrity": False, "provenanceValidated": False}
119
+ expected = {(item["filename"], item["digest"]) for item in manifest.get("artifacts", [])}
120
+ actual = {(item.get("filename"), item.get("digest")) for item in records}
121
+ integrity = bool(assurance.get("checks", {}).get("artifactIntegrity")) and expected == actual
122
+ if not integrity:
123
+ limitations.append("manifest artifact references do not match checksum-verified, reproducible assurance artifacts")
124
+ return {"records": sorted(records, key=lambda item: item["filename"]), "integrity": integrity,
125
+ "provenanceValidated": integrity and bool(assurance.get("checks", {}).get("buildProvenanceVerification"))}
126
+
127
+ @staticmethod
128
+ def _workflow(root: Path, assurance: Mapping[str, Any], limitations: list[str]) -> dict[str, Any]:
129
+ directory = root / ".github" / "workflows"
130
+ records = [{"path": str(item.relative_to(root)), "digest": "sha256:" + sha256(item.read_bytes()).hexdigest()}
131
+ for item in sorted(directory.glob("*.y*ml"))] if directory.is_dir() else []
132
+ workflow = assurance.get("workflows", {})
133
+ integrity = bool(workflow.get("immutableActions")) and bool(workflow.get("leastPrivilege")) and bool(records)
134
+ if not integrity:
135
+ limitations.append("workflow provenance, immutable actions, or least-privilege evidence is unavailable")
136
+ return {"records": records, "immutableActions": bool(workflow.get("immutableActions")),
137
+ "leastPrivilege": bool(workflow.get("leastPrivilege")), "integrity": integrity}
@@ -0,0 +1,5 @@
1
+ Metadata-Version: 2.4
2
+ Name: technical-debt-engine-runtime
3
+ Version: 0.1.0
4
+ Summary: Technical Debt Engine runtime foundation API
5
+ Requires-Python: >=3.11
@@ -0,0 +1,33 @@
1
+ tde_cli/__init__.py,sha256=nfLKy9af_L7AkShru2wINR11XlthP2RYas7oDEJ3RmI,108
2
+ tde_cli/main.py,sha256=sExbye_XFA0qpD7h1qFZOLruLomeRXb6bnoBzdgvuTk,25763
3
+ tde_runtime/__init__.py,sha256=a3F_jaulHsYtvNir7bu5h7YZYfv8LHlFbFLpianR-mQ,209
4
+ tde_runtime/baseline.py,sha256=V6Q2NAKYsMlJJrFJ8DVUEuLatNqX7EY1IdaGePObSQo,12220
5
+ tde_runtime/code_size.py,sha256=MZUICW01Hpr2pptZdL3xkvevy1xVvPRogyb8xk1okP4,3920
6
+ tde_runtime/complexity.py,sha256=qkXceiNRhMDfEUW6welqCehkK-x4dW05As6LLFqAFS8,5560
7
+ tde_runtime/configuration.py,sha256=Pk5LhOl1LAnHF4_UFIrE8fhanHRNet7zEPz8FW6n67U,4606
8
+ tde_runtime/dependency_health.py,sha256=Q-YCLfXHHDC6nPuQoU7KUqFSYW8l477Vm6vquDYzz7M,1896
9
+ tde_runtime/docker_artifact.py,sha256=4Xtc8WKAkxXbmgHkMj6p40VivQUpJyVl8ATLHyfZPyo,2270
10
+ tde_runtime/evidence_store.py,sha256=w2lzPZ-KnhXKZlBY5hnpWl58Ld8i20vG_lUXCpq8BQk,4062
11
+ tde_runtime/execution.py,sha256=qvKxS7DfNQlHpOLSHv9HHlVDPKHFjOkq3ofPVqctwpw,17288
12
+ tde_runtime/maintainability.py,sha256=cFlSogrKeoh7reQ1uHx7s_QHga6zPZaptscyl_QjI5s,1282
13
+ tde_runtime/models.py,sha256=wa--Ryn8y81lGSCc6qqcRHys2KJYt4R0Qtczm6O7m8E,1789
14
+ tde_runtime/policy.py,sha256=bRfKWRa4rBxutYItF-SJUp1X1JXZqHJoS303_RQNJb4,12503
15
+ tde_runtime/query.py,sha256=wiFafUy5ah1mHes8p5k5dHe6txsjHSGnFVR9PjIJ2V4,2626
16
+ tde_runtime/registries.py,sha256=weJ9JyRpqjYVkyY8KOFRp9VXyphmNcksiBVzqoKGAKc,903
17
+ tde_runtime/release_bundle.py,sha256=g9XmdtIiUfGoluUo40awtQUdXOpghhwWsSN05vZdbdQ,1744
18
+ tde_runtime/release_candidate.py,sha256=G69PalpAZWetHgGE_dpkMq7QG7j85wVl4ku64uriDBQ,3519
19
+ tde_runtime/release_certification.py,sha256=adyZh6EvXQODUIYxxWn9cyjKEosUOJrcXZD5twP66IE,5865
20
+ tde_runtime/release_publication.py,sha256=LUruMnUpa9LWkysfPeaoMTQJ1IZEJaO1o3B4forzass,8318
21
+ tde_runtime/release_qualification.py,sha256=zStbHQDbzExhUOq7Hur0eAHcoDrobeFZ29CHBDyL59E,7076
22
+ tde_runtime/runtime.py,sha256=ccD0psn76VgKL3gWuiVuUzu9ERrqgzdSl7UbjVwBzX8,12918
23
+ tde_runtime/runtime_qualification.py,sha256=edDuGrcZPVUywq7syL8Tx3z_e5A60bJzSyVt3dVNtBs,4075
24
+ tde_runtime/software_assurance.py,sha256=PuHqwtGwV7jrwZFERbQmrdAsq3qYAq2_JWcK9nnTJn8,12669
25
+ tde_runtime/trend.py,sha256=lHI_HhqQ5w-bZrL7KUuRP7_G9zwSRRO1bUSDPe_7k9w,4258
26
+ tde_runtime/trusted_delivery.py,sha256=R1PHQP6l1tcbK3au-3jbVdrdK4SGIqx8SfCY3Rq9emo,8826
27
+ tde_runtime/policies/__init__.py,sha256=BElFqFO-IljGDlnnJsBmc0yfm_FOh3vWRbrnAc7K1EQ,57
28
+ tde_runtime/policies/generation-1.json,sha256=BuhZYZwT9hjRd-hf4vKENwSwy8DRIv_g3aOSRP2TDvU,1224
29
+ technical_debt_engine_runtime-0.1.0.dist-info/METADATA,sha256=CRx_dlxoJUQZ0KwHkhpdhC0ZlWasPHE2PSaXkpcW3HE,151
30
+ technical_debt_engine_runtime-0.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
31
+ technical_debt_engine_runtime-0.1.0.dist-info/entry_points.txt,sha256=Stpn7-vZYlZ8VYVfoscTtV1DRxktV8flogT0tWFl1GE,50
32
+ technical_debt_engine_runtime-0.1.0.dist-info/top_level.txt,sha256=Iz1bgDYbK6v7h3XujaLDy-Or-T3aRDf2BVmdtXlPOys,20
33
+ technical_debt_engine_runtime-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.9.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tde = tde_cli.main:console_main
@@ -0,0 +1,2 @@
1
+ tde_cli
2
+ tde_runtime