From a6584845547f076bb033c5db8616635ea0170d04 Mon Sep 17 00:00:00 2001 From: AlteredCoder <64792091+AlteredCoder@users.noreply.github.com> Date: Tue, 14 Apr 2026 15:17:58 +0000 Subject: [PATCH] Update python SDK v0.15.25 --- LICENSE | 2 +- README.md | 7 +- crowdsec_service_api/__init__.py | 68 +- .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 4892 bytes .../__pycache__/base_model.cpython-311.pyc | Bin 3668 -> 4370 bytes .../__pycache__/http_client.cpython-311.pyc | Bin 7631 -> 7760 bytes .../__pycache__/models.cpython-311.pyc | Bin 0 -> 147754 bytes crowdsec_service_api/base_model.py | 42 +- crowdsec_service_api/http_client.py | 13 +- crowdsec_service_api/models.py | 1919 ++- .../__pycache__/__init__.cpython-311.pyc | Bin 234 -> 199 bytes .../__pycache__/allowlists.cpython-311.pyc | Bin 0 -> 12910 bytes .../__pycache__/blocklists.cpython-311.pyc | Bin 0 -> 15114 bytes .../services/__pycache__/cves.cpython-311.pyc | Bin 0 -> 11005 bytes .../__pycache__/decisions.cpython-311.pyc | Bin 0 -> 3660 bytes .../__pycache__/fingerprints.cpython-311.pyc | Bin 0 -> 10911 bytes .../services/__pycache__/hub.cpython-311.pyc | Bin 0 -> 3270 bytes .../services/__pycache__/info.cpython-311.pyc | Bin 0 -> 2028 bytes .../__pycache__/integrations.cpython-311.pyc | Bin 0 -> 8068 bytes .../__pycache__/metrics.cpython-311.pyc | Bin 0 -> 2600 bytes .../__pycache__/products.cpython-311.pyc | Bin 0 -> 3775 bytes .../tracker_events.cpython-311.pyc | Bin 0 -> 2907 bytes .../__pycache__/tracker_tags.cpython-311.pyc | Bin 0 -> 5691 bytes .../__pycache__/vendors.cpython-311.pyc | Bin 0 -> 10344 bytes crowdsec_service_api/services/allowlists.py | 8 +- crowdsec_service_api/services/blocklists.py | 8 +- crowdsec_service_api/services/cves.py | 155 +- crowdsec_service_api/services/decisions.py | 63 + crowdsec_service_api/services/fingerprints.py | 230 + crowdsec_service_api/services/hub.py | 2 + crowdsec_service_api/services/info.py | 2 + crowdsec_service_api/services/integrations.py | 17 +- crowdsec_service_api/services/metrics.py | 2 + crowdsec_service_api/services/products.py | 65 + .../services/tracker_events.py | 41 + crowdsec_service_api/services/tracker_tags.py | 115 + crowdsec_service_api/services/vendors.py | 232 + doc/Allowlists.md | 223 +- doc/Blocklists.md | 267 +- doc/Cves.md | 313 +- doc/Decisions.md | 113 + doc/Fingerprints.md | 357 + doc/Hub.md | 76 +- doc/Info.md | 13 +- doc/Integrations.md | 145 +- doc/Metrics.md | 23 +- doc/Models.md | 739 +- doc/Products.md | 89 + doc/README.md | 122 +- doc/TrackerEvents.md | 53 + doc/TrackerTags.md | 173 + doc/Vendors.md | 361 + public-openapi.json | 13547 ++++++++++++++++ pyproject.toml | 2 +- uv.lock | 337 + 55 files changed, 19427 insertions(+), 517 deletions(-) create mode 100644 crowdsec_service_api/__pycache__/__init__.cpython-311.pyc create mode 100644 crowdsec_service_api/__pycache__/models.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/allowlists.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/blocklists.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/decisions.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/info.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/integrations.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/products.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/tracker_tags.cpython-311.pyc create mode 100644 crowdsec_service_api/services/__pycache__/vendors.cpython-311.pyc create mode 100644 crowdsec_service_api/services/decisions.py create mode 100644 crowdsec_service_api/services/fingerprints.py create mode 100644 crowdsec_service_api/services/products.py create mode 100644 crowdsec_service_api/services/tracker_events.py create mode 100644 crowdsec_service_api/services/tracker_tags.py create mode 100644 crowdsec_service_api/services/vendors.py create mode 100644 doc/Decisions.md create mode 100644 doc/Fingerprints.md create mode 100644 doc/Products.md create mode 100644 doc/TrackerEvents.md create mode 100644 doc/TrackerTags.md create mode 100644 doc/Vendors.md create mode 100644 public-openapi.json create mode 100644 uv.lock diff --git a/LICENSE b/LICENSE index f12f6b4..be8e4da 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2025 Crowdsec +Copyright (c) 2026 Crowdsec Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index c71f804..2ea145a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # crowdsec_service_api -**crowdsec_service_api** is a Python SDK for the [CrowdSec Service API](https://docs.crowdsec.net/u/service_api/intro/). +**crowdsec_service_api** is a Python SDK for the [CrowdSec Service API](https://docs.crowdsec.net/u/console/service_api/getting_started). This library enables you to manage CrowdSec resources such as blocklists, integrations in your python applications. ## Installation @@ -11,10 +11,11 @@ pip install crowdsec_service_api ## Usage -You can follow this [documentation](https://docs.crowdsec.net/u/service_api/quickstart/blocklists) to see the basic usage of the SDK. +You can follow this [documentation](https://docs.crowdsec.net/u/console/service_api/sdks/python) to see the basic usage of the SDK. ## Documentation -You can access the full usage documentation [here](https://github.com/crowdsecurity/crowdsec-service-api-sdk-python/tree/main/doc). +You can access [the quickstart guide here](https://docs.crowdsec.net/u/console/service_api/quickstart/authentication). +Or you have the full usage documentation [here](https://github.com/crowdsecurity/crowdsec-service-api-sdk-python/tree/main/doc). ## Contributing diff --git a/crowdsec_service_api/__init__.py b/crowdsec_service_api/__init__.py index af6c9a0..7e7da95 100644 --- a/crowdsec_service_api/__init__.py +++ b/crowdsec_service_api/__init__.py @@ -4,23 +4,35 @@ from .services.allowlists import Allowlists from .services.blocklists import Blocklists from .services.integrations import Integrations +from .services.decisions import Decisions from .services.info import Info from .services.metrics import Metrics from .services.hub import Hub from .services.cves import Cves +from .services.vendors import Vendors +from .services.products import Products +from .services.tracker_tags import TrackerTags +from .services.fingerprints import Fingerprints +from .services.tracker_events import TrackerEvents from .http_client import ApiKeyAuth class Server(Enum): - production_server = 'https://admin.api.crowdsec.net/v1/' + production_server = 'https://admin.api.crowdsec.net/v1' __all__ = [ 'Allowlists', 'Blocklists', 'Integrations', + 'Decisions', 'Info', 'Metrics', 'Hub', 'Cves', + 'Vendors', + 'Products', + 'TrackerTags', + 'Fingerprints', + 'TrackerEvents', 'AllowlistCreateRequest', 'AllowlistCreateResponse', 'AllowlistGetItemsResponse', @@ -61,6 +73,7 @@ class Server(Enum): 'BlocklistUpdateRequest', 'BlocklistUsageStats', 'Body_uploadBlocklistContent', + 'CVESubscription', 'ComputedMetrics', 'ComputedSavedMetrics', 'CtiAs', @@ -69,7 +82,16 @@ class Server(Enum): 'CtiCountry', 'CtiIp', 'CtiScenario', + 'DecisionCreateRequest', + 'DecisionCreateResponse', + 'DecisionResponse', + 'DecisionTargetModel', + 'DecisionTargetType', + 'DecisionsGetResponsePage', + 'DecisionsSortBy', + 'DecisionsSortOrder', 'EntityType', + 'FingerprintSubscription', 'GetRemediationMetricsResponse', 'HTTPValidationError', 'InfoResponse', @@ -97,6 +119,7 @@ class Server(Enum): 'Stats', 'SubscriberEntityType', 'ValidationError', + 'VendorSubscription', 'AppsecConfigIndex', 'AppsecRuleIndex', 'CollectionIndex', @@ -106,21 +129,64 @@ class Server(Enum): 'PostoverflowIndex', 'ScenarioIndex', 'VersionDetail', + 'AdjustmentScore', 'AffectedComponent', + 'AllowlistSubscription', 'AttackDetail', 'Behavior', + 'CVEEventOutput', + 'CVEExploitationPhase', + 'CVEResponseBase', + 'CVEsubscription', + 'CWE', 'Classification', 'Classifications', + 'ExploitationPhase', + 'ExploitationPhaseChangeEventItem', + 'ExploitationPhaseChangeEventsResponsePage', + 'FacetBucket', + 'FingerprintEventOutput', + 'FingerprintRuleResponse', + 'FingerprintRuleSummary', + 'FingerprintTimelineItem', 'GetCVEIPsResponsePage', + 'GetCVEProtectRulesResponse', 'GetCVEResponse', + 'GetCVESubscribedIntegrationsResponsePage', + 'GetCVEsResponsePage', + 'GetCVEsSortBy', + 'GetCVEsSortOrder', + 'GetFingerprintIPsResponsePage', + 'GetFingerprintRulesResponsePage', + 'GetFingerprintSubscribedIntegrationsResponsePage', + 'GetVendorIPsResponsePage', + 'GetVendorSubscribedIntegrationsResponsePage', 'History', 'IPItem', + 'IntegrationResponse', + 'IntervalOptions', + 'IpsDetailsStats', 'Location', + 'LookupImpactCVEItem', + 'LookupImpactFingerprintItem', + 'LookupImpactResponsePage', + 'LookupListItemWithStats', + 'LookupListWithStatsResponsePage', 'MitreTechnique', + 'ProtectRule', + 'ProtectRuleTag', 'Reference', 'ScoreBreakdown', 'Scores', + 'SinceOptions', 'SubscribeCVEIntegrationRequest', + 'SubscribeFingerprintIntegrationRequest', + 'SubscribeVendorIntegrationRequest', + 'ThreatContext', + 'TimelineItem', + 'TopProductItem', + 'VendorSortBy', + 'VendorStatsResponse', 'ApiKeyAuth', 'Server', 'Page' diff --git a/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc b/crowdsec_service_api/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0de17014041a71723e0f4e6c48ce36bd65ea331 GIT binary patch literal 4892 zcma)9%X1?+8E+@f%df<7;$-re2V1)kwn%^@Y*CeXGCMA2c1-M@t?Elxr(3Z_)Q^?a z$%NA$IPf3rg%bxT;6LHyqe}-aoc1;_oc6>gsaxHhWT+IaULXnbq=mR})OP_Zi&%b)Y-$=pbOt7JZ?+EqncAPd2wy{OuY zWGPs-msNX-tOPZ?rrOJ-9yIKRYOj!H(6U>qT_dZ(n!TplbV;Y zYzAGstJ*EH6>Qtvs=Z1c1UvSQYOj&qV9(xD?KasD9@-C8d!0NA9@~#A)|~aZ<#&E> z`5UP6=XuNeJN)aP{bX$Un}4dtO3UNj|8E>S>q+-&J&{@?%LExMKw0+A$%~ zHNlKC**hVTcbWAX{g9(EbvcegiLN|F9%gB$+7B-xATGT`oMKPn^UsrW_*8pWNOqTA zqtK72Y%ULI0vO zmZy=wck57nYaz?7_?A8ASL}Iz4h}yr7KeylA^N)~6V7Ayi=!jg4{&(s#`w^q(Y4Qz zcNijmboH|@4yt0=aY8phjw5Q069BtJwi}M~b>fl~X~+5;AOnY~#s6x(lT3X7o1;k- zpd*@uA)-glbwn?ZVDq2AX68FafVmv`4)ZUMG8WWA*h7vS>Nq&W+;I-$8`_0+Rn>t8 zlf7@u-)#Gr)9R)!bT1ot@He_7+sm?Ak(KlfT9;KrR!v#8WVI@*HCeS~C1ptEKB8+3 zqDK)hdxpMF5aVL&4xPnd7DzlWz~_kfISSYrN}>JtLel!gMiDlXw(p~=@jC{Q+k6@O z1@?CD#Zo@XAS)lNWo8b&C@!97n4B|@;&Vh#Lyq~4$j@^dQvBtT$YIutl8}qNd=tHB zES)No?VWW~G-W?mN%_pVN-}ynp{-p8&gp{_VV5w`I_4bQj-}ozHcniIJ?T`%QC;Kz z$G+bmfF`x_+lJl)nU5oSBQ|qV1YsiNL+)}W@)gQbeqe?_MFeqFSbWPs{m>(ckDg(| z5oKc40Iw(>6#gW*| zZjZ8IbZ?W>6R%}-6Bs%fW#rN^;x8i~5wTt-j&8t%w=)`ph?GrNT3a>9FrxhACZEnE z;T81}6*X-EYN@Tl?NpN5zFIm!K33ObD!Xhm(Rn@^4PLthLyQ7PKcy7J1^4MiWQJ@P zZr8F%9^8Xuc2Ix{hZ8&Z)AgYXn3hk0P&TLH&KZ*Kyzl~tm!N-r(l6nbVxp=2GBcdU ztAv9kJ&S1Ia#0%~8ek^h3!*WACj#8_BP{)TYml51>>1NEBH4WpppH>HbFZ_V*3Zyw z(Tna~+EbUiVnM|OQPVL%svv7CVJv8$*|;456u5d@h3ooFQ!)jJwlO>QyRSi- zu;Nq1T})t8|F;R_fsDmoM3HD8UtGYR$d?Wsg+LdZ_ufOIp>KzDp=IOXEeICsA*MAe zHe~+|1Qrb86Luamh!U!0VHXZo#vQM=W~0)L(Y6(gX<%lOS**))gm= zaDWI7k>YF<926v@ZaVEmii;ghh8Hmh<;ax`m!hRHv*(X=-`J*K@LV%Xt=iEe%fx0% zOoQE8p{qlkjA8{j+-CJr87}dvcKvC2zz6WT4KuV4-QMg|gM7d;OV1%=k`i->M|iE0?@dR~@`4`Z3c+&a~Svzlc(6?7WDg%OvgxvFj#-DD;qM zDUUya7yG3jU5AkR$OynhV~7FHj{nd|R@!Br+-2{mPYhl>>)mlr%(zsQcZW1b6PZ4w zQBE{Up3xdbF`Pwagi3jhG^*-5xs&$f3oR24h16arLv#^ZUmScSst9sgDpOyv2-I3Q2Qp}SHmD*fDt*7wVw z>Ad+@^dHcb2|8m?zn!mCDl=&)!;ht3QnXEvf&_ Up~cI&`rKP9ufJK6e@ZF;0~AL9Y5)KL literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc b/crowdsec_service_api/__pycache__/base_model.cpython-311.pyc index a8dddcd5088736053468b84d5bd42a5ee8fca5c5..9f7b737ea287877c89e5939f420b817c7bf3908b 100644 GIT binary patch literal 4370 zcma)9OKcm*8J>M|`H(1CvLxHGMO$)h)(;hlQPj5T`XR$k;K)X0yTx7>8}3M2nOrin zOUDuzKq(BA1=LoD6gJ=l(4kNj#0R$sP@~AX$dL*Ngcu;b6g}idK|T~Y_5Wx25Gl9K zaQ2(mzq2#{n}6!*i4iEjH~-=OEkejYanLL<7Gles>#Pa-n8L7d2A z;uuufPzd=9p0JqxVl4`5F{*d1?UMlWNWBc@#_dAj<~=*hBX^ey^uEow za>ZMMFR53G!NRwA85qQF20`Ik)}>yM2@e*c-WcqZq4R5y3nixH5L3PfoTQ2)J(s(9 zqQbo9D9_cdd7VZat<4{5IQkUq>BOBxnaoK}Z$iUKWZ)6S_*?6GFX%H)w` z#(`TsJkes!tn+~D?!1?06z-wXM**{EpcirIoL$TYJTgn!Ll;;Pu`=NWk@-y_YS53v zvvU*R57HC3R?u97nGJY8gC{JDtrbUdNlE^r^gB?`l2jsAOP~&c1Ija>lC;7#zgVD* z8x7E(0yg?Nl%Xc13W?24x$EO*~4{vNC>ARpqRt}ZuY+;EVgx#0-?`GcF z=HYr_$v*|~?-f!rMt-aPCbAl-8Y2}W1@-BKz{d}#QtSvcTt$-Q{*J5S)IKCU3IMk}n5rB+y{50}FD5=e{dMxKuaa+lIkA?cs3o}HtX#bXw-wwT3!!m{2g+Szc0p`o$MPWqfLDe5yJ=wQ{5U%Qd&!ld7mwP`A{n zx+-g9b@D&KkhD8eogh9vAGR-ymq)5Ux)~0>KZZ=k`*ir7rsv#2S+>27BZ1G6sR|xJ zd90e6qk^$%JkfH3=nYgipgD#j?$AWsQfT67vE^!UCVG zGVr-g#XAeTbtqokvKoYzwLG%>WMFEom0^5s5MYITlN?$LK3ZA_%{x&|o~Rfn1XE_x zI{N_-uoDO;0l4A^j3sdR2Eqt}P*UU)JJSU8GX9SN+8R-pCGF(8f^s>z88)K-ItaJK z-MDnOLn_EVEIS_qw54(nA^}y~{u=zhgub1E&+nL(UpuS3c2>n%M>CB*yM%E=Go!E) z>)1aMz5_a8aP`$JK$-Z<0BtFN%ZU%HU0J<4A5aJvJX$ZWU6QR1JQNT94!2}I3LBo-N-7(=BXSgAv z4Wuw!wIRFUu_A;b3-}Ct69%b@4~Kv*QWzw1`AJ9Eg^((jl;=`s76xIqWu}cVn^xFm zc$-~8xC#JfnS_SN7a*Z&1pKrb#)!*E)S_%g+Av;(k+H9lE3|?lnw^hU2xfZdcy0gT z_30NTxYf}ZxYf}ZxYf~ESrt(d0_8}^@bf_5;d;>Xi<{no^LO9W>2f$MQj*&4$WI2y zr$%wQvaMf9yJ;7j_DPr@G=&Urf_rQ2v5038r8B&KAn&GHZ)W37V$qi5MT|G1JR^<* zpuAhPmK{sWm!2DegbEg)? z*=6Oz$Gt_cIGLN4f6NAe+yK*v{2OKkqg56!nM4#J>Q?LSr(Tcj(gD2_RhV zZ|ZC-Cqmcl{~e$aTb}-6D|x({JYFYCw0HCFb5nG_**9A2o84CAfnHGKfnEstJ-v`1 zB>Gk_tp2P{qS0&8zYZK-pQs*tqk8P()`6+&fvNJ_wc$h6;S*mEpZaR}6yzDzfr(1r zJ5V<`3@0mztF`1nIS7qv9PX2jc6;eJVV3nEU}hWUMW|5>S<~&BF?|z` z3L~mt0BF1Bx~yn1;ENVp9}vyvv}j&tMDyic(R4#BsSQ5O)(JG5k6tFKlh;N6ze0Ew zJjYCWh$ld{S@+$uLefH4xKUVgY%g##OvS^Z*@k%|8YI_)rGo3tGql1mK#9AexrnrY zYv}bJg$$X-S@eY=S44Io;+cq0f)||$#COJ2n9N>c_uw^jwf=p;x*|zZjU26X)*885 z`G2)WrYhgB*2qw$v)0IXrL)%cxP)ov>v8S;wpe+!dwo=vPJ&|Z0VIZ5Q2gdnjA#i+ yhOd2i>+!7>sjlnN(K^`+<*BE`>-`@e+{U$6ZGwIKrNKJc3)?vN>NN{O75)Q$?8pQF literal 3668 zcmb7GO>7&-6`uX&@?W+bNtT?5Qj|E1EfG%KG<8&=wiNgWE^R<=4lLTmnmdwKS}y6? zl`9D{pcDqm7HX?Q3K?(;=uoH%;)4?eXbwFTIpw$tScF(0r=o}4D9DGxXo0>rOH!h( zpy=%Eo0<1!cjmo$?|bv-WHLse{QEy+)-{!of8d~1BF)bJm(bZHCNTw@l!SsHU|+Pw zl2njNazW-}$yQ2gK`liJk&;%>O3^};^JP0$iWlP0S4`DTl#+#{Ktytxn34O$)Tp#A z5%Mv-VJW0ULZfDMTL3P+O>UZh5rZ${G(}aKKG_nHZ5d|5+nm|OXC`1~a$5umyiLh5 zGc`@J>2GnE6#{LM*%gDiG%E(tONL8-TsEm4#3swmj5RxD6}_w+L@rZ@GOHM9)AY_F zb&535Zd5$0>=k!CSP3i=Dx-K!XS3V^D2|JMIEmgt{u{rlKZd1c#}|4 z5KK}KL1D=h9*NJWESnN+R}K>Gy-k}7fojbLTc+puHi>yAGh`NZf>qzqB*wcfTlV97iG4P)4g)p&fQ%0 z=E_d)&9QUm#?GD3ExmON40^Kzi^jS2U;gwm=^$gD{ z=3G|H-3BA${-`}xS!O9%oD&T??r9)v?Wf-T;>Lw~s;41|C)7Ox-eyq)|Y{B z>u3Xi0W*Ge$izPZ-vuL!Y#_=y1MRS;AS$JHP#Cq_6m@dBHRTcGvcm#Xr5q6!c9kU(wPN@dhrWX{tF{`aT1e%4_Vj7fa=CxC2%e(#H`f}^gI zc^HRft8IxE2isNB8L!jiBO#v^Lp7rg1gDM%0UV5WmIdOX;W8PnY9Qm3l_=L0yD#B{ zAt0b;f5z`WyPiz-w<-uKfuzo7Tc~k2XzMO%&D`y(As0=p9 zcM(lcZVC$JJG_FI>$3IWJtN7 znKA^K#?Lj-ID|st3S=eP^Bd6F?1*oOUGb67nG_+K+uq%bX7H@< z!ME%!Aka@h6U65rqcyQ7D}^52p5)?s5W|N;xT^_R?I?a3rnoNxStH*Jyt1?Ox#D)+?0vyNV6Rh)0R26;$K3C8VJ9(HJCiU(=pA^D?h z;$@3Gk~^aVQ3jrqfo?$Q2cNr_QK$@ie=NY$D2T& zcgqeS9*0)+mmtQka;A>4p|!T&$}UaU9D|7~$6Bu0hG_hW`vnj{-gNi+N`pwz)HlaZ z)w`zmB(XaMSC8%#z(+FGP)VX|{lf1jelzjl)!q0|Ek4vBYIIWg=gFb1k=pPZwc&Sm zPmb44j#sbMdk1R0r@!t!^HuK|xX#qNNBpjvPB==b^WcrCqu=T1J zriSRVm@l~=V=>S$1ac119P!a2{4~PI<2jgT6eNiMt^?!%y&IySObJ`vh?Y~r&Q#bw zz7@7dP&J{Pcwlaw`*5~Fpu01&bLY`%-u+GzZUr}xhYL^w4iqk(WBhozZv5>ColV*wV_Ia3cmRq+4#X8 za-STC5=2R?U9L{PfBpXTHKC!V1Wa&8)9Uzx-mPOF_V01|lf$!yyMz-B@;uo?-jgE) H+;;y3cl|E} diff --git a/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc b/crowdsec_service_api/__pycache__/http_client.cpython-311.pyc index b77e6a73ef594f37441da6126b0d5c49fe1d05ec..6e8e83a4a61a9cdec2a9f81f6b8c7b8c770b0092 100644 GIT binary patch delta 1750 zcmZ`(O>7%Q6rQnnynVOw-zq^2rg(3l@LdSkT{T{9xO{#T#+~!wWk~q@9oA(u$)=VH*ene z=Kajh%x^DkO=({RgFXW70@PZBI-|Bo5MIHKXvul9a<3|8@2q!tpNY14am9PkN zb2pQ?v?O=!nG6~aqeU-MZpb+g^TJ%^N>O6I8&b}T^P-FSK~~WRc!_pxSb#Sb76fB2 z(_pc0A7SfR2sj@bfW`g;xG->m1Gqupg1sEX8Unq>=p0GLF1CH=45NB>xy)CMtWcq> zws)aWG({EL#jzCj=-|N4g(|=5rjcZBD{z&4$$^EWw$-LU4C0J$}7B5 zH3kJ#v^%U@4!#nKOA>4&kjbu(~|O560kZS(iwB+ZyU zZJuVV1#ODbN%LN4k-lbm2Xb^O0}+$57=b}tK){ros?H##i1Vm;17RAV?JjX+hd1wr zpYddnxnTYrJ`%<38`|CpI02>?t$)KCv^fV9Y(!6(w{fk#gZ*Pk)k>`!3{5Wse4{wq zX}ijxb}wz)-#qAQcs3GF!%ONW;>stH2<7Je;aO`wa+>CHV9}?#YP~n0c&Cp;BHjh< z|B8i`YiQXpZ;zZZrw0d2HLh8+u`znKe=NCLF!aT}`t9-#h<4TdVmL}awC)c#XztCv zse2e-<_7Qe_ZH^l95LJv=gC^Y^l(Y6T^P`cQ&7{k@x=D97n@xs9zsJx%@zM-j zXy;u#1`hX~6g&yy3IcAExQc)=d!Npes6)Ufwe}O-*$pzc0f1k}M@FA&4IS?IHTh77 z0Q@-^?Z`OskWl2-Qb$4AOQP|Pic*01v`!EuG~NdZ>z6}yN>7^8V|p4>7dnC$!G68% oJTQm7XMNi{wNhdAWj-wy&4*(@o~cn9?~wlZkF9@l0Bbw_4-Y|m#Q*>R delta 1477 zcmaJ>&ubGw6y8a8^Q*}wX_J~(?csSsP9c4JC*6XxI1d z(MrW>ts-b-HM3~x1C?BUJ~ykIe}$|`=d-gqnB^>kX{MF4ih0dsd3%%Nr%Ybj5w}4C z!_Y*+!Bhxrm_P75A;WyoJJYcfiCqW-{F%2aI*7wCLJ(oM0RF){MRxNozMiEoKs=Uo zDMP4~anLU6(4Ew&%X10{;-WHDW?a;DTgkYn8&r?(o{_2dww&?c`;3G7VC?luc+<#Q z4(-t0)DO8H8h~$otvpphTk_E$eB9Ai^wAJ#{(op;&;qR*6zc?DrOJeqh}L}LmQ^`g zD(Yp6d0{p+&veezvsG5A$+@akV12lo>AYN@sz3*z6P_PsfXC9JlN%k|Rm&|z0dq2c z7Vh4+C}kUqMBvS}mO>?{?nr;z2t>lo0uWdVVIM-0r~L6=xxRM|8naAngx~aU@7G{( zOIq&jzboGhF2^=Q2rNfp5WHWz*FP#fEI%sS-~Ho6u92HHo>E817_X>PWW;{2juMjM zN~k~%+vQM(jE;d>LSa1+*eQfQ1kubPl-z6_i8R7NfSPkwxBlu}?%e7^19pn<>g>~O_FQZ@c+#vIceX{#H8E9{%RB~3n z(3qWQzHYWIi)Nwb<}i2Bj>i^A@=V*#TvRXVmfq?&$*=k&u^jq^oBZm@_xWnioh7yd z4V~$9IuT?|X8^ElGeQ!eCLhLsK7{Yv5E{FVyUK7m8Lk1t-We8TE$7DwatQc;ny(1{ zq;RK1SaB#y?}`NQv`d5+$6lQfgU=IFBDR8RA75W3WQ4!lknhD7*))O&K^#@0-XI^1 a$H*+7jK3M1BP6yWwZ~P#|NMt4PQgE48%urw diff --git a/crowdsec_service_api/__pycache__/models.cpython-311.pyc b/crowdsec_service_api/__pycache__/models.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c9eae82f9e833538dcd50929e081d15f03edae50 GIT binary patch literal 147754 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 z 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 WQB+&>)C~#V-S4*5C$`zRAe(Jc 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 Optional["BaseModelSdk"]: + return (client if client is not None else self._client).next_page(self) + + +class RootModelSdk(RootModel): + def __getattr__(self, item: str) -> Any: + return getattr(self.root, item) T = TypeVar("T") class Page(BaseModelSdk, Generic[T]): - _client: "Service" items: Sequence[T] total: Optional[int] page: Optional[int] @@ -23,28 +35,26 @@ class Page(BaseModelSdk, Generic[T]): pages: Optional[int] = None links: Optional[dict] = None - def __init__(self, _client: "Service", **data): - super().__init__(**data) - self._client = _client - - def next(self, client: "Service" = None) -> "Page[T]": - return (client if client is not None else self._client).next_page(self) - class Service: - def __init__(self, base_url: str, auth: Auth) -> None: - self.http_client = HttpClient(base_url=base_url, auth=auth) + def __init__(self, base_url: str, auth: Auth, user_agent: str = None) -> None: + self.http_client = HttpClient( + base_url=base_url, auth=auth, user_agent=user_agent + ) - def next_page(self, page: Page[T]) -> Page[T]: - if not page.links: + def next_page(self, page: BaseModelSdk) -> Optional[BaseModelSdk]: + if not hasattr(page, "links") or not page.links: raise ValueError( "No links found in the response, this is not a paginated response." ) - if page.links.get("next"): + if page.links.next: # links are relative to host not to full base url. We need to pass a full formatted url here parsed_url = urlparse(self.http_client.base_url) response = self.http_client.get( - f"{parsed_url.scheme}://{parsed_url.netloc}{page.links['next']}", path_params=None, params=None, headers=None + f"{parsed_url.scheme}://{parsed_url.netloc}{page.links.next}", + path_params=None, + params=None, + headers=None, ) return page.__class__(_client=self, **response.json()) return None diff --git a/crowdsec_service_api/http_client.py b/crowdsec_service_api/http_client.py index 7fd53a6..63b3f93 100644 --- a/crowdsec_service_api/http_client.py +++ b/crowdsec_service_api/http_client.py @@ -45,11 +45,20 @@ def auth_flow(self, request): class HttpClient: - def __init__(self, base_url: str, auth: httpx.Auth, aws_region="eu-west-1") -> None: + def __init__( + self, + base_url: str, + auth: httpx.Auth, + user_agent: str = None, + aws_region="eu-west-1", + ) -> None: self.aws_region = aws_region self.base_url = base_url self.auth = auth - self.client = httpx.Client() + headers = {"Accept-Encoding": "gzip"} + if user_agent: + headers["User-Agent"] = user_agent + self.client = httpx.Client(headers=headers) self.timeout = 30 def _replace_path_params(self, url: str, path_params: dict): diff --git a/crowdsec_service_api/models.py b/crowdsec_service_api/models.py index 540e50a..7d19408 100644 --- a/crowdsec_service_api/models.py +++ b/crowdsec_service_api/models.py @@ -1,15 +1,16 @@ # generated by datamodel-codegen: # filename: -# timestamp: 2025-12-02T14:56:05+00:00 +# timestamp: 2026-04-14T15:17:48+00:00 from __future__ import annotations -from enum import StrEnum -from typing import Annotated, Dict, List, Optional, Union +from datetime import datetime +from enum import IntEnum, StrEnum +from typing import Annotated, Dict, List, Literal, Optional, Union -from pydantic import AnyUrl, AwareDatetime, ConfigDict, Field, RootModel +from pydantic import AnyUrl, ConfigDict, Field, RootModel -from .base_model import BaseModelSdk +from .base_model import BaseModelSdk, RootModelSdk class AllowlistCreateRequest(BaseModelSdk): @@ -49,11 +50,11 @@ class AllowlistCreateResponse(BaseModelSdk): Field(description='Description of the allowlist', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist was created', title='Created At'), ] updated_at: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist was updated', title='Updated At'), ] = None from_cti_query: Annotated[ @@ -84,7 +85,7 @@ class AllowlistItemUpdateRequest(BaseModelSdk): Field(description='Description of the allowlist entry', title='Description'), ] = None expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist entry will expire', title='Expiration'), ] = None @@ -102,7 +103,7 @@ class AllowlistItemsCreateRequest(BaseModelSdk): Field(description='Description of the allowlist entry', title='Description'), ] expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist entry will expire', title='Expiration'), ] = None @@ -131,7 +132,7 @@ class AllowlistSubscriptionResponse(BaseModelSdk): ] = None -class Name(RootModel[str]): +class Name(RootModelSdk[str]): root: Annotated[ str, Field( @@ -179,7 +180,7 @@ class BlocklistAddIPsRequest(BaseModelSdk): ) ips: Annotated[List[str], Field(description='List of IPs or networks', title='Ips')] expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Expiration date', examples=['2030-01-01T00:00:00.000Z'], @@ -326,7 +327,7 @@ class BlocklistUsageStats(BaseModelSdk): total_subscribed_organizations: Annotated[ Optional[int], Field(title='Total Subscribed Organizations') ] = 0 - updated_at: Annotated[Optional[AwareDatetime], Field(title='Updated At')] = None + updated_at: Annotated[Optional[datetime], Field(title='Updated At')] = None class BodyUploadBlocklistContent(BaseModelSdk): @@ -335,6 +336,10 @@ class BodyUploadBlocklistContent(BaseModelSdk): ] +class CVESubscription(BaseModelSdk): + id: Annotated[str, Field(description='CVE ID', title='Id')] + + class CtiAs(BaseModelSdk): model_config = ConfigDict( extra='allow', @@ -393,6 +398,28 @@ class CtiScenario(BaseModelSdk): total_ips: Annotated[int, Field(title='Total Ips')] +class DecisionCreateResponse(BaseModelSdk): + uuid: Annotated[ + str, Field(description='UUID of the created decision', title='Uuid') + ] + + +class DecisionTargetType(StrEnum): + ORG = 'org' + TAG = 'tag' + ENTITY = 'entity' + + +class DecisionsSortBy(StrEnum): + CREATED_AT = 'created_at' + EXPIRE_AT = 'expire_at' + + +class DecisionsSortOrder(StrEnum): + ASC = 'asc' + DESC = 'desc' + + class EntityType(StrEnum): ORG = 'org' TAG = 'tag' @@ -403,6 +430,10 @@ class EntityType(StrEnum): LOG_PROCESSOR = 'log_processor' +class FingerprintSubscription(BaseModelSdk): + id: Annotated[str, Field(description='Fingerprint ID', title='Id')] + + class InfoResponse(BaseModelSdk): organization_id: Annotated[ str, Field(description='The organization ID', title='Organization Id') @@ -481,7 +512,7 @@ class RemediationMetricsData(BaseModelSdk): Union[int, float], Field(description='Value of the metric', title='Value') ] timestamp: Annotated[ - AwareDatetime, Field(description='Timestamp of the metric', title='Timestamp') + datetime, Field(description='Timestamp of the metric', title='Timestamp') ] @@ -519,6 +550,10 @@ class ValidationError(BaseModelSdk): type: Annotated[str, Field(title='Error Type')] +class VendorSubscription(BaseModelSdk): + id: Annotated[str, Field(description='Vendor ID', title='Id')] + + class VersionDetail(BaseModelSdk): deprecated: Annotated[ Optional[bool], @@ -537,6 +572,19 @@ class VersionDetail(BaseModelSdk): ] +class AdjustmentScore(BaseModelSdk): + total: Annotated[ + Optional[int], Field(description='Total score adjustment', title='Total') + ] = 0 + recency: Annotated[ + Optional[int], Field(description='Recency score adjustment', title='Recency') + ] = 0 + low_info: Annotated[ + Optional[int], + Field(description='Low information score adjustment', title='Low Info'), + ] = 0 + + class AffectedComponent(BaseModelSdk): vendor: Annotated[ Optional[str], @@ -548,6 +596,10 @@ class AffectedComponent(BaseModelSdk): ] = None +class AllowlistSubscription(BaseModelSdk): + id: Annotated[str, Field(title='Id')] + + class AttackDetail(BaseModelSdk): name: Annotated[str, Field(description='Attack detail name', title='Name')] label: Annotated[str, Field(description='Attack detail label', title='Label')] @@ -568,6 +620,45 @@ class Behavior(BaseModelSdk): ] +class CVEEventOutput(BaseModelSdk): + name: Annotated[str, Field(title='Name')] + date: Annotated[str, Field(title='Date')] + description: Annotated[str, Field(title='Description')] + label: Annotated[str, Field(title='Label')] + sorting_priority: Annotated[int, Field(title='Sorting Priority')] + + +class CVEExploitationPhase(StrEnum): + INSUFFICIENT_DATA = 'insufficient_data' + EARLY_EXPLOITATION = 'early_exploitation' + FRESH_AND_POPULAR = 'fresh_and_popular' + TARGETED_EXPLOITATION = 'targeted_exploitation' + MASS_EXPLOITATION = 'mass_exploitation' + BACKGROUND_NOISE = 'background_noise' + UNPOPULAR = 'unpopular' + WEARING_OUT = 'wearing_out' + UNCLASSIFIED = 'unclassified' + + +class CvssScore(RootModelSdk[float]): + root: Annotated[ + float, + Field(description='CVSS score of the CVE', ge=0.0, le=10.0, title='Cvss Score'), + ] + + +class CVEsubscription(BaseModelSdk): + id: Annotated[str, Field(title='Id')] + + +class CWE(BaseModelSdk): + name: Annotated[str, Field(description='Name of the CWE', title='Name')] + label: Annotated[str, Field(description='Label of the CWE', title='Label')] + description: Annotated[ + str, Field(description='Description of the CWE', title='Description') + ] + + class Classification(BaseModelSdk): name: Annotated[str, Field(description='Classification name', title='Name')] label: Annotated[str, Field(description='Classification label', title='Label')] @@ -587,53 +678,183 @@ class Classifications(BaseModelSdk): ] = 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')] - affected_components: Annotated[ - List[AffectedComponent], - Field(description='List of affected components', title='Affected Components'), +class ExploitationPhase(BaseModelSdk): + name: Annotated[ + str, Field(description='Name of the exploitation phase', title='Name') ] - let_score: Annotated[ - int, Field(description='LET score of the CVE', ge=0, le=10, title='Let Score') + label: Annotated[ + str, Field(description='Label of the exploitation phase', title='Label') ] - first_seen: Annotated[ - AwareDatetime, Field(description='First seen date', title='First Seen') + description: Annotated[ + str, + Field(description='Description of the exploitation phase', title='Description'), ] - last_seen: Annotated[ - AwareDatetime, Field(description='Last seen date', title='Last Seen') + + +class ExploitationPhaseChangeEventItem(BaseModelSdk): + cve_id: Annotated[str, Field(description='CVE identifier', title='Cve Id')] + name: Annotated[str, Field(description='Event type name', title='Name')] + date: Annotated[str, Field(description='Date of the phase change', title='Date')] + label: Annotated[ + str, Field(description='Human-readable event label', title='Label') ] - nb_ips: Annotated[ - int, Field(description='Number of unique IPs affected', ge=0, title='Nb Ips') + description: Annotated[ + str, Field(description='Rendered event description', title='Description') ] - published_date: Annotated[ - AwareDatetime, - Field(description='Published date of the CVE', title='Published Date'), + previous_phase: Annotated[ + str, + Field(description='Previous exploitation phase label', title='Previous Phase'), ] - cvss_score: Annotated[ - float, - Field(description='CVSS score of the CVE', ge=0.0, le=10.0, title='Cvss Score'), + new_phase: Annotated[ + str, Field(description='New exploitation phase label', title='New Phase') ] - references: Annotated[ - List[str], - Field(description='List of references for the CVE', title='References'), + + +class ExploitationPhaseChangeEventsResponsePage(BaseModelSdk): + items: Annotated[List[ExploitationPhaseChangeEventItem], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class FacetBucket(BaseModelSdk): + value: Annotated[str, Field(description='Facet value', title='Value')] + count: Annotated[ + int, Field(description='Number of IPs matching this value', ge=0, title='Count') ] - description: Annotated[ - str, Field(description='Description of the CVE', title='Description') + + +class FingerprintEventOutput(BaseModelSdk): + name: Annotated[str, Field(title='Name')] + date: Annotated[str, Field(title='Date')] + description: Annotated[str, Field(title='Description')] + label: Annotated[str, Field(title='Label')] + + +class FingerprintTimelineItem(BaseModelSdk): + timestamp: Annotated[ + datetime, + Field(description='Timestamp of the timeline event', title='Timestamp'), + ] + count: Annotated[ + int, Field(description='Count of occurrences at the timestamp', title='Count') ] +class GetCVEsSortBy(StrEnum): + RULE_RELEASE_DATE = 'rule_release_date' + TRENDING = 'trending' + NB_IPS = 'nb_ips' + NAME = 'name' + FIRST_SEEN = 'first_seen' + + +class GetCVEsSortOrder(StrEnum): + ASC = 'asc' + DESC = 'desc' + + class History(BaseModelSdk): first_seen: Annotated[ - AwareDatetime, Field(description='First seen timestamp', title='First Seen') + datetime, Field(description='First seen timestamp', title='First Seen') ] last_seen: Annotated[ - AwareDatetime, Field(description='Last seen timestamp', title='Last Seen') + datetime, Field(description='Last seen timestamp', title='Last Seen') ] full_age: Annotated[int, Field(description='Full age in days', title='Full Age')] days_age: Annotated[int, Field(description='Days age', title='Days Age')] +class IntegrationResponse(BaseModelSdk): + tags: Annotated[Optional[List[str]], Field(title='Tags')] = [] + organization_id: Annotated[str, Field(title='Organization Id')] + created_at: Annotated[ + Optional[datetime], + Field(description='Time the integration was created', title='Created At'), + ] = None + entity_type: Annotated[EntityType, Field(description='Type of the integration')] + id: Annotated[ + Optional[str], Field(description='ID of the integration', title='Id') + ] = None + blocklists: Annotated[ + Optional[List[BlocklistSubscription]], Field(title='Blocklists') + ] = [] + allowlists: Annotated[ + Optional[List[AllowlistSubscription]], Field(title='Allowlists') + ] = [] + cves: Annotated[Optional[List[CVEsubscription]], Field(title='Cves')] = None + fingerprints: Annotated[ + Optional[List[FingerprintSubscription]], Field(title='Fingerprints') + ] = None + vendors: Annotated[Optional[List[VendorSubscription]], Field(title='Vendors')] = ( + None + ) + name: Annotated[str, Field(description='Name of the integration', title='Name')] + updated_at: Annotated[ + Optional[datetime], + Field(description='Last time the integration was updated', title='Updated At'), + ] = None + description: Annotated[ + Optional[str], + Field(description='Description of the integration', title='Description'), + ] = None + output_format: Annotated[ + OutputFormat, Field(description='Output format of the integration') + ] + last_pull: Annotated[ + Optional[datetime], + Field( + description='Last time the integration pulled blocklists', title='Last Pull' + ), + ] = None + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False + + +class IntervalOptions(StrEnum): + HOUR = 'hour' + DAY = 'day' + WEEK = 'week' + + +class IpsDetailsStats(BaseModelSdk): + total: Annotated[ + int, Field(description='Total number of matching IPs', ge=0, title='Total') + ] + reputation: Annotated[ + List[FacetBucket], + Field(description='IP count by reputation', title='Reputation'), + ] + country: Annotated[ + List[FacetBucket], + Field(description='IP count by country (top 5)', title='Country'), + ] + as_name: Annotated[ + List[FacetBucket], + Field(description='IP count by AS name (top 5)', title='As Name'), + ] + cves: Annotated[ + List[FacetBucket], Field(description='IP count by CVE (top 5)', title='Cves') + ] + classifications: Annotated[ + List[FacetBucket], + Field( + description='IP count by classification (top 5)', title='Classifications' + ), + ] + + class Location(BaseModelSdk): country: Annotated[ Optional[str], Field(description='Country code', title='Country') @@ -647,6 +868,53 @@ class Location(BaseModelSdk): ] = None +class LookupListItemWithStats(BaseModelSdk): + value: Annotated[str, Field(description='Lookup entry value', title='Value')] + nb_cves: Annotated[ + Optional[int], Field(description='Number of CVEs', ge=0, title='Nb Cves') + ] = 0 + nb_fingerprints: Annotated[ + Optional[int], + Field(description='Number of fingerprint rules', ge=0, title='Nb Fingerprints'), + ] = 0 + nb_ips: Annotated[ + Optional[int], + Field( + description='Total number of unique IPs targeting this entry', + ge=0, + title='Nb Ips', + ), + ] = 0 + nb_ips_cves: Annotated[ + Optional[int], + Field(description='Number of IPs across CVEs', ge=0, title='Nb Ips Cves'), + ] = 0 + nb_ips_fingerprints: Annotated[ + Optional[int], + Field( + description='Number of IPs across fingerprint rules', + ge=0, + title='Nb Ips Fingerprints', + ), + ] = 0 + latest_rule_release: Annotated[ + Optional[datetime], + Field( + description='Most recent rule release date for this entry', + title='Latest Rule Release', + ), + ] = None + + +class LookupListWithStatsResponsePage(BaseModelSdk): + items: Annotated[List[LookupListItemWithStats], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + class MitreTechnique(BaseModelSdk): name: Annotated[str, Field(description='MITRE technique ID', title='Name')] label: Annotated[str, Field(description='MITRE technique label', title='Label')] @@ -655,6 +923,11 @@ class MitreTechnique(BaseModelSdk): ] +class ProtectRuleTag(BaseModelSdk): + tag: Annotated[str, Field(description='Tag identifier', title='Tag')] + label: Annotated[str, Field(description='Human-readable tag label', title='Label')] + + class Reference(BaseModelSdk): name: Annotated[str, Field(description='Reference name', title='Name')] label: Annotated[str, Field(description='Reference label', title='Label')] @@ -680,6 +953,12 @@ class Scores(BaseModelSdk): last_month: Annotated[ScoreBreakdown, Field(description='Last month scores')] +class SinceOptions(IntEnum): + INTEGER_1 = 1 + INTEGER_7 = 7 + INTEGER_30 = 30 + + class SubscribeCVEIntegrationRequest(BaseModelSdk): model_config = ConfigDict( extra='forbid', @@ -689,6 +968,133 @@ class SubscribeCVEIntegrationRequest(BaseModelSdk): ] +class SubscribeFingerprintIntegrationRequest(BaseModelSdk): + model_config = ConfigDict( + extra='forbid', + ) + name: Annotated[ + str, Field(description='Name of the integration to subscribe', title='Name') + ] + + +class SubscribeVendorIntegrationRequest(BaseModelSdk): + model_config = ConfigDict( + extra='forbid', + ) + name: Annotated[ + str, Field(description='Name of the integration to subscribe', title='Name') + ] + + +class ThreatContext(BaseModelSdk): + attacker_countries: Annotated[ + Optional[Dict[str, int]], + Field( + description='Attacker country distribution (country code → count)', + title='Attacker Countries', + ), + ] = None + defender_countries: Annotated[ + Optional[Dict[str, int]], + Field( + description='Defender country distribution (country code → count)', + title='Defender Countries', + ), + ] = None + industry_types: Annotated[ + Optional[Dict[str, int]], + Field( + description='Industry type distribution (type → count)', + title='Industry Types', + ), + ] = None + industry_risk_profiles: Annotated[ + Optional[Dict[str, int]], + Field( + description='Industry risk profile distribution (profile → count)', + title='Industry Risk Profiles', + ), + ] = None + attacker_objectives: Annotated[ + Optional[Dict[str, int]], + Field( + description='Attacker objective distribution (objective → count)', + title='Attacker Objectives', + ), + ] = None + + +class TimelineItem(BaseModelSdk): + timestamp: Annotated[ + datetime, + Field(description='Timestamp of the timeline event', title='Timestamp'), + ] + count: Annotated[ + int, Field(description='Count of occurrences at the timestamp', title='Count') + ] + + +class TopProductItem(BaseModelSdk): + value: Annotated[str, Field(description='Product name', title='Value')] + nb_ips_cves: Annotated[ + Optional[int], + Field(description='Number of IPs across CVEs', ge=0, title='Nb Ips Cves'), + ] = 0 + nb_ips_fingerprints: Annotated[ + Optional[int], + Field( + description='Number of IPs across fingerprint rules', + ge=0, + title='Nb Ips Fingerprints', + ), + ] = 0 + + +class VendorSortBy(StrEnum): + VALUE = 'value' + NB_CVES = 'nb_cves' + NB_IPS = 'nb_ips' + LATEST_RULE_RELEASE = 'latest_rule_release' + + +class VendorStatsResponse(BaseModelSdk): + value: Annotated[str, Field(description='Vendor name', title='Value')] + nb_cves: Annotated[ + Optional[int], Field(description='Number of CVEs', ge=0, title='Nb Cves') + ] = 0 + nb_fingerprints: Annotated[ + Optional[int], + Field(description='Number of fingerprint rules', ge=0, title='Nb Fingerprints'), + ] = 0 + nb_ips: Annotated[ + Optional[int], + Field( + description='Total number of unique IPs targeting this vendor', + ge=0, + title='Nb Ips', + ), + ] = 0 + nb_ips_cves: Annotated[ + Optional[int], + Field(description='Number of IPs across CVEs', ge=0, title='Nb Ips Cves'), + ] = 0 + nb_ips_fingerprints: Annotated[ + Optional[int], + Field( + description='Number of IPs across fingerprint rules', + ge=0, + title='Nb Ips Fingerprints', + ), + ] = 0 + top_products: Annotated[ + Optional[List[TopProductItem]], + Field( + description='Top products for this vendor sorted by total IPs descending', + title='Top Products', + ), + ] = None + + class AllowlistsListAllowlistsQueryParameters(BaseModelSdk): page: Annotated[ Optional[int], Field(description='Page number', ge=1, title='Page') @@ -871,10 +1277,10 @@ class BlocklistsDeleteBlocklistPathParameters(BaseModelSdk): class BlocklistsUploadBlocklistContentQueryParameters(BaseModelSdk): expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Blocklist expiration', - examples='2025-12-02T14:55:58.773978+00:00', + examples=['2026-04-13T08:55:24.249164+00:00'], title='Expiration', ), ] = None @@ -998,8 +1404,18 @@ class IntegrationsUpdateIntegrationPathParameters(BaseModelSdk): integration_id: Annotated[str, Field(title='Integration Id')] -class IntegrationsDeleteIntegrationPathParameters(BaseModelSdk): - integration_id: Annotated[str, Field(title='Integration Id')] +class IntegrationsDeleteIntegrationQueryParameters(BaseModelSdk): + force: Annotated[ + Optional[bool], + Field( + description='Force delete the integration even if it has active subscriptions (it will unsubscribe from all lists)', + title='Force', + ), + ] = False + + +class IntegrationsDeleteIntegrationPathParameters(BaseModelSdk): + integration_id: Annotated[str, Field(title='Integration Id')] class IntegrationsHeadIntegrationContentPathParameters(BaseModelSdk): @@ -1008,7 +1424,7 @@ class IntegrationsHeadIntegrationContentPathParameters(BaseModelSdk): ] -class PageSize(RootModel[int]): +class PageSize(RootModelSdk[int]): root: Annotated[ int, Field( @@ -1030,6 +1446,10 @@ class IntegrationsGetIntegrationContentQueryParameters(BaseModelSdk): title='Page Size', ), ] = None + pull_limit: Annotated[Optional[int], Field(title='Pull Limit')] = None + enable_ip_aggregation: Annotated[ + Optional[bool], Field(title='Enable Ip Aggregation') + ] = False class IntegrationsGetIntegrationContentPathParameters(BaseModelSdk): @@ -1054,16 +1474,59 @@ class IntegrationsGetIntegrationContentStreamPathParameters(BaseModelSdk): ] +class DecisionsGetDecisionsQueryParameters(BaseModelSdk): + instance_ids: Annotated[ + Optional[List[str]], + Field(description='Filter decisions by instance IDs', title='Instance Ids'), + ] = [] + tag_ids: Annotated[ + Optional[List[str]], + Field(description='Filter decisions by tag IDs', title='Tag Ids'), + ] = [] + remediation_types: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by remediation types', + title='Remediation Types', + ), + ] = [] + ips: Annotated[ + Optional[List[str]], + Field( + description='Filter decisions by IPs (only for IP decisions)', title='Ips' + ), + ] = [] + sort_by: Annotated[ + Optional[DecisionsSortBy], + Field( + description='Field to sort by (e.g., created_at, duration)', title='Sort By' + ), + ] = 'created_at' + sort_order: Annotated[ + Optional[DecisionsSortOrder], + Field( + description="Sort order: 'asc' for ascending, 'desc' for descending", + title='Sort Order', + ), + ] = 'desc' + 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 + + class MetricsGetMetricsRemediationQueryParameters(BaseModelSdk): start_date: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Start date of the metrics, default to last day', title='Start Date', ), ] = None end_date: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='End date of the metrics', title='End Date'), ] = None engine_ids: Annotated[ @@ -1114,28 +1577,454 @@ class HubHeadItemContentPathParameters(BaseModelSdk): tenant: Annotated[str, Field(title='Tenant')] +class CvesGetCvesQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], Field(description='Search query for CVEs', title='Query') + ] = None + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + exploitation_phase: Annotated[ + Optional[CVEExploitationPhase], + Field(description='Filter by exploitation phase', title='Exploitation Phase'), + ] = None + 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 + + class CvesGetCvePathParameters(BaseModelSdk): cve_id: Annotated[str, Field(title='Cve Id')] -class Since(RootModel[str]): +class CvesGetCveProtectRulesPathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class CvesDownloadCveIpsPathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class Since(RootModelSdk[str]): root: Annotated[ str, Field( - description='Filter IPs seen since this date, format duration (e.g., 7d, 24h)', + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', pattern='^\\d+[hd]$', title='Since', ), ] -class CvesGetCveIpsQueryParameters(BaseModelSdk): +class CvesGetCveIpsDetailsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + 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 + + +class CvesGetCveIpsDetailsPathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class CvesGetCveIpsDetailsStatsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + + +class CvesGetCveIpsDetailsStatsPathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class CvesSubscribeIntegrationToCvePathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class CvesGetCveSubscribedIntegrationsQueryParameters(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 + + +class CvesGetCveSubscribedIntegrationsPathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class CvesUnsubscribeIntegrationFromCvePathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + integration_name: Annotated[str, Field(title='Integration Name')] + + +class CvesGetCveTimelineQueryParameters(BaseModelSdk): + since_days: Annotated[ + Optional[SinceOptions], + Field( + description='Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days.' + ), + ] = 7 + + +class CvesGetCveTimelinePathParameters(BaseModelSdk): + cve_id: Annotated[str, Field(title='Cve Id')] + + +class VendorsGetVendorsQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], Field(description='Search query for vendors', title='Query') + ] = None + sort_by: Annotated[ + Optional[VendorSortBy], + Field( + description='Sort by: value, nb_cves, nb_ips, latest_rule_release', + title='Sort By', + ), + ] = None + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: asc or desc', title='Sort Order'), + ] = 'desc' + 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 + + +class VendorsGetVendorStatsPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsDownloadVendorIpsPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsGetVendorIpsDetailsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + 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 + + +class VendorsGetVendorIpsDetailsPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsGetVendorIpsDetailsStatsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + + +class VendorsGetVendorIpsDetailsStatsPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsSubscribeIntegrationToVendorPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsGetVendorSubscribedIntegrationsQueryParameters(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 + + +class VendorsGetVendorSubscribedIntegrationsPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class VendorsUnsubscribeIntegrationFromVendorPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + integration_name: Annotated[str, Field(title='Integration Name')] + + +class VendorsGetVendorImpactQueryParameters(BaseModelSdk): + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + 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 + + +class VendorsGetVendorImpactPathParameters(BaseModelSdk): + vendor: Annotated[str, Field(title='Vendor')] + + +class ProductsGetProductsQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], Field(description='Search query for products', title='Query') + ] = None + 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 + + +class ProductsGetProductImpactQueryParameters(BaseModelSdk): + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + 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 + + +class ProductsGetProductImpactPathParameters(BaseModelSdk): + product: Annotated[str, Field(title='Product')] + + +class TrackerTagsGetTagsQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], Field(description='Search query for tags', title='Query') + ] = None + 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 + + +class TrackerTagsGetTagImpactQueryParameters(BaseModelSdk): + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + 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 + + +class TrackerTagsGetTagImpactPathParameters(BaseModelSdk): + tag: Annotated[str, Field(title='Tag')] + + +class TrackerTagsGetTrackerTagsQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], Field(description='Search query for tags', title='Query') + ] = None + 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 + + +class TrackerTagsGetTrackerTagImpactQueryParameters(BaseModelSdk): + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + 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 + + +class TrackerTagsGetTrackerTagImpactPathParameters(BaseModelSdk): + tag: Annotated[str, Field(title='Tag')] + + +class FingerprintsGetFingerprintRulesQueryParameters(BaseModelSdk): + query: Annotated[ + Optional[str], + Field(description='Search query for fingerprint rules', title='Query'), + ] = None + sort_by: Annotated[ + Optional[GetCVEsSortBy], Field(description='Field to sort by', title='Sort By') + ] = 'rule_release_date' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + 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 + + +class FingerprintsDownloadFingerprintIpsPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsGetFingerprintIpsDetailsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + 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 + + +class FingerprintsGetFingerprintIpsDetailsPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsGetFingerprintIpsDetailsStatsQueryParameters(BaseModelSdk): + since: Annotated[ + Optional[Since], + Field( + description='Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d', + title='Since', + ), + ] = '14d' + + +class FingerprintsGetFingerprintIpsDetailsStatsPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsSubscribeIntegrationToFingerprintPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsGetFingerprintSubscribedIntegrationsQueryParameters(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 + + +class FingerprintsGetFingerprintSubscribedIntegrationsPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsUnsubscribeIntegrationFromFingerprintPathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + integration_name: Annotated[str, Field(title='Integration Name')] + + +class FingerprintsGetFingerprintTimelineQueryParameters(BaseModelSdk): + since_days: Annotated[ + Optional[SinceOptions], + Field( + description='Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days.' + ), + ] = 7 + interval: Annotated[ + Optional[IntervalOptions], + Field( + description="Interval for aggregating timeline data. Options: 'hour', 'day', 'week'. Default is adapted based on 'since' parameter.", + title='Interval', + ), + ] = None + + +class FingerprintsGetFingerprintTimelinePathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class FingerprintsGetFingerprintRulePathParameters(BaseModelSdk): + fingerprint: Annotated[str, Field(title='Fingerprint')] + + +class TrackerEventsGetExploitationPhaseChangeEventsQueryParameters(BaseModelSdk): since: Annotated[ - Optional[Since], + Optional[str], Field( - description='Filter IPs seen since this date, format duration (e.g., 7d, 24h)', + description="Duration string (e.g. '30d', '24h') to filter events", title='Since', ), + ] = '30d' + sort_order: Annotated[ + Optional[GetCVEsSortOrder], + Field(description='Sort order: ascending or descending', title='Sort Order'), + ] = 'desc' + cve_id: Annotated[ + Optional[str], + Field(description='Filter by CVE identifier (exact match)', title='Cve Id'), + ] = None + previous_phase: Annotated[ + Optional[CVEExploitationPhase], + Field( + description='Filter by previous exploitation phase name', + title='Previous Phase', + ), + ] = None + new_phase: Annotated[ + Optional[CVEExploitationPhase], + Field(description='Filter by new exploitation phase name', title='New Phase'), ] = None page: Annotated[ Optional[int], Field(description='Page number', ge=1, title='Page') @@ -1145,19 +2034,6 @@ class CvesGetCveIpsQueryParameters(BaseModelSdk): ] = 50 -class CvesGetCveIpsPathParameters(BaseModelSdk): - cve_id: Annotated[str, Field(title='Cve Id')] - - -class CvesSubscribeIntegrationToCvePathParameters(BaseModelSdk): - cve_id: Annotated[str, Field(title='Cve Id')] - - -class CvesUnsubscribeIntegrationFromCvePathParameters(BaseModelSdk): - cve_id: Annotated[str, Field(title='Cve Id')] - integration_name: Annotated[str, Field(title='Integration Name')] - - class AllowlistSubscriberEntity(BaseModelSdk): id: Annotated[str, Field(description='Subscriber entity id', title='Id')] entity_type: SubscriberEntityType @@ -1208,11 +2084,11 @@ class AllowlistUpdateResponse(BaseModelSdk): Field(description='Description of the allowlist', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist was created', title='Created At'), ] updated_at: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist was updated', title='Updated At'), ] = None from_cti_query: Annotated[ @@ -1292,7 +2168,7 @@ class BlocklistContentStats(BaseModelSdk): Optional[List[CtiCountry]], Field(title='Top Attacking Countries') ] = [] top_ips: Annotated[Optional[List[CtiIp]], Field(title='Top Ips')] = [] - updated_at: Annotated[Optional[AwareDatetime], Field(title='Updated At')] = None + updated_at: Annotated[Optional[datetime], Field(title='Updated At')] = None class BlocklistOrigin(BaseModelSdk): @@ -1398,7 +2274,7 @@ class BlocklistStats(BaseModelSdk): Optional[float], Field(title='Change Month Percentage') ] = 0.0 count: Annotated[Optional[int], Field(title='Count')] = 0 - updated_at: Annotated[Optional[AwareDatetime], Field(title='Updated At')] = None + updated_at: Annotated[Optional[datetime], Field(title='Updated At')] = None class BlocklistSubscriberEntity(BaseModelSdk): @@ -1437,6 +2313,15 @@ class BlocklistSubscriptionRequest(BaseModelSdk): ] = None +class DecisionTargetModel(BaseModelSdk): + type: Annotated[ + DecisionTargetType, Field(description='Type of the decision target') + ] + value: Annotated[ + str, Field(description='Value of the decision target', title='Value') + ] + + class HTTPValidationError(BaseModelSdk): detail: Annotated[Optional[List[ValidationError]], Field(title='Detail')] = None @@ -1462,6 +2347,17 @@ class IntegrationCreateRequest(BaseModelSdk): output_format: Annotated[ OutputFormat, Field(description='Output format of the integration') ] + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False class IntegrationCreateResponse(BaseModelSdk): @@ -1481,11 +2377,11 @@ class IntegrationCreateResponse(BaseModelSdk): Field(description='Description of the integration', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the integration was created', title='Created At'), ] updated_at: Annotated[ - AwareDatetime, + datetime, Field(description='Last time the integration was updated', title='Updated At'), ] entity_type: Annotated[ @@ -1495,7 +2391,7 @@ class IntegrationCreateResponse(BaseModelSdk): OutputFormat, Field(description='Output format of the integration') ] last_pull: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Last time the integration pulled blocklists', title='Last Pull' ), @@ -1507,6 +2403,24 @@ class IntegrationCreateResponse(BaseModelSdk): title='Blocklists', ), ] + cves: Annotated[ + List[CVESubscription], + Field(description='CVEs that are subscribed by the integration', title='Cves'), + ] + fingerprints: Annotated[ + List[FingerprintSubscription], + Field( + description='Fingerprints that are subscribed by the integration', + title='Fingerprints', + ), + ] + vendors: Annotated[ + List[VendorSubscription], + Field( + description='Vendors that are subscribed by the integration', + title='Vendors', + ), + ] endpoint: Annotated[ AnyUrl, Field( @@ -1521,6 +2435,17 @@ class IntegrationCreateResponse(BaseModelSdk): Optional[List[str]], Field(description='Tags associated with the integration', title='Tags'), ] = [] + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False credentials: Annotated[ Union[ApiKeyCredentials, BasicAuthCredentials], Field( @@ -1547,11 +2472,11 @@ class IntegrationGetResponse(BaseModelSdk): Field(description='Description of the integration', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the integration was created', title='Created At'), ] updated_at: Annotated[ - AwareDatetime, + datetime, Field(description='Last time the integration was updated', title='Updated At'), ] entity_type: Annotated[ @@ -1561,7 +2486,7 @@ class IntegrationGetResponse(BaseModelSdk): OutputFormat, Field(description='Output format of the integration') ] last_pull: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Last time the integration pulled blocklists', title='Last Pull' ), @@ -1573,6 +2498,24 @@ class IntegrationGetResponse(BaseModelSdk): title='Blocklists', ), ] + cves: Annotated[ + List[CVESubscription], + Field(description='CVEs that are subscribed by the integration', title='Cves'), + ] + fingerprints: Annotated[ + List[FingerprintSubscription], + Field( + description='Fingerprints that are subscribed by the integration', + title='Fingerprints', + ), + ] + vendors: Annotated[ + List[VendorSubscription], + Field( + description='Vendors that are subscribed by the integration', + title='Vendors', + ), + ] endpoint: Annotated[ AnyUrl, Field( @@ -1587,6 +2530,17 @@ class IntegrationGetResponse(BaseModelSdk): Optional[List[str]], Field(description='Tags associated with the integration', title='Tags'), ] = [] + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False class IntegrationGetResponsePage(BaseModelSdk): @@ -1619,6 +2573,17 @@ class IntegrationUpdateRequest(BaseModelSdk): title='Regenerate Credentials', ), ] = None + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False class IntegrationUpdateResponse(BaseModelSdk): @@ -1638,11 +2603,11 @@ class IntegrationUpdateResponse(BaseModelSdk): Field(description='Description of the integration', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the integration was created', title='Created At'), ] updated_at: Annotated[ - AwareDatetime, + datetime, Field(description='Last time the integration was updated', title='Updated At'), ] entity_type: Annotated[ @@ -1652,7 +2617,7 @@ class IntegrationUpdateResponse(BaseModelSdk): OutputFormat, Field(description='Output format of the integration') ] last_pull: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field( description='Last time the integration pulled blocklists', title='Last Pull' ), @@ -1664,6 +2629,24 @@ class IntegrationUpdateResponse(BaseModelSdk): title='Blocklists', ), ] + cves: Annotated[ + List[CVESubscription], + Field(description='CVEs that are subscribed by the integration', title='Cves'), + ] + fingerprints: Annotated[ + List[FingerprintSubscription], + Field( + description='Fingerprints that are subscribed by the integration', + title='Fingerprints', + ), + ] + vendors: Annotated[ + List[VendorSubscription], + Field( + description='Vendors that are subscribed by the integration', + title='Vendors', + ), + ] endpoint: Annotated[ AnyUrl, Field( @@ -1678,6 +2661,17 @@ class IntegrationUpdateResponse(BaseModelSdk): Optional[List[str]], Field(description='Tags associated with the integration', title='Tags'), ] = [] + pull_limit: Annotated[ + Optional[int], + Field(description='Maximum number of items to pull', title='Pull Limit'), + ] = None + enable_ip_aggregation: Annotated[ + Optional[bool], + Field( + description='Whether to enable IP aggregation into ranges', + title='Enable Ip Aggregation', + ), + ] = False credentials: Annotated[ Optional[Union[ApiKeyCredentials, BasicAuthCredentials]], Field(description='Credentials for the integration', title='Credentials'), @@ -1697,10 +2691,10 @@ class OriginMetrics(BaseModelSdk): class PublicBlocklistResponse(BaseModelSdk): id: Annotated[str, Field(description='Blocklist id', title='Id')] created_at: Annotated[ - AwareDatetime, Field(description='Blocklist creation date', title='Created At') + datetime, Field(description='Blocklist creation date', title='Created At') ] updated_at: Annotated[ - AwareDatetime, Field(description='Blocklist update date', title='Updated At') + datetime, Field(description='Blocklist update date', title='Updated At') ] name: Annotated[ str, @@ -2382,22 +3376,391 @@ class ScenarioIndex(BaseModelSdk): versions: Annotated[ Optional[Dict[str, VersionDetail]], Field( - description="A dictionary where each key is a version number (e.g., '0.1', '0.2')", - examples=[ - { - '0.1': { - 'deprecated': False, - 'digest': '3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1', - }, - '0.2': { - 'deprecated': False, - 'digest': 'd1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91', - }, - } - ], - title='Versions', + description="A dictionary where each key is a version number (e.g., '0.1', '0.2')", + examples=[ + { + '0.1': { + 'deprecated': False, + 'digest': '3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1', + }, + '0.2': { + 'deprecated': False, + 'digest': 'd1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91', + }, + } + ], + title='Versions', + ), + ] = None + + +class CVEResponseBase(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')] + affected_components: Annotated[ + List[AffectedComponent], + Field(description='List of affected components', title='Affected Components'), + ] + crowdsec_score: Annotated[ + int, + Field( + description='Live Exploit Tracker score of the CVE', + ge=0, + le=10, + title='Crowdsec Score', + ), + ] + opportunity_score: Annotated[ + Optional[int], + Field( + description="Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + ge=0, + le=5, + title='Opportunity Score', + ), + ] = 0 + momentum_score: Annotated[ + Optional[int], + Field( + description="Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + 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 affected', ge=0, title='Nb Ips') + ] + published_date: Annotated[ + datetime, Field(description='Published date of the CVE', title='Published Date') + ] + cvss_score: Annotated[ + Optional[CvssScore], + Field(description='CVSS score of the CVE', title='Cvss Score'), + ] = None + has_public_exploit: Annotated[ + bool, + Field( + description='Indicates if there is a public exploit for the CVE', + title='Has Public Exploit', + ), + ] + rule_release_date: Annotated[ + Optional[datetime], + Field( + description='Release date of the associated detection rule', + title='Rule Release Date', + ), + ] = None + exploitation_phase: Annotated[ + ExploitationPhase, Field(description='Current exploitation phase of the CVE') + ] + adjustment_score: Annotated[ + Optional[AdjustmentScore], + Field( + description='Score adjustments applied to the CVE score based on various factors' + ), + ] = None + threat_context: Annotated[ + Optional[ThreatContext], + Field( + description='Threat context (attacker/defender countries, industries, objectives)' + ), + ] = None + + +class FingerprintRuleResponse(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 + tags: Annotated[ + Optional[List[str]], + Field(description='Tags associated with the fingerprint rule', title='Tags'), + ] = None + description: Annotated[ + Optional[str], + Field(description='Fingerprint rule description', title='Description'), + ] = None + references: Annotated[ + Optional[List[str]], + Field( + description='Reference links for the fingerprint rule', title='References' + ), + ] = None + crowdsec_analysis: Annotated[ + Optional[str], + Field( + description='CrowdSec analysis for this fingerprint rule', + title='Crowdsec Analysis', + ), + ] = None + events: Annotated[ + Optional[List[FingerprintEventOutput]], + Field( + description='List of events related to the fingerprint rule', title='Events' + ), + ] = 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')] + title: Annotated[str, Field(description='Title of the CVE', 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 of the CVE', + ge=0, + le=10, + title='Crowdsec Score', + ), + ] + opportunity_score: Annotated[ + Optional[int], + Field( + description="Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + ge=0, + le=5, + title='Opportunity Score', + ), + ] = 0 + momentum_score: Annotated[ + Optional[int], + Field( + description="Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + 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 affected', ge=0, title='Nb Ips') + ] + published_date: Annotated[ + datetime, Field(description='Published date of the CVE', title='Published Date') + ] + cvss_score: Annotated[ + Optional[CvssScore], + Field(description='CVSS score of the CVE', title='Cvss Score'), + ] = None + has_public_exploit: Annotated[ + bool, + Field( + description='Indicates if there is a public exploit for the CVE', + title='Has Public Exploit', + ), + ] + rule_release_date: Annotated[ + Optional[datetime], + Field( + description='Release date of the associated detection rule', + title='Rule Release Date', + ), + ] = None + exploitation_phase: Annotated[ + ExploitationPhase, Field(description='Current exploitation phase of the CVE') + ] + adjustment_score: Annotated[ + Optional[AdjustmentScore], + Field( + description='Score adjustments applied to the CVE score based on various factors' + ), + ] = None + threat_context: Annotated[ + Optional[ThreatContext], + Field( + 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[ + List[str], + Field(description='List of references for the CVE', title='References'), + ] + description: Annotated[ + str, Field(description='Description of the CVE', title='Description') + ] + crowdsec_analysis: Annotated[ + Optional[str], + Field(description='CrowdSec analysis of the CVE', title='Crowdsec Analysis'), + ] = None + cwes: Annotated[ + List[CWE], + Field(description='List of CWEs associated with the CVE', title='Cwes'), + ] + events: Annotated[ + Optional[List[CVEEventOutput]], + Field(description='List of events related to the CVE', title='Events'), + ] = None + + +class GetCVESubscribedIntegrationsResponsePage(BaseModelSdk): + items: Annotated[List[IntegrationResponse], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class GetCVEsResponsePage(BaseModelSdk): + items: Annotated[List[CVEResponseBase], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class GetFingerprintRulesResponsePage(BaseModelSdk): + items: Annotated[List[FingerprintRuleSummary], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class GetFingerprintSubscribedIntegrationsResponsePage(BaseModelSdk): + items: Annotated[List[IntegrationResponse], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class GetVendorSubscribedIntegrationsResponsePage(BaseModelSdk): + items: Annotated[List[IntegrationResponse], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links class IPItem(BaseModelSdk): @@ -2475,6 +3838,232 @@ class IPItem(BaseModelSdk): scores: Annotated[Optional[Scores], Field(description='Scoring information')] = None +class LookupImpactCVEItem(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')] + affected_components: Annotated[ + List[AffectedComponent], + Field(description='List of affected components', title='Affected Components'), + ] + crowdsec_score: Annotated[ + int, + Field( + description='Live Exploit Tracker score of the CVE', + ge=0, + le=10, + title='Crowdsec Score', + ), + ] + opportunity_score: Annotated[ + Optional[int], + Field( + description="Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + ge=0, + le=5, + title='Opportunity Score', + ), + ] = 0 + momentum_score: Annotated[ + Optional[int], + Field( + description="Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + 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 affected', ge=0, title='Nb Ips') + ] + published_date: Annotated[ + datetime, Field(description='Published date of the CVE', title='Published Date') + ] + cvss_score: Annotated[ + Optional[CvssScore], + Field(description='CVSS score of the CVE', title='Cvss Score'), + ] = None + has_public_exploit: Annotated[ + bool, + Field( + description='Indicates if there is a public exploit for the CVE', + title='Has Public Exploit', + ), + ] + rule_release_date: Annotated[ + Optional[datetime], + Field( + description='Release date of the associated detection rule', + title='Rule Release Date', + ), + ] = None + exploitation_phase: Annotated[ + ExploitationPhase, Field(description='Current exploitation phase of the CVE') + ] + adjustment_score: Annotated[ + Optional[AdjustmentScore], + Field( + description='Score adjustments applied to the CVE score based on various factors' + ), + ] = None + threat_context: Annotated[ + Optional[ThreatContext], + Field( + 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[ + List[str], + Field(description='List of references for the CVE', title='References'), + ] + description: Annotated[ + str, Field(description='Description of the CVE', title='Description') + ] + crowdsec_analysis: Annotated[ + Optional[str], + Field(description='CrowdSec analysis of the CVE', title='Crowdsec Analysis'), + ] = None + cwes: Annotated[ + List[CWE], + Field(description='List of CWEs associated with the CVE', title='Cwes'), + ] + events: Annotated[ + Optional[List[CVEEventOutput]], + Field(description='List of events related to the CVE', title='Events'), + ] = None + type: Annotated[ + Literal['cve'], Field(description='Resource type', title='Type') + ] = 'cve' + + +class LookupImpactFingerprintItem(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 + tags: Annotated[ + Optional[List[str]], + Field(description='Tags associated with the fingerprint rule', title='Tags'), + ] = None + description: Annotated[ + Optional[str], + Field(description='Fingerprint rule description', title='Description'), + ] = None + references: Annotated[ + Optional[List[str]], + Field( + description='Reference links for the fingerprint rule', title='References' + ), + ] = None + crowdsec_analysis: Annotated[ + Optional[str], + Field( + description='CrowdSec analysis for this fingerprint rule', + title='Crowdsec Analysis', + ), + ] = None + events: Annotated[ + Optional[List[FingerprintEventOutput]], + Field( + description='List of events related to the fingerprint rule', title='Events' + ), + ] = None + type: Annotated[ + Literal['fingerprint'], Field(description='Resource type', title='Type') + ] = 'fingerprint' + + +class Items(RootModelSdk[Union[LookupImpactCVEItem, LookupImpactFingerprintItem]]): + root: Annotated[ + Union[LookupImpactCVEItem, LookupImpactFingerprintItem], + Field(discriminator='type'), + ] + + +class LookupImpactResponsePage(BaseModelSdk): + items: Annotated[List[Items], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class ProtectRule(BaseModelSdk): + link: Annotated[str, Field(description='URL to the rule source', title='Link')] + published_date: Annotated[ + Optional[datetime], + Field(description='Date the rule was published', title='Published Date'), + ] = None + tags: Annotated[ + Optional[List[ProtectRuleTag]], + Field(description='Tags associated with the rule', title='Tags'), + ] = None + name: Annotated[str, Field(description='Rule name', title='Name')] + label: Annotated[str, Field(description='Human-readable rule label', title='Label')] + content: Annotated[ + Optional[str], Field(description='Rule content/definition', title='Content') + ] = None + + class AllowlistGetItemsResponse(BaseModelSdk): id: Annotated[ str, @@ -2505,11 +4094,11 @@ class AllowlistGetItemsResponse(BaseModelSdk): str, Field(description='Value of the allowlist entry', title='Value') ] created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist entry was created', title='Created At'), ] updated_at: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist entry was updated', title='Updated At'), ] = None created_by: Annotated[ @@ -2520,7 +4109,7 @@ class AllowlistGetItemsResponse(BaseModelSdk): Field(description='The source user who updated the allowlist entry'), ] = None expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist entry will expire', title='Expiration'), ] = None @@ -2552,11 +4141,11 @@ class AllowlistGetResponse(BaseModelSdk): Field(description='Description of the allowlist', title='Description'), ] = None created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist was created', title='Created At'), ] updated_at: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist was updated', title='Updated At'), ] = None from_cti_query: Annotated[ @@ -2623,11 +4212,11 @@ class AllowlistItemUpdateResponse(BaseModelSdk): str, Field(description='Value of the allowlist entry', title='Value') ] created_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist entry was created', title='Created At'), ] updated_at: Annotated[ - AwareDatetime, + datetime, Field(description='Time the allowlist entry was updated', title='Updated At'), ] created_by: Annotated[ @@ -2637,7 +4226,7 @@ class AllowlistItemUpdateResponse(BaseModelSdk): SourceInfo, Field(description='The source user who updated the allowlist entry') ] expiration: Annotated[ - Optional[AwareDatetime], + Optional[datetime], Field(description='Time the allowlist entry will expire', title='Expiration'), ] = None @@ -2657,6 +4246,104 @@ class ComputedSavedMetrics(BaseModelSdk): ] = [] +class DecisionCreateRequest(BaseModelSdk): + model_config = ConfigDict( + extra='forbid', + ) + created_at: Annotated[Optional[datetime], Field(title='Created At')] = None + uuid: Annotated[ + Optional[str], Field(description='UUID of the decision', title='Uuid') + ] = None + id: Annotated[ + Optional[int], Field(description='ID of the decision', title='Id') + ] = None + duration: Annotated[ + str, Field(description='Duration of the decision', title='Duration') + ] + origin: Annotated[str, Field(description='Origin of the decision', title='Origin')] + scenario: Annotated[ + str, Field(description='Scenario of the decision', title='Scenario') + ] + 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 + target: Annotated[DecisionTargetModel, Field(description='Target of the decision')] + + +class DecisionResponse(BaseModelSdk): + created_at: Annotated[Optional[datetime], Field(title='Created At')] = None + uuid: Annotated[str, Field(description='UUID of the decision', title='Uuid')] + id: Annotated[int, Field(description='ID of the decision', title='Id')] + duration: Annotated[ + str, Field(description='Duration of the decision', title='Duration') + ] + origin: Annotated[str, Field(description='Origin of the decision', title='Origin')] + scenario: Annotated[ + str, Field(description='Scenario of the decision', title='Scenario') + ] + 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 + target: Annotated[DecisionTargetModel, Field(description='Target of the decision')] + + +class DecisionsGetResponsePage(BaseModelSdk): + items: Annotated[List[DecisionResponse], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + class RawMetrics(BaseModelSdk): dropped: Annotated[ Optional[List[RemediationMetrics]], @@ -2701,6 +4388,34 @@ class GetCVEIPsResponsePage(BaseModelSdk): links: Links +class GetCVEProtectRulesResponse(BaseModelSdk): + protect_rules: Annotated[ + Optional[List[ProtectRule]], + Field( + description='Protection/detection rules associated with the CVE', + title='Protect Rules', + ), + ] = None + + +class GetFingerprintIPsResponsePage(BaseModelSdk): + items: Annotated[List[IPItem], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + +class GetVendorIPsResponsePage(BaseModelSdk): + items: Annotated[List[IPItem], 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')] + pages: Annotated[int, Field(ge=0, title='Pages')] + links: Links + + class ComputedMetrics(BaseModelSdk): saved: Annotated[ComputedSavedMetrics, Field(description='estimated saved metrics')] dropped: Annotated[ diff --git a/crowdsec_service_api/services/__pycache__/__init__.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/__init__.cpython-311.pyc index b5d7b60be07f1040cec34eb698fd82b045985a04..a8fd9316b1564a5f04a6b70e24001e6257ee3a37 100644 GIT binary patch delta 78 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 H)*t@^3tdTa literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/cves.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..385adb48bd416a791d4e26eb80118db9034e2d19 GIT binary patch literal 11005 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 F{tJXShWP*h literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/fingerprints.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..4bc6988a7c135961f4ee58ca8dc29890c4c1a53d GIT binary patch literal 10911 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 literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/hub.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..00766b0ab7d9c233e3e4b4ceb5407fd320356d3d GIT binary patch literal 3270 zcmb_e-;WbT9G~s}=x)2cAGE-6iku4ERiqUJO$Zo062J#f49ClwxY_GYX>oU3XSZ;7 zTq6%8)`S=}C_eab4+f9GgOC0RKACzUUNgxV5`FQl1WXK1e!sij+KYF=M5oiw%y;HH zGvE3Cn*BDDNf9Vt8^2WdCJFf!iMYtU&ciREbCcM_793(=n{Wg-VI&0Xi;n0@hUChI z>?(!=W0Ea9$ysa_M|Cwrb5lkts+<&WJl|jE3t|&Neq| zWCfBSr-_}uMr@s?Zi$54fqzttoGqLq`ONP~&g2EI&eS|QyHKZjk*jalgKEvQ94?>t zpu@E{Jg*j50kwZm06(w`FXR(kI%{2^Jb8|?OVtvE0d3my>033M!pc)s>e#@kg`GFO zat#RSjYd#`HgzTl>L;Bl^@36)P=s2Kc=#T4J_4;#VhA=d684atprS2O3H4J}TBI!4 z%C(FkYs4P5RT$UcpQ4H_(PUYLTg!$D_m<+hvSMehNru)U^Ma9ryN_`3Ok?ixvlS4< zKUOSSwp;ZIR=rv%vD#(Zr=@~NgW{z_T(UrFuFk>b%m#C~!f4Q7-b|^lPLLMOjr7B_ z0AC0^$XdMgQsL0i z!r`NNk>y}7mIdIc2C$f594`Q?$bO?v8COlS>Qw{N%u8JIsZ$Pl!&O`}&5~pJzG?ar zY%nn~arN=}Vx{KNB5QaaWkvIHjlExFm*_z}HE!Vq%Fr)N-+sTisenCU{bHptSEw(r zU9kV64w^5-@?>Dd&jb85x zj}HgLS+B6CaaMy9AV@*z#SBJBpB#Z%{~o|q($&e>w9wMmhjJfRu2))OXIrk7Tp!(j zV|-oT-_{R8UCBo6ntozcKhfF!Y*!?i*B+2WX6O;Z15w(RdPD$P${#7R^Qjvb*Y$mE z{Y9uNV$`nb$5-{^y|pJctlf!gccxltkR>;EFZ=vjc5*d4*%^6y<-qslA1=UYxhYtY z13rM3`iDwJwzr2Tp?*4lv-x@Rvkz~47}0HYlI;%fUJa-VmJTYLNA8cn^zR}UqIavv z8u0)BC9>i-o-Frc48-i0ts^T;>Q9W2D}9|bXW4VGE!&HLxiX(*FJS)w!ixZWPtT1( zjVGfNxY3ze0a;%{I0O*8@T)lRw;#WZ_k8iB@ZX%V3(lBp1)FihsAF%KphSQneV_Kq) z1Fx;Xo`O*yAA#4yFlU%mL(p;JX8?Hl;$Jr*$R(jm5Wkv@+Ld!r+kV%KI#0kM^33yH zZA_l(5`g<7*{+O)LPm4lB=%H@`G_G!w4rV~W)1lxIFgfd_p>{?GPJ#w*i&&24SVE? z5UM!5XnuR>s9X-<3)5%#w8E>sP_KFyn1tHEKw=m}TnW>&&r{*&R!A`XEM%B4xmsVa z;i<2d7(S8=708F}bceL-w~fs~xhhy;=R|cqiU!V9&j6vY~dR U!va|4pU|3ofTNE#nF_V=7lYUr&j0`b literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/info.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/info.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..c865bd7a41976fe6a685fcacc891e877a6a180bb GIT binary patch literal 2028 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 QFJ8LK-rQf~JzJ0e0_Mn1^#A|> literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/metrics.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..fb5e9970054fa5df45248339c88c779764d66cf3 GIT binary patch literal 2600 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 literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc b/crowdsec_service_api/services/__pycache__/tracker_events.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..66602330c22c06acf01640e07ecd8cef1b620956 GIT binary patch literal 2907 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 HM0e&t7ROCP literal 0 HcmV?d00001 diff --git a/crowdsec_service_api/services/allowlists.py b/crowdsec_service_api/services/allowlists.py index 2269f08..b0df36d 100644 --- a/crowdsec_service_api/services/allowlists.py +++ b/crowdsec_service_api/services/allowlists.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def list_allowlists( self, @@ -30,7 +32,7 @@ def list_allowlists( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return AllowlistGetResponsePage(**response.json()) + return AllowlistGetResponsePage(_client=self, **response.json()) def create_allowlist( self, @@ -147,7 +149,7 @@ def get_allowlist_items( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return AllowlistGetItemsResponsePage(**response.json()) + return AllowlistGetItemsResponsePage(_client=self, **response.json()) def create_allowlist_items( self, @@ -267,7 +269,7 @@ def get_allowlist_subscribers( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return AllowlistSubscriberEntityPage(**response.json()) + return AllowlistSubscriberEntityPage(_client=self, **response.json()) def subscribe_allowlist( self, diff --git a/crowdsec_service_api/services/blocklists.py b/crowdsec_service_api/services/blocklists.py index 909b3fe..7ddced9 100644 --- a/crowdsec_service_api/services/blocklists.py +++ b/crowdsec_service_api/services/blocklists.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def get_blocklists( self, @@ -35,7 +37,7 @@ def get_blocklists( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return PublicBlocklistResponsePage(**response.json()) + return PublicBlocklistResponsePage(_client=self, **response.json()) def create_blocklist( self, @@ -83,7 +85,7 @@ def search_blocklist( url=endpoint_url, path_params=path_params, params=params, headers=headers, json=payload ) - return PublicBlocklistResponsePage(**response.json()) + return PublicBlocklistResponsePage(_client=self, **response.json()) def get_blocklist( self, @@ -283,7 +285,7 @@ def get_blocklist_subscribers( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return BlocklistSubscriberEntityPage(**response.json()) + return BlocklistSubscriberEntityPage(_client=self, **response.json()) def subscribe_blocklist( self, diff --git a/crowdsec_service_api/services/cves.py b/crowdsec_service_api/services/cves.py index ee65b0f..3695b97 100644 --- a/crowdsec_service_api/services/cves.py +++ b/crowdsec_service_api/services/cves.py @@ -10,6 +10,33 @@ from ..http_client import HttpClient 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/v0.15.25") + + def get_cves( + self, + query: Optional[str] = None, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + exploitation_phase: Optional[CVEExploitationPhase] = None, + page: int = 1, + size: int = 50, + )-> GetCVEsResponsePage: + endpoint_url = "/cves" + loc = locals() + headers = {} + params = json.loads( + CvesGetCvesQueryParameters(**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 GetCVEsResponsePage(_client=self, **response.json()) def get_cve( self, @@ -31,23 +58,88 @@ def get_cve( return GetCVEResponse(**response.json()) - def get_cve_ips( + def get_cve_protect_rules( self, cve_id: str, - since: Optional[str] = None, + )-> GetCVEProtectRulesResponse: + endpoint_url = "/cves/{cve_id}/protect-rules" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + CvesGetCveProtectRulesPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetCVEProtectRulesResponse(**response.json()) + + def download_cve_ips( + self, + cve_id: str, + )-> str: + endpoint_url = "/cves/{cve_id}/ips-download" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + CvesDownloadCveIpsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return response.text + + def get_cve_ips_details( + self, + cve_id: str, + since: Optional[str] = "14d", page: int = 1, size: int = 50, )-> GetCVEIPsResponsePage: - endpoint_url = "/cves/{cve_id}/ips" + endpoint_url = "/cves/{cve_id}/ips-details" + loc = locals() + headers = {} + params = json.loads( + CvesGetCveIpsDetailsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + CvesGetCveIpsDetailsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetCVEIPsResponsePage(_client=self, **response.json()) + + def get_cve_ips_details_stats( + self, + cve_id: str, + since: Optional[str] = "14d", + )-> IpsDetailsStats: + endpoint_url = "/cves/{cve_id}/ips-details-stats" loc = locals() headers = {} params = json.loads( - CvesGetCveIpsQueryParameters(**loc).model_dump_json( + CvesGetCveIpsDetailsStatsQueryParameters(**loc).model_dump_json( exclude_none=True ) ) path_params = json.loads( - CvesGetCveIpsPathParameters(**loc).model_dump_json( + CvesGetCveIpsDetailsStatsPathParameters(**loc).model_dump_json( exclude_none=True ) ) @@ -56,7 +148,33 @@ def get_cve_ips( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return GetCVEIPsResponsePage(**response.json()) + return IpsDetailsStats(**response.json()) + + def get_cve_subscribed_integrations( + self, + cve_id: str, + page: int = 1, + size: int = 50, + )-> GetCVESubscribedIntegrationsResponsePage: + endpoint_url = "/cves/{cve_id}/integrations" + loc = locals() + headers = {} + params = json.loads( + CvesGetCveSubscribedIntegrationsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + CvesGetCveSubscribedIntegrationsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetCVESubscribedIntegrationsResponsePage(_client=self, **response.json()) def subscribe_integration_to_cve( self, @@ -104,4 +222,29 @@ def unsubscribe_integration_from_cve( ) return None + + def get_cve_timeline( + self, + cve_id: str, + since_days: SinceOptions, + )-> list[TimelineItem]: + endpoint_url = "/cves/{cve_id}/timeline" + loc = locals() + headers = {} + params = json.loads( + CvesGetCveTimelineQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + CvesGetCveTimelinePathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return [TimelineItem(**item) for item in response.json()] \ No newline at end of file diff --git a/crowdsec_service_api/services/decisions.py b/crowdsec_service_api/services/decisions.py new file mode 100644 index 0000000..8306e45 --- /dev/null +++ b/crowdsec_service_api/services/decisions.py @@ -0,0 +1,63 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_decisions( + self, + instance_ids: list[str] = [], + tag_ids: list[str] = [], + remediation_types: list[str] = [], + ips: list[str] = [], + 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() + headers = {} + params = json.loads( + DecisionsGetDecisionsQueryParameters(**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 DecisionsGetResponsePage(_client=self, **response.json()) + + def create_decision( + self, + request: DecisionCreateRequest, + )-> DecisionCreateResponse: + endpoint_url = "/decisions" + loc = locals() + headers = {} + params = {} + path_params = {} + + payload = json.loads( + request.model_dump_json( + exclude_none=True + ) + ) if "request" in loc else None + response = self.http_client.post( + url=endpoint_url, path_params=path_params, params=params, headers=headers, json=payload + ) + + return DecisionCreateResponse(**response.json()) + \ No newline at end of file diff --git a/crowdsec_service_api/services/fingerprints.py b/crowdsec_service_api/services/fingerprints.py new file mode 100644 index 0000000..3e0743b --- /dev/null +++ b/crowdsec_service_api/services/fingerprints.py @@ -0,0 +1,230 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_fingerprint_rules( + self, + query: Optional[str] = None, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> GetFingerprintRulesResponsePage: + endpoint_url = "/fingerprints" + loc = locals() + headers = {} + params = json.loads( + FingerprintsGetFingerprintRulesQueryParameters(**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 GetFingerprintRulesResponsePage(_client=self, **response.json()) + + def download_fingerprint_ips( + self, + fingerprint: str, + )-> str: + endpoint_url = "/fingerprints/{fingerprint}/ips-download" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + FingerprintsDownloadFingerprintIpsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return response.text + + def get_fingerprint_ips_details( + self, + fingerprint: str, + since: Optional[str] = "14d", + page: int = 1, + size: int = 50, + )-> GetFingerprintIPsResponsePage: + endpoint_url = "/fingerprints/{fingerprint}/ips-details" + loc = locals() + headers = {} + params = json.loads( + FingerprintsGetFingerprintIpsDetailsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + FingerprintsGetFingerprintIpsDetailsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetFingerprintIPsResponsePage(_client=self, **response.json()) + + def get_fingerprint_ips_details_stats( + self, + fingerprint: str, + since: Optional[str] = "14d", + )-> IpsDetailsStats: + endpoint_url = "/fingerprints/{fingerprint}/ips-details-stats" + loc = locals() + headers = {} + params = json.loads( + FingerprintsGetFingerprintIpsDetailsStatsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + FingerprintsGetFingerprintIpsDetailsStatsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return IpsDetailsStats(**response.json()) + + def get_fingerprint_subscribed_integrations( + self, + fingerprint: str, + page: int = 1, + size: int = 50, + )-> GetFingerprintSubscribedIntegrationsResponsePage: + endpoint_url = "/fingerprints/{fingerprint}/integrations" + loc = locals() + headers = {} + params = json.loads( + FingerprintsGetFingerprintSubscribedIntegrationsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + FingerprintsGetFingerprintSubscribedIntegrationsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetFingerprintSubscribedIntegrationsResponsePage(_client=self, **response.json()) + + def subscribe_integration_to_fingerprint( + self, + request: SubscribeFingerprintIntegrationRequest, + fingerprint: str, + ): + endpoint_url = "/fingerprints/{fingerprint}/integrations" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + FingerprintsSubscribeIntegrationToFingerprintPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + payload = json.loads( + request.model_dump_json( + exclude_none=True + ) + ) if "request" in loc else None + response = self.http_client.post( + url=endpoint_url, path_params=path_params, params=params, headers=headers, json=payload + ) + + return None + + def unsubscribe_integration_from_fingerprint( + self, + fingerprint: str, + integration_name: str, + ): + endpoint_url = "/fingerprints/{fingerprint}/integrations/{integration_name}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + FingerprintsUnsubscribeIntegrationFromFingerprintPathParameters(**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 get_fingerprint_timeline( + self, + fingerprint: str, + since_days: SinceOptions, + interval: Optional[IntervalOptions] = None, + )-> list[FingerprintTimelineItem]: + endpoint_url = "/fingerprints/{fingerprint}/timeline" + loc = locals() + headers = {} + params = json.loads( + FingerprintsGetFingerprintTimelineQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + FingerprintsGetFingerprintTimelinePathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return [FingerprintTimelineItem(**item) for item in response.json()] + + def get_fingerprint_rule( + self, + fingerprint: str, + )-> FingerprintRuleResponse: + endpoint_url = "/fingerprints/{fingerprint}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + FingerprintsGetFingerprintRulePathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return FingerprintRuleResponse(**response.json()) + \ No newline at end of file diff --git a/crowdsec_service_api/services/hub.py b/crowdsec_service_api/services/hub.py index 1705da2..dbf062b 100644 --- a/crowdsec_service_api/services/hub.py +++ b/crowdsec_service_api/services/hub.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def get_index( self, diff --git a/crowdsec_service_api/services/info.py b/crowdsec_service_api/services/info.py index bac69b8..c6b9cd7 100644 --- a/crowdsec_service_api/services/info.py +++ b/crowdsec_service_api/services/info.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def get_info( self, diff --git a/crowdsec_service_api/services/integrations.py b/crowdsec_service_api/services/integrations.py index 4583420..9efef4c 100644 --- a/crowdsec_service_api/services/integrations.py +++ b/crowdsec_service_api/services/integrations.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def get_integrations( self, @@ -31,7 +33,7 @@ def get_integrations( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return IntegrationGetResponsePage(**response.json()) + return IntegrationGetResponsePage(_client=self, **response.json()) def create_integration( self, @@ -77,11 +79,16 @@ def get_integration( def delete_integration( self, integration_id: str, + force: bool = False, ): endpoint_url = "/integrations/{integration_id}" loc = locals() headers = {} - params = {} + params = json.loads( + IntegrationsDeleteIntegrationQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) path_params = json.loads( IntegrationsDeleteIntegrationPathParameters(**loc).model_dump_json( exclude_none=True @@ -124,7 +131,9 @@ def get_integration_content( integration_id: str, page: int = 1, page_size: Optional[int] = None, - ): + pull_limit: Optional[int] = None, + enable_ip_aggregation: bool = False, + )-> str: endpoint_url = "/integrations/{integration_id}/content" loc = locals() headers = {} @@ -143,7 +152,7 @@ def get_integration_content( url=endpoint_url, path_params=path_params, params=params, headers=headers ) - return None + return response.text def get_integration_content_stream( self, diff --git a/crowdsec_service_api/services/metrics.py b/crowdsec_service_api/services/metrics.py index 8f5d97f..c0362b9 100644 --- a/crowdsec_service_api/services/metrics.py +++ b/crowdsec_service_api/services/metrics.py @@ -10,6 +10,8 @@ from ..http_client import HttpClient 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/v0.15.25") def get_metrics_remediation( self, diff --git a/crowdsec_service_api/services/products.py b/crowdsec_service_api/services/products.py new file mode 100644 index 0000000..c9d1724 --- /dev/null +++ b/crowdsec_service_api/services/products.py @@ -0,0 +1,65 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_products( + self, + query: Optional[str] = None, + page: int = 1, + size: int = 50, + )-> LookupListWithStatsResponsePage: + endpoint_url = "/products" + loc = locals() + headers = {} + params = json.loads( + ProductsGetProductsQueryParameters(**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 LookupListWithStatsResponsePage(_client=self, **response.json()) + + def get_product_impact( + self, + product: str, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> LookupImpactResponsePage: + endpoint_url = "/products/{product}" + loc = locals() + headers = {} + params = json.loads( + ProductsGetProductImpactQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + ProductsGetProductImpactPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return LookupImpactResponsePage(_client=self, **response.json()) + \ No newline at end of file diff --git a/crowdsec_service_api/services/tracker_events.py b/crowdsec_service_api/services/tracker_events.py new file mode 100644 index 0000000..02b131f --- /dev/null +++ b/crowdsec_service_api/services/tracker_events.py @@ -0,0 +1,41 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_exploitation_phase_change_events( + self, + since: str = "30d", + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + cve_id: Optional[str] = None, + previous_phase: Optional[CVEExploitationPhase] = None, + new_phase: Optional[CVEExploitationPhase] = None, + page: int = 1, + size: int = 50, + )-> ExploitationPhaseChangeEventsResponsePage: + endpoint_url = "/tracker-events/exploitation-phase-change" + loc = locals() + headers = {} + params = json.loads( + TrackerEventsGetExploitationPhaseChangeEventsQueryParameters(**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 ExploitationPhaseChangeEventsResponsePage(_client=self, **response.json()) + \ No newline at end of file diff --git a/crowdsec_service_api/services/tracker_tags.py b/crowdsec_service_api/services/tracker_tags.py new file mode 100644 index 0000000..09609c1 --- /dev/null +++ b/crowdsec_service_api/services/tracker_tags.py @@ -0,0 +1,115 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_tags( + self, + query: Optional[str] = None, + page: int = 1, + size: int = 50, + )-> LookupListWithStatsResponsePage: + endpoint_url = "/tags" + loc = locals() + headers = {} + params = json.loads( + TrackerTagsGetTagsQueryParameters(**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 LookupListWithStatsResponsePage(_client=self, **response.json()) + + def get_tag_impact( + self, + tag: str, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> LookupImpactResponsePage: + endpoint_url = "/tags/{tag}" + loc = locals() + headers = {} + params = json.loads( + TrackerTagsGetTagImpactQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + TrackerTagsGetTagImpactPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return LookupImpactResponsePage(_client=self, **response.json()) + + def get_tracker_tags( + self, + query: Optional[str] = None, + page: int = 1, + size: int = 50, + )-> LookupListWithStatsResponsePage: + endpoint_url = "/tracker-tags" + loc = locals() + headers = {} + params = json.loads( + TrackerTagsGetTrackerTagsQueryParameters(**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 LookupListWithStatsResponsePage(_client=self, **response.json()) + + def get_tracker_tag_impact( + self, + tag: str, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> LookupImpactResponsePage: + endpoint_url = "/tracker-tags/{tag}" + loc = locals() + headers = {} + params = json.loads( + TrackerTagsGetTrackerTagImpactQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + TrackerTagsGetTrackerTagImpactPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return LookupImpactResponsePage(_client=self, **response.json()) + \ No newline at end of file diff --git a/crowdsec_service_api/services/vendors.py b/crowdsec_service_api/services/vendors.py new file mode 100644 index 0000000..2770575 --- /dev/null +++ b/crowdsec_service_api/services/vendors.py @@ -0,0 +1,232 @@ +import json +from types import NoneType +from typing import Optional, Union, Annotated + +from ..models import * +from ..base_model import Page, Service +from pydantic import BaseModel, Field +from pydantic.fields import FieldInfo +from httpx import Auth +from ..http_client import HttpClient + +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/v0.15.25") + + def get_vendors( + self, + query: Optional[str] = None, + sort_by: Optional[VendorSortBy] = None, + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> LookupListWithStatsResponsePage: + endpoint_url = "/vendors" + loc = locals() + headers = {} + params = json.loads( + VendorsGetVendorsQueryParameters(**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 LookupListWithStatsResponsePage(_client=self, **response.json()) + + def get_vendor_stats( + self, + vendor: str, + )-> VendorStatsResponse: + endpoint_url = "/vendors/{vendor}/stats" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + VendorsGetVendorStatsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return VendorStatsResponse(**response.json()) + + def download_vendor_ips( + self, + vendor: str, + )-> str: + endpoint_url = "/vendors/{vendor}/ips-download" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + VendorsDownloadVendorIpsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return response.text + + def get_vendor_ips_details( + self, + vendor: str, + since: Optional[str] = "14d", + page: int = 1, + size: int = 50, + )-> GetVendorIPsResponsePage: + endpoint_url = "/vendors/{vendor}/ips-details" + loc = locals() + headers = {} + params = json.loads( + VendorsGetVendorIpsDetailsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + VendorsGetVendorIpsDetailsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetVendorIPsResponsePage(_client=self, **response.json()) + + def get_vendor_ips_details_stats( + self, + vendor: str, + since: Optional[str] = "14d", + )-> IpsDetailsStats: + endpoint_url = "/vendors/{vendor}/ips-details-stats" + loc = locals() + headers = {} + params = json.loads( + VendorsGetVendorIpsDetailsStatsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + VendorsGetVendorIpsDetailsStatsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return IpsDetailsStats(**response.json()) + + def get_vendor_subscribed_integrations( + self, + vendor: str, + page: int = 1, + size: int = 50, + )-> GetVendorSubscribedIntegrationsResponsePage: + endpoint_url = "/vendors/{vendor}/integrations" + loc = locals() + headers = {} + params = json.loads( + VendorsGetVendorSubscribedIntegrationsQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + VendorsGetVendorSubscribedIntegrationsPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return GetVendorSubscribedIntegrationsResponsePage(_client=self, **response.json()) + + def subscribe_integration_to_vendor( + self, + request: SubscribeVendorIntegrationRequest, + vendor: str, + ): + endpoint_url = "/vendors/{vendor}/integrations" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + VendorsSubscribeIntegrationToVendorPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + payload = json.loads( + request.model_dump_json( + exclude_none=True + ) + ) if "request" in loc else None + response = self.http_client.post( + url=endpoint_url, path_params=path_params, params=params, headers=headers, json=payload + ) + + return None + + def unsubscribe_integration_from_vendor( + self, + vendor: str, + integration_name: str, + ): + endpoint_url = "/vendors/{vendor}/integrations/{integration_name}" + loc = locals() + headers = {} + params = {} + path_params = json.loads( + VendorsUnsubscribeIntegrationFromVendorPathParameters(**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 get_vendor_impact( + self, + vendor: str, + sort_by: Optional[GetCVEsSortBy] = GetCVEsSortBy("rule_release_date"), + sort_order: Optional[GetCVEsSortOrder] = GetCVEsSortOrder("desc"), + page: int = 1, + size: int = 50, + )-> LookupImpactResponsePage: + endpoint_url = "/vendors/{vendor}" + loc = locals() + headers = {} + params = json.loads( + VendorsGetVendorImpactQueryParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + path_params = json.loads( + VendorsGetVendorImpactPathParameters(**loc).model_dump_json( + exclude_none=True + ) + ) + + response = self.http_client.get( + url=endpoint_url, path_params=path_params, params=params, headers=headers + ) + + return LookupImpactResponsePage(_client=self, **response.json()) + \ No newline at end of file diff --git a/doc/Allowlists.md b/doc/Allowlists.md index 90cccd2..b215c8b 100644 --- a/doc/Allowlists.md +++ b/doc/Allowlists.md @@ -38,16 +38,19 @@ ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.list_allowlists( - page=1, - size=50, -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.list_allowlists( + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -71,20 +74,23 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, AllowlistCreateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) +client = Allowlists(auth=auth) request = AllowlistCreateRequest( name=None, description=None, ) -response = client.create_allowlist( - request=request, -) -print(response) +try: + response = client.create_allowlist( + request=request, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -109,15 +115,18 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.get_allowlist( - allowlist_id='allowlist_id', -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.get_allowlist( + allowlist_id='allowlist_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -141,16 +150,19 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.delete_allowlist( - allowlist_id='allowlist_id', - force=True, -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.delete_allowlist( + allowlist_id='allowlist_id', + force=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -176,21 +188,24 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, AllowlistUpdateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) +client = Allowlists(auth=auth) request = AllowlistUpdateRequest( name=None, description=None, ) -response = client.update_allowlist( - request=request, - allowlist_id='allowlist_id', -) -print(response) +try: + response = client.update_allowlist( + request=request, + allowlist_id='allowlist_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -217,17 +232,20 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.get_allowlist_items( - allowlist_id='allowlist_id', - page=1, - size=50, -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.get_allowlist_items( + allowlist_id='allowlist_id', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -251,22 +269,25 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, AllowlistItemsCreateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) +client = Allowlists(auth=auth) request = AllowlistItemsCreateRequest( items=None, description=None, expiration=None, ) -response = client.create_allowlist_items( - request=request, - allowlist_id='allowlist_id', -) -print(response) +try: + response = client.create_allowlist_items( + request=request, + allowlist_id='allowlist_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -292,16 +313,19 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.get_allowlist_item( - allowlist_id='allowlist_id', - item_id='item_id', -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.get_allowlist_item( + allowlist_id='allowlist_id', + item_id='item_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -325,16 +349,19 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.delete_allowlist_item( - allowlist_id='allowlist_id', - item_id='item_id', -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.delete_allowlist_item( + allowlist_id='allowlist_id', + item_id='item_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -361,22 +388,25 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, AllowlistItemUpdateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) +client = Allowlists(auth=auth) request = AllowlistItemUpdateRequest( description=None, expiration=None, ) -response = client.update_allowlist_item( - request=request, - allowlist_id='allowlist_id', - item_id='item_id', -) -print(response) +try: + response = client.update_allowlist_item( + request=request, + allowlist_id='allowlist_id', + item_id='item_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -403,17 +433,20 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.get_allowlist_subscribers( - allowlist_id='allowlist_id', - page=1, - size=50, -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.get_allowlist_subscribers( + allowlist_id='allowlist_id', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -439,21 +472,24 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, AllowlistSubscriptionRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) +client = Allowlists(auth=auth) request = AllowlistSubscriptionRequest( ids=None, entity_type=None, ) -response = client.subscribe_allowlist( - request=request, - allowlist_id='allowlist_id', -) -print(response) +try: + response = client.subscribe_allowlist( + request=request, + allowlist_id='allowlist_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -477,15 +513,18 @@ print(response) ```python from crowdsec_service_api import ( Allowlists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Allowlists(base_url=Server.production_server.value, auth=auth) -response = client.unsubscribe_allowlist( - allowlist_id='allowlist_id', - entity_id='entity_id', -) -print(response) +client = Allowlists(auth=auth) +try: + response = client.unsubscribe_allowlist( + allowlist_id='allowlist_id', + entity_id='entity_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Blocklists.md b/doc/Blocklists.md index cd370ab..78168f1 100644 --- a/doc/Blocklists.md +++ b/doc/Blocklists.md @@ -45,21 +45,24 @@ ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.get_blocklists( - page=1, - page_size=100, - subscribed_only=True, - exclude_subscribed=True, - include_filter=['private', 'shared'], - category=None, - size=50, -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.get_blocklists( + page=1, + page_size=100, + subscribed_only=True, + exclude_subscribed=True, + include_filter=['private', 'shared'], + category=None, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -84,12 +87,12 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistCreateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistCreateRequest( name=None, label=None, @@ -97,10 +100,13 @@ request = BlocklistCreateRequest( references=None, tags=None, ) -response = client.create_blocklist( - request=request, -) -print(response) +try: + response = client.create_blocklist( + request=request, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -126,12 +132,12 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistSearchRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistSearchRequest( page=None, page_size=None, @@ -146,12 +152,15 @@ request = BlocklistSearchRequest( is_private=None, is_subscribed=None, ) -response = client.search_blocklist( - request=request, - page=1, - size=50, -) -print(response) +try: + response = client.search_blocklist( + request=request, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -176,15 +185,18 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.get_blocklist( - blocklist_id='sample-blocklist-id', -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.get_blocklist( + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -208,16 +220,19 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.delete_blocklist( - blocklist_id='sample-blocklist-id', - force=True, -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.delete_blocklist( + blocklist_id='sample-blocklist-id', + force=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -245,12 +260,12 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistUpdateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistUpdateRequest( label=None, description=None, @@ -259,11 +274,14 @@ request = BlocklistUpdateRequest( from_cti_query=None, since=None, ) -response = client.update_blocklist( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.update_blocklist( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -290,21 +308,24 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistAddIPsRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistAddIPsRequest( ips=None, expiration=None, ) -response = client.add_ips_to_blocklist( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.add_ips_to_blocklist( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -331,21 +352,24 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistAddIPsRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistAddIPsRequest( ips=None, expiration=None, ) -response = client.overwrite_ips( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.overwrite_ips( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -371,20 +395,23 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistDeleteIPsRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistDeleteIPsRequest( ips=None, ) -response = client.delete_ips_from_blocklist( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.delete_ips_from_blocklist( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -413,17 +440,20 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.download_blocklist_content( - blocklist_id='sample-blocklist-id', - if_modified_since=None, - if_none_match=None, -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.download_blocklist_content( + blocklist_id='sample-blocklist-id', + if_modified_since=None, + if_none_match=None, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -450,17 +480,20 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.get_blocklist_subscribers( - blocklist_id='sample-blocklist-id', - page=1, - size=50, -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.get_blocklist_subscribers( + blocklist_id='sample-blocklist-id', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -486,22 +519,25 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistSubscriptionRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistSubscriptionRequest( ids=None, entity_type=None, remediation=None, ) -response = client.subscribe_blocklist( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.subscribe_blocklist( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -525,16 +561,19 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.unsubscribe_blocklist( - blocklist_id='sample-blocklist-id', - entity_id='entity_id', -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.unsubscribe_blocklist( + blocklist_id='sample-blocklist-id', + entity_id='entity_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -559,20 +598,23 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, BlocklistShareRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) +client = Blocklists(auth=auth) request = BlocklistShareRequest( organizations=None, ) -response = client.share_blocklist( - request=request, - blocklist_id='sample-blocklist-id', -) -print(response) +try: + response = client.share_blocklist( + request=request, + blocklist_id='sample-blocklist-id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -597,15 +639,18 @@ print(response) ```python from crowdsec_service_api import ( Blocklists, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Blocklists(base_url=Server.production_server.value, auth=auth) -response = client.unshare_blocklist( - blocklist_id='sample-blocklist-id', - unshare_organization_id='unshare_organization_id', -) -print(response) +client = Blocklists(auth=auth) +try: + response = client.unshare_blocklist( + blocklist_id='sample-blocklist-id', + unshare_organization_id='unshare_organization_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Cves.md b/doc/Cves.md index c8f396a..4b9c0ac 100644 --- a/doc/Cves.md +++ b/doc/Cves.md @@ -3,10 +3,61 @@ # Cves Methods | Method | Description | | ------ | ----------- | +| [get_cves](#get_cves) | Get a paginated list of CVEs that CrowdSec is tracking | | [get_cve](#get_cve) | Get information about a specific CVE ID | -| [get_cve_ips](#get_cve_ips) | Get information about IPs exploiting 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 | +| [get_cve_ips_details](#get_cve_ips_details) | Get detailed information about IPs exploiting a specific CVE ID | +| [get_cve_ips_details_stats](#get_cve_ips_details_stats) | Get aggregated statistics about IPs exploiting a specific CVE ID | +| [get_cve_subscribed_integrations](#get_cve_subscribed_integrations) | Get the list of integrations subscribed to a specific CVE ID | | [subscribe_integration_to_cve](#subscribe_integration_to_cve) | Subscribe an integration to receive threats related to a specific CVE ID | | [unsubscribe_integration_from_cve](#unsubscribe_integration_from_cve) | Unsubscribe an integration from receiving threats related to a specific CVE ID | +| [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 +- Endpoint: `/cves` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| query | Optional[str] | Search query for CVEs | 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") | +| exploitation_phase | Optional[CVEExploitationPhase] | Filter by exploitation phase | False | None | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetCVEsResponsePage](./Models.md#getcvesresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.get_cves( + query=None, + sort_by=rule_release_date, + sort_order=desc, + exploitation_phase=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + ## **get_cve** ### Get information about a specific CVE ID @@ -29,28 +80,103 @@ ```python from crowdsec_service_api import ( Cves, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.get_cve( + cve_id='cve_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_cve_protect_rules** +### Get protection/detection rules associated with a specific CVE ID +- Endpoint: `/cves/{cve_id}/protect-rules` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| cve_id | str | | True | | +### Returns: +[GetCVEProtectRulesResponse](./Models.md#getcveprotectrulesresponse) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | CVE Not Found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, +) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Cves(base_url=Server.production_server.value, auth=auth) -response = client.get_cve( - cve_id='cve_id', +client = Cves(auth=auth) +try: + response = client.get_cve_protect_rules( + cve_id='cve_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **download_cve_ips** +### Download the list of IPs exploiting a specific CVE ID in raw format +- Endpoint: `/cves/{cve_id}/ips-download` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| cve_id | str | | True | | +### Returns: +[str](./Models.md#str) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | CVE Not Found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, ) -print(response) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.download_cve_ips( + cve_id='cve_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` -## **get_cve_ips** -### Get information about IPs exploiting a specific CVE ID -- Endpoint: `/cves/{cve_id}/ips` +## **get_cve_ips_details** +### Get detailed information about IPs exploiting a specific CVE ID +- Endpoint: `/cves/{cve_id}/ips-details` - Method: `GET` ### Parameters: | Parameter | Type | Description | Required | Default | | --------- | ---- | ----------- | -------- | ------- | | cve_id | str | | True | | -| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h) | False | None | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | | page | int | Page number | False | 1 | | size | int | Page size | False | 50 | ### Returns: @@ -65,18 +191,99 @@ print(response) ```python from crowdsec_service_api import ( Cves, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Cves(base_url=Server.production_server.value, auth=auth) -response = client.get_cve_ips( - cve_id='cve_id', - since=None, - page=1, - size=50, +client = Cves(auth=auth) +try: + response = client.get_cve_ips_details( + cve_id='cve_id', + since=14d, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_cve_ips_details_stats** +### Get aggregated statistics about IPs exploiting a specific CVE ID +- Endpoint: `/cves/{cve_id}/ips-details-stats` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| cve_id | str | | True | | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | +### Returns: +[IpsDetailsStats](./Models.md#ipsdetailsstats) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | CVE Not Found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, ) -print(response) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.get_cve_ips_details_stats( + cve_id='cve_id', + since=14d, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_cve_subscribed_integrations** +### Get the list of integrations subscribed to a specific CVE ID +- Endpoint: `/cves/{cve_id}/integrations` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| cve_id | str | | True | | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetCVESubscribedIntegrationsResponsePage](./Models.md#getcvesubscribedintegrationsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | CVE Not Found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.get_cve_subscribed_integrations( + cve_id='cve_id', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -101,20 +308,23 @@ print(response) ```python from crowdsec_service_api import ( Cves, - Server, ApiKeyAuth, SubscribeCVEIntegrationRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Cves(base_url=Server.production_server.value, auth=auth) +client = Cves(auth=auth) request = SubscribeCVEIntegrationRequest( name=None, ) -response = client.subscribe_integration_to_cve( - request=request, - cve_id='cve_id', -) -print(response) +try: + response = client.subscribe_integration_to_cve( + request=request, + cve_id='cve_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -139,15 +349,56 @@ print(response) ```python from crowdsec_service_api import ( Cves, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Cves(base_url=Server.production_server.value, auth=auth) -response = client.unsubscribe_integration_from_cve( - cve_id='cve_id', - integration_name='integration_name', +client = Cves(auth=auth) +try: + response = client.unsubscribe_integration_from_cve( + cve_id='cve_id', + integration_name='integration_name', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_cve_timeline** +### Get timeline data of occurrences for a specific CVE ID +- Endpoint: `/cves/{cve_id}/timeline` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| cve_id | str | | True | | +| since_days | SinceOptions | Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days. | False | | +### Returns: +[list[TimelineItem]](./Models.md#list[timelineitem]) +### Errors: +| Code | Description | +| ---- | ----------- | +| 404 | CVE Not Found | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Cves, + ApiKeyAuth, ) -print(response) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Cves(auth=auth) +try: + response = client.get_cve_timeline( + cve_id='cve_id', + since_days=None, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Decisions.md b/doc/Decisions.md new file mode 100644 index 0000000..e4248a1 --- /dev/null +++ b/doc/Decisions.md @@ -0,0 +1,113 @@ + + +# Decisions Methods +| Method | Description | +| ------ | ----------- | +| [get_decisions](#get_decisions) | Get decisions | +| [create_decision](#create_decision) | Create a new decision. | + +## **get_decisions** +### Get decisions +- Endpoint: `/decisions` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| 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 | [] | +| 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 + +```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_decisions( + instance_ids=['sample-item'], + tag_ids=['sample-item'], + remediation_types=['sample-item'], + ips=['sample-item'], + sort_by=created_at, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **create_decision** +### Create a new decision. +- Endpoint: `/decisions` +- Method: `POST` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| request | [DecisionCreateRequest](./Models.md#decisioncreaterequest) | Request body | Yes | - | +### Returns: +[DecisionCreateResponse](./Models.md#decisioncreateresponse) +### Errors: +| Code | Description | +| ---- | ----------- | +| 409 | Conflict: Decision value is in allowlists; cannot create decision. | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Decisions, + ApiKeyAuth, + DecisionCreateRequest, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Decisions(auth=auth) +request = DecisionCreateRequest( + created_at=None, + uuid=None, + id=None, + duration=None, + origin=None, + scenario=None, + scope=None, + type=None, + value=None, + country=None, + as_name=None, + as_num=None, + city=None, + latitude=None, + longitude=None, + target=None, +) +try: + response = client.create_decision( + request=request, + ) + 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 new file mode 100644 index 0000000..8336e47 --- /dev/null +++ b/doc/Fingerprints.md @@ -0,0 +1,357 @@ + + +# Fingerprints Methods +| Method | Description | +| ------ | ----------- | +| [get_fingerprint_rules](#get_fingerprint_rules) | Get a paginated list of fingerprint rules | +| [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 | +| [get_fingerprint_subscribed_integrations](#get_fingerprint_subscribed_integrations) | Get the list of integrations subscribed to a specific fingerprint rule | +| [subscribe_integration_to_fingerprint](#subscribe_integration_to_fingerprint) | Subscribe an integration to receive threats related to a specific fingerprint rule | +| [unsubscribe_integration_from_fingerprint](#unsubscribe_integration_from_fingerprint) | Unsubscribe an integration from receiving threats related to a specific fingerprint rule | +| [get_fingerprint_timeline](#get_fingerprint_timeline) | Get timeline data of occurrences for a specific fingerprint rule | +| [get_fingerprint_rule](#get_fingerprint_rule) | Get information about a specific fingerprint rule | + +## **get_fingerprint_rules** +### Get a paginated list of fingerprint rules +- Endpoint: `/fingerprints` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| 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") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetFingerprintRulesResponsePage](./Models.md#getfingerprintrulesresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_rules( + query=None, + sort_by=rule_release_date, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **download_fingerprint_ips** +### Download the list of IPs exploiting a specific fingerprint rule in raw format +- Endpoint: `/fingerprints/{fingerprint}/ips-download` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +### Returns: +[str](./Models.md#str) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.download_fingerprint_ips( + fingerprint='fingerprint', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_fingerprint_ips_details** +### Get detailed information about IPs exploiting a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/ips-details` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetFingerprintIPsResponsePage](./Models.md#getfingerprintipsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_ips_details( + fingerprint='fingerprint', + since=14d, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_fingerprint_ips_details_stats** +### Get aggregated statistics about IPs exploiting a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/ips-details-stats` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | +### Returns: +[IpsDetailsStats](./Models.md#ipsdetailsstats) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_ips_details_stats( + fingerprint='fingerprint', + since=14d, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_fingerprint_subscribed_integrations** +### Get the list of integrations subscribed to a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/integrations` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetFingerprintSubscribedIntegrationsResponsePage](./Models.md#getfingerprintsubscribedintegrationsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_subscribed_integrations( + fingerprint='fingerprint', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **subscribe_integration_to_fingerprint** +### Subscribe an integration to receive threats related to a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/integrations` +- Method: `POST` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| request | [SubscribeFingerprintIntegrationRequest](./Models.md#subscribefingerprintintegrationrequest) | Request body | Yes | - | +| fingerprint | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, + SubscribeFingerprintIntegrationRequest, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +request = SubscribeFingerprintIntegrationRequest( + name=None, +) +try: + response = client.subscribe_integration_to_fingerprint( + request=request, + fingerprint='fingerprint', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **unsubscribe_integration_from_fingerprint** +### Unsubscribe an integration from receiving threats related to a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/integrations/{integration_name}` +- Method: `DELETE` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +| integration_name | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.unsubscribe_integration_from_fingerprint( + fingerprint='fingerprint', + integration_name='integration_name', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_fingerprint_timeline** +### Get timeline data of occurrences for a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}/timeline` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +| since_days | SinceOptions | Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days. | False | | +| interval | Optional[IntervalOptions] | Interval for aggregating timeline data. Options: 'hour', 'day', 'week'. Default is adapted based on 'since' parameter. | False | None | +### Returns: +[list[FingerprintTimelineItem]](./Models.md#list[fingerprinttimelineitem]) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_timeline( + fingerprint='fingerprint', + since_days=None, + interval=None, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_fingerprint_rule** +### Get information about a specific fingerprint rule +- Endpoint: `/fingerprints/{fingerprint}` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| fingerprint | str | | True | | +### Returns: +[FingerprintRuleResponse](./Models.md#fingerprintruleresponse) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Fingerprints, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Fingerprints(auth=auth) +try: + response = client.get_fingerprint_rule( + fingerprint='fingerprint', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/doc/Hub.md b/doc/Hub.md index 677fb51..8ee7fc9 100644 --- a/doc/Hub.md +++ b/doc/Hub.md @@ -36,17 +36,20 @@ content is returned. | ```python from crowdsec_service_api import ( Hub, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Hub(base_url=Server.production_server.value, auth=auth) -response = client.get_index( - branch='branch', - tenant='tenant', - with_content=True, -) -print(response) +client = Hub(auth=auth) +try: + response = client.get_index( + branch='branch', + tenant='tenant', + with_content=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -74,17 +77,20 @@ cache expiration policies. No body content is returned. ```python from crowdsec_service_api import ( Hub, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Hub(base_url=Server.production_server.value, auth=auth) -response = client.head_index( - branch='branch', - tenant='tenant', - with_content=True, -) -print(response) +client = Hub(auth=auth) +try: + response = client.head_index( + branch='branch', + tenant='tenant', + with_content=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -109,17 +115,20 @@ print(response) ```python from crowdsec_service_api import ( Hub, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Hub(base_url=Server.production_server.value, auth=auth) -response = client.get_item_content( - item_path='item_path', - branch='branch', - tenant='tenant', -) -print(response) +client = Hub(auth=auth) +try: + response = client.get_item_content( + item_path='item_path', + branch='branch', + tenant='tenant', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -145,16 +154,19 @@ content is returned. ```python from crowdsec_service_api import ( Hub, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Hub(base_url=Server.production_server.value, auth=auth) -response = client.head_item_content( - item_path='item_path', - branch='branch', - tenant='tenant', -) -print(response) +client = Hub(auth=auth) +try: + response = client.head_item_content( + item_path='item_path', + branch='branch', + tenant='tenant', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Info.md b/doc/Info.md index 32f783f..234ba08 100644 --- a/doc/Info.md +++ b/doc/Info.md @@ -20,13 +20,16 @@ ```python from crowdsec_service_api import ( Info, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Info(base_url=Server.production_server.value, auth=auth) -response = client.get_info( -) -print(response) +client = Info(auth=auth) +try: + response = client.get_info( + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Integrations.md b/doc/Integrations.md index 0c8619d..2eb97aa 100644 --- a/doc/Integrations.md +++ b/doc/Integrations.md @@ -34,17 +34,20 @@ ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.get_integrations( - tag=None, - page=1, - size=50, -) -print(response) +client = Integrations(auth=auth) +try: + response = client.get_integrations( + tag=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -68,22 +71,27 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, IntegrationCreateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) +client = Integrations(auth=auth) request = IntegrationCreateRequest( name=None, description=None, entity_type=None, output_format=None, + pull_limit=None, + enable_ip_aggregation=None, ) -response = client.create_integration( - request=request, -) -print(response) +try: + response = client.create_integration( + request=request, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -107,15 +115,18 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.get_integration( - integration_id='integration_id', -) -print(response) +client = Integrations(auth=auth) +try: + response = client.get_integration( + integration_id='integration_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -128,6 +139,7 @@ print(response) | Parameter | Type | Description | Required | Default | | --------- | ---- | ----------- | -------- | ------- | | integration_id | str | | True | | +| force | bool | Force delete the integration even if it has active subscriptions (it will unsubscribe from all lists) | False | False | ### Errors: | Code | Description | | ---- | ----------- | @@ -137,15 +149,19 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.delete_integration( - integration_id='integration_id', -) -print(response) +client = Integrations(auth=auth) +try: + response = client.delete_integration( + integration_id='integration_id', + force=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -170,23 +186,28 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, IntegrationUpdateRequest, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) +client = Integrations(auth=auth) request = IntegrationUpdateRequest( name=None, description=None, output_format=None, regenerate_credentials=None, + pull_limit=None, + enable_ip_aggregation=None, ) -response = client.update_integration( - request=request, - integration_id='integration_id', -) -print(response) +try: + response = client.update_integration( + request=request, + integration_id='integration_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -201,27 +222,37 @@ print(response) | integration_id | str | | True | | | page | int | Page number to return | False | 1 | | page_size | Optional[int] | Maximum number of items to return, 0 means no limit (default), should be greater than 10000 | False | None | +| pull_limit | Optional[int] | | False | None | +| enable_ip_aggregation | bool | | False | False | +### Returns: +[str](./Models.md#str) ### Errors: | Code | Description | | ---- | ----------- | | 404 | Integration not found | +| 204 | Integration has no subscribed blocklists or no content available | | 422 | Validation Error | ### Usage ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.get_integration_content( - integration_id='integration_id', - page=1, - page_size=None, -) -print(response) +client = Integrations(auth=auth) +try: + response = client.get_integration_content( + integration_id='integration_id', + page=1, + page_size=None, + pull_limit=None, + enable_ip_aggregation=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -244,15 +275,18 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.head_integration_content( - integration_id='integration_id', -) -print(response) +client = Integrations(auth=auth) +try: + response = client.head_integration_content( + integration_id='integration_id', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` @@ -276,15 +310,18 @@ print(response) ```python from crowdsec_service_api import ( Integrations, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Integrations(base_url=Server.production_server.value, auth=auth) -response = client.get_integration_content_stream( - integration_id='integration_id', - startup=True, -) -print(response) +client = Integrations(auth=auth) +try: + response = client.get_integration_content_stream( + integration_id='integration_id', + startup=True, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Metrics.md b/doc/Metrics.md index 14a4942..4d88515 100644 --- a/doc/Metrics.md +++ b/doc/Metrics.md @@ -29,18 +29,21 @@ ```python from crowdsec_service_api import ( Metrics, - Server, ApiKeyAuth, ) +from httpx import HTTPStatusError auth = ApiKeyAuth(api_key='your_api_key') -client = Metrics(base_url=Server.production_server.value, auth=auth) -response = client.get_metrics_remediation( - start_date='start_date', - end_date='end_date', - engine_ids=['sample-item'], - integration_ids=['sample-item'], - tags=['sample-item'], -) -print(response) +client = Metrics(auth=auth) +try: + response = client.get_metrics_remediation( + start_date='start_date', + end_date='end_date', + engine_ids=['sample-item'], + integration_ids=['sample-item'], + tags=['sample-item'], + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") ``` diff --git a/doc/Models.md b/doc/Models.md index 89efd30..7e05f77 100644 --- a/doc/Models.md +++ b/doc/Models.md @@ -34,7 +34,7 @@ id, allowlist_id, description, scope, value, created_at, created_by | id | str | ID of the allowlist entry || | allowlist_id | str | ID of the allowlist || | description | str | Description of the allowlist entry || -| scope | str | None || +| scope | AllowlistScope | None || | value | Union[str, str] | Value of the allowlist entry || | created_at | str | Time the allowlist entry was created || | updated_at | Optional[str] | Time the allowlist entry was updated || @@ -101,7 +101,7 @@ id, allowlist_id, description, scope, value, created_at, updated_at, created_by, | id | str | ID of the allowlist entry || | allowlist_id | str | ID of the allowlist || | description | str | Description of the allowlist entry || -| scope | str | None || +| scope | AllowlistScope | None || | value | Union[str, str] | Value of the allowlist entry || | created_at | str | Time the allowlist entry was created || | updated_at | str | Time the allowlist entry was updated || @@ -130,7 +130,7 @@ id, entity_type | Property | Type | Description | Example | |----------|------|-------------|---------| | id | str | Subscriber entity id || -| entity_type | str | None || +| entity_type | SubscriberEntityType | None || # **AllowlistSubscriberEntityPage** ## Required: @@ -151,7 +151,7 @@ entity_type, count ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| entity_type | str | None || +| entity_type | SubscriberEntityType | None || | count | int | Subscriber entity count || # **AllowlistSubscriptionRequest** @@ -161,7 +161,7 @@ entity_type | Property | Type | Description | Example | |----------|------|-------------|---------| | ids | list[str] | List of subscriber entity id || -| entity_type | str | None || +| entity_type | EntityType | None || # **AllowlistSubscriptionResponse** ## Required: @@ -294,7 +294,7 @@ label, id, pricing_tier |----------|------|-------------|---------| | label | str | Label of the blocklist || | id | str | ID of the blocklist || -| pricing_tier | str | None || +| pricing_tier | PricingTiers | None || # **BlocklistSearchRequest** ## Properties @@ -347,7 +347,7 @@ id, entity_type, remediation | Property | Type | Description | Example | |----------|------|-------------|---------| | id | str | Subscriber entity id || -| entity_type | str | None || +| entity_type | SubscriberEntityType | None || | remediation | str | Remediation || # **BlocklistSubscriberEntityPage** @@ -369,7 +369,7 @@ entity_type, count ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| entity_type | str | None || +| entity_type | SubscriberEntityType | None || | count | int | Subscriber entity count || # **BlocklistSubscription** @@ -390,7 +390,7 @@ entity_type | Property | Type | Description | Example | |----------|------|-------------|---------| | ids | list[str] | List of subscriber entity id || -| entity_type | str | None || +| entity_type | SubscriberEntityType | None || | remediation | Optional[str] | Remediation || # **BlocklistSubscriptionResponse** @@ -432,6 +432,14 @@ file |----------|------|-------------|---------| | file | str | Blocklist file in txt format || +# **CVESubscription** +## Required: +id +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | CVE ID || + # **ComputedMetrics** ## Required: saved @@ -514,10 +522,106 @@ name, label, description, references, total_ips | references | list[str] | None || | total_ips | int | None || +# **DecisionCreateRequest** +## Required: +duration, origin, scenario, scope, type, value, target +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| created_at | str | None || +| uuid | Optional[str] | UUID of the decision || +| id | Optional[int] | ID of the decision || +| duration | str | Duration of the decision || +| origin | str | Origin of the decision || +| scenario | str | Scenario of the decision || +| 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 || +| target | DecisionTargetModel | None || + +# **DecisionCreateResponse** +## Required: +uuid +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| uuid | str | UUID of the created decision || + +# **DecisionResponse** +## Required: +uuid, id, duration, origin, scenario, scope, type, value, target +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| created_at | str | None || +| uuid | str | UUID of the decision || +| id | int | ID of the decision || +| duration | str | Duration of the decision || +| origin | str | Origin of the decision || +| scenario | str | Scenario of the decision || +| 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 || +| target | DecisionTargetModel | None || + +# **DecisionTargetModel** +## Required: +type, value +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| type | DecisionTargetType | None || +| value | str | Value of the decision target || + +# **DecisionTargetType** +## Enum: +ORG, TAG, ENTITY + +# **DecisionsGetResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[DecisionResponse] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **DecisionsSortBy** +## Enum: +CREATED_AT, EXPIRE_AT + +# **DecisionsSortOrder** +## Enum: +ASC, DESC + # **EntityType** ## Enum: ORG, TAG, ENGINE, FIREWALL_INTEGRATION, REMEDIATION_COMPONENT_INTEGRATION, REMEDIATION_COMPONENT, LOG_PROCESSOR +# **FingerprintSubscription** +## Required: +id +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | Fingerprint ID || + # **GetRemediationMetricsResponse** ## Required: raw, computed @@ -551,12 +655,14 @@ name, entity_type, output_format |----------|------|-------------|---------| | name | str | Name of the integration || | description | str | Description of the integration || -| entity_type | str | None || -| output_format | str | None || +| entity_type | IntegrationType | None || +| output_format | OutputFormat | None || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || # **IntegrationCreateResponse** ## Required: -id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, endpoint, credentials +id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, cves, fingerprints, vendors, endpoint, credentials ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| @@ -566,18 +672,23 @@ id, name, organization_id, created_at, updated_at, entity_type, output_format, b | description | str | Description of the integration || | created_at | str | Time the integration was created || | updated_at | str | Last time the integration was updated || -| entity_type | str | None || -| output_format | str | None || +| entity_type | IntegrationType | None || +| output_format | OutputFormat | None || | last_pull | Optional[str] | Last time the integration pulled blocklists || | blocklists | list[BlocklistSubscription] | Blocklists that are subscribed by the integration || +| cves | list[CVESubscription] | CVEs that are subscribed by the integration || +| fingerprints | list[FingerprintSubscription] | Fingerprints that are subscribed by the integration || +| vendors | list[VendorSubscription] | Vendors that are subscribed by the integration || | endpoint | str | Url that should be used by the firewall or the remediation component to fetch the integration's content || | stats | Stats | None || | tags | list[str] | Tags associated with the integration || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || | credentials | Union[ApiKeyCredentials, BasicAuthCredentials] | Credentials that were generated for the integration || # **IntegrationGetResponse** ## Required: -id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, endpoint +id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, cves, fingerprints, vendors, endpoint ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| @@ -587,13 +698,18 @@ id, name, organization_id, created_at, updated_at, entity_type, output_format, b | description | str | Description of the integration || | created_at | str | Time the integration was created || | updated_at | str | Last time the integration was updated || -| entity_type | str | None || -| output_format | str | None || +| entity_type | IntegrationType | None || +| output_format | OutputFormat | None || | last_pull | Optional[str] | Last time the integration pulled blocklists || | blocklists | list[BlocklistSubscription] | Blocklists that are subscribed by the integration || +| cves | list[CVESubscription] | CVEs that are subscribed by the integration || +| fingerprints | list[FingerprintSubscription] | Fingerprints that are subscribed by the integration || +| vendors | list[VendorSubscription] | Vendors that are subscribed by the integration || | endpoint | str | Url that should be used by the firewall or the remediation component to fetch the integration's content || | stats | Stats | None || | tags | list[str] | Tags associated with the integration || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || # **IntegrationGetResponsePage** ## Required: @@ -618,12 +734,14 @@ FIREWALL_INTEGRATION, REMEDIATION_COMPONENT_INTEGRATION |----------|------|-------------|---------| | name | str | New name || | description | str | New description || -| output_format | str | None || +| output_format | OutputFormat | None || | regenerate_credentials | bool | Regenerate credentials for the integration || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || # **IntegrationUpdateResponse** ## Required: -id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, endpoint +id, name, organization_id, created_at, updated_at, entity_type, output_format, blocklists, cves, fingerprints, vendors, endpoint ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| @@ -633,13 +751,18 @@ id, name, organization_id, created_at, updated_at, entity_type, output_format, b | description | str | Description of the integration || | created_at | str | Time the integration was created || | updated_at | str | Last time the integration was updated || -| entity_type | str | None || -| output_format | str | None || +| entity_type | IntegrationType | None || +| output_format | OutputFormat | None || | last_pull | Optional[str] | Last time the integration pulled blocklists || | blocklists | list[BlocklistSubscription] | Blocklists that are subscribed by the integration || +| cves | list[CVESubscription] | CVEs that are subscribed by the integration || +| fingerprints | list[FingerprintSubscription] | Fingerprints that are subscribed by the integration || +| vendors | list[VendorSubscription] | Vendors that are subscribed by the integration || | endpoint | str | Url that should be used by the firewall or the remediation component to fetch the integration's content || | stats | Stats | None || | tags | list[str] | Tags associated with the integration || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || | credentials | Optional[ApiKeyCredentials, BasicAuthCredentials] | Credentials for the integration || # **Links** @@ -692,8 +815,8 @@ id, created_at, updated_at, name, description, is_private, pricing_tier, source, | references | list[str] | Blocklist references || | is_private | bool | Private blocklist if True or public if False || | tags | list[str] | Classification tags || -| pricing_tier | str | None || -| source | str | None || +| pricing_tier | PricingTiers | None || +| source | BlocklistSources | None || | stats | BlocklistStats | None || | from_cti_query | Optional[str] | CTI query from which the blocklist was created || | since | Optional[str] | Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days || @@ -729,7 +852,7 @@ total, unit, progression, data | Property | Type | Description | Example | |----------|------|-------------|---------| | total | Union[int, float] | Total value of the metric || -| unit | str | None || +| unit | MetricUnits | None || | progression | Optional[int] | Progression of the metric value from the previous period || | data | list[OriginMetrics] | Data points per origin || @@ -749,7 +872,7 @@ organization_id, permission | Property | Type | Description | Example | |----------|------|-------------|---------| | organization_id | str | None || -| permission | str | None || +| permission | Permission | None || # **SourceInfo** ## Required: @@ -757,7 +880,7 @@ source_type, identifier ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| source_type | str | None || +| source_type | SourceType | None || | identifier | str | The source identifier that created the allowlist entry || # **SourceType** @@ -786,6 +909,14 @@ loc, msg, type | msg | str | None || | type | str | None || +# **VendorSubscription** +## Required: +id +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | Vendor ID || + # **AppsecConfigIndex** ## Properties | Property | Type | Description | Example | @@ -904,12 +1035,28 @@ digest | deprecated | Optional[bool] | Indicates whether this version is deprecated. || | digest | str | The SHA256 digest of the versioned file. || +# **AdjustmentScore** +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| total | int | Total score adjustment || +| recency | int | Recency score adjustment || +| low_info | int | Low information score adjustment || + # **AffectedComponent** ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| vendor | str | Vendor of the affected component || -| product | str | Product name of the affected component || +| vendor | Optional[str] | Vendor of the affected component || +| product | Optional[str] | Product name of the affected component || + +# **AllowlistSubscription** +## Required: +id +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | None || # **AttackDetail** ## Required: @@ -932,6 +1079,64 @@ name, label, description | label | str | Behavior label || | description | str | Behavior description || +# **CVEEventOutput** +## Required: +name, date, description, label, sorting_priority +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | None || +| date | str | None || +| description | str | None || +| label | str | None || +| sorting_priority | int | None || + +# **CVEExploitationPhase** +## Enum: +INSUFFICIENT_DATA, EARLY_EXPLOITATION, FRESH_AND_POPULAR, TARGETED_EXPLOITATION, MASS_EXPLOITATION, BACKGROUND_NOISE, UNPOPULAR, WEARING_OUT, UNCLASSIFIED + +# **CVEResponseBase** +## Required: +id, name, title, affected_components, crowdsec_score, nb_ips, published_date, has_public_exploit, exploitation_phase +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | ID of the CVE || +| name | str | Name of the CVE || +| title | str | Title of the CVE || +| affected_components | list[AffectedComponent] | List of affected components || +| crowdsec_score | int | Live Exploit Tracker score of the CVE || +| opportunity_score | int | Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5) || +| momentum_score | int | Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5) || +| first_seen | Optional[str] | First seen date || +| last_seen | Optional[str] | Last seen date || +| nb_ips | int | Number of unique IPs affected || +| published_date | str | Published date of the CVE || +| cvss_score | Optional[float] | CVSS score of the CVE || +| has_public_exploit | bool | Indicates if there is a public exploit for the CVE || +| rule_release_date | Optional[str] | Release date of the associated detection rule || +| 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) || + +# **CVEsubscription** +## Required: +id +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | None || + +# **CWE** +## Required: +name, label, description +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | Name of the CWE || +| label | str | Label of the CWE || +| description | str | Description of the CWE || + # **Classification** ## Required: name, label, description @@ -949,6 +1154,119 @@ name, label, description | false_positives | list[Classification] | False positive classifications || | classifications | list[Classification] | Main classifications || +# **ExploitationPhase** +## Required: +name, label, description +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | Name of the exploitation phase || +| label | str | Label of the exploitation phase || +| description | str | Description of the exploitation phase || + +# **ExploitationPhaseChangeEventItem** +## Required: +cve_id, name, date, label, description, previous_phase, new_phase +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| cve_id | str | CVE identifier || +| name | str | Event type name || +| date | str | Date of the phase change || +| label | str | Human-readable event label || +| description | str | Rendered event description || +| previous_phase | str | Previous exploitation phase label || +| new_phase | str | New exploitation phase label || + +# **ExploitationPhaseChangeEventsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[ExploitationPhaseChangeEventItem] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **FacetBucket** +## Required: +value, count +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| value | str | Facet value || +| count | int | Number of IPs matching this value || + +# **FingerprintEventOutput** +## Required: +name, date, description, label +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | None || +| date | str | None || +| description | str | None || +| label | str | None || + +# **FingerprintRuleResponse** +## 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) || +| tags | list[str] | Tags associated with the fingerprint rule || +| description | Optional[str] | Fingerprint rule description || +| references | list[str] | Reference links for the fingerprint rule || +| 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 +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| timestamp | str | Timestamp of the timeline event || +| count | int | Count of occurrences at the timestamp || + # **GetCVEIPsResponsePage** ## Required: items, total, page, size, pages, links @@ -962,23 +1280,140 @@ items, total, page, size, pages, links | pages | int | None || | links | Links | None || +# **GetCVEProtectRulesResponse** +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| protect_rules | list[ProtectRule] | Protection/detection rules associated with the CVE || + # **GetCVEResponse** ## Required: -id, name, affected_components, let_score, first_seen, last_seen, nb_ips, published_date, cvss_score, references, description +id, name, title, affected_components, crowdsec_score, nb_ips, published_date, has_public_exploit, exploitation_phase, references, description, crowdsec_analysis, cwes ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| | id | str | ID of the CVE || | name | str | Name of the CVE || +| title | str | Title of the CVE || | affected_components | list[AffectedComponent] | List of affected components || -| let_score | int | LET score of the CVE || -| first_seen | str | First seen date || -| last_seen | str | Last seen date || +| crowdsec_score | int | Live Exploit Tracker score of the CVE || +| opportunity_score | int | Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5) || +| momentum_score | int | Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5) || +| first_seen | Optional[str] | First seen date || +| last_seen | Optional[str] | Last seen date || | nb_ips | int | Number of unique IPs affected || | published_date | str | Published date of the CVE || -| cvss_score | float | CVSS score of the CVE || +| cvss_score | Optional[float] | CVSS score of the CVE || +| has_public_exploit | bool | Indicates if there is a public exploit for the CVE || +| rule_release_date | Optional[str] | Release date of the associated detection rule || +| 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 | 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 || + +# **GetCVESubscribedIntegrationsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[IntegrationResponse] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetCVEsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[CVEResponseBase] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetCVEsSortBy** +## Enum: +RULE_RELEASE_DATE, TRENDING, NB_IPS, NAME, FIRST_SEEN + +# **GetCVEsSortOrder** +## Enum: +ASC, DESC + +# **GetFingerprintIPsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[IPItem] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetFingerprintRulesResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[FingerprintRuleSummary] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetFingerprintSubscribedIntegrationsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[IntegrationResponse] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetVendorIPsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[IPItem] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **GetVendorSubscribedIntegrationsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[IntegrationResponse] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || # **History** ## Required: @@ -998,7 +1433,7 @@ ip | Property | Type | Description | Example | |----------|------|-------------|---------| | ip | str | IP address || -| reputation | str | Reputation of the IP || +| reputation | Optional[str] | Reputation of the IP || | ip_range | Optional[str] | IP range || | ip_range_score | Optional[int] | IP range score || | ip_range_24 | Optional[str] | IP range /24 || @@ -1006,20 +1441,61 @@ ip | ip_range_24_score | Optional[int] | IP range /24 score || | as_name | Optional[str] | AS name || | as_num | Optional[int] | AS number || -| background_noise_score | int | Background noise score || +| background_noise_score | Optional[int] | Background noise score || | background_noise | Optional[str] | Background noise level || | confidence | Optional[str] | Confidence level || | location | Optional[Location] | IP location information || | reverse_dns | Optional[str] | Reverse DNS || | behaviors | list[Behavior] | List of behaviors || | references | list[Reference] | List of references || -| history | History | None || -| classifications | Classifications | None || +| history | Optional[History] | Historical data || +| classifications | Optional[Classifications] | Classification data || | mitre_techniques | list[MitreTechnique] | MITRE techniques || | cves | list[str] | List of CVEs || | attack_details | list[AttackDetail] | Attack details || | target_countries | Target Countries | Target countries || -| scores | Scores | None || +| scores | Optional[Scores] | Scoring information || + +# **IntegrationResponse** +## Required: +organization_id, entity_type, name, output_format +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| tags | list[str] | None || +| organization_id | str | None || +| created_at | str | Time the integration was created || +| entity_type | EntityType | None || +| id | str | ID of the integration || +| blocklists | list[BlocklistSubscription] | None || +| allowlists | list[AllowlistSubscription] | None || +| cves | Optional[list[CVEsubscription]] | None || +| fingerprints | Optional[list[FingerprintSubscription]] | None || +| vendors | Optional[list[VendorSubscription]] | None || +| name | str | Name of the integration || +| updated_at | str | Last time the integration was updated || +| description | Optional[str] | Description of the integration || +| output_format | OutputFormat | None || +| last_pull | Optional[str] | Last time the integration pulled blocklists || +| pull_limit | Optional[int] | Maximum number of items to pull || +| enable_ip_aggregation | bool | Whether to enable IP aggregation into ranges || + +# **IntervalOptions** +## Enum: +HOUR, DAY, WEEK + +# **IpsDetailsStats** +## Required: +total, reputation, country, as_name, cves, classifications +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| total | int | Total number of matching IPs || +| reputation | list[FacetBucket] | IP count by reputation || +| country | list[FacetBucket] | IP count by country (top 5) || +| as_name | list[FacetBucket] | IP count by AS name (top 5) || +| cves | list[FacetBucket] | IP count by CVE (top 5) || +| classifications | list[FacetBucket] | IP count by classification (top 5) || # **Location** ## Properties @@ -1030,6 +1506,104 @@ ip | latitude | Optional[float] | Latitude coordinate || | longitude | Optional[float] | Longitude coordinate || +# **LookupImpactCVEItem** +## Required: +id, name, title, affected_components, crowdsec_score, nb_ips, published_date, has_public_exploit, exploitation_phase, references, description, crowdsec_analysis, cwes +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| id | str | ID of the CVE || +| name | str | Name of the CVE || +| title | str | Title of the CVE || +| affected_components | list[AffectedComponent] | List of affected components || +| crowdsec_score | int | Live Exploit Tracker score of the CVE || +| opportunity_score | int | Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5) || +| momentum_score | int | Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5) || +| first_seen | Optional[str] | First seen date || +| last_seen | Optional[str] | Last seen date || +| nb_ips | int | Number of unique IPs affected || +| published_date | str | Published date of the CVE || +| cvss_score | Optional[float] | CVSS score of the CVE || +| has_public_exploit | bool | Indicates if there is a public exploit for the CVE || +| rule_release_date | Optional[str] | Release date of the associated detection rule || +| 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 | 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 || +| type | str | Resource type || + +# **LookupImpactFingerprintItem** +## 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) || +| tags | list[str] | Tags associated with the fingerprint rule || +| description | Optional[str] | Fingerprint rule description || +| references | list[str] | Reference links for the fingerprint rule || +| crowdsec_analysis | Optional[str] | CrowdSec analysis for this fingerprint rule || +| events | list[FingerprintEventOutput] | List of events related to the fingerprint rule || +| type | str | Resource type || + +# **LookupImpactResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[Annotated[Union[LookupImpactCVEItem, LookupImpactFingerprintItem], Field(discriminator='type')]] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + +# **LookupListItemWithStats** +## Required: +value +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| value | str | Lookup entry value || +| nb_cves | int | Number of CVEs || +| nb_fingerprints | int | Number of fingerprint rules || +| nb_ips | int | Total number of unique IPs targeting this entry || +| nb_ips_cves | int | Number of IPs across CVEs || +| nb_ips_fingerprints | int | Number of IPs across fingerprint rules || +| latest_rule_release | Optional[str] | Most recent rule release date for this entry || + +# **LookupListWithStatsResponsePage** +## Required: +items, total, page, size, pages, links +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| items | list[LookupListItemWithStats] | None || +| total | int | None || +| page | int | None || +| size | int | None || +| pages | int | None || +| links | Links | None || + # **MitreTechnique** ## Required: name, label, description @@ -1040,6 +1614,28 @@ name, label, description | label | str | MITRE technique label || | description | str | MITRE technique description || +# **ProtectRule** +## Required: +link, name, label +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| link | str | URL to the rule source || +| published_date | Optional[str] | Date the rule was published || +| tags | list[ProtectRuleTag] | Tags associated with the rule || +| name | str | Rule name || +| label | str | Human-readable rule label || +| content | Optional[str] | Rule content/definition || + +# **ProtectRuleTag** +## Required: +tag, label +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| tag | str | Tag identifier || +| label | str | Human-readable tag label || + # **Reference** ## Required: name, label, description @@ -1073,10 +1669,75 @@ overall, last_day, last_week, last_month | last_week | ScoreBreakdown | None || | last_month | ScoreBreakdown | None || +# **SinceOptions** + # **SubscribeCVEIntegrationRequest** ## Required: name ## Properties | Property | Type | Description | Example | |----------|------|-------------|---------| -| name | str | Name of the integration to subscribe || \ No newline at end of file +| name | str | Name of the integration to subscribe || + +# **SubscribeFingerprintIntegrationRequest** +## Required: +name +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | Name of the integration to subscribe || + +# **SubscribeVendorIntegrationRequest** +## Required: +name +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| name | str | Name of the integration to subscribe || + +# **ThreatContext** +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| attacker_countries | Attacker Countries | Attacker country distribution (country code → count) || +| defender_countries | Defender Countries | Defender country distribution (country code → count) || +| industry_types | Industry Types | Industry type distribution (type → count) || +| industry_risk_profiles | Industry Risk Profiles | Industry risk profile distribution (profile → count) || +| attacker_objectives | Attacker Objectives | Attacker objective distribution (objective → count) || + +# **TimelineItem** +## Required: +timestamp, count +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| timestamp | str | Timestamp of the timeline event || +| count | int | Count of occurrences at the timestamp || + +# **TopProductItem** +## Required: +value +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| value | str | Product name || +| nb_ips_cves | int | Number of IPs across CVEs || +| nb_ips_fingerprints | int | Number of IPs across fingerprint rules || + +# **VendorSortBy** +## Enum: +VALUE, NB_CVES, NB_IPS, LATEST_RULE_RELEASE + +# **VendorStatsResponse** +## Required: +value +## Properties +| Property | Type | Description | Example | +|----------|------|-------------|---------| +| value | str | Vendor name || +| nb_cves | int | Number of CVEs || +| nb_fingerprints | int | Number of fingerprint rules || +| nb_ips | int | Total number of unique IPs targeting this vendor || +| nb_ips_cves | int | Number of IPs across CVEs || +| nb_ips_fingerprints | int | Number of IPs across fingerprint rules || +| top_products | list[TopProductItem] | Top products for this vendor sorted by total IPs descending || \ No newline at end of file diff --git a/doc/Products.md b/doc/Products.md new file mode 100644 index 0000000..5e5e678 --- /dev/null +++ b/doc/Products.md @@ -0,0 +1,89 @@ + + +# Products Methods +| Method | Description | +| ------ | ----------- | +| [get_products](#get_products) | Get a paginated list of products | +| [get_product_impact](#get_product_impact) | Get CVE and fingerprint rules affecting a product | + +## **get_products** +### Get a paginated list of products +- Endpoint: `/products` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| query | Optional[str] | Search query for products | False | None | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupListWithStatsResponsePage](./Models.md#lookuplistwithstatsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Products, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Products(auth=auth) +try: + response = client.get_products( + query=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_product_impact** +### Get CVE and fingerprint rules affecting a product +- Endpoint: `/products/{product}` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| product | str | | True | | +| 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") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupImpactResponsePage](./Models.md#lookupimpactresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Products, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Products(auth=auth) +try: + response = client.get_product_impact( + product='product', + sort_by=rule_release_date, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/doc/README.md b/doc/README.md index 97e0a89..5c3aa07 100644 --- a/doc/README.md +++ b/doc/README.md @@ -17,6 +17,8 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [Integrations](./Integrations.md) +[Decisions](./Decisions.md) + [Info](./Info.md) [Metrics](./Metrics.md) @@ -25,6 +27,16 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [Cves](./Cves.md) +[Vendors](./Vendors.md) + +[Products](./Products.md) + +[TrackerTags](./TrackerTags.md) + +[Fingerprints](./Fingerprints.md) + +[TrackerEvents](./TrackerEvents.md) + ## API Endpoint models [AllowlistCreateRequest](./Models.md#allowlistcreaterequest) @@ -107,6 +119,8 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [Body_uploadBlocklistContent](./Models.md#body_uploadblocklistcontent) +[CVESubscription](./Models.md#cvesubscription) + [ComputedMetrics](./Models.md#computedmetrics) [ComputedSavedMetrics](./Models.md#computedsavedmetrics) @@ -123,8 +137,26 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [CtiScenario](./Models.md#ctiscenario) +[DecisionCreateRequest](./Models.md#decisioncreaterequest) + +[DecisionCreateResponse](./Models.md#decisioncreateresponse) + +[DecisionResponse](./Models.md#decisionresponse) + +[DecisionTargetModel](./Models.md#decisiontargetmodel) + +[DecisionTargetType](./Models.md#decisiontargettype) + +[DecisionsGetResponsePage](./Models.md#decisionsgetresponsepage) + +[DecisionsSortBy](./Models.md#decisionssortby) + +[DecisionsSortOrder](./Models.md#decisionssortorder) + [EntityType](./Models.md#entitytype) +[FingerprintSubscription](./Models.md#fingerprintsubscription) + [GetRemediationMetricsResponse](./Models.md#getremediationmetricsresponse) [HTTPValidationError](./Models.md#httpvalidationerror) @@ -179,6 +211,8 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [ValidationError](./Models.md#validationerror) +[VendorSubscription](./Models.md#vendorsubscription) + [AppsecConfigIndex](./Models.md#appsecconfigindex) [AppsecRuleIndex](./Models.md#appsecruleindex) @@ -197,32 +231,118 @@ You can find a Quickstart about this SDK, following this [documentation](https:/ [VersionDetail](./Models.md#versiondetail) +[AdjustmentScore](./Models.md#adjustmentscore) + [AffectedComponent](./Models.md#affectedcomponent) +[AllowlistSubscription](./Models.md#allowlistsubscription) + [AttackDetail](./Models.md#attackdetail) [Behavior](./Models.md#behavior) +[CVEEventOutput](./Models.md#cveeventoutput) + +[CVEExploitationPhase](./Models.md#cveexploitationphase) + +[CVEResponseBase](./Models.md#cveresponsebase) + +[CVEsubscription](./Models.md#cvesubscription) + +[CWE](./Models.md#cwe) + [Classification](./Models.md#classification) [Classifications](./Models.md#classifications) +[ExploitationPhase](./Models.md#exploitationphase) + +[ExploitationPhaseChangeEventItem](./Models.md#exploitationphasechangeeventitem) + +[ExploitationPhaseChangeEventsResponsePage](./Models.md#exploitationphasechangeeventsresponsepage) + +[FacetBucket](./Models.md#facetbucket) + +[FingerprintEventOutput](./Models.md#fingerprinteventoutput) + +[FingerprintRuleResponse](./Models.md#fingerprintruleresponse) + +[FingerprintRuleSummary](./Models.md#fingerprintrulesummary) + +[FingerprintTimelineItem](./Models.md#fingerprinttimelineitem) + [GetCVEIPsResponsePage](./Models.md#getcveipsresponsepage) +[GetCVEProtectRulesResponse](./Models.md#getcveprotectrulesresponse) + [GetCVEResponse](./Models.md#getcveresponse) +[GetCVESubscribedIntegrationsResponsePage](./Models.md#getcvesubscribedintegrationsresponsepage) + +[GetCVEsResponsePage](./Models.md#getcvesresponsepage) + +[GetCVEsSortBy](./Models.md#getcvessortby) + +[GetCVEsSortOrder](./Models.md#getcvessortorder) + +[GetFingerprintIPsResponsePage](./Models.md#getfingerprintipsresponsepage) + +[GetFingerprintRulesResponsePage](./Models.md#getfingerprintrulesresponsepage) + +[GetFingerprintSubscribedIntegrationsResponsePage](./Models.md#getfingerprintsubscribedintegrationsresponsepage) + +[GetVendorIPsResponsePage](./Models.md#getvendoripsresponsepage) + +[GetVendorSubscribedIntegrationsResponsePage](./Models.md#getvendorsubscribedintegrationsresponsepage) + [History](./Models.md#history) [IPItem](./Models.md#ipitem) +[IntegrationResponse](./Models.md#integrationresponse) + +[IntervalOptions](./Models.md#intervaloptions) + +[IpsDetailsStats](./Models.md#ipsdetailsstats) + [Location](./Models.md#location) +[LookupImpactCVEItem](./Models.md#lookupimpactcveitem) + +[LookupImpactFingerprintItem](./Models.md#lookupimpactfingerprintitem) + +[LookupImpactResponsePage](./Models.md#lookupimpactresponsepage) + +[LookupListItemWithStats](./Models.md#lookuplistitemwithstats) + +[LookupListWithStatsResponsePage](./Models.md#lookuplistwithstatsresponsepage) + [MitreTechnique](./Models.md#mitretechnique) +[ProtectRule](./Models.md#protectrule) + +[ProtectRuleTag](./Models.md#protectruletag) + [Reference](./Models.md#reference) [ScoreBreakdown](./Models.md#scorebreakdown) [Scores](./Models.md#scores) -[SubscribeCVEIntegrationRequest](./Models.md#subscribecveintegrationrequest) \ No newline at end of file +[SinceOptions](./Models.md#sinceoptions) + +[SubscribeCVEIntegrationRequest](./Models.md#subscribecveintegrationrequest) + +[SubscribeFingerprintIntegrationRequest](./Models.md#subscribefingerprintintegrationrequest) + +[SubscribeVendorIntegrationRequest](./Models.md#subscribevendorintegrationrequest) + +[ThreatContext](./Models.md#threatcontext) + +[TimelineItem](./Models.md#timelineitem) + +[TopProductItem](./Models.md#topproductitem) + +[VendorSortBy](./Models.md#vendorsortby) + +[VendorStatsResponse](./Models.md#vendorstatsresponse) \ No newline at end of file diff --git a/doc/TrackerEvents.md b/doc/TrackerEvents.md new file mode 100644 index 0000000..791e0f9 --- /dev/null +++ b/doc/TrackerEvents.md @@ -0,0 +1,53 @@ + + +# TrackerEvents Methods +| Method | Description | +| ------ | ----------- | +| [get_exploitation_phase_change_events](#get_exploitation_phase_change_events) | Get a paginated list of exploitation phase change events across tracked CVEs | + +## **get_exploitation_phase_change_events** +### Get a paginated list of exploitation phase change events across tracked CVEs +- Endpoint: `/tracker-events/exploitation-phase-change` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| since | str | Duration string (e.g. '30d', '24h') to filter events | False | "30d" | +| sort_order | Optional[GetCVEsSortOrder] | Sort order: ascending or descending | False | GetCVEsSortOrder("desc") | +| cve_id | Optional[str] | Filter by CVE identifier (exact match) | False | None | +| previous_phase | Optional[CVEExploitationPhase] | Filter by previous exploitation phase name | False | None | +| new_phase | Optional[CVEExploitationPhase] | Filter by new exploitation phase name | False | None | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[ExploitationPhaseChangeEventsResponsePage](./Models.md#exploitationphasechangeeventsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + TrackerEvents, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = TrackerEvents(auth=auth) +try: + response = client.get_exploitation_phase_change_events( + since=30d, + sort_order=desc, + cve_id=None, + previous_phase=None, + new_phase=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/doc/TrackerTags.md b/doc/TrackerTags.md new file mode 100644 index 0000000..72cb44d --- /dev/null +++ b/doc/TrackerTags.md @@ -0,0 +1,173 @@ + + +# TrackerTags Methods +| Method | Description | +| ------ | ----------- | +| [get_tags](#get_tags) | Get a paginated list of tags | +| [get_tag_impact](#get_tag_impact) | Get CVE and fingerprint rules affecting a tag | +| [get_tracker_tags](#get_tracker_tags) | Get a paginated list of tracker tags | +| [get_tracker_tag_impact](#get_tracker_tag_impact) | Get CVE and fingerprint rules affecting a tracker tag | + +## **get_tags** +### Get a paginated list of tags +- Endpoint: `/tags` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| query | Optional[str] | Search query for tags | False | None | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupListWithStatsResponsePage](./Models.md#lookuplistwithstatsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + TrackerTags, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = TrackerTags(auth=auth) +try: + response = client.get_tags( + query=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_tag_impact** +### Get CVE and fingerprint rules affecting a tag +- Endpoint: `/tags/{tag}` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| tag | str | | True | | +| 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") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupImpactResponsePage](./Models.md#lookupimpactresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + TrackerTags, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = TrackerTags(auth=auth) +try: + response = client.get_tag_impact( + tag='tag', + sort_by=rule_release_date, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_tracker_tags** +### Get a paginated list of tracker tags +- Endpoint: `/tracker-tags` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| query | Optional[str] | Search query for tags | False | None | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupListWithStatsResponsePage](./Models.md#lookuplistwithstatsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + TrackerTags, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = TrackerTags(auth=auth) +try: + response = client.get_tracker_tags( + query=None, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_tracker_tag_impact** +### Get CVE and fingerprint rules affecting a tracker tag +- Endpoint: `/tracker-tags/{tag}` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| tag | str | | True | | +| 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") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupImpactResponsePage](./Models.md#lookupimpactresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + TrackerTags, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = TrackerTags(auth=auth) +try: + response = client.get_tracker_tag_impact( + tag='tag', + sort_by=rule_release_date, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/doc/Vendors.md b/doc/Vendors.md new file mode 100644 index 0000000..9368be1 --- /dev/null +++ b/doc/Vendors.md @@ -0,0 +1,361 @@ + + +# Vendors Methods +| Method | Description | +| ------ | ----------- | +| [get_vendors](#get_vendors) | Get a paginated list of vendors | +| [get_vendor_stats](#get_vendor_stats) | Get statistics for a vendor including CVE/fingerprint counts, IP counts, and top affected products | +| [download_vendor_ips](#download_vendor_ips) | Download the list of IPs exploiting a specific vendor in raw format | +| [get_vendor_ips_details](#get_vendor_ips_details) | Get detailed information about IPs exploiting a specific vendor | +| [get_vendor_ips_details_stats](#get_vendor_ips_details_stats) | Get aggregated statistics about IPs exploiting a specific vendor | +| [get_vendor_subscribed_integrations](#get_vendor_subscribed_integrations) | Get the list of integrations subscribed to a specific vendor | +| [subscribe_integration_to_vendor](#subscribe_integration_to_vendor) | Subscribe an integration to receive threats related to a specific vendor | +| [unsubscribe_integration_from_vendor](#unsubscribe_integration_from_vendor) | Unsubscribe an integration from receiving threats related to a specific vendor | +| [get_vendor_impact](#get_vendor_impact) | Get CVE and fingerprint rules affecting a vendor | + +## **get_vendors** +### Get a paginated list of vendors +- Endpoint: `/vendors` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| query | Optional[str] | Search query for vendors | False | None | +| sort_by | Optional[VendorSortBy] | Sort by: value, nb_cves, nb_ips, latest_rule_release | False | None | +| sort_order | Optional[GetCVEsSortOrder] | Sort order: asc or desc | False | GetCVEsSortOrder("desc") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupListWithStatsResponsePage](./Models.md#lookuplistwithstatsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendors( + query=None, + sort_by=None, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_vendor_stats** +### Get statistics for a vendor including CVE/fingerprint counts, IP counts, and top affected products +- Endpoint: `/vendors/{vendor}/stats` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +### Returns: +[VendorStatsResponse](./Models.md#vendorstatsresponse) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendor_stats( + vendor='vendor', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **download_vendor_ips** +### Download the list of IPs exploiting a specific vendor in raw format +- Endpoint: `/vendors/{vendor}/ips-download` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +### Returns: +[str](./Models.md#str) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.download_vendor_ips( + vendor='vendor', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_vendor_ips_details** +### Get detailed information about IPs exploiting a specific vendor +- Endpoint: `/vendors/{vendor}/ips-details` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetVendorIPsResponsePage](./Models.md#getvendoripsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendor_ips_details( + vendor='vendor', + since=14d, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_vendor_ips_details_stats** +### Get aggregated statistics about IPs exploiting a specific vendor +- Endpoint: `/vendors/{vendor}/ips-details-stats` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +| since | Optional[str] | Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d | False | "14d" | +### Returns: +[IpsDetailsStats](./Models.md#ipsdetailsstats) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendor_ips_details_stats( + vendor='vendor', + since=14d, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_vendor_subscribed_integrations** +### Get the list of integrations subscribed to a specific vendor +- Endpoint: `/vendors/{vendor}/integrations` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[GetVendorSubscribedIntegrationsResponsePage](./Models.md#getvendorsubscribedintegrationsresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendor_subscribed_integrations( + vendor='vendor', + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **subscribe_integration_to_vendor** +### Subscribe an integration to receive threats related to a specific vendor +- Endpoint: `/vendors/{vendor}/integrations` +- Method: `POST` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| request | [SubscribeVendorIntegrationRequest](./Models.md#subscribevendorintegrationrequest) | Request body | Yes | - | +| vendor | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, + SubscribeVendorIntegrationRequest, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +request = SubscribeVendorIntegrationRequest( + name=None, +) +try: + response = client.subscribe_integration_to_vendor( + request=request, + vendor='vendor', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **unsubscribe_integration_from_vendor** +### Unsubscribe an integration from receiving threats related to a specific vendor +- Endpoint: `/vendors/{vendor}/integrations/{integration_name}` +- Method: `DELETE` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +| integration_name | str | | True | | +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.unsubscribe_integration_from_vendor( + vendor='vendor', + integration_name='integration_name', + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + + +## **get_vendor_impact** +### Get CVE and fingerprint rules affecting a vendor +- Endpoint: `/vendors/{vendor}` +- Method: `GET` + +### Parameters: +| Parameter | Type | Description | Required | Default | +| --------- | ---- | ----------- | -------- | ------- | +| vendor | str | | True | | +| 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") | +| page | int | Page number | False | 1 | +| size | int | Page size | False | 50 | +### Returns: +[LookupImpactResponsePage](./Models.md#lookupimpactresponsepage) +### Errors: +| Code | Description | +| ---- | ----------- | +| 422 | Validation Error | +### Usage + +```python +from crowdsec_service_api import ( + Vendors, + ApiKeyAuth, +) +from httpx import HTTPStatusError +auth = ApiKeyAuth(api_key='your_api_key') +client = Vendors(auth=auth) +try: + response = client.get_vendor_impact( + vendor='vendor', + sort_by=rule_release_date, + sort_order=desc, + page=1, + size=50, + ) + print(response) +except HTTPStatusError as e: + print(f"An error occurred: {e.response.status_code} - {e.response.text}") +``` + diff --git a/public-openapi.json b/public-openapi.json new file mode 100644 index 0000000..9d5ce94 --- /dev/null +++ b/public-openapi.json @@ -0,0 +1,13547 @@ +{ + "openapi": "3.1.0", + "info": { + "title": "Service API", + "description": "This is the API to manage Crowdsec services", + "version": "v0.15.25", + "contact": { + "name": "CrowdSec", + "url": "https://crowdsec.net", + "email": "info@crowdsec.net" + } + }, + "servers": [ + { + "url": "https://admin.api.crowdsec.net/v1", + "description": "Production server" + } + ], + "paths": { + "/allowlists": { + "post": { + "tags": [ + "Allowlists" + ], + "summary": "Create Allowlist", + "description": "Create a new allowlist for an organization", + "operationId": "createAllowlist", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistCreateResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Allowlists" + ], + "summary": "List Allowlists", + "description": "List all allowlists for an organization", + "operationId": "listAllowlists", + "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" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistGetResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/allowlists/{allowlist_id}": { + "get": { + "tags": [ + "Allowlists" + ], + "summary": "Get Allowlist", + "description": "Get an allowlist by ID", + "operationId": "getAllowlist", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistGetResponse" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Allowlists" + ], + "summary": "Update Allowlist", + "description": "Update an allowlist by ID", + "operationId": "updateAllowlist", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistUpdateResponse" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Allowlists" + ], + "summary": "Delete Allowlist", + "description": "Delete an allowlist by ID", + "operationId": "deleteAllowlist", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "name": "force", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Force delete the allowlist, even if it has subscribers", + "default": false, + "title": "Force" + }, + "description": "Force delete the allowlist, even if it has subscribers" + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/allowlists/{allowlist_id}/items": { + "post": { + "tags": [ + "Allowlists" + ], + "summary": "Create Allowlist Items", + "description": "Create items for an allowlist", + "operationId": "createAllowlistItems", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistItemsCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Allowlists" + ], + "summary": "Get Allowlist Items", + "description": "Get items in an allowlist", + "operationId": "getAllowlistItems", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistGetItemsResponsePage" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/allowlists/{allowlist_id}/items/{item_id}": { + "get": { + "tags": [ + "Allowlists" + ], + "summary": "Get Allowlist Item", + "description": "Get an allowlist item by ID", + "operationId": "getAllowlistItem", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "name": "item_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Item Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistGetItemsResponse" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Allowlists" + ], + "summary": "Update Allowlist Item", + "description": "Update an allowlist item by ID", + "operationId": "updateAllowlistItem", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "name": "item_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Item Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistItemUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistItemUpdateResponse" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Allowlists" + ], + "summary": "Delete Allowlist Item", + "description": "Delete an allowlist item by ID", + "operationId": "deleteAllowlistItem", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "name": "item_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Item Id" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/allowlists/{allowlist_id}/subscribers": { + "get": { + "tags": [ + "Allowlists" + ], + "summary": "Get Allowlist Subscribers", + "description": "Get subscribers of an allowlist", + "operationId": "getAllowlistSubscribers", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistSubscriberEntityPage" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "Allowlists" + ], + "summary": "Subscribe Allowlist", + "description": "Subscribe to an allowlist", + "operationId": "subscribeAllowlist", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistSubscriptionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AllowlistSubscriptionResponse" + } + } + } + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/allowlists/{allowlist_id}/subscribers/{entity_id}": { + "delete": { + "tags": [ + "Allowlists" + ], + "summary": "Unsubscribe Allowlist", + "description": "Unsubscribe from an allowlist", + "operationId": "unsubscribeAllowlist", + "parameters": [ + { + "name": "allowlist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Allowlist Id" + } + }, + { + "name": "entity_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Entity Id" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "404": { + "description": "Allowlist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Create Blocklist", + "description": "Create a new blocklist owned by your organization. The name must be unique within your organization. The list will only be visible to your organization and organizations you shared the blocklist with. This operation is submitted to quotas", + "operationId": "createBlocklist", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicBlocklistResponse" + } + } + } + }, + "409": { + "description": "Blocklist already exists" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Blocklists" + ], + "summary": "Get Blocklists", + "description": "Get multiple blocklists. Only blocklists owned by your organization, shared with your organization or public blocklists are returned. Filters and pagination are available as query parameters.", + "operationId": "getBlocklists", + "parameters": [ + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number", + "default": 1, + "title": "Page" + }, + "description": "Page number" + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 1000, + "description": "Page size", + "default": 100, + "title": "Page Size" + }, + "description": "Page size" + }, + { + "name": "subscribed_only", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "only subscribed blocklists", + "default": false, + "title": "Subscribed Only" + }, + "description": "only subscribed blocklists" + }, + { + "name": "exclude_subscribed", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "exclude subscribed blocklists", + "default": false, + "title": "Exclude Subscribed" + }, + "description": "exclude subscribed blocklists" + }, + { + "name": "include_filter", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BlocklistIncludeFilters" + }, + "description": "Include blocklists with the specified filters", + "default": [ + "private", + "shared" + ], + "title": "Include Filter" + }, + "description": "Include blocklists with the specified filters" + }, + { + "name": "category", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "Filter by category", + "title": "Category" + }, + "description": "Filter by category" + }, + { + "name": "size", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "maximum": 100, + "minimum": 1, + "description": "Page size", + "default": 50, + "title": "Size" + }, + "description": "Page size" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicBlocklistResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/search": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Search Blocklists", + "description": "Search blocklists", + "operationId": "searchBlocklist", + "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" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistSearchRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicBlocklistResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}": { + "get": { + "tags": [ + "Blocklists" + ], + "summary": "Get Blocklist", + "description": "Get the details of a blocklist by ID. The content of the blocklist is not returned.", + "operationId": "getBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicBlocklistResponse" + } + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Blocklists" + ], + "summary": "Update Blocklist", + "description": "Update a blocklist's details by ID. It is not possible to update the blocklist content using this operation.", + "operationId": "updateBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PublicBlocklistResponse" + } + } + } + }, + "403": { + "description": "Blocklist is read-only" + }, + "404": { + "description": "Blocklist not found" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Blocklists" + ], + "summary": "Delete Blocklist", + "description": "Delete a blocklist by ID. If the blocklist is shared with other organizations or it has subscriptions, the operation will fail. If you want to force delete the blocklist, you can use the force query parameter, so the blocklists will be unshared / unsubscribed.", + "operationId": "deleteBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "name": "force", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Force delete the blocklist if it is shared or subscribed", + "default": false, + "title": "Force" + }, + "description": "Force delete the blocklist if it is shared or subscribed" + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "404": { + "description": "Blocklist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/upload": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Upload Blocklist Content", + "description": "Upload a blocklist. The file must be in txt format with one IP per line. This operation will overwrite the existing blocklist content.", + "operationId": "uploadBlocklistContent", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "name": "expiration", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "description": "Blocklist expiration", + "examples": [ + "2026-04-13T08:55:24.249164+00:00" + ], + "title": "Expiration" + }, + "description": "Blocklist expiration" + }, + { + "name": "ignore_invalid_ips", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "description": "Ignore invalid IPs", + "default": false, + "title": "Ignore Invalid Ips" + }, + "description": "Ignore invalid IPs" + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "$ref": "#/components/schemas/Body_uploadBlocklistContent" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "400": { + "description": "Invalid IP in blocklist file content" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/ips": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Add Ips To Blocklist", + "description": "Add IPs to a blocklist. If an IP is already in the blocklist, its expiration will be updated with the new expiration.", + "operationId": "addIpsToBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistAddIPsRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "403": { + "description": "Blocklist is read-only" + }, + "404": { + "description": "Blocklist not found" + }, + "412": { + "description": "Payload too large for one operation, limit is 20000 IPs per request" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/ips/bulk_overwrite": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Bulk Overwrite Blocklist Ips", + "description": "Overwrite blocklist content", + "operationId": "overwriteIps", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistAddIPsRequest" + } + } + } + }, + "responses": { + "202": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "403": { + "description": "Blocklist is read-only" + }, + "404": { + "description": "Blocklist not found" + }, + "412": { + "description": "Payload too large for one operation, limit is 20000 IPs per request" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/ips/delete": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Delete Ips From Blocklist", + "description": "Delete IPs from a blocklist", + "operationId": "deleteIpsFromBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistDeleteIPsRequest" + } + } + } + }, + "responses": { + "204": { + "description": "Successful Response" + }, + "403": { + "description": "Blocklist is read-only" + }, + "404": { + "description": "Blocklist not found" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/download": { + "get": { + "tags": [ + "Blocklists" + ], + "summary": "Download Blocklist Content", + "description": "Download blocklist content as a list of ips as plain text separated by new lines. The response will include the ETag header for cache control. If_Modified_Since and If_None_Match cache control headers are supported for conditional requests.", + "operationId": "downloadBlocklistContent", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "name": "if-modified-since", + "in": "header", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "If_Modified_Since cache control header", + "title": "If-Modified-Since" + }, + "description": "If_Modified_Since cache control header" + }, + { + "name": "if-none-match", + "in": "header", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "If_None_Match cache control header", + "title": "If-None-Match" + }, + "description": "If_None_Match cache control header" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "204": { + "description": "Blocklist is empty" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/subscribers": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Subscribe Blocklist", + "description": "Subscribe to a blocklist with a remediation type. If the entity type is the full organization or a Tag, all the engines belonging to the organization or the Tag will be subscribed and new engines that will join the organization or the Tag will also be automatically subscribed. If the subscription has been done on an organization or Tag you cannot unsubscribe individual engines. In case of errors for some subscribers, the operation will still succeed for the entities that were successfully subscribed and you'll have the list of errors in the operation's result. This operation is submitted to quotas.", + "operationId": "subscribeBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistSubscriptionRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistSubscriptionResponse" + } + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Blocklists" + ], + "summary": "Get Blocklist Subscribers", + "description": "Get blocklist subscribers within your organization.", + "operationId": "getBlocklistSubscribers", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistSubscriberEntityPage" + } + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/subscribers/{entity_id}": { + "delete": { + "tags": [ + "Blocklists" + ], + "summary": "Unsubscribe Blocklist", + "description": "Unsubscribe from a blocklist. You cannot unsubscribe individual engines if the subscription has been done on an organization or Tag.", + "operationId": "unsubscribeBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "name": "entity_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Entity Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/shares": { + "post": { + "tags": [ + "Blocklists" + ], + "summary": "Share Blocklist", + "description": "Share a blocklist with other organizations given their IDs. The blocklist must be owned by your organization. You can give read-only access or read-write access to the blocklist. Sharing a blocklist will not automatically subscribe the shared organizations to the blocklist.", + "operationId": "shareBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/BlocklistShareRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Blocklist not found" + }, + "409": { + "description": "Blocklist is not private" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/blocklists/{blocklist_id}/shares/{unshare_organization_id}": { + "delete": { + "tags": [ + "Blocklists" + ], + "summary": "Unshare Blocklist", + "description": "Unshare a blocklist with other organizations. If the blocklist is subscribed by the organization, the operation will fail.Use force query parameter to unshare a blocklist even if subscriptions exists.", + "operationId": "unshareBlocklist", + "parameters": [ + { + "name": "blocklist_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Blocklist Id" + } + }, + { + "name": "unshare_organization_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Unshare Organization Id" + } + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "404": { + "description": "Blocklist not found" + }, + "409": { + "description": "Blocklist is not private" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/integrations": { + "post": { + "tags": [ + "Integrations" + ], + "summary": "Create Integration", + "description": "Create an integration to a firewall or remediation component, owned by your organization. The name should be unique within the organization. This operation is submitted to quotas.", + "operationId": "createIntegration", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationCreateResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Integrations" + ], + "summary": "Get Integrations", + "description": "Get integrations owned by your organization", + "operationId": "getIntegrations", + "parameters": [ + { + "name": "tag", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "array", + "items": { + "type": "string" + } + }, + { + "type": "null" + } + ], + "description": "List of tags associated with the integrations (any of)", + "title": "Tag" + }, + "description": "List of tags associated with the integrations (any of)" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationGetResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/integrations/{integration_id}": { + "get": { + "tags": [ + "Integrations" + ], + "summary": "Get Integration", + "description": "Get an integration by ID", + "operationId": "getIntegration", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationGetResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "patch": { + "tags": [ + "Integrations" + ], + "summary": "Update Integration", + "description": "Update the integration details", + "operationId": "updateIntegration", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationUpdateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IntegrationUpdateResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "delete": { + "tags": [ + "Integrations" + ], + "summary": "Delete Integration", + "description": "Delete the integration by ID", + "operationId": "deleteIntegration", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Id" + } + }, + { + "name": "force", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Force delete the integration even if it has active subscriptions (it will unsubscribe from all lists)", + "default": false, + "title": "Force" + }, + "description": "Force delete the integration even if it has active subscriptions (it will unsubscribe from all lists)" + } + ], + "responses": { + "204": { + "description": "Successful Response" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/integrations/{integration_id}/content": { + "head": { + "tags": [ + "Integrations" + ], + "summary": "Head Integration Content", + "description": "Check if the integration has content", + "operationId": "headIntegrationContent", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Integration Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Integration not found" + }, + "204": { + "description": "Integration has no subscribed blocklists or no content available" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Integrations" + ], + "summary": "Get Integration Content", + "description": "Get the ips associated to the integration in plain text format. The content can be paginated to accomodate limits in firewalls.", + "operationId": "getIntegrationContent", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Integration Id" + } + }, + { + "name": "page", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "minimum": 1, + "description": "Page number to return", + "default": 1, + "title": "Page" + }, + "description": "Page number to return" + }, + { + "name": "page_size", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "integer", + "minimum": 10000 + }, + { + "type": "null" + } + ], + "description": "Maximum number of items to return, 0 means no limit (default), should be greater than 10000", + "title": "Page Size" + }, + "description": "Maximum number of items to return, 0 means no limit (default), should be greater than 10000" + }, + { + "name": "pull_limit", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit" + } + }, + { + "name": "enable_ip_aggregation", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false, + "title": "Enable Ip Aggregation" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "Integration not found" + }, + "204": { + "description": "Integration has no subscribed blocklists or no content available" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/integrations/{integration_id}/v1/decisions/stream": { + "get": { + "tags": [ + "Integrations" + ], + "summary": "Get Integration Content Stream", + "description": "Get the ips associated to the integration in a format compatible with a remediation component. As for the remediation components, you can fetch the full content with startup=true or only the changes since the last pull", + "operationId": "getIntegrationContentStream", + "parameters": [ + { + "name": "integration_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "format": "ObjectId", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ], + "title": "Integration Id" + } + }, + { + "name": "startup", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "description": "Set to true if it's the first run to fetch all the content, otherwise only changes since the last pull.", + "default": false, + "title": "Startup" + }, + "description": "Set to true if it's the first run to fetch all the content, otherwise only changes since the last pull." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Integration not found" + }, + "204": { + "description": "Integration has no subscribed blocklists or no content available" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/decisions": { + "get": { + "tags": [ + "Decisions" + ], + "summary": "Get Decisions", + "description": "Get decisions", + "operationId": "getDecisions", + "parameters": [ + { + "name": "instance_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Filter decisions by instance IDs", + "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", + "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", + "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)", + "default": [], + "title": "Ips" + }, + "description": "Filter decisions by IPs (only for IP decisions)" + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/DecisionsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by (e.g., created_at, duration)", + "default": "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", + "default": "desc", + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DecisionsGetResponsePage" + } + } + } + }, + "404": { + "description": "Not found" + }, + "500": { + "description": "Internal server error" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "post": { + "tags": [ + "Decisions" + ], + "summary": "Create Decision", + "description": "Create a new decision.", + "operationId": "createDecision", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DecisionCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DecisionCreateResponse" + } + } + } + }, + "409": { + "description": "Conflict: Decision value is in allowlists; cannot create decision." + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/info": { + "get": { + "tags": [ + "Info" + ], + "summary": "Get Me Info", + "description": "Get the current user and organization informations", + "operationId": "getInfo", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/InfoResponse" + } + } + } + } + } + } + }, + "/metrics/remediation": { + "get": { + "tags": [ + "Metrics" + ], + "summary": "Get Metrics Remediation", + "description": "Get remediation metrics", + "operationId": "getMetricsRemediation", + "parameters": [ + { + "name": "start_date", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time", + "description": "Start date of the metrics, default to last day", + "title": "Start Date" + }, + "description": "Start date of the metrics, default to last day" + }, + { + "name": "end_date", + "in": "query", + "required": false, + "schema": { + "type": "string", + "format": "date-time", + "description": "End date of the metrics", + "title": "End Date" + }, + "description": "End date of the metrics" + }, + { + "name": "engine_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of engine ids", + "default": [], + "title": "Engine Ids" + }, + "description": "List of engine ids" + }, + { + "name": "integration_ids", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of integration ids", + "default": [], + "title": "Integration Ids" + }, + "description": "List of integration ids" + }, + { + "name": "tags", + "in": "query", + "required": false, + "schema": { + "type": "array", + "items": { + "type": "string" + }, + "description": "List of tags", + "default": [], + "title": "Tags" + }, + "description": "List of tags" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetRemediationMetricsResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/hub/index/{tenant}/{branch}/.index.json": { + "get": { + "description": "Get a (minimized) index file for 'cscli hub update'. May or may not include unused fields\n(content, long descriptions, labels...) or redundant ones (author, name).", + "operationId": "getIndex", + "parameters": [ + { + "in": "path", + "name": "branch", + "required": true, + "schema": { + "title": "Branch", + "type": "string" + } + }, + { + "in": "path", + "name": "tenant", + "required": true, + "schema": { + "title": "Tenant", + "type": "string" + } + }, + { + "description": "Include content in the index", + "in": "query", + "name": "with_content", + "required": false, + "schema": { + "default": false, + "description": "Include content in the index", + "title": "With Content", + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Index" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Get a minimized index file (crowdsec only)", + "tags": [ + "Hub" + ] + }, + "head": { + "description": "This endpoint returns cache-related headers for the index file without the full content.\nIt is useful for validating cache, checking resource freshness, and managing client-side\ncache expiration policies. No body content is returned.", + "operationId": "headIndex", + "parameters": [ + { + "in": "path", + "name": "branch", + "required": true, + "schema": { + "title": "Branch", + "type": "string" + } + }, + { + "in": "path", + "name": "tenant", + "required": true, + "schema": { + "title": "Tenant", + "type": "string" + } + }, + { + "description": "Include content in the index", + "in": "query", + "name": "with_content", + "required": false, + "schema": { + "default": false, + "description": "Include content in the index", + "title": "With Content", + "type": "boolean" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Index" + } + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Check cache control headers for the index file", + "tags": [ + "Hub" + ] + } + }, + "/hub/index/{tenant}/{branch}/{item_path}": { + "get": { + "description": "Get an item's content from its path. This is usually a YAML file.", + "operationId": "getItemContent", + "parameters": [ + { + "in": "path", + "name": "item_path", + "required": true, + "schema": { + "title": "Item Path", + "type": "string" + } + }, + { + "in": "path", + "name": "branch", + "required": true, + "schema": { + "title": "Branch", + "type": "string" + } + }, + { + "in": "path", + "name": "tenant", + "required": true, + "schema": { + "title": "Tenant", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "404": { + "description": "No content field" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Get an item's content (crowdsec only)", + "tags": [ + "Hub" + ] + }, + "head": { + "description": "This endpoint returns cache-related headers for an item's content. It is useful for validating\ncache, checking resource freshness, and managing client-side cache expiration policies. No body\ncontent is returned.", + "operationId": "headItemContent", + "parameters": [ + { + "in": "path", + "name": "item_path", + "required": true, + "schema": { + "title": "Item Path", + "type": "string" + } + }, + { + "in": "path", + "name": "branch", + "required": true, + "schema": { + "title": "Branch", + "type": "string" + } + }, + { + "in": "path", + "name": "tenant", + "required": true, + "schema": { + "title": "Tenant", + "type": "string" + } + } + ], + "responses": { + "200": { + "content": { + "application/json": { + "schema": {} + } + }, + "description": "Successful Response" + }, + "422": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + }, + "description": "Validation Error" + } + }, + "summary": "Check cache control headers for an item's content", + "tags": [ + "Hub" + ] + } + }, + "/cves": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get list of CVEs CrowdSec is tracking", + "description": "Get a paginated list of CVEs that CrowdSec is tracking", + "operationId": "getCves", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for CVEs", + "title": "Query" + }, + "description": "Search query for CVEs" + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or descending" + }, + { + "name": "exploitation_phase", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/CVEExploitationPhase" + }, + { + "type": "null" + } + ], + "description": "Filter by exploitation phase", + "title": "Exploitation Phase" + }, + "description": "Filter by exploitation phase" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCVEsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get CVE ID informations", + "description": "Get information about a specific CVE ID", + "operationId": "getCve", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCVEResponse" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/protect-rules": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get protection rules for a CVE ID", + "description": "Get protection/detection rules associated with a specific CVE ID", + "operationId": "getCveProtectRules", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCVEProtectRulesResponse" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/ips-download": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Download IPs exploiting a CVE ID (raw)", + "description": "Download the list of IPs exploiting a specific CVE ID in raw format", + "operationId": "downloadCveIps", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/ips-details": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get IPs details exploiting a CVE ID", + "description": "Get detailed information about IPs exploiting a specific CVE ID", + "operationId": "getCveIpsDetails", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCVEIPsResponsePage" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/ips-details-stats": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get stats about IPs exploiting a CVE ID", + "description": "Get aggregated statistics about IPs exploiting a specific CVE ID", + "operationId": "getCveIpsDetailsStats", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpsDetailsStats" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/integrations": { + "post": { + "tags": [ + "Cves" + ], + "summary": "Subscribe an integration to a CVE ID", + "description": "Subscribe an integration to receive threats related to a specific CVE ID", + "operationId": "subscribeIntegrationToCve", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscribeCVEIntegrationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Integration Not Found" + }, + "400": { + "description": "CVE Already Subscribed" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Cves" + ], + "summary": "Get subscribed integrations for a CVE ID", + "description": "Get the list of integrations subscribed to a specific CVE ID", + "operationId": "getCveSubscribedIntegrations", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCVESubscribedIntegrationsResponsePage" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/integrations/{integration_name}": { + "delete": { + "tags": [ + "Cves" + ], + "summary": "Unsubscribe an integration from a CVE ID", + "description": "Unsubscribe an integration from receiving threats related to a specific CVE ID", + "operationId": "unsubscribeIntegrationFromCve", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + }, + { + "name": "integration_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "404": { + "description": "Integration Not Found" + }, + "400": { + "description": "CVE Already Unsubscribed" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/cves/{cve_id}/timeline": { + "get": { + "tags": [ + "Cves" + ], + "summary": "Get timeline data for a CVE ID", + "description": "Get timeline data of occurrences for a specific CVE ID", + "operationId": "getCveTimeline", + "parameters": [ + { + "name": "cve_id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Cve Id" + } + }, + { + "name": "since_days", + "in": "query", + "required": false, + "schema": { + "$ref": "#/components/schemas/SinceOptions", + "description": "Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days.", + "default": 7 + }, + "description": "Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TimelineItem" + }, + "title": "Response Getcvetimeline" + } + } + } + }, + "404": { + "description": "CVE Not Found" + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get list of vendors", + "description": "Get a paginated list of vendors", + "operationId": "getVendors", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for vendors", + "title": "Query" + }, + "description": "Search query for vendors" + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/VendorSortBy" + }, + { + "type": "null" + } + ], + "description": "Sort by: value, nb_cves, nb_ips, latest_rule_release", + "title": "Sort By" + }, + "description": "Sort by: value, nb_cves, nb_ips, latest_rule_release" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: asc or desc", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: asc or desc" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupListWithStatsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/stats": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get vendor statistics", + "description": "Get statistics for a vendor including CVE/fingerprint counts, IP counts, and top affected products", + "operationId": "getVendorStats", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/VendorStatsResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/ips-download": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Download IPs exploiting a vendor (raw)", + "description": "Download the list of IPs exploiting a specific vendor in raw format", + "operationId": "downloadVendorIps", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/ips-details": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get IP details exploiting a vendor", + "description": "Get detailed information about IPs exploiting a specific vendor", + "operationId": "getVendorIpsDetails", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetVendorIPsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/ips-details-stats": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get stats about IPs exploiting a vendor", + "description": "Get aggregated statistics about IPs exploiting a specific vendor", + "operationId": "getVendorIpsDetailsStats", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpsDetailsStats" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/integrations": { + "post": { + "tags": [ + "Vendors" + ], + "summary": "Subscribe an integration to a vendor", + "description": "Subscribe an integration to receive threats related to a specific vendor", + "operationId": "subscribeIntegrationToVendor", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscribeVendorIntegrationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get subscribed integrations for a vendor", + "description": "Get the list of integrations subscribed to a specific vendor", + "operationId": "getVendorSubscribedIntegrations", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetVendorSubscribedIntegrationsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}/integrations/{integration_name}": { + "delete": { + "tags": [ + "Vendors" + ], + "summary": "Unsubscribe an integration from a vendor", + "description": "Unsubscribe an integration from receiving threats related to a specific vendor", + "operationId": "unsubscribeIntegrationFromVendor", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + }, + { + "name": "integration_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/vendors/{vendor}": { + "get": { + "tags": [ + "Vendors" + ], + "summary": "Get vendor impact", + "description": "Get CVE and fingerprint rules affecting a vendor", + "operationId": "getVendorImpact", + "parameters": [ + { + "name": "vendor", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Vendor" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or 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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupImpactResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/products": { + "get": { + "tags": [ + "Products" + ], + "summary": "Get list of products", + "description": "Get a paginated list of products", + "operationId": "getProducts", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for products", + "title": "Query" + }, + "description": "Search query for products" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupListWithStatsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/products/{product}": { + "get": { + "tags": [ + "Products" + ], + "summary": "Get product impact", + "description": "Get CVE and fingerprint rules affecting a product", + "operationId": "getProductImpact", + "parameters": [ + { + "name": "product", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Product" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or 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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupImpactResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tags": { + "get": { + "tags": [ + "Tracker Tags" + ], + "summary": "Get list of tags", + "description": "Get a paginated list of tags", + "operationId": "getTags", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for tags", + "title": "Query" + }, + "description": "Search query for tags" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupListWithStatsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tags/{tag}": { + "get": { + "tags": [ + "Tracker Tags" + ], + "summary": "Get tag impact", + "description": "Get CVE and fingerprint rules affecting a tag", + "operationId": "getTagImpact", + "parameters": [ + { + "name": "tag", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Tag" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or 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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupImpactResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tracker-tags": { + "get": { + "tags": [ + "Tracker Tags" + ], + "summary": "Get list of tracker tags", + "description": "Get a paginated list of tracker tags", + "operationId": "getTrackerTags", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for tags", + "title": "Query" + }, + "description": "Search query for tags" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupListWithStatsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tracker-tags/{tag}": { + "get": { + "tags": [ + "Tracker Tags" + ], + "summary": "Get tracker tag impact", + "description": "Get CVE and fingerprint rules affecting a tracker tag", + "operationId": "getTrackerTagImpact", + "parameters": [ + { + "name": "tag", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Tag" + } + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or 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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/LookupImpactResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get list of fingerprint rules", + "description": "Get a paginated list of fingerprint rules", + "operationId": "getFingerprintRules", + "parameters": [ + { + "name": "query", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Search query for fingerprint rules", + "title": "Query" + }, + "description": "Search query for fingerprint rules" + }, + { + "name": "sort_by", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortBy" + }, + { + "type": "null" + } + ], + "description": "Field to sort by", + "default": "rule_release_date", + "title": "Sort By" + }, + "description": "Field to sort by" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or 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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetFingerprintRulesResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/ips-download": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Download IPs exploiting a fingerprint rule (raw)", + "description": "Download the list of IPs exploiting a specific fingerprint rule in raw format", + "operationId": "downloadFingerprintIps", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/ips-details": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get IP details exploiting a fingerprint rule", + "description": "Get detailed information about IPs exploiting a specific fingerprint rule", + "operationId": "getFingerprintIpsDetails", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetFingerprintIPsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/ips-details-stats": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get stats about IPs exploiting a fingerprint rule", + "description": "Get aggregated statistics about IPs exploiting a specific fingerprint rule", + "operationId": "getFingerprintIpsDetailsStats", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + }, + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string", + "pattern": "^\\d+[hd]$" + }, + { + "type": "null" + } + ], + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d", + "default": "14d", + "title": "Since" + }, + "description": "Filter IPs seen since this date, format duration (e.g., 7d, 24h), default to 14d" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/IpsDetailsStats" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/integrations": { + "post": { + "tags": [ + "Fingerprints" + ], + "summary": "Subscribe an integration to a fingerprint rule", + "description": "Subscribe an integration to receive threats related to a specific fingerprint rule", + "operationId": "subscribeIntegrationToFingerprint", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SubscribeFingerprintIntegrationRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + }, + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get subscribed integrations for a fingerprint rule", + "description": "Get the list of integrations subscribed to a specific fingerprint rule", + "operationId": "getFingerprintSubscribedIntegrations", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetFingerprintSubscribedIntegrationsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/integrations/{integration_name}": { + "delete": { + "tags": [ + "Fingerprints" + ], + "summary": "Unsubscribe an integration from a fingerprint rule", + "description": "Unsubscribe an integration from receiving threats related to a specific fingerprint rule", + "operationId": "unsubscribeIntegrationFromFingerprint", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + }, + { + "name": "integration_name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Integration Name" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": {} + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}/timeline": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get timeline data for a fingerprint rule", + "description": "Get timeline data of occurrences for a specific fingerprint rule", + "operationId": "getFingerprintTimeline", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + }, + { + "name": "since_days", + "in": "query", + "required": false, + "schema": { + "$ref": "#/components/schemas/SinceOptions", + "description": "Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days.", + "default": 7 + }, + "description": "Time range for the timeline data (in days). Options: 1 (1 day), 7 (1 week), 30 (1 month). Default is 7 days." + }, + { + "name": "interval", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/IntervalOptions" + }, + { + "type": "null" + } + ], + "description": "Interval for aggregating timeline data. Options: 'hour', 'day', 'week'. Default is adapted based on 'since' parameter.", + "title": "Interval" + }, + "description": "Interval for aggregating timeline data. Options: 'hour', 'day', 'week'. Default is adapted based on 'since' parameter." + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/FingerprintTimelineItem" + }, + "title": "Response Getfingerprinttimeline" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/fingerprints/{fingerprint}": { + "get": { + "tags": [ + "Fingerprints" + ], + "summary": "Get fingerprint rule information", + "description": "Get information about a specific fingerprint rule", + "operationId": "getFingerprintRule", + "parameters": [ + { + "name": "fingerprint", + "in": "path", + "required": true, + "schema": { + "type": "string", + "title": "Fingerprint" + } + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FingerprintRuleResponse" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + }, + "/tracker-events/exploitation-phase-change": { + "get": { + "tags": [ + "Tracker events" + ], + "summary": "Get exploitation phase change events", + "description": "Get a paginated list of exploitation phase change events across tracked CVEs", + "operationId": "getExploitationPhaseChangeEvents", + "parameters": [ + { + "name": "since", + "in": "query", + "required": false, + "schema": { + "type": "string", + "description": "Duration string (e.g. '30d', '24h') to filter events", + "default": "30d", + "title": "Since" + }, + "description": "Duration string (e.g. '30d', '24h') to filter events" + }, + { + "name": "sort_order", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/GetCVEsSortOrder" + }, + { + "type": "null" + } + ], + "description": "Sort order: ascending or descending", + "default": "desc", + "title": "Sort Order" + }, + "description": "Sort order: ascending or descending" + }, + { + "name": "cve_id", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Filter by CVE identifier (exact match)", + "title": "Cve Id" + }, + "description": "Filter by CVE identifier (exact match)" + }, + { + "name": "previous_phase", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/CVEExploitationPhase" + }, + { + "type": "null" + } + ], + "description": "Filter by previous exploitation phase name", + "title": "Previous Phase" + }, + "description": "Filter by previous exploitation phase name" + }, + { + "name": "new_phase", + "in": "query", + "required": false, + "schema": { + "anyOf": [ + { + "$ref": "#/components/schemas/CVEExploitationPhase" + }, + { + "type": "null" + } + ], + "description": "Filter by new exploitation phase name", + "title": "New Phase" + }, + "description": "Filter by new exploitation phase name" + }, + { + "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": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExploitationPhaseChangeEventsResponsePage" + } + } + } + }, + "422": { + "description": "Validation Error", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/HTTPValidationError" + } + } + } + } + } + } + } + }, + "components": { + "schemas": { + "AllowlistCreateRequest": { + "properties": { + "name": { + "type": "string", + "maxLength": 200, + "minLength": 1, + "title": "Name", + "description": "Name of the allowlist" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Description of the allowlist" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "title": "AllowlistCreateRequest" + }, + "AllowlistCreateResponse": { + "properties": { + "id": { + "type": "string", + "format": "ObjectId", + "title": "Id", + "description": "ID of the allowlist", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the allowlist" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the allowlist" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the allowlist was created" + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At", + "description": "Time the allowlist was updated" + }, + "from_cti_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "From Cti Query", + "description": "CTI query from which the blocklist was created" + }, + "since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Since", + "description": "Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days" + }, + "total_items": { + "type": "integer", + "title": "Total Items", + "description": "Number of items in the allowlist" + } + }, + "type": "object", + "required": [ + "id", + "organization_id", + "name", + "created_at", + "total_items" + ], + "title": "AllowlistCreateResponse" + }, + "AllowlistGetItemsResponse": { + "properties": { + "id": { + "type": "string", + "format": "ObjectId", + "title": "Id", + "description": "ID of the allowlist entry", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "allowlist_id": { + "type": "string", + "format": "ObjectId", + "title": "Allowlist Id", + "description": "ID of the allowlist", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "description": { + "type": "string", + "minLength": 1, + "title": "Description", + "description": "Description of the allowlist entry" + }, + "scope": { + "$ref": "#/components/schemas/AllowlistScope", + "description": "Scope of the allowlist entry" + }, + "value": { + "anyOf": [ + { + "type": "string", + "format": "ipvanyaddress" + }, + { + "type": "string", + "format": "ipvanynetwork" + } + ], + "title": "Value", + "description": "Value of the allowlist entry" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the allowlist entry was created" + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At", + "description": "Time the allowlist entry was updated" + }, + "created_by": { + "$ref": "#/components/schemas/SourceInfo", + "description": "The source user who created the allowlist entry" + }, + "updated_by": { + "anyOf": [ + { + "$ref": "#/components/schemas/SourceInfo" + }, + { + "type": "null" + } + ], + "description": "The source user who updated the allowlist entry" + }, + "expiration": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Expiration", + "description": "Time the allowlist entry will expire" + } + }, + "type": "object", + "required": [ + "id", + "allowlist_id", + "description", + "scope", + "value", + "created_at", + "created_by" + ], + "title": "AllowlistGetItemsResponse" + }, + "AllowlistGetItemsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AllowlistGetItemsResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "AllowlistGetItemsResponsePage" + }, + "AllowlistGetResponse": { + "properties": { + "id": { + "type": "string", + "format": "ObjectId", + "title": "Id", + "description": "ID of the allowlist", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the allowlist" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the allowlist" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the allowlist was created" + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At", + "description": "Time the allowlist was updated" + }, + "from_cti_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "From Cti Query", + "description": "CTI query from which the blocklist was created" + }, + "since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Since", + "description": "Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days" + }, + "total_items": { + "type": "integer", + "title": "Total Items", + "description": "Number of items in the allowlist" + }, + "subscribers": { + "items": { + "$ref": "#/components/schemas/AllowlistSubscribersCount" + }, + "type": "array", + "title": "Subscribers", + "description": "List of subscribers count by entity type", + "default": [] + } + }, + "type": "object", + "required": [ + "id", + "organization_id", + "name", + "created_at", + "total_items" + ], + "title": "AllowlistGetResponse" + }, + "AllowlistGetResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AllowlistGetResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "AllowlistGetResponsePage" + }, + "AllowlistItemUpdateRequest": { + "properties": { + "description": { + "type": "string", + "title": "Description", + "description": "Description of the allowlist entry" + }, + "expiration": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Expiration", + "description": "Time the allowlist entry will expire" + } + }, + "additionalProperties": false, + "type": "object", + "title": "AllowlistItemUpdateRequest" + }, + "AllowlistItemUpdateResponse": { + "properties": { + "id": { + "type": "string", + "format": "ObjectId", + "title": "Id", + "description": "ID of the allowlist entry", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "allowlist_id": { + "type": "string", + "format": "ObjectId", + "title": "Allowlist Id", + "description": "ID of the allowlist", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "description": { + "type": "string", + "minLength": 1, + "title": "Description", + "description": "Description of the allowlist entry" + }, + "scope": { + "$ref": "#/components/schemas/AllowlistScope", + "description": "Scope of the allowlist entry" + }, + "value": { + "anyOf": [ + { + "type": "string", + "format": "ipvanyaddress" + }, + { + "type": "string", + "format": "ipvanynetwork" + } + ], + "title": "Value", + "description": "Value of the allowlist entry" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the allowlist entry was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Time the allowlist entry was updated" + }, + "created_by": { + "$ref": "#/components/schemas/SourceInfo", + "description": "The source user who created the allowlist entry" + }, + "updated_by": { + "$ref": "#/components/schemas/SourceInfo", + "description": "The source user who updated the allowlist entry" + }, + "expiration": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Expiration", + "description": "Time the allowlist entry will expire" + } + }, + "type": "object", + "required": [ + "id", + "allowlist_id", + "description", + "scope", + "value", + "created_at", + "updated_at", + "created_by", + "updated_by" + ], + "title": "AllowlistItemUpdateResponse" + }, + "AllowlistItemsCreateRequest": { + "properties": { + "items": { + "items": { + "anyOf": [ + { + "type": "string", + "format": "ipvanyaddress" + }, + { + "type": "string", + "format": "ipvanynetwork" + } + ] + }, + "type": "array", + "title": "Items", + "description": "List of values to add to the allowlist" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the allowlist entry" + }, + "expiration": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Expiration", + "description": "Time the allowlist entry will expire" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "items", + "description" + ], + "title": "AllowlistItemsCreateRequest" + }, + "AllowlistScope": { + "type": "string", + "enum": [ + "ip", + "range" + ], + "title": "AllowlistScope" + }, + "AllowlistSubscriberEntity": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Subscriber entity id" + }, + "entity_type": { + "$ref": "#/components/schemas/SubscriberEntityType" + } + }, + "type": "object", + "required": [ + "id", + "entity_type" + ], + "title": "AllowlistSubscriberEntity" + }, + "AllowlistSubscriberEntityPage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/AllowlistSubscriberEntity" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "AllowlistSubscriberEntityPage" + }, + "AllowlistSubscribersCount": { + "properties": { + "entity_type": { + "$ref": "#/components/schemas/SubscriberEntityType", + "description": "Subscriber entity type" + }, + "count": { + "type": "integer", + "title": "Count", + "description": "Subscriber entity count" + } + }, + "type": "object", + "required": [ + "entity_type", + "count" + ], + "title": "AllowlistSubscribersCount" + }, + "AllowlistSubscriptionRequest": { + "properties": { + "ids": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Ids", + "description": "List of subscriber entity id" + }, + "entity_type": { + "$ref": "#/components/schemas/EntityType" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "entity_type" + ], + "title": "AllowlistSubscriptionRequest" + }, + "AllowlistSubscriptionResponse": { + "properties": { + "updated": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Updated", + "description": "List of updated allowlist ids", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "errors": { + "anyOf": [ + { + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Errors", + "description": "List of errors if any", + "examples": [ + { + "5f9d88b9e5c4f5b9a3d3e8b1": "error message" + } + ] + } + }, + "type": "object", + "required": [ + "updated", + "errors" + ], + "title": "AllowlistSubscriptionResponse" + }, + "AllowlistUpdateRequest": { + "properties": { + "name": { + "anyOf": [ + { + "type": "string", + "maxLength": 200, + "minLength": 1 + }, + { + "type": "null" + } + ], + "title": "Name", + "description": "Name of the allowlist" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Description of the allowlist" + } + }, + "additionalProperties": false, + "type": "object", + "title": "AllowlistUpdateRequest" + }, + "AllowlistUpdateResponse": { + "properties": { + "id": { + "type": "string", + "format": "ObjectId", + "title": "Id", + "description": "ID of the allowlist", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the allowlist" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the allowlist" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the allowlist was created" + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At", + "description": "Time the allowlist was updated" + }, + "from_cti_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "From Cti Query", + "description": "CTI query from which the blocklist was created" + }, + "since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Since", + "description": "Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days" + }, + "total_items": { + "type": "integer", + "title": "Total Items", + "description": "Number of items in the allowlist" + }, + "subscribers": { + "items": { + "$ref": "#/components/schemas/AllowlistSubscribersCount" + }, + "type": "array", + "title": "Subscribers", + "description": "List of subscribers count by entity type", + "default": [] + } + }, + "type": "object", + "required": [ + "id", + "organization_id", + "name", + "created_at", + "total_items" + ], + "title": "AllowlistUpdateResponse" + }, + "ApiKeyCredentials": { + "properties": { + "api_key": { + "type": "string", + "title": "Api Key", + "description": "API key for the integration" + } + }, + "type": "object", + "required": [ + "api_key" + ], + "title": "ApiKeyCredentials" + }, + "AttacksMetrics": { + "properties": { + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "Total", + "description": "Total value of the metric" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Label of the metric which is the attack type" + }, + "progression": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Progression", + "description": "Progression of the metric value from the previous period" + }, + "data": { + "items": { + "$ref": "#/components/schemas/RemediationMetricsData" + }, + "type": "array", + "title": "Data", + "description": "Data points" + } + }, + "type": "object", + "required": [ + "total", + "label", + "progression", + "data" + ], + "title": "AttacksMetrics" + }, + "BasicAuthCredentials": { + "properties": { + "username": { + "type": "string", + "title": "Username", + "description": "Basic auth username for the integration" + }, + "password": { + "type": "string", + "title": "Password", + "description": "Basic auth password for the integration" + } + }, + "type": "object", + "required": [ + "username", + "password" + ], + "title": "BasicAuthCredentials" + }, + "BlocklistAddIPsRequest": { + "properties": { + "ips": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Ips", + "description": "List of IPs or networks" + }, + "expiration": { + "type": "string", + "format": "date-time", + "title": "Expiration", + "description": "Expiration date", + "examples": [ + "2030-01-01T00:00:00.000Z" + ] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "ips" + ], + "title": "BlocklistAddIPsRequest" + }, + "BlocklistCategory": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "label": { + "type": "string", + "title": "Label" + }, + "description": { + "type": "string", + "title": "Description" + }, + "priority": { + "type": "integer", + "title": "Priority" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description", + "priority" + ], + "title": "BlocklistCategory" + }, + "BlocklistContentStats": { + "properties": { + "total_seen": { + "type": "integer", + "title": "Total Seen", + "default": 0 + }, + "total_fire": { + "type": "integer", + "title": "Total Fire", + "default": 0 + }, + "total_seen_1m": { + "type": "integer", + "title": "Total Seen 1M", + "default": 0 + }, + "total_in_other_lists": { + "type": "integer", + "title": "Total In Other Lists", + "default": 0 + }, + "total_false_positive": { + "type": "integer", + "title": "Total False Positive", + "default": 0 + }, + "false_positive_removed_by_crowdsec": { + "type": "integer", + "title": "False Positive Removed By Crowdsec", + "default": 0 + }, + "most_present_behaviors": { + "items": { + "$ref": "#/components/schemas/CtiBehavior" + }, + "type": "array", + "title": "Most Present Behaviors", + "default": [] + }, + "most_present_categories": { + "items": { + "$ref": "#/components/schemas/CtiCategory" + }, + "type": "array", + "title": "Most Present Categories", + "default": [] + }, + "most_present_scenarios": { + "items": { + "$ref": "#/components/schemas/CtiScenario" + }, + "type": "array", + "title": "Most Present Scenarios", + "default": [] + }, + "top_as": { + "items": { + "$ref": "#/components/schemas/CtiAs" + }, + "type": "array", + "title": "Top As", + "default": [] + }, + "top_attacking_countries": { + "items": { + "$ref": "#/components/schemas/CtiCountry" + }, + "type": "array", + "title": "Top Attacking Countries", + "default": [] + }, + "top_ips": { + "items": { + "$ref": "#/components/schemas/CtiIp" + }, + "type": "array", + "title": "Top Ips", + "default": [] + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "additionalProperties": true, + "type": "object", + "title": "BlocklistContentStats" + }, + "BlocklistCreateRequest": { + "properties": { + "name": { + "type": "string", + "maxLength": 200, + "minLength": 1, + "title": "Name", + "description": "Blocklist name, must be unique within the organization" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Blocklist human readable name (Default: name)" + }, + "description": { + "type": "string", + "minLength": 1, + "title": "Description", + "description": "Blocklist description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Useful references on the list's origins", + "default": [] + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Classification tags", + "default": [] + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name", + "description" + ], + "title": "BlocklistCreateRequest" + }, + "BlocklistDeleteIPsRequest": { + "properties": { + "ips": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Ips", + "description": "List of IPs or networks" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "ips" + ], + "title": "BlocklistDeleteIPsRequest" + }, + "BlocklistIncludeFilters": { + "type": "string", + "enum": [ + "public", + "private", + "shared", + "all" + ], + "title": "BlocklistIncludeFilters" + }, + "BlocklistOrigin": { + "properties": { + "label": { + "type": "string", + "title": "Label", + "description": "Label of the blocklist" + }, + "id": { + "type": "string", + "title": "Id", + "description": "ID of the blocklist" + }, + "pricing_tier": { + "$ref": "#/components/schemas/PricingTiers", + "description": "Pricing tier of the blocklist" + } + }, + "type": "object", + "required": [ + "label", + "id", + "pricing_tier" + ], + "title": "BlocklistOrigin" + }, + "BlocklistSearchRequest": { + "properties": { + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page", + "description": "Page number", + "default": 1 + }, + "page_size": { + "type": "integer", + "maximum": 1000.0, + "title": "Page Size", + "description": "Page size", + "default": 100 + }, + "pricing_tiers": { + "items": { + "$ref": "#/components/schemas/PricingTiers" + }, + "type": "array", + "title": "Pricing Tiers", + "description": "Pricing tiers", + "default": [] + }, + "query": { + "type": "string", + "title": "Query", + "description": "Search query", + "default": "" + }, + "targeted_countries": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Targeted Countries", + "description": "Targeted countries", + "default": [] + }, + "classifications": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Classifications", + "description": "Classifications", + "default": [] + }, + "behaviors": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Behaviors", + "description": "Behaviors", + "default": [] + }, + "min_ips": { + "type": "integer", + "minimum": 0.0, + "title": "Min Ips", + "description": "Minimum number of IPs", + "default": 0 + }, + "sources": { + "items": { + "$ref": "#/components/schemas/BlocklistSources" + }, + "type": "array", + "title": "Sources", + "description": "Sources", + "default": [] + }, + "categories": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Categories", + "description": "Categories", + "default": [] + }, + "is_private": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Private", + "description": "Private blocklist" + }, + "is_subscribed": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "title": "Is Subscribed", + "description": "Subscribed blocklist (None: all)" + } + }, + "additionalProperties": false, + "type": "object", + "title": "BlocklistSearchRequest" + }, + "BlocklistShareRequest": { + "properties": { + "organizations": { + "items": { + "$ref": "#/components/schemas/Share" + }, + "type": "array", + "title": "Organizations", + "description": "List of organizations to share the blocklist" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "organizations" + ], + "title": "BlocklistShareRequest" + }, + "BlocklistSources": { + "type": "string", + "enum": [ + "crowdsec", + "third_party", + "custom" + ], + "title": "BlocklistSources" + }, + "BlocklistStats": { + "properties": { + "content_stats": { + "$ref": "#/components/schemas/BlocklistContentStats", + "default": { + "total_seen": 0, + "total_fire": 0, + "total_seen_1m": 0, + "total_in_other_lists": 0, + "total_false_positive": 0, + "false_positive_removed_by_crowdsec": 0, + "most_present_behaviors": [], + "most_present_categories": [], + "most_present_scenarios": [], + "top_as": [], + "top_attacking_countries": [], + "top_ips": [] + } + }, + "usage_stats": { + "anyOf": [ + { + "$ref": "#/components/schemas/BlocklistUsageStats" + }, + { + "type": "null" + } + ], + "default": { + "engines_subscribed_directly": 0, + "engines_subscribed_through_org": 0, + "engines_subscribed_through_tag": 0, + "total_subscribed_engines": 0, + "total_subscribed_organizations": 0 + } + }, + "addition_2days": { + "type": "integer", + "title": "Addition 2Days", + "default": 0 + }, + "addition_month": { + "type": "integer", + "title": "Addition Month", + "default": 0 + }, + "suppression_2days": { + "type": "integer", + "title": "Suppression 2Days", + "default": 0 + }, + "suppression_month": { + "type": "integer", + "title": "Suppression Month", + "default": 0 + }, + "change_2days_percentage": { + "type": "number", + "title": "Change 2Days Percentage", + "default": 0.0 + }, + "change_month_percentage": { + "type": "number", + "title": "Change Month Percentage", + "default": 0.0 + }, + "count": { + "type": "integer", + "title": "Count", + "default": 0 + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "additionalProperties": true, + "type": "object", + "title": "BlocklistStats" + }, + "BlocklistSubscriberEntity": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Subscriber entity id" + }, + "entity_type": { + "$ref": "#/components/schemas/SubscriberEntityType" + }, + "remediation": { + "type": "string", + "title": "Remediation", + "description": "Remediation" + } + }, + "type": "object", + "required": [ + "id", + "entity_type", + "remediation" + ], + "title": "BlocklistSubscriberEntity" + }, + "BlocklistSubscriberEntityPage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscriberEntity" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "BlocklistSubscriberEntityPage" + }, + "BlocklistSubscribersCount": { + "properties": { + "entity_type": { + "$ref": "#/components/schemas/SubscriberEntityType", + "description": "Subscriber entity type" + }, + "count": { + "type": "integer", + "title": "Count", + "description": "Subscriber entity count" + } + }, + "type": "object", + "required": [ + "entity_type", + "count" + ], + "title": "BlocklistSubscribersCount" + }, + "BlocklistSubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id" + }, + "remediation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Remediation" + }, + "name": { + "type": "string", + "title": "Name" + }, + "label": { + "type": "string", + "title": "Label" + } + }, + "type": "object", + "required": [ + "id", + "name", + "label" + ], + "title": "BlocklistSubscription" + }, + "BlocklistSubscriptionRequest": { + "properties": { + "ids": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Ids", + "description": "List of subscriber entity id" + }, + "entity_type": { + "$ref": "#/components/schemas/SubscriberEntityType" + }, + "remediation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Remediation", + "description": "Remediation" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "entity_type" + ], + "title": "BlocklistSubscriptionRequest" + }, + "BlocklistSubscriptionResponse": { + "properties": { + "updated": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Updated", + "description": "List of updated blocklist ids", + "examples": [ + "5f9d88b9e5c4f5b9a3d3e8b1" + ] + }, + "errors": { + "anyOf": [ + { + "items": { + "additionalProperties": { + "type": "string" + }, + "type": "object" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Errors", + "description": "List of errors if any", + "examples": [ + { + "5f9d88b9e5c4f5b9a3d3e8b1": "error message" + } + ] + } + }, + "type": "object", + "required": [ + "updated", + "errors" + ], + "title": "BlocklistSubscriptionResponse" + }, + "BlocklistUpdateRequest": { + "properties": { + "label": { + "type": "string", + "title": "Label", + "description": "Blocklist human readable name" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Blocklist description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Blocklist references" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Blocklist tags" + }, + "from_cti_query": { + "type": "string", + "title": "From Cti Query", + "description": "CTI query (doc link available soon)" + }, + "since": { + "type": "string", + "title": "Since", + "description": "Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days" + } + }, + "additionalProperties": false, + "type": "object", + "title": "BlocklistUpdateRequest" + }, + "BlocklistUsageStats": { + "properties": { + "engines_subscribed_directly": { + "type": "integer", + "title": "Engines Subscribed Directly", + "default": 0 + }, + "engines_subscribed_through_org": { + "type": "integer", + "title": "Engines Subscribed Through Org", + "default": 0 + }, + "engines_subscribed_through_tag": { + "type": "integer", + "title": "Engines Subscribed Through Tag", + "default": 0 + }, + "total_subscribed_engines": { + "type": "integer", + "title": "Total Subscribed Engines", + "default": 0 + }, + "total_subscribed_organizations": { + "type": "integer", + "title": "Total Subscribed Organizations", + "default": 0 + }, + "updated_at": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Updated At" + } + }, + "additionalProperties": true, + "type": "object", + "title": "BlocklistUsageStats" + }, + "Body_uploadBlocklistContent": { + "properties": { + "file": { + "type": "string", + "format": "binary", + "title": "File", + "description": "Blocklist file in txt format" + } + }, + "type": "object", + "required": [ + "file" + ], + "title": "Body_uploadBlocklistContent" + }, + "CVESubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "CVE ID" + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "CVESubscription" + }, + "ComputedMetrics": { + "properties": { + "saved": { + "$ref": "#/components/schemas/ComputedSavedMetrics", + "description": "estimated saved metrics" + }, + "dropped": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Dropped", + "description": "estimated dropped metrics", + "default": [] + }, + "prevented": { + "items": { + "$ref": "#/components/schemas/AttacksMetrics" + }, + "type": "array", + "title": "Prevented", + "description": "prevented attacks metrics", + "default": [] + } + }, + "type": "object", + "required": [ + "saved" + ], + "title": "ComputedMetrics" + }, + "ComputedSavedMetrics": { + "properties": { + "log_lines": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Log Lines", + "description": "estimated log lines saved", + "default": [] + }, + "storage": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Storage", + "description": "estimated storage saved", + "default": [] + }, + "egress_traffic": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Egress Traffic", + "description": "estimated egress traffic saved", + "default": [] + } + }, + "type": "object", + "title": "ComputedSavedMetrics" + }, + "CtiAs": { + "properties": { + "as_num": { + "type": "string", + "title": "As Num" + }, + "as_name": { + "type": "string", + "title": "As Name" + }, + "total_ips": { + "type": "integer", + "title": "Total Ips" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "as_num", + "as_name", + "total_ips" + ], + "title": "CtiAs" + }, + "CtiBehavior": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "label": { + "type": "string", + "title": "Label" + }, + "description": { + "type": "string", + "title": "Description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References" + }, + "total_ips": { + "type": "integer", + "title": "Total Ips" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "name", + "label", + "description", + "references", + "total_ips" + ], + "title": "CtiBehavior" + }, + "CtiCategory": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "label": { + "type": "string", + "title": "Label" + }, + "description": { + "type": "string", + "title": "Description" + }, + "total_ips": { + "type": "integer", + "title": "Total Ips" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "name", + "label", + "description", + "total_ips" + ], + "title": "CtiCategory" + }, + "CtiCountry": { + "properties": { + "country_short": { + "type": "string", + "title": "Country Short" + }, + "total_ips": { + "type": "integer", + "title": "Total Ips" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "country_short", + "total_ips" + ], + "title": "CtiCountry" + }, + "CtiIp": { + "properties": { + "ip": { + "type": "string", + "title": "Ip" + }, + "total_signals_1m": { + "type": "integer", + "title": "Total Signals 1M" + }, + "reputation": { + "type": "string", + "title": "Reputation", + "default": "unknown" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "ip", + "total_signals_1m" + ], + "title": "CtiIp" + }, + "CtiScenario": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "label": { + "type": "string", + "title": "Label" + }, + "description": { + "type": "string", + "title": "Description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References" + }, + "total_ips": { + "type": "integer", + "title": "Total Ips" + } + }, + "additionalProperties": true, + "type": "object", + "required": [ + "name", + "label", + "description", + "references", + "total_ips" + ], + "title": "CtiScenario" + }, + "DecisionCreateRequest": { + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "uuid": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Uuid", + "description": "UUID of the decision" + }, + "id": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Id", + "description": "ID of the decision" + }, + "duration": { + "type": "string", + "title": "Duration", + "description": "Duration of the decision" + }, + "origin": { + "type": "string", + "title": "Origin", + "description": "Origin of the decision" + }, + "scenario": { + "type": "string", + "title": "Scenario", + "description": "Scenario of the decision" + }, + "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" + }, + "target": { + "$ref": "#/components/schemas/DecisionTargetModel", + "description": "Target of the decision" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "duration", + "origin", + "scenario", + "scope", + "type", + "value", + "target" + ], + "title": "DecisionCreateRequest" + }, + "DecisionCreateResponse": { + "properties": { + "uuid": { + "type": "string", + "title": "Uuid", + "description": "UUID of the created decision" + } + }, + "type": "object", + "required": [ + "uuid" + ], + "title": "DecisionCreateResponse" + }, + "DecisionResponse": { + "properties": { + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At" + }, + "uuid": { + "type": "string", + "title": "Uuid", + "description": "UUID of the decision" + }, + "id": { + "type": "integer", + "title": "Id", + "description": "ID of the decision" + }, + "duration": { + "type": "string", + "title": "Duration", + "description": "Duration of the decision" + }, + "origin": { + "type": "string", + "title": "Origin", + "description": "Origin of the decision" + }, + "scenario": { + "type": "string", + "title": "Scenario", + "description": "Scenario of the decision" + }, + "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" + }, + "target": { + "$ref": "#/components/schemas/DecisionTargetModel", + "description": "Target of the decision" + } + }, + "type": "object", + "required": [ + "uuid", + "id", + "duration", + "origin", + "scenario", + "scope", + "type", + "value", + "target" + ], + "title": "DecisionResponse" + }, + "DecisionTargetModel": { + "properties": { + "type": { + "$ref": "#/components/schemas/DecisionTargetType", + "description": "Type of the decision target" + }, + "value": { + "type": "string", + "title": "Value", + "description": "Value of the decision target" + } + }, + "type": "object", + "required": [ + "type", + "value" + ], + "title": "DecisionTargetModel" + }, + "DecisionTargetType": { + "type": "string", + "enum": [ + "org", + "tag", + "entity" + ], + "title": "DecisionTargetType" + }, + "DecisionsGetResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/DecisionResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "DecisionsGetResponsePage" + }, + "DecisionsSortBy": { + "type": "string", + "enum": [ + "created_at", + "expire_at" + ], + "title": "DecisionsSortBy" + }, + "DecisionsSortOrder": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "title": "DecisionsSortOrder" + }, + "EntityType": { + "type": "string", + "enum": [ + "org", + "tag", + "engine", + "firewall_integration", + "remediation_component_integration", + "remediation_component", + "log_processor" + ], + "title": "EntityType" + }, + "FingerprintSubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Fingerprint ID" + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "FingerprintSubscription" + }, + "GetRemediationMetricsResponse": { + "properties": { + "raw": { + "$ref": "#/components/schemas/RawMetrics", + "description": "Raw metrics data" + }, + "computed": { + "$ref": "#/components/schemas/ComputedMetrics", + "description": "Computed metrics data" + } + }, + "type": "object", + "required": [ + "raw", + "computed" + ], + "title": "GetRemediationMetricsResponse" + }, + "HTTPValidationError": { + "properties": { + "detail": { + "items": { + "$ref": "#/components/schemas/ValidationError" + }, + "title": "Detail", + "type": "array" + } + }, + "title": "HTTPValidationError", + "type": "object" + }, + "InfoResponse": { + "properties": { + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "The organization ID" + }, + "subscription_type": { + "type": "string", + "title": "Subscription Type", + "description": "The organization subscription type" + }, + "api_key_name": { + "type": "string", + "title": "Api Key Name", + "description": "The API key name that is used" + } + }, + "type": "object", + "required": [ + "organization_id", + "subscription_type", + "api_key_name" + ], + "title": "InfoResponse" + }, + "IntegrationCreateRequest": { + "properties": { + "name": { + "type": "string", + "minLength": 1, + "title": "Name", + "description": "Name of the integration" + }, + "description": { + "type": "string", + "minLength": 1, + "title": "Description", + "description": "Description of the integration" + }, + "entity_type": { + "$ref": "#/components/schemas/IntegrationType", + "description": "Type of the integration" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "Output format of the integration" + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name", + "entity_type", + "output_format" + ], + "title": "IntegrationCreateRequest" + }, + "IntegrationCreateResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the integration" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration. Should be unique within the organization" + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the integration" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the integration was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Last time the integration was updated" + }, + "entity_type": { + "$ref": "#/components/schemas/IntegrationType", + "description": "Type of the integration" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "Output format of the integration" + }, + "last_pull": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Last Pull", + "description": "Last time the integration pulled blocklists" + }, + "blocklists": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscription" + }, + "type": "array", + "title": "Blocklists", + "description": "Blocklists that are subscribed by the integration" + }, + "cves": { + "items": { + "$ref": "#/components/schemas/CVESubscription" + }, + "type": "array", + "title": "Cves", + "description": "CVEs that are subscribed by the integration" + }, + "fingerprints": { + "items": { + "$ref": "#/components/schemas/FingerprintSubscription" + }, + "type": "array", + "title": "Fingerprints", + "description": "Fingerprints that are subscribed by the integration" + }, + "vendors": { + "items": { + "$ref": "#/components/schemas/VendorSubscription" + }, + "type": "array", + "title": "Vendors", + "description": "Vendors that are subscribed by the integration" + }, + "endpoint": { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri", + "title": "Endpoint", + "description": "Url that should be used by the firewall or the remediation component to fetch the integration's content" + }, + "stats": { + "$ref": "#/components/schemas/Stats", + "description": "Stats of the integration", + "default": { + "count": 0 + } + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the integration", + "default": [] + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + }, + "credentials": { + "anyOf": [ + { + "$ref": "#/components/schemas/ApiKeyCredentials" + }, + { + "$ref": "#/components/schemas/BasicAuthCredentials" + } + ], + "title": "Credentials", + "description": "Credentials that were generated for the integration" + } + }, + "type": "object", + "required": [ + "id", + "name", + "organization_id", + "created_at", + "updated_at", + "entity_type", + "output_format", + "blocklists", + "cves", + "fingerprints", + "vendors", + "endpoint", + "credentials" + ], + "title": "IntegrationCreateResponse" + }, + "IntegrationGetResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the integration" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration. Should be unique within the organization" + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the integration" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the integration was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Last time the integration was updated" + }, + "entity_type": { + "$ref": "#/components/schemas/IntegrationType", + "description": "Type of the integration" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "Output format of the integration" + }, + "last_pull": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Last Pull", + "description": "Last time the integration pulled blocklists" + }, + "blocklists": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscription" + }, + "type": "array", + "title": "Blocklists", + "description": "Blocklists that are subscribed by the integration" + }, + "cves": { + "items": { + "$ref": "#/components/schemas/CVESubscription" + }, + "type": "array", + "title": "Cves", + "description": "CVEs that are subscribed by the integration" + }, + "fingerprints": { + "items": { + "$ref": "#/components/schemas/FingerprintSubscription" + }, + "type": "array", + "title": "Fingerprints", + "description": "Fingerprints that are subscribed by the integration" + }, + "vendors": { + "items": { + "$ref": "#/components/schemas/VendorSubscription" + }, + "type": "array", + "title": "Vendors", + "description": "Vendors that are subscribed by the integration" + }, + "endpoint": { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri", + "title": "Endpoint", + "description": "Url that should be used by the firewall or the remediation component to fetch the integration's content" + }, + "stats": { + "$ref": "#/components/schemas/Stats", + "description": "Stats of the integration", + "default": { + "count": 0 + } + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the integration", + "default": [] + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + } + }, + "type": "object", + "required": [ + "id", + "name", + "organization_id", + "created_at", + "updated_at", + "entity_type", + "output_format", + "blocklists", + "cves", + "fingerprints", + "vendors", + "endpoint" + ], + "title": "IntegrationGetResponse" + }, + "IntegrationGetResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IntegrationGetResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "IntegrationGetResponsePage" + }, + "IntegrationType": { + "type": "string", + "enum": [ + "firewall_integration", + "remediation_component_integration" + ], + "title": "IntegrationType" + }, + "IntegrationUpdateRequest": { + "properties": { + "name": { + "type": "string", + "minLength": 1, + "title": "Name", + "description": "New name" + }, + "description": { + "type": "string", + "minLength": 1, + "title": "Description", + "description": "New description" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "New output format" + }, + "regenerate_credentials": { + "type": "boolean", + "title": "Regenerate Credentials", + "description": "Regenerate credentials for the integration" + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + } + }, + "additionalProperties": false, + "type": "object", + "title": "IntegrationUpdateRequest" + }, + "IntegrationUpdateResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the integration" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration. Should be unique within the organization" + }, + "organization_id": { + "type": "string", + "title": "Organization Id", + "description": "ID of the owner organization" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the integration" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the integration was created" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Last time the integration was updated" + }, + "entity_type": { + "$ref": "#/components/schemas/IntegrationType", + "description": "Type of the integration" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "Output format of the integration" + }, + "last_pull": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Last Pull", + "description": "Last time the integration pulled blocklists" + }, + "blocklists": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscription" + }, + "type": "array", + "title": "Blocklists", + "description": "Blocklists that are subscribed by the integration" + }, + "cves": { + "items": { + "$ref": "#/components/schemas/CVESubscription" + }, + "type": "array", + "title": "Cves", + "description": "CVEs that are subscribed by the integration" + }, + "fingerprints": { + "items": { + "$ref": "#/components/schemas/FingerprintSubscription" + }, + "type": "array", + "title": "Fingerprints", + "description": "Fingerprints that are subscribed by the integration" + }, + "vendors": { + "items": { + "$ref": "#/components/schemas/VendorSubscription" + }, + "type": "array", + "title": "Vendors", + "description": "Vendors that are subscribed by the integration" + }, + "endpoint": { + "type": "string", + "maxLength": 2083, + "minLength": 1, + "format": "uri", + "title": "Endpoint", + "description": "Url that should be used by the firewall or the remediation component to fetch the integration's content" + }, + "stats": { + "$ref": "#/components/schemas/Stats", + "description": "Stats of the integration", + "default": { + "count": 0 + } + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the integration", + "default": [] + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + }, + "credentials": { + "anyOf": [ + { + "$ref": "#/components/schemas/ApiKeyCredentials" + }, + { + "$ref": "#/components/schemas/BasicAuthCredentials" + }, + { + "type": "null" + } + ], + "title": "Credentials", + "description": "Credentials for the integration" + } + }, + "type": "object", + "required": [ + "id", + "name", + "organization_id", + "created_at", + "updated_at", + "entity_type", + "output_format", + "blocklists", + "cves", + "fingerprints", + "vendors", + "endpoint" + ], + "title": "IntegrationUpdateResponse" + }, + "Links": { + "properties": { + "first": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "First", + "examples": [ + "/api/v1/users?limit=1&offset1" + ] + }, + "last": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Last", + "examples": [ + "/api/v1/users?limit=1&offset1" + ] + }, + "self": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Self", + "examples": [ + "/api/v1/users?limit=1&offset1" + ] + }, + "next": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Next", + "examples": [ + "/api/v1/users?limit=1&offset1" + ] + }, + "prev": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Prev", + "examples": [ + "/api/v1/users?limit=1&offset1" + ] + } + }, + "type": "object", + "title": "Links" + }, + "MetricUnits": { + "type": "string", + "enum": [ + "byte", + "packet", + "request", + "ip", + "line", + "event" + ], + "title": "MetricUnits" + }, + "OriginMetrics": { + "properties": { + "origin": { + "anyOf": [ + { + "$ref": "#/components/schemas/BlocklistOrigin" + }, + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Origin", + "description": "Origin of the metric" + }, + "data": { + "items": { + "$ref": "#/components/schemas/RemediationMetricsData" + }, + "type": "array", + "title": "Data", + "description": "Data points" + } + }, + "type": "object", + "required": [ + "origin", + "data" + ], + "title": "OriginMetrics" + }, + "OutputFormat": { + "type": "string", + "enum": [ + "plain_text", + "f5", + "remediation_component", + "fortigate", + "paloalto", + "checkpoint", + "cisco", + "juniper", + "mikrotik", + "pfsense", + "opnsense", + "sophos" + ], + "title": "OutputFormat" + }, + "Permission": { + "type": "string", + "enum": [ + "read", + "write" + ], + "title": "Permission" + }, + "PricingTiers": { + "type": "string", + "enum": [ + "free", + "premium", + "platinum" + ], + "title": "PricingTiers" + }, + "PublicBlocklistResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Blocklist id" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Blocklist creation date" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Blocklist update date" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Blocklist name, unique within the organization" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Blocklist human readable name" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Blocklist description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Blocklist references", + "default": [] + }, + "is_private": { + "type": "boolean", + "title": "Is Private", + "description": "Private blocklist if True or public if False" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Classification tags", + "default": [] + }, + "pricing_tier": { + "$ref": "#/components/schemas/PricingTiers", + "description": "Pricing tier for Crowdsec blocklists only" + }, + "source": { + "$ref": "#/components/schemas/BlocklistSources", + "description": "Blocklist source" + }, + "stats": { + "$ref": "#/components/schemas/BlocklistStats", + "description": "Blocklist stats" + }, + "from_cti_query": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "From Cti Query", + "description": "CTI query from which the blocklist was created" + }, + "since": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Since", + "description": "Since duration for the CTI query (eg. 5m, 2h, 7d). Max is 30 days" + }, + "shared_with": { + "items": { + "$ref": "#/components/schemas/Share" + }, + "type": "array", + "title": "Shared With", + "description": "List of organizations shared with", + "default": [] + }, + "organization_id": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Organization Id", + "description": "Blocklists owner's organization id" + }, + "subscribers": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscribersCount" + }, + "type": "array", + "title": "Subscribers", + "description": "List of subscribers to the blocklist. Only subscribers belonging to your organization are returned", + "default": [] + }, + "categories": { + "items": { + "$ref": "#/components/schemas/BlocklistCategory" + }, + "type": "array", + "title": "Categories", + "description": "List of categories for the blocklist", + "default": [] + } + }, + "type": "object", + "required": [ + "id", + "created_at", + "updated_at", + "name", + "description", + "is_private", + "pricing_tier", + "source", + "stats" + ], + "title": "PublicBlocklistResponse" + }, + "PublicBlocklistResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/PublicBlocklistResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "PublicBlocklistResponsePage" + }, + "RawMetrics": { + "properties": { + "dropped": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Dropped", + "description": "dropped metrics", + "default": [] + }, + "processed": { + "items": { + "$ref": "#/components/schemas/RemediationMetrics" + }, + "type": "array", + "title": "Processed", + "description": "processed metrics", + "default": [] + } + }, + "type": "object", + "title": "RawMetrics" + }, + "RemediationMetrics": { + "properties": { + "total": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "Total", + "description": "Total value of the metric" + }, + "unit": { + "$ref": "#/components/schemas/MetricUnits", + "description": "Unit of the metric" + }, + "progression": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Progression", + "description": "Progression of the metric value from the previous period" + }, + "data": { + "items": { + "$ref": "#/components/schemas/OriginMetrics" + }, + "type": "array", + "title": "Data", + "description": "Data points per origin" + } + }, + "type": "object", + "required": [ + "total", + "unit", + "progression", + "data" + ], + "title": "RemediationMetrics" + }, + "RemediationMetricsData": { + "properties": { + "value": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "number" + } + ], + "title": "Value", + "description": "Value of the metric" + }, + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp", + "description": "Timestamp of the metric" + } + }, + "type": "object", + "required": [ + "value", + "timestamp" + ], + "title": "RemediationMetricsData" + }, + "Share": { + "properties": { + "organization_id": { + "type": "string", + "title": "Organization Id" + }, + "permission": { + "$ref": "#/components/schemas/Permission" + } + }, + "type": "object", + "required": [ + "organization_id", + "permission" + ], + "title": "Share" + }, + "SourceInfo": { + "properties": { + "source_type": { + "$ref": "#/components/schemas/SourceType", + "description": "The source type that created the allowlist entry" + }, + "identifier": { + "type": "string", + "title": "Identifier", + "description": "The source identifier that created the allowlist entry" + } + }, + "type": "object", + "required": [ + "source_type", + "identifier" + ], + "title": "SourceInfo" + }, + "SourceType": { + "type": "string", + "enum": [ + "user", + "apikey" + ], + "title": "SourceType" + }, + "Stats": { + "properties": { + "count": { + "type": "integer", + "title": "Count", + "description": "Number of total blocklists items the integration will pull" + } + }, + "type": "object", + "required": [ + "count" + ], + "title": "Stats" + }, + "SubscriberEntityType": { + "type": "string", + "enum": [ + "org", + "tag", + "engine", + "firewall_integration", + "remediation_component_integration" + ], + "title": "SubscriberEntityType" + }, + "ValidationError": { + "properties": { + "loc": { + "items": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "integer" + } + ] + }, + "title": "Location", + "type": "array" + }, + "msg": { + "title": "Message", + "type": "string" + }, + "type": { + "title": "Error Type", + "type": "string" + } + }, + "required": [ + "loc", + "msg", + "type" + ], + "title": "ValidationError", + "type": "object" + }, + "VendorSubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "Vendor ID" + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "VendorSubscription" + }, + "AppsecConfigIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "title": "AppsecConfigIndex", + "type": "object" + }, + "AppsecRuleIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "title": "AppsecRuleIndex", + "type": "object" + }, + "CollectionIndex": { + "properties": { + "appsec-configs": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of appsec-configs", + "title": "Appsec-Configs" + }, + "appsec-rules": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of appsec-rules", + "title": "Appsec-Rules" + }, + "collections": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of collections", + "title": "Collections" + }, + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "contexts": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of contexts", + "title": "Contexts" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "parsers": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of parsers", + "title": "Parsers" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "postoverflows": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of postoverflows", + "title": "Postoverflows" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "scenarios": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of scenarios", + "title": "Scenarios" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "title": "CollectionIndex", + "type": "object" + }, + "ContextIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "title": "ContextIndex", + "type": "object" + }, + "Index": { + "description": "Index document served to crowdsec/cscli.", + "properties": { + "appsec-configs": { + "additionalProperties": { + "$ref": "#/components/schemas/AppsecConfigIndex" + }, + "title": "Appsec-Configs", + "type": "object" + }, + "appsec-rules": { + "additionalProperties": { + "$ref": "#/components/schemas/AppsecRuleIndex" + }, + "title": "Appsec-Rules", + "type": "object" + }, + "collections": { + "additionalProperties": { + "$ref": "#/components/schemas/CollectionIndex" + }, + "title": "Collections", + "type": "object" + }, + "contexts": { + "additionalProperties": { + "$ref": "#/components/schemas/ContextIndex" + }, + "title": "Contexts", + "type": "object" + }, + "parsers": { + "additionalProperties": { + "$ref": "#/components/schemas/ParserIndex" + }, + "title": "Parsers", + "type": "object" + }, + "postoverflows": { + "additionalProperties": { + "$ref": "#/components/schemas/PostoverflowIndex" + }, + "title": "Postoverflows", + "type": "object" + }, + "scenarios": { + "additionalProperties": { + "$ref": "#/components/schemas/ScenarioIndex" + }, + "title": "Scenarios", + "type": "object" + } + }, + "title": "Index", + "type": "object" + }, + "ParserIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "stage": { + "description": "The stage of the parser", + "title": "Stage", + "type": "string" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "required": [ + "stage" + ], + "title": "ParserIndex", + "type": "object" + }, + "PostoverflowIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "stage": { + "description": "The stage of the postoverflow", + "title": "Stage", + "type": "string" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "required": [ + "stage" + ], + "title": "PostoverflowIndex", + "type": "object" + }, + "ScenarioIndex": { + "properties": { + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "The YAML content of the item, in plaintext.", + "examples": [ + "type: leaky\n#debug: true\nname: crowdsecurity/vsftpd-bf\ndescription: \"Detect FTP bruteforce (vsftpd)\"\nfilter: evt.Meta.log_type == 'ftp_failed_auth'\nleakspeed: \"10s\"\ncapacity: 5\ngroupby: evt.Meta.source_ip\nblackhole: 5m\nlabels:\n confidence: 3\n spoofable: 0\n classification:\n - attack.T1110\n behavior: \"ftp:bruteforce\"\n label: \"VSFTPD Bruteforce\"\n remediation: true\n service: vsftpd" + ], + "title": "Content" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "A short, plaintext description of the item", + "title": "Description" + }, + "labels": { + "anyOf": [ + { + "additionalProperties": { + "anyOf": [ + { + "type": "string" + }, + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "integer" + } + ] + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "Classification labels for the item", + "examples": [ + { + "behavior": "ftp:bruteforce", + "classification": [ + "attack.T1110" + ], + "confidence": 3, + "label": "VSFTPD Bruteforce", + "remediation": true, + "service": "vsftpd", + "spoofable": 0 + } + ], + "title": "Labels" + }, + "path": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Relative path to the item's YAML content", + "examples": [ + "scenarios/crowdsecurity/vsftpd-bf.yaml" + ], + "title": "Path" + }, + "references": { + "anyOf": [ + { + "items": { + "type": "string" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "description": "List of references to external resources", + "title": "References" + }, + "version": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "description": "Current version of the collection", + "examples": [ + "0.2" + ], + "title": "Version" + }, + "versions": { + "anyOf": [ + { + "additionalProperties": { + "$ref": "#/components/schemas/VersionDetail" + }, + "type": "object" + }, + { + "type": "null" + } + ], + "description": "A dictionary where each key is a version number (e.g., '0.1', '0.2')", + "examples": [ + { + "0.1": { + "deprecated": false, + "digest": "3591247988014705cf3a7e42388f0c87f9b86d3141268d996c5820ceab6364e1" + }, + "0.2": { + "deprecated": false, + "digest": "d1ddf4797250c1899a93ce634e6366e5deaaaf7508135056d17e9b09998ddf91" + } + } + ], + "title": "Versions" + } + }, + "title": "ScenarioIndex", + "type": "object" + }, + "VersionDetail": { + "properties": { + "deprecated": { + "anyOf": [ + { + "type": "boolean" + }, + { + "type": "null" + } + ], + "default": false, + "description": "Indicates whether this version is deprecated.", + "title": "Deprecated" + }, + "digest": { + "description": "The SHA256 digest of the versioned file.", + "examples": [ + "Detect FTP bruteforce (vsftpd)" + ], + "title": "Digest", + "type": "string" + } + }, + "required": [ + "digest" + ], + "title": "VersionDetail", + "type": "object" + }, + "AdjustmentScore": { + "properties": { + "total": { + "type": "integer", + "title": "Total", + "description": "Total score adjustment", + "default": 0 + }, + "recency": { + "type": "integer", + "title": "Recency", + "description": "Recency score adjustment", + "default": 0 + }, + "low_info": { + "type": "integer", + "title": "Low Info", + "description": "Low information score adjustment", + "default": 0 + } + }, + "type": "object", + "title": "AdjustmentScore" + }, + "AffectedComponent": { + "properties": { + "vendor": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Vendor", + "description": "Vendor of the affected component" + }, + "product": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Product", + "description": "Product name of the affected component" + } + }, + "type": "object", + "title": "AffectedComponent", + "description": "Affected Component in a CVE" + }, + "AllowlistSubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id" + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "AllowlistSubscription" + }, + "AttackDetail": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Attack detail name" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Attack detail label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Attack detail description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Attack detail references" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "AttackDetail" + }, + "Behavior": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Behavior name" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Behavior label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Behavior description" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "Behavior" + }, + "CVEEventOutput": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "date": { + "type": "string", + "title": "Date" + }, + "description": { + "type": "string", + "title": "Description" + }, + "label": { + "type": "string", + "title": "Label" + }, + "sorting_priority": { + "type": "integer", + "title": "Sorting Priority" + } + }, + "type": "object", + "required": [ + "name", + "date", + "description", + "label", + "sorting_priority" + ], + "title": "CVEEventOutput" + }, + "CVEExploitationPhase": { + "type": "string", + "enum": [ + "insufficient_data", + "early_exploitation", + "fresh_and_popular", + "targeted_exploitation", + "mass_exploitation", + "background_noise", + "unpopular", + "wearing_out", + "unclassified" + ], + "title": "CVEExploitationPhase" + }, + "CVEResponseBase": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the CVE" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the CVE" + }, + "title": { + "type": "string", + "title": "Title", + "description": "Title of the CVE" + }, + "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 of the CVE" + }, + "opportunity_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Opportunity Score", + "description": "Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + "default": 0 + }, + "momentum_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Momentum Score", + "description": "Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + "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 affected" + }, + "published_date": { + "type": "string", + "format": "date-time", + "title": "Published Date", + "description": "Published date of the CVE" + }, + "cvss_score": { + "anyOf": [ + { + "type": "number", + "maximum": 10.0, + "minimum": 0.0 + }, + { + "type": "null" + } + ], + "title": "Cvss Score", + "description": "CVSS score of the CVE" + }, + "has_public_exploit": { + "type": "boolean", + "title": "Has Public Exploit", + "description": "Indicates if there is a public exploit for the CVE" + }, + "rule_release_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Rule Release Date", + "description": "Release date of the associated detection rule" + }, + "exploitation_phase": { + "$ref": "#/components/schemas/ExploitationPhase", + "description": "Current exploitation phase of the CVE" + }, + "adjustment_score": { + "anyOf": [ + { + "$ref": "#/components/schemas/AdjustmentScore" + }, + { + "type": "null" + } + ], + "description": "Score adjustments applied to the CVE score based on various factors" + }, + "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", + "published_date", + "has_public_exploit", + "exploitation_phase" + ], + "title": "CVEResponseBase", + "description": "GET CVE ID Response" + }, + "CVEsubscription": { + "properties": { + "id": { + "type": "string", + "title": "Id" + } + }, + "type": "object", + "required": [ + "id" + ], + "title": "CVEsubscription" + }, + "CWE": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Name of the CWE" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Label of the CWE" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the CWE" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "CWE", + "description": "CWE Information" + }, + "Classification": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Classification name" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Classification label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Classification description" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "Classification" + }, + "Classifications": { + "properties": { + "false_positives": { + "items": { + "$ref": "#/components/schemas/Classification" + }, + "type": "array", + "title": "False Positives", + "description": "False positive classifications" + }, + "classifications": { + "items": { + "$ref": "#/components/schemas/Classification" + }, + "type": "array", + "title": "Classifications", + "description": "Main classifications" + } + }, + "type": "object", + "title": "Classifications" + }, + "ExploitationPhase": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Name of the exploitation phase" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Label of the exploitation phase" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Description of the exploitation phase" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "ExploitationPhase" + }, + "ExploitationPhaseChangeEventItem": { + "properties": { + "cve_id": { + "type": "string", + "title": "Cve Id", + "description": "CVE identifier" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Event type name" + }, + "date": { + "type": "string", + "title": "Date", + "description": "Date of the phase change" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Human-readable event label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Rendered event description" + }, + "previous_phase": { + "type": "string", + "title": "Previous Phase", + "description": "Previous exploitation phase label" + }, + "new_phase": { + "type": "string", + "title": "New Phase", + "description": "New exploitation phase label" + } + }, + "type": "object", + "required": [ + "cve_id", + "name", + "date", + "label", + "description", + "previous_phase", + "new_phase" + ], + "title": "ExploitationPhaseChangeEventItem" + }, + "ExploitationPhaseChangeEventsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/ExploitationPhaseChangeEventItem" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "ExploitationPhaseChangeEventsResponsePage" + }, + "FacetBucket": { + "properties": { + "value": { + "type": "string", + "title": "Value", + "description": "Facet value" + }, + "count": { + "type": "integer", + "minimum": 0.0, + "title": "Count", + "description": "Number of IPs matching this value" + } + }, + "type": "object", + "required": [ + "value", + "count" + ], + "title": "FacetBucket" + }, + "FingerprintEventOutput": { + "properties": { + "name": { + "type": "string", + "title": "Name" + }, + "date": { + "type": "string", + "title": "Date" + }, + "description": { + "type": "string", + "title": "Description" + }, + "label": { + "type": "string", + "title": "Label" + } + }, + "type": "object", + "required": [ + "name", + "date", + "description", + "label" + ], + "title": "FingerprintEventOutput" + }, + "FingerprintRuleResponse": { + "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)" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the fingerprint rule" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Fingerprint rule description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Reference links for the fingerprint rule" + }, + "crowdsec_analysis": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Crowdsec Analysis", + "description": "CrowdSec analysis for this fingerprint rule" + }, + "events": { + "items": { + "$ref": "#/components/schemas/FingerprintEventOutput" + }, + "type": "array", + "title": "Events", + "description": "List of events related to the fingerprint rule" + } + }, + "type": "object", + "required": [ + "id", + "name", + "title", + "affected_components", + "crowdsec_score", + "nb_ips", + "exploitation_phase" + ], + "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": { + "type": "string", + "format": "date-time", + "title": "Timestamp", + "description": "Timestamp of the timeline event" + }, + "count": { + "type": "integer", + "title": "Count", + "description": "Count of occurrences at the timestamp" + } + }, + "type": "object", + "required": [ + "timestamp", + "count" + ], + "title": "FingerprintTimelineItem" + }, + "GetCVEIPsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IPItem" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetCVEIPsResponsePage" + }, + "GetCVEProtectRulesResponse": { + "properties": { + "protect_rules": { + "items": { + "$ref": "#/components/schemas/ProtectRule" + }, + "type": "array", + "title": "Protect Rules", + "description": "Protection/detection rules associated with the CVE" + } + }, + "type": "object", + "title": "GetCVEProtectRulesResponse", + "description": "Response for the protect rules endpoint." + }, + "GetCVEResponse": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the CVE" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the CVE" + }, + "title": { + "type": "string", + "title": "Title", + "description": "Title of the CVE" + }, + "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 of the CVE" + }, + "opportunity_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Opportunity Score", + "description": "Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + "default": 0 + }, + "momentum_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Momentum Score", + "description": "Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + "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 affected" + }, + "published_date": { + "type": "string", + "format": "date-time", + "title": "Published Date", + "description": "Published date of the CVE" + }, + "cvss_score": { + "anyOf": [ + { + "type": "number", + "maximum": 10.0, + "minimum": 0.0 + }, + { + "type": "null" + } + ], + "title": "Cvss Score", + "description": "CVSS score of the CVE" + }, + "has_public_exploit": { + "type": "boolean", + "title": "Has Public Exploit", + "description": "Indicates if there is a public exploit for the CVE" + }, + "rule_release_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Rule Release Date", + "description": "Release date of the associated detection rule" + }, + "exploitation_phase": { + "$ref": "#/components/schemas/ExploitationPhase", + "description": "Current exploitation phase of the CVE" + }, + "adjustment_score": { + "anyOf": [ + { + "$ref": "#/components/schemas/AdjustmentScore" + }, + { + "type": "null" + } + ], + "description": "Score adjustments applied to the CVE score based on various factors" + }, + "threat_context": { + "anyOf": [ + { + "$ref": "#/components/schemas/ThreatContext" + }, + { + "type": "null" + } + ], + "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": { + "type": "string", + "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", + "required": [ + "id", + "name", + "title", + "affected_components", + "crowdsec_score", + "nb_ips", + "published_date", + "has_public_exploit", + "exploitation_phase", + "references", + "description", + "crowdsec_analysis", + "cwes" + ], + "title": "GetCVEResponse" + }, + "GetCVESubscribedIntegrationsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IntegrationResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetCVESubscribedIntegrationsResponsePage" + }, + "GetCVEsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/CVEResponseBase" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetCVEsResponsePage" + }, + "GetCVEsSortBy": { + "type": "string", + "enum": [ + "rule_release_date", + "trending", + "nb_ips", + "name", + "first_seen" + ], + "title": "GetCVEsSortBy" + }, + "GetCVEsSortOrder": { + "type": "string", + "enum": [ + "asc", + "desc" + ], + "title": "GetCVEsSortOrder" + }, + "GetFingerprintIPsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IPItem" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetFingerprintIPsResponsePage" + }, + "GetFingerprintRulesResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/FingerprintRuleSummary" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetFingerprintRulesResponsePage" + }, + "GetFingerprintSubscribedIntegrationsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IntegrationResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetFingerprintSubscribedIntegrationsResponsePage" + }, + "GetVendorIPsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IPItem" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetVendorIPsResponsePage" + }, + "GetVendorSubscribedIntegrationsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/IntegrationResponse" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "GetVendorSubscribedIntegrationsResponsePage" + }, + "History": { + "properties": { + "first_seen": { + "type": "string", + "format": "date-time", + "title": "First Seen", + "description": "First seen timestamp" + }, + "last_seen": { + "type": "string", + "format": "date-time", + "title": "Last Seen", + "description": "Last seen timestamp" + }, + "full_age": { + "type": "integer", + "title": "Full Age", + "description": "Full age in days" + }, + "days_age": { + "type": "integer", + "title": "Days Age", + "description": "Days age" + } + }, + "type": "object", + "required": [ + "first_seen", + "last_seen", + "full_age", + "days_age" + ], + "title": "History" + }, + "IPItem": { + "properties": { + "ip": { + "type": "string", + "title": "Ip", + "description": "IP address" + }, + "reputation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Reputation", + "description": "Reputation of the IP" + }, + "ip_range": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ip Range", + "description": "IP range" + }, + "ip_range_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ip Range Score", + "description": "IP range score" + }, + "ip_range_24": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ip Range 24", + "description": "IP range /24" + }, + "ip_range_24_reputation": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Ip Range 24 Reputation", + "description": "IP range /24 reputation" + }, + "ip_range_24_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Ip Range 24 Score", + "description": "IP range /24 score" + }, + "as_name": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "As Name", + "description": "AS name" + }, + "as_num": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "As Num", + "description": "AS number" + }, + "background_noise_score": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Background Noise Score", + "description": "Background noise score" + }, + "background_noise": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Background Noise", + "description": "Background noise level" + }, + "confidence": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Confidence", + "description": "Confidence level" + }, + "location": { + "anyOf": [ + { + "$ref": "#/components/schemas/Location" + }, + { + "type": "null" + } + ], + "description": "IP location information" + }, + "reverse_dns": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Reverse Dns", + "description": "Reverse DNS" + }, + "behaviors": { + "items": { + "$ref": "#/components/schemas/Behavior" + }, + "type": "array", + "title": "Behaviors", + "description": "List of behaviors" + }, + "references": { + "items": { + "$ref": "#/components/schemas/Reference" + }, + "type": "array", + "title": "References", + "description": "List of references" + }, + "history": { + "anyOf": [ + { + "$ref": "#/components/schemas/History" + }, + { + "type": "null" + } + ], + "description": "Historical data" + }, + "classifications": { + "anyOf": [ + { + "$ref": "#/components/schemas/Classifications" + }, + { + "type": "null" + } + ], + "description": "Classification data" + }, + "mitre_techniques": { + "items": { + "$ref": "#/components/schemas/MitreTechnique" + }, + "type": "array", + "title": "Mitre Techniques", + "description": "MITRE techniques" + }, + "cves": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Cves", + "description": "List of CVEs" + }, + "attack_details": { + "items": { + "$ref": "#/components/schemas/AttackDetail" + }, + "type": "array", + "title": "Attack Details", + "description": "Attack details" + }, + "target_countries": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Target Countries", + "description": "Target countries" + }, + "scores": { + "anyOf": [ + { + "$ref": "#/components/schemas/Scores" + }, + { + "type": "null" + } + ], + "description": "Scoring information" + } + }, + "type": "object", + "required": [ + "ip" + ], + "title": "IPItem" + }, + "IntegrationResponse": { + "properties": { + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "default": [] + }, + "organization_id": { + "type": "string", + "title": "Organization Id" + }, + "created_at": { + "type": "string", + "format": "date-time", + "title": "Created At", + "description": "Time the integration was created" + }, + "entity_type": { + "$ref": "#/components/schemas/EntityType", + "description": "Type of the integration" + }, + "id": { + "type": "string", + "title": "Id", + "description": "ID of the integration" + }, + "blocklists": { + "items": { + "$ref": "#/components/schemas/BlocklistSubscription" + }, + "type": "array", + "title": "Blocklists", + "default": [] + }, + "allowlists": { + "items": { + "$ref": "#/components/schemas/AllowlistSubscription" + }, + "type": "array", + "title": "Allowlists", + "default": [] + }, + "cves": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/CVEsubscription" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Cves" + }, + "fingerprints": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/FingerprintSubscription" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Fingerprints" + }, + "vendors": { + "anyOf": [ + { + "items": { + "$ref": "#/components/schemas/VendorSubscription" + }, + "type": "array" + }, + { + "type": "null" + } + ], + "title": "Vendors" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration" + }, + "updated_at": { + "type": "string", + "format": "date-time", + "title": "Updated At", + "description": "Last time the integration was updated" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Description of the integration" + }, + "output_format": { + "$ref": "#/components/schemas/OutputFormat", + "description": "Output format of the integration" + }, + "last_pull": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Last Pull", + "description": "Last time the integration pulled blocklists" + }, + "pull_limit": { + "anyOf": [ + { + "type": "integer" + }, + { + "type": "null" + } + ], + "title": "Pull Limit", + "description": "Maximum number of items to pull" + }, + "enable_ip_aggregation": { + "type": "boolean", + "title": "Enable Ip Aggregation", + "description": "Whether to enable IP aggregation into ranges", + "default": false + } + }, + "type": "object", + "required": [ + "organization_id", + "entity_type", + "name", + "output_format" + ], + "title": "IntegrationResponse" + }, + "IntervalOptions": { + "type": "string", + "enum": [ + "hour", + "day", + "week" + ], + "title": "IntervalOptions" + }, + "IpsDetailsStats": { + "properties": { + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total", + "description": "Total number of matching IPs" + }, + "reputation": { + "items": { + "$ref": "#/components/schemas/FacetBucket" + }, + "type": "array", + "title": "Reputation", + "description": "IP count by reputation" + }, + "country": { + "items": { + "$ref": "#/components/schemas/FacetBucket" + }, + "type": "array", + "title": "Country", + "description": "IP count by country (top 5)" + }, + "as_name": { + "items": { + "$ref": "#/components/schemas/FacetBucket" + }, + "type": "array", + "title": "As Name", + "description": "IP count by AS name (top 5)" + }, + "cves": { + "items": { + "$ref": "#/components/schemas/FacetBucket" + }, + "type": "array", + "title": "Cves", + "description": "IP count by CVE (top 5)" + }, + "classifications": { + "items": { + "$ref": "#/components/schemas/FacetBucket" + }, + "type": "array", + "title": "Classifications", + "description": "IP count by classification (top 5)" + } + }, + "type": "object", + "required": [ + "total", + "reputation", + "country", + "as_name", + "cves", + "classifications" + ], + "title": "IpsDetailsStats" + }, + "Location": { + "properties": { + "country": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Country", + "description": "Country code" + }, + "city": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "City", + "description": "City name" + }, + "latitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Latitude", + "description": "Latitude coordinate" + }, + "longitude": { + "anyOf": [ + { + "type": "number" + }, + { + "type": "null" + } + ], + "title": "Longitude", + "description": "Longitude coordinate" + } + }, + "type": "object", + "title": "Location" + }, + "LookupImpactCVEItem": { + "properties": { + "id": { + "type": "string", + "title": "Id", + "description": "ID of the CVE" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Name of the CVE" + }, + "title": { + "type": "string", + "title": "Title", + "description": "Title of the CVE" + }, + "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 of the CVE" + }, + "opportunity_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Opportunity Score", + "description": "Opportunity score indicating if it's an opportunistic(0) or targeted(5) attack (between 0-5)", + "default": 0 + }, + "momentum_score": { + "type": "integer", + "maximum": 5.0, + "minimum": 0.0, + "title": "Momentum Score", + "description": "Momentum score indicating the vulnerability's trendiness based on signal comparison with the previous month. Higher scores (4-5) indicate significantly more signals this month than last month's average, while lower scores (0-1) indicate declining activity (between 0-5)", + "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 affected" + }, + "published_date": { + "type": "string", + "format": "date-time", + "title": "Published Date", + "description": "Published date of the CVE" + }, + "cvss_score": { + "anyOf": [ + { + "type": "number", + "maximum": 10.0, + "minimum": 0.0 + }, + { + "type": "null" + } + ], + "title": "Cvss Score", + "description": "CVSS score of the CVE" + }, + "has_public_exploit": { + "type": "boolean", + "title": "Has Public Exploit", + "description": "Indicates if there is a public exploit for the CVE" + }, + "rule_release_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Rule Release Date", + "description": "Release date of the associated detection rule" + }, + "exploitation_phase": { + "$ref": "#/components/schemas/ExploitationPhase", + "description": "Current exploitation phase of the CVE" + }, + "adjustment_score": { + "anyOf": [ + { + "$ref": "#/components/schemas/AdjustmentScore" + }, + { + "type": "null" + } + ], + "description": "Score adjustments applied to the CVE score based on various factors" + }, + "threat_context": { + "anyOf": [ + { + "$ref": "#/components/schemas/ThreatContext" + }, + { + "type": "null" + } + ], + "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": { + "type": "string", + "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": { + "type": "string", + "const": "cve", + "title": "Type", + "description": "Resource type", + "default": "cve" + } + }, + "type": "object", + "required": [ + "id", + "name", + "title", + "affected_components", + "crowdsec_score", + "nb_ips", + "published_date", + "has_public_exploit", + "exploitation_phase", + "references", + "description", + "crowdsec_analysis", + "cwes" + ], + "title": "LookupImpactCVEItem" + }, + "LookupImpactFingerprintItem": { + "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)" + }, + "tags": { + "items": { + "type": "string" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the fingerprint rule" + }, + "description": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Description", + "description": "Fingerprint rule description" + }, + "references": { + "items": { + "type": "string" + }, + "type": "array", + "title": "References", + "description": "Reference links for the fingerprint rule" + }, + "crowdsec_analysis": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Crowdsec Analysis", + "description": "CrowdSec analysis for this fingerprint rule" + }, + "events": { + "items": { + "$ref": "#/components/schemas/FingerprintEventOutput" + }, + "type": "array", + "title": "Events", + "description": "List of events related to the fingerprint rule" + }, + "type": { + "type": "string", + "const": "fingerprint", + "title": "Type", + "description": "Resource type", + "default": "fingerprint" + } + }, + "type": "object", + "required": [ + "id", + "name", + "title", + "affected_components", + "crowdsec_score", + "nb_ips", + "exploitation_phase" + ], + "title": "LookupImpactFingerprintItem" + }, + "LookupImpactResponsePage": { + "properties": { + "items": { + "items": { + "oneOf": [ + { + "$ref": "#/components/schemas/LookupImpactCVEItem" + }, + { + "$ref": "#/components/schemas/LookupImpactFingerprintItem" + } + ], + "discriminator": { + "propertyName": "type", + "mapping": { + "cve": "#/components/schemas/LookupImpactCVEItem", + "fingerprint": "#/components/schemas/LookupImpactFingerprintItem" + } + } + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "LookupImpactResponsePage" + }, + "LookupListItemWithStats": { + "properties": { + "value": { + "type": "string", + "title": "Value", + "description": "Lookup entry value" + }, + "nb_cves": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Cves", + "description": "Number of CVEs", + "default": 0 + }, + "nb_fingerprints": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Fingerprints", + "description": "Number of fingerprint rules", + "default": 0 + }, + "nb_ips": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips", + "description": "Total number of unique IPs targeting this entry", + "default": 0 + }, + "nb_ips_cves": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Cves", + "description": "Number of IPs across CVEs", + "default": 0 + }, + "nb_ips_fingerprints": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Fingerprints", + "description": "Number of IPs across fingerprint rules", + "default": 0 + }, + "latest_rule_release": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Latest Rule Release", + "description": "Most recent rule release date for this entry" + } + }, + "type": "object", + "required": [ + "value" + ], + "title": "LookupListItemWithStats" + }, + "LookupListWithStatsResponsePage": { + "properties": { + "items": { + "items": { + "$ref": "#/components/schemas/LookupListItemWithStats" + }, + "type": "array", + "title": "Items" + }, + "total": { + "type": "integer", + "minimum": 0.0, + "title": "Total" + }, + "page": { + "type": "integer", + "minimum": 1.0, + "title": "Page" + }, + "size": { + "type": "integer", + "minimum": 1.0, + "title": "Size" + }, + "pages": { + "type": "integer", + "minimum": 0.0, + "title": "Pages" + }, + "links": { + "$ref": "#/components/schemas/Links", + "readOnly": true + } + }, + "type": "object", + "required": [ + "items", + "total", + "page", + "size", + "pages", + "links" + ], + "title": "LookupListWithStatsResponsePage" + }, + "MitreTechnique": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "MITRE technique ID" + }, + "label": { + "type": "string", + "title": "Label", + "description": "MITRE technique label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "MITRE technique description" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "MitreTechnique" + }, + "ProtectRule": { + "properties": { + "link": { + "type": "string", + "title": "Link", + "description": "URL to the rule source" + }, + "published_date": { + "anyOf": [ + { + "type": "string", + "format": "date-time" + }, + { + "type": "null" + } + ], + "title": "Published Date", + "description": "Date the rule was published" + }, + "tags": { + "items": { + "$ref": "#/components/schemas/ProtectRuleTag" + }, + "type": "array", + "title": "Tags", + "description": "Tags associated with the rule" + }, + "name": { + "type": "string", + "title": "Name", + "description": "Rule name" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Human-readable rule label" + }, + "content": { + "anyOf": [ + { + "type": "string" + }, + { + "type": "null" + } + ], + "title": "Content", + "description": "Rule content/definition" + } + }, + "type": "object", + "required": [ + "link", + "name", + "label" + ], + "title": "ProtectRule", + "description": "A protection/detection rule reference from vuln_scores." + }, + "ProtectRuleTag": { + "properties": { + "tag": { + "type": "string", + "title": "Tag", + "description": "Tag identifier" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Human-readable tag label" + } + }, + "type": "object", + "required": [ + "tag", + "label" + ], + "title": "ProtectRuleTag", + "description": "A tag on a protect rule reference." + }, + "Reference": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Reference name" + }, + "label": { + "type": "string", + "title": "Label", + "description": "Reference label" + }, + "description": { + "type": "string", + "title": "Description", + "description": "Reference description" + } + }, + "type": "object", + "required": [ + "name", + "label", + "description" + ], + "title": "Reference" + }, + "ScoreBreakdown": { + "properties": { + "aggressiveness": { + "type": "integer", + "title": "Aggressiveness", + "description": "Aggressiveness score" + }, + "threat": { + "type": "integer", + "title": "Threat", + "description": "Threat score" + }, + "trust": { + "type": "integer", + "title": "Trust", + "description": "Trust score" + }, + "anomaly": { + "type": "integer", + "title": "Anomaly", + "description": "Anomaly score" + }, + "total": { + "type": "integer", + "title": "Total", + "description": "Total score" + } + }, + "type": "object", + "required": [ + "aggressiveness", + "threat", + "trust", + "anomaly", + "total" + ], + "title": "ScoreBreakdown" + }, + "Scores": { + "properties": { + "overall": { + "$ref": "#/components/schemas/ScoreBreakdown", + "description": "Overall scores" + }, + "last_day": { + "$ref": "#/components/schemas/ScoreBreakdown", + "description": "Last day scores" + }, + "last_week": { + "$ref": "#/components/schemas/ScoreBreakdown", + "description": "Last week scores" + }, + "last_month": { + "$ref": "#/components/schemas/ScoreBreakdown", + "description": "Last month scores" + } + }, + "type": "object", + "required": [ + "overall", + "last_day", + "last_week", + "last_month" + ], + "title": "Scores" + }, + "SinceOptions": { + "type": "integer", + "enum": [ + 1, + 7, + 30 + ], + "title": "SinceOptions" + }, + "SubscribeCVEIntegrationRequest": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration to subscribe" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "title": "SubscribeCVEIntegrationRequest" + }, + "SubscribeFingerprintIntegrationRequest": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration to subscribe" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "title": "SubscribeFingerprintIntegrationRequest" + }, + "SubscribeVendorIntegrationRequest": { + "properties": { + "name": { + "type": "string", + "title": "Name", + "description": "Name of the integration to subscribe" + } + }, + "additionalProperties": false, + "type": "object", + "required": [ + "name" + ], + "title": "SubscribeVendorIntegrationRequest" + }, + "ThreatContext": { + "properties": { + "attacker_countries": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Attacker Countries", + "description": "Attacker country distribution (country code \u2192 count)" + }, + "defender_countries": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Defender Countries", + "description": "Defender country distribution (country code \u2192 count)" + }, + "industry_types": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Industry Types", + "description": "Industry type distribution (type \u2192 count)" + }, + "industry_risk_profiles": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Industry Risk Profiles", + "description": "Industry risk profile distribution (profile \u2192 count)" + }, + "attacker_objectives": { + "additionalProperties": { + "type": "integer" + }, + "type": "object", + "title": "Attacker Objectives", + "description": "Attacker objective distribution (objective \u2192 count)" + } + }, + "type": "object", + "title": "ThreatContext" + }, + "TimelineItem": { + "properties": { + "timestamp": { + "type": "string", + "format": "date-time", + "title": "Timestamp", + "description": "Timestamp of the timeline event" + }, + "count": { + "type": "integer", + "title": "Count", + "description": "Count of occurrences at the timestamp" + } + }, + "type": "object", + "required": [ + "timestamp", + "count" + ], + "title": "TimelineItem" + }, + "TopProductItem": { + "properties": { + "value": { + "type": "string", + "title": "Value", + "description": "Product name" + }, + "nb_ips_cves": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Cves", + "description": "Number of IPs across CVEs", + "default": 0 + }, + "nb_ips_fingerprints": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Fingerprints", + "description": "Number of IPs across fingerprint rules", + "default": 0 + } + }, + "type": "object", + "required": [ + "value" + ], + "title": "TopProductItem" + }, + "VendorSortBy": { + "type": "string", + "enum": [ + "value", + "nb_cves", + "nb_ips", + "latest_rule_release" + ], + "title": "VendorSortBy" + }, + "VendorStatsResponse": { + "properties": { + "value": { + "type": "string", + "title": "Value", + "description": "Vendor name" + }, + "nb_cves": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Cves", + "description": "Number of CVEs", + "default": 0 + }, + "nb_fingerprints": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Fingerprints", + "description": "Number of fingerprint rules", + "default": 0 + }, + "nb_ips": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips", + "description": "Total number of unique IPs targeting this vendor", + "default": 0 + }, + "nb_ips_cves": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Cves", + "description": "Number of IPs across CVEs", + "default": 0 + }, + "nb_ips_fingerprints": { + "type": "integer", + "minimum": 0.0, + "title": "Nb Ips Fingerprints", + "description": "Number of IPs across fingerprint rules", + "default": 0 + }, + "top_products": { + "items": { + "$ref": "#/components/schemas/TopProductItem" + }, + "type": "array", + "title": "Top Products", + "description": "Top products for this vendor sorted by total IPs descending" + } + }, + "type": "object", + "required": [ + "value" + ], + "title": "VendorStatsResponse" + } + }, + "securitySchemes": { + "ApiKeyAuth": { + "type": "apiKey", + "in": "header", + "name": "x-api-key", + "description": "If integration key is provided, can also work to get integration content" + }, + "BasicAuth": { + "type": "http", + "scheme": "basic", + "description": "Basic Auth for integration content endpoint only" + } + } + }, + "security": [ + { + "ApiKeyAuth": [] + }, + { + "BasicAuth": [] + } + ] +} \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index 8262bda..11a1680 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "crowdsec_service_api" -version = "1.87.2" +version = "v0.15.25" license = { text = "MIT" } authors = [ { name="crowdsec", email="info@crowdsec.net" } diff --git a/uv.lock b/uv.lock new file mode 100644 index 0000000..edce21e --- /dev/null +++ b/uv.lock @@ -0,0 +1,337 @@ +version = 1 +revision = 3 +requires-python = ">=3.11" + +[[package]] +name = "annotated-types" +version = "0.7.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, +] + +[[package]] +name = "anyio" +version = "4.13.0" +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" } +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" }, +] + +[[package]] +name = "botocore" +version = "1.42.89" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "jmespath" }, + { name = "python-dateutil" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/cc/e6be943efa9051bd15c2ee14077c2b10d6e27c9e9385fc43a03a5c4ed8b5/botocore-1.42.89.tar.gz", hash = "sha256:95ac52f472dad29942f3088b278ab493044516c16dbf9133c975af16527baa99", size = 15206290, upload-time = "2026-04-13T19:36:02.321Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/91/f1/90a7b8eda38b7c3a65ca7ee0075bdf310b6b471cb1b95fab6e8994323a50/botocore-1.42.89-py3-none-any.whl", hash = "sha256:d9b786c8d9db6473063b4cc5be0ba7e6a381082307bd6afb69d4216f9fa95f35", size = 14887287, upload-time = "2026-04-13T19:35:56.677Z" }, +] + +[[package]] +name = "certifi" +version = "2026.2.25" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/af/2d/7bf41579a8986e348fa033a31cdd0e4121114f6bce2457e8876010b092dd/certifi-2026.2.25.tar.gz", hash = "sha256:e887ab5cee78ea814d3472169153c2d12cd43b14bd03329a39a9c6e2e80bfba7", size = 155029, upload-time = "2026-02-25T02:54:17.342Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9a/3c/c17fb3ca2d9c3acff52e30b309f538586f9f5b9c9cf454f3845fc9af4881/certifi-2026.2.25-py3-none-any.whl", hash = "sha256:027692e4402ad994f1c42e52a4997a9763c646b73e4096e4d5d6db8af1d6f0fa", size = 153684, upload-time = "2026-02-25T02:54:15.766Z" }, +] + +[[package]] +name = "crowdsec-service-api" +version = "0.15.25" +source = { editable = "." } +dependencies = [ + { name = "botocore" }, + { name = "httpx" }, + { name = "pydantic", extra = ["email", "timezone"] }, +] + +[package.metadata] +requires-dist = [ + { name = "botocore" }, + { name = "httpx", specifier = "==0.27.0" }, + { name = "pydantic", extras = ["email", "timezone"], specifier = ">=2.5.0,<3.0.0" }, +] + +[[package]] +name = "dnspython" +version = "2.8.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/8c/8b/57666417c0f90f08bcafa776861060426765fdb422eb10212086fb811d26/dnspython-2.8.0.tar.gz", hash = "sha256:181d3c6996452cb1189c4046c61599b84a5a86e099562ffde77d26984ff26d0f", size = 368251, upload-time = "2025-09-07T18:58:00.022Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/5a/18ad964b0086c6e62e2e7500f7edc89e3faa45033c71c1893d34eed2b2de/dnspython-2.8.0-py3-none-any.whl", hash = "sha256:01d9bbc4a2d76bf0db7c1f729812ded6d912bd318d3b1cf81d30c0f845dbf3af", size = 331094, upload-time = "2025-09-07T18:57:58.071Z" }, +] + +[[package]] +name = "email-validator" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "dnspython" }, + { name = "idna" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/f5/22/900cb125c76b7aaa450ce02fd727f452243f2e91a61af068b40adba60ea9/email_validator-2.3.0.tar.gz", hash = "sha256:9fc05c37f2f6cf439ff414f8fc46d917929974a82244c20eb10231ba60c54426", size = 51238, upload-time = "2025-08-26T13:09:06.831Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/15/545e2b6cf2e3be84bc1ed85613edd75b8aea69807a71c26f4ca6a9258e82/email_validator-2.3.0-py3-none-any.whl", hash = "sha256:80f13f623413e6b197ae73bb10bf4eb0908faf509ad8362c5edeb0be7fd450b4", size = 35604, upload-time = "2025-08-26T13:09:05.858Z" }, +] + +[[package]] +name = "h11" +version = "0.16.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "certifi" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, +] + +[[package]] +name = "httpx" +version = "0.27.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "certifi" }, + { name = "httpcore" }, + { name = "idna" }, + { name = "sniffio" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5c/2d/3da5bdf4408b8b2800061c339f240c1802f2e82d55e50bd39c5a881f47f0/httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5", size = 126413, upload-time = "2024-02-21T13:07:52.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/41/7b/ddacf6dcebb42466abd03f368782142baa82e08fc0c1f8eaa05b4bae87d5/httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5", size = 75590, upload-time = "2024-02-21T13:07:50.455Z" }, +] + +[[package]] +name = "idna" +version = "3.11" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/6f/6d/0703ccc57f3a7233505399edb88de3cbd678da106337b9fcde432b65ed60/idna-3.11.tar.gz", hash = "sha256:795dafcc9c04ed0c1fb032c2aa73654d8e8c5023a7df64a53f39190ada629902", size = 194582, upload-time = "2025-10-12T14:55:20.501Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0e/61/66938bbb5fc52dbdf84594873d5b51fb1f7c7794e9c0f5bd885f30bc507b/idna-3.11-py3-none-any.whl", hash = "sha256:771a87f49d9defaf64091e6e6fe9c18d4833f140bd19464795bc32d966ca37ea", size = 71008, upload-time = "2025-10-12T14:55:18.883Z" }, +] + +[[package]] +name = "jmespath" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/d3/59/322338183ecda247fb5d1763a6cbe46eff7222eaeebafd9fa65d4bf5cb11/jmespath-1.1.0.tar.gz", hash = "sha256:472c87d80f36026ae83c6ddd0f1d05d4e510134ed462851fd5f754c8c3cbb88d", size = 27377, upload-time = "2026-01-22T16:35:26.279Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/14/2f/967ba146e6d58cf6a652da73885f52fc68001525b4197effc174321d70b4/jmespath-1.1.0-py3-none-any.whl", hash = "sha256:a5663118de4908c91729bea0acadca56526eb2698e83de10cd116ae0f4e97c64", size = 20419, upload-time = "2026-01-22T16:35:24.919Z" }, +] + +[[package]] +name = "pydantic" +version = "2.13.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/84/6b/69fd5c7194b21ebde0f8637e2a4ddc766ada29d472bfa6a5ca533d79549a/pydantic-2.13.0.tar.gz", hash = "sha256:b89b575b6e670ebf6e7448c01b41b244f471edd276cd0b6fe02e7e7aca320070", size = 843468, upload-time = "2026-04-13T10:51:35.571Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/01/d7/c3a52c61f5b7be648e919005820fbac33028c6149994cd64453f49951c17/pydantic-2.13.0-py3-none-any.whl", hash = "sha256:ab0078b90da5f3e2fd2e71e3d9b457ddcb35d0350854fbda93b451e28d56baaf", size = 471872, upload-time = "2026-04-13T10:51:33.343Z" }, +] + +[package.optional-dependencies] +email = [ + { name = "email-validator" }, +] +timezone = [ + { name = "tzdata", marker = "sys_platform == 'win32'" }, +] + +[[package]] +name = "pydantic-core" +version = "2.46.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/6f/0a/9414cddf82eda3976b14048cc0fa8f5b5d1aecb0b22e1dcd2dbfe0e139b1/pydantic_core-2.46.0.tar.gz", hash = "sha256:82d2498c96be47b47e903e1378d1d0f770097ec56ea953322f39936a7cf34977", size = 471441, upload-time = "2026-04-13T09:06:33.813Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ce/43/9bc38d43a6a48794209e4eb6d61e9c68395f69b7949f66842854b0cd1344/pydantic_core-2.46.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:0027da787ae711f7fbd5a76cb0bb8df526acba6c10c1e44581de1b838db10b7b", size = 2121004, upload-time = "2026-04-13T09:05:17.531Z" }, + { url = "https://files.pythonhosted.org/packages/8c/1d/f43342b7107939b305b5e4efeef7d54e267a5ef51515570a5c1d77726efb/pydantic_core-2.46.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:63e288fc18d7eaeef5f16c73e65c4fd0ad95b25e7e21d8a5da144977b35eb997", size = 1947505, upload-time = "2026-04-13T09:04:48.975Z" }, + { url = "https://files.pythonhosted.org/packages/4a/cd/ccf48cbbcaf0d99ba65969459ebfbf7037600b2cfdcca3062084dd83a008/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:080a3bdc6807089a1fe1fbc076519cea287f1a964725731d80b49d8ecffaa217", size = 1973301, upload-time = "2026-04-13T09:05:42.149Z" }, + { url = "https://files.pythonhosted.org/packages/c2/ff/a7bb1e7a762fb1f40ad5ef4e6a92c012864a017b7b1fdfb71cf91faa8b73/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c065f1c3e54c3e79d909927a8cb48ccbc17b68733552161eba3e0628c38e5d19", size = 2042208, upload-time = "2026-04-13T09:05:32.591Z" }, + { url = "https://files.pythonhosted.org/packages/ea/64/d3f11c6f6ace71526f3b03646df95eaab3f21edd13e00daae3f20f4e5a09/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7e2db58ab46cfe602d4255381cce515585998c3b6699d5b1f909f519bc44a5aa", size = 2229046, upload-time = "2026-04-13T09:04:18.59Z" }, + { url = "https://files.pythonhosted.org/packages/d0/64/93db9a63cce71630c58b376d63de498aa93cb341c72cd5f189b5c08f5c28/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c660974890ec1e4c65cff93f5670a5f451039f65463e9f9c03ad49746b49fc78", size = 2292138, upload-time = "2026-04-13T09:04:13.816Z" }, + { url = "https://files.pythonhosted.org/packages/e9/96/936fccce22f1f2ae8b2b694de651c2c929847be5f701c927a0bb3b1eb679/pydantic_core-2.46.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d3be91482a8db77377c902cca87697388a4fb68addeb3e943ac74f425201a099", size = 2093333, upload-time = "2026-04-13T09:05:15.729Z" }, + { url = "https://files.pythonhosted.org/packages/75/76/c325e7fda69d589e26e772272044fe704c7e525c47d0d32a74f8345ac657/pydantic_core-2.46.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:1c72de82115233112d70d07f26a48cf6996eb86f7e143423ec1a182148455a9d", size = 2138802, upload-time = "2026-04-13T09:03:51.142Z" }, + { url = "https://files.pythonhosted.org/packages/c0/6f/ccaa2ff7d53a017b66841e2d38edd1f38d19ae1a2d0c5efee17f2d432229/pydantic_core-2.46.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7904e58768cd79304b992868d7710bfc85dc6c7ed6163f0f68dbc1dcd72dc231", size = 2181358, upload-time = "2026-04-13T09:04:30.737Z" }, + { url = "https://files.pythonhosted.org/packages/6c/71/0c4b6303e92d63edcb81f5301695cdf70bb351775b4733eea65acdac8384/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1af8d88718005f57bb4768f92f4ff16bf31a747d39dfc919b22211b84e72c053", size = 2183985, upload-time = "2026-04-13T09:04:06.792Z" }, + { url = "https://files.pythonhosted.org/packages/71/eb/f6bf255de38a4393aaa10bff224e882b630576bc26ebfb401e42bb965092/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:a5b891301b02770a5852253f4b97f8bd192e5710067bc129e20d43db5403ede2", size = 2328559, upload-time = "2026-04-13T09:06:14.143Z" }, + { url = "https://files.pythonhosted.org/packages/f2/71/93895a1545f50823a24b21d7761c2bd1b1afea7a6ddc019787caec237361/pydantic_core-2.46.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:48b671fe59031fd9754c7384ac05b3ed47a0cccb7d4db0ec56121f0e6a541b90", size = 2367466, upload-time = "2026-04-13T09:05:59.613Z" }, + { url = "https://files.pythonhosted.org/packages/78/39/62331b3e71f41fb13d486621e2aec49900ba56567fb3a0ae5999fded0005/pydantic_core-2.46.0-cp311-cp311-win32.whl", hash = "sha256:0a52b7262b6cc67033823e9549a41bb77580ac299dc964baae4e9c182b2e335c", size = 1981367, upload-time = "2026-04-13T09:07:37.563Z" }, + { url = "https://files.pythonhosted.org/packages/9f/51/caac70958420e2d6115962f550676df59647c11f96a44c2fcb61662fcd16/pydantic_core-2.46.0-cp311-cp311-win_amd64.whl", hash = "sha256:4103fea1beeef6b3a9fed8515f27d4fa30c929a1973655adf8f454dc49ee0662", size = 2065942, upload-time = "2026-04-13T09:06:37.873Z" }, + { url = "https://files.pythonhosted.org/packages/b2/cf/576b2a4eb5500a1a5da485613b1ea8bc0d7279b27e0426801574b284ae65/pydantic_core-2.46.0-cp311-cp311-win_arm64.whl", hash = "sha256:3137cd88938adb8e567c5e938e486adc7e518ffc96b4ae1ec268e6a4275704d7", size = 2052532, upload-time = "2026-04-13T09:06:03.697Z" }, + { url = "https://files.pythonhosted.org/packages/a7/d2/206c72ad47071559142a35f71efc29eb16448a4a5ae9487230ab8e4e292b/pydantic_core-2.46.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:66ccedb02c934622612448489824955838a221b3a35875458970521ef17b2f9c", size = 2117060, upload-time = "2026-04-13T09:04:47.443Z" }, + { url = "https://files.pythonhosted.org/packages/17/2c/7a53b33f91c8b77e696b1a6aa3bed609bf9374bdc0f8dcda681bc7d922b8/pydantic_core-2.46.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a44f27f4d2788ef9876ec47a43739b118c5904d74f418f53398f6ced3bbcacf2", size = 1951802, upload-time = "2026-04-13T09:05:34.591Z" }, + { url = "https://files.pythonhosted.org/packages/fc/20/90e548c1f6d38800ef11c915881525770ce270d8e5e887563ff046a08674/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f26a1032bcce6ca4b4670eb3f7d8195bd0a8b8f255f1307823e217ca3cfa7c27", size = 1976621, upload-time = "2026-04-13T09:04:03.909Z" }, + { url = "https://files.pythonhosted.org/packages/20/3c/9c5810ca70b60c623488cdd80f7e9ee1a0812df81e97098b64788719860f/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b8d1412f725060527e56675904b17a2d421dddcf861eecf7c75b9dda47921a4", size = 2056721, upload-time = "2026-04-13T09:04:40.992Z" }, + { url = "https://files.pythonhosted.org/packages/1a/a3/d6e5f4cdec84278431c75540f90838c9d0a4dfe9402a8f3902073660ff28/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dc3d1569edd859cabaa476cabce9eecd05049a7966af7b4a33b541bfd4ca1104", size = 2239634, upload-time = "2026-04-13T09:03:52.478Z" }, + { url = "https://files.pythonhosted.org/packages/46/42/ef58aacf330d8de6e309d62469aa1f80e945eaf665929b4037ac1bfcebc1/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:38108976f2d8afaa8f5067fd1390a8c9f5cc580175407cda636e76bc76e88054", size = 2315739, upload-time = "2026-04-13T09:05:04.971Z" }, + { url = "https://files.pythonhosted.org/packages/8b/86/c63b12fafa2d86a515bfd1840b39c23a49302f02b653161bf9c3a0566c50/pydantic_core-2.46.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a5a06d8ed01dad5575056b5187e5959b336793c6047920a3441ee5b03533836", size = 2098169, upload-time = "2026-04-13T09:07:27.151Z" }, + { url = "https://files.pythonhosted.org/packages/76/19/b5b33a2f6be4755b21a20434293c4364be255f4c1a108f125d101d4cc4ee/pydantic_core-2.46.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:04017ace142da9ce27cafd423a480872571b5c7e80382aec22f7d715ca8eb870", size = 2170830, upload-time = "2026-04-13T09:04:39.448Z" }, + { url = "https://files.pythonhosted.org/packages/99/ae/7559f99a29b7d440012ddb4da897359304988a881efaca912fd2f655652e/pydantic_core-2.46.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2629ad992ed1b1c012e6067f5ffafd3336fcb9b54569449fabb85621f1444ed3", size = 2203901, upload-time = "2026-04-13T09:04:01.048Z" }, + { url = "https://files.pythonhosted.org/packages/dd/0e/b0ef945a39aeb4ac58da316813e1106b7fbdfbf20ac141c1c27904355ac5/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:3068b1e7bd986aebc88f6859f8353e72072538dcf92a7fb9cf511a0f61c5e729", size = 2191789, upload-time = "2026-04-13T09:06:39.915Z" }, + { url = "https://files.pythonhosted.org/packages/90/f4/830484e07188c1236b013995818888ab93bab8fd88aa9689b1d8fd22220d/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:1e366916ff69ff700aa9326601634e688581bc24c5b6b4f8738d809ec7d72611", size = 2344423, upload-time = "2026-04-13T09:05:12.252Z" }, + { url = "https://files.pythonhosted.org/packages/fd/ba/e455c18cbdc333177af754e740be4fe9d1de173d65bbe534daf88da02ac0/pydantic_core-2.46.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:485a23e8f4618a1b8e23ac744180acde283fffe617f96923d25507d5cade62ec", size = 2384037, upload-time = "2026-04-13T09:06:24.503Z" }, + { url = "https://files.pythonhosted.org/packages/78/1f/b35d20d73144a41e78de0ae398e60fdd8bed91667daa1a5a92ab958551ba/pydantic_core-2.46.0-cp312-cp312-win32.whl", hash = "sha256:520940e1b702fe3b33525d0351777f25e9924f1818ca7956447dabacf2d339fd", size = 1967068, upload-time = "2026-04-13T09:05:23.374Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/4b6252e9606e8295647b848233cc4137ee0a04ebba8f0f9fb2977655b38c/pydantic_core-2.46.0-cp312-cp312-win_amd64.whl", hash = "sha256:90d2048e0339fa365e5a66aefe760ddd3b3d0a45501e088bc5bc7f4ed9ff9571", size = 2071008, upload-time = "2026-04-13T09:05:21.392Z" }, + { url = "https://files.pythonhosted.org/packages/39/95/d08eb508d4d5560ccbd226ee5971e5ef9b749aba9b413c0c4ed6e406d4f6/pydantic_core-2.46.0-cp312-cp312-win_arm64.whl", hash = "sha256:a70247649b7dffe36648e8f34be5ce8c5fa0a27ff07b071ea780c20a738c05ce", size = 2036634, upload-time = "2026-04-13T09:05:48.299Z" }, + { url = "https://files.pythonhosted.org/packages/df/05/ab3b0742bad1d51822f1af0c4232208408902bdcfc47601f3b812e09e6c2/pydantic_core-2.46.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a05900c37264c070c683c650cbca8f83d7cbb549719e645fcd81a24592eac788", size = 2116814, upload-time = "2026-04-13T09:04:12.41Z" }, + { url = "https://files.pythonhosted.org/packages/98/08/30b43d9569d69094a0899a199711c43aa58fce6ce80f6a8f7693673eb995/pydantic_core-2.46.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8de8e482fd4f1e3f36c50c6aac46d044462615d8f12cfafc6bebeaa0909eea22", size = 1951867, upload-time = "2026-04-13T09:04:02.364Z" }, + { url = "https://files.pythonhosted.org/packages/db/a0/bf9a1ba34537c2ed3872a48195291138fdec8fe26c4009776f00d63cf0c8/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c525ecf8a4cdf198327b65030a7d081867ad8e60acb01a7214fff95cf9832d47", size = 1977040, upload-time = "2026-04-13T09:06:16.088Z" }, + { url = "https://files.pythonhosted.org/packages/71/70/0ba03c20e1e118219fc18c5417b008b7e880f0e3fb38560ec4465984d471/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f14581aeb12e61542ce73b9bfef2bca5439d65d9ab3efe1a4d8e346b61838f9b", size = 2055284, upload-time = "2026-04-13T09:05:25.125Z" }, + { url = "https://files.pythonhosted.org/packages/58/cf/1e320acefbde7fb7158a9e5def55e0adf9a4634636098ce28dc6b978e0d3/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c108067f2f7e190d0dbd81247d789ec41f9ea50ccd9265a3a46710796ac60530", size = 2238896, upload-time = "2026-04-13T09:05:01.345Z" }, + { url = "https://files.pythonhosted.org/packages/df/f5/ea8ba209756abe9eba891bb0ef3772b4c59a894eb9ad86cd5bd0dd4e3e52/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ac10967e9a7bb1b96697374513f9a1a90a59e2fb41566b5e00ee45392beac59", size = 2314353, upload-time = "2026-04-13T09:06:07.942Z" }, + { url = "https://files.pythonhosted.org/packages/e8/f8/5885350203b72e96438eee7f94de0d8f0442f4627237ca8ef75de34db1cd/pydantic_core-2.46.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7897078fe8a13b73623c0955dfb2b3d2c9acb7177aac25144758c9e5a5265aaa", size = 2098522, upload-time = "2026-04-13T09:04:23.239Z" }, + { url = "https://files.pythonhosted.org/packages/bf/88/5930b0e828e371db5a556dd3189565417ddc3d8316bb001058168aadcf5f/pydantic_core-2.46.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:e69ce405510a419a082a78faed65bb4249cfb51232293cc675645c12f7379bf7", size = 2168757, upload-time = "2026-04-13T09:07:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/da/75/63d563d3035a0548e721c38b5b69fd5626fdd51da0f09ff4467503915b82/pydantic_core-2.46.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fd28d13eea0d8cf351dc1fe274b5070cc8e1cca2644381dee5f99de629e77cf3", size = 2202518, upload-time = "2026-04-13T09:05:44.418Z" }, + { url = "https://files.pythonhosted.org/packages/a7/53/1958eacbfddc41aadf5ae86dd85041bf054b675f34a2fa76385935f96070/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:ee1547a6b8243e73dd10f585555e5a263395e55ce6dea618a078570a1e889aef", size = 2190148, upload-time = "2026-04-13T09:06:56.151Z" }, + { url = "https://files.pythonhosted.org/packages/c7/17/098cc6d3595e4623186f2bc6604a6195eb182e126702a90517236391e9ce/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:c3dc68dcf62db22a18ddfc3ad4960038f72b75908edc48ae014d7ac8b391d57a", size = 2342925, upload-time = "2026-04-13T09:04:17.286Z" }, + { url = "https://files.pythonhosted.org/packages/71/a7/abdb924620b1ac535c690b36ad5b8871f376104090f8842c08625cecf1d3/pydantic_core-2.46.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:004a2081c881abfcc6854a4623da6a09090a0d7c1398a6ae7133ca1256cee70b", size = 2383167, upload-time = "2026-04-13T09:04:52.643Z" }, + { url = "https://files.pythonhosted.org/packages/d7/c9/2ddd10f50e4b7350d2574629a0f53d8d4eb6573f9c19a6b43e6b1487a31d/pydantic_core-2.46.0-cp313-cp313-win32.whl", hash = "sha256:59d24ec8d5eaabad93097525a69d0f00f2667cb353eb6cda578b1cfff203ceef", size = 1965660, upload-time = "2026-04-13T09:06:05.877Z" }, + { url = "https://files.pythonhosted.org/packages/b5/e7/1efc38ed6f2680c032bcefa0e3ebd496a8c77e92dfdb86b07d0f2fc632b1/pydantic_core-2.46.0-cp313-cp313-win_amd64.whl", hash = "sha256:71186dad5ac325c64d68fe0e654e15fd79802e7cc42bc6f0ff822d5ad8b1ab25", size = 2069563, upload-time = "2026-04-13T09:07:14.738Z" }, + { url = "https://files.pythonhosted.org/packages/c3/1e/a325b4989e742bf7e72ed35fa124bc611fd76539c9f8cd2a9a7854473533/pydantic_core-2.46.0-cp313-cp313-win_arm64.whl", hash = "sha256:8e4503f3213f723842c9a3b53955c88a9cfbd0b288cbd1c1ae933aebeec4a1b4", size = 2034966, upload-time = "2026-04-13T09:04:21.629Z" }, + { url = "https://files.pythonhosted.org/packages/36/3b/914891d384cdbf9a6f464eb13713baa22ea1e453d4da80fb7da522079370/pydantic_core-2.46.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:4fc801c290342350ffc82d77872054a934b2e24163727263362170c1db5416ca", size = 2113349, upload-time = "2026-04-13T09:04:59.407Z" }, + { url = "https://files.pythonhosted.org/packages/35/95/3a0c6f65e231709fb3463e32943c69d10285cb50203a2130a4732053a06d/pydantic_core-2.46.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:0a36f2cc88170cc177930afcc633a8c15907ea68b59ac16bd180c2999d714940", size = 1949170, upload-time = "2026-04-13T09:06:09.935Z" }, + { url = "https://files.pythonhosted.org/packages/d1/63/d845c36a608469fe7bee226edeff0984c33dbfe7aecd755b0e7ab5a275c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2a3912e0c568a1f99d4d6d3e41def40179d61424c0ca1c8c87c4877d7f6fd7fb", size = 1977914, upload-time = "2026-04-13T09:04:56.16Z" }, + { url = "https://files.pythonhosted.org/packages/08/6f/f2e7a7f85931fb31671f5378d1c7fc70606e4b36d59b1b48e1bd1ef5d916/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3534c3415ed1a19ab23096b628916a827f7858ec8db49ad5d7d1e44dc13c0d7b", size = 2050538, upload-time = "2026-04-13T09:05:06.789Z" }, + { url = "https://files.pythonhosted.org/packages/8c/97/f4aa7181dd9a16dd9059a99fc48fdab0c2aab68307283a5c04cf56de68c4/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21067396fc285609323a4db2f63a87570044abe0acddfcca8b135fc7948e3db7", size = 2236294, upload-time = "2026-04-13T09:07:03.2Z" }, + { url = "https://files.pythonhosted.org/packages/24/c1/6a5042fc32765c87101b500f394702890af04239c318b6002cfd627b710d/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2afd85b7be186e2fe7cdbb09a3d964bcc2042f65bbcc64ad800b3c7915032655", size = 2312954, upload-time = "2026-04-13T09:06:11.919Z" }, + { url = "https://files.pythonhosted.org/packages/cb/e4/566101a561492ce8454f0844ca29c3b675a6b3a7b3ff577db85ed05c8c50/pydantic_core-2.46.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:67e2c2e171b78db8154da602de72ffdc473c6ee51de8a9d80c0f1cd4051abfc7", size = 2102533, upload-time = "2026-04-13T09:06:58.664Z" }, + { url = "https://files.pythonhosted.org/packages/3e/ac/adc11ee1646a5c4dd9abb09a00e7909e6dc25beddc0b1310ca734bb9b48e/pydantic_core-2.46.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:c16ae1f3170267b1a37e16dba5c297bdf60c8b5657b147909ca8774ce7366644", size = 2169447, upload-time = "2026-04-13T09:04:11.143Z" }, + { url = "https://files.pythonhosted.org/packages/26/73/408e686b45b82d28ac19e8229e07282254dbee6a5d24c5c7cf3cf3716613/pydantic_core-2.46.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:133b69e1c1ba34d3702eed73f19f7f966928f9aa16663b55c2ebce0893cca42e", size = 2200672, upload-time = "2026-04-13T09:03:54.056Z" }, + { url = "https://files.pythonhosted.org/packages/0a/3b/807d5b035ec891b57b9079ce881f48263936c37bd0d154a056e7fd152afb/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:15ed8e5bde505133d96b41702f31f06829c46b05488211a5b1c7877e11de5eb5", size = 2188293, upload-time = "2026-04-13T09:07:07.614Z" }, + { url = "https://files.pythonhosted.org/packages/f1/ed/719b307516285099d1196c52769fdbe676fd677da007b9c349ae70b7226d/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_armv7l.whl", hash = "sha256:8cfc29a1c66a7f0fcb36262e92f353dd0b9c4061d558fceb022e698a801cb8ae", size = 2335023, upload-time = "2026-04-13T09:04:05.176Z" }, + { url = "https://files.pythonhosted.org/packages/8d/90/8718e4ae98c4e8a7325afdc079be82be1e131d7a47cb6c098844a9531ffe/pydantic_core-2.46.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:e1155708540f13845bf68d5ac511a55c76cfe2e057ed12b4bf3adac1581fc5c2", size = 2377155, upload-time = "2026-04-13T09:06:18.081Z" }, + { url = "https://files.pythonhosted.org/packages/dd/dc/7172789283b963f81da2fc92b186e22de55687019079f71c4d570822502b/pydantic_core-2.46.0-cp314-cp314-win32.whl", hash = "sha256:de5635a48df6b2eef161d10ea1bc2626153197333662ba4cd700ee7ec1aba7f5", size = 1963078, upload-time = "2026-04-13T09:05:30.615Z" }, + { url = "https://files.pythonhosted.org/packages/e0/69/03a7ea4b6264def3a44eabf577528bcec2f49468c5698b2044dea54dc07e/pydantic_core-2.46.0-cp314-cp314-win_amd64.whl", hash = "sha256:f07a5af60c5e7cf53dd1ff734228bd72d0dc9938e64a75b5bb308ca350d9681e", size = 2068439, upload-time = "2026-04-13T09:04:57.729Z" }, + { url = "https://files.pythonhosted.org/packages/f5/eb/1c3afcfdee2ab6634b802ab0a0f1966df4c8b630028ec56a1cb0a710dc58/pydantic_core-2.46.0-cp314-cp314-win_arm64.whl", hash = "sha256:e7a77eca3c7d5108ff509db20aae6f80d47c7ed7516d8b96c387aacc42f3ce0f", size = 2026470, upload-time = "2026-04-13T09:05:08.654Z" }, + { url = "https://files.pythonhosted.org/packages/5c/30/1177dde61b200785c4739665e3aa03a9d4b2c25d2d0408b07d585e633965/pydantic_core-2.46.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:5e7cdd4398bee1aaeafe049ac366b0f887451d9ae418fd8785219c13fea2f928", size = 2107447, upload-time = "2026-04-13T09:05:46.314Z" }, + { url = "https://files.pythonhosted.org/packages/b1/60/4e0f61f99bdabbbc309d364a2791e1ba31e778a4935bc43391a7bdec0744/pydantic_core-2.46.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:5c2c92d82808e27cef3f7ab3ed63d657d0c755e0dbe5b8a58342e37bdf09bd2e", size = 1926927, upload-time = "2026-04-13T09:06:20.371Z" }, + { url = "https://files.pythonhosted.org/packages/1d/d0/67f89a8269152c1d6eaa81f04e75a507372ebd8ca7382855a065222caa80/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0bab80af91cd7014b45d1089303b5f844a9d91d7da60eabf3d5f9694b32a6655", size = 1966613, upload-time = "2026-04-13T09:07:05.389Z" }, + { url = "https://files.pythonhosted.org/packages/cd/07/8dfdc3edc78f29a80fb31f366c50203ec904cff6a4c923599bf50ac0d0ff/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1e49ffdb714bc990f00b39d1ad1d683033875b5af15582f60c1f34ad3eeccfaa", size = 2032902, upload-time = "2026-04-13T09:06:42.47Z" }, + { url = "https://files.pythonhosted.org/packages/b0/2a/111c5e8fe24f99c46bcad7d3a82a8f6dbc738066e2c72c04c71f827d8c78/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ca877240e8dbdeef3a66f751dc41e5a74893767d510c22a22fc5c0199844f0ce", size = 2244456, upload-time = "2026-04-13T09:05:36.484Z" }, + { url = "https://files.pythonhosted.org/packages/6b/7c/cfc5d11c15a63ece26e148572c77cfbb2c7f08d315a7b63ef0fe0711d753/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87e6843f89ecd2f596d7294e33196c61343186255b9880c4f1b725fde8b0e20d", size = 2294535, upload-time = "2026-04-13T09:06:01.689Z" }, + { url = "https://files.pythonhosted.org/packages/c4/2c/f0d744e3dab7bd026a3f4670a97a295157cff923a2666d30a15a70a7e3d0/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e20bc5add1dd9bc3b9a3600d40632e679376569098345500799a6ad7c5d46c72", size = 2104621, upload-time = "2026-04-13T09:04:34.388Z" }, + { url = "https://files.pythonhosted.org/packages/a7/64/e7cc4698dc024264d214b51d5a47a2404221b12060dd537d76f831b2120a/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:ee6ff79a5f0289d64a9d6696a3ce1f98f925b803dd538335a118231e26d6d827", size = 2130718, upload-time = "2026-04-13T09:04:26.23Z" }, + { url = "https://files.pythonhosted.org/packages/0b/a8/224e655fec21f7d4441438ad2ecaccb33b5a3876ce7bb2098c74a49efc14/pydantic_core-2.46.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:52d35cfb58c26323101c7065508d7bb69bb56338cda9ea47a7b32be581af055d", size = 2180738, upload-time = "2026-04-13T09:05:50.253Z" }, + { url = "https://files.pythonhosted.org/packages/32/7b/b3025618ed4c4e4cbaa9882731c19625db6669896b621760ea95bc1125ef/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d14cc5a6f260fa78e124061eebc5769af6534fc837e9a62a47f09a2c341fa4ea", size = 2171222, upload-time = "2026-04-13T09:07:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/7b/e3/68170aa1d891920af09c1f2f34df61dc5ff3a746400027155523e3400e89/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_armv7l.whl", hash = "sha256:4f7ff859d663b6635f6307a10803d07f0d09487e16c3d36b1744af51dbf948b2", size = 2320040, upload-time = "2026-04-13T09:06:35.732Z" }, + { url = "https://files.pythonhosted.org/packages/67/1b/5e65807001b84972476300c1f49aea2b4971b7e9fffb5c2654877dadd274/pydantic_core-2.46.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:8ef749be6ed0d69dba31902aaa8255a9bb269ae50c93888c4df242d8bb7acd9e", size = 2377062, upload-time = "2026-04-13T09:07:39.945Z" }, + { url = "https://files.pythonhosted.org/packages/75/03/48caa9dd5f28f7662bd52bff454d9a451f6b7e5e4af95e289e5e170749c9/pydantic_core-2.46.0-cp314-cp314t-win32.whl", hash = "sha256:d93ca72870133f86360e4bb0c78cd4e6ba2a0f9f3738a6486909ffc031463b32", size = 1951028, upload-time = "2026-04-13T09:04:20.224Z" }, + { url = "https://files.pythonhosted.org/packages/87/ed/e97ff55fe28c0e6e3cba641d622b15e071370b70e5f07c496b07b65db7c9/pydantic_core-2.46.0-cp314-cp314t-win_amd64.whl", hash = "sha256:6ebb2668afd657e2127cb40f2ceb627dd78e74e9dfde14d9bf6cdd532a29ff59", size = 2048519, upload-time = "2026-04-13T09:05:10.464Z" }, + { url = "https://files.pythonhosted.org/packages/b6/51/e0db8267a287994546925f252e329eeae4121b1e77e76353418da5a3adf0/pydantic_core-2.46.0-cp314-cp314t-win_arm64.whl", hash = "sha256:4864f5bbb7993845baf9209bae1669a8a76769296a018cb569ebda9dcb4241f5", size = 2026791, upload-time = "2026-04-13T09:04:37.724Z" }, + { url = "https://files.pythonhosted.org/packages/2d/f1/6731c2d6caf03efe822101edb4783eb3f212f34b7b005a34f039f67e76e1/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-macosx_10_12_x86_64.whl", hash = "sha256:ce2e38e27de73ff6a0312a9e3304c398577c418d90bbde97f0ba1ee3ab7ac39f", size = 2121259, upload-time = "2026-04-13T09:07:34.845Z" }, + { url = "https://files.pythonhosted.org/packages/72/fd/ac34d4c92e739e37a040be9e7ea84d116afec5f983a7db856c27135fba77/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-macosx_11_0_arm64.whl", hash = "sha256:f0d34ba062396de0be7421e6e69c9a6821bf6dc73a0ab9959a48a5a6a1e24754", size = 1945798, upload-time = "2026-04-13T09:04:24.729Z" }, + { url = "https://files.pythonhosted.org/packages/b6/a4/f413a522c4047c46b109be6805a3095d35e5a4882fd5b4fdc0909693dfc0/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4c0a12147b4026dd68789fb9f22f1a8769e457f9562783c181880848bbd6412", size = 1986062, upload-time = "2026-04-13T09:05:57.177Z" }, + { url = "https://files.pythonhosted.org/packages/91/2e/9760025ea8b0f49903c0ceebdfc2d8ef839da872426f2b03cae9de036a7c/pydantic_core-2.46.0-graalpy311-graalpy242_311_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a99896d9db56df901ab4a63cd6a36348a569cff8e05f049db35f4016a817a3d9", size = 2145344, upload-time = "2026-04-13T09:03:56.924Z" }, + { url = "https://files.pythonhosted.org/packages/74/0c/106ed5cc50393d90523f09adcc50d05e42e748eb107dc06aea971137f02d/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_10_12_x86_64.whl", hash = "sha256:bc0e2fefe384152d7da85b5c2fe8ce2bf24752f68a58e3f3ea42e28a29dfdeb2", size = 2104968, upload-time = "2026-04-13T09:06:26.967Z" }, + { url = "https://files.pythonhosted.org/packages/f5/71/b494cef3165e3413ee9bbbb5a9eedc9af0ea7b88d8638beef6c2061b110e/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-macosx_11_0_arm64.whl", hash = "sha256:a2ab0e785548be1b4362a62c4004f9217598b7ee465f1f420fc2123e2a5b5b02", size = 1940442, upload-time = "2026-04-13T09:06:29.332Z" }, + { url = "https://files.pythonhosted.org/packages/7e/3e/a4d578c8216c443e26a1124f8c1e07c0654264ce5651143d3883d85ff140/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:16d45aecb18b8cba1c68eeb17c2bb2d38627ceed04c5b30b882fc9134e01f187", size = 1999672, upload-time = "2026-04-13T09:04:42.798Z" }, + { url = "https://files.pythonhosted.org/packages/cd/c1/9114560468685525a21770138382fd0cb849aaf351ff2c7b97f760d121e0/pydantic_core-2.46.0-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5078f6c377b002428e984259ac327ef8902aacae6c14b7de740dd4869a491501", size = 2154533, upload-time = "2026-04-13T09:04:50.868Z" }, + { url = "https://files.pythonhosted.org/packages/09/ed/fbd8127e4a19c4fdbb2f4983cf72c7b3534086df640c813c5c0ec4218177/pydantic_core-2.46.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:be3e04979ba4d68183f247202c7f4f483f35df57690b3f875c06340a1579b47c", size = 2119951, upload-time = "2026-04-13T09:04:35.923Z" }, + { url = "https://files.pythonhosted.org/packages/ec/77/df8711ebb45910412f90d75198430fa1120f5618336b71fa00303601c5a4/pydantic_core-2.46.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b1eae8d7d9b8c2a90b34d3d9014804dca534f7f40180197062634499412ea14e", size = 1953812, upload-time = "2026-04-13T09:05:40.293Z" }, + { url = "https://files.pythonhosted.org/packages/12/fe/14b35df69112bd812d6818a395eeab22eeaa2befc6f85bc54ed648430186/pydantic_core-2.46.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a95a2773680dd4b6b999d4eccdd1b577fd71c31739fb4849f6ada47eabb9c56", size = 2139585, upload-time = "2026-04-13T09:06:46.94Z" }, + { url = "https://files.pythonhosted.org/packages/1f/f0/4fea4c14ebbdeb87e5f6edd2620735fcbd384865f06707fe229c021ce041/pydantic_core-2.46.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:25988c3159bb097e06abfdf7b21b1fcaf90f187c74ca6c7bb842c1f72ce74fa8", size = 2179154, upload-time = "2026-04-13T09:04:15.639Z" }, + { url = "https://files.pythonhosted.org/packages/5c/36/6329aa79ba32b73560e6e453164fb29702b115fd3b2b650e796e1dc27862/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:747d89bd691854c719a3381ba46b6124ef916ae85364c79e11db9c84995d8d03", size = 2182917, upload-time = "2026-04-13T09:07:24.483Z" }, + { url = "https://files.pythonhosted.org/packages/92/61/edbf7aea71052d410347846a2ea43394f74651bf6822b8fad8703ca00575/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:909a7327b83ca93b372f7d48df0ebc7a975a5191eb0b6e024f503f4902c24124", size = 2327716, upload-time = "2026-04-13T09:06:31.681Z" }, + { url = "https://files.pythonhosted.org/packages/a4/11/aa5089b941e85294b1d5d526840b18f0d4464f842d43d8999ce50ef881c1/pydantic_core-2.46.0-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:2f7e6a3752378a69fadf3f5ee8bc5fa082f623703eec0f4e854b12c548322de0", size = 2365925, upload-time = "2026-04-13T09:05:38.338Z" }, + { url = "https://files.pythonhosted.org/packages/0c/75/e187b0ea247f71f2009d156df88b7d8449c52a38810c9a1bd55dd4871206/pydantic_core-2.46.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:ef47ee0a3ac4c2bb25a083b3acafb171f65be4a0ac1e84edef79dd0016e25eaa", size = 2193856, upload-time = "2026-04-13T09:05:03.114Z" }, +] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "six" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, +] + +[[package]] +name = "six" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, +] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/72/94/1a15dd82efb362ac84269196e94cf00f187f7ed21c242792a923cdb1c61f/typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466", size = 109391, upload-time = "2025-08-25T13:49:26.313Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/18/67/36e9267722cc04a6b9f15c7f3441c2363321a3ea07da7ae0c0707beb2a9c/typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548", size = 44614, upload-time = "2025-08-25T13:49:24.86Z" }, +] + +[[package]] +name = "typing-inspection" +version = "0.4.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/dc/9b/47798a6c91d8bdb567fe2698fe81e0c6b7cb7ef4d13da4114b41d239f65d/typing_inspection-0.4.2-py3-none-any.whl", hash = "sha256:4ed1cacbdc298c220f1bd249ed5287caa16f34d44ef4e9c3d0cbad5b521545e7", size = 14611, upload-time = "2025-10-01T02:14:40.154Z" }, +] + +[[package]] +name = "tzdata" +version = "2026.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/19/f5/cd531b2d15a671a40c0f66cf06bc3570a12cd56eef98960068ebbad1bf5a/tzdata-2026.1.tar.gz", hash = "sha256:67658a1903c75917309e753fdc349ac0efd8c27db7a0cb406a25be4840f87f98", size = 197639, upload-time = "2026-04-03T11:25:22.002Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b0/70/d460bd685a170790ec89317e9bd33047988e4bce507b831f5db771e142de/tzdata-2026.1-py2.py3-none-any.whl", hash = "sha256:4b1d2be7ac37ceafd7327b961aa3a54e467efbdb563a23655fbfe0d39cfc42a9", size = 348952, upload-time = "2026-04-03T11:25:20.313Z" }, +] + +[[package]] +name = "urllib3" +version = "2.6.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/24/5f1b3bdffd70275f6661c76461e25f024d5a38a46f04aaca912426a2b1d3/urllib3-2.6.3.tar.gz", hash = "sha256:1b62b6884944a57dbe321509ab94fd4d3b307075e0c2eae991ac71ee15ad38ed", size = 435556, upload-time = "2026-01-07T16:24:43.925Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/39/08/aaaad47bc4e9dc8c725e68f9d04865dbcb2052843ff09c97b08904852d84/urllib3-2.6.3-py3-none-any.whl", hash = "sha256:bf272323e553dfb2e87d9bfd225ca7b0f467b919d7bbd355436d3fd37cb0acd4", size = 131584, upload-time = "2026-01-07T16:24:42.685Z" }, +]