diff --git a/openapi.public.json b/openapi.public.json index a148931..de01a8e 100644 --- a/openapi.public.json +++ b/openapi.public.json @@ -1698,6 +1698,13 @@ "description": "The finding's recorded lifecycle state: `NEW`, `UNCHANGED`, `RESOLVED`\n or `REINTRODUCED`.", "type": "string" }, + "local_findings": { + "description": "Earlier occurrences in the author's local reviews linked by exact patch\n identity. These links carry no verdict or finding decision.", + "items": { + "$ref": "#/components/schemas/MatchedLocalFinding" + }, + "type": "array" + }, "placement": { "anyOf": [ { @@ -3674,6 +3681,32 @@ ], "type": "string" }, + "MatchedLocalFinding": { + "description": "A local occurrence with the same semantic fingerprint as this finding.", + "properties": { + "created_at": { + "description": "When the local review was requested.", + "format": "date-time", + "type": "string" + }, + "finding_id": { + "description": "The occurrence in that local review.", + "format": "uuid", + "type": "string" + }, + "review_id": { + "description": "The author's local review, linked by exact patch identity.", + "format": "uuid", + "type": "string" + } + }, + "required": [ + "review_id", + "finding_id", + "created_at" + ], + "type": "object" + }, "NotAssessedView": { "properties": { "environment_display_name": { diff --git a/proofline/_generated/models/__init__.py b/proofline/_generated/models/__init__.py index d66468a..59ec348 100644 --- a/proofline/_generated/models/__init__.py +++ b/proofline/_generated/models/__init__.py @@ -91,6 +91,7 @@ from .gate_status import GateStatus from .local_reverification import LocalReverification from .local_reverification_outcome import LocalReverificationOutcome +from .matched_local_finding import MatchedLocalFinding from .not_assessed_view import NotAssessedView from .occurrence_capture import OccurrenceCapture from .occurrence_question import OccurrenceQuestion @@ -271,6 +272,7 @@ "GateStatus", "LocalReverification", "LocalReverificationOutcome", + "MatchedLocalFinding", "NotAssessedView", "OccurrenceCapture", "OccurrenceQuestion", diff --git a/proofline/_generated/models/customer_finding.py b/proofline/_generated/models/customer_finding.py index b6a79e6..55ea189 100644 --- a/proofline/_generated/models/customer_finding.py +++ b/proofline/_generated/models/customer_finding.py @@ -19,6 +19,7 @@ from ..models.finding_placement_view import FindingPlacementView from ..models.finding_rule_ref_view import FindingRuleRefView from ..models.finding_support import FindingSupport + from ..models.matched_local_finding import MatchedLocalFinding from ..models.thread_observation_view import ThreadObservationView @@ -65,6 +66,9 @@ class CustomerFinding: latest_validation (CustomerFindingValidation | None | Unset): The latest decision on the finding's series, with who made it, where and when. Null when no decision is recorded. + local_findings (list[MatchedLocalFinding] | Unset): Earlier occurrences in the author's local reviews linked by + exact patch + identity. These links carry no verdict or finding decision. placement (FindingPlacementView | None | Unset): Where this review's comment gate placed the finding, as it recorded the placement. Null when the review recorded none. @@ -102,6 +106,7 @@ class CustomerFinding: finding_fingerprint: None | str | Unset = UNSET github_comment_url: None | str | Unset = UNSET latest_validation: CustomerFindingValidation | None | Unset = UNSET + local_findings: list[MatchedLocalFinding] | Unset = UNSET placement: FindingPlacementView | None | Unset = UNSET remediation: None | str | Unset = UNSET supporting_evidence: FindingSupport | None | Unset = UNSET @@ -194,6 +199,13 @@ def to_dict(self) -> dict[str, Any]: else: latest_validation = self.latest_validation + local_findings: list[dict[str, Any]] | Unset = UNSET + if not isinstance(self.local_findings, Unset): + local_findings = [] + for local_findings_item_data in self.local_findings: + local_findings_item = local_findings_item_data.to_dict() + local_findings.append(local_findings_item) + placement: dict[str, Any] | None | Unset if isinstance(self.placement, Unset): placement = UNSET @@ -258,6 +270,8 @@ def to_dict(self) -> dict[str, Any]: field_dict["github_comment_url"] = github_comment_url if latest_validation is not UNSET: field_dict["latest_validation"] = latest_validation + if local_findings is not UNSET: + field_dict["local_findings"] = local_findings if placement is not UNSET: field_dict["placement"] = placement if remediation is not UNSET: @@ -283,6 +297,7 @@ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: from ..models.finding_placement_view import FindingPlacementView # noqa: PLC0415 from ..models.finding_rule_ref_view import FindingRuleRefView # noqa: PLC0415 from ..models.finding_support import FindingSupport # noqa: PLC0415 + from ..models.matched_local_finding import MatchedLocalFinding # noqa: PLC0415 from ..models.thread_observation_view import ThreadObservationView # noqa: PLC0415 d = dict(src_dict) @@ -448,6 +463,15 @@ def _parse_latest_validation(data: object) -> CustomerFindingValidation | None | latest_validation = _parse_latest_validation(d.pop("latest_validation", UNSET)) + _local_findings = d.pop("local_findings", UNSET) + local_findings: list[MatchedLocalFinding] | Unset = UNSET + if _local_findings is not UNSET: + local_findings = [] + for local_findings_item_data in _local_findings: + local_findings_item = MatchedLocalFinding.from_dict(local_findings_item_data) + + local_findings.append(local_findings_item) + def _parse_placement(data: object) -> FindingPlacementView | None | Unset: if data is None: return data @@ -534,6 +558,7 @@ def _parse_validation(data: object) -> None | str | Unset: finding_fingerprint=finding_fingerprint, github_comment_url=github_comment_url, latest_validation=latest_validation, + local_findings=local_findings, placement=placement, remediation=remediation, supporting_evidence=supporting_evidence, diff --git a/proofline/_generated/models/matched_local_finding.py b/proofline/_generated/models/matched_local_finding.py new file mode 100644 index 0000000..2232db3 --- /dev/null +++ b/proofline/_generated/models/matched_local_finding.py @@ -0,0 +1,80 @@ +from __future__ import annotations + +import datetime +from collections.abc import Mapping +from typing import Any, TypeVar +from uuid import UUID + +from attrs import define as _attrs_define +from attrs import field as _attrs_field + +T = TypeVar("T", bound="MatchedLocalFinding") + + +@_attrs_define +class MatchedLocalFinding: + """A local occurrence with the same semantic fingerprint as this finding. + + Attributes: + created_at (datetime.datetime): When the local review was requested. + finding_id (UUID): The occurrence in that local review. + review_id (UUID): The author's local review, linked by exact patch identity. + """ + + created_at: datetime.datetime + finding_id: UUID + review_id: UUID + additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict) + + def to_dict(self) -> dict[str, Any]: + created_at = self.created_at.isoformat() + + finding_id = str(self.finding_id) + + review_id = str(self.review_id) + + field_dict: dict[str, Any] = {} + field_dict.update(self.additional_properties) + field_dict.update( + { + "created_at": created_at, + "finding_id": finding_id, + "review_id": review_id, + } + ) + + return field_dict + + @classmethod + def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T: + d = dict(src_dict) + created_at = datetime.datetime.fromisoformat(d.pop("created_at")) + + finding_id = UUID(d.pop("finding_id")) + + review_id = UUID(d.pop("review_id")) + + matched_local_finding = cls( + created_at=created_at, + finding_id=finding_id, + review_id=review_id, + ) + + matched_local_finding.additional_properties = d + return matched_local_finding + + @property + def additional_keys(self) -> list[str]: + return list(self.additional_properties.keys()) + + def __getitem__(self, key: str) -> Any: + return self.additional_properties[key] + + def __setitem__(self, key: str, value: Any) -> None: + self.additional_properties[key] = value + + def __delitem__(self, key: str) -> None: + del self.additional_properties[key] + + def __contains__(self, key: str) -> bool: + return key in self.additional_properties