Skip to content

Conversation

@Anshgrover23
Copy link
Contributor

@Anshgrover23 Anshgrover23 commented Jan 10, 2026

Untitled.mov

Summary by CodeRabbit

  • New Features

    • Added full Cortex Linux visual branding (wallpapers, boot and login themes, MOTD, icons, OS identity).
  • Build Process

    • Simplified build to a single make-driven flow with bootstrap/build/help targets; CI updated to new build and artifact paths.
  • Documentation

    • README streamlined to a concise build-focused quick start; several legacy runbooks and compatibility docs removed.
  • Chores

    • Added Business Source License and expanded ignore rules; removed legacy ISO/live-build tooling and reproducible-builds workflow.

✏️ 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

Replaces the legacy ISO/live-build workflow with a script-driven Makefile and CI flow, removes live-build/preseed/firstboot assets, and adds a new Debian cortex-branding package with themes, wallpapers, MOTD scripts, and packaging metadata.

Changes

Cohort / File(s) Summary
Build system & repo housekeeping
\.gitignore, Makefile, clean_all.sh
Adds comprehensive ignore rules; replaces monolithic ISO Makefile with minimalist script-driven targets (build, bootstrap, help) that delegate to external scripts; adds cleanup script.
Removed ISO/live-build artifacts
iso/live-build/auto/*, iso/live-build/config/*, iso/live-build/config/hooks/*, iso/live-build/config/includes.chroot/*, iso/live-build/config/package-lists/*, iso/preseed/cortex.preseed
Deletes live-build config, auto scripts, hooks, package lists, includes (firstboot), and preseed—removes legacy ISO-centric build and first-boot provisioning logic.
CI/CD workflows
.github/workflows/build-iso.yml, .github/workflows/reproducible-builds.yml
Reworks build-iso into a matrix-driven, script-based CI flow with debootstrap cache and artifact path changes; removes reproducible-builds workflow.
Documentation
README.md, docs/HARDWARE-COMPATIBILITY.md, docs/KEY-MANAGEMENT-RUNBOOK.md, docs/KEY-ROTATION-RUNBOOK.md
Simplifies README and removes hardware compatibility and key-management runbooks.
Branding package & packaging metadata
packages/cortex-branding/*, packages/cortex-branding/debian/*, packages/cortex-branding/.gitignore
Adds new cortex-branding Debian package: control, changelog, rules, maintainer scripts (postinst/prerm/postrm), copyright, source format, and package-level .gitignore.
Branding asset generation
packages/cortex-branding/Makefile, packages/cortex-branding/boot/grub/themes/*, packages/cortex-branding/usr/share/.../theme/*
New Makefile to generate logos/wallpapers/icons via ImageMagick; adds GRUB theme and GNOME Shell theme CSS.
Desktop/GDM/terminal defaults
packages/cortex-branding/etc/dconf/*, packages/cortex-branding/usr/share/glib-2.0/schemas/*, packages/cortex-branding/etc/skel/*
Adds dconf profiles and GSettings overrides to set GDM, GNOME desktop, and terminal defaults; disables GNOME initial-setup.
MOTD, neofetch & templates
packages/cortex-branding/etc/update-motd.d/*, packages/cortex-branding/etc/neofetch/*, packages/cortex-branding/usr/share/cortex/templates/*, packages/cortex-branding/usr/share/neofetch/ascii/*
Adds MOTD banner, system-info and update notification scripts, Neofetch config and ASCII art, and os-release/issue/lsb templates.
License
LICENSE
Adds Business Source License 1.1 file describing change date and commercial-use terms.

Sequence Diagram(s)

sequenceDiagram
    participant GH as GitHub Actions
    participant Runner as Runner
    participant Cache as Debootstrap Cache
    participant Scripts as Repo Scripts (install-deps.sh / bootstrap / build.sh)
    participant Artifacts as Artifact Storage (src/dist)

    GH->>Runner: Start matrix job
    Runner->>Cache: Ensure debootstrap cache (setup / verify)
    Runner->>Scripts: run install-deps.sh
    Scripts->>Runner: install deps complete
    Runner->>Scripts: run bootstrap (uses Cache)
    Scripts->>Cache: read/write cache
    Runner->>Scripts: run build.sh (ARCH-aware)
    Scripts->>Artifacts: write ISO/artifacts to src/dist
    Runner->>GH: upload artifacts (src/dist/*)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Poem

A rabbit hops through changes wide,
Old builds dissolve, new themes abide,
Tiny scripts hum, bright wallpapers spin,
MOTD candles glow — the new package grins. 🐇✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1
❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 58.75% 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 PR title clearly and specifically summarizes the main change: bootstrapping a Cortex Linux distro with hybrid ISO capability supporting both live boot and full installer modes.

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


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 <[email protected]>
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 [email protected] 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 [email protected] 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 [email protected] 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.

scripts/build.sh Outdated
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.

scripts/build.sh Outdated
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.

- 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/[email protected])
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/[email protected]
📝 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/[email protected]) 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., [email protected],[email protected]) or remove
[email protected] 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 [email protected],[email protected],[email protected]

# Use strong MACs
MACs [email protected],[email protected]

# Use strong key exchange
KexAlgorithms curve25519-sha256,[email protected]
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 [email protected] and the AES‑GCM variants ([email protected], [email protected]). (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 must be FIPS compliant: remove/disable [email protected] and prefer [email protected] or [email protected] (and ensure the underlying crypto library is FIPS‑validated and the host is in FIPS mode). (docs.redhat.com)
  • If interoperating with non‑FIPS clients/servers and you want the best performance on low‑CPU devices, chacha20-poly1305 offers good performance but will break FIPS requirements — test and document exceptions if you decide to permit it. (docs.gigamon.com)

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 [email protected] 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:

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., [email protected],[email protected])
or remove [email protected] 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 [email protected] for socket-activated or traditional modes. Some recent/unreleased changes add an [email protected] template in experimental/sid. [1][2][4]

What that means for you

  • Use systemctl start|stop|restart ssh (or manage ssh.socket / [email protected] 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, [email protected]).
[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 [email protected] 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.

README.md Outdated
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.
Your Name added 4 commits January 18, 2026 02:23
… 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/[email protected]
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.

scripts/build.sh Outdated
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/[email protected]

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 +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.

scripts/build.sh Outdated
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.

Your Name added 4 commits January 21, 2026 01:11
- Added new background and scrollbar images for GRUB themes to improve visual consistency.
- Updated various icons and logos to align with the latest branding design.
- Enhanced Plymouth theme with additional animated progress assets for a more dynamic user experience.
- Streamlined asset management in the build process to ensure all new images are included correctly.
- Added a new step in the GitHub Actions workflow to trigger an APT repository update with package information after ISO builds.
- Updated the branding package's post-install script to configure Plymouth and GDM settings for improved user experience.
- Introduced new Plymouth theme assets, including an animated boot video and additional images for a cohesive branding experience.
- Cleaned up the build script to ensure fresh package indices and prevent stale markers during ISO creation.
- Adjusted the speed divisor in the Plymouth theme script from 2 to 1.5 to enhance animation playback, achieving approximately 40fps at 60fps refresh rate.
- This change aims to provide a smoother visual experience during the boot process.
… live session

- Updated the Cortex Linux live session configuration to generate a hashed password for the default user instead of using plaintext.
- Added a fallback mechanism to create the Cortex user if it does not exist, ensuring proper user setup during the live session.
- Configured necessary group memberships for the Cortex user to enhance functionality and access rights.
Your Name added 6 commits January 24, 2026 03:55
…tex Linux

- Deleted the OSS.md file as it was no longer relevant.
- Updated installation scripts for various themes and extensions to reflect the new naming convention for Cortex Linux.
- Added new Gnome extensions for location switching and notification management, enhancing user experience.
- Introduced a new auto-repair script to streamline system recovery processes.
- Adjusted dconf settings to improve the default user interface and experience.
…or Cortex Linux

- Deleted several outdated documentation files including branding guidelines, hardware compatibility matrix, and key management runbooks to reduce clutter.
- Removed the SBOM generation script and ISO verification tests as they are no longer needed.
- Cleaned up the branding assets directory by eliminating unnecessary files, ensuring a more organized structure.
- This update aims to enhance maintainability and focus on relevant documentation and assets for Cortex Linux.
- Changed the default Ubuntu version from "noble" to "plucky" in args.sh and upgrade.sh to align with the latest release.
- Enhanced the build script to set architecture-specific mirrors for apt sources based on TARGET_ARCH, improving flexibility for different architectures.
- Added support for APT Cacher NG in both the build and chroot environments to optimize package downloads.
- Updated kernel installation logic to differentiate between amd64 and arm64 architectures, ensuring appropriate kernel packages are installed.
- Improved DNS configuration handling in the chroot environment to ensure network connectivity during the build process.
- Removed validation and testing jobs to simplify the workflow.
- Eliminated references to outdated documentation branding assets.
- Streamlined artifact handling by focusing on ISO files and checksum generation.
- Adjusted release job dependencies to reflect the updated workflow structure.
- Removed the build_all.sh script to streamline the build process.
- Updated Makefile to change the default goal to 'build' and added architecture-specific configurations for release builds.
- Introduced new configuration files for release builds targeting amd64 and arm64 architectures.
- Enhanced build.sh to support building from a JSON configuration file, improving flexibility for single language builds.
- Cleaned up args.sh to set default mirrors based on architecture and removed obsolete comments.
- Adjusted GitHub Actions workflow to reflect changes in the build command.
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 `@clean_all.sh`:
- Line 24: The cd invocation uses an unquoted variable (cd $SCRIPT_DIR) which
can break on paths with spaces or special chars; update the command to safely
handle such paths by quoting the variable and guarding against directory names
starting with a dash, e.g. replace the cd $SCRIPT_DIR use with cd --
"$SCRIPT_DIR" where SCRIPT_DIR is defined.

In `@LICENSE`:
- Around line 3-56: Request formal legal/compliance review and sign-off for the
custom license text in LICENSE, specifically the "Additional Use Grant", "Change
Date"/"Change License" transition, and the "Pricing" and "Commercial Use"
clauses; have counsel confirm that this BSL-like variant is enforceable and
compatible with OSS/packaging/distribution requirements, verify required
notice/header wording for downstream distributions (the required inclusion of
"This License", copyright notice, Change Date/Change License), confirm the
contact email and pricing language are appropriate, and attach the written legal
approval to the PR before merging.

In `@Makefile`:
- Around line 16-33: The DEPS variable (and its ARCH-specific branches) is
defined but never consumed; either remove the DEPS/C OMMON_DEPS block entirely
or wire it into the bootstrap flow: export DEPS from the Makefile (or pass it as
an argument from the bootstrap target) and refactor scripts/install-deps.sh to
accept/consume DEPS (e.g., read an environment variable or CLI arg) instead of
using its own internal package lists; update the bootstrap target invocation to
pass ARCH and DEPS so scripts/install-deps.sh uses the Makefile-provided package
set.
- Around line 63-70: The Makefile's unsupported-architecture branch currently
prints an error with echo and calls shell exit, which runs at recipe time;
replace that with a Makefile-level error by removing the shell echo/@exit lines
and invoking Make's error function so the failure happens during parse; use
$(error Unsupported architecture: $(ARCH). Only amd64 and arm64 are supported.)
(referencing ARCH and the surrounding ifeq/else ifeq/endif block) to ensure the
message is emitted correctly.
- Around line 43-54: The bootstrap target currently uses lsb_release -i which
can be missing on minimal systems; update the bootstrap recipe to fallback to
parsing /etc/os-release (e.g., look for ID or PRETTY_NAME) when lsb_release is
unavailable, or ensure lsb_release is installed before the check (install
package lsb-release) and then perform the same grep against
"(Ubuntu|Debian|Tuxedo|Cortex)"; modify the bootstrap block that calls
lsb_release -i and the subsequent ARCH=$(ARCH) sudo bash scripts/install-deps.sh
invocation to use the new robust OS detection or preinstall step so the check
does not fail on systems without lsb_release.

In `@README.md`:
- Line 7: The README's HTML image tag is missing alt text which fails
accessibility rule MD045; update the <img> tag (the one with
src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg" and attributes
align/width/height) to include a meaningful alt attribute (e.g., alt="Arcmenu
patch logo" or another concise descriptive string) so screen readers and
accessibility checks can identify the image.
♻️ Duplicate comments (4)
.github/workflows/build-iso.yml (4)

8-27: Path filters now include the workflow file on push but still missing on pull_request.

The push trigger includes .github/workflows/build-iso.yml (line 18), but the pull_request trigger (lines 19-26) does not include this path. PRs that only modify the workflow file won't trigger CI validation.

Proposed fix
   pull_request:
     branches: [main]
     paths:
       - 'src/**'
       - 'config/**'
       - 'packages/**'
       - 'scripts/**'
       - 'Makefile'
+      - '.github/workflows/build-iso.yml'

46-47: Pin jlumbroso/free-disk-space to a stable version.

Using @main exposes builds to supply chain risks. Pin to a stable release.

Recommended change
       - name: Free disk space
-        uses: jlumbroso/free-disk-space@main
+        uses: jlumbroso/[email protected]

141-142: Update softprops/action-gh-release to v2.

Static analysis indicates @v1 uses an outdated runner that may cause failures on current GitHub Actions runners.

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

135-139: Checksum generation may fail if no ISO files exist.

If the build produces no .iso files, sha256sum *.iso will fail. Consider adding a guard or using shopt -s nullglob.

Proposed fix
       - name: Generate combined checksums
         run: |
           cd release
+          shopt -s nullglob
+          isos=(*.iso)
+          if [ ${`#isos`[@]} -eq 0 ]; then
+            echo "ERROR: No ISO files found"
+            exit 1
+          fi
           sha256sum *.iso > SHA256SUMS
           sha512sum *.iso > SHA512SUMS
🧹 Nitpick comments (3)
packages/cortex-branding/etc/dconf/db/local.d/00-cortex-desktop (1)

22-24: Add trailing newline to EOF.

The dconf file is missing a trailing newline for POSIX compliance. The calamares-install-cortex.desktop entry is correct—the .desktop file is provided by the calamares package when installed, not by cortex-branding.

Add trailing newline
 [org/gnome/shell]
 welcome-dialog-last-shown-version='9999999999'
 favorite-apps=['firefox-esr.desktop', 'org.gnome.Nautilus.desktop', 'org.gnome.Terminal.desktop', 'org.gnome.Settings.desktop', 'calamares-install-cortex.desktop']
+
packages/cortex-branding/Makefile (1)

42-52: Add a preflight check for ImageMagick (magick).
Fail fast with a clear message if the dependency isn’t installed.

🔧 Suggested fix
+.PHONY: check-magick
+check-magick:
+	`@command` -v magick >/dev/null 2>&1 || { \
+		echo "ImageMagick (magick) not found in PATH"; \
+		exit 1; \
+	}
+
 # Default target
 .PHONY: default
-default: $(ALL_ASSETS)
+default: check-magick $(ALL_ASSETS)
 	`@echo` ""
 	`@echo` "✓ Branding assets generated"
 	`@echo` ""
packages/cortex-branding/debian/rules (1)

26-46: Use cp -a (and /.) to preserve attributes and include dotfiles.
cp -r dir/* skips dotfiles and may alter symlinks; packaging assets are safer with cp -a.

🔧 Suggested fix
-	cp -r usr/share/plymouth/themes/cortex/* $(CURDIR)/debian/cortex-branding/usr/share/plymouth/themes/cortex/
+	cp -a usr/share/plymouth/themes/cortex/. $(CURDIR)/debian/cortex-branding/usr/share/plymouth/themes/cortex/
...
-	cp -r boot/grub/themes/cortex/* $(CURDIR)/debian/cortex-branding/boot/grub/themes/cortex/
+	cp -a boot/grub/themes/cortex/. $(CURDIR)/debian/cortex-branding/boot/grub/themes/cortex/
...
-	cp -r usr/share/backgrounds/cortex/* $(CURDIR)/debian/cortex-branding/usr/share/backgrounds/cortex/
+	cp -a usr/share/backgrounds/cortex/. $(CURDIR)/debian/cortex-branding/usr/share/backgrounds/cortex/
...
-	cp -r usr/share/cortex/logos/* $(CURDIR)/debian/cortex-branding/usr/share/cortex/logos/
+	cp -a usr/share/cortex/logos/. $(CURDIR)/debian/cortex-branding/usr/share/cortex/logos/

}

# ============= main ================
cd $SCRIPT_DIR
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

Quote SCRIPT_DIR in cd to avoid word-splitting.
Unquoted paths can fail under strict mode if the repo path contains spaces.

🔧 Suggested fix
-cd $SCRIPT_DIR
+cd "$SCRIPT_DIR"
📝 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
cd $SCRIPT_DIR
cd "$SCRIPT_DIR"
🤖 Prompt for AI Agents
In `@clean_all.sh` at line 24, The cd invocation uses an unquoted variable (cd
$SCRIPT_DIR) which can break on paths with spaces or special chars; update the
command to safely handle such paths by quoting the variable and guarding against
directory names starting with a dash, e.g. replace the cd $SCRIPT_DIR use with
cd -- "$SCRIPT_DIR" where SCRIPT_DIR is defined.

Comment on lines 3 to 56
## Parameters

**Licensor:** AI Venture Holdings LLC

**Licensed Work:** Cortex Linux v0.1.0 and later versions
The Licensed Work is (c) 2025-2026 AI Venture Holdings LLC

**Additional Use Grant:** You may use the Licensed Work for:
- Personal, non-commercial use (1 system)
- Internal business operations (not offering as a service)
- Educational and research purposes
- Contributing to the Licensed Work

**Change Date:** January 15, 2032 (6 years from release)

**Change License:** Apache License, Version 2.0

---

## Terms

The Licensor hereby grants you the right to copy, modify, create derivative works, redistribute, and make non-production use of the Licensed Work.

**Effective on the Change Date**, the Licensor grants you rights under the terms of the Change License, and the rights granted above terminate.

If your use of the Licensed Work does not comply with the requirements currently in effect as described in this License, you must purchase a commercial license from the Licensor, its affiliated entities, or authorized resellers.

**All copies** of the original and modified Licensed Work must include:
- This License
- The copyright notice
- The Change Date and Change License

---

## Commercial Use

**"Commercial Use"** means using the Licensed Work to:
1. Run on more than one (1) system
2. Offer a competing product or service
3. Provide managed services based on the Licensed Work
4. Sell, resell, or sublicense the Licensed Work

For Commercial Use licensing, contact: [email protected]

---

## Pricing

- **Personal (1 system):** Free
- **Additional systems:** $20/system/month
- **Pro (up to 25 systems):** $99/month
- **Enterprise (up to 100 systems):** $299/month

See https://cortexlinux.com/pricing for current rates.
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

Confirm legal review for the custom BSL terms and pricing.
This introduces a non-standard BSL variant with an additional use grant, pricing, and a fixed change date. Please ensure legal/compliance sign‑off and that distribution/OSS notices align with these terms.

🤖 Prompt for AI Agents
In `@LICENSE` around lines 3 - 56, Request formal legal/compliance review and
sign-off for the custom license text in LICENSE, specifically the "Additional
Use Grant", "Change Date"/"Change License" transition, and the "Pricing" and
"Commercial Use" clauses; have counsel confirm that this BSL-like variant is
enforceable and compatible with OSS/packaging/distribution requirements, verify
required notice/header wording for downstream distributions (the required
inclusion of "This License", copyright notice, Change Date/Change License),
confirm the contact email and pricing language are appropriate, and attach the
written legal approval to the PR before merging.

Makefile Outdated
Comment on lines 63 to 70
ifeq ($(ARCH),amd64)
@cd $(SRC_DIR) && ARCH=$(ARCH) APT_CACHER_NG_URL="$(APT_CACHER_NG_URL)" ./build.sh -c ../$(CONFIG_DIR)/release-amd64.json
else ifeq ($(ARCH),arm64)
@cd $(SRC_DIR) && ARCH=$(ARCH) APT_CACHER_NG_URL="$(APT_CACHER_NG_URL)" ./build.sh -c ../$(CONFIG_DIR)/release-arm64.json
else
@echo "[ERROR] Unsupported architecture: $(ARCH). Only amd64 and arm64 are supported."
@exit 1
endif
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 $(error ...) for Make-level errors instead of shell exit.

The @exit 1 at line 69 is inside an ifeq block which is evaluated at Makefile parse time, not recipe execution time. This means for unsupported architectures, the error message on line 68 won't print before exit. Use Make's $(error ...) instead.

Proposed fix
 ifeq ($(ARCH),amd64)
 	`@cd` $(SRC_DIR) && ARCH=$(ARCH) APT_CACHER_NG_URL="$(APT_CACHER_NG_URL)" ./build.sh -c ../$(CONFIG_DIR)/release-amd64.json
 else ifeq ($(ARCH),arm64)
 	`@cd` $(SRC_DIR) && ARCH=$(ARCH) APT_CACHER_NG_URL="$(APT_CACHER_NG_URL)" ./build.sh -c ../$(CONFIG_DIR)/release-arm64.json
 else
-	`@echo` "[ERROR] Unsupported architecture: $(ARCH). Only amd64 and arm64 are supported."
-	`@exit` 1
+	$(error Unsupported architecture: $(ARCH). Only amd64 and arm64 are supported.)
 endif
🤖 Prompt for AI Agents
In `@Makefile` around lines 63 - 70, The Makefile's unsupported-architecture
branch currently prints an error with echo and calls shell exit, which runs at
recipe time; replace that with a Makefile-level error by removing the shell
echo/@exit lines and invoking Make's error function so the failure happens
during parse; use $(error Unsupported architecture: $(ARCH). Only amd64 and
arm64 are supported.) (referencing ARCH and the surrounding ifeq/else ifeq/endif
block) to ensure the message is emitted correctly.

README.md Outdated
[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](LICENSE)
[![Debian](https://img.shields.io/badge/base-Debian%2013%20trixie-A81D33.svg)](https://debian.org)
[![Build](https://img.shields.io/github/actions/workflow/status/cortexlinux/cortex-distro/build-iso.yml?branch=main)](https://github.com/cortexlinux/cortex-distro/actions)
<img align="right" width="100" height="100" src="./src/mods/30-gnome-extension-arcmenu-patch/logo.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 | 🟡 Minor

Add alt text to the HTML logo image.
Improves accessibility and resolves MD045.

🔧 Suggested fix
-<img align="right" width="100" height="100" src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg">
+<img align="right" width="100" height="100" alt="Cortex Linux logo" src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg">
📝 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
<img align="right" width="100" height="100" src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg">
<img align="right" width="100" height="100" alt="Cortex Linux logo" src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg">
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

7-7: Images should have alternate text (alt text)

(MD045, no-alt-text)

🤖 Prompt for AI Agents
In `@README.md` at line 7, The README's HTML image tag is missing alt text which
fails accessibility rule MD045; update the <img> tag (the one with
src="./src/mods/30-gnome-extension-arcmenu-patch/logo.svg" and attributes
align/width/height) to include a meaningful alt attribute (e.g., alt="Arcmenu
patch logo" or another concise descriptive string) so screen readers and
accessibility checks can identify the image.

@mikejmorgan-ai
Copy link
Member

Branch Created: ubuntu-variant

To preserve both Debian and Ubuntu approaches, this PR's work has been copied to a new branch:

ubuntu-variant - https://github.com/cortexlinux/cortex-distro/tree/ubuntu-variant

Why?

  • main stays Debian-based (Debian 12/13) - needed for an influencer request
  • ubuntu-variant contains your Ubuntu debootstrap work for testing and development

Next Steps

  1. This PR can be closed (work preserved in ubuntu-variant)
  2. Or we can retarget this PR to merge into ubuntu-variant for continued iteration
  3. Future: potentially offer both Debian and Ubuntu ISOs

@Anshgrover23 - Great work on the modular build system and ARM64 support! We want to keep both options available.

Your Name added 4 commits January 25, 2026 13:38
- Cleared the "live_firefox_mirror" field in both amd64 and arm64 release configuration files to prevent potential misconfigurations.
- Enhanced the build script to copy DNS configuration from the host to the chroot environment, ensuring proper hostname resolution during builds.
- Added logic to configure an APT Cacher NG proxy in the chroot environment if specified, improving package download efficiency.
- Removed the obsolete repair.sh script and associated auto-repair functionality to streamline the codebase.
- Renamed the build step from "Build in Debian container" to "Build ISO" for clarity.
- Simplified the build command by exporting environment variables and removing the Docker run command, enhancing readability and maintainability.
- Ensured that the build process remains efficient by retaining the use of xz and lz4 compression based on the build context.
- Improved DNS configuration handling in the build script to ensure hostname resolution in the chroot environment.
- Added logic to configure an APT Cacher NG proxy for optimized package downloads during the build process.
- Enhanced kernel installation logic to verify the presence of kernel and initrd files, providing better error handling and feedback.
- Updated gnome extensions installation scripts to ensure proper PATH configuration and verify the installation of required tools.
- Streamlined unmounting processes in the build script to handle busy mounts more gracefully.
- Added steps to retrieve the Ubuntu version and set up a debootstrap cache directory in the GitHub Actions workflow, improving build efficiency.
- Updated the build script to copy DNS configuration from the host to the chroot environment, ensuring hostname resolution.
- Configured an APT Cacher NG proxy in the chroot environment if specified, optimizing package downloads.
- Improved gnome extensions installation scripts to ensure proper PATH configuration for pipx-installed binaries.
Your Name and others added 3 commits January 26, 2026 03:33
- Changed the debootstrap cache directory to a user-writable location at ~/.cache/debootstrap, improving accessibility.
- Removed the existing /var/cache/debootstrap and created a symlink to the new cache location, ensuring debootstrap can write to it.
- Added verification steps to check the cache population after the build process, enhancing feedback on cache usage.
- Updated the build script to change the EFI boot image directory structure from isolinux to boot-prep, improving organization.
- Implemented a two-step approach for creating EFI boot images, enhancing compatibility and support for secure boot.
- Added installation of GRUB EFI packages for the Ubiquity installer, ensuring proper installation of GRUB in target systems.
- Improved timestamp handling for generated files, ensuring consistency in build outputs.
- Enhanced error handling and feedback during the ISO creation process, providing clearer messages for users.
Merged BSL 1.1 license changes and new CI workflow from main with
the complete ISO builder rewrite from ini-2. Removed legacy live-build
tooling in favor of new streamlined make-driven architecture.

Co-Authored-By: Claude Opus 4.5 <[email protected]>
@mikejmorgan-ai mikejmorgan-ai merged commit d1b50a3 into main Jan 27, 2026
0 of 4 checks passed
@mikejmorgan-ai mikejmorgan-ai deleted the ini-2 branch January 27, 2026 04:25
@vikramships vikramships self-assigned this Jan 31, 2026
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.

5 participants