synapse 2.185.0__py311-none-any.whl → 2.187.0__py311-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 synapse might be problematic. Click here for more details.
- synapse/cortex.py +5 -4
- synapse/exc.py +2 -0
- synapse/lib/ast.py +1 -1
- synapse/lib/cell.py +65 -2
- synapse/lib/drive.py +45 -10
- synapse/lib/hive.py +1 -1
- synapse/lib/modelrev.py +771 -11
- synapse/lib/snap.py +0 -6
- synapse/lib/spooled.py +26 -3
- synapse/lib/storm.py +7 -0
- synapse/lib/stormlib/model.py +320 -250
- synapse/lib/stormtypes.py +36 -10
- synapse/lib/types.py +6 -0
- synapse/lib/version.py +2 -2
- synapse/models/infotech.py +49 -22
- synapse/models/risk.py +3 -0
- synapse/tests/test_cortex.py +10 -5
- synapse/tests/test_lib_base.py +2 -2
- synapse/tests/test_lib_cell.py +16 -4
- synapse/tests/test_lib_modelrev.py +918 -379
- synapse/tests/test_lib_spooled.py +34 -0
- synapse/tests/test_lib_stormlib_model.py +0 -270
- synapse/tests/test_lib_stormtypes.py +11 -0
- synapse/tests/test_model_infotech.py +14 -11
- synapse/tests/test_model_risk.py +2 -0
- synapse/tests/test_tools_snapshot.py +47 -0
- synapse/tools/aha/clone.py +3 -1
- synapse/tools/aha/easycert.py +1 -1
- synapse/tools/aha/enroll.py +3 -1
- synapse/tools/aha/provision/service.py +3 -1
- synapse/tools/aha/provision/user.py +3 -1
- synapse/tools/changelog.py +11 -3
- synapse/tools/livebackup.py +3 -1
- synapse/tools/promote.py +9 -3
- synapse/tools/snapshot.py +69 -0
- {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/METADATA +1 -1
- {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/RECORD +40 -41
- {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/WHEEL +1 -1
- synapse/assets/__init__.py +0 -35
- synapse/assets/storm/migrations/model-0.2.28.storm +0 -355
- synapse/tests/test_assets.py +0 -25
- {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/LICENSE +0 -0
- {synapse-2.185.0.dist-info → synapse-2.187.0.dist-info}/top_level.txt +0 -0
synapse/lib/modelrev.py
CHANGED
|
@@ -2,14 +2,18 @@ import regex
|
|
|
2
2
|
import logging
|
|
3
3
|
|
|
4
4
|
import synapse.exc as s_exc
|
|
5
|
-
import synapse.assets as s_assets
|
|
6
5
|
import synapse.common as s_common
|
|
7
6
|
|
|
7
|
+
import synapse.lib.cache as s_cache
|
|
8
8
|
import synapse.lib.layer as s_layer
|
|
9
|
+
import synapse.lib.msgpack as s_msgpack
|
|
10
|
+
import synapse.lib.spooled as s_spooled
|
|
11
|
+
|
|
12
|
+
import synapse.models.infotech as s_infotech
|
|
9
13
|
|
|
10
14
|
logger = logging.getLogger(__name__)
|
|
11
15
|
|
|
12
|
-
maxvers = (0, 2,
|
|
16
|
+
maxvers = (0, 2, 31)
|
|
13
17
|
|
|
14
18
|
class ModelRev:
|
|
15
19
|
|
|
@@ -45,6 +49,7 @@ class ModelRev:
|
|
|
45
49
|
# Model revision 0.2.28 skipped
|
|
46
50
|
((0, 2, 29), self.revModel_0_2_29),
|
|
47
51
|
((0, 2, 30), self.revModel_0_2_30),
|
|
52
|
+
((0, 2, 31), self.revModel_0_2_31),
|
|
48
53
|
)
|
|
49
54
|
|
|
50
55
|
async def _uniqSortArray(self, todoprops, layers):
|
|
@@ -791,15 +796,6 @@ class ModelRev:
|
|
|
791
796
|
async def revModel_0_2_27(self, layers):
|
|
792
797
|
await self._normPropValu(layers, 'it:dev:repo:commit:id')
|
|
793
798
|
|
|
794
|
-
async def revModel_0_2_28(self, layers):
|
|
795
|
-
|
|
796
|
-
opts = {'vars': {
|
|
797
|
-
'layridens': [layr.iden for layr in layers],
|
|
798
|
-
}}
|
|
799
|
-
|
|
800
|
-
text = s_assets.getStorm('migrations', 'model-0.2.28.storm')
|
|
801
|
-
await self.runStorm(text, opts=opts)
|
|
802
|
-
|
|
803
799
|
async def revModel_0_2_29(self, layers):
|
|
804
800
|
await self._propToForm(layers, 'ou:industry:type', 'ou:industry:type:taxonomy')
|
|
805
801
|
|
|
@@ -814,6 +810,11 @@ class ModelRev:
|
|
|
814
810
|
await self._normFormSubs(layers, 'inet:ipv6', cmprvalu='2001:20::/28')
|
|
815
811
|
await self._normFormSubs(layers, 'inet:ipv6', cmprvalu='2001:30::/28')
|
|
816
812
|
|
|
813
|
+
async def revModel_0_2_31(self, layers):
|
|
814
|
+
migr = await ModelMigration_0_2_31.anit(self.core, layers)
|
|
815
|
+
await migr.revModel_0_2_31()
|
|
816
|
+
await self._normFormSubs(layers, 'it:sec:cpe')
|
|
817
|
+
|
|
817
818
|
async def runStorm(self, text, opts=None):
|
|
818
819
|
'''
|
|
819
820
|
Run storm code in a schedcoro and log the output messages.
|
|
@@ -1205,3 +1206,762 @@ class ModelRev:
|
|
|
1205
1206
|
}
|
|
1206
1207
|
'''
|
|
1207
1208
|
await self.runStorm(storm, opts=opts)
|
|
1209
|
+
|
|
1210
|
+
class ModelMigration_0_2_31:
|
|
1211
|
+
@classmethod
|
|
1212
|
+
async def anit(cls, core, layers):
|
|
1213
|
+
self = cls()
|
|
1214
|
+
|
|
1215
|
+
self.core = core
|
|
1216
|
+
self.layers = layers
|
|
1217
|
+
|
|
1218
|
+
self.meta = {'time': s_common.now(), 'user': self.core.auth.rootuser.iden}
|
|
1219
|
+
|
|
1220
|
+
self.editcount = 0
|
|
1221
|
+
self.nodeedits = {}
|
|
1222
|
+
|
|
1223
|
+
self.nodes = await s_spooled.Dict.anit(dirn=self.core.dirn)
|
|
1224
|
+
self.todos = await s_spooled.Set.anit(dirn=self.core.dirn)
|
|
1225
|
+
|
|
1226
|
+
self.core.onfini(self.nodes)
|
|
1227
|
+
self.core.onfini(self.todos)
|
|
1228
|
+
|
|
1229
|
+
try:
|
|
1230
|
+
await self.core.getCoreQueue('model_0_2_31:nodes')
|
|
1231
|
+
self.hasq = True
|
|
1232
|
+
except s_exc.NoSuchName:
|
|
1233
|
+
self.hasq = False
|
|
1234
|
+
|
|
1235
|
+
return self
|
|
1236
|
+
|
|
1237
|
+
async def _queueEdit(self, layriden, edit):
|
|
1238
|
+
self.nodeedits.setdefault(layriden, {})
|
|
1239
|
+
buid, formname, edits = edit
|
|
1240
|
+
self.nodeedits[layriden].setdefault(buid, (buid, formname, []))
|
|
1241
|
+
self.nodeedits[layriden][buid][2].extend(edits)
|
|
1242
|
+
self.editcount += 1
|
|
1243
|
+
|
|
1244
|
+
if self.editcount >= 1000: # pragma: no cover
|
|
1245
|
+
await self._flushEdits()
|
|
1246
|
+
|
|
1247
|
+
async def _flushEdits(self):
|
|
1248
|
+
for layriden, layredits in self.nodeedits.items():
|
|
1249
|
+
layer = self.core.getLayer(layriden)
|
|
1250
|
+
if layer is None: # pragma: no cover
|
|
1251
|
+
continue
|
|
1252
|
+
|
|
1253
|
+
await layer.storNodeEditsNoLift(list(layredits.values()), self.meta)
|
|
1254
|
+
|
|
1255
|
+
self.editcount = 0
|
|
1256
|
+
self.nodeedits = {}
|
|
1257
|
+
|
|
1258
|
+
# NOTE: For the edit* functions below, we only need precise state tracking for nodes and properties. Don't precisely
|
|
1259
|
+
# track the rest.
|
|
1260
|
+
async def editNodeAdd(self, layriden, buid, formname, formvalu, stortype):
|
|
1261
|
+
if not self.nodes.has(buid):
|
|
1262
|
+
|
|
1263
|
+
node = {
|
|
1264
|
+
'formname': formname,
|
|
1265
|
+
'formvalu': formvalu,
|
|
1266
|
+
'sodes': {},
|
|
1267
|
+
'nodedata': {},
|
|
1268
|
+
'n1edges': {},
|
|
1269
|
+
'n2edges': {},
|
|
1270
|
+
}
|
|
1271
|
+
await self.nodes.set(buid, node)
|
|
1272
|
+
|
|
1273
|
+
await self._queueEdit(layriden,
|
|
1274
|
+
(buid, formname, (
|
|
1275
|
+
(s_layer.EDIT_NODE_ADD, (formvalu, stortype), ()),
|
|
1276
|
+
)),
|
|
1277
|
+
)
|
|
1278
|
+
|
|
1279
|
+
async def editPropSet(self, layriden, buid, formname, propname, newvalu, oldvalu, stortype):
|
|
1280
|
+
assert self.nodes.has(buid)
|
|
1281
|
+
node = self.getNode(buid)
|
|
1282
|
+
|
|
1283
|
+
sode = node['sodes'].get(layriden, {})
|
|
1284
|
+
node['sodes'][layriden] = sode
|
|
1285
|
+
|
|
1286
|
+
props = sode.get('props', {})
|
|
1287
|
+
sode['props'] = props
|
|
1288
|
+
|
|
1289
|
+
if oldvalu is not None:
|
|
1290
|
+
assert props.get(propname) == (oldvalu, stortype), f'GOT: {props.get(propname)} EXPECTED: {(oldvalu, stortype)}'
|
|
1291
|
+
props[propname] = (newvalu, stortype)
|
|
1292
|
+
|
|
1293
|
+
await self.nodes.set(buid, node)
|
|
1294
|
+
|
|
1295
|
+
await self._queueEdit(layriden,
|
|
1296
|
+
(buid, formname, (
|
|
1297
|
+
(s_layer.EDIT_PROP_SET, (propname, newvalu, oldvalu, stortype), ()),
|
|
1298
|
+
)),
|
|
1299
|
+
)
|
|
1300
|
+
|
|
1301
|
+
async def editTagSet(self, layriden, buid, formname, tagname, newvalu, oldvalu):
|
|
1302
|
+
await self._queueEdit(layriden,
|
|
1303
|
+
(buid, formname, (
|
|
1304
|
+
(s_layer.EDIT_TAG_SET, (tagname, newvalu, oldvalu), ()),
|
|
1305
|
+
)),
|
|
1306
|
+
)
|
|
1307
|
+
|
|
1308
|
+
async def editTagpropSet(self, layriden, buid, formname, tagname, propname, newvalu, oldvalu, stortype):
|
|
1309
|
+
await self._queueEdit(layriden,
|
|
1310
|
+
(buid, formname, (
|
|
1311
|
+
(s_layer.EDIT_TAGPROP_SET, (tagname, propname, newvalu, oldvalu, stortype), ()),
|
|
1312
|
+
)),
|
|
1313
|
+
)
|
|
1314
|
+
|
|
1315
|
+
async def editNodedataSet(self, layriden, buid, formname, name, newvalu, oldvalu):
|
|
1316
|
+
await self._queueEdit(layriden,
|
|
1317
|
+
(buid, formname, (
|
|
1318
|
+
(s_layer.EDIT_NODEDATA_SET, (name, newvalu, oldvalu), ()),
|
|
1319
|
+
)),
|
|
1320
|
+
)
|
|
1321
|
+
|
|
1322
|
+
async def editEdgeAdd(self, layriden, buid, formname, verb, iden):
|
|
1323
|
+
await self._queueEdit(layriden,
|
|
1324
|
+
(buid, formname, (
|
|
1325
|
+
(s_layer.EDIT_EDGE_ADD, (verb, iden), ()),
|
|
1326
|
+
)),
|
|
1327
|
+
)
|
|
1328
|
+
|
|
1329
|
+
async def editNodeDel(self, layriden, buid, formname, formvalu):
|
|
1330
|
+
assert self.nodes.has(buid)
|
|
1331
|
+
node = self.nodes.pop(buid)
|
|
1332
|
+
|
|
1333
|
+
for layriden in node['layers']:
|
|
1334
|
+
await self._queueEdit(layriden,
|
|
1335
|
+
(buid, formname, (
|
|
1336
|
+
(s_layer.EDIT_NODE_DEL, formvalu, ()),
|
|
1337
|
+
)),
|
|
1338
|
+
)
|
|
1339
|
+
|
|
1340
|
+
async def editPropDel(self, layriden, buid, formname, propname, propvalu, stortype):
|
|
1341
|
+
assert self.nodes.has(buid)
|
|
1342
|
+
node = self.getNode(buid)
|
|
1343
|
+
|
|
1344
|
+
sode = node['sodes'][layriden]
|
|
1345
|
+
props = sode.get('props', {})
|
|
1346
|
+
|
|
1347
|
+
assert props.get(propname) == (propvalu, stortype), f'GOT: {props.get(propname)} EXPECTED: {(propvalu, stortype)}'
|
|
1348
|
+
|
|
1349
|
+
props.pop(propname)
|
|
1350
|
+
|
|
1351
|
+
await self.nodes.set(buid, node)
|
|
1352
|
+
|
|
1353
|
+
await self._queueEdit(layriden,
|
|
1354
|
+
(buid, formname, (
|
|
1355
|
+
(s_layer.EDIT_PROP_DEL, (propname, propvalu, stortype), ()),
|
|
1356
|
+
)),
|
|
1357
|
+
)
|
|
1358
|
+
|
|
1359
|
+
async def editTagDel(self, layriden, buid, formname, tagname, tagvalu):
|
|
1360
|
+
await self._queueEdit(layriden,
|
|
1361
|
+
(buid, formname, (
|
|
1362
|
+
(s_layer.EDIT_TAG_DEL, (tagname, tagvalu), ()),
|
|
1363
|
+
)),
|
|
1364
|
+
)
|
|
1365
|
+
|
|
1366
|
+
async def editTagpropDel(self, layriden, buid, formname, tagname, propname, propvalu, stortype):
|
|
1367
|
+
await self._queueEdit(layriden,
|
|
1368
|
+
(buid, formname, (
|
|
1369
|
+
(s_layer.EDIT_TAGPROP_DEL, (tagname, propname, propvalu, stortype), ()),
|
|
1370
|
+
)),
|
|
1371
|
+
)
|
|
1372
|
+
|
|
1373
|
+
async def editNodedataDel(self, layriden, buid, formname, name, valu):
|
|
1374
|
+
await self._queueEdit(layriden,
|
|
1375
|
+
(buid, formname, (
|
|
1376
|
+
(s_layer.EDIT_NODEDATA_DEL, (name, valu), ()),
|
|
1377
|
+
)),
|
|
1378
|
+
)
|
|
1379
|
+
|
|
1380
|
+
async def editEdgeDel(self, layriden, buid, formname, verb, iden):
|
|
1381
|
+
await self._queueEdit(layriden,
|
|
1382
|
+
(buid, formname, (
|
|
1383
|
+
(s_layer.EDIT_EDGE_DEL, (verb, iden), ()),
|
|
1384
|
+
)),
|
|
1385
|
+
)
|
|
1386
|
+
|
|
1387
|
+
def getNode(self, buid):
|
|
1388
|
+
node = self.nodes.get(buid, {})
|
|
1389
|
+
if not node:
|
|
1390
|
+
node.setdefault('refs', {})
|
|
1391
|
+
node.setdefault('sodes', {})
|
|
1392
|
+
node.setdefault('layers', [])
|
|
1393
|
+
node.setdefault('n1edges', {})
|
|
1394
|
+
node.setdefault('n2edges', {})
|
|
1395
|
+
node.setdefault('verdict', None)
|
|
1396
|
+
node.setdefault('nodedata', {})
|
|
1397
|
+
return node
|
|
1398
|
+
|
|
1399
|
+
async def _loadNode(self, layer, buid, node=None):
|
|
1400
|
+
if node is None:
|
|
1401
|
+
node = self.getNode(buid)
|
|
1402
|
+
|
|
1403
|
+
sode = await layer.getStorNode(buid)
|
|
1404
|
+
if sode:
|
|
1405
|
+
node['sodes'].setdefault(layer.iden, {})
|
|
1406
|
+
node['sodes'][layer.iden] = sode
|
|
1407
|
+
|
|
1408
|
+
if (formvalu := sode.get('valu')) is not None:
|
|
1409
|
+
if node.get('formvalu') is None:
|
|
1410
|
+
node['formvalu'] = formvalu[0]
|
|
1411
|
+
node['formname'] = sode.get('form')
|
|
1412
|
+
|
|
1413
|
+
if layer.iden not in node['layers']:
|
|
1414
|
+
layers = list(node['layers'])
|
|
1415
|
+
layers.append(layer.iden)
|
|
1416
|
+
node['layers'] = layers
|
|
1417
|
+
|
|
1418
|
+
# Get nodedata
|
|
1419
|
+
nodedata = [k async for k in layer.iterNodeData(buid)]
|
|
1420
|
+
if nodedata:
|
|
1421
|
+
node['nodedata'][layer.iden] = nodedata
|
|
1422
|
+
|
|
1423
|
+
# Collect N1 edges
|
|
1424
|
+
n1edges = [k async for k in layer.iterNodeEdgesN1(buid)]
|
|
1425
|
+
if n1edges:
|
|
1426
|
+
node['n1edges'][layer.iden] = n1edges
|
|
1427
|
+
|
|
1428
|
+
# Collect N2 edges
|
|
1429
|
+
n2edges = []
|
|
1430
|
+
async for verb, iden in layer.iterNodeEdgesN2(buid):
|
|
1431
|
+
n2edges.append((verb, iden))
|
|
1432
|
+
|
|
1433
|
+
await self.todos.add(('getvalu', (s_common.uhex(iden), False)))
|
|
1434
|
+
|
|
1435
|
+
if n2edges:
|
|
1436
|
+
node['n2edges'][layer.iden] = n2edges
|
|
1437
|
+
|
|
1438
|
+
await self.nodes.set(buid, node)
|
|
1439
|
+
return node
|
|
1440
|
+
|
|
1441
|
+
async def revModel_0_2_31(self):
|
|
1442
|
+
|
|
1443
|
+
form = self.core.model.form('it:sec:cpe')
|
|
1444
|
+
|
|
1445
|
+
logger.info(f'Collecting and classifying it:sec:cpe nodes in {len(self.layers)} layers')
|
|
1446
|
+
|
|
1447
|
+
# Pick up and classify all bad CPE nodes
|
|
1448
|
+
for idx, layer in enumerate(self.layers):
|
|
1449
|
+
logger.debug(f'Classifying nodes in layer {idx}')
|
|
1450
|
+
|
|
1451
|
+
async for buid, sode in layer.getStorNodesByForm('it:sec:cpe'):
|
|
1452
|
+
|
|
1453
|
+
verdict = 'remove'
|
|
1454
|
+
|
|
1455
|
+
# Delete invalid v2_2 props while we're iterating
|
|
1456
|
+
props = sode.get('props', {})
|
|
1457
|
+
if (v2_2 := props.get('v2_2')) is not None:
|
|
1458
|
+
propvalu, stortype = v2_2
|
|
1459
|
+
if not s_infotech.isValidCpe22(propvalu):
|
|
1460
|
+
await self._queueEdit(
|
|
1461
|
+
layer.iden,
|
|
1462
|
+
(buid, 'it:sec:cpe', (
|
|
1463
|
+
(s_layer.EDIT_PROP_DEL, ('v2_2', propvalu, stortype), ()),
|
|
1464
|
+
))
|
|
1465
|
+
)
|
|
1466
|
+
else:
|
|
1467
|
+
verdict = 'migrate'
|
|
1468
|
+
|
|
1469
|
+
if (formvalu := sode.get('valu')) is None:
|
|
1470
|
+
continue
|
|
1471
|
+
|
|
1472
|
+
formvalu = formvalu[0]
|
|
1473
|
+
if s_infotech.isValidCpe23(formvalu):
|
|
1474
|
+
continue
|
|
1475
|
+
|
|
1476
|
+
node = self.getNode(buid)
|
|
1477
|
+
node['formvalu'] = formvalu
|
|
1478
|
+
node['formname'] = 'it:sec:cpe'
|
|
1479
|
+
node['verdict'] = verdict
|
|
1480
|
+
layers = list(node['layers'])
|
|
1481
|
+
layers.append(layer.iden)
|
|
1482
|
+
node['layers'] = layers
|
|
1483
|
+
|
|
1484
|
+
await self.nodes.set(buid, node)
|
|
1485
|
+
|
|
1486
|
+
await self._flushEdits()
|
|
1487
|
+
|
|
1488
|
+
invalid = len(self.nodes)
|
|
1489
|
+
logger.info(f'Processing {invalid} invalid it:sec:cpe nodes in {len(self.layers)} layers')
|
|
1490
|
+
|
|
1491
|
+
# Pick up all related CPE node info. The majority of the work happens in this loop
|
|
1492
|
+
for idx, layer in enumerate(self.layers):
|
|
1493
|
+
logger.debug(f'Processing nodes in layer {idx}')
|
|
1494
|
+
|
|
1495
|
+
for buid, node in self.nodes.items():
|
|
1496
|
+
await self._loadNode(layer, buid, node=node)
|
|
1497
|
+
|
|
1498
|
+
formvalu = node.get('formvalu')
|
|
1499
|
+
formname = node.get('formname')
|
|
1500
|
+
formndef = (formname, formvalu)
|
|
1501
|
+
|
|
1502
|
+
refs = node['refs'].get(layer.iden, [])
|
|
1503
|
+
|
|
1504
|
+
for refinfo in self.getRefInfo(formname):
|
|
1505
|
+
(refform, refprop, reftype, isarray, isro) = refinfo
|
|
1506
|
+
|
|
1507
|
+
if reftype == 'ndef':
|
|
1508
|
+
propvalu = formndef
|
|
1509
|
+
else:
|
|
1510
|
+
propvalu = formvalu
|
|
1511
|
+
|
|
1512
|
+
async for refbuid, refsode in self.getSodeByPropValuNoNorm(layer, refform, refprop, propvalu):
|
|
1513
|
+
# Save the reference info
|
|
1514
|
+
refs.append((s_common.ehex(refbuid), refinfo))
|
|
1515
|
+
|
|
1516
|
+
# Add a todo to get valu and refs to the new nodes
|
|
1517
|
+
await self.todos.add(('getvalu', (refbuid, True)))
|
|
1518
|
+
|
|
1519
|
+
if refs:
|
|
1520
|
+
node['refs'][layer.iden] = refs
|
|
1521
|
+
|
|
1522
|
+
await self.nodes.set(buid, node)
|
|
1523
|
+
|
|
1524
|
+
logger.info('Processing invalid it:sec:cpe node references (this may happen multiple times)')
|
|
1525
|
+
|
|
1526
|
+
# Collect sources, direct references, second-degree references, etc.
|
|
1527
|
+
while len(self.todos):
|
|
1528
|
+
# Copy the list of todos and then clear the original list. This makes it so we will process all the todos
|
|
1529
|
+
# but we can add new todos (that will iterate over all the layers) below to gather supporting data as
|
|
1530
|
+
# needed.
|
|
1531
|
+
todotmp = await self.todos.copy()
|
|
1532
|
+
await self.todos.clear()
|
|
1533
|
+
|
|
1534
|
+
for idx, layer in enumerate(self.layers):
|
|
1535
|
+
logger.debug(f'Processing references in layer {idx}')
|
|
1536
|
+
|
|
1537
|
+
async for entry in todotmp:
|
|
1538
|
+
match entry:
|
|
1539
|
+
case ('getvalu', (buid, fullnode)):
|
|
1540
|
+
if fullnode:
|
|
1541
|
+
node = await self._loadNode(layer, buid)
|
|
1542
|
+
formvalu = node.get('formvalu')
|
|
1543
|
+
if formvalu is None:
|
|
1544
|
+
continue
|
|
1545
|
+
|
|
1546
|
+
formname = node.get('formname')
|
|
1547
|
+
|
|
1548
|
+
await self.todos.add(('getrefs', (buid, formname, formvalu)))
|
|
1549
|
+
else:
|
|
1550
|
+
sode = await layer.getStorNode(buid)
|
|
1551
|
+
|
|
1552
|
+
if (formvalu := sode.get('valu')) is None:
|
|
1553
|
+
continue
|
|
1554
|
+
|
|
1555
|
+
formvalu = formvalu[0]
|
|
1556
|
+
formname = sode.get('form')
|
|
1557
|
+
|
|
1558
|
+
node = self.getNode(buid)
|
|
1559
|
+
node['formvalu'] = formvalu
|
|
1560
|
+
node['formname'] = formname
|
|
1561
|
+
layers = list(node['layers'])
|
|
1562
|
+
layers.append(layer.iden)
|
|
1563
|
+
node['layers'] = layers
|
|
1564
|
+
|
|
1565
|
+
await self.nodes.set(buid, node)
|
|
1566
|
+
|
|
1567
|
+
case ('getrefs', (buid, formname, formvalu)):
|
|
1568
|
+
|
|
1569
|
+
node = self.getNode(buid)
|
|
1570
|
+
formndef = (formname, formvalu)
|
|
1571
|
+
|
|
1572
|
+
node.setdefault('refs', {})
|
|
1573
|
+
refs = node['refs'].get(layer.iden, [])
|
|
1574
|
+
|
|
1575
|
+
for refinfo in self.getRefInfo(formname):
|
|
1576
|
+
(refform, refprop, reftype, isarray, isro) = refinfo
|
|
1577
|
+
|
|
1578
|
+
if reftype == 'ndef':
|
|
1579
|
+
propvalu = formndef
|
|
1580
|
+
else:
|
|
1581
|
+
propvalu = formvalu
|
|
1582
|
+
|
|
1583
|
+
async for refbuid, refsode in self.getSodeByPropValuNoNorm(layer, refform, refprop, propvalu):
|
|
1584
|
+
# Save the reference info
|
|
1585
|
+
refs.append((s_common.ehex(refbuid), refinfo))
|
|
1586
|
+
|
|
1587
|
+
# Add a todo to get valu and refs to the new nodes
|
|
1588
|
+
await self.todos.add(('getvalu', (refbuid, True)))
|
|
1589
|
+
|
|
1590
|
+
if refs:
|
|
1591
|
+
node['refs'][layer.iden] = refs
|
|
1592
|
+
|
|
1593
|
+
await self.nodes.set(buid, node)
|
|
1594
|
+
|
|
1595
|
+
await todotmp.fini()
|
|
1596
|
+
|
|
1597
|
+
logger.info(f'Migrating/removing {invalid} invalid it:sec:cpe nodes')
|
|
1598
|
+
|
|
1599
|
+
count = 0
|
|
1600
|
+
removed = 0
|
|
1601
|
+
migrated = 0
|
|
1602
|
+
for buid, node in self.nodes.items():
|
|
1603
|
+
action = node.get('verdict')
|
|
1604
|
+
|
|
1605
|
+
if action is None:
|
|
1606
|
+
continue
|
|
1607
|
+
|
|
1608
|
+
if action == 'migrate':
|
|
1609
|
+
propvalu = None
|
|
1610
|
+
for layriden, sode in node.get('sodes').items():
|
|
1611
|
+
props = sode.get('props', {})
|
|
1612
|
+
propvalu, stortype = props.get('v2_2', (None, None))
|
|
1613
|
+
if propvalu is not None:
|
|
1614
|
+
break
|
|
1615
|
+
|
|
1616
|
+
newvalu, _ = form.type.norm(propvalu)
|
|
1617
|
+
await self.moveNode(buid, newvalu)
|
|
1618
|
+
|
|
1619
|
+
migrated += 1
|
|
1620
|
+
|
|
1621
|
+
elif action == 'remove':
|
|
1622
|
+
newvalu = None
|
|
1623
|
+
# Before removing the node, iterate over the sodes looking for a good :v2_2 value
|
|
1624
|
+
for layriden, sode in node.get('sodes').items():
|
|
1625
|
+
props = sode.get('props', {})
|
|
1626
|
+
propvalu, stortype = props.get('v2_2', (None, None))
|
|
1627
|
+
if propvalu is None:
|
|
1628
|
+
continue
|
|
1629
|
+
|
|
1630
|
+
newvalu, _ = form.type.norm(propvalu)
|
|
1631
|
+
# This prop is going to be the new primary value so delete the secondary prop
|
|
1632
|
+
await self.editPropDel(layriden, buid, 'it:sec:cpe', 'v2_2', propvalu, stortype)
|
|
1633
|
+
|
|
1634
|
+
# Oh yeah! Migrate the node instead of removing it
|
|
1635
|
+
await self.moveNode(buid, newvalu)
|
|
1636
|
+
|
|
1637
|
+
migrated += 1
|
|
1638
|
+
break
|
|
1639
|
+
|
|
1640
|
+
else:
|
|
1641
|
+
await self.removeNode(buid)
|
|
1642
|
+
removed += 1
|
|
1643
|
+
|
|
1644
|
+
count = migrated + removed
|
|
1645
|
+
if count % 1000 == 0: # pragma: no cover
|
|
1646
|
+
logger.info(f'Processed {count} it:sec:cpe nodes')
|
|
1647
|
+
|
|
1648
|
+
await self._flushEdits()
|
|
1649
|
+
|
|
1650
|
+
logger.info(f'Finished processing {count} it:sec:cpe nodes: {migrated} migrated, {removed} removed')
|
|
1651
|
+
|
|
1652
|
+
await self.todos.fini()
|
|
1653
|
+
await self.nodes.fini()
|
|
1654
|
+
|
|
1655
|
+
@s_cache.memoizemethod()
|
|
1656
|
+
def getRoProps(self, formname):
|
|
1657
|
+
roprops = []
|
|
1658
|
+
|
|
1659
|
+
form = self.core.model.form(formname)
|
|
1660
|
+
for propname, prop in form.props.items():
|
|
1661
|
+
if prop.info.get('ro', False):
|
|
1662
|
+
roprops.append(propname)
|
|
1663
|
+
|
|
1664
|
+
return roprops
|
|
1665
|
+
|
|
1666
|
+
@s_cache.memoizemethod()
|
|
1667
|
+
def getRefInfo(self, formname):
|
|
1668
|
+
props = []
|
|
1669
|
+
props.extend(self.core.model.getPropsByType(formname))
|
|
1670
|
+
props.extend(self.core.model.getPropsByType('array'))
|
|
1671
|
+
props.extend(self.core.model.getPropsByType('ndef'))
|
|
1672
|
+
|
|
1673
|
+
props = [k for k in props if k.form.name != formname]
|
|
1674
|
+
|
|
1675
|
+
refinfo = []
|
|
1676
|
+
for prop in props:
|
|
1677
|
+
|
|
1678
|
+
if prop.form.name == formname: # pragma: no cover
|
|
1679
|
+
continue
|
|
1680
|
+
|
|
1681
|
+
proptype = prop.type
|
|
1682
|
+
|
|
1683
|
+
if prop.type.isarray:
|
|
1684
|
+
proptype = prop.type.arraytype
|
|
1685
|
+
|
|
1686
|
+
if proptype.name not in (formname, 'ndef'):
|
|
1687
|
+
continue
|
|
1688
|
+
|
|
1689
|
+
refinfo.append((
|
|
1690
|
+
prop.form.name,
|
|
1691
|
+
prop.name,
|
|
1692
|
+
proptype.name,
|
|
1693
|
+
prop.type.isarray,
|
|
1694
|
+
prop.info.get('ro', False)
|
|
1695
|
+
))
|
|
1696
|
+
|
|
1697
|
+
return refinfo
|
|
1698
|
+
|
|
1699
|
+
async def removeNode(self, buid):
|
|
1700
|
+
assert self.nodes.has(buid)
|
|
1701
|
+
node = self.getNode(buid)
|
|
1702
|
+
|
|
1703
|
+
await self.storeNode(buid)
|
|
1704
|
+
|
|
1705
|
+
formname = node.get('formname')
|
|
1706
|
+
formvalu = node.get('formvalu')
|
|
1707
|
+
formndef = (formname, formvalu)
|
|
1708
|
+
refs = node.get('refs')
|
|
1709
|
+
|
|
1710
|
+
# Delete references
|
|
1711
|
+
for reflayr, reflist in refs.items():
|
|
1712
|
+
for refiden, refinfo in reflist:
|
|
1713
|
+
refbuid = s_common.uhex(refiden)
|
|
1714
|
+
(refform, refprop, reftype, isarray, isro) = refinfo
|
|
1715
|
+
|
|
1716
|
+
if reftype == 'ndef':
|
|
1717
|
+
propvalu = formndef
|
|
1718
|
+
else:
|
|
1719
|
+
propvalu = formvalu
|
|
1720
|
+
|
|
1721
|
+
if isro:
|
|
1722
|
+
await self.removeNode(refbuid)
|
|
1723
|
+
continue
|
|
1724
|
+
|
|
1725
|
+
refnode = self.getNode(refbuid)
|
|
1726
|
+
refsode = refnode['sodes'].get(reflayr)
|
|
1727
|
+
|
|
1728
|
+
curv, stortype = refsode['props'].get(refprop, (None, None))
|
|
1729
|
+
|
|
1730
|
+
if isarray:
|
|
1731
|
+
|
|
1732
|
+
_curv = curv
|
|
1733
|
+
|
|
1734
|
+
newv = list(_curv).copy()
|
|
1735
|
+
|
|
1736
|
+
while propvalu in newv:
|
|
1737
|
+
newv.remove(propvalu)
|
|
1738
|
+
|
|
1739
|
+
if not newv:
|
|
1740
|
+
await self.editPropDel(reflayr, refbuid, refform, refprop, curv, stortype)
|
|
1741
|
+
|
|
1742
|
+
else:
|
|
1743
|
+
await self.editPropSet(reflayr, refbuid, refform, refprop, newv, curv, stortype)
|
|
1744
|
+
|
|
1745
|
+
else:
|
|
1746
|
+
await self.editPropDel(reflayr, refbuid, refform, refprop, curv, stortype)
|
|
1747
|
+
|
|
1748
|
+
await self.delNode(buid)
|
|
1749
|
+
|
|
1750
|
+
async def storeNode(self, buid):
|
|
1751
|
+
assert self.nodes.has(buid)
|
|
1752
|
+
node = self.getNode(buid)
|
|
1753
|
+
|
|
1754
|
+
formname = node.get('formname')
|
|
1755
|
+
formvalu = node.get('formvalu')
|
|
1756
|
+
|
|
1757
|
+
sources = set()
|
|
1758
|
+
# Resolve sources
|
|
1759
|
+
n2edges = {}
|
|
1760
|
+
for layriden, edges in node['n2edges'].items():
|
|
1761
|
+
n2edges.setdefault(layriden, [])
|
|
1762
|
+
|
|
1763
|
+
for verb, n2iden in edges:
|
|
1764
|
+
n2buid = s_common.uhex(n2iden)
|
|
1765
|
+
assert self.nodes.has(n2buid)
|
|
1766
|
+
n2node = self.nodes.get(n2buid)
|
|
1767
|
+
if n2node is None: # pragma: no cover
|
|
1768
|
+
continue
|
|
1769
|
+
|
|
1770
|
+
n2edges[layriden].append((verb, n2iden, n2node['formname']))
|
|
1771
|
+
|
|
1772
|
+
if verb == 'seen':
|
|
1773
|
+
formvalu = n2node.get('formvalu')
|
|
1774
|
+
assert formvalu is not None
|
|
1775
|
+
sources.add(formvalu)
|
|
1776
|
+
|
|
1777
|
+
# Make some changes before serializing
|
|
1778
|
+
item = s_msgpack.deepcopy(node)
|
|
1779
|
+
item.pop('verdict', None)
|
|
1780
|
+
item['iden'] = s_common.ehex(buid)
|
|
1781
|
+
item['sources'] = list(sources)
|
|
1782
|
+
item['n2edges'] = n2edges
|
|
1783
|
+
|
|
1784
|
+
roprops = self.getRoProps(formname)
|
|
1785
|
+
for layriden, sode in node['sodes'].items():
|
|
1786
|
+
props = sode.get('props')
|
|
1787
|
+
if props is None: # pragma: no cover
|
|
1788
|
+
continue
|
|
1789
|
+
|
|
1790
|
+
props = {name: valu for name, valu in list(props.items()) if name not in roprops}
|
|
1791
|
+
if props:
|
|
1792
|
+
item['sodes'][layriden]['props'] = props
|
|
1793
|
+
else:
|
|
1794
|
+
item['sodes'][layriden].pop('props')
|
|
1795
|
+
|
|
1796
|
+
if not self.hasq:
|
|
1797
|
+
await self.core.addCoreQueue('model_0_2_31:nodes', {})
|
|
1798
|
+
self.hasq = True
|
|
1799
|
+
|
|
1800
|
+
await self.core.coreQueuePuts('model_0_2_31:nodes', (item,))
|
|
1801
|
+
|
|
1802
|
+
async def getSodeByPropValuNoNorm(self, layer, formname, propname, valu, cmpr='='):
|
|
1803
|
+
prop = self.core.model.reqProp(f'{formname}:{propname}')
|
|
1804
|
+
|
|
1805
|
+
stortype = prop.type.stortype
|
|
1806
|
+
|
|
1807
|
+
# Normally we'd call proptype.getStorCmprs() here to get the cmprvals
|
|
1808
|
+
# but getStorCmprs() calls norm() which we're trying to avoid so build
|
|
1809
|
+
# cmprvals manually here.
|
|
1810
|
+
|
|
1811
|
+
if prop.type.isarray:
|
|
1812
|
+
stortype &= (~s_layer.STOR_FLAG_ARRAY)
|
|
1813
|
+
liftfunc = layer.liftByPropArray
|
|
1814
|
+
else:
|
|
1815
|
+
liftfunc = layer.liftByPropValu
|
|
1816
|
+
|
|
1817
|
+
cmprvals = ((cmpr, valu, stortype),)
|
|
1818
|
+
|
|
1819
|
+
async for _, buid, sode in liftfunc(formname, propname, cmprvals):
|
|
1820
|
+
yield buid, sode
|
|
1821
|
+
|
|
1822
|
+
async def delNode(self, buid):
|
|
1823
|
+
assert self.nodes.has(buid)
|
|
1824
|
+
node = self.getNode(buid)
|
|
1825
|
+
|
|
1826
|
+
formname = node.get('formname')
|
|
1827
|
+
formvalu = node.get('formvalu')
|
|
1828
|
+
|
|
1829
|
+
# Edits
|
|
1830
|
+
for layriden, sode in node['sodes'].items():
|
|
1831
|
+
props = sode.get('props', {}).copy()
|
|
1832
|
+
for propname, propvalu in props.items():
|
|
1833
|
+
propvalu, stortype = propvalu
|
|
1834
|
+
await self.editPropDel(layriden, buid, formname, propname, propvalu, stortype)
|
|
1835
|
+
|
|
1836
|
+
tags = sode.get('tags', {})
|
|
1837
|
+
for tagname, tagvalu in tags.items():
|
|
1838
|
+
await self.editTagDel(layriden, buid, formname, tagname, tagvalu)
|
|
1839
|
+
|
|
1840
|
+
tagprops = sode.get('tagprops', {})
|
|
1841
|
+
for tagname, propvalus in tagprops.items():
|
|
1842
|
+
for propname, propvalu in propvalus.items():
|
|
1843
|
+
propvalu, stortype = propvalu
|
|
1844
|
+
await self.editTagpropDel(layriden, buid, formname, tagname, propname, propvalu, stortype)
|
|
1845
|
+
|
|
1846
|
+
# Nodedata
|
|
1847
|
+
for layriden, data in node['nodedata'].items():
|
|
1848
|
+
for name, valu in data:
|
|
1849
|
+
await self.editNodedataDel(layriden, buid, formname, name, valu)
|
|
1850
|
+
|
|
1851
|
+
# Edges
|
|
1852
|
+
for layriden, edges in node['n1edges'].items():
|
|
1853
|
+
for verb, iden in edges:
|
|
1854
|
+
await self.editEdgeDel(layriden, buid, formname, verb, iden)
|
|
1855
|
+
|
|
1856
|
+
for layriden, edges in node['n2edges'].items():
|
|
1857
|
+
for verb, iden in edges:
|
|
1858
|
+
n2buid = s_common.uhex(iden)
|
|
1859
|
+
|
|
1860
|
+
n2node = self.nodes.get(n2buid)
|
|
1861
|
+
if n2node is None: # pragma: no cover
|
|
1862
|
+
continue
|
|
1863
|
+
|
|
1864
|
+
n2form = n2node.get('formname')
|
|
1865
|
+
await self.editEdgeDel(layriden, n2buid, n2form, verb, s_common.ehex(buid))
|
|
1866
|
+
|
|
1867
|
+
# Node
|
|
1868
|
+
await self.editNodeDel(layriden, buid, formname, formvalu)
|
|
1869
|
+
|
|
1870
|
+
async def moveNode(self, buid, newvalu):
|
|
1871
|
+
assert self.nodes.has(buid)
|
|
1872
|
+
node = self.getNode(buid)
|
|
1873
|
+
|
|
1874
|
+
formname = node.get('formname')
|
|
1875
|
+
formvalu = node.get('formvalu')
|
|
1876
|
+
refs = node.get('refs')
|
|
1877
|
+
|
|
1878
|
+
oldndef = (formname, formvalu)
|
|
1879
|
+
newndef = (formname, newvalu)
|
|
1880
|
+
newbuid = s_common.buid((formname, newvalu))
|
|
1881
|
+
|
|
1882
|
+
form = self.core.model.reqForm(formname)
|
|
1883
|
+
|
|
1884
|
+
# Node
|
|
1885
|
+
for layriden in node['layers']:
|
|
1886
|
+
# Create the new node in the same layers as the old node
|
|
1887
|
+
await self.editNodeAdd(layriden, newbuid, formname, newvalu, form.type.stortype)
|
|
1888
|
+
|
|
1889
|
+
# Edits
|
|
1890
|
+
for layriden, sode in node['sodes'].items():
|
|
1891
|
+
props = sode.get('props', {})
|
|
1892
|
+
for propname, propvalu in props.items():
|
|
1893
|
+
propvalu, stortype = propvalu
|
|
1894
|
+
await self.editPropSet(layriden, newbuid, formname, propname, propvalu, None, stortype)
|
|
1895
|
+
|
|
1896
|
+
tags = sode.get('tags', {})
|
|
1897
|
+
for tagname, tagvalu in tags.items():
|
|
1898
|
+
await self.editTagSet(layriden, newbuid, formname, tagname, tagvalu, None)
|
|
1899
|
+
|
|
1900
|
+
tagprops = sode.get('tagprops', {})
|
|
1901
|
+
for tagname, propvalus in tagprops.items():
|
|
1902
|
+
for propname, propvalu in propvalus.items():
|
|
1903
|
+
propvalu, stortype = propvalu
|
|
1904
|
+
|
|
1905
|
+
await self.editTagpropSet(layriden, newbuid, formname, tagname, propname, propvalu, None, stortype)
|
|
1906
|
+
|
|
1907
|
+
# Nodedata
|
|
1908
|
+
for layriden, data in node['nodedata'].items():
|
|
1909
|
+
for name, valu in data:
|
|
1910
|
+
await self.editNodedataSet(layriden, newbuid, formname, name, valu, None)
|
|
1911
|
+
|
|
1912
|
+
# Edges
|
|
1913
|
+
for layriden, edges in node['n1edges'].items():
|
|
1914
|
+
for verb, iden in edges:
|
|
1915
|
+
await self.editEdgeAdd(layriden, newbuid, formname, verb, iden)
|
|
1916
|
+
|
|
1917
|
+
for layriden, edges in node['n2edges'].items():
|
|
1918
|
+
for verb, iden in edges:
|
|
1919
|
+
n2buid = s_common.uhex(iden)
|
|
1920
|
+
|
|
1921
|
+
n2node = self.nodes.get(n2buid)
|
|
1922
|
+
if n2node is None: # pragma: no cover
|
|
1923
|
+
continue
|
|
1924
|
+
|
|
1925
|
+
n2form = n2node.get('formname')
|
|
1926
|
+
await self.editEdgeAdd(layriden, n2buid, n2form, verb, s_common.ehex(newbuid))
|
|
1927
|
+
|
|
1928
|
+
# Move references
|
|
1929
|
+
for reflayr, reflist in refs.items():
|
|
1930
|
+
for refiden, refinfo in reflist:
|
|
1931
|
+
refbuid = s_common.uhex(refiden)
|
|
1932
|
+
(refform, refprop, reftype, isarray, isro) = refinfo
|
|
1933
|
+
|
|
1934
|
+
if isro:
|
|
1935
|
+
await self.removeNode(refbuid)
|
|
1936
|
+
continue
|
|
1937
|
+
|
|
1938
|
+
if reftype == 'ndef':
|
|
1939
|
+
oldpropv = oldndef
|
|
1940
|
+
newpropv = newndef
|
|
1941
|
+
else:
|
|
1942
|
+
oldpropv = formvalu
|
|
1943
|
+
newpropv = newvalu
|
|
1944
|
+
|
|
1945
|
+
refnode = self.getNode(refbuid)
|
|
1946
|
+
refsode = refnode['sodes'].get(reflayr)
|
|
1947
|
+
|
|
1948
|
+
curv, stortype = refsode.get('props', {}).get(refprop, (None, None))
|
|
1949
|
+
assert stortype is not None
|
|
1950
|
+
|
|
1951
|
+
if isarray:
|
|
1952
|
+
|
|
1953
|
+
_curv = curv
|
|
1954
|
+
|
|
1955
|
+
newv = list(_curv).copy()
|
|
1956
|
+
|
|
1957
|
+
while oldpropv in newv:
|
|
1958
|
+
newv.remove(oldpropv)
|
|
1959
|
+
|
|
1960
|
+
newv.append(newpropv)
|
|
1961
|
+
|
|
1962
|
+
await self.editPropSet(reflayr, refbuid, refform, refprop, newv, curv, stortype)
|
|
1963
|
+
|
|
1964
|
+
else:
|
|
1965
|
+
await self.editPropSet(reflayr, refbuid, refform, refprop, newpropv, curv, stortype)
|
|
1966
|
+
|
|
1967
|
+
await self.delNode(buid)
|