synapse 2.204.1__py311-none-any.whl → 2.206.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.

Files changed (41) hide show
  1. synapse/axon.py +4 -4
  2. synapse/common.py +0 -3
  3. synapse/cortex.py +14 -1
  4. synapse/lib/aha.py +13 -8
  5. synapse/lib/httpapi.py +196 -97
  6. synapse/lib/lmdbslab.py +2 -0
  7. synapse/lib/modelrev.py +3 -3
  8. synapse/lib/schemas.py +11 -0
  9. synapse/lib/spooled.py +2 -1
  10. synapse/lib/stormlib/aha.py +5 -1
  11. synapse/lib/stormlib/model.py +1 -1
  12. synapse/lib/stormtypes.py +10 -0
  13. synapse/lib/version.py +2 -2
  14. synapse/models/base.py +9 -0
  15. synapse/models/economic.py +15 -2
  16. synapse/models/inet.py +9 -1
  17. synapse/models/infotech.py +7 -0
  18. synapse/models/risk.py +2 -0
  19. synapse/models/telco.py +23 -2
  20. synapse/tests/test_axon.py +42 -41
  21. synapse/tests/test_common.py +4 -23
  22. synapse/tests/test_cortex.py +18 -6
  23. synapse/tests/test_lib_aha.py +17 -0
  24. synapse/tests/test_lib_cell.py +5 -3
  25. synapse/tests/test_lib_httpapi.py +225 -33
  26. synapse/tests/test_lib_lmdbslab.py +30 -0
  27. synapse/tests/test_lib_modelrev.py +7 -7
  28. synapse/tests/test_lib_spooled.py +2 -0
  29. synapse/tests/test_lib_stormlib_aha.py +7 -7
  30. synapse/tests/test_lib_stormlib_cortex.py +61 -60
  31. synapse/tests/test_model_economic.py +3 -0
  32. synapse/tests/test_model_infotech.py +2 -0
  33. synapse/tests/test_model_telco.py +7 -2
  34. synapse/tests/utils.py +3 -0
  35. synapse/tools/aha/easycert.py +4 -0
  36. synapse/tools/aha/mirror.py +6 -4
  37. {synapse-2.204.1.dist-info → synapse-2.206.0.dist-info}/METADATA +2 -3
  38. {synapse-2.204.1.dist-info → synapse-2.206.0.dist-info}/RECORD +41 -41
  39. {synapse-2.204.1.dist-info → synapse-2.206.0.dist-info}/WHEEL +1 -1
  40. {synapse-2.204.1.dist-info → synapse-2.206.0.dist-info}/licenses/LICENSE +0 -0
  41. {synapse-2.204.1.dist-info → synapse-2.206.0.dist-info}/top_level.txt +0 -0
synapse/lib/modelrev.py CHANGED
@@ -1455,7 +1455,7 @@ class ModelMigration_0_2_31:
1455
1455
 
1456
1456
  # Pick up and classify all bad CPE nodes
1457
1457
  for idx, layer in enumerate(self.layers):
1458
- logger.debug(f'Classifying nodes in layer {idx}')
1458
+ logger.debug('Classifying nodes in layer %s %s', idx, layer.iden)
1459
1459
 
1460
1460
  async for buid, sode in layer.getStorNodesByForm('it:sec:cpe'):
1461
1461
 
@@ -1499,7 +1499,7 @@ class ModelMigration_0_2_31:
1499
1499
 
1500
1500
  # Pick up all related CPE node info. The majority of the work happens in this loop
1501
1501
  for idx, layer in enumerate(self.layers):
1502
- logger.debug(f'Processing nodes in layer {idx}')
1502
+ logger.debug('Processing nodes in layer %s %s', idx, layer.iden)
1503
1503
 
1504
1504
  for buid, node in self.nodes.items():
1505
1505
  await self._loadNode(layer, buid, node=node)
@@ -1541,7 +1541,7 @@ class ModelMigration_0_2_31:
1541
1541
  await self.todos.clear()
1542
1542
 
1543
1543
  for idx, layer in enumerate(self.layers):
1544
- logger.debug(f'Processing references in layer {idx}')
1544
+ logger.debug('Processing references in layer %s %s', idx, layer.iden)
1545
1545
 
