Skip to content

Conversation

@Anshgrover23
Copy link

@Anshgrover23 Anshgrover23 commented Jan 10, 2026

Untitled.mov

Summary by CodeRabbit

  • New Features

    • Added comprehensive Cortex branding system including GRUB bootloader theme, Plymouth splash screen, desktop wallpapers, and GDM login screen styling.
    • Introduced automated first-boot provisioning with system hardening, SSH configuration, and security tooling setup.
    • Added multiple installation partitioning schemes: simple UEFI, LVM, RAID1 mirroring, and full-disk encryption.
    • Created meta-packages for targeted deployments (core system, full desktop, security operations).
    • Added system information display on login via MOTD.
  • Chores

    • Reorganized build system and Makefile for modular command dispatch.
    • Updated GitHub Actions workflows for architecture-specific builds.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Jan 10, 2026

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

📝 Walkthrough

Walkthrough

Comprehensive build system and branding infrastructure overhaul. Replaces inline Makefile logic with external script delegation, introduces modular command-driven build architecture, adds complete GRUB/preseed bootloader configurations, implements first-boot provisioning system, and introduces a full branding package with themes, assets, and system configurations.

Changes

Cohort / File(s) Summary
Build System Refactor
Makefile, scripts/build.sh, scripts/install-deps.sh
Makefile migrated from in-file logic to external script delegation via BUILD_SCRIPT variable. scripts/build.sh completely rewritten with modular command dispatch (cmd_build, cmd_validate, cmd_test, cmd_clean, cmd_branding_package, etc.). New install-deps.sh automates dependency installation with architecture detection.
Bootloader & Partitioning
iso/live-build/config/bootloaders/grub-pc/*, iso/preseed/partitioning/*
New GRUB PC configuration suite: config.cfg (font/graphics), grub.cfg (menu structure), install_gui.cfg/install_text.cfg (installer modes), memtest.cfg, theme.cfg. Five new preseed configurations for UEFI/BIOS partitioning: simple-uefi, simple-bios, lvm-uefi, fde-uefi, raid1-uefi.
Provisioning System
iso/provisioning/first-boot.sh, iso/provisioning/cortex-first-boot.service, iso/live-build/config/hooks/live/0100-cortex-config.hook.chroot
New first-boot provisioning script (406 lines) with idempotent, network-aware setup for machine-id, SSH hardening, UFW/fail2ban, repository integration, and cleanup. Systemd service (cortex-first-boot.service) manages execution with proper ordering and state tracking. Hook refactored with updated unit names and security hardening.
Branding Package (cortex-branding)
packages/cortex-branding/ (entire subtree: 40+ files)
Complete new Debian package: build system (Makefile generating Plymouth/GRUB/wallpaper/logo assets), themes (Plymouth script, GRUB theme.txt), configurations (dconf, GSettings, GDM, neofetch), MOTD scripts (banner/sysinfo/updates/footer), templates (os-release, issue files), Debian metadata (control, rules, postinst, prerm, postrm), and CSS/XML styling.
Live Build Configuration
iso/live-build/config/package-lists/live.list.chroot, iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot, iso/live-build/config/hooks/live/99-live-session.hook.chroot, iso/live-build/config/includes.chroot/etc/pam.d/*, iso/live-build/config/includes.chroot/etc/skel/.bashrc
New live.list.chroot package manifest. Branding verification hook (50-cortex-branding.hook.chroot). Live session setup hook (99-live-session.hook.chroot) configuring GDM autologin. PAM configurations for login/sshd with MOTD support. Comprehensive .bashrc with Cortex theming, aliases, Git integration.
Package Metadata
packages/cortex-core/DEBIAN/control, packages/cortex-full/DEBIAN/control, packages/cortex-secops/DEBIAN/control
Three new meta-package control files defining dependency graphs and descriptions for cortex-core (archive-keyring, upgrade, gpu, verify), cortex-full (desktop + dev tools), and cortex-secops (security tools suite).
Deleted Legacy Build Scripts
iso/live-build/auto/build, iso/live-build/auto/clean, iso/live-build/auto/config
Removed three auto scripts (build, clean, config) that previously orchestrated live-build directly; functionality now delegated to scripts/build.sh.
Deleted Package List
iso/live-build/config/package-lists/cortex-core.list.chroot
Removed entire cortex-core package list (113 lines); packages now managed through live.list.chroot and external Cortex repository.
Deleted Provisioning
iso/live-build/config/includes.chroot/usr/lib/cortex/firstboot.sh
Removed old first-boot script (369 lines); replaced with new iso/provisioning/first-boot.sh with improved structure and state management.
CI/CD Workflow
.github/workflows/build-iso.yml, .github/workflows/reproducible-builds.yml
build-iso.yml expanded with multi-job matrix (Validate, Build ISO per-arch, Test ISO, Release), containerized builds, dynamic compression (xz/lz4), per-arch SBOM uploads. reproducible-builds.yml deleted entirely.
Documentation
docs/branding/BRAND-GUIDELINES.md, docs/branding/GDM-THEMING.md, docs/branding/GRUB-ASSETS.md, docs/branding/PLYMOUTH-ASSETS.md, docs/branding/WALLPAPERS-ASSETS.md, README.md
Five new branding documentation files (brand guidelines, theming, asset specifications). README.md updated with new build flow (make iso, make check-deps, install-deps.sh), provisioning directory, and cortex-branding references.
Configuration & Git
.gitignore, iso/live-build/config/packages.chroot/.gitkeep, packages/cortex-branding/.gitignore
New root .gitignore for build artifacts and OS metadata. gitkeep documentation for local packages. cortex-branding-specific .gitignore for dpkg artifacts.
Live Build Package List
iso/live-build/config/package-lists/cortex.list.chroot
Updated with renamed sections (SYSTEM BASE, CORTEX PACKAGES), removed cortex-core/full placeholders, added neofetch, commentary cleanup.
Repository Management
repository/scripts/repo-manage.sh
Changed Packages file generation from silent fallback to explicit directory check with empty Packages file creation if absent.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant Makefile
    participant build.sh
    participant lb as live-build
    participant pkg as dpkg/apt
    participant iso[ISO Output]

    User->>Makefile: make iso ARCH=amd64
    Makefile->>build.sh: cmd_build
    build.sh->>build.sh: prepare_build_dir()
    build.sh->>build.sh: copy_grub_theme()
    build.sh->>build.sh: copy_preseed_files()
    build.sh->>lb: configure_live_build()
    lb->>lb: lb config (UEFI/BIOS setup)
    build.sh->>pkg: dpkg -i cortex-branding*.deb<br/>(pre-loaded in packages.chroot)
    build.sh->>lb: build_iso()
    lb->>iso: create ISO with live system
    build.sh->>iso: move_output()
    build.sh->>build.sh: generate_sbom()
    build.sh-->>User: ISO at output/
Loading
sequenceDiagram
    participant Boot as System Boot
    participant systemd
    participant fbs as first-boot.sh
    participant net as Network
    participant repo as APT Repo
    participant sys as System Config
    participant state as State File

    Boot->>systemd: Load cortex-first-boot.service
    systemd->>state: Check .first-boot-complete
    state-->>systemd: Not found → proceed
    systemd->>fbs: ExecStart /opt/cortex/provisioning/first-boot.sh
    fbs->>fbs: Log initialization
    fbs->>net: Probe connectivity (non-blocking)
    net-->>fbs: Online/Offline result
    fbs->>sys: Ensure machine-id
    fbs->>sys: Configure sudo for cortex user
    fbs->>sys: Generate SSH host keys
    fbs->>sys: Configure UFW/fail2ban (if present)
    alt Network Available
        fbs->>repo: Add Cortex APT repository
        fbs->>repo: Update package lists
    end
    fbs->>state: Write completion marker
    fbs->>systemd: Disable first-boot service
    fbs-->>Boot: Provisioning complete
Loading
sequenceDiagram
    participant dpkg as dpkg (postinst)
    participant cb as cortex-branding
    participant os[OS Files]
    participant plym as Plymouth
    participant grub as GRUB
    participant dconf as dconf/GSettings
    participant user as User/Desktop

    dpkg->>cb: postinst configure
    cb->>os: Copy os-release, lsb-release, issue
    cb->>plym: update-alternatives + set-default-theme
    cb->>plym: Regenerate initramfs
    cb->>grub: Update /etc/default/grub with GRUB_THEME
    cb->>grub: update-grub
    cb->>dconf: Update dconf settings (GDM/local)
    cb->>dconf: glib-compile-schemas
    cb->>user: Enable MOTD scripts
    dconf-->>user: Display branded login screen
    plym-->>user: Show Cortex boot splash
    user->>user: Display Cortex wallpaper & terminal theme
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~150 minutes

Poem

🐰 A rabbit's tale of build perfection:

The Makefile did delegate with grace,
Themes and provisioning found their place,
With bootloaders configured just right,
Cortex now boots with Cortex delight,
From grub splash to first-boot's final sight! 🌠

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 59.49% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the main objective of the PR: bootstrapping a Cortex Linux distro with a hybrid ISO that supports both live boot and full installer modes.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@gemini-code-assist
Copy link

Summary of Changes

Hello @Anshgrover23, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a foundational build system for Cortex Linux, enabling the creation of diverse ISO images tailored for various use cases, from minimal servers to security-hardened desktops. It standardizes the distribution's visual identity through comprehensive branding and streamlines the post-installation experience with automated provisioning, significantly enhancing the development and deployment workflow.

Highlights

  • Refactored ISO Build System: The Makefile has been completely overhauled to support building Cortex Linux ISOs for multiple profiles (core, full, secops) and architectures (amd64, arm64), replacing the previous simplified build targets with a more modular and robust system.
  • Comprehensive Branding Integration: Extensive branding assets and configurations have been added across the distribution, including custom themes for Plymouth (boot splash), GRUB (bootloader), GDM (login screen), desktop wallpapers, Message of the Day (MOTD), and Neofetch, ensuring a consistent visual identity.
  • Automated Installation Profiles: New preseed files introduce automated installation for distinct profiles: 'core' for minimal server setups, 'full' for desktop and development environments, and 'secops' for security-hardened systems with Full Disk Encryption (FDE) and advanced security tools.
  • First-Boot Provisioning Script: A new first-boot.sh script and systemd service automate post-installation setup, handling tasks like machine-id generation, sudo configuration, SSH hardening, firewall setup, and profile-specific configurations (e.g., Docker for 'full', AppArmor for 'secops').
  • Detailed Documentation: New documentation files (DEVELOPERS.md, QUICK-START.md, automated-installation.md) have been added to guide developers on building ISOs and contributing, and users on quick setup and automated installations.
  • Debian Package Definitions: Debian package control files have been introduced for cortex-branding, cortex-core, cortex-full, and cortex-secops, enabling modular installation and management of Cortex Linux components.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This is an impressive and comprehensive pull request that bootstraps an entire Linux distribution build system. The structure is well-thought-out, with a powerful Makefile, support for different profiles, and a clear separation of concerns for branding, configuration, and documentation. My review focuses on improving the robustness and security of the build and provisioning process. I've identified a few areas where error handling can be improved to make the build process more reliable, and a critical security issue related to the handling of the default passphrase for full-disk encryption that needs to be addressed.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 12

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

🤖 Fix all issues with AI agents
In @branding/gdm/gdm-branding.conf:
- Around line 1-8: The GDM config references a non-existent logo path
'/usr/share/cortex/logos/cortex-logo-light.svg'; update the login-screen logo
setting to the actual filename 'cortex-logo.svg' and ensure the asset is
installed to that path by either modifying the install-branding.sh script to
copy 'branding/gdm/cortex-logo.svg' into '/usr/share/cortex/logos/' (creating
the directory if needed) or change the config to point to wherever
install-branding.sh currently places the logo; update the value in
[org/gnome/login-screen] (logo=) and adjust install-branding.sh accordingly so
the file and path match.
- Around line 20-28: The GDM config sets icon-theme='cortex-icons' in the
[org/gnome/desktop/interface] section but that theme isn’t provided; either
remove that cortex-icons entry or install/ship the cortex-icons theme and ensure
it’s referenced identically in the live session hooks (the
live/99-configure-gnome.hook.chroot usage that currently uses
icon-theme='Adwaita'); update the GDM key icon-theme='cortex-icons' to
icon-theme='Adwaita' if you prefer to align with the live session, or add the
cortex-icons theme package and update both GDM and live session hooks to use it.

In @docs/DEVELOPERS.md:
- Around line 9-15: The documented live-build version requirement is invalid;
update the version string in the DEVELOPER doc block where the live-build
install instructions and the "Verify live-build version" check appear so it
references a real release for your supported distro (e.g., change "live-build >=
1:20210814" to a valid version such as "live-build >= 1:20230502" for bookworm+
or to the specific minimum available in your minimum-supported release); ensure
the comment and the dpkg verification line reflect the chosen valid version.

In @docs/QUICK-START.md:
- Around line 54-63: The example commands in the docs use incorrect flags;
replace `cortex-upgrade --check` with the supported `cortex-upgrade plan` (and
mention the valid subcommands: plan, execute, rollback, status) and change
`cortex-verify --quick` to just `cortex-verify` (or note supported output flags
like `--json`) while leaving `cortex-gpu status` as-is; update the README
examples and any occurrences of `cortex-upgrade --check` and `cortex-verify
--quick` to the correct command forms (`cortex-upgrade plan` and
`cortex-verify`) and optionally add a brief note about `--json` output for
`cortex-verify`.

In @iso/live-build/config/includes.binary/boot/grub/themes/cortex/theme.txt:
- Line 12: Remove the stray '+' prefix from GRUB theme block declarations (e.g.,
boot_menu) so block names are bare identifiers followed by their opening brace;
locate each block declaration that begins with '+' and delete the '+' character
so the syntax matches "block_name { ... }" for all theme blocks.

In @iso/live-build/config/includes.chroot/boot/grub/themes/cortex/theme.txt:
- Around line 11-32: The theme file contains literal '+' characters before block
names which breaks GRUB parsing; remove the leading '+' characters from the
block definitions such as boot_menu, every label block, and progress_bar so the
blocks read e.g. "boot_menu {", "label {", and "progress_bar {" instead of "+
boot_menu {" etc.; update any occurrences (e.g., boot_menu, label, progress_bar)
throughout theme.txt so all block headers start without '+' and ensure
spacing/indentation remains valid for the GRUB theme parser.

In
@iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script:
- Around line 98-137: display_normal_callback may call password_dialogue_opacity
before globals set by password_dialogue_setup, causing null-derefs; modify
password_dialogue_opacity to guard uses of global.password_entry,
global.password_prompt, and iterate only if global.password_bullets is non-null
(or initialize those globals to sensible defaults at top-level), e.g., check
each global is defined before calling .sprite or looping, and return early if
none exist so display_normal_callback can safely call it.

In @iso/preseed/profiles/cortex-full.preseed:
- Around line 23-30: The preseed currently sets a deterministic/placeholder
password via the debconf key d-i passwd/user-password-crypted (and related keys
like d-i passwd/username and d-i user-setup/allow-password-weak), which creates
a predictable backdoor; remove the hardcoded d-i passwd/user-password-crypted
and user-setup/allow-password-weak lines so the installer prompts for a password
interactively, or convert the value into a required build-time substitution
variable (fail the build if unset) and document the substitution; ensure any
CI/build script that generates this file validates the substitution and rejects
commits that still contain the placeholder.

In @iso/preseed/profiles/cortex-secops.preseed:
- Around line 47-51: The preseed embeds a static full-disk-encryption passphrase
via the partman-crypto/passphrase and partman-crypto/passphrase-again entries,
which exposes all builds; remove these hardcoded values and instead require
interactive entry or generate a unique passphrase per ISO build and display it
once during build output; alternatively disable automated FDE in the preseed
(remove partman-crypto/* passphrase keys and related auto-enable flags) and
document manual FDE setup, and if you implement per-build generation use the
REQUIRE_FDE_PASSPHRASE_CHANGE variable only for enforcement and ensure build
tooling injects the secret securely (not committed in the preseed).

In @packages/cortex-branding/DEBIAN/postinst:
- Around line 10-25: Postinst sets GRUB_THEME in /etc/default/grub but prerm
does not restore it, leaving a broken GRUB_THEME pointing to a removed file;
modify postinst to save the previous GRUB_THEME value (or empty marker) to
/var/lib/cortex-branding/grub-theme.prev before writing the new GRUB_THEME and
modify prerm to read /var/lib/cortex-branding/grub-theme.prev and either restore
the original GRUB_THEME line in /etc/default/grub (if a previous value exists)
or remove the GRUB_THEME line entirely (if marker indicates none), then run
update-grub (or update-grub 2>/dev/null || true) to apply changes; reference the
scripts postinst and prerm, the GRUB_THEME entry in /etc/default/grub, and the
state file /var/lib/cortex-branding/grub-theme.prev when implementing.

In @packages/cortex-branding/DEBIAN/prerm:
- Around line 6-21: The prerm currently calls "plymouth-set-default-theme -R"
which only rebuilds initrd for the current theme; change the flow so the package
either saves the prior theme in postinst (e.g., write the original theme name to
a persistent state file) and then prerm reads that state and restores it, or
replace "-R" with "-r -R" to reset to system default and rebuild; likewise, stop
indiscriminately chmod'ing all /etc/update-motd.d/??-* scripts — have postinst
record exactly which MOTD scripts this package disabled (e.g., write their
filenames to a state file) and make prerm iterate only over that recorded list
to re-enable (chmod +x) those files, leaving other scripts untouched (refer to
the postinst logic that disables non-cortex scripts in lines 34–39 for exact
criteria).

In @packages/cortex-core/DEBIAN/control:
- Around line 1-20: The control file's Depends field lists non-existent packages
causing install failures; open the DEBIAN control and update the Depends line to
reference only existing packages (keep cortex-archive-keyring), remove or
replace cortex-upgrade and cortex-verify with their correct package names if
they exist, and replace cortex-gpu with the actual GPU package(s) (e.g.,
cortex-gpu-amd and/or cortex-gpu-nvidia) or change it to a Suggests/Provides if
it’s meant to be virtual; ensure the Depends field remains a comma-separated
list and adjust Recommends/Suggests accordingly if you move packages out of
Depends.
🟠 Major comments (18)
branding/motd/99-cortex-footer-14-24 (1)

14-24: Verify that MOTD tips reference only universally available commands.

The MOTD is installed system-wide for all installations, but several referenced commands are either missing or conditionally available:

  • cortex — no implementation found in codebase
  • cortex-update — not found (only 20-cortex-updates script exists)
  • lynis — only included in the cortex-secops profile, not in base installations

Consider either implementing these commands, making the MOTD profile-aware, or replacing these tips with universally available alternatives.

branding/motd/10-cortex-sysinfo-17-67 (1)

17-67: Fix fallback correctness for DISTRO/IP_ADDR/USERS and guard numeric comparisons.

Right now, several || echo ... fallbacks won’t trigger because the last command in the pipeline (cut/awk/wc) commonly exits 0 even when the “real” source command failed or produced empty output.

Proposed diff
--- a/branding/motd/10-cortex-sysinfo
+++ b/branding/motd/10-cortex-sysinfo
@@
 HOSTNAME=$(hostname)
-DISTRO=$(grep PRETTY_NAME /etc/os-release 2>/dev/null | cut -d'"' -f2 || echo "Cortex Linux")
+DISTRO=$(
+  awk -F= '/^PRETTY_NAME=/{gsub(/^"|"$/, "", $2); print $2; exit}' /etc/os-release 2>/dev/null
+)
+[ -n "$DISTRO" ] || DISTRO="Cortex Linux"
@@
-IP_ADDR=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "N/A")
+IP_ADDR="$(hostname -I 2>/dev/null | awk '{print $1}')"
+[ -n "$IP_ADDR" ] || IP_ADDR="N/A"
@@
-USERS=$(who 2>/dev/null | wc -l || echo "0")
+USERS="$(who 2>/dev/null | wc -l 2>/dev/null)"
+case "$USERS" in (''|*[!0-9]*) USERS=0 ;; esac
@@
 mem_color() {
-    if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
+    case "$1" in (''|*[!0-9]*) set -- 0 ;; esac
+    if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
+    elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }
@@
 disk_color() {
-    if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
+    case "$1" in (''|*[!0-9]*) set -- 0 ;; esac
+    if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
+    elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }
iso/preseed/partitioning/simple-uefi.preseed-10-12 (1)

10-12: Installer robustness: avoid hardcoding /dev/sda, add explicit ESP mountpoint, and clarify the EFI debconf key.

  • /dev/sda will break on NVMe, virtio, and other storage types. Use partman/early_command to set partman-auto/disk dynamically (e.g., list-devices disk | head -n1), or reference stable /dev/disk/by-id or /dev/disk/by-path instead.
  • Add explicit mountpoint{ /boot/efi } to the ESP recipe (lines 20–26) for clarity and to avoid relying on undocumented partman defaults.
  • The name partman-efi/non_efi_system is counterintuitive (setting it true means "force UEFI-only"), but your usage is correct; document it locally for maintainers.

Same issues apply to all UEFI preseed variants: fde-uefi, lvm-uefi, raid1-uefi, and simple-uefi.

iso/preseed/partitioning/fde-uefi.preseed-33-34 (1)

33-34: Security concern: Hardcoded LUKS passphrase in version-controlled file.

The plaintext passphrase cortex-temp-passphrase is committed to the repository. While comments indicate it should be changed at first boot, this creates risk:

  • Users may forget or skip the passphrase change step
  • The default passphrase becomes publicly known if the repo is public
  • Automated scanners may flag this as a credential leak

Consider using a preseed hook to prompt for passphrase entry, or document this very prominently in installation guides.

iso/preseed/partitioning/raid1-uefi.preseed-62-67 (1)

62-67: Missing LVM logical volume definitions inside RAID.

The preseed defines the RAID arrays and volume group cortex-vg, but doesn't include the logical volume definitions for root (20GB), swap (8GB), and home (remaining) as described in the header comments (lines 10-13). Without these, the installation will fail or produce unexpected results.

Compare with lvm-uefi.preseed lines 44-61 which properly define the LV layout within the expert_recipe.

packages/cortex-branding/DEBIAN/postinst-26-40 (1)

26-40: Track which MOTD scripts you disable (avoid blanket chmod behavior on uninstall).
The loop disables “non-cortex” scripts (Lines 34-39) but you don’t record which ones changed—so prerm can’t safely revert without re-enabling everything.

Proposed change (write disabled list for prerm)
         if [ -d /etc/update-motd.d ]; then
@@
             # Disable default Ubuntu/Debian MOTD scripts
+            mkdir -p /var/lib/cortex-branding
+            : > /var/lib/cortex-branding/motd-disabled.list
             for f in /etc/update-motd.d/??-* ; do
                 case "$(basename $f)" in
                     *cortex*) ;;  # Keep our scripts
-                    *) chmod -x "$f" 2>/dev/null || true ;;
+                    *)
+                        chmod -x "$f" 2>/dev/null || true
+                        printf '%s\n' "$f" >> /var/lib/cortex-branding/motd-disabled.list
+                        ;;
                 esac
             done
         fi
iso/live-build/config/bootloaders/grub-pc/theme.cfg-5-8 (1)

5-8: Fix GRUB theme path — it will not load as configured.

set theme=/boot/grub/live-theme/theme.txt (Line 6) does not match the actual deployment path used throughout the codebase. All build hooks, installation scripts, and the Makefile consistently deploy the theme to /boot/grub/themes/cortex/theme.txt. GRUB will fail to find the file at the configured path and silently fall back to defaults, removing custom branding.

Proposed fix
-# Always load Cortex theme
-set theme=/boot/grub/live-theme/theme.txt
+# Always load Cortex theme
+set theme=/boot/grub/themes/cortex/theme.txt
 set menu_color_normal=light-gray/black
 set menu_color_highlight=cyan/black
branding/wallpapers/ASSETS.md-1-19 (1)

1-19: Wallpaper assets incomplete: only single resolution per wallpaper exists instead of documented 3 resolutions.

ASSETS.md requires all 6 wallpapers at three resolutions (4K, QHD, FHD), but only 6 PNG files exist in branding/wallpapers/images/ — one per wallpaper. Either the documentation should be updated to reflect single-resolution assets, or the missing QHD and FHD variants (12 additional files) must be generated to match the documented requirements.

branding/gdm/INSTALL.md-49-71 (1)

49-71: Method 3 + Troubleshooting: fix glib-compile-resources invocation and restore commands (current doc is likely broken).

  • glib-compile-resources typically needs --target (and often --sourcedir) to produce the expected output file.
  • The XML references gnome-shell.css, but the guide never creates/copies gnome-shell.css from cortex-gdm.css.
  • The “restore backup” command uses relative filenames and won’t restore the actual backed-up paths; also consider restoring the .gresource backup (not just CSS).
Proposed doc fix
 # Build resource
-glib-compile-resources gnome-shell-theme.gresource.xml
+cp cortex-gdm.css gnome-shell.css
+glib-compile-resources gnome-shell-theme.gresource.xml \
+  --target=gnome-shell-theme.gresource \
+  --sourcedir=.

 # Install
 sudo cp gnome-shell-theme.gresource /usr/share/gnome-shell/
 ### Black screen after changes
 1. Boot to recovery mode
-2. Restore backup: `sudo cp gnome-shell.css.backup gnome-shell.css`
+2. Restore backup:
+   - `sudo cp /usr/share/gnome-shell/theme/gnome-shell.css.backup /usr/share/gnome-shell/theme/gnome-shell.css`
+   - `sudo cp /usr/share/gnome-shell/gnome-shell-theme.gresource.backup /usr/share/gnome-shell/gnome-shell-theme.gresource`
 3. Reboot normally

Also applies to: 96-99

iso/live-build/config/bootloaders/grub-pc/install_start_text.cfg-1-4 (1)

1-4: Fix duplicate --hotkey=i entries causing menu collision. Multiple menuentry definitions across install_start_text.cfg, install_text.cfg, install_start_gui.cfg, and install_gui.cfg use --hotkey=i. When GRUB loads these configurations, only the first match becomes active, making the hotkey unreliable and breaking expected menu behavior. Each installer variant (text/GUI, Start vs. Install, themed vs. unthemed) should have unique hotkeys.

iso/preseed/profiles/cortex-full.preseed-36-83 (1)

36-83: Document EFI-only limitation and provide BIOS alternative for profiles.

These three profiles (cortex-core, cortex-full, cortex-secops) all hardcode /dev/sda and use GPT + EFI-only partitioning recipes. This will fail on BIOS-only systems. While simple-bios.preseed exists in iso/preseed/partitioning/, it is not integrated or documented as an alternative.

At minimum, add a comment in each profile documenting:

  1. That /dev/sda is unconditionally targeted (state how to override via boot parameter if supported)
  2. That these are EFI-only; provide guidance to use the BIOS preseed for legacy systems
  3. Or unify the recipe conditionally (like the main cortex.preseed does with $iflabel{ gpt }) to support both architectures
packages/cortex-secops/DEBIAN/control-6-38 (1)

6-38: Remove or replace ossec-hids from Recommends — it is not available in Debian 12 (bookworm) official repositories.

The package ossec-hids requires a third-party repository (Atomicorp/Wazuh) and will cause apt resolver errors if that repo is not configured. The other flagged packages (tiger, tripwire, psad) do exist in bookworm. Either remove ossec-hids, document the third-party repo requirement explicitly, or substitute an alternative that exists in official repos (e.g., wazuh-agent if using Wazuh's official repo, or remove it entirely if it is optional).

iso/preseed/partitioning/simple-bios.preseed-11-11 (1)

11-11: Hard-coded disk path limits installation flexibility.

The fixed /dev/sda path will fail on systems with NVMe drives (/dev/nvme0n1), virtio (/dev/vda), or when the target disk is not the first SCSI device. This significantly restricts where this preseed can be used.

💡 Suggested fix: Use dynamic disk detection

Consider one of these approaches:

Option 1: Omit the disk directive to let the installer prompt or auto-detect:

 d-i partman-auto/method string regular
-d-i partman-auto/disk string /dev/sda

Option 2: Use a preseed early_command to detect the first available disk dynamically:

+# Detect first available disk dynamically
+d-i partman/early_command string \
+    DISK=$(list-devices disk | head -n1); \
+    debconf-set partman-auto/disk "$DISK"
 d-i partman-auto/method string regular
-d-i partman-auto/disk string /dev/sda
iso/preseed/cortex-base.preseed-36-44 (1)

36-44: Clarify weak password handling and first-boot provisioning dependency.

The preseed configuration creates a default cortex user with a placeholder password hash ($6$rounds=4096$cortexsalt$placeholder) and relies on first-boot provisioning or cloud-init to set a real password. This is operationally risky if:

  1. First-boot provisioning fails or is skipped.
  2. The system is used before first-boot provisioning runs.
  3. An operator mistakes the placeholder for a real password.

Recommendations:

  • Document clearly in comments that this password must be changed before the system is accessible to users.
  • Consider enforcing password expiration in PAM (e.g., chage -d 0 cortex) to force a password change on first login if first-boot provisioning is unavailable.
  • Add validation/logging in first-boot provisioning to confirm password was changed.
  • Consider requiring a secure boot sequence that ensures first-boot provisioning runs before network access is granted.
branding/os-release/os-release-1-13 (1)

1-13: Fix incorrect GitHub repository name in URLs.

The SUPPORT_URL and BUG_REPORT_URL reference a non-existent repository cortexlinux/cortex-distro. The actual repository is cortexlinux/cortex. Update lines 9–10:

SUPPORT_URL="https://github.com/cortexlinux/cortex/discussions"
BUG_REPORT_URL="https://github.com/cortexlinux/cortex/issues"
docs/automated-installation.md-324-328 (1)

324-328: Security: Reconsider exposing the default FDE passphrase in documentation.

Documenting the default FDE passphrase (cortex-temp-fde-passphrase) in plain text creates a security risk. If users deploy SecOps installations without changing this passphrase, attackers with access to this documentation can decrypt the disk.

Consider:

  1. Using a randomly generated passphrase during installation that's displayed once
  2. Forcing passphrase change on first boot for SecOps profile
  3. At minimum, adding a more prominent warning about this being publicly documented
branding/generate-assets.sh-9-11 (1)

9-11: Add ImageMagick version compatibility check.

The script uses the magick command (ImageMagick 7 syntax) extensively, but Debian Bookworm ships ImageMagick 6 by default, which uses convert instead. Without a compatibility layer, the script will fail on systems with only IM6 installed.

Implement the suggested wrapper to detect and use the available command:

Compatibility wrapper
 set -e

 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+
+# ImageMagick compatibility: IM7 uses 'magick', IM6 uses 'convert'
+if command -v magick &>/dev/null; then
+    IM_CMD="magick"
+elif command -v convert &>/dev/null; then
+    IM_CMD="convert"
+else
+    echo "ERROR: ImageMagick not installed"
+    exit 1
+fi

Then replace all magick invocations with $IM_CMD.

iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script-138-147 (1)

138-147: Reuse the message sprite instead of allocating a new one per message.
message_callback() creates a new Sprite every time; repeated status updates can stack sprites and waste memory.

Proposed fix
 fun message_callback(text) {
     message.image = Image.Text(text, 0.6, 0.6, 0.7, 1, "Sans 11");
-    message.sprite = Sprite(message.image);
+    if (!message.sprite) {
+        message.sprite = Sprite(message.image);
+    } else {
+        message.sprite.SetImage(message.image);
+    }
     message.x = screen_x + screen_width / 2 - message.image.GetWidth() / 2;
     message.y = screen_y + screen_height - 50;
     message.sprite.SetPosition(message.x, message.y, 10);
 }
🟡 Minor comments (17)
iso/provisioning/first-boot.sh-358-378 (1)

358-378: Inconsistent volume group name in FDE notice.

Line 378 references cortex-sec-vg but the FDE preseed uses cortex-vg as the volume group name. This will confuse users trying to verify their encryption status.

🐛 Proposed fix
 To verify encryption status:
-    sudo cryptsetup status cortex-sec-vg
+    sudo cryptsetup status cortex-vg
branding/plymouth/cortex/ASSETS.md-1-51 (1)

1-51: **Fix Markdown fencing (currently likely to render broken due to mixed and ````).** The file starts/ends with ```` which conflicts with the innerbash block.

Proposed change (use standard triple-backtick fences only)
-````
 # Plymouth Theme Assets
@@
 ```bash
 # Generate placeholder assets (requires ImageMagick)
 convert -size 200x200 xc:transparent \
@@
     progress-bar.png

-````

</details>

</blockquote></details>
<details>
<summary>packages/cortex-branding/DEBIAN/postinst-42-46 (1)</summary><blockquote>

`42-46`: **Guard `dconf update` with a command check, not just file check.**

On minimal or server installations where GDM (`gdm3`) is not installed, the `dconf` command will be absent. While your file check on line 43 ensures the config exists, `dconf` itself may not be present, causing the command to fail (though suppressed by `|| true`).

This pattern is already used elsewhere in the script (line 11 with `command -v`). Apply the same guard:

<details>
<summary>Proposed change</summary>

```diff
         # Update GDM branding
         if [ -f /etc/gdm3/greeter.dconf-defaults ]; then
-            dconf update 2>/dev/null || true
+            command -v dconf >/dev/null 2>&1 && dconf update 2>/dev/null || true
         fi
iso/live-build/config/includes.chroot/boot/grub/themes/cortex/ASSETS.md-42-52 (1)

42-52: Update optional icons section to match actual files present.

The required theme assets and theme.txt references are correct and all PNG files listed in the asset table exist. However, the optional icons section documents six icons (cortex.png, debian.png, linux.png, windows.png, recovery.png, settings.png) but only three are present in the repository: cortex.png, linux.png, and recovery.png. Either add the missing icon files (debian.png, windows.png, settings.png) or update the documentation to reflect only the icons that exist.

The installation instructions assume manual post-installation setup, which is standard; note that in this live-build context, the theme is pre-included in the ISO build process.

branding/gdm/INSTALL.md-7-13 (1)

7-13: Clarify exact install destinations (paths) for “GDM theme / GDM resources”.
Right now the table mixes conceptual destinations (“GDM theme”, “GDM resources”) with one concrete path; it’ll be hard to automate/review correctness across Debian/GNOME versions. Consider listing the exact on-disk paths (and whether assets must be embedded into gnome-shell-theme.gresource).

branding/gdm/cortex-gdm.css-148-151 (1)

148-151: Consider ignoring Biome's unknown pseudo-class warning on .user-list-item:selected.
While :selected is valid in GNOME Shell CSS (part of GTK widget states), Biome's CSS linter will flag it since it's not standard web CSS. The suggestion to add an inline ignore comment is optional for developers who lint locally, but this is not a CI blocker since Biome is not currently invoked in your build pipeline.

-.user-list-item:selected {
+/* biome-ignore lint/correctness/noUnknownPseudoClass: GNOME Shell theme pseudo-class */
+.user-list-item:selected {
     background-color: rgba(107, 33, 168, 0.5);
     border: 1px solid #6B21A8;
 }
packages/cortex-full/DEBIAN/control-12-26 (1)

12-26: firefox-esr package name may not be available on Ubuntu.

Line 22 recommends firefox-esr, which is the Debian package name. Ubuntu typically provides Firefox via snap or as firefox (not firefox-esr). This won't block installation (Recommends vs Depends) but may result in missing Firefox on Ubuntu systems.

Consider a more portable browser recommendation

If targeting both Debian and Ubuntu:

- firefox-esr,
+ firefox-esr | firefox,

This allows either package name to satisfy the recommendation. Alternatively, document this difference in the installation guide.

iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot-75-97 (1)

75-97: Address icon theme inconsistency across branding configurations.

The background image path at lines 85-86, 91 (/usr/share/backgrounds/cortex/cortex-default.png) is properly installed—the file exists in iso/live-build/config/includes.chroot/usr/share/backgrounds/cortex/ and is verified by the 50-cortex-branding.hook.chroot hook.

However, icon theme inconsistency exists: Line 80 sets icon-theme='Adwaita' for the live user session, while branding/gdm/gdm-branding.conf specifies icon-theme='cortex-icons'. This creates a mismatch in icon themes across environments. The actual GDM hook (50-cortex-branding.hook.chroot) does not set an icon-theme for the login screen, leaving it unspecified. Clarify the intended icon theme strategy and update configurations consistently—either use cortex-icons throughout or document why different themes apply to different contexts.

Line 95's welcome-dialog-last-shown-version='9999999999' is functional but non-standard. Consider adding a comment explaining this approach.

iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot-61-61 (1)

61-61: Remove unnecessary execute permission on .desktop file.

The execute permission is not required by the XDG/Freedesktop autostart specification for files in ~/.config/autostart. GNOME's autostart mechanism reads the .desktop file as configuration and executes the command specified in the Exec key regardless of filesystem permissions. The chmod +x line serves no purpose and should be removed.

Execute permissions are only needed if the file is intended to be double-clicked/launched from a file manager, which is not the case here.

iso/preseed/profiles/cortex-secops.preseed-41-41 (1)

41-41: Same hardcoded disk path issue as core profile.

See the comment on cortex-core.preseed regarding /dev/sda hardcoding.

Makefile-204-206 (1)

204-206: Silent failure on missing ISO output.

The mv ... || true pattern will silently succeed even if the ISO wasn't built, making it hard to detect build failures. Consider checking if the source file exists first or failing explicitly.

🐛 Proposed fix
 	@# Move output
-	@mv $(BUILD_DIR)/$(1)/live-image-$(ARCH).hybrid.iso \
-		$(OUTPUT_DIR)/$(ISO_NAME)-$(1)-$(ISO_VERSION)-$(ARCH).iso 2>/dev/null || true
+	@if [ -f "$(BUILD_DIR)/$(1)/live-image-$(ARCH).hybrid.iso" ]; then \
+		mv $(BUILD_DIR)/$(1)/live-image-$(ARCH).hybrid.iso \
+			$(OUTPUT_DIR)/$(ISO_NAME)-$(1)-$(ISO_VERSION)-$(ARCH).iso; \
+	else \
+		echo "ERROR: ISO not found at $(BUILD_DIR)/$(1)/live-image-$(ARCH).hybrid.iso"; \
+		exit 1; \
+	fi
 	@echo "ISO built: $(OUTPUT_DIR)/$(ISO_NAME)-$(1)-$(ISO_VERSION)-$(ARCH).iso"
branding/generate-assets.sh-403-403 (1)

403-403: Fix find command to count all image files correctly.

The -o operator has lower precedence than the implicit -print, so only .svg files will be counted. The .png files won't be included in the output.

🐛 Proposed fix
-find "${SCRIPT_DIR}" -name "*.png" -o -name "*.svg" | wc -l | xargs echo "  Total images:"
+find "${SCRIPT_DIR}" \( -name "*.png" -o -name "*.svg" \) | wc -l | xargs echo "  Total images:"
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot-101-104 (1)

101-104: Fix GRUB_DISTRIBUTOR configuration logic.

The sed -i command returns success (exit 0) even when the pattern isn't found, so the fallback echo will never execute. If GRUB_DISTRIBUTOR doesn't exist in the file, it won't be added. Use the same grep-then-sed-or-echo pattern used for GRUB_THEME above.

🐛 Proposed fix
-    # Also set timeout and other branding options
-    sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
-        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    # Also set distributor branding
+    if grep -q "^GRUB_DISTRIBUTOR=" /etc/default/grub; then
+        sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub
+    else
+        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    fi
iso/preseed/profiles/cortex-core.preseed-41-41 (1)

41-41: Hardcoded disk path may cause installation failures.

Hardcoding /dev/sda will fail on systems with NVMe drives (/dev/nvme0n1), virtio disks (/dev/vda), or other storage configurations. Consider using an empty string to let the installer auto-detect, or documenting this as a template that must be customized.

♻️ Suggested alternative for auto-detection
 ### Partitioning - Simple UEFI (default for core)
 d-i partman-auto/method string regular
-d-i partman-auto/disk string /dev/sda
+# Leave blank for auto-detection, or set via boot parameter
+d-i partman-auto/disk string
iso/preseed/profiles/cortex-core.preseed-30-31 (1)

30-31: Password setup requires user action at first login; document security expectations clearly.

The preseed uses a placeholder password hash intentionally to force users to set their own credentials at first login, rather than shipping a pre-configured password. However, this design choice should be more explicitly documented in the preseed file itself—a comment like # IMPORTANT: User MUST set password on first login would prevent confusion about whether this is a misconfiguration or intentional.

Additionally, allow-password-weak boolean true (line 31) should be reconsidered for a server-focused core profile. Even with first-login setup, allowing weak passwords creates an exploitable window. Consider changing this to false and documenting the password requirements for users.

iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script-123-129 (1)

123-129: Avoid leaking i into global scope in the bullets loop.
i isn’t declared local, so it may become global and collide with other loops/callbacks.

Proposed fix
 fun password_dialogue_opacity(opacity) {
+    local.i;
     if (global.password_entry && global.password_entry.sprite)
         global.password_entry.sprite.SetOpacity(opacity);
     if (global.password_prompt && global.password_prompt.sprite)
         global.password_prompt.sprite.SetOpacity(opacity);
     for (i = 0; global.password_bullets[i]; i++) {
         global.password_bullets[i].sprite.SetOpacity(opacity);
     }
 }
iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script-73-96 (1)

73-96: Clamp progress values and clear progress bar on zero to avoid stale visuals.

The current code only updates the progress bar image when new_width > 1, leaving smaller values with the previously scaled image visible. Additionally, Scale() expects integer dimensions; floating-point values from out-of-range progress may cause unexpected behavior. Clamp progress to the expected range for each callback (0–1 for boot progress, 0–100 for system updates), convert to integer with Math.Int(), and use SetOpacity(0) to hide the bar when new_width <= 0.

Proposed fix
 fun progress_callback(duration, progress) {
     if (progress_bar.original_image.GetWidth() > 0) {
+        if (progress < 0) progress = 0;
+        if (progress > 1) progress = 1;
-        new_width = progress_bar.original_image.GetWidth() * progress;
-        if (new_width > 1) {
+        new_width = Math.Int(progress_bar.original_image.GetWidth() * progress);
+        if (new_width <= 0) {
+            progress_bar.sprite.SetOpacity(0);
+        } else {
+            progress_bar.sprite.SetOpacity(1);
             progress_bar.image = progress_bar.original_image.Scale(new_width, progress_bar.original_image.GetHeight());
             progress_bar.sprite.SetImage(progress_bar.image);
         }
     }
 }
@@
 fun system_update_callback(progress) {
     if (progress_bar.original_image.GetWidth() > 0) {
+        if (progress < 0) progress = 0;
+        if (progress > 100) progress = 100;
-        new_width = progress_bar.original_image.GetWidth() * progress / 100;
-        if (new_width > 1) {
+        new_width = Math.Int(progress_bar.original_image.GetWidth() * progress / 100);
+        if (new_width <= 0) {
+            progress_bar.sprite.SetOpacity(0);
+        } else {
+            progress_bar.sprite.SetOpacity(1);
             progress_bar.image = progress_bar.original_image.Scale(new_width, progress_bar.original_image.GetHeight());
             progress_bar.sprite.SetImage(progress_bar.image);
         }
     }
 }
🧹 Nitpick comments (36)
iso/live-build/config/includes.binary/boot/grub/themes/cortex/ASSETS.md (1)

1-53: Consider DRY principle: documentation duplication detected.

This file is identical to branding/grub/cortex/ASSETS.md. While the duplication may be intentional for different deployment contexts (binary ISO vs. branding source), it creates a maintenance burden where asset specifications must be kept synchronized manually.

Consider one of these approaches:

  • Use a single source of truth with symlinks
  • Generate this file from the canonical version during build
  • Add a comment referencing the canonical location if duplication is required
iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/ASSETS.md (1)

16-24: Add language specifier to color palette code block.

The code block lacks a language identifier, which affects rendering and syntax highlighting. Consider specifying a language for better documentation clarity.

📝 Proposed fix for markdown linting
 ## Color Palette
 
-```
+```text
 Primary Purple:   #6B21A8 (rgb: 107, 33, 168)
 Electric Cyan:    #06B6D4 (rgb: 6, 182, 212)
 Dark Background:  #0F0F23 (rgb: 15, 15, 35)
 Text Light:       #E2E8F0 (rgb: 226, 232, 240)
 Text Muted:       #94A3B8 (rgb: 148, 163, 184)
</details>

</blockquote></details>
<details>
<summary>iso/live-build/config/package-lists/live.list.chroot (1)</summary><blockquote>

`1-42`: **Confirm target Debian release + consider trimming size-heavy choices (`task-gnome-desktop`, `live-boot-doc`).**

- Please verify every package here exists in (and is appropriate for) the target Debian suite you’re building Cortex on; `task-gnome-desktop` in particular can pull a large dependency set and may make ISO size/control harder.  
- `live-boot-doc` is usually safe to drop from a production ISO unless you explicitly want offline docs.

 
<details>
<summary>Proposed diff (optional size trim)</summary>

```diff
--- a/iso/live-build/config/package-lists/live.list.chroot
+++ b/iso/live-build/config/package-lists/live.list.chroot
@@
 live-boot
-live-boot-doc
 initramfs-tools
branding/BRAND-GUIDELINES.md (1)

149-175: Fix markdownlint MD040 by adding languages to the fenced blocks (Buttons/Cards/Input Fields).

Proposed diff
--- a/branding/BRAND-GUIDELINES.md
+++ b/branding/BRAND-GUIDELINES.md
@@
 ### Buttons
-
-```
+```text
 Primary: #6B21A8 background, white text
 Secondary: transparent, #6B21A8 border
 Ghost: transparent, #94A3B8 text
 Danger: #EF4444 background, white text

@@

Cards

- +text
Background: #1E1E3F (dark) or #FFFFFF (light)
Border: 1px solid rgba(107, 33, 168, 0.2)
Border radius: 12px
Shadow: 0 4px 20px rgba(0, 0, 0, 0.15)

@@
### Input Fields
-
-```
+```text
Background: #0F0F23 (dark) or #F8FAFC (light)
Border: 1px solid #2D2D5A
Focus border: #06B6D4
Border radius: 8px
</details>

</blockquote></details>
<details>
<summary>iso/live-build/config/includes.chroot/boot/grub/themes/cortex/theme.txt (1)</summary><blockquote>

`4-10`: **Verify font support in your GRUB build (likely needs `.pf2` fonts + `loadfont`).**

Theme entries like `terminal-font: "DejaVu Sans Mono Regular 14"` and `item_font = "DejaVu Sans Regular 16"` only work if the corresponding GRUB font assets are present/loaded in your GRUB config.

 


Also applies to: 17-31

</blockquote></details>
<details>
<summary>branding/motd/10-cortex-sysinfo (1)</summary><blockquote>

`28-48`: **Optional: avoid calling `free`/`df` multiple times.**

Minor perf/cleanliness: you can capture `free` and `df` output once to avoid 3 subprocesses each (useful on slow systems and reduces MOTD latency).

</blockquote></details>
<details>
<summary>iso/preseed/partitioning/fde-uefi.preseed (1)</summary><blockquote>

`91-91`: **Duplicate directive: `weak_passphrase` already set on line 27.**

This directive is redundant and can be removed.


<details>
<summary>♻️ Proposed fix</summary>

```diff
-# Skip LUKS warning about weak passphrase (will be changed at first-boot)
-d-i partman-crypto/weak_passphrase boolean true
branding/motd/20-cortex-updates (1)

51-52: Minor style: Useless use of cat.

The cat is unnecessary here and in line 62.

♻️ Proposed fix
-        REBOOT_PKGS=$(cat /var/run/reboot-required.pkgs | head -3 | tr '\n' ', ' | sed 's/,$//')
+        REBOOT_PKGS=$(head -3 /var/run/reboot-required.pkgs | tr '\n' ', ' | sed 's/,$//')
-    cat "$CORTEX_NOTICE" | sed 's/^/    /'
+    sed 's/^/    /' "$CORTEX_NOTICE"
iso/preseed/partitioning/raid1-uefi.preseed (1)

30-31: Duplicate directive: new_vg_name set twice.

Lines 30 and 63 both set partman-auto-lvm/new_vg_name. Remove the duplicate.

Also applies to: 63-63

iso/provisioning/first-boot.sh (2)

61-72: Validate profile file content before sourcing.

The script sources ${PROFILE_FILE} directly without validating its contents. While the file should be root-owned, consider adding basic validation to ensure it only contains expected variable assignments.

♻️ Safer profile loading
 load_profile() {
     if [[ ! -f "${PROFILE_FILE}" ]]; then
         log_warn "Profile file not found, defaulting to 'core'"
         CORTEX_PROFILE="core"
     else
-        # shellcheck source=/dev/null
-        source "${PROFILE_FILE}"
+        # Only read CORTEX_PROFILE variable, ignore other content
+        CORTEX_PROFILE=$(grep -Po '^CORTEX_PROFILE=\K(core|full|secops)$' "${PROFILE_FILE}" 2>/dev/null || echo "core")
     fi
 
     log_info "Profile: ${CORTEX_PROFILE:-core}"
     export CORTEX_PROFILE="${CORTEX_PROFILE:-core}"
 }

74-83: Consider alternative network checks for restricted environments.

Pinging 8.8.8.8 may fail in environments where ICMP is blocked. Consider falling back to DNS resolution or HTTP connectivity checks.

♻️ More robust network check
 check_network() {
-    if ping -c 1 -W 3 8.8.8.8 &>/dev/null; then
+    if ping -c 1 -W 3 8.8.8.8 &>/dev/null || \
+       curl -s --max-time 3 -o /dev/null https://apt.cortexlinux.com &>/dev/null; then
         log_info "Network: Online"
         export NETWORK_AVAILABLE=true
     else
iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.plymouth (1)

1-8: Consider DRY: duplicate Plymouth theme configuration.

This file is identical to branding/plymouth/cortex/cortex.plymouth. While having separate copies for the branding package and live-build is a valid deployment strategy, consider symlinking or copying from a single source during build to avoid drift.

iso/live-build/config/bootloaders/grub-pc/live-theme/theme.txt (1)

12-25: Remove duplicate selected_item_color property.

selected_item_color is defined twice (lines 20 and 24) with the same value. Remove the duplicate to improve maintainability.

Suggested fix
 + boot_menu {
     left = 15%
     top = 25%
     width = 70%
     height = 50%
     item_font = "DejaVu Sans Regular 14"
     item_color = "#E2E8F0"
     selected_item_font = "DejaVu Sans Bold 14"
     selected_item_color = "#06B6D4"
     item_height = 36
     item_padding = 12
     item_spacing = 4
-    selected_item_color = "#06B6D4"
 }
branding/motd/00-cortex-banner (1)

7-27: Prefer printf over echo -e (and drop/justify unused color vars).
echo -e behavior can vary; printf is deterministic. Also PURPLE/CYAN/WHITE are currently unused (Lines 8-10).

Proposed change
-echo -e "${GRAY}                              L I N U X${RESET}"
-echo ""
+printf '%b\n\n' "${GRAY}                              L I N U X${RESET}"
docs/DEVELOPERS.md (1)

145-150: Verify QEMU testing commands are compatible with build output.

The QEMU testing commands (lines 145-150) assume the build process generates ISO files in output/ with the expected naming scheme. Ensure:

  1. The ISO naming matches the pattern cortex-linux-full-*.iso
  2. The wildcard expansion will work correctly in shell commands
  3. QEMU paths are correct for common Linux distributions

Note: These are illustrative examples, but developers may copy them verbatim.

Consider making the QEMU examples more robust:

Optional improvement: More robust QEMU examples
  ### Test ISO in VM

  ```bash
-# QEMU (amd64)
-qemu-system-x86_64 -m 4G -cdrom output/cortex-linux-full-*.iso -boot d
-
-# QEMU (arm64)
-qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -cdrom output/cortex-linux-full-*-arm64.iso
+# QEMU (amd64)
+ISO=$(ls output/cortex-linux-full-*-amd64.iso 2>/dev/null | tail -1)
+qemu-system-x86_64 -m 4G -cdrom "$ISO" -boot d
+
+# QEMU (arm64)
+ISO=$(ls output/cortex-linux-full-*-arm64.iso 2>/dev/null | tail -1)
+qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -cdrom "$ISO"
</details>

</blockquote></details>
<details>
<summary>branding/wallpapers/ASSETS.md (1)</summary><blockquote>

`45-77`: **Design guidelines are well-documented, but implementation needs verification.**

The design guidelines for each of the 6 wallpaper themes are detailed and provide clear visual direction:
- Neural Dark/Light with network patterns
- Gradient Purple/Cyan variations
- Minimal Dark with logo
- Circuit Board tech aesthetic

These provide good guidance for designers, but confirm:
1. The actual asset files match these design specifications
2. The design is cohesive and professional across all themes
3. Colors and patterns are rendered correctly at all specified resolutions



Consider adding design asset sources or generation instructions if wallpapers are being generated programmatically (e.g., via `branding/generate-assets.sh` mentioned in AI summary). This would help future maintainers reproduce or modify the wallpapers.

<details>
<summary>Optional enhancement: Document wallpaper generation</summary>

If wallpapers are generated (not hand-created), document:

```markdown
## Generation

Wallpapers can be generated using the `branding/generate-assets.sh` script:

\`\`\`bash
./branding/generate-assets.sh --wallpapers
\`\`\`

This regenerates all wallpapers at the specified resolutions.
branding/gdm/INSTALL.md (1)

16-37: Method 1: verify that update-alternatives on gnome-shell.css actually affects GDM on the target GNOME Shell build.
On many distros the greeter theme is effectively driven by the compiled gnome-shell-theme.gresource; if GDM doesn’t read /usr/share/gnome-shell/theme/gnome-shell.css, this method won’t apply (or will apply inconsistently). If it does work for your target, consider adding the missing “select it” step so users don’t forget.

Proposed doc tweak
 sudo update-alternatives --install \
     /usr/share/gnome-shell/theme/gnome-shell.css \
     gdm-theme /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 100
+
+# Select the alternative (if multiple are installed)
+sudo update-alternatives --config gdm-theme
packages/cortex-secops/DEBIAN/control (1)

1-6: Consider version-pinning the bundle to the matching cortex-core version.
For metapackages, Depends: cortex-core (= ${binary:Version}) (or at least >=) helps prevent mixed-version installs when repos lag or users partially upgrade.

Also applies to: 38-55

iso/preseed/profiles/cortex-full.preseed (1)

140-148: Late-command: add systemctl daemon-reload before enabling the new unit.
Enabling a freshly-copied unit can fail if systemd hasn’t noticed it yet.

Proposed change
 d-i preseed/late_command string \
     in-target mkdir -p /opt/cortex/provisioning; \
     in-target mkdir -p /var/log/cortex; \
     cp /cdrom/provisioning/first-boot.sh /target/opt/cortex/provisioning/; \
     cp /cdrom/provisioning/cortex-first-boot.service /target/etc/systemd/system/; \
     echo "CORTEX_PROFILE=full" > /target/opt/cortex/provisioning/profile; \
     in-target chmod +x /opt/cortex/provisioning/first-boot.sh; \
+    in-target systemctl daemon-reload; \
     in-target systemctl enable cortex-first-boot.service
iso/preseed/partitioning/simple-bios.preseed (1)

17-37: Consider documenting the absence of swap or making it configurable.

The partition recipe defines no swap space, which may be intentional for modern systems with adequate RAM or container/cloud deployments. However, many traditional installations benefit from swap (especially for hibernation, memory-constrained systems, or swap-on-zram).

📋 Optional: Add a swap partition or document the rationale

If swap should be included, add a swap partition entry before the root partition:

               .                                               \
+              2048 4096 8192 linux-swap                        \
+                      $primary{ }                             \
+                      method{ swap } format{ }                \
+              .                                               \
               8192 16384 -1 ext4                               \

Alternatively, add a comment explaining why swap is omitted:

 # Define partition recipe
+# Note: No swap partition - assumes adequate RAM or swap-on-zram at runtime
 d-i partman-auto/expert_recipe string                         \
docs/QUICK-START.md (1)

42-48: Consider increasing disk recommendation for cortex-full.

The 20GB disk requirement for cortex-full might be insufficient for active development. Docker images, Node.js node_modules, Go/Rust build artifacts, and development projects can quickly consume space. Consider recommending 40GB+ for comfortable development use.

 | Profile | RAM | Disk | Use Case |
 |---------|-----|------|----------|
 | cortex-core | 512MB | 2GB | Servers, embedded, minimal |
-| cortex-full | 4GB | 20GB | Workstations, development |
+| cortex-full | 4GB | 40GB | Workstations, development |
 | cortex-secops | 4GB | 20GB | Security-critical systems |
iso/preseed/cortex-base.preseed (1)

60-77: Package selection is well-curated for a minimal server install.

The included packages balance essential tools (ssh, sudo, curl, git, firewall) with a minimal footprint. This is a solid foundation for base installations.

✓ Security tools (sudo, ufw, fail2ban, ca-certificates, gnupg) included.
✓ Admin/dev tools (vim, htop, python3, git) included.
✓ No unnecessary bloat (no X11, no heavy applications).

If this base is intended for minimal/core profiles, consider whether to add grub-pc or grub-efi explicitly (they should be pulled in by task selection, but explicit inclusion reduces surprises).

iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot (2)

102-123: Consider avoiding blanket error suppression on schema compilation.

Line 123 suppresses all errors from glib-compile-schemas with || true. While this prevents build failures, it may hide genuine schema syntax errors or permission issues.

Consider logging errors for debugging:

♻️ Proposed refinement
 # Compile schemas
-glib-compile-schemas /usr/share/glib-2.0/schemas/ 2>/dev/null || true
+if ! glib-compile-schemas /usr/share/glib-2.0/schemas/ 2>&1; then
+  echo "Warning: glib-compile-schemas failed, but continuing..." >&2
+fi

25-40: Remove redundant GDM configuration file.

/etc/gdm3/daemon.conf and /etc/gdm3/custom.conf serve the same purpose and contain identical settings. GDM3 reads only one system override file per distribution; custom.conf is the standard and recommended file across modern GDM3 versions. Keep only custom.conf and remove the daemon.conf creation to avoid unnecessary duplication.

branding/grub/cortex/theme.txt (1)

46-56: Hardcoded version string requires manual maintenance.

Line 52 contains the hardcoded version string "v1.0 Synapse". This will require manual updates for each new release. Consider:

  1. Documenting this as a required update step in release procedures, or
  2. Generating this file dynamically during the build process using version information from branding/os-release/os-release.
docs/automated-installation.md (1)

36-38: Add language specifier to fenced code blocks for better rendering.

Per static analysis hints, several code blocks are missing language specifiers (lines 36, 140, 185, 207, 310). Adding language identifiers improves syntax highlighting and accessibility.

Example fix
-```
+```text
 preseed/file=/cdrom/preseed/profiles/cortex-{profile}.preseed
branding/install-branding.sh (2)

152-155: Handle empty glob safely to avoid unexpected behavior.

If /etc/update-motd.d/ is empty or doesn't exist, the glob * won't expand and the loop will iterate once with the literal string *, causing the [ -f "$f" ] check to fail unexpectedly. While this won't break the script due to || true, it's cleaner to handle explicitly.

Suggested fix
     # Disable existing MOTD scripts
-    for f in /etc/update-motd.d/*; do
-        [ -f "$f" ] && chmod -x "$f" 2>/dev/null || true
-    done
+    if [ -d /etc/update-motd.d ]; then
+        for f in /etc/update-motd.d/*; do
+            [ -f "$f" ] && chmod -x "$f" 2>/dev/null || true
+        done
+    fi

131-134: Clarify GDM detection logic.

The condition ! command -v gdm3 &>/dev/null && ! [ -d /etc/gdm3 ] returns true when both the command is missing and the directory doesn't exist. This is correct for an OR-skip scenario due to De Morgan's law, but could be clearer for maintainability.

Consider using explicit OR logic:

Suggested refactor
-    if ! command -v gdm3 &>/dev/null && ! [ -d /etc/gdm3 ]; then
+    if ! command -v gdm3 &>/dev/null && ! [ -d /etc/gdm3 ]; then
+        # Neither gdm3 command nor config directory exists
         log_warn "GDM not found, skipping"
         return
     fi

Actually, the logic appears intentional - skip only if both are absent. Adding a comment would improve clarity.

packages/cortex-branding/DEBIAN/control (1)

6-8: Consider making plymouth a Recommends instead of Depends.

The package's postinst and prerm scripts already gracefully handle systems without Plymouth (using if command -v checks), and no content files require Plymouth to be present. Moving plymouth and plymouth-themes to Recommends would allow users to install cortex-branding for other features (OS identity, GRUB theme, wallpapers, GDM styling, MOTD) without pulling in unnecessary graphics dependencies on headless systems.

Note: The current architecture already mitigates this concern—cortex-core (the minimal profile) doesn't depend on cortex-branding at all, while cortex-full (desktop) includes both. This suggestion would add flexibility for users who want branding components without the boot splash.

Suggested change
-Depends: plymouth, plymouth-themes
+Depends:
+Recommends: plymouth, plymouth-themes, gnome-shell, gdm3
-Recommends: gnome-shell, gdm3
 Suggests: neofetch
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (2)

55-61: Add timeout and retry logic for network operation.

The curl command to download the GPG key lacks timeout options and retry logic. During ISO build, network issues could cause the build to hang indefinitely or fail unpredictably.

♻️ Suggested improvement
 # Download and install GPG key
 mkdir -p /usr/share/keyrings
-curl -fsSL https://apt.cortexlinux.com/keys/cortex-linux.gpg.asc | gpg --dearmor -o /usr/share/keyrings/cortex-linux.gpg
+curl --retry 3 --retry-delay 5 --max-time 30 -fsSL https://apt.cortexlinux.com/keys/cortex-linux.gpg.asc | gpg --dearmor -o /usr/share/keyrings/cortex-linux.gpg

196-196: Nitpick: Avoid useless use of cat.

The cat /proc/loadavg | awk pattern can be simplified.

♻️ Suggested fix
-LOAD=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
+LOAD=$(awk '{print $1, $2, $3}' /proc/loadavg)
branding/generate-assets.sh (1)

18-18: Remove unused variable.

LIGHT_CYAN is defined but never used in the script, as flagged by shellcheck.

♻️ Suggested fix
 ELECTRIC_CYAN="#06B6D4"
-LIGHT_CYAN="#22D3EE"
 DARK_BG="#0F0F23"
branding/plymouth/cortex/cortex.script (1)

139-146: Message sprites may accumulate without cleanup.

Each call to message_callback creates a new sprite without removing the previous one. While this is unlikely to cause issues during a typical boot sequence, rapid message updates could lead to visual artifacts or memory accumulation.

♻️ Suggested fix to reuse message sprite
+// Initialize message sprite once
+global.message_sprite = Sprite();
+global.message_sprite.SetOpacity(0);
+
 // Message display
 fun message_callback(text) {
     message.image = Image.Text(text, 0.6, 0.6, 0.7, 1, "Sans 11");
-    message.sprite = Sprite(message.image);
+    global.message_sprite.SetImage(message.image);
     message.x = screen_x + screen_width / 2 - message.image.GetWidth() / 2;
     message.y = screen_y + screen_height - 50;
-    message.sprite.SetPosition(message.x, message.y, 10);
+    global.message_sprite.SetPosition(message.x, message.y, 10);
+    global.message_sprite.SetOpacity(1);
 }
Makefile (2)

227-237: ARM64 targets run validation twice.

The ARM64 targets have check-deps validate as prerequisites, but then call $(MAKE) ARCH=arm64 iso-<profile> which also has these prerequisites. This causes redundant validation runs.

♻️ Suggested simplification
 # ARM64 ISO targets
 iso-arm64: iso-arm64-full

-iso-arm64-core: check-deps validate $(BUILD_DIR) $(OUTPUT_DIR)
+iso-arm64-core:
 	$(MAKE) ARCH=arm64 iso-core

-iso-arm64-full: check-deps validate $(BUILD_DIR) $(OUTPUT_DIR)
+iso-arm64-full:
 	$(MAKE) ARCH=arm64 iso-full

-iso-arm64-secops: check-deps validate $(BUILD_DIR) $(OUTPUT_DIR)
+iso-arm64-secops:
 	$(MAKE) ARCH=arm64 iso-secops

367-373: Branding package may be incomplete due to silent copy failures.

The cp ... || true patterns on lines 367-373 will silently skip missing source files, potentially producing an incomplete .deb package. Consider adding validation or removing the || true to catch missing assets.

♻️ Suggested improvement to validate sources
+	@# Validate required assets exist
+	@test -f $(BRANDING_DIR)/plymouth/cortex/cortex.plymouth || { echo "ERROR: Plymouth theme missing"; exit 1; }
+	@test -f $(BRANDING_DIR)/grub/cortex/theme.txt || { echo "ERROR: GRUB theme missing"; exit 1; }
 	@# Copy Plymouth theme
-	@cp $(BRANDING_DIR)/plymouth/cortex/* $(BUILD_DIR)/cortex-branding/usr/share/plymouth/themes/cortex/ 2>/dev/null || true
+	@cp $(BRANDING_DIR)/plymouth/cortex/* $(BUILD_DIR)/cortex-branding/usr/share/plymouth/themes/cortex/
 	@# Copy GRUB theme
-	@cp $(BRANDING_DIR)/grub/cortex/* $(BUILD_DIR)/cortex-branding/boot/grub/themes/cortex/ 2>/dev/null || true
+	@cp $(BRANDING_DIR)/grub/cortex/* $(BUILD_DIR)/cortex-branding/boot/grub/themes/cortex/
iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script (1)

55-71: Pulse animation is coupled to progress updates (may "freeze" early).
pulse_logo() is only called from progress_callback(). If boot progress updates are infrequent, the pulse won't animate. Additionally, global.progress is declared but never used.

Consider decoupling the animation using Plymouth.SetRefreshFunction(), which is the supported mechanism for independent frame-based animations in Plymouth and runs up to 50 times per second:

Proposed fix (decouple animation from progress)
 // Animation variables
 global.progress = 0;
 global.pulse_opacity = 1;
 global.pulse_direction = -1;

+fun refresh_callback() {
+    pulse_logo();
+}
+Plymouth.SetRefreshFunction(refresh_callback);
+
 // Progress callback
 fun progress_callback(duration, progress) {
+    global.progress = progress;
     if (progress_bar.original_image.GetWidth() > 0) {
         new_width = progress_bar.original_image.GetWidth() * progress;
@@
-    pulse_logo();
 }
 Plymouth.SetBootProgressFunction(progress_callback);

This applies to progress_callback() and system_update_callback() patterns.

Comment on lines +1 to +8
# Cortex Linux GDM Configuration
#
# This file configures GDM branding settings.
# Place in /etc/gdm3/greeter.dconf-defaults

[org/gnome/login-screen]
# Logo displayed on login screen
logo='/usr/share/cortex/logos/cortex-logo-light.svg'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for cortex logo files in branding
echo "=== Searching for cortex logo files ==="
fd -t f "cortex-logo" branding/

echo -e "\n=== Listing branding directory structure ==="
find branding/ -type f -name "*.svg" -o -name "*.png" | head -20

echo -e "\n=== Checking for installation scripts/hooks ==="
fd -t f "(install|hook|spec|debian|postinst)" branding/ | head -20

echo -e "\n=== Checking gdm-branding.conf directory ==="
ls -la branding/gdm/

Repository: cortexlinux/cortex-distro

Length of output: 1629


🏁 Script executed:

#!/bin/bash
# Check installation script and documentation
echo "=== install-branding.sh content ==="
cat branding/install-branding.sh

echo -e "\n=== INSTALL.md content ==="
cat branding/gdm/INSTALL.md

Repository: cortexlinux/cortex-distro

Length of output: 9247


Fix logo path and filename in GDM configuration.

Line 8 references /usr/share/cortex/logos/cortex-logo-light.svg, but this file doesn't exist in the branding assets. The actual logo file is branding/gdm/cortex-logo.svg (without the "-light" suffix), and the install-branding.sh script doesn't copy any logo to /usr/share/cortex/logos/. Update the configuration to use the correct filename and ensure the logo asset is properly installed to the referenced path, or revise the installation script to copy the logo file appropriately.

🤖 Prompt for AI Agents
In @branding/gdm/gdm-branding.conf around lines 1 - 8, The GDM config references
a non-existent logo path '/usr/share/cortex/logos/cortex-logo-light.svg'; update
the login-screen logo setting to the actual filename 'cortex-logo.svg' and
ensure the asset is installed to that path by either modifying the
install-branding.sh script to copy 'branding/gdm/cortex-logo.svg' into
'/usr/share/cortex/logos/' (creating the directory if needed) or change the
config to point to wherever install-branding.sh currently places the logo;
update the value in [org/gnome/login-screen] (logo=) and adjust
install-branding.sh accordingly so the file and path match.

Comment on lines 9 to 15
```bash
# Debian/Ubuntu
sudo apt update
sudo apt install live-build gpg python3 shellcheck debootstrap

# Verify live-build version (need >= 1:20210814)
dpkg -l live-build
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

live-build version 1:20210814 Debian Ubuntu 2025 2026 repository support

💡 Result:

Short answer: live-build version "1:20210814" is not present in current Debian or Ubuntu archives — Debian packages in stable/testing/unstable use other timestamps (examples: 1:20210407 in bullseye, 1:20230502 in bookworm, 1:20250505 in trixie and 1:20250814 in forky/sid), and Ubuntu publishes live-build as the 3.0~a57... series. See Debian and Ubuntu package pages below for details. [1][2][3]

Sources:

  • Debian live-build package listings (bullseye/bookworm/trixie/forky/sid). [1]
  • Debian live-build (source in trixie). [2]
  • Ubuntu / Launchpad live-build package versions (jammy/noble). [3]

🌐 Web query:

live-build latest stable version Debian bullseye bookworm trixie 2025 2026

💡 Result:

Summary (live-build package versions in Debian suites):

  • Trixie (stable): 1:20250505+deb13u1. [1][2]
  • Bookworm (oldstable): 1:20230502. [1][3]
  • Bullseye (oldoldstable): 1:20210407. [1][4]

Source: Debian package pages for live-build. [1][2][3][4]


🌐 Web query:

live-build package version history Debian live-build >= 1.20210814

💡 Result:

Here are Debian live-build source-package versions (chronological, versions >= 20210814) with Debian references:

  • 1:20220505 — appeared in testing (after 2021). [1]
  • 1:20230131 — migrated to testing Feb 2023. [2]
  • 1:20230502 — migrated to testing May 2023 / in bookworm. [1][3]
  • 1:20240810 — (found in bug reports / tracker as a later release). [4]
  • 1:20250225 — later unstable/testing snapshot (seen in bug tracker). [4]
  • 1:20250814 — current unstable/forky/sid source package (Debian VCS / package page). [1][5]

Sources:

  1. packages.debian.org — live-build package listings (versions by suite). [packages.debian.org live-build]. [1]
  2. Debian package tracker / news (migration 2023-02-03: 1:20230131). [tracker.debian.org]. [2]
  3. PTS / news (1:20230502 migrated to testing). [packages.qa.debian.org]. [3]
  4. Debian Bug tracker / package news entries citing versions 20240810, 20250225. [bugs.debian.org / tracker]. [4]
  5. live-build source package page (sid) and Salsa git (1:20250814). [packages.debian.org source live-build]. [5]

If you want a full changelog (full entries/dates) I can fetch the Debian changelog file (debian/changelog) and paste the entries for each version.


The version requirement live-build >= 1:20210814 does not exist in any Debian or Ubuntu repository.

The version "1:20210814" is not published in Debian (bullseye, bookworm, trixie, or sid) or Ubuntu archives. Current available versions are: 1:20210407 (bullseye), 1:20230502 (bookworm), and 1:20250505 (trixie).

Update the version requirement to a valid version that exists in the target distribution. If bullseye support is not required, change this to live-build >= 1:20230502 (bookworm+) or the appropriate version for your minimum supported Debian release.

🤖 Prompt for AI Agents
In @docs/DEVELOPERS.md around lines 9 - 15, The documented live-build version
requirement is invalid; update the version string in the DEVELOPER doc block
where the live-build install instructions and the "Verify live-build version"
check appear so it references a real release for your supported distro (e.g.,
change "live-build >= 1:20210814" to a valid version such as "live-build >=
1:20230502" for bookworm+ or to the specific minimum available in your
minimum-supported release); ensure the comment and the dpkg verification line
reflect the chosen valid version.

Comment on lines 54 to 63
```bash
# System upgrade with rollback support
cortex-upgrade --check

# GPU detection and driver status
cortex-gpu status

# Verify system integrity
cortex-verify --quick
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find tool implementations
echo "=== Searching for tool implementations ==="
find . -type f -name "*cortex*" | grep -E "(cortex-upgrade|cortex-gpu|cortex-verify)" | head -20
find . -type f \( -name "*.py" -o -name "*.js" -o -name "*.ts" -o -name "*.sh" \) | xargs grep -l "cortex-upgrade\|cortex-gpu\|cortex-verify" 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 347


🏁 Script executed:

#!/bin/bash
# Search for CLI argument parsing for these tools
echo "=== Searching for argument/flag definitions ==="
rg "add_argument.*--check|argparse|click.*--check" -t py -t js -A 2 | head -50
rg "cortex-upgrade|cortex-gpu|cortex-verify" -t py -A 5 | head -100

Repository: cortexlinux/cortex-distro

Length of output: 4796


🏁 Script executed:

#!/bin/bash
# Look for main entry points and CLI definitions
fd -t f "main.py\|cli.py\|index.js\|app.py" | xargs grep -l "cortex-upgrade\|cortex-gpu\|cortex-verify" 2>/dev/null
ls -la . | head -20
git ls-files | grep -E "cortex|cli|main" | head -30

Repository: cortexlinux/cortex-distro

Length of output: 2189


🏁 Script executed:

#!/bin/bash
# Read cortex-upgrade.py to check all arguments
echo "=== cortex-upgrade.py arguments ==="
cat packages/cortex-core/cortex-upgrade.py | grep -A 50 "parser.add_argument"

Repository: cortexlinux/cortex-distro

Length of output: 2414


🏁 Script executed:

#!/bin/bash
# Read cortex-gpu.py to check all arguments
echo "=== cortex-gpu.py arguments and subcommands ==="
cat packages/cortex-core/cortex-gpu.py | grep -A 50 "parser.add_argument\|subparsers\|add_parser"

Repository: cortexlinux/cortex-distro

Length of output: 3027


🏁 Script executed:

#!/bin/bash
# Read cortex-verify.py to check all arguments
echo "=== cortex-verify.py arguments ==="
cat packages/cortex-core/cortex-verify.py | grep -A 30 "parser.add_argument"

Repository: cortexlinux/cortex-distro

Length of output: 1299


Update command examples to match actual tool interfaces.

The documentation contains inaccurate command flags:

  • cortex-upgrade --check does not exist; use cortex-upgrade plan instead (commands: plan, execute, rollback, status)
  • cortex-verify --quick does not exist; use cortex-verify to run all checks or add flags like --json for output formatting
  • cortex-gpu status is correct and supported
🤖 Prompt for AI Agents
In @docs/QUICK-START.md around lines 54 - 63, The example commands in the docs
use incorrect flags; replace `cortex-upgrade --check` with the supported
`cortex-upgrade plan` (and mention the valid subcommands: plan, execute,
rollback, status) and change `cortex-verify --quick` to just `cortex-verify` (or
note supported output flags like `--json`) while leaving `cortex-gpu status`
as-is; update the README examples and any occurrences of `cortex-upgrade
--check` and `cortex-verify --quick` to the correct command forms
(`cortex-upgrade plan` and `cortex-verify`) and optionally add a brief note
about `--json` output for `cortex-verify`.

Comment on lines 6 to 21
set -e

case "$1" in
remove|upgrade|deconfigure)
# Restore default Plymouth theme
if command -v plymouth-set-default-theme &>/dev/null; then
plymouth-set-default-theme -R 2>/dev/null || true
fi

# Re-enable default MOTD scripts
if [ -d /etc/update-motd.d ]; then
for f in /etc/update-motd.d/??-* ; do
chmod +x "$f" 2>/dev/null || true
done
fi
;;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Find the Debian package files related to cortex-branding
find packages/cortex-branding/DEBIAN -type f | head -20

Repository: cortexlinux/cortex-distro

Length of output: 187


🏁 Script executed:

# Check the postinst script to see what state is actually persisted
if [ -f packages/cortex-branding/DEBIAN/postinst ]; then
    cat -n packages/cortex-branding/DEBIAN/postinst
fi

Repository: cortexlinux/cortex-distro

Length of output: 2625


🏁 Script executed:

# Check for any other relevant scripts (preinst, postrm)
ls -la packages/cortex-branding/DEBIAN/

Repository: cortexlinux/cortex-distro

Length of output: 350


🌐 Web query:

plymouth-set-default-theme -R flag documentation

💡 Result:

The -R flag is --rebuild-initrd. It tells plymouth-set-default-theme to rebuild the initial ramdisk (initrd) after changing the Plymouth theme (necessary because Plymouth is loaded from initrd). [1][2]

Example: sudo plymouth-set-default-theme -R THEME. [1]

Sources:
[1] Debian man page — plymouth-set-default-theme.
[2] Mankier / man page summary for plymouth-set-default-theme.


🌐 Web query:

what does plymouth-set-default-theme -R do restore default theme

💡 Result:

  • -R (or --rebuild-initrd) tells plymouth-set-default-theme to rebuild the initrd so the chosen theme is embedded into the initial ramdisk (necessary for the theme to actually appear at boot). [1][2]

  • It does not reset the theme to the default. Use -r (or --reset) to reset to the default theme; use -R after changing or resetting to ensure the initrd is rebuilt. [1][2]

Sources: [1] Debian manpage for plymouth-set-default-theme. [2] Arch/manpage (mankier) for plymouth-set-default-theme.


🌐 Web query:

plymouth-set-default-theme command syntax requires theme argument

💡 Result:

The script requires a theme name when you intend to change the theme. Usage (from the man page):

  • Show current theme: plymouth-set-default-theme
  • List available themes: plymouth-set-default-theme -l. [1]
  • Set a theme: sudo plymouth-set-default-theme THEME (optionally add -R or --rebuild-initrd to rebuild initrd). [1][2]

Note: On Ubuntu the recommended method is update-alternatives --config default.plymouth to choose the default.plymouth file. [2]

Sources:
[1] plymouth-set-default-theme man page. [2] Ask Ubuntu — how to install/choose Plymouth themes.


🌐 Web query:

what happens plymouth-set-default-theme -R without theme name error

💡 Result:

If you run plymouth-set-default-theme -R without giving a THEME, the command uses the currently selected theme and rebuilds the initrd (i.e. regenerates the initial ramdisk for that current theme). The manpage documents that invoking with no parameters shows the current theme, and -R/--rebuild-initrd rebuilds the initrd. [1][2]

Sources:

  • plymouth-set-default-theme man page (description and -R option). [1]
  • Arch/manpage copy (synopsis/behavior). [2]

Removal path doesn't reliably restore Plymouth theme and indiscriminately re-enables MOTD scripts.

  • plymouth-set-default-theme -R (Line 12) rebuilds the initrd for the currently set theme but does not restore the theme that existed before the package was installed. The package should either save the previous theme in postinst and restore it here, or use -r -R to reset to the system default and rebuild.
  • The loop chmod +x /etc/update-motd.d/??-* (Lines 17-19) re-enables all scripts indiscriminately, but postinst selectively disables non-cortex scripts (postinst lines 34–39). Without tracking which scripts were actually disabled by this package, prerm cannot safely restore the original state.
Recommended approach (requires pairing with postinst to persist state)
-        if command -v plymouth-set-default-theme &>/dev/null; then
-            plymouth-set-default-theme -R 2>/dev/null || true
-        fi
+        if command -v plymouth-set-default-theme &>/dev/null; then
+            if [ -f /var/lib/cortex-branding/plymouth-theme.prev ]; then
+                prev_theme="$(cat /var/lib/cortex-branding/plymouth-theme.prev)"
+                plymouth-set-default-theme "$prev_theme" -R 2>/dev/null || true
+                rm -f /var/lib/cortex-branding/plymouth-theme.prev
+            fi
+        fi
@@
-        if [ -d /etc/update-motd.d ]; then
-            for f in /etc/update-motd.d/??-* ; do
-                chmod +x "$f" 2>/dev/null || true
-            done
-        fi
+        # Re-enable only scripts we disabled (tracked in postinst)
+        if [ -f /var/lib/cortex-branding/motd-disabled.list ]; then
+            while IFS= read -r f; do
+                [ -e "$f" ] && chmod +x "$f" 2>/dev/null || true
+            done < /var/lib/cortex-branding/motd-disabled.list
+            rm -f /var/lib/cortex-branding/motd-disabled.list
+        fi
🤖 Prompt for AI Agents
In @packages/cortex-branding/DEBIAN/prerm around lines 6 - 21, The prerm
currently calls "plymouth-set-default-theme -R" which only rebuilds initrd for
the current theme; change the flow so the package either saves the prior theme
in postinst (e.g., write the original theme name to a persistent state file) and
then prerm reads that state and restores it, or replace "-R" with "-r -R" to
reset to system default and rebuild; likewise, stop indiscriminately chmod'ing
all /etc/update-motd.d/??-* scripts — have postinst record exactly which MOTD
scripts this package disabled (e.g., write their filenames to a state file) and
make prerm iterate only over that recorded list to re-enable (chmod +x) those
files, leaving other scripts untouched (refer to the postinst logic that
disables non-cortex scripts in lines 34–39 for exact criteria).

Comment on lines +1 to +20
Package: cortex-core
Version: 0.1.0
Section: metapackages
Priority: optional
Architecture: all
Depends: cortex-archive-keyring, cortex-upgrade, cortex-gpu, cortex-verify
Recommends: neofetch, htop, curl, wget, git
Suggests: cortex-full, cortex-secops
Maintainer: Cortex Linux Team <team@cortexlinux.com>
Homepage: https://cortexlinux.com
Description: Cortex Linux core meta-package with CLI tools
This meta-package installs the core Cortex Linux components:
.
- cortex-upgrade: Safe system upgrades with LVM/Btrfs/ZFS snapshot rollback
- cortex-gpu: GPU detection, NVIDIA/AMD driver enablement, Secure Boot MOK setup
- cortex-verify: Offline integrity verification
- cortex-archive-keyring: GPG keyring for Cortex APT repository trust
.
Install this package to get the essential Cortex Linux tools on any
Debian or Ubuntu system.
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the dependency packages in this repository
for pkg in cortex-archive-keyring cortex-upgrade cortex-gpu cortex-verify cortex-full cortex-secops; do
  echo "Searching for package: $pkg"
  fd -t d "^${pkg}$" packages/ || echo "  Not found in packages/"
done

Repository: cortexlinux/cortex-distro

Length of output: 374


🏁 Script executed:

#!/bin/bash
# Search more broadly for the missing packages
echo "=== Searching entire repository for package definitions ==="
for pkg in cortex-upgrade cortex-gpu cortex-verify; do
  echo ""
  echo "Looking for $pkg:"
  fd -t d "$pkg" . 2>/dev/null | head -20
done

echo ""
echo "=== Checking git ls-files for these package names ==="
git ls-files | grep -E "(cortex-upgrade|cortex-gpu|cortex-verify)" | head -20

Repository: cortexlinux/cortex-distro

Length of output: 756


🏁 Script executed:

#!/bin/bash
# Check if cortex-gpu-amd and cortex-gpu-nvidia have proper control files
echo "=== Checking GPU package control files ==="
for dir in packages/cortex-gpu-amd packages/cortex-gpu-nvidia; do
  if [ -f "$dir/DEBIAN/control" ]; then
    echo "Found: $dir/DEBIAN/control"
    sed -n '1,3p' "$dir/DEBIAN/control"
  elif [ -f "$dir/debian/control" ]; then
    echo "Found: $dir/debian/control"
    sed -n '1,3p' "$dir/debian/control"
  fi
done

echo ""
echo "=== Searching for cortex-upgrade and cortex-verify package definitions ==="
find packages -name "control" -type f -exec grep -l "Package: cortex-upgrade\|Package: cortex-verify" {} \;

echo ""
echo "=== List all packages with DEBIAN or debian control files ==="
find packages -name "control" -type f | sed 's|/[^/]*/control||' | sort -u

Repository: cortexlinux/cortex-distro

Length of output: 655


Fix critical dependency declaration on line 6.

The Depends field declares 4 packages, but only 1 exists in the repository:

  • cortex-archive-keyring — exists
  • cortex-upgrade — does not exist
  • cortex-gpu — does not exist (repository has cortex-gpu-amd and cortex-gpu-nvidia instead)
  • cortex-verify — does not exist

Missing or incorrectly named dependencies will cause installation failures. Update line 6 to declare only packages that exist, or replace cortex-gpu with the appropriate GPU variant(s) if this is a virtual package that should be provided elsewhere.

🤖 Prompt for AI Agents
In @packages/cortex-core/DEBIAN/control around lines 1 - 20, The control file's
Depends field lists non-existent packages causing install failures; open the
DEBIAN control and update the Depends line to reference only existing packages
(keep cortex-archive-keyring), remove or replace cortex-upgrade and
cortex-verify with their correct package names if they exist, and replace
cortex-gpu with the actual GPU package(s) (e.g., cortex-gpu-amd and/or
cortex-gpu-nvidia) or change it to a Suggests/Provides if it’s meant to be
virtual; ensure the Depends field remains a comma-separated list and adjust
Recommends/Suggests accordingly if you move packages out of Depends.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @Makefile:
- Around line 194-201: The Makefile rule currently copies preseed and
provisioning files using cp with failures suppressed (commands with 2>/dev/null
|| true), which hides missing files; update the rule to perform the copies
normally and then explicitly validate that expected files exist in
$(BUILD_DIR)/$(1)/config/includes.binary/preseed/,
$(BUILD_DIR)/$(1)/config/includes.binary/preseed/profiles/,
$(BUILD_DIR)/$(1)/config/includes.binary/preseed/partitioning/ and
$(BUILD_DIR)/$(1)/config/includes.binary/provisioning/ (use shell tests like [
-e ] or glob checks) and if any required files from $(PRESEED_DIR) or
$(PROVISION_DIR) are missing emit an error message and exit non‑zero so the
build fails early; keep references to the existing variables PRESEED_DIR,
PROVISION_DIR, BUILD_DIR and the copy commands to locate where to add the
checks.
- Around line 205-206: The mv invocation that moves the generated ISO currently
swallows errors via `2>/dev/null || true`, masking failures; remove the
redirection and the `|| true` and instead ensure the move reports failures and
fails the build (e.g., let mv return a non-zero exit code or on failure print a
clear error and exit 1). Update the line with the `mv
$(BUILD_DIR)/$(1)/live-image-$(ARCH).hybrid.iso
$(OUTPUT_DIR)/$(ISO_NAME)-$(1)-$(ISO_VERSION)-$(ARCH).iso` invocation so any
failure is propagated (or explicitly handled by printing an error mentioning the
ISO name and exiting non-zero) to prevent false-success builds.
- Around line 160-177: The Makefile silences copy failures with "2>/dev/null ||
true" causing missing branding/hook/bootloader assets to go unnoticed; update
the copy blocks referencing BUILD_DIR and ISO_DIR (the package-lists cp, hooks
cp, includes.chroot/includes.binary/bootloaders cp blocks) to validate source
existence before copying and let failures surface: remove the "2>/dev/null ||
true" for critical assets, replace with explicit existence checks (e.g. if [ -d
"$(ISO_DIR)/live-build/config/includes.chroot" ]; then cp -r ... || { echo >&2
"Failed to copy includes.chroot"; exit 1; }; else echo >&2 "Missing
includes.chroot"; exit 1; fi), and decide which noncritical assets may log a
warning instead of exiting so builds fail visibly when required branding or
bootloader files are absent.

In @scripts/build.sh:
- Around line 180-197: In scripts/build.sh, validate the required branding
assets before copying instead of silencing errors: check that all expected files
(e.g., "${PROJECT_ROOT}/branding/grub/cortex/theme.txt" and the specific PNGs
like background.png and any other required *.png) exist and log a clear error
then exit non‑zero if any required file is missing; replace the silent cp
"${PROJECT_ROOT}/branding/grub/cortex/"*.png 2>/dev/null || true with an
explicit existence check and selective copy of known filenames (or iterate the
glob after confirming it expands) so missing files cause a clear failure, and
avoid using a broad wildcard when copying to
config/includes.chroot/boot/grub/themes/cortex—use the validated list of files
to copy and use consistent logging (log error + exit) on validation failures
rather than mixing silent suppression and hard failures.
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4e631aa and 82ebb7a.

📒 Files selected for processing (8)
  • .gitignore
  • Makefile
  • iso/live-build/auto/build
  • iso/live-build/auto/clean
  • iso/live-build/auto/config
  • iso/live-build/config/bootloaders/grub-pc/config.cfg
  • iso/live-build/config/package-lists/cortex-core.list.chroot
  • scripts/build.sh
💤 Files with no reviewable changes (4)
  • iso/live-build/auto/clean
  • iso/live-build/auto/build
  • iso/live-build/config/package-lists/cortex-core.list.chroot
  • iso/live-build/auto/config
🚧 Files skipped from review as they are similar to previous changes (2)
  • iso/live-build/config/bootloaders/grub-pc/config.cfg
  • .gitignore
🧰 Additional context used
🪛 checkmake (0.2.2)
Makefile

[warning] 52-52: Target body for "help" exceeds allowed length of 5 (45).

(maxbodylength)


[warning] 136-136: Target body for "lint" exceeds allowed length of 5 (6).

(maxbodylength)


[warning] 241-241: Target body for "test" exceeds allowed length of 5 (14).

(maxbodylength)


[warning] 258-258: Target body for "clean" exceeds allowed length of 5 (7).

(maxbodylength)


[warning] 321-321: Target body for "config" exceeds allowed length of 5 (7).

(maxbodylength)


[warning] 320-320: Missing required phony target "clean"

(minphony)


[warning] 320-320: Missing required phony target "test"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (1)
Makefile (1)

100-112: LGTM! Dependency checking is thorough and user-friendly.

The dependency validation logic properly checks for:

  • Required commands using command -v
  • live-build version compatibility with Debian Bookworm
  • Python 3.11+ with graceful degradation (warning vs error)

The implementation provides clear, actionable error messages to help users resolve dependency issues.

Your Name added 4 commits January 12, 2026 00:58
- Consolidated validation checks into a single build script.
- Updated dependency checks and validation functions for better error handling.
- Enhanced preseed and provisioning file management.
- Streamlined ISO build process with clearer output and logging.
- Improved branding package creation with better file handling and checks.
- Removed obsolete first-boot provisioning script and integrated its functionality into the build process.
- Added support for generating SBOM (Software Bill of Materials) during builds.
- Updated hooks and configuration scripts for better compatibility and error handling.
- Added support for multiple ISO profiles (core, full) in the build process.
- Introduced a validation job to check dependencies before building.
- Created a dedicated job for building the branding package.
- Updated workflow to include SBOM generation and improved artifact handling.
- Enhanced release process to include combined checksums and branding package downloads.
- Improved logging and output management for better traceability.
…treamline build process

- Added installation of git and sudo in the validation and build jobs.
- Consolidated dependency installation steps for improved clarity.
- Introduced a containerized environment using Debian Bookworm for all jobs.
- Removed redundant steps and improved overall workflow efficiency.
…lation

- Added 'make' to the list of packages installed in the build process.
- Improved clarity and completeness of the dependency management step.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 20

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 44-60: The container jobs "validate" (runs 'make validate') and
the Branding Package job (runs 'make branding-package') install git/shellcheck
but not GNU make, causing the make invocations to fail; update the
package-install step(s) named "Install git" in the 'validate' job and the
corresponding install step in the Branding Package job to include make (e.g.,
add 'make' or 'build-essential' to the apt-get install -y list) so that the
subsequent 'make validate' and 'make branding-package' commands succeed.
- Around line 27-39: The workflow_dispatch input profile is unused and
misleading because jobs build-iso and test-iso currently run a fixed matrix
([core, full]) and ignore secops; update the jobs to honor the workflow_dispatch
input by filtering the matrix on manual runs (or by generating the matrix from
the input). Specifically, in the build-iso and test-iso jobs, reference
github.event.workflow_dispatch.inputs.profile and add an if condition to skip
matrix entries when the job was manually triggered (e.g., if: github.event_name
!= 'workflow_dispatch' ||
contains(split(github.event.workflow_dispatch.inputs.profile, ','),
matrix.profile)), or alternatively compute the matrix dynamically from the input
via fromJSON/values so secops can be included when provided; make sure to update
the matrix key name (matrix.profile) used by those jobs so selected profiles
actually run.
- Around line 19-27: The pull_request path filter currently omits the workflow
itself so PRs that only change .github/workflows/build-iso.yml won’t trigger CI;
update the pull_request: paths list (the pull_request.paths key in the workflow)
to include the workflow file (for example add '.github/workflows/build-iso.yml'
or a broader '.github/workflows/**' pattern), or remove the paths filter
entirely so workflow changes trigger the workflow; edit the build-iso.yml to
modify the pull_request.paths entry accordingly.
- Around line 235-236: Replace the GitHub Action reference to
softprops/action-gh-release@v1 with the v2 release to avoid Node 16 usage;
update the workflow step that currently uses softprops/action-gh-release@v1 to
softprops/action-gh-release@v2 (or a specific v2.x tag such as v2.5.0) so the
action runs on Node 20+.

In @iso/live-build/config/hooks/live/0100-cortex-config.hook.chroot:
- Around line 133-163: The unit can still run and fail if the first-boot script
is absent and calling systemctl enable in a chroot is unreliable; update the
unit (cortex-first-boot.service) to add a
ConditionPathExists=/opt/cortex/provisioning/first-boot.sh in addition to the
existing ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete so
the unit won’t be scheduled when the script is missing, and replace the runtime
systemctl enable call with creating the multi-user.target symlink yourself
(create a symlink from the cortex-first-boot.service unit into
multi-user.target.wants) so the unit is enabled in the offline/chroot build
environment without requiring a running systemd.

In @iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot:
- Around line 9-12: The build hook currently uses non-deterministic network
fetches and only sets "set -e"; change the script to be failure-safe and
deterministic by adding "set -euo pipefail" at the top and replacing the remote
key download with a local, versioned key file shipped in the tree (e.g., use a
bundled file like cortex-apt-key.gpg and import it via apt-key add or gpg
--dearmor into /usr/share/keyrings), update the repository entry to reference
the local keyring, and ensure all commands that read from pipes will fail on
errors so failures are clear and reproducible.
- Around line 93-104: The GRUB_DISTRIBUTOR update uses `sed -i
's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub ||
echo ...` which fails to append when no match is present because `sed` exits 0;
change the logic to explicitly test for existence (e.g., `if grep -q
"^GRUB_DISTRIBUTOR=" /etc/default/grub; then sed -i
's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub;
else echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub; fi`) so that
`GRUB_DISTRIBUTOR` is replaced if present and appended if missing.
- Around line 49-63: This hook redundantly adds the apt.cortexlinux.com
repository and a different keyring (cortex-linux.gpg) which conflicts with the
canonical repo.cortexlinux.com/apt configured in 0100-cortex-config.hook.chroot
(which uses cortex-archive-keyring.gpg); remove the block that creates
/usr/share/keyrings/cortex-linux.gpg and the echo writing "deb
[signed-by=/usr/share/keyrings/cortex-linux.gpg] https://apt.cortexlinux.com
stable main" so only the canonical repo (repo.cortexlinux.com/apt with
cortex-archive-keyring.gpg) remains, or if consolidation is required replace the
apt.cortexlinux.com lines to match the repo.cortexlinux.com/apt entry and use
cortex-archive-keyring.gpg.

In @iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot:
- Around line 8-44: The hook must skip GNOME/GDM steps when dconf isn't present
to avoid failing non-GNOME profiles; wrap the GNOME-specific sections (creation
of /etc/live/config.conf.d/cortex-gnome.conf, /etc/gdm3/daemon.conf and
/etc/gdm3/custom.conf, and the systemctl set-default graphical.target call) in a
conditional that checks for dconf (e.g. if command -v dconf >/dev/null 2>&1;
then ... fi), and replace the unconditional dconf update call with the same
guarded call pattern (mirroring the existing conditional used for
glib-compile-schemas).

In @iso/provisioning/first-boot.sh:
- Around line 41-58: check_already_complete calls log_info before logging is
initialized which can fail because LOG_DIR/LOG_FILE may not exist; move logging
initialization (create LOG_DIR and LOG_FILE) before any log_info calls or ensure
check_already_complete creates/validates LOG_DIR and LOG_FILE itself.
Specifically, either invoke init_logging() before calling check_already_complete
or add the same mkdir -p "${LOG_DIR}" && touch "${LOG_FILE}" && chmod 640
"${LOG_FILE}" steps into check_already_complete so log_info can safely write;
reference symbols: check_already_complete, init_logging, log_info, LOG_DIR,
LOG_FILE, STATE_FILE.
- Around line 471-484: The cleanup() function uses rm -f /var/log/installer/*
which can return non-zero if any entries are directories (and under set -e would
abort); change that to safely remove only files or tolerate directories: either
replace that line with a find invocation (e.g. use find /var/log/installer
-mindepth 1 -maxdepth 1 -type f -exec rm -f -- {} +) to delete only regular
files, or use rm -rf -- /var/log/installer/* || true to force recursive removal
and avoid exiting on non-zero. Ensure you update the line inside cleanup() where
rm -f /var/log/installer/* appears.
- Around line 97-131: Several places assume the cortex user exists and will
hard-fail; add an existence guard (e.g., check id -u cortex) before performing
user-specific actions in setup_password_change (guard the chage -d 0 cortex), in
full_desktop_setup (guard the groups cortex and usermod -aG docker cortex
calls), and in secops_hardening (guard writes to
/home/cortex/SECURITY-NOTICE.txt and chown cortex:cortex). If the check fails,
skip the user-specific steps and log a notice instead so the script remains
idempotent and tolerant of systems where the cortex user isn’t present.
- Around line 412-449: In setup_cortex_repository: ensure the keyring directory
exists before writing by running mkdir -p for the local variable keyring_dir,
stop piping curl directly into gpg and instead download the key to a temporary
file, verify its fingerprint against the expected value before importing,
dearmor and write the final key to ${keyring_dir}/cortex-linux.gpg, and set its
permissions to 0644 (chmod 644 "${keyring_dir}/cortex-linux.gpg"); keep using
the existing sources_file variable and existing apt-get update logic once the
key is validated and installed.
- Around line 132-184: In setup_ssh, the SSH hardening block is contradictory
and uses the wrong service name: the comment says "Disable password
authentication for root" while the file sets PasswordAuthentication yes, and the
reload checks for sshd service; change PasswordAuthentication to no (or update
the comment to accurately reflect that password auth remains enabled if
intended) so the config and comment align, and replace systemctl
is-active/reload checks referencing sshd with the Debian-standard service name
ssh (i.e., use systemctl is-active --quiet ssh and systemctl reload ssh ||
true); refer to the setup_ssh function and the sshd_config variable to locate
the changes.

In @repository/scripts/repo-manage.sh:
- Around line 136-143: The script currently uses touch "${arch_dir}/Packages"
which can leave stale content if the file already exists; change it to truncate
the file instead (overwrite with an empty file) when dpkg-scanpackages is not
run so Packages is emptied rather than preserved; update the branch in
repo-manage.sh that handles the else path after dpkg-scanpackages (the block
that currently calls touch "${arch_dir}/Packages") to create an empty/truncated
"${arch_dir}/Packages" before gzip -9 -k -f runs.

In @scripts/build.sh:
- Around line 94-154: The script currently treats dpkg-deb as optional in
cmd_check_deps but branding-package needs it; either mark dpkg-deb as required
by changing its check in cmd_check_deps to mirror other required checks (use
check_command dpkg-deb || failed=1 and ensure the final failed logic returns
non-zero), or add a dedicated runtime check inside cmd_branding_package that
tests command -v dpkg-deb and exits/fails with a clear error message if missing;
update references to the failed variable and error/warn calls so the failure
path is deterministic and the message explains that branding-package requires
dpkg-deb.
- Around line 67-76: The function copy_glob_if_exists has an unquoted glob and
uses cp without -r which breaks on filenames with spaces, directories, and
creates flaky builds; update it to safely expand globs into an array (or enable
nullglob), check if the array is non-empty, and iterate over matches quoting
each item when copying, and use cp -a (or cp -r --) to preserve directories and
handle recursive copies; keep references to the function name
copy_glob_if_exists and the variables pattern and dest when making these
changes.
- Around line 570-572: The live-build commands use unconditional sudo which
fails when running as root; update both invocations of "lb build" and "lb clean"
to run conditionally based on EUID: replace each `sudo lb build` and `sudo lb
clean` with an EUID check that runs `lb build`/`lb clean` directly if $EUID is
0, otherwise prefixes with sudo (e.g., if [[ $EUID -eq 0 ]]; then lb build; else
sudo lb build; fi and same pattern for lb clean).
🟡 Minor comments (4)
packages/cortex-branding/DEBIAN/prerm-15-20 (1)

15-20: Re-enabling every /etc/update-motd.d/??-* script can unintentionally override admin/system intent.

If you can’t restore prior chmod state, consider only re-enabling known distro defaults (or only undo what your postinst changed).

scripts/build.sh-600-610 (1)

600-610: SBOM generation should create the output dir (and consider not chmod +x-ing repo files during builds).

At least mkdir -p "${OUTPUT_DIR}/sbom" before invoking the generator.

iso/provisioning/first-boot.sh-361-389 (1)

361-389: Hardcoded FDE device path (/dev/sda3) is risky and profile-dependent.

This guidance appears only for the secops profile (when REQUIRE_FDE_PASSPHRASE_CHANGE=true), but assumes a fixed partition scheme. On systems installed to different disks (nvme0n1, /dev/sdb, etc.), the command will fail. Consider either:

  • Detecting the actual encrypted device at runtime (e.g., cryptsetup status cortex-sec-vg | grep device)
  • Injecting the device path via preseed/profile configuration
  • Documenting the assumption that installations must use /dev/sda
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot-124-147 (1)

124-147: Warn if GDM logo asset is missing (dconf will reference a non-existent file).

Line 135 hardcodes /usr/share/pixmaps/cortex-logo.png with no existence check (unlike wallpapers/plymouth/grub checks). Add a warning (or install it here) to avoid silent broken branding.

🧹 Nitpick comments (3)
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (1)

263-266: Don’t let initramfs update break the ISO build unexpectedly.

Even if update-initramfs exists (Line 264), it can fail depending on kernel/initramfs state in the chroot. Consider making it non-fatal or gating on presence of kernels.

iso/live-build/config/hooks/live/0100-cortex-config.hook.chroot (2)

148-153: Hardening flags are explicitly disabled (verify this is intentional).

Lines 149-151 set NoNewPrivileges=false, ProtectSystem=false, ProtectHome=false. If the provisioning script truly needs broad writes, that’s fine, but then the “security hardening” intent is undermined.

If you want hardening here, consider NoNewPrivileges=true at minimum, and ProtectSystem=full + ReadWritePaths= for only the directories the script must mutate.


168-173: Service-existence check may be ineffective; confirm systemctl list-unit-files <unit> behavior.

Depending on systemd version, systemctl list-unit-files "$svc" can exit 0 even if the unit isn’t present, which defeats the guard.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 82ebb7a and aac8af0.

📒 Files selected for processing (12)
  • .github/workflows/build-iso.yml
  • Makefile
  • branding/install-branding.sh
  • iso/live-build/config/hooks/live/0100-cortex-config.hook.chroot
  • iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot
  • iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot
  • iso/live-build/config/includes.chroot/usr/lib/cortex/firstboot.sh
  • iso/provisioning/first-boot.sh
  • packages/cortex-branding/DEBIAN/postinst
  • packages/cortex-branding/DEBIAN/prerm
  • repository/scripts/repo-manage.sh
  • scripts/build.sh
💤 Files with no reviewable changes (1)
  • iso/live-build/config/includes.chroot/usr/lib/cortex/firstboot.sh
🚧 Files skipped from review as they are similar to previous changes (1)
  • branding/install-branding.sh
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

236-236: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 checkmake (0.2.2)
Makefile

[warning] 46-46: Target body for "help" exceeds allowed length of 5 (44).

(maxbodylength)


[warning] 204-204: Target body for "config" exceeds allowed length of 5 (7).

(maxbodylength)


[warning] 16-16: Missing required phony target "clean"

(minphony)


[warning] 16-16: Missing required phony target "test"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (3)
packages/cortex-branding/DEBIAN/prerm (1)

6-21: plymouth-set-default-theme -R without specifying a theme may not restore the “default” theme as intended.

If the goal is “undo cortex theme,” consider restoring the previously active theme (stored during postinst) or explicitly setting a known baseline theme for Debian Bookworm before running -R.

Makefile (1)

16-21: Makefile structure is clear and consistent with script-driven build.

(Optional) checkmake warnings about long help/config bodies are cosmetic and can be ignored unless you enforce that linter.

Also applies to: 46-91, 204-211

iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot (1)

25-44: No action needed. The GDM autologin configuration and graphical.target change are already isolated to the live environment. The installed system is created fresh via debian-installer and preseed, which do not copy /etc/gdm3/ or other live-only configurations. If GNOME is installed on the target system (e.g., via cortex-full.preseed), it will be installed from packages with default GDM settings, not inheriting the live autologin configuration.

Likely an incorrect or invalid review comment.

Comment on lines 19 to 27
pull_request:
branches: [main]
paths:
- 'iso/**'
- 'branding/**'
- 'packages/**'
- 'scripts/**'
- 'Makefile'
workflow_dispatch:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

PR path filter omits the workflow file, so CI won’t run when only the workflow changes.

Push includes .github/workflows/build-iso.yml (Line 18) but pull_request does not (Lines 21-27).

Proposed fix
   pull_request:
     branches: [main]
     paths:
       - 'iso/**'
       - 'branding/**'
       - 'packages/**'
       - 'scripts/**'
       - 'Makefile'
+      - '.github/workflows/build-iso.yml'
🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 19 - 27, The pull_request path
filter currently omits the workflow itself so PRs that only change
.github/workflows/build-iso.yml won’t trigger CI; update the pull_request: paths
list (the pull_request.paths key in the workflow) to include the workflow file
(for example add '.github/workflows/build-iso.yml' or a broader
'.github/workflows/**' pattern), or remove the paths filter entirely so workflow
changes trigger the workflow; edit the build-iso.yml to modify the
pull_request.paths entry accordingly.

Comment on lines +133 to 163
# Cortex first-boot service (canonical version from iso/provisioning/)
# Note: The actual first-boot.sh is deployed via preseed to /opt/cortex/provisioning/
cat > /etc/systemd/system/cortex-first-boot.service << 'EOF'
[Unit]
Description=Cortex Linux First Boot Provisioning
After=network-online.target
Wants=network-online.target
ConditionPathExists=!/etc/cortex/.firstboot-complete
Description=Cortex Linux First-Boot Provisioning
Documentation=https://github.com/cortexlinux/cortex-distro
After=network-pre.target systemd-resolved.service
Before=network.target getty@tty1.service display-manager.service
Wants=network-pre.target
ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete
[Service]
Type=oneshot
ExecStart=/usr/lib/cortex/firstboot.sh
ExecStartPost=/usr/bin/touch /etc/cortex/.firstboot-complete
ExecStart=/opt/cortex/provisioning/first-boot.sh
RemainAfterExit=yes
TimeoutSec=600
NoNewPrivileges=false
ProtectSystem=false
ProtectHome=false
PrivateTmp=true
StandardOutput=journal+console
StandardError=journal+console
SyslogIdentifier=cortex-first-boot
[Install]
WantedBy=multi-user.target
EOF

# Enable first-boot service
systemctl enable cortex-firstboot.service
systemctl enable cortex-first-boot.service

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

First-boot unit: ensure it won’t run (and fail) on live boot, and don’t rely on systemctl enable working in chroot.

  • The unit only checks !/opt/cortex/provisioning/.first-boot-complete (Line 142). If /opt/cortex/provisioning/first-boot.sh isn’t present in the live environment, it’ll still attempt to start and error.
  • systemctl enable ... in a build chroot (Line 162) is a common failure mode unless done in offline mode (or by creating the symlink yourself).
Proposed fix (safer conditions + enable without needing a running systemd)
 [Unit]
@@
-ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete
+ConditionPathExists=/opt/cortex/provisioning/first-boot.sh
+ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete
-# Enable first-boot service
-systemctl enable cortex-first-boot.service
+# Enable first-boot service (avoid requiring a running systemd in chroot)
+mkdir -p /etc/systemd/system/multi-user.target.wants
+ln -sf ../cortex-first-boot.service /etc/systemd/system/multi-user.target.wants/cortex-first-boot.service
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Cortex first-boot service (canonical version from iso/provisioning/)
# Note: The actual first-boot.sh is deployed via preseed to /opt/cortex/provisioning/
cat > /etc/systemd/system/cortex-first-boot.service << 'EOF'
[Unit]
Description=Cortex Linux First Boot Provisioning
After=network-online.target
Wants=network-online.target
ConditionPathExists=!/etc/cortex/.firstboot-complete
Description=Cortex Linux First-Boot Provisioning
Documentation=https://github.com/cortexlinux/cortex-distro
After=network-pre.target systemd-resolved.service
Before=network.target getty@tty1.service display-manager.service
Wants=network-pre.target
ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete
[Service]
Type=oneshot
ExecStart=/usr/lib/cortex/firstboot.sh
ExecStartPost=/usr/bin/touch /etc/cortex/.firstboot-complete
ExecStart=/opt/cortex/provisioning/first-boot.sh
RemainAfterExit=yes
TimeoutSec=600
NoNewPrivileges=false
ProtectSystem=false
ProtectHome=false
PrivateTmp=true
StandardOutput=journal+console
StandardError=journal+console
SyslogIdentifier=cortex-first-boot
[Install]
WantedBy=multi-user.target
EOF
# Enable first-boot service
systemctl enable cortex-firstboot.service
systemctl enable cortex-first-boot.service
# Cortex first-boot service (canonical version from iso/provisioning/)
# Note: The actual first-boot.sh is deployed via preseed to /opt/cortex/provisioning/
cat > /etc/systemd/system/cortex-first-boot.service << 'EOF'
[Unit]
Description=Cortex Linux First-Boot Provisioning
Documentation=https://github.com/cortexlinux/cortex-distro
After=network-pre.target systemd-resolved.service
Before=network.target getty@tty1.service display-manager.service
Wants=network-pre.target
ConditionPathExists=/opt/cortex/provisioning/first-boot.sh
ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete
[Service]
Type=oneshot
ExecStart=/opt/cortex/provisioning/first-boot.sh
RemainAfterExit=yes
TimeoutSec=600
NoNewPrivileges=false
ProtectSystem=false
ProtectHome=false
PrivateTmp=true
StandardOutput=journal+console
StandardError=journal+console
SyslogIdentifier=cortex-first-boot
[Install]
WantedBy=multi-user.target
EOF
# Enable first-boot service (avoid requiring a running systemd in chroot)
mkdir -p /etc/systemd/system/multi-user.target.wants
ln -sf ../cortex-first-boot.service /etc/systemd/system/multi-user.target.wants/cortex-first-boot.service
🤖 Prompt for AI Agents
In @iso/live-build/config/hooks/live/0100-cortex-config.hook.chroot around lines
133 - 163, The unit can still run and fail if the first-boot script is absent
and calling systemctl enable in a chroot is unreliable; update the unit
(cortex-first-boot.service) to add a
ConditionPathExists=/opt/cortex/provisioning/first-boot.sh in addition to the
existing ConditionPathExists=!/opt/cortex/provisioning/.first-boot-complete so
the unit won’t be scheduled when the script is missing, and replace the runtime
systemctl enable call with creating the multi-user.target symlink yourself
(create a symlink from the cortex-first-boot.service unit into
multi-user.target.wants) so the unit is enabled in the offline/chroot build
environment without requiring a running systemd.

Comment on lines 9 to 12
set -e

echo "Installing Cortex Linux branding..."

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major

Make the APT key/repo setup deterministic and failure-safe (avoid network fetch in build hook).

Line 57 downloads a signing key during the build; that’s brittle (network/endpoint changes) and a supply-chain risk. Also, with set -e (Line 9) and no pipefail, failures can be confusing in pipelines.

Proposed direction (ship key in tree + safer bash settings)
-set -e
+set -euo pipefail
-# Download and install GPG key
-mkdir -p /usr/share/keyrings
-curl -fsSL https://apt.cortexlinux.com/keys/cortex-linux.gpg.asc | gpg --dearmor -o /usr/share/keyrings/cortex-linux.gpg
+mkdir -p /usr/share/keyrings
+# Prefer: include the armored key in the repo and install it from includes.chroot (no network).
+# If you must download here, at least verify a pinned fingerprint after download.
+curl -fsSL "$CORTEX_KEY_URL" | gpg --dearmor -o /usr/share/keyrings/cortex-linux.gpg

Also applies to: 55-61

🤖 Prompt for AI Agents
In @iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot around lines
9 - 12, The build hook currently uses non-deterministic network fetches and only
sets "set -e"; change the script to be failure-safe and deterministic by adding
"set -euo pipefail" at the top and replacing the remote key download with a
local, versioned key file shipped in the tree (e.g., use a bundled file like
cortex-apt-key.gpg and import it via apt-key add or gpg --dearmor into
/usr/share/keyrings), update the repository entry to reference the local
keyring, and ensure all commands that read from pipes will fail on errors so
failures are clear and reproducible.

Comment on lines 136 to 143
# Generate Packages file
log "Generating Packages for ${suite}/${arch}..."
(cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages" 2>/dev/null || true)
if [ -d "${REPO_DIR}/pool/main" ]; then
(cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages")
else
touch "${arch_dir}/Packages"
fi
gzip -9 -k -f "${arch_dir}/Packages"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

touch Packages can leave stale repository metadata; truncate instead.

Proposed fix
-            if [ -d "${REPO_DIR}/pool/main" ]; then
-                (cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages")
-            else
-                touch "${arch_dir}/Packages"
-            fi
+            if [ -d "${REPO_DIR}/pool/main" ]; then
+                (cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages")
+            else
+                : > "${arch_dir}/Packages"
+            fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Generate Packages file
log "Generating Packages for ${suite}/${arch}..."
(cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages" 2>/dev/null || true)
if [ -d "${REPO_DIR}/pool/main" ]; then
(cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages")
else
touch "${arch_dir}/Packages"
fi
gzip -9 -k -f "${arch_dir}/Packages"
# Generate Packages file
log "Generating Packages for ${suite}/${arch}..."
if [ -d "${REPO_DIR}/pool/main" ]; then
(cd "${REPO_DIR}" && dpkg-scanpackages --arch "$arch" pool/main > "${arch_dir}/Packages")
else
: > "${arch_dir}/Packages"
fi
gzip -9 -k -f "${arch_dir}/Packages"
🤖 Prompt for AI Agents
In @repository/scripts/repo-manage.sh around lines 136 - 143, The script
currently uses touch "${arch_dir}/Packages" which can leave stale content if the
file already exists; change it to truncate the file instead (overwrite with an
empty file) when dpkg-scanpackages is not run so Packages is emptied rather than
preserved; update the branch in repo-manage.sh that handles the else path after
dpkg-scanpackages (the block that currently calls touch "${arch_dir}/Packages")
to create an empty/truncated "${arch_dir}/Packages" before gzip -9 -k -f runs.

Comment on lines 94 to 154
cmd_check_deps() {
local failed=0

header "Checking build dependencies"

# Required dependencies
check_command lb live-build || failed=1
check_command gpg gnupg || failed=1
check_command python3 python3 || failed=1

# Check live-build version
if command -v lb &>/dev/null; then
local lb_version
lb_version=$(dpkg-query -W -f='${Version}' live-build 2>/dev/null || echo "0")
if dpkg --compare-versions "$lb_version" lt "1:20210814"; then
warn "live-build version $lb_version may be too old. Recommended: >= 1:20210814"
else
log "live-build version: $lb_version"
fi
fi

# Check Python version
if command -v python3 &>/dev/null; then
if python3 -c "import sys; sys.exit(0 if sys.version_info >= (3, 11) else 1)" 2>/dev/null; then
log "Python version: $(python3 --version 2>&1 | cut -d' ' -f2)"
else
warn "Python 3.11+ recommended (found: $(python3 --version 2>&1 | cut -d' ' -f2))"
fi
fi

# Optional dependencies
echo ""
log "Checking optional dependencies..."

if command -v shellcheck &>/dev/null; then
log "shellcheck: OK"
else
warn "Non-Debian OS - build may not work correctly"
fi

# Check for required commands
local required_cmds=(
"dpkg-buildpackage"
"lb"
"debootstrap"
"xorriso"
"mksquashfs"
)

for cmd in "${required_cmds[@]}"; do
if command -v "$cmd" &>/dev/null; then
log "Found: $cmd"
warn "shellcheck not installed (optional, for linting)"
fi

if command -v convert &>/dev/null; then
log "ImageMagick: OK"
else
warn "ImageMagick not installed (optional, for GRUB theme images)"
fi

if command -v dpkg-deb &>/dev/null; then
log "dpkg-deb: OK"
else
warn "dpkg-deb not installed (needed for branding-package)"
fi

echo ""
if [ $failed -eq 0 ]; then
log "All required dependencies found."
return 0
else
error "Missing required dependencies."
return 1
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

branding-package needs dpkg-deb but dependency check treats it as optional.

Either make dpkg-deb required in cmd_check_deps (or check it inside cmd_branding_package and fail with a clear message).

Also applies to: 730-818

🤖 Prompt for AI Agents
In @scripts/build.sh around lines 94 - 154, The script currently treats dpkg-deb
as optional in cmd_check_deps but branding-package needs it; either mark
dpkg-deb as required by changing its check in cmd_check_deps to mirror other
required checks (use check_command dpkg-deb || failed=1 and ensure the final
failed logic returns non-zero), or add a dedicated runtime check inside
cmd_branding_package that tests command -v dpkg-deb and exits/fails with a clear
error message if missing; update references to the failed variable and
error/warn calls so the failure path is deterministic and the message explains
that branding-package requires dpkg-deb.

Comment on lines +570 to +572
log "Starting live-build (this may take a while)..."
sudo lb build

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, find the build.sh file
fd -t f "build.sh" scripts/

Repository: cortexlinux/cortex-distro

Length of output: 85


🏁 Script executed:

# Check if the file exists and get line count
wc -l scripts/build.sh 2>/dev/null || echo "File not found"

Repository: cortexlinux/cortex-distro

Length of output: 89


🏁 Script executed:

# Read the context around lines 570-572
if [ -f scripts/build.sh ]; then
  sed -n '560,580p' scripts/build.sh
fi

Repository: cortexlinux/cortex-distro

Length of output: 549


🏁 Script executed:

# Search for all instances of 'lb build' and 'lb clean' in the script
if [ -f scripts/build.sh ]; then
  echo "=== Instances of 'lb build' ===" && grep -n "lb build" scripts/build.sh
  echo "=== Instances of 'lb clean' ===" && grep -n "lb clean" scripts/build.sh
fi

Repository: cortexlinux/cortex-distro

Length of output: 180


🏁 Script executed:

# Read the beginning of the file to see shebang and initial documentation
head -50 scripts/build.sh

Repository: cortexlinux/cortex-distro

Length of output: 1529


🏁 Script executed:

# Check for existing EUID checks or sudo patterns in the file
grep -n "EUID\|getuid\|whoami\|id -u" scripts/build.sh || echo "No explicit user checks found"

Repository: cortexlinux/cortex-distro

Length of output: 98


🏁 Script executed:

# Look for other sudo commands to understand the pattern
grep -n "^[[:space:]]*sudo " scripts/build.sh | head -20

Repository: cortexlinux/cortex-distro

Length of output: 116


🏁 Script executed:

# Check surrounding context of the build_iso function
sed -n '550,600p' scripts/build.sh

Repository: cortexlinux/cortex-distro

Length of output: 1419


Unconditional sudo will fail when running as root (common in CI/CD environments); use conditional sudo for both lb build and lb clean.

Apply the EUID check to both occurrences:

  • Line 571: sudo lb build
  • Line 643: sudo lb clean

Use: if [[ $EUID -eq 0 ]]; then lb build; else sudo lb build; fi (and same pattern for lb clean).

🤖 Prompt for AI Agents
In @scripts/build.sh around lines 570 - 572, The live-build commands use
unconditional sudo which fails when running as root; update both invocations of
"lb build" and "lb clean" to run conditionally based on EUID: replace each `sudo
lb build` and `sudo lb clean` with an EUID check that runs `lb build`/`lb clean`
directly if $EUID is 0, otherwise prefixes with sudo (e.g., if [[ $EUID -eq 0
]]; then lb build; else sudo lb build; fi and same pattern for lb clean).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Line 236: The workflow currently pins the GitHub Action as
"softprops/action-gh-release@v1" which is outdated; update the uses entry for
softprops/action-gh-release to a newer release (e.g., "@v2" or a specific commit
SHA) to ensure compatibility with current runners and satisfy actionlint; locate
the "uses: softprops/action-gh-release@v1" line in the workflow and replace the
version tag with the chosen newer tag or SHA, then run the workflow lint/CI to
verify the change.
- Around line 28-38: The workflow defines an unused inputs.profile with options
[core, full, secops, all] while the build-iso and test-iso strategy matrices
(matrix in the build-iso job and matrix in the test-iso job) are hardcoded to
[core, full]; either remove the extra options from inputs.profile or make the
matrices respect the input by replacing their static arrays with the dynamic
value (use the inputs.profile value in the matrix expressions for both the
build-iso and test-iso jobs) so selecting secops or all actually affects which
profiles are built and tested.
🧹 Nitpick comments (3)
.github/workflows/build-iso.yml (3)

152-158: Re-evaluate continue-on-error for SBOM uploads.

Setting continue-on-error: true for SBOM uploads (software bill of materials) may hide issues with SBOM generation. While SBOMs might be optional for the build to succeed, their absence could have compliance or security implications.

Consider one of the following approaches:

  1. Remove continue-on-error if SBOMs are required for releases
  2. Add conditional logic to fail on tags but allow errors on PR builds
  3. Add explicit logging when SBOM generation fails

Example for conditional strictness:

      - name: Upload SBOM
        uses: actions/upload-artifact@v4
        with:
          name: sbom-${{ matrix.profile }}-${{ matrix.arch }}
          path: output/sbom/
          retention-days: 14
        continue-on-error: ${{ github.ref_type != 'tag' }}

182-198: Add explicit verification that ISO files exist.

The shell loops using *.iso will fail gracefully if no ISOs exist (thanks to the conditional check on line 186), but could be more explicit about the failure case.

Consider adding an explicit check:

      - name: Verify checksums
        run: |
          shopt -s nullglob
          isos=(*.iso)
          if [ ${#isos[@]} -eq 0 ]; then
            echo "Error: No ISO files found"
            exit 1
          fi
          for iso in "${isos[@]}"; do
            if [ -f "${iso}.sha256" ]; then
              sha256sum -c "${iso}.sha256"
            fi
          done

This makes the workflow fail more explicitly if artifacts are missing.


229-233: Add file existence checks before generating checksums.

The checksum generation assumes *.iso and *.deb files exist. If artifact downloads fail or produce no files, the sha256sum command will fail with a cryptic error.

Add verification before checksum generation:

      - name: Generate combined checksums
        run: |
          cd release
          # Verify files exist
          if ! ls *.iso >/dev/null 2>&1; then
            echo "Error: No ISO files found for release"
            exit 1
          fi
          if ! ls *.deb >/dev/null 2>&1; then
            echo "Error: No DEB packages found for release"
            exit 1
          fi
          sha256sum *.iso *.deb > SHA256SUMS
          sha512sum *.iso *.deb > SHA512SUMS
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aac8af0 and 2882c18.

📒 Files selected for processing (1)
  • .github/workflows/build-iso.yml
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

236-236: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build ISO (core)
  • GitHub Check: Build ISO (full)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (3)
.github/workflows/build-iso.yml (3)

44-59: LGTM!

The validation job correctly sets up dependencies and runs validation checks in a containerized environment.


76-84: Verify artifact path pattern matches expected output.

The wildcard output/*.deb assumes the branding package build produces at least one .deb file. If the build succeeds but no package is generated, the upload step will fail silently.

Consider adding a verification step before upload:

      - name: Verify package output
        run: |
          if [ ! -f output/*.deb ]; then
            echo "Error: No branding package found in output/"
            exit 1
          fi
          ls -lh output/*.deb

89-92: Document the security implications of --privileged.

The --privileged flag grants extended privileges to the container, which is necessary for live-build to access loop devices and create bootable ISOs. While this is acceptable in a controlled CI environment, it does expand the attack surface.

Ensure that:

  1. The repository has appropriate access controls
  2. Workflow permissions follow the principle of least privilege
  3. This requirement is documented in the build documentation

Consider adding a comment explaining why --privileged is necessary:

    container:
      image: debian:bookworm
      # Privileged mode required for live-build to access loop devices
      options: --privileged

sha512sum *.iso *.deb > SHA512SUMS
- name: Create Release
uses: softprops/action-gh-release@v1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update to the latest version of softprops/action-gh-release.

The v1 tag uses an outdated runner version that may not work on GitHub Actions. Update to a more recent version (e.g., v2 or a specific commit SHA).

Based on the static analysis hint from actionlint.

📦 Proposed fix
       - name: Create Release
-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@v2
         with:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
uses: softprops/action-gh-release@v1
uses: softprops/action-gh-release@v2
🧰 Tools
🪛 actionlint (1.7.10)

236-236: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml at line 236, The workflow currently pins the
GitHub Action as "softprops/action-gh-release@v1" which is outdated; update the
uses entry for softprops/action-gh-release to a newer release (e.g., "@v2" or a
specific commit SHA) to ensure compatibility with current runners and satisfy
actionlint; locate the "uses: softprops/action-gh-release@v1" line in the
workflow and replace the version tag with the chosen newer tag or SHA, then run
the workflow lint/CI to verify the change.

Your Name added 3 commits January 12, 2026 01:54
…availability. Added a message to indicate the repository is currently skipped.
- Adjusted boot menu dimensions and item font sizes for better readability.
- Enhanced title and subtitle labels with updated text and styling.
- Refined help text positioning and font size for clarity.
- Added new message and background colors for improved visual appeal.
- Removed the container specification for the build job, simplifying the workflow.
- Added a disk cleanup step to free up space before the build process.
- Consolidated dependency installation into a Docker run command for better isolation and management.
- Ensured that the build process includes dependency checks and ISO creation in a single step.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 27-38: The workflow_dispatch input "profile" is misleading because
the build matrix doesn't use it; update the workflow to either (A) drive the
build matrix from the "profile" input by mapping the input value to the
matrix.include or matrix.strategy (e.g., read github.event.inputs.profile in the
job and set matrix values to run core/full/secops/all accordingly), or (B)
restrict the workflow_dispatch options to only "core" and "full" to match the
current matrix; locate the workflow_dispatch block and the job that defines the
build matrix and change the matrix definition to conditionally use
github.event.inputs.profile (or add a mapping step to populate matrix.include)
or prune the input options to match the existing matrix.
- Around line 245-250: The "Generate combined checksums" step can fail when glob
patterns match nothing; change the run block to avoid bare globs by enabling
nullglob (shopt -s nullglob) or by building an explicit file list (e.g.,
files=(release/*.{iso,deb}) or use find) and only run sha256sum/sha512sum when
the list is non-empty; update the commands that call sha256sum and sha512sum to
use the guarded file array/variable so the step exits successfully when there
are no matches.
- Around line 193-215: The workflow's "Download ISO", "Verify checksums", and
"Check ISO structure" steps assume .iso files in the runner root but
actions/download-artifact extracts into a subfolder, causing the for-loops to
see a literal "*.iso" and skip checks; change the download step to save
artifacts into a known directory (e.g., an explicit target dir name) and then in
the "Verify checksums" and "Check ISO structure" steps cd into that directory
(or reference that directory in the loops) and enable safe globbing (e.g.,
nullglob) or use a secure find pattern so the verification and xorriso checks
actually iterate real .iso files.
- Around line 251-252: Update the GitHub Actions step that currently uses
softprops/action-gh-release@v1 to the maintained v2 release; locate the workflow
step with the uses: softprops/action-gh-release@v1 entry in the Create Release
job and change the reference to softprops/action-gh-release@v2 so the action
runs on Node 20-compatible version.
🧹 Nitpick comments (3)
.github/workflows/build-iso.yml (3)

44-60: Containerized validate job is good; drop sudo or set strict shell flags (Line 44–60).
In a Debian container you’re typically root already; sudo is extra surface area. Consider set -euo pipefail in the install step for cleaner failures.


96-151: Re-check need for docker run --privileged + add timeouts for apt (Line 96–151).
--privileged is a big hammer; if live-build only needs loop devices/mounts, consider narrower caps/devices. Also, apt-get with no retries/timeouts can hang a runner.


168-175: SBOM upload: consider if-no-files-found: ignore instead of continue-on-error (Line 168–175).
This avoids masking other upload errors while still allowing “no SBOM produced” to be non-fatal.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 922ee06 and e8211b8.

📒 Files selected for processing (2)
  • .github/workflows/build-iso.yml
  • branding/grub/cortex/theme.txt
🚧 Files skipped from review as they are similar to previous changes (1)
  • branding/grub/cortex/theme.txt
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

252-252: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build Branding Package
  • GitHub Check: Build (First Pass)
🔇 Additional comments (2)
.github/workflows/build-iso.yml (2)

12-26: Workflow triggers look fine, but ensure new paths are intentional (Line 12–26).
Adding branding/** and scripts/** will increase CI frequency; if that’s expected, LGTM.


61-85: Branding package build/upload looks consistent (Line 61–85).
Artifact name + output/*.deb convention is clear.

Comment on lines 193 to 215
- name: Download ISO
uses: actions/download-artifact@v4
with:
name: cortex-linux-${{ matrix.profile }}-${{ matrix.arch }}

- name: Verify checksums
run: |
ls -la
for iso in *.iso; do
if [ -f "${iso}.sha256" ]; then
sha256sum -c "${iso}.sha256"
fi
done
- name: Check ISO structure
run: |
sudo apt-get update
sudo apt-get install -y xorriso
for iso in *.iso; do
echo "=== Checking $iso ==="
xorriso -indev "$iso" -find / -maxdepth 1 2>/dev/null | head -20
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

test-iso likely doesn’t test anything due to artifact extraction layout (Line 193–215).
actions/download-artifact will usually extract into a subfolder (artifact name) unless you flatten; your for iso in *.iso loops can end up iterating the literal *.iso and silently skipping verification.

Proposed fix: download into a known dir and `cd` there (also make globbing safe)
   test-iso:
@@
     steps:
       - name: Download ISO
         uses: actions/download-artifact@v4
         with:
           name: cortex-linux-${{ matrix.profile }}-${{ matrix.arch }}
+          path: artifacts

       - name: Verify checksums
         run: |
-          ls -la
-          for iso in *.iso; do
+          set -euo pipefail
+          shopt -s nullglob
+          cd artifacts
+          # If download-artifact created a subdir, enter it
+          d="cortex-linux-${{ matrix.profile }}-${{ matrix.arch }}"
+          [ -d "$d" ] && cd "$d"
+          ls -la
+          for iso in *.iso; do
             if [ -f "${iso}.sha256" ]; then
               sha256sum -c "${iso}.sha256"
             fi
           done

       - name: Check ISO structure
         run: |
+          set -euo pipefail
+          shopt -s nullglob
           sudo apt-get update
           sudo apt-get install -y xorriso
-          for iso in *.iso; do
+          cd artifacts
+          d="cortex-linux-${{ matrix.profile }}-${{ matrix.arch }}"
+          [ -d "$d" ] && cd "$d"
+          for iso in *.iso; do
             echo "=== Checking $iso ==="
             xorriso -indev "$iso" -find / -maxdepth 1 2>/dev/null | head -20
           done
🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 193 - 215, The workflow's
"Download ISO", "Verify checksums", and "Check ISO structure" steps assume .iso
files in the runner root but actions/download-artifact extracts into a
subfolder, causing the for-loops to see a literal "*.iso" and skip checks;
change the download step to save artifacts into a known directory (e.g., an
explicit target dir name) and then in the "Verify checksums" and "Check ISO
structure" steps cd into that directory (or reference that directory in the
loops) and enable safe globbing (e.g., nullglob) or use a secure find pattern so
the verification and xorriso checks actually iterate real .iso files.

- Introduced a new action to free up disk space before the build process.
- Added additional cleanup commands to remove various unnecessary files and directories.
- Improved overall efficiency of the workflow by ensuring more space is available for builds.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 29-38: The workflow_dispatch input declares profile options
'secops' and 'all' that the build matrix doesn't support; either remove those
unsupported options from the profile input (leave options as 'core' and 'full'
only) or modify the strategy.matrix.profile logic to evaluate github.event_name
and github.event.inputs.profile so a manual dispatch uses the input (supporting
'all' to expand to multiple profiles or a single-profile array) as shown in the
suggested conditional matrix expression; update both the input block named
profile and the strategy.matrix.profile handling so they stay consistent.
- Around line 259-260: The workflow's "Create Release" step uses the outdated
action reference softprops/action-gh-release@v1 which may fail on modern
runners; update the uses entry to the newer major version (e.g.,
softprops/action-gh-release@v2) in the Create Release job so the workflow pulls
the updated action release instead of @v1.
- Around line 96-105: The workflow step named "Free disk space" currently
references the external action jlumbroso/free-disk-space@main; change that
reference to a fixed, published version (e.g., jlumbroso/free-disk-space@v1.3.1)
to avoid supply-chain risks, updating the uses field in that step while leaving
the existing with: inputs unchanged.
🧹 Nitpick comments (1)
.github/workflows/build-iso.yml (1)

206-222: Consider more thorough ISO structure validation.

The current test only lists top-level contents. Consider verifying essential files exist (e.g., boot loader, squashfs, etc.) to catch structural issues:

💡 Enhanced structure verification
      - name: Check ISO structure
        run: |
          sudo apt-get update
          sudo apt-get install -y xorriso
          for iso in *.iso; do
            echo "=== Checking $iso ==="
            xorriso -indev "$iso" -find / -maxdepth 1 2>/dev/null | head -20
+           # Verify essential boot components exist
+           xorriso -indev "$iso" -find / -name "*.squashfs" 2>/dev/null | grep -q squashfs || echo "WARNING: No squashfs found"
+           xorriso -indev "$iso" -find /boot -maxdepth 2 2>/dev/null | head -10
          done
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e8211b8 and b071385.

📒 Files selected for processing (1)
  • .github/workflows/build-iso.yml
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

260-260: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Build ISO (core)
  • GitHub Check: Build ISO (full)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (4)
.github/workflows/build-iso.yml (4)

44-59: LGTM!

The validate job is well-structured with appropriate dependencies installed in a consistent Debian container environment.


61-84: LGTM!

The branding package build job properly chains after validation and uploads the artifact for downstream jobs.


130-159: LGTM!

The containerized build approach with --privileged is appropriate for live-build operations that require loop device access and chroot capabilities. The set -e ensures the build fails fast on errors.


253-267: LGTM with a defensive improvement suggestion.

The checksum generation and release assets are well-organized. The branding package should always be present from the earlier job, so the glob pattern should match.

For robustness, you could add shopt -s nullglob to avoid errors if a glob pattern unexpectedly matches nothing:

💡 Optional: Defensive glob handling
      - name: Generate combined checksums
        run: |
          cd release
+          shopt -s nullglob
+          files=(*.iso *.deb)
+          if [ ${#files[@]} -eq 0 ]; then
+            echo "ERROR: No ISO or deb files found"
+            exit 1
+          fi
          sha256sum *.iso *.deb > SHA256SUMS
          sha512sum *.iso *.deb > SHA512SUMS

Comment on lines 96 to 105
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

jlumbroso/free-disk-space GitHub Action latest release version

💡 Result:

Latest release: v1.3.1 — released Oct 18, 2023. [1]

Sources
[1] jlumbroso/free-disk-space tags (v1.3.1).


Pin jlumbroso/free-disk-space to a stable version instead of @main.

Using @main exposes the build to supply chain risks—breaking changes or malicious commits could affect builds without notice. Pin to a stable release like v1.3.1:

Recommended change
      - name: Free disk space
-        uses: jlumbroso/free-disk-space@main
+        uses: jlumbroso/free-disk-space@v1.3.1
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Free disk space
uses: jlumbroso/free-disk-space@main
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true
- name: Free disk space
uses: jlumbroso/free-disk-space@v1.3.1
with:
tool-cache: true
android: true
dotnet: true
haskell: true
large-packages: true
docker-images: true
swap-storage: true
🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 96 - 105, The workflow step
named "Free disk space" currently references the external action
jlumbroso/free-disk-space@main; change that reference to a fixed, published
version (e.g., jlumbroso/free-disk-space@v1.3.1) to avoid supply-chain risks,
updating the uses field in that step while leaving the existing with: inputs
unchanged.

Comment on lines 259 to 260
- name: Create Release
uses: softprops/action-gh-release@v1
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update softprops/action-gh-release to a newer version.

The static analysis tool indicates that @v1 is too old to run on current GitHub Actions runners. This could cause failures or deprecated behavior warnings.

🔧 Update to v2
      - name: Create Release
-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@v2
        with:
          files: |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Create Release
uses: softprops/action-gh-release@v1
- name: Create Release
uses: softprops/action-gh-release@v2
🧰 Tools
🪛 actionlint (1.7.10)

260-260: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 259 - 260, The workflow's
"Create Release" step uses the outdated action reference
softprops/action-gh-release@v1 which may fail on modern runners; update the uses
entry to the newer major version (e.g., softprops/action-gh-release@v2) in the
Create Release job so the workflow pulls the updated action release instead of
@v1.

…ld process

- Simplified ISO build targets in the Makefile, consolidating profiles into a single command.
- Updated help text to reflect changes in ISO build commands and removed obsolete profiles.
- Enhanced GitHub Actions workflow to support both amd64 and arm64 architectures with improved artifact handling.
- Removed profile-specific inputs from the workflow, focusing on a unified build approach.
- Improved preseed file management and validation checks in the build script for better reliability.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 238-246: The GitHub Actions step named "Create Release" is using
the outdated action reference softprops/action-gh-release@v1; update the uses
value to softprops/action-gh-release@v2, then verify the step's inputs (the
files multiline input) remain compatible with v2 and run the workflow to confirm
the release artifacts (release/*.iso, release/*.deb, release/SHA256SUMS,
release/SHA512SUMS, release/sbom/*) are still uploaded correctly.
🧹 Nitpick comments (11)
scripts/install-deps.sh (3)

14-16: Minor inconsistency with logging format.

The logging functions here use [+] and [!] prefixes, while scripts/build.sh uses [BUILD] and [WARN] prefixes. Consider aligning these for consistency across the build tooling.

Based on the relevant code snippets from scripts/build.sh:

log() { echo -e "${GREEN}[BUILD]${NC} $*"; }
warn() { echo -e "${YELLOW}[WARN]${NC} $*"; }
♻️ Optional: Align with build.sh format
-log() { echo -e "${GREEN}[+]${NC} $1"; }
-warn() { echo -e "${YELLOW}[!]${NC} $1"; }
-error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }
+log() { echo -e "${GREEN}[DEPS]${NC} $1"; }
+warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
+error() { echo -e "${RED}[ERROR]${NC} $1" >&2; }

28-29: Consider quieting apt-get update output.

The apt-get update output can be verbose. Consider adding -qq for quieter output, or redirecting stdout while preserving stderr for errors.

♻️ Suggested improvement
 # Update package lists
-apt-get update
+apt-get update -qq

51-52: Add --no-install-recommends to reduce image size.

For build tooling, installing only the required packages without recommends can reduce disk usage and build time.

♻️ Suggested improvement
 log "Installing common packages..."
-apt-get install -y "${COMMON_PACKAGES[@]}"
+apt-get install -y --no-install-recommends "${COMMON_PACKAGES[@]}"
.github/workflows/build-iso.yml (2)

186-192: Checksum verification may silently skip ISOs without checksums.

The loop continues silently if a .sha256 file doesn't exist. Consider logging or failing explicitly if expected checksums are missing.

♻️ Suggested improvement
       - name: Verify checksums
         run: |
           ls -la
           for iso in *.iso; do
             if [ -f "${iso}.sha256" ]; then
               sha256sum -c "${iso}.sha256"
+            else
+              echo "Warning: No checksum file found for ${iso}"
             fi
           done

232-236: Checksum generation may fail if no .deb files exist.

If the branding package download fails (despite continue-on-error: true on SBOM), the sha256sum *.deb glob may fail. Consider adding a fallback.

♻️ Suggested improvement
       - name: Generate combined checksums
         run: |
           cd release
-          sha256sum *.iso *.deb > SHA256SUMS
-          sha512sum *.iso *.deb > SHA512SUMS
+          sha256sum *.iso > SHA256SUMS
+          sha256sum *.deb >> SHA256SUMS 2>/dev/null || true
+          sha512sum *.iso > SHA512SUMS
+          sha512sum *.deb >> SHA512SUMS 2>/dev/null || true
Makefile (2)

137-142: Root check implementation is correct but could be extracted.

The inline root check works, but duplicating this logic (also in install-deps.sh) could be consolidated into a shared helper if more targets require root.


152-160: Add security note for chroot-shell target.

Entering a chroot with sudo chroot is powerful. Consider adding a comment or warning that this is for development only and the chroot environment should not be trusted.

♻️ Optional: Add development-only warning
 # Enter interactive shell inside the chroot filesystem
+# WARNING: Development use only - chroot environment is not sanitized
 chroot-shell:
 	@if [ -d "$(BUILD_DIR)/chroot" ]; then \
+		echo "WARNING: Entering unsanitized chroot environment"; \
 		echo "Entering chroot..."; \
scripts/build.sh (4)

100-109: Live-build version comparison may fail if dpkg-query returns non-version string.

If dpkg-query fails or returns an unexpected format, the comparison could behave unexpectedly. The fallback to "0" is good, but consider also handling the case where dpkg --compare-versions itself fails.

♻️ Optional: Add defensive error handling
     if command -v lb &>/dev/null; then
         local lb_version
         lb_version=$(dpkg-query -W -f='${Version}' live-build 2>/dev/null || echo "0")
-        if dpkg --compare-versions "$lb_version" lt "1:20210814"; then
+        if dpkg --compare-versions "$lb_version" lt "1:20210814" 2>/dev/null; then
             warn "live-build version $lb_version may be too old. Recommended: >= 1:20210814"
         else
             log "live-build version: $lb_version"

659-662: Hardcoded package version should be parameterized.

The pkg_version="1.0.0" is hardcoded. Consider reading this from the DEBIAN/control file or making it configurable via environment variable for release versioning.

♻️ Suggested improvement
 cmd_branding_package() {
     local pkg_name="cortex-branding"
-    local pkg_version="1.0.0"
+    local pkg_version="${BRANDING_VERSION:-1.0.0}"
     local pkg_dir="${BUILD_DIR}/${pkg_name}"

Alternatively, extract version from the control file:

local pkg_version
pkg_version=$(grep '^Version:' "${PACKAGES_DIR}/${pkg_name}/DEBIAN/control" | cut -d' ' -f2)

602-612: cmd_clean uses sudo but doesn't verify build directory safety.

Before running sudo lb clean in an arbitrary directory, consider validating that BUILD_DIR is within the expected project structure to prevent accidental cleanup of unintended paths.

♻️ Add path validation
 cmd_clean() {
     header "Cleaning build"
 
     if [ -d "$BUILD_DIR" ]; then
+        # Ensure BUILD_DIR is within PROJECT_ROOT
+        case "$BUILD_DIR" in
+            "${PROJECT_ROOT}/"*) ;;
+            *) error "BUILD_DIR is outside project root"; return 1 ;;
+        esac
         cd "$BUILD_DIR"
         sudo lb clean
         log "Clean complete"

536-545: Consider adding sudo -n flag to fail fast if authentication is required.

While the build runs in a --privileged Docker container (which typically allows sudo without TTY), using sudo -n is defensive and will cause the build to fail immediately if sudo authentication is required, rather than hanging.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b071385 and 3b68a92.

📒 Files selected for processing (4)
  • .github/workflows/build-iso.yml
  • Makefile
  • scripts/build.sh
  • scripts/install-deps.sh
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/install-deps.sh (1)
scripts/build.sh (3)
  • error (44-44)
  • log (42-42)
  • warn (43-43)
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

239-239: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🪛 checkmake (0.2.2)
Makefile

[warning] 43-43: Target body for "help" exceeds allowed length of 5 (32).

(maxbodylength)


[warning] 166-166: Target body for "config" exceeds allowed length of 5 (7).

(maxbodylength)


[warning] 14-14: Missing required phony target "clean"

(minphony)


[warning] 14-14: Missing required phony target "test"

(minphony)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (9)
scripts/install-deps.sh (1)

55-64: LGTM on architecture handling.

Good conditional handling for amd64 and arm64 architectures with a sensible fallback warning for unknown architectures.

.github/workflows/build-iso.yml (1)

75-86: LGTM on matrix strategy.

Good use of fail-fast: false to allow both architectures to complete independently, and appropriate runner selection for arm64.

Makefile (3)

14-17: LGTM on .PHONY declaration.

The static analysis warning about missing clean and test phony targets appears to be a false positive—both are listed on line 15.


20-21: Good shell strictness settings.

Using -eu -o pipefail ensures errors are caught and pipelines fail properly. This is a best practice for robust Makefiles.


103-108: Consider adding validate dependency to iso-arm64 as well.

The iso target has check-deps validate as dependencies, but iso-arm64 only invokes $(MAKE) ARCH=arm64 iso. This is correct since it delegates to iso, but verify the recursive make call inherits the dependencies properly.

scripts/build.sh (4)

7-7: LGTM on strict mode.

Using set -euo pipefail ensures the script fails fast on errors, unset variables, and pipeline failures.


63-72: Glob expansion is intentionally unquoted.

The shellcheck disable comment correctly documents that the unquoted glob is intentional for pattern matching. Good use of the disable directive.


798-839: LGTM on main entry point.

Clean command dispatcher pattern with sensible defaults and help fallback for unknown commands.


286-295: Error accumulation pattern loses granularity.

Using || errors=$((errors + $?)) to capture exit codes is creative, but $? after || will always be 0 since the || clause succeeded. The validation functions return error counts directly, which works, but this pattern is fragile.

🐛 Issue explanation and fix

When you write validate_provision || errors=$((errors + $?)), the $? in the right-hand side reflects the exit status of the || expression itself (which is 0 if the right side executes). The actual error count from validate_provision is lost.

Consider capturing the return value explicitly:

         provision)
-            validate_provision || errors=$((errors + $?))
+            validate_provision || { local rc=$?; errors=$((errors + rc)); }
             ;;
         hooks)
-            validate_hooks || errors=$((errors + $?))
+            validate_hooks || { local rc=$?; errors=$((errors + rc)); }
             ;;
         lint)
-            run_shellcheck || errors=$((errors + $?))
+            run_shellcheck || { local rc=$?; errors=$((errors + rc)); }

Or restructure to use:

validate_provision; errors=$((errors + $?))

Likely an incorrect or invalid review comment.

- Removed obsolete preseed profiles (core, full, secops) to streamline configuration management.
- Updated the base preseed file to clarify its purpose and settings.
- Simplified the first-boot provisioning script by removing profile-specific logic and enhancing core setup functions.
- Improved logging and error handling in the provisioning script for better maintainability.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 13

🤖 Fix all issues with AI agents
In @iso/preseed/cortex-base.preseed:
- Around line 59-77: The preseed is missing the unattended-upgrades package so
first-boot.sh’s check for unattended-upgrades will always skip; add
"unattended-upgrades" to the d-i pkgsel/include string in the preseed (alongside
sudo, openssh-server, etc.) so the package is present on install, or
alternatively update the first-boot.sh patch that checks for
"unattended-upgrades" to attempt to install the package when online (i.e.,
detect missing package and run apt-get install unattended-upgrades before
configuring it).
- Around line 11-17: The preseed contains two hostname keys that conflict:
netcfg/get_hostname and netcfg/hostname; pick one canonical key and remove the
other to avoid ambiguity (e.g., keep netcfg/hostname string cortex and delete
the netcfg/get_hostname line, or vice versa), and ensure any downstream scripts
that read the hostname use the chosen key (update references if needed) so
preseeding yields a single authoritative hostname source.
- Around line 30-44: Replace the invalid placeholder in d-i
passwd/user-password-crypted with a real crypt(3) SHA-512 hash for a known
temporary password (so the installer accepts it), do not rely on
allow-password-weak as the only safeguard (keep or set d-i
user-setup/allow-password-weak appropriately), and ensure the account is forced
to rotate the password at first login by adding a late_command that runs chage
-d 0 for the cortex user (targeting the username "cortex") so the temporary
password cannot remain in use.
- Around line 96-103: The late_command uses semicolon-separated commands so
failures are ignored; replace the cp + in-target chmod sequence with atomic
installs using install -m to copy files with correct permissions (for example
install -m 0755 for first-boot.sh and appropriate mode for
cortex-first-boot.service), and chain commands with && (or explicit conditional
checks) so the chain aborts on error; ensure you still use in-target for
systemctl enable cortex-first-boot.service and make the overall
preseed/late_command fail-fast if any install or mkdir step fails so
provisioning errors are not silently ignored.

In @iso/provisioning/first-boot.sh:
- Around line 235-256: The setup_unattended_upgrades function is effectively a
no-op under the current preseed because unattended-upgrades isn't installed;
either ensure the package is installed before the check or remove the function
call. Modify setup_unattended_upgrades to invoke package installation (e.g.,
apt-get install -y unattended-upgrades) if command -v returns false, or delete
the setup_unattended_upgrades invocation and its helper if you intend not to
enable unattended upgrades by default; refer to the function name
setup_unattended_upgrades and the auto_upgrades variable to locate the relevant
code to change.
- Around line 107-114: The setup_password_change function currently only
enforces chage -d 0 when REQUIRE_PASSWORD_CHANGE is explicitly true, which can
leave installs with unchanged placeholder passwords; update
setup_password_change to default to forcing rotation (treat
REQUIRE_PASSWORD_CHANGE as true when unset) or additionally detect a known
temporary/placeholder hash for the cortex account and force chage -d 0 when that
hash is present; make changes to the function that reference
REQUIRE_PASSWORD_CHANGE, chage -d 0 and the cortex username, and ensure you log
the decision via log_info so the behavior is auditable.
- Around line 258-277: The setup_desktop function calls groups cortex and
usermod -aG docker cortex without checking the cortex user exists, which can
cause the script to fail under set -e; before invoking groups or usermod, guard
those calls with a check like getent passwd cortex (or id -u cortex) to ensure
the user exists, and only run groups and usermod when that check succeeds so
setup_desktop safely skips Docker group configuration if the cortex user is
missing.
- Around line 81-105: The sudo Defaults in setup_sudo are currently global;
modify the here-doc written to sudoers_file (variable sudoers_file and function
setup_sudo) so each Defaults line is scoped to the cortex user by prefixing with
"Defaults:cortex" (e.g., Defaults:cortex env_reset, Defaults:cortex
logfile=...), keep the cortex ALL=(ALL:ALL) ALL line as-is, then after writing
the file run a syntax check with visudo -cf "${sudoers_file}" before chmod 440
to ensure validity.
- Around line 58-67: The check_network() function currently invokes ping
directly which under set -e will cause the script to exit if ping is missing;
update check_network to first test for ping's existence (e.g., using command -v
ping or type ping) and if not found log_warn "Network: Offline (ping missing)"
and export NETWORK_AVAILABLE=false, otherwise run the existing ping check and
set NETWORK_AVAILABLE=true/false based on its result; ensure any invocation of
ping is guarded so a missing binary or non-zero exit does not trigger an
unexpected script termination.
- Around line 16-55: The script currently logs in check_already_complete and
mark_complete before ensuring LOG_DIR/LOG_FILE and PROVISION_DIR exist, causing
non-idempotent failures; modify startup to bootstrap directories and log file
first (mkdir -p "${LOG_DIR}" and "${PROVISION_DIR}", touch/chmod "${LOG_FILE}")
before any call to log or running check_already_complete, and update
mark_complete() to ensure PROVISION_DIR exists (mkdir -p "${PROVISION_DIR}")
before creating STATE_FILE so writing the state is safe and idempotent.
- Around line 318-336: In setup_ssh_keys(), the systemctl call uses the
Debian-incompatible unit name "sshd"; change the restart to use the canonical
"ssh" unit instead (i.e., replace the systemctl restart sshd || true call with
systemctl restart ssh || true) so the SSH service restart is reliable across
Debian/Ubuntu systems after generating host keys.
- Around line 116-168: The SSH hardening block in setup_ssh has a mismatched
comment for PasswordAuthentication, a non‑FIPS-first cipher order in Ciphers,
and uses the nonstandard service name sshd; update the comment near
PasswordAuthentication to reflect that it enables or disables password auth
globally (adjust text for PasswordAuthentication yes/no to match the actual
value of the setting), reorder the Ciphers line to list AES-GCM ciphers first
(e.g., aes256-gcm@openssh.com,aes128-gcm@openssh.com) or remove
chacha20-poly1305@openssh.com if FIPS compliance is required, and change the
systemctl checks/reload that reference sshd to use ssh (i.e., replace systemctl
is-active --quiet sshd and systemctl reload sshd with ssh) while keeping the
rest of setup_ssh and the sshd_config filename unchanged.
🧹 Nitpick comments (2)
iso/provisioning/first-boot.sh (2)

170-193: Use ufw --force enable instead of piping echo "y".

Less brittle under pipefail, and avoids interactive behavior changes across UFW versions.

Proposed change
-            echo "y" | ufw enable
+            ufw --force enable

370-403: Add an explicit root check early.

Right now, a non-root invocation will fail mid-script in less obvious places; fail fast with a clear log.

Proposed addition
 main() {
+    if [[ "${EUID}" -ne 0 ]]; then
+        echo "first-boot.sh must be run as root" >&2
+        exit 1
+    fi
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3b68a92 and 13953b2.

📒 Files selected for processing (2)
  • iso/preseed/cortex-base.preseed
  • iso/provisioning/first-boot.sh
🧰 Additional context used
🧬 Code graph analysis (1)
iso/provisioning/first-boot.sh (3)
repository/scripts/repo-manage.sh (1)
  • log (31-31)
scripts/build.sh (2)
  • log (42-42)
  • main (798-839)
branding/install-branding.sh (4)
  • log_info (22-22)
  • log_warn (24-24)
  • log_error (25-25)
  • main (213-242)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)

Comment on lines +16 to +55
set -euo pipefail

readonly CORTEX_DIR="/opt/cortex"
readonly PROVISION_DIR="${CORTEX_DIR}/provisioning"
readonly LOG_DIR="/var/log/cortex"
readonly LOG_FILE="${LOG_DIR}/first-boot.log"
readonly STATE_FILE="${PROVISION_DIR}/.first-boot-complete"

# Logging functions
log() {
local level="$1"
shift
local message="$*"
local timestamp
timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[${timestamp}] [${level}] ${message}" | tee -a "${LOG_FILE}"
}

log_info() { log "INFO" "$@"; }
log_warn() { log "WARN" "$@"; }
log_error() { log "ERROR" "$@"; }

# Check if already completed
check_already_complete() {
if [[ -f "${STATE_FILE}" ]]; then
log_info "First-boot provisioning already completed. Exiting."
exit 0
fi
}

# Initialize logging
init_logging() {
mkdir -p "${LOG_DIR}"
touch "${LOG_FILE}"
chmod 640 "${LOG_FILE}"
log_info "=== Cortex Linux First-Boot Provisioning Started ==="
log_info "Hostname: $(hostname)"
log_info "Date: $(date)"
log_info "Kernel: $(uname -r)"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Make idempotency truly safe: init logging/state dirs before any possible logging and before writing STATE_FILE.

Today, a “completed” run can still fail if ${LOG_DIR} or ${LOG_FILE} is missing (e.g., user cleanup) because check_already_complete logs before init_logging, and mark_complete assumes ${PROVISION_DIR} exists.

Proposed fix (directory bootstrap first, then state check)
 main() {
-    check_already_complete
-    init_logging
+    # Bootstrap dirs early so logging/state is safe even on "already complete" paths.
+    mkdir -p "${LOG_DIR}" "${PROVISION_DIR}"
+    touch "${LOG_FILE}"
+    chmod 640 "${LOG_FILE}"
+
+    check_already_complete
+    init_logging
     check_network

And in mark_complete():

 mark_complete() {
+    mkdir -p "${PROVISION_DIR}"
     local completion_time
🤖 Prompt for AI Agents
In @iso/provisioning/first-boot.sh around lines 16 - 55, The script currently
logs in check_already_complete and mark_complete before ensuring
LOG_DIR/LOG_FILE and PROVISION_DIR exist, causing non-idempotent failures;
modify startup to bootstrap directories and log file first (mkdir -p
"${LOG_DIR}" and "${PROVISION_DIR}", touch/chmod "${LOG_FILE}") before any call
to log or running check_already_complete, and update mark_complete() to ensure
PROVISION_DIR exists (mkdir -p "${PROVISION_DIR}") before creating STATE_FILE so
writing the state is safe and idempotent.

Comment on lines +116 to +168
# Configure SSH hardening
setup_ssh() {
log_info "Configuring SSH..."

local sshd_config="/etc/ssh/sshd_config.d/cortex-hardening.conf"

if [[ ! -f "${sshd_config}" ]]; then
mkdir -p /etc/ssh/sshd_config.d
cat > "${sshd_config}" << 'EOF'
# Cortex Linux SSH Hardening
# Disable root login
PermitRootLogin no
# Disable password authentication for root
PasswordAuthentication yes
PubkeyAuthentication yes
# Disable empty passwords
PermitEmptyPasswords no
# Limit authentication attempts
MaxAuthTries 3
# Disable X11 forwarding (enable if needed)
X11Forwarding no
# Client alive settings
ClientAliveInterval 300
ClientAliveCountMax 2
# Disable TCP forwarding by default
AllowTcpForwarding no
# Use strong ciphers only
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
# Use strong MACs
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
# Use strong key exchange
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
EOF
chmod 644 "${sshd_config}"
log_info "SSH hardening configured"

# Reload SSH if running
if systemctl is-active --quiet sshd; then
systemctl reload sshd || true
fi
else
log_info "SSH hardening already configured"
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Check if there's any documentation or context about Cortex Linux in the repo
find . -type f \( -name "*.md" -o -name "*.txt" -o -name "*.sh" \) | head -20 | xargs grep -l "cortex\|Cortex" 2>/dev/null | head -5

Repository: cortexlinux/cortex-distro

Length of output: 198


🌐 Web query:

Debian systemctl SSH service name ssh vs sshd openssh-server

💡 Result:

Short answer: On Debian and Ubuntu the unit provided by the openssh-server package is ssh.service (you should use systemctl start|stop|status ssh). sshd (the daemon binary) and its config remain named sshd/sshd_config; sshd.service is an alias for compatibility on Debian-derived systems. [1][2][3]

Useful commands:

  • Check unit: systemctl status ssh
  • Binary path: which sshd or ps aux | grep sshd
  • Config: /etc/ssh/sshd_config

Sources:
[1] Debian mailing list / openssh packaging (describes ssh.service, socket activation and aliasing).
[2] Ubuntu OpenSSH docs showing use of systemctl restart ssh.service and /etc/ssh/sshd_config.
[3] Discussion/examples showing ssh.service with Alias=sshd.service and note that sshd is the daemon program.


🌐 Web query:

openssh ciphers chacha20-poly1305 aes256-gcm aes128-gcm FIPS compliance compatibility

💡 Result:

Short answer

  • OpenSSH supports chacha20-poly1305@openssh.com and the AES‑GCM variants (aes128-gcm@openssh.com, aes256-gcm@openssh.com). (docs.gigamon.com)
  • ChaCha20‑Poly1305 is not NIST FIPS‑approved (and therefore is normally disallowed in FIPS mode / by FIPS crypto policies). AES‑GCM variants are accepted by FIPS policies and commonly allowed when the crypto provider is FIPS‑validated. (docs.redhat.com)
  • Practically this means: on a system or distro in FIPS mode (or using a system‑wide FIPS crypto policy) OpenSSH will not offer/use ChaCha20‑Poly1305; AES‑GCM (and other FIPS‑approved AES ciphers/CTR modes) should be used for FIPS compliance. System/distro policies or OpenSSH/FIPS configuration can also remove or reorder advertised ciphers, so explicit sshd_config/ssh_config entries may be required for compatibility. (docs.redhat.com)

Compatibility guidance (practical)

If you want, I can:

  • show the exact sshd_config/ssh_config lines to enforce AES‑GCM only, or
  • check how your OS/distribution’s FIPS policy will affect OpenSSH on a specific release (please tell me the OS and version).

Citations:


🏁 Script executed:

find . -type f \( -name "*.md" -o -name "*.txt" -o -name "README*" \) | xargs grep -i "fips\|compliance" 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 230


🏁 Script executed:

# Check the provisioning script context and any related hardening docs
ls -la iso/provisioning/ 2>/dev/null || ls -la . | head -20

Repository: cortexlinux/cortex-distro

Length of output: 322


🏁 Script executed:

# Look for any OS distro identification or FIPS mode checks in the script
cat iso/provisioning/first-boot.sh 2>/dev/null | head -50

Repository: cortexlinux/cortex-distro

Length of output: 1288


🏁 Script executed:

# Check for more context on the SSH setup function and security requirements
sed -n '116,168p' iso/provisioning/first-boot.sh | head -60

Repository: cortexlinux/cortex-distro

Length of output: 1362


🏁 Script executed:

# Look for any FIPS-related setup or security hardening docs in the repo
find . -type f -name "*.md" | xargs grep -i "ssh\|sshd\|hardening" 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 1168


🌐 Web query:

Cortex Linux distro FIPS compliance security requirements

💡 Result:

Do you mean (A) Palo Alto Networks’ Cortex cloud product, (B) a specific Linux distribution named “Cortex”, or (C) running a Linux system on ARM Cortex processors? I can proceed once you confirm.

Meanwhile, here are the concise, general FIPS compliance security requirements for Linux distributions (what vendors follow and you must implement to claim FIPS compliance):

  • Use NIST‑validated cryptographic modules (CMVP certificates) for all crypto operations; only the validated module versions and configurations listed in the module’s security policy may be used. [1][2][3]
  • Enable “FIPS mode” at installation (or follow the vendor’s supported FIPS enablement procedure). Enabling FIPS after installing workloads may not guarantee compliance; many vendors require enabling during install or immediate post‑install steps and regenerating keys. [2][4][5]
  • Restrict algorithms/ciphers to FIPS‑approved algorithms and approved protocol parameters (TLS suites, key sizes, KDFs, RNGs) and enforce system‑wide crypto policies so non‑approved ciphers are not offered. [4][5]
  • Use the exact package versions of crypto libraries/modules that were validated (and keep to vendor guidance about updates/patch channels for validated packages). [6][3]
  • Ensure kernel/OS module boundaries meet FIPS module definitions (some distros implement a kernel FIPS object module with self‑tests and early loading). Follow distro-specific kernel guidance. [7][4]
  • Perform and preserve self‑tests (power‑up, conditional) and continuous integrity checks required by the validated module’s security policy. [1][7]
  • Protect key material lifecycle: generate keys in FIPS mode, avoid exporting/using keys in non‑FIPS contexts unless allowed by policy (wrapping rules). [2][4]
  • Maintain documentation and evidence (security policy, validated module certificate numbers, tested configuration) for audits and for CMVP mapping. [1][6]
  • Follow vendor/distro-specific caveats and interoperability notes (e.g., TLS EMS requirements, disabled algorithms, compatibility impacts). Test workloads for functionality in FIPS mode. [4][5]

If you want, I can:

  • Check whether a specific “Cortex” product/distribution has an assigned CMVP certificate and its security policy (and cite the exact certificate and requirements).
  • Provide a step‑by‑step FIPS enablement checklist for a given distro (RHEL/Ubuntu/SLES/Oracle).

Which “Cortex” did you mean?

Sources: NIST CMVP and vendor FIPS docs (examples): [1] NIST CMVP certificate listing; [2] Red Hat FIPS docs; [3] Oracle Linux FIPS modules; [4] Linux kernel FIPS blog; [5] SUSE FIPS guidance; [6] Ubuntu FIPS announcement.


Fix comment mismatch, reorder crypto preferences for FIPS compliance, and use standard ssh service name.

  • Comment states "Disable password authentication for root" but PasswordAuthentication yes applies globally (enables password auth). Update the comment to reflect the actual setting.
  • Listing chacha20-poly1305@openssh.com first breaks FIPS compliance (ChaCha20-Poly1305 is not FIPS-approved). If FIPS compliance is a requirement, reorder to list only AES-GCM ciphers, or conditionally include ChaCha20 with documentation. If FIPS is not required, clarify this in a comment.
  • Use ssh.service instead of sshd.service to match Debian/Ubuntu conventions (the openssh-server package provides ssh.service; sshd.service is an alias for compatibility).
Suggested fixes
-# Disable password authentication for root
-PasswordAuthentication yes
+# Password authentication is enabled globally (set to "no" for key-only SSH)
+PasswordAuthentication yes

Reorder ciphers to prioritize FIPS-approved algorithms:

-Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
+Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,chacha20-poly1305@openssh.com

Use standard ssh service name:

-        if systemctl is-active --quiet sshd; then
-            systemctl reload sshd || true
+        if systemctl is-active --quiet ssh; then
+            systemctl reload ssh || true
         fi
🤖 Prompt for AI Agents
In @iso/provisioning/first-boot.sh around lines 116 - 168, The SSH hardening
block in setup_ssh has a mismatched comment for PasswordAuthentication, a
non‑FIPS-first cipher order in Ciphers, and uses the nonstandard service name
sshd; update the comment near PasswordAuthentication to reflect that it enables
or disables password auth globally (adjust text for PasswordAuthentication
yes/no to match the actual value of the setting), reorder the Ciphers line to
list AES-GCM ciphers first (e.g., aes256-gcm@openssh.com,aes128-gcm@openssh.com)
or remove chacha20-poly1305@openssh.com if FIPS compliance is required, and
change the systemctl checks/reload that reference sshd to use ssh (i.e., replace
systemctl is-active --quiet sshd and systemctl reload sshd with ssh) while
keeping the rest of setup_ssh and the sshd_config filename unchanged.

Comment on lines +235 to +256
# Configure automatic security updates
setup_unattended_upgrades() {
log_info "Configuring automatic security updates..."

if command -v unattended-upgrade &>/dev/null; then
local auto_upgrades="/etc/apt/apt.conf.d/20auto-upgrades"

if [[ ! -f "${auto_upgrades}" ]]; then
cat > "${auto_upgrades}" << 'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
EOF
log_info "Automatic security updates enabled"
else
log_info "Automatic updates already configured"
fi
else
log_warn "unattended-upgrades not installed, skipping"
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Either install unattended-upgrades or remove this step (currently a no-op in the default package set).

Given the preseed package list, this will almost always log “not installed, skipping.”

🤖 Prompt for AI Agents
In @iso/provisioning/first-boot.sh around lines 235 - 256, The
setup_unattended_upgrades function is effectively a no-op under the current
preseed because unattended-upgrades isn't installed; either ensure the package
is installed before the check or remove the function call. Modify
setup_unattended_upgrades to invoke package installation (e.g., apt-get install
-y unattended-upgrades) if command -v returns false, or delete the
setup_unattended_upgrades invocation and its helper if you intend not to enable
unattended upgrades by default; refer to the function name
setup_unattended_upgrades and the auto_upgrades variable to locate the relevant
code to change.

Comment on lines +258 to +277
# Desktop environment setup
setup_desktop() {
log_info "Configuring desktop environment..."

# Add Flathub repository if flatpak is installed
if command -v flatpak &>/dev/null && [[ "${NETWORK_AVAILABLE}" == "true" ]]; then
if ! flatpak remote-list | grep -q flathub; then
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo || true
log_info "Flathub repository added"
fi
fi

# Configure Docker for cortex user
if command -v docker &>/dev/null; then
if ! groups cortex | grep -q docker; then
usermod -aG docker cortex
log_info "Added cortex user to docker group"
fi
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Guard groups/usermod with an existence check for the cortex user.

If the user creation ever changes (or fails), groups cortex/usermod will hard-fail provisioning under set -e.

Proposed guard
     # Configure Docker for cortex user
     if command -v docker &>/dev/null; then
-        if ! groups cortex | grep -q docker; then
-            usermod -aG docker cortex
-            log_info "Added cortex user to docker group"
-        fi
+        if id -u cortex &>/dev/null; then
+            if ! id -nG cortex | tr ' ' '\n' | grep -qx docker; then
+                usermod -aG docker cortex
+                log_info "Added cortex user to docker group"
+            fi
+        else
+            log_warn "User 'cortex' not found; skipping docker group setup"
+        fi
     fi
🤖 Prompt for AI Agents
In @iso/provisioning/first-boot.sh around lines 258 - 277, The setup_desktop
function calls groups cortex and usermod -aG docker cortex without checking the
cortex user exists, which can cause the script to fail under set -e; before
invoking groups or usermod, guard those calls with a check like getent passwd
cortex (or id -u cortex) to ensure the user exists, and only run groups and
usermod when that check succeeds so setup_desktop safely skips Docker group
configuration if the cortex user is missing.

Comment on lines +279 to +316
# Add Cortex repository (requires network)
setup_cortex_repository() {
if [[ "${NETWORK_AVAILABLE}" != "true" ]]; then
log_warn "Network unavailable, skipping Cortex repository setup"
return 0
fi

log_info "Setting up Cortex package repository..."

local keyring_dir="/usr/share/keyrings"
local sources_file="/etc/apt/sources.list.d/cortex-linux.list"

# Check if already configured (from live image or previous run)
if [[ -f "${sources_file}" ]]; then
log_info "Cortex repository already configured"
return 0
fi

log_info "Adding Cortex Linux APT repository..."

# Download and install GPG key
if curl -fsSL https://apt.cortexlinux.com/keys/cortex-linux.gpg.asc | gpg --dearmor -o "${keyring_dir}/cortex-linux.gpg"; then
log_info "Cortex GPG key installed"
else
log_error "Failed to download Cortex GPG key"
return 1
fi

# Add repository source
echo "deb [signed-by=${keyring_dir}/cortex-linux.gpg] https://apt.cortexlinux.com stable main" > "${sources_file}"

# Update package lists
if apt-get update -qq; then
log_info "Cortex repository configured successfully"
else
log_warn "apt-get update failed, repository may not be accessible"
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🌐 Web query:

/usr/share/keyrings directory Debian Ubuntu default exists standard

💡 Result:

Short answer: No — /usr/share/keyrings is not guaranteed to be present on a fresh Debian/Ubuntu install; it is the conventional location for keyring files that are installed and managed by packages, and packages that provide keyrings will place files there. For locally-managed repository keys you should use /etc/apt/keyrings instead. [1][2][3]

Sources:

  1. Debian Wiki — DebianKeyring (notes that installed keyrings are placed in /usr/share/keyrings). [Debian Wiki]. [1]
  2. Debian Wiki — UseThirdParty / guidance: /usr/share/keyrings for package-managed keys, /etc/apt/keyrings for locally managed keys. [2]
  3. APT notes / documentation explaining how /usr/share/keyrings is used (ignored by default unless referenced with signed-by). [3]

🏁 Script executed:

# Check if there are other instances of keyring setup in the codebase
rg -n "keyrings|gpg.*--dearmor" iso/provisioning/ --type sh

Repository: cortexlinux/cortex-distro

Length of output: 313


🏁 Script executed:

# Check if there are other repository setup examples in the script
rg -n "apt-key|sources.list|signed-by" iso/provisioning/first-boot.sh -A 3 -B 3

Repository: cortexlinux/cortex-distro

Length of output: 618


🌐 Web query:

/etc/apt/keyrings directory Debian Ubuntu APT local repository keys exists

💡 Result:

Short answer: Yes — /etc/apt/keyrings is the recommended place for locally-managed APT repository OpenPGP key files (keys managed by you, not by a package). Newer APT (since ~2.4) uses this location and you should reference the key with the signed-by= option in your source entry. On older Debian/Ubuntu releases the directory may not exist by default; create it (mode 0755) and place dearmoured .gpg key files there. [1][2][3]

Useful references:

  • Debian guidance: Use /etc/apt/keyrings for locally-managed keys (use /usr/share/keyrings for keys installed by packages). [1]
  • Debian SecureApt / apt-key deprecation details. [2]
  • Ubuntu/apt manpage and examples showing /etc/apt/keyrings + signed-by usage. [3]

🌐 Web query:

apt-get GPG key file permissions requirements 0644 readable

💡 Result:

apt (and apt-key/apt-key-like checks) requires repository public-key files to be readable by the unprivileged _apt user. If a key file in /etc/apt/trusted.gpg or /etc/apt/trusted.gpg.d/ is not world- or _apt-readable apt will ignore it and you'll see messages like "the key(s) ... are ignored as the file is not readable by user '_apt'". Recommended permissions are 0644 (rw‑r--r--) with root ownership (or root:root); 0644 makes the file readable by _apt. Alternatively you may set owner to _apt so only that user needs read (chown _apt:root). Example fixes:

  • Make file world-readable:
    sudo chmod 644 /etc/apt/trusted.gpg.d/NAME.gpg

  • Or make it readable by _apt:
    sudo chown _apt:root /etc/apt/trusted.gpg.d/NAME.gpg
    sudo chmod 640 /etc/apt/trusted.gpg.d/NAME.gpg

Note: current best practice is to store third‑party keys under /etc/apt/keyrings or /usr/share/keyrings and use the signed-by option in your sources, instead of putting many keys into /etc/apt/trusted.gpg.d. (blog.cynexia.com)

Citations:


🏁 Script executed:

# Check if there are other uses of /etc/apt or keyrings in the codebase
rg -n "/etc/apt" iso/provisioning/ --type sh

Repository: cortexlinux/cortex-distro

Length of output: 271


Use /etc/apt/keyrings for locally-managed repository keys, not /usr/share/keyrings — and ensure directory and key file have correct permissions.

The current code uses /usr/share/keyrings, which is reserved for package-managed keys per Debian guidelines. Locally-downloaded keys should go in /etc/apt/keyrings. Additionally, create the directory with proper permissions and ensure the key file is readable by the _apt user.

Proposed fix
-    local keyring_dir="/usr/share/keyrings"
+    local keyring_dir="/etc/apt/keyrings"
     local sources_file="/etc/apt/sources.list.d/cortex-linux.list"
+    mkdir -p "${keyring_dir}"
+    chmod 0755 "${keyring_dir}"
 
     # Download and install GPG key
     if curl -fsSL https://apt.cortexlinux.com/keys/cortex-linux.gpg.asc | gpg --dearmor -o "${keyring_dir}/cortex-linux.gpg"; then
         log_info "Cortex GPG key installed"
+        chmod 0644 "${keyring_dir}/cortex-linux.gpg"
     else
         log_error "Failed to download Cortex GPG key"
         return 1

Comment on lines +318 to +336
# Generate SSH host keys if missing
setup_ssh_keys() {
log_info "Checking SSH host keys..."

local keys_generated=false

for keytype in rsa ecdsa ed25519; do
local keyfile="/etc/ssh/ssh_host_${keytype}_key"
if [[ ! -f "${keyfile}" ]]; then
ssh-keygen -t "${keytype}" -f "${keyfile}" -N "" -q
keys_generated=true
log_info "Generated SSH ${keytype} host key"
fi
done

if [[ "${keys_generated}" == "true" ]]; then
systemctl restart sshd || true
fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Debian SSH systemd service name sshd vs ssh unit

💡 Result:

Short answer

  • On Debian the packaged systemd unit is named ssh.service (not sshd.service); the daemon binary remains /usr/sbin/sshd and config files are still sshd_config. [1][2]
  • Debian also ships socket/template units ssh.socket and ssh@.service for socket-activated or traditional modes. Some recent/unreleased changes add an sshd@.service template in experimental/sid. [1][2][4]

What that means for you

  • Use systemctl start|stop|restart ssh (or manage ssh.socket / ssh@.service for socket activation). systemctl restart sshd may not exist on some Debian/Ubuntu installs. [1][2]
  • The “sshd” names are still used for the binary, configs and PAM files (sshd_config, /etc/pam.d/sshd). Renaming the unit to ssh is a packaging/compatibility choice. [2][5]

References
[1] Debian openssh-server file list (shows ssh.service, ssh.socket, ssh@.service).
[2] Debian mailing-list discussion / systemd support in openssh-server.
[3] Ask Ubuntu explanation that Debian/Ubuntu use ssh.service (not sshd).
[4] Debian bug/changelog showing addition of sshd@.service template in newer packaging.
[5] Debian package file lists showing /usr/sbin/sshd and sshd_config.


🌐 Web query:

systemctl restart sshd Debian compatibility service alias

💡 Result:

Short answer: On Debian the canonical systemd unit is ssh.service; sshd.service is provided as a compatibility alias so "systemctl restart sshd" usually works. Use ssh.service when creating drop-ins or editing the unit (override files must use the real unit name). [1][2][3]

Sources:

  • Debian Handbook — ssh.service unit (includes "Alias=sshd.service"). [1]
  • Debian Wiki (systemd guidance: use canonical service name). [2]
  • Debian mailing-list note: sshd.service is an alias for ssh.service (implications for drop‑ins). [3]

🏁 Script executed:

cat -n iso/provisioning/first-boot.sh | head -50

Repository: cortexlinux/cortex-distro

Length of output: 1638


🏁 Script executed:

# Check for any OS detection or Debian-specific logic in the script
rg -i "debian|ubuntu|systemd" iso/provisioning/first-boot.sh -B 2 -A 2

Repository: cortexlinux/cortex-distro

Length of output: 195


Use the correct SSH systemd unit name for Debian: ssh.service instead of sshd.

On Debian, the canonical systemd unit is ssh.service, not sshd. While sshd is provided as a compatibility alias on most installs, it may not exist on all Debian/Ubuntu systems, causing the restart to fail silently or error. Use ssh.service for consistency and reliability:

systemctl restart ssh || true

🤖 Prompt for AI Agents
In @iso/provisioning/first-boot.sh around lines 318 - 336, In setup_ssh_keys(),
the systemctl call uses the Debian-incompatible unit name "sshd"; change the
restart to use the canonical "ssh" unit instead (i.e., replace the systemctl
restart sshd || true call with systemctl restart ssh || true) so the SSH service
restart is reliable across Debian/Ubuntu systems after generating host keys.

- Updated README.md to streamline installation instructions and clarify build commands for ISO and dependencies.
- Removed obsolete references to specific profiles in the automated installation guide, consolidating to a single preseed file.
- Enhanced the developers' guide with clearer instructions for building ISOs and managing package lists.
- Introduced a new package list for complete system installations, replacing the removed core profile.
- Improved overall documentation structure for better clarity and usability.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In @docs/DEVELOPERS.md:
- Around line 137-142: The QEMU ARM64 example is missing firmware specification
causing boot failures; update the qemu-system-aarch64 invocation to add a
firmware flag (use either -bios or -pflash) and point it to the typical UEFI
firmware file (e.g., edk2-aarch64-code.fd), for example modify the
qemu-system-aarch64 command shown so it includes "-bios edk2-aarch64-code.fd"
(or "-pflash <path-to-edk2-aarch64-code.fd>") alongside the existing -M, -cpu,
-m and -cdrom options to ensure the VM can boot the ISO.

In @README.md:
- Around line 39-43: Update the README examples to reflect the date-based ISO
versioning used by ISO_VERSION: replace the hardcoded
cortex-linux-0.1.0-amd64.iso examples with a date-based pattern like
cortex-linux-YYYYMMDD-amd64.iso (e.g., cortex-linux-20250112-amd64.iso) or add a
note that the ISO name is generated from ISO_VERSION (date format), while
leaving the SBOM examples (which use CORTEX_VERSION and default to 0.1.0)
unchanged.
🧹 Nitpick comments (4)
docs/automated-installation.md (1)

25-27: Add language specifiers to fenced code blocks.

Several code blocks are missing language specifiers, which affects syntax highlighting and accessibility tools. Per static analysis hints, add appropriate language identifiers.

Suggested fixes

Line 25: Add language specifier for kernel boot parameters

-```
+```text
 preseed/file=/cdrom/preseed/cortex.preseed

Line 66: Add language specifier for preseed syntax

-```
+```text
 d-i partman-auto/expert_recipe string \

Line 109: Add language specifier for DHCP config

-```
+```text
 filename "pxelinux.0";

Line 131: Add language specifier for PXE config

-```
+```text
 DEFAULT cortex

Line 216: Add language specifier for preseed

-```
+```text
 d-i netcfg/disable_autoconfig boolean true

Also applies to: 66-74, 109-112, 131-136, 216-222

docs/DEVELOPERS.md (1)

208-212: Consider adding automated link verification to CI.

The Resources section links to external Debian documentation. Consider implementing periodic link validation in the CI/build process to catch broken references early, though this is optional.

README.md (2)

93-95: Clarify what's included versus what needs additional installation.

The terms "GPU support prerequisites" and "AI/ML prerequisites" are ambiguous. Consider specifying whether:

  • GPU drivers (NVIDIA/AMD) are pre-installed, or just kernel modules/dependencies
  • AI/ML packages (numpy, scipy, pandas) are pre-installed, or users need to install them post-boot

Suggestion: Use consistent language like "GPU driver support for NVIDIA and AMD" or "Pre-installed AI/ML libraries (numpy, scipy, pandas)" to clarify what's actually in the ISO.

📝 Proposed clarification
-- GPU support prerequisites (NVIDIA, AMD)
+- GPU driver support for NVIDIA and AMD hardware
 - Modern CLI tools (htop, btop, fzf, ripgrep, bat)
-- AI/ML prerequisites (numpy, scipy, pandas)
+- Pre-installed AI/ML libraries (numpy, scipy, pandas)

48-72: Consider adding a language specifier to the directory tree code block.

The static analysis tool flagged the fenced code block for missing a language specifier. While this is a minor issue, adding text or plaintext after the opening backticks would resolve the warning and improve Markdown compliance.

📝 Proposed fix for Markdown compliance
-```
+```text
 cortex-distro/
 ├── iso/                        # ISO build configuration

Based on static analysis hints from markdownlint-cli2.

📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 13953b2 and aa34a92.

📒 Files selected for processing (6)
  • README.md
  • docs/DEVELOPERS.md
  • docs/QUICK-START.md
  • docs/automated-installation.md
  • iso/live-build/config/package-lists/cortex-core.list.chroot
  • iso/live-build/config/package-lists/cortex.list.chroot
💤 Files with no reviewable changes (1)
  • iso/live-build/config/package-lists/cortex-core.list.chroot
🧰 Additional context used
🪛 LanguageTool
docs/automated-installation.md

[grammar] ~177-~177: Ensure spelling is correct
Context: ...rd:** Must be set at first login > The preseed uses a placeholder password hash. The f...

(QB_NEW_EN_ORTHOGRAPHY_ERROR_IDS_1)

🪛 markdownlint-cli2 (0.18.1)
README.md

56-56: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

docs/automated-installation.md

25-25: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


66-66: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


109-109: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


131-131: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


216-216: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (17)
docs/DEVELOPERS.md (2)

1-33: Clear and well-structured setup instructions.

The prerequisites section provides both automated (install-deps.sh) and manual installation paths, which is helpful for different user preferences. The version verification step for live-build is a good practice.


54-81: Project structure documentation is comprehensive.

The tree structure clearly documents the repository layout, including the new branding, provisioning, and live-build components introduced in this PR. This aligns well with the modular build system changes.

iso/live-build/config/package-lists/cortex.list.chroot (3)

233-238: Cortex package placeholders are appropriately commented.

The commented placeholders for cortex-archive-keyring, cortex-core, and cortex-console correctly indicate these will be enabled when the Cortex APT repository is available. This aligns with the modular branding approach documented in the PR.


1-14: LGTM on the refactored system base section.

The reorganization from "INCLUDE CORE" to "SYSTEM BASE" with explicit essential system utilities improves clarity. The package list now clearly defines the foundational system components.


151-157: No action needed. nvidia-smi is available as a standalone package in Debian's non-free archive and can be installed independently. The package is properly listed.

Likely an incorrect or invalid review comment.

docs/automated-installation.md (2)

76-101: First-boot provisioning documentation is thorough.

The documentation clearly explains idempotency, offline capability, state tracking location (/opt/cortex/provisioning/.first-boot-complete), and log locations. This aligns with the provisioning scripts introduced in iso/provisioning/.


230-236: Security considerations section provides essential guidance.

The recommendations for SSH key regeneration, system updates, firewall review, and fail2ban configuration are appropriate for production deployments.

docs/QUICK-START.md (4)

1-4: Clear and concise introduction.

The "2 minutes" promise sets appropriate expectations for the repository installation path. The guide effectively provides two clear installation options.


36-42: System requirements are reasonable.

The minimum (2GB RAM, 10GB disk) and recommended (4GB+ RAM, 20GB+ disk) requirements are appropriate for a development-oriented Linux distribution with container and AI/ML tooling.


86-89: Cross-references to related documentation are helpful.

The links to automated-installation.md and DEVELOPERS.md provide clear next steps for users who need more advanced workflows.


7-17: Verify APT repository URL is correct and accessible.

The documentation references https://apt.cortexlinux.com for the GPG key and repository installation. Ensure this domain is properly configured and both the /keys/cortex-linux.gpg.asc and repository endpoints are accessible, or update to the correct URL if different.

README.md (6)

46-72: LGTM! Clear and well-organized architecture documentation.

The directory structure accurately reflects the new branding-centric organization and clearly documents the preseed/provisioning infrastructure for automated installations.


161-171: LGTM! Build targets are clear and well-documented.

The simplified build target documentation aligns well with the streamlined build workflow. The explicit ARM64 target and install-deps convenience target improve usability.


196-196: Good addition of ARM64 architecture support.

Explicitly documenting ARM64 support aligns with the make iso ARCH=arm64 build target and makes hardware requirements clear for users.


134-134: Verify the cortex-branding package path and version.

The example references packages/cortex-branding_1.0.0_all.deb. Confirm:

  1. The package directory structure matches this path
  2. The version 1.0.0 is intentional (differs from the ISO version 0.1.0)
  3. The package naming convention follows Debian standards (package_version_arch.deb)

103-103: Preseed file is properly included.

The preseed file exists at iso/preseed/cortex.preseed and is tracked in the repository, so the boot parameter reference at line 103 is correct and will be properly included in the ISO build.


24-25: The scripts/install-deps.sh script exists with executable permissions set correctly. No action required.

Comment on lines 147 to 155
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-cpu host \
-cdrom cortex-linux-*.iso \
-drive file=cortex.qcow2,format=qcow2 \
-boot d \
-append "auto=true priority=critical preseed/file=/cdrom/preseed/cortex.preseed"
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

QEMU -append flag requires -kernel to function.

The -append parameter only works when booting with -kernel directly, not when booting from an ISO via -cdrom. For ISO-based installation with preseed, the boot parameters need to be edited interactively at the GRUB menu or baked into the ISO's bootloader configuration.

Suggested documentation fix
 # Boot from ISO with preseed
 qemu-system-x86_64 \
     -enable-kvm \
     -m 4096 \
     -cpu host \
     -cdrom cortex-linux-*.iso \
     -drive file=cortex.qcow2,format=qcow2 \
-    -boot d \
-    -append "auto=true priority=critical preseed/file=/cdrom/preseed/cortex.preseed"
+    -boot d
+
+# At the GRUB menu, edit the boot entry and append:
+# auto=true priority=critical preseed/file=/cdrom/preseed/cortex.preseed
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-cpu host \
-cdrom cortex-linux-*.iso \
-drive file=cortex.qcow2,format=qcow2 \
-boot d \
-append "auto=true priority=critical preseed/file=/cdrom/preseed/cortex.preseed"
```
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-cpu host \
-cdrom cortex-linux-*.iso \
-drive file=cortex.qcow2,format=qcow2 \
-boot d
# At the GRUB menu, edit the boot entry and append:
# auto=true priority=critical preseed/file=/cdrom/preseed/cortex.preseed

Comment on lines 137 to 142
# QEMU (amd64)
qemu-system-x86_64 -m 4G -cdrom output/cortex-linux-*.iso -boot d

# QEMU (arm64)
qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -cdrom output/cortex-linux-*-arm64.iso
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

QEMU arm64 command may not boot correctly without a firmware path.

The qemu-system-aarch64 command for ARM64 testing is missing the -bios or -pflash flag to specify UEFI firmware (typically edk2-aarch64-code.fd). Without this, the VM may fail to boot the ISO.

Suggested fix
 # QEMU (arm64)
-qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G -cdrom output/cortex-linux-*-arm64.iso
+qemu-system-aarch64 -M virt -cpu cortex-a72 -m 4G \
+  -bios /usr/share/qemu-efi-aarch64/QEMU_EFI.fd \
+  -cdrom output/cortex-linux-*-arm64.iso -boot d
🤖 Prompt for AI Agents
In @docs/DEVELOPERS.md around lines 137 - 142, The QEMU ARM64 example is missing
firmware specification causing boot failures; update the qemu-system-aarch64
invocation to add a firmware flag (use either -bios or -pflash) and point it to
the typical UEFI firmware file (e.g., edk2-aarch64-code.fd), for example modify
the qemu-system-aarch64 command shown so it includes "-bios
edk2-aarch64-code.fd" (or "-pflash <path-to-edk2-aarch64-code.fd>") alongside
the existing -M, -cpu, -m and -cdrom options to ensure the VM can boot the ISO.

Comment on lines +39 to +43
├── cortex-linux-0.1.0-amd64.iso # Bootable ISO
├── cortex-linux-0.1.0-amd64.iso.sha256
└── sbom/
├── cortex-linux-0.1.0.cdx.json # CycloneDX SBOM
└── cortex-linux-0.1.0.spdx.json # SPDX SBOM
├── cortex-linux-0.1.0.cdx.json # CycloneDX SBOM
└── cortex-linux-0.1.0.spdx.json # SPDX SBOM
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# Search for version references in build configuration and common config files
rg -n 'version\s*[=:]\s*["\']?0\.1\.0' -i --max-count=20

Repository: cortexlinux/cortex-distro

Length of output: 137


🏁 Script executed:

# Look for version definitions in common configuration files
fd -e 'py|toml|json|yaml|yml|sh|Makefile|mk|cfg|ini' --max-depth 3 | head -20

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Check the README.md file for version context
cat -n README.md | sed -n '30,50p'

Repository: cortexlinux/cortex-distro

Length of output: 632


🏁 Script executed:

# Search for version definitions without quote issues
rg -n '0\.1\.0' --max-count=30

Repository: cortexlinux/cortex-distro

Length of output: 1199


🏁 Script executed:

# Search for VERSION variable definitions
rg -n 'VERSION\s*=' --max-count=20

Repository: cortexlinux/cortex-distro

Length of output: 800


🏁 Script executed:

# List top-level files to identify build config
ls -la | grep -E 'Makefile|setup|version|VERSION'

Repository: cortexlinux/cortex-distro

Length of output: 127


🏁 Script executed:

# Check if there's a Makefile and search for version there
if [ -f Makefile ]; then head -50 Makefile; fi

Repository: cortexlinux/cortex-distro

Length of output: 1483


🏁 Script executed:

# Check Makefile for how ISO_VERSION and ISO_NAME are used
cat -n Makefile | grep -A 5 -B 5 'ISO_NAME\|ISO_VERSION'

Repository: cortexlinux/cortex-distro

Length of output: 1880


🏁 Script executed:

# Check the build.sh script to see actual ISO filename generation
rg -n 'ISO_NAME|ISO_VERSION' scripts/build.sh -A 2 -B 2

Repository: cortexlinux/cortex-distro

Length of output: 727


Update README.md output examples to reflect actual versioning scheme.

The documented ISO filename examples in lines 39-43 are inaccurate. The build system uses a date-based version format (YYYYMMDD) for ISO_VERSION, not the hardcoded 0.1.0 shown in the README. The actual ISO output will be cortex-linux-YYYYMMDD-amd64.iso (e.g., cortex-linux-20250112-amd64.iso), not cortex-linux-0.1.0-amd64.iso. Update the documentation examples to match the actual build output, or clearly indicate these are example filenames only.

Note: SBOM filenames default to 0.1.0 via CORTEX_VERSION, so those examples are correct; only the ISO filename examples require updating.

🤖 Prompt for AI Agents
In @README.md around lines 39 - 43, Update the README examples to reflect the
date-based ISO versioning used by ISO_VERSION: replace the hardcoded
cortex-linux-0.1.0-amd64.iso examples with a date-based pattern like
cortex-linux-YYYYMMDD-amd64.iso (e.g., cortex-linux-20250112-amd64.iso) or add a
note that the ISO name is generated from ISO_VERSION (date format), while
leaving the SBOM examples (which use CORTEX_VERSION and default to 0.1.0)
unchanged.

- Updated GitHub Actions workflow to use xz compression for release builds and lz4 for faster CI builds, optimizing build times and output size.
- Modified build.sh to support dynamic compression type based on the build context, improving efficiency and logging.
- Added liblz4-tool to the dependency installation script to support lz4 compression during builds.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 245-253: The GitHub Actions step named "Create Release" uses
softprops/action-gh-release@v1 which is outdated; update the uses value to
softprops/action-gh-release@v2 in that step (keep the existing inputs like files
unchanged), commit the workflow change, and validate by running the workflow or
a dry-run to ensure the v2 action accepts the same inputs and produces the
expected release artifacts.
- Around line 192-199: The Verify checksums step's loop can exit silently if no
.sha256 files exist; modify the shell block in the "Verify checksums" step to
detect whether any checksum files were found and validated (e.g., set a counter
or use nullglob to list *.sha256) and fail the step if none were verified by
exiting non-zero or printing an error; ensure you still run sha256sum -c for
each existing "${iso}.sha256" but after the loop check the counter (or absence
of matches) and call exit 1 with a clear message if zero checksum files were
processed.
- Around line 240-243: The checksum commands can fail when no .iso or .deb files
exist; update the workflow step that runs sha256sum and sha512sum to first
detect matching files (e.g., using a glob check or find) and only run sha256sum
*.iso *.deb and sha512sum *.iso *.deb when the file list is non-empty, otherwise
create empty/placeholder SHA256SUMS and SHA512SUMS or skip generation; modify
the shell block containing the sha256sum and sha512sum invocations so it guards
execution with a file-existence check before calling those tools.

In @scripts/build.sh:
- Around line 682-691: The script block that copies DEBIAN control files then
unconditionally runs chmod on "${pkg_dir}/DEBIAN/postinst" and
"${pkg_dir}/DEBIAN/prerm" can fail if those files are absent; update the logic
in scripts/build.sh to test for each file's existence before changing
permissions (or only chmod if the file exists) after the cp step, referencing
the variables PACKAGES_DIR, pkg_name and pkg_dir and the filenames postinst and
prerm so the script skips chmod when a file is missing and avoids a failure.
- Around line 286-294: The arithmetic expansion currently uses `$?` after an
assignment so it captures the exit status of the assignment (always 0) instead
of the function's return value; for each call (validate_provision,
validate_hooks, run_shellcheck) capture the function's exit code into a
temporary variable immediately after the call (e.g., local ret=0;
validate_provision || ret=$?) and then add that ret to errors with
errors=$((errors + ret)); this avoids miscapturing `$?` and is safe if set -e is
enabled.
🧹 Nitpick comments (2)
scripts/install-deps.sh (1)

14-16: Minor inconsistency in log prefix format.

The logging functions here use [+], [!], and [ERROR] prefixes, while scripts/build.sh uses [BUILD], [WARN], and [ERROR]. Consider aligning the prefix style for consistency across scripts. Based on the relevant code snippets from build.sh.

♻️ Optional: Align with build.sh logging style
-log() { echo -e "${GREEN}[+]${NC} $1"; }
-warn() { echo -e "${YELLOW}[!]${NC} $1"; }
+log() { echo -e "${GREEN}[DEPS]${NC} $1"; }
+warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
scripts/build.sh (1)

547-547: sudo lb build may fail silently under set -e in certain edge cases.

The sudo lb build command runs the actual ISO build. Consider capturing and checking the exit status explicitly, and logging more context on failure to aid debugging.

♻️ Proposed enhancement
 build_iso() {
     header "Building ISO"

     cd "$BUILD_DIR"

     log "Starting live-build (this may take a while)..."
-    sudo lb build
+    if ! sudo lb build; then
+        error "live-build failed. Check build.log for details."
+        exit 1
+    fi

     log "Build complete"
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between aa34a92 and 070ed6b.

📒 Files selected for processing (3)
  • .github/workflows/build-iso.yml
  • scripts/build.sh
  • scripts/install-deps.sh
🧰 Additional context used
🧬 Code graph analysis (1)
scripts/install-deps.sh (1)
scripts/build.sh (3)
  • error (44-44)
  • log (42-42)
  • warn (43-43)
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

246-246: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (8)
scripts/install-deps.sh (2)

32-50: LGTM! Comprehensive package list for live-build.

The package selection covers all necessary build tools including live-build, debootstrap, squashfs-tools, xorriso, bootloader utilities, and the newly added liblz4-tool for lz4 compression support as mentioned in the PR objectives.


56-65: No changes needed. The current bootloader package installation is correct for amd64 builds. The standard grub-pc-bin (64-bit) already supports legacy BIOS systems on amd64 architecture. There is no evidence in the codebase indicating that i386 cross-compilation support or multiarch configuration is required for this project's build process.

.github/workflows/build-iso.yml (2)

33-48: LGTM! Validation job properly configured.

The validation job correctly runs in a Debian bookworm container with necessary dependencies (git, sudo, make, shellcheck) and delegates to the Makefile's validate target.


122-141: Verify privileged Docker mode is acceptable for your CI environment.

The --privileged flag grants extensive capabilities to the container. While this is typically required for live-build operations (loopback mounts, chroot), ensure this aligns with your security policies.

scripts/build.sh (4)

7-7: Good use of strict mode.

set -euo pipefail provides robust error handling: exit on error, undefined variable access, and pipeline failures. This is best practice for build scripts.


63-72: Unquoted glob expansion is intentional but fragile with special characters.

The copy_glob_if_exists function correctly disables shellcheck for the intentional glob expansion. However, if filenames contain spaces or special characters, this will break. Consider using find with -exec for robustness if this becomes an issue.


758-797: LGTM! Comprehensive help documentation.

The help text clearly documents all commands, environment variables, and provides usage examples. This improves developer experience significantly.


803-844: LGTM! Clean entry point with proper command dispatch.

The main function handles command dispatch cleanly with a sensible default (help) and proper error handling for unknown commands.

Comment on lines +192 to +199
- name: Verify checksums
run: |
ls -la
for iso in *.iso; do
if [ -f "${iso}.sha256" ]; then
sha256sum -c "${iso}.sha256"
fi
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Checksum verification loop may silently pass when no checksums exist.

If no .sha256 files are present, the loop completes without error. Consider adding a check to ensure at least one checksum file was verified.

🔧 Proposed fix
      - name: Verify checksums
        run: |
          ls -la
+          verified=0
          for iso in *.iso; do
            if [ -f "${iso}.sha256" ]; then
              sha256sum -c "${iso}.sha256"
+              verified=$((verified + 1))
            fi
          done
+          if [ $verified -eq 0 ]; then
+            echo "WARNING: No checksum files found to verify"
+            exit 1
+          fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Verify checksums
run: |
ls -la
for iso in *.iso; do
if [ -f "${iso}.sha256" ]; then
sha256sum -c "${iso}.sha256"
fi
done
- name: Verify checksums
run: |
ls -la
verified=0
for iso in *.iso; do
if [ -f "${iso}.sha256" ]; then
sha256sum -c "${iso}.sha256"
verified=$((verified + 1))
fi
done
if [ $verified -eq 0 ]; then
echo "WARNING: No checksum files found to verify"
exit 1
fi
🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 192 - 199, The Verify checksums
step's loop can exit silently if no .sha256 files exist; modify the shell block
in the "Verify checksums" step to detect whether any checksum files were found
and validated (e.g., set a counter or use nullglob to list *.sha256) and fail
the step if none were verified by exiting non-zero or printing an error; ensure
you still run sha256sum -c for each existing "${iso}.sha256" but after the loop
check the counter (or absence of matches) and call exit 1 with a clear message
if zero checksum files were processed.

Comment on lines +286 to +294
;;
provision)
validate_provision || errors=$((errors + $?))
;;
hooks)
validate_hooks || errors=$((errors + $?))
;;
lint)
run_shellcheck || errors=$((errors + $?))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Arithmetic expansion of $? after || always yields 0 or 1.

When using validate_provision || errors=$((errors + $?)), the $? after || captures the exit status of the assignment (always 0), not validate_provision. The functions return actual error counts, but this pattern doesn't capture them correctly.

🔧 Proposed fix using command substitution or direct capture
        provision)
-            validate_provision || errors=$((errors + $?))
+            validate_provision || errors=1
            ;;
        hooks)
-            validate_hooks || errors=$((errors + $?))
+            validate_hooks || errors=1
            ;;
        lint)
-            run_shellcheck || errors=$((errors + $?))
+            run_shellcheck || errors=1
            ;;
        all)
            validate_preseed
            echo ""
-            validate_provision || errors=$((errors + $?))
+            validate_provision || errors=1
            echo ""
-            validate_hooks || errors=$((errors + $?))
+            validate_hooks || errors=1
            echo ""
-            run_shellcheck || errors=$((errors + $?))
+            run_shellcheck || errors=1
            ;;

Alternatively, if you need the actual error count:

if ! validate_provision; then
    errors=$((errors + $?))
fi

But note that set -e may interfere. A cleaner approach:

local ret=0
validate_provision || ret=$?
errors=$((errors + ret))
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
;;
provision)
validate_provision || errors=$((errors + $?))
;;
hooks)
validate_hooks || errors=$((errors + $?))
;;
lint)
run_shellcheck || errors=$((errors + $?))
;;
provision)
validate_provision || errors=1
;;
hooks)
validate_hooks || errors=1
;;
lint)
run_shellcheck || errors=1
🤖 Prompt for AI Agents
In @scripts/build.sh around lines 286 - 294, The arithmetic expansion currently
uses `$?` after an assignment so it captures the exit status of the assignment
(always 0) instead of the function's return value; for each call
(validate_provision, validate_hooks, run_shellcheck) capture the function's exit
code into a temporary variable immediately after the call (e.g., local ret=0;
validate_provision || ret=$?) and then add that ret to errors with
errors=$((errors + ret)); this avoids miscapturing `$?` and is safe if set -e is
enabled.

- Changed environment variable from LB_COMPRESSION to SQUASHFS_COMP in the GitHub Actions workflow and build.sh script to ensure uniformity in compression handling.
- This update enhances clarity and maintains consistency across the build process.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @.github/workflows/build-iso.yml:
- Around line 245-253: The workflow is using the outdated
softprops/action-gh-release@v1 action which is incompatible with newer runners;
update the uses entry to softprops/action-gh-release@v2 (replace
"softprops/action-gh-release@v1" with "@v2") and ensure the existing inputs (the
multi-line files list: release/*.iso, release/*.deb, release/SHA256SUMS,
release/SHA512SUMS, release/sbom/*) remain unchanged and still supported by v2;
run a test pipeline to confirm the release step executes successfully and adjust
any v2-specific input names if the action's docs require it.
🧹 Nitpick comments (3)
.github/workflows/build-iso.yml (1)

192-208: Add nullglob or check for ISO existence to handle missing files gracefully.

If no .iso files exist (e.g., build failure), *.iso remains literal and the loops will fail confusingly. Consider adding a check or using bash's nullglob.

Suggested improvement
       - name: Verify checksums
         run: |
           ls -la
+          shopt -s nullglob
+          isos=(*.iso)
+          if [ ${#isos[@]} -eq 0 ]; then
+            echo "ERROR: No ISO files found"
+            exit 1
+          fi
           for iso in *.iso; do
             if [ -f "${iso}.sha256" ]; then
               sha256sum -c "${iso}.sha256"
             fi
           done
scripts/build.sh (2)

541-550: Consider validating sudo availability before use.

The script uses sudo lb build without first checking if sudo is available or if the user has the necessary privileges. This could lead to confusing failures partway through the build process.

💡 Suggested improvement

Add a sudo check early in cmd_build:

 cmd_build() {
     header "Building Cortex Linux ISO"
     log "Architecture: ${ARCH}"
     log "Debian version: ${DEBIAN_VERSION}"
 
+    # Verify sudo access early to fail fast
+    if ! sudo -v 2>/dev/null; then
+        error "sudo access required for building ISO"
+        exit 1
+    fi
+
     prepare_build_dir

619-626: Add safety check for rm -rf on variable paths.

While set -u provides some protection against unset variables, adding an explicit check before destructive operations is a defensive practice that prevents accidental data loss if variable definitions are ever modified.

💡 Suggested defensive check
 cmd_clean_all() {
     header "Cleaning all build artifacts"
 
+    # Safety check to prevent accidental rm -rf on root or home
+    if [[ -z "$BUILD_DIR" || "$BUILD_DIR" == "/" || "$BUILD_DIR" == "$HOME" ]]; then
+        error "BUILD_DIR has unsafe value: '$BUILD_DIR'"
+        exit 1
+    fi
+    if [[ -z "$OUTPUT_DIR" || "$OUTPUT_DIR" == "/" || "$OUTPUT_DIR" == "$HOME" ]]; then
+        error "OUTPUT_DIR has unsafe value: '$OUTPUT_DIR'"
+        exit 1
+    fi
+
     rm -rf "$BUILD_DIR"
     rm -rf "$OUTPUT_DIR"
 
     log "Full clean complete"
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 070ed6b and 26cc7f5.

📒 Files selected for processing (2)
  • .github/workflows/build-iso.yml
  • scripts/build.sh
🧰 Additional context used
🪛 actionlint (1.7.10)
.github/workflows/build-iso.yml

246-246: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (16)
.github/workflows/build-iso.yml (4)

75-86: LGTM on the matrix strategy and job dependencies.

The multi-architecture build matrix with fail-fast: false is appropriate - it allows both architectures to complete even if one fails, which is useful for debugging. The dependency chain (validatebuild-branding-packagebuild-iso) ensures proper build ordering.


122-141: Docker-based build approach is solid.

The compression strategy (xz for releases, lz4 for PR builds) provides a good balance between size and build speed. Using set -e ensures the build fails fast on errors. The privileged container is necessary for live-build operations.


210-237: Release artifact collection is well-structured.

The continue-on-error: true for SBOM download is appropriate since SBOM generation may be optional. Using merge-multiple: true with patterns cleanly consolidates artifacts from the matrix builds.


88-97: The jlumbroso/free-disk-space action does not publish versioned releases. The repository is maintained only on the main branch, making @main the only available reference. The suggested pin to v1.3.1 is not a valid version tag for this action and cannot be implemented.

If reproducibility and supply-chain safety are concerns with using @main, consider evaluating alternative disk-cleanup actions that publish releases, or accept the trade-off of using @main for this particular action.

Likely an incorrect or invalid review comment.

scripts/build.sh (12)

1-36: LGTM!

The script header and configuration section are well-structured with sensible defaults, proper set -euo pipefail for strict error handling, and clear organization.


42-47: LGTM!

Clean logging functions with appropriate color coding and stderr output for errors.


63-72: LGTM!

The copy_glob_if_exists function correctly uses shellcheck disable for intentional glob expansion. The pattern check before copy prevents errors on non-matching globs.


90-150: LGTM!

Thorough dependency checking with clear separation between required and optional dependencies. The version checks using dpkg --compare-versions are appropriate for a Debian-based distro build script.


156-180: LGTM!

The preseed validation correctly checks for trailing whitespace which could cause issues in preseed files. The regex '^[^#]*[[:space:]]$' appropriately ignores commented lines.


277-318: LGTM!

The cmd_validate dispatcher is well-structured with clear mode handling. The error accumulation pattern || errors=$((errors + $?)) correctly captures function return values before the || short-circuit evaluates.


324-420: LGTM!

Comprehensive test suite covering preseed files, provisioning scripts, branding assets, hooks, and package control files. The syntax validation for shell scripts and consistent pass/fail reporting provide good pre-build verification.


491-518: LGTM!

The configure_live_build function has a well-documented compression choice (lz4 for CI speed vs xz for release size), comprehensive lb config options, and good logging.


644-658: LGTM!

The sync function correctly checks for directory existence before copying and provides appropriate warnings.


664-752: LGTM!

The branding package function correctly structures the .deb package with appropriate directory hierarchy, sets proper permissions on maintainer scripts, and includes the GRUB background conversion for compatibility. The cleanup of the temporary package directory prevents accumulation of build artifacts.


758-797: LGTM!

Comprehensive help documentation with clear command descriptions, environment variable documentation, and practical examples.


803-844: LGTM!

Clean command dispatcher with sensible default to help, graceful handling of missing arguments via shift || true, and proper error handling for unknown commands.

Comment on lines 245 to +253
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
*.iso
*.deb
SHA256SUMS
SHA512SUMS
release/*.iso
release/*.deb
release/SHA256SUMS
release/SHA512SUMS
release/sbom/*
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Update softprops/action-gh-release to v2.

Static analysis indicates @v1 is too old for current GitHub Actions runners. The action should be updated to v2 for compatibility and continued support.

Suggested fix
       - name: Create Release
-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@v2
         with:
           files: |
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
*.iso
*.deb
SHA256SUMS
SHA512SUMS
release/*.iso
release/*.deb
release/SHA256SUMS
release/SHA512SUMS
release/sbom/*
- name: Create Release
uses: softprops/action-gh-release@v2
with:
files: |
release/*.iso
release/*.deb
release/SHA256SUMS
release/SHA512SUMS
release/sbom/*
🧰 Tools
🪛 actionlint (1.7.10)

246-246: the runner of "softprops/action-gh-release@v1" action is too old to run on GitHub Actions. update the action's version to fix this issue

(action)

🤖 Prompt for AI Agents
In @.github/workflows/build-iso.yml around lines 245 - 253, The workflow is
using the outdated softprops/action-gh-release@v1 action which is incompatible
with newer runners; update the uses entry to softprops/action-gh-release@v2
(replace "softprops/action-gh-release@v1" with "@v2") and ensure the existing
inputs (the multi-line files list: release/*.iso, release/*.deb,
release/SHA256SUMS, release/SHA512SUMS, release/sbom/*) remain unchanged and
still supported by v2; run a test pipeline to confirm the release step executes
successfully and adjust any v2-specific input names if the action's docs require
it.

- Implemented functionality to copy the GRUB theme from the branding directory to the includes.chroot directory during the build process.
- Ensured that the theme is copied both in the prepare_build_dir and cmd_sync functions, enhancing the customization of the installed system's boot experience.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In @scripts/build.sh:
- Around line 695-704: The script unconditionally chmods DEBIAN/postinst and
DEBIAN/prerm which will fail if those files are absent; update the block after
the cp to test each file exists before changing mode (e.g., if [ -f
"${pkg_dir}/DEBIAN/postinst" ]; then chmod 755 "${pkg_dir}/DEBIAN/postinst"; fi
and same for prerm), or alternatively iterate over existing files matching
"${pkg_dir}/DEBIAN/postinst" and "${pkg_dir}/DEBIAN/prerm" and chmod only those
present to avoid "No such file or directory" errors.
🧹 Nitpick comments (2)
scripts/build.sh (2)

375-387: Minor inconsistency: Hook test only checks .hook.chroot files.

The cmd_test function only tests *.hook.chroot files, while validate_hooks (line 217) tests both *.hook.chroot and *.hook.binary. Consider aligning the test coverage.

♻️ Suggested fix
     # Test hooks
     log "Testing live-build hooks..."
     local hooks_dir="${ISO_DIR}/live-build/config/hooks/live"
-    for hook in "$hooks_dir"/*.hook.chroot; do
+    for hook in "$hooks_dir"/*.hook.chroot "$hooks_dir"/*.hook.binary; do
         if [ -f "$hook" ]; then
             if bash -n "$hook"; then
                 pass "$(basename "$hook"): syntax OK"

652-670: Silent failure on copy errors.

The [ -d ... ] && cp -r ... pattern masks copy failures. If a directory exists but the copy fails (e.g., permission denied, disk full), no error is reported and the function logs "Config synced" despite incomplete sync.

♻️ Suggested fix using explicit error handling
 cmd_sync() {
     header "Syncing config"

     if [ -d "$BUILD_DIR" ]; then
-        [ -d "${ISO_DIR}/live-build/config/hooks" ] && \
-            cp -r "${ISO_DIR}/live-build/config/hooks" "${BUILD_DIR}/config/"
-        [ -d "${ISO_DIR}/live-build/config/includes.chroot" ] && \
-            cp -r "${ISO_DIR}/live-build/config/includes.chroot" "${BUILD_DIR}/config/"
-        [ -d "${ISO_DIR}/live-build/config/includes.binary" ] && \
-            cp -r "${ISO_DIR}/live-build/config/includes.binary" "${BUILD_DIR}/config/"
+        if [ -d "${ISO_DIR}/live-build/config/hooks" ]; then
+            cp -r "${ISO_DIR}/live-build/config/hooks" "${BUILD_DIR}/config/" && log "Synced hooks"
+        fi
+        if [ -d "${ISO_DIR}/live-build/config/includes.chroot" ]; then
+            cp -r "${ISO_DIR}/live-build/config/includes.chroot" "${BUILD_DIR}/config/" && log "Synced includes.chroot"
+        fi
+        if [ -d "${ISO_DIR}/live-build/config/includes.binary" ]; then
+            cp -r "${ISO_DIR}/live-build/config/includes.binary" "${BUILD_DIR}/config/" && log "Synced includes.binary"
+        fi
         # Copy GRUB theme to includes.chroot
         if [ -d "${BRANDING_DIR}/grub/cortex" ]; then
             mkdir -p "${BUILD_DIR}/config/includes.chroot/boot/grub/themes/cortex"
-            cp -r "${BRANDING_DIR}/grub/cortex/"* "${BUILD_DIR}/config/includes.chroot/boot/grub/themes/cortex/"
+            cp -r "${BRANDING_DIR}/grub/cortex/"* "${BUILD_DIR}/config/includes.chroot/boot/grub/themes/cortex/" && log "Synced GRUB theme"
         fi
         log "Config synced"
     else
         warn "Build directory not found: ${BUILD_DIR}"
     fi
 }
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 26cc7f5 and c9c502b.

📒 Files selected for processing (1)
  • scripts/build.sh
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build ISO (amd64)
  • GitHub Check: Build (First Pass)
🔇 Additional comments (8)
scripts/build.sh (8)

1-48: LGTM!

The configuration and logging setup is well-structured. Good use of set -euo pipefail for strict error handling, and the path derivation from SCRIPT_DIR is safe.


53-84: LGTM!

Helper functions are appropriately designed. The intentional unquoted glob expansion in copy_glob_if_exists is acceptable for this controlled build environment, and the shellcheck disable comment correctly acknowledges this.


90-150: LGTM!

Thorough dependency checking with good separation between required and optional dependencies. The version checking for live-build and Python is well implemented with appropriate fallbacks and warnings.


152-318: LGTM!

The validation subsystem is well-designed with clear separation of concerns. The || errors=$((errors + $?)) pattern correctly captures error counts while preventing script exit under set -e.


422-609: LGTM!

The ISO build functions are well-structured. The dual GRUB theme copying (in prepare_build_dir for the installed system and copy_grub_theme for live boot) aligns with the commit message objectives. The exit 1 on missing required theme.txt is appropriate.


611-646: LGTM!

Clean functions are appropriately designed. The rm -rf operations on build/output directories are safe since the paths are derived from the project root.


771-810: LGTM!

Comprehensive and well-organized help text covering all commands, environment variables, and examples.


816-857: LGTM!

Clean dispatcher pattern with good defaults. The shift || true pattern correctly handles the case when no arguments are provided.

- Deleted the .github/workflows/reproducible-builds.yml file, removing the entire reproducible builds workflow from the CI/CD pipeline.
- This change simplifies the workflow configuration and eliminates the need for maintaining the associated build and comparison steps.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot:
- Around line 99-102: The sed replacement will never trigger the echo fallback
because sed exits 0 when no match is found; change the logic to explicitly test
for an existing GRUB_DISTRIBUTOR line first (e.g., grep -q '^GRUB_DISTRIBUTOR='
/etc/default/grub), and if found run the sed substitution to replace its value,
otherwise append GRUB_DISTRIBUTOR="Cortex Linux" to /etc/default/grub; update
the block that currently runs sed ... || echo to use this conditional check so
the echo fallback actually occurs when the variable is missing.
- Around line 19-31: The branding assets use two different domains; standardize
to a single canonical domain across all files by replacing all occurrences of
the alternate domain with the chosen canonical one: update the os-release
entries HOME_URL, SUPPORT_URL and PRIVACY_POLICY_URL (currently set to
cortex.io) to match the canonical domain you pick, and update the MOTD footer
(the footer text that references cortexlinux.com/support and
docs.cortexlinux.com) and any branding comments that reference
apt.cortexlinux.com so they all use the same domain string consistently; ensure
you change every occurrence (HOME_URL, SUPPORT_URL, PRIVACY_POLICY_URL, MOTD
footer text, and branding comments) to the chosen canonical domain.
🧹 Nitpick comments (5)
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (5)

160-162: Loop may silently skip on glob mismatch.

When /etc/update-motd.d/* matches no files, bash defaults to iterating over the literal string. The [ -f "$f" ] guard handles this, but adding shopt -s nullglob or checking for directory existence first would be cleaner.

♻️ Optional improvement
 # Disable default Debian MOTD scripts
+if [ -d /etc/update-motd.d ]; then
-for f in /etc/update-motd.d/*; do
-    [ -f "$f" ] && chmod -x "$f"
-done
+    for f in /etc/update-motd.d/*; do
+        [ -f "$f" ] && chmod -x "$f"
+    done
+fi

198-206: Minor: Avoid useless use of cat.

cat /proc/loadavg | awk can be simplified to awk '{print $1, $2, $3}' /proc/loadavg.

♻️ Suggested simplification
-LOAD=$(cat /proc/loadavg | awk '{print $1, $2, $3}')
+LOAD=$(awk '{print $1, $2, $3}' /proc/loadavg)

232-245: Potential slow login if apt cache is stale.

apt list --upgradable can be slow without a recent apt update. Consider caching results or adding a timeout to avoid blocking user login.

♻️ Add timeout to prevent login delays
     else
         # Quick check (may not be accurate without apt update)
-        UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable || echo "0")
+        UPDATES=$(timeout 2 apt list --upgradable 2>/dev/null | grep -c upgradable || echo "0")
         SECURITY="?"
     fi

269-274: Potential command injection if notice file contains shell metacharacters.

While /opt/cortex/notice is likely controlled, piping file contents directly to sed and displaying could have unexpected behavior with special characters. Consider using cat with proper quoting or printf '%s\n'.

♻️ Safer approach
 CORTEX_NOTICE="/opt/cortex/notice"
 if [ -f "$CORTEX_NOTICE" ]; then
     echo -e "  ${CYAN}◆ Cortex Notice:${RESET}"
-    cat "$CORTEX_NOTICE" | sed 's/^/    /'
+    while IFS= read -r line; do
+        printf '    %s\n' "$line"
+    done < "$CORTEX_NOTICE"
     echo ""
 fi

352-362: Consider using image_source instead of ascii_distro for custom ASCII.

Neofetch's ascii_distro is designed for built-in distro names. For custom ASCII art, using image_source="/usr/share/neofetch/ascii/distro/cortex" in the config may be more reliable.

♻️ More reliable custom ASCII configuration
 # Cortex branding colors (purple/cyan)
 colors=(5 6 7 5 6 7)
 bold="on"
-ascii_distro="cortex"
+image_source="/usr/share/neofetch/ascii/distro/cortex"
+image_backend="ascii"
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c9c502b and 09eede1.

📒 Files selected for processing (3)
  • .github/workflows/reproducible-builds.yml
  • iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot
  • iso/live-build/config/package-lists/cortex.list.chroot
💤 Files with no reviewable changes (1)
  • .github/workflows/reproducible-builds.yml
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build ISO (amd64)
🔇 Additional comments (7)
iso/live-build/config/package-lists/cortex.list.chroot (4)

1-14: LGTM! System base packages are well-organized.

The essential system utilities section correctly includes the minimal required packages for a functioning Debian-based system (systemd, dbus, udev, init).


191-191: Good addition to support branding.

Adding neofetch aligns with the branding hook script that creates custom Cortex neofetch configuration and ASCII art.


234-239: Placeholder packages are clearly documented.

The commented Cortex packages with the explanatory note about APT repository availability is a reasonable approach for bootstrapping.


151-156: No action needed — nvidia-smi is available as a standalone package in Debian Bookworm.

nvidia-smi is provided as a standalone non-free package in Debian Bookworm and resolves independently with its dependencies (libnvidia-ml runtime and related packages). The package list inclusion is valid.

Likely an incorrect or invalid review comment.

iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (3)

9-11: Good use of strict error handling.

set -e ensures the script fails fast on errors, appropriate for a build-time hook where partial branding would be problematic.


368-373: Good: initramfs update included for Plymouth changes.

Running update-initramfs -u ensures the Plymouth theme is properly included in the initramfs for boot splash display.


345-349: No action required. The ascii_distro="cortex" configuration will work correctly because the hook script itself creates the ASCII file at /usr/share/neofetch/ascii/distro/cortex (lines 352–354) before the neofetch config references it. The ASCII art is properly formatted with valid color tokens.

Likely an incorrect or invalid review comment.

Comment on lines 19 to 31
cat > /etc/os-release << 'EOF'
PRETTY_NAME="Cortex Linux"
NAME="Cortex Linux"
VERSION_ID="1.0"
VERSION="1.0 (Bookworm)"
VERSION_CODENAME=bookworm
ID=cortex
ID_LIKE=debian
HOME_URL="https://cortex.io"
SUPPORT_URL="https://cortex.io/support"
BUG_REPORT_URL="https://github.com/cortex/cortex-distro/issues"
PRIVACY_POLICY_URL="https://cortex.io/privacy"
EOF
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for domain references in the entire repository
echo "=== All references to cortex domains ==="
rg "cortex\.io|cortexlinux\.com|cortexlinux\.io|docs\.cortexlinux" -n --type sh --type txt
echo ""
echo "=== Checking the specific file ==="
cat -n iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot 2>/dev/null | head -40

Repository: cortexlinux/cortex-distro

Length of output: 2331


🏁 Script executed:

#!/bin/bash
# Check file length and search for MOTD
echo "=== File line count ==="
wc -l iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot

echo ""
echo "=== Looking for MOTD section ==="
rg -n "MOTD|motd" iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot

echo ""
echo "=== Search for domain references in the branding file ==="
rg -n "cortex\.io|cortexlinux\.com|cortexlinux\.io|docs\.cortexlinux" iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot

Repository: cortexlinux/cortex-distro

Length of output: 1566


Resolve domain inconsistency across branding files.

The os-release file uses cortex.io (HOME_URL, SUPPORT_URL, PRIVACY_POLICY_URL) while the MOTD footer references cortexlinux.com and docs.cortexlinux.com. Choose one canonical domain and update all branding files accordingly:

  • os-release (lines 27-30): cortex.io
  • MOTD footer (line 306): cortexlinux.com/support and docs.cortexlinux.com
  • Branding file comments (lines 53, 56-57): reference apt.cortexlinux.com
🤖 Prompt for AI Agents
In @iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot around lines
19 - 31, The branding assets use two different domains; standardize to a single
canonical domain across all files by replacing all occurrences of the alternate
domain with the chosen canonical one: update the os-release entries HOME_URL,
SUPPORT_URL and PRIVACY_POLICY_URL (currently set to cortex.io) to match the
canonical domain you pick, and update the MOTD footer (the footer text that
references cortexlinux.com/support and docs.cortexlinux.com) and any branding
comments that reference apt.cortexlinux.com so they all use the same domain
string consistently; ensure you change every occurrence (HOME_URL, SUPPORT_URL,
PRIVACY_POLICY_URL, MOTD footer text, and branding comments) to the chosen
canonical domain.

Comment on lines 99 to 102
# Also set timeout and other branding options
sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

Bug: GRUB_DISTRIBUTOR will not be appended if missing.

The sed command returns exit code 0 even when the pattern isn't found (it just produces no substitutions). The || echo fallback will never execute.

🐛 Proposed fix
     # Also set timeout and other branding options
-    sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
-        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    if grep -q "^GRUB_DISTRIBUTOR=" /etc/default/grub; then
+        sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub
+    else
+        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Also set timeout and other branding options
sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
fi
# Also set timeout and other branding options
if grep -q "^GRUB_DISTRIBUTOR=" /etc/default/grub; then
sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub
else
echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
fi
fi
🤖 Prompt for AI Agents
In @iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot around lines
99 - 102, The sed replacement will never trigger the echo fallback because sed
exits 0 when no match is found; change the logic to explicitly test for an
existing GRUB_DISTRIBUTOR line first (e.g., grep -q '^GRUB_DISTRIBUTOR='
/etc/default/grub), and if found run the sed substitution to replace its value,
otherwise append GRUB_DISTRIBUTOR="Cortex Linux" to /etc/default/grub; update
the block that currently runs sed ... || echo to use this conditional check so
the echo fallback actually occurs when the variable is missing.

- Introduced a new GNOME terminal profile for Cortex Linux, enhancing user experience with customized colors and settings.
- Updated PAM configuration files for login and SSH services to enable dynamic message of the day (MOTD) display.
- Added a new .bashrc file with Cortex-specific aliases and prompt customization for improved usability and branding.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In @iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot:
- Around line 98-124: The GNOME Terminal profile block uses an invalid literal
name "cortex"; replace the profile path
[org/gnome/terminal/legacy/profiles:/:cortex] with a valid UUID-based path
(e.g., [org/gnome/terminal/legacy/profiles:/:<UUID>]) and update
default='cortex' and list=['cortex'] to reference that same UUID string; keep
visible-name='Cortex' unchanged and generate the UUID with uuidgen (or similar)
so all three places (profile section name, default, and list) use the identical
UUID.

In @iso/live-build/config/includes.chroot/etc/pam.d/login:
- Line 16: Remove the deprecated and insecure user_readenv=1 option from the
pam_env.so session line: locate the line that invokes pam_env.so (currently
"session required pam_env.so user_readenv=1 envfile=/etc/default/locale") and
either drop the user_readenv=1 entirely or change it to user_readenv=0 so the
entry reads "session required pam_env.so envfile=/etc/default/locale" (or with
user_readenv=0) to mitigate the CVE issues.
🧹 Nitpick comments (9)
iso/live-build/config/includes.chroot/etc/skel/.bashrc (2)

46-61: Consider using bash pattern matching for efficiency.

The function spawns multiple subshells (echo | grep) for each status check. Using bash's built-in pattern matching would be faster, especially since this runs on every prompt.

♻️ Suggested refactor using bash patterns
 __git_status() {
     local status=""
     local git_status=$(git status --porcelain 2>/dev/null)
     if [[ -n "$git_status" ]]; then
-        if echo "$git_status" | grep -q "^??"; then
+        if [[ "$git_status" == *$'\n?? '* ]] || [[ "$git_status" == '?? '* ]]; then
             status+="?"
         fi
-        if echo "$git_status" | grep -q "^.M\|^M"; then
+        if [[ "$git_status" =~ (^|$'\n')[^\ ]?M ]]; then
             status+="*"
         fi
-        if echo "$git_status" | grep -q "^A\|^.A"; then
+        if [[ "$git_status" =~ (^|$'\n')[^\ ]?A ]]; then
             status+="+"
         fi
     fi
     [[ -n "$status" ]] && echo " $status"
 }

87-89: Remove redundant stderr redirection.

&>/dev/null already redirects both stdout and stderr, making the trailing 2>&1 redundant.

♻️ Suggested fix
-    if git rev-parse --is-inside-work-tree &>/dev/null 2>&1; then
+    if git rev-parse --is-inside-work-tree &>/dev/null; then
iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot (3)

25-40: Duplicate GDM configuration files with identical content.

Both daemon.conf (Lines 27-32) and custom.conf (Lines 35-40) contain the same [daemon] section. GDM3 typically reads from custom.conf, making daemon.conf redundant. This duplication may cause maintenance confusion.

Consider removing daemon.conf and keeping only custom.conf:

Proposed fix
 # Configure GDM to start automatically in live mode
 mkdir -p /etc/gdm3
-cat > /etc/gdm3/daemon.conf << 'EOF'
-# Cortex Linux GDM Configuration for Live Environment
-[daemon]
-AutomaticLoginEnable=true
-AutomaticLogin=cortex
-EOF
-
-# Configure GDM session
 cat > /etc/gdm3/custom.conf << 'EOF'
 # Cortex Linux GDM Custom Configuration
 [daemon]
 AutomaticLoginEnable=true
 AutomaticLogin=cortex
+
+[security]
+
+[xdmcp]
+
+[chooser]
+
+[debug]
 EOF

61-61: Unnecessary executable permission on .desktop file.

Desktop entry files don't require executable permission in modern GNOME environments. The Exec line is interpreted by the desktop environment, not executed directly.

Proposed fix
-chmod +x /etc/skel/.config/autostart/welcome.desktop

150-153: Schema compilation may fail silently in chroot.

The glib-compile-schemas call suppresses all output, making debugging difficult if it fails. Consider adding error handling or at least logging the result.

Proposed fix
 # Compile schemas
 if command -v glib-compile-schemas &>/dev/null; then
-    glib-compile-schemas /usr/share/glib-2.0/schemas/
+    glib-compile-schemas /usr/share/glib-2.0/schemas/ || echo "    WARNING: Failed to compile GLib schemas"
 fi
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (4)

99-102: Potential double-append of GRUB_DISTRIBUTOR.

If sed fails for a reason other than the pattern not being found (e.g., permission issue), the || echo fallback will append a duplicate GRUB_DISTRIBUTOR line. Consider checking if the key exists first:

Proposed fix
     # Also set timeout and other branding options
-    sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
-        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    if grep -q "^GRUB_DISTRIBUTOR=" /etc/default/grub; then
+        sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub
+    else
+        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    fi
 fi

232-245: Update check logic conflates errors with "no updates".

Line 239's grep -c upgradable || echo "0" returns "0" both when there are no updates and when apt list fails. This could mislead users into thinking their system is up-to-date when apt encountered an error.

Proposed fix
     else
         # Quick check (may not be accurate without apt update)
-        UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable || echo "0")
+        UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable) || UPDATES="?"
         SECURITY="?"
     fi

260-263: Complex pipeline may produce unexpected output with special characters.

If package names contain unusual characters, the tr '\n' ',' and sed pipeline could produce malformed output. Additionally, cat | sed is a UUOC (useless use of cat).

Proposed fix
     if [ -f "/var/run/reboot-required.pkgs" ]; then
-        REBOOT_PKGS=$(cat /var/run/reboot-required.pkgs | head -3 | tr '\n' ', ' | sed 's/,$//')
+        REBOOT_PKGS=$(head -3 /var/run/reboot-required.pkgs | paste -sd ', ')
         echo -e "  ${GRAY}  Packages: ${REBOOT_PKGS}${RESET}"
     fi

269-274: UUOC and potential issues with untrusted notice content.

Using cat "$CORTEX_NOTICE" | sed is unnecessary, and if the notice file contains escape sequences, they could be interpreted unexpectedly by echo -e elsewhere or cause display issues.

Proposed fix
 CORTEX_NOTICE="/opt/cortex/notice"
 if [ -f "$CORTEX_NOTICE" ]; then
     echo -e "  ${CYAN}◆ Cortex Notice:${RESET}"
-    cat "$CORTEX_NOTICE" | sed 's/^/    /'
+    sed 's/^/    /' "$CORTEX_NOTICE"
     echo ""
 fi
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 09eede1 and 6564a1a.

📒 Files selected for processing (6)
  • branding/terminal/cortex-terminal.dconf
  • iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot
  • iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot
  • iso/live-build/config/includes.chroot/etc/pam.d/login
  • iso/live-build/config/includes.chroot/etc/pam.d/sshd
  • iso/live-build/config/includes.chroot/etc/skel/.bashrc
✅ Files skipped from review due to trivial changes (1)
  • branding/terminal/cortex-terminal.dconf
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Build ISO (amd64)
🔇 Additional comments (8)
iso/live-build/config/includes.chroot/etc/skel/.bashrc (5)

1-8: LGTM - Well-structured shell configuration.

The interactive shell check, history configuration, shell options, dircolors setup, and bash-completion sourcing all follow standard Debian/Ubuntu conventions and are implemented correctly.

Also applies to: 10-24, 103-114, 146-155


26-43: LGTM - Thoughtful prompt design.

The branded prompt correctly captures exit code at function entry, differentiates root vs. regular user styling, and includes git branch/status integration. The use of PROMPT_COMMAND for dynamic prompt generation is appropriate.

Also applies to: 64-86, 90-101


119-144: LGTM - Reasonable alias set.

The safety aliases (rm -i, cp -i, mv -i) are user-friendly defaults, and the htop-to-top fallback (line 139) gracefully handles missing packages. Cortex-specific aliases provide convenient shortcuts for system maintenance.


157-164: LGTM - Smart neofetch gate.

Using CORTEX_WELCOMED environment variable to prevent duplicate neofetch runs in subshells is a good pattern. The command -v check ensures graceful handling when neofetch isn't installed.


166-181: LGTM - PATH handling is correct.

The directory existence checks before PATH modification are appropriate, and prepending user directories ensures user-local binaries take precedence over system-wide ones.

iso/live-build/config/includes.chroot/etc/pam.d/sshd (1)

1-15: LGTM!

The PAM configuration follows standard Debian patterns for sshd. The dual pam_motd.so approach correctly displays both dynamic (/run/motd.dynamic) and static MOTD content. The module_unknown=ignore handling for pam_selinux.so ensures graceful fallback on systems without SELinux.

iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (2)

1-11: Overall script structure is well-organized.

The branding hook follows good practices: set -e for early failure detection, clear section comments, and graceful fallbacks for missing commands. The modular approach with verification warnings for missing assets aids debugging during ISO builds.

Also applies to: 366-374


159-162: This code is intentional branding behavior; no action needed.

The MOTD script disabling is documented through the section header, file purpose, and immediate replacement with a custom Cortex MOTD. Disabling default MOTD scripts does not break system behavior—MOTD only displays informational messages at login. Being selective would defeat the purpose of a branding hook that replaces default Debian messaging with Cortex identity.

Likely an incorrect or invalid review comment.

Comment on lines 98 to 124
[org/gnome/terminal/legacy/profiles:/:cortex]
audible-bell=false
background-color='#0D0D0D'
bold-color='#06B6D4'
bold-color-same-as-fg=false
bold-is-bright=true
cursor-background-color='#06B6D4'
cursor-colors-set=true
cursor-foreground-color='#0D0D0D'
cursor-shape='ibeam'
default-size-columns=120
default-size-rows=32
font='JetBrains Mono 11'
foreground-color='#E5E5E5'
highlight-background-color='#6B21A8'
highlight-colors-set=true
highlight-foreground-color='#FFFFFF'
palette=['#0D0D0D', '#EF4444', '#22C55E', '#EAB308', '#3B82F6', '#A855F7', '#06B6D4', '#A3A3A3', '#525252', '#F87171', '#4ADE80', '#FACC15', '#60A5FA', '#C084FC', '#22D3EE', '#F5F5F5']
scroll-on-output=false
scrollback-lines=10000
use-system-font=false
use-theme-colors=false
visible-name='Cortex'
[org/gnome/terminal/legacy/profiles:]
default='cortex'
list=['cortex']
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, check the file and its full context
head -n 150 iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot | tail -n 60

Repository: cortexlinux/cortex-distro

Length of output: 1907


🏁 Script executed:

# Search for how GNOME Terminal profiles are configured in the repository
rg -n "profiles" iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot -A 2 -B 2

Repository: cortexlinux/cortex-distro

Length of output: 422


🌐 Web query:

GNOME Terminal dconf profile format UUID vs arbitrary names

💡 Result:

Short answer

  • GNOME Terminal stores each profile under a path that uses a UUID (GUID): /org/gnome/terminal/legacy/profiles:/:/ — the profile list key (/org/gnome/terminal/legacy/profiles:/ list) contains those UUID strings. The human-visible name is stored separately as the visible-name key inside the profile. You cannot use arbitrary plain names as the profile path; use a UUID (you can generate one with uuidgen). [1][2][3]

Sources

  • GNOME Terminal FAQ (profile ID & gsettings examples). [1]
  • Explanation of relocatable schema and profile storage (org.gnome.Terminal.Legacy.Profile at /.../profiles:/:/). [2]
  • Examples showing gsettings/dconf paths and profile UUID list. [3]

🌐 Web query:

org/gnome/terminal/legacy/profiles dconf configuration requirements

💡 Result:

Summary — what dconf expects for /org/gnome/terminal/legacy/profiles:

  • Top-level path: /org/gnome/terminal/legacy/profiles:/ contains at least:
    • default — string UUID of the default profile. [1]
    • list — array of profile UUID strings (order not important). [1][3]
  • Each profile is stored under the path template:
    /org/gnome/terminal/legacy/profiles:/:/
    and must be a keyfile section (i.e., keys/values under that path). Typical keys come from the org.gnome.Terminal.Legacy.Profile schema (visible-name, font, use-system-font, palette, background-color, foreground-color, use-theme-colors, default-size-columns/rows, etc.). Types follow the schema (strings, booleans, integers, arrays). [2][3]
  • dconf/gsettings syntax notes:
    • dconf paths include the colon after profiles (profiles:/). Use the full path when writing with dconf. Example: dconf write /org/gnome/terminal/legacy/profiles:/:/font "'Monospace 12'". Note the nested quoting for string values. [2][3]
    • Equivalent gsettings form uses the schema prefix: gsettings set org.gnome.Terminal.Legacy.Profile:/org/gnome/terminal/legacy/profiles:/:/ . [2]
  • Backup/restore and reset:
    • Use dconf dump /org/gnome/terminal/ to export, dconf load /org/gnome/terminal/ to import, and dconf reset -f /org/gnome/terminal/ to wipe. [3]
  • dconf profile/database behavior:
    • System/user databases and dconf profiles determine precedence (user-db then system-db lines in /etc/dconf/profile/*). Changes require re-login to apply profile changes. [1]

If you want, I can show exact dconf write/gsettings commands for a specific key or produce a sample dconf dump for one profile.

Sources: [1] GNOME dconf profiles docs; [2] gsettings/dconf notes/example usage; [3] example dconf dump and keys.


Terminal profile must use a valid UUID, not arbitrary names.

GNOME Terminal identifies profiles by UUID in dconf, not arbitrary names. The path [org/gnome/terminal/legacy/profiles:/:cortex] and default='cortex' will be silently ignored. The profile path must follow the format [org/gnome/terminal/legacy/profiles:/:UUID] where UUID is a valid UUID string (e.g., generated with uuidgen), and both default and list values must reference this UUID.

Proposed fix (example with generated UUID)
-[org/gnome/terminal/legacy/profiles:/:cortex]
+[org/gnome/terminal/legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9]
 audible-bell=false
 ...
 visible-name='Cortex'

 [org/gnome/terminal/legacy/profiles:]
-default='cortex'
-list=['cortex']
+default='b1dcc9dd-5262-4d8d-a863-c897e6d979b9'
+list=['b1dcc9dd-5262-4d8d-a863-c897e6d979b9']
🤖 Prompt for AI Agents
In @iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot around lines
98 - 124, The GNOME Terminal profile block uses an invalid literal name
"cortex"; replace the profile path [org/gnome/terminal/legacy/profiles:/:cortex]
with a valid UUID-based path (e.g.,
[org/gnome/terminal/legacy/profiles:/:<UUID>]) and update default='cortex' and
list=['cortex'] to reference that same UUID string; keep visible-name='Cortex'
unchanged and generate the UUID with uuidgen (or similar) so all three places
(profile section name, default, and list) use the identical UUID.

session optional pam_motd.so motd=/run/motd.dynamic
session optional pam_motd.so noupdate
session optional pam_mail.so standard
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

pam_env user_readenv deprecated security vulnerability

💡 Result:

Short answer: Yes — pam_env's user_readenv is deprecated because it’s insecure, and its use has been linked to real vulnerabilities (e.g. a DoS in cockpit and local privilege-escalation issues). Mitigation: remove/disable user_readenv (set user_readenv=0 or remove the option) or upgrade to a Linux-PAM release where it’s disabled by default (>=1.4.0) — the option was marked deprecated in 1.5.0 and planned for removal. Sources and details below.

Key references

  • CVE-2024-6126 (cockpit): authenticated users can kill processes when pam_env user_readenv is enabled — disable user_readenv to mitigate. [1]
  • CVE-2025-6018 / advisories: LPE/vector where pam_env reading user ~/.pam_environment (user_readenv) enabled by default on some distros; vendors recommend setting user_readenv=0 and note it is deprecated and removed in newer PAM. [2][3]
  • pam_env manpage / upstream: documents user_readenv, notes default-off in many builds and that the functionality is deprecated since PAM 1.5.0. [4]

Recommended actions (pick all that apply for your environment)

  • Check PAM config files in /etc/pam.d/ (and any packaged pambase/pambase-like configs) for pam_env.so user_readenv=1 and remove that option or set user_readenv=0. [4]
  • Upgrade Linux-PAM to a version where user_readenv is disabled by default (>=1.4.0) or to a release that removed the feature. [3][4]
  • Apply vendor/security advisories and patches for affected packages (e.g., cockpit, distro packages) and follow distro-specific guidance. [1][2]
  • If you must allow user environment reading for specific services, evaluate the PAM stack ordering (avoid calling pam_env before modules like pam_systemd/polkit) and restrict which services invoke pam_env. [2]

If you want, tell me your distribution and I’ll list exactly which PAM files to check and give the precise edits/commands.

Sources:
[1] NVD / CVE-2024-6126 (cockpit DoS).
[2] Wiz / CVE-2025-6018 advisory (pam_env user_readenv LPE analysis).
[3] Snyk advisory and recommendations (workaround: set user_readenv=0; deprecated in 1.5.0).
[4] pam_env manpage (notes user_readenv deprecated since 1.5.0).


Remove user_readenv=1 due to deprecated security vulnerability.

The user_readenv=1 option has been deprecated since PAM 1.5.0 and is linked to multiple security vulnerabilities:

  • CVE-2024-6126: Authenticated users can kill arbitrary processes when user_readenv is enabled
  • CVE-2025-6018: Local privilege escalation vector through user-controlled ~/.pam_environment file manipulation

Security advisories from Wiz, Snyk, and Linux-PAM upstream recommend removing this option (or setting user_readenv=0). Modern PAM versions (>=1.4.0) disable it by default.

Proposed fix
-session    required   pam_env.so user_readenv=1 envfile=/etc/default/locale
+session    required   pam_env.so envfile=/etc/default/locale
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
session required pam_env.so user_readenv=1 envfile=/etc/default/locale
session required pam_env.so envfile=/etc/default/locale
🤖 Prompt for AI Agents
In @iso/live-build/config/includes.chroot/etc/pam.d/login at line 16, Remove the
deprecated and insecure user_readenv=1 option from the pam_env.so session line:
locate the line that invokes pam_env.so (currently "session required pam_env.so
user_readenv=1 envfile=/etc/default/locale") and either drop the user_readenv=1
entirely or change it to user_readenv=0 so the entry reads "session required
pam_env.so envfile=/etc/default/locale" (or with user_readenv=0) to mitigate the
CVE issues.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot`:
- Around line 92-97: The current post-check using "$?" after running
plymouth-set-default-theme is ineffective under set -e because the script will
exit on failure; replace the two-step run+exit-code-check with a non-fatal
failure idiom so failures emit a warning but do not abort: run
plymouth-set-default-theme cortex with a failure-safe construct (e.g., a logical
OR fallback or an if ! ...; then ...; fi) so that plymouth-set-default-theme can
fail without causing immediate exit and the warning is printed (refer to the
plymouth-set-default-theme invocation and the surrounding if command -v ...
block).
- Around line 399-411: Replace the current "run command then check $? later"
pattern for update-initramfs: either run the command inside a conditional (if
update-initramfs -u -k all; then ... else echo "ERROR: Failed to update
initramfs" ; exit 1; fi) or immediately capture its exit code (rc=$? right after
update-initramfs) before any potential early-exit behavior; update the echo/exit
logic around the update-initramfs invocation and remove the delayed if [ $? -eq
0 ] check so the failure message and exit happen reliably.

In `@scripts/build.sh`:
- Around line 742-748: The unquoted glob in the chmod call can break on
filenames with spaces or if the glob expands to nothing; update the post-copy
permission step (the block that calls copy_glob_if_exists and then chmod on
"${pkg_dir}/etc/update-motd.d/"*) to iterate safely over matched files or use a
safe find/exec pattern: ensure you check for existence before chmod and quote
each filename when changing permissions (refer to the copy_glob_if_exists
invocation and the chmod invocation) so filenames with spaces are handled and
the case of no matches does not cause an unintended chmod argument.
♻️ Duplicate comments (9)
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (3)

9-9: Consider using stricter bash settings.

Using set -euo pipefail instead of just set -e would catch unset variable references and pipeline failures, making the script more robust.

-set -e
+set -euo pipefail

27-30: Domain inconsistency across branding files persists.

These URLs use cortex.io, but line 334 (MOTD footer) references cortexlinux.com and docs.cortexlinux.com. Standardize on one canonical domain for consistency.


127-130: Bug: GRUB_DISTRIBUTOR will not be appended if missing.

The sed command returns exit code 0 even when the pattern isn't matched (no substitutions made). The || echo fallback will never execute. This issue was flagged in previous reviews.

Apply the same fix pattern used for GRUB_THEME on lines 121-125:

     # Also set timeout and other branding options
-    sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub || \
-        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    if grep -q "^GRUB_DISTRIBUTOR=" /etc/default/grub; then
+        sed -i 's|^GRUB_DISTRIBUTOR=.*|GRUB_DISTRIBUTOR="Cortex Linux"|' /etc/default/grub
+    else
+        echo 'GRUB_DISTRIBUTOR="Cortex Linux"' >> /etc/default/grub
+    fi
scripts/build.sh (6)

63-72: Unquoted glob and missing -r flag remain unaddressed.

This was flagged in a prior review. The unquoted glob can break on filenames with spaces, and cp without -r will fail if directories are matched.


136-140: dpkg-deb still treated as optional despite being required for branding-package.

This was flagged in a prior review. cmd_branding_package at line 759 calls dpkg-deb --build which will fail if the tool is missing.


287-304: Arithmetic expansion of $? after || still captures wrong value.

This was flagged in a prior review. In func || errors=$((errors + $?)), the $? captures the exit status of the || short-circuit (always 0 when the assignment runs), not the function's return value.


549-558: Unconditional sudo lb build still present.

This was flagged in a prior review. Running sudo when already root fails in many CI environments. Use conditional sudo based on $EUID.


615-625: Unconditional sudo lb clean has the same issue.

This was flagged in a prior review alongside sudo lb build. Both need conditional sudo based on $EUID.


695-704: Unconditional chmod on postinst and prerm still present.

This was flagged in a prior review. If either file is missing from the source DEBIAN/ directory, the script will fail.

🧹 Nitpick comments (1)
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (1)

263-264: Consider PCRE availability.

grep -oP (Perl-Compatible Regular Expressions) may not be available on all systems. If busybox grep or older GNU grep is present without PCRE support, these lines will fail silently (stderr redirected).

Consider using extended regex (grep -oE) or basic pattern matching as a fallback:

-        UPDATES=$(grep -oP '\d+ updates' "$UPDATES_FILE" 2>/dev/null | grep -oP '\d+' || echo "0")
-        SECURITY=$(grep -oP '\d+ security' "$UPDATES_FILE" 2>/dev/null | grep -oP '\d+' || echo "0")
+        UPDATES=$(grep -oE '[0-9]+ updates' "$UPDATES_FILE" 2>/dev/null | grep -oE '[0-9]+' || echo "0")
+        SECURITY=$(grep -oE '[0-9]+ security' "$UPDATES_FILE" 2>/dev/null | grep -oE '[0-9]+' || echo "0")
📜 Review details

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6564a1a and 79c2cda.

📒 Files selected for processing (2)
  • iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot
  • scripts/build.sh
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2026-01-12T20:51:13.828Z
Learnt from: CR
Repo: cortexlinux/cortex PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-01-12T20:51:13.828Z
Learning: Applies to **/*.py : Do not use silent sudo - require explicit user confirmation for privilege escalation

Applied to files:

  • scripts/build.sh
🔇 Additional comments (9)
iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot (4)

49-61: LGTM!

The APT repository configuration is appropriately commented out with a clear TODO, avoiding the previously flagged duplicate repository issue.


137-149: LGTM!

Wallpaper verification with appropriate warnings for missing assets.


151-177: LGTM!

GDM branding configuration is well-guarded with directory and command existence checks.


343-392: LGTM!

Neofetch configuration with custom ASCII art is well-structured.

scripts/build.sh (5)

7-47: LGTM: Clean configuration and logging setup.

The use of set -euo pipefail for strict error handling and the modular logging functions are well-structured.


499-526: LGTM: Configurable compression and well-structured live-build options.

The SQUASHFS_COMP variable for fast CI builds (lz4) vs smaller release builds (xz) is a good pattern. The boot parameters and live-build configuration are comprehensive.


320-420: LGTM: Comprehensive test suite with clear pass/fail reporting.

The test function covers key build artifacts (preseed, provisioning, branding, hooks, package controls) with proper syntax validation. The [ -f "$hook" ] check handles the glob edge case when no files match.


816-857: LGTM: Clean command dispatch pattern.

The entry point is well-structured with a clear case-based dispatch, proper help aliases, and argument passthrough to subcommands.


470-497: LGTM: Good validation for required GRUB theme file.

The explicit check for theme.txt with a clear error message (lines 483-489) addresses the branding validation concern from prior reviews.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment on lines 399 to 411
if command -v update-initramfs &>/dev/null; then
# Update ALL kernels
update-initramfs -u -k all

if [ $? -eq 0 ]; then
echo " Initramfs updated successfully"
else
echo " ERROR: Failed to update initramfs"
exit 1
fi
else
echo " WARNING: update-initramfs command not found"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Ineffective exit code check pattern.

Same issue as the Plymouth section: with set -e, if update-initramfs -u -k all fails, the script exits before the if [ $? -eq 0 ] check. The error message on line 406-407 will never be displayed.

If you want custom error handling:

 if command -v update-initramfs &>/dev/null; then
     # Update ALL kernels
-    update-initramfs -u -k all
-
-    if [ $? -eq 0 ]; then
+    if update-initramfs -u -k all; then
         echo "    Initramfs updated successfully"
     else
         echo "    ERROR: Failed to update initramfs"
         exit 1
     fi
 else
     echo "    WARNING: update-initramfs command not found"
 fi
🤖 Prompt for AI Agents
In `@iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot` around lines
399 - 411, Replace the current "run command then check $? later" pattern for
update-initramfs: either run the command inside a conditional (if
update-initramfs -u -k all; then ... else echo "ERROR: Failed to update
initramfs" ; exit 1; fi) or immediately capture its exit code (rc=$? right after
update-initramfs) before any potential early-exit behavior; update the echo/exit
logic around the update-initramfs invocation and remove the delayed if [ $? -eq
0 ] check so the failure message and exit happen reliably.

scripts/build.sh Outdated
Comment on lines 742 to 748
# Copy MOTD scripts
log "Copying MOTD scripts..."
if [ -d "${BRANDING_DIR}/motd" ]; then
if copy_glob_if_exists "${BRANDING_DIR}/motd/*" "${pkg_dir}/etc/update-motd.d/"; then
chmod 755 "${pkg_dir}/etc/update-motd.d/"*
fi
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Unquoted glob in chmod can break on filenames with spaces or empty matches.

Line 746 uses an unquoted glob "${pkg_dir}/etc/update-motd.d/"* which will fail if filenames contain spaces or if no files were copied.

🔧 Proposed fix using a loop or find
     # Copy MOTD scripts
     log "Copying MOTD scripts..."
     if [ -d "${BRANDING_DIR}/motd" ]; then
         if copy_glob_if_exists "${BRANDING_DIR}/motd/*" "${pkg_dir}/etc/update-motd.d/"; then
-            chmod 755 "${pkg_dir}/etc/update-motd.d/"*
+            find "${pkg_dir}/etc/update-motd.d/" -type f -exec chmod 755 {} +
         fi
     fi
🤖 Prompt for AI Agents
In `@scripts/build.sh` around lines 742 - 748, The unquoted glob in the chmod call
can break on filenames with spaces or if the glob expands to nothing; update the
post-copy permission step (the block that calls copy_glob_if_exists and then
chmod on "${pkg_dir}/etc/update-motd.d/"*) to iterate safely over matched files
or use a safe find/exec pattern: ensure you check for existence before chmod and
quote each filename when changing permissions (refer to the copy_glob_if_exists
invocation and the chmod invocation) so filenames with spaces are handled and
the case of no matches does not cause an unintended chmod argument.

Your Name added 2 commits January 17, 2026 02:45
- Updated the branding guidelines to reflect the new "CX" monogram logo design and its variations.
- Enhanced the asset generation script to utilize the new logo files and removed obsolete logo assets.
- Introduced a circular spinner animation for the Plymouth theme, replacing the previous progress bar setup.
- Added new spinner assets and updated the Plymouth script for improved visual feedback during boot.
- Removed unnecessary files and streamlined the asset generation process for better maintainability.
- Updated the theme to feature a centered CX logo on a pure black background, removing all animations, progress bars, and wordmarks for a clean aesthetic.
- Adjusted asset requirements and removed obsolete files, including spinner and progress assets.
- Enhanced the script to load and display the logo without additional elements, streamlining the boot experience.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Fix all issues with AI agents
In `@branding/BRAND-GUIDELINES.md`:
- Around line 163-186: Three fenced code blocks (the one listing "Primary:
`#6B21A8` background, white text", the "Cards" block starting with "Background:
`#1E1E3F`..." and the "Input Fields" block starting with "Background: `#0F0F23`...")
are missing language identifiers and trigger MD040; update each triple-backtick
fence to include the language tag `text` (e.g., change ``` to ```text) so the
blocks become ```text ... ``` for the three sections.

In `@branding/generate-assets.sh`:
- Around line 14-29: The script currently hard-fails if LOGO_DARK is missing
even though only LOGO_TRANSPARENT is used by extract_logo; relax this by
removing the exit-on-missing check for LOGO_DARK or turning it into a non-fatal
warning, and update the final summary to only mention LOGO_DARK when the file
exists; locate the checks referencing LOGO_DARK and LOGO_TRANSPARENT and the
extract_logo calls to implement the conditional validation and summary change.

In `@branding/plymouth/cortex/cortex.script`:
- Around line 53-65: The callback display_normal_callback can run before
password_dialogue_setup initializes the globals, causing null derefs in
password_dialogue_opacity; update password_dialogue_opacity to defensively check
that global.password_entry and global.password_prompt are non-null before
calling SetOpacity and that global.password_bullets is a valid array (or
non-null) before iterating, returning early if none are initialized; keep
function names password_dialogue_opacity, display_normal_callback and
password_dialogue_setup unchanged so the guard logic simply skips or no-ops when
the UI elements are not yet created.
♻️ Duplicate comments (1)
iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script (1)

53-65: Guard against null deref when normal display is shown first.

Same issue as previously noted: display_normal_callback() can run before password_dialogue_setup(), and password_dialogue_opacity() dereferences unset globals. Please add guards or initialize defaults.

🧹 Nitpick comments (2)
branding/generate-assets.sh (2)

9-12: Harden the script with strict mode and a magick dependency check.

This improves failure clarity and avoids running with missing tooling.

🛠️ Proposed fix
-set -e
+set -euo pipefail
+
+if ! command -v magick >/dev/null 2>&1; then
+    echo "ERROR: ImageMagick 'magick' not found in PATH."
+    echo "Please install ImageMagick before running this script."
+    exit 1
+fi

76-81: Guard the wordmark font choice to avoid environment-specific failures.

Helvetica-Bold may not exist on minimal build images; this can change outputs or fail. Consider a configurable font with a safe fallback.

🛠️ Proposed fix
+# Wordmark font (allow override via env, fallback if missing)
+WORDMARK_FONT="${WORDMARK_FONT:-Helvetica-Bold}"
+if ! magick -list font | grep -qi "${WORDMARK_FONT}"; then
+    WORDMARK_FONT="DejaVu-Sans-Bold"
+fi
+
 magick -size 300x50 xc:transparent \
-    -font "Helvetica-Bold" -pointsize 28 \
+    -font "${WORDMARK_FONT}" -pointsize 28 \
     -fill "${TEXT_LIGHT}" \
     -gravity center -annotate 0 "CORTEX LINUX" \
     "${PLYMOUTH_DIR}/wordmark.png"

Comment on lines +163 to +186
```
Primary: #6B21A8 background, white text
Secondary: transparent, #6B21A8 border
Ghost: transparent, #94A3B8 text
Danger: #EF4444 background, white text
```

### Cards

```
Background: #1E1E3F (dark) or #FFFFFF (light)
Border: 1px solid rgba(107, 33, 168, 0.2)
Border radius: 12px
Shadow: 0 4px 20px rgba(0, 0, 0, 0.15)
```

### Input Fields

```
Background: #0F0F23 (dark) or #F8FAFC (light)
Border: 1px solid #2D2D5A
Focus border: #06B6D4
Border radius: 8px
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add language identifiers to fenced blocks to satisfy markdownlint.

These three fenced blocks are missing a language tag, which triggers MD040. Consider marking them as text.

🛠️ Proposed fix
-```
+```text
 Primary: `#6B21A8` background, white text
 Secondary: transparent, `#6B21A8` border
 Ghost: transparent, `#94A3B8` text
 Danger: `#EF4444` background, white text

@@
- +text
Background: #1E1E3F (dark) or #FFFFFF (light)
Border: 1px solid rgba(107, 33, 168, 0.2)
Border radius: 12px
Shadow: 0 4px 20px rgba(0, 0, 0, 0.15)

@@
-```
+```text
Background: `#0F0F23` (dark) or `#F8FAFC` (light)
Border: 1px solid `#2D2D5A`
Focus border: `#06B6D4`
Border radius: 8px
</details>

<!-- suggestion_start -->

<details>
<summary>📝 Committable suggestion</summary>

> ‼️ **IMPORTANT**
> Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

```suggestion

🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

163-163: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


172-172: Fenced code blocks should have a language specified

(MD040, fenced-code-language)


181-181: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In `@branding/BRAND-GUIDELINES.md` around lines 163 - 186, Three fenced code
blocks (the one listing "Primary: `#6B21A8` background, white text", the "Cards"
block starting with "Background: `#1E1E3F`..." and the "Input Fields" block
starting with "Background: `#0F0F23`...") are missing language identifiers and
trigger MD040; update each triple-backtick fence to include the language tag
`text` (e.g., change ``` to ```text) so the blocks become ```text ... ``` for
the three sections.

Comment on lines +53 to +65
fun password_dialogue_opacity(opacity) {
global.password_entry.sprite.SetOpacity(opacity);
global.password_prompt.sprite.SetOpacity(opacity);
for (i = 0; global.password_bullets[i]; i++) {
global.password_bullets[i].sprite.SetOpacity(opacity);
}
}

Plymouth.SetDisplayPasswordFunction(password_dialogue_setup);

fun display_normal_callback() {
password_dialogue_opacity(0);
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, locate the file
find . -name "cortex.script" -type f

Repository: cortexlinux/cortex-distro

Length of output: 196


🏁 Script executed:

# Read the entire cortex.script file to understand the context
cat -n branding/plymouth/cortex/cortex.script

Repository: cortexlinux/cortex-distro

Length of output: 3274


🏁 Script executed:

# Search for password_dialogue_setup definition
rg -n "password_dialogue_setup" branding/plymouth/cortex/

Repository: cortexlinux/cortex-distro

Length of output: 259


🏁 Script executed:

# Check if there are other Plymouth scripts that might give context
fd -e script branding/plymouth/ | head -20

Repository: cortexlinux/cortex-distro

Length of output: 446


🏁 Script executed:

# Search for any Plymouth documentation or comments about callback order
rg -i "plymouth\|callback" branding/plymouth/ -A 2 -B 2 | head -50

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Check if there are any other references or initialization of these globals elsewhere
rg "global\.password_" branding/plymouth/cortex/

Repository: cortexlinux/cortex-distro

Length of output: 752


🏁 Script executed:

# Check the Plymouth API documentation references in comments
rg -i "setdisplay\|callback" . --type script

Repository: cortexlinux/cortex-distro

Length of output: 99


🏁 Script executed:

# Check if there's any initialization of these globals at the module level
rg "password_entry\|password_prompt\|password_bullets" branding/plymouth/cortex/ -B 5 -A 5

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Search for any Plymouth theme examples or documentation in the repo
find . -name "*.md" -o -name "README*" | xargs grep -l "plymouth\|password" 2>/dev/null | head -5

Repository: cortexlinux/cortex-distro

Length of output: 122


🏁 Script executed:

# Check the documentation files for any Plymouth-related information
cat -n ./docs/DEVELOPERS.md | grep -A 10 -B 10 -i "plymouth\|theme"

Repository: cortexlinux/cortex-distro

Length of output: 1113


🏁 Script executed:

# Look for any other Plymouth theme files that might show a pattern
find . -name "*.script" -type f

Repository: cortexlinux/cortex-distro

Length of output: 196


🏁 Script executed:

# Check the other cortex.script file to see if there's any difference
diff -u branding/plymouth/cortex/cortex.script ./iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Search for Plymouth documentation or examples online pattern
rg -i "setdisplaynormal\|setdisplaypassword" . 2>/dev/null

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Check if there's any initialization of password globals at module level before callbacks
head -30 branding/plymouth/cortex/cortex.script

Repository: cortexlinux/cortex-distro

Length of output: 950


🏁 Script executed:

# Search online documentation patterns in code comments or READMEs
rg -i "plymouth.*api\|password.*callback" . 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Check if there are any git history or comments explaining the callback order
git log --oneline branding/plymouth/cortex/cortex.script 2>/dev/null | head -10

Repository: cortexlinux/cortex-distro

Length of output: 130


🏁 Script executed:

# Let's also check the other included cortex.script file to see if there's any difference in how it handles this
cat -n ./iso/live-build/config/includes.chroot/usr/share/plymouth/themes/cortex/cortex.script | sed -n '50,70p'

Repository: cortexlinux/cortex-distro

Length of output: 857


Guard against null deref when normal display is shown first.

display_normal_callback() can run before password_dialogue_setup() is ever called (e.g., boot without password prompt), but password_dialogue_opacity() accesses global.password_entry, global.password_prompt, and global.password_bullets without guards. These globals are only initialized inside password_dialogue_setup(), causing a crash if the callback fires first.

✅ Suggested defensive guards
 fun password_dialogue_opacity(opacity) {
-    global.password_entry.sprite.SetOpacity(opacity);
-    global.password_prompt.sprite.SetOpacity(opacity);
-    for (i = 0; global.password_bullets[i]; i++) {
-        global.password_bullets[i].sprite.SetOpacity(opacity);
-    }
+    if (global.password_entry && global.password_entry.sprite)
+        global.password_entry.sprite.SetOpacity(opacity);
+    if (global.password_prompt && global.password_prompt.sprite)
+        global.password_prompt.sprite.SetOpacity(opacity);
+    if (global.password_bullets) {
+        for (i = 0; global.password_bullets[i]; i++) {
+            if (global.password_bullets[i].sprite)
+                global.password_bullets[i].sprite.SetOpacity(opacity);
+        }
+    }
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
fun password_dialogue_opacity(opacity) {
global.password_entry.sprite.SetOpacity(opacity);
global.password_prompt.sprite.SetOpacity(opacity);
for (i = 0; global.password_bullets[i]; i++) {
global.password_bullets[i].sprite.SetOpacity(opacity);
}
}
Plymouth.SetDisplayPasswordFunction(password_dialogue_setup);
fun display_normal_callback() {
password_dialogue_opacity(0);
}
fun password_dialogue_opacity(opacity) {
if (global.password_entry && global.password_entry.sprite)
global.password_entry.sprite.SetOpacity(opacity);
if (global.password_prompt && global.password_prompt.sprite)
global.password_prompt.sprite.SetOpacity(opacity);
if (global.password_bullets) {
for (i = 0; global.password_bullets[i]; i++) {
if (global.password_bullets[i].sprite)
global.password_bullets[i].sprite.SetOpacity(opacity);
}
}
}
Plymouth.SetDisplayPasswordFunction(password_dialogue_setup);
fun display_normal_callback() {
password_dialogue_opacity(0);
}
🤖 Prompt for AI Agents
In `@branding/plymouth/cortex/cortex.script` around lines 53 - 65, The callback
display_normal_callback can run before password_dialogue_setup initializes the
globals, causing null derefs in password_dialogue_opacity; update
password_dialogue_opacity to defensively check that global.password_entry and
global.password_prompt are non-null before calling SetOpacity and that
global.password_bullets is a valid array (or non-null) before iterating,
returning early if none are initialized; keep function names
password_dialogue_opacity, display_normal_callback and password_dialogue_setup
unchanged so the guard logic simply skips or no-ops when the UI elements are not
yet created.

- Replaced multiple branding images in the grub and plymouth themes to enhance visual consistency.
- Added new branding assets, including a light logo and updated wallpapers.
- Removed outdated background and plymouth theme files to streamline the asset directory.
- Updated theme references in the build configuration for improved organization.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 Fix all issues with AI agents
In `@iso/live-build/config/includes.chroot/boot/grub/themes/cortex`:
- Line 1: The symlink pointing to the repository branding (the
"../../../../../branding/grub/cortex" target) will be broken inside the built
ISO; fix by either replacing the symlink in
includes.chroot/boot/grub/themes/cortex with the actual theme files (copy the
directory contents into that chroot path) or update the existing build hook that
currently only warns on missing branding to actively copy branding/grub/cortex
into the chroot location during the build so GRUB/Plymouth/GDM reference real
files rather than a symlink to a non-existent repo path.

In `@iso/live-build/config/includes.chroot/usr/share/backgrounds/cortex`:
- Line 1: Remove the placeholder text file that contains
"../../../../../../../branding/wallpapers/images" or replace it with real
wallpaper image files; ensure the directory `/usr/share/backgrounds/cortex` (the
contents created from this entry) contains the branding-required filename
cortex-default.png (in addition to existing minimal-dark.png and
circuit-board.png) so the branding hook and build scripts can copy images
correctly and avoid the ISO build WARNING.

@@ -0,0 +1 @@
../../../../../../../branding/grub/cortex No newline at end of file
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# First, confirm the symlink file exists and check its content
ls -la "iso/live-build/config/includes.chroot/boot/grub/themes/cortex" 2>&1

# Check if it's actually a symlink and what it points to
file "iso/live-build/config/includes.chroot/boot/grub/themes/cortex" 2>&1

# Check the branding directory structure
ls -la "branding/grub/" 2>&1

# Check if cortex directory exists in branding
ls -la "branding/grub/cortex/" 2>&1

# Find the build hook
find . -name "*50-cortex-branding*" -o -name "*cortex*branding*" 2>&1 | head -20

# Also search for any hooks that reference branding
fd -t f '\.hook\.' --exec grep -l 'branding\|cortex' {} \; 2>&1 | head -20

Repository: cortexlinux/cortex-distro

Length of output: 2415


🏁 Script executed:

# Examine the build hook that handles branding
cat "iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot"

# Check if there's a theme.txt at the expected location
cat "branding/grub/cortex/theme.txt" 2>&1 | head -20

# Search for any other references to how this symlink should be handled
rg -n 'symlink|cortex.*theme|branding.*grub' iso/live-build/config/ -A 2 -B 2

# Check live-build documentation or comments about includes.chroot
rg -n 'includes\.chroot' . --type txt --type md 2>&1 | head -10

Repository: cortexlinux/cortex-distro

Length of output: 15293


🏁 Script executed:

# Check if there are any other hooks that copy branding files into the chroot
find iso/live-build/config/hooks -name "*.hook.chroot" -exec grep -l "cp.*branding\|install.*branding" {} \;

# Check if there's a package that handles this
cat packages/cortex-branding/debian/postinst 2>/dev/null || echo "No postinst script"

# Verify what gets included from branding in the build
rg "branding" iso/live-build/config/ --type conf --type config -B 2 -A 2

# Check if there's any mechanism in the build system to resolve symlinks
rg "symlink" iso/live-build/ -B 2 -A 2

# List what's actually in the live-build source includes
find iso/live-build/config/includes.chroot -type l 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 988


🏁 Script executed:

# Verify the actual resolution of the symlink in context
# Check the directory structure more carefully
cd iso/live-build/config/includes.chroot && find . -type l -exec readlink -f {} \; -print 2>&1 | head -30

# Check if there's a .config or manifest that specifies what gets included
cat iso/live-build/auto/config 2>/dev/null || echo "No auto/config"

# Also check what the actual target would resolve to in chroot
# Symlink: iso/live-build/config/includes.chroot/boot/grub/themes/cortex -> ../../../../../../../branding/grub/cortex
# When installed in chroot, this would be: /boot/grub/themes/cortex -> ../../../../../../../branding/grub/cortex
# Which resolves to: /branding/grub/cortex

# Verify if the actual theme files get copied anywhere
find iso/live-build/config/includes.chroot -name "*.png" -o -name "theme.txt" 2>/dev/null

Repository: cortexlinux/cortex-distro

Length of output: 518


🏁 Script executed:

# Final verification: check if live-build has special handling for symlinks
rg "cp.*-P|--preserve.*link|dereference" iso/live-build/ 2>/dev/null || echo "No special symlink handling found"

# Check the live-build documentation
ls -la iso/live-build/*.md iso/live-build/docs/ 2>/dev/null | head -20

# Confirm what the hook expects vs what exists
echo "=== Hook expects these files to exist in chroot ==="
grep "if \[ ! -f" iso/live-build/config/hooks/live/50-cortex-branding.hook.chroot | grep -oP '(?<=-f )[^ ]+'

echo ""
echo "=== Actual files in includes.chroot ==="
find iso/live-build/config/includes.chroot -type f | head -20

Repository: cortexlinux/cortex-distro

Length of output: 552


Symlink targets will not exist in the built ISO—all branding symlinks are broken.

The symlink points to ../../../../../../../branding/grub/cortex, which resolves to /branding/grub/cortex in the chroot filesystem. The branding/ directory exists only in the source repository, not in the built ISO, so this symlink will be broken at runtime.

This affects multiple subsystems:

  • GRUB theme loading will fail (path referenced in /etc/default/grub will be invalid)
  • Plymouth theme symlink is also broken
  • Wallpaper and GDM logo symlinks are also broken

The build hook verifies these paths (lines 115–117) but only warns on failure—it doesn't copy or resolve the symlinks, and GRUB configuration still references the broken path.

Fix by either:

  1. Copying actual theme files directly into includes.chroot/boot/grub/themes/cortex/ instead of using symlinks
  2. Using the build hook to copy files from branding/grub/cortex/ to the correct chroot location during build
🤖 Prompt for AI Agents
In `@iso/live-build/config/includes.chroot/boot/grub/themes/cortex` at line 1, The
symlink pointing to the repository branding (the
"../../../../../branding/grub/cortex" target) will be broken inside the built
ISO; fix by either replacing the symlink in
includes.chroot/boot/grub/themes/cortex with the actual theme files (copy the
directory contents into that chroot path) or update the existing build hook that
currently only warns on missing branding to actively copy branding/grub/cortex
into the chroot location during the build so GRUB/Plymouth/GDM reference real
files rather than a symlink to a non-existent repo path.

Your Name added 4 commits January 17, 2026 15:40
- Added support for a new light logo with a gradient ring for Plymouth theme.
- Improved script output formatting for better user experience during asset generation.
- Streamlined Plymouth and GRUB asset creation processes, ensuring consistency and clarity.
- Updated warnings for missing logo files to enhance user awareness.
- Consolidated logo and wallpaper asset creation steps for efficiency.
…uration syncing

- Updated the build script to use symlinks for the GRUB theme, ensuring the latest assets are referenced without duplication.
- Enhanced the copying process for includes.chroot to follow symlinks, improving build efficiency and reducing conflicts.
- Added checks for local apt-cacher-ng to optimize package mirror usage during builds, enhancing performance and reliability.
- Introduced a new loading indicator featuring three animated dots at the bottom of the screen, enhancing user feedback during boot.
- Updated the theme script to include dot animations and refresh callbacks for improved visual experience.
- Added new assets for the loading dots (dot-on.png and dot-off.png) to support the animation functionality.
- Maintained the minimal design aesthetic while providing dynamic loading feedback.
- Introduced a new primary logo (cx-logo-primary.png) for consistent branding across themes.
- Updated the asset generation script to prioritize the primary logo and fallback to alternative logos if necessary.
- Enhanced Plymouth, GRUB, and GDM themes to utilize the new primary logo, ensuring a cohesive visual experience.
- Revised wallpaper assets to include centered logos and updated documentation for clarity on available wallpapers.
- Set 'minimal-dark.png' as the default wallpaper in GNOME configurations for improved user experience.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🤖 Fix all issues with AI agents
In `@branding/plymouth/cortex/cortex.script`:
- Around line 136-143: message_callback currently allocates a new Sprite every
call causing leaked sprites; change it to reuse the existing sprite like
animate_dots does: always create message.image via Image.Text(text, ...), then
if message.sprite exists call message.sprite.SetImage(message.image) otherwise
create message.sprite = Sprite(message.image); finally update
message.x/message.y and call message.sprite.SetPosition(...). Use the same
symbols (message_callback, message.image, message.sprite, SetImage, Sprite,
SetPosition) to locate and implement the change.

In `@branding/wallpapers/ASSETS.md`:
- Around line 17-21: Update the fenced code blocks in ASSETS.md to include a
language specifier (use "text") so linting and rendering are consistent;
specifically replace the triple-backtick fences in the blocks around the color
palette and installation path (the blocks shown at the diff and the ones at
lines noted in the comment) from ``` to ```text so the
Background/Surface/Border, Accent Colors, and installation path snippets are
fenced as text blocks.

In `@iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot`:
- Around line 42-43: Replace the direct systemctl call (systemctl set-default
graphical.target) with a systemd-safe offline method: instead of invoking
systemctl inside the chroot, create/update the default.target symlink to point
to graphical.target (i.e., manage /etc/systemd/system/default.target ->
/lib/systemd/system/graphical.target) so the live image boots to GNOME without
requiring a running systemd bus; modify the hook around the existing systemctl
invocation to perform that symlink update in the chroot environment.

In `@scripts/build.sh`:
- Around line 502-514: The apt-cacher-ng detection uses curl but curl is not
enforced as a dependency; add "curl" to the cmd_check_deps dependency list and
also harden the detection by guarding the curl call (e.g. use command -v curl
>/dev/null 2>&1 && curl -s --connect-timeout 2 http://localhost:3142 >/dev/null
2>&1) in the block that sets mirror_bootstrap/mirror_chroot/mirror_binary so the
script will either fail earlier via cmd_check_deps or skip the proxy check
cleanly if curl is absent.
♻️ Duplicate comments (11)
branding/generate-assets.sh (1)

74-75: Progress counter mismatch.

The progress indicators start at [1/4] but there are actually 5 sections (Plymouth, GRUB, Wallpapers, Logos, GDM). The last section shows [5/5], which is inconsistent with the earlier [1/4] through [4/4].

Proposed fix
-echo "[1/4] Plymouth theme..."
+echo "[1/5] Plymouth theme..."

And similarly update lines 110, 150, and 192 to use /5 instead of /4.

scripts/build.sh (7)

63-72: copy_glob_if_exists still has unsafe glob handling.

This function uses unquoted glob expansion which breaks on filenames with spaces and directories. The cp lacks -r for recursive copying.


136-140: dpkg-deb is required for branding-package but treated as optional here.

The cmd_branding_package command will fail at runtime if dpkg-deb is missing. Either make it a required dependency or add a runtime check in cmd_branding_package.


287-303: Arithmetic $? capture after || doesn't work as intended.

After validate_provision || errors=$((errors + $?)), the $? captures the exit status of the assignment (always 0), not the function's return value.


560-569: Unconditional sudo will fail when already running as root.

In CI/CD environments that run as root, sudo lb build may fail or behave unexpectedly. Use an EUID check: if [[ $EUID -eq 0 ]]; then lb build; else sudo lb build; fi.


626-636: Same unconditional sudo issue applies to lb clean.

Apply the EUID check pattern here as well: if [[ $EUID -eq 0 ]]; then lb clean; else sudo lb clean; fi.


704-713: Unconditional chmod on postinst/prerm will fail if files are missing.

Add existence checks before changing permissions: [ -f "${pkg_dir}/DEBIAN/postinst" ] && chmod 755 "${pkg_dir}/DEBIAN/postinst".


751-757: Unquoted glob in chmod can break on filenames with spaces or empty matches.

Use find ... -exec chmod 755 {} + instead of the unquoted glob pattern.

iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot (2)

15-44: Guard GNOME-specific steps when dconf is missing.

This was already raised earlier: the hook runs for profiles without GNOME, so dconf update and GNOME config should be skipped when dconf isn’t present.

Also applies to: 127-129


98-124: GNOME Terminal profiles require UUIDs, not literal names.

This was already raised earlier: cortex isn’t a valid profile ID in dconf; use a UUID and update default/list accordingly.

branding/plymouth/cortex/cortex.script (1)

117-130: Guard against null password UI elements.
Same issue as previous review: display_normal_callback() can run before password_dialogue_setup(), causing null derefs in password_dialogue_opacity(). Please add defensive checks.

🧹 Nitpick comments (1)
branding/generate-assets.sh (1)

215-222: Clean up temporary file.

The script creates /tmp/gdm-logo.png but doesn't remove it after generating the SVG. Consider adding cleanup to avoid leaving artifacts.

Proposed fix
 # GDM logo SVG with embedded PNG
 extract_logo 200 /tmp/gdm-logo.png
 LOGO_BASE64=$(base64 -w0 /tmp/gdm-logo.png)
+rm -f /tmp/gdm-logo.png
 cat > "${GDM_DIR}/cortex-logo.svg" << EOF

Comment on lines +136 to +143
fun message_callback(text) {
message.image = Image.Text(text, 0.6, 0.6, 0.7, 1, "Sans 11");
message.sprite = Sprite(message.image);
message.x = screen_x + screen_width / 2 - message.image.GetWidth() / 2;
message.y = screen_y + screen_height - 50;
message.sprite.SetPosition(message.x, message.y, 10);
}
Plymouth.SetMessageFunction(message_callback);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the file structure and find other Plymouth script files for reference
find branding/plymouth -type f -name "*.script" | head -20

Repository: cortexlinux/cortex-distro

Length of output: 107


🌐 Web query:

Plymouth boot splash screen API Sprite SetImage memory management

💡 Result:

Do you want: (A) how the script-level Sprite.SetImage/Image objects are managed (lifetime/reference semantics), or (B) how to avoid leaks/crashes when repeatedly calling SetImage from a theme script (I can inspect the C source to confirm)?

I can start by checking Plymouth's script docs and source for exact memory/semmantics — which do you prefer? References: Plymouth scripting docs and development overview. [1][2]

[1] https://www.freedesktop.org/wiki/Software/Plymouth/Scripts/
[2] Plymouth docs (development.txt) — Plymouth graphical boot system.


🏁 Script executed:

# Search for other uses of SetMessageFunction and message_callback patterns in the codebase
rg "SetMessageFunction|message_callback" --type-list | head -20
rg "SetMessageFunction|message_callback" -A 5 -B 5

Repository: cortexlinux/cortex-distro

Length of output: 1794


🏁 Script executed:

# Read the cortex.script file to understand sprite management patterns
cat -n branding/plymouth/cortex/cortex.script | head -200

Repository: cortexlinux/cortex-distro

Length of output: 5605


🏁 Script executed:

# Search for Sprite usage patterns in the script
rg "Sprite" branding/plymouth/cortex/cortex.script -B 2 -A 2

Repository: cortexlinux/cortex-distro

Length of output: 1252


🌐 Web query:

Plymouth Sprite class API documentation SetImage method

💡 Result:

SetImage(image)

  • Purpose: assign an Image object to the Sprite so that the sprite displays that image.
  • Signature/example: my_sprite.SetImage(some_image) where some_image is an Image (e.g., created via Image("file.png") or Image():Rotate/Scale/etc.).
  • Notes: you can also supply the image to the Sprite constructor (Sprite(image)); default sprite position is (0,0). Use GetImage() to retrieve the current image.
    Sources: [1], [2].

Sources
[1] Plymouth Scripts (freedesktop.org) — "my_sprite = Sprite (); my_sprite.SetImage (fat_logo_image); ...".
[2] Gentoo Wiki — Plymouth/Theming (sprite_example.SetImage(image); sprite_example.GetImage();).


🏁 Script executed:

# Look for any sprite cleanup or management code
rg "sprite\.|SetImage|SetOpacity" branding/plymouth/cortex/cortex.script -A 1

Repository: cortexlinux/cortex-distro

Length of output: 971


Reuse the message sprite instead of recreating it on every callback.

The message_callback() creates a new Sprite object with each call, which accumulates unused sprite objects in memory. The same file demonstrates the correct pattern in animate_dots() (lines 68, 71), which reuses sprites via SetImage(). Update message_callback() to check if the sprite already exists and call SetImage() to update it:

♻️ Suggested update
 fun message_callback(text) {
     message.image = Image.Text(text, 0.6, 0.6, 0.7, 1, "Sans 11");
-    message.sprite = Sprite(message.image);
+    if (!message.sprite) {
+        message.sprite = Sprite(message.image);
+    } else {
+        message.sprite.SetImage(message.image);
+    }
     message.x = screen_x + screen_width / 2 - message.image.GetWidth() / 2;
     message.y = screen_y + screen_height - 50;
     message.sprite.SetPosition(message.x, message.y, 10);
 }
🤖 Prompt for AI Agents
In `@branding/plymouth/cortex/cortex.script` around lines 136 - 143,
message_callback currently allocates a new Sprite every call causing leaked
sprites; change it to reuse the existing sprite like animate_dots does: always
create message.image via Image.Text(text, ...), then if message.sprite exists
call message.sprite.SetImage(message.image) otherwise create message.sprite =
Sprite(message.image); finally update message.x/message.y and call
message.sprite.SetPosition(...). Use the same symbols (message_callback,
message.image, message.sprite, SetImage, Sprite, SetPosition) to locate and
implement the change.

Comment on lines 42 to 43
# Ensure GNOME starts on boot in live environment
systemctl set-default graphical.target
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use offline/systemd-safe mode for systemctl set-default.

In a live-build chroot, systemctl often fails to connect to the bus, and set -e will abort the build. Prefer offline mode (or a direct symlink) to make this robust.

🛠️ Proposed fix
- systemctl set-default graphical.target
+ SYSTEMD_OFFLINE=1 systemctl set-default graphical.target
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Ensure GNOME starts on boot in live environment
systemctl set-default graphical.target
# Ensure GNOME starts on boot in live environment
SYSTEMD_OFFLINE=1 systemctl set-default graphical.target
🤖 Prompt for AI Agents
In `@iso/live-build/config/hooks/live/99-configure-gnome.hook.chroot` around lines
42 - 43, Replace the direct systemctl call (systemctl set-default
graphical.target) with a systemd-safe offline method: instead of invoking
systemctl inside the chroot, create/update the default.target symlink to point
to graphical.target (i.e., manage /etc/systemd/system/default.target ->
/lib/systemd/system/graphical.target) so the live image boots to GNOME without
requiring a running systemd bus; modify the hook around the existing systemctl
invocation to perform that symlink update in the chroot environment.

Comment on lines 502 to 514
# Check if apt-cacher-ng is running locally for package caching
local mirror_bootstrap="http://deb.debian.org/debian"
local mirror_chroot="http://deb.debian.org/debian"
local mirror_binary="http://deb.debian.org/debian"

if curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
log "apt-cacher-ng detected, using local cache proxy"
mirror_bootstrap="http://localhost:3142/deb.debian.org/debian"
mirror_chroot="http://localhost:3142/deb.debian.org/debian"
mirror_binary="http://deb.debian.org/debian" # Keep binary mirror direct for ISO
else
warn "apt-cacher-ng not running, using direct mirrors (slower)"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

curl is used but not checked in dependencies.

The apt-cacher-ng detection uses curl, but it's not included in cmd_check_deps. If curl is not installed, this check silently fails and falls through to the else branch, which is safe but may confuse users who have apt-cacher-ng running but can't benefit from it.

🔧 Suggested fix: check for curl before using it
     # Check if apt-cacher-ng is running locally for package caching
     local mirror_bootstrap="http://deb.debian.org/debian"
     local mirror_chroot="http://deb.debian.org/debian"
     local mirror_binary="http://deb.debian.org/debian"
     
-    if curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
+    if command -v curl &>/dev/null && curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
         log "apt-cacher-ng detected, using local cache proxy"
🤖 Prompt for AI Agents
In `@scripts/build.sh` around lines 502 - 514, The apt-cacher-ng detection uses
curl but curl is not enforced as a dependency; add "curl" to the cmd_check_deps
dependency list and also harden the detection by guarding the curl call (e.g.
use command -v curl >/dev/null 2>&1 && curl -s --connect-timeout 2
http://localhost:3142 >/dev/null 2>&1) in the block that sets
mirror_bootstrap/mirror_chroot/mirror_binary so the script will either fail
earlier via cmd_check_deps or skip the proxy check cleanly if curl is absent.

Your Name added 7 commits January 17, 2026 19:56
… enhanced visuals

- Modified the asset generation script to create gradient backgrounds for GRUB, GDM, and wallpapers, replacing solid dark backgrounds.
- Updated the minimal dark wallpaper to feature a gradient with a centered logo, enhancing visual appeal.
- Improved the circuit board wallpaper to include gradient effects and circuit traces, providing a modern look.
- Revised the GDM login background to utilize a gradient, ensuring consistency across themes.
- Updated various branding images to reflect the new design changes, enhancing overall branding coherence.
- Removed the legacy asset generation script in favor of a Makefile approach, streamlining the asset build process.
- Introduced dependency tracking to rebuild only changed assets, improving efficiency.
- Updated documentation to reflect the new asset generation commands and structure.
- Ensured all branding assets, including Plymouth, GRUB, wallpapers, and logos, are generated consistently through the Makefile.
- Deleted the Automated Installation Guide, Developer Guide, and Quick Start Guide to streamline documentation and reduce redundancy.
- These guides were previously maintained but are now considered obsolete or integrated into other resources.
- Ensured that the remaining documentation is up-to-date and reflects the current state of the project.
… package building

- Simplified clean and sync commands in the Makefile to enhance usability.
- Removed fallback logo references in the cortex-branding package for clarity.
- Updated build script to streamline package building process, consolidating logic for meta-package creation.
- Removed legacy command alias for branding package to reduce confusion.
- Removed the build branding package job to streamline the workflow.
- Updated paths to include documentation branding assets instead of the deprecated branding directory.
- Adjusted artifact upload and download steps to handle packages more efficiently.
- Enhanced checksum generation to handle cases where no .deb files are present.
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Fix all issues with AI agents
In `@packages/cortex-branding/boot/grub/themes/cortex/theme.txt`:
- Around line 19-27: The theme file defines selected_item_color twice (symbols:
selected_item_color) creating a duplicate; remove the redundant
selected_item_color declaration so only a single selected_item_color remains
(keep the intended value already defined), e.g., delete the later/duplicate
selected_item_color entry to clean up the theme block alongside existing
item_font, item_color, selected_item_font, item_height, item_padding, and
item_spacing settings.

In `@packages/cortex-branding/debian/postinst`:
- Around line 125-134: Remove the conditional check that gates registration on
the existence of the alternatives group by deleting the "if update-alternatives
--list gdm3-theme.css" test and its fi; always run the update-alternatives calls
so that "update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css
gdm3-theme.css /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200" and
"update-alternatives --set gdm3-theme.css
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css" execute (the --install will
create the group if missing), keeping the surrounding checks for the
gnome-shell.css file and for the presence of update-alternatives.

In `@packages/cortex-branding/etc/dconf/db/local.d/01-cortex-terminal`:
- Around line 4-32: The file uses incomplete dconf section headers (e.g.,
[legacy/profiles:/:cortex] and [legacy/profiles:]) so GNOME Terminal will ignore
the keys; update the section headers to the fully-qualified schema path by
replacing those headers with the corresponding
org/gnome/terminal/legacy/profiles variants (i.e., change
[legacy/profiles:/:cortex] to [org/gnome/terminal/legacy/profiles:/:cortex] and
[legacy/profiles:] to [org/gnome/terminal/legacy/profiles:]) and then re-run
dconf update to apply the settings.

In `@packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css`:
- Around line 9-13: The CSS references GResource URIs that are missing (e.g.,
resource:///org/gnome/shell/theme/cortex-login-bg.png used in the
`#lockDialogGroup` rule and resource:///org/gnome/shell/theme/cortex-logo.svg
referenced elsewhere), causing the theme to fail at runtime; fix by either
adding the missing assets and wiring them into a GResource manifest and
build/install step so those resource URIs are available, or replace the
GResource URIs in gnome-shell.css (e.g., in the `#lockDialogGroup` rule and the
logo usage) with valid local file paths or inline/base64 assets and update any
related theme references accordingly.

In `@README.md`:
- Around line 36-44: Update the fenced code block showing the build output by
adding a language specifier to the opening fence so it reads ```text instead of
```; locate the block containing the tree output lines (the lines starting with
"output/" and the indented file tree entries) and change only the opening fence
to include "text" to satisfy markdownlint MD040 and improve readability.

In `@scripts/build.sh`:
- Around line 94-98: Add a check for the dpkg-buildpackage tool in the
dependency check so cmd_check_deps fails early if dpkg-dev/dpkg-buildpackage is
missing: in the same block where check_command lb, gpg and python3 are
validated, call check_command dpkg-buildpackage (or verify the dpkg-buildpackage
binary) and set failed=1 on failure; this ensures build_pkg_cortex_branding()
and other meta-package build flows that call dpkg-buildpackage fail fast with a
clear missing-dependency signal.
♻️ Duplicate comments (13)
packages/cortex-branding/usr/share/plymouth/themes/cortex/cortex.script (2)

117-130: Guard against null deref when normal display is shown first.

display_normal_callback() can run before password_dialogue_setup() is called (e.g., boot without password prompt), but password_dialogue_opacity() accesses global.password_entry, global.password_prompt, and global.password_bullets without guards—causing a crash if the callback fires first.

🐛 Proposed defensive guards
 fun password_dialogue_opacity(opacity) {
-    global.password_entry.sprite.SetOpacity(opacity);
-    global.password_prompt.sprite.SetOpacity(opacity);
-    for (i = 0; global.password_bullets[i]; i++) {
-        global.password_bullets[i].sprite.SetOpacity(opacity);
-    }
+    if (global.password_entry && global.password_entry.sprite)
+        global.password_entry.sprite.SetOpacity(opacity);
+    if (global.password_prompt && global.password_prompt.sprite)
+        global.password_prompt.sprite.SetOpacity(opacity);
+    if (global.password_bullets) {
+        for (i = 0; global.password_bullets[i]; i++) {
+            if (global.password_bullets[i].sprite)
+                global.password_bullets[i].sprite.SetOpacity(opacity);
+        }
+    }
 }

136-143: Reuse the message sprite instead of recreating it on every callback.

message_callback() creates a new Sprite object with each call, accumulating unused sprites in memory. The same file demonstrates the correct pattern in animate_dots() (lines 68, 71) which reuses sprites via SetImage().

♻️ Suggested fix
 fun message_callback(text) {
     message.image = Image.Text(text, 0.6, 0.6, 0.7, 1, "Sans 11");
-    message.sprite = Sprite(message.image);
+    if (!message.sprite) {
+        message.sprite = Sprite(message.image);
+    } else {
+        message.sprite.SetImage(message.image);
+    }
     message.x = screen_x + screen_width / 2 - message.image.GetWidth() / 2;
     message.y = screen_y + screen_height - 50;
     message.sprite.SetPosition(message.x, message.y, 10);
 }
docs/branding/WALLPAPERS-ASSETS.md (1)

16-40: Add language specifiers to fenced blocks for MD040.

✍️ Proposed fix
-```
+```text
 Background:     `#0F0F23`
 Surface:        `#1E1E3F`
 Border:         `#2D2D5A`
-```
+```

-```
+```text
 Primary Purple: `#6B21A8`
 Light Purple:   `#A855F7`
 Electric Cyan:  `#06B6D4`
 Light Cyan:     `#22D3EE`
-```
+```

-```
+```text
 /usr/share/backgrounds/cortex/
 ├── minimal-dark.png    (default)
 └── circuit-board.png

 /usr/share/gnome-background-properties/
 └── cortex-wallpapers.xml
-```
+```
docs/branding/BRAND-GUIDELINES.md (1)

163-186: Add language identifiers to fenced code blocks.

The code blocks at lines 163, 172, and 181 are missing language specifiers, triggering MD040. Consider adding text as the language identifier.

packages/cortex-branding/etc/dconf/db/gdm.d/01-cortex-branding (1)

6-8: Verify logo asset exists at the referenced path.

Line 8 references /usr/share/cortex/logos/cortex-logo-light.svg. This path must exist and be installed by the branding package. The verification hook (50-cortex-branding.hook.chroot, line 65) also checks for this file, so ensure it's included in the package assets.

#!/bin/bash
# Verify the logo file exists in the package source
echo "=== Searching for cortex-logo-light.svg ==="
fd -t f "cortex-logo-light" packages/cortex-branding/

echo -e "\n=== List all logo files ==="
fd -t f -e svg -e png "logo" packages/cortex-branding/
README.md (1)

39-40: Align ISO filename example with date-based ISO_VERSION.
ISO_VERSION defaults to a YYYYMMDD value (e.g., 20260117), so 0.1.0 can mislead.

🔧 Suggested fix
-├── cortex-linux-0.1.0-amd64.iso           # Bootable ISO
-├── cortex-linux-0.1.0-amd64.iso.sha256
+├── cortex-linux-YYYYMMDD-amd64.iso        # Bootable ISO
+├── cortex-linux-YYYYMMDD-amd64.iso.sha256
scripts/build.sh (4)

62-68: Harden copy_glob_if_exists against spaces/dirs.
Unquoted globs and cp without -r will break on directories or filenames with spaces and can create flaky builds.

🔧 Suggested fix
 copy_glob_if_exists() {
     local pattern="$1"
     local dest="$2"
-    # shellcheck disable=SC2086
-    if ls $pattern 1>/dev/null 2>&1; then
-        cp $pattern "$dest"
-        return 0
-    fi
-    return 1
+    shopt -s nullglob
+    local matches=($pattern)
+    shopt -u nullglob
+    if ((${`#matches`[@]} > 0)); then
+        cp -r -- "${matches[@]}" "$dest"
+        return 0
+    fi
+    return 1
 }

499-505: Guard the apt-cacher-ng probe when curl isn’t available.
If curl is missing, the check falls through and logs a misleading warning.

🔧 Suggested fix
-    if curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
+    if command -v curl &>/dev/null && curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then

272-293: Fix error aggregation in cmd_validate.
errors=$((errors + $?)) after || captures the assignment status, so errors never accumulate.

🔧 Suggested fix
 cmd_validate() {
     local mode="${1:-all}"
     local errors=0
+    local ret=0
@@
         provision)
-            validate_provision || errors=$((errors + $?))
+            ret=0
+            validate_provision || ret=$?
+            errors=$((errors + ret))
             ;;
         hooks)
-            validate_hooks || errors=$((errors + $?))
+            ret=0
+            validate_hooks || ret=$?
+            errors=$((errors + ret))
             ;;
         lint)
-            run_shellcheck || errors=$((errors + $?))
+            ret=0
+            run_shellcheck || ret=$?
+            errors=$((errors + ret))
             ;;
         all)
             validate_preseed
             echo ""
-            validate_provision || errors=$((errors + $?))
+            ret=0
+            validate_provision || ret=$?
+            errors=$((errors + ret))
             echo ""
-            validate_hooks || errors=$((errors + $?))
+            ret=0
+            validate_hooks || ret=$?
+            errors=$((errors + ret))
             echo ""
-            run_shellcheck || errors=$((errors + $?))
+            ret=0
+            run_shellcheck || ret=$?
+            errors=$((errors + ret))
             ;;

561-563: Avoid unconditional sudo for lb build/lb clean.
When running as root (common in CI), sudo can fail; use an EUID check.

🔧 Suggested fix
-    sudo lb build
+    if [[ $EUID -eq 0 ]]; then
+        lb build
+    else
+        sudo lb build
+    fi
@@
-        sudo lb clean
+        if [[ $EUID -eq 0 ]]; then
+            lb clean
+        else
+            sudo lb clean
+        fi

Also applies to: 655-657

.github/workflows/build-iso.yml (3)

222-223: Update softprops/action-gh-release to v2.

Static analysis indicates @v1 uses an outdated runner that may not work on current GitHub Actions. Update to v2 for compatibility:

       - name: Create Release
-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@v2
         with:

19-26: PR path filter omits the workflow file itself.

Changes to .github/workflows/build-iso.yml won't trigger CI on pull requests, making it hard to validate workflow modifications before merging.

   pull_request:
     branches: [main]
     paths:
       - 'iso/**'
       - 'packages/**'
       - 'scripts/**'
       - 'docs/branding/**'
       - 'Makefile'
+      - '.github/workflows/build-iso.yml'

168-175: Checksum verification silently passes when no .sha256 files exist.

If no checksum files are present, the loop completes without error, giving a false sense of validation success.

Proposed fix
       - name: Verify checksums
         run: |
           ls -la
+          verified=0
           for iso in *.iso; do
             if [ -f "${iso}.sha256" ]; then
               sha256sum -c "${iso}.sha256"
+              verified=$((verified + 1))
             fi
           done
+          if [ $verified -eq 0 ]; then
+            echo "ERROR: No checksum files found to verify"
+            exit 1
+          fi
🧹 Nitpick comments (10)
packages/cortex-branding/usr/share/plymouth/themes/cortex/cortex.script (1)

93-115: Password bullet display is incomplete and prompt should be declared as local.

The global.password_bullets array (line 106) is initialized but never populated. The password_dialogue_opacity function (line 120) attempts to iterate over bullets that don't exist, indicating the feature was intended but the mechanism to add bullet sprites when the user types is missing.

Additionally, prompt (lines 108-114) lacks a local. declaration, creating an implicit global. For consistency with entry and bullet_image, declare it explicitly:

Suggested fix
 fun password_dialogue_setup(title, bullet) {
     local.entry;
     local.bullet_image;
+    local.prompt;
packages/cortex-branding/etc/update-motd.d/10-cortex-sysinfo (2)

22-22: Consider avoiding useless use of cat.

The cat piped to awk can be simplified by passing the file directly to awk.

♻️ Suggested improvement
-LOAD=$(cat /proc/loadavg | awk '{print $1" "$2" "$3}')
+LOAD=$(awk '{print $1" "$2" "$3}' /proc/loadavg)

57-67: Guard against non-numeric input in color functions.

The mem_color and disk_color functions use integer comparisons (-lt) which will produce errors if the argument is empty or non-numeric (e.g., if awk fails unexpectedly). Consider adding a fallback or validation.

♻️ Suggested improvement
 mem_color() {
+    local val="${1:-0}"
+    [[ "$val" =~ ^[0-9]+$ ]] || val=0
-    if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
+    if [ "$val" -lt 50 ]; then echo -e "${GREEN}";
+    elif [ "$val" -lt 80 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }

 disk_color() {
+    local val="${1:-0}"
+    [[ "$val" =~ ^[0-9]+$ ]] || val=0
-    if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
+    if [ "$val" -lt 70 ]; then echo -e "${GREEN}";
+    elif [ "$val" -lt 90 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }
packages/cortex-branding/etc/update-motd.d/20-cortex-updates (2)

51-52: Consider avoiding useless use of cat.

The cat piped to head and tr can be simplified.

♻️ Suggested improvement
-        REBOOT_PKGS=$(cat /var/run/reboot-required.pkgs | head -3 | tr '\n' ', ' | sed 's/,$//')
+        REBOOT_PKGS=$(head -3 /var/run/reboot-required.pkgs | tr '\n' ', ' | sed 's/,$//')

62-62: Consider avoiding useless use of cat.

The cat piped to sed can be simplified.

♻️ Suggested improvement
-    cat "$CORTEX_NOTICE" | sed 's/^/    /'
+    sed 's/^/    /' "$CORTEX_NOTICE"
packages/cortex-branding/etc/update-motd.d/00-cortex-banner (1)

7-12: Unused color variables.

PURPLE, CYAN, and WHITE are defined but not used in this script. This may be intentional for consistency with other MOTD scripts, but consider removing them if not needed.

packages/cortex-branding/debian/prerm (1)

47-52: MOTD re-enable logic may have unintended side effects.

The glob pattern ??-* (line 49) only matches scripts with exactly two-digit prefixes, potentially missing scripts with single-digit or three-digit prefixes. More importantly, chmod +x on all scripts (line 50) will re-enable scripts that may have been intentionally disabled by the administrator before the package was installed.

Consider either:

  1. Tracking which scripts the package disabled during install
  2. Only restoring scripts that the package itself created
iso/live-build/config/hooks/live/99-live-session.hook.chroot (2)

41-54: Duplicate GDM configuration files with identical content.

Both /etc/gdm3/daemon.conf and /etc/gdm3/custom.conf are created with the same autologin settings. While this might be intentional for compatibility across GDM versions (some versions prefer one file over the other), consider documenting why both are needed or consolidating to a single file if only one is required.


76-86: Desktop entry file doesn't require executable permission.

Line 86 makes the .desktop file executable, but .desktop files are parsed as data files by the XDG autostart mechanism—they don't need the executable bit. This is harmless but unnecessary.

Suggested change
-chmod +x /etc/skel/.config/autostart/welcome.desktop
+# .desktop files don't need executable permission for autostart
.github/workflows/build-iso.yml (1)

63-64: Pin jlumbroso/free-disk-space to a stable version.

Using @main exposes the build to supply chain risks—breaking changes or malicious commits could affect builds. Pin to a stable release:

       - name: Free disk space
-        uses: jlumbroso/free-disk-space@main
+        uses: jlumbroso/free-disk-space@v1.3.1
What is the latest version of jlumbroso/free-disk-space GitHub Action?

Comment on lines +19 to +27
item_font = "DejaVu Sans Regular 14"
item_color = "#E2E8F0"
selected_item_font = "DejaVu Sans Bold 14"
selected_item_color = "#06B6D4"
item_height = 36
item_padding = 12
item_spacing = 4
selected_item_color = "#06B6D4"
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Duplicate property: selected_item_color defined twice.

Lines 22 and 26 both define selected_item_color with the same value. This appears to be a copy-paste oversight. Remove the duplicate to keep the theme file clean.

🔧 Suggested fix
     item_font = "DejaVu Sans Regular 14"
     item_color = "#E2E8F0"
     selected_item_font = "DejaVu Sans Bold 14"
     selected_item_color = "#06B6D4"
     item_height = 36
     item_padding = 12
     item_spacing = 4
-    selected_item_color = "#06B6D4"
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
item_font = "DejaVu Sans Regular 14"
item_color = "#E2E8F0"
selected_item_font = "DejaVu Sans Bold 14"
selected_item_color = "#06B6D4"
item_height = 36
item_padding = 12
item_spacing = 4
selected_item_color = "#06B6D4"
}
item_font = "DejaVu Sans Regular 14"
item_color = "#E2E8F0"
selected_item_font = "DejaVu Sans Bold 14"
selected_item_color = "#06B6D4"
item_height = 36
item_padding = 12
item_spacing = 4
}
🤖 Prompt for AI Agents
In `@packages/cortex-branding/boot/grub/themes/cortex/theme.txt` around lines 19 -
27, The theme file defines selected_item_color twice (symbols:
selected_item_color) creating a duplicate; remove the redundant
selected_item_color declaration so only a single selected_item_color remains
(keep the intended value already defined), e.g., delete the later/duplicate
selected_item_color entry to clean up the theme block alongside existing
item_font, item_color, selected_item_font, item_height, item_padding, and
item_spacing settings.

Comment on lines +125 to +134
if [ -f /usr/share/gnome-shell/theme/Cortex/gnome-shell.css ]; then
# Register Cortex GDM theme with update-alternatives
if command -v update-alternatives &>/dev/null; then
# Check if gdm3-theme alternative exists
if update-alternatives --list gdm3-theme.css &>/dev/null 2>&1; then
update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200 || true
update-alternatives --set gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's find and examine the actual file
find . -name "postinst" -path "*/cortex-branding/*"

Repository: cortexlinux/cortex-distro

Length of output: 111


🌐 Web query:

update-alternatives --list behavior when group doesn't exist fresh install

💡 Result:

Short answer: if the link group doesn't exist, update-alternatives prints an error like
"update-alternatives: error: no alternatives for " and exits with a non‑zero status (exit status 2 for error conditions). To create a group you must use --install (or install a package that calls update-alternatives). [1][2]

Sources:

  • update‑alternatives manual (error message / exit status details). [1]
  • Examples and common output when a group is missing (shows the "no alternatives for ..." message and usage of --install to create a group). [2]

🌐 Web query:

Debian update-alternatives command reference documentation

💡 Result:

Here are the official reference/manpage locations for Debian's update-alternatives (includes synopsis, commands, examples and options):

  • Stable (trixie) manpage (dpkg update-alternatives). [1]
  • Older dpkg manpage (detailed COMMANDS section). [2]
  • Multilingual/manpages index (French copy of the manpage). [3]

If you want, I can open any of these and extract the exact --install/--remove/--config syntax or paste the full COMMANDS section.


🏁 Script executed:

cat -n ./packages/cortex-branding/debian/postinst | sed -n '115,145p'

Repository: cortexlinux/cortex-distro

Length of output: 1823


🏁 Script executed:

# Check update-alternatives documentation for --install behavior
# Let's also verify how --install works when group doesn't exist
web_search_result=$(cat << 'EOF'
Need to verify: does update-alternatives --install create a new group if it doesn't exist?
EOF
)

Repository: cortexlinux/cortex-distro

Length of output: 51


🌐 Web query:

update-alternatives --install create new group first time

💡 Result:

Use update-alternatives --install. Syntax:

sudo update-alternatives --install [--slave ...]

Example (create new group "editor" pointing /usr/bin/editor to /usr/bin/vim with priority 50):

sudo update-alternatives --install /usr/bin/editor editor /usr/bin/vim 50

When the group is first created it is put into automatic mode (the highest-priority alternative is chosen). To pick a specific alternative interactively afterwards run --config, or set it non‑interactively with --set. [1][2][3]

References:
[1] update-alternatives manpage (dpkg).
[2] Debian Alternatives wiki (examples, adding a new link group).
[3] Example usage and explanation (how-to/tutorial).


Remove the conditional check that blocks GDM theme registration on first install.

On fresh systems, update-alternatives --list gdm3-theme.css fails because the alternatives group doesn't exist yet. This causes the subsequent --install and --set commands to be skipped entirely, so the GDM theme is never applied. Since --install creates the group if needed, the existence check is unnecessary and prevents the theme from being registered on new installations.

🔧 Suggested fix
-                # Check if gdm3-theme alternative exists
-                if update-alternatives --list gdm3-theme.css &>/dev/null 2>&1; then
-                    update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css \
-                        /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200 || true
-                    update-alternatives --set gdm3-theme.css \
-                        /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
-                fi
+                update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css \
+                    /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200 || true
+                update-alternatives --set gdm3-theme.css \
+                    /usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [ -f /usr/share/gnome-shell/theme/Cortex/gnome-shell.css ]; then
# Register Cortex GDM theme with update-alternatives
if command -v update-alternatives &>/dev/null; then
# Check if gdm3-theme alternative exists
if update-alternatives --list gdm3-theme.css &>/dev/null 2>&1; then
update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200 || true
update-alternatives --set gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
fi
if [ -f /usr/share/gnome-shell/theme/Cortex/gnome-shell.css ]; then
# Register Cortex GDM theme with update-alternatives
if command -v update-alternatives &>/dev/null; then
update-alternatives --install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200 || true
update-alternatives --set gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
fi
🤖 Prompt for AI Agents
In `@packages/cortex-branding/debian/postinst` around lines 125 - 134, Remove the
conditional check that gates registration on the existence of the alternatives
group by deleting the "if update-alternatives --list gdm3-theme.css" test and
its fi; always run the update-alternatives calls so that "update-alternatives
--install /usr/share/gnome-shell/theme/gdm3.css gdm3-theme.css
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 200" and
"update-alternatives --set gdm3-theme.css
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css" execute (the --install will
create the group if missing), keeping the surrounding checks for the
gnome-shell.css file and for the presence of update-alternatives.

Comment on lines +4 to +32
[legacy/profiles:/:cortex]
audible-bell=false
background-color='#0D0D0D'
background-transparency-percent=5
bold-color='#06B6D4'
bold-color-same-as-fg=false
bold-is-bright=true
cursor-background-color='#06B6D4'
cursor-colors-set=true
cursor-foreground-color='#0D0D0D'
cursor-shape='ibeam'
default-size-columns=120
default-size-rows=32
font='JetBrains Mono 11'
foreground-color='#E5E5E5'
highlight-background-color='#6B21A8'
highlight-colors-set=true
highlight-foreground-color='#FFFFFF'
palette=['#0D0D0D', '#EF4444', '#22C55E', '#EAB308', '#3B82F6', '#A855F7', '#06B6D4', '#A3A3A3', '#525252', '#F87171', '#4ADE80', '#FACC15', '#60A5FA', '#C084FC', '#22D3EE', '#F5F5F5']
scroll-on-output=false
scrollback-lines=10000
use-system-font=false
use-theme-colors=false
use-transparent-background=false
visible-name='Cortex'

[legacy/profiles:]
default='cortex'
list=['cortex']
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, verify the file exists and check its content
find . -name "01-cortex-terminal" -o -name "*dconf*" | head -20

Repository: cortexlinux/cortex-distro

Length of output: 172


🏁 Script executed:

# Check the exact content of the file in question
cat packages/cortex-branding/etc/dconf/db/local.d/01-cortex-terminal

Repository: cortexlinux/cortex-distro

Length of output: 1048


🌐 Web query:

GNOME Terminal dconf schema org/gnome/terminal/legacy/profiles keyfile format

💡 Result:

Short answer: GNOME Terminal profile keyfiles use the dconf "keyfile" format: INI-style groups named with dconf paths (e.g. [org/gnome/terminal/legacy/profiles:/…]) and key = value lines where values are serialized GVariant literals (strings in single quotes, booleans true/false, arrays like ['a','b'], rgb(...) etc.). After editing, run dconf update to compile them into /etc/dconf/db/*. Example:

[legacy/profiles:]
list=['b1dcc9dd-5262-4d8d-a863-c897e6d979b9']
default='b1dcc9dd-5262-4d8d-a863-c897e6d979b9'

[legacy/profiles:/:b1dcc9dd-5262-4d8d-a863-c897e6d979b9]
visible-name='Default'
font='Monospace 12'
use-theme-colors=false
palette=['rgb(23,20,33)','rgb(208,207,204)']

Docs: GNOME dconf keyfile format and examples. [1][2][3]

Sources:

  • "Control system settings with keyfiles" (GNOME admin guide). [1]
  • "Custom default values for system settings" (GNOME admin guide). [2]
  • Example dconf dump / gnome-terminal profile snippet. [3]

Use fully-qualified dconf paths in system keyfiles so settings actually apply.

This system dconf file is located in /etc/dconf/db/local.d/, which is processed by dconf update. Section headers must include the full schema path (e.g., [org/gnome/terminal/legacy/profiles:/:cortex]). Without the org/gnome/terminal/ prefix, the keys won't be placed where GNOME Terminal reads them and the configuration will be ignored.

✅ Proposed fix
-[legacy/profiles:/:cortex]
+[org/gnome/terminal/legacy/profiles:/:cortex]
 audible-bell=false
 background-color='#0D0D0D'
 ...
-[legacy/profiles:]
+[org/gnome/terminal/legacy/profiles:]
 default='cortex'
 list=['cortex']
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
[legacy/profiles:/:cortex]
audible-bell=false
background-color='#0D0D0D'
background-transparency-percent=5
bold-color='#06B6D4'
bold-color-same-as-fg=false
bold-is-bright=true
cursor-background-color='#06B6D4'
cursor-colors-set=true
cursor-foreground-color='#0D0D0D'
cursor-shape='ibeam'
default-size-columns=120
default-size-rows=32
font='JetBrains Mono 11'
foreground-color='#E5E5E5'
highlight-background-color='#6B21A8'
highlight-colors-set=true
highlight-foreground-color='#FFFFFF'
palette=['#0D0D0D', '#EF4444', '#22C55E', '#EAB308', '#3B82F6', '#A855F7', '#06B6D4', '#A3A3A3', '#525252', '#F87171', '#4ADE80', '#FACC15', '#60A5FA', '#C084FC', '#22D3EE', '#F5F5F5']
scroll-on-output=false
scrollback-lines=10000
use-system-font=false
use-theme-colors=false
use-transparent-background=false
visible-name='Cortex'
[legacy/profiles:]
default='cortex'
list=['cortex']
[org/gnome/terminal/legacy/profiles:/:cortex]
audible-bell=false
background-color='#0D0D0D'
background-transparency-percent=5
bold-color='#06B6D4'
bold-color-same-as-fg=false
bold-is-bright=true
cursor-background-color='#06B6D4'
cursor-colors-set=true
cursor-foreground-color='#0D0D0D'
cursor-shape='ibeam'
default-size-columns=120
default-size-rows=32
font='JetBrains Mono 11'
foreground-color='#E5E5E5'
highlight-background-color='#6B21A8'
highlight-colors-set=true
highlight-foreground-color='#FFFFFF'
palette=['#0D0D0D', '#EF4444', '#22C55E', '#EAB308', '#3B82F6', '#A855F7', '#06B6D4', '#A3A3A3', '#525252', '#F87171', '#4ADE80', '#FACC15', '#60A5FA', '#C084FC', '#22D3EE', '#F5F5F5']
scroll-on-output=false
scrollback-lines=10000
use-system-font=false
use-theme-colors=false
use-transparent-background=false
visible-name='Cortex'
[org/gnome/terminal/legacy/profiles:]
default='cortex'
list=['cortex']
🤖 Prompt for AI Agents
In `@packages/cortex-branding/etc/dconf/db/local.d/01-cortex-terminal` around
lines 4 - 32, The file uses incomplete dconf section headers (e.g.,
[legacy/profiles:/:cortex] and [legacy/profiles:]) so GNOME Terminal will ignore
the keys; update the section headers to the fully-qualified schema path by
replacing those headers with the corresponding
org/gnome/terminal/legacy/profiles variants (i.e., change
[legacy/profiles:/:cortex] to [org/gnome/terminal/legacy/profiles:/:cortex] and
[legacy/profiles:] to [org/gnome/terminal/legacy/profiles:]) and then re-run
dconf update to apply the settings.

Comment on lines +9 to +13
#lockDialogGroup {
background: #0F0F23 url('resource:///org/gnome/shell/theme/cortex-login-bg.png');
background-size: cover;
background-position: center;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for the referenced image assets
echo "=== Searching for login background and logo assets ==="
fd -t f "cortex-login-bg\|cortex-logo" packages/cortex-branding/

echo -e "\n=== Check for GResource XML or asset installation ==="
fd -t f "gresource\|\.xml" packages/cortex-branding/ | head -20

echo -e "\n=== List all files in the theme directory ==="
find packages/cortex-branding/usr/share/gnome-shell/theme/Cortex -type f 2>/dev/null | sort

echo -e "\n=== Check meson.build or similar build files ==="
fd -t f "meson\.build\|CMakeLists\.txt\|setup\.py\|Makefile" packages/cortex-branding/

Repository: cortexlinux/cortex-distro

Length of output: 351


🏁 Script executed:

#!/bin/bash
# Read the gnome-shell.css file
echo "=== Full content of gnome-shell.css ==="
cat -n packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css

echo -e "\n=== Total line count ==="
wc -l packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css

echo -e "\n=== Search for resource references ==="
rg "resource:///" packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css

Repository: cortexlinux/cortex-distro

Length of output: 5188


Add missing theme assets or remove GResource references.

The CSS file references GResource paths that do not exist in the repository:

  • resource:///org/gnome/shell/theme/cortex-login-bg.png (line 10)
  • resource:///org/gnome/shell/theme/cortex-logo.svg (line 161)

Neither asset file exists in packages/cortex-branding/, and there is no GResource XML configuration or build mechanism to register them. The theme will fail to load the background and logo at runtime. Either provide the missing assets and configure GResource registration, or remove these resource references and use local file paths or inline styles instead.

🤖 Prompt for AI Agents
In `@packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css`
around lines 9 - 13, The CSS references GResource URIs that are missing (e.g.,
resource:///org/gnome/shell/theme/cortex-login-bg.png used in the
`#lockDialogGroup` rule and resource:///org/gnome/shell/theme/cortex-logo.svg
referenced elsewhere), causing the theme to fail at runtime; fix by either
adding the missing assets and wiring them into a GResource manifest and
build/install step so those resource URIs are available, or replace the
GResource URIs in gnome-shell.css (e.g., in the `#lockDialogGroup` rule and the
logo usage) with valid local file paths or inline/base64 assets and update any
related theme references accordingly.

Comment on lines 36 to 44
After a successful build:
```
output/
├── cortex-linux-0.1.0-amd64-offline.iso # Bootable ISO
├── cortex-linux-0.1.0-amd64-offline.iso.sha256
├── packages/
│ ├── cortex-archive-keyring_*.deb
│ ├── cortex-core_*.deb
│ └── cortex-full_*.deb
├── cortex-linux-0.1.0-amd64.iso # Bootable ISO
├── cortex-linux-0.1.0-amd64.iso.sha256
└── sbom/
├── cortex-linux-0.1.0.cdx.json # CycloneDX SBOM
└── cortex-linux-0.1.0.spdx.json # SPDX SBOM
├── cortex-linux-0.1.0.cdx.json # CycloneDX SBOM
└── cortex-linux-0.1.0.spdx.json # SPDX SBOM
```
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's check if README.md exists and read the relevant lines
if [ -f README.md ]; then
  echo "=== README.md lines 30-50 ==="
  sed -n '30,50p' README.md | cat -n
else
  echo "README.md not found, searching for it..."
  find . -name "README.md" -type f
fi

Repository: cortexlinux/cortex-distro

Length of output: 662


🏁 Script executed:

# Check for markdownlint configuration
find . -name ".markdownlint*" -o -name "markdownlint.json" -o -name "markdownlintrc*" | head -20

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Search for any linting configuration files
find . -maxdepth 2 -name ".markdownlintrc*" -o -name "markdownlint.json" -o -name ".markdownlintignore"

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Count exact lines to verify line number mapping
wc -l README.md
echo "---"
# Get lines 36-44 directly
sed -n '36,44p' README.md | cat -n

Repository: cortexlinux/cortex-distro

Length of output: 416


Add language specifier to fenced code block to comply with markdownlint MD040.

The code block at lines 37–44 lacks a language identifier. Change the opening fence from ``` to ```text to improve readability and pass linting rules.

-```
+```text
 output/
 ├── cortex-linux-0.1.0-amd64.iso           # Bootable ISO
 ├── cortex-linux-0.1.0-amd64.iso.sha256
 └── sbom/
     ├── cortex-linux-0.1.0.cdx.json        # CycloneDX SBOM
     └── cortex-linux-0.1.0.spdx.json       # SPDX SBOM

<details>
<summary>🧰 Tools</summary>

<details>
<summary>🪛 markdownlint-cli2 (0.18.1)</summary>

37-37: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

</details>

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

In @README.md around lines 36 - 44, Update the fenced code block showing the
build output by adding a language specifier to the opening fence so it reads
text instead of ; locate the block containing the tree output lines (the
lines starting with "output/" and the indented file tree entries) and change
only the opening fence to include "text" to satisfy markdownlint MD040 and
improve readability.


</details>

<!-- fingerprinting:phantom:medusa:eagle -->

<!-- This is an auto-generated comment by CodeRabbit -->

Comment on lines +94 to +98
# Required dependencies
check_command lb live-build || failed=1
check_command gpg gnupg || failed=1
check_command python3 python3 || failed=1

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

# First, let's examine the file around lines 94-98
head -n 100 scripts/build.sh | tail -n 15

Repository: cortexlinux/cortex-distro

Length of output: 481


🏁 Script executed:

# Search for dpkg-buildpackage usage
rg "dpkg-buildpackage" scripts/

Repository: cortexlinux/cortex-distro

Length of output: 498


🏁 Script executed:

# Find the build_pkg_cortex_branding function
rg -A 20 "build_pkg_cortex_branding" scripts/build.sh

Repository: cortexlinux/cortex-distro

Length of output: 799


🏁 Script executed:

# Check what cmd_check_deps function looks like and all current checks
rg -A 15 "cmd_check_deps" scripts/build.sh

Repository: cortexlinux/cortex-distro

Length of output: 978


dpkg-buildpackage is required but not checked.
Both build_pkg_cortex_branding() and meta-package builds invoke dpkg-buildpackage, so cmd_check_deps should fail early if dpkg-dev is missing.

🔧 Suggested fix
     # Required dependencies
     check_command lb live-build || failed=1
     check_command gpg gnupg || failed=1
     check_command python3 python3 || failed=1
+    check_command dpkg-buildpackage dpkg-dev || failed=1
🤖 Prompt for AI Agents
In `@scripts/build.sh` around lines 94 - 98, Add a check for the dpkg-buildpackage
tool in the dependency check so cmd_check_deps fails early if
dpkg-dev/dpkg-buildpackage is missing: in the same block where check_command lb,
gpg and python3 are validated, call check_command dpkg-buildpackage (or verify
the dpkg-buildpackage binary) and set failed=1 on failure; this ensures
build_pkg_cortex_branding() and other meta-package build flows that call
dpkg-buildpackage fail fast with a clear missing-dependency signal.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

🤖 Fix all issues with AI agents
In `@Makefile`:
- Around line 57-65: Update the Makefile help text to accurately reflect
existing targets and semantics: change the "Package Targets" block so it
clarifies that `make packages` builds all packages and does not accept
`PKG=...`, list only actual package names produced by the repo (or remove the
hardcoded list), and replace the misleading line suggesting `make packages`
accepts `PKG=...` with instructions to use `make build-package PKG=<name>` for
single-package builds; also adjust the "Branding Targets" note to match the real
target name `branding-package` and its install path/usage if different, ensuring
consistency with the `build-package` and `branding-package` targets referenced
in the Makefile.

In `@packages/cortex-branding/debian/prerm`:
- Around line 8-52: The script currently uses set -e so any failing
write/ln/update-alternatives will abort removal; change the risky operations (ln
-sf /usr/lib/os-release /etc/os-release, the echo redirections to /etc/issue and
/etc/issue.net, the cat > /etc/lsb-release here-doc, update-alternatives
--remove calls, plymouth-set-default-theme -R, and the chmod loop over
/etc/update-motd.d) to be non-fatal by adding explicit failure handling (e.g.,
append || { echo "Warning: failed to restore <resource>" >&2; } to each command
or redirect errors and continue), or check writability first (e.g., [ -w /etc ]
|| { warn; } ) before attempting writes so the prerm emits warnings on failure
instead of exiting due to set -e. Ensure each referenced command (ln, echo
redirects, cat heredoc to /etc/lsb-release, update-alternatives,
plymouth-set-default-theme, chmod) has its own guarded fallback so removal never
aborts.

In `@packages/cortex-branding/etc/dconf/db/local.d/01-cortex-terminal`:
- Around line 15-18: The GNOME Terminal config hardcodes font='JetBrains Mono
11' but the package dependency is missing; update debian/control to add
fonts-jetbrains-mono to the Depends: field so the JetBrains Mono font is
installed for the branding. Edit the package metadata (debian/control) and
append fonts-jetbrains-mono to the appropriate package's Depends line, ensuring
the binary package that ships the dconf snippet will pull the font; keep the
existing font string ("font='JetBrains Mono 11'") in the dconf file unchanged.

In `@packages/cortex-branding/etc/update-motd.d/10-cortex-sysinfo`:
- Around line 56-67: The mem_color and disk_color functions can fail if "$1" is
empty or non-numeric; add defensive numeric validation at the start of each
function by assigning a local variable (e.g., val="$1"), checking it with a
regex like ^[0-9]+$ (or test -n and digits), and if it fails set a safe default
(e.g., val=0) before performing the -lt comparisons; update comparisons to use
that validated variable (val) so the integer tests in mem_color and disk_color
never receive non-numeric input.

In `@packages/cortex-branding/etc/update-motd.d/20-cortex-updates`:
- Around line 28-30: The UPDATES assignment can produce a duplicated "0" when
grep exits non-zero, causing UPDATES to be "0\n0" and triggering false
positives; change the logic around the UPDATES calculation in the
20-cortex-updates script: let the pipeline run without forcing an alternate echo
(use "|| true" or let the command fail silently), then normalize the result to a
single numeric string (e.g., treat empty or non-numeric output as "0" via
parameter expansion or a conditional) so UPDATES is always a single "0" or a
count; update the code that sets UPDATES (and any downstream check against "0")
to use this normalized value.

In `@packages/cortex-branding/usr/share/cortex/templates/os-release`:
- Around line 1-13: Update the LOGO entry in the os-release template: replace
the incorrect LOGO value "cortex-logo" with the actual asset name
"cortex-logo-light" so the LOGO field matches the available logo asset (update
the LOGO= line in the os-release template).

In `@packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css`:
- Around line 159-167: The CSS rule .login-dialog-logo references a missing
resource cortex-logo.svg and no GResource is defined; either add cortex-logo.svg
to the theme resources and register it in a GResource manifest (.gresource.xml)
under the org/gnome/shell/theme path so
resource:///org/gnome/shell/theme/cortex-logo.svg resolves, or update the
.login-dialog-logo background-image to point to the existing file (for example
use file:///usr/share/cortex/logos/cortex-logo-light.svg or the exact path dconf
uses) and ensure the referenced filename matches cortex-logo-light.svg; update
the package manifest to include the chosen asset so the login screen can load
it.

In `@scripts/build.sh`:
- Around line 607-614: The loop that builds iso_packages (local
iso_packages="cortex-branding") currently ignores failures by calling warn;
change it so required package build failures stop the script: when
build_single_package "$pkg" fails, call an error/fatal handler or echo an error
and exit 1 instead of warn. Update the for-loop in scripts/build.sh (referencing
iso_packages and build_single_package) to treat failures as fatal (e.g., replace
"|| warn 'Failed to build ${pkg}'" with a block that logs the error via log or a
fatal function and exits with non-zero status).
- Around line 549-553: The provisioning copy currently swallows errors (cp uses
2>/dev/null and || true), risking an ISO without provisioning; update the block
that references PROVISION_DIR and BUILD_DIR to remove stderr redirection and the
"|| true", run cp -r "${PROVISION_DIR}"/*
"${BUILD_DIR}/config/includes.binary/provisioning/" and check its exit status,
and if cp fails call the existing log function with a clear error message
including $PROVISION_DIR and $BUILD_DIR and then exit 1 (fail fast) so build
stops when provisioning copy fails.
♻️ Duplicate comments (17)
docs/branding/WALLPAPERS-ASSETS.md (1)

17-40: Code blocks still lack language specifiers.

The fenced code blocks at lines 17, 24, and 33 are missing language specifiers. This was flagged in a previous review and marked as addressed, but the issue persists in the current code.

Proposed fix
 ### Dark Theme
-```
+```text
 Background:     `#0F0F23`
 Surface:        `#1E1E3F`
 Border:         `#2D2D5A`

Accent Colors

- +text
Primary Purple: #6B21A8
Light Purple: #A855F7
Electric Cyan: #06B6D4
Light Cyan: #22D3EE


## Installation Path

-```
+```text
/usr/share/backgrounds/cortex/
packages/cortex-branding/etc/dconf/db/gdm.d/01-cortex-branding (1)

6-9: Verify the referenced GDM logo asset is packaged.

Line 8 points to /usr/share/cortex/logos/cortex-logo-light.svg. Please confirm that this exact filename is shipped by the branding package; otherwise the login screen will fall back to a missing or default logo.

Run this to verify the asset exists in the repo and is staged by packaging:

#!/bin/bash
# Check for the referenced logo asset
echo "=== Search for cortex-logo-light.svg ==="
fd -t f 'cortex-logo-light\.svg' packages/cortex-branding -E 'debian/**' 2>/dev/null

echo "=== List all cortex logo assets ==="
fd -t f 'cortex-logo' packages/cortex-branding -E 'debian/**' 2>/dev/null
docs/branding/BRAND-GUIDELINES.md (1)

163-186: Add language identifiers to the fenced blocks.

The blocks at Lines 163-186 still lack a language tag and will trigger MD040.

🛠️ Proposed fix
-```
+```text
 Primary: `#6B21A8` background, white text
 Secondary: transparent, `#6B21A8` border
 Ghost: transparent, `#94A3B8` text
 Danger: `#EF4444` background, white text

@@
- +text
Background: #1E1E3F (dark) or #FFFFFF (light)
Border: 1px solid rgba(107, 33, 168, 0.2)
Border radius: 12px
Shadow: 0 4px 20px rgba(0, 0, 0, 0.15)

@@
-```
+```text
Background: `#0F0F23` (dark) or `#F8FAFC` (light)
Border: 1px solid `#2D2D5A`
Focus border: `#06B6D4`
Border radius: 8px
</details>

</blockquote></details>
<details>
<summary>packages/cortex-branding/usr/share/plymouth/themes/cortex/cortex.script (2)</summary><blockquote>

`117-123`: **Guard against null deref when normal display is shown first.**

This issue was already identified in a previous review. The `display_normal_callback()` can fire before `password_dialogue_setup()` initializes the globals, causing crashes when accessing `global.password_entry`, `global.password_prompt`, and `global.password_bullets`.

Add null guards as suggested previously.

---

`136-143`: **Reuse message sprite instead of recreating it each callback.**

This issue was already identified in a previous review. Creating a new `Sprite` on every `message_callback()` invocation leaks sprite objects. The correct pattern (demonstrated in `animate_dots()`) is to check if the sprite exists and call `SetImage()` to update it.

</blockquote></details>
<details>
<summary>scripts/build.sh (5)</summary><blockquote>

`62-68`: **`copy_glob_if_exists` is unsafe for spaces/dirs and can miscopy.**

Unquoted globbing + `cp` without `-r` will break on directories or filenames with spaces, and can yield flaky builds.  

  
<details>
<summary>🔧 Safe globbing + recursive copy</summary>

```diff
 copy_glob_if_exists() {
     local pattern="$1"
     local dest="$2"
-    # shellcheck disable=SC2086
-    if ls $pattern 1>/dev/null 2>&1; then
-        cp $pattern "$dest"
-        return 0
-    fi
-    return 1
+    shopt -s nullglob
+    local matches=($pattern)
+    shopt -u nullglob
+    if ((${`#matches`[@]} > 0)); then
+        cp -r -- "${matches[@]}" "$dest"
+        return 0
+    fi
+    return 1
 }

94-139: Make dpkg-deb/dpkg-buildpackage required dependencies.

dpkg-deb is currently optional, yet package builds depend on it; dpkg-buildpackage is not checked at all. This can make make iso fail mid-way even after check-deps reports success.

🔧 Require packaging tools up front
     # Required dependencies
     check_command lb live-build || failed=1
     check_command gpg gnupg || failed=1
     check_command python3 python3 || failed=1
+    check_command dpkg-deb dpkg-dev || failed=1
+    check_command dpkg-buildpackage dpkg-dev || failed=1
@@
-    if command -v dpkg-deb &>/dev/null; then
-        log "dpkg-deb: OK"
-    else
-        warn "dpkg-deb not installed (needed for branding-package)"
-    fi

272-293: Error accumulation in cmd_validate is incorrect.

errors=$((errors + $?)) after || uses the status of the assignment (0), not the failed command. This causes false “passed” validation.

🔧 Capture exit codes safely
-            validate_provision || errors=$((errors + $?))
+            local ret=0
+            validate_provision || ret=$?
+            errors=$((errors + ret))
@@
-            validate_hooks || errors=$((errors + $?))
+            local ret=0
+            validate_hooks || ret=$?
+            errors=$((errors + ret))
@@
-            run_shellcheck || errors=$((errors + $?))
+            local ret=0
+            run_shellcheck || ret=$?
+            errors=$((errors + ret))

499-510: curl is used without being checked as a dependency.

If curl is missing, the apt-cacher check emits a command-not-found error and silently falls back. Either check for curl or add it to cmd_check_deps.

🔧 Guard the curl probe
-    if curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
+    if command -v curl &>/dev/null && curl -s --connect-timeout 2 http://localhost:3142 >/dev/null 2>&1; then
         log "apt-cacher-ng detected, using local cache proxy"

561-563: Unconditional sudo breaks when running as root.

sudo lb build / sudo lb clean will fail in root contexts (common in CI). Use an EUID guard.

🔧 Conditional sudo
-    sudo lb build
+    if [[ $EUID -eq 0 ]]; then
+        lb build
+    else
+        sudo lb build
+    fi
-        sudo lb clean
+        if [[ $EUID -eq 0 ]]; then
+            lb clean
+        else
+            sudo lb clean
+        fi

Also applies to: 654-657

README.md (1)

38-43: Update ISO filename examples to match date-based versioning.

ISO_VERSION defaults to YYYYMMDD, so examples like cortex-linux-0.1.0-amd64.iso are misleading.

🔧 Suggested example update
-├── cortex-linux-0.1.0-amd64.iso           # Bootable ISO
-├── cortex-linux-0.1.0-amd64.iso.sha256
+├── cortex-linux-YYYYMMDD-amd64.iso        # Bootable ISO
+├── cortex-linux-YYYYMMDD-amd64.iso.sha256
.github/workflows/build-iso.yml (6)

19-27: Privileged container runs on PRs—consider approval gating.

docker run --privileged executes on pull_request, which is risky for untrusted code. Consider removing PR triggers for this workflow or requiring manual approval via environments.

Also applies to: 91-105


19-27: PR path filter omits the workflow file.

Changes to .github/workflows/build-iso.yml alone won’t trigger CI. Add the workflow path (or use .github/workflows/**) in the PR path filter.

🔧 Include the workflow in PR paths
   pull_request:
     branches: [main]
     paths:
       - 'iso/**'
       - 'packages/**'
       - 'scripts/**'
       - 'docs/branding/**'
       - 'Makefile'
+      - '.github/workflows/build-iso.yml'

63-65: Pin jlumbroso/free-disk-space to a release tag.

Using @main is a supply-chain risk and can break unpredictably.

🔧 Pin to a stable release
-        uses: jlumbroso/free-disk-space@main
+        uses: jlumbroso/free-disk-space@v1.3.1

163-175: Artifact download layout likely breaks ISO verification.

actions/download-artifact typically extracts into a subfolder, so for iso in *.iso can iterate the literal *.iso and skip checks. Also, checksum verification should fail if no .sha256 files were processed.

🔧 Download to a known path and verify at least one checksum
       - name: Download ISO
         uses: actions/download-artifact@v4
         with:
           name: cortex-linux-${{ matrix.arch }}
+          path: artifacts

       - name: Verify checksums
         run: |
-          ls -la
-          for iso in *.iso; do
+          set -euo pipefail
+          shopt -s nullglob
+          cd artifacts
+          d="cortex-linux-${{ matrix.arch }}"
+          [ -d "$d" ] && cd "$d"
+          verified=0
+          for iso in *.iso; do
             if [ -f "${iso}.sha256" ]; then
               sha256sum -c "${iso}.sha256"
+              verified=$((verified + 1))
             fi
           done
+          if [ $verified -eq 0 ]; then
+            echo "No checksum files verified"
+            exit 1
+          fi

       - name: Check ISO structure
         run: |
+          set -euo pipefail
+          shopt -s nullglob
           sudo apt-get update
           sudo apt-get install -y xorriso
-          for iso in *.iso; do
+          cd artifacts
+          d="cortex-linux-${{ matrix.arch }}"
+          [ -d "$d" ] && cd "$d"
+          for iso in *.iso; do
             echo "=== Checking $iso ==="
             xorriso -indev "$iso" -find / -maxdepth 1 2>/dev/null | head -20
           done

Also applies to: 177-184


216-220: Checksum generation should guard empty globs.

If no *.deb (or no *.iso) files exist, glob expansion can fail and the step will error under bash -e.

🔧 Guard checksums
       - name: Generate combined checksums
         run: |
           cd release
-          sha256sum *.iso *.deb > SHA256SUMS 2>/dev/null || sha256sum *.iso > SHA256SUMS
-          sha512sum *.iso *.deb > SHA512SUMS 2>/dev/null || sha512sum *.iso > SHA512SUMS
+          shopt -s nullglob
+          files=( *.iso *.deb )
+          if ((${`#files`[@]})); then
+            sha256sum "${files[@]}" > SHA256SUMS
+            sha512sum "${files[@]}" > SHA512SUMS
+          else
+            echo "No ISO or DEB files found for checksumming"
+            exit 1
+          fi

223-223: Update softprops/action-gh-release to v2.

@v1 is outdated and flagged by actionlint; update to @v2.

🔧 Update action version
-        uses: softprops/action-gh-release@v1
+        uses: softprops/action-gh-release@v2
🧹 Nitpick comments (5)
packages/cortex-branding/etc/update-motd.d/10-cortex-sysinfo (2)

22-22: Minor: Avoid useless use of cat.

awk can read the file directly without piping from cat.

♻️ Suggested simplification
-LOAD=$(cat /proc/loadavg | awk '{print $1" "$2" "$3}')
+LOAD=$(awk '{print $1" "$2" "$3}' /proc/loadavg)

78-79: Quote variables passed to color functions.

While unlikely to cause issues with numeric values, quoting variables is a shell scripting best practice to prevent word splitting.

♻️ Suggested change
-echo -e "  ${GRAY}│${RESET}  ${CYAN}Memory${RESET}     $(mem_color $MEM_PERCENT)${MEM_USED}${RESET} / ${MEM_TOTAL} (${MEM_PERCENT}%)"
-echo -e "  ${GRAY}│${RESET}  ${CYAN}Disk${RESET}       $(disk_color $DISK_PERCENT)${DISK_USED}${RESET} / ${DISK_TOTAL} (${DISK_PERCENT}%)"
+echo -e "  ${GRAY}│${RESET}  ${CYAN}Memory${RESET}     $(mem_color "$MEM_PERCENT")${MEM_USED}${RESET} / ${MEM_TOTAL} (${MEM_PERCENT}%)"
+echo -e "  ${GRAY}│${RESET}  ${CYAN}Disk${RESET}       $(disk_color "$DISK_PERCENT")${DISK_USED}${RESET} / ${DISK_TOTAL} (${DISK_PERCENT}%)"
packages/cortex-branding/boot/grub/themes/cortex/theme.txt (1)

14-27: Duplicate property in boot_menu block.

selected_item_color is defined twice (lines 22 and 26) with the same value. Remove the duplicate to avoid confusion.

Proposed fix
 + boot_menu {
     left = 15%
     top = 25%
     width = 70%
     height = 50%
     item_font = "DejaVu Sans Regular 14"
     item_color = "#E2E8F0"
     selected_item_font = "DejaVu Sans Bold 14"
     selected_item_color = "#06B6D4"
     item_height = 36
     item_padding = 12
     item_spacing = 4
-    selected_item_color = "#06B6D4"
 }
iso/live-build/config/hooks/live/99-live-session.hook.chroot (1)

76-86: Unnecessary chmod +x on .desktop file.

Desktop entry files don't need the executable bit to be launched by the desktop environment. The chmod +x on line 86 is unnecessary.

Proposed fix
 cat > /etc/skel/.config/autostart/welcome.desktop << 'EOF'
 [Desktop Entry]
 Type=Application
 Name=Welcome to Cortex Linux
 Exec=gnome-terminal -- bash -c "echo 'Welcome to Cortex Linux Live!'; echo 'Desktop environment: GNOME'; echo 'Username: cortex'; echo 'Password: cortex'; echo ''; echo 'Press Enter to continue...'; read"
 Terminal=false
 StartupNotify=false
 X-GNOME-Autostart-enabled=true
 EOF
-
-chmod +x /etc/skel/.config/autostart/welcome.desktop
packages/cortex-branding/debian/postinst (1)

103-110: Consider a more targeted approach for disabling MOTD scripts.

The glob pattern ??-* assumes all MOTD scripts follow the NN-name naming convention. While this is standard, some distributions may have differently named scripts. The current approach is acceptable but could inadvertently skip scripts with non-standard names.

♻️ Alternative approach using find
-            for f in /etc/update-motd.d/??-*; do
-                if [ -f "$f" ]; then
-                    case "$(basename "$f")" in
-                        *cortex*) ;;  # Keep our scripts
-                        *) chmod -x "$f" 2>/dev/null || true ;;
-                    esac
-                fi
-            done
+            for f in /etc/update-motd.d/*; do
+                if [ -f "$f" ] && [ -x "$f" ]; then
+                    case "$(basename "$f")" in
+                        *cortex*) ;;  # Keep our scripts
+                        *) chmod -x "$f" 2>/dev/null || true ;;
+                    esac
+                fi
+            done

Comment on lines +57 to +65
@echo "Package Targets:"
@echo " make packages Build all .deb packages"
@echo " make build-package PKG=name Build specific package"
@echo " Available: cortex-branding cortex-core cortex-full cortex-secops"
@echo ""
@echo "Branding Targets:"
@echo " make branding-package Build cortex-branding .deb package"
@echo " (To install: sudo apt install ./output/cortex-branding_*.deb)"
@echo ""
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Help text and branding-package note are inconsistent with actual targets.

make packages ignores PKG=..., and the help list includes packages that may not exist. Consider aligning help/docs with build-package semantics and actual packages.

🔧 Align help text
-    `@echo` "  make packages         Build all .deb packages"
-    `@echo` "  make build-package PKG=name  Build specific package"
-    `@echo` "                        Available: cortex-branding cortex-core cortex-full cortex-secops"
+    `@echo` "  make packages         Build all .deb packages"
+    `@echo` "  make build-package PKG=name  Build specific package"
+    `@echo` "                        Available: cortex-branding"
@@
-# Build cortex-branding package (use 'make packages PKG=cortex-branding' instead)
+# Build cortex-branding package (use 'make build-package PKG=cortex-branding' instead)

Also applies to: 158-160

🤖 Prompt for AI Agents
In `@Makefile` around lines 57 - 65, Update the Makefile help text to accurately
reflect existing targets and semantics: change the "Package Targets" block so it
clarifies that `make packages` builds all packages and does not accept
`PKG=...`, list only actual package names produced by the repo (or remove the
hardcoded list), and replace the misleading line suggesting `make packages`
accepts `PKG=...` with instructions to use `make build-package PKG=<name>` for
single-package builds; also adjust the "Branding Targets" note to match the real
target name `branding-package` and its install path/usage if different, ensuring
consistency with the `build-package` and `branding-package` targets referenced
in the Makefile.

Comment on lines +8 to +52
set -e

case "$1" in
remove|upgrade|deconfigure)
echo "Removing Cortex Linux branding..."

# Restore Debian OS identity files
# On Debian, /etc/os-release is a symlink to /usr/lib/os-release (from base-files)
if [ -f /usr/lib/os-release ]; then
echo " -> Restoring Debian OS identity files..."
ln -sf /usr/lib/os-release /etc/os-release
# Restore generic Debian issue files
echo "Debian GNU/Linux \\n \\l" > /etc/issue
echo "Debian GNU/Linux" > /etc/issue.net
# lsb-release can be regenerated by lsb-release package if installed
if command -v lsb_release &>/dev/null; then
cat > /etc/lsb-release << 'EOLSB'
DISTRIB_ID=Debian
DISTRIB_DESCRIPTION="Debian GNU/Linux"
EOLSB
fi
fi

# Restore default Plymouth theme
if command -v update-alternatives &>/dev/null; then
update-alternatives --remove default.plymouth \
/usr/share/plymouth/themes/cortex/cortex.plymouth 2>/dev/null || true
fi

if command -v plymouth-set-default-theme &>/dev/null; then
plymouth-set-default-theme -R 2>/dev/null || true
fi

# Remove GDM theme alternative
if command -v update-alternatives &>/dev/null; then
update-alternatives --remove gdm3-theme.css \
/usr/share/gnome-shell/theme/Cortex/gnome-shell.css 2>/dev/null || true
fi

# Re-enable default MOTD scripts
if [ -d /etc/update-motd.d ]; then
for f in /etc/update-motd.d/??-*; do
[ -f "$f" ] && chmod +x "$f" 2>/dev/null || true
done
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Avoid failing package removal on branding restore errors.

With set -e, any failed ln/echo/cat write to /etc/* can abort prerm and block package removal. Consider guarding these writes and emitting warnings instead of hard failures.

🔧 Safer restore (non-fatal writes)
-            ln -sf /usr/lib/os-release /etc/os-release
+            ln -sf /usr/lib/os-release /etc/os-release || echo "WARN: failed to restore /etc/os-release" >&2
 ...
-            echo "Debian GNU/Linux \\n \\l" > /etc/issue
-            echo "Debian GNU/Linux" > /etc/issue.net
+            echo "Debian GNU/Linux \\n \\l" > /etc/issue || echo "WARN: failed to restore /etc/issue" >&2
+            echo "Debian GNU/Linux" > /etc/issue.net || echo "WARN: failed to restore /etc/issue.net" >&2
 ...
-                cat > /etc/lsb-release << 'EOLSB'
+                cat > /etc/lsb-release << 'EOLSB' || echo "WARN: failed to restore /etc/lsb-release" >&2
 DISTRIB_ID=Debian
 DISTRIB_DESCRIPTION="Debian GNU/Linux"
 EOLSB
🤖 Prompt for AI Agents
In `@packages/cortex-branding/debian/prerm` around lines 8 - 52, The script
currently uses set -e so any failing write/ln/update-alternatives will abort
removal; change the risky operations (ln -sf /usr/lib/os-release
/etc/os-release, the echo redirections to /etc/issue and /etc/issue.net, the cat
> /etc/lsb-release here-doc, update-alternatives --remove calls,
plymouth-set-default-theme -R, and the chmod loop over /etc/update-motd.d) to be
non-fatal by adding explicit failure handling (e.g., append || { echo "Warning:
failed to restore <resource>" >&2; } to each command or redirect errors and
continue), or check writability first (e.g., [ -w /etc ] || { warn; } ) before
attempting writes so the prerm emits warnings on failure instead of exiting due
to set -e. Ensure each referenced command (ln, echo redirects, cat heredoc to
/etc/lsb-release, update-alternatives, plymouth-set-default-theme, chmod) has
its own guarded fallback so removal never aborts.

Comment on lines +15 to +18
default-size-columns=120
default-size-rows=32
font='JetBrains Mono 11'
foreground-color='#E5E5E5'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# First, let's explore the cortex-branding package structure
git ls-files packages/cortex-branding/debian/ 2>/dev/null | head -20

Repository: cortexlinux/cortex-distro

Length of output: 394


🏁 Script executed:

# Check the debian/control file for dependencies
cat packages/cortex-branding/debian/control 2>/dev/null

Repository: cortexlinux/cortex-distro

Length of output: 1209


🏁 Script executed:

# Search for any JetBrains Mono references in the packaging
rg -r "jetbrains|fonts-jetbrains|Mono" packages/cortex-branding/debian/ --no-heading 2>/dev/null

Repository: cortexlinux/cortex-distro

Length of output: 51


🏁 Script executed:

# Check for any font-related dependencies in debian files
rg "Depends:|font|Font" packages/cortex-branding/debian/ -A 2 -B 1 2>/dev/null

Repository: cortexlinux/cortex-distro

Length of output: 614


Declare JetBrains Mono font as a package dependency.

Line 17 hardcodes font='JetBrains Mono 11', but the debian/control file does not declare fonts-jetbrains-mono as a dependency. If the font package is not installed, GNOME Terminal will silently fall back to its default font, undermining the branding. Add fonts-jetbrains-mono to the Depends: field in debian/control.

🤖 Prompt for AI Agents
In `@packages/cortex-branding/etc/dconf/db/local.d/01-cortex-terminal` around
lines 15 - 18, The GNOME Terminal config hardcodes font='JetBrains Mono 11' but
the package dependency is missing; update debian/control to add
fonts-jetbrains-mono to the Depends: field so the JetBrains Mono font is
installed for the branding. Edit the package metadata (debian/control) and
append fonts-jetbrains-mono to the appropriate package's Depends line, ensuring
the binary package that ships the dconf snippet will pull the font; keep the
existing font string ("font='JetBrains Mono 11'") in the dconf file unchanged.

Comment on lines +56 to +67
# Color based on usage
mem_color() {
if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}

disk_color() {
if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Add defensive numeric validation in color functions.

If the percent values are empty or non-numeric (e.g., due to unexpected command output), the integer comparison -lt will fail with an error message displayed in the MOTD.

🛠️ Proposed defensive fix
 # Color based on usage
 mem_color() {
+    local val="${1:-0}"
+    [[ "$val" =~ ^[0-9]+$ ]] || val=0
-    if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
+    if [ "$val" -lt 50 ]; then echo -e "${GREEN}";
+    elif [ "$val" -lt 80 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }
 
 disk_color() {
+    local val="${1:-0}"
+    [[ "$val" =~ ^[0-9]+$ ]] || val=0
-    if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
-    elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
+    if [ "$val" -lt 70 ]; then echo -e "${GREEN}";
+    elif [ "$val" -lt 90 ]; then echo -e "${YELLOW}";
     else echo -e "${RED}"; fi
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Color based on usage
mem_color() {
if [ "$1" -lt 50 ]; then echo -e "${GREEN}";
elif [ "$1" -lt 80 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}
disk_color() {
if [ "$1" -lt 70 ]; then echo -e "${GREEN}";
elif [ "$1" -lt 90 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}
# Color based on usage
mem_color() {
local val="${1:-0}"
[[ "$val" =~ ^[0-9]+$ ]] || val=0
if [ "$val" -lt 50 ]; then echo -e "${GREEN}";
elif [ "$val" -lt 80 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}
disk_color() {
local val="${1:-0}"
[[ "$val" =~ ^[0-9]+$ ]] || val=0
if [ "$val" -lt 70 ]; then echo -e "${GREEN}";
elif [ "$val" -lt 90 ]; then echo -e "${YELLOW}";
else echo -e "${RED}"; fi
}
🤖 Prompt for AI Agents
In `@packages/cortex-branding/etc/update-motd.d/10-cortex-sysinfo` around lines 56
- 67, The mem_color and disk_color functions can fail if "$1" is empty or
non-numeric; add defensive numeric validation at the start of each function by
assigning a local variable (e.g., val="$1"), checking it with a regex like
^[0-9]+$ (or test -n and digits), and if it fails set a safe default (e.g.,
val=0) before performing the -lt comparisons; update comparisons to use that
validated variable (val) so the integer tests in mem_color and disk_color never
receive non-numeric input.

Comment on lines +28 to +30
# Quick check (may not be accurate without apt update)
UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable || echo "0")
SECURITY="?"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix zero-updates fallback to avoid false update notifications.

At Line 29, grep -c returns exit code 1 when there are no matches and still prints 0, so the || echo "0" appends another 0. This makes UPDATES become 0\n0, which passes the later != "0" check and incorrectly prints update info.

✅ Proposed fix
-        UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable || echo "0")
+        UPDATES=$(apt list --upgradable 2>/dev/null | grep -c upgradable || true)
🤖 Prompt for AI Agents
In `@packages/cortex-branding/etc/update-motd.d/20-cortex-updates` around lines 28
- 30, The UPDATES assignment can produce a duplicated "0" when grep exits
non-zero, causing UPDATES to be "0\n0" and triggering false positives; change
the logic around the UPDATES calculation in the 20-cortex-updates script: let
the pipeline run without forcing an alternate echo (use "|| true" or let the
command fail silently), then normalize the result to a single numeric string
(e.g., treat empty or non-numeric output as "0" via parameter expansion or a
conditional) so UPDATES is always a single "0" or a count; update the code that
sets UPDATES (and any downstream check against "0") to use this normalized
value.

Comment on lines +1 to +13
PRETTY_NAME="Cortex Linux 1.0 (Synapse)"
NAME="Cortex Linux"
VERSION_ID="1.0"
VERSION="1.0 (Synapse)"
VERSION_CODENAME=synapse
ID=cortex
ID_LIKE=debian
HOME_URL="https://cortexlinux.com"
SUPPORT_URL="https://github.com/cortexlinux/cortex-distro/discussions"
BUG_REPORT_URL="https://github.com/cortexlinux/cortex-distro/issues"
PRIVACY_POLICY_URL="https://cortexlinux.com/privacy"
LOGO=cortex-logo
ANSI_COLOR="0;35"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

# Search for cortex-logo asset in the branding package
find packages/cortex-branding/ -type f -name "*cortex-logo*" 2>/dev/null || echo "No exact cortex-logo file found"

# Check for logo references across branding package
rg -n 'cortex-logo' packages/cortex-branding/ 2>/dev/null | head -20

# Check for lsb-release file for consistency comparison
find packages/cortex-branding/ -type f -name "lsb-release*" 2>/dev/null

# List files in the templates directory
ls -la packages/cortex-branding/usr/share/cortex/templates/ 2>/dev/null || echo "Templates directory structure not found"

Repository: cortexlinux/cortex-distro

Length of output: 904


🏁 Script executed:

# Read lsb-release file for consistency comparison
cat -n packages/cortex-branding/usr/share/cortex/templates/lsb-release

# Check all logo-related files in the logos directory
find packages/cortex-branding/usr/share/cortex/logos/ -type f 2>/dev/null

# Check if there's a cortex-logo file (without suffix) or if only light variant exists
ls -la packages/cortex-branding/usr/share/cortex/logos/

Repository: cortexlinux/cortex-distro

Length of output: 730


Fix LOGO field reference — asset name mismatch

The LOGO=cortex-logo references a non-existent file. The available logo asset is cortex-logo-light.svg, so the LOGO field should be updated to LOGO=cortex-logo-light. The lsb-release template is consistent with the os-release values (version 1.0, codename synapse).

🤖 Prompt for AI Agents
In `@packages/cortex-branding/usr/share/cortex/templates/os-release` around lines
1 - 13, Update the LOGO entry in the os-release template: replace the incorrect
LOGO value "cortex-logo" with the actual asset name "cortex-logo-light" so the
LOGO field matches the available logo asset (update the LOGO= line in the
os-release template).

Comment on lines +159 to +167
/* Logo/branding area */
.login-dialog-logo {
background-image: url('resource:///org/gnome/shell/theme/cortex-logo.svg');
background-size: contain;
background-repeat: no-repeat;
background-position: center;
min-height: 80px;
min-width: 200px;
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

# Search for cortex-logo.svg in the branding package
fd "cortex-logo" packages/cortex-branding
# Also check for any GResource XML that might bundle assets
fd -e gresource.xml packages/cortex-branding
fd -e gresource packages/cortex-branding
# Check for .xml files that might be GResource manifests
fd -e xml packages/cortex-branding

Repository: cortexlinux/cortex-distro

Length of output: 155


🏁 Script executed:

# List files in the branding package using git
git ls-files packages/cortex-branding | head -50

# Search for cortex-logo references with rg
rg "cortex-logo" packages/cortex-branding --type-list

# Look for the SVG file directly
git ls-files packages/cortex-branding | grep -i "logo\|svg"

Repository: cortexlinux/cortex-distro

Length of output: 3898


🏁 Script executed:

# Read the Makefile to see build instructions
cat packages/cortex-branding/Makefile

# Search for cortex-logo references in the entire package
rg "cortex-logo" packages/cortex-branding

# Check if there's a gresource definition or build script
rg "gresource\|resource:::" packages/cortex-branding

Repository: cortexlinux/cortex-distro

Length of output: 8201


Add the missing cortex-logo.svg to the GResource bundle or update the CSS to reference the correct existing file.

The .login-dialog-logo CSS references resource:///org/gnome/shell/theme/cortex-logo.svg, which does not exist in the package. Only cortex-logo-light.svg is present in usr/share/cortex/logos/. Additionally, there is no GResource XML configuration to bundle these assets into the resource system. Either:

  1. Create and add cortex-logo.svg and define a GResource manifest (.gresource.xml) in the GNOME Shell theme directory, or
  2. Change the CSS to reference the file directly: url('file:///usr/share/cortex/logos/cortex-logo-light.svg') or use the path that dconf already references

Without this fix, the logo will not display on the login screen.

🤖 Prompt for AI Agents
In `@packages/cortex-branding/usr/share/gnome-shell/theme/Cortex/gnome-shell.css`
around lines 159 - 167, The CSS rule .login-dialog-logo references a missing
resource cortex-logo.svg and no GResource is defined; either add cortex-logo.svg
to the theme resources and register it in a GResource manifest (.gresource.xml)
under the org/gnome/shell/theme path so
resource:///org/gnome/shell/theme/cortex-logo.svg resolves, or update the
.login-dialog-logo background-image to point to the existing file (for example
use file:///usr/share/cortex/logos/cortex-logo-light.svg or the exact path dconf
uses) and ensure the referenced filename matches cortex-logo-light.svg; update
the package manifest to include the chosen asset so the login screen can load
it.

Comment on lines +549 to +553
# Copy provisioning files (use -r for directories)
if [ -d "$PROVISION_DIR" ]; then
cp -r "${PROVISION_DIR}"/* "${BUILD_DIR}/config/includes.binary/provisioning/" 2>/dev/null || true
log "Copied provisioning files"
fi
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Provisioning copy failures are silently ignored.

Provisioning scripts are critical for first-boot; suppressing copy errors risks producing an ISO without required provisioning.

🔧 Fail fast (or warn explicitly) on provisioning copy errors
-    if [ -d "$PROVISION_DIR" ]; then
-        cp -r "${PROVISION_DIR}"/* "${BUILD_DIR}/config/includes.binary/provisioning/" 2>/dev/null || true
-        log "Copied provisioning files"
-    fi
+    if [ -d "$PROVISION_DIR" ]; then
+        if ls "${PROVISION_DIR}"/* 1>/dev/null 2>&1; then
+            cp -r "${PROVISION_DIR}"/* "${BUILD_DIR}/config/includes.binary/provisioning/" || {
+                error "Failed to copy provisioning files"
+                exit 1
+            }
+            log "Copied provisioning files"
+        else
+            warn "No provisioning files found in ${PROVISION_DIR}"
+        fi
+    fi
🤖 Prompt for AI Agents
In `@scripts/build.sh` around lines 549 - 553, The provisioning copy currently
swallows errors (cp uses 2>/dev/null and || true), risking an ISO without
provisioning; update the block that references PROVISION_DIR and BUILD_DIR to
remove stderr redirection and the "|| true", run cp -r "${PROVISION_DIR}"/*
"${BUILD_DIR}/config/includes.binary/provisioning/" and check its exit status,
and if cp fails call the existing log function with a clear error message
including $PROVISION_DIR and $BUILD_DIR and then exit 1 (fail fast) so build
stops when provisioning copy fails.

Comment on lines +607 to 614
# Build packages needed for ISO (cortex-branding is required)
# Add more packages here as needed
local iso_packages="cortex-branding"

for pkg in $iso_packages; do
log "Building ${pkg}..."
cd "${PROJECT_ROOT}/packages/${pkg}"

# Clean previous builds
rm -f ../cortex-*.deb ../cortex-*.buildinfo ../cortex-*.changes 2>/dev/null || true

# Build
dpkg-buildpackage -us -uc -b

log "${pkg} built successfully"
build_single_package "$pkg" || warn "Failed to build ${pkg}"
done
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

build_local_packages should fail if required packages don’t build.

The comment says cortex-branding is required, but failures only emit a warning and the build continues. This can produce an ISO missing required packages.

🔧 Fail on required package build failure
-    for pkg in $iso_packages; do
+    for pkg in $iso_packages; do
         log "Building ${pkg}..."
-        build_single_package "$pkg" || warn "Failed to build ${pkg}"
+        build_single_package "$pkg" || {
+            error "Failed to build required package: ${pkg}"
+            exit 1
+        }
     done
🤖 Prompt for AI Agents
In `@scripts/build.sh` around lines 607 - 614, The loop that builds iso_packages
(local iso_packages="cortex-branding") currently ignores failures by calling
warn; change it so required package build failures stop the script: when
build_single_package "$pkg" fails, call an error/fatal handler or echo an error
and exit 1 instead of warn. Update the for-loop in scripts/build.sh (referencing
iso_packages and build_single_package) to treat failures as fatal (e.g., replace
"|| warn 'Failed to build ${pkg}'" with a block that logs the error via log or a
fatal function and exits with non-zero status).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants