feat: show application ownership and scoped console management

This commit is contained in:
2026-09-27 12:12:46 +08:00
parent ed17713ea1
commit 1f2e7230dc
26 changed files with 757 additions and 47 deletions

View File

@@ -105,7 +105,37 @@ call('/v1/subscriptions/' + subscription_id + ':configure', {'expected_revision'
if private:
Path(private, 'host.env').write_text(f"ORBIT_URL={base}\nORBIT_TOKEN={rotate['token']}\nORBIT_NAMESPACE_ID={op['namespace_id']}\nORBIT_QUEUE_ID={queue}\n")
Path(private, 'result.json').write_text(json.dumps({'application': name, 'namespace_id': op['namespace_id'], 'queue_id': queue, 'credential_id': op['credential_id'], 'task_id': task_id, 'subscription_id': subscription_id}))
# 登录管理员按应用范围读取和管理;SDK 不能使用范围请求头。
scope_headers = {'X-Orbit-Namespace': op['namespace_id'], 'X-Orbit-Console': '1'}
original_scope = call('/console/scope')
scope = call('/console/scope', headers=scope_headers)
assert scope['entry']['application'] == name and scope['entry']['environment'] == 'test'
assert scope['entry']['namespace_id'] == op['namespace_id'] and scope['can_switch']
assert any(q['id'] == queue for q in scope['queues'])
call('/console/scope', token=rotate['token'], headers=scope_headers, expected=403, session=False)
call('/v1/tasks/' + task_id, headers=scope_headers, token=rotate['token'], expected=403)
call('/v1/tasks/' + task_id, expected=404)
assert call('/v1/tasks/' + task_id, headers=scope_headers)['id'] == task_id
assert any(t['id'] == task_id for t in call('/v1/tasks?queue_id=' + queue, headers=scope_headers)['items'])
assert any(s['id'] == subscription_id for s in call('/v1/subscriptions?queue_id=' + queue, headers=scope_headers)['items'])
assert call('/v1/subscriptions/' + subscription_id, headers=scope_headers)['credential_id'] == op['credential_id']
for path in ['/v1/schedules?queue_id=' + queue, '/v1/workflows', '/console/retention/preview', '/console/archive/plans', '/console/archive/jobs']:
call(path, headers=scope_headers)
foreign_queue = original_scope['queues'][0]['id']
assert call('/v1/tasks?queue_id=' + foreign_queue, headers=scope_headers)['items'] == []
call('/v1/queues/' + foreign_queue, headers=scope_headers, expected=404)
call('/console/retention/export', {'kind': 'tasks', 'expected_revision': '0'}, headers={**scope_headers, 'Origin': 'https://other.invalid'}, expected=403)
# 管理订阅不改绑原 SDK 凭据,重复操作仍返回同一回执。
sub_current = call('/v1/subscriptions/' + subscription_id, headers=scope_headers)
pause = {'expected_revision': sub_current['revision'], 'enabled': False, 'reason': 'scoped console acceptance'}
manage_headers = {**scope_headers, 'Idempotency-Key': 'scope-pause-subscription'}
call('/v1/subscriptions/' + subscription_id + ':configure', pause, headers=manage_headers)
call('/v1/subscriptions/' + subscription_id + ':configure', pause, headers=manage_headers)
assert call('/v1/subscriptions/' + subscription_id, token=rotate['token'], session=False)['credential_id'] == op['credential_id']
assert call('/console/scope')['entry']['namespace_id'] == original_scope['entry']['namespace_id']
print('PASS: scoped task/schedule/workflow/subscription/retention/archive reads, subscription management/replay, SDK ownership, CSRF and cross-application isolation')
call('/console/auth/logout', {})
call('/console/applications', expected=401)
call('/v1/tasks/' + task_id, headers=scope_headers, expected=401)
print('PASS: application create/replay, CSRF/session isolation, permanent expiry, overlapping rotation/finalization, original task/subscription preserved, logout')
print('Test application: ' + name)