mirror of
https://github.com/jhd3197/ServerKit.git
synced 2026-10-31 09:06:52 +09:00
Vela holds one ServerKit API key as a host-side secret and polls the
fleet list, so this read route moves from bare @jwt_required() to
auth_required() + require_scope('servers:read') — a deliberate,
per-route jwt_only_census exception, not a sweep. JWT callers are
unchanged; a restricted key without servers:read gets 403 from the
scope middleware, no credentials get 401.
Scope choice: the existing servers:read catalog entry already covers
'list servers, agents, and metrics', and the serverkit-gui read routes
(capabilities/frame/surface, sibling repo) take the same scope, so one
key scope serves the whole Vela polling surface.
The census ceiling ratchets down to 600 and the migration inventory is
regenerated, as both ratchets require. tests/test_servers_api_key_scope.py
pins the four cases: scoped key 200, wrong-scope key 403, JWT 200,
anonymous 401.
41 lines
1.5 KiB
Python
41 lines
1.5 KiB
Python
"""GET /api/v1/servers accepts a scoped API key (deliberate conversion).
|
|
|
|
A Vela host holds one ServerKit API key as a host-side secret and polls the
|
|
fleet list, so this read route takes a JWT *or* an ``X-API-Key`` carrying the
|
|
``servers:read`` scope. That is a recorded jwt_only_census exception — JWT-only
|
|
stays the default elsewhere (see tests/jwt_only_census.py); these tests pin
|
|
the behavior of the exception itself.
|
|
"""
|
|
from factories import make_user, headers_for
|
|
from app.services.api_key_service import ApiKeyService
|
|
|
|
|
|
def _api_key_headers(db, scopes):
|
|
user = make_user(db)
|
|
_, raw_key = ApiKeyService.create_key(user.id, name='servers-poll', scopes=scopes)
|
|
return {'X-API-Key': raw_key}
|
|
|
|
|
|
def test_api_key_with_servers_read_scope_lists_servers(client, db_session):
|
|
resp = client.get('/api/v1/servers',
|
|
headers=_api_key_headers(db_session, ['servers:read']))
|
|
assert resp.status_code == 200
|
|
assert isinstance(resp.json, list)
|
|
|
|
|
|
def test_api_key_without_the_scope_is_denied(client, db_session):
|
|
resp = client.get('/api/v1/servers',
|
|
headers=_api_key_headers(db_session, ['databases:read']))
|
|
assert resp.status_code == 403
|
|
|
|
|
|
def test_jwt_caller_still_lists_servers(client, db_session):
|
|
resp = client.get('/api/v1/servers',
|
|
headers=headers_for(make_user(db_session)))
|
|
assert resp.status_code == 200
|
|
assert isinstance(resp.json, list)
|
|
|
|
|
|
def test_unauthenticated_gets_401(client):
|
|
assert client.get('/api/v1/servers').status_code == 401
|