|
4 | 4 | from dataclasses import dataclass, field
|
5 | 5 | from datetime import date, datetime
|
6 | 6 | from enum import Enum
|
7 |
| -from typing import Any, ClassVar, Dict, List, Optional, cast |
| 7 | +from typing import Any, ClassVar, Dict, List, Literal, Optional, Type, cast |
8 | 8 | from uuid import UUID
|
9 | 9 |
|
10 | 10 | import marshmallow_dataclass
|
@@ -794,3 +794,179 @@ class JWTService(Enum):
|
794 | 794 | """Enum for the different services GIM can generate a JWT for."""
|
795 | 795 |
|
796 | 796 | HMSL = "hmsl"
|
| 797 | + |
| 798 | + |
| 799 | +@dataclass |
| 800 | +class Detector(Base, FromDictMixin): |
| 801 | + name: str |
| 802 | + display_name: str |
| 803 | + nature: str |
| 804 | + family: str |
| 805 | + detector_group_name: str |
| 806 | + detector_group_display_name: str |
| 807 | + |
| 808 | + |
| 809 | +Severity = Literal["low", "medium", "high", "critical", "unknown"] |
| 810 | +ValidityStatus = Literal["valid", "invalid", "failed_to_check", "no_checker", "unknown"] |
| 811 | +IncidentStatus = Literal["IGNORED", "TRIGGERED", "RESOLVED", "ASSIGNED"] |
| 812 | +Tag = Literal[ |
| 813 | + "DEFAULT_BRANCH", |
| 814 | + "FROM_HISTORICAL_SCAN", |
| 815 | + "CHECK_RUN_SKIP_FALSE_POSITIVE", |
| 816 | + "CHECK_RUN_SKIP_LOW_RISK", |
| 817 | + "CHECK_RUN_SKIP_TEST_CRED", |
| 818 | + "IGNORED_IN_CHECK_RUN", |
| 819 | + "FALSE_POSITIVE", |
| 820 | + "PUBLICLY_EXPOSED", |
| 821 | + "PUBLICLY_LEAKED", |
| 822 | + "REGRESSION", |
| 823 | + "SENSITIVE_FILE", |
| 824 | + "TEST_FILE", |
| 825 | +] |
| 826 | +IgnoreReason = Literal["test_credential", "false_positive", "low_risk"] |
| 827 | +OccurrenceKind = Literal["realtime", "historical"] |
| 828 | +OccurrencePresence = Literal["present", "removed"] |
| 829 | +Visibility = Literal["private", "internal", "public"] |
| 830 | + |
| 831 | + |
| 832 | +@dataclass |
| 833 | +class SecretPresence(Base, FromDictMixin): |
| 834 | + files_requiring_code_fix: int |
| 835 | + files_pending_merge: int |
| 836 | + files_fixed: int |
| 837 | + outside_vcs: int |
| 838 | + removed_outside_vcs: int |
| 839 | + in_vcs: int |
| 840 | + removed_in_vcs: int |
| 841 | + |
| 842 | + |
| 843 | +@dataclass |
| 844 | +class Answer(Base, FromDictMixin): |
| 845 | + type: str |
| 846 | + field_ref: str |
| 847 | + field_label: str |
| 848 | + boolean: Optional[bool] = None |
| 849 | + text: Optional[str] = None |
| 850 | + |
| 851 | + |
| 852 | +@dataclass |
| 853 | +class Feedback(Base, FromDictMixin): |
| 854 | + created_at: datetime |
| 855 | + updated_at: datetime |
| 856 | + member_id: int |
| 857 | + email: str |
| 858 | + answers: List[Answer] |
| 859 | + |
| 860 | + |
| 861 | +@dataclass |
| 862 | +class Source(Base, FromDictMixin): |
| 863 | + id: int |
| 864 | + url: str |
| 865 | + type: str |
| 866 | + full_name: str |
| 867 | + health: Literal["safe", "unknown", "at_risk"] |
| 868 | + default_branch: Optional[str] |
| 869 | + default_branch_head: Optional[str] |
| 870 | + open_incidents_count: int |
| 871 | + closed_incidents_count: int |
| 872 | + secret_incidents_breakdown: Dict[str, Any] # TODO: add SecretIncidentsBreakdown |
| 873 | + visibility: Visibility |
| 874 | + external_id: str |
| 875 | + source_criticality: str |
| 876 | + last_scan: Optional[Dict[str, Any]] # TODO: add LastScan |
| 877 | + monitored: bool |
| 878 | + |
| 879 | + |
| 880 | +@dataclass |
| 881 | +class OccurrenceMatch(Base, FromDictMixin): |
| 882 | + """ |
| 883 | + Describes the match of an occurrence, different from the Match return as part of a PolicyBreak. |
| 884 | +
|
| 885 | + name: type of the match such as "api_key", "password", "client_id", "client_secret"... |
| 886 | + indice_start: start index of the match in the document (0-based) |
| 887 | + indice_end: end index of the match in the document (0-based, strictly greater than indice_start) |
| 888 | + pre_line_start: Optional start line number (1-based) of the match in the document (before the git patch) |
| 889 | + pre_line_end: Optional end line number (1-based) of the match in the document (before the git patch) |
| 890 | + post_line_start: Optional start line number (1-based) of the match in the document (after the git patch) |
| 891 | + post_line_end: Optional end line number (1-based) of the match in the document (after the git patch) |
| 892 | + """ |
| 893 | + |
| 894 | + name: str |
| 895 | + indice_start: int |
| 896 | + indice_end: int |
| 897 | + pre_line_start: Optional[int] |
| 898 | + pre_line_end: Optional[int] |
| 899 | + post_line_start: Optional[int] |
| 900 | + post_line_end: Optional[int] |
| 901 | + |
| 902 | + |
| 903 | +@dataclass |
| 904 | +class SecretOccurrence(Base, FromDictMixin): |
| 905 | + id: int |
| 906 | + incident_id: int |
| 907 | + kind: OccurrenceKind |
| 908 | + source: Source |
| 909 | + author_name: str |
| 910 | + author_info: str |
| 911 | + date: datetime # Publish date |
| 912 | + url: str |
| 913 | + matches: List[OccurrenceMatch] |
| 914 | + tags: List[str] |
| 915 | + sha: Optional[str] # Commit sha |
| 916 | + presence: OccurrencePresence |
| 917 | + filepath: Optional[str] |
| 918 | + |
| 919 | + |
| 920 | +SecretOccurrenceSchema = cast( |
| 921 | + Type[BaseSchema], |
| 922 | + marshmallow_dataclass.class_schema(SecretOccurrence, base_schema=BaseSchema), |
| 923 | +) |
| 924 | +SecretOccurrence.SCHEMA = SecretOccurrenceSchema() |
| 925 | + |
| 926 | + |
| 927 | +@dataclass(repr=False) # the default repr would be too long |
| 928 | +class SecretIncident(Base, FromDictMixin): |
| 929 | + """ |
| 930 | + Secret Incident describes a leaked secret incident. |
| 931 | + """ |
| 932 | + |
| 933 | + id: int |
| 934 | + date: datetime |
| 935 | + detector: Detector |
| 936 | + secret_hash: str |
| 937 | + hmsl_hash: str |
| 938 | + gitguardian_url: str |
| 939 | + regression: bool |
| 940 | + status: IncidentStatus |
| 941 | + assignee_id: Optional[int] |
| 942 | + assignee_email: Optional[str] |
| 943 | + occurrences_count: int |
| 944 | + secret_presence: SecretPresence |
| 945 | + ignore_reason: Optional[IgnoreReason] |
| 946 | + triggered_at: Optional[datetime] |
| 947 | + ignored_at: Optional[datetime] |
| 948 | + ignorer_id: Optional[int] |
| 949 | + ignorer_api_token_id: Optional[UUID] |
| 950 | + resolver_id: Optional[int] |
| 951 | + resolver_api_token_id: Optional[UUID] |
| 952 | + secret_revoked: bool |
| 953 | + severity: Severity |
| 954 | + validity: ValidityStatus |
| 955 | + resolved_at: Optional[datetime] |
| 956 | + share_url: Optional[str] |
| 957 | + tags: List[Tag] |
| 958 | + feedback_list: List[Feedback] |
| 959 | + occurrences: Optional[List[SecretOccurrence]] |
| 960 | + |
| 961 | + def __repr__(self) -> str: |
| 962 | + return ( |
| 963 | + f"id:{self.id}, detector_name:{self.detector.name}," |
| 964 | + f" url:{self.gitguardian_url}" |
| 965 | + ) |
| 966 | + |
| 967 | + |
| 968 | +SecretIncidentSchema = cast( |
| 969 | + Type[BaseSchema], |
| 970 | + marshmallow_dataclass.class_schema(SecretIncident, base_schema=BaseSchema), |
| 971 | +) |
| 972 | +SecretIncident.SCHEMA = SecretIncidentSchema() |
0 commit comments