Skip to content

Commit 4402710

Browse files
William ChrispJoshArmi
authored andcommitted
Add git support and remove driver interdependency.
Fix tests with new changes and add full coverage.
1 parent ff670df commit 4402710

File tree

17 files changed

+425
-210
lines changed

17 files changed

+425
-210
lines changed

publisher/drivers/checkov.py

Lines changed: 16 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,55 +1,31 @@
11
from time import time
22
from typing import Tuple, Union
3-
from uuid import uuid4
4-
5-
import structlog
63

74
from publisher.drivers.event_source import EventSource
8-
from publisher.drivers.file_source import FileSource
9-
from publisher.entities.events import Event
10-
from publisher.entities.guardrail import (
5+
from publisher.entities.events import (
6+
Event,
117
GuardrailActivated,
12-
GuardrailActivatedDetail,
138
GuardrailPassed,
14-
GuardrailPassedDetail,
159
)
1610

17-
LOGGER = structlog.get_logger(__name__)
18-
1911

20-
class Checkov(EventSource):
21-
def __init__(self) -> None:
22-
self.file_source = FileSource()
23-
24-
def get_events(self, file: str) -> Union[Exception, Tuple[Event]]:
12+
class Checkov(EventSource):
13+
def get_events(self, file_data: dict, repo_name: str) -> Union[Exception, Tuple[Event]]:
2514
current_time = int(time())
26-
data = self.file_source.read_file(file)
27-
if isinstance(data, Exception):
28-
LOGGER.error(f"Unable to read Checkov results file: {file}", exception=str(data))
29-
return data
3015
events = []
31-
if "results" in data:
32-
for result in data["results"]["passed_checks"]:
33-
events.append(GuardrailPassed(
34-
source = "contino.custom",
35-
detail_type = "Checkov Guardrail Passed",
36-
detail = GuardrailPassedDetail(
37-
aggregate_id = result["resource"], # Will need a better way of getting resource id, current method is not live id
38-
guardrail_id = result["check_id"],
39-
time = current_time,
40-
)
41-
))
42-
for result in data["results"]["failed_checks"]:
16+
if "results" in file_data:
17+
for result in file_data["results"]["passed_checks"]:
18+
events.append(GuardrailPassed(
19+
aggregate_id = repo_name + "." + result["resource"],
20+
guardrail_id = result["check_id"],
21+
time = current_time,
22+
))
23+
for result in file_data["results"]["failed_checks"]:
4324
events.append(GuardrailActivated(
44-
source = "contino.custom",
45-
detail_type = "Checkov Guardrail Activated",
46-
detail = GuardrailActivatedDetail(
47-
aggregate_id = result["resource"], # Will need a better way of getting resource id, current method is not live id
48-
guardrail_id = result["check_id"],
49-
time = current_time,
50-
)
25+
aggregate_id = repo_name + "." + result["resource"],
26+
guardrail_id = result["check_id"],
27+
time = current_time,
5128
))
5229
return tuple(events)
53-
LOGGER.error(f"Unable to read Checkov results from file: {file}")
54-
return Exception(f"Unable to read Checkov results from file: {file}")
30+
return Exception(f"Unable to read Checkov results from file")
5531

publisher/drivers/event_bridge.py

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
11
import json
2-
from typing import Dict, Any, Optional, List, Union
2+
from typing import Dict, Any, List, Union
33

44
import boto3
5-
import structlog
65

76
from publisher.drivers.event_sink import EventSink
87
from publisher.entities.events import Event
98

109

11-
LOGGER = structlog.get_logger(__name__)
12-
13-
1410
class EventBridge(EventSink):
1511
def __init__(self) -> None:
1612
self.event_bridge_client = boto3.client("events")
@@ -22,22 +18,22 @@ def _split_events(self, events: List[Dict[str, Any]]) -> Any:
2218

2319
def _format_events(self, event: Dict) -> Dict:
2420
return {
25-
"Source": event.source,
26-
"DetailType": event.detail_type,
27-
"Detail": json.dumps(event.detail.__dict__),
28-
"EventBusName": event.event_bus_name,
21+
"Source": "contino.flight_controller",
22+
"DetailType": event.event_type,
23+
"Detail": json.dumps(event.__dict__),
24+
"EventBusName": "main_lambda_bus_cdktf",
2925
}
3026

31-
def send_events(self, events: List[Event]) -> Optional[Union[Exception, str]]:
27+
def send_events(self, events: List[Event]) -> Union[Exception, str]:
3228
try:
3329
events = [self._format_events(event) for event in events]
3430
if len(events) > 10:
3531
event_groups = self._split_events(events)
32+
response = []
3633
for event_group in event_groups:
37-
response = self.event_bridge_client.put_events(Entries=event_group)
34+
response.append(self.event_bridge_client.put_events(Entries=event_group))
3835
else:
3936
response = self.event_bridge_client.put_events(Entries=events)
4037
return str(response)
4138
except Exception as err:
4239
return err
43-

publisher/drivers/event_sink.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,5 +6,5 @@
66

77
class EventSink(ABC):
88
@abstractmethod
9-
def send_events(self, events: List[Event]) -> Optional[Union[Exception, str]]:
9+
def send_events(self, events: List[Event]) -> Union[Exception, str]:
1010
raise NotImplementedError() # pragma: no cover

publisher/drivers/event_source.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from abc import ABC, abstractmethod
2-
from typing import Tuple, Union
2+
from typing import Tuple, Union, Optional
33

44
from publisher.entities.events import Event
55

66

77
class EventSource(ABC):
88
@abstractmethod
9-
def get_events(self, file: str) -> Union[Exception, Tuple[Event]]:
9+
def get_events(self, file_data: dict, repo_name: Optional[str]) -> Union[Exception, Tuple[Event]]:
1010
raise NotImplementedError() # pragma: no cover
1111

publisher/drivers/file_source.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import json
2-
from typing import Dict
3-
4-
import structlog
5-
6-
LOGGER = structlog.get_logger(__name__)
2+
from typing import Dict, Union
73

84

95
class FileSource():
10-
def read_file(self, file: str) -> Dict:
6+
def read_file(self, file: str) -> Union[Exception, Dict]:
117
try:
128
with open(file, "r") as file:
139
return json.loads(file.read())
1410
except FileNotFoundError as err:
15-
LOGGER.error(f"File {file} not found!", exception=str(err))
1611
return err
1712
except Exception as err:
18-
LOGGER.error(f"file_source.py raised an exception", exception=str(err))
1913
return err
20-

publisher/drivers/git.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import subprocess
2+
from typing import Union
3+
4+
5+
class Git():
6+
def _check_git_available(self) -> bool:
7+
return subprocess.run(['git', '--version'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL).returncode == 0
8+
9+
def get_repo_name(self) -> Union[Exception, str]:
10+
if self._check_git_available() == True:
11+
try:
12+
repo_name = subprocess.check_output(['git', 'rev-parse', '--show-toplevel'], stderr=subprocess.DEVNULL).strip().decode('utf-8').split('/')[-1]
13+
return repo_name
14+
except Exception as err:
15+
return err
16+
else:
17+
return Exception("Git not available")
Lines changed: 12 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,54 +1,31 @@
11
from time import time
22
from typing import Tuple, Union
33

4-
import structlog
5-
64
from publisher.drivers.event_source import EventSource
7-
from publisher.drivers.file_source import FileSource
8-
from publisher.entities.events import Event
9-
from publisher.entities.guardrail import (
5+
from publisher.entities.events import (
6+
Event,
107
GuardrailActivated,
11-
GuardrailActivatedDetail,
128
GuardrailPassed,
13-
GuardrailPassedDetail,
149
)
1510

16-
LOGGER = structlog.get_logger(__name__)
1711

1812
class OpenPolicyAgent(EventSource):
19-
def __init__(self) -> None:
20-
self.file_source = FileSource()
21-
22-
def get_events(self, file: str) -> Union[Exception, Tuple[Event]]:
13+
def get_events(self, file_data: dict, repo_name: str) -> Union[Exception, Tuple[Event]]:
2314
current_time = int(time())
24-
data = self.file_source.read_file(file)
25-
if isinstance(data, Exception):
26-
LOGGER.error(f"Unable to read Open Policy Agent results file: {file}", exception=str(data))
27-
return data
2815
events = []
29-
if "results" in data:
30-
for result in data["results"]:
16+
if "results" in file_data:
17+
for result in file_data["results"]:
3118
if result["allow"] == True:
3219
events.append(GuardrailPassed(
33-
source = "contino.custom",
34-
detail_type = "Open Policy Agent Guardrail Passed",
35-
detail = GuardrailPassedDetail(
36-
aggregate_id = result["input"]["metadata"]["name"] + "-" + result["input"]["metadata"]["namespace"],
37-
guardrail_id = result["query"],
38-
time = current_time,
39-
)
20+
aggregate_id = repo_name + "." + result["input"]["metadata"]["namespace"] + "." + result["input"]["metadata"]["name"],
21+
guardrail_id = result["query"],
22+
time = current_time,
4023
))
4124
else:
4225
events.append(GuardrailActivated(
43-
source = "contino.custom",
44-
detail_type = "Open Policy Agent Guardrail Activated",
45-
detail = GuardrailActivatedDetail(
46-
aggregate_id = result["input"]["metadata"]["name"] + "-" + result["input"]["metadata"]["namespace"],
47-
guardrail_id = result["query"],
48-
time = current_time,
49-
)
26+
aggregate_id = repo_name + "." + result["input"]["metadata"]["namespace"] + "." + result["input"]["metadata"]["name"],
27+
guardrail_id = result["query"],
28+
time = current_time,
5029
))
5130
return tuple(events)
52-
LOGGER.error(f"Unable to read Open Policy Agent results from file: {file}")
53-
return Exception(f"Unable to read Open Policy Agent results from file: {file}")
54-
31+
return Exception(f"Unable to read Open Policy Agent results from file")

publisher/entities/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from dataclasses import dataclass
2-
from typing import Literal
2+
33

44
# Base event used across all other events
55
@dataclass
66
class BaseEvent:
7-
detail_type: str
7+
aggregate_id: str

publisher/entities/events.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,7 @@
22

33
from publisher.entities.guardrail import (
44
GuardrailActivated,
5-
GuardrailActivatedDetail,
65
GuardrailPassed,
7-
GuardrailPassedDetail,
86
)
97

108

@@ -20,12 +18,6 @@
2018
]
2119

2220

23-
Detail = Union[
24-
GuardrailActivatedDetail,
25-
GuardrailPassedDetail
26-
]
27-
28-
2921
EVENT_CLASSES = {
3022
"guardrail_activated": GuardrailActivated,
3123
"guardrail_passed": GuardrailPassed

publisher/entities/guardrail.py

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,18 @@
11
from dataclasses import dataclass
2-
from typing import Union, Literal
2+
from typing import Literal
33

44
from publisher.entities.base import BaseEvent
55

66

77
@dataclass
8-
class GuardrailActivatedDetail():
9-
aggregate_id: str
8+
class GuardrailActivated(BaseEvent):
109
guardrail_id: str
1110
time: int
1211
event_type: Literal["guardrail_activated"] = "guardrail_activated"
1312

14-
@dataclass
15-
class GuardrailActivated(BaseEvent):
16-
source: str
17-
detail: GuardrailActivatedDetail
18-
event_bus_name: Literal["main_lambda_bus_cdktf"] = "main_lambda_bus_cdktf"
1913

2014
@dataclass
21-
class GuardrailPassedDetail():
22-
aggregate_id: str
15+
class GuardrailPassed(BaseEvent):
2316
guardrail_id: str
2417
time: int
25-
event_type: Literal["guardrail_passed"] = "guardrail_passed"
26-
27-
@dataclass
28-
class GuardrailPassed(BaseEvent):
29-
source: str
30-
detail: GuardrailPassedDetail
31-
event_bus_name: Literal["main_lambda_bus_cdktf"] = "main_lambda_bus_cdktf"
18+
event_type: Literal["guardrail_passed"] = "guardrail_passed"

0 commit comments

Comments
 (0)