From b06741270ba325975c80e4ea3b053c973558209e Mon Sep 17 00:00:00 2001 From: mazzma12 <23187108+mazzma12@users.noreply.github.com> Date: Mon, 29 Jun 2026 14:16:10 +0000 Subject: [PATCH] Update python SDK v0.16.1 --- crowdsec_service_api/__init__.py | 9 +- .../__pycache__/__init__.cpython-311.pyc | Bin 5024 -> 5163 bytes .../__pycache__/base_model.cpython-311.pyc | Bin 4378 -> 4370 bytes .../__pycache__/http_client.cpython-311.pyc | Bin 7768 -> 7760 bytes .../__pycache__/models.cpython-311.pyc | Bin 158635 -> 166499 bytes crowdsec_service_api/models.py | 408 +++++-- .../__pycache__/__init__.cpython-311.pyc | Bin 207 -> 199 bytes .../__pycache__/allowlists.cpython-311.pyc | Bin 12917 -> 12909 bytes .../__pycache__/blocklists.cpython-311.pyc | Bin 15121 -> 15113 bytes .../services/__pycache__/cves.cpython-311.pyc | Bin 12321 -> 12356 bytes .../__pycache__/decisions.cpython-311.pyc | Bin 4338 -> 7214 bytes .../__pycache__/fingerprints.cpython-311.pyc | Bin 12310 -> 12345 bytes .../services/__pycache__/hub.cpython-311.pyc | Bin 3277 -> 3269 bytes .../services/__pycache__/info.cpython-311.pyc | Bin 2035 -> 2027 bytes .../__pycache__/integrations.cpython-311.pyc | Bin 8075 -> 8067 bytes .../__pycache__/metrics.cpython-311.pyc | Bin 2607 -> 2599 bytes .../__pycache__/products.cpython-311.pyc | Bin 3782 -> 3774 bytes .../tracker_events.cpython-311.pyc | Bin 2914 -> 2906 bytes .../__pycache__/tracker_tags.cpython-311.pyc | Bin 5698 -> 5690 bytes .../__pycache__/vendors.cpython-311.pyc | Bin 10351 -> 10343 bytes crowdsec_service_api/services/allowlists.py | 2 +- crowdsec_service_api/services/blocklists.py | 2 +- crowdsec_service_api/services/cves.py | 3 +- crowdsec_service_api/services/decisions.py | 80 +- crowdsec_service_api/services/fingerprints.py | 3 +- crowdsec_service_api/services/hub.py | 2 +- crowdsec_service_api/services/info.py | 2 +- crowdsec_service_api/services/integrations.py | 2 +- crowdsec_service_api/services/metrics.py | 2 +- crowdsec_service_api/services/products.py | 2 +- .../services/tracker_events.py | 2 +- crowdsec_service_api/services/tracker_tags.py | 2 +- crowdsec_service_api/services/vendors.py | 2 +- doc/Blocklists.md | 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..1cc513d14635e93ac9144487c234e573d0e0ef90 100644 GIT binary patch delta 284 zcmZ3WzFLECIWI340}#m7Ic4RFZseIV z5<-5mEQh3&B!Uk!r#LvjsKlvqa|ClIi@pd<)Hg9XBQq~GxCChBEeUL*u6d=on;)=W zWEK&24s(Us=#pBJn3$7#slp Cc4LhI delta 167 zcmZ3ju|S<~IWI340|=CAW$h8!$XCUr7O9_+pPQ;*RGOEUTBILeo?n!$pPZjpoS&1b zn^=$uWlvtll)<=hGC#A+=2OgVESnoRE-(x5JBPUjr4|77N<^5;khO*=9Zb4 zo?28;l$lo&RGO0-T$-DkSX8;$k~f!?@#5y?LYa)xMNHgG9~cm113L&7$p9S&05`@q ABme*a diff --git a/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc b/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc index 98b9f58568825bc4f734f1e579444f5920d5390c..5513e0973a4f132ea293fe174e1e217e3c1b3e70 100644 GIT binary patch delta 56 zcmbQGG)akjIWI340}wFPIc?-tW|j-q&&bbB)h{Z|%S$cNk1x+J%GNI`OVv#*$OO`x JLzs{80syPR5hVZs delta 64 zcmbQFG)swlIWI340}wnd(b~wZ%&ZozpOK%Ns$W!^mzP?kA77qdl&znfpI4lpld79o NkO^gP_F+E83jlAr6*>R_ diff --git a/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc b/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc index 1bc5815900c09dcc5d59b8b7d1636dda5e5ee5f9..1ce5c788b430fa90f7cde6ebcc35a702327369f8 100644 GIT binary patch delta 56 zcmca%bHRptIWI340}wFPIc?-V$0!$~pOK%Ns$W!^mzP?kA77qdl&xP>ma3arkO`zW J|7VPp0RZfD63PGo delta 64 zcmca$bHj#vIWI340}wnd(b~v;j!`W}KO;XkRlle-FE6!7KfXM_C|f@{Kd(4HCsjAG NAQQ^o{GBmU1^~M}7T*8> diff --git a/crowdsec_service_api/__pycache__/models.cpython-311.pyc b/crowdsec_service_api/__pycache__/models.cpython-311.pyc index 6ec2ace3e093ffc22a4a8f92ab2f5aa7fa9fef13..e3e2d25f6fb1f4466a0851b9af2d643f11c8b6a5 100644 GIT binary patch delta 37843 zcmdUY2|!iF_dj!m$G#|w;DU$?qKF_Wf~X+k?i2TYL3k)GfcN1Nrl9S+I^|Sm+N!o% z_Kg-x%Wr!YwtO=xv)y(m>s#cv{^xV<<2~NxA@%+D`!5O~=FW2F%$b=p%bhv*-go>z zxjrCdUvO}M7yXOfJZi<^i?@eFYrpi^-lwWvge_7&;2RSfrFo6@DhjyRt0>UcuNKni{r3Z3hPFhcL$R)L3@O9d0$HxK8GUOtrYZ7?Oi5(WW9H1!XO_o(Z^>x z;e~`gvX*>&73zK%J3pvxZLL3d6=1{nH=L%ig8(s zqRis3%PH&%Vs|#P`-ks0l-DP=xOYOc&mAXy8>8<)7sCIdm>?pEo@m3>(>0vxoi&s~6;TuES!&<>3f0q*)W5 z-{d~jF(M3+21O#$-bh!Z?;~B2rbN{uQc^S`-5BkP^hLBQ(%6_FUka{>I}jLQ3)&`Z z-RU=8E{aPyG@$zjq6($krWIvf3>0W&%%ZMJY$o%qn**+;#Cim)@UKhG}aY1QmSw%rbNm;3V@!|tsKZ3c&DFc?5 zt+ox&*Or#r^Z|?4m+319=<96#3(8CAuRPEzTebJ2O1Lhmy@-`ld&d&l?(%d}YOjuz z+^RRkb`fNp^JCW!D-p?=iKC-!e|;o$fk$(iz&{;A2WC+>~J0H)j%PqFeuzic@y zd0<-W$r2F}&;^b-0Oyz}Q%A?hz012+#pEnorrVYkRM?6}+X_qUki+ycy<*e_bz#LN zy1im?p>9Ly;)04MAKQlV5}ie6P4v-YK(!N~GeKS0nDNu5&sdy0EiY$A-sr_SGn#zz z=H!o`mNR4g6l*idWU^?IkQxw2zjp9i?fieTV`8m$gn{IsAEO9KvNp5eP(n{%G10_= z9zq1_f>xIm*;XwsEGsQ8S*COOGswSL-kkM7_yKy+uf0G{&FU-f&mkq(yN^*h19v3H z94hPmtO!b{7*>5K5@Z}2-e-Z9<6iV;ndBkTSipFIsU>8=4=_~L_5In%CQI&3t`15= z$RGl1WwF|_Rg9E>r1tRv-;Jt$q!uBM^hs680h+J;bU?}&Q}!sfo(bTBa*?Ot(UkpU z_yLOO*S?a9oG33!8DsDozy7r|u`&3yO)uJDp;-iT23>B3K)d|E`w0WbT>=LW|ayw0Z% zo8oOPSZ&jXAVupPa4CWTw|J?KLP%pQAJWaBv6L#jNHz?KZjy3n`n=g_VvZI@u0+4q zh0HOz99-F^a@arzu%CX7D&8^CPY$+4$t?OCI@D1R8#GVZ(DH7c6xK2j0sOx6 zxkm;VLS9Cm6GX18%=kLqQ|gsS4S14%?XvNP-tzv;u148cQs3RsRBr3A_j+(MosJZy zf|S7z@VuOqWiwKjp^4UJt+zl1jXl-&DA7fh49~Ja5|s(E`sqk{ba-s6C$8+E2Y6ea z8$QvXX9vCF5tlSE)G*>2kuIx7>XvmNxKO3;5lO0cj|frMUoUzZ*_5l>0z|63I{UuX zyCGK(Xy_XOn*gTrRl*POzTBMiguzcG_^CdYA-9d{Jl*Jmh*b_)Lts5%X}w)=o~BGN zBDQh~{VqMY)_V^97^<|2yWafV#evN_i+nCOKE_07D+mF6c8u<4FuRq~mb#_8 zXLJv9x~q{65F|ez-P=fbHI-65wV0}|`jucgBX5T92#R2>93;hrZt}If9^)#Iire{G zxFE-F#hbdVWi@@bSlGBH*jO&cWNA9HWk0t7AuuohShmnr>?@B_pM zaxB49EPJ7LKA2dh{#Yu4<(zTdnwrg~aZANId3xMpks-6k7g|u~l~d772FeG=1<23F zM`@e9)RqR(Q60Qj#K`^=MlRzqVjSpVphygAy<)i?xjMY7MYTH2+zhgSB%wlfiow!v z;-iM_Z#K%XM+`c&Y0^k-A%?5-<-He_IPcrwx*c!_;7$M!b|&fFiU7bQA#eLfgse@s z$ZuzbtKDmapR`UnVDND()K7Z;y8fQJ>OPPFEJX#B;E5|>9}-1OozQCpd3l~{-Gj)0 z<-(Y1-8j`T)w%~Ie{t%JfIWzUk+xE8ixORB?z9VfRKw3yko(~WSVdger&8aEqJl)p z!0Cxb8SV$gh`F|bqio9y)|Hg$x|6i-p#|&fK@gg%aeypH?MyA*Uxv&GO5+MWh`@&k zta>$^CT0%753rV)`LV>w%#oQrk$JjPM5K}LR$ zL&Dj!=U9v~$y;Y9SY}b&$^oqEPtUG2PsCg^A#SusK;0zD!|(&_K#sGVqI_XavXSdy zqh3pM{;VV)0Yy)>D9g@9Mm$5IyC^IDABe^c`583i-t)>mw*F&?2DlrET&@2Y>D$bz z=%%^);Yu@?rx5~pRu(K8Zcsdpc5-Ubyq>Kqyl;>U@Ty#} zIKh~ped8s?Rg>jAiwi8-6jHfVZGTGimO)E`<(eh;d7SZm2Qq+Kp&ptdB4mDnV_EQB zlce%P$Cp;vmKn>x85fk>^pBC~69Q8u!21ip8GxxZ{Qy6}hcbR?FQc44K(Aybi2gF} zxs*f4mNp3U)aoas;x7F&T>l3A0{9hR%Hk~i0H4anqJJ1!oaJJ?W}7Nz$++SOw?;X# zxO2Zb6ur)S(s*lLoloAZJnIZI(ceH6@Uy(6c(6hAHzxXSaiREB4qvt~&b_kh0`e#2 zjJGbHkvC^Xoi=8${-u0k**tT-`=XZv{*e8b&oC;`SIB3IqiL0%G1x@Xn-wIQU z8$YAPf~XrP0YYS0d30D%cy%8B8{M&+LDE_>(WEl#yvIz-BkhnsEpPJpnUm}Mi0K*Q zturT^1<(uR0pYT)#L-WC$!9jxjQsk3a>9y}9;e;?kqSVHeC1d}Z2dXa(X_Nf@2>2x znR=g|h7?@YgWxjN?Lhbe;x#nXj&f#cu0eI6lb4T6(}!fEx*&|Y0BWhLOYGR+@H}T2 z0+N6uA3`{ zo9In-(whd?bbyI+KKuYHHI*}rG+*$?esbxC1x6nETrO&=GVFqSb4#6tq|EJX4}@pJ z53qq-YJ{9r=}@UNnJD%R->B@^_XbpyOKN8R=7J31BF&i5P8kzGYdG2(OEh}+Towb( z%6hA#7gLA0VdH#S#5Qc4Oly*n7tZy~Ao|wI0%JMy>c$ZH;f3)Tn60$3q~eK;Nk|L8 z1mH56xv9ixpbMHbN_Y9mCaar5&Dxx0R&$F$0U+h}&3z5wE+WovCSDg*jWZV9R#{Nh zPrhB%vnMm{aWl0Tga9|muGNlpd@&33vg*116%b}Rf$Tm!R{CxUiChmKkki)!u$Xd8 zACC_Am1DLf^oWMPsldyT3*a`5CW%%lMs$_;Zy9Wqe7RBb`Fk>C=GK3>mArB5-dGc< z)gT2p08%+JRYk~GFG@8;u-e%ahF@HIo-O1pAOiS@X6z;f?4+%Z%m9PRmL@8rLvv^4 z+1D<$7wRSD*xAI#t{-@htY?!Pox z?yB;qc2#=mtn*aSr62=1D$iW%sG>`WMXS8*vN=@Wr!TV-jRBX>I}eS^K?Crjy#I0s zjmx>17&j(d5!+&a?<%C=-gq@!rdq)ALI>13d!wH`eB}s3fLAhi)~kw%yO9^7v;&F5 z(5r2|T5pKgf+FBO2gUq?NVWSo?etY{i*VJ=wO|^Pn-22eqgisvHP7 z&SzCg=}Noj0rUps4){%ew|$Y3=?z?0m>KNcVYMVvVC8&Tw8hIHnb|9c9zB!dg%ZHK zoiWN(OUG(^mq9RVr1ZT$daSdb>m?LfhxAnOo-zBPg9f4JU4^C5?e-IP^J=>Av6k@~z z9(0Ow*o_M<`zb;tjdLp!RM=(o67=O8U-#I?9s)H$B2lx?l-UKnjOKp!rtY-K_WJHf z8J6r%%k?msaw1H9vrG8Pg*P8I>OPt1cao*Md}a2o5V2oQ*_9UfFbGn6g+3M&=-ue9 zt|Rx6pN9qNV~EOq8xhRqd=!3wLGs+LQltGnD$8%l8CFA{)6Hw7g zgsE&HLJmdV)?EZ{LgPqB>};8Hdl_xqk z+S7(attH*%_4oA3aA&N}d)$tLpy)GVHdK|F=%;KSHDt-4!BWv zdq5fW_bX>pKf;*%%7g2IW!QtOMdP8(4|W!&6`tM*0xaPF!1X)e4}eK#=imo8B-xgw4+sF5I1umy9F=?j@u9&1Z6hC#Q7qAhM+@e87{2tKU>u{DuHeGprQZk_HUadT z$mLnGLC6m9IW>|W<$X2tj4XqUEHMR|_t|Itp;ZV|3*Na3nW6uml zf&jqVoBG*Yj0!U3$WVi`NTZNhBM;qqBtv*y`gTToK#2V9=tQGecGh_N!&(wAFMFn& zo4S1HncilF+Z_}Dk+S|7M=$Ko8RJb_>9cWxX=nw52pVUr?px_4%^S~lON5v_@3r>< zK|p6J(vP{cLEKlpe-X{==nbe*u09U(1*4p#^+cpPR-WN|i7AHA5UHi`- z!~Zn7WDo%Kcaf8~9FOH)v_o;v?esS9prs-OD*-wMFgQ{V>}BG0|# z*g;D%D)Z%xQG3y~Fh$aD1GGMyqeDC-6M_P8c{?I=q0^aE(JR-@#l(>30J;TnSv&Z_ z1r_08BESW3=@1j!8Au6O>8->-EmB^4I6$s^b*#~>GK^+5Kew0s`PGng&YHCoD<-HT zYohsZL!Hm8oJlijd(1j&F)gj8>-WlG$79S*a2WChY?P~yJKiD;qcVQl*;PIbaX33~ zxO_CZ_qEC>&bmd>Wyu+^L1#6`+#87OmWpEjCsww(ISP<1d{ zgi7m)ivplQzZ{4zqPDN19uo0J*OAbr9^N>!vgLYUWoybb7nuU~%knqo8+ql*6K@>z z_^x9DVgnvR1983UplzZz3x`fb=p+Kqs>h08K#hB1tIYXqq}=t^;dGM-ry>D!Zeltg z0f487(vS2W`sHvHH&b-JVUY-+scpf##woAg-VBt>>q2GRze3yMZ6+uJUUcVeCW#_b z-uAELwg}7y0l;hS1ZFp@w|9n&9gS#QBYAL*0dT$PW8pNFb1wVQH6|Y|N+x}pEPK8i>9GYY1Vz9npqS!R5euCZ z7uE$z%UhvxeO>q{CuMyR(k&+N+%^gj4EV;KY(X=!{fGZ)a)lrV_{l|1e*f`Q8U0@R zU#tTgNCAEaDOVlXxDIOHOKqzTmVp4k*M}UgKC_Go*xyfTi$Dno0D|2Kl(1~--=AwS z6^u zUqVp%pmRMTugncORCPL96u7tG#6Z)k&1mM_eKBI_c0dJSEnpqMlSV2>0HBln` zx)FgF5_oRWn-L6{-WoWoTwNWuOD7cJYjiFJl5>U-fH? zz!e|>xYV7%6^=UY)fR!PKmc&HJAtblMF^DnU$;r*8V~{Oa3^vN6Zzunfo*Yd9S8t! zbSH4#p{d_I(qad72V!&GNVrUOvmJhbTbtL--0vK9vz>W*=ewk~c)9^}01vtIbc3r; zZv8&%FZM|VqJSC@b@fTbT#c+xZHud$Kmc&movWK1N-;@(Ti<__v#aQ<5Pvm+=ia&t z!GPyMt`tw)>vl0eI~)46#m{ae0UUSdXSZ_z%lx5lpp&12l1qSZ%596Iv;+&W_0P7 z&Mu(gV$ZK5rR}E`9^W_KiFAOkefYhX+W46WkikFu8gt4!S&$Qc36=#v#|^y;k?$t( zTpI@v4EP?x+=nNwjRT}RN63Hw{P}tG=e>vx_z`Jc`tx1~1O3~|{C*Gs{O+Fl{Y>D? zUoKB;o$&{e7NA+k;Tr27;ALVsI5ns->JW+4n2qztrz%F1OpP?3;ZZ*>d-I03t^trKaLdK1Wo$tF$4ex5GlKJ zQtxxaIN>-0{TR5qVZTUki>oI=3Xti})sqmVxJPzB(XVQm*E~y+ug$y2FNy z(o-})#moyS>O@bS`N=1oj^lMvj|w{Iv-urMr`Gy#LNm_GUaRE^=H%@sJAz zHOm7}Epr&{Om1Wn)I<;YSR3zbwqLD@_EnDiEpY|K6*fJtVtI)@u82w+*QcbkaMfCS z$vRu2TTv4RrVLE$pOQ*HGg4AA`Db2&tAM%2eVMqNinuX)*=iIs)OCkuaWVPv@wLhw zIkh2@Kac4E4vxpTDYL-P*S_11sy?jE{B8%v%7FtA%B^VwN zvf)g$spg9!vl|UcclC~vQhSAmraPXz3rY)ZapSq^>Zs<* ziwz0~HPN?2MZvQEDJiMwV1{#`3TY>z+8b@*D5Qx7QF*H~*9aBsEixvgW(-XpoSK}P zl9D`VVDtVsz8pQ#XhF{+JvXC&!iBbE)t`rxTU38)WtF#J!#}_!1GL?$45PK71?w*% zKDWD9;4(G7H{b`j!DxK)_mBGj*{0U1Gg@5`+F558G~iKvWf9%Xt?&)B!n71;-Ho=b zvQ^kztUCkp3o4f97wB}Khg5*Qk#$#@Ip1ALA_;$8@Z z$J@8irm@pslIF~|HGald*jBr?F?w=x9PxO|_p$Z)e>^OegxA70`Pi+y&)%AFdAorvQj8VNsV4rYgn*r6XG0`j%$pTKF#_*?h^;(f{SDW13t-#W8y z2o+t1e}RBAfG+`G5qPen?-2}01ii2E6sx`?b<5{%)b21bYtWx2)_~-IWM7rgUW_0r z?YlOSdc3`epY#J_{0R8dM1MwXz#wpV7EfH_pSi7+PZh(|#tx!yc!zlbMd392h~U|W zpvgz1x~GHKq1`1^`CD|+WoEco9LOUPk8YPhd8jwSh1~)TQF$XjFNzR1wHs3)RLTP) zN+k!2_^OKKwz%cCf^`?f71=5ZN>;@cm)KSn+2i^Y*_@}ElHv;Wvh_uFTOnQIEm(Dd zy~Ivl>urR(t=Oj9NRg7;w$4^sL4QeK+7si7%k(%K9h#4$ef+qRQX21VajQz~70Gd< zZN&v^S5?^KD$3&e78k6t+u&Mhvz2os-DWSRyRnG9Y~T6msY=MUO{vWn&Mqr>eV({o_$2>jCqn zZsQiSC!HLQ3;?$x1J}AZ++gqCSdrLP38O#)aKOEUQ3i=I-9-PkNJN7K;C^=!(dxuR zF-A3X6MuClsS_vy9s%7>~<16~hg2{`6!Y`_NhY|Kq)vAh51#N(jA30oVIn_vA*iZBsIuLPMCou@Y0DpH9 zgA5Y?=_mZs{1B%jl#0iJW(a}-!5~oxB^;~r>5vFEBy*HX68)f>t{pA9sMAT}s!4xB zPwPP-YHHC#;RlF8M!|TBRl%9G`$z}y)zAG!-?mDdi8O$|?xoE%O1mTZyoxvrsR7BZ zf}*rp=DzUw0H-$YqI^@t)oHAf^#~9!6>22>0GS}_QobXZrJbo_KwE{%0R=#wd!cfS zLfw`s(%K@C3lf0w?j&*z-8*fd81)x-@$*0tFc}nGx;M{YDl$zBX^W|`AOV==&eT|! z?tLLmq>pm8aJ?H+#1VLIsN)d~mSZePk8?7Uj9;V!UyWjaRp~;GeJK)R3xtW-x0Jv z3Avei(@gjQu7Ct4{j*ZY{UoLiqt(>lL6?g8O<{J{fa8i6gTCx zEkAu4XqmX13qQc^Dtnl?z^LE3&4iMWCHnmRLczIN9q^F5Q05y#`7ujO?1k4qo_ozg zqy{|iXRISO3~!pcENmv1Plk&-^Z!e^6d()0%V2Oip19TuoTAzM_e-S^*#O>imr9`_ zl@8e=dFUdb-0-GqLDYh%Z*x;dROCnLN=+ z`R9mhda=mP+YiPR`28J=>OZlZE-ophyCda#Nohr#zIK((!`eF4vAF*4*Ve{L_`J#| zF~GcWZ?&=mB;f< zC7=k1@h3;Eb2(9BG?=Gyh2PLNrb??p0?-vC3Y`jOwX-ATsM({%V8?uE-_-whs#J!I z0Ex)Rm?|N+GVnTU=UCydKFbrKLsuZ)N&?S)e+_~GneIhi!$r=vOsCf?w!!*vL~DJ5 zXh$$$gnOy&MyYuLduoixMycb*iv8!AEv*G9zyy$T&6d_0buf6G$Y`rf>p=oA)4fdV z4HBoviQ#RLxBw&obKOZ?U`&^GjTe(fwf5G|>hU<=Mo_irsnI#6sqkYR`!xXOOeT+nOy^fgoUoKQ^J&0~3YAI7tcyZ3 z*y1X`+OwD>7?r>v-0`*e=vTTxVjf&I+$a zVE}umF!nRVb+wnYyc~jax$hctpsQVtw017Nube$gSO<(i`Eapa|A@eItzQS)fLf!G zemSeDkzQvgmj||sLUs9UQQ(W)Cf3Fj-VJCsN5t}lp2lQ8Eulut5z!WupfQ;vl+6)c zgi=?}5kqFXUq5L%zh{ZyT1B(%T~1?aQ#-&b;BAt_k0m>v>7oYD6;o;4*;_)*6njZj z_!0|B+c*(77S+LWQq(KviS9jHKbe0s$O2BO2j>aLfuNfWfqvMdudE#sta9gz*-0)G(cE&Pr78ZWi6u zh6PPi#XUxK>|Y@EFBp!@xOPXvl?})N7S+(_>Oh*$K zwk;LsLR>bCNP&6nxII$U7t-GMi-qF7cKz;x2vDHJaP!>BWk~5^WY$F;+#nK$J^}ZW zfWv^N04xxb1Rg>FU}ylO7VRs*997rnp&f-StaIKaA2u&DIY%eSuOU9 zU)2Mv#rqaqzH74BmR03f^KvO&A2Hukbcuwu7S|5w>BqnpPd1-}i?5$Q57!HT7XdE; zUIx4ZFp29~_yGzaE*$f~c3;iLHR5`Qu%6{I!Zx5rKF0fVTnv0=xq_2>@M>O{^B7fLl;P&Dzw)!fX0m zAQBy7t97=q{IG3E&}?{6wUuIG&z)2V&!a>g;scJUksHNGqpj5$1TjGDyigP@;qgJ2 zh|0?RdbqfG+yED!*x3n}`*@%$_?hbLefR-hq7vyh;we^b+wRcv0h>hUQM=#?jjP`R zmmzddC(TbG81M#Y?Zy)?GEW)&S8o#b&d$DK)%PL-YieWYR3V$i%*l{V%hP|ZZs1bw zh-og)Y0w0`iwe4+Nx#o91bNzM&@_H^jA%L*(cGk2YxHq;TZQ~%MN}eRN2{E|=c;g6ZN4X(Fq5VVeiTvOAfj&TsznU;VS=7p zz{e;7;0p-Rb$#t)C+})~l_(bD)Tt^lD;amaJQMm1ga8d7WL$DlVY_Kapk>VE<~JW_ z5S#mlseycf06?S4+#-?;L4IM>=p|dk_9m^+Wvf_3b~`q173)QY`f;nUR&kp-gNE}Z z;2QwWZI02ugOksBwmA6Vs%hqihd<|GPjhvD1?B+1qq?7?1_2%B_^*y$B%U<*{i}hMV0tmZM;G}MDG>)Un%|>wF!B)5P|Z&O5E@9)*Tm| zubcmh%sF|ha`+Ze0C9njUM=2qD57tTTKeG{@kiBnh{1~Jd$>GH04&xcI2W!4xY{T_ zWbgyx@!k0!;o`gVXW`-t^gqG%Igb75Kg0QN0CWgOF*-Dj`xnA^vWt;28GU_3#zZUeq_6mS|v`Gm+hIt~7+xSdVQ9gWLW1Dg%v|8^T1 zg=X--(}pUqkgawHT~zRcYmPr=Q;*dgq;|lJ$-GTeTT2H*x7x%*dgvx zDR+o1%P>hz3^q^PSQ1#SG_z&xTK@z=CZMkKN{HvVCe;vtD1hZb)WDAk6+1}lR5S2S zai61J0*rd$Rriv+#lpW;Q-mOQz$3`LMBZQ1MGe~5q$om+tZ8MItG?JLA}sfyT})N9 zG?-+$7w-Gi^!;LSA2b#HL4c`rVW1Cq3iMavGNk%rKdob8)q{r}b2oWF{N(WvbT|?N zUQ>79BOK-t!wsHjzlIIl!MKMiKSKH~?68Qhx#V7PmnJf5`aK{DG_kSfnuDT)mLG!} z=mcPsDlwqT702zV3m#(u8xf^DTs;7$vUG$W;C=P|!=k}x-yP4#j@s~u=uj1nbev}= zxHwN3PtZBzu5fYg-QZ#t;^1OF;^AUu*fN5NqXdKk`UR7t7oKd3;$D_PKw}~ zsDFr+TA-5^^b~AYJYOUFv~R(d`lCh^20A%2%;ROMeUFKBi@_z?^Nv>A=8Hb6=i{Pp zl?R3sJD9slU+~9b?*~^BfW^XA8eCP8i~yF%0JvBpDR8w~GhvAc22_$D>`w^wQ96uY zz8qWA;R%}c7*&;co~layAFQQ;U=Hw=do97sy_VGR!(w}~vy$`{6+?uawW1p}p{{;P z%t`l90lKFaGYGr@GH6h?|65&iRP0mFJ}n&UjzNZqh>eTXV@E_p>R;o9+MC=mw5MFM z#9P%oMZ3&tN9h#tVC4B{8B9lHz!f1iR~!}Ij=D=fPu<0be(cU9_*}yBEc0g2ueJUKWci zIA+_p8IzHkiLZztvVQ!5Sn9orilera(}6nD014{JdfM`weu};Tfv#FPk3Z1D`Ku$R z1lhGxub&btRl(b2@d~MA`4tvzcAiSDp;MM?J`{JWb8id(suud93sKYaAp5ZZSYp%J zDw-9K{C;-^T(bb+$xs!nNan(C9$*2$q&J7b570N1dciCzWVM$%5~g*mseM&ciyO9S zz11H-(V6S2pXfU$ul6M?4fJ^s^~rDKb=0E80{m3uIXYujf2G6f%`k4EH5a@lRv8nW z#&K-JFu0bk?_l2BIHBpey;@x>q60^Qi)=uS+Eyzr3e1HYi;c!*j-AgKHQ@y9TS5qp z1x~-mPKY5`SE9TVpM%QdWZh%n_`#+@@!l}StcneL3=gfEzy%|vg|Ffo~yZWErs=0 zF>i};zB;7ccq!&jvi#0Kb<^9Tu!;qr*kYrr)k^hLpInu!|G7RrRpla-03cD7KTsQ~ z=KnRD|0TY4D33)()x7kc$Pj5+NWkmM;c)SaWCUEzssoRs07i`{>+hmtRZC%`K~6w4 zwo@|^u1SE&0B)pH;K~O~1#lUs!Nup-r^Dr55BhBQvG5nVwreKQL3~-38gJ@qjrrW7 z$dudwV`e-DiRY@U55>|dqxH{+59F5E;^thdHPLGKYPAx|kPF~5RKig7C-rog7VYd# zvFg{~$arwKoe}Ebaq3dklg7EaPMIp`r>#;$J`u${xi#6}GP97#o)9e;0onz#m{X z@u#oD6HnhZ7>o`6oL={Ax|@s;R$ndx)s?S{AT=gT`+Iq)M6Q4(;31f*&fuZa;Ni(H z#K0A65$EqL_=O+{C~+_Ng+`{w&WQehf2Ny}DT8~an+@$?|5Ds6#4Hu^H4TGDYG~JE zu4Z|VYP)irQ}O=tExjXn0Dd;7-`MZOA&Z?<0WD%lBi8i)9`A7Qf}^s4SCq1zmOC5O z_Vu)l@^ihoLR_t?8^oJFY~fIS)QP@cR(^#~&6*!X?-s@%xsM(}liLFBw*oE#TnxAb z02X!dq+g0haH3xZ*X4jK0Q|Ov)##OYi6)i@I7Ul_vvgyIB6 zvxK)HZ@}}^FdefI9>ml?!?X_P)1l?Gj6NQv#nzBr$`nzx7=(CeTLKpkZ3S?dhPI{f zb51t&LOk+3s|YU76ASQdLoknZ#c=UxwhS&F&6baW(=?owz>nuU^^{ASTHlGT*(^gCvR;APw*elvJgi1Rmx^|19 z6;7wRDA&E>rq@%r@Y^`uwa9rbTJ!52=elhiS3(i!uA#$(0^dgF4p3Qv4aFI3a)9i- z8-@$$MHy~2vYBbRK3T{g^=vwixlAuxTkaw?2A}whbD1o_BC0>td!-J-i#!ruRX|DF zpgRe1+{o62B3-kuiPAY0*gns{h1Sm-qO}fTQ}mK$C8gj1d#{aCIQYpJEnTA#hN4cH zO!qa5)*7FlaVt+86}gEa*rjmD3Gqie;^Y2y(CU)X#Z3h0{XfynpIorPNz?wPh*AP~ zq6HgVMC}mUbVI7H&!igl;<#Nnyo&dxf4vcWI4Q*X&)cEV#X6mE+kS zSGIJ8t*|1l4;m_LAs9vvM#quy4S21zU62^JzNBI~KQ%EFhqttA?QsRAMO4MBZS=Uh zSzB%*j;i)sZG0HZ-Z-%tf9l36Iv2R5t2V5cXT^34dNp7_ROBzbjobbjkw8tfCRXdA z7ThVqBZGW=EcISZ(7>)Bg=lKf)pXFuqPo+cPF_B9M6LI1`Z>W!4ns@c!dgPSCQoE# zsO7swaFzc&pQ0ez2no)jx-Rl36EY$66zX{LEefNj_KqjNq7L*F?s)Pi!!Yd}hGG2a zGIkU_b##OU7DdxjjN>VY%*3>Fn2GVH4Vy0X)Rn_xhmfpkgdj2Og;e}4>`G2E2)Ndsrs`df2O+*_P^1Wf9W1$oNqT+Vz(}t#S z2?In|G!gyNO52^}oy28jnX3z7g+9M!^S}V6ZtJ4amo4WD->Rk#>#k5;8l*`*7&d^M zu@gf)&V$%+xoi4wvR;nSiiOF=*THa{d9Xf!1`GHM-Fmx_IR!mcU948;AK~R6Tp#S^ zLs#UJ$x?86sUIC7bvj%4lBvTr4}`lu>v6ys@bS(nFy18=mDE#<>5w>ic-T|@x zO^3RUfj>Y2@#i?yg#sUQP8hFKpN42rRm0)SOB?5Dn7`?Kt9~af)s5G)cf-{cIq|H$ z8(hzU!{_i4as^o2hbSESTr;`&g=w>SV*hu^TZTW5 z7%Y${;6gjppM;B-Scl<4)6<^@=*dY*qCIFRc z$m*YPajQ80;9!zuEwTZ8hFaT=!=im^rp9U;92@AhMwOlErhRTXfw;N!1+@egoj0A_B%QZW3P5CdO45 zRO9c$4=^^|uw?O0Z_Qx|=Ut;*o)1{4e-6_$dIs45E_KiJ3=6JiP>L2IywQ3wJ?f;2Q?){K z+h*}`1OEoZOoIFhet_%3@tuoeqh7u;`b_n)FnKyFs^-3d)C@CmIINY?jn9plD1Qga zfL-A#W{@@`h@}M&YoAPY!65CTs=9V`(^ro~t;7R*0}=sAfPsK4z+}Kwz)S#XEw8$E zv`L^Z#iI?d46qVV2CxGv0abvlfU5!518xM|%pteJxess;;C{d%Kn>t=z+u2MfMbB? z0j~hw1e^q%27Ckf4)6njzZmozT)woxn5mWS9A z0Fwau0R93fKHbTm&g8FO@|P?5!;<_-$U2|mRb>Sg{AEY}3?qLwk-vM$A1mbV3-X8k z`1^V~eHoAP-wl%Z=p26@j=%86A7zgzf{HFk>YPW@n@F! z<462yBL1ile+h`c=EI-l;jilOmvH#YHT=C9y($G0v2;KNU>G19kPDaq;4gFJ!!;8y z8!#6zAFvRBZ!_>075G~S{5=EyCINp}fX(%@iG8+~&t~u0hCSJ#r}}3L@oe6mO|-L_ zbvBdErq0<$IU5*fgWzn`n@w@EIc+wA&Gx9-xHMaZX7kQ$qM2%VL|wTg|FvLQ>h_Q)m|+2SEvC}eAcY%-AT{IPvLwx`E-+Ss%j+eBllW^9~{jfAnG zFSggkHnrF)7TdLAQ&enBiY-CuJ*ucfvu!1|fy9Q4*isOi^kJhsY*vR&-mujgHa^3~ zV%XjbTWnz?D{Ll(O`EU*5w-!shB(+32Ai~CyAx~$f{i)A+yb?~La<;1ECZAPRs+fa zYXG>o%~!7Z(llRt=9|iV*_bZ~^EF<+d&^g5`R*&h!7u zAdS0ad=reXP4P`9z6`_{cK8wv-+tlyCwzs2uV3)x3BIJjC-nKeI-erv^VfW0n9uj} zX;nTn$|pPdgeIShq@##ve~HkN0|A2o>3|HtFu)=J9~j`*^LYKu@1Oa7uB zpo1*$FVK8^RB(yrtA1Xr^%V^&e5uwqwZSV;1lM=*6}0h9KqhyayKba%kjGh9P=p%2 zRO>;hmoL>)L_^I@OSL8K)Ro0rmyS0kHFy;Z5qy@>aMw?3r;>`bv>J*rSX-DW=8!yr z4UEm*HxlOvIomwElFXhGX9NuZmuoM@CXchOpiwHNP>T-V-=)FJBHEt?u&cg9&5`BW K8OML^-2~@_ zb`xBT`m~mm<|@?3c%UHi&4!U~% zC|?_y&-bo+{VA=jOlv1;1fX8GK#KE|asEb6-dZ`%9Qa2{Ec2}PYBH6{hf4eD%#+vJ z`$}|m@Rc!P4nri)mFUUO${0_6-62-Sgcy)>tznl8CpgBo(~CWXs#+kcderE^S2_Ah z;f8{V@L`nlxJ-HCE~bZ5+9H{@STb1a_?x7D-O0D7Uhr|0Z?nwz%w06bQ`#1pwpG$d zY6>Yv6F$@wQk*6XaK6m!*SJX8d7R5qndJ?HtABUdWq-RFc(r?!jH-3N#bgv|kl*si ztqcT3)tf>eAYhX=Q6*tXSwb{efDw?o(u;139-BtREHG#~~L1R!!D2!-B;V7{@-&ssg9vYvSE-o95C z)fQD9g;-Dk_80wptUvqXCR~#xIf|m`8=!ZOifY!smjY;OI)-nWomf= z|755y_nYg+D`PfigJ!mxj-H<=&juMrt-Zp2J}HLkU}Aw}_a=EMDaCJ#pM zF?Svr3U_K)nUs^*r&iUmpAR~KZL%#R`IVk&TJ8A|flrJt^|xj6g(wB6(zq4{ugYH2 zu9ve`xDc$1?>$*ZKBLz+HYpfE0r0Y&@H@o9`HS5=MP;aBreGxDuO#GK%&9Kt4s&wi z<-K=?k%jW@+VI50F{~|rIx)^B zv&A3>IBUm~MIfJ^?#%s@%CgK1WT=Ab0t zS6!v7~j%AJ-r0^siRCs2s#dT z&-gC`gAfDIyR5C`yLGB6TPG!Co* zA+h%ia~Ef4uxUJJfWK>fBW2f(;-7TxWVWeL&7K}GN44ewnJo?I^mSvzAOq`4*&fOa zGQfPw2U+4i%4}&5YZ9dgSZD4U>B1wkx=*D6w<{RIs2lF8*N4S0$tFoXX~1RxO6!|*1L6SvdGkS+wdUL)TOpoD4t}t6yp0lD5eFC} zrBTP@iP~?+VS|j zIez7c)7juo!~rJpb9o~*rg!q_p-+U=Q&4SKxjF;o+VYQvc8{cH+k@xlBxI|$s@aQV zKq*fgrfSvfC1%eKn=tIJR0RT!R8oaJfQO|z%f?9KXvwz>&(vzGl3jSRL92=9k4TPe zgxCQP13U&|X=Y+AdEE#^D^=t(2IT)Q~|rlDQ6cpbE!nwBBG&Md{ zTBI8D3uk6qJ7WI!SYN%jKMBHs7x=BQ<|*AtqBlA}NIx@dl02kujeWn=A$|4yody}e z0lq)qOy)F6d?UZN;h#u7#=8}i@HL~o*c;qbFjddUdE^0@c(20VTH~H4O}|n&@*aNR z3d#YFX?`GUoY@atfo+N{i&=NRe_WvhFR?+m% z;fVVb`F0#knX)pnQ)?Vjhe;dM*YQ2-0DQyqi@Ixdd{1>$7ma5h@K#gC1X#;Zbr^k;MC-PH4eiEXXM?r zHt|Gv12j>juWHTDz2LcKT2qanCoi1p!xP^K;sd6ITg`vwO>5Uir%fLa0yruBUoW)c zr>8a3sQB>Jq8|?_{=la31fm$AnZnO)@a9n^X1fXGEy{eVD@zI#{o)AYx7NsE2rC1H1>gqoX7IE#?Gp;*_1s&0?h9@O`P!ceJ`_Jy6 zN!Ewj-#B|H>uRlFH5s`BA&pK!Nk{->^Xm@{(#Rwc-%%ZyKX+f&oR=8gs>PfvrXNOA z>uIJT)E}Uu-Vbqr0`C9t9F2NEQ0JI(UwgP#Z>IxLAP{_JBBUdifjB_1v{UmUK0}g= z=X)P%6|oY<8dlgq6b3w`(C$&I@U!;#?;N2FXpJ_Ig#WgLg^DT{#hDj$bmPb9nO+{-~%2%$yLsy5kves;|`j*V#?k<<8G6R3LBB&3Bed{q1>;(d7MxYZd z7u*5nD$80j6=AsVt)asCBes}G+RiIcP znzs@mojuP(9N>iPs_ppt<$bh9nrGoVY{f*`UskSoKw~wZR1&byI3^7iT&xsh{g_4~oL z#*Kxj2yhAAaS3%tZ$3jBXu%>svE>Igg#W^4j?RMkaR73LePpP{zO-Sy8!B zO-0ZFv1K%Ms&SArq^V`LN6*Em7*NYktsSfBY%vYPrR%a;5I?%Euzh!#Y`gSIlm`52 z9!}gIb>jsAFpC@|0gn9a2D5+Tazswy`A>H9hi9sBo>-)o&CD+|8cVXRw@mqgCwu8#!3Gcn zwBUxP%oCvv(qZ=CWlwp;{Yw&5-yu29AgD9bZ72-zX(9vfA_w*3ZS|`1-Z;jvNoFX| z6$OHI;@dZ#vFXWnfD*uuuij*CxE)00a#y)0h{~xv5)n%qsB2e zCwFL8^57bmfjL9+@&~8(wK3n{kBR`X{E01r(tv6=d9Uf-l*i8u=e1i@tD&HH>j=NY z$ggWh6XE~~{Ijj*d7g=6|8QYXUh?cTPn62G-htxZK0D4Pwbwxn(2o~yOVu>_I@(gK z+$A^oin=S!s=wbB$Xu`+r*=f{2=2RMx;WEHao{U=Y*)hU#EYp)D^cah9K>%2WaGcK zvt{+{od+2v68l+e`F_WbKeML|e`I$s>%zD0p3K@-JMa0Ll~}7#+dd9NJy>zm{6>8r zHC_OG0JsRK0dzqYxKH&m9zOwm2GFVNJmLVk)rHUhi)j*`Cw*b-w&aEOJ+0ZOu}{w# zI=H4uzvKsM?1!hOX6h+^0g8Yp_~{oyHG*G|%E(zx*jL0-`8)f@+hezdKl5TAUiRV& z!*2OdK7wz3F@g83YA4rrg;g`dF`U@;I^Uuaz;c-63Nh$a)}B|b^yK@xdEuY9?5ue4 zJ`=p$?Hn8owE)dPzom}&;{M%+?_}xnG`aQKnJ+o;wf@x_Qne0t1EC)PHvu~R)glhC zo4-`OLX)R5Yr7JvVxLh9$L!uOw#t}Zzk!VKuJb>sQggFSeX$))<@%fncfwTiWR z{{zau0;r4shR`2?KLI*6enK4JU=!{>$cwLheupDdbx`_;l>Hijv63CgCxRF)!y zK}ubQ5LWlal2e;)ubFpIVNg)wTA~Aj=@y2Fr5*ny_DvB&XKm^r83So zm-e6uxDHE+5Gze`u&+7dp{d8-!e-JxvM~wyM}{^x$Uy~bjz->tT?0r1ZV2OwQOU&DA7VDwiOo<3&_wbsr{Lcl@9szg zmD~cj(XF-Ia7ecDlS|(S)sK^2AOUdZZ@ppepu|AeK~zwuDpB5T8xLCffJc^|KHv04r~gP$-}S02>ziE*6Y9Ku3G= zP^>hfo2NHuEfy?Ib8yO9beUklIzYqoo(K>E3fq-Py;;82fSzAk?6sb zFUIpP-dk*Q)4n%K0CvI-#@92~n@U~zz=dCV-!HBYawSTz?cS1+4A^T;B$Z$nW^x`7)l2jz!7VP(j|e(jTIh% z!hqw}g$M9YEB1taSbc|_4wb>{F zc-O)VkG|lios)R{!w8pp0(ArVjW7H1KR@&iv$clI1tq`-pcEp_Ne$*(KQL2T_)+JS zdP?db-%Yu2QONz>2bKU|9an+hKRdVrgt zXHocwbvIZq{`|*LjkW$r5CHrR0+tRjl3Hxww`fV(z0G#;zE9U9USn5uft~_VZjIet7Cu^9?JZQc`LivkuOPJm_t6#~BdAXVOae>>6aj2GmGMXbG?xOEeamy+i{uVp9G6~o>!m@w&6izL{$8J$ z3VMJ9C`fA}e)NhT-|}4`f9p%zeySLS0IAkmEv9Cf`?U){@s(d(335%BVB2nIAQ_Np zO=O1IPlfW4R}aR(Ic2M<$Qxwco68Uf7=-d^c%t51W@aM1F$QL#2w=1|1GA*Hr}5xx zYdxZ)^P=M7yG6xE$3(`&Ms<&i=5Jo}cgT>8r19JoZ{e@Vvs}L4jEd7uBalOLsSlx& zAZyNNBMvamfnM;5WwFeOzx9oI8*DZS;QyTq?{=*vFS_2mF+s{f4=~GGka8k)?Rv+? z2w-1X1w3p`U@j4O>q{5D=3C#!h|B{Kztza zl`lY9z;a7jD1Cu!%Q*R_!mE1r_mi2vnI1za>VuCX6lC2@3lRt4cQ#YZ4RbRsB)RtA z=+qc*i$Djk)0($MUi|;<-P+H|`jkx&@#icWFK0MNTS1 z)*K|8>F>6aGT#8Z$i zBY*82w*h&clwi9tHX#}CIdu6Ho~SW4nLTQIe(u*V@8MB5qXgh8%3D0@W-|kBJo>kQ z#+cXwB7mFLOl%<{$A4QC*{}f5qAcJ)D60+kYko=Oul#=K9!IEmpcLQ_lp0gtiFc6L zNB{UvPTKeVdB|XtS?JiAKVNYx)Bzh{Y5d9#^5Sm%!&}h?Y=?zAVPx)1?Tiu)ZulTjE>0KuO=uW$+dy$*i391(@1fl1V z00=RN7MY5d7&w7BiJ&GdK;z|kXk094!eZkZVQ3#H0lHWiLJj+<(~J#MXkRlTYm(ha z#|e%``w317GI>JNkxmnw<&z6NxsGfqzjLvl(2Sm%k93~kE}vS^lgCIG`8|vM1TT8> zmWQ-jir4H}s8YTPM;OzDYjYMLCOWXMS-C0K!1^;699yMr&GI#3P@0r(tTS^J-?%eX z#5*%*1NQC9H`XWdihFlw-S#es)9X1>>;cGM4WL?ILg*l%!H!;qR6uvBu`+|Sn`V|B z@JhQ{cah{OB?|D6TfApn*ibRgmGu+{f|>dBL>09Sb7P^boR=p0i~erR*XG>Qgqi>) zqSB3-U*?<0w3CdTUiN0OO|r4oY<-#r@*PG=lJ5vY{{S2X(9U!avXFZqV>*Nc0)w`f z@zys!;HnkN|knAX3_}1dZ4+_;zus4J)_l2~VOB zV2c6oVY_ODPS$g9!I$~Py^c(%H(PxJ!60jK-a#B-2Q2yoo=DbrsOlMQS=*FTh)@eKut+UiS@ZwywYsZGg{bhphf&^f{BzUuj$n{X#iBs)ZJ5ADe zEp&VOv7oGfBl~&4U#{T-asy0Y`8_-l%NL0BkZjgV{N~3Z9GL8h9wN@4tuZ_)ZMbfR zSlxs9iSPVbo(uH?^s>6g5SuR61+YE_bc^y0a*y0o^d8T;iGV<6Y^3XjJL_I7sWo7T z?8Va6E+MYL{&o?mfFn|%vbQ8xcXT(=CYY6rv#GZ`*G1}FaUm=@3h(p0l0oyT9e3LexkNw#qfs4fw?% zwuUkD_X*dC?FYhHNMnM3kMe+~jxu0T-SiEwg`R$g7cgUp`uks z7Os4wh}>bUtr**pEz5vR*?aE#EWjdakhL4Ri8=s2sKYWNx=9QccVgjOc_C2?Q9xSGUCPepiB73Y3^g_?J9DRe{q&e6G6iPPB_R8{i z_;@?9G?s0Z4O0~^8)jM@%ZeEwo7=W;_W&h8rM18wn$FtyWMOfh$kQ+hZzKa2T9feB zNF43SoZ_y^X1&LEfvrFSum~h94yu(Hl*#hMka!ji@AQu$(mOpH&z27Q3vODyjyiQ# zLg!NeYf;g+$Po_@W<^y0#M{%Av>0FVM41SyN#4bZrGy$|csm_R`w0r;o2KtURb@rf*^ zF%lsl0eHijM2KLcb<(tTwXd9;)k|qxwkS{ld~dC-D0IP* zVoN`^sgQisz5SZiyH9Js)*$m;Q8nPE*b*lF{>oV9d&eBLtESzBX)Juo|3$lMXVen} zrh);qnCpQ!fW4CpMB<4OduW;))SuJ(zw#p7?9C1 z7LPbUJ15#7Ya1+A8{IQ*Pu%07lvVd%9|@=y(8*dK37S3*4q%z>k4ZUg8&MyW1|&Pt z&YXzPygfzf1C{)e`@hsi3J3#I!B#gs1w-2@nr*Owtjqn^ML$#n7-p@Dewr@M4`h*X ziOAEiLeh{7m*A@(s2599l{>67w z8yWDkK?JZ0L@Wb-wl?6;AHsT>2mD?C>#;r;bpSS@4$D}d3r2^Ds9~(B@E*#V$7Ld8 zmIT{IJs8P=7pw&ye22i@RX^nF*8U6UXl5x54>OgT(zK<3B{O$g0btL~ zJi8J%3fW@iF@`OSR@#Q!$#HCq;c+>5TXx|duXsW}-+TW%+(o|$XW8_iSr|6BRM1t4 zScCJLV#opTkaCn=mAqEkiIfTKE3J`>HOp+ijCB$-jjS*-4AR7c?t2n!Yqk_L0ewZ2 ziOhUNyHumpB~mFC&P8%_?({@9&=JQ~v+JU012Se3^E2QqWnH8=Hc2X|WD;v_0OvA7 zF1EeJ)=8`lTPhAuVm*c|0}tSr4zS)mD-A>vsNJy(No8~2JA>s+J%Qu&ycQyymaDJ%w?`?e`%|wA%hTgZ=JmxjsO#6Mrt0MjcSb zd`!Qn?87D%&p;`VF5FY!n=P%$Q6F)$7NK>3^#B3b0C*Dc6ksD@6X0pUW&o*Ar>`|g zZ~;CKQJ?h0Oz4NAa70>&1+3NWE23Unz#b1S2ZuUh`#=n! zI7?!EaW{~7;?dhLj`o?Jdz3k|j5}>e+KQ`6Ch@ufzia#G@9prAK4BN7^{m2Ap4gs_4&CJs@Vi606!p=U#hKTnT zGhg=^$a}}|vVIB63|S?)vpvWhLUuq8F?|V3)Ew#|&B){+GeJZzWd%kWU(}h%OJl(- zgvcfyM2HT3%tpw1I8h%$oUXNwAP$fqg;D3=DHzH-qE#vfinNruh=qezA3;ddr>zsC zN0AIj1+jT}3I?&G8nLQntjy9)veo&>K#pA-dqtn+Z0JB}$NH-|kgyoPWh6jOy*$T2 z6Oe_*nR9zM@DUL!ZV%eWG;VNjnD}lbn`lUoqLt%|)*xP7>?RhkVnH!D_iek4j-v*^ zNC>GNiv=UcK{igbT+NEQ>U!?~ph%z%ZciWqFkb9m%{poAeL~~!_tk9m9d~_=;GgVD z;9>GW-_h;N$$`c!obS^v`&#KK_HgFPLsLTKPVE%VvMZ>;K0>Qq0$c&mc@p(g1nC^f zU7O(+H3x!S8mb!n3hNZO2TX#lPsjpr8|J^fqFY<;_dlNEALrzWkCL@)p(foalFrm( z9m`_|^o+WhQnH?6`+An(3#rul(K%cF5S)UEy0OB&qY}kO?dZZfi&26Vg;3Xg6D;T? z{TPMt{aD=sk-L=ni>6O9UwJ82Q_*n)OJeVfX&cys>;v)H2DXA-6zY?#Li*t!o@D!7 zVA`sJ`Z6#%^AfK=#dfx&vj}(TPt4oMUTAoLrw`aJfITYSpc3Ck7QkX>)9g*`-{xWJ zZOsUZHnUq5r;&x6$iEP3P)X`LNT!L)8H5_wka`yR=ySYt2+`+w?;>;&n)o+DH3bNs zNANvBy^hrP@kkPe7b&lsF!~w24oBD5IN8vYbER}Op>F36aMbENP^x0ST zee!c3qdGv6=(&xlnk{~;Df#xTXLJWx{wAdnp9!CLvj4B`CFTEWFXby}=~T9d%^h)3ihuXI(4xi$yBP}VZSFI~ z0j9c``aj1mnfuyjWCq+gJ6ufL%a-{p95&$RBR_T1+^42`^ zk(Ofe3v&Gzj8^|bb9_5qkSE9FZ1dZFY!rQOE2j!_Yoh~h%@Y+bvS0(cZFwOLM~FNB zBJ0tD+`YOEbTG*;r|4iUT1Q(c7UBSU?EceaQ$}y;$PKl)Huu@!`<}LCQ<{qx#ONl%ZlcjETgTl zKvJ84>U4G$34n7hrX?@2x6RFQRqK`H2QIwK#@tswa2<65+KDBm+kW7>R-;@>^%Y}Z zVP1x%$dxJ{dWB^fmLa@cy!8sp4~9{ws{lGtzC#=!RAjx%%$L=Er?vRyS6KkFd9L6F zN&#X;yF<);nZON=nW)ojj_LP9Y=_bm&HG6&*{g7pu$}4TKUjjI%(4^Dd@1kQEj`di zWPimRO}&q?i!4_+^Y{;Hu=JKXJpK-#J6vud#Ox*L#Q6ycfK)N@IJ==4@J|-T#P@G7 zkBXm>i)#15u$2-Lx}4710kyLPlTveJJd>5D>mwPKpbGLs|+;3Q!oq-QR8KR z{)i*nn44+&2{u)6G_xXZon#ZeZE#aQRNHlU=@e`4Xyy!_eU?i-bL9_cS)O{6b*!+# zXt;;I12};%Qf^a(oB^Z`7lcS1qzP9%k|x{`B26?ys6qX^I3gMFnX4)1E%v&(Ysj-2 z+n78eewr;R`R{4p9hC!yxXFN~eR1qnIX26Y@=Y3-VbVb)y(SNuc6o<& zim{YLRWp%4dq*VNAqVkI*XKx%$MyHiC@agYM#2tg4jmWk&EmLrk&CpA=-T< z*X04zCkD)%Yz&YU;$BM}psbrGW_%@&YUX^zE{wfo8vrtDc}O1Q!{GO_f!Jc~{K!-pEl^wOtn8phzj&zbysUX*^$a^2g3 zo*%$pLfs?v8=+3`%a`JAU&yWRK#}tWh76?3%bMgS+s!XnkCxywTMb1~;pLLOgbrg=qKb&Y-(< z*Bo^g-&|!q?BO{0<<4Eil8MHMv$y0Ne<{I2bd1~sZvCe7c; zYmtXa1%v$oIxY7=9N-IR8Fx&`X{l+)HCAix3Oz{6?3H@kd$2;9oqtWsw4xGuwNR;A zR5Ek$tZBv}vx zMko@{1we8{Aw)`vMo3c%4Q}Xebz=V?+F3?_G4c|NG{9o&#@xOyUHtPB>p_=3*I_fI zyXf^XYpWUZL|j+`v+b$KY1QQK**KASna!C-_7&b-Kd?4vv9^2wnQeo{nh7}oC8nfW zmaJ%gAX6l_P^O8SKd_0zv74s5154XXOF;r{rllfey_sfvZzvD70WLHbRX62JF!DNi zT5T0SGVgXhlC|HvFiseiRa7=}l$9qI1<{J{sQby#2rvY=0`nWnPyga8&fL8Hsz$zg zh8nj1BwgF~XPLXV%?>JV$$QT3D_0}I72s>)O7z(#*VbomGV^E4BQ>`E{WI%2Whk=V zPmPQQLBJ2PZj~;xphl8!yrGK^|HC@p|4PTAQowK4mCASI=>1E7VNWrKTxn(5f}N7@ zEaV0LVniM5Bz>sda%hcb)5~=%Okuml<=^F?wM#_)!9KU2B;A{sv7JSl`u)i=n6j%0 zCbezF^S9(1jalN@W15CgF`&d=4mtWE zrT{4bd((g>${usCEzq>(VNkOE|LQA~!8lD#vJfKQG!P-uL^eV+!sZ}EPAeCoL4d)4 z{vypu8CHQU>Ax|O{{_DYih4DdqDDZDyYvpYRH0J)Yw~TXQhL8QCyyE)YB2mC5%wt2~PYk>D=hC#nyk`N&btf}?urzTSy7 z8&v^XiA)b=tTt-R)_U7152XW>yF;~}$_yIt%M-9QB^G-rzS^~&1L;{_YSl?8wZjS= zn-cPci?`CLFP6i1zt#_g=b-5b>6X^ax{1>qumlJYPkJj`G?wOQEXj{Oz0L0qW(oQE zO!qaNqQ&KK#a$kAsSQ_3r2{OCPzE)vaVQ%e!t<;QJL(Bee&$` zX*_U8yh!RO7nc<=ioZh_8Cxe_h*A28h)&ApjC8P?A)x^&kY9Zq%p#M%gUv+(Ai4z> zu(vcZ=8_oL=zinAzRO#L+5qEWF_w3Ei?sUWA&8ahqm-5v|Gk3{>SOTwwBh#zLb^s> z0tT00u{{kOE<%=Is7;!Pp;UB^`=Q@h?o=P)q=X#Kw z)^`$%ddf+}5%FSAWr((ifX(S((J@}>!Q}qI>R>UqwGv^#*17y~CHRhaS}U?y} zq1zbijI=O!|3jW$S{R^28!$_$8%yhts{u+^11?6an~WC>JfOO*$O%;99k7P26EhCT z-!TZNZZA#-DlzsqWt_O_s|=ld_xi;0Qioo)k(!Udj>&T95=P4m>E1Unu0taLzG`7g z?xpN7FQM0I?d#B6`O>f+SvuqT?txOxiG7re3aUpSegoi10Q9Rqh0sR8CIH#$(+JU6 zwHYC@+Gh|VMz`ju4ch?yw&vai@H~dzoy}$KTSzZV(5w z@-U4{R3@0Uuv^mtxrOv(WypPf6Yw1B1SE-b(Mn66DrwSi z_oXU>nDhEHB~x~VtTZJ%>bb5$93am_tnROvPfJ#53!`i4O4@y0D<42@fN36BD|?Gg8A`g=0P-_L zIULCEWBo^$^CWR^5eb?e>rs6-P8aeLga`IIW z1XOs)z)N_d5$#oItymn)Qhe@zrH4=rV3BpD@}v;-*5{ozV(LJp&Hy7VpN6xEeqwR9 zGDdI2q(idgqoAnM<`KjJR(lA)9A%=`Hu7K)>S%t#UH-sXOVgV<(ijsjNZ-@In1&=h zcv|vbmSrbaz9hF{hYnJ@yOQ#dlpWSptRJL2TA_NwvxZ8jX(Bfc=?65`-iS*E z^aJzKY2*MJE#^S!3Zb<6a!`g<^bjb9tW%dtO2YAY>-=r+K+Cj z+Y#Cc*bArv8~_{yyaqT7I0`rkI1QlVtyd8G6!0bBD&Tv-Zvamw!3Pis2n9p{BAH!< zTu&lMN2Gcp)CZ6R=m(%5mB8;p(9bWZgAp1D7!4?tP~$Lh+VsMi^t%Cc=|A1bPgmyC z758)_J>3>hH@DLT>~uLg?m3tBZvdfffE|G60Q&&@0Vcrffb)Pa0CdqYT{8R=9_;O`y6259YoiO-=<+jpV;Q!N=YqmKKqX)SfNtJegwPVeGQbMJ zD!>}RI)DId0&E6s0pR)|x($e~=AmnLw3~AFA)yL@+f?YTlM1?e} z`pjANNJIbi2DAeB0DJ-M00Dp?KnNfd5C(_}KptQiU<6a60V zFdgfqqpx&im5z1N0Zcj*NoN`9G$9@Mqmz1c;EfJ!(di{RQ$&Y!=wJyQ0iiPubjW~? z1kf9PdYfKBFRV!Gpwe~$*6_4yrbQ>M1yx#fVfmx3pbb3C_-V#T6E2zo(Nu*-ej1Qz2&F-d1{oRy z$X)CFc%4&%{55C!BBzgfS`w8#-L9-QO8h!psTOM~a`$`;kx!*G>@MJ}QUh?F*Hb9lOc$b`ov?ETIjO0U7b5C8>m&UR$ViS4^{? MP_8QW!BXS@4?>c7H2?qr diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index d2625ae..d428316 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-06-29T14:15:58+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-06-25T08:19:41.526068+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..b0b698d7f3449fb002a3d3a870cfd700456eeed4 100644 GIT binary patch delta 38 scmX@lc$|@YIWI340}wFPIZfm?WsI8WD9lwma3arkO`zWKWFaK0|33x7BT<; delta 76 zcmaEx@->BfIWI340|=CAZRCz+W;fI`G_ue$n4HfXq?V$ek)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x4-&)la60AeE<1poj5 diff --git a/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc index d87cdb1bac7f4880ebeb44a85f3d6e4d5ffdd4cb..0ffe9813c399efd695e714b6e02568e1fcbc6eab 100644 GIT binary patch delta 68 zcmbPO)>+2AoR^o20SM&koHlabWo9ok&@(jCGo1XMIY=%>KO;XkRlle-FE6!7KfXM_ VC|kd%ELAtLAQMP$PG?zV1^~T+7Bc_< delta 76 zcmeAyn^?xZoR^o20R&35Hgex(W;fI`G_ue$nEakONG(M_BR@A)zo;}XFSSTNzC6Du YTR%BJuQ)#^RX4F96UyEk&$7x40A#iq1^@s6 diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc index 7d05d919d947b7bbc0e723946bb4f0ca957ad427..28800ea2e06ebcf9910f5ff7b5d27b781e260ef5 100644 GIT binary patch delta 2202 zcma)8ZD?C%6uxhI^VxfoCe3G?q-m2jA6=7mYggO44ccNWTE{-nt+;lz@0*#LCgE*X zH`i{6gYAcw$@^nd5v-sh3R2?y;g5l!{*)p6F@m^(|HcL>`a_U0&$+R*o&DGi_qp$L z?s?C1&bjAavUKXlQ|cG0YLVawUKp4jURH-lqa7(6fBr@!>9TZ9V$v9)(wL66iYytq zNNdwZsxT9ieN{(5sscBx<5u9tb=(HrypGo~3$?Ra>VQ*bO1h5LU(%1M)X8Mv*0fAr zm*g?qf4mO38@L_#MRbtC-~offEa8u~X^y@pl3Ej}Pg`gM2sptvx~Z?sTxkPs1Ru8+ zF{XK~Mew9e)DL&PT{OUacoR|xLJAF}`z9O9^W09j$JR$bg{A`@to$TC~>=ZTfk>Jaz*Yh(h z#n0q&jHf2v%=0%=e2#TY7BX-Z=jD&dbHc0d_n0UvPG+)=BPtMHCukViqf&etj+26`}gWDbu_%UpsI4TK-&? zq_5zt9t&#Gwz`ISFi`!xlp*t~sMNNLcMRVVtLQU^dw2|-$_mTTLOzo#PMqP{a!ocr z#dm|9rx23pVd8AIkk8GsSu4yTrpFrPT2zvnHCcYQfT?pOc z2Xjz744ZYlSKK!@HXTH3Kf<#J8@2d;@r~jZeHJ%Klnz@S>=62dl2{GBsD#KMY#t#8 zN`EUici8x=wGB6_yccpP%SCp!$Z@w@L~Jo~q%>+9)-|tH)rpyErI|OBcEcVgJ>srC zW_SiYdWGs}NoobYgglCXP2R5Fla67ME`8=$)IHh8jar9XNzl6B>R8oUcKIV~THADV z#dVmxT^e*>d76?Qc)JZfka9UGR=goG?6a-vz3S_ZYkE&r*7v?~@?pu>(5Kr!2H}oz zt(z0DjO%#^_5^3EI%V1nXw#zg*tns`SN)y%sQTf3$GVwliIe;*LFoZCSFoN(R!V!d{2(KUvTvE>0&R28zp!ct6n|%;EA3Kv_AO z$xX3Cg<=N2Zu}hD=S4ZOmrMz3``kre@Q%}U$LX%vz4{?ikr40MJlAX9U8v|alR0}3>GQSdaJefw!g1Zs~Hrj-cwPvrB$*yDmHCdhs&yp zLo)j-^=Nfg6*pj4$-HY?N4i8YdA?420{Efl_%{JY>~Yddgz%fOJ#apD1p`!D8;)DHjv delta 2178 zcma)6OH5l=5WUwtf1d4!vGIqGjSU9u$H$ICzL2CUphA>>6q5c>NojYe{ z-uSIe-kwxGR}?G3&qCLQ$ci#dn;n7@^5;*KkPpaB!pJz)$hbiZ^AsIjnlWiMW?@p} zW*i}!9k{8AE5OZFycW1z#U0G5)xlR{wwYSZdDS>>*IY~juFObU{Z(nac9T1RyMfnj za%pBs(mddB$^`$kc5&c)qM(X^YsRWIfIvOOc5E9fF*mf-2r(X!u~S4=H+jsI}#yZ!?*ldwC5i04LCHDX3Uc$&D;5u=^j=1 zkU5+v+F4r5W|HaL`2{^ytVw02^*99UF@#=#qD5!(Sty##D?s_O`LN_74M9HT^%WkN zzoUK?L%R_Y0IEgbk9Hrz0lqG`*bbq27~u$iC^rXBpxKWwfUs3hKgL(>UVhT*rD|c) z`r97)XYE~E@-N#%bPzI((&GiQvbx9Zd$pb3s_LMcqLgEoayq8)@;*nDo-Ukoj2K!g zP42^*MW^zXPS>0&J;d)jqkP?OLrKpT1WZ^Im(JhW>6i2s(*Ic!S(l4GkMi+ z%I1>rD$_5a{|bN5)kk0E;qJGW+@7D^-jc&-9Hu3L_>04LtLDSSl2N!!#MN}Gcf%Pi znFY5HPhdUJyWx(NWZ|%qK*xH=(G7op$tE0j;&7D|Vb-EqPF+W2f5|DlLZz%#A|~P5 zU+C$%V4!{cX6%Y8-k13L)}08rIeGvApWGwMvAK-4kYXqFkN7}*_0)(&2chzv|6M!$ MNBQ)xU4n$bzmi(Lp#T5? diff --git a/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc index d705642e1226909db262b964ed97acbc6e614089..57dc54252ea03d0cfa6e42420c9107a21b0947be 100644 GIT binary patch literal 7214 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 diff --git a/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc index 43a3794d6559f7bed7b0eeec2036e4ad35245093..8d2b4eebf0e65035a018fd7dd901223f56497243 100644 GIT binary patch delta 2287 zcma)6Z){Ul6u-B9ZC_ve+O_MSbz4Wrwr+2K+WmoT3=jun2^bN_pDcqg3hxezrLFgM zFkoYRFwv+%lA8b@{9s~~;GY<&e$Wp_zi4720YV~aqLJ^@l;Ag_@!VTkTbRSwykE~b z_uO-S_nhLU$9pUPBb!1Fu9JGcMixnq|tV*AfYIX-3k0uSrv? z9r2&uChUPHa+LNj@&K+GMGry%H#kREbe2dB(5wR=j|kZ=yvh{3GqN6n)mput`1l%7 zXaEX+;nyhiFz5lu&>?J1B&e?;@*=6LIG031q`s^}&Ky!F%?H;6Q1*VyQvYqOU^$o`Q*k9&}rbF@LnUf?= zXVYmyb~k=~Fz;)>_)v%R0#=k}0AWq-^3CDM&{0EIDdhZX!Zl zHpBZ+f!1F^I$p4`TXKU%PND@n+tS`*u_n>H%)WJOv?yS6uxvw1+&1r+SLW@XNFPcF zeGG5uS#ahaj}jPkt8SS`Nj&dl58Auf8SAfDWs|n1A=(bB1t&@C*-SE>o1Ueqf;p8r zO5RR8S-Anr#w$Z^*ZCqsD!@IP?K%GVSN`0Ecz#cl#i_;J5eF zVbBXwj?Cq*%e0;^KF48%!$uC(`RFEgNZF6I{Fll;Q*${*FLxDr>{WSOZ4vf@8nO<; zdZC|<`s>+FRbdxZw{?hb8D{URoiUMeJJ+Ke_|aEm@JOA;oAU=;?^ZH+Iypos3@@kL z;vmnuY9~(P5At$& zpUGP40t>Wmldfah$39xKfbX!5$a=3hV)Yl1i42wIqgTww#fZ#qM%*LIO?iB3(UAlv zapW0H_=)4q&*QK2+2;2u*o;*NuC@)8A5~AAvSW85cYJq(CQd@hs6kg|-og{5IjmAc&iqc>7`~eiMx#%CWL0&8 zNQG`uvAK>~ex*c8S4wa^nLb8nmcr#VF`FV2|6WscD_kG}_G8B|{)3sdFQQ|dON2u+ zfQBhIXr@ZjF0F6?yBg_T2S!6m3G6kw1JZ+;i6#E82xYLAAl6Lx@h~_7+tky0};hT7&EzMUSwG z_@yiY&A8Z~4|E?i;Q?mE&ee!kx;aS?hd%aqtPa1!g7I%gb7nkJL@VQ^p$B5+&;MAb HVTkq*&^+Ig delta 2219 zcma)6Z){Ul6u-B7eQjU+)<0{vb!$fpYuOuH+l`FD#$qOwK#a>6prn#O!@GrIY3q9( zATq}X48~|;auUEqq92Tgh#$1ZgfApS6ZMl2i7_Q6_{A@3QlsDSgZJFdwdK$7HT}JF z&OP^>-#zEtcm43i!|KPXst|k@hmXfUQ`59x6)GWreMCALUb3`dJkoJ8aea++qMdx^HO=GvJr9%V4m@r`XPF*d$6k%A6sA)ZSfE1h6T zW3gCdM)J_9lJQdVNU3O+3T!l6&acQ|N}od1x>1$N*`ur`nfWv9hzvLFensJZzC?7o zB*UJreyc4{mhA9y*G6iC@14_D2iFx??%xoU&njmfXYJRdk0e4q;s3_7Y zm4MgfyVM0)+W?%m`NIkBVT>Y-aH!c0W|lcMX1cfvU)l~(Pt|R|O+!QIGmMbppxKQv zl*bV^!#|EK(-SCeL73!FlPc_V<*ME2L(2@pHiRjJ_N2x%oKT*pL)EX9{g!AmPZC{4 zGDlmoa4Z5DH7H}k+BnPy`rw>bfh($8Zls6L)!~FlnZ^(?ggC+)43y48bbIx9=X1Y8C)NV#JjLmxU@CxAo(-g(O)4ok7#M^b0ly}S@xSVDKX6hl^RVVG9L|xt3vMZX zDEe&Gcf0#6GxOZK&k(%!b5XMzoA^u2PGgEhYsFNE;@R3dSMQxouZ~GgDwoWPrZmcf z(bgW5nys9DrBKT1d|noVW%_3I*I>Wp!MSWt7!Ex%(@ZGqtiUR)ts^gD-ZeXNihfw_ z3GcVajc!0}aEEl28Y#HGZi(K8$;gCH9JT#MycU^k3}{MB%aw>7evY`OR-5zRxkYCV zBZ=%2n8c$8==JJy^n(^A=`o$}(rC@QyQt@nWGf|OSEW*(&sL5ZIlf|AI7A{w2xI3t zoSBB%&H)I;9dL8dPk)0S2Omj49NX4diY(-BszE;V=KCDM|c`x7s76Y=Md%)_9EkyRLRy=V_fF-gEa{?s#jdZWSh(`1&r7-ti9A zZ9=z`K=@X8^o~DKcL;+*+`hU~h%OWxkvfTEsO}b45wsC{1yeq2_+Fs5ZsqT4dSs7< uj>E;os~$0YZY1bMNI^8&OW%g6rc~p{nIWI340}#m7Ic?;wU}7&b&@(jCGo0MT6eJg_pOK%Ns$W!^mzP?kA77qd Vl&xP>ma3arkO`zWGclj$1OSH%6s!OM delta 76 zcmX>qc~+8pIWI340|=CAZRDpOK%Ns$W!^mzP?kA77qd Vl&xP>ma3arkO`zW-)9nG1pte_6u2k)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x4-&LqML04d@ZlK=n! diff --git a/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc index 53c1b9a9ec792af93fa36c27f740d87492cd99cb..940b1307359e259c6cfbb43c89719ad47f1873bc 100644 GIT binary patch delta 68 zcmeCSZ?@-N&dbZi00eS%P8+$^nc2$>^bF1P3@2MM2g$|hXXNLm>KB#f<)s$s$Cu|9 VW$PD}rRpXYWCH2U8<}rO0{~!b6s-UN delta 76 zcmZp+@3!Y&&dbZi00O028@bh)*$wp!jV$yGCR;KGsio;>nG>u73b%q>LwOsLfM;FGT)L00QhkifB*mh diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc index 3dd88f559c910ce5387a7850a10836d8cccbb337..9a0943b11b31472b2ea776a54d94cd473fe04ec8 100644 GIT binary patch delta 68 zcmZ24vRs6FIWI340}#m7Ic?;g!Ngu>pl4{NXE=EkQ;=Mwenx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yiti;UA4gh~~6bb+U delta 76 zcmZ23vR;IHIWI340|=CAZRDQ8#BQi(Xk?*hFnJYIkXoXCMt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~HdikX)k03GcX-2eap diff --git a/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/products.cpython-311.pyc index 46ae2eb243d215432d14d619a14b512bbe5e3d54..9635bc70e227ef3a54dc93406f1c03563d168411 100644 GIT binary patch delta 68 zcmX>myHA#TIWI340}#m7Ic?;=&%|D4pl4{NXE^yIQ;=Mgenx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yioXH%^4FIaK6?6aq delta 76 zcmdlddrX#lIWI340|=CAZREbs#BQi(Xk?*hF!>`>kXn*{Mt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~H7kvWzd08gbDM*si- diff --git a/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc index 80c82367ed26d1b3aa8f4a8bc76f0c16126bf6b6..b12dca14d9295594e14c7e607f7d4e0ec5b2a825 100644 GIT binary patch delta 54 zcmaDPc1w(VIWI340}#m7Ic?-V!^B=@pl4{NXE^yDQxIdqWJ6|QuA;J3-Nb@S{i3qX IVaz-n0F71-y#N3J delta 62 zcmca5_DGC-IWI340|=CAZR9?~#BQi(Xk?*hF!>%+5M#zma3arkO`zW|6_I$0sxLK6+Hj| delta 76 zcmdm`b4Z7KIWI340|=CAZR9RtW;fI`G_ue$nB2x3q?V?ik)NBYUsRfxms+GBU!Gr- Yt)HBqSDc@ds+(Al31x5o#_S>l04-7&5C8xG diff --git a/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc index d4f743a50282e1bb623c56cac65a0e44cf40b373..40c2ccdc8f9ee7490c32f79574bf7a2e18a0efae 100644 GIT binary patch delta 68 zcmaDK@H~KfIWI340}#m7Ic?-V#>`%3pl4{NXE^x=bC6u5enx(7s(w*vUS4XEetda; VQMP_jS*mVgK_-yi9Ka&40szr66}|uf delta 76 zcmaDJ@IHWhIWI340|=CAZR9@2%xXk?*hF!=^^kXoXCMt*Lpeo<*&UTTqke0hFR YwtjMcUU7a-s%~OICX~I|gGF8i0D4{+kpKVy diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 057a909..7a03537 100644 --- a/crowdsec_service_api/services/allowlists.py +++ b/crowdsec_service_api/services/allowlists.py @@ -11,7 +11,7 @@ class Allowlists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def list_allowlists( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index ac2cad5..31a6fc1 100644 --- a/crowdsec_service_api/services/blocklists.py +++ b/crowdsec_service_api/services/blocklists.py @@ -11,7 +11,7 @@ class Blocklists(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_blocklists( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index 6d90155..24bad21 100644 --- a/crowdsec_service_api/services/cves.py +++ b/crowdsec_service_api/services/cves.py @@ -11,7 +11,7 @@ class Cves(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_cves( self, @@ -19,6 +19,7 @@ def get_cves( sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), exploitation_phase: Optional[CVEExploitationPhase] = None, + detailed: bool = False, page: int = 1, size: int = 50, )-> GetCVEsResponsePage: diff --git a/crowdsec_service_api/services/decisions.py b/crowdsec_service_api/services/decisions.py index 7468e0a..44613e4 100644 --- a/crowdsec_service_api/services/decisions.py +++ b/crowdsec_service_api/services/decisions.py @@ -11,18 +11,21 @@ class Decisions(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_decisions( self, + page: int = 1, + size: int = 50, instance_ids: list[str] = [], tag_ids: list[str] = [], remediation_types: list[str] = [], ips: list[str] = [], + alert_ids: list[str] = [], + decision_ids: list[str] = [], + created_at_from: Optional[str] = None, sort_by: Optional[DecisionsSortBy] = DecisionsSortBy("created_at"), sort_order: Optional[DecisionsSortOrder] = DecisionsSortOrder("desc"), - page: int = 1, - size: int = 50, )-> DecisionsGetResponsePage: endpoint_url = "/decisions" loc = locals() @@ -80,4 +83,75 @@ def delete_decision( ) return None + + def get_aggregated_decisions( + self, + page: int = 1, + size: int = 50, + instance_ids: list[str] = [], + tag_ids: list[str] = [], + remediation_types: list[str] = [], + ips: list[str] = [], + alert_ids: list[str] = [], + decision_ids: list[str] = [], + created_at_from: Optional[str] = None, + sort_by: Optional[AggregatedDecisionsSortBy] = AggregatedDecisionsSortBy("first_created_at"), + sort_order: Optional[DecisionsSortOrder] = DecisionsSortOrder("desc"), + )-> AggregatedDecisionsGetResponsePage: + endpoint_url = "/decisions/aggregated" + loc = locals() + headers = {} + params = json.loads( + DecisionsGetAggregatedDecisionsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = {} + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return AggregatedDecisionsGetResponsePage(_client=self, **response.json()) + + def delete_aggregated_decisions( + self, + aggregated_id: str, + ): + endpoint_url = "/decisions/aggregated/{aggregated_id}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + DecisionsDeleteAggregatedDecisionsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.delete( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return None + + def delete_aggregated_decision_item( + self, + aggregated_id: str, + decision_id: str, + ): + endpoint_url = "/decisions/aggregated/{aggregated_id}/items/{decision_id}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + DecisionsDeleteAggregatedDecisionItemPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.delete( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return None \ No newline at end of file diff --git a/crowdsec_service_api/services/fingerprints.py b/crowdsec_service_api/services/fingerprints.py index 1bc0b40..e3c141a 100644 --- a/crowdsec_service_api/services/fingerprints.py +++ b/crowdsec_service_api/services/fingerprints.py @@ -11,13 +11,14 @@ class Fingerprints(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_fingerprint_rules( self, query: Optional[str] = None, sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + detailed: bool = False, page: int = 1, size: int = 50, )-> GetFingerprintRulesResponsePage: diff --git a/crowdsec_service_api/services/hub.py b/crowdsec_service_api/services/hub.py index 3a1546e..1f004e1 100644 --- a/crowdsec_service_api/services/hub.py +++ b/crowdsec_service_api/services/hub.py @@ -11,7 +11,7 @@ class Hub(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index c5b2050..0f02e26 100644 --- a/crowdsec_service_api/services/info.py +++ b/crowdsec_service_api/services/info.py @@ -11,7 +11,7 @@ class Info(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 73f5656..b3f4a9f 100644 --- a/crowdsec_service_api/services/integrations.py +++ b/crowdsec_service_api/services/integrations.py @@ -11,7 +11,7 @@ class Integrations(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_integrations( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 322c7c5..197a104 100644 --- a/crowdsec_service_api/services/metrics.py +++ b/crowdsec_service_api/services/metrics.py @@ -11,7 +11,7 @@ class Metrics(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py index 5d173fc..ec7e9aa 100644 --- a/crowdsec_service_api/services/products.py +++ b/crowdsec_service_api/services/products.py @@ -11,7 +11,7 @@ class Products(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_products( self, diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py index fa41f55..66b5650 100644 --- a/crowdsec_service_api/services/tracker_events.py +++ b/crowdsec_service_api/services/tracker_events.py @@ -11,7 +11,7 @@ class TrackerEvents(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_exploitation_phase_change_events( self, diff --git a/crowdsec_service_api/services/tracker_tags.py b/crowdsec_service_api/services/tracker_tags.py index 270d8f4..5a77252 100644 --- a/crowdsec_service_api/services/tracker_tags.py +++ b/crowdsec_service_api/services/tracker_tags.py @@ -11,7 +11,7 @@ class TrackerTags(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") def get_tags( self, diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py index dab3932..360a270 100644 --- a/crowdsec_service_api/services/vendors.py +++ b/crowdsec_service_api/services/vendors.py @@ -11,7 +11,7 @@ class Vendors(Service): def __init__(self, auth: Auth, base_url: str = "https://admin.api.crowdsec.net/v1") -> None: - super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/1.128.0") + super().__init__(base_url=base_url, auth=auth, user_agent="crowdsec_service_api/v0.16.1") 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..d46af21 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.41", "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-06-25T08:19:41.526068+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..55cf4fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "crowdsec_service_api" -version = "1.128.0" +version = "v0.16.1" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock index 2dd3cda..c512915 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.36" 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/7c/37/da9e7f6ca73ac73afd7f0bb7f238aa5daba35c081e98d7f48a7c399599c0/botocore-1.43.36.tar.gz", hash = "sha256:4cae47d1b2d426316b85a0087d9e69e048f13bc003b5177d74639fe9dfd28205", size = 15625488, upload-time = "2026-06-23T02:47:03.192Z" } 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/5c/19/934f81592527a3f7f9b943c893e334c721a4644948642bc33885d584e9ec/botocore-1.43.36-py3-none-any.whl", hash = "sha256:3c65fdc39ed01d8dfde1e961b34038aed03c459f8ddf80717a12ac006475e49d", size = 15313630, upload-time = "2026-06-23T02:46:59.327Z" }, ] [[package]] name = "certifi" -version = "2026.5.20" +version = "2026.6.17" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/ce/ee2ecad540810a79593028e88299baeae54d346cc7a0d94b6199988b89b1/certifi-2026.5.20.tar.gz", hash = "sha256:69dea482ab64caa7b9f6aba1c6bf48bb6a5448d1c0f1b17ab42ad8c763a5344d", size = 135422, upload-time = "2026-05-20T11:46:50.073Z" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/c7/424b75da314c1045981bd9777432fad05a9e0c69daa4ed7e308bbaffe405/certifi-2026.6.17.tar.gz", hash = "sha256:024c88eeec92ca068db80f02b8b07c9cef7b9fe261d1d535abfd5abd6f6af432", size = 134594, upload-time = "2026-06-17T10:31:07.894Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/59/8c/57e832b7af6d7c5abe66eb3fbe3a3a32f4d11ea23a1aa7131371035be991/certifi-2026.5.20-py3-none-any.whl", hash = "sha256:3c52e209ba0a4ad7aebe60436a4ab349c39e1e602e8c134221e546902ad25897", size = 134134, upload-time = "2026-05-20T11:46:48.578Z" }, + { url = "https://files.pythonhosted.org/packages/ef/2f/c5464532e965badff2f4c4c1a3a83f5697f0d7c407ed0cda44aaa99bb451/certifi-2026.6.17-py3-none-any.whl", hash = "sha256:2227dcbaafe0d2f59279d1762ddddc37783ed4354594f194ffc31d20f41fc3db", size = 133289, upload-time = "2026-06-17T10:31:06.348Z" }, ] [[package]] name = "crowdsec-service-api" -version = "1.128.0" +version = "0.16.1" source = { editable = "." } dependencies = [ { name = "botocore" },