Skip to content

Commit d0a07a3

Browse files
authored
Merge pull request #7 from crowdsecurity/$main-a24dfe8
Update python SDK version: 1.95.1
2 parents a24dfe8 + 9eb5e39 commit d0a07a3

File tree

13 files changed

+119
-9
lines changed

13 files changed

+119
-9
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2025 Crowdsec
3+
Copyright (c) 2026 Crowdsec
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

crowdsec_tracker_api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@ class Server(Enum):
5252
'Reference',
5353
'ScoreBreakdown',
5454
'Scores',
55+
'SinceOptions',
5556
'SubscribeCVEIntegrationRequest',
57+
'TimelineItem',
5658
'ApiKeyAuth',
5759
'Server',
5860
'Page'
0 Bytes
Binary file not shown.
0 Bytes
Binary file not shown.

crowdsec_tracker_api/models.py

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
# generated by datamodel-codegen:
22
# filename: <stdin>
3-
# timestamp: 2025-12-31T15:56:47+00:00
3+
# timestamp: 2026-01-06T11:14:02+00:00
44

55
from __future__ import annotations
66

77
from datetime import datetime
8-
from enum import StrEnum
8+
from enum import IntEnum, StrEnum
99
from typing import Annotated, Dict, List, Optional, Union
1010

1111
from pydantic import AnyUrl, ConfigDict, Field, RootModel
@@ -418,6 +418,12 @@ class Scores(BaseModelSdk):
418418
last_month: Annotated[ScoreBreakdown, Field(description='Last month scores')]
419419

420420

421+
class SinceOptions(IntEnum):
422+
INTEGER_1 = 1
423+
INTEGER_7 = 7
424+
INTEGER_30 = 30
425+
426+
421427
class SubscribeCVEIntegrationRequest(BaseModelSdk):
422428
model_config = ConfigDict(
423429
extra='forbid',
@@ -427,6 +433,16 @@ class SubscribeCVEIntegrationRequest(BaseModelSdk):
427433
]
428434

429435

