feat: firewalls (#4074)

* Firewall Init

* Enable service
This commit is contained in:
HADEON 2026-01-05 10:04:43 +01:00 committed by GitHub
parent e590277e69
commit 450664cdc4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 109 additions and 0 deletions

View File

@ -0,0 +1,33 @@
from typing import TYPE_CHECKING
from archinstall.lib.models.application import Firewall, FirewallConfiguration
from archinstall.lib.output import debug
if TYPE_CHECKING:
from archinstall.lib.installer import Installer
class FirewallApp:
@property
def ufw_packages(self) -> list[str]:
return [
'ufw',
]
@property
def ufw_services(self) -> list[str]:
return [
'ufw.service',
]
def install(
self,
install_session: 'Installer',
firewall_config: FirewallConfiguration,
) -> None:
debug(f'Installing firewall: {firewall_config.firewall.value}')
match firewall_config.firewall:
case Firewall.UFW:
install_session.add_additional_packages(self.ufw_packages)
install_session.enable_service(self.ufw_services)

View File

@ -2,6 +2,7 @@ from typing import TYPE_CHECKING
from archinstall.applications.audio import AudioApp from archinstall.applications.audio import AudioApp
from archinstall.applications.bluetooth import BluetoothApp from archinstall.applications.bluetooth import BluetoothApp
from archinstall.applications.firewall import FirewallApp
from archinstall.applications.power_management import PowerManagementApp from archinstall.applications.power_management import PowerManagementApp
from archinstall.applications.print_service import PrintServiceApp from archinstall.applications.print_service import PrintServiceApp
from archinstall.lib.models import Audio from archinstall.lib.models import Audio
@ -36,5 +37,11 @@ class ApplicationHandler:
if app_config.print_service_config and app_config.print_service_config.enabled: if app_config.print_service_config and app_config.print_service_config.enabled:
PrintServiceApp().install(install_session) PrintServiceApp().install(install_session)
if app_config.firewall_config:
FirewallApp().install(
install_session,
app_config.firewall_config,
)
application_handler = ApplicationHandler() application_handler = ApplicationHandler()

View File

@ -7,6 +7,8 @@ from archinstall.lib.models.application import (
Audio, Audio,
AudioConfiguration, AudioConfiguration,
BluetoothConfiguration, BluetoothConfiguration,
Firewall,
FirewallConfiguration,
PowerManagement, PowerManagement,
PowerManagementConfiguration, PowerManagementConfiguration,
PrintServiceConfiguration, PrintServiceConfiguration,
@ -70,6 +72,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
enabled=SysInfo.has_battery(), enabled=SysInfo.has_battery(),
key='power_management_config', key='power_management_config',
), ),
MenuItem(
text=tr('Firewall'),
action=select_firewall,
preview_action=self._prev_firewall,
key='firewall_config',
),
] ]
def _prev_power_management(self, item: MenuItem) -> str | None: def _prev_power_management(self, item: MenuItem) -> str | None:
@ -102,6 +110,12 @@ class ApplicationMenu(AbstractSubMenu[ApplicationConfiguration]):
return output return output
return None return None
def _prev_firewall(self, item: MenuItem) -> str | None:
if item.value is not None:
config: FirewallConfiguration = item.value
return f'{tr("Firewall")}: {config.firewall.value}'
return None
def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None: def select_power_management(preset: PowerManagementConfiguration | None = None) -> PowerManagementConfiguration | None:
group = MenuItemGroup.from_enum(PowerManagement) group = MenuItemGroup.from_enum(PowerManagement)
@ -203,3 +217,26 @@ def select_audio(preset: AudioConfiguration | None = None) -> AudioConfiguration
return AudioConfiguration(audio=result.get_value()) return AudioConfiguration(audio=result.get_value())
case ResultType.Reset: case ResultType.Reset:
raise ValueError('Unhandled result type') raise ValueError('Unhandled result type')
def select_firewall(preset: FirewallConfiguration | None = None) -> FirewallConfiguration | None:
group = MenuItemGroup.from_enum(Firewall)
if preset:
group.set_focus_by_value(preset.firewall)
result = SelectMenu[Firewall](
group,
allow_skip=True,
alignment=Alignment.CENTER,
allow_reset=True,
frame=FrameProperties.min(tr('Firewall')),
).run()
match result.type_:
case ResultType.Skip:
return preset
case ResultType.Selection:
return FirewallConfiguration(firewall=result.get_value())
case ResultType.Reset:
return None

View File

@ -30,6 +30,14 @@ class PrintServiceConfigSerialization(TypedDict):
enabled: bool enabled: bool
class Firewall(StrEnum):
UFW = 'ufw'
class FirewallConfigSerialization(TypedDict):
firewall: str
class ZramAlgorithm(StrEnum): class ZramAlgorithm(StrEnum):
ZSTD = 'zstd' ZSTD = 'zstd'
LZO_RLE = 'lzo-rle' LZO_RLE = 'lzo-rle'
@ -43,6 +51,7 @@ class ApplicationSerialization(TypedDict):
audio_config: NotRequired[AudioConfigSerialization] audio_config: NotRequired[AudioConfigSerialization]
power_management_config: NotRequired[PowerManagementConfigSerialization] power_management_config: NotRequired[PowerManagementConfigSerialization]
print_service_config: NotRequired[PrintServiceConfigSerialization] print_service_config: NotRequired[PrintServiceConfigSerialization]
firewall_config: NotRequired[FirewallConfigSerialization]
@dataclass @dataclass
@ -101,6 +110,22 @@ class PrintServiceConfiguration:
return PrintServiceConfiguration(arg['enabled']) return PrintServiceConfiguration(arg['enabled'])
@dataclass
class FirewallConfiguration:
firewall: Firewall
def json(self) -> FirewallConfigSerialization:
return {
'firewall': self.firewall.value,
}
@staticmethod
def parse_arg(arg: dict[str, Any]) -> 'FirewallConfiguration':
return FirewallConfiguration(
Firewall(arg['firewall']),
)
@dataclass(frozen=True) @dataclass(frozen=True)
class ZramConfiguration: class ZramConfiguration:
enabled: bool enabled: bool
@ -122,6 +147,7 @@ class ApplicationConfiguration:
audio_config: AudioConfiguration | None = None audio_config: AudioConfiguration | None = None
power_management_config: PowerManagementConfiguration | None = None power_management_config: PowerManagementConfiguration | None = None
print_service_config: PrintServiceConfiguration | None = None print_service_config: PrintServiceConfiguration | None = None
firewall_config: FirewallConfiguration | None = None
@staticmethod @staticmethod
def parse_arg( def parse_arg(
@ -146,6 +172,9 @@ class ApplicationConfiguration:
if args and (print_service_config := args.get('print_service_config')) is not None: if args and (print_service_config := args.get('print_service_config')) is not None:
app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config) app_config.print_service_config = PrintServiceConfiguration.parse_arg(print_service_config)
if args and (firewall_config := args.get('firewall_config')) is not None:
app_config.firewall_config = FirewallConfiguration.parse_arg(firewall_config)
return app_config return app_config
def json(self) -> ApplicationSerialization: def json(self) -> ApplicationSerialization:
@ -163,4 +192,7 @@ class ApplicationConfiguration:
if self.print_service_config: if self.print_service_config:
config['print_service_config'] = self.print_service_config.json() config['print_service_config'] = self.print_service_config.json()
if self.firewall_config:
config['firewall_config'] = self.firewall_config.json()
return config return config