Files
ServerKit/backend/app/api/connect.py
Juan Denis d866de5439 feat(connect): apply the managed presentation profile (plan 25)
Panel side of the managed profile: the panel receives a presentation
profile from Cloud over the existing command channel, stores it,
acknowledges it, and hides or simplifies fleet-owner-only surfaces
until the profile is lifted or the link is revoked.

- ui.managed_profile command handler with managed-profile.json
  storage, audit entries, and ack-by-output; profile is cleared on
  disconnect and on consent revoke
- GET /api/v1/connect/managed-profile for the local UI
- ManagedProfileContext with capability-driven filtering of sidebar
  items, command palette actions, and sidebar settings; ManagedCard
  explains the managed state
- In-page collapses for Templates deploy, About self-update, and
  Backup schedules/storage (restore stays available)
- Settings gains a ServerKit Cloud tab showing link and profile state

Local verification: 153 backend tests pass, 198 frontend node tests
pass, lint clean, build ok. No live policy has been pushed to a real
panel yet.
2026-09-13 03:50:02 -04:00

31 lines
1.1 KiB
Python

"""Connect API — expose this panel's ServerKit Cloud connection state.
Pairing itself happens via `serverkit connect` on the host (see
app/services/connect_client.py); this read-only endpoint lets the Settings
UI render the connection state.
"""
from flask import Blueprint, jsonify
from app.middleware.rbac import admin_required
from app.services import connect_client
connect_bp = Blueprint('connect', __name__)
@connect_bp.route('/status', methods=['GET'])
@admin_required
def get_status():
"""Current ServerKit Cloud connection state (unpaired/paired_offline/...)."""
return jsonify(connect_client.status())
@connect_bp.route('/managed-profile', methods=['GET'])
@admin_required
def get_managed_profile():
"""The managed profile in force (plan 25). Read-only: the signed
ui.managed_profile command handler is the only writer, and lifting the
profile from ServerKit Cloud — never from here — is the only off switch
other than expiry or revocation."""
from app.services import connect_managed_profile
return jsonify(connect_managed_profile.current())