436+
class TimelineItem(BaseModelSdk):
437+
timestamp: Annotated[
438+
datetime,
439+
Field(description='Timestamp of the timeline event', title='Timestamp'),
440+
]
441+
count: Annotated[
442+
int, Field(description='Count of occurrences at the timestamp', title='Count')
443+
]
444+
445+
430446
class IntegrationsGetIntegrationsQueryParameters(BaseModelSdk):
431447
tag: Annotated[
432448
Optional[List[str]],
@@ -591,6 +607,19 @@ class CvesUnsubscribeIntegrationFromCvePathParameters(BaseModelSdk):
591607
integration_name: Annotated[str, Field(title='Integration Name')]
592608

593609

610+
class CvesGetCveTimelineQueryParameters(BaseModelSdk):
611+
since_days: Annotated[
612+
Optional[SinceOptions],
613+
Field(
614+
description='Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days.'
615+
),
616+
] = 7
617+
618+
619+
class CvesGetCveTimelinePathParameters(BaseModelSdk):
620+
cve_id: Annotated[str, Field(title='Cve Id')]
621+
622+
594623
class HTTPValidationError(BaseModelSdk):
595624
detail: Annotated[Optional[List[ValidationError]], Field(title='Detail')] = None
596625

Binary file not shown.

crowdsec_tracker_api/services/cves.py

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class Cves(Service):
1313
def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None:
14-
super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_tracker_api/1.95.0")
14+
super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_tracker_api/1.95.1")
1515

1616
def get_cves(
1717
self,
@@ -176,4 +176,29 @@ def unsubscribe_integration_from_cve(
176176
)
177177

178178
return None
179+
180+
def get_cve_timeline(
181+
self,
182+
cve_id: str,
183+
since_days: SinceOptions,
184+
)-> list[TimelineItem]:
185+
endpoint_url = "/cves/{cve_id}/timeline"
186+
loc = locals()
187+
headers = {}
188+
params = json.loads(
189+
CvesGetCveTimelineQueryParameters(**loc).model_dump_json(
190+
exclude_none=True
191+
)
192+
)
193+
path_params = json.loads(
194+
CvesGetCveTimelinePathParameters(**loc).model_dump_json(
195+
exclude_none=True
196+
)
197+
)
198+
199+
response = self.http_client.get(
200+
url=endpoint_url, path_params=path_params, params=params, headers=headers
201+
)
202+
203+
return list[TimelineItem](**response.json())
179204

crowdsec_tracker_api/services/integrations.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class Integrations(Service):
1313
def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None:
14-
super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_tracker_api/1.95.0")
14+
super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_tracker_api/1.95.1")
1515

1616
def get_integrations(
1717
self,

doc/Cves.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
| [get_cve_subscribed_integrations](#get_cve_subscribed_integrations) | Get the list of integrations subscribed to a specific CVE ID |
1111
| [subscribe_integration_to_cve](#subscribe_integration_to_cve) | Subscribe an integration to receive threats related to a specific CVE ID |
1212
| [unsubscribe_integration_from_cve](#unsubscribe_integration_from_cve) | Unsubscribe an integration from receiving threats related to a specific CVE ID |
13+
| [get_cve_timeline](#get_cve_timeline) | Get timeline data of occurrences for a specific CVE ID |
1314

1415
## **get_cves**
1516
### Get a paginated list of CVEs that CrowdSec is tracking
@@ -285,3 +286,41 @@ except HTTPStatusError as e:
285286
print(f"An error occurred: {e.response.status_code} - {e.response.text}")
286287
```
287288

289+
290+
## **get_cve_timeline**
291+
### Get timeline data of occurrences for a specific CVE ID
292+
- Endpoint: `/cves/{cve_id}/timeline`
293+
- Method: `GET`
294+
295+
### Parameters:
296+
| Parameter | Type | Description | Required | Default |
297+
| --------- | ---- | ----------- | -------- | ------- |
298+
| cve_id | str | | True | |
299+
| since_days | SinceOptions | Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days. | False | |
300+
### Returns:
301+
[list[TimelineItem]](./Models.md#list[timelineitem])
302+
### Errors:
303+
| Code | Description |
304+
| ---- | ----------- |
305+
| 404 | CVE Not Found |
306+
| 422 | Validation Error |
307+
### Usage
308+
309+
```python
310+
from crowdsec_tracker_api import (
311+
Cves,
312+
ApiKeyAuth,
313+
)
314+
from httpx import HTTPStatusError
315+
auth = ApiKeyAuth(api_key='your_api_key')
316+
client = Cves(auth=auth)
317+
try:
318+
response = client.get_cve_timeline(
319+
cve_id='cve_id',
320+
since_days=None,
321+
)
322+
print(response)
323+
except HTTPStatusError as e:
324+
print(f"An error occurred: {e.response.status_code} - {e.response.text}")
325+
```
326+

doc/Models.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -463,10 +463,21 @@ overall, last_day, last_week, last_month
463463
| last_week | ScoreBreakdown | None ||
464464
| last_month | ScoreBreakdown | None ||
465465

466+
# **SinceOptions**
467+
466468
# **SubscribeCVEIntegrationRequest**
467469
## Required:
468470
name
469471
## Properties
470472
| Property | Type | Description | Example |
471473
|----------|------|-------------|---------|
472-
| name | str | Name of the integration to subscribe ||
474+
| name | str | Name of the integration to subscribe ||
475+
476+
# **TimelineItem**
477+
## Required:
478+
timestamp, count
479+
## Properties
480+
| Property | Type | Description | Example |
481+
|----------|------|-------------|---------|
482+
| timestamp | str | Timestamp of the timeline event ||
483+
| count | int | Count of occurrences at the timestamp ||

0 commit comments

Comments
 (0)