Serialize enriched finding details for the modern web UI.
(finding_id, enriched_finding, default_last_update=None)
| 13351 | def _finalize_update(update_result: dict) -> None: |
| 13352 | """Kick off dependency install + provisioning + restart after a good pull.""" |
| 13353 | warnings = update_result.setdefault('warnings', []) |
| 13354 | outcome = _launch_post_update(update_result.get('requirements_changed', False), warnings) |
| 13355 | update_result['post_update_started'] = outcome != 'failed' |
| 13356 | update_result['restart_pending'] = True |
| 13357 | if outcome == 'failed': |
| 13358 | # Nothing else will restart the service, so do it here: the new code is |
| 13359 | # on disk and running it is better than leaving the old one loaded. |
| 13360 | _schedule_service_restart() |
| 13361 | |
| 13362 | |
| 13363 | def _update_response(update_result: dict): |
| 13364 | """Turn a git_updater result into the JSON shape the dashboard expects.""" |
| 13365 | payload = { |
| 13366 | 'success': bool(update_result.get('ok')), |
| 13367 | 'warnings': update_result.get('warnings', []), |
| 13368 | 'output': update_result.get('output', ''), |
| 13369 | 'update_output': update_result.get('output', ''), |
| 13370 | 'branch': update_result.get('branch', ''), |
| 13371 | 'from_commit': update_result.get('from_commit', ''), |
| 13372 | 'to_commit': update_result.get('to_commit', ''), |
| 13373 | 'forced': update_result.get('forced', False), |
| 13374 | 'local_changes_preserved': bool(update_result.get('stash_ref')), |
| 13375 | 'local_changes_restored': bool(update_result.get('stash_ref')) |
| 13376 | and not update_result.get('stash_kept'), |
| 13377 | 'requirements_changed': update_result.get('requirements_changed', False), |
| 13378 | 'post_update_started': update_result.get('post_update_started', False), |
| 13379 | 'restart_pending': update_result.get('restart_pending', False), |
| 13380 | } |
| 13381 | if payload['success']: |
| 13382 | payload['message'] = 'Update applied successfully.' |
| 13383 | return jsonify(payload) |
| 13384 | |
| 13385 | payload['error'] = update_result.get('error') or 'Unknown error during update' |
| 13386 | payload['code'] = update_result.get('code', '') |
| 13387 | payload['hint'] = update_result.get('hint', '') |
| 13388 | payload['steps'] = update_result.get('steps', []) |
| 13389 | # 'busy' is not a failure - another update is simply already running. |
| 13390 | return jsonify(payload), 409 if payload['code'] == 'busy' else 500 |
| 13391 | |
| 13392 | |
| 13393 | def _execute_pwn_git_update(repo_path: str) -> dict: |
| 13394 | """Run the git pull sequence for the Pwnagotchi clone at repo_path. |
| 13395 | |
| 13396 | Mirrors `_execute_git_update` but: |
| 13397 | - All git operations go through `sudo -n` (non-interactive) so a |
| 13398 | misconfigured NOPASSWD surfaces as an error instead of hanging. |
| 13399 | - Skips the Ragnar-specific pre-pull chown and post-pull chmod steps. |
| 13400 | - Never restarts any service (callers handle that decision). |
| 13401 | """ |
| 13402 | result = { |
| 13403 | 'success': False, |
| 13404 | 'output': '', |
| 13405 | 'error': '', |
| 13406 | 'warnings': [] |
no test coverage detected