From c35131462e3ce0ee9b7be229f8333a2650265cb1 Mon Sep 17 00:00:00 2001 From: Smittix Date: Mon, 2 Mar 2026 09:59:41 +0000 Subject: [PATCH] fix: prevent root-owned database files when running with sudo When start.sh runs via sudo, chown instance/ and data/ back to the invoking user so the SQLite DB stays accessible without sudo. Also adds a clear error message in get_connection() when the DB can't be opened due to permissions. Co-Authored-By: Claude Opus 4.6 --- start.sh | 9 +++++++++ utils/database.py | 50 +++++++++++++++++++++++++++-------------------- 2 files changed, 38 insertions(+), 21 deletions(-) diff --git a/start.sh b/start.sh index 85e9922..f13c8f0 100755 --- a/start.sh +++ b/start.sh @@ -78,6 +78,15 @@ done export INTERCEPT_HOST="$HOST" export INTERCEPT_PORT="$PORT" +# ── Fix ownership of user data dirs when run via sudo ──────────────────────── +if [[ "$(id -u)" -eq 0 && -n "${SUDO_USER:-}" ]]; then + for dir in instance data; do + if [[ -d "$SCRIPT_DIR/$dir" ]]; then + chown -R "$SUDO_USER" "$SCRIPT_DIR/$dir" + fi + done +fi + # ── Dependency check (delegate to intercept.py) ───────────────────────────── if [[ "$CHECK_DEPS" -eq 1 ]]; then exec "$PYTHON" intercept.py --check-deps diff --git a/utils/database.py b/utils/database.py index a87c54d..ad71fb0 100644 --- a/utils/database.py +++ b/utils/database.py @@ -35,10 +35,18 @@ def get_connection() -> sqlite3.Connection: """Get a thread-local database connection.""" if not hasattr(_local, 'connection') or _local.connection is None: db_path = get_db_path() - _local.connection = sqlite3.connect(str(db_path), check_same_thread=False) - _local.connection.row_factory = sqlite3.Row - # Enable foreign keys - _local.connection.execute('PRAGMA foreign_keys = ON') + try: + _local.connection = sqlite3.connect(str(db_path), check_same_thread=False) + _local.connection.row_factory = sqlite3.Row + # Enable foreign keys + _local.connection.execute('PRAGMA foreign_keys = ON') + except sqlite3.OperationalError as e: + logger.error( + f"Cannot open database at {db_path}: {e}. " + f"If the file is owned by root, fix with: " + f"sudo chown -R $(whoami) {DB_DIR}" + ) + raise return _local.connection @@ -550,12 +558,12 @@ def init_db() -> None: INSERT OR IGNORE INTO tracked_satellites (norad_id, name, tle_line1, tle_line2, enabled, builtin) VALUES ('25544', 'ISS (ZARYA)', NULL, NULL, 1, 1) ''') - conn.execute(''' - INSERT OR IGNORE INTO tracked_satellites (norad_id, name, tle_line1, tle_line2, enabled, builtin) - VALUES ('40069', 'METEOR-M2', NULL, NULL, 1, 1) - ''') - - logger.info("Database initialized successfully") + conn.execute(''' + INSERT OR IGNORE INTO tracked_satellites (norad_id, name, tle_line1, tle_line2, enabled, builtin) + VALUES ('40069', 'METEOR-M2', NULL, NULL, 1, 1) + ''') + + logger.info("Database initialized successfully") def close_db() -> None: @@ -2285,10 +2293,10 @@ def update_tracked_satellite(norad_id: str, enabled: bool) -> bool: return cursor.rowcount > 0 -def remove_tracked_satellite(norad_id: str) -> tuple[bool, str]: - """Delete a tracked satellite by NORAD ID. Refuses to delete builtins.""" - with get_db() as conn: - row = conn.execute( +def remove_tracked_satellite(norad_id: str) -> tuple[bool, str]: + """Delete a tracked satellite by NORAD ID. Refuses to delete builtins.""" + with get_db() as conn: + row = conn.execute( 'SELECT builtin FROM tracked_satellites WHERE norad_id = ?', (str(norad_id),), ).fetchone() @@ -2296,10 +2304,10 @@ def remove_tracked_satellite(norad_id: str) -> tuple[bool, str]: return False, 'Satellite not found' if row[0]: return False, 'Cannot remove builtin satellite' - conn.execute( - 'DELETE FROM tracked_satellites WHERE norad_id = ?', - (str(norad_id),), - ) - return True, 'Removed' - - + conn.execute( + 'DELETE FROM tracked_satellites WHERE norad_id = ?', + (str(norad_id),), + ) + return True, 'Removed' + +