Skip to content

WIP: Add support for Secret Incidents API endpoints #84

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 7 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ verify_ssl = true

[packages]
pygitguardian = { editable = true, path = "." }
strenum = "*"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding StrEnum here is not required: non-dev dependencies only need to be in setup.py.


[dev-packages]
black = "==22.3.0"
Expand Down
138 changes: 138 additions & 0 deletions pygitguardian/incident_models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
from dataclasses import dataclass, field
from datetime import datetime
from typing import List, Optional, Type, Union, cast

from marshmallow_dataclass import class_schema

from pygitguardian.incident_models.constants import (
IncidentIgnoreReason,
IncidentSeverity,
IncidentStatus,
IncidentTag,
IncidentValidity,
OccurrenceKind,
OccurrencePresence,
)
from pygitguardian.models import Base, BaseSchema, FromDictMixin
from pygitguardian.source_models import Source


@dataclass
class Detector(Base, FromDictMixin):
name: str
display_name: str
nature: str
family: str
detector_group_name: str
detector_group_display_name: str


DetectorSchema = cast(Type[BaseSchema], class_schema(Detector, BaseSchema))
Detector.SCHEMA = DetectorSchema()


@dataclass
class Match(Base, FromDictMixin):
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is already a Match class in models, can we name this one OccurrenceMatch?

name: str
indice_start: int
indice_end: int
pre_line_start: Optional[int]
pre_line_end: Optional[int]
post_line_start: Optional[int]
post_line_end: Optional[int]


MatchSchema = cast(Type[BaseSchema], class_schema(Match, BaseSchema))
Match.SCHEMA = MatchSchema()


@dataclass
class Occurrence(Base, FromDictMixin):
id: int
incident_id: int
kind: OccurrenceKind = field(metadata={"by_value": True})
sha: str
source: Source
author_name: str
author_info: str
date: datetime
presence: OccurrencePresence = field(metadata={"by_value": True})
url: str
matches: List[Match]
filepath: str


OccurrenceSchema = cast(Type[BaseSchema], class_schema(Occurrence, BaseSchema))
Occurrence.SCHEMA = OccurrenceSchema()


@dataclass
class Incident(Base, FromDictMixin):
id: int
date: datetime
detector: Detector
secret_hash: str
gitguardian_url: str
regression: bool
status: IncidentStatus = field(metadata={"by_value": True})
assignee_email: Optional[str]
occurrences_count: int
occurrences: Optional[List[Occurrence]]
ignore_reason: Optional[IncidentIgnoreReason] = field(metadata={"by_value": True})
ignored_at: Optional[datetime]
secret_revoked: bool
severity: IncidentSeverity = field(metadata={"by_value": True})
validity: IncidentValidity = field(metadata={"by_value": True})
resolved_at: Optional[datetime]
share_url: Optional[str]
tags: List[IncidentTag] = field(metadata={"by_value": True})

def __int__(self):
return self.id
Comment on lines +90 to +91
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd rather not have such magic behavior, using .id is simple enough.



IncidentSchema = cast(Type[BaseSchema], class_schema(Incident, BaseSchema))
Incident.SCHEMA = IncidentSchema()


@dataclass
class Link:
url: str
rel: str


@dataclass
class Links:
next: Optional[Link]
prev: Optional[Link]


@dataclass
class ListIncidentResult(Base, FromDictMixin):
incidents: List[Incident]
links: Optional[Links] = None


ListIncidentResultSchema = cast(
Type[BaseSchema], class_schema(ListIncidentResult, BaseSchema)
)
ListIncidentResult.SCHEMA = ListIncidentResultSchema()


@dataclass
class SharedIncidentDetails(Base, FromDictMixin):
incident_id: int
share_url: str
feedback_collection: bool
auto_healing: bool
token: str
expire_at: Optional[datetime] = None
revoked_at: Optional[datetime] = None


SharedIncidentDetailsSchema = cast(
Type[BaseSchema], class_schema(SharedIncidentDetails, BaseSchema)
)
SharedIncidentDetails.SCHEMA = SharedIncidentDetailsSchema()

IncidentIdOrIncident = Union[int, Incident]
70 changes: 70 additions & 0 deletions pygitguardian/incident_models/constants.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
from enum import auto

from strenum import LowercaseStrEnum, MacroCaseStrEnum, SnakeCaseStrEnum, StrEnum


class IncidentIgnoreReason(SnakeCaseStrEnum):
TEST_CREDENTIAL = auto()
FALSE_POSITIVE = auto()
LOW_RISK = auto()


class IncidentOrdering(StrEnum):
DATE_ASC = "date"
DATE_DESC = "-date"
RESOLVED_AT_ASC = "resolved_at"
RESOLVED_AT_DESC = "-resolved_at"
IGNORED_AT_ASC = "ignored_at"
IGNORED_AT_DESC = "-ignored_at"


class IncidentPermission(LowercaseStrEnum):
CAN_VIEW = auto()
CAN_EDIT = auto()
FULL_ACCESS = auto()


class IncidentSeverity(SnakeCaseStrEnum):
CRITICAL = auto()
HIGH = auto()
MEDIUM = auto()
LOW = auto()
INFO = auto()
UNKNOWN = auto()


class IncidentStatus(MacroCaseStrEnum):
IGNORED = auto()
TRIGGERED = auto()
ASSIGNED = auto()
RESOLVED = auto()


class IncidentTag(MacroCaseStrEnum):
DEFAULT_BRANCH = auto()
FROM_HISTORICAL_SCAN = auto()
IGNORED_IN_CHECK_RUN = auto()
PUBLIC = auto()
PUBLICLY_EXPOSED = auto()
PUBLICLY_LEAKED = auto()
REGRESSION = auto()
SENSITIVE_FILE = auto()
TEST_FILE = auto()


class IncidentValidity(SnakeCaseStrEnum):
VALID = auto()
INVALID = auto()
FAILED_TO_CHECK = auto()
NO_CHECKER = auto()
UNKNOWN = auto()


class OccurrenceKind(LowercaseStrEnum):
REALTIME = auto()
HISTORICAL = auto()


class OccurrencePresence(SnakeCaseStrEnum):
present = auto()
removed = auto()
Comment on lines +69 to +70
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you make these values upper-case, like the others?

4 changes: 3 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,10 @@ def get_version() -> str:
install_requires=[
"marshmallow>=3.5, <4",
"requests>=2, <3",
"marshmallow-dataclass >=8.5.8, <8.6.0",
"marshmallow-dataclass[enum,union] >=8.5.8, <8.6.0",
"typing-extensions",
"urllib3<2",
"strenum",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you pin StrEnum to >=0.4, <0.5 (even if you are very close to StrEnum maintainer 😉)?

],
include_package_data=True,
zip_safe=True,
Expand Down