Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
e8fc158
CRITICAL: Fix all code review issues - 15 bugs resolved
claude Nov 10, 2025
f706768
Fix ISO build: create /usr/local/bin directory before copying installers
claude Nov 10, 2025
b9d270a
Fix ISO build: check for complete rootfs before using
claude Nov 10, 2025
732c0ce
Fix GRUB package conflict: use -bin packages for hybrid ISO
claude Nov 10, 2025
0b554e5
Fix pre-install: remove deprecated gksu package
claude Nov 10, 2025
5de0b19
Fix ISO build: let grub-mkrescue auto-create hybrid boot
claude Nov 10, 2025
139f8c5
Fix live boot: add live-boot packages and fix installer desktop entry
claude Nov 10, 2025
191c046
Add default user setup: icenet/icenet and root/root
claude Nov 11, 2025
adb9b10
Set hostname to icenet-os in live system
claude Nov 11, 2025
e86bb61
Add desktop environment to ISO: auto-install Openbox+tint2+jgmenu wit…
claude Nov 11, 2025
f775e10
Fix desktop install: handle broken packages and use --no-install-reco…
claude Nov 11, 2025
b107d69
Add rebuild-iso convenience script for quick rebuilds
claude Nov 11, 2025
d3fbd64
Fix X server: add display drivers and disable autologin for debugging
claude Nov 11, 2025
29e6ae4
Fix rebuild-iso script to resolve symlinks correctly
claude Nov 11, 2025
b70dbb5
Fix jgmenu config and add Reticulum stack (nomadnet, sideband) to ISO
claude Nov 11, 2025
239eae9
Add COMPLETE Mesh & Radio Suite: Edge, LoRa, SDR, and mesh protocols
claude Nov 11, 2025
21ef3e5
Fix clipit→diodon and thermal service error handling for VMs
claude Nov 11, 2025
4acb43e
Bug fixes: clipit→diodon, thermal restart policy, missing packages, i…
claude Nov 11, 2025
8bda758
Fix rebuild-iso script to resolve symlinks correctly
claude Nov 11, 2025
0d28e06
Fix openbox: remove non-existent openbox-themes package, use Clearloo…
claude Nov 11, 2025
f91e590
Add polkit-gnome auth agent and fix Openbox titleLayout for window bu…
claude Nov 11, 2025
8031fe3
Refactor to minimal LXDE base ISO with Software Center
claude Nov 11, 2025
cedafab
Add rebuild-iso script to resolve symlinks correctly
claude Nov 11, 2025
755f1e7
Fix minimal base installer: replace leafpad with mousepad, add gnupg
claude Nov 11, 2025
d9d3fc9
Fix initramfs generation timing issue with live-boot
claude Nov 11, 2025
990deca
Add cache validation for fast build mode
claude Nov 11, 2025
40ccd2a
Move gnupg and wget to base system to prevent initramfs trigger
claude Nov 11, 2025
a2148b3
Fix initramfs-tools update-initramfs not found error
claude Nov 11, 2025
7cde27e
Pre-configure US keyboard to prevent interactive prompts
claude Nov 11, 2025
3564fd0
Suppress locale warnings and service start messages during build
claude Nov 11, 2025
18dacbc
Add user account, autologin, and fix boot to desktop
claude Nov 11, 2025
24d8c20
Add live-config packages for proper live system configuration
claude Nov 11, 2025
02c426b
Fix desktop session crash - add proper session configuration
claude Nov 12, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
548 changes: 548 additions & 0 deletions docs/CODE_REVIEW_FIXES.md

Large diffs are not rendered by default.

57 changes: 57 additions & 0 deletions install-rebuild-command.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
#!/bin/bash
# Install rebuild-iso command to PATH
# Run once: sudo ./install-rebuild-command.sh

set -e

BLUE='\033[0;34m'
GREEN='\033[0;32m'
RED='\033[0;31m'
NC='\033[0m'

if [ "$EUID" -ne 0 ]; then
echo -e "${RED}Error:${NC} This script must be run as root"
echo "Usage: sudo ./install-rebuild-command.sh"
exit 1
fi

REPO_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
SCRIPT_PATH="$REPO_ROOT/rebuild-iso.sh"
SYMLINK_PATH="/usr/local/bin/rebuild-iso"

echo -e "${BLUE}Installing rebuild-iso command...${NC}"
echo ""

# Check if script exists
if [ ! -f "$SCRIPT_PATH" ]; then
echo -e "${RED}Error:${NC} rebuild-iso.sh not found at $SCRIPT_PATH"
exit 1
fi

# Make sure script is executable
chmod +x "$SCRIPT_PATH"

# Create symlink
if [ -L "$SYMLINK_PATH" ] || [ -f "$SYMLINK_PATH" ]; then
echo "Removing existing command..."
rm -f "$SYMLINK_PATH"
fi

ln -s "$SCRIPT_PATH" "$SYMLINK_PATH"

echo -e "${GREEN}✓ Command installed successfully!${NC}"
echo ""
echo "You can now rebuild the ISO from anywhere with:"
echo -e " ${GREEN}sudo rebuild-iso${NC} (normal build, 20-30 min)"
echo -e " ${GREEN}sudo rebuild-iso --fast${NC} (fast build, 5-10 min)"
echo ""
echo "What this command does:"
echo " 1. Pulls latest changes from git"
echo " 2. Cleans old build artifacts (unless --fast)"
echo " 3. Builds the ISO"
echo ""
echo "Fast mode uses:"
echo " • Cached base system (no debootstrap)"
echo " • gzip compression (faster than xz)"
echo " • Perfect for testing changes quickly"
echo ""
2 changes: 1 addition & 1 deletion integrations/icenet-desktop/config/jgmenurc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
position_mode = pointer
stay_alive = 1
hide_on_startup = 0
csv_cmd = pmenu
csv_cmd = apps
tint2_look = 0
at_pointer = 0
terminal_exec = lxterminal
Expand Down
11 changes: 9 additions & 2 deletions integrations/icenet-desktop/config/openbox-autostart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@
# IceNet-OS Openbox Autostart
# Applications and daemons to start with the desktop

# PolicyKit authentication agent (REQUIRED for pkexec to work)
if [ -f /usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 ]; then
/usr/lib/policykit-1-gnome/polkit-gnome-authentication-agent-1 &
elif command -v lxpolkit >/dev/null 2>&1; then
lxpolkit &
fi

# Set background
nitrogen --restore &

Expand All @@ -22,8 +29,8 @@ if command -v volumeicon >/dev/null 2>&1; then
fi

# Clipboard manager
if command -v clipit >/dev/null 2>&1; then
clipit &
if command -v diodon >/dev/null 2>&1; then
diodon &
fi

# Notification daemon
Expand Down
4 changes: 2 additions & 2 deletions integrations/icenet-desktop/config/openbox-rc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@
</placement>

<theme>
<name>IceNet-Dark</name>
<titleLayout>NLIMC</titleLayout>
<name>Clearlooks</name>
<titleLayout>NDSLIMC</titleLayout>
<keepBorder>yes</keepBorder>
<animateIconify>yes</animateIconify>
<font place="ActiveWindow">
Expand Down
4 changes: 2 additions & 2 deletions integrations/icenet-desktop/install-desktop.sh
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ install_packages() {
galculator \
lxrandr \
dunst \
clipit \
diodon \
unclutter \
fonts-dejavu \
papirus-icon-theme \
Expand All @@ -95,7 +95,7 @@ install_packages() {
galculator \
lxrandr \
dunst \
clipit \
diodon \
unclutter \
ttf-dejavu \
papirus-icon-theme \
Expand Down
152 changes: 123 additions & 29 deletions integrations/service-manager/icenet-service-manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -164,28 +164,61 @@ def create_service_card(self, service):

return frame

def run_command(self, command):
"""Run a system command"""
def run_command(self, command_args):
"""
Run a system command safely without shell=True.

Args:
command_args: List of command arguments or single command string

Returns:
Tuple of (success: bool, stdout: str, stderr: str)
"""
try:
# Convert to list if needed
if isinstance(command_args, str):
command_args = command_args.split()

result = subprocess.run(
command,
shell=True,
command_args,
shell=False, # SECURITY: Never use shell=True
capture_output=True,
text=True
text=True,
timeout=10 # Prevent hanging
)
return result.returncode == 0, result.stdout, result.stderr
except subprocess.TimeoutExpired:
return False, "", "Command timed out"
except Exception as e:
return False, "", str(e)

def is_service_enabled(self, service_name):
"""Check if service is enabled"""
success, stdout, _ = self.run_command(f"systemctl is-enabled {service_name} 2>/dev/null")
return "enabled" in stdout
"""
Check if service is enabled at boot.

Args:
service_name: Name of the systemd service

Returns:
bool: True if enabled, False otherwise
"""
success, stdout, _ = self.run_command(['systemctl', 'is-enabled', service_name])
# Check both success AND stdout content
return success and "enabled" in stdout.lower()

def is_service_active(self, service_name):
"""Check if service is currently running"""
success, stdout, _ = self.run_command(f"systemctl is-active {service_name} 2>/dev/null")
return "active" in stdout
"""
Check if service is currently running.

Args:
service_name: Name of the systemd service

Returns:
bool: True if active, False otherwise
"""
success, stdout, _ = self.run_command(['systemctl', 'is-active', service_name])
# Check both success AND stdout content
return success and "active" in stdout.lower()

def refresh_service_states(self):
"""Refresh the state of all services"""
Expand Down Expand Up @@ -226,72 +259,133 @@ def on_switch_activated(self, switch, gparam, service):
def enable_service(self, service):
"""Enable service at boot"""
service_name = service['service']
success, _, error = self.run_command(f"pkexec systemctl enable {service_name}")
success, _, error = self.run_command(['pkexec', 'systemctl', 'enable', service_name])

if success:
self.show_notification(f"{service['name']} enabled", "Service will start at boot")
self.show_notification(
f"{service['name']} enabled",
"Service will start automatically at next boot"
)
self.refresh_service_states()
else:
self.show_error(f"Failed to enable {service['name']}", error)
# Provide more specific error messages
if "Permission denied" in error or "Authentication" in error:
self.show_error(
"Permission Denied",
f"You don't have permission to enable {service['name']}.\n\n"
"Authentication via PolicyKit is required."
)
elif "not found" in error.lower():
self.show_error(
"Service Not Found",
f"The {service['name']} service is not installed.\n"
f"Service: {service_name}"
)
else:
self.show_error(f"Failed to enable {service['name']}", error)
service['switch'].set_active(False)

def disable_service(self, service):
"""Disable service at boot"""
service_name = service['service']
success, _, error = self.run_command(f"pkexec systemctl disable {service_name}")
success, _, error = self.run_command(['pkexec', 'systemctl', 'disable', service_name])

if success:
self.show_notification(f"{service['name']} disabled", "Service will not start at boot")
self.show_notification(
f"{service['name']} disabled",
"Service will not start automatically at boot"
)
self.refresh_service_states()
else:
self.show_error(f"Failed to disable {service['name']}", error)
if "Permission denied" in error or "Authentication" in error:
self.show_error(
"Permission Denied",
f"You don't have permission to disable {service['name']}."
)
else:
self.show_error(f"Failed to disable {service['name']}", error)
service['switch'].set_active(True)

def on_start_service(self, button, service):
"""Start service now"""
service_name = service['service']
success, _, error = self.run_command(f"pkexec systemctl start {service_name}")
success, _, error = self.run_command(['pkexec', 'systemctl', 'start', service_name])

if success:
self.show_notification(f"{service['name']} started", "Service is now running")
self.show_notification(
f"{service['name']} started",
"Service is now running"
)
GLib.timeout_add_seconds(1, self.refresh_service_states)
else:
self.show_error(f"Failed to start {service['name']}", error)
if "already" in error.lower():
self.show_notification(
f"{service['name']} already running",
"Service was already started"
)
elif service_name == "icenet-thermal.service":
# Check journal for thermal zone error
_, journal_out, _ = self.run_command(['journalctl', '-u', service_name, '-n', '20', '--no-pager'])
if "No thermal zones found" in journal_out or "thermal zone not found" in journal_out.lower():
self.show_error(
"Thermal Service Not Supported",
"This system has no thermal sensors (common in VMs).\n\n"
"The thermal management service is designed for physical hardware "
"in cold environments.\n\n"
"This service is not needed for your system."
)
else:
self.show_error(f"Failed to start {service['name']}", error)
else:
self.show_error(f"Failed to start {service['name']}", error)

def on_stop_service(self, button, service):
"""Stop service now"""
service_name = service['service']
success, _, error = self.run_command(f"pkexec systemctl stop {service_name}")
success, _, error = self.run_command(['pkexec', 'systemctl', 'stop', service_name])

if success:
self.show_notification(f"{service['name']} stopped", "Service has been stopped")
self.show_notification(
f"{service['name']} stopped",
"Service has been stopped"
)
GLib.timeout_add_seconds(1, self.refresh_service_states)
else:
self.show_error(f"Failed to stop {service['name']}", error)
if "not loaded" in error.lower() or "not running" in error.lower():
self.show_notification(
f"{service['name']} not running",
"Service was already stopped"
)
else:
self.show_error(f"Failed to stop {service['name']}", error)

def show_notification(self, title, message):
"""Show notification dialog"""
"""Show notification dialog with proper cleanup"""
dialog = Gtk.MessageDialog(
transient_for=self,
message_type=Gtk.MessageType.INFO,
buttons=Gtk.ButtonsType.OK,
text=title
)
dialog.format_secondary_text(message)
dialog.run()
dialog.destroy()
try:
dialog.run()
finally:
dialog.destroy()

def show_error(self, title, message):
"""Show error dialog"""
"""Show error dialog with proper cleanup"""
dialog = Gtk.MessageDialog(
transient_for=self,
message_type=Gtk.MessageType.ERROR,
buttons=Gtk.ButtonsType.OK,
text=title
)
dialog.format_secondary_text(message)
dialog.run()
dialog.destroy()
try:
dialog.run()
finally:
dialog.destroy()

def main():
win = ServiceControlPanel()
Expand Down
Loading