Skip to content

Commit 5688012

Browse files
Merge pull request #206 from TokenNotIncluded/fix/home-summary-fixtures-20261001
Preserve homepage read contracts and align installed restore checks
2 parents 5dbc03b + ab301ca commit 5688012

6 files changed

Lines changed: 65 additions & 23 deletions

File tree

‎scripts/check_installed_server.py‎

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -181,10 +181,13 @@ async def restore_drill(settings, folder, client, packet, source_dsn):
181181
expected_settings['recovery_quarantine'] = current_settings['recovery_quarantine']
182182
original['tables']['settings'] = sorted(canonical(row) for row in expected_settings.items())
183183
assert current == original, 'Restore changed other table values or sequence state'
184+
restored_settings = load_settings(folder / 'restore-etc')
185+
marker = restored_settings.recovery_marker
186+
assert marker.is_file(), 'Restore did not install its configured quarantine marker'
184187
for marker_present in (True, False):
185188
if not marker_present:
186-
(folder / 'restore-etc/recovery-drill.json').unlink()
187-
recovered = Application(load_settings(folder / 'restore-etc'))
189+
marker.unlink()
190+
recovered = Application(restored_settings)
188191
try:
189192
await recovered.load()
190193
replay = await recovered.executor.execute(packet)

‎src/msg/plugins/discovery.py‎

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -570,8 +570,15 @@ def install(app):
570570
op, finish = registration(app, 'discovery', ('identity', 'content'))
571571
fields = {'type': 'array', 'items': STRING, 'maxItems': 30, 'uniqueItems': True}
572572

573+
@op(
574+
'discovery.read_query',
575+
obj({'home_summary': {'const': True}}, ('home_summary',)),
576+
effect='read',
577+
version=4,
578+
)
573579
async def home(ctx, request, tx):
574580
"""Live counts and recent resources, filtered by current read access."""
581+
require(ctx.principal.subject is None, 'public_home_summary_only')
575582
timezone = ZoneInfo('Asia/Taipei')
576583
today = ctx.now.astimezone(timezone).date()
577584
posts = posts_today = users = 0
@@ -805,16 +812,6 @@ async def read_segment(ctx, request, tx):
805812

806813
async def list_items(ctx, request, tx, *, arguments=None, budget=None):
807814
a = dict(request.arguments if arguments is None else arguments)
808-
if 'home_summary' in a:
809-
require(
810-
request.operation == 'discovery.read_query'
811-
and request.contract_version == 1
812-
and a == {'home_summary': True},
813-
'invalid_home_summary',
814-
)
815-
require(ctx.principal.subject is None, 'public_home_summary_only')
816-
return await home(ctx, request, tx)
817-
818815
stable = request.operation == 'discovery.read_query'
819816
internal_page = getattr(request, 'internal_page_state', None)
820817
if internal_page is not None:
@@ -957,7 +954,7 @@ async def list_items(ctx, request, tx, *, arguments=None, budget=None):
957954

958955
op('discovery.list', obj(listing), effect='read')(list_items)
959956
op('discovery.search', obj(listing, ('query',)), effect='read')(list_items)
960-
op('discovery.read_query', obj({**listing, 'home_summary': BOOLEAN}), effect='read')(list_items)
957+
op('discovery.read_query', obj(listing), effect='read')(list_items)
961958

962959
nested_schema = obj(
963960
{

‎src/msg/transports/http_routes.py‎

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1764,10 +1764,15 @@ async def dispatch(request: Request):
17641764
if header:
17651765
packet = path_packet(header, 'j', limits.max_request_bytes)
17661766
require(packet.operation == spec.name, 'operation_mismatch')
1767+
require(packet.contract_version == spec.version, 'representation_mismatch')
17671768
require(dict(packet.arguments) == args, 'representation_mismatch')
17681769
else:
17691770
packet = request_for(
1770-
spec.name, args, service.settings.service_url, source='manual'
1771+
spec.name,
1772+
args,
1773+
service.settings.service_url,
1774+
source='manual',
1775+
contract_version=spec.version,
17711776
)
17721777
result = await service.executor.execute(packet, entry='network')
17731778
value = result_wire(result)
@@ -1791,6 +1796,7 @@ async def dispatch(request: Request):
17911796
{'home_summary': True},
17921797
service.settings.service_url,
17931798
source='manual',
1799+
contract_version=4,
17941800
)
17951801
result = await service.executor.execute(packet, entry='network')
17961802
if result.error and result.error.code != 'query_cost_exceeded':

‎tests/test_branding.py‎

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@
99
import pytest
1010
from test_service import NOW, call, register
1111

12-
from msg.core.codec import canonical, wire
12+
from msg.core.codec import b64, canonical, wire
13+
from msg.core.requests import request_for
14+
from msg.transports.dictionary import build_dictionary
1315
from msg.transports.http import create_app
1416

1517

@@ -217,11 +219,43 @@ async def test_home_summary_uses_existing_read_authority_and_remains_public(inst
217219
app, _ = installed
218220
assert all(operation.name != 'discovery.home' for operation in app.registry.operations())
219221
key, uid, cert = await register(app, 'home-summary-reader')
220-
anonymous = await call(app, 'discovery.read_query', {'home_summary': True})
222+
anonymous = await call(app, 'discovery.read_query', {'home_summary': True}, contract_version=4)
221223
assert anonymous.status == 'ok' and 'posts' in anonymous.data
222224
authenticated = await call(
223-
app, 'discovery.read_query', {'home_summary': True}, key=key, subject=uid, certs=(cert,)
225+
app,
226+
'discovery.read_query',
227+
{'home_summary': True},
228+
key=key,
229+
subject=uid,
230+
certs=(cert,),
231+
contract_version=4,
224232
)
225233
assert authenticated.error.code == 'public_home_summary_only'
226-
mixed = await call(app, 'discovery.read_query', {'home_summary': True, 'parent': '/main'})
227-
assert mixed.error.code == 'invalid_home_summary'
234+
mixed = await call(
235+
app, 'discovery.read_query', {'home_summary': True, 'parent': '/main'}, contract_version=4
236+
)
237+
assert mixed.error.code == 'schema_validation'
238+
for args in ({}, {'home_summary': False}):
239+
invalid = await call(app, 'discovery.read_query', args, contract_version=4)
240+
assert invalid.error.code == 'schema_validation'
241+
legacy = await call(app, 'discovery.read_query', {'home_summary': True})
242+
assert legacy.error.code == 'schema_validation'
243+
dictionary = build_dictionary(app.registry)
244+
direct_path = next(
245+
row['example']
246+
for row in dictionary.document['operations']
247+
if row['name'] == 'discovery.read_query' and row['version'] == 4
248+
)
249+
wrong_version = request_for(
250+
'discovery.read_query', {'home_summary': True}, app.settings.service_url
251+
)
252+
async with httpx.AsyncClient(
253+
transport=httpx.ASGITransport(app=create_app(app)), base_url=app.settings.service_url
254+
) as http:
255+
direct = await http.get(direct_path)
256+
assert direct.status_code == 200 and 'posts' in direct.json()['data']
257+
mismatched = await http.get(
258+
direct_path, headers={'X-Msg-Request': b64(canonical(wrong_version))}
259+
)
260+
assert mismatched.status_code == 400
261+
assert mismatched.json()['error']['code'] == 'representation_mismatch'

‎tests/test_nginx_secret_logs.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,10 @@ def recovery_drill_active(self):
157157
async def execute(self, packet, *, entry):
158158
# The homepage is the only read exercised by this boundary fixture.
159159
# Any attempted business execution still fails immediately.
160-
assert packet.operation == 'discovery.home'
160+
assert packet.operation == 'discovery.read_query'
161+
assert packet.contract_version == 4
161162
assert entry == 'network'
162-
assert not packet.arguments
163+
assert packet.arguments == {'home_summary': True}
163164
return SimpleNamespace(
164165
error=None,
165166
data={

‎tests/test_request_target_safety.py‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,9 +27,10 @@ def recovery_drill_active(self):
2727
async def execute(self, packet, *, entry):
2828
# The homepage is the only read exercised by this boundary fixture.
2929
# Any attempted business execution still fails immediately.
30-
assert packet.operation == 'discovery.home'
30+
assert packet.operation == 'discovery.read_query'
31+
assert packet.contract_version == 4
3132
assert entry == 'network'
32-
assert not packet.arguments
33+
assert packet.arguments == {'home_summary': True}
3334
return SimpleNamespace(
3435
error=None,
3536
data={

0 commit comments

Comments
 (0)