pyattackforge 0.2.2__py3-none-any.whl → 0.2.3__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.
- pyattackforge/config.py +1 -1
- pyattackforge/resources/findings.py +3 -0
- pyattackforge/resources/groups.py +15 -0
- pyattackforge/resources/projects.py +5 -0
- {pyattackforge-0.2.2.dist-info → pyattackforge-0.2.3.dist-info}/METADATA +20 -1
- {pyattackforge-0.2.2.dist-info → pyattackforge-0.2.3.dist-info}/RECORD +9 -9
- {pyattackforge-0.2.2.dist-info → pyattackforge-0.2.3.dist-info}/WHEEL +0 -0
- {pyattackforge-0.2.2.dist-info → pyattackforge-0.2.3.dist-info}/licenses/LICENSE +0 -0
- {pyattackforge-0.2.2.dist-info → pyattackforge-0.2.3.dist-info}/top_level.txt +0 -0
pyattackforge/config.py
CHANGED
|
@@ -16,7 +16,7 @@ class ClientConfig:
|
|
|
16
16
|
timeout: float = 30.0
|
|
17
17
|
max_retries: int = 3
|
|
18
18
|
backoff_factor: float = 0.5
|
|
19
|
-
user_agent: str = "pyattackforge/0.2.
|
|
19
|
+
user_agent: str = "pyattackforge/0.2.3"
|
|
20
20
|
http2: bool = True
|
|
21
21
|
# Default visibility for newly created findings. False = pending/hidden.
|
|
22
22
|
default_findings_visible: bool = False
|
|
@@ -36,6 +36,9 @@ class FindingsResource(BaseResource):
|
|
|
36
36
|
def get_vulnerability(self, vulnerability_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
37
37
|
return self._get(f"/api/ss/vulnerability/{vulnerability_id}", params=params)
|
|
38
38
|
|
|
39
|
+
def get_vulnerabilities_by_group(self, group_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
40
|
+
return self._get(f"/api/ss/groups/{group_id}/vulnerabilities", params=params)
|
|
41
|
+
|
|
39
42
|
def get_project_vulnerabilities(self, project_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
40
43
|
return self._get(f"/api/ss/project/{project_id}/vulnerabilities", params=params)
|
|
41
44
|
|
|
@@ -18,3 +18,18 @@ class GroupsResource(BaseResource):
|
|
|
18
18
|
|
|
19
19
|
def get_group(self, group_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
20
20
|
return self._get(f"/api/ss/group/{group_id}", params=params)
|
|
21
|
+
|
|
22
|
+
def update_group(self, group_id: str, payload: Dict[str, Any]) -> Any:
|
|
23
|
+
return self._put(f"/api/ss/group/{group_id}", json=payload)
|
|
24
|
+
|
|
25
|
+
def archive_group(self, group_id: str) -> Any:
|
|
26
|
+
return self._put(f"/api/ss/group/{group_id}/archive")
|
|
27
|
+
|
|
28
|
+
def restore_group(self, group_id: str) -> Any:
|
|
29
|
+
return self._put(f"/api/ss/group/{group_id}/restore")
|
|
30
|
+
|
|
31
|
+
def get_group_projects(self, group_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
32
|
+
return self._get(f"/api/ss/groups/{group_id}/projects", params=params)
|
|
33
|
+
|
|
34
|
+
def get_group_vulnerabilities(self, group_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
35
|
+
return self._get(f"/api/ss/groups/{group_id}/vulnerabilities", params=params)
|
|
@@ -33,6 +33,9 @@ class ProjectsResource(BaseResource):
|
|
|
33
33
|
def get_projects(self, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
34
34
|
return self._get("/api/ss/projects", params=params)
|
|
35
35
|
|
|
36
|
+
def get_projects_by_group(self, group_id: str, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
37
|
+
return self._get(f"/api/ss/groups/{group_id}/projects", params=params)
|
|
38
|
+
|
|
36
39
|
def get_projects_and_vulnerabilities(self, params: Optional[Dict[str, Any]] = None) -> Any:
|
|
37
40
|
return self._get("/api/ss/projects-and-vulnerabilities", params=params)
|
|
38
41
|
|
|
@@ -148,6 +151,8 @@ class ProjectsResource(BaseResource):
|
|
|
148
151
|
project = project["data"]
|
|
149
152
|
if isinstance(project, dict) and isinstance(project.get("project"), dict):
|
|
150
153
|
project = project["project"]
|
|
154
|
+
if not isinstance(project, dict):
|
|
155
|
+
raise ValueError("Project response is not a dict; cannot resolve groups")
|
|
151
156
|
groups = project.get("groups") or project.get("project_groups") or []
|
|
152
157
|
group_ids: List[str] = []
|
|
153
158
|
if isinstance(groups, list):
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pyattackforge
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.3
|
|
4
4
|
Summary: Python SDK for the AttackForge SSAPI
|
|
5
5
|
Author: hackman238
|
|
6
6
|
License: GNU AFFERO GENERAL PUBLIC LICENSE
|
|
@@ -812,6 +812,25 @@ with AttackForgeClient() as client:
|
|
|
812
812
|
client.link_vulnerability_to_testcases("project_id", "vuln_id", ["testcase_id"])
|
|
813
813
|
```
|
|
814
814
|
|
|
815
|
+
Group management (examples):
|
|
816
|
+
|
|
817
|
+
```python
|
|
818
|
+
from pyattackforge import AttackForgeClient
|
|
819
|
+
|
|
820
|
+
with AttackForgeClient() as client:
|
|
821
|
+
group = client.groups.create_group({
|
|
822
|
+
"name": "SDK Group",
|
|
823
|
+
"group_owner": "Owner Name",
|
|
824
|
+
"primary_contact_name": "Owner Name",
|
|
825
|
+
"primary_contact_email": "owner@example.com",
|
|
826
|
+
"primary_contact_number": "0000000000",
|
|
827
|
+
})
|
|
828
|
+
group_id = group.get("group_id") or group.get("id")
|
|
829
|
+
client.projects.add_project_to_group("project_id", group_id)
|
|
830
|
+
client.groups.get_group_projects(group_id)
|
|
831
|
+
client.groups.get_group_vulnerabilities(group_id)
|
|
832
|
+
```
|
|
833
|
+
|
|
815
834
|
## Testing
|
|
816
835
|
|
|
817
836
|
Unit tests:
|
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
pyattackforge/__init__.py,sha256=ebRH36uyrbMl6C4H9JejeW0cA6S9xTTzScyD69I0Jso,97
|
|
2
2
|
pyattackforge/cache.py,sha256=zTGWzL4F6n4u6opCNCi0CYkkSWPx5ShZMVmDagMpPQ0,933
|
|
3
3
|
pyattackforge/client.py,sha256=C_nCWuQByRr3GwZVIVUjdsrNA5j-Gv0ttkqig1GkwFg,5664
|
|
4
|
-
pyattackforge/config.py,sha256=
|
|
4
|
+
pyattackforge/config.py,sha256=m6Fpqj8JUGbeWG5SXLIXZR-yO0YYvYxCd3ahWNiH5TI,2240
|
|
5
5
|
pyattackforge/exceptions.py,sha256=YFzV7VQ3UkOGXKpHhXctuM7fZUtR4LgYuPR_po4pksA,592
|
|
6
6
|
pyattackforge/transport.py,sha256=slYM9zqleyWlTiUpZZfF0CVB95I0u8UMkqsK09Qa9W4,6500
|
|
7
7
|
pyattackforge/resources/__init__.py,sha256=Tim25zMXM8FoprSyh_r2PJQjouWUq4FxfqMvNT6RI_g,646
|
|
8
8
|
pyattackforge/resources/assets.py,sha256=cVe4PrLp3Afxv52SBekQZaiDvQpV7zCKN6bLkUHl-uA,1420
|
|
9
9
|
pyattackforge/resources/base.py,sha256=x5C8SG2MfwCtOkcRi8plDTF6TkJqXz-b58KS4qkP0Zw,1286
|
|
10
|
-
pyattackforge/resources/findings.py,sha256=
|
|
11
|
-
pyattackforge/resources/groups.py,sha256=
|
|
10
|
+
pyattackforge/resources/findings.py,sha256=KjCKUqdffL8-5j4I0srxNgpjR3gLbfck_WQKyX04FEE,34341
|
|
11
|
+
pyattackforge/resources/groups.py,sha256=RR1kWW0kBPT6QPoV0pD59X-tnu5ViP_cTjLE9p7ghaA,1358
|
|
12
12
|
pyattackforge/resources/notes.py,sha256=r-TR3QuatrhGzwmoR7AQt7wiHXTrvmMvm7rYtkBCOkQ,5741
|
|
13
|
-
pyattackforge/resources/projects.py,sha256=
|
|
13
|
+
pyattackforge/resources/projects.py,sha256=i9IU4yObv4u4hmcmg7aiXrucsLw966ywhpEBILYx2XE,9201
|
|
14
14
|
pyattackforge/resources/reports.py,sha256=43wDK8SB2qqz-tjerjFBOV4G9EcgLk5WL3O8H-On5b0,805
|
|
15
15
|
pyattackforge/resources/users.py,sha256=8SF_3QdNQalsyU-60V_oJtsJbo6nHkI3WPbCBebEkrk,2275
|
|
16
16
|
pyattackforge/resources/writeups.py,sha256=iBShGQFrwYie3Gx8F0ekSOW0rf_ZzziRDsRpdQYUsSg,3001
|
|
17
|
-
pyattackforge-0.2.
|
|
18
|
-
pyattackforge-0.2.
|
|
19
|
-
pyattackforge-0.2.
|
|
20
|
-
pyattackforge-0.2.
|
|
21
|
-
pyattackforge-0.2.
|
|
17
|
+
pyattackforge-0.2.3.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
|
|
18
|
+
pyattackforge-0.2.3.dist-info/METADATA,sha256=xiUYFVZ9dJcefPjZGtK_yx8OCJ-HvjnNP2FqSr3TR40,46741
|
|
19
|
+
pyattackforge-0.2.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
20
|
+
pyattackforge-0.2.3.dist-info/top_level.txt,sha256=1rDeMkWvFWuX3MS8V65no7KuybYyvtfIgbYSt5m_uPU,14
|
|
21
|
+
pyattackforge-0.2.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|