fix: copy button HTTP fallback, reset-admin-password in Docker, scripts volume

- CellNetwork.jsx CopyButton: use execCommand fallback when clipboard API
  is unavailable (HTTP non-localhost context)
- Makefile reset-admin-password: run inside cell-api container via docker exec
  so bcrypt and all deps are available without host installation
- docker-compose.yml: mount ./scripts:/app/scripts:ro in cell-api so the
  reset script is accessible inside the container
- scripts/reset_admin_password.py: auto-detect API module path and data dir
  so the script works in both host (api/ sibling) and container (/app) layouts

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-01 11:34:38 -04:00
parent e8b3288a41
commit 56d677e925
4 changed files with 31 additions and 7 deletions
+18 -5
View File
@@ -11,11 +11,24 @@ import os
import secrets
import string
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'api'))
_here = os.path.dirname(os.path.abspath(__file__))
# Find auth_manager: host layout has api/ sibling, container has it one level up at /app
for _api_path in [os.path.join(_here, '..', 'api'), os.path.join(_here, '..'), '/app']:
if os.path.isfile(os.path.join(_api_path, 'auth_manager.py')):
sys.path.insert(0, os.path.normpath(_api_path))
break
ROOT = os.path.join(os.path.dirname(__file__), '..')
INIT_PW_FILE = os.path.normpath(os.path.join(ROOT, 'data', 'api', '.admin_initial_password'))
TEST_PW_FILE = os.path.normpath(os.path.join(ROOT, 'data', 'api', '.test_admin_pass'))
ROOT = os.path.normpath(os.path.join(_here, '..'))
# data dir: host uses ROOT/data/api, container mounts data/api at ROOT/data
for _data in [os.path.join(ROOT, 'data', 'api'), os.path.join(ROOT, 'data'), '/app/data']:
if os.path.isdir(_data):
_DATA_DIR = _data
break
else:
_DATA_DIR = os.path.join(ROOT, 'data', 'api')
INIT_PW_FILE = os.path.join(_DATA_DIR, '.admin_initial_password')
TEST_PW_FILE = os.path.join(_DATA_DIR, '.test_admin_pass')
def _generate_password(length: int = 20) -> str:
@@ -32,7 +45,7 @@ def _generate_password(length: int = 20) -> str:
def _set_password(new_password: str) -> None:
from auth_manager import AuthManager
data_dir = os.path.normpath(os.path.join(ROOT, 'data', 'api'))
data_dir = _DATA_DIR
os.makedirs(data_dir, exist_ok=True)
mgr = AuthManager(data_dir=data_dir, config_dir='/tmp')
if mgr.set_password_admin('admin', new_password):