From 56388363529a970c18dad6c68efaa899cf68dedc Mon Sep 17 00:00:00 2001 From: AlteredCoder <64792091+AlteredCoder@users.noreply.github.com> Date: Wed, 1 Jul 2026 08:55:27 +0000 Subject: [PATCH] Update python SDK 1.132.4 --- 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 -> 166507 bytes crowdsec_service_api/models.py | 408 +++++-- .../__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 | 8 +- doc/Cves.md | 6 +- doc/Decisions.md | 152 ++- doc/Fingerprints.md | 6 +- doc/Models.md | 104 +- doc/README.md | 16 +- public-openapi.json | 1079 ++++++++++++++--- pyproject.toml | 2 +- uv.lock | 20 +- 42 files changed, 1569 insertions(+), 347 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..818de24978563939fa755f072471bc415013d78d 100644 GIT binary patch delta 249 zcmZ3WzFC8BIWI340}%YU>XMZ!x{;5AnQ_}>ab_3C^z@?C^u&_X6qnTG%;L=aJkOHU z+*@*(;>GT%B|)jh1^Ic!skf96@{?sbB&8$~e3&`K!TCicPL-P@m^)eYMPQ=7iOCt6 zd8xrAKr3%aU=wxCE6v^ffc+w~h_G{*E6hfh)RM%^oYa)b2f43pUeA-m%6M(Fj8G<{ VbU70@(+36w*}x8hMKVCY0sxvqS5W`} delta 124 zcmdn2u|S<~IWI340|=CAW$h8!$j8CVxN)*Lv&-g7%xx^2J2);d3-CLKxdx>c7v$#^ zr#dATr%uk{xh5{=mYJ8HT2xS!nO722nv)t_nwy(gRJqxaHavlWUl0H{l?5dL delta 20 acmbQGG)swlIWI340}wnd(b~w(F9-lM=>)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..73b665fc4a1d6bdf0961eaddc36ceb5ea7087f7f 100644 GIT binary patch delta 20 acmca%bHj#vIWI340}wpC>avmBR}KI~`UW5X 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..e9c41f8f3caf29750d0fd441b97d8f365138445e 100644 GIT binary patch delta 37807 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 b-`lC)%OcvI1+c5GUG?E*+G))jQ=R_>F_VlY delta 32896 zcmc(I30zf0`#*DlD}pSFsK~ykEFzoAB7&%>xLi?iBNb3kQ9(Rt>dger%*=h%u`-ve zY%x>GsMOS!f4y&u*e+@6+h%2n*-DH5`99}zZ})JK`n~=B|HAKQ&dix-p68ioo>|V! z+^@H|KJh_YkA3d$t`7KbVbtuH;!Pf1l*^%;BC7g%KjP@%@Pz!Q{g>~fI1F_tc3tUE z>{g;r>qKeoWSVAZAq_WgZnw_$_=FV zy2|(bnw1+wY5p=TK+*_Cx$Yqp7bxR`O1ya&<~zI#|j%YOmfC8P&03EnP~0zG` zzN>sTs(y&YdySJh+u2oIT+iG^MzrExlNA%73<*GTARq`30>Im9EFd0`2nYpG3E>EJ zZvsSBej@^6ly3aZ*f&@hFY7UYx9^r3tJ)*2Ba;L&fYA=T?q{FQz3ZItcZN^~v=Wmb z)8^|Td~EmlZYlC@qne70I%5412goI2{CM~FnojyR<@e|jpV)H#OymblKp+D^0%ta5 z-`^wgCfNrg1K<_}`dP9MMt1&e+{|{J5Z76P(KJJ}KgD{AxR0fk{E-;pOcf-SM=K-w zC-HImT7fC3!2qfns-$c@>NGGEaexB(uX2uv-@+orhB?fIuSrPPbTO2;$(S^PCnSa$ zG>-T!iLd8^vQZrd3LyPh8-4v*nP{>65y%ZFlm99gqWmbnxA$nR=n*_K%a>2RFM#*z z6PRdg9ra3fPQCNkOykfjy-=e;6i~&h`h;ktMneiwH-!a>>cNU<%{P5YSeh+Gbv*JB zs}m8@scIbJ04wFc>tn^HF06}~aGG`Ev2VJFdy8dY-ZfWg&U^XGC=U$yeNXego=4ox6kuELko8BZzsQPu1psrQGUinW} z`ld%%3HOY4)rv1b@n}2csTG0tT1^qM0}k@vQq4RUk$Q7VSTtYK@9R)|*-DTN@QnOd z$orDVz2l#;B zKInO^`~_5g;HxQo!(hK$i*rzCUlosj={vvqF7!l$L@Lz=7Y$iq`mDO6@mpZU~<}q_+)$$A*OI39JGEKpXzq zknS3RRlNPsZEYfCq|wxyx1SNj-y9k?tQ>EmX4QEB=rPh+FE>fM5$QTc*CP(#&Xb4b zXyvRY^R;*f{@$=dY2*#av6DBLWQWvd!~r@o8OX;I`TxySPv=I>36r zxiGwd`SXks)7e5%kfL-E4PUSzelXLOe>$R*vdCfU9;LH5`786~Jx6BDpx!hAbkU_o zw$lq~^{`}2Br~;mt68q+&sg*c(XGP$-6Ji zgrLrd9zh&nCZrhCBt<9gI?n7X9wAcRx0ECdESXhwYw0{y)o3E89Sc_HBLS7y7|RP2 z{iLP0_;-7Lb7wc)XL5a6T=4S5FL%Y=!7y5Cz=H&rCEA1P&AD z8IvY9)yo5udKhx#JEmB2<`*WJGXLbCK*8EHLh$%3Kv#)J5C>R?N*v#$wZWPoN6Zyi zKHDP1&Ff8l67>E`bv=(40o!E3>H$2F6+e$6Va44hSJ*ZGV|W#?2N|vAf6U@&FHDKd zu+>DpmBnlht?aijCt94lk|Ex0jhv~&_e(pR^;ziJ*0Yw#?%SRAnc*3?Z?K* z*XrArEUqY3OA3k>7@IlXde=c?voiCt1{Y-J)wj)>n3Fv=O9u62zKSvdPx3Ye<}uo< zmXeAKLiNKv$IRS8^-hDcatG;2y#Z2y!~D4>Qg0BcUkdsgP9pUbPb)0j5~ zCkp52yP|iI0;uJKiu!Bj@NQGxoGi+}iHEs}tbkL}!}O32ZFy0kXz*u!_;b^W3{f({ zG>sqX87g+yF(>}*G^E>hl8+`a}a=?^d9H?>hAB(!4E^eRk zK3@MoLh~w7KSJ6$fUX66jyS-(+^M9SM)q?ED$aG3lZ}g~S#-^=lAqX6o$9_sz7W7y zfUf~p0N(&~gNvtEkHgmUD)Mb+3;H)vhXv_6Zb4$xh>YYn&Eh(3V)%MSw z9SiyKQXjm$P?)jMa6m$s}g=_*PBd<{eH$xqGo=2fL;?{}37J6bxOeaM4mPYJda zsophbWM;OpATMiTUcEA;k9wZ(n4PaTj9*az;Ct>lCr{Sy1Eqm9KiM_MzmJZflWYcq z>zyZz&CY8!L-9uQ1vv7CIU#MR@q05KKO}{ZnH!~ZW%W)&#%5*Jx5*isH7a}DsCpO4 zXHzMu+l;m78hM^L^zWSOs^fqBoe55rO+fUbT*kPYCW$j&33vwq=X_ZC@C z1MVD@xR|(#lG?c42=49|f|22p*@Jry^0jVOL+iOAY92%VE9KxZJF<^@hxx z>=9Ybd|)q70>sD~>Eh|`0|(gT0(*f$_~qQnD!Wsn-pCC|;0=|DT7C9LeRkoecSrI$ z3p!0X38_v2-UIxpxi*`}X^shR)dN~=y-6q)kj6h=&|7O#Nu*11I5QR=v|HaP$OafJ z>$|eA_#;#C=i_cQdzF+XS!-_1>DKZ{Djh@s!xf$}%}00+R4|kpDF3u>BOP>V$`*}d z3AXj1W+H0{B-0tm03-m6{QJdYG+B}gK7D)Vs12aivVKQ_B4DwCbuMlk2K7eDKTW-(B&|cvT_q8dxD=>_ z@dL{|xJy+RImHO6nk1(fw^hwb!C0hO2dzm#!xWtqIVcmbl>1kgO7FJkHXlAv%NI6kXUop&30hW#E0{MXzG2s~S+Hc$W zpa@vcZ>$)hQOpNLUV6u*ww4hz56%eWU*6&2V;MhNXNBg`;fahkJYr=JyDfJzN&#%+ zWh*CWEqAika{E7+!u{_&Vk7yvJ9q0PF9HR?PQG>3aE;HRrkW1At2{iVMG+SwE8uZ{ z=q|JSTG*5|e0BTeR*YmZ@&gXZmaH1_L|w^ZtKyHY&Zb2W(_k8P6f9xxJmv0A(oAyh z9)A<S#w(~ z>Y{{+lirFmkKfeIFjW#U8~d_NF{GOw{GCmS+CtG(Y6ZPEKV{cVuLJ{t^RjX)*YJ?) z03N{SYn-eEC%pQ(+|64SOdbiXBm>A3rpr*hQ$^9t5_KR2D@#o!Y8Hadh^?f-SiQ3x zZOy5)-}dfC*?1l6}B7}e7V>a2P%G6Q@aW#DbRLG635)ZRoMaQ_s;4w-1m zv3{l*aF)69N%wn;iDy|mUU&Z!cBd8(gDxP@k)PS(&As~hXd}M&cbKPQ50iamO!5*H zzRXL+^j89T-UItsDF5w&-fRbt-#{DwV7};zUazEY; zfdF_xFX!Wk14QzVcb03ae_T`joLv$9o{%ZVNT)x~2PCEXw!`xBatd-X^M>i^9RNK* zB7bX_zozs9Qt3rDzI^iTuKLQROz+-q_S7)_|1Ele< z_n3!*wM`w$!`{eZv|Ul-KRh_iE~ytm3NV;2+?%C|@ggdw=Iq`K=0U5*(Rc?VW^r+_ z(n$>Xhy~(XU0c57Q7>Nka1e{({NYDgL`~WwKQpZ-C=-W1Wbr)bC1+moXtGl*GVk$a zKD6veADBc2XC9((8*9U3M|d*-nhuYB$*OdtE-F3*Rf;tM8p^2egPRWk9|Fz->H#Q3 z`xJEnkCy_^nTNOSNUH-f7tAabxQp z2WL*IcbbruH9}ASGtdXz<;aiE?aZ${>7nWMGctJTQ2E>grG_l|hG`1Vcq)x|ekznb z%Tu2^%^u~h2d5e!n5kSQ_2*9bJ-p0!@6`|h&e*kpF|A08a5x(Nt3tI6%m{s}o z1Uns*x&}E0La=)fLbs%@MTnLO*2$24bvh{W9l%HMSw4LC^TV{_9QdYReYGW)w4)O= z6VIleb>2}g{`%1_+K_XcCCcwuc(<1OeFfzJKBaDD$uV=cqEIo^{r!Awtl^a8+cc7B zF5BeEmml{J$H>+`?@pizxWZ2zH;?n2tZWZ^!Kkr4h#%S%&QHD&EJq5LUKn>1E)Adv zxJF!7oG^1~0983a9$w>dQhv&X9ouKg1q1-UprK8|q@Q0sm7=NCg{YiP&!}1TVhXd{ zgYcq4>PrniriN4tWVz?iO0=%5$dd46u>-M*arbQMr{yZg`O3D~YNBc%rU2$V_hXUneDZ;K-&eA=H*s2uN8M-uSK(LrubKGo18` zZ{d_5?WP+--2puS5r9x65NqKSLR^@HXeTVb`SV}j*sfJ_7!^kbef~|4fm_f9F<4T! z0$Ls?MS&tbmfI_Eu4t)A&m~yMuf$52*9i+hi{k1*qVo>w0Or>P5A@qwe(}t5`om7%K8-gy1nv3pM|``+ygJ@l2{8 z@nTPW(2d9Td1vS5)lVjB%B>pw|yi)N)4>LtoTKwt|@sdiT=rh*Ena7~g^VHN`n!pUpU_n(iF`tZNGi{Cfk<2(5lhsuQqq=8xtR&7nhvcJ1#Xou~%YJ zT%Y84e&(wnmd&qywJurL3uc2!s^`TZA8O0TT3eu2jG@k;{C3r%YL-|l??vewVtg>v>F5ek60N(5v!#{w3QQM8Uru= z?(h2FH6RSw55m^Ax`wJND?|Q2L>V-O_{bl|+x-@@8B_qT@smH87iu>X z1^NB0pNJdA41DU3r>C7lEwl$%T)V3C-1?!n_T`gog@!Bky!2KS4>;|teWR1@nm_TA z`5WC<(#6o9XWM06ATQt|KmBtLt^Eti(eqb#KIoU=yxTMpai^&*XplZ_xXZhs-h5B6v7LPapvhF5Deif9b8hY0MC799dFpY#cyNK&&kr z2S}eYA`~xi-$2D*tm~tAjGXC^-=?@tiBqvlnk==rZN5vft9){!r*`>mxGqavdT&i5Hz%cg3_(PAL<%d9vQ3+?jo;n6{XoJMPA0NUTVwkcE+a%lNjU59<920gVrrsgBE>rBo!Wp$q+FhfnMJa%C1HPe)o$kzhzM~d(QY$~?O?Nb69ou%Z5u`hYyd>RmgkAug0MN2` zC|)7|Kt^*E2?PdOWWi{}yvlNvj8NR^%Qox3XugD8_H6JJ5&-u~?OgA@wTO9(qOQ!m zKkF3Plk8-AiZfl=61$SW3JQST22twA5;TYSDtMWk{2~%jxKVu>!BAUa-a;JUVc792 zcp^#PYAQEcEb(Xl17AbRzX1ORye`4MYpp{vU_S`HfhQtZM+D{efO~rXWm<0|H{g&# zJQcvqoz&Y+l=_IwKo&ak9lZ4};4c&Y0B-|o!Q^{*A|^i|(zh68|K}LQqMVs*aUH~f zAhy|XuQc1n`P7*9_hoM4#~_wxAme{a|n2!cbr@U1%Nv!X!;P}21q+8^kv;dU^I&|d@Ykrd&#cnjh7C1Ml@TS4OxwkH9KWt zRY9n&7rBmt0KO>5IwZPItS;=yB3l#oM^FHS+Y0+5QSgdkF^R3%-p`-_h_F%+EL;lP zG|?BQVp!k5In!?hRX|Trway+IiLb@ISX^t8{RRqvK32YIJF!1zHGUh))h#lnM_Tc#H=|qF1o3sdCX?xGjwjR zD`?TyM>IdwF6-L9+wXv^fNEPwJ7~FMQdmT?H{NNPgb$Jd zD{V>mXe8jGQWMn6Qd2iM6xkU>0INa7>a;s+8kb&suJW}a)~B+4WB!8URj@9jtz47z|LplkKM!5VA-PG_;LNf!zdfRnb;g@Qy`Yq`Ub8}PDi z?r=>oi~kKBz|#Jv|LqRafY(6U>VLayvRxR!`nJYh1V{kR*m4)4afbyQu_==!4YXLh zdIMT^kXh_EohVQQya$R5Phl{pD6wZGnHA$RcVf)r>3-qL2@K#5!SwlaUcY^YOAz3O=*@TBJt>8 zwqpkQteg9}W@|)NKi8snO8^sq>kx*9cbI>b%TbiQ^7i=6%6=v<9KVWFtT zFaS;U`XUbC780|dCx>KR7=#Vkw&q)F;>HD|QAmdzqc{&9t*pBz&sbMetqmQFAOhG3BG#dUQPUMo_%`IS zKIZX*zxYosyXSvAh`=UA6|e)PSqBk08p}WDvEIoe@XkmH_M5<1Bmc7xgCq>iozOLC$Lmc2gE^-FfS@i79{KRLIS%fw=n5OAMw%UY5 ziwyRyxCE2{-&=Jd`Wv;G_AKQv69;SL zAudX3o&dKp;+DsO}vc!g&@Vzt zF6Gf#RwXzE3=<<~F;%mwN{u@yZietIlS^r#rEIhT;x>-J@ey%vDT|71d0*shAPN{G z6?wf69i#P{&3vRDizYE#Zxh8&C%cQQYvo$;s@bgRE+z5QY&Lrs9XUr~&2}yR=_Z2} zD1wC42~>>)z(i3rhZSl9RciuWoWmZS&;y#GN{mE^j@U*cr0sb1L(m`46F?jKdm%*o z_TvzW2Vm=b2L5z2`4)-Tk1ASoEYL6fRy3qo4~+W-Qv9dIw;KEVBe z9e@V_I{~C^oq{$a!2o=sZEfKqwuniCIx$N&OdPBf(M#AAZG-z@u{=`gDV|@#d=02+ z(+JUckR^-uCKhJ*BhhY92E5T$Zs8WQOw7EAe7B~BVF|WD&NzNQJUg zw&M~Jyp+A7t%gmR)lDy$s&Yo zI}dd+;&c^x9C3g&S+=?aPhn8)ajj6yM~32g3_9Avaq%mYxjUR^}?M(0f3QE z>=GP{psW5uM8f)}?**qUf<}uUH?SE>nyl@+yNi_@S!^Pnh?EBmkz1=QgpPTGhXzQFGeNHd&8_m?kzI3yE$+eVM6( z##okfYzcCZD35g-tEjrpq0Y_&E&^~4ZHW3G1Zf9Lv!!>dazmg}>LOb_y!INn2F!$p zUy&K$UCjTBj4kY_Cdg|fNUiTymd99xDBs3Roxr6?w}N8rg{{IQJ{8_*p$PPZKL zY&y9YMBT-|P^eC}kCFL;_*$^l?0vCdJG+&AD8Am#*0Zz1bT6x7^`h}!c1U&~`|o2f zccLu~&GaEw-OrwExo@X)d>^22%HE<%#iE95KQ zM997>pr5ypOoNlt2(=Y_+X$US>N^P47b5sBg6{#)m{s^{^?f{& zh#w+kUrl(s9?3crK8HBKW!Ku#yV(h|+~+j8V;*ELjQ=NH*T*OhFhFGPZ5q;kOoj1t zqiz?YA7a5xH_>^d_-bc8_dUcS`rOby?dA)nEwXsKHQsy95SXw33TR1!TL)rt^u+YH2tQ)neBp?5x&wE@~2;-RmV9 z=CCADxRu=}7C*{j|9>0NK-j^5V??I)G|$<&U(P(1KgMpIcvfno`3`uiR$FX<$f&o* zPY?%~<5oNRadzHpjh|@hEL#*Q7VKyDWUR+)8zeNpHRN+7QRzBE{|pI$SKUPVlPpIL zPcLm`fwfOQ$%Zm*Bsz|KSH)9u_!9k;{0to<#yrI)8PI-BMRbNzUVtdhJ;nOABOk7A zh3()BWDo8&qL&+4(Kf^_6w3~>xo$MTyA=_O#19AMym^nvJ;XM3rN(M!x?+;|vdC}U zoes0p+8tak^2|pfM7uJ%TW)BLwEk7%sT#I?CPt5u?)m`}NnJt3Q;`6g4$+kRE65*( zIGW$k092=<%XkHF2G;!&6UVQ!uC<4rX0o!wkn^(U738R9y14KRn{vxP=^Cz}bU;8m zS$Zko@VvjMsbyodqOWKsV4hqBh#Akaj)r@XB}-I4D@U_y5nd9onjr79Nld6Cy=$annpbS2A~^oZXm>*BJ0<|49QV-f9}u_l(i#-_J1 zb0^L`BwHlrVuG@C|CjXr8o%JmVXZI`gDA18X<^TaI(2+u87>99P3cs@e^j zSH7TR@q+B~;*!Ni)uJG^nL;GV|E8{R#8?I7y30UQT{+4)!3>J882KjKl<>EUHwn5% zMqUxvK@5J21tr;0y=u>NI)EL(gOZ)fpG3PeY@f(HE%zmo1$D46b%#i*V;$rFHfOv# zRbCEPC-*pcqo}{imk(YBeCJ;4a)vpX-JXxe52{Q&^fvP<|J(fhWez%n1HfQ8OfgrK zD14a(vU)k7eEJJ>|*Zu_cui^1A$zfkl-ijp^FDO7>Oe?v`ELBXSB2 zRU7%q)p6p+yV6;r%W9mNMJLbXd7Zn2E)YpWt?rUEwN=tJCSvMGQq2vYvskIN;4fINrncNB zwPkve@QEM;4aj<-!$z;RQGG{bji<2KUss z5O2na$zQTz;&piqztXshMino8$;!pa3#@Hbv!#|6>qb{CG_@e-NRBWI+ztik>Z>o} z0H2}0a4E>2hRF`Kr5?)pW);_$Do);E0yF=F-C8BhJgC0YkkWE_K~#lWTE1ZH!nq~6 z3(Lxi)Fo;XN}#z|GD0+xPeI7GKGjsjg#e_L$}eaLkrAdL)M72F{hg|0IvtEp$D5>x z41{QN^8kcwYpjJausw^{X;r7ZY|zejk}H2no>F_0S?w(z%D86w$~GJN6_z4@5d(Qh z9exOPbr3~$taElS9<0*SMGnMJI1*ZxJ_5-kd?Z3qPGag%#Xp?*jzbJ7As!)HB{UXL z&+d6yer$R{dLq}nqM4QOMT;E7{Hte%&@Rq{{mC}Pm3YMij%6p~?r|M?1@9|Ni>4>f(o1K+c*%D^HK zQp^1QQ7$He3&2HB++O3FS?7emGftVjVT<_`!^9?b^2Fmm$kQ+TACxz5-Pq3D-2T)+ z#kC)p??1{~K3D^Msj)V!&Ix~KoQ7Fh%Wq;WSA6s%OPD}TExZmy0xi5| zA!NJoYJUZBG6({`lg6Xc%_3wOlc`{_@h4VY@{bof6@>zRwH7LNUXgQG{xiFeu^iE> zkxgaK*2n1;UCvDQA)-W!nE5-aG0c<>*_11m2PwU3jep4Lud>fk z8)TpCtF#eEZm?mpjs9_i?P1khcPsB`mq`_)7pdLEliyM4f?0u%OOFXcnLpu+LEfbu6>-SdCZaAVkYya}g>7lsm~TNZ;iYA_d@7JJwNo zOwn3wVXYkAmi#~RkGHh$AJvgylN{72gh*N=Le#5{Mu=6x6y)COudyD4$3>VLm~ zmOQrHJr98hwq28&i8xaIK!ix)gAk%h7>p39p7PSDW~8{wU74h5z5QSAl61X$i(@8x zs;>kWfTK{o7pcCsz(esg+jAx97+V$(cqy}PvSWK82`0fyeh*b|MJ(Y z8TOBQ=tU?K(78Q24^i4dG527LG}EZ-p!8sdDEWqI4h>0tIx2ZIyfvlCZ*E~?b4R7C zTlrtY?${>m*bPtC}oUGy>sRCc@-s%qG%(F6Ae*HC|xSr zIL$I2!cB&0&RFm_iup#_cQ;*c7$EARl^_-?8lshp*~7qAwuBbsiADM)iv>dPkKzDWBfl!P{PgG{Pks+)^ z#GT?$qEeI%qxjQLm^EMZruJaZYSx1aV4qY?4+DCCDXXbvT+to%+v3Z_lwS*C$|HS4^jFVFp-s>0>{#=DX)Ym{hh9(m|y*rab?Zt zF4pf&^hq!T1`U}t`=ARnt%IYR-=et{S_XW9+I#?89HMF$_fu{)FH~*Ss?)u{^116a zyo(aGi`T`*6s5bS>p`@}VNrDz*{Q(m+X43i=rhWF2;C3Z0U(Qg03qtSb|OT!y9*%_ zWH&-2%^rkky!RkNB-dVq=!(#X5Q5Uwhn;Sb_=tRNK7qFC>u+i4Q4j}o?oc~BLn$^Z z=TVC{c;+8<1dpRQz<>^-F|)}LJYGA0ptN!QPS+>#GMT^ugmkTFKjHw{9q6p$Z-W%` zO#=Hh=4lDCez2k{E>0q3sazHh9-_Ez%aR+H7G@~}3|P!IjUWq^3GGCEmJ(xdMPyb} zWTF8}+@?WI&#vOuA+lR;Cw2}|#yMe?o9B%7A-bZ|P$hb@hm2}oH!d<(69i>y3+N!M zwgZ5Sii~;*49uL=he5;*SDw-D&Z|XMsx)1FJ%a?m!VbcBgp#Jwe8wupt0R=4*)@3UpPYq02ZDeq zsYLZ@JW+r5oVDO%BbBcIe8ERi6kxS&!AGg!T6w8vN5-BMvi=hwqEqB? z!~r&S5Zy;BGc-jW*W?L&)r)U@t`jy@y4QX@TFyUHKahQV3%wwc^yE*0Jm7&2B7KaK z*N)VM2xCNo*f~bIqe}IGOYSbA-chbK(r>q_{SlW57z`K+7y%d!7$>3Lv2uY*zl=%0 zRH+srp#)G0C<812ECDP9tOBeDYzAxrY?rHz+7HI54;4t6_;Ca9?zzM*s zfHwfNG4~=u{{egsxD2=o_!Z#IB=`bC0NnvmfL_d@O8Z?HZSQmnBGUl_0D}Sa(;@hw z5BlW|`UwsC)eHJj3i@4%dgmE)=M^oWABvz~d!XNCpx;oSpFB`kAoofD-P=zW?r*{) zr}DQWxEJs+;BmkKz#%{_;6(tg-KM*->DFqxRGO}KrdyZkN@Tjjn64eBtApwOU%I}R zuG^*Sap_`Px^R~6h*hh4Dw1k1Kq8j_;~BCi&~x;I_X zfr~ZhN({Qyf^MgvD57k59s;=x@~|i44?!4bm*QA&C{`VI-5=>zUk~X zoxY~i)2c68tREmiLKPhdrX#&{GMCQK(kWOvxJqY4>3k=hucR}MbX1WJ719YmI;uy9 z=jcQmok^o(UvzAXj$P4dC_2wXCz9w45uE~3^Q*wfWWZEFApnO@=-ddM^Pn>tbjpGb zB+yv`+NMw2>S=#FZ55||+bV60#`a~}&`bMoX_qQ(9;IEJwDFR*JYsXAY>C)WNE`HM zLmKVQqCHcz^N6;`&_)*8szEy@XiEcaN}#;}^a-9mLDM&1`qE0DHR;Qu>I-A*3&;jw zEu2=KY2jC`qJ>thanhP2t*Oy!5Uoq7w6K6lzBa+8St(|RD$T+$AEN07%>`(vN+U5E zAJNE$I)CbispF(>jJgzZ|I$gzX{645H@c+B9}AZsf6~=ABz@WZ9V#2*1e>VTh_ZaS zP5aO!C0%4rl4Jf)CMxS{uTD~g934$od}?2rs(j|**5Kg9JTwqT%9J3{c8=mz`)Qf- zj$^dE5vRdH!Zm<3^k^DId~bLfwNmIPHmp?qJ8ztO&0#cS?%xw?;f7)b uiHXs@WnKpf*8tYgcFBy4_}-dS&ctL%t@h)Uimy^zb(eBkaSD@F@qYnWaq!Fl diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index d2625ae..881a10d 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-01T08:55:20+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', @@ -420,6 +425,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 +1391,7 @@ class BlocklistsUploadBlocklistContentQueryParameters(BaseModelSdk): Optional[datetime], Field( description='Blocklist expiration', - examples=['2026-06-11T08:40:13.370581+00:00'], + examples=['2026-07-01T08:53:00.399398+00:00'], title='Expiration', ), ] = None @@ -1587,6 +1598,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 +1636,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 +1676,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 +1874,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 +2310,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 +2788,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 +3879,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 +3959,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 +4066,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 +4181,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 +4190,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 +4517,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..c69549a2f8ac1a47ae7c201e8d4380bc49ac2636 100644 GIT binary patch delta 19 ZcmX@lc%G4aIWI340}wpC>N1i02mm$L1BfIWI340}%YU>avkLftkhFNY7+*J~Nv>0G>(+-T(jq delta 30 jcmeyG@->BfIWI340|=CAZRAd1W-+qRGuWKZ%%%?jhFb@1 diff --git a/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc index d87cdb1bac7f4880ebeb44a85f3d6e4d5ffdd4cb..ac0ffa8f581acc56c71db2968e6dacd98f03133a 100644 GIT binary patch delta 30 kcmbPOHnEI*IWI340}%YU>avmh0W*uSk)Fxs_smM>0F%-QUH||9 delta 30 jcmbPOHnEI*IWI340|=CAZRCEy%wlArXR!G_vywRgd*cV~ diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc index 7d05d919d947b7bbc0e723946bb4f0ca957ad427..f8a9a4909558778c1491026077f0eb1856c2943a 100644 GIT binary patch delta 2165 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 GF7OX*Z?ZH1 diff --git a/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc index d705642e1226909db262b964ed97acbc6e614089..5f15b77495efabdd2d3ef4412e558db680623a0f 100644 GIT binary patch literal 7222 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 diff --git a/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc index 43a3794d6559f7bed7b0eeec2036e4ad35245093..2811fe1ce72d65d1105d5c298511fd671343e162 100644 GIT binary patch delta 2250 zcma)6Z){Ul6u-B9ZC_ve+O_MSbz4Wr)^2bA*?^4!&PiDUMnwK)8AK?&J1i+{eXq!X z&GCUmqXbEA0(|g;iBW=@7^!~ogOM+q_<;byNSbKm`!pr^!Gvf$=T_Dh=I}M|*K^K2 z_nhB7=e&FA(2YatRaI38Jb(U}JT~!#nxsu$RN;AelM?b4xl9InMskdBcQH=Zm-fkpgXE`FLUa3OwoPtO3XFw(f#LaQ*OPUNuW#9k{&oGO{q?T zKRqt&p(k>b_b*@o&$Ob4A%GX06U#bFtPW^4fR9gv>=0fR3jS$XkHBiZ-pB&D1{9ir zLQwcM3q1;Y2r_gETMG;8tC+mN8mi7Eu?TCd=nympL7SE~sjOLVg>yt$wBl8f;3yH+ zQqf`mYS_O@B$QYTNVNfp*0;$lom#z{Xj+kL)?3ohVBgxpU)DIK6MVI;W1XzCd@7w` zdQr-yjwrv^ zuv&Dp89kRx&*TrDFfv7JCVRx_2fNXS(2E|j!OUEC#$=`nYK&iXOj7@K`8I9V(5D+= z4S*&agD4LntmVHs*YmSM=b$kHdQr-=+59!xXvD?m5JnL;BGl$HHt|=LeN-!arR=q| zR#FV0tH|T5$>WK~_={@9z8=<#gM2*L$hWHszo2^U!?F6-LsZgH)5iM^ z<1jADsFcf^c}*!72IH(eEk#Ezbt;oh=`c2n!3O?jWRkvH_$kt4d2%{y(|MY=V!9!_ z&N3{|YC3TMv#!{Qlk}s49NlZNm%G42?OUX4)L6qmSv61Z@Xpvezc^y;7mL2Z(0CiF{2q{ z9RoPMk>7SixjUio>+J!$$iHu2maZqhq57lhjVs%Brt+`tOc|-;P%^_bmS^6EiDnR1 zs39`H6Hn5+g>WMA)JIlRH;7d15fz*5tj8-QR=!fg6X}_w%*YvVdF?upVY~jlri>Th z0txXSI!Ea5+^T(_Miip`1E*xt%>V!Z delta 2134 zcma)6S!`QX5WUxaeqLX^#9O>Hc4Iq!S)5H-nvJGSqgERnhky?v`hhG_RpOIHM)U*m#hvRmc1jX>);pe= zJ2PkI&e-=Ct}RHnB*}!}S#CQO`$C$;eu=9H{rNRU=py<65tPIVN@|q7G>fO!(mKUV z3`A&p;)jr8VY*nSOH9|-=?%oFSlKHOQ`(}~F6feG#ZCmK3u!@dTo95LBZ808!tKsy z^4H>}^qNU=u>=jwIkK&@K&)v|aWfwqPZ{N2wG{TWLGiFthvFrTaK=h#VkJ1apO5Q) zrn?wJjN1altpr&~9%yN;+BU1*OPXpuvZQ-hQr~8fh4__b7UU&?npaKY@xhwT;zKNc z4<{5zGb<|0iU?goXK^w-i{#d_Wh%3DlF)wbH$v}FqPwIOqL|9MR!PXGPLi@v$ebgK zB7NQLq~~=;EYhnUzeb;-Hj9s5X|!QIz1cXTGiK1LiRO$gUE+#q#kgYlT=-N#=ri_K zpH*|w`c!7K6&2kI%HS0#DO@twgGfAkPT`N$h`o4R4@&U^n*A6 zFvy@R6v^4*ZG-9q%NW2ufMI~G-0BEjHXXbrJtq(;39;ji`#ezA1iajl+khhC}VI#eYaXJkIw;d0YUE-NRz>DniA!vEFg zM$}9F?pJWWbk04Y8Jl4Z98-D2b4-+VYCGH$tU`4u_=xy)`CaJiCqV!5PE2l&yDa2$ zg`#Y#P8zc9KJKzUpL#Q!ODSybP}TcQC-CLc?@fNqvpcqxG#WTGRwES^k|jkV8|xPA zCE(uW=5Gbg;7>};!8wgs9X0KY929P2wVU2=Ud0>qxlq4{x4UJ#S=Mq7zy6;>26`t1 zOSc{x7~b6Vr@ixOEI<*d|EL7|o(k{BUzIL~Kd!50vO{5!GA`SXEGe1AR57O>E*A4M zsp6|@nw=Ch3_>9_0QocY!^nR83w;>bscQI{_~}~INT;LKpUThTU1Cee`I1Va@6K(dn*8Zru#7Aizgf&vorPs}&tLiOAu*-ub{DujsjMK(65T!OjQH zM8(JrCS-L~%v`j9Sk2UcjPZ(L=Lk&;=j4ycHe$E*i)s)62L88U^mI;H&XRHUU3#EveWIYn!xgkWUK#v@pFG~-oTvQ<>YJ~; diff --git a/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc index 9c5bafe5e48a74bcc5b7523b7ea994a416066e27..90f8eb0e2eceb4b64ff30c843d8804950d98bd55 100644 GIT binary patch delta 30 kcmX>rc~+8pIWI340}%YU>avl$nu*2ONY7+*7n3s=0EWp3L;wH) delta 30 jcmX>rc~+8pIWI340|=CAZRDavkLf{Df0NY7+*I#UlT0E?0cdH?_b delta 30 jcmey&|CyhAIWI340|=CAZRCz%VllGNGuWKY)WZq@bE5|d diff --git a/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc index 53c1b9a9ec792af93fa36c27f740d87492cd99cb..d3e5f761bdda0aff5f95fec9d73dc6a62b110ba6 100644 GIT binary patch delta 30 kcmeCS@3!Y&&dbZi00cj-x@_duVrDTm(lgm?$s8mD0DDshjQ{`u delta 30 jcmeCS@3!Y&&dbZi00O028@aWZS&S_73^rRb2gv{cV`K&# diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc index 3dd88f559c910ce5387a7850a10836d8cccbb337..f5b7b68511b3dff4ae9d776b805f98d12fc4f3e2 100644 GIT binary patch delta 30 kcmZ24vR;IHIWI340}%YU>avl0HWQ1nk)FxsRZOky0D)!*eEmdrX#lIWI340}%YU>avmh5fh8Ck)Fxsk4#s&0gb2$p8x;= delta 30 jcmX>mdrX#lIWI340|=CAZRCE$#A0NjXR!Gr(^YN&b-4&G diff --git a/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc index 80c82367ed26d1b3aa8f4a8bc76f0c16126bf6b6..b41b8f679bdf092ff206a92b0834202be61ddeec 100644 GIT binary patch delta 30 kcmaDP_DGC-IWI340}%YU>avmhJQIttk)FxsdrU1H0Fa{zPXGV_ delta 30 jcmaDP_DGC-IWI340|=CAZR9@B#A0NjXR!GmQws+Gc(e!J diff --git a/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc index 7aeca28cde4a0ff40e041360eb356d7d52e08cab..f4f13b496742ec52765e383e0664aef1ccf29db8 100644 GIT binary patch delta 30 kcmX@4b4Z7KIWI340}%YU>avl$oSDVgNY7+*8}l9^0Es&Y&j0`b delta 30 jcmX@4b4Z7KIWI340|=CAZR9RzW-+qRGuYh5yhjKCaZCqZ diff --git a/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc index d4f743a50282e1bb623c56cac65a0e44cf40b373..5c1d7dfc0aa7a017f5470f619ef6455269b25950 100644 GIT binary patch delta 30 kcmaDK@IHWhIWI340}%YU>avmhBr}V#k)Fxs8_d&H0H8Gr0ssI2 delta 30 jcmaDK@IHWhIWI340|=CAZR9@5%wlArXR!GO^K=yeh(-vJ diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 057a909..2ace72a 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.132.4") def list_allowlists( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index ac2cad5..90af305 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.132.4") def get_blocklists( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index 6d90155..1869dee 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.132.4") 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..d2b5dc3 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.132.4") 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..c9d9e48 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.132.4") 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..4dad54d 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.132.4") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index c5b2050..77673ba 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.132.4") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 73f5656..b3c4893 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.132.4") def get_integrations( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 322c7c5..9f62cc7 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.132.4") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py index 5d173fc..dde026c 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.132.4") def get_products( self, diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py index fa41f55..28e8d39 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.132.4") 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..bc5c772 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.132.4") def get_tags( self, diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py index dab3932..572ab93 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.132.4") def get_vendors( self, diff --git a/doc/Blocklists.md b/doc/Blocklists.md index 78168f1..fd190ed 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 @@ -178,7 +178,7 @@ except HTTPStatusError as e: ### Errors: | Code | Description | | ---- | ----------- | -| 404 | Blocklist not found | +| 404 | Not found | | 422 | Validation Error | ### Usage @@ -251,8 +251,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..1b552a0 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 @@ -553,6 +611,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 +1178,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 +1201,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 +1326,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 +1403,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 +1437,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..9742c42 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.43", "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-01T08:53:00.399398+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,17 +2756,350 @@ ], "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", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/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": "Validation Error", - "content": { - "application/json": { - "schema": { - "$ref": "#/components/schemas/HTTPValidationError" - } - } - } + "description": "Unprocessable entity" + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" } } } @@ -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": { @@ -8247,6 +8973,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 +12033,7 @@ ], "title": "CVEExploitationPhase" }, - "CVEResponseBase": { + "CVEResponseDetailed": { "properties": { "id": { "type": "string", @@ -11421,6 +12176,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 +12246,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 +12687,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 +13029,7 @@ "properties": { "items": { "items": { - "$ref": "#/components/schemas/CVEResponseBase" + "$ref": "#/components/schemas/CVEResponseDetailed" }, "type": "array", "title": "Items" @@ -12459,7 +13138,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..2f73391 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.132.4" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock index 2dd3cda..87ffbce 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.38" 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/73/6c/815f49f0c582396b1a4c37df554ffab6bb420abd5a96d5329183a97022de/botocore-1.43.38.tar.gz", hash = "sha256:70fbd5c74f5742f5975ddcc61e6afb5174cb80577c2ccc17c6898ad3a49b51f3", size = 15628316, upload-time = "2026-06-30T19:55:19.2Z" } 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/22/b4/fdff7920b3776b37f8b42d4e6eabb141974fa88f9fb1aae5c2224bdaf635/botocore-1.43.38-py3-none-any.whl", hash = "sha256:54c1c41aff82422d2b88a8a7d782fde8ae1299a45f088d00011d85c4bc44b0cc", size = 15312254, upload-time = "2026-06-30T19:55:14.837Z" }, ] [[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.132.4" source = { editable = "." } dependencies = [ { name = "botocore" },