1546
1546
  async for entry in todotmp:
1547
1547
  match entry:
synapse/lib/schemas.py CHANGED
@@ -1128,3 +1128,14 @@ _reqValidOauth2TokenResponseSchema = {
1128
1128
  'required': ['access_token', 'expires_in'],
1129
1129
  }
1130
1130
  reqValidOauth2TokenResponse = s_config.getJsValidator(_reqValidOauth2TokenResponseSchema)
1131
+
1132
+ _httpLoginV1Schema = {
1133
+ 'type': 'object',
1134
+ 'properties': {
1135
+ 'user': {'type': 'string'},
1136
+ 'passwd': {'type': 'string'},
1137
+ },
1138
+ 'additionalProperties': False,
1139
+ 'required': ['user', 'passwd'],
1140
+ }
1141
+ reqValidHttpLoginV1 = s_config.getJsValidator(_httpLoginV1Schema)
synapse/lib/spooled.py CHANGED
@@ -8,6 +8,7 @@ import synapse.lib.msgpack as s_msgpack
8
8
  import synapse.lib.lmdbslab as s_lmdbslab
9
9
 
10
10
  MAX_SPOOL_SIZE = 10000
11
+ DEFAULT_MAPSIZE = s_const.mebibyte * 32
11
12
 
12
13
  class Spooled(s_base.Base):
13
14
  '''
@@ -48,7 +49,7 @@ class Spooled(s_base.Base):
48
49
 
49
50
  slabpath = tempfile.mkdtemp(dir=dirn, prefix='spooled_', suffix='.lmdb')
50
51
 
51
- self.slab = await s_lmdbslab.Slab.anit(slabpath, map_size=s_const.mebibyte * 32)
52
+ self.slab = await s_lmdbslab.Slab.anit(slabpath, map_size=DEFAULT_MAPSIZE)
52
53
  if self.cell is not None:
53
54
  self.slab.addResizeCallback(self.cell.checkFreeSpace)
54
55
 
@@ -691,6 +691,7 @@ The ready column indicates that a service has entered into the realtime change w
691
691
  {"name": "host", "width": 16},
692
692
  {"name": "port", "width": 8},
693
693
  {"name": "version", "width": 12},
694
+ {"name": "synapse", "width": 12},
694
695
  {"name": "nexus idx", "width": 10},
695
696
  ],
696
697
  "separators": {
@@ -732,6 +733,7 @@ The ready column indicates that a service has entered into the realtime change w
732
733
  'host': $svcinfo.urlinfo.host,
733
734
  'port': $svcinfo.urlinfo.port,
734
735
  'version': '<unknown>',
736
+ 'synapse_version': '<unknown>',
735
737
  'nexs_indx': (0)
736
738
  })
737
739
  if ($cell_infos.$svcname) {
@@ -743,7 +745,8 @@ The ready column indicates that a service has entered into the realtime change w
743
745
  } else {
744
746
  $status.role = 'leader'
745
747
  }
746
- $status.version = $info.synapse.verstring
748
+ $status.version = $info.cell.verstring
749
+ $status.synapse_version = $info.synapse.verstring
747
750
  }
748
751
  $group_status.append($status)
749
752
  }
@@ -779,6 +782,7 @@ The ready column indicates that a service has entered into the realtime change w
779
782
  $status.host,
780
783
  $status.port,
781
784
  $status.version,
785
+ $status.synapse_version,
782
786
  $status.nexs_indx
783
787
  )
784
788
  $lib.print($printer.row($row))
@@ -1181,7 +1181,7 @@ class LibModelMigrations_0_2_31(s_stormtypes.Lib):
1181
1181
  await self.runt.printf(f' layer: {layriden}')
1182
1182
  for iden, refinfo in reflist:
1183
1183
  form, prop, *_ = refinfo
1184
- await self.runt.printf(f' - {form}:{prop} (iden: {iden}')
1184
+ await self.runt.printf(f' - {form}:{prop} (iden: {iden})')
1185
1185
 
1186
1186
  n1edges = node['n1edges']
1187
1187
  n2edges = node['n2edges']
synapse/lib/stormtypes.py CHANGED
@@ -3933,6 +3933,16 @@ class LibQueue(Lib):
3933
3933
  'returns': {'type': 'list',
3934
3934
  'desc': 'A list of queue definitions the current user is allowed to interact with.', }}},
3935
3935
  )
3936
+ _storm_lib_perms = (
3937
+ {'perm': ('queue', 'add'), 'gate': 'cortex',
3938
+ 'desc': 'Permits a user to create a named queue.'},
3939
+ {'perm': ('queue', 'get'), 'gate': 'queue',
3940
+ 'desc': 'Permits a user to access a queue. This allows the user to read from the queue and remove items from it.'},
3941
+ {'perm': ('queue', 'put'), 'gate': 'queue',
3942
+ 'desc': 'Permits a user to put items into a queue.'},
3943
+ {'perm': ('queue', 'del'), 'gate': 'queue',
3944
+ 'desc': 'Permits a user to delete a queue.'},
3945
+ )
3936
3946
  _storm_lib_path = ('queue',)
3937
3947
 
3938
3948
  def getObjLocals(self):
synapse/lib/version.py CHANGED
@@ -223,6 +223,6 @@ def reqVersion(valu, reqver,
223
223
  ##############################################################################
224
224
  # The following are touched during the release process by bumpversion.
225
225
  # Do not modify these directly.
226
- version = (2, 204, 1)
226
+ version = (2, 206, 0)
227
227
  verstring = '.'.join([str(x) for x in version])
228
- commit = '8698255e2c915ecb1b175a0d2aaf3b8274f51fe0'
228
+ commit = '0be7ce9e061b2c752fb454adb50c5267cc14fdfe'
synapse/models/base.py CHANGED
@@ -188,6 +188,15 @@ class BaseModule(s_module.CoreModule):
188
188
  (('meta:ruleset', 'has', 'meta:rule'), {
189
189
  'doc': 'The meta:ruleset includes the meta:rule.'}),
190
190
 
191
+ (('meta:ruleset', 'has', 'inet:service:rule'), {
192
+ 'doc': 'The meta:ruleset includes the inet:service:rule.'}),
193
+
194
+ (('meta:ruleset', 'has', 'it:app:snort:rule'), {
195
+ 'doc': 'The meta:ruleset includes the it:app:snort:rule.'}),
196
+
197
+ (('meta:ruleset', 'has', 'it:app:yara:rule'), {
198
+ 'doc': 'The meta:ruleset includes the it:app:yara:rule.'}),
199
+
191
200
  (('meta:rule', 'matches', None), {
192
201
  'doc': 'The meta:rule has matched on target node.'}),
193
202
 
@@ -317,20 +317,33 @@ class EconModule(s_module.CoreModule):
317
317
  )),
318
318
 
319
319
  ('econ:acct:balance', {}, (
320
+
320
321
  ('time', ('time', {}), {
321
322
  'doc': 'The time the balance was recorded.'}),
323
+
324
+ ('instrument', ('econ:pay:instrument', {}), {
325
+ 'doc': 'The financial instrument holding the balance.'}),
326
+
322
327
  ('pay:card', ('econ:pay:card', {}), {
323
- 'doc': 'The payment card holding the balance.'}),
328
+ 'deprecated': True,
329
+ 'doc': 'Deprecated. Please use :instrument.'}),
330
+
324
331
  ('crypto:address', ('crypto:currency:address', {}), {
325
- 'doc': 'The crypto currency address holding the balance.'}),
332
+ 'deprecated': True,
333
+ 'doc': 'Deprecated. Please use :instrument.'}),
334
+
326
335
  ('amount', ('econ:price', {}), {
327
336
  'doc': 'The account balance at the time.'}),
337
+
328
338
  ('currency', ('econ:currency', {}), {
329
339
  'doc': 'The currency of the balance amount.'}),
340
+
330
341
  ('delta', ('econ:price', {}), {
331
342
  'doc': 'The change since last regular sample.'}),
343
+
332
344
  ('total:received', ('econ:price', {}), {
333
345
  'doc': 'The total amount of currency received by the account.'}),
346
+
334
347
  ('total:sent', ('econ:price', {}), {
335
348
  'doc': 'The total amount of currency sent from the account.'}),
336
349
  )),
synapse/models/inet.py CHANGED
@@ -108,12 +108,20 @@ class Addr(s_types.Str):
108
108
  s_types.Str.postTypeInit(self)
109
109
  self.setNormFunc(str, self._normPyStr)
110
110
 
111
+ self.defport = self.opts.get('defport', None)
112
+ self.defproto = self.opts.get('defproto', 'tcp')
113
+
111
114
  def _getPort(self, valu):
115
+
112
116
  parts = valu.split(':', 1)
113
117
  if len(parts) == 2:
114
118
  valu, port = parts
115
119
  port = self.modl.type('inet:port').norm(port)[0]
116
120
  return valu, port, f':{port}'
121
+
122
+ if self.defport:
123
+ return valu, self.defport, f':{self.defport}'
124
+
117
125
  return valu, None, ''
118
126
 
119
127
  def _normPyStr(self, valu):
@@ -123,7 +131,7 @@ class Addr(s_types.Str):
123
131
  # no protos use case sensitivity yet...
124
132
  valu = valu.lower()
125
133
 
126
- proto = 'tcp'
134
+ proto = self.defproto
127
135
  parts = valu.split('://', 1)
128
136
  if len(parts) == 2:
129
137
  proto, valu = parts
@@ -1101,6 +1101,8 @@ class ItModule(s_module.CoreModule):
1101
1101
  'edges': (
1102
1102
  (('it:prod:soft', 'uses', 'ou:technique'), {
1103
1103
  'doc': 'The software uses the technique.'}),
1104
+ (('it:prod:soft', 'uses', 'risk:vuln'), {
1105
+ 'doc': 'The software uses the vulnerability.'}),
1104
1106
  (('it:exec:query', 'found', None), {
1105
1107
  'doc': 'The target node was returned as a result of running the query.'}),
1106
1108
  (('it:app:snort:rule', 'detects', None), {
@@ -1294,6 +1296,11 @@ class ItModule(s_module.CoreModule):
1294
1296
  ('net6', ('inet:net6', {}), {
1295
1297
  'doc': 'The optional contiguous IPv6 address range of this network.'}),
1296
1298
 
1299
+ ('dns:resolvers', ('array', {'type': 'inet:server',
1300
+ 'typeopts': {'defport': 53, 'defproto': 'udp'},
1301
+ 'sorted': True, 'uniq': True}), {
1302
+ 'doc': 'An array of DNS servers configured to resolve requests for hosts on the network.'})
1303
+
1297
1304
  )),
1298
1305
  ('it:account', {}, (
1299
1306
  ('user', ('inet:user', {}), {
synapse/models/risk.py CHANGED
@@ -211,6 +211,8 @@ class RiskModule(s_module.CoreModule):
211
211
 
212
212
  (('risk:attack', 'targets', 'ou:industry'), {
213
213
  'doc': 'The attack targeted the industry.'}),
214
+ (('risk:compromise', 'targets', 'ou:industry'), {
215
+ 'doc': "The compromise was assessed to be based on the victim's role in the industry."}),
214
216
  (('risk:threat', 'targets', 'ou:industry'), {
215
217
  'doc': 'The threat cluster targets the industry.'}),
216
218
 
synapse/models/telco.py CHANGED
@@ -153,6 +153,10 @@ class TelcoModule(s_module.CoreModule):
153
153
  ('tel:call', ('guid', {}), {
154
154
  'doc': 'A guid for a telephone call record.'}),
155
155
 
156
+ ('tel:phone:type:taxonomy', ('taxonomy', {}), {
157
+ 'interfaces': ('meta:taxonomy',),
158
+ 'doc': 'A taxonomy of phone number types.'}),
159
+
156
160
  ('tel:txtmesg', ('guid', {}), {
157
161
  'doc': 'A guid for an individual text message.'}),
158
162
 
@@ -189,14 +193,26 @@ class TelcoModule(s_module.CoreModule):
189
193
  'doc': 'A mobile cell site which a phone may connect to.'
190
194
  }),
191
195
 
196
+ # TODO - eventually break out ISO-3 country code into a sub
197
+ # https://en.wikipedia.org/wiki/TADIG_code
198
+ ('tel:mob:tadig', ('str', {'regex': '^[A-Z0-9]{5}$', 'strip': True}), {
199
+ 'doc': 'A Transferred Account Data Interchange Group number issued to a GSM carrier.'}),
200
+
192
201
  ),
193
202
 
194
203
  'forms': (
204
+
205
+ ('tel:phone:type:taxonomy', {}, ()),
195
206
  ('tel:phone', {}, (
207
+
208
+ ('type', ('tel:phone:type:taxonomy', {}), {
209
+ 'doc': 'The type of phone number.'}),
210
+
196
211
  ('loc', ('loc', {}), {
197
- 'doc': 'The location associated with the number.',
198
- }),
212
+ 'doc': 'The location associated with the number.'}),
213
+
199
214
  )),
215
+
200
216
  ('tel:call', {}, (
201
217
  ('src', ('tel:phone', {}), {
202
218
  'doc': 'The source phone number for a call.'
@@ -311,6 +327,9 @@ class TelcoModule(s_module.CoreModule):
311
327
  ('loc', ('loc', {}), {
312
328
  'doc': 'Location the carrier operates from.'
313
329
  }),
330
+
331
+ ('tadig', ('tel:mob:tadig', {}), {
332
+ 'doc': 'The TADIG code issued to the carrier.'}),
314
333
  )),
315
334
  ('tel:mob:cell', {}, (
316
335
  ('carrier', ('tel:mob:carrier', {}), {'doc': 'Mobile carrier.', 'ro': True, }),
@@ -329,6 +348,8 @@ class TelcoModule(s_module.CoreModule):
329
348
  'doc': 'The place associated with the latlong property.'}),
330
349
  )),
331
350
 
351
+ ('tel:mob:tadig', {}, ()),
352
+
332
353
  ('tel:mob:telem', {}, (
333
354
 
334
355
  ('time', ('time', {}), {}),
@@ -1,7 +1,7 @@
1
1
  import io
2
2
  import os
3
3
  import csv
4
- import sys
4
+ import http
5
5
  import base64
6
6
  import shutil
7
7
  import struct
@@ -573,14 +573,14 @@ bar baz",vv
573
573
  # No auth - coverage
574
574
  async with self.getHttpSess() as sess:
575
575
  async with sess.get(f'{url_dl}/foobar') as resp:
576
- self.eq(401, resp.status)
576
+ self.eq(resp.status, http.HTTPStatus.UNAUTHORIZED)
577
577
  info = await resp.json()
578
578
  self.eq('NotAuthenticated', info.get('code'))
579
579
  async with sess.head(f'{url_dl}/foobar') as resp:
580
- self.eq(401, resp.status)
580
+ self.eq(resp.status, http.HTTPStatus.UNAUTHORIZED)
581
581
  # aiohttp ignores HEAD bodies
582
582
  async with sess.delete(f'{url_dl}/foobar') as resp:
583
- self.eq(401, resp.status)
583
+ self.eq(resp.status, http.HTTPStatus.UNAUTHORIZED)
584
584
  info = await resp.json()
585
585
  self.eq('NotAuthenticated', info.get('code'))
586
586
 
@@ -588,31 +588,31 @@ bar baz",vv
588
588
  async with self.getHttpSess(auth=('newb', 'secret'), port=port) as sess:
589
589
 
590
590
  async with sess.get(f'{url_dl}/{asdfhash_h}') as resp:
591
- self.eq(403, resp.status)
591
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
592
592
  item = await resp.json()
593
593
  self.eq('err', item.get('status'))
594
594
 
595
595
  async with sess.delete(f'{url_dl}/{asdfhash_h}') as resp:
596
- self.eq(403, resp.status)
596
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
597
597
  item = await resp.json()
598
598
  self.eq('err', item.get('status'))
599
599
 
600
600
  async with sess.get(f'{url_hs}/{asdfhash_h}') as resp:
601
- self.eq(403, resp.status)
601
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
602
602
  item = await resp.json()
603
603
  self.eq('err', item.get('status'))
604
604
 
605
605
  async with sess.head(f'{url_dl}/{asdfhash_h}') as resp:
606
- self.eq(403, resp.status)
606
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
607
607
  item = await resp.json()
608
608
 
609
609
  async with sess.post(url_de) as resp:
610
- self.eq(403, resp.status)
610
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
611
611
  item = await resp.json()
612
612
  self.eq('err', item.get('status'))
613
613
 
614
614
  async with sess.post(url_ul, data=abuf) as resp:
615
- self.eq(403, resp.status)
615
+ self.eq(resp.status, http.HTTPStatus.FORBIDDEN)
616
616
  item = await resp.json()
617
617
  self.eq('err', item.get('status'))
618
618
 
@@ -631,27 +631,27 @@ bar baz",vv
631
631
  # Basic
632
632
  async with self.getHttpSess(auth=('newb', 'secret'), port=port) as sess:
633
633
  async with sess.get(f'{url_dl}/foobar') as resp:
634
- self.eq(404, resp.status)
634
+ self.eq(resp.status, http.HTTPStatus.NOT_FOUND)
635
635
  info = await resp.json()
636
636
  self.eq('err', info.get('status'))
637
637
  self.eq('BadArg', info.get('code'))
638
638
  self.eq('Hash is not a SHA-256: foobar', info.get('mesg'))
639
639
 
640
640
  async with sess.get(f'{url_dl}/{asdfhash_h}') as resp:
641
- self.eq(404, resp.status)
641
+ self.eq(resp.status, http.HTTPStatus.NOT_FOUND)
642
642
  info = await resp.json()
643
643
  self.eq('err', info.get('status'))
644
644
  self.eq('NoSuchFile', info.get('code'))
645
645
  self.eq(f'SHA-256 not found: {asdfhash_h}', info.get('mesg'))
646
646
 
647
647
  async with sess.get(f'{url_hs}/{asdfhash_h}') as resp:
648
- self.eq(200, resp.status)
648
+ self.eq(resp.status, http.HTTPStatus.OK)
649
649
  item = await resp.json()
650
650
  self.eq('ok', item.get('status'))
651
651
  self.false(item.get('result'))
652
652
 
653
653
  async with sess.post(url_ul, data=abuf) as resp:
654
- self.eq(200, resp.status)
654
+ self.eq(resp.status, http.HTTPStatus.OK)
655
655
  item = await resp.json()
656
656
  self.eq('ok', item.get('status'))
657
657
  result = item.get('result')
@@ -661,13 +661,13 @@ bar baz",vv
661
661
  self.true(await realaxon.has(asdfhash))
662
662
 
663
663
  async with sess.get(f'{url_hs}/{asdfhash_h}') as resp:
664
- self.eq(200, resp.status)
664
+ self.eq(resp.status, http.HTTPStatus.OK)
665
665
  item = await resp.json()
666
666
  self.eq('ok', item.get('status'))
667
667
  self.true(item.get('result'))
668
668
 
669
669
  async with sess.put(url_ul, data=abuf) as resp:
670
- self.eq(200, resp.status)
670
+ self.eq(resp.status, http.HTTPStatus.OK)
671
671
  item = await resp.json()
672
672
  self.eq('ok', item.get('status'))
673
673
  result = item.get('result')
@@ -676,14 +676,14 @@ bar baz",vv
676
676
  self.true(await realaxon.has(asdfhash))
677
677
 
678
678
  async with sess.get(f'{url_dl}/{asdfhash_h}') as resp:
679
- self.eq(200, resp.status)
679
+ self.eq(resp.status, http.HTTPStatus.OK)
680
680
  self.eq(abuf, await resp.read())
681
681
 
682
682
  # Streaming upload
683
683
  byts = io.BytesIO(bbuf)
684
684
 
685
685
  async with sess.post(url_ul, data=byts) as resp:
686
- self.eq(200, resp.status)
686
+ self.eq(resp.status, http.HTTPStatus.OK)
687
687
  item = await resp.json()
688
688
  self.eq('ok', item.get('status'))
689
689
  result = item.get('result')
@@ -694,7 +694,7 @@ bar baz",vv
694
694
  byts = io.BytesIO(bbuf)
695
695
 
696
696
  async with sess.put(url_ul, data=byts) as resp:
697
- self.eq(200, resp.status)
697
+ self.eq(resp.status, http.HTTPStatus.OK)
698
698
  item = await resp.json()
699
699
  self.eq('ok', item.get('status'))
700
700
  result = item.get('result')
@@ -705,7 +705,7 @@ bar baz",vv
705
705
  byts = io.BytesIO(b'')
706
706
 
707
707
  async with sess.post(url_ul, data=byts) as resp:
708
- self.eq(200, resp.status)
708
+ self.eq(resp.status, http.HTTPStatus.OK)
709
709
  item = await resp.json()
710
710
  self.eq('ok', item.get('status'))
711
711
  result = item.get('result')
@@ -715,7 +715,7 @@ bar baz",vv
715
715
 
716
716
  # Streaming download
717
717
  async with sess.get(f'{url_dl}/{bbufhash_h}') as resp:
718
- self.eq(200, resp.status)
718
+ self.eq(resp.status, http.HTTPStatus.OK)
719
719
 
720
720
  byts = []
721
721
  async for bytz in resp.content.iter_chunked(1024):
@@ -726,44 +726,44 @@ bar baz",vv
726
726
 
727
727
  # HEAD
728
728
  async with sess.head(f'{url_dl}/{bbufhash_h}') as resp:
729
- self.eq(200, resp.status)
729
+ self.eq(resp.status, http.HTTPStatus.OK)
730
730
  self.eq('33554437', resp.headers.get('content-length'))
731
731
  self.none(resp.headers.get('content-range'))
732
732
 
733
733
  async with sess.head(f'{url_dl}/foobar') as resp:
734
- self.eq(404, resp.status)
734
+ self.eq(resp.status, http.HTTPStatus.NOT_FOUND)
735
735
  self.eq('0', resp.headers.get('content-length'))
736
736
 
737
737
  # DELETE method by sha256
738
738
  async with sess.delete(f'{url_dl}/foobar') as resp:
739
- self.eq(404, resp.status)
739
+ self.eq(resp.status, http.HTTPStatus.NOT_FOUND)
740
740
  info = await resp.json()
741
741
  self.eq('err', info.get('status'))
742
742
  self.eq('BadArg', info.get('code'))
743
743
  self.eq('Hash is not a SHA-256: foobar', info.get('mesg'))
744
744
 
745
745
  async with sess.delete(f'{url_dl}/{asdfhash_h}') as resp:
746
- self.eq(200, resp.status)
746
+ self.eq(resp.status, http.HTTPStatus.OK)
747
747
  item = await resp.json()
748
748
  self.eq('ok', item.get('status'))
749
749
  self.true(item.get('result'))
750
750
 
751
751
  async with sess.delete(f'{url_dl}/{asdfhash_h}') as resp:
752
- self.eq(404, resp.status)
752
+ self.eq(resp.status, http.HTTPStatus.NOT_FOUND)
753
753
  item = await resp.json()
754
754
  self.eq('err', item.get('status'))
755
755
 
756
756
  # test /api/v1/axon/file/del API
757
757
  data = {'sha256s': (asdfhash_h, asdfhash_h)}
758
758
  async with sess.post(url_de, json=data) as resp:
759
- self.eq(200, resp.status)
759
+ self.eq(resp.status, http.HTTPStatus.OK)
760
760
  item = await resp.json()
761
761
  self.eq('ok', item.get('status'))
762
762
  self.eq(((asdfhash_h, False), (asdfhash_h, False)), item.get('result'))
763
763
 
764
764
  data = {'newp': 'newp'}
765
765
  async with sess.post(url_de, json=data) as resp:
766
- self.eq(200, resp.status)
766
+ self.eq(resp.status, http.HTTPStatus.BAD_REQUEST)
767
767
  item = await resp.json()
768
768
  self.eq('err', item.get('status'))
769
769
  self.eq('SchemaViolation', item.get('code'))
@@ -783,7 +783,7 @@ bar baz",vv
783
783
 
784
784
  headers = {'range': 'bytes=2-4'}
785
785
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
786
- self.eq(206, resp.status)
786
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
787
787
  self.eq('3', resp.headers.get('content-length'))
788
788
  self.eq('bytes 2-4/12', resp.headers.get('content-range'))
789
789
  buf = b''
@@ -793,7 +793,7 @@ bar baz",vv
793
793
 
794
794
  headers = {'range': 'bytes=,2-'}
795
795
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
796
- self.eq(206, resp.status)
796
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
797
797
  self.eq('10', resp.headers.get('content-length'))
798
798
  self.eq('bytes 2-11/12', resp.headers.get('content-range'))
799
799
  buf = b''
@@ -803,7 +803,7 @@ bar baz",vv
803
803
 
804
804
  headers = {'range': 'bytes=0-11'}
805
805
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
806
- self.eq(206, resp.status)
806
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
807
807
  self.eq('12', resp.headers.get('content-length'))
808
808
  self.eq('bytes 0-11/12', resp.headers.get('content-range'))
809
809
  buf = b''
@@ -813,7 +813,7 @@ bar baz",vv
813
813
 
814
814
  headers = {'range': 'bytes=10-11'}
815
815
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
816
- self.eq(206, resp.status)
816
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
817
817
  self.eq('2', resp.headers.get('content-length'))
818
818
  self.eq('bytes 10-11/12', resp.headers.get('content-range'))
819
819
  buf = b''
@@ -823,7 +823,7 @@ bar baz",vv
823
823
 
824
824
  headers = {'range': 'bytes=11-11'}
825
825
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
826
- self.eq(206, resp.status)
826
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
827
827
  self.eq('1', resp.headers.get('content-length'))
828
828
  self.eq('bytes 11-11/12', resp.headers.get('content-range'))
829
829
  buf = b''
@@ -833,7 +833,7 @@ bar baz",vv
833
833
 
834
834
  headers = {'range': 'bytes=2-4,8-11'}
835
835
  async with sess.get(f'{url_dl}/{shatext}', headers=headers) as resp:
836
- self.eq(206, resp.status)
836
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
837
837
  self.eq('3', resp.headers.get('content-length'))
838
838
  self.eq('bytes 2-4/12', resp.headers.get('content-range'))
839
839
  buf = b''
@@ -844,39 +844,40 @@ bar baz",vv
844
844
  # HEAD tests
845
845
  headers = {'range': 'bytes=2-4'}
846
846
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
847
- self.eq(206, resp.status)
847
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
848
848
  self.eq('3', resp.headers.get('content-length'))
849
849
  self.eq('bytes 2-4/12', resp.headers.get('content-range'))
850
850
 
851
851
  headers = {'range': 'bytes=10-11'}
852
852
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
853
- self.eq(206, resp.status)
853
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
854
854
  self.eq('2', resp.headers.get('content-length'))
855
855
  self.eq('bytes 10-11/12', resp.headers.get('content-range'))
856
856
 
857
857
  headers = {'range': 'bytes=11-11'}
858
858
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
859
- self.eq(206, resp.status)
859
+ self.eq(resp.status, http.HTTPStatus.PARTIAL_CONTENT)
860
860
  self.eq('1', resp.headers.get('content-length'))
861
861
  self.eq('bytes 11-11/12', resp.headers.get('content-range'))
862
862
 
863
+ # TODO - In python 3.13+ this can be HTTPStatus.RANGE_NOT_SATISFIABLE
863
864
  # Reading past blobsize isn't valid HTTP
864
865
  headers = {'range': 'bytes=10-20'}
865
866
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
866
- self.eq(416, resp.status)
867
+ self.eq(resp.status, http.HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
867
868
 
868
869
  headers = {'range': 'bytes=11-12'}
869
870
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
870
- self.eq(416, resp.status)
871
+ self.eq(resp.status, http.HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
871
872
 
872
873
  headers = {'range': 'bytes=20-40'}
873
874
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
874
- self.eq(416, resp.status)
875
+ self.eq(resp.status, http.HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
875
876
 
876
877
  # Negative size
877
878
  headers = {'range': 'bytes=20-4'}
878
879
  async with sess.head(f'{url_dl}/{shatext}', headers=headers) as resp:
879
- self.eq(416, resp.status)
880
+ self.eq(resp.status, http.HTTPStatus.REQUESTED_RANGE_NOT_SATISFIABLE)
880
881
 
881
882
  async def test_axon_perms(self):
882
883
  async with self.getTestAxon() as axon: