From ef5b6898e2ffa1ba2504cd4eab47d8c609bb1c5c Mon Sep 17 00:00:00 2001 From: AlteredCoder <64792091+AlteredCoder@users.noreply.github.com> Date: Mon, 6 Jul 2026 10:20:34 +0000 Subject: [PATCH] Update python SDK v0.16.2 --- crowdsec_service_api/__init__.py | 9 +- .../__pycache__/__init__.cpython-311.pyc | Bin 5024 -> 5163 bytes .../__pycache__/base_model.cpython-311.pyc | Bin 4378 -> 4370 bytes .../__pycache__/http_client.cpython-311.pyc | Bin 7768 -> 7760 bytes .../__pycache__/models.cpython-311.pyc | Bin 158635 -> 166715 bytes crowdsec_service_api/models.py | 415 +++++-- .../__pycache__/__init__.cpython-311.pyc | Bin 207 -> 199 bytes .../__pycache__/allowlists.cpython-311.pyc | Bin 12917 -> 12909 bytes .../__pycache__/blocklists.cpython-311.pyc | Bin 15121 -> 15113 bytes .../services/__pycache__/cves.cpython-311.pyc | Bin 12321 -> 12356 bytes .../__pycache__/decisions.cpython-311.pyc | Bin 4338 -> 7214 bytes .../__pycache__/fingerprints.cpython-311.pyc | Bin 12310 -> 12345 bytes .../services/__pycache__/hub.cpython-311.pyc | Bin 3277 -> 3269 bytes .../services/__pycache__/info.cpython-311.pyc | Bin 2035 -> 2027 bytes .../__pycache__/integrations.cpython-311.pyc | Bin 8075 -> 8067 bytes .../__pycache__/metrics.cpython-311.pyc | Bin 2607 -> 2599 bytes .../__pycache__/products.cpython-311.pyc | Bin 3782 -> 3774 bytes .../tracker_events.cpython-311.pyc | Bin 2914 -> 2906 bytes .../__pycache__/tracker_tags.cpython-311.pyc | Bin 5698 -> 5690 bytes .../__pycache__/vendors.cpython-311.pyc | Bin 10351 -> 10343 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..e37f6a9bea436304bf49e87f098e28bee6b81686 100644 GIT binary patch delta 284 zcmZ3WzFLECIWI340}!M)dS~T|ZseIV z5<-5mEQh3&B!Uk!r#LvjsKlvqa|ClIi@pd<)Hg9XBQq~GxCChBEeUL*u6d=on;)=W zWEK&24s(Us=#pBJn3$7#sjt CYh&U7 delta 167 zcmZ3ju|S<~IWI340|=CAW$h8!$XCUr7O9_+pPQ;*RGOEUTBILeo?n!$pPZjpoS&1b zn^=$uWlvtll)<=hGC#A+=2OgVESnoRE-(x5JBPUjr4|77N<^5;khO*=9Zb4 zo?28;l$lo&RGO0-T$-DkSX8;$k~f!?@#5y?LYa)xMNHgG9~cm113L&7$p9S&05`@q ABme*a diff --git a/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc b/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc index 98b9f58568825bc4f734f1e579444f5920d5390c..ec9b898e9b8b21bb8229c3c0a533e7ce604b3eeb 100644 GIT binary patch delta 56 zcmbQGG)akjIWI340}yyMdT-=bW|j-q&&bbB)h{Z|%S$cNk1x+J%GNI`OVv#*$OO`x JLzs{80sy(m5qSUr delta 64 zcmbQFG)swlIWI340}wnd(b~wZ%&ZozpOK%Ns$W!^mzP?kA77qdl&znfpI4lpld79o NkO^gP_F+E83jlAr6*>R_ diff --git a/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc b/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc index 1bc5815900c09dcc5d59b8b7d1636dda5e5ee5f9..aa7c3f1e644fad42ed757f11378977ce0dcb50db 100644 GIT binary patch delta 56 zcmca%bHRptIWI340}yyMdT-=D$0!$~pOK%Ns$W!^mzP?kA77qdl&xP>ma3arkO`zW J|7VPp0RZ}Y6CMBn delta 64 zcmca$bHj#vIWI340}wnd(b~v;j!`W}KO;XkRlle-FE6!7KfXM_C|f@{Kd(4HCsjAG NAQQ^o{GBmU1^~M}7T*8> diff --git a/crowdsec_service_api/__pycache__/models.cpython-311.pyc b/crowdsec_service_api/__pycache__/models.cpython-311.pyc index 6ec2ace3e093ffc22a4a8f92ab2f5aa7fa9fef13..97dc8ab9423814873dd7f02e0d3f853cec266a10 100644 GIT binary patch delta 38106 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 eFN=H>jY_-J)SXx_f-i#VTue}TziT!j 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

B0m`fNvaiVY2Z) zOF6SUp)5T-Gx%YiVfH)Gw&9M!`X1Lqk>IlcZpvr*!J4HW&HIwpjw`F zpbEoLAx#BATD=QE#9Ez8RYEdAM=4p&Wm&$?MRYTf-_EiH;0r?_$Hd8fmYi!~U z66Y)B4%*kV*+>J#Z7Rg~A!7DTEH1Y7laIH8C}5P-=C!^!;vz2I#H?4Q+)C8t1z&Mu z;2hT9dI^ZAox^U*r*F$qQOg&jzK|#ka68D8fI4C7kN}tmFo)){N5=O; zacaO=gy#P#kp#B zRd+Lhrl-|Ts$7XUz(%?0qq4=CwpMD|+N`pltyf4`w$!i=uC+TL9rO?zpx>6aw+shO zYMBiPZ3Jur2*75*{eUfit$=NS2LRgvq-dRP)+50He6+nKX)#;GG*;JZtm3Ol@zX7A zvUY-fs2CNe#EX??7Gyw6n+wIi4zmn#(aa*9z7yIB@_<*`gJ8R@n`sJN0C2$M4*b3MNcmS~7l6Dsxqoipr z%5J*;t()!n)-}&3GJffNWW}dJCQ+q1fYErE(yQ7XhnTx7;O2 zg2PsCL#XvJ;RKQad7!uyPm!Q_LZi51HLK}i>tsfC88VQgw+*%8DpRzNuf%UFS=0^C zT+5>r_D*9TCXiDv;VD!AD1vrxk$2i8i%-`yTkI*DoV~?A*RmN(Hsj$dqeaO&mY9lj z?arI*Sr7%3LP+}|-Dfp&aupIPzFNm->z(vJQ4YqZ=kj?Z04hAi%Js~8ci8h9xwqD{ zb@uN*%oCcw`{-@Gnyni1tmY5ZQsgvIe!F0-rN%mo7CQ&H0KkW4!_*HEqys7~_S)@Q z4F{JrMz;EO+KXTsFcYeMUKW6NvHmaoHnL-yTX>Pguzb3al`s|~iVtU>&13p*^wk0o2#bDil7LkoR~aogBqtq<<>q29ZwoQk)ql$VhOaF3^DF<8YM#%2K$Y8Q<0q=nm%X!46NV#>dJJ{Ai{P+TGr53NK!KO+J0HoSww~is zC+6*C?`wVMf+o_why3~A-svJ~6Wb#4_p!wP-$s-RJNR#m$Sf}$lt-?r9+S(CQTy4= z6W*7~Xt~a_E49@Qh=O`+{0MP?IbN2~N7*?hPk`LER_-$mSR5;cKF01Hv<5lulhE=) zkdKi>73*yL5)uF}cnRNwazz`7Cci{YWV!7i8_u+;=veYygAd86%TJHX*Uo)J_#rmY zfc|SPr;jA%-J0USA=b|umSa>mf(|}%>?Q9(Oz!vzQ%tr>wPC*Y2wk=*oXgM-#T57Tm=b0 zx;MWyJ641~#jLk;UDb-qZI)XsZ#~8KD0H{##r}L(b(m$x36`y}g_g6YSVyH;w-)^# zH0@oc36DPm=z5#q5Mr(pbkcl_1VEk`_#C^cDe7Ar7x&hFhYUpg2ZYEze?*9C_z5AZ z<`;yhu3r(N3SCek)v7qD+6{4l4N{S6J3K|gwh&bz1N5IbXHa}Brhl?IikFQQ^LQ+_ zcwMT82z-gfbZEhuFuuep+^x)sU3+A2q;(ideD{*{`WmN5F+jPBGhVgc)24P@R7Hr*URh~Yp-z^XADY^ zfL+vj51CiBz_fTlLDh8AVxwx)irPXAlGK0GK=@`@1&r~Lf#wEkC*w43f?s3nQvP)H zW+9f(sJrW{Vo#n_5`4A zmF``M$0NP*OF<|Np!0V0!8(9THPt-G#N#PScT3_$R>%BZ+}wN`0h$*IqQvW~Dzte2*N5zWsXMBOFU)jtFk_5g%RXu6GLzwnNH;c)2^%VFW7*TcKix_wWXPSZ;VY4Qiu*>@~2F@x?7&+g*#ny!b?2&DeLPBKgG}YNfhy) zv3#*rUW1}E-6gYh75p<+CDvYG?Q2_Xv$WbQx)!0O1-VFahk4+0I6&7_{SXJZgr>r+ zAHSO=yI3;)lyfcGtRJ3}kh-UJc2syT-nuWM~hl;4a7POUh@~zzfOi!E+krIpX`Su#xiq@bg#LIJuHbIxnXNasoHFkxdg_F39nb%qiAS zKWMjVpw9dTS!t`bSqQEHRZwn*w2I%^rg$nv@r6&>&P2#H=@JKT=p=sonw4t9R3WJx zca@2kudx~9G5ytDR;KOfUaJd$r@g zWr3`psQi|7Q*z72RSWC>mvS)yTmUZk$;;9LJ#$XG;@=t99DZ`6_0xq3&Fqv2^LO&o zmL>7s1NjcG`4%ZMx#V z@lGY5E!_B;vWwM;YNouYT^ThULy4taQKDPiq(yy{t|u=CztaE}faw4e08FW1M4f?0 zaG=gaXck~LU~fAKG`ie`$2w%0gAnbB%|)mZP=#9u_2bS|qyStk5w6NUMeDUwEpq;C z`hVjiZ*1E~szu)wX4o^Ze6w)uP;v*18LPjBU3%CJz(blXpG1&Sp)H6qbN?f z)i6k^x#=dkDi|(0^;V+fWl&h%Z^=WQmYrLeAC{D&J7jDQ0D+Ll-ks%T3cY#%8()YzBNB|_uR;>A+ z?@a6|iu)>4M0J8E{IRE}r8Q^vRUB`6?LVbj9nlj6a ztYSGL?i9t$nSpotmO_kbqHrBv<6fFdtpK!HJi{g8n$OCN$n~ zTsE-z25ov$XJ(!ve~{8uiE$BiK}xhx`YZA!N|0hyK5mDY$x0L5jwt5zR(!;Lp-MM5 z(xf;Ps*EtesWugeb-k5Dkr<|QcZF)j$S`H50T)s>O~;E@aXC!Mq-j!VA6 zf9FK+1;b&^5LvShx+c>;IlBH`nH!;Gz$a+S2XMk6P#y~jwB%;nkV@UhK7n`{@`zasVmrz>Hvc~iht!cyMq0eoFUT8^+#VHLuN9Ag9zz5(gDN)3Odq9imwb+ ztRE>J(3r<&ve=)esEUWHxVl8{kv9%gJjLled4wr%m@?Ra&24ibnW;?i7W;=OeGHz6 z%xjKJHDJrzJf!*AQw$p}hh}e4HC!3%id}CWRvf4i{&=|3dy=n=YS}m*GFFoWb!r>x zAgp==Kt@GDy@-bp2Po+%&G@`_T|iyFa$56Ahe%FZYClt;4Esx`C`V8=U~We&wXIiz zAJH`1dpB5_Fnh<}p3n7Y>(3|R!>#tmnJ_&+= zTB$_!2|Uq|_oThzRW~Tz{`!iKp(?-%$BK_p#TI#cW+%oT69Y#ob$ZJu^^y6X01=%c zk0TDSuA}&Fq%uQO0>!qEEl0!@5*7mm4OgRdh(}09`Ha%;X7I> z@g{X4!Wfexszxh!)T)8-%h3`V+R05v`ZZT|0OE20Ljl79g@BQOu@V~E$=_n6AKav$ zy;RGQU;@krR00+NZUHO-+yz(zSP$3$*etglwO@x*A42G1zyZJ^z!AVvz&`*_0Zss3 z0K5XAGrAWL`VjCj;4cR{ISY?Fe-yA_oEn1BL?VS3>ZU z9`qX<^ivsXDIO;Q$|W?o&6qo{d;$F=1pTaoYDUr$z*4~NfaL(XoS!b$Ux!Cd^>0RS zH((E7Kj0wXFu($M27nv3=^AXhpqlQFrdyopf@Qk?n64|P8;0qUV7lp-?&+m_b?F{l zy1|ximZi&J)!KMPQcVD)0{Q_40CE6B0QrCsfFghqPz)#mV6{v)A<}JzbR!{MC`gy} z(RF%sGalV;N7vNRRdaOto4miRt1P?(6qW+&0JzLdT`sD}DiO6C5f*@LfbD>t0J=hH z4?=qZbe9m_0dx?LhXA-mM!WC@*R;?@D|BND-E=}%l+bk|bRh@br9rn~&_xz>A%(mZ zVuUP5S31zG4A(#g_Z`rc1$4UrT@XMY^wUT7^pQM$#!la&(Fl+-9%Xj|b^{Iq4g+xTlTKjLp-DQaNGA*FG$5U> zlc&k>3gIj=egMF+Av)YbXHn>&1)X=G0||7bfL`X)J9K)DOz&^$ttq{rq<4gBkn~mb zZbiN#kRj}3)3!0~+S2|g?N8EvVJ&Tj(LN4sD5$g{fW^7CFs79y7Ii8up0JFeRRYc7 zX^u(LCz{mIbc6oSby(vgQT-*^2nCI3ohT>3{+o{^ktWIscB3S zXC^51V!(~^koB@sWuWL#D(C9;6P4AL6Q#;N78lCA8eLk#=1Er(`;9$msAc^mHkK)ud}Tp@=Bt6Yvq}jS@6S>EEl*S_Z?@~*4|FA51=vH6WK+a9w%A6MiBU@= zcV|>3z*18q=S984P(s30fIYM`m?FNh#WoIO;>rT0i{?{me7+&n!j01vB&POGlVx2bTm{%e(5sC2#-3EgM7*SC UIe4cMq*z9-P%bO3k+SXn2ly05?*IS* diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index d2625ae..ceb782f 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-06T10:20:23+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-06T08:55:11.675044+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..126c2bc910b857a2e9f9a37b752933160382f22b 100644 GIT binary patch delta 38 scmX@lc$|@YIWI340}yyMdQapwWsI8WD9lw8Wo9ok&@(jCGn$;w93&T`pOK%Ns$W!^mzP?kA77qd Vl&xP>ma3arkO`zWKWFaK0|3w_7Ki`< delta 76 zcmaEx@->BfIWI340|=CAZRCz+W;fI`G_ue$n4HfXq?V$ek)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x4-&)la60AeE<1poj5 diff --git a/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc index d87cdb1bac7f4880ebeb44a85f3d6e4d5ffdd4cb..42696f19c3e43872579b26552eac83aeeb0cd2af 100644 GIT binary patch delta 68 zcmbPO)>+2AoR^o20SM9?y*F~-Wo9ok&@(jCGn)LKIY=%>KO;XkRlle-FE6!7KfXM_ VC|kd%ELAtLAQMP$PG?zV1_0057Ks1= delta 76 zcmeAyn^?xZoR^o20R&35Hgex(W;fI`G_ue$nEakONG(M_BR@A)zo;}XFSSTNzC6Du YTR%BJuQ)#^RX4F96UyEk&$7x40A#iq1^@s6 diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc index 7d05d919d947b7bbc0e723946bb4f0ca957ad427..3e88c891390825c560e15015c0909def60f81326 100644 GIT binary patch delta 2202 zcma)8UrbwN6u)1&{mZ>AE&U5E6k6yXM!PW>0&Yt-BAAKGfapdX8}faf#nLt(1&0I4 z;*#w_mo4AJrp81})EG_7Qs;vYOH9;9vlt$h#<(TEEn8Be4<=@r=iEww$zZp+zx(~p zJ>U7AbMCn}T|WKeY4rg`D3`13a+Nf)JS5|hRVmBw_mMP$g} z60J@dslrT5_Ej7KsS4b%fm?waH*gzp^9EkSEY!}bsRK@#DXAJ-dqF>@QYVvvTT?Q1 zU699Y|M42&Zs2y{OXwhj!2JjMY+07yleQ5SVgZf)Xk&dR8m-$=5y(6;nXb8l&Uhh zNxmEGJc*D%4-;oI`CN8}%~*j3#bsl+?3BEX;zra{yl4E0_~Yoi3!wubX5xEs-HFg8 zelRzPhat0$_lW!E`o@E3?L&ATVY3$BFTPRSqSxXk@!~PdgB?PjP~vN$FDpTE7&Z@* z1I53UTRUw0)!K?1Ro(+Rl;i?CTj03cEyA`a87>al26Rp9Rqeq{wbIO+O1o)~k#2F< z9yL6N9z8;JG$*tIUq&85z$R~3?@7l1NfkeHT-H6=#?4wsT?x>7$JM^3b;IQkuWN17 z(N)(ma=v)jed$?Bdf@FcbVJIegjn?k#emPYruUk!E2il^Q(52p#>t08UtOXGoVe2)??$Q9$)eA!AI2x?@Ml`5VP<)+=qdIN!v9SxaI!gx1GOWO2=8Bpo#8C2SY9O-e@`#$?Ao-qfo5U^=9!&$SHmg*?KDz1)6ImYe|GK ziK!hjiG=&fAH_`g{S8_4N2W0rDJi4rX_iT6*^31>&2wO!(E$X5+>c?on2IEbQ+yEV z+$zz#kqAtoG1}U-p5MkM&0&lknlvAcl1Jjx=tIX4dIu4j0Ahp>iRD-=X%RPL`9b;h zTn;`+@MYq?=yCwz5JEq~0Ky=`O9;aVBM7e|97i~bFfPu-!v>1Ww742?Yslhq7NDez zq_dOkXugn!uN$97`+_LN_mW9rZJS&2HQaH!?l|3LyI0>&$`ax|o9BAfdy8egW->^Q zy6f#L_GsCtag*c<+zzy_I1^>FX0S+smfI~oEB@YcwPsMHT2EQkmR8B;DBHAU4K6Dx z4$15<*P_)~QQU-`Mf0vH9qAN>#JL*n3E+pG>6q5c>NojYe{ z-uSIe-kwxGR}?G3&qCLQ$ci#dn;n7@^5;*KkPpaB!pJz)$hbiZ^AsIjnlWiMW?@p} zW*i}!9k{8AE5OZFycW1z#U0G5)xlR{wwYSZdDS>>*IY~juFObU{Z(nac9T1RyMfnj za%pBs(mddB$^`$kc5&c)qM(X^YsRWIfIvOOc5E9fF*mf-2r(X!u~S4=H+jsI}#yZ!?*ldwC5i04LCHDX3Uc$&D;5u=^j=1 zkU5+v+F4r5W|HaL`2{^ytVw02^*99UF@#=#qD5!(Sty##D?s_O`LN_74M9HT^%WkN zzoUK?L%R_Y0IEgbk9Hrz0lqG`*bbq27~u$iC^rXBpxKWwfUs3hKgL(>UVhT*rD|c) z`r97)XYE~E@-N#%bPzI((&GiQvbx9Zd$pb3s_LMcqLgEoayq8)@;*nDo-Ukoj2K!g zP42^*MW^zXPS>0&J;d)jqkP?OLrKpT1WZ^Im(JhW>6i2s(*Ic!S(l4GkMi+ z%I1>rD$_5a{|bN5)kk0E;qJGW+@7D^-jc&-9Hu3L_>04LtLDSSl2N!!#MN}Gcf%Pi znFY5HPhdUJyWx(NWZ|%qK*xH=(G7op$tE0j;&7D|Vb-EqPF+W2f5|DlLZz%#A|~P5 zU+C$%V4!{cX6%Y8-k13L)}08rIeGvApWGwMvAK-4kYXqFkN7}*_0)(&2chzv|6M!$ MNBQ)xU4n$bzmi(Lp#T5? diff --git a/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc index d705642e1226909db262b964ed97acbc6e614089..b35426cd109e4b092b975c1c8d6cdd6b56edbdaa 100644 GIT binary patch literal 7214 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 diff --git a/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc index 43a3794d6559f7bed7b0eeec2036e4ad35245093..8045e26e916fbaed30d5e4c1561c9c74519050ba 100644 GIT binary patch delta 2287 zcma)6Z){Ul6u-B9ZC_ve+O_MSbz4Wrwr+2K+WmoTj7^-3B|t{glA8b@{9s~~;GY<&e$Wp_zi4720YV~aqLJ^@l;Ag_@!VTkTbRSwykE~b z_uO-S_nhqQwF`6CGhx? zZksXdb|MogP;>;;RnX04x&w4eneHT3y^1Kh3toxXW*oZvylKj=R}%?zX-3jL=cOst ziug}&5q94bIg0z2cmT(YqWd9$6P&}VI!mMqXx4y_ON49{UL^|d8Ceg&YPDWVJbVo( z)By#r@T(Vk5Og18XcM*u;@8&^d5P4Nol7DCQd`m?Xb6JVt!z?Bz1|4t2#{dOt0ciu z0;Hj&!~XTKf1OAukr0q-0uqgHqIo>Eeh<>LJkyLnSx$CGdio>1>@VX)!=dQ0)Cm%$ zbIBy3(dknu`bw0ZBwev|9RAsy^eG-^>rJg2Wu0VW@dVNHQaUzE@=_*#h8(r5G!Y># z8{vJZKv=ZoY&e* z2SLwESu&r!F4J1R_#B5J4x2et=A*;xkg^|Zxi6J{hQ?BgZtg1bSS#{4T0(568Zh_6 zdcK#9dTZGZRbdxZr+I*H8D#IP?Gcf38`r}e_|ey5@JOA;Be?^Pcgq<(ogAX%2Uk)K zySzmf11qMpF3)(81$T9BPiMx&C}j3zW7&*mEvtthw?^sH7rrnm@ z1z)XU?6troek=ELpw95*bXKNw)NkYI`ph~>kSwX_#6g~Q%}$)cALQiV zK7+Z~1?FqsDqY94hkdke5#M2Lp^a{F#L6!s6&fhcN4J=diy@ia3^|8Zn)3M6q9ZX* z;>a_Y@DoQHpT}S4(v9zxu^GdJ9cT{tXJLQF01yh%dLHXIz?seLwk62yVTIjj_TXjq zL-VS19W9&6KdP=4W&7?}_So(ijh%p!(F|Rkc@s~R*pF?4_zz~(z6g(TE+Gz$ z02-#;pc%?dyR;_ui#D}EI+9AkEeH|mCca^W!&VO4IqcxDi^EGC_Hx+ANPDOG02dFl zEA5(jhKncI_w6lJ{A;0E4yQQGvq$ZHc$7suGE0GmdmisSkFVhLn|9*@;`p1>f7ST* zV!IP|c;BQ^LP=8t|enl<8~0$Lp}4LlGlfBwfh I4MMbk0LqNt=l}o! delta 2219 zcma)6Z){Ul6u-B7eQjU+)<0{vb!$fpYuOuH+l`FD#$qOwK#a>6prn#O!@GrIY3q9( zATq}X48~|;auUEqq92Tgh#$1ZgfApS6ZMl2i7_Q6_{A@3QlsDSgZJFdwdK$7HT}JF z&OP^>-#zEtcm43i!|KPXst|k@hmXfUQ`59x6)GWreMCALUb3`dJkoJ8aea++qMdx^HO=GvJr9%V4m@r`XPF*d$6k%A6sA)ZSfE1h6T zW3gCdM)J_9lJQdVNU3O+3T!l6&acQ|N}od1x>1$N*`ur`nfWv9hzvLFensJZzC?7o zB*UJreyc4{mhA9y*G6iC@14_D2iFx??%xoU&njmfXYJRdk0e4q;s3_7Y zm4MgfyVM0)+W?%m`NIkBVT>Y-aH!c0W|lcMX1cfvU)l~(Pt|R|O+!QIGmMbppxKQv zl*bV^!#|EK(-SCeL73!FlPc_V<*ME2L(2@pHiRjJ_N2x%oKT*pL)EX9{g!AmPZC{4 zGDlmoa4Z5DH7H}k+BnPy`rw>bfh($8Zls6L)!~FlnZ^(?ggC+)43y48bbIx9=X1Y8C)NV#JjLmxU@CxAo(-g(O)4ok7#M^b0ly}S@xSVDKX6hl^RVVG9L|xt3vMZX zDEe&Gcf0#6GxOZK&k(%!b5XMzoA^u2PGgEhYsFNE;@R3dSMQxouZ~GgDwoWPrZmcf z(bgW5nys9DrBKT1d|noVW%_3I*I>Wp!MSWt7!Ex%(@ZGqtiUR)ts^gD-ZeXNihfw_ z3GcVajc!0}aEEl28Y#HGZi(K8$;gCH9JT#MycU^k3}{MB%aw>7evY`OR-5zRxkYCV zBZ=%2n8c$8==JJy^n(^A=`o$}(rC@QyQt@nWGf|OSEW*(&sL5ZIlf|AI7A{w2xI3t zoSBB%&H)I;9dL8dPk)0S2Omj49NX4diY(-BszE;V=KCDM|c`x7s76Y=Md%)_9EkyRLRy=V_fF-gEa{?s#jdZWSh(`1&r7-ti9A zZ9=z`K=@X8^o~DKcL;+*+`hU~h%OWxkvfTEsO}b45wsC{1yeq2_+Fs5ZsqT4dSs7< uj>E;os~$0YZY1bMNI^8&OW%g6rc~p{nIWI340}!M)dT->eU}7&b&@(jCGn(AR6eJg_pOK%Ns$W!^mzP?kA77qd Vl&xP>ma3arkO`zWGclj$1OS<06#@VN delta 76 zcmX>qc~+8pIWI340|=CAZRDpOK%Ns$W!^mzP?kA77qd Vl&xP>ma3arkO`zW-)9nG1puBE6&3&h delta 76 zcmaFO|CyhAIWI340|=CAZR8GRVmH(?G_ue$n4HcOq!y>2k)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x4-&LqML04d@ZlK=n! diff --git a/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc index 53c1b9a9ec792af93fa36c27f740d87492cd99cb..512eb52153c2bc137bb63a440015110ec25b73f7 100644 GIT binary patch delta 68 zcmeCSZ?@-N&dbZi00ilc-W$2qnc2$>^bF1Pj3!$$2g$|hXXNLm>KB#f<)s$s$Cu|9 VW$PD}rRpXYWCH2U8<}rO0|0Wv6$1bO delta 76 zcmZp+@3!Y&&dbZi00O028@bh)*$wp!jV$yGCR;KGsio;>nG>u73b%q>LwOsLfM;FGT)L00QhkifB*mh diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc index 3dd88f559c910ce5387a7850a10836d8cccbb337..fe20ee9de7c6ad0a3a8408b09b998438bd38cbad 100644 GIT binary patch delta 68 zcmZ24vRs6FIWI340}!M)dT->O!Ngu>pl4{NXEb>gQ;=Mwenx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yiti;UA4gitJ6kq@V delta 76 zcmZ23vR;IHIWI340|=CAZRDQ8#BQi(Xk?*hFnJYIkXoXCMt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~HdikX)k03GcX-2eap diff --git a/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc index 46ae2eb243d215432d14d619a14b512bbe5e3d54..f7000796ef3d1b259af4aed0a258e6f390517a6b 100644 GIT binary patch delta 68 zcmX>myHA#TIWI340}!M)dT->u&%|D4pl4{NXEgaEQ;=Mgenx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yioXH%^4FJ6e70Lhr delta 76 zcmdlddrX#lIWI340|=CAZREbs#BQi(Xk?*hF!>`>kXn*{Mt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~H7kvWzd08gbDM*si- 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..4894cb66b3025d0a72998a3acf69e62faab17c7c 100644 GIT binary patch delta 54 zcmaDPc1w(VIWI340}!M)dT-=D!^B=@pl4{NXEga9QxIdqWJ6|QuA;J3-Nb@S{i3qX IVaz-n0Gjy^6951J delta 62 zcmca5_DGC-IWI340|=CAZR9?~#BQi(Xk?*hF!>%+5M#zma3arkO`zW|6_I$0sx?e6_Wq} delta 76 zcmdm`b4Z7KIWI340|=CAZR9RtW;fI`G_ue$nB2x3q?V?ik)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x5o#_S>l04-7&5C8xG diff --git a/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc index d4f743a50282e1bb623c56cac65a0e44cf40b373..add682af865d6198d04dfcef60145059e7a6f7cf 100644 GIT binary patch delta 68 zcmaDK@H~KfIWI340}!M)dT-=D#>`%3pl4{NXEgZ+bC6u5enx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yi9Ka&40s!NQ78C#g delta 76 zcmaDJ@IHWhIWI340|=CAZR9@2%xXk?*hF!=^^kXoXCMt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~I|gGF8i0D4{+kpKVy diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 057a909..cdcabce 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/v0.16.2") def list_allowlists( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index ac2cad5..ee88346 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/v0.16.2") def get_blocklists( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index 6d90155..fc85982 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/v0.16.2") 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..3a854ff 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/v0.16.2") 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..8771c93 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/v0.16.2") 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..0cab685 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/v0.16.2") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index c5b2050..23e369b 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/v0.16.2") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 73f5656..48b7acc 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/v0.16.2") def get_integrations( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 322c7c5..c06d8b7 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/v0.16.2") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py index 5d173fc..42a511a 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/v0.16.2") def get_products( self, diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py index fa41f55..8e19015 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/v0.16.2") 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..59a89d8 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/v0.16.2") def get_tags( self, diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py index dab3932..1a880e1 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/v0.16.2") 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..e424031 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.45", "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-06T08:55:11.675044+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..54c9236 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 = "v0.16.2" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock index 2dd3cda..e9f5faf 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.40" 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/d0/50/269986277f852cc83029bccbdcdc0b343a685cfd570599e58029792808d8/botocore-1.43.40.tar.gz", hash = "sha256:2085a4314cfd2c8bc1d08ab8039f76c92e99278db0d2a0e2437010526d5d5d70", size = 15639899, upload-time = "2026-07-03T00:28:16.125Z" } 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/dc/8c/5f7e73fd66b28f0705bc55d7060d41ef72328b656b86ca53e75765b3ba2c/botocore-1.43.40-py3-none-any.whl", hash = "sha256:0bc9d352267c9e48415c5d7bb61ff05c3f193eac2fc7e69cfd229a05fbab67d6", size = 15323870, upload-time = "2026-07-03T00:28:12.56Z" }, ] [[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 = "0.16.2" 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]]