cartography 0.94.0rc2__py3-none-any.whl → 0.95.0rc1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of cartography might be problematic. Click here for more details.
- cartography/cli.py +42 -24
- cartography/config.py +12 -8
- cartography/data/indexes.cypher +0 -2
- cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json +13 -13
- cartography/driftdetect/cli.py +1 -1
- cartography/graph/job.py +8 -1
- cartography/intel/aws/permission_relationships.py +6 -2
- cartography/intel/gcp/__init__.py +110 -23
- cartography/intel/kandji/__init__.py +1 -1
- cartography/intel/semgrep/findings.py +106 -59
- cartography/intel/snipeit/__init__.py +30 -0
- cartography/intel/snipeit/asset.py +74 -0
- cartography/intel/snipeit/user.py +75 -0
- cartography/intel/snipeit/util.py +35 -0
- cartography/models/semgrep/findings.py +3 -1
- cartography/models/snipeit/__init__.py +0 -0
- cartography/models/snipeit/asset.py +81 -0
- cartography/models/snipeit/tenant.py +17 -0
- cartography/models/snipeit/user.py +49 -0
- cartography/sync.py +2 -2
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/LICENSE +1 -1
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/METADATA +3 -5
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/RECORD +26 -22
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/WHEEL +1 -1
- cartography/data/jobs/cleanup/crxcavator_import_cleanup.json +0 -18
- cartography/intel/crxcavator/__init__.py +0 -44
- cartography/intel/crxcavator/crxcavator.py +0 -329
- cartography-0.94.0rc2.dist-info/NOTICE +0 -4
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/entry_points.txt +0 -0
- {cartography-0.94.0rc2.dist-info → cartography-0.95.0rc1.dist-info}/top_level.txt +0 -0
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
same "printed page" as the copyright notice for easier
|
|
188
188
|
identification within third-party archives.
|
|
189
189
|
|
|
190
|
-
Copyright
|
|
190
|
+
Copyright 2024 The Linux Foundation
|
|
191
191
|
|
|
192
192
|
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
193
|
you may not use this file except in compliance with the License.
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: cartography
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.95.0rc1
|
|
4
4
|
Summary: Explore assets and their relationships across your technical infrastructure.
|
|
5
|
-
Home-page: https://www.github.com/
|
|
6
|
-
Maintainer:
|
|
7
|
-
Maintainer-email: security@lyft.com
|
|
5
|
+
Home-page: https://www.github.com/cartography-cncf/cartography
|
|
6
|
+
Maintainer: Cartography Contributors
|
|
8
7
|
License: apache2
|
|
9
8
|
Classifier: Development Status :: 4 - Beta
|
|
10
9
|
Classifier: Intended Audience :: Developers
|
|
@@ -18,7 +17,6 @@ Classifier: Topic :: Software Development :: Libraries
|
|
|
18
17
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
19
18
|
Description-Content-Type: text/markdown
|
|
20
19
|
License-File: LICENSE
|
|
21
|
-
License-File: NOTICE
|
|
22
20
|
Requires-Dist: backoff >=2.1.2
|
|
23
21
|
Requires-Dist: boto3 >=1.15.1
|
|
24
22
|
Requires-Dist: botocore >=1.18.1
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
cartography/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
2
2
|
cartography/__main__.py,sha256=JftXT_nUPkqcEh8uxCCT4n-OyHYqbldEgrDS-4ygy0U,101
|
|
3
|
-
cartography/cli.py,sha256=
|
|
4
|
-
cartography/config.py,sha256=
|
|
3
|
+
cartography/cli.py,sha256=tfIPOMh3DtQG7Dgmg9rNNqoTcxgocBu45k88CAM09Nk,32368
|
|
4
|
+
cartography/config.py,sha256=QbFqwUb6P8-wdkf4ljE5HJhduXl_3Gt2xzBQRayq0sg,11566
|
|
5
5
|
cartography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
6
|
cartography/stats.py,sha256=dbybb9V2FuvSuHjjNwz6Vjwnd1hap2C7h960rLoKcl8,4406
|
|
7
|
-
cartography/sync.py,sha256=
|
|
7
|
+
cartography/sync.py,sha256=ziD63T_774gXSuD5zdz6fLGvv1Kt2ntQySSVbmcCZb8,9708
|
|
8
8
|
cartography/util.py,sha256=umfnjX8jVLu0rpYA75X-WvRpYzHQxns9qZiPwfyAlwQ,14478
|
|
9
9
|
cartography/client/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
10
10
|
cartography/client/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -12,7 +12,7 @@ cartography/client/aws/iam.py,sha256=dYsGikc36DEsSeR2XVOVFFUDwuU9yWj_EVkpgVYCFgM
|
|
|
12
12
|
cartography/client/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
13
13
|
cartography/client/core/tx.py,sha256=4_kTBxrtlwsOM-e8Xtjf7wmmzwZ-DGRJL0rPFp0Xj0Q,10805
|
|
14
14
|
cartography/data/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
15
|
-
cartography/data/indexes.cypher,sha256=
|
|
15
|
+
cartography/data/indexes.cypher,sha256=Ha8VemktSz8ikIS4On-8FTiv2-WwRx5j3l02gQnSWXk,27262
|
|
16
16
|
cartography/data/permission_relationships.yaml,sha256=RuKGGc_3ZUQ7ag0MssB8k_zaonCkVM5E8I_svBWTmGc,969
|
|
17
17
|
cartography/data/jobs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
18
18
|
cartography/data/jobs/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -88,7 +88,6 @@ cartography/data/jobs/cleanup/azure_storage_account_cleanup.json,sha256=XZdjKDOj
|
|
|
88
88
|
cartography/data/jobs/cleanup/azure_subscriptions_cleanup.json,sha256=bowUBCjHYlC4Xd60lv33sxRi-bv1wiT5gAOStaHMX4k,430
|
|
89
89
|
cartography/data/jobs/cleanup/azure_tenant_cleanup.json,sha256=jcjmZH6kfVGZ9q68rfvnroF0kNNHZ2uTZQ17Rmd4FH0,220
|
|
90
90
|
cartography/data/jobs/cleanup/crowdstrike_import_cleanup.json,sha256=bBPwftvz1iMUKrqKFCFZEH3LgVRzg-t5fRUh6Chx-vo,1426
|
|
91
|
-
cartography/data/jobs/cleanup/crxcavator_import_cleanup.json,sha256=IvGVD_lRR-0nEPorq3vhVKmO2R1bKBpivujJIxVo3hE,607
|
|
92
91
|
cartography/data/jobs/cleanup/digitalocean_droplet_cleanup.json,sha256=f26TdPUPYnIp45ipPys5M6VVfConUZySIbkgSr3iQno,703
|
|
93
92
|
cartography/data/jobs/cleanup/digitalocean_project_cleanup.json,sha256=5mo9vPshCdUZfgTWd_22_TLSyfe6hd41u7z-B8H1qgY,702
|
|
94
93
|
cartography/data/jobs/cleanup/gcp_compute_firewall_cleanup.json,sha256=FVNJ8EPaPhmQ_sh4vyTdMyEgs6Y-DIoFTdWJaELgz44,1904
|
|
@@ -118,11 +117,11 @@ cartography/data/jobs/cleanup/okta_groups_cleanup.json,sha256=cBI3f_okl4pnVH48L1
|
|
|
118
117
|
cartography/data/jobs/cleanup/okta_import_cleanup.json,sha256=4XQwYpY9vITLhnLpijMVa5PxO0Tm38CcMydnbPdQPm0,3798
|
|
119
118
|
cartography/data/jobs/cleanup/pagerduty_import_cleanup.json,sha256=RJqG_Uw_QEGTer_-s2IuZ3a2kykhUcCdDNZu0S7SEB4,4457
|
|
120
119
|
cartography/data/jobs/scoped_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
121
|
-
cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json,sha256=
|
|
120
|
+
cartography/data/jobs/scoped_analysis/semgrep_sca_risk_analysis.json,sha256=eIYxbl5TdgVzN8En2JozWoyKAiIh3Dp8wUMkTDPGZY0,6485
|
|
122
121
|
cartography/driftdetect/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
123
122
|
cartography/driftdetect/__main__.py,sha256=Sz24Kxy5x6RC3GQEkuUDXzjOV3SvlHVkZdvPl1GLl5E,125
|
|
124
123
|
cartography/driftdetect/add_shortcut.py,sha256=COtcCW9T0ss-bP1B2y9gEk3kN6HA01kkurSiDBNLzco,2377
|
|
125
|
-
cartography/driftdetect/cli.py,sha256=
|
|
124
|
+
cartography/driftdetect/cli.py,sha256=SiNTsVtxCyMUoTzjCMkSUQ-TYPceGoZ67hp8eejp71k,9172
|
|
126
125
|
cartography/driftdetect/config.py,sha256=wHx1RmKRU3fJ9xD8Nf62uIFGOoaohgyqrFIAy-Fc_xM,2974
|
|
127
126
|
cartography/driftdetect/detect_deviations.py,sha256=pfNce5VWfs_oNNI2-PFgOAOzZ8YPprrE7LxdBo27kqU,4349
|
|
128
127
|
cartography/driftdetect/get_states.py,sha256=iAAoIqItZx-dHV9OmWIhHy0YjhHA1AH8DGtUwp6YO1c,5965
|
|
@@ -135,7 +134,7 @@ cartography/driftdetect/util.py,sha256=Lqxv8QoFn3_3Fz18qCOjkjJ6yBwgrHjrxXmArBAEd
|
|
|
135
134
|
cartography/graph/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
136
135
|
cartography/graph/cleanupbuilder.py,sha256=87vFrOJo66hOrrqeNwXp18WrNQEheHTlZko9KUkXWhY,8021
|
|
137
136
|
cartography/graph/context.py,sha256=RGxGb8EnxowcqjR0nFF86baNhgRHeUF9wjIoFUoG8LU,1230
|
|
138
|
-
cartography/graph/job.py,sha256=
|
|
137
|
+
cartography/graph/job.py,sha256=RZWsbNhHuJlcSpw4C73ZuovRTp7kGrcm3X9yUH8vT1Q,7488
|
|
139
138
|
cartography/graph/querybuilder.py,sha256=MMXzUEg4td-YmHMNM97KAqDZ6-1wNClO2jmJoG47BTY,20108
|
|
140
139
|
cartography/graph/statement.py,sha256=VsqG46ty_Mm87fr8YdIwfr6a82OUXU7yZe6S-Py9hZg,5345
|
|
141
140
|
cartography/intel/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -157,7 +156,7 @@ cartography/intel/aws/inspector.py,sha256=S22ZgRKEnmnBTJ-u0rodqRPB7_LkSIek47NeBx
|
|
|
157
156
|
cartography/intel/aws/kms.py,sha256=bZUzMxAH_DsAcGTJBs08gg2tLKYu-QWjvMvV9C-6v50,11731
|
|
158
157
|
cartography/intel/aws/lambda_function.py,sha256=KKTyn53xpaMI9WvIqxmsOASFwflHt-2_5ow-zUFc2wg,9890
|
|
159
158
|
cartography/intel/aws/organizations.py,sha256=HaQZ3J5XF15BuykuDypqFORDYpnoHuRRr4DuceewH4s,4485
|
|
160
|
-
cartography/intel/aws/permission_relationships.py,sha256=
|
|
159
|
+
cartography/intel/aws/permission_relationships.py,sha256=IarV9gt5BaplZ5TPo_mfypt9bTKfT9qDtqC3Ob89qGI,14904
|
|
161
160
|
cartography/intel/aws/rds.py,sha256=vnlNYmrO2Cc0PNn31CeG2QwYhwjVosbQFE9Ol1vQyLE,25252
|
|
162
161
|
cartography/intel/aws/redshift.py,sha256=KOqiXIllHmtPTeaNGl-cX4srY5pFE6o12j8MQ5-zWpc,6694
|
|
163
162
|
cartography/intel/aws/resourcegroupstaggingapi.py,sha256=aq4kPF6t8QZZoTxdkQVLXH65Di41CDJVM9llJNe6iaY,10278
|
|
@@ -206,8 +205,6 @@ cartography/intel/crowdstrike/__init__.py,sha256=dAtgI-0vZAQZ3cTFQhMEzzt7aqiNSNu
|
|
|
206
205
|
cartography/intel/crowdstrike/endpoints.py,sha256=tdqokMDW3p4fK3dHKKb2T1DTogvOJBCpwyrxdQlbUhw,3815
|
|
207
206
|
cartography/intel/crowdstrike/spotlight.py,sha256=yNhj44-RYF6ubck-hHMKhKiNU0fCfhQf4Oagopc31EM,4754
|
|
208
207
|
cartography/intel/crowdstrike/util.py,sha256=gfJ6Ptr6YdbBS9Qj9a_-Jc-IJroADDRcXqjh5TW0qXE,277
|
|
209
|
-
cartography/intel/crxcavator/__init__.py,sha256=VM6N_7dMagzuQQjUeFgqrt2_d2Is9ugDMTrgKke2c0g,1606
|
|
210
|
-
cartography/intel/crxcavator/crxcavator.py,sha256=tnx6bq8Oz020mhMDmx8gKZ_ro_0UvUGeWrshmFr7bBw,13797
|
|
211
208
|
cartography/intel/cve/__init__.py,sha256=A7XjKQSanmwMSIXSum1qJSegtYcQCuz_713RU-bFQz8,2504
|
|
212
209
|
cartography/intel/cve/feed.py,sha256=JkfRV18JoydOuncKR1y3s8esuN2Xk4gIB6viKNXU_X0,10020
|
|
213
210
|
cartography/intel/digitalocean/__init__.py,sha256=SMYB7LGIQOj_EgGSGVjWZk7SJNbP43hQuOfgOu6xYm4,1526
|
|
@@ -222,7 +219,7 @@ cartography/intel/duo/phones.py,sha256=ueJheqSLD2xYcMus5eOiixPYS3_xVjgQzeomjV2a6
|
|
|
222
219
|
cartography/intel/duo/tokens.py,sha256=bEEnjfc4waQnkRHVSnZLAeGE8wHOOZL7FA9m80GGQdQ,2396
|
|
223
220
|
cartography/intel/duo/users.py,sha256=lc7ly_XKeUjJ50szw31WT_GiCrZfGKJv1zVUpmTchh4,4097
|
|
224
221
|
cartography/intel/duo/web_authn_credentials.py,sha256=IbDf3CWqfEyI7f9zJugUvoDd6vZOECfb_7ANZaRYzuk,2636
|
|
225
|
-
cartography/intel/gcp/__init__.py,sha256=
|
|
222
|
+
cartography/intel/gcp/__init__.py,sha256=jJOT6Ys97qm1W0jGXFwtSOOSGPa7q-Xxr1YIR8fKejo,15849
|
|
226
223
|
cartography/intel/gcp/compute.py,sha256=CH2cBdOwbLZCAbkfRJkkI-sFybXVKRWEUGDJANQmvyA,48333
|
|
227
224
|
cartography/intel/gcp/crm.py,sha256=Uw5PILhVFhpM8gq7uu2v7F_YikDW3gsTZ3d7-e8Z1_k,12324
|
|
228
225
|
cartography/intel/gcp/dns.py,sha256=y2pvbmV04cnrMyuu_nbW3oc7uwHX6yEzn1n7veCsjmk,7748
|
|
@@ -238,7 +235,7 @@ cartography/intel/gsuite/api.py,sha256=J0dkNdfBVMrEv8vvStQu7YKVxXSyV45WueFhUS4aO
|
|
|
238
235
|
cartography/intel/jamf/__init__.py,sha256=Nof-LrUeevoieo6oP2GyfTwx8k5TUIgreW6hSj53YjQ,419
|
|
239
236
|
cartography/intel/jamf/computers.py,sha256=EfjlupQ-9HYTjOrmuwrGuJDy9ApAnJvk8WrYcp6_Jkk,1673
|
|
240
237
|
cartography/intel/jamf/util.py,sha256=EAyP8VpOY2uAvW3HtX6r7qORNjGa1Tr3fuqezuLQ0j4,1017
|
|
241
|
-
cartography/intel/kandji/__init__.py,sha256=
|
|
238
|
+
cartography/intel/kandji/__init__.py,sha256=Y38bVRmrGVJRy0mSof8xU-cuEyJ7N_oI7KekYjYyuiQ,1076
|
|
242
239
|
cartography/intel/kandji/devices.py,sha256=j_rP6rQ5VPT_XEcGXx7Yt6eCOm1Oe3I2qWIxXODXEcA,2224
|
|
243
240
|
cartography/intel/kubernetes/__init__.py,sha256=jaOTEanWnTrYvcBN1XUC5oqBhz1AJbFmzoT9uu_VBSg,1481
|
|
244
241
|
cartography/intel/kubernetes/namespaces.py,sha256=6o-FgAX_Ai5NCj2xOWM-RNWEvn0gZjVQnZSGCJlcIhw,2710
|
|
@@ -271,7 +268,11 @@ cartography/intel/pagerduty/teams.py,sha256=aRubUXgEVVReyLrXAX_be1E_QBJv3Qlr4n77
|
|
|
271
268
|
cartography/intel/pagerduty/users.py,sha256=oltGssxrnzYsV6QTGP1SsPoA1rCUDStj6vGlGWY695g,1623
|
|
272
269
|
cartography/intel/pagerduty/vendors.py,sha256=WlDHExrWRBegDQKtxBV5nJiYgwoTLxNee4HrQDJ-Pdg,1559
|
|
273
270
|
cartography/intel/semgrep/__init__.py,sha256=94vjdszGEosvXiKtYWKD34BRKwRbJxlBO1PZcKdxnFA,619
|
|
274
|
-
cartography/intel/semgrep/findings.py,sha256=
|
|
271
|
+
cartography/intel/semgrep/findings.py,sha256=9MSbDFrRUqb5nkEWN0R9Fx57RJMt27-9obpIHXNd45Y,10836
|
|
272
|
+
cartography/intel/snipeit/__init__.py,sha256=0uIh8NbuI7IbfgaOrPHg4Nfm1yO6mTRC_qaFiIjR2FA,992
|
|
273
|
+
cartography/intel/snipeit/asset.py,sha256=KkGRUgIydvf_6SHtgpVLT-TjtEGz029SrOaoh0qDW6E,1997
|
|
274
|
+
cartography/intel/snipeit/user.py,sha256=hm9v_p29bphHtGe9LKVo1FD_rQcbCigrCRf8YsmteXA,1971
|
|
275
|
+
cartography/intel/snipeit/util.py,sha256=fXlzdFQXm01Oaa2REYNN7x3y3k2l3zCVhf_BxcRUELY,1040
|
|
275
276
|
cartography/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
276
277
|
cartography/models/aws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
277
278
|
cartography/models/aws/emr.py,sha256=TkuwoZnw_VHbJ5bwkac7-ZfwSLe_TeK3gxkuwGQOUk4,3037
|
|
@@ -330,12 +331,15 @@ cartography/models/lastpass/tenant.py,sha256=TG-9LFo9Sfzb9UgcTt_gFVTKocLItbgQMMP
|
|
|
330
331
|
cartography/models/lastpass/user.py,sha256=SMTTYN6jgccc9k76hY3rVImElJOhHhZ9f1aZ6JzcrHw,3487
|
|
331
332
|
cartography/models/semgrep/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
332
333
|
cartography/models/semgrep/deployment.py,sha256=or5qZDuR51MXzINpH15jZrqmSUvXQevCNYWJ7D6v-JI,745
|
|
333
|
-
cartography/models/semgrep/findings.py,sha256=
|
|
334
|
+
cartography/models/semgrep/findings.py,sha256=RPd-QzvP38fbTIqFARx6XpcZSsd5JM3KIg-ZlJA7NlE,5490
|
|
334
335
|
cartography/models/semgrep/locations.py,sha256=kSk7Nn5Mn4Ob84MVZOo2GR0YFi-9Okq9pgA3FfC6_bk,3061
|
|
335
|
-
cartography
|
|
336
|
-
cartography
|
|
337
|
-
cartography
|
|
338
|
-
cartography
|
|
339
|
-
cartography-0.
|
|
340
|
-
cartography-0.
|
|
341
|
-
cartography-0.
|
|
336
|
+
cartography/models/snipeit/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
337
|
+
cartography/models/snipeit/asset.py,sha256=FyRAaeXuZjMy0eUQcSDFcgEAF5lbLMlvqp1Tv9d3Lv4,3238
|
|
338
|
+
cartography/models/snipeit/tenant.py,sha256=p4rFnpNNuF1W5ilGBbexDaETWTwavfb38RcQGoImkQI,679
|
|
339
|
+
cartography/models/snipeit/user.py,sha256=MsB4MiCVNTH6JpESime7cOkB89autZOXQpL6Z0l7L6o,2113
|
|
340
|
+
cartography-0.95.0rc1.dist-info/LICENSE,sha256=kvLEBRYaQ1RvUni6y7Ti9uHeooqnjPoo6n_-0JO1ETc,11351
|
|
341
|
+
cartography-0.95.0rc1.dist-info/METADATA,sha256=t7FVdB2ipkDkwlWl-x_N60Oaa_1VBd30eU0virQyKOE,1966
|
|
342
|
+
cartography-0.95.0rc1.dist-info/WHEEL,sha256=OVMc5UfuAQiSplgO0_WdW7vXVGAt9Hdd6qtN4HotdyA,91
|
|
343
|
+
cartography-0.95.0rc1.dist-info/entry_points.txt,sha256=GVIAWD0o0_K077qMA_k1oZU4v-M0a8GLKGJR8tZ-qH8,112
|
|
344
|
+
cartography-0.95.0rc1.dist-info/top_level.txt,sha256=BHqsNJQiI6Q72DeypC1IINQJE59SLhU4nllbQjgJi9g,12
|
|
345
|
+
cartography-0.95.0rc1.dist-info/RECORD,,
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"statements": [{
|
|
3
|
-
"query": "MATCH (n:ChromeExtension) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
4
|
-
"iterative": true,
|
|
5
|
-
"iterationsize": 100
|
|
6
|
-
},
|
|
7
|
-
{
|
|
8
|
-
"query": "MATCH (n:GSuiteUser) WHERE n.lastupdated <> $UPDATE_TAG WITH n LIMIT $LIMIT_SIZE DETACH DELETE (n)",
|
|
9
|
-
"iterative": true,
|
|
10
|
-
"iterationsize": 100
|
|
11
|
-
},
|
|
12
|
-
{
|
|
13
|
-
"query": "MATCH (GSuiteUser)-[r:INSTALLS]->(:ChromeExtension) WHERE r.lastupdated <> $UPDATE_TAG WITH r LIMIT $LIMIT_SIZE DELETE (r)",
|
|
14
|
-
"iterative": true,
|
|
15
|
-
"iterationsize": 100
|
|
16
|
-
}],
|
|
17
|
-
"name": "cleanup CRXcavator extensions"
|
|
18
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import logging
|
|
2
|
-
|
|
3
|
-
import neo4j
|
|
4
|
-
from requests import exceptions
|
|
5
|
-
|
|
6
|
-
from cartography.config import Config
|
|
7
|
-
from cartography.intel.crxcavator.crxcavator import sync_extensions
|
|
8
|
-
from cartography.util import run_cleanup_job
|
|
9
|
-
from cartography.util import timeit
|
|
10
|
-
|
|
11
|
-
logger = logging.getLogger(__name__)
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
@timeit
|
|
15
|
-
def start_extension_ingestion(neo4j_session: neo4j.Session, config: Config) -> None:
|
|
16
|
-
"""
|
|
17
|
-
If this module is configured, perform ingestion of CRXcavator data. Otherwise warn and exit
|
|
18
|
-
:param neo4j_session: Neo4J session for database interface
|
|
19
|
-
:param config: A cartography.config object
|
|
20
|
-
:return: None
|
|
21
|
-
"""
|
|
22
|
-
if not config.crxcavator_api_base_uri or not config.crxcavator_api_key:
|
|
23
|
-
logger.warning('CRXcavator import is not configured - skipping this module. See docs to configure.')
|
|
24
|
-
return
|
|
25
|
-
|
|
26
|
-
common_job_parameters = {
|
|
27
|
-
"UPDATE_TAG": config.update_tag,
|
|
28
|
-
}
|
|
29
|
-
# while we typically want to crash sync on failure of module,
|
|
30
|
-
# the crxcavator API is still in beta and is not always available.
|
|
31
|
-
# if we receive a requests exception from raise_for_status
|
|
32
|
-
# we'll handle and continue with other modules, otherwise crash sync
|
|
33
|
-
try:
|
|
34
|
-
sync_extensions(
|
|
35
|
-
neo4j_session, common_job_parameters, config.crxcavator_api_key,
|
|
36
|
-
config.crxcavator_api_base_uri,
|
|
37
|
-
)
|
|
38
|
-
run_cleanup_job(
|
|
39
|
-
'crxcavator_import_cleanup.json',
|
|
40
|
-
neo4j_session,
|
|
41
|
-
common_job_parameters,
|
|
42
|
-
)
|
|
43
|
-
except exceptions.RequestException as e:
|
|
44
|
-
logger.error("Could not complete request to the CRXcavator API: {}", e)
|
|
@@ -1,329 +0,0 @@
|
|
|
1
|
-
import json
|
|
2
|
-
import logging
|
|
3
|
-
from typing import Any
|
|
4
|
-
from typing import Dict
|
|
5
|
-
from typing import List
|
|
6
|
-
from typing import Tuple
|
|
7
|
-
|
|
8
|
-
import neo4j
|
|
9
|
-
import requests.auth
|
|
10
|
-
from requests import exceptions
|
|
11
|
-
|
|
12
|
-
from cartography.util import timeit
|
|
13
|
-
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
# Connect and read timeouts of 60 seconds each; see https://requests.readthedocs.io/en/master/user/advanced/#timeouts
|
|
16
|
-
_TIMEOUT = (60, 60)
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
@timeit
|
|
20
|
-
def get_extension_details(
|
|
21
|
-
crxcavator_api_key: str, crxcavator_base_url: str, extension_id: str,
|
|
22
|
-
version: str,
|
|
23
|
-
) -> List[Dict]:
|
|
24
|
-
"""
|
|
25
|
-
Get metadata for the specific extension_id and version number provided
|
|
26
|
-
:param crxcavator_api_key: The API key to access the CRXcavator service
|
|
27
|
-
:param crxcavator_base_url: The URL for the CRXcavator API
|
|
28
|
-
:param extension_id: The extension id to request metadata for
|
|
29
|
-
:param version: The version number of the extension to request metadata for
|
|
30
|
-
:return: JSON text blob containing all extension metadata defined at
|
|
31
|
-
https://crxcavator.io/apidocs#tag/group/paths/~1group~1extensions~1combined/get
|
|
32
|
-
"""
|
|
33
|
-
return call_crxcavator_api(f"/report/{extension_id}/{version}", crxcavator_api_key, crxcavator_base_url)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
@timeit
|
|
37
|
-
def get_users_extensions(crxcavator_api_key: str, crxcavator_base_url: str) -> List[Dict]:
|
|
38
|
-
"""
|
|
39
|
-
Gets listing of all users who have installed each extension
|
|
40
|
-
:param crxcavator_api_key: The API key to access the CRXcavator service
|
|
41
|
-
:param crxcavator_base_url: The URL for the CRXcavator API
|
|
42
|
-
:return: JSON text blob containing user email to extension id mapping defined at
|
|
43
|
-
https://crxcavator.io/apidocs#tag/group/paths/~1group~1users~1extensions/get
|
|
44
|
-
"""
|
|
45
|
-
return call_crxcavator_api("/group/users/extensions", crxcavator_api_key, crxcavator_base_url)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@timeit
|
|
49
|
-
def call_crxcavator_api(api_and_parameters: str, crxcavator_api_key: str, crxcavator_base_url: str) -> List[Dict]:
|
|
50
|
-
"""
|
|
51
|
-
Perform the call requested to the CRXcavator API
|
|
52
|
-
:param crxcavator_api_key: The API key to access the CRXcavator service
|
|
53
|
-
:param crxcavator_base_url: The URL for the CRXcavator API
|
|
54
|
-
:param api_and_parameters: Query string for the API including the required parameters
|
|
55
|
-
:return: Returns JSON text blob for the API called. API spec is at https://crxcavator.io/apidocs
|
|
56
|
-
"""
|
|
57
|
-
uri = crxcavator_base_url + api_and_parameters
|
|
58
|
-
try:
|
|
59
|
-
data = requests.get(
|
|
60
|
-
uri,
|
|
61
|
-
headers={
|
|
62
|
-
'Accept': 'application/json',
|
|
63
|
-
'API-Key': crxcavator_api_key,
|
|
64
|
-
},
|
|
65
|
-
timeout=_TIMEOUT,
|
|
66
|
-
)
|
|
67
|
-
except requests.exceptions.Timeout as e:
|
|
68
|
-
# Add context and re-raise for callers to handle
|
|
69
|
-
logger.warning(f"requests.get('{uri}') timed out", e)
|
|
70
|
-
raise
|
|
71
|
-
# if call failed, use requests library to raise an exception
|
|
72
|
-
data.raise_for_status()
|
|
73
|
-
return data.json()
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
@timeit
|
|
77
|
-
def get_extensions(crxcavator_api_key: str, crxcavator_base_url: str, extensions_list: List[Dict]) -> List[Dict]:
|
|
78
|
-
"""
|
|
79
|
-
Retrieves the detailed information for all the extension_id and version pairs
|
|
80
|
-
:param crxcavator_api_key: The API key to access the CRXcavator service
|
|
81
|
-
:param crxcavator_base_url: The URL for the CRXcavator API
|
|
82
|
-
:param extensions_list: list of dictonary items containing the extension_id and version pairs
|
|
83
|
-
:return: list containing all metadata for extensions
|
|
84
|
-
"""
|
|
85
|
-
extensions_details: List[Dict] = []
|
|
86
|
-
for extension in extensions_list:
|
|
87
|
-
extension_id = extension['extension_id']
|
|
88
|
-
version = extension['version']
|
|
89
|
-
name = extension['name']
|
|
90
|
-
try:
|
|
91
|
-
details = get_extension_details(crxcavator_api_key, crxcavator_base_url, extension_id, version)
|
|
92
|
-
if not details:
|
|
93
|
-
# we only have the name and version from group API, create minimal version
|
|
94
|
-
logger.debug(f"No results returned from report API for extension {extension_id} {version}")
|
|
95
|
-
details = {
|
|
96
|
-
'data': dict(
|
|
97
|
-
webstore={
|
|
98
|
-
'name': name,
|
|
99
|
-
},
|
|
100
|
-
), 'extension_id': extension_id, 'version': version,
|
|
101
|
-
}
|
|
102
|
-
extensions_details.append(details)
|
|
103
|
-
except exceptions.RequestException as e:
|
|
104
|
-
logger.info(f"API error retrieving details for extension {extension_id}", e)
|
|
105
|
-
except requests.exceptions.Timeout:
|
|
106
|
-
logger.info(f"Skipping {extension_id} due to timeout; continuing")
|
|
107
|
-
continue
|
|
108
|
-
return extensions_details
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
@timeit
|
|
112
|
-
def transform_extensions(extension_details: List[Dict]) -> List[Dict]:
|
|
113
|
-
"""
|
|
114
|
-
Transforms the raw extensions JSON from the API into a list of extensions data
|
|
115
|
-
:param extension_details: List containing the extension details
|
|
116
|
-
:return: List containing extension info for ingestion
|
|
117
|
-
"""
|
|
118
|
-
# the JSON returned from the CRXcavator API does not return well formatted objects
|
|
119
|
-
# instead, each object is named after it's key, making enumeration more difficult
|
|
120
|
-
# will build a cleaner object for import into graph
|
|
121
|
-
|
|
122
|
-
extensions: List[Dict] = []
|
|
123
|
-
for extension in extension_details:
|
|
124
|
-
extension_id = extension['extension_id']
|
|
125
|
-
version = extension['version']
|
|
126
|
-
data = extension.get('data')
|
|
127
|
-
if not data:
|
|
128
|
-
logger.warning(f'Could not retrieve details for extension {extension}')
|
|
129
|
-
continue
|
|
130
|
-
risk = data.get('risk', {})
|
|
131
|
-
webstore = data.get('webstore', {})
|
|
132
|
-
extensions.append({
|
|
133
|
-
'id': f"{extension_id}|{version}",
|
|
134
|
-
'extension_id': extension_id,
|
|
135
|
-
'version': version,
|
|
136
|
-
'risk_total': risk.get('total', 0),
|
|
137
|
-
'risk_permissions_score': get_risk_data(risk, 'permissions'),
|
|
138
|
-
'risk_webstore_score': get_risk_data(risk, 'webstore'),
|
|
139
|
-
'risk_metadata': json.dumps(risk.get('metadata')),
|
|
140
|
-
'risk_optional_permissions_score': get_risk_data(risk, 'optional_permissions'),
|
|
141
|
-
'risk_csp_score': get_risk_data(risk, 'csp'),
|
|
142
|
-
'risk_extcalls_score': get_risk_data(risk, 'extcalls'),
|
|
143
|
-
'risk_vuln_score': get_risk_data(risk, 'retire'),
|
|
144
|
-
'address': webstore.get('address'),
|
|
145
|
-
'email': webstore.get('email'),
|
|
146
|
-
'icon': webstore.get('icon'),
|
|
147
|
-
'crxcavator_last_updated': webstore.get('last_updated'),
|
|
148
|
-
'name': webstore.get('name'),
|
|
149
|
-
'offered_by': webstore.get('offered_by'),
|
|
150
|
-
'permissions_warnings': webstore.get('permission_warnings'),
|
|
151
|
-
'privacy_policy': webstore.get('privacy_policy'),
|
|
152
|
-
'rating': webstore.get('rating'),
|
|
153
|
-
'rating_users': webstore.get('rating_users'),
|
|
154
|
-
'short_description': webstore.get('short_description'),
|
|
155
|
-
'size': webstore.get('size'),
|
|
156
|
-
'support_site': webstore.get('support_site'),
|
|
157
|
-
'users': webstore.get('users'),
|
|
158
|
-
'website': webstore.get('website'),
|
|
159
|
-
'type': webstore.get('type'),
|
|
160
|
-
'price': webstore.get('price'),
|
|
161
|
-
'report_link': f"https://crxcavator.io/report/{extension_id}/{version}",
|
|
162
|
-
})
|
|
163
|
-
return extensions
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
@timeit
|
|
167
|
-
def get_risk_data(data_dict: Dict, key: str) -> int:
|
|
168
|
-
"""
|
|
169
|
-
Gets the total risk value from the provided key and returns the value else 0
|
|
170
|
-
:param data_dict: input data dictionary to parse
|
|
171
|
-
:param key: key name to retrieve
|
|
172
|
-
:return:
|
|
173
|
-
"""
|
|
174
|
-
data = data_dict.get(key)
|
|
175
|
-
data_score = data.get('total', 0) if data else 0
|
|
176
|
-
return data_score
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
@timeit
|
|
180
|
-
def load_extensions(extensions: List[Dict], neo4j_session: neo4j.Session, update_tag: int) -> None:
|
|
181
|
-
"""
|
|
182
|
-
Ingests the extension details into Neo4J
|
|
183
|
-
:param extensions: List of extension data to load to Neo4J
|
|
184
|
-
:param session: Neo4J session object for server communication
|
|
185
|
-
:param update_tag: Timestamp used to determine data freshness
|
|
186
|
-
:return: None
|
|
187
|
-
"""
|
|
188
|
-
ingestion_cypher = """
|
|
189
|
-
UNWIND $ExtensionsData as extension
|
|
190
|
-
MERGE (e:ChromeExtension{id: extension.id})
|
|
191
|
-
ON CREATE SET
|
|
192
|
-
e.extension_id = extension.extension_id,
|
|
193
|
-
e.version = extension.version,
|
|
194
|
-
e.firstseen = timestamp()
|
|
195
|
-
SET
|
|
196
|
-
e.extcalls = extension.extcalls,
|
|
197
|
-
e.risk_total = extension.risk_total,
|
|
198
|
-
e.risk_permissions_score = extension.risk_permissions_score,
|
|
199
|
-
e.risk_metadata = extension.risk_metadata,
|
|
200
|
-
e.risk_webstore_score = extension.risk_webstore_score,
|
|
201
|
-
e.risk_optional_permissions_score = extension.risk_optional_permissions_score,
|
|
202
|
-
e.risk_csp_score = extension.risk_csp_score,
|
|
203
|
-
e.risk_extcalls_score = extension.risk_extcalls_score,
|
|
204
|
-
e.risk_vuln_score = extension.risk_vuln_score,
|
|
205
|
-
e.address = extension.address,
|
|
206
|
-
e.email = extension.email,
|
|
207
|
-
e.icon = extension.icon,
|
|
208
|
-
e.crxcavator_last_updated = extension.crxcavator_last_updated,
|
|
209
|
-
e.name = extension.name,
|
|
210
|
-
e.offered_by = extension.offered_by,
|
|
211
|
-
e.permissions_warnings = extension.permissions_warnings,
|
|
212
|
-
e.privacy_policy = extension.privacy_policy,
|
|
213
|
-
e.rating = extension.rating,
|
|
214
|
-
e.rating_users = extension.rating_users,
|
|
215
|
-
e.short_description = extension.short_description,
|
|
216
|
-
e.size = extension.size,
|
|
217
|
-
e.support_site = extension.support_site,
|
|
218
|
-
e.users = extension.users,
|
|
219
|
-
e.website = extension.website,
|
|
220
|
-
e.type = extension.type,
|
|
221
|
-
e.price = extension.price,
|
|
222
|
-
e.report_link = extension.report_link,
|
|
223
|
-
e.lastupdated = $UpdateTag
|
|
224
|
-
"""
|
|
225
|
-
|
|
226
|
-
logger.info(f'Ingesting {len(extensions)} extensions')
|
|
227
|
-
neo4j_session.run(ingestion_cypher, ExtensionsData=extensions, UpdateTag=update_tag)
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
@timeit
|
|
231
|
-
def transform_user_extensions(user_extension_json: Dict) -> Tuple[List[Any], List[Dict], List[Dict]]:
|
|
232
|
-
"""
|
|
233
|
-
Transforms the raw extensions JSON from the API into a list of extensions mapped to users
|
|
234
|
-
:param user_extension_json: The JSON text blob returned from the CRXcavator API
|
|
235
|
-
:return: Tuple containing unique users list, unique extension list, and extension mapping for ingestion
|
|
236
|
-
"""
|
|
237
|
-
user_extensions = user_extension_json.items()
|
|
238
|
-
users_set = set()
|
|
239
|
-
extensions: List[Dict] = []
|
|
240
|
-
extensions_by_user: List[Dict] = []
|
|
241
|
-
for extension in user_extensions:
|
|
242
|
-
for details in extension[1].items():
|
|
243
|
-
extension_id = extension[0]
|
|
244
|
-
version = details[0]
|
|
245
|
-
extensions.append({
|
|
246
|
-
'extension_id': extension_id,
|
|
247
|
-
'version': version,
|
|
248
|
-
'name': details[1]['name'],
|
|
249
|
-
})
|
|
250
|
-
for user in details[1]['users']:
|
|
251
|
-
if user is None:
|
|
252
|
-
logger.info(f'bad user for {extension_id}{version}')
|
|
253
|
-
continue
|
|
254
|
-
users_set.add(user)
|
|
255
|
-
extensions_by_user.append({
|
|
256
|
-
'id': f"{extension_id}|{version}",
|
|
257
|
-
'user': user,
|
|
258
|
-
})
|
|
259
|
-
if len(users_set) == 0:
|
|
260
|
-
raise ValueError('No users returned from CRXcavator')
|
|
261
|
-
if len(extensions) == 0:
|
|
262
|
-
raise ValueError('No extensions information returned from CRXcavator')
|
|
263
|
-
if len(extensions_by_user) == 0:
|
|
264
|
-
raise ValueError('No user->extension mapping returned from CRXcavator')
|
|
265
|
-
|
|
266
|
-
return list(users_set), extensions, extensions_by_user
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
@timeit
|
|
270
|
-
def load_user_extensions(
|
|
271
|
-
users: List[Dict], extensions_by_user: Dict, neo4j_session: neo4j.Session,
|
|
272
|
-
update_tag: int,
|
|
273
|
-
) -> None:
|
|
274
|
-
"""
|
|
275
|
-
Ingests the extension to user mapping details into Neo4J
|
|
276
|
-
:param users: List of user objects to create for mapping
|
|
277
|
-
:param extensions_by_user: List of user to extension id mappings
|
|
278
|
-
:param session: Neo4J session object for server communication
|
|
279
|
-
:param update_tag: Timestamp used to determine data freshness
|
|
280
|
-
:return: None
|
|
281
|
-
"""
|
|
282
|
-
|
|
283
|
-
user_ingestion_cypher = """
|
|
284
|
-
UNWIND $Users as user_email
|
|
285
|
-
MERGE (user:GSuiteUser{email: user_email})
|
|
286
|
-
ON CREATE SET
|
|
287
|
-
user.firstseen = timestamp()
|
|
288
|
-
SET user.lastupdated = $UpdateTag
|
|
289
|
-
"""
|
|
290
|
-
|
|
291
|
-
extension_ingestion_cypher = """
|
|
292
|
-
UNWIND $ExtensionsUsers as extension_user
|
|
293
|
-
MATCH (user:GSuiteUser{email: extension_user.user}),(ext:ChromeExtension{id:extension_user.id})
|
|
294
|
-
MERGE (user)-[r:INSTALLS]->(ext)
|
|
295
|
-
ON CREATE SET
|
|
296
|
-
r.firstseen = timestamp()
|
|
297
|
-
SET r.lastupdated = $UpdateTag
|
|
298
|
-
"""
|
|
299
|
-
|
|
300
|
-
logger.info(f'Ingesting {len(users)} users')
|
|
301
|
-
neo4j_session.run(user_ingestion_cypher, Users=users, UpdateTag=update_tag)
|
|
302
|
-
logger.info(f'Ingesting {len(extensions_by_user)} user->extension relationships')
|
|
303
|
-
neo4j_session.run(extension_ingestion_cypher, ExtensionsUsers=extensions_by_user, UpdateTag=update_tag)
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
@timeit
|
|
307
|
-
def sync_extensions(
|
|
308
|
-
neo4j_session: neo4j.Session, common_job_parameters: Dict, crxcavator_api_key: str,
|
|
309
|
-
crxcavator_base_url: str,
|
|
310
|
-
) -> None:
|
|
311
|
-
"""
|
|
312
|
-
Performs the sequential tasks to collect, transform, and sync extension data
|
|
313
|
-
:param neo4j_session: Neo4J session for database interface
|
|
314
|
-
:param common_job_parameters: Common job parameters containing UPDATE_TAG
|
|
315
|
-
:param crxcavator_api_key: The API key to access the CRXcavator service
|
|
316
|
-
:param crxcavator_base_url: The URL for the CRXcavator API
|
|
317
|
-
:return: None
|
|
318
|
-
"""
|
|
319
|
-
|
|
320
|
-
try:
|
|
321
|
-
user_extensions_json = get_users_extensions(crxcavator_api_key, crxcavator_base_url)
|
|
322
|
-
except requests.exceptions.Timeout:
|
|
323
|
-
logger.warning("get_users_extensions() failed due to timeout. Skipping CRXcavator sync.")
|
|
324
|
-
return
|
|
325
|
-
users, extensions_list, user_extensions = transform_user_extensions(user_extensions_json)
|
|
326
|
-
extension_details = get_extensions(crxcavator_api_key, crxcavator_base_url, extensions_list)
|
|
327
|
-
extensions = transform_extensions(extension_details)
|
|
328
|
-
load_extensions(extensions, neo4j_session, common_job_parameters['UPDATE_TAG'])
|
|
329
|
-
load_user_extensions(users, user_extensions, neo4j_session, common_job_parameters['UPDATE_TAG'])
|
|
File without changes
|
|
File without changes
|