Add ERP Local Agent secure self update framework
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
from __future__ import annotations
|
||||
from __future__ import annotations
|
||||
|
||||
from datetime import date, datetime, timezone
|
||||
import asyncio
|
||||
@@ -80,7 +80,7 @@ from app.modules.documents.services import (
|
||||
from app.modules.services.models import ClientServiceSubscription
|
||||
from app.modules.core.tenancy.models import Branch, Tenant
|
||||
from app.modules.core.tenancy.year_control import is_row_financial_year_locked
|
||||
from app.modules.documents.agent_package import build_agent_env, build_preconfigured_agent_zip
|
||||
from app.modules.documents.agent_package import ERP_LOCAL_AGENT_VERSION, build_agent_env, build_preconfigured_agent_zip, build_agent_update_zip
|
||||
from app.modules.documents.models import BranchStorageNode
|
||||
|
||||
from app.modules.services.task_documents import (
|
||||
@@ -1073,7 +1073,7 @@ def _default_node_name(db, tenant_id: int, branch_id: int | None) -> str:
|
||||
|
||||
def _agent_download_filename(node_code: str, suffix: str) -> str:
|
||||
safe = re.sub(r"[^A-Za-z0-9_.-]+", "_", node_code or "storage_node")
|
||||
return f"AuditFirmStorageAgent_{safe}{suffix}"
|
||||
return f"ERPLocalAgent_{safe}{suffix}"
|
||||
|
||||
|
||||
def _find_existing_storage_node(db, tenant_id: int, branch_id: int | None) -> BranchStorageNode | None:
|
||||
@@ -1226,7 +1226,7 @@ def _branch_name_map(db, branches=None):
|
||||
|
||||
def _storage_scope_title(user, scope) -> str:
|
||||
if scope.is_system_admin:
|
||||
return "All audit firms — monitoring only"
|
||||
return "All audit firms — monitoring only"
|
||||
if scope.is_firm_admin:
|
||||
return "All branches of your audit firm"
|
||||
if _is_partner_branch_storage_scope(scope):
|
||||
@@ -1282,6 +1282,7 @@ def storage_nodes(request: Request):
|
||||
recent_download_requests=requests,
|
||||
generated_secret=None,
|
||||
storage_scope_title=_storage_scope_title(user, scope),
|
||||
erp_local_agent_version=ERP_LOCAL_AGENT_VERSION,
|
||||
can_manage_branch_storage=_can_manage_branch_storage(scope),
|
||||
forced_branch_id=branch_filter,
|
||||
)
|
||||
@@ -1575,6 +1576,33 @@ def _agent_auth(db, request: Request, x_node_code: str | None, x_node_secret: st
|
||||
return node, None
|
||||
|
||||
|
||||
@router.get("/erp-local-agent/update-manifest")
|
||||
def erp_local_agent_update_manifest(request: Request, x_node_code: str | None = Header(None), x_node_secret: str | None = Header(None)):
|
||||
import hashlib
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
node, error = _agent_auth(db, request, x_node_code, x_node_secret)
|
||||
if error:
|
||||
return error
|
||||
package = build_agent_update_zip()
|
||||
db.commit()
|
||||
return {"ok": True, "agent_name": "ERP Local Agent", "latest_version": ERP_LOCAL_AGENT_VERSION, "sha256": hashlib.sha256(package).hexdigest(), "size_bytes": len(package), "download_url": "/documents/erp-local-agent/update-package", "channel": "stable"}
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
@router.get("/erp-local-agent/update-package")
|
||||
def erp_local_agent_update_package(request: Request, x_node_code: str | None = Header(None), x_node_secret: str | None = Header(None)):
|
||||
db = CommonSessionLocal()
|
||||
try:
|
||||
node, error = _agent_auth(db, request, x_node_code, x_node_secret)
|
||||
if error:
|
||||
return error
|
||||
package = build_agent_update_zip()
|
||||
db.commit()
|
||||
filename = f"ERP_Local_Agent_{ERP_LOCAL_AGENT_VERSION}.zip"
|
||||
return Response(package, media_type="application/zip", headers={"Content-Disposition": f'attachment; filename="{filename}"'})
|
||||
finally:
|
||||
db.close()
|
||||
@router.post("/storage-agent/heartbeat")
|
||||
async def storage_agent_heartbeat(request: Request, x_node_code: str | None = Header(None), x_node_secret: str | None = Header(None)):
|
||||
db = CommonSessionLocal()
|
||||
@@ -1891,3 +1919,4 @@ def delete_document(request: Request, document_id: int, csrf_token: str = Form(.
|
||||
return RedirectResponse(url=f"/documents/engagements/{document.engagement_id}?deleted=1", status_code=303)
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user