From d5785610e25ca0e8e60d61083df301b87688b1b6 Mon Sep 17 00:00:00 2001 From: nitescuc <1108077+nitescuc@users.noreply.github.com> Date: Wed, 8 Jul 2026 08:44:40 +0000 Subject: [PATCH] Update python SDK 1.133.1 --- crowdsec_service_api/__init__.py | 9 +- .../__pycache__/__init__.cpython-311.pyc | Bin 5024 -> 5171 bytes .../__pycache__/base_model.cpython-311.pyc | Bin 4378 -> 4378 bytes .../__pycache__/http_client.cpython-311.pyc | Bin 7768 -> 7768 bytes .../__pycache__/models.cpython-311.pyc | Bin 158635 -> 166723 bytes crowdsec_service_api/models.py | 415 +++++-- .../__pycache__/__init__.cpython-311.pyc | Bin 207 -> 207 bytes .../__pycache__/allowlists.cpython-311.pyc | Bin 12917 -> 12917 bytes .../__pycache__/blocklists.cpython-311.pyc | Bin 15121 -> 15121 bytes .../services/__pycache__/cves.cpython-311.pyc | Bin 12321 -> 12364 bytes .../__pycache__/decisions.cpython-311.pyc | Bin 4338 -> 7222 bytes .../__pycache__/fingerprints.cpython-311.pyc | Bin 12310 -> 12353 bytes .../services/__pycache__/hub.cpython-311.pyc | Bin 3277 -> 3277 bytes .../services/__pycache__/info.cpython-311.pyc | Bin 2035 -> 2035 bytes .../__pycache__/integrations.cpython-311.pyc | Bin 8075 -> 8075 bytes .../__pycache__/metrics.cpython-311.pyc | Bin 2607 -> 2607 bytes .../__pycache__/products.cpython-311.pyc | Bin 3782 -> 3782 bytes .../tracker_events.cpython-311.pyc | Bin 2914 -> 2914 bytes .../__pycache__/tracker_tags.cpython-311.pyc | Bin 5698 -> 5698 bytes .../__pycache__/vendors.cpython-311.pyc | Bin 10351 -> 10351 bytes crowdsec_service_api/services/allowlists.py | 2 +- crowdsec_service_api/services/blocklists.py | 2 +- crowdsec_service_api/services/cves.py | 3 +- crowdsec_service_api/services/decisions.py | 80 +- crowdsec_service_api/services/fingerprints.py | 3 +- crowdsec_service_api/services/hub.py | 2 +- crowdsec_service_api/services/info.py | 2 +- crowdsec_service_api/services/integrations.py | 2 +- crowdsec_service_api/services/metrics.py | 2 +- crowdsec_service_api/services/products.py | 2 +- .../services/tracker_events.py | 2 +- crowdsec_service_api/services/tracker_tags.py | 2 +- crowdsec_service_api/services/vendors.py | 2 +- doc/Blocklists.md | 9 +- doc/Cves.md | 6 +- doc/Decisions.md | 152 ++- doc/Fingerprints.md | 6 +- doc/Models.md | 105 +- doc/README.md | 16 +- public-openapi.json | 1069 ++++++++++++++--- pyproject.toml | 2 +- uv.lock | 26 +- 42 files changed, 1579 insertions(+), 342 deletions(-) diff --git a/crowdsec_service_api/__init__.py b/crowdsec_service_api/__init__.py index f2c57ce..d57f24c 100644 --- a/crowdsec_service_api/__init__.py +++ b/crowdsec_service_api/__init__.py @@ -33,6 +33,10 @@ class Server(Enum): 'TrackerTags', 'Fingerprints', 'TrackerEvents', + 'AggregatedDecisionItem', + 'AggregatedDecisionsGetResponse', + 'AggregatedDecisionsGetResponsePage', + 'AggregatedDecisionsSortBy', 'AllowlistCreateRequest', 'AllowlistCreateResponse', 'AllowlistGetItemsResponse', @@ -84,6 +88,8 @@ class Server(Enum): 'CtiScenario', 'DecisionCreateRequest', 'DecisionCreateResponse', + 'DecisionMachineState', + 'DecisionMachineStateEnum', 'DecisionResponse', 'DecisionTargetModel', 'DecisionTargetType', @@ -138,7 +144,7 @@ class Server(Enum): 'Behavior', 'CVEEventOutput', 'CVEExploitationPhase', - 'CVEResponseBase', + 'CVEResponseDetailed', 'CVEsubscription', 'CWE', 'Classification', @@ -149,7 +155,6 @@ class Server(Enum): 'FacetBucket', 'FingerprintEventOutput', 'FingerprintRuleResponse', - 'FingerprintRuleSummary', 'FingerprintTimelineItem', 'GetCVEIPsResponsePage', 'GetCVEProtectRulesResponse', diff --git a/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc b/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc index 2db00239d7de4999aa3c5ce54bc923355cb316a5..7abbb28e49c1427a364461a416f21a99015d449b 100644 GIT binary patch delta 249 zcmZ3WzFC8BIWI340}y=R^~=f?-N?tm%(!i`IJ1jmdU{c6dSXdxic4y8W^rbIo@YsF z?kzb?@nZMXlAzS$g8aPV)LTjj`N^^zl2VcgKFplr;QXQzr^?L{%$+RyA}~?k#N>?3 zywudPHM{JgWT6Pujk2OWxTdoMktd} Ux}1rd=>r3TY+wh$A{n4x0pwp+ivR!s delta 124 zcmdn2u|S<~IWI340|=CAW$h8!$j8CVxN)*Lv&-g7%xx^2J2);d3-CLKxdx>c7v$#^ zr#dATr%uk{xh5{=mYJ8HT2xS!nO722nv)t_nwy(gRJqxaH)C- diff --git a/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc b/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc index 1bc5815900c09dcc5d59b8b7d1636dda5e5ee5f9..058ea6559e595138c7ada5b46ca2b548e17927b1 100644 GIT binary patch delta 20 acmca%bHj#vIWI340}wpm_1nnpD+d5Tbp>Gn delta 20 acmca%bHj#vIWI340}wnd(b~xED+d5VP6ep| diff --git a/crowdsec_service_api/__pycache__/models.cpython-311.pyc b/crowdsec_service_api/__pycache__/models.cpython-311.pyc index 6ec2ace3e093ffc22a4a8f92ab2f5aa7fa9fef13..ddfe8f5bbbb88af5cf541d77d20b058345331a11 100644 GIT binary patch delta 38068 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 K;t(P$>i+;Y-kzZV diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index d2625ae..4d75648 100644 --- a/crowdsec_service_api/models.py +++ b/crowdsec_service_api/models.py @@ -1,6 +1,6 @@ # generated by datamodel-codegen: # filename: -# timestamp: 2026-06-11T08:42:40+00:00 +# timestamp: 2026-07-08T08:44:32+00:00 from __future__ import annotations @@ -13,6 +13,27 @@ from .base_model import BaseModelSdk, RootModelSdk +class Total(RootModelSdk[int]): + root: Annotated[int, Field(ge=0, title='Total')] + + +class Page(RootModelSdk[int]): + root: Annotated[int, Field(ge=1, title='Page')] + + +class Size(RootModelSdk[int]): + root: Annotated[int, Field(ge=1, title='Size')] + + +class Pages(RootModelSdk[int]): + root: Annotated[int, Field(ge=0, title='Pages')] + + +class AggregatedDecisionsSortBy(StrEnum): + FIRST_CREATED_AT = 'first_created_at' + FIRST_EXPIRATION = 'first_expiration' + + class AllowlistCreateRequest(BaseModelSdk): model_config = ConfigDict( extra='forbid', @@ -76,22 +97,6 @@ class AllowlistCreateResponse(BaseModelSdk): ] -class Total(RootModelSdk[int]): - root: Annotated[int, Field(ge=0, title='Total')] - - -class Page(RootModelSdk[int]): - root: Annotated[int, Field(ge=1, title='Page')] - - -class Size(RootModelSdk[int]): - root: Annotated[int, Field(ge=1, title='Size')] - - -class Pages(RootModelSdk[int]): - root: Annotated[int, Field(ge=0, title='Pages')] - - class AllowlistItemUpdateRequest(BaseModelSdk): model_config = ConfigDict( extra='forbid', @@ -244,6 +249,13 @@ class BlocklistCreateRequest(BaseModelSdk): tags: Annotated[ Optional[List[str]], Field(description='Classification tags', title='Tags') ] = [] + store_full_content_in_s3: Annotated[ + Optional[bool], + Field( + description='Whether to store the full blocklist content in S3 or not', + title='Store Full Content In S3', + ), + ] = False class BlocklistDeleteIPsRequest(BaseModelSdk): @@ -420,6 +432,12 @@ class DecisionCreateResponse(BaseModelSdk): ] +class DecisionMachineStateEnum(StrEnum): + PENDING_CREATE = 'PENDING_CREATE' + PENDING_DELETE = 'PENDING_DELETE' + APPLIED = 'APPLIED' + + class DecisionTargetType(StrEnum): ORG = 'org' TAG = 'tag' @@ -1380,7 +1398,7 @@ class BlocklistsUploadBlocklistContentQueryParameters(BaseModelSdk): Optional[datetime], Field( description='Blocklist expiration', - examples=['2026-06-11T08:40:13.370581+00:00'], + examples=['2026-07-08T08:42:28.511313+00:00'], title='Expiration', ), ] = None @@ -1587,6 +1605,12 @@ class IntegrationsGetIntegrationContentStreamPathParameters(BaseModelSdk): class DecisionsGetDecisionsQueryParameters(BaseModelSdk): + page: Annotated[ + Optional[int], Field(description='Page number', ge=1, title='Page') + ] = 1 + size: Annotated[ + Optional[int], Field(description='Page size', ge=1, le=100, title='Size') + ] = 50 instance_ids: Annotated[ Optional[List[str]], Field( @@ -1619,6 +1643,30 @@ class DecisionsGetDecisionsQueryParameters(BaseModelSdk): title='Ips', ), ] = [] + alert_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by associated alert IDs', + examples=[['alert-abc123', 'alert-def456']], + title='Alert Ids', + ), + ] = [] + decision_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by decision IDs', + examples=[['dec-abc123', 'dec-def456']], + title='Decision Ids', + ), + ] = [] + created_at_from: Annotated[ + Optional[datetime], + Field( + description='Filter decisions created after this date (inclusive)', + examples=['2023-01-01T00:00:00Z'], + title='Created At From', + ), + ] = None sort_by: Annotated[ Optional[DecisionsSortBy], Field( @@ -1635,15 +1683,99 @@ class DecisionsGetDecisionsQueryParameters(BaseModelSdk): title='Sort Order', ), ] = 'desc' + + +class DecisionsDeleteDecisionPathParameters(BaseModelSdk): + decision_id: Annotated[str, Field(title='Decision Id')] + + +class DecisionsGetAggregatedDecisionsQueryParameters(BaseModelSdk): page: Annotated[ Optional[int], Field(description='Page number', ge=1, title='Page') ] = 1 size: Annotated[ Optional[int], Field(description='Page size', ge=1, le=100, title='Size') ] = 50 + instance_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by instance IDs', + examples=[['inst-abc123', 'inst-def456']], + title='Instance Ids', + ), + ] = [] + tag_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by tag IDs', + examples=[['tag-001', 'tag-002']], + title='Tag Ids', + ), + ] = [] + remediation_types: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by remediation types', + examples=[['ban', 'captcha']], + title='Remediation Types', + ), + ] = [] + ips: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by IPs (only for IP decisions)', + examples=[['203.0.113.7', '198.51.100.42']], + title='Ips', + ), + ] = [] + alert_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by associated alert IDs', + examples=[['alert-abc123', 'alert-def456']], + title='Alert Ids', + ), + ] = [] + decision_ids: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by decision IDs', + examples=[['dec-abc123', 'dec-def456']], + title='Decision Ids', + ), + ] = [] + created_at_from: Annotated[ + Optional[datetime], + Field( + description='Filter decisions created after this date (inclusive)', + examples=['2023-01-01T00:00:00Z'], + title='Created At From', + ), + ] = None + sort_by: Annotated[ + Optional[AggregatedDecisionsSortBy], + Field( + description='Field to sort by (e.g., created_at, duration)', + examples=['created_at'], + title='Sort By', + ), + ] = 'first_created_at' + sort_order: Annotated[ + Optional[DecisionsSortOrder], + Field( + description="Sort order: 'asc' for ascending, 'desc' for descending", + examples=['desc'], + title='Sort Order', + ), + ] = 'desc' -class DecisionsDeleteDecisionPathParameters(BaseModelSdk): +class DecisionsDeleteAggregatedDecisionsPathParameters(BaseModelSdk): + aggregated_id: Annotated[str, Field(title='Aggregated Id')] + + +class DecisionsDeleteAggregatedDecisionItemPathParameters(BaseModelSdk): + aggregated_id: Annotated[str, Field(title='Aggregated Id')] decision_id: Annotated[str, Field(title='Decision Id')] @@ -1749,6 +1881,14 @@ class CvesGetCvesQueryParameters(BaseModelSdk): title='Exploitation Phase', ), ] = None + detailed: Annotated[ + Optional[bool], + Field( + description='Include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE in the list. Defaults to false to keep the response lightweight.', + examples=[True], + title='Detailed', + ), + ] = False page: Annotated[ Optional[int], Field(description='Page number', ge=1, title='Page') ] = 1 @@ -2177,6 +2317,14 @@ class FingerprintsGetFingerprintRulesQueryParameters(BaseModelSdk): title='Sort Order', ), ] = 'desc' + detailed: Annotated[ + Optional[bool], + Field( + description='Include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each fingerprint rule in the list. Defaults to false to keep the response lightweight.', + examples=[True], + title='Detailed', + ), + ] = False page: Annotated[ Optional[int], Field(description='Page number', ge=1, title='Page') ] = 1 @@ -2647,6 +2795,16 @@ class BlocklistSubscriptionRequest(BaseModelSdk): ] = None +class DecisionMachineState(BaseModelSdk): + timestamp: Annotated[ + datetime, + Field(description='Date of when the state has been set', title='Timestamp'), + ] + state: Annotated[ + DecisionMachineStateEnum, Field(description='State of the decision') + ] + + class DecisionTargetModel(BaseModelSdk): type: Annotated[ DecisionTargetType, Field(description='Type of the decision target') @@ -3728,7 +3886,7 @@ class ScenarioIndex(BaseModelSdk): ] = None -class CVEResponseBase(BaseModelSdk): +class CVEResponseDetailed(BaseModelSdk): id: Annotated[str, Field(description='ID of the CVE', title='Id')] name: Annotated[str, Field(description='Name of the CVE', title='Name')] title: Annotated[str, Field(description='Title of the CVE', title='Title')] @@ -3808,6 +3966,29 @@ class CVEResponseBase(BaseModelSdk): description='Threat context (attacker/defender countries, industries, objectives)' ), ] = None + tags: Annotated[ + Optional[List[str]], + Field(description='Tags associated with the CVE', title='Tags'), + ] = None + references: Annotated[ + Optional[List[str]], + Field(description='List of references for the CVE', title='References'), + ] = None + description: Annotated[ + Optional[str], Field(description='Description of the CVE', title='Description') + ] = None + crowdsec_analysis: Annotated[ + Optional[str], + Field(description='CrowdSec analysis of the CVE', title='Crowdsec Analysis'), + ] = None + cwes: Annotated[ + Optional[List[CWE]], + Field(description='List of CWEs associated with the CVE', title='Cwes'), + ] = None + events: Annotated[ + Optional[List[CVEEventOutput]], + Field(description='List of events related to the CVE', title='Events'), + ] = None class FingerprintRuleResponse(BaseModelSdk): @@ -3892,61 +4073,6 @@ class FingerprintRuleResponse(BaseModelSdk): ] = None -class FingerprintRuleSummary(BaseModelSdk): - id: Annotated[str, Field(description='Fingerprint rule identifier', title='Id')] - name: Annotated[str, Field(description='Fingerprint rule name', title='Name')] - title: Annotated[str, Field(description='Fingerprint rule title', title='Title')] - affected_components: Annotated[ - List[AffectedComponent], - Field(description='List of affected components', title='Affected Components'), - ] - crowdsec_score: Annotated[ - int, - Field( - description='Live Exploit Tracker score for the fingerprint rule', - ge=0, - le=10, - title='Crowdsec Score', - ), - ] - opportunity_score: Annotated[ - Optional[int], - Field(description='Opportunity score', ge=0, le=5, title='Opportunity Score'), - ] = 0 - momentum_score: Annotated[ - Optional[int], - Field(description='Momentum score', ge=0, le=5, title='Momentum Score'), - ] = 0 - first_seen: Annotated[ - Optional[datetime], Field(description='First seen date', title='First Seen') - ] = None - last_seen: Annotated[ - Optional[datetime], Field(description='Last seen date', title='Last Seen') - ] = None - nb_ips: Annotated[ - int, Field(description='Number of unique IPs observed', ge=0, title='Nb Ips') - ] - rule_release_date: Annotated[ - Optional[datetime], - Field( - description='Release date of the fingerprint rule', - title='Rule Release Date', - ), - ] = None - exploitation_phase: Annotated[ - ExploitationPhase, Field(description='Current exploitation phase') - ] - adjustment_score: Annotated[ - Optional[AdjustmentScore], Field(description='Score adjustment details') - ] = None - threat_context: Annotated[ - Optional[ThreatContext], - Field( - description='Threat context (attacker/defender countries, industries, objectives)' - ), - ] = None - - class GetCVEResponse(BaseModelSdk): id: Annotated[str, Field(description='ID of the CVE', title='Id')] name: Annotated[str, Field(description='Name of the CVE', title='Name')] @@ -4062,7 +4188,7 @@ class GetCVESubscribedIntegrationsResponsePage(BaseModelSdk): class GetCVEsResponsePage(BaseModelSdk): - items: Annotated[List[CVEResponseBase], Field(title='Items')] + items: Annotated[List[CVEResponseDetailed], Field(title='Items')] total: Annotated[int, Field(ge=0, title='Total')] page: Annotated[int, Field(ge=1, title='Page')] size: Annotated[int, Field(ge=1, title='Size')] @@ -4071,7 +4197,7 @@ class GetCVEsResponsePage(BaseModelSdk): class GetFingerprintRulesResponsePage(BaseModelSdk): - items: Annotated[List[FingerprintRuleSummary], Field(title='Items')] + items: Annotated[List[FingerprintRuleResponse], Field(title='Items')] total: Annotated[int, Field(ge=0, title='Total')] page: Annotated[int, Field(ge=1, title='Page')] size: Annotated[int, Field(ge=1, title='Size')] @@ -4398,6 +4524,141 @@ class ProtectRule(BaseModelSdk): ] = None +class AggregatedDecisionItem(BaseModelSdk): + id: Annotated[ + str, Field(description='ID of the decision aggregated item', title='Id') + ] + first_created_at: Annotated[ + datetime, + Field( + description='Creation date of the first decision in the group', + title='First Created At', + ), + ] + last_created_at: Annotated[ + datetime, + Field( + description='Creation date of the last decision in the group', + title='Last Created At', + ), + ] + origin: Annotated[str, Field(description='Origin of the decision', title='Origin')] + scenario: Annotated[ + str, Field(description='Scenario of the decision', title='Scenario') + ] + min_duration: Annotated[ + str, + Field( + description='Min duration in the group of decisions', title='Min Duration' + ), + ] + max_duration: Annotated[ + str, + Field( + description='Max durations in the group of decisions', title='Max Duration' + ), + ] + first_expiration: Annotated[ + datetime, + Field( + description='First expiration date in the group of decisions', + title='First Expiration', + ), + ] + last_expiration: Annotated[ + datetime, + Field( + description='Last expiration date in the group of decisions', + title='Last Expiration', + ), + ] + count: Annotated[ + int, Field(description='Number of decisions in the group', title='Count') + ] + machines: Annotated[ + Dict[str, DecisionMachineState], + Field( + description='Machines object (the instance ID is the key) with the decision status and timestamp', + title='Machines', + ), + ] + target: Annotated[DecisionTargetModel, Field(description='Target of the decision')] + + +class AggregatedDecisionsGetResponse(BaseModelSdk): + id: Annotated[ + str, Field(description='ID of the decision aggregated item', title='Id') + ] + scope: Annotated[str, Field(description='Scope of the decision', title='Scope')] + type: Annotated[str, Field(description='Type of the decision', title='Type')] + value: Annotated[str, Field(description='Value of the decision', title='Value')] + country: Annotated[ + Optional[str], + Field(description='Country associated with the decision', title='Country'), + ] = None + as_name: Annotated[ + Optional[str], + Field(description='AS name associated with the decision', title='As Name'), + ] = None + as_num: Annotated[ + Optional[int], + Field(description='AS number associated with the decision', title='As Num'), + ] = None + city: Annotated[ + Optional[str], + Field(description='City associated with the decision', title='City'), + ] = None + latitude: Annotated[ + Optional[float], + Field(description='Latitude associated with the decision', title='Latitude'), + ] = None + longitude: Annotated[ + Optional[float], + Field(description='Longitude associated with the decision', title='Longitude'), + ] = None + first_created_at: Annotated[ + Optional[datetime], + Field( + description='Creation date of the first decision in the group', + title='First Created At', + ), + ] = None + last_created_at: Annotated[ + Optional[datetime], + Field( + description='Creation date of the last decision in the group', + title='Last Created At', + ), + ] = None + first_expiration: Annotated[ + Optional[datetime], + Field( + description='Expiration date of the first decision in the group', + title='First Expiration', + ), + ] = None + last_expiration: Annotated[ + Optional[datetime], + Field( + description='Expiration date of the last decision in the group', + title='Last Expiration', + ), + ] = None + decisions: Annotated[ + List[AggregatedDecisionItem], + Field(description='List of decisions in the group', title='Decisions'), + ] + + +class AggregatedDecisionsGetResponsePage(BaseModelSdk): + items: Annotated[List[AggregatedDecisionsGetResponse], Field(title='Items')] + total: Annotated[Optional[Total], Field(title='Total')] = None + page: Annotated[Optional[Page], Field(title='Page')] = None + size: Annotated[Optional[Size], Field(title='Size')] = None + pages: Annotated[Optional[Pages], Field(title='Pages')] = None + links: Links + + class AllowlistGetItemsResponse(BaseModelSdk): id: Annotated[ str, diff --git a/crowdsec_service_api/services/__pycache__/__init__.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/__init__.cpython-311.pyc index 03cc6cd2b678c4bb7fde146020819a3126108035..78d2ea3077659e02794dead9025378e6d7d66e93 100644 GIT binary patch delta 19 ZcmX@lc%G4aIWI340}wpm^_$3j1OPG-1rh)N delta 19 ZcmX@lc%G4aIWI340}wnd(VED81OPLl1zG?A diff --git a/crowdsec_service_api/services/__pycache__/allowlists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/allowlists.cpython-311.pyc index 43c12d0fa29acc733d3ff5413d13fc4bbf224419..34d0231131bc97522b72d389cfbcfec38982adde 100644 GIT binary patch delta 30 kcmeyG@->BfIWI340}y=R_1nmuz|3N7tY^46pP5Y`0FllJ761SM delta 30 jcmeyG@->BfIWI340|=CAZRAd1W-+qRGuWKZ%%%?jhFb@1 diff --git a/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc index d87cdb1bac7f4880ebeb44a85f3d6e4d5ffdd4cb..fe618de81f71e4ef742233ee95811def2e3ad77d 100644 GIT binary patch delta 30 kcmbPOHnEI*IWI340}y=R_1nn(fSJYESkG|tduAnb0EboxmH+?% delta 30 jcmbPOHnEI*IWI340|=CAZRCEy%wlArXR!G_vywRgd*cV~ diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc index 7d05d919d947b7bbc0e723946bb4f0ca957ad427..562a3acad6bb57b8c96eb8ea178464cd137e2bb8 100644 GIT binary patch delta 2165 zcma)8Uuaup6u)13^SAdVO`5+=(xy$?{OOw7wY4^N8?41fv>RIsZpC%0{l1KpvHuPgCH`b4x_%=33&<8=rJmdT z-1D8^Ip;g~l8p;LUy#3$Ws?9`Nj@<@zA29puN5g=fBr@U;hJz$V8S$^!nB5V@(f9? z(Z-aXO3c7SPsI_C%D{Cs+zeb_!!5v#HN1(LsFgKR8+=73rJ88-RqeD)?Mwu2PKnfU zRh+i`$D4pVfm?yEp@Rqp7Z_|t0Y9`$b@V)yR8^okWuh%0UzJRlRXYIT zIv`v?^$fChD9X<|YVPZ32%-hog)3w_G$}-5{P~8T#Qy$xU!g&C5b_dtYe!rL%JQ@6 z45LLcH+zv4#ijI{Y|g;T7Q4v==XX<}WYxfL7`$3zT39vljdmA*EK5A+6^W6TT_f5? zuuEL_1$zxE(n{ls>1*+GQ4qd@Z{=E*^Ol`89JP*WSA;ZKk$I`Ho4>33j+l8u9~@F5 z;8c{@BF$yfi}~}HluWT9lbutZ1H00T5JwM#!j^K`#U-|61{&bk^+TdvaJTWzh^w%z z|B?7&=z9p^FhJCx^y7K}VUYh|Y~_!FMvXGe9~ixD$Iv>0@FGIJmU4uDBRP4(~bbMOJSz8{xjs;!i-=3UytjxuC)!K)<985S%&3V)L2nd zg&0cir3NBphl@7_lH`}d*}#}aSD7CEq-#|Ck|>AygN`)$hff6uZM!@p9|xnAu6OWH zf_DCU(2}T36lm_0tR@k}B<2suBpezee-tvI_iM5k3ol?SQk16B3oMgfWH0C0f|3Q} zk_I3UP<$9x;q&1*vGWhZ1G^=9KOBZB)JM7otNGP7=`zMRph?S-2zksujXbhVpmzYF z9Uw}S3BD0+CY}6tG?x_L$Y$Y%1aBrKfi6c8jw6gAj3XowUPU;KFp2OQ!Wo2f2s8X* zETp5jO!E(7-K~qbyaZ5`Cew>^>|`#VhPRutjP?~?jP;W_ZtlLk=4riWcigi(OIEjb zjFbe#ZHwzx!+WbGt!mNTPuX2On@Za_KY}w-_qiQe-{?5Cd!&|;YsZljZ zLbIzRt4p(Bv6U?9vI&OSMVPIjM$U7 en{e*#z4J;^B*!7+y?@q+%9Xo+?c=2QA@0A%JjR3o delta 2187 zcma)6TWlLe6rFL_Z*SIi>^M&RO6=I)Je+5n<|#;`rYJmAT8glsB+8Ddi<7u(rwY_j zS`mpL@t%*C9}pjRPn*wafoiqp77;uN9Zzr_f>j4mUBl2}1Wof4)Qd~7{sP^`p6 z1n+JfLW+%XLlqYpH&*d_#?4h+A{NEYZh=@+^@?LdpR_4XA}}td1f^j^NY?LiiE$U> z_FXQd)&<4Q91b&rpAz8|u@byI(9d~*@n$9w<31Z{QG%=_AMsbZu2`&39|=@A69_SZAm7_c zLVUfoYTcl;vHWeDXcZ^*;S)%X)3Lg*h5jRnUd=4HF%9ZRMIk%?94QL9^owM{NYCm0 z*hu@VEqYTLt(oa1(Y;?|%pqC9A7U`@pOmjw;zlQ~=34m?}MUzT$+2y4i$%%~8tHvSh z)V??VfPFH=bOQ7-kWFeo*aHBA^p-hbJq+d$z!8cqEx`#eM*v0vYK7D>I%?^{vUbMu z%K^EwwvL+IS8X9YNx!lk!{eGHUO!;>&-Ky9s>)a;MIldC^XepRmnOvH%#nMA!9`Ru z(M$fI_J-uswN{$#h1z+?=9-ST9I^rO7Tf5y!$l>hL?y{gW6ofLH~t9hivq*|_L)Q8 zIfIGzh4b}l+4~hiE6%mn-R`nMHz-bc?K^3Y)82)?K#8#i^)16u{* z9y;L-(YV)+57S}qAaC`&w_oOh|EtSw?`iyw*4sRy8-I#rJgIWs)6A6hY8QL(^H)BJ z{HXAg#m8W*8T>V0-}JvPv?yekb9vdKHbVx;rt*^ZYQJdA&cBdZo>$oU+x9lmLH`3- z(^mYV?%wlVEBbEm(0E1EppXp76WLsr<%$Yu?qvUQb23@K4%Hk=Lp! zn2M_zwpGSO+sX7I$)uOaLwT~OE-`0L#~>6^eUSScy%bB}2Kq^C(0PBM^v_s~)fb3I zp}ww~!K}dceFx*AZ^q;JZ~9sM*XY9#9Rg@&AY&CAvaZ_os2rhNa(1#Vy_8pnA#@zz zL4YZMqX07ivjE2d9tSuD@Fc*~0MF2kj)-9a%ro@kj?Ta$n0W?8+llnj0(mT(PqS~K zx(faa^skNq`~>anJiqR8-*PpUB#(X?mk{7>$#bRd)wPnIy9~(Le5HHG5ic1zHzBwG zroVf~l_;6H!-D+nH`|AId?O_*ci52REQ#E#2eX{oj?BK2gL}D3S*wH$+|{oQcAeGX z0s3Czg3Q0W@Xc2p0Pu=bKLEVFJEpP4Wo0EpCe*j+RL}L<839kS%J+V34*gbM{bQdX GF7OX*Z?ZH1 diff --git a/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc index d705642e1226909db262b964ed97acbc6e614089..a094f4db00e96e2648b9888891e3d4528d06341a 100644 GIT binary patch literal 7222 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 delta 1118 zcmZ`%OK1~87@kS@o$RLBY_>_$XiE@Xt8MC|ty&+orByunIM{$l$V|#gZ0jU~k4Ob&SrI>VbrC zt-Q+bx4MG?y(t&yitJc{G*_C&fmHLa;IdAyTREuHM^;ugd~hvF3r=2Ee9$oHhr~WP z#ypcQD)|AuVK!oo=nLto#9kYlt#Qq&$A57Ekb>j}@L|Jx4CxmoN$>E{mbYW0hx zK`wXkb(QSqTo^-~?cuPOzBarqJcjJ&aDcZsoIrKtZ^Q>)6vsC$FF6@W0*ICf{wBzBGH`AsU!e_aL!ZgJ;tx?$n4> z^=oy)-*3?7&(z5X&pO0qY8;pSnm;=;CO+~BeBmNyrQ^I{g2OR7-LW%r9@52*lhOR9 zW^QA1v)9aIsh-ZxH=R_|al>RrJ_WkOX*4Rm!sZd=?F z>Ova8vKR7qroyO@F<^H-=wD834Najfkjj0?^)EYxFfNRC5VymGpf;z;yx+~1poj5 diff --git a/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc index 43a3794d6559f7bed7b0eeec2036e4ad35245093..f64241e7d8dca7c96908f64f64b4850b8efd4927 100644 GIT binary patch delta 2250 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 diff --git a/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc index 9c5bafe5e48a74bcc5b7523b7ea994a416066e27..e5b92ea8f7330b34bb53f26e34eaaf4d35b606a6 100644 GIT binary patch delta 30 kcmX>rc~+8pIWI340}y=R_1nl@&BS7CtY^5ni^-V_0D4Uad;kCd delta 30 jcmX>rc~+8pIWI340|=CAZRDltpgWDb%60B+X?#Q*>R delta 30 jcmeCS@3!Y&&dbZi00O028@aWZS&S_73^rRb2gv{cV`K&# diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc index 3dd88f559c910ce5387a7850a10836d8cccbb337..250f87f82861eadb68d6700599f95e2f91493c81 100644 GIT binary patch delta 30 kcmZ24vR;IHIWI340}y=R_1nljn~BBPSkG|tDyCL;0CegHwEzGB delta 30 jcmZ24vR;IHIWI340|=CAZRDQK#A0NjXRvt{Q!6_FX?F(< diff --git a/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc index 46ae2eb243d215432d14d619a14b512bbe5e3d54..41ffec21920a1b1e5940ac1958756e5885388036 100644 GIT binary patch delta 30 kcmX>mdrX#lIWI340}y=R_1nn(h>6A6SkG|tN2aUX0D&wB*8l(j delta 30 jcmX>mdrX#lIWI340|=CAZRCE$#A0NjXR!Gr(^YN&b-4&G diff --git a/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc index 80c82367ed26d1b3aa8f4a8bc76f0c16126bf6b6..6ebc822057917e7b82582e5d2cd519f0ba2f4a4e 100644 GIT binary patch delta 30 kcmaDP_DGC-IWI340}y=R_1nmOo{7cSSkG|tJ*E~80E8z9hX4Qo delta 30 jcmaDP_DGC-IWI340|=CAZR9@B#A0NjXR!GmQws+Gc(e!J diff --git a/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc index 7aeca28cde4a0ff40e041360eb356d7d52e08cab..99904e09e4b7f71cc8a3f179aa2f36138ac53648 100644 GIT binary patch delta 30 kcmX@4b4Z7KIWI340}y=R_1nl@&dg$LtY^5njd_m{0DQj)2LJ#7 delta 30 jcmX@4b4Z7KIWI340|=CAZR9RzW-+qRGuYh5yhjKCaZCqZ diff --git a/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc index d4f743a50282e1bb623c56cac65a0e44cf40b373..85ed5d3d61184eb04bba3384db0b6254b4e21c8c 100644 GIT binary patch delta 30 kcmaDK@IHWhIWI340}y=R_1nmOl9|QWSkG|t4d&@80F${1IsgCw delta 30 jcmaDK@IHWhIWI340|=CAZR9@5%wlArXR!GO^K=yeh(-vJ diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 057a909..d74a17e 100644 --- a/crowdsec_service_api/services/allowlists.py +++ b/crowdsec_service_api/services/allowlists.py @@ -11,7 +11,7 @@ class Allowlists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def list_allowlists( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index ac2cad5..e2907b7 100644 --- a/crowdsec_service_api/services/blocklists.py +++ b/crowdsec_service_api/services/blocklists.py @@ -11,7 +11,7 @@ class Blocklists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_blocklists( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index 6d90155..9934444 100644 --- a/crowdsec_service_api/services/cves.py +++ b/crowdsec_service_api/services/cves.py @@ -11,7 +11,7 @@ class Cves(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_cves( self, @@ -19,6 +19,7 @@ def get_cves( sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), exploitation_phase: Optional[CVEExploitationPhase] = None, + detailed: bool = False, page: int = 1, size: int = 50, )-> GetCVEsResponsePage: diff --git a/crowdsec_service_api/services/decisions.py b/crowdsec_service_api/services/decisions.py index 7468e0a..a9adc2a 100644 --- a/crowdsec_service_api/services/decisions.py +++ b/crowdsec_service_api/services/decisions.py @@ -11,18 +11,21 @@ class Decisions(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_decisions( self, + page: int = 1, + size: int = 50, instance_ids: list[str] = [], tag_ids: list[str] = [], remediation_types: list[str] = [], ips: list[str] = [], + alert_ids: list[str] = [], + decision_ids: list[str] = [], + created_at_from: Optional[str] = None, sort_by: Optional[DecisionsSortBy] = DecisionsSortBy("created_at"), sort_order: Optional[DecisionsSortOrder] = DecisionsSortOrder("desc"), - page: int = 1, - size: int = 50, )-> DecisionsGetResponsePage: endpoint_url = "/decisions" loc = locals() @@ -80,4 +83,75 @@ def delete_decision( ) return None + + def get_aggregated_decisions( + self, + page: int = 1, + size: int = 50, + instance_ids: list[str] = [], + tag_ids: list[str] = [], + remediation_types: list[str] = [], + ips: list[str] = [], + alert_ids: list[str] = [], + decision_ids: list[str] = [], + created_at_from: Optional[str] = None, + sort_by: Optional[AggregatedDecisionsSortBy] = AggregatedDecisionsSortBy("first_created_at"), + sort_order: Optional[DecisionsSortOrder] = DecisionsSortOrder("desc"), + )-> AggregatedDecisionsGetResponsePage: + endpoint_url = "/decisions/aggregated" + loc = locals() + headers = {} + params = json.loads( + DecisionsGetAggregatedDecisionsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = {} + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return AggregatedDecisionsGetResponsePage(_client=self, **response.json()) + + def delete_aggregated_decisions( + self, + aggregated_id: str, + ): + endpoint_url = "/decisions/aggregated/{aggregated_id}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + DecisionsDeleteAggregatedDecisionsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.delete( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return None + + def delete_aggregated_decision_item( + self, + aggregated_id: str, + decision_id: str, + ): + endpoint_url = "/decisions/aggregated/{aggregated_id}/items/{decision_id}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + DecisionsDeleteAggregatedDecisionItemPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.delete( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return None \ No newline at end of file diff --git a/crowdsec_service_api/services/fingerprints.py b/crowdsec_service_api/services/fingerprints.py index 1bc0b40..725140c 100644 --- a/crowdsec_service_api/services/fingerprints.py +++ b/crowdsec_service_api/services/fingerprints.py @@ -11,13 +11,14 @@ class Fingerprints(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_fingerprint_rules( self, query: Optional[str] = None, sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + detailed: bool = False, page: int = 1, size: int = 50, )-> GetFingerprintRulesResponsePage: diff --git a/crowdsec_service_api/services/hub.py b/crowdsec_service_api/services/hub.py index 3a1546e..8f3821b 100644 --- a/crowdsec_service_api/services/hub.py +++ b/crowdsec_service_api/services/hub.py @@ -11,7 +11,7 @@ class Hub(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index c5b2050..0743a34 100644 --- a/crowdsec_service_api/services/info.py +++ b/crowdsec_service_api/services/info.py @@ -11,7 +11,7 @@ class Info(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 73f5656..1c6be4b 100644 --- a/crowdsec_service_api/services/integrations.py +++ b/crowdsec_service_api/services/integrations.py @@ -11,7 +11,7 @@ class Integrations(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_integrations( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 322c7c5..41f3241 100644 --- a/crowdsec_service_api/services/metrics.py +++ b/crowdsec_service_api/services/metrics.py @@ -11,7 +11,7 @@ class Metrics(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py index 5d173fc..828d1ba 100644 --- a/crowdsec_service_api/services/products.py +++ b/crowdsec_service_api/services/products.py @@ -11,7 +11,7 @@ class Products(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_products( self, diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py index fa41f55..aef19e5 100644 --- a/crowdsec_service_api/services/tracker_events.py +++ b/crowdsec_service_api/services/tracker_events.py @@ -11,7 +11,7 @@ class TrackerEvents(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_exploitation_phase_change_events( self, diff --git a/crowdsec_service_api/services/tracker_tags.py b/crowdsec_service_api/services/tracker_tags.py index 270d8f4..36901be 100644 --- a/crowdsec_service_api/services/tracker_tags.py +++ b/crowdsec_service_api/services/tracker_tags.py @@ -11,7 +11,7 @@ class TrackerTags(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_tags( self, diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py index dab3932..a21c77e 100644 --- a/crowdsec_service_api/services/vendors.py +++ b/crowdsec_service_api/services/vendors.py @@ -11,7 +11,7 @@ class Vendors(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.1") def get_vendors( self, diff --git a/doc/Blocklists.md b/doc/Blocklists.md index 78168f1..01e7143 100644 --- a/doc/Blocklists.md +++ b/doc/Blocklists.md @@ -80,7 +80,7 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 409 | Blocklist already exists | +| 409 | Already exists | | 422 | Validation Error | ### Usage @@ -99,6 +99,7 @@ request = BlocklistCreateRequest( description=None, references=None, tags=None, + store_full_content_in_s3=None, ) try: response = client.create_blocklist( @@ -178,7 +179,7 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 404 | Blocklist not found | +| 404 | Not found | | 422 | Validation Error | ### Usage @@ -251,8 +252,8 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 403 | Blocklist is read-only | -| 404 | Blocklist not found | +| 403 | Read-only | +| 404 | Not found | | 500 | Internal server error | | 422 | Validation Error | ### Usage diff --git a/doc/Cves.md b/doc/Cves.md index 9b8a39b..a0e497f 100644 --- a/doc/Cves.md +++ b/doc/Cves.md @@ -3,7 +3,7 @@ # Cves Methods | Method | Description | | ------ | ----------- | -| [get_cves](#get_cves) | Get a paginated list of CVEs that CrowdSec is tracking | +| [get_cves](#get_cves) | Get a paginated list of CVEs that CrowdSec is tracking. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE; they are omitted by default to keep the list light. | | [get_cve](#get_cve) | Get information about a specific CVE ID | | [get_cve_protect_rules](#get_cve_protect_rules) | Get protection/detection rules associated with a specific CVE ID | | [download_cve_ips](#download_cve_ips) | Download the list of IPs exploiting a specific CVE ID in raw format | @@ -16,7 +16,7 @@ | [get_cve_timeline](#get_cve_timeline) | Get timeline data of occurrences for a specific CVE ID | ## **get_cves** -### Get a paginated list of CVEs that CrowdSec is tracking +### Get a paginated list of CVEs that CrowdSec is tracking. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE; they are omitted by default to keep the list light. - Endpoint: `/cves` - Method: `GET` @@ -27,6 +27,7 @@ | sort_by | Optional[GetCVEsSortBy] | Field to sort by | False | GetCVEsSortBy("rule_release_date") | | sort_order | Optional[GetCVEsSortOrder] | Sort order: ascending or descending | False | GetCVEsSortOrder("desc") | | exploitation_phase | Optional[CVEExploitationPhase] | Filter by exploitation phase | False | None | +| detailed | bool | Include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE in the list. Defaults to false to keep the response lightweight. | False | False | | page | int | Page number | False | 1 | | size | int | Page size | False | 50 | ### Returns: @@ -51,6 +52,7 @@ try: sort_by=rule_release_date, sort_order=desc, exploitation_phase=None, + detailed=True, page=1, size=50, ) diff --git a/doc/Decisions.md b/doc/Decisions.md index d4b739b..1a9c134 100644 --- a/doc/Decisions.md +++ b/doc/Decisions.md @@ -6,6 +6,9 @@ | [get_decisions](#get_decisions) | Get decisions | | [create_decision](#create_decision) | Create a new decision. | | [delete_decision](#delete_decision) | Delete a decision by its UUID. | +| [get_aggregated_decisions](#get_aggregated_decisions) | None | +| [delete_aggregated_decisions](#delete_aggregated_decisions) | Delete one decision by ID | +| [delete_aggregated_decision_item](#delete_aggregated_decision_item) | Delete one decision by ID | ## **get_decisions** ### Get decisions @@ -15,21 +18,23 @@ ### Parameters: | Parameter | Type | Description | Required | Default | | --------- | ---- | ----------- | -------- | ------- | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | | instance_ids | list[str] | Filter decisions by instance IDs | False | [] | | tag_ids | list[str] | Filter decisions by tag IDs | False | [] | | remediation_types | list[str] | Filter decisions by remediation types | False | [] | | ips | list[str] | Filter decisions by IPs (only for IP decisions) | False | [] | +| alert_ids | list[str] | Filter decisions by associated alert IDs | False | [] | +| decision_ids | list[str] | Filter decisions by decision IDs | False | [] | +| created_at_from | Optional[str] | Filter decisions created after this date (inclusive) | False | None | | sort_by | Optional[DecisionsSortBy] | Field to sort by (e.g., created_at, duration) | False | DecisionsSortBy("created_at") | | sort_order | Optional[DecisionsSortOrder] | Sort order: 'asc' for ascending, 'desc' for descending | False | DecisionsSortOrder("desc") | -| page | int | Page number | False | 1 | -| size | int | Page size | False | 50 | ### Returns: [DecisionsGetResponsePage](./Models.md#decisionsgetresponsepage) ### Errors: | Code | Description | | ---- | ----------- | | 404 | Not found | -| 500 | Internal server error | | 422 | Validation Error | ### Usage @@ -43,14 +48,17 @@ auth = ApiKeyAuth(api_key='your_api_key') client = Decisions(auth=auth) try: response = client.get_decisions( + page=1, + size=50, instance_ids=['sample-item'], tag_ids=['sample-item'], remediation_types=['sample-item'], ips=['sample-item'], + alert_ids=['sample-item'], + decision_ids=['sample-item'], + created_at_from=None, sort_by=created_at, sort_order=desc, - page=1, - size=50, ) print(response) except HTTPStatusError as e: @@ -72,7 +80,7 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 409 | Conflict: Decision value is in allowlists; cannot create decision. | +| 409 | Already exists | | 422 | Validation Error | ### Usage @@ -125,7 +133,9 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 422 | Validation Error | +| 422 | Unprocessable entity | +| 404 | Not found | +| 500 | Internal server error | ### Usage ```python @@ -145,3 +155,131 @@ except HTTPStatusError as e: print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` + +## **get_aggregated_decisions** +### None +- Endpoint: `/decisions/aggregated` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +| instance_ids | list[str] | Filter decisions by instance IDs | False | [] | +| tag_ids | list[str] | Filter decisions by tag IDs | False | [] | +| remediation_types | list[str] | Filter decisions by remediation types | False | [] | +| ips | list[str] | Filter decisions by IPs (only for IP decisions) | False | [] | +| alert_ids | list[str] | Filter decisions by associated alert IDs | False | [] | +| decision_ids | list[str] | Filter decisions by decision IDs | False | [] | +| created_at_from | Optional[str] | Filter decisions created after this date (inclusive) | False | None | +| sort_by | Optional[AggregatedDecisionsSortBy] | Field to sort by (e.g., created_at, duration) | False | AggregatedDecisionsSortBy("first_created_at") | +| sort_order | Optional[DecisionsSortOrder] | Sort order: 'asc' for ascending, 'desc' for descending | False | DecisionsSortOrder("desc") | +### Returns: +[AggregatedDecisionsGetResponsePage](./Models.md#aggregateddecisionsgetresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | Not found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Decisions, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Decisions(auth=auth) +try: + response = client.get_aggregated_decisions( + page=1, + size=50, + instance_ids=['sample-item'], + tag_ids=['sample-item'], + remediation_types=['sample-item'], + ips=['sample-item'], + alert_ids=['sample-item'], + decision_ids=['sample-item'], + created_at_from=None, + sort_by=first_created_at, + sort_order=desc, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **delete_aggregated_decisions** +### Delete one decision by ID +- Endpoint: `/decisions/aggregated/{aggregated_id}` +- Method: `DELETE` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| aggregated_id | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Unprocessable entity | +| 404 | Not found | +| 500 | Internal server error | +### Usage + +```python +from crowdsec_service_api import ( + Decisions, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Decisions(auth=auth) +try: + response = client.delete_aggregated_decisions( + aggregated_id='aggregated_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **delete_aggregated_decision_item** +### Delete one decision by ID +- Endpoint: `/decisions/aggregated/{aggregated_id}/items/{decision_id}` +- Method: `DELETE` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| aggregated_id | str | | True | | +| decision_id | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Unprocessable entity | +| 404 | Not found | +| 500 | Internal server error | +### Usage + +```python +from crowdsec_service_api import ( + Decisions, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Decisions(auth=auth) +try: + response = client.delete_aggregated_decision_item( + aggregated_id='aggregated_id', + decision_id='decision_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/doc/Fingerprints.md b/doc/Fingerprints.md index addb9a3..c804f4b 100644 --- a/doc/Fingerprints.md +++ b/doc/Fingerprints.md @@ -3,7 +3,7 @@ # Fingerprints Methods | Method | Description | | ------ | ----------- | -| [get_fingerprint_rules](#get_fingerprint_rules) | Get a paginated list of fingerprint rules | +| [get_fingerprint_rules](#get_fingerprint_rules) | Get a paginated list of fingerprint rules. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each rule; they are omitted by default to keep the list light. | | [download_fingerprint_ips](#download_fingerprint_ips) | Download the list of IPs exploiting a specific fingerprint rule in raw format | | [get_fingerprint_ips_details](#get_fingerprint_ips_details) | Get detailed information about IPs exploiting a specific fingerprint rule | | [get_fingerprint_ips_details_stats](#get_fingerprint_ips_details_stats) | Get aggregated statistics about IPs exploiting a specific fingerprint rule | @@ -15,7 +15,7 @@ | [get_fingerprint_rule](#get_fingerprint_rule) | Get information about a specific fingerprint rule | ## **get_fingerprint_rules** -### Get a paginated list of fingerprint rules +### Get a paginated list of fingerprint rules. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each rule; they are omitted by default to keep the list light. - Endpoint: `/fingerprints` - Method: `GET` @@ -25,6 +25,7 @@ | query | Optional[str] | Search query for fingerprint rules | False | None | | sort_by | Optional[GetCVEsSortBy] | Field to sort by | False | GetCVEsSortBy("rule_release_date") | | sort_order | Optional[GetCVEsSortOrder] | Sort order: ascending or descending | False | GetCVEsSortOrder("desc") | +| detailed | bool | Include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each fingerprint rule in the list. Defaults to false to keep the response lightweight. | False | False | | page | int | Page number | False | 1 | | size | int | Page size | False | 50 | ### Returns: @@ -48,6 +49,7 @@ try: query=None, sort_by=rule_release_date, sort_order=desc, + detailed=True, page=1, size=50, ) diff --git a/doc/Models.md b/doc/Models.md index b6ab9c0..e81d5ac 100644 --- a/doc/Models.md +++ b/doc/Models.md @@ -1,5 +1,63 @@ +# **AggregatedDecisionItem** +## Required: +id, first_created_at, last_created_at, origin, scenario, min_duration, max_duration, first_expiration, last_expiration, count, machines, target +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | ID of the decision aggregated item || +| first_created_at | str | Creation date of the first decision in the group || +| last_created_at | str | Creation date of the last decision in the group || +| origin | str | Origin of the decision || +| scenario | str | Scenario of the decision || +| min_duration | str | Min duration in the group of decisions || +| max_duration | str | Max durations in the group of decisions || +| first_expiration | str | First expiration date in the group of decisions || +| last_expiration | str | Last expiration date in the group of decisions || +| count | int | Number of decisions in the group || +| machines | Machines | Machines object (the instance ID is the key) with the decision status and timestamp || +| target | DecisionTargetModel | None || + +# **AggregatedDecisionsGetResponse** +## Required: +id, scope, type, value, decisions +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | ID of the decision aggregated item || +| scope | str | Scope of the decision || +| type | str | Type of the decision || +| value | str | Value of the decision || +| country | Optional[str] | Country associated with the decision || +| as_name | Optional[str] | AS name associated with the decision || +| as_num | Optional[int] | AS number associated with the decision || +| city | Optional[str] | City associated with the decision || +| latitude | Optional[float] | Latitude associated with the decision || +| longitude | Optional[float] | Longitude associated with the decision || +| first_created_at | str | Creation date of the first decision in the group || +| last_created_at | str | Creation date of the last decision in the group || +| first_expiration | str | Expiration date of the first decision in the group || +| last_expiration | str | Expiration date of the last decision in the group || +| decisions | list[AggregatedDecisionItem] | List of decisions in the group || + +# **AggregatedDecisionsGetResponsePage** +## Required: +items, page, size, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[AggregatedDecisionsGetResponse] | None || +| total | Optional[int] | None || +| page | Optional[int] | None || +| size | Optional[int] | None || +| pages | Optional[int] | None || +| links | Links | None || + +# **AggregatedDecisionsSortBy** +## Enum: +FIRST_CREATED_AT, FIRST_EXPIRATION + # **AllowlistCreateRequest** ## Required: name @@ -273,6 +331,7 @@ name, description | description | str | Blocklist description || | references | list[str] | Useful references on the list's origins || | tags | list[str] | Classification tags || +| store_full_content_in_s3 | bool | Whether to store the full blocklist content in S3 or not || # **BlocklistDeleteIPsRequest** ## Required: @@ -553,6 +612,19 @@ uuid |----------|------|-------------|---------| | uuid | str | UUID of the created decision || +# **DecisionMachineState** +## Required: +timestamp, state +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| timestamp | str | Date of when the state has been set || +| state | DecisionMachineStateEnum | None || + +# **DecisionMachineStateEnum** +## Enum: +PENDING_CREATE, PENDING_DELETE, APPLIED + # **DecisionResponse** ## Required: uuid, id, duration, origin, scenario, scope, type, value, target @@ -1107,7 +1179,7 @@ name, date, description, label, sorting_priority ## Enum: INSUFFICIENT_DATA, EARLY_EXPLOITATION, FRESH_AND_POPULAR, TARGETED_EXPLOITATION, MASS_EXPLOITATION, BACKGROUND_NOISE, UNPOPULAR, WEARING_OUT, UNCLASSIFIED -# **CVEResponseBase** +# **CVEResponseDetailed** ## Required: id, name, title, affected_components, crowdsec_score, nb_ips, published_date, has_public_exploit, exploitation_phase ## Properties @@ -1130,6 +1202,12 @@ id, name, title, affected_components, crowdsec_score, nb_ips, published_date, ha | exploitation_phase | ExploitationPhase | None || | adjustment_score | Optional[AdjustmentScore] | Score adjustments applied to the CVE score based on various factors || | threat_context | Optional[ThreatContext] | Threat context (attacker/defender countries, industries, objectives) || +| tags | list[str] | Tags associated with the CVE || +| references | list[str] | List of references for the CVE || +| description | Optional[str] | Description of the CVE || +| crowdsec_analysis | Optional[str] | CrowdSec analysis of the CVE || +| cwes | list[CWE] | List of CWEs associated with the CVE || +| events | list[CVEEventOutput] | List of events related to the CVE || # **CVEsubscription** ## Required: @@ -1249,27 +1327,6 @@ id, name, title, affected_components, crowdsec_score, nb_ips, exploitation_phase | crowdsec_analysis | Optional[str] | CrowdSec analysis for this fingerprint rule || | events | list[FingerprintEventOutput] | List of events related to the fingerprint rule || -# **FingerprintRuleSummary** -## Required: -id, name, title, affected_components, crowdsec_score, nb_ips, exploitation_phase -## Properties -| Property | Type | Description | Example | -|----------|------|-------------|---------| -| id | str | Fingerprint rule identifier || -| name | str | Fingerprint rule name || -| title | str | Fingerprint rule title || -| affected_components | list[AffectedComponent] | List of affected components || -| crowdsec_score | int | Live Exploit Tracker score for the fingerprint rule || -| opportunity_score | int | Opportunity score || -| momentum_score | int | Momentum score || -| first_seen | Optional[str] | First seen date || -| last_seen | Optional[str] | Last seen date || -| nb_ips | int | Number of unique IPs observed || -| rule_release_date | Optional[str] | Release date of the fingerprint rule || -| exploitation_phase | ExploitationPhase | None || -| adjustment_score | Optional[AdjustmentScore] | Score adjustment details || -| threat_context | Optional[ThreatContext] | Threat context (attacker/defender countries, industries, objectives) || - # **FingerprintTimelineItem** ## Required: timestamp, count @@ -1347,7 +1404,7 @@ items, total, page, size, pages, links ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| items | list[CVEResponseBase] | None || +| items | list[CVEResponseDetailed] | None || | total | int | None || | page | int | None || | size | int | None || @@ -1381,7 +1438,7 @@ items, total, page, size, pages, links ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| items | list[FingerprintRuleSummary] | None || +| items | list[FingerprintRuleResponse] | None || | total | int | None || | page | int | None || | size | int | None || diff --git a/doc/README.md b/doc/README.md index 445188f..0ce498f 100644 --- a/doc/README.md +++ b/doc/README.md @@ -39,6 +39,14 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ ## API Endpoint models +[AggregatedDecisionItem](./Models.md#aggregateddecisionitem) + +[AggregatedDecisionsGetResponse](./Models.md#aggregateddecisionsgetresponse) + +[AggregatedDecisionsGetResponsePage](./Models.md#aggregateddecisionsgetresponsepage) + +[AggregatedDecisionsSortBy](./Models.md#aggregateddecisionssortby) + [AllowlistCreateRequest](./Models.md#allowlistcreaterequest) [AllowlistCreateResponse](./Models.md#allowlistcreateresponse) @@ -141,6 +149,10 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [DecisionCreateResponse](./Models.md#decisioncreateresponse) +[DecisionMachineState](./Models.md#decisionmachinestate) + +[DecisionMachineStateEnum](./Models.md#decisionmachinestateenum) + [DecisionResponse](./Models.md#decisionresponse) [DecisionTargetModel](./Models.md#decisiontargetmodel) @@ -249,7 +261,7 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [CVEExploitationPhase](./Models.md#cveexploitationphase) -[CVEResponseBase](./Models.md#cveresponsebase) +[CVEResponseDetailed](./Models.md#cveresponsedetailed) [CVEsubscription](./Models.md#cvesubscription) @@ -271,8 +283,6 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [FingerprintRuleResponse](./Models.md#fingerprintruleresponse) -[FingerprintRuleSummary](./Models.md#fingerprintrulesummary) - [FingerprintTimelineItem](./Models.md#fingerprinttimelineitem) [GetCVEIPsResponsePage](./Models.md#getcveipsresponsepage) diff --git a/public-openapi.json b/public-openapi.json index 2e5d94e..586f667 100644 --- a/public-openapi.json +++ b/public-openapi.json @@ -3,7 +3,7 @@ "info": { "title": "Service API", "description": "This is the API to manage Crowdsec services", - "version": "1.70.29", + "version": "1.70.46", "contact": { "name": "CrowdSec", "url": "https://crowdsec.net", @@ -820,7 +820,7 @@ } }, "409": { - "description": "Blocklist already exists" + "description": "Already exists" }, "422": { "description": "Validation Error", @@ -1097,7 +1097,7 @@ } }, "404": { - "description": "Blocklist not found" + "description": "Not found" }, "422": { "description": "Validation Error", @@ -1155,10 +1155,10 @@ } }, "403": { - "description": "Blocklist is read-only" + "description": "Read-only" }, "404": { - "description": "Blocklist not found" + "description": "Not found" }, "500": { "description": "Internal server error" @@ -1270,7 +1270,7 @@ ], "description": "Blocklist expiration", "examples": [ - "2026-06-11T08:40:13.370581+00:00" + "2026-07-08T08:42:28.511313+00:00" ], "title": "Expiration" }, @@ -2445,6 +2445,33 @@ "description": "Get decisions", "operationId": "getDecisions", "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number", + "default": 1, + "title": "Page" + }, + "description": "Page number" + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "description": "Page size", + "default": 50, + "title": "Size" + }, + "description": "Page size" + }, { "name": "instance_ids", "in": "query", @@ -2529,6 +2556,70 @@ }, "description": "Filter decisions by IPs (only for IP decisions)" }, + { + "name": "alert_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by associated alert IDs", + "examples": [ + [ + "alert-abc123", + "alert-def456" + ] + ], + "default": [], + "title": "Alert Ids" + }, + "description": "Filter decisions by associated alert IDs" + }, + { + "name": "decision_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by decision IDs", + "examples": [ + [ + "dec-abc123", + "dec-def456" + ] + ], + "default": [], + "title": "Decision Ids" + }, + "description": "Filter decisions by decision IDs" + }, + { + "name": "created_at_from", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "description": "Filter decisions created after this date (inclusive)", + "examples": [ + "2023-01-01T00:00:00Z" + ], + "title": "Created At From" + }, + "description": "Filter decisions created after this date (inclusive)" + }, { "name": "sort_by", "in": "query", @@ -2572,33 +2663,6 @@ "title": "Sort Order" }, "description": "Sort order: 'asc' for ascending, 'desc' for descending" - }, - { - "name": "page", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "minimum": 1, - "description": "Page number", - "default": 1, - "title": "Page" - }, - "description": "Page number" - }, - { - "name": "size", - "in": "query", - "required": false, - "schema": { - "type": "integer", - "maximum": 100, - "minimum": 1, - "description": "Page size", - "default": 50, - "title": "Size" - }, - "description": "Page size" } ], "responses": { @@ -2615,9 +2679,6 @@ "404": { "description": "Not found" }, - "500": { - "description": "Internal server error" - }, "422": { "description": "Validation Error", "content": { @@ -2659,7 +2720,7 @@ } }, "409": { - "description": "Conflict: Decision value is in allowlists; cannot create decision." + "description": "Already exists" }, "422": { "description": "Validation Error", @@ -2695,7 +2756,261 @@ ], "responses": { "204": { - "description": "Successful Response" + "description": "No Content" + }, + "422": { + "description": "Unprocessable entity" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/decisions/aggregated": { + "get": { + "tags": [ + "Decisions" + ], + "summary": "Get Aggregated Decisions", + "operationId": "getAggregatedDecisions", + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number", + "default": 1, + "title": "Page" + }, + "description": "Page number" + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "description": "Page size", + "default": 50, + "title": "Size" + }, + "description": "Page size" + }, + { + "name": "instance_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by instance IDs", + "examples": [ + [ + "inst-abc123", + "inst-def456" + ] + ], + "default": [], + "title": "Instance Ids" + }, + "description": "Filter decisions by instance IDs" + }, + { + "name": "tag_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by tag IDs", + "examples": [ + [ + "tag-001", + "tag-002" + ] + ], + "default": [], + "title": "Tag Ids" + }, + "description": "Filter decisions by tag IDs" + }, + { + "name": "remediation_types", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by remediation types", + "examples": [ + [ + "ban", + "captcha" + ] + ], + "default": [], + "title": "Remediation Types" + }, + "description": "Filter decisions by remediation types" + }, + { + "name": "ips", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by IPs (only for IP decisions)", + "examples": [ + [ + "203.0.113.7", + "198.51.100.42" + ] + ], + "default": [], + "title": "Ips" + }, + "description": "Filter decisions by IPs (only for IP decisions)" + }, + { + "name": "alert_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by associated alert IDs", + "examples": [ + [ + "alert-abc123", + "alert-def456" + ] + ], + "default": [], + "title": "Alert Ids" + }, + "description": "Filter decisions by associated alert IDs" + }, + { + "name": "decision_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by decision IDs", + "examples": [ + [ + "dec-abc123", + "dec-def456" + ] + ], + "default": [], + "title": "Decision Ids" + }, + "description": "Filter decisions by decision IDs" + }, + { + "name": "created_at_from", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "description": "Filter decisions created after this date (inclusive)", + "examples": [ + "2023-01-01T00:00:00Z" + ], + "title": "Created At From" + }, + "description": "Filter decisions created after this date (inclusive)" + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/AggregatedDecisionsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by (e.g., created_at, duration)", + "examples": [ + "created_at" + ], + "default": "first_created_at", + "title": "Sort By" + }, + "description": "Field to sort by (e.g., created_at, duration)" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/DecisionsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: 'asc' for ascending, 'desc' for descending", + "examples": [ + "desc" + ], + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: 'asc' for ascending, 'desc' for descending" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AggregatedDecisionsGetResponsePage" + } + } + } + }, + "404": { + "description": "Not found" }, "422": { "description": "Validation Error", @@ -2710,6 +3025,85 @@ } } }, + "/decisions/aggregated/{aggregated_id}": { + "delete": { + "tags": [ + "Decisions" + ], + "summary": "Delete Aggregated Decision", + "description": "Delete one decision by ID", + "operationId": "deleteAggregatedDecisions", + "parameters": [ + { + "name": "aggregated_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Aggregated Id" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "422": { + "description": "Unprocessable entity" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, + "/decisions/aggregated/{aggregated_id}/items/{decision_id}": { + "delete": { + "tags": [ + "Decisions" + ], + "summary": "Delete Aggregated Decision Item", + "description": "Delete one decision by ID", + "operationId": "deleteAggregatedDecisionItem", + "parameters": [ + { + "name": "aggregated_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Aggregated Id" + } + }, + { + "name": "decision_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Decision Id" + } + } + ], + "responses": { + "204": { + "description": "No Content" + }, + "422": { + "description": "Unprocessable entity" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + } + } + } + }, "/info": { "get": { "tags": [ @@ -3110,7 +3504,7 @@ "Cves" ], "summary": "Get list of CVEs CrowdSec is tracking", - "description": "Get a paginated list of CVEs that CrowdSec is tracking", + "description": "Get a paginated list of CVEs that CrowdSec is tracking. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE; they are omitted by default to keep the list light.", "operationId": "getCves", "parameters": [ { @@ -3199,6 +3593,21 @@ }, "description": "Filter by exploitation phase" }, + { + "name": "detailed", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE in the list. Defaults to false to keep the response lightweight.", + "examples": [ + true + ], + "default": false, + "title": "Detailed" + }, + "description": "Include the heavy detail fields (description, crowdsec_analysis, cwes, references, events, tags) for each CVE in the list. Defaults to false to keep the response lightweight." + }, { "name": "page", "in": "query", @@ -5139,7 +5548,7 @@ "Fingerprints" ], "summary": "Get list of fingerprint rules", - "description": "Get a paginated list of fingerprint rules", + "description": "Get a paginated list of fingerprint rules. Pass detailed=true to also include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each rule; they are omitted by default to keep the list light.", "operationId": "getFingerprintRules", "parameters": [ { @@ -5207,6 +5616,21 @@ }, "description": "Sort order: ascending or descending" }, + { + "name": "detailed", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each fingerprint rule in the list. Defaults to false to keep the response lightweight.", + "examples": [ + true + ], + "default": false, + "title": "Detailed" + }, + "description": "Include the heavy detail fields (description, crowdsec_analysis, references, events, tags) for each fingerprint rule in the list. Defaults to false to keep the response lightweight." + }, { "name": "page", "in": "query", @@ -5988,24 +6412,326 @@ "$ref": "#/components/schemas/ExploitationPhaseChangeEventsResponsePage" } } - } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AggregatedDecisionItem": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the decision aggregated item" + }, + "first_created_at": { + "type": "string", + "format": "date-time", + "title": "First Created At", + "description": "Creation date of the first decision in the group" + }, + "last_created_at": { + "type": "string", + "format": "date-time", + "title": "Last Created At", + "description": "Creation date of the last decision in the group" + }, + "origin": { + "type": "string", + "title": "Origin", + "description": "Origin of the decision" + }, + "scenario": { + "type": "string", + "title": "Scenario", + "description": "Scenario of the decision" + }, + "min_duration": { + "type": "string", + "title": "Min Duration", + "description": "Min duration in the group of decisions" + }, + "max_duration": { + "type": "string", + "title": "Max Duration", + "description": "Max durations in the group of decisions" + }, + "first_expiration": { + "type": "string", + "format": "date-time", + "title": "First Expiration", + "description": "First expiration date in the group of decisions" + }, + "last_expiration": { + "type": "string", + "format": "date-time", + "title": "Last Expiration", + "description": "Last expiration date in the group of decisions" + }, + "count": { + "type": "integer", + "title": "Count", + "description": "Number of decisions in the group" + }, + "machines": { + "additionalProperties": { + "$ref": "#/components/schemas/DecisionMachineState" + }, + "type": "object", + "title": "Machines", + "description": "Machines object (the instance ID is the key) with the decision status and timestamp" + }, + "target": { + "$ref": "#/components/schemas/DecisionTargetModel", + "description": "Target of the decision" + } + }, + "type": "object", + "required": [ + "id", + "first_created_at", + "last_created_at", + "origin", + "scenario", + "min_duration", + "max_duration", + "first_expiration", + "last_expiration", + "count", + "machines", + "target" + ], + "title": "AggregatedDecisionItem" + }, + "AggregatedDecisionsGetResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the decision aggregated item" + }, + "scope": { + "type": "string", + "title": "Scope", + "description": "Scope of the decision" + }, + "type": { + "type": "string", + "title": "Type", + "description": "Type of the decision" + }, + "value": { + "type": "string", + "title": "Value", + "description": "Value of the decision" + }, + "country": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Country", + "description": "Country associated with the decision" + }, + "as_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "As Name", + "description": "AS name associated with the decision" + }, + "as_num": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "As Num", + "description": "AS number associated with the decision" + }, + "city": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "City", + "description": "City associated with the decision" + }, + "latitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Latitude", + "description": "Latitude associated with the decision" + }, + "longitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Longitude", + "description": "Longitude associated with the decision" + }, + "first_created_at": { + "type": "string", + "format": "date-time", + "title": "First Created At", + "description": "Creation date of the first decision in the group" + }, + "last_created_at": { + "type": "string", + "format": "date-time", + "title": "Last Created At", + "description": "Creation date of the last decision in the group" + }, + "first_expiration": { + "type": "string", + "format": "date-time", + "title": "First Expiration", + "description": "Expiration date of the first decision in the group" + }, + "last_expiration": { + "type": "string", + "format": "date-time", + "title": "Last Expiration", + "description": "Expiration date of the last decision in the group" + }, + "decisions": { + "items": { + "$ref": "#/components/schemas/AggregatedDecisionItem" + }, + "type": "array", + "title": "Decisions", + "description": "List of decisions in the group" + } + }, + "type": "object", + "required": [ + "id", + "scope", + "type", + "value", + "decisions" + ], + "title": "AggregatedDecisionsGetResponse" + }, + "AggregatedDecisionsGetResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AggregatedDecisionsGetResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "anyOf": [ + { + "type": "integer", + "minimum": 0.0 + }, + { + "type": "null" + } + ], + "title": "Total" + }, + "page": { + "anyOf": [ + { + "type": "integer", + "minimum": 1.0 + }, + { + "type": "null" + } + ], + "title": "Page" + }, + "size": { + "anyOf": [ + { + "type": "integer", + "minimum": 1.0 + }, + { + "type": "null" + } + ], + "title": "Size" }, - "422": { - "description": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } + "pages": { + "anyOf": [ + { + "type": "integer", + "minimum": 0.0 + }, + { + "type": "null" } - } + ], + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true } - } - } - } - }, - "components": { - "schemas": { + }, + "type": "object", + "required": [ + "items", + "page", + "size", + "links" + ], + "title": "AggregatedDecisionsGetResponsePage" + }, + "AggregatedDecisionsSortBy": { + "type": "string", + "enum": [ + "first_created_at", + "first_expiration" + ], + "title": "AggregatedDecisionsSortBy" + }, "AllowlistCreateRequest": { "properties": { "name": { @@ -7210,6 +7936,12 @@ "title": "Tags", "description": "Classification tags", "default": [] + }, + "store_full_content_in_s3": { + "type": "boolean", + "title": "Store Full Content In S3", + "description": "Whether to store the full blocklist content in S3 or not", + "default": false } }, "additionalProperties": false, @@ -8247,6 +8979,35 @@ ], "title": "DecisionCreateResponse" }, + "DecisionMachineState": { + "properties": { + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp", + "description": "Date of when the state has been set" + }, + "state": { + "$ref": "#/components/schemas/DecisionMachineStateEnum", + "description": "State of the decision" + } + }, + "type": "object", + "required": [ + "timestamp", + "state" + ], + "title": "DecisionMachineState" + }, + "DecisionMachineStateEnum": { + "type": "string", + "enum": [ + "PENDING_CREATE", + "PENDING_DELETE", + "APPLIED" + ], + "title": "DecisionMachineStateEnum" + }, "DecisionResponse": { "properties": { "created_at": { @@ -11278,7 +12039,7 @@ ], "title": "CVEExploitationPhase" }, - "CVEResponseBase": { + "CVEResponseDetailed": { "properties": { "id": { "type": "string", @@ -11421,6 +12182,62 @@ } ], "description": "Threat context (attacker/defender countries, industries, objectives)" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the CVE" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "List of references for the CVE" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Description of the CVE" + }, + "crowdsec_analysis": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Crowdsec Analysis", + "description": "CrowdSec analysis of the CVE" + }, + "cwes": { + "items": { + "$ref": "#/components/schemas/CWE" + }, + "type": "array", + "title": "Cwes", + "description": "List of CWEs associated with the CVE" + }, + "events": { + "items": { + "$ref": "#/components/schemas/CVEEventOutput" + }, + "type": "array", + "title": "Events", + "description": "List of events related to the CVE" } }, "type": "object", @@ -11435,8 +12252,8 @@ "has_public_exploit", "exploitation_phase" ], - "title": "CVEResponseBase", - "description": "GET CVE ID Response" + "title": "CVEResponseDetailed", + "description": "List item able to carry the heavy detail fields.\n\nThe list endpoint only populates these when ``detailed=true`` is passed;\notherwise they are left unset and stripped from the response via\n``response_model_exclude_unset``. All fields are therefore optional so a\nlean list item stays valid. Values are served straight from the cache\n(same source as the detail endpoint)." }, "CVEsubscription": { "properties": { @@ -11876,138 +12693,6 @@ ], "title": "FingerprintRuleResponse" }, - "FingerprintRuleSummary": { - "properties": { - "id": { - "type": "string", - "title": "Id", - "description": "Fingerprint rule identifier" - }, - "name": { - "type": "string", - "title": "Name", - "description": "Fingerprint rule name" - }, - "title": { - "type": "string", - "title": "Title", - "description": "Fingerprint rule title" - }, - "affected_components": { - "items": { - "$ref": "#/components/schemas/AffectedComponent" - }, - "type": "array", - "title": "Affected Components", - "description": "List of affected components" - }, - "crowdsec_score": { - "type": "integer", - "maximum": 10.0, - "minimum": 0.0, - "title": "Crowdsec Score", - "description": "Live Exploit Tracker score for the fingerprint rule" - }, - "opportunity_score": { - "type": "integer", - "maximum": 5.0, - "minimum": 0.0, - "title": "Opportunity Score", - "description": "Opportunity score", - "default": 0 - }, - "momentum_score": { - "type": "integer", - "maximum": 5.0, - "minimum": 0.0, - "title": "Momentum Score", - "description": "Momentum score", - "default": 0 - }, - "first_seen": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "First Seen", - "description": "First seen date" - }, - "last_seen": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Last Seen", - "description": "Last seen date" - }, - "nb_ips": { - "type": "integer", - "minimum": 0.0, - "title": "Nb Ips", - "description": "Number of unique IPs observed" - }, - "rule_release_date": { - "anyOf": [ - { - "type": "string", - "format": "date-time" - }, - { - "type": "null" - } - ], - "title": "Rule Release Date", - "description": "Release date of the fingerprint rule" - }, - "exploitation_phase": { - "$ref": "#/components/schemas/ExploitationPhase", - "description": "Current exploitation phase" - }, - "adjustment_score": { - "anyOf": [ - { - "$ref": "#/components/schemas/AdjustmentScore" - }, - { - "type": "null" - } - ], - "description": "Score adjustment details" - }, - "threat_context": { - "anyOf": [ - { - "$ref": "#/components/schemas/ThreatContext" - }, - { - "type": "null" - } - ], - "description": "Threat context (attacker/defender countries, industries, objectives)" - } - }, - "type": "object", - "required": [ - "id", - "name", - "title", - "affected_components", - "crowdsec_score", - "nb_ips", - "exploitation_phase" - ], - "title": "FingerprintRuleSummary" - }, "FingerprintTimelineItem": { "properties": { "timestamp": { @@ -12350,7 +13035,7 @@ "properties": { "items": { "items": { - "$ref": "#/components/schemas/CVEResponseBase" + "$ref": "#/components/schemas/CVEResponseDetailed" }, "type": "array", "title": "Items" @@ -12459,7 +13144,7 @@ "properties": { "items": { "items": { - "$ref": "#/components/schemas/FingerprintRuleSummary" + "$ref": "#/components/schemas/FingerprintRuleResponse" }, "type": "array", "title": "Items" diff --git a/pyproject.toml b/pyproject.toml index 3475644..47cf8ac 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "crowdsec_service_api" -version = "1.128.0" +version = "1.133.1" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock index 2dd3cda..b3dbec3 100644 --- a/uv.lock +++ b/uv.lock @@ -13,43 +13,43 @@ wheels = [ [[package]] name = "anyio" -version = "4.13.0" +version = "4.14.1" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "idna" }, { name = "typing-extensions", marker = "python_full_version < '3.13'" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" } +sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" }, + { url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" }, ] [[package]] name = "botocore" -version = "1.43.27" +version = "1.43.42" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "jmespath" }, { name = "python-dateutil" }, { name = "urllib3" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/fa/4e/db50ef135f1d9ffc85e209a124004a5829d8f12f4a7a0afdf380cb19866d/botocore-1.43.27.tar.gz", hash = "sha256:2093c316c24214e50e18640b1869513b759bb8cc48b95b004a8306cb9f0d6703", size = 15504242, upload-time = "2026-06-10T19:38:25.389Z" } +sdist = { url = "https://files.pythonhosted.org/packages/54/de/c264abcfb6b371d05c7c1ffbd10d666bf517b6a259390d3e49c921f2a1c5/botocore-1.43.42.tar.gz", hash = "sha256:d813d5d5707db5f1c73b5d65f6b172c49f38375b23b30c593966fef56f8b5e40", size = 15680498, upload-time = "2026-07-07T19:35:41.747Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2d/46/05b227b34e434b54867c2c942b0bfbbe2fe41789c18bb15ef787d03e9a56/botocore-1.43.27-py3-none-any.whl", hash = "sha256:4976544e652d5a1d8eca135da019f8e1c2d749efa2f9a31a8fb8c76f1895a40b", size = 15190293, upload-time = "2026-06-10T19:38:22.298Z" }, + { url = "https://files.pythonhosted.org/packages/b2/c5/ca819ae7489a233b03241d20458518b0de150bddc6b87c20192de3eaff7e/botocore-1.43.42-py3-none-any.whl", hash = "sha256:62aa017eb5bb9791b1bc655571fa1548611e508f35e13e636d3939e1be3745f0", size = 15367131, upload-time = "2026-07-07T19:35:36.881Z" }, ] [[package]] name = "certifi" -version = "2026.5.20" +version = "2026.6.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, + { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, ] [[package]] name = "crowdsec-service-api" -version = "1.128.0" +version = "1.133.1" source = { editable = "." } dependencies = [ { name = "botocore" }, @@ -299,11 +299,11 @@ wheels = [ [[package]] name = "typing-extensions" -version = "4.15.0" +version = "4.16.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +sdist = { url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5", size = 113555, upload-time = "2026-07-02T08:40:05.92Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, + { url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8", size = 45571, upload-time = "2026-07-02T08:40:04.659Z" }, ] [[package]]