sovereign 1.0.0b102__tar.gz → 1.0.0b103__tar.gz
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 sovereign might be problematic. Click here for more details.
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/PKG-INFO +1 -1
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/pyproject.toml +1 -1
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/schemas.py +1 -1
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/sources/poller.py +152 -45
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/LICENSE.txt +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/README.md +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/app.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/cache.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/constants.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/context.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/dynamic_config/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/dynamic_config/deser.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/dynamic_config/loaders.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/error_info.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/logging/access_logger.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/logging/application_logger.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/logging/base_logger.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/logging/bootstrapper.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/logging/types.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/middlewares.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/modifiers/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/modifiers/lib.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/rendering.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/response_class.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/server.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/sources/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/sources/file.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/sources/inline.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/sources/lib.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/static/node_expression.js +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/static/panel.js +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/static/sass/style.scss +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/static/style.css +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/statistics.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/templates/base.html +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/templates/err.html +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/templates/resources.html +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/testing/loaders.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/testing/modifiers.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/tracing.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/auth.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/crypto.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/aes_gcm_cipher.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/base_cipher.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/disabled_cipher.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/fernet_cipher.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/dictupdate.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/eds.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/entry_point_loader.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/mock.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/resources.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/templates.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/timer.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/version_info.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/weighted_clusters.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/__init__.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/api.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/crypto.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/discovery.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/healthchecks.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/views/interface.py +0 -0
- {sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/worker.py +0 -0
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import json
|
|
2
|
+
import uuid
|
|
2
3
|
import asyncio
|
|
3
4
|
import traceback
|
|
4
5
|
from copy import deepcopy
|
|
@@ -33,29 +34,100 @@ Mods = Dict[str, Type[Modifier]]
|
|
|
33
34
|
GMods = Dict[str, Type[GlobalModifier]]
|
|
34
35
|
|
|
35
36
|
|
|
36
|
-
def
|
|
37
|
-
if not isinstance(old, dict) or not isinstance(new, dict):
|
|
38
|
-
return ["content_changed"]
|
|
39
|
-
|
|
37
|
+
def _deep_diff(old, new, path="") -> list[dict[str, Any]]:
|
|
40
38
|
changes = []
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
39
|
+
|
|
40
|
+
# handle add/remove
|
|
41
|
+
if (old, new) == (None, None):
|
|
42
|
+
return changes
|
|
43
|
+
elif old is None:
|
|
44
|
+
changes.append({
|
|
45
|
+
"op": "add",
|
|
46
|
+
"path": path,
|
|
47
|
+
"value": new
|
|
48
|
+
})
|
|
49
|
+
return changes
|
|
50
|
+
elif new is None:
|
|
51
|
+
changes.append({
|
|
52
|
+
"op": "remove",
|
|
53
|
+
"path": path,
|
|
54
|
+
"old_value": old
|
|
55
|
+
})
|
|
56
|
+
return changes
|
|
57
|
+
|
|
58
|
+
# handle completely different types
|
|
59
|
+
if type(old) is not type(new):
|
|
60
|
+
changes.append({
|
|
61
|
+
"op": "change",
|
|
62
|
+
"path": path,
|
|
63
|
+
"old_value": old,
|
|
64
|
+
"new_value": new
|
|
65
|
+
})
|
|
66
|
+
return changes
|
|
67
|
+
|
|
68
|
+
# handle fields recursively
|
|
69
|
+
if isinstance(old, dict) and isinstance(new, dict):
|
|
70
|
+
all_keys = set(old.keys()) | set(new.keys())
|
|
71
|
+
|
|
72
|
+
for key in sorted(all_keys):
|
|
73
|
+
old_val = old.get(key)
|
|
74
|
+
new_val = new.get(key)
|
|
75
|
+
|
|
76
|
+
current_path = f"{path}.{key}" if path else key
|
|
77
|
+
|
|
48
78
|
if key not in old:
|
|
49
|
-
changes.append(
|
|
79
|
+
changes.append({
|
|
80
|
+
"op": "add",
|
|
81
|
+
"path": current_path,
|
|
82
|
+
"value": new_val
|
|
83
|
+
})
|
|
50
84
|
elif key not in new:
|
|
51
|
-
changes.append(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
85
|
+
changes.append({
|
|
86
|
+
"op": "remove",
|
|
87
|
+
"path": current_path,
|
|
88
|
+
"old_value": old_val
|
|
89
|
+
})
|
|
90
|
+
elif old_val != new_val:
|
|
91
|
+
nested_changes = _deep_diff(old_val, new_val, current_path)
|
|
92
|
+
changes.extend(nested_changes)
|
|
93
|
+
|
|
94
|
+
# handle items recursively
|
|
95
|
+
elif isinstance(old, list) and isinstance(new, list):
|
|
96
|
+
max_len = max(len(old), len(new))
|
|
97
|
+
|
|
98
|
+
for i in range(max_len):
|
|
99
|
+
current_path = f"{path}[{i}]" if path else f"[{i}]"
|
|
100
|
+
|
|
101
|
+
if i >= len(old):
|
|
102
|
+
changes.append({
|
|
103
|
+
"op": "add",
|
|
104
|
+
"path": current_path,
|
|
105
|
+
"value": new[i]
|
|
106
|
+
})
|
|
107
|
+
elif i >= len(new):
|
|
108
|
+
changes.append({
|
|
109
|
+
"op": "remove",
|
|
110
|
+
"path": current_path,
|
|
111
|
+
"old_value": old[i]
|
|
112
|
+
})
|
|
113
|
+
elif old[i] != new[i]:
|
|
114
|
+
nested_changes = _deep_diff(old[i], new[i], current_path)
|
|
115
|
+
changes.extend(nested_changes)
|
|
116
|
+
|
|
117
|
+
# handle primitives
|
|
118
|
+
else:
|
|
119
|
+
if old != new:
|
|
120
|
+
changes.append({
|
|
121
|
+
"op": "change",
|
|
122
|
+
"path": path,
|
|
123
|
+
"old_value": old,
|
|
124
|
+
"new_value": new
|
|
125
|
+
})
|
|
126
|
+
|
|
55
127
|
return changes
|
|
56
128
|
|
|
57
129
|
|
|
58
|
-
def per_field_diff(old, new):
|
|
130
|
+
def per_field_diff(old, new) -> list[dict[str, Any]]:
|
|
59
131
|
changes = []
|
|
60
132
|
max_len = max(len(old), len(new))
|
|
61
133
|
|
|
@@ -64,45 +136,75 @@ def per_field_diff(old, new):
|
|
|
64
136
|
new_inst = new[i] if i < len(new) else None
|
|
65
137
|
|
|
66
138
|
if old_inst is None:
|
|
67
|
-
changes.append(
|
|
139
|
+
changes.append({
|
|
140
|
+
"op": "add",
|
|
141
|
+
"path": f"[{i}]",
|
|
142
|
+
"value": new_inst
|
|
143
|
+
})
|
|
68
144
|
elif new_inst is None:
|
|
69
|
-
changes.append(
|
|
145
|
+
changes.append({
|
|
146
|
+
"op": "remove",
|
|
147
|
+
"path": f"[{i}]",
|
|
148
|
+
"old_value": old_inst
|
|
149
|
+
})
|
|
70
150
|
elif old_inst != new_inst:
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
151
|
+
# Use the deep diff with index prefix
|
|
152
|
+
field_changes = _deep_diff(old_inst, new_inst, f"[{i}]")
|
|
153
|
+
changes.extend(field_changes)
|
|
74
154
|
|
|
75
155
|
return changes
|
|
76
156
|
|
|
77
157
|
|
|
78
|
-
def
|
|
158
|
+
def _gen_uuid(diff_summary: dict[str, Any]) -> str:
|
|
159
|
+
blob = json.dumps(diff_summary, sort_keys=True, separators=('', ''))
|
|
160
|
+
return str(uuid.uuid5(uuid.NAMESPACE_DNS, blob))
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def source_diff_summary(prev, curr) -> dict[str, Any]:
|
|
79
164
|
if prev is None:
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
165
|
+
summary = {
|
|
166
|
+
"type": "initial_load",
|
|
167
|
+
"scopes": {
|
|
168
|
+
scope: {"added": len(instances)}
|
|
169
|
+
for scope, instances in curr.scopes.items()
|
|
170
|
+
if instances
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
else:
|
|
174
|
+
summary = {
|
|
175
|
+
"type": "update",
|
|
176
|
+
"scopes": {}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
all_scopes = set(prev.scopes.keys()) | set(curr.scopes.keys())
|
|
180
|
+
|
|
181
|
+
for scope in sorted(all_scopes):
|
|
182
|
+
old = prev.scopes.get(scope, [])
|
|
183
|
+
new = curr.scopes.get(scope, [])
|
|
85
184
|
|
|
86
|
-
|
|
87
|
-
|
|
185
|
+
n_old = len(old)
|
|
186
|
+
n_new = len(new)
|
|
88
187
|
|
|
89
|
-
|
|
90
|
-
old = prev.scopes.get(scope, [])
|
|
91
|
-
new = curr.scopes.get(scope, [])
|
|
188
|
+
scope_changes = {}
|
|
92
189
|
|
|
93
|
-
|
|
94
|
-
|
|
190
|
+
if n_old == 0 and n_new > 0:
|
|
191
|
+
scope_changes["added"] = n_new
|
|
192
|
+
elif n_old > 0 and n_new == 0:
|
|
193
|
+
scope_changes["removed"] = n_old
|
|
194
|
+
elif old != new:
|
|
195
|
+
detailed_changes = per_field_diff(old, new)
|
|
196
|
+
if detailed_changes:
|
|
197
|
+
scope_changes["field_changes"] = detailed_changes
|
|
198
|
+
scope_changes["count_change"] = n_new - n_old
|
|
95
199
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
elif n_old > 0 and n_new == 0:
|
|
99
|
-
summary.append(f"scope:{scope} removed:{n_old} instances")
|
|
100
|
-
elif old != new:
|
|
101
|
-
detailed_changes = per_field_diff(old, new)
|
|
102
|
-
if detailed_changes:
|
|
103
|
-
summary.append(f"scope:{scope} changes: {'; '.join(detailed_changes)}")
|
|
200
|
+
if scope_changes:
|
|
201
|
+
summary["scopes"][scope] = scope_changes
|
|
104
202
|
|
|
105
|
-
|
|
203
|
+
if not summary["scopes"]:
|
|
204
|
+
summary = {"type": "no_changes"}
|
|
205
|
+
|
|
206
|
+
summary["uuid"] = _gen_uuid(summary)
|
|
207
|
+
return summary
|
|
106
208
|
|
|
107
209
|
|
|
108
210
|
class SourcePoller:
|
|
@@ -229,7 +331,10 @@ class SourcePoller:
|
|
|
229
331
|
try:
|
|
230
332
|
new = SourceData()
|
|
231
333
|
for source in self.sources:
|
|
232
|
-
|
|
334
|
+
scope = source.scope
|
|
335
|
+
if scope not in new.scopes:
|
|
336
|
+
new.scopes[scope] = []
|
|
337
|
+
new.scopes[scope].extend(source.get())
|
|
233
338
|
except Exception as e:
|
|
234
339
|
self.logger.error(
|
|
235
340
|
event="Error while refreshing sources",
|
|
@@ -345,6 +450,8 @@ class SourcePoller:
|
|
|
345
450
|
or is_debug_request(node_value)
|
|
346
451
|
)
|
|
347
452
|
if match:
|
|
453
|
+
if scope not in ret.scopes:
|
|
454
|
+
ret.scopes[scope] = []
|
|
348
455
|
ret.scopes[scope].append(instance)
|
|
349
456
|
return ret
|
|
350
457
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/aes_gcm_cipher.py
RENAMED
|
File without changes
|
{sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/base_cipher.py
RENAMED
|
File without changes
|
{sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/disabled_cipher.py
RENAMED
|
File without changes
|
{sovereign-1.0.0b102 → sovereign-1.0.0b103}/src/sovereign/utils/crypto/suites/fernet_cipher.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|