From 866c1dcb15dfd78ba614b7c14759dd7920a53141 Mon Sep 17 00:00:00 2001 From: nitescuc <1108077+nitescuc@users.noreply.github.com> Date: Mon, 6 Jul 2026 08:57:43 +0000 Subject: [PATCH] Update python SDK 1.133.0 --- crowdsec_service_api/__init__.py | 9 +- .../__pycache__/__init__.cpython-311.pyc | Bin 5024 -> 5171 bytes .../__pycache__/base_model.cpython-311.pyc | Bin 4378 -> 4378 bytes .../__pycache__/http_client.cpython-311.pyc | Bin 7768 -> 7768 bytes .../__pycache__/models.cpython-311.pyc | Bin 158635 -> 166723 bytes crowdsec_service_api/models.py | 415 +++++-- .../__pycache__/__init__.cpython-311.pyc | Bin 207 -> 207 bytes .../__pycache__/allowlists.cpython-311.pyc | Bin 12917 -> 12917 bytes .../__pycache__/blocklists.cpython-311.pyc | Bin 15121 -> 15121 bytes .../services/__pycache__/cves.cpython-311.pyc | Bin 12321 -> 12364 bytes .../__pycache__/decisions.cpython-311.pyc | Bin 4338 -> 7222 bytes .../__pycache__/fingerprints.cpython-311.pyc | Bin 12310 -> 12353 bytes .../services/__pycache__/hub.cpython-311.pyc | Bin 3277 -> 3277 bytes .../services/__pycache__/info.cpython-311.pyc | Bin 2035 -> 2035 bytes .../__pycache__/integrations.cpython-311.pyc | Bin 8075 -> 8075 bytes .../__pycache__/metrics.cpython-311.pyc | Bin 2607 -> 2607 bytes .../__pycache__/products.cpython-311.pyc | Bin 3782 -> 3782 bytes .../tracker_events.cpython-311.pyc | Bin 2914 -> 2914 bytes .../__pycache__/tracker_tags.cpython-311.pyc | Bin 5698 -> 5698 bytes .../__pycache__/vendors.cpython-311.pyc | Bin 10351 -> 10351 bytes crowdsec_service_api/services/allowlists.py | 2 +- crowdsec_service_api/services/blocklists.py | 2 +- crowdsec_service_api/services/cves.py | 3 +- crowdsec_service_api/services/decisions.py | 80 +- crowdsec_service_api/services/fingerprints.py | 3 +- crowdsec_service_api/services/hub.py | 2 +- crowdsec_service_api/services/info.py | 2 +- crowdsec_service_api/services/integrations.py | 2 +- crowdsec_service_api/services/metrics.py | 2 +- crowdsec_service_api/services/products.py | 2 +- .../services/tracker_events.py | 2 +- crowdsec_service_api/services/tracker_tags.py | 2 +- crowdsec_service_api/services/vendors.py | 2 +- doc/Blocklists.md | 9 +- doc/Cves.md | 6 +- doc/Decisions.md | 152 ++- doc/Fingerprints.md | 6 +- doc/Models.md | 105 +- doc/README.md | 16 +- public-openapi.json | 1069 ++++++++++++++--- pyproject.toml | 2 +- uv.lock | 26 +- 42 files changed, 1579 insertions(+), 342 deletions(-) diff --git a/crowdsec_service_api/__init__.py b/crowdsec_service_api/__init__.py index f2c57ce..d57f24c 100644 --- a/crowdsec_service_api/__init__.py +++ b/crowdsec_service_api/__init__.py @@ -33,6 +33,10 @@ class Server(Enum): 'TrackerTags', 'Fingerprints', 'TrackerEvents', + 'AggregatedDecisionItem', + 'AggregatedDecisionsGetResponse', + 'AggregatedDecisionsGetResponsePage', + 'AggregatedDecisionsSortBy', 'AllowlistCreateRequest', 'AllowlistCreateResponse', 'AllowlistGetItemsResponse', @@ -84,6 +88,8 @@ class Server(Enum): 'CtiScenario', 'DecisionCreateRequest', 'DecisionCreateResponse', + 'DecisionMachineState', + 'DecisionMachineStateEnum', 'DecisionResponse', 'DecisionTargetModel', 'DecisionTargetType', @@ -138,7 +144,7 @@ class Server(Enum): 'Behavior', 'CVEEventOutput', 'CVEExploitationPhase', - 'CVEResponseBase', + 'CVEResponseDetailed', 'CVEsubscription', 'CWE', 'Classification', @@ -149,7 +155,6 @@ class Server(Enum): 'FacetBucket', 'FingerprintEventOutput', 'FingerprintRuleResponse', - 'FingerprintRuleSummary', 'FingerprintTimelineItem', 'GetCVEIPsResponsePage', 'GetCVEProtectRulesResponse', diff --git a/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc b/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc index 2db00239d7de4999aa3c5ce54bc923355cb316a5..3928ef80b39c9b6cc6748810525d9df4eabc131a 100644 GIT binary patch delta 249 zcmZ3WzFC8BIWI340}%Yl_0Gx_-N?tm%(!i`IJ1jmdU{c6dSXdxic4y8W^rbIo@YsF z?kzb?@nZMXlAzS$g8aPV)LTjj`N^^zl2VcgKFplr;QXQzr^?L{%$+RyA}~?k#N>?3 zywudPHM{JgWT6Pujk2OWxTdoMktd} Ux}1rd=>r3TY+wh$A{n4x0Yuc7v$#^ zr#dATr%uk{xh5{=mYJ8HT2xS!nO722nv)t_nwy(gRJqxaH)C- diff --git a/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc b/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc index 1bc5815900c09dcc5d59b8b7d1636dda5e5ee5f9..3d20aa7649c5c748eb5f90d6ce7a5f858eceb613 100644 GIT binary patch delta 20 acmca%bHj#vIWI340}wpO_1?(sD+d5VrUkwL delta 20 acmca%bHj#vIWI340}wnd(b~xED+d5VP6ep| diff --git a/crowdsec_service_api/__pycache__/models.cpython-311.pyc b/crowdsec_service_api/__pycache__/models.cpython-311.pyc index 6ec2ace3e093ffc22a4a8f92ab2f5aa7fa9fef13..4825d4d4513d31379ba265d62ac953474572a6d3 100644 GIT binary patch delta 38068 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 delta 32381 zcmd6Q2|$&_`Zx0e2L(YCPyyKy0TEDC5D^6hMG+Bk$qi6ZaRGhN)RPIOmbs#%j+&-s zu9=}!r&6z4dF!^R?a`v%u4Sv3wvp90zvn%0JTC{S`}hBSU&XI^XL;tCXP$XxpYzgY z=O;dB?zZ36)!7dJ%!{1fdGdO)o9t4k z4{JkVEo7K$p=V)R?xuLRY)5`>(ywKmAMeFl*w=;oP@qA=F z-v;>xP*{5z<|kH(S6(n3dG;p8g|Hv&vV zjHHkUWynJfm>xx8D`eQilEE6M-z4>KoB8(C7knbcdsN2T*?`6*3fm>ac1s$4o1+xt z2p2R*Dc&FqbiT+OHn_;L^8}YwGRn(vSKV^i?@(6_yvjXRdeyl9$)p!akpI~_yWXAW zA%ppLk31QvnP-3{QoNTXlJG*LcfAm)Z<~vjNHOg!k=C_Cq&M0jQi8XylZ$6ziwaiQ zUjF&|z(MN_L==H(R>7njT}m|Ij*T$-1swwG~ud52zH>Gy#*d?y<)G0^}7zIZk0F^d{ z(jM*@cZan75gRZTj$ZX?`=bi@bFoufw1Hn+30cM|{LD}fo?Ye5Yu0)2KjOlb_IBdv zRn}IxCn~LY{x_~-Rg~hxKkpKot`i^>K@9{@4N+ZX;8Q1w0q_Il$-mMW;`Cb9g|F>r&61F`u6q>C69E}{!%a>wO0jU0U1wdu1fIafBbcPgi1i#udUCTX>)VMftc7Uy>Q-Gv^N;B8)z06z} zfNOEilXcyaFU-CTTG(AwMF9*z5VOTJ*4-?A*8uOkXToc zBKQH$@WIK28vjKky>rR)4G=cI_ZWrOkFZT7WWBiZ4YaGCV z$bV8sk*!!%KE<4Q#b6KqaY_iA&Hqf9r13Lbba9f+Zfokntcd1~*C|!!Y%n(uFdv|k z$6WXUK9GN&7c+Je7Jas@ftJF&dgy>U0h|~ZlK5T*q158%n9V+_8i&>KKVtUk}&MWxDS@|eK^xAhXWW9xc}I{gYWfP3RT z*8Z`nZW}V&kiylDhr)H$;*ZV@Hb9?@!*26Dk=e!p`X#cfSZ8iOr0)#s-n)V)^zjib z^rEqtcG6Ii6qz22t~NSC*a)(KjbUfeV*{%%iMUEp}{U~kxG$Z z>@Q2&vq}uT#l~SMawq1tArUe62wd9%I{=RYkXm20Ti^#6z^@IvsPVK#8zl_Cw{xP6 z6uaRE7%z*XPQn+}<8GO1S%+}>ZF^MmIAQ`Ou?-8ncuB6=+&oT-v@_#e!9-q*RuxUa>qIJou?T6+JsJ72d8BlFV z%gW8jy+=>-6i5R0lU0tM=;l(MUY@RTbILrri}vpG^vDWB|wb`urd{G)c+x=NIyO z8%`tO4EHQ3_OdRs`VvB3=AvMRo~L&a0x)skiM=H;mhZ*$FGlh$6UW@a3|vAoz!@?F zQIpJO;1U_a@|CPRUq7k95Gi9AC-TcDL%8qc6E+7j{{|(%SticpF;CvI#ESxZet>uRCxsm}l3#$us=z5(ihe%w6=G9!_!_Qn z0N(<>1L#O!g&*J}{`9nGG}2ckx6=c&rDwIn%%bALYRAHR3yY;{SPhu?uSLF{awt+} zMpjz2W7UBT7P*_kOBS$Vl>qjRg3 z^zQ1XeC~`fK020v14+P5#;?v8uJQbvS)u*-{F&|bZN(ucEv0|8UM{ zy&}z2JAU+t2fsA4xklB4r_A)`0cV4GlL;;%196cghM=$b|Th6&Vs{B%|pCM zo>DqoH>0a|7%@C8r`nK`oiRAAfmwf5lHHIN(3QVB zH%=37H_qmbo_HE1IsJelklJBjwS+zYu0?=O(*{kFXegNC_Ck|D4}ZOOs6ckhWk1 z>#Ea-6vPffX>_X47Xg4Q{>H*#8kxStw|h7X;5DmT@~kPYRr8IROy9Gn)zeIeYXCq; zy+8Z_`TWoO7HZV{gF44Z{Ix|jdc7Tl1VP|)FkCuv8Sn$ll6pHb!;!Q%-S?Z@ewud%!eXuEe}q{D8Rax1ZzP68X)M3l?~1SixjCx z`MmE*Ki+1^0Ihu4W&;z%cPz=WGB7_aNz!+6IiLhs!3RGOsS(Jb+9WOf*8`a}4L7FB z!Ba5ry);OcC2whN2P%in#knz{2w1Dg>9-gEZfSRo>=>%X?WYIvRm)l$wDBw7wJgS6 z8@8gXC4kv-bT%-=R$Cnh(tynf_75w<__|5AM>JxBx@|kMda$ z4boUEAeH#}q2fC%I?h8nz#&Cj@7b}!ymB&+Qr}w9DxnF5S^yG&qmq9$3tu#jTVN45 ze>g)bPl1tj6!Au>Os_ob%KcY1*QSKoR0&v2gm=lxmUpNIBd7zO(W>FOm1aR1Et#dP z8tv#KMQ-GkQ6b!2w%qfp+G$zkQdaJ(eE{98}+Kb@_I4fJMAHR34c`b9Xh3#hRrpTsKvhE&@Rk`3LRkLPYa%kg9`2eT_ z&Qt%@vLu|ZtMHdYhm$M(dEk`RqVG>ENmRrs&OCJebCUX}>xZ!kJZ3}g?c#W1LmX?* zFK&3>rgknv9)M4wohzwP{>bNO8n#Sh{{|b*KioKXd?t#Y03e%~EM3(OvkRscs;T5G zEix9WX>dBix0Hrc)sAxHG^5mZr}{8*2h=G1;HL3ft`Af9oV_`V1@oPo3p#X{;kJ{n zLvp~c=5FP?rOv#+2#_K=QsK|fCHLWHM7sf&Stm`7Cm@x+`AV*B=dm8K0d_oai+KjP zUUGO`X3}|UUTEXoaijz|@ye}cGsk5ooyz-c>lOeNu6CYMq?XRjD=jQ6&az%vgB((yK8P&3{`Y7bHU z_{ey}b{WB#E&6U@QGD6%E5c~iU{MntwTE>USg7(`LKK=$&?YC<|fQvPFCr)28^N3~P- z(CiVJDLK_HLxv8|&C5yaXJhDp6d3{H`PAL!dE!x0g!8*qE6YFRvC;k~5L;JyCinr8 z_)CwO$9pDo-_et2?V0I;R9V)GQ2fn36Kzs^5!3+v`H;ucG&#OVO}*rRT<^>1p}19@ zdpwA_U^PzdgxHb%x4k9esdkDZFWL9F5^g8fr7LYkMKk6oKCWW!eB1suRipMl!!U?A z#@f|y7V)w}K79Pa5EjFi9Gu45SABi(D^_eRMQv3%2$^9LPJ%c22Jopnyp7;}|Toh04U+C#>=jdpt0cbk< z9W}vq#|{|2m#K~ESc$F5uCiw-*2Pp2tTnRhaQy(d0niDs27Z78eB;w=wc^%LCUY;$ zRI*GQM` zO0ZL8FyLcp;ylIT=j5Pf>G9rLzH)=+74v+@^Ta4==4PH4DhHS+PK>=nU#@^6;6Jh( zX~UhDwBX}Un&&_YpYv9Ke*R>R;f!RCSn+_H>15agP>~ShX8y5_vvB#xT(Rbk20NQ}-#P91bx8S*_&HNfbxoZ3A z&sc}FMn%{R1OUI<^PMjiXgoEelmRa-U_Q2n%5F&G#-mS%@ef{(&~{(sVnEHzM4oas zz{*n2I2)$#9zBs7;LH!54U^sT;?w^8+Sz;R_QtaQIX)D>5)oJ5%iur*RVU6pTEkAi>)~I{ffOU2K3Plfz?P4f*S&Ex<^yOAEeK@Y43L zsZM|7!cTwTpOB1LeI(d6b}0x39JVHsLiG^y;lFvS_dP?1>)`qvNLl(JCE%D$d83=~ zD`e69vv1A&(*4X#L^Q>~K#&2Pv}RzSBrvV1#DkC+@RD`nLHtbh{R83=N>WdNt0#c! zMook>*t$HK@B{n{w0hx-T1F<707g{%;C=H0S|tfSyI*qs0Zrdht~kW8>32Nl{b+vW%1fHXnncxB`$f#(thN~-3P^(BEY&uH+R33WZ5yjuNCil< zh#TUVMXAPp?ZWq7^-m~9tP%;f>w6A@0fViH%rP6QFrN6;GjaVXeH!8hTQ~7i_yL9? zeLB9ViI=v8YB`!KHKDK*8mrk*< ziLtS~WwN(ZhGZz+IGbOt?aXg|GbTYd(m=2_hgg7|g00z~4?n;}M{N)A(fDTk(6{DA zvH4VpKfib3p5L_L8Q-;RsxU^71I)87jFAYv_Fbo@2w=fk1>9#%U=a~G^rZ_|zxQp5 z$YKxyEU_lC*j$|0rU;aS0N^2O0_8+t_qDD~5qJOu0BfuXJRmDILGEFAR*kBe#`IOS z9I2>DJ_uK^byY2cAAsLhRUSW>t7;jsw*H5xrdV46GJt*7tgWE7n{wmtn%tG32RICR zmbSZ6Gr6@lV&j@vWr2fdVN3mmFz-il6+om6lFWI=9-+aa#~)s|4Hiu^qvH|3IAE@D;*a z{pinQKJ37c)_!pZ!}=&91Fj;e#jrkV&fAr@x)qqvME<)#1aQNWKjgNHi0rwwBCc`X zA46Ke&q%9{1d#SIO1tIv~-u7#De&#$mE2eR;`4x^2WZM;4|SD{$U1 zU3}Y;1&VY7`-&M&u}*9NbHRC6TKzO`5M2hy(j~jF7UK0*Ocg#Z@(e8&_KlC!2l28y zH)`EdFo@Ik9SQar%3lSbT%U&P89<}Wy%M2-?owi<2B|`BmbLP7yBc>9=*j{&d&t$` zr&_QPVuCB{DK>;M^MQ*>s+!BLkU(UeeG?trn4isostLIPibcK~>&QYxiNdhs6=k~Q z#p3OAur6(V1_uQ^fn-#`lW_e5a0)=n*ujWGW}CF>I06VzB5n2KkUUd=D&A4-^kzm) zr;gX@rWo(THt3FYsV{+sEmb{(0Kis*2=--38nH95_TqpqGukwauOJa%mjPR~UA087 z)N^2J&-@c!L?q;!rM?Vjuyv{4f*)WnH2W;RsK{?o*2DZ*`_xzA`7gk0fY&A1wl?Px z3^)v0Z{Uk)ou^iUjdt<79~+tQmkGWN5`d$U;Ef(4)bR@g)fjBwV^jjF*9sf(q>eG0!uo83nU z1)P-SDSb^cbz7?wwIR$XD%0y4*+e z$GpUZE^Lwkwj--nTN*f?)^TZZfmDKl-X2U}OOy}isIknBXWbn#Tz zI$L5dg7R6SklNfrq{OjyO^L<{qyR&$MdKva$FTx~m*lzjm{^~Tjp1(WkiH{zL2}|# z$6|8?0ERnZ%-2>pbZ6#czs)rki@G;$XLvpp>}S!DKPnQ?=pCfK(9twA49ZY_q^T588c7M|dNIE|C= zLNH*NH3=_`#Lh(4Ea9rG>^s~*Yzq>A6(C_TU~NU0OqMI+da*9BUXSKV>-9h{wrbd4 zFyrdC$Wx~~bj}5^5gC1l7$K+=Z;jV2Nh~t1iQ@W#SHNCNaYd^b)<;MyZ4imQS>+u} zwI5Og4qBJg4{Dbz#wN4adOLkEnXQf^JFVWdQI4?ujVV(K>(Nvl zg@Xj(f`uuuI!+Gfa4S?4rLy?c`f67HgmCR-Y}-vF62t)Sff&PA2!s?V3I?%hVo*QU zu?!s%;{y&kh+8Ox-gQ*Yz4QP7658%*DI->DKfjuPaWSVvP}Q8H}ekEi^R_WOR%r!VlorOfI8|TOqPGyav_v!ikVc#oZT25^@DZS&Jh{ z6UU~(Y;cD&vY58pNHS6bQku~Mp76=68@D7wBEMw+m%>N|VL%$#>V~fn2s>3%jmtw= z%-xqoe`Es~X)TNXnk=5qV$lhG5T|j0q$3zG10?$5D+GL}*9|WML`*pI6D32LuM?)8 z?$y!a!U%a%?)jl?&190+|3KwccjTy3tbyu)q4D!BUz%k$3Jj~&VD4Q08WC6rL!NYv642L^^9wxG^0TR@T#RW z;;DgVdDM(%y_=H97*GJbVW9wdjM4h~C+=aHf3vS22a166plIpq$7#h{FoyMQim3@8 z0r<$8sR`85v<|=9SeDYQUOY{8`1zm+__UcgIJR!lEgyv}bHTJlbw&&qF=HINs^3|& zOj{-)lCB9(gdgDF%`m;9xr?tjIi7`UUH3$-+_gE(ReU;vxrx3LSlgx~Pza)co7NI2 z1jm`;;|Z)gJ0@D?u_ZAWS!AgWNIjG&H$1*Tc?BUa8jWH3O9fq(h&4L4nT2uyTFY{jUX|&~ z?L=@P`%}xwn^CGL8ALRbu-z z)?>K!G1!I!(;)B&YPT&=PxK42&G6D<}r>4s#*$^;zpGIFkO;vdN^Ar;VYbVz) zS`ydM3m?esRvOEUD1}o4=~BJt(bY5kI667N+jqPw(&cWPHTDH z&ko47tbg3kJ~7~)f%%aYc@MIgsd_Q%s+9Rbl9or+EYc$jN7AEh;K#uqjZgQ%MK|B} z!*u{~5O4_a1mG}0C%8TE1H22l3CRqWv`nj(u#IM^?V*CoW7<8%{H3g|`K-3sxRgB@ zVg#Eyibp^Zpg2p4{qWe3n7XWP59x?$*>ELZI}~lvP4~ui^B8z1=~mf`i}P7f1QOfSxTA;)Xo+HG)hV2ZDdAxj zVHVxddWFk&pM&_fbt~f1N;WvOLNaQ*cR7yufF5G#D%M9crpGmcvWuB4TCHaJh19#K za}k$%f_ZR}j@%0u9SoTdmvv{NE`Xn|;!eU3kR(f_F2q*|w*eQ)z#Tr&>X*OBv5=0>Du64S?e=Qp^5YlOQ62j6LEZqTO z>dSKmGy$37_*(XWCc!gW{6ZPM4 z(lL_;>){sR27w*wq#C`z^(u-0n2I)VRwjV)F#pRZB)8{({L@1``nEg;lC_B~(@OX% zmC$s36U$`=G>F={vUEMgGQpC3Q82Z>U(QlL2B%=6b^@N9jOD%d#jwtz*A`Y3O8vmU zz=E!%pCJ*hp4C1eVpp>O@zqwWWIZKEFfLnJU-rJp+{*4{ABvZ@vbF3Zk+Y4JNpt-6 zHg?nn8m%hGFaskpPx06zY+oBXpU^;nV#0Rzq|M6!BsRMI_5t{#}(pf zgS}%m98S`7WIA0qSL>zK>5T;)ihA784RzBUoo|K7k+Ls`blsgKx1QeO^j^6*v~({ERebEk>3_+A zyYv|<+nM`5`M*y^{yw&)tbuySa$8^bgl=2f7gb^q{774ulX6t)=10DEoh{LaF~#6*8`+Db(;oY|-eCqzoEP4K1>4 zwB;e8UJXBoA7F-yspAvuQ?nX=PQv493nE13lWbMLwTQM(Lc{kozCaM=uG8=<2mri- z3LD5LtZm2L7Pk=tkH~po2&(>yRz=H?$P;FA9Qx){Y%Ja3Wy5hFTfRss--Z-p)P@@Y19B1V`IuKH0G z2?QM7_AaGmrt`H-qs_fQQX8b|q<0kofD10B>Cdp&nVez&V}mxso+L~rHvX=fhHsG_ zz)wtnuFf=ktC!@hsTWuvvw8C1I#L1R#qYKhl?`&11`$d4!Kg+ijDjo z;Ro2*LOSg66#^ZD*Cgqnf5eW*nX75mKiLe$$;^tl_$r&?WrG{z2yG=|b7r00qB#9RIBuTi!MUrrXt5Ny8 zI3XDDc?(m_>+D6dxsvBN9%u4Y`I~IT|DyEWkvU+vt8`eT4=*d}`|;Q*14LA^e7xwp z^K$uU|69y0`tNCld@H4+2s|zithPMIqT+1GUA3hkt-&JTF;{WDvpl9d_GPwNv^&p6 zXu8@Of{L(WugBlyObolgMkRP4qrb|P7a{|Ga5Y`Jz#PoA=2c&73&o;$nEU@?)wKl& zfc|m_a$D8G%c|;J=-d##R<&X#bVf1dDJuJQ})4xhNCKK zY9T0L2f%h|5!HQwD16e^U01le0dy9Pu7U%&6in%3%+&redxVJ@-_^Z~>`j$q+W0w} zi9T9#EAQ%y>?XmgkNE;MB!H~ zRC~F14n5M#FP(B0uYbjQ(96BG@+O%)44ZvXp0P;#n#GGf7nz4x^0hP&)dqScu{5H= zQb?nM)X9)W`eet*W~G7C0RWwFd%zEH1;WKc7IMgHTK)~IF}HvoBwY4fy~^F&Rcc#6 zb({2}V)<;*Y_+I(ZqB@!g~R8~npL1KRO3OAWRkC`*J#5I`!7+`od0 zbRr2Z+f@J^>5X8z_MHqDm9!6Bbo93`T(?z+{IosvOw}^eDWFbnI`L$HI3T{I6wf$Q z**9$D?W!l|pwgKFU+{g71CDACar8#7YCy#fMQeNb(W%N{lQ=n z)LNM--nqf1jKXS~?)fZjF)bAVw3wC#m-S+r?UkZjye`U07v2Ev6)4sbH`fQSJAht;yd_))-szlQdz= z_AqxZo9$0roXULeDpzB`72qr4O87r6r`44=nfdnf7>%u}pIO)GBM|j&N@N@e0)CKr ztMo7iRg&EAhDsd&g>}CBnNC2afZwb$l{@5U>N9?2+n8gv)Uqsb`BnK2Cw?Iy;Wri~ zO{83HXoqjp=HFPj!VZX2zss&@zi|75{l{UdZ0TayUKVW%{gY)dWxqW}vF$glQU7G_S;LKequU4!GbyiE?R7w3D+z@v4iYU^gT#ELI4h?NC)Mh zxz*-t()z)mWd0SySoVL#Fshm0m5k63xTwfka0O6TITTJZPuXw{1LOb(h_L3$$TBQN z|BWvBFIYfO)C+Vras&)@mv&&J>?_N)e@(wNSF+9WooyP{LdjrW|37rMY6>_ev8KXB zvg}8rE|PG6c#>Gt;i6$krpR+s?$IRL>M!>xy3V@ML5?l4mLhM!afsEO#A=FfskAgp zRPM9O_Kn|x5f8RfrrqHZ={!&ZxXax{^B!`|&v{Q}4t4RyBwBqc@=|=Y$6JTcw|oXGN||kk2{zUoyoGZcC8{50 zyA5~pgJ36U{6Vs%DY0%yv=A%-0>#2M$}YL)-&(Pzo02S?J1dW73xBqHe>*CGS}y0pUV^G{8pi%6n48S?U7 z-LYGN+yIlHDGOm{sRLV~Sv(S66JW|q*#}z4A&L` zv~_3aUh)S7(_R@d zt>I+EvUx*WY$WWHumYq%^lGDJICSTy8#kdU0AIE;1tlqa&C}scS}kAct$bnFj3}M) z;`b0K=zu;-Mj7QJ;J*d16#xmV+u(WxupK}ey8|xjsvd=lbay9Q#ON-#h}+$8(FpD_ zxQOpPaM8PykHZC_sCym8O57*E8%}^N^7va)H~`{+wyjO6eU-^(DICzGK*k|FRT+L) z*ZB`2Pe5OBw5!rae3`14pT#&t*~$l|>2-njVr@UAR)3=ONu;KVKLVGofgOe)AfvT* zVej4kius29VXaJ9ycfsP6xGm7Ml(*Ng?lj|T}hX!yEa`JCii4XXh(HSU_j0q|h#y%fN>(fZzh9EuZGawDvAq!BNX(vjak!z{l zbCm8aLQoI{WrcSY_vR=|%TzCTg-NKkm&<_kE1zm__@w~)0|o#F1BL=dNT{}#KUPOS zp-4Yws1_ig5Ksh|1(*w12v`Jo5U>`o0k9FU1<$Lgy8({__5lt9Dgnm;&j4NkoB*5x zyaIRwKu20H!S!#z7l5mPYk=PX9!!EaAP5i!hy+A4yE5$uM6_ebJ>i)Q=nLo%pkJZD z4@uB(Hqg&4&@Uv=ZyC^U5mY-)nORaWmwsP>ej$LK?x)A~=`nnIyPh7Gr#If|rFMEs z9j~Ix{I`Jk9>89}A;1y9QGf~XA^?v#)4R*`E;2nyOb-In3%&HHF1>E{=`ec!i=OaOmx%=P>nC|te-e{S=06#z=AQ%t| z2m^!zA|-U7JB@TLkuC?)Ej_wyN7v%$mYSL@4vtj(+_R7<8;}FY6&Iv$Sw7qo0fm66 z0J@qm11=oOr&IKFM4gV0(?M=J@=T|aRUGT3L%4KMmClyZ$xAvONhcQRq#>R4qr-W0 ztd0(*$#Yc@AWj+4u^&1?M~WIr2RYELQ}n^ znWAkCTD+%4Wm@Z{^;KHVq;*AF=PRStD_U`(^#PjN)1;fGxinj(Nt{ZPB}`jr^iKnI z8Y0pNiH0mRwxFJxI#BBJs1u@2fowLJ(A&+fx3n|0&64D=Kg(^DWc3Y6U$$1e(wbQD z(P*Vg$X72%h}HKfCrq!5Q4X?B0nDYwt|4q0cOAYrEkXU6*gZ~ZV>&ucc~UX0$WvIQggDjMxiHt7_M%LFuo|&vi4x0dOz$pH^6kZ2%arzQ zDrR1{8_JmLO+w9GGg-X3Om@G^mMd*Kb(87sBwPnrT#%{sxM>M0W~Ob+mF|jZ)C%RQ K;t(P$>i+;Y-kzZV diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index d2625ae..1cfb655 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-06T08:57:32+00:00 from __future__ import annotations @@ -13,6 +13,27 @@ from .base_model import BaseModelSdk, RootModelSdk +class Total(RootModelSdk[int]): + root: Annotated[int, Field(ge=0, title='Total')] + + +class Page(RootModelSdk[int]): + root: Annotated[int, Field(ge=1, title='Page')] + + +class Size(RootModelSdk[int]): + root: Annotated[int, Field(ge=1, title='Size')] + + +class Pages(RootModelSdk[int]): + root: Annotated[int, Field(ge=0, title='Pages')] + + +class AggregatedDecisionsSortBy(StrEnum): + FIRST_CREATED_AT = 'first_created_at' + FIRST_EXPIRATION = 'first_expiration' + + class AllowlistCreateRequest(BaseModelSdk): model_config = ConfigDict( extra='forbid', @@ -76,22 +97,6 @@ class AllowlistCreateResponse(BaseModelSdk): ] -class Total(RootModelSdk[int]): - root: Annotated[int, Field(ge=0, title='Total')] - - -class Page(RootModelSdk[int]): - root: Annotated[int, Field(ge=1, title='Page')] - - -class Size(RootModelSdk[int]): - root: Annotated[int, Field(ge=1, title='Size')] - - -class Pages(RootModelSdk[int]): - root: Annotated[int, Field(ge=0, title='Pages')] - - class AllowlistItemUpdateRequest(BaseModelSdk): model_config = ConfigDict( extra='forbid', @@ -244,6 +249,13 @@ class BlocklistCreateRequest(BaseModelSdk): tags: Annotated[ Optional[List[str]], Field(description='Classification tags', title='Tags') ] = [] + store_full_content_in_s3: Annotated[ + Optional[bool], + Field( + description='Whether to store the full blocklist content in S3 or not', + title='Store Full Content In S3', + ), + ] = False class BlocklistDeleteIPsRequest(BaseModelSdk): @@ -420,6 +432,12 @@ class DecisionCreateResponse(BaseModelSdk): ] +class DecisionMachineStateEnum(StrEnum): + PENDING_CREATE = 'PENDING_CREATE' + PENDING_DELETE = 'PENDING_DELETE' + APPLIED = 'APPLIED' + + class DecisionTargetType(StrEnum): ORG = 'org' TAG = 'tag' @@ -1380,7 +1398,7 @@ class BlocklistsUploadBlocklistContentQueryParameters(BaseModelSdk): Optional[datetime], Field( description='Blocklist expiration', - examples=['2026-06-11T08:40:13.370581+00:00'], + examples=['2026-07-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..41094b4cdb77f1d2b581986103856ebf0c10b822 100644 GIT binary patch delta 19 ZcmX@lc%G4aIWI340}wpO^`6Lm1OPMT1#bWV delta 19 ZcmX@lc%G4aIWI340}wnd(VED81OPLl1zG?A diff --git a/crowdsec_service_api/services/__pycache__/allowlists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/allowlists.cpython-311.pyc index 43c12d0fa29acc733d3ff5413d13fc4bbf224419..3cf258774cc1c0ffc0c7304bd3fc36629fc77cc0 100644 GIT binary patch delta 28 icmeyG@->BfIWI340}%Yl_1?&xz|3T9yg8SdLmvQ$We6Ss delta 28 hcmeyG@->BfIWI340|=CAZRAd1W-_waoXgCi4*+<32MquK diff --git a/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc index d87cdb1bac7f4880ebeb44a85f3d6e4d5ffdd4cb..879998bcc93aaa0383b6d3b00b654520fa53c500 100644 GIT binary patch delta 28 icmbPOHnEI*IWI340}%Yl_1?(+fSJkIc=KCk6>|W7H3*&n delta 28 hcmbPOHnEI*IWI340|=CAZRCEy%w%M-`7N`GIRI`;2aNy# diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc index 7d05d919d947b7bbc0e723946bb4f0ca957ad427..3b3a18bc9b77a6e4c8a8ec4727adf8cccbf954dc 100644 GIT binary patch delta 2163 zcma)7Uuaup6u)13^Z(wYN%OZ&+O$cVKV4I|w$`R@gSFVmtYd4zEx2yA-g_MSN@+?WN zP;**OC1zlvx8ev$W#GCRZUL^Z;a1?r8s5lE)W*!z4quT;=|&Syvb$^e9P)Enc(zp2$U=v_;o{z)|e5NO?<80%^%AW&$o!g$hX|XS~J)s zF8hMLh9zmqykz=H{7e*tFX3CcmgRzVdkqJzquM1QLzZM-Hh1%Pb>9*TPw0b#N(7ur z5}T*_TxPy-?xK<{HDq%$%5z{>dJ*F2VNlpYJ~zL>7A!ym{F;7HbO@d{z8-NGH}yXd zUkrT@ARGdS8k9a<_ahAO?~SeeQP8MShWGB$>EfsMYnrFqSg&=$ z83(Pmoju!H>rP*&sa&#e&@-SLgp^BhzU2wO3c^h)YB$fpGOAU2uqQZMl_^taK%Ew~$NIV+U-uovqZ)?iCAUzB znv`bThk+C|o81a8>GRWz+1xaRnbP`ClW&Sse))eruGhNSHh^0FB^_m1R$x(MMNJiA zD7l*&h-^9CyfKg@KNrsgMm4(1^zbKLBjOiCIm91yWXRuqGB{x0;TicT7_D@@gMS=! z@ZW;gL}j8tbGu|Ui6AC1yH6(J&?x!6m<_#Olf`Iw4r7s$G?|%W*~~n9xxnU>92gfg z0D*ww!>|gU4abRt-wOBdl<56%7^YAk=^Ci!SKFjZ7-OF%Ek+{bG5;j;$UctV0fcsd zC{f1wTC|CD^4rmTQhXzqgBKFKnUn;&96>mSFp4mSkVJR|;S|CI!fObp5zZn^@e8q# zj^Z-IKZtd=&g1eTKuMa&%+IhB`9cQXZptFsmv|}GM`pOC`_hWH^`66d&*3WDJlauG z77#bB?wbwoEtj>bNhjEwZ}x21B4xeG4T95u*Wa_@h?kA3!6f)Q?{*Gt_!4EaYLJ8` zcUe}K7Qt#STh(PFE-NZ_!RRYDq191Qti%4I@xZKx^z%aetw!|(@I|lS|38e_lemX) c?&-aAJSmc6kn!$6tAksWyMONCr1&B3zXtWji~s-t delta 2185 zcma)6TWlLe6rFL_Z?D&O>^M&RO6=I)Je=myrg;jIs3{5$m6jqbD2cLT>f$8s+NlC{ zlvYHdNWABxy)Gyo=5U%3{FEqP@ZM8URlt?DD9ucuk;QiWXRJWntR)|d@$if>9#zfIlr||X zY}Ko@l4ixVP6SqypOxU_fdS5gjJGg}IQQ8|s}f=*`AMMKb=6{h`bn_LnLwBcg!tYz z66Wh|HR}eYo#k)8gjR7%A32WX1RZPmTGxMAGYVczL;6us$jv`TNkO>`?bs<$w|mCoBEy~d)oXepXM5X%HX1n&N-9xvO&Wloi#>i-sleWvH&#+(8Hi)Qb|6yyp$(-kx_cpID}o= z_r@QvUxt`2fIbGYN$m%F0AP^bG6$`Pz#IZNOtGakGy&!az$ieykUB<3E!|kwPFsH2 zCwI=)S(p2&EsQ7WSGJ>gT$9A>`|SSN9&4(pj8#$+3S_mQPSOr(LOjMC`BxZRKxGrX z7zk-^NPb;gwb=tuJMY+B*YT!PHbCA|JKb`+spOKVB$;X46-x5PAAx-_fH=S&b11lG zFwwqnyT=6>3csTrXc^IsKgBYhP`U0YX3BcCn?3mXtDHoB zRQSo_V=&eY{+hpU`rj8?5^~G=f^1P+AOmDmc}csqUoz(AU&t=cEA0Gj`I_lq-~p^@ zD*;h=@Aa0G-i`=~>&C!^i?C+(%^Yc&;2 zCDbh2D&vyvL}rm>GfU*50$Eg-m@}_q5Du$;$bFVxj3;p;{Uko|uxw1GF)au?h}ZSL=FIj?zszH`$O`DyYK{Iu7t4 zz!bm{fEj>UfMWoU1DphS65wfoXXr*})UW{NY5H+zS8x%`0)vw6cxGvVJeDhD*tbw! z1^;>aSLXnJf_8PCTX%bIxtq$8S3ix*2=KP#z0&aNT3OFs2IOkF(zESMl#QI5kSB06 z(6jAMmd)H@L4l5&9mCuHk+PLLY)EpIMQ+-`tfY1zv%l=*UanHnDkB4T^=pIOXLNXg zzLz{N^Y1Qv^HnDRydpIK0B`S(X>4&>S;>+K^({Kpdwq6Bz>}=<-5-~Reygnhu}2UW F_y7&-6`m!R4k4nk45c5R?WPi|45Zc(5;6>C9&hy@H7=%MhXVBiEOj2`;l zEO+@MN^zPV3bdo)n|U*D=jZMB-nro_A_<;i>&%BzAzt_Ay7J*vm_HxLMe@;9R3I*Lil`lzh$_>-RW~6w;Af>&Ocka{BKQE= zsf1ukQ^f+ESuD|n+mv1@>Dgi-oijbJ7NBDKj~5C>J*`vqfeYk8To_HbOz~`bj+(w{ z%HGLlC^Yy_q&0e`s8V?H#VpOKAnE6o(}me0FyiqAeICldq^_4v=CZV)XRHNTw6DfI z+z0b~09vCYC8#9jQg^8?>Q>!UME%TqSIDfOdM^c29@VExbEN*KdR&BhRsU51_6t8N zL7PtvG`G!ms2x-S-AHPX`l)D7PKess!iQS;t`+EjJBLg$4Hz_~w*acj0?V0RM)d_&n94ZD0gyrCMgHMgAfE`I65W9k zAy=X82K=nF+R$US5mI)Q1y#7|YBoDGRamlnYH7e;mZDkaqrh5|hsF<0OpG5)xLFK_ zV&GDU8CU=b1uU(ggNb>xg%V|^q$t@!R#%jSXo?!m&2m}(l<8NLOfIcyilT`yz^+}p zE zfQo(aBoH%@VU({Zt(&4swTvm2(D#U1c8QvDwxH?hLWU|?RWp5hdX87ZjOMADO`|VU zbZ~8&>CTok)1S^!rgIV5UO(qT^;wizR?M3|tq6i|Et&ydDKeF^jErlmB_EU=Cg7ma z#|z8y)<9VfX327=-T<=;=uLUjaim&Oy;)KY{!I9>u!`?*Q&L?w-OU!>%q@pto~|;v zV4px_)w^jBXei6&u5zf{c~iU!^W1ReS`O=>y1eRDJ!O&=%Hj4vZ#D*8H2~Z<^(aus z#>{oWl<9k!+=5D#0-Q6~MbnL@*HKFA^GYer(s|AF)=J+zO@p4{MFNcRgt$%;lIhJA zGwGaWiWf9EkUY6!8ea9VgSAssck1UBC|f*>gHj#G3FYxbQq+ZfN#Rd-pp&Q#Zo22F zZpNL5VW9I=D}iZHJl(EGSU>23?LjhxWEja_B>Rx;M>2v00nSE|96<5}5ZHA=Efuo` zoqHNL?16n7JD)-_ff5p{&89_w1zT-NYyhQ#ut>$msf}LL= z`P?l=0$&gyE8c2=^!BZE+>iFIM~60|``4oTD_sNE4&0vo^Bg=E8-d4SAPi(h`cfiY zBSvTv@+}d_ZRvNx-voah`fbQ+G^9y3i2L#}`t}0V^o(N&(CQeKXd9Jl8>4aq*hTnx z;OA9cW%oPqKH3{uSy*i_KA5SNR5zFa%vBE;nz;gmAj>{5D91!r9n-SMz!H4Ex9lm4 zW#3KDRgk#hNG(e`I>B1v1}=Rqb7JH0EPDaS3`+t{co;fHjv)(899KuN?J)NH*b%Jr zhNrQ149Rzafa@%3y4ho6=p=WoHs}+63-CA4H9rsswiaM( zuGGQoQlCAY1_v_wa;FP-ru_;CfL3Y)+DbUO;;r<=S30UP>Fm8SWCRBxf9WUD-pivE zIl3Vat;s_*{0=w4H;V9$2CAG$WO$_NC;l$LaxBhaJhB!YabRq`nL#8cT9LfZ2pxfZ zP5Nc<7s2bHn*d_u4e5vl;tty|;SgyL=5j_Js8cs4jP`PIq=dpdlt@vy60}dtQR~u$R#8T zoiF3iTcOher34~2C~KIs#&Cewh{={N4(lJm2o@%vY;~j@llOZ1FJHJPA2Q@4kZ+x| z$_;sPO`fcw@pQ8{?L|2D1~`&y2pnCDjyecL_#J439~eYeY(=+l)-{`Dny%D?l>dh! z@P-=F7NN*ecLPw+>p<$ z$>(Y?KHm)Ee?KUA(g>Z0e0vzkosmC{{bB6)$v-BoMngJp;XK%|i~lW;y00(pyZ8-Gb_`RU zuyc#=K6lxNf$FA{U9wO1qmPBdWLBqn?du->6JLqV(=hDz@T|qC9G;I63bct&cW#Y7 z1-G@7aF)3ZP`T)b2-XjPK&%iT@o8Z@v_5OdFG9XEWR)B8YisgrHMG9|A4F?HVE8?m z=*63&0(=Q8iWyK8_!3^oVO>^~w-?emtA}-hsOi>p#;)=OYJpjCs9Hu4;g?pPQ_k>LG|_BZ&Tgxe9PeSEprqHFY6)N}NHcwf~6Wz|dkJF7mdk!CU) z@x<sehPI64b3`)2GHRF)FD(shb{CNYNxlqt#(GDwLU0e zZ#{jeU(n%K5*{>hwgXI%okmiF{x-{-vNi!J)OKK=z%r>@!n delta 1116 zcmZ`%O-vI(7@aA*-Jf>1?RHyQN)^%=T~PV|6%~Yl#*;!!Xktv$8ORz0+?K?j5@JHo zgE1sSA_t5lCV0@8D2Yd}-Ux{tnw~g#;b5{Tcb%C+A}F(&m-pU$-xj?NRa+yaX7eAp&U+ijfHzn;Qq^#{;kzNox>*cXXBq^&})8 z_K>UP67MI3>2Oh(|%-P zjcR>NK#_SN9Y9emjCoKc<-up*0ZfO6ffXkU6&s%B&h=Y@4693O*1?%PMt3s#l7Mh7 zyTfj`(@cRZh>c`hH1(1&of*d^A!k3rS%o~&lTabA^@OO}VAe+(&6Mc1K|v*(p$np) zdKy{rrka$3R`3^m?}asizBD?^V^+@x4mbeFi^Kx3VL@MoWY-%eF9I==kiL4X0QoMR zBQ>&_WQTE@7&KBS$qvpZqcGx}rD%yx19Mncxt}Ms zGug`4C8v#XZgeo##h{yfQmr#A#<|Gg5`!aWkft*aC#EvUxlAg2S7816pzj;3W}7+ zgq_Pf?ERK1?8&^-!?Jprj11tcowKJV`}s${iSN%~S~|cA1{qu@F7cQ;GQTHh-& zU~_yR(WpU^n*bmDU}BV@CPu1X{9xpZCVn75NF+@(@_m{T{5E4e=T_Dh=I}M|*K^K2 z_nhB7=e&F6*sWvgbyZaeJb#_qcXI42b(Ge5QHAI6ZA!@72uMNB3W}O}X`ICV?)^NP6I+G^IKT z{`3}M4?UHmxPJ))cxDtm3<1309ADE}VpTx127G)XWUKHhQSi^mdIVOh^;#CdHK0%j z6oSI9Ug%NKLy)0O*cw<^-@xQ0R#SE^iA7j#Nr#{@2wJzgNoDnVBb+0`q9w1A1V@Rm zhLR5ZH^Tl6BB8`$K&lByG`>UT>D0ypMAPzIv)-``4CGd9W(?tirBiGsFBw2Lwovlqady*{3{Cn3nn*uf$ z&(t;bI2K$B%7XI?=~Ic2&*3dTi|*``83BWC*KG?VNf+GwQELZ3YyXw1eA3Y{Xtcs= z-p%IpOgcH2J$l+m<*ljo38M$>MmItiddLPdGwC^#nJTC;e%&!i{Ws;iv|dA>4un1c zO*Z;b9zfW{e|K)-7lO`yV+i!Tlx6eT8?sT0i!UGyBWy#c%x7%puPKMAmitCIWN9p= z=tWnN$61lb(-PzR)QEixtmpgrNU)agRTX|o_1Xt<%MkxqZSNK-ccUIhz@x9nU`0Jj zcjTr$AC@zCHaSGe53Q!$?h6)K46d5a`vPM{7U=5TlQBodD3}MbiL9wP%jzM>ty7fC z^FI@J;m% z2x~qBxIhYSeoG1Pqkc#3-B7J%$E#pHXb4`1LDXzUC;W*SDo&H=vzQK1Nk>H+AJ&Y( zxG2L?CT(UlrC1n@v;MT?9ht=0R63!<*enNY_*;=l`d;qmNS)>B>8woWso#z12JAXZ zu`H|T#1YK8ZYR#rPjYhfki}l?0uMFsl5S9=kAJpdk>2BNvCV#Q#L6!s9UCmpN3WQV zOEH<>j(LYyoATt;q9X|;ar`+<@WefhFVb&wnZ}RG*o;!fr<)_;S=et{0Aewt9%G#Z zIJb@8bws&4uJD`90lLh8Y+jSDr)6vTN7dD$>={pFUms5xiBnKA!!*`r-h_$f5Z0+7 zGQZa{O7G{w@%S?zSw-C-Qod7EY`(1;uasEvN(ql8=VqCaG2rr=IGth>|6WtZOK^dN z_)l#^^bc;;zK)L~ml#4LfJO~8XqIx*eyxfBqD^g*j;GUb3qnL=D{k07j79)#r24SABv=7h`-qT?&MH(Iif)4_r zf;Vg%rv-xen>T#T`u<|UCQNqXuf5iF-`7@f2wf(@=$&ZS{XloYDGUm!4i{WPbQ7QaO0?38Bz*{d{O|4>`T-C3d^eJ{ W(%}MG8!rz&5-WfH$GQ=PX#W5s#nKG` delta 2132 zcma)6S!`QX5WUxVeqLX^#9O>Hb`v{(S)5H-nvJGSqgERnhky?v`hlKARf$g)8PN~K7k94P*eOZiS?_pe z?#!H-J7eEpxV9kOk|Z;NXSwZE>pB%xSA)zo1WA6bBKQE~Ev;c|k~8O$a_pGq<~* z$zP3^(raeL%@Wiz=ay}q1!7B!iii2wdCDmFs-|$Hjf$6@Iu##jfHPJ?BP+qh{rp@H zFx|}lPP1uQy?lUiAiah77e^{q#zM9UJJ)h7r9fgI3KnXKL;eSIjG>731f^rvgHsvA6Q9 zT8g%(GMlWZ=vPn%uUP0^dpo@>KEzg06s%08>xL789r;@6c+6YsF@A}Iad2$|=w=`r)gF+00s5$59vJBdaR6YD zfhH8m+2U=Z>Icghz&?OsfUVr>2wgTG$MMp4<~d!g%F_j|oXk{9#;jT&eM@SguSs^? zPv@gydPDNjQ$aIbmtqOdH3_j%fEd6o)Xw^OJX%ugZ|EXb>g`#FIP0v#Ekdu_AXndW zxH$D)hp(kdy$j*5jtqXWbliEZmT-q&spLLXAsc68e%j&o&`WL`C%oz2Cv(F8)#gUj zM+2T$aK3cTGoc%sVGSHpdBbx|l=W&m+!L%qWhwZG_;mSQ7-}a#|ME>tZjM_M^0`7$ zHdiJM*>)edX2_@B%;r)Gn>$qXe&Y#zx%7KuK=DXD4fRW-MCv~(fxf3A`|($$i;<6Os+sIiSfq?K$B`u^vzRL8)WgMMekN6X zRZX*#f{sBrtOg-}hJM(xAOAuhw(L|j{7eFLEo!3E(aKL{XosqsA>nC&UG8rq`ZE5Z zl!(RtHK{H4Mf34q%jTriL3$@1!V~n{_%!~F`sI7EgTNC8h%k_`3IkM}z!~am z@56ocXnSGJ<^Iv-DN7#x3@#(UM>g;Ex_4H~dTtVt(|^75fg@fvaNUU9q3=VT4_t|| zi5tww<}6#dXa%v7sUDf)WgEBhq?Oc9u-mB*J#zcXdiGs9+VO%8_tK9N=ViW9@Qrc~+8pIWI340}%Yl_1?%`&BSDEyt#wPl?woJdrc~+8pIWI340|=CAZRD2yg8Mrj}-uS8wa`o delta 28 hcmey&|CyhAIWI340|=CAZRCz%VluMWoXXV43IJy@2B`o5 diff --git a/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc index 53c1b9a9ec792af93fa36c27f740d87492cd99cb..eaacb2bf52b1e2828e0a12122acd0ab5a061b667 100644 GIT binary patch delta 28 icmeCS@3!Y&&dbZi00e(>y*F}eF*6w(Z#HKRkpTc`76#1# delta 28 hcmeCS@3!Y&&dbZi00O028@aWZnT#wpn=^;V003Al1-t+N diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc index 3dd88f559c910ce5387a7850a10836d8cccbb337..9e880ec40e1b6a3b085fcb0cb5221bc38fa3f3c3 100644 GIT binary patch delta 28 icmZ24vR;IHIWI340}%Yl_1?%mn~BNTc=HOTc6I=5We2?g delta 28 hcmZ24vR;IHIWI340|=CAZRDQK#AIZ#c?DBDI{;mK2CM)8 diff --git a/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc index 46ae2eb243d215432d14d619a14b512bbe5e3d54..f321656a288269aa39273b8f2a92834165126eb0 100644 GIT binary patch delta 28 icmX>mdrX#lIWI340}%Yl_1?(+h>6MAc=LOv>)Zf%nF!wi delta 28 hcmX>mdrX#lIWI340|=CAZRCE$#AIZ#`90HhZUAVn2hIQh 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..7d4c73809176f503ed0256bf33a63e6bd79f8a87 100644 GIT binary patch delta 28 icmaDP_DGC-IWI340}%Yl_1?&Ro{7oWc=H{mHVy!LW(bb} delta 28 hcmaDP_DGC-IWI340|=CAZR9@B#AIZ#`3_SX2LNk)2Yvtm diff --git a/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc index 7aeca28cde4a0ff40e041360eb356d7d52e08cab..5f995d1318b86a8a12c5bedb253bc4b2ef92c460 100644 GIT binary patch delta 28 icmX@4b4Z7KIWI340}%Yl_1?%`&dg+Nyt##WpAZ0a)Cdm% delta 28 hcmX@4b4Z7KIWI340|=CAZR9RzW-_wa+`_z12moa22L1p5 diff --git a/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc index d4f743a50282e1bb623c56cac65a0e44cf40b373..0465be721e49635d40d0e881ea0ec7dd93bebf5f 100644 GIT binary patch delta 28 icmaDK@IHWhIWI340}%Yl_1?&Rl9|cac=I*pnJNH@<_SUo delta 28 hcmaDK@IHWhIWI340|=CAZR9@5%w%M-`5N;~6##ks2r&Qv diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 057a909..d1a9895 100644 --- a/crowdsec_service_api/services/allowlists.py +++ b/crowdsec_service_api/services/allowlists.py @@ -11,7 +11,7 @@ class Allowlists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def list_allowlists( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index ac2cad5..fa33f72 100644 --- a/crowdsec_service_api/services/blocklists.py +++ b/crowdsec_service_api/services/blocklists.py @@ -11,7 +11,7 @@ class Blocklists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_blocklists( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index 6d90155..686ffa9 100644 --- a/crowdsec_service_api/services/cves.py +++ b/crowdsec_service_api/services/cves.py @@ -11,7 +11,7 @@ class Cves(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") 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..2ed139b 100644 --- a/crowdsec_service_api/services/decisions.py +++ b/crowdsec_service_api/services/decisions.py @@ -11,18 +11,21 @@ class Decisions(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") 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..b279f4a 100644 --- a/crowdsec_service_api/services/fingerprints.py +++ b/crowdsec_service_api/services/fingerprints.py @@ -11,13 +11,14 @@ class Fingerprints(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") 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..45ef78d 100644 --- a/crowdsec_service_api/services/hub.py +++ b/crowdsec_service_api/services/hub.py @@ -11,7 +11,7 @@ class Hub(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index c5b2050..9bdb59d 100644 --- a/crowdsec_service_api/services/info.py +++ b/crowdsec_service_api/services/info.py @@ -11,7 +11,7 @@ class Info(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 73f5656..2ae1d6b 100644 --- a/crowdsec_service_api/services/integrations.py +++ b/crowdsec_service_api/services/integrations.py @@ -11,7 +11,7 @@ class Integrations(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_integrations( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 322c7c5..c20755e 100644 --- a/crowdsec_service_api/services/metrics.py +++ b/crowdsec_service_api/services/metrics.py @@ -11,7 +11,7 @@ class Metrics(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py index 5d173fc..0d93591 100644 --- a/crowdsec_service_api/services/products.py +++ b/crowdsec_service_api/services/products.py @@ -11,7 +11,7 @@ class Products(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_products( self, diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py index fa41f55..3500151 100644 --- a/crowdsec_service_api/services/tracker_events.py +++ b/crowdsec_service_api/services/tracker_events.py @@ -11,7 +11,7 @@ class TrackerEvents(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") 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..0f9f0d6 100644 --- a/crowdsec_service_api/services/tracker_tags.py +++ b/crowdsec_service_api/services/tracker_tags.py @@ -11,7 +11,7 @@ class TrackerTags(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") def get_tags( self, diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py index dab3932..80548db 100644 --- a/crowdsec_service_api/services/vendors.py +++ b/crowdsec_service_api/services/vendors.py @@ -11,7 +11,7 @@ class Vendors(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.133.0") 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..36c10ec 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.44", "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..f9e589d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "crowdsec_service_api" -version = "1.128.0" +version = "1.133.0" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock index 2dd3cda..c79ae27 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 = "1.133.0" 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]]