installer v1 (A+B): install-code enrollment, panel code UI, EXE publish; DPAPI credential store

This commit is contained in:
gti
2026-09-23 16:38:19 -03:00
parent b058affa29
commit 91c4030b06
15 changed files with 1135 additions and 54 deletions
+48 -3
View File
@@ -36,6 +36,14 @@ def router(session_factory):
def client_ip(request):
return request.client.host if request.client else None
def _aware(value: datetime | None) -> datetime | None:
"""SQLite (used by the test suite) drops tzinfo on round-trip even for
a DateTime(timezone=True) column; Postgres never does. Normalize to
UTC before comparing against datetime.now(timezone.utc)."""
if value is None or value.tzinfo is not None:
return value
return value.replace(tzinfo=timezone.utc)
def set_session_cookies(response, token, csrf, seconds):
cfg = config.settings
response.set_cookie(cfg.web_cookie_name, token, max_age=seconds, httponly=True, secure=cfg.web_cookie_secure, samesite="lax")
@@ -289,7 +297,7 @@ def router(session_factory):
return session.scalar(select(AgentEnrollment).where(AgentEnrollment.enrollment_uuid == enrollment_uuid))
@routes.get("/agents/pending/{enrollment_uuid}", response_class=HTMLResponse)
def pending_installation_detail(request: Request, enrollment_uuid: str, link: str | None = None):
def pending_installation_detail(request: Request, enrollment_uuid: str, link: str | None = None, code: str | None = None):
session, auth_data, redirect = page_auth(request)
if redirect: return redirect
try:
@@ -298,7 +306,11 @@ def router(session_factory):
release = session.get(AgentRelease, enr.release_id)
tenant = session.get(Tenant, enr.tenant_id)
installed_agent = session.get(Agent, enr.agent_id) if enr.agent_id else None
return render(request, "agent_pending_detail.html", {"enr": enr, "release": release, "tenant": tenant, "installed_agent": installed_agent, "download_link": link, "auth": auth_data})
active_code = bool(enr.install_code_hash and enr.install_code_expires_at and _aware(enr.install_code_expires_at) > datetime.now(timezone.utc))
code_expires_at = enr.install_code_expires_at if active_code else None
return render(request, "agent_pending_detail.html", {"enr": enr, "release": release, "tenant": tenant, "installed_agent": installed_agent,
"download_link": link, "install_code": code, "code_active": active_code,
"code_expires_at": code_expires_at, "auth": auth_data})
finally: session.close()
@routes.post("/agents/pending/{enrollment_uuid}/link")
@@ -347,17 +359,50 @@ def router(session_factory):
require_csrf(web_session, values.get("csrf_token"))
enr = _pending_or_404(session, enrollment_uuid)
if not enr: return HTMLResponse("Installation not found", status_code=404)
was_code_active = bool(enr.install_code_hash)
enr.status = "REVOKED"
enr.download_token_hash = None
enr.enrollment_token_hash = None
enr.install_code_hash = None
enr.install_code_expires_at = None
if enr.agent_id:
agent = session.get(Agent, enr.agent_id)
if agent: agent.enabled = False
record_audit(session, admin_user_id=admin.id, tenant_id=enr.tenant_id, action="INSTALLATION_REVOKED", target_type="agent_enrollment", target_id=enrollment_uuid, context={"had_agent": bool(enr.agent_id)})
record_audit(session, admin_user_id=admin.id, tenant_id=enr.tenant_id, action="INSTALLATION_REVOKED", target_type="agent_enrollment", target_id=enrollment_uuid,
context={"had_agent": bool(enr.agent_id), "had_install_code": was_code_active})
if was_code_active:
record_audit(session, admin_user_id=admin.id, tenant_id=enr.tenant_id, action="INSTALLATION_CODE_REVOKED", target_type="agent_enrollment", target_id=enrollment_uuid, context={})
session.commit()
return RedirectResponse(f"/agents/pending/{enrollment_uuid}", status_code=303)
finally: session.close()
@routes.post("/agents/pending/{enrollment_uuid}/code")
async def generate_install_code(request: Request, enrollment_uuid: str):
"""Generate (or rotate) the installation code shown to the operator and
typed into the universal EXE installer. Only the SHA-256 of the
normalized code is ever stored; the plaintext is returned in the HTML
once, to the SSO-authenticated operator who created the installation."""
session, auth_data, redirect = page_auth(request)
if redirect: return redirect
try:
values = await form_values(request); web_session, admin = auth_data
require_csrf(web_session, values.get("csrf_token"))
enr = _pending_or_404(session, enrollment_uuid)
if not enr: return HTMLResponse("Installation not found", status_code=404)
if enr.status in ("ENROLLED", "REVOKED"):
return RedirectResponse(f"/agents/pending/{enrollment_uuid}", status_code=303)
code = enrollment.generate_install_code()
now = datetime.now(timezone.utc)
enr.install_code_hash = enrollment.install_code_digest(code)
enr.install_code_expires_at = now + timedelta(seconds=config.settings.agent_enrollment_ttl_seconds)
enr.install_code_attempts = 0
enr.install_code_created_at = now
record_audit(session, admin_user_id=admin.id, tenant_id=enr.tenant_id, action="INSTALLATION_CODE_CREATED", target_type="agent_enrollment",
target_id=enrollment_uuid, context={"ttl_seconds": config.settings.agent_enrollment_ttl_seconds, "ip": client_ip(request)})
session.commit()
return RedirectResponse(f"/agents/pending/{enrollment_uuid}?code={code}", status_code=303)
finally: session.close()
@routes.get("/blockers", response_class=HTMLResponse)
def blockers(request: Request, page: int = 1, client: str | None = None, installation: str | None = None, field: str | None = None, blocker_type: str | None = None, status: str = "OPEN", age: str | None = None, search: str | None = None, agent_id: int | None = None, product_code: str | None = None):
session, auth_data, redirect = page_auth(request)