Repository navigation
Conversation
The design (docs/superpowers/specs) and the plan for the first stage are included. The core parses configuration without sourcing it, writes managed files with backup and restore, keeps secrets in 0600 files and masks them in logs, and runs every module step in its own subshell so a failing command always stops the step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…ewall, keys and downloads A rule that could not be removed now stays in the registry, and firewalld rules are changed with firewall-offline-cmd while the service is stopped, so a port can no longer reopen unnoticed when firewalld starts again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
bash ignores set -e inside functions called from a condition, and subshells, also asynchronous ones, inherit that. A module step now runs in its own process (lib/step.sh) with the settings serialised into a private context file, so a failing command always stops the step. Also: secret names are validated before any command substitution, and the package index refresh is remembered per run across those processes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…s formatting Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Cover the remaining branches of log, os, config, files, template, secrets, state, pkg, service, firewall, fetch and module, and add tests for repo.sh (gpg stub, file_write recorded instead of writing below /etc) and ui.sh (whiptail stub; the menu itself runs under script for a terminal). New stubs: gpg, journalctl, whiptail. The systemctl stub now exits with $STUB_EXIT_systemctl for commands other than is-active/is-enabled. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Modules system, time, swap, admin-user, tools and logging, plus ssh-hardening (keys only, algorithms filtered to what the installed OpenSSH knows, lockout check) and firewall (ufw/firewalld, SSH first, rollback timer over SSH). Library helpers opt/opt_bool/opt_int, file_ensure_lines, svc_unit and os_in_container. tests/integration/run.sh installs, verifies, reinstalls (must be unchanged) and removes each module in a systemd container per distribution or on the runner VM for kernel modules. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…-2-core Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
docker build needs -f for Containerfile. fw_ssh_port and the fail2ban jail no longer fail under pipefail when sshd is missing or awk stops reading early. Unit tests for opt/opt_bool/opt_int, file_ensure_lines, os_in_container, svc_unit and the fw_ssh_port fallback. Adds the fail2ban module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…unit test Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…et-up Modules fail2ban, crowdsec (packagecloud repository with pinned key), kernel-hardening, mac, auditd (rules filtered per architecture), auto-updates (reboot window), aide, rkhunter, clamav (EICAR check), lynis (lss audit, index history), usbguard, password-policy (pwquality, faillock, login.defs), ssh-2fa (TOTP with nullok transition) and guard (daily verify and repair, alerts by webhook or mail). repo.sh: per-release suite override and RPM_GPGCHECK; a repository must check at least one signature. Tests: docker exec -i so settings reach the container, Debian/Ubuntu images without policy-rc.d, getent lookups no longer fail under pipefail, matrix covers every module. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Security: ssh-2fa creates and reads the TOTP secret as the user and refuses symlinks; file_ensure_lines and admin-user refuse symlinked targets, chown no longer follows links (a user could otherwise make root chown /etc/shadow). Integration fixes: unattended-upgrades Origins-Pattern uses key=value entries; time sets only the time zone inside containers (the host owns the clock) and is tested with chrony on the VM; ssh-hardening installs the ssh client, creates /run/sshd before sshd -t and computes algorithm lists outside the process substitution; admin-user checks the sudoers group rule instead of sudo -l (PAM in containers); auditd matches auditctl -l output; rkhunter without unhide on the RHEL family. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
fail2ban on Rocky and AlmaLinux logs to the journal, so the recidive jail found no log file and the configuration test failed. lss now pins fail2ban's own log to /var/log/fail2ban.log and creates it before the test. freshclam failed silently on AlmaLinux 10 and the module only noticed after seven minutes. The first download now runs in the foreground with up to three tries, so its reason shows in the log; the daemon is stopped meanwhile so it cannot hold the database lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Workflows for Scorecard, secret scanning and ShellCheck code scanning, sign-off checks, actionlint, zizmor, REUSE and Dependabot auto-merge, all with pinned actions, harden-runner and concurrency groups. Dependabot keeps the actions and the digest-pinned test images current. Security policy, contributing guide, governance, support, code of conduct, issue and pull request templates, and a changelog with the 1.x history. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
|
You are seeing this message because GitHub Code Scanning has recently been set up for this repository, or this pull request contains the workflow file for the Code Scanning tool. What Enabling Code Scanning Means:
For more information about GitHub Code Scanning, check out the documentation. |
freshclam runs as clamupdate on RHEL and could not open /var/log/freshclam.log, so the daemon exited at once. It now logs to the journal only. The foreground download from the last commit is reverted: it broke Debian and Ubuntu, where the daemon already worked. CrowdSec has no packages for EL10 yet; RPM_BASEURL_<major> lets a repository use the EL9 packages there, which are static binaries. The firewall bouncer could start before the local API listened, and dnf may install it before cscli exists, leaving it without a key. lss now waits for the API and registers the bouncer itself when the key is missing, passing the key through the environment so it never appears in the process list. svc_enable shows the unit's journal when a start fails, so CI logs name the cause. The integration workflow splits modules with read -a instead of an unquoted variable (actionlint), and Dependabot waits seven days before proposing a new release (zizmor). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…odules The README describes the modular lss instead of the 1.x script. The hardening guide maps the security modules to the CIS Benchmark areas and lists every deliberate deviation with its reason and setting; the troubleshooting guide covers lockouts and the common messages; the module guide is for contributors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
authselect has no with-pwquality feature: every profile includes pam_pwquality. The profile for local accounts is "minimal" up to authselect 1.4 (EL9) and "local" from 1.5 (EL10); lss now picks the one that exists and only adds the faillock feature. A reload restarts CrowdSec's local API for a few seconds, so a verify right after the install could fail. The check now waits up to 30 seconds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
A misspelt key in lss.conf was silently ignored, so the module ran with its default. lss now warns about every setting that no module reads. Two keys in the integration settings had exactly that problem. The integration harness gains a profile mode: install a whole profile, verify, install again without a change, then run the Lynis audit with a minimum index. CI runs it for minimal-secure on a virtual machine. The minimum starts at 0 to record the index; it is raised once the first runs show what the profile reaches. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
module_meta printed metadata without a final newline, so every while-read loop over MOD_OPTIONS skipped the last option: lss info never listed it, and the new unknown-settings check reported valid keys such as LSS_SYSTEM_UPGRADE. It now ends with a newline, which command substitutions drop as before. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
visudo -c checks every sudoers file, so a problem in a file of the cloud image or CI runner made admin-user fail although its own file was valid and sudo worked. The module now fails only when /etc/sudoers.d/00-lss is invalid and reports problems in other files as a warning with visudo's output. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
aide --init hashes every file. On the CI runner VM, with tens of GB of toolchains, the profile run sat at "Running aide --init" until it was cancelled; servers with large data directories have the same problem. LSS_AIDE_EXCLUDE adds directories to leave out, the database is built at low CPU and I/O priority, and lss reports how long it took. The integration settings exclude the runner's toolchain directories. On RHEL the excludes were appended to /etc/aide.conf only once, so a changed setting never took effect. The block after the lss marker is now rewritten on every run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
The verify step hid the output, so a failure on the CI runner VM gave no reason. It now prints the last lines of a debug run. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
As soon as auto-updates enables unattended-upgrades it starts and holds the dpkg lock, so the next module's package install failed (lynis in the profile run), and so could any install on a fresh server where apt-daily runs at boot. apt now waits up to ten minutes for the lock, and the auto-updates check waits while another unattended-upgrade holds its own lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
apt-daily-upgrade.timer has Persistent=true. On a server where it was off but had run before (cloud and CI images), enabling it made systemd catch up at once: unattended-upgrades upgraded every package and held the dpkg lock for many minutes while the next modules waited. Before a stopped timer is started, lss now records "ran now" in its stamp file, so the first automatic upgrade happens at the next regular time. The system module already installs all updates during the setup. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
A reload sends SIGHUP and CrowdSec restarts its local API in the background, so the bouncer and the next lss verify could hit it while it was down. lss now restarts the service, which systemd waits for, and the check uses the result of its wait loop instead of asking a second time. On failure it shows cscli's answer and the journal. The profile run on a VM reached a Lynis hardening index of 75; CI now fails below 70. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
unattended-upgrade --dry-run needs the dpkg lock. When a real update ran on the VM, lss verify waited silently for up to ten minutes. apt-config parses the same files without any lock. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Sources and tests are now separate, and three rules are accepted with their reasons. The integration images run as root on purpose; Bash predicates need their last command's status, so a trailing return 0 would break them. Also merged nested ifs, moved the faillock arithmetic out of the heredoc, sorted the image package lists and added log group helpers. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
docs/assurance.md documents the threat model, the trust boundaries, the secure design principles and the weaknesses lss counters, with the tests that back each claim. The OpenSSF Best Practices entry links to it, and the README shows its badge. Governance no longer says that version tags are already restricted to the release workflow. That restriction comes with 2.0.0. Pull requests now get a dependency review. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
apt and its hooks (man-db, needrestart, package postinst scripts) filled the console with lines that say nothing about lss. log_command now writes this output to the run log. The terminal shows it only with --verbose, or the last 40 lines when the command fails. Package installs, removals and upgrades and the AIDE database build use it. The two AIDE hints are now debug messages. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
Ubuntu 26.04 (resolute) has been the current LTS release since April 2026. lss now accepts it, and CI runs every module group in a 26.04 container. CrowdSec has no resolute suite yet, so the noble packages are used, as with Debian 13. The LTS check now accepts any NN.04 release among the supported majors. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
The README will state what each profile and module needs. These figures come from the test runs instead of guesses: each install prints its duration, the memory it took from MemAvailable, the disk space it used and the largest processes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…n tests MemAvailable after an install says little: ClamAV loads its whole signature database only while it scans, so the figure the README needs is the peak. A sampler reads MemAvailable twice a second from the install through the verify step. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
The figures come from the RESOURCES lines of the integration tests on all seven systems: the largest value per module, rounded up. ClamAV peaks at 1.6 GB while it scans, not 1.2 GB as the profile and the hardening guide said. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
chronyd resolves the server names in the background. On a fast start the verify step ran before the first source was listed and failed although chronyd was configured correctly (seen once on the kernel VM job). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
The ignores for shelldre:S7682 and S7679 in .sonarcloud.properties never took effect (299 open issues on the pull request), and the 1.x script on main carries 58 more. All are fixed in the code now: - S7682: every function ends its body with a return. A bare return keeps the status of the last command, so predicates behave as before. - S7679: positional parameters are copied into named locals; secret_load uses prefixed names because printf -v would assign a local that has the caller's variable name. - 1.x script: [[ instead of [ (S7688), a default branch in every case (S131), lower-case locals (S7684). The docker:S6471 ignore for the test images works and stays. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
…loads shfmt expands one-line functions with two statements, so they are written on several lines, and stubs return 0 or 1 directly. Touching the 1.x script made SonarQube Cloud report its downloads (shell:S6506): curl now accepts only HTTPS with TLS 1.2 or later, also on redirects, and replaces wget. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
SonarQube Cloud (shelldre:S1192) asks for a constant instead of six copies of the same option. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: VectoDE <system.bot.discord.utility@gmail.com>
|
VectoDE
marked this pull request as ready for review
October 13, 2026 16:12
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What changes and why
This is stage 1 of lss 2.0, which replaces the single 1.x install script with a modular tool. A server can be set up from a profile in one run or one module at a time, and modules can be added, reconfigured, verified or removed later. The 1.x script stays in the repository until 2.0.0 is released.
lsscommand andlib/. It handles settings (parsed, never sourced), dependency order, a separate process per step, managed files with backup and restore, pinned repository keys and checksums, secrets, firewall rules per module, state and the interactive menu.minimal-secureprofile installs 18 of them. ssh-2fa, crowdsec (instead of fail2ban), clamav and usbguard are opt-in.lib/, enforced at 90 %. Integration tests install, verify, reinstall and remove every module on Debian 12 and 13, Ubuntu 22.04 and 24.04, Rocky Linux 9 and AlmaLinux 10. A virtual machine runs the kernel modules and the full profile, followed by a Lynis audit that must reach an index of 70 (it measures 75).Closes #11
Checklist
scripts/dev/lint.shpassMOD_OPTIONSand the README;CHANGELOG.mdhas an entry under "Unreleased"