0.3.4 — Security: accept sshd-session (OpenSSH 9.8+ on Ubuntu 26.04 / Fedora 41+)
Security release. Fixes a real production defect: pamsignal silently dropped every sshd auth event on Ubuntu 26.04, Fedora 41+, and Debian Trixie (any host running OpenSSH 9.8+). Surfaced by an end-to-end scenario test on Ubuntu 26.04 / OpenSSH 9.10p2 / OpenSSL 3.5.5 / systemd 259 — a stack CI doesn't currently exercise. Bundles repository-hygiene additions (CONTRIBUTING.md, issue templates, PR template) that accumulated under ## Unreleased since v0.3.3, plus the tests/scenario.sh script that caught the sshd-session bug, plus forward-compat hardening of the CI mock webhook for OpenSSL 3.5+.
Security
-
_EXEallowlist now acceptssshd-session. OpenSSH 9.8 (released 2024-07) split the server into a privilege-separated listener (sshd) and a per-connection auth process (sshd-session). Failed-password / accepted-password journal entries on Ubuntu 26.04, Fedora 41+, and Debian Trixie come fromsshd-session, notsshd. Pamsignal's anti-spoofing_EXEallowlist accepted only the latter, so every sshd auth event on those distributions was dropped atsrc/journal_watch.c's pre-parse filter — the daemon ran fine, journald accumulated events fine, the daemon just didn't see them. Fix: extend the basename allowlist withsshd-session(refactored into a testableps_is_trusted_exehelper). Eight new CMocka test cases cover the canonical paths (/usr/sbin/sshd,/usr/bin/sudo, etc.), the new sshd-session paths (/usr/sbin/sshd-session,/usr/lib/openssh/sshd-session), the alternate system-prefix paths (/sbin,/lib,/lib64,/opt), and the spoofing-rejection paths (logger, /tmp/, /home/, basename-imposter binaries, NULL/empty input, paths without a slash). test_journal_watch grows from 19 → 27 tests.
Tooling
-
tests/scenario.sh— full-stack local end-to-end scenario test that mirrorsrelease-packages.yml's test-deb job and adds two pieces of coverage that don't exist in CI: explicitType=notifyactivation verification (systemctl reportsactiveonly aftersd_notify(READY=1)actually fires), and the v0.3.0 sudo brute-force scenario with testpamuser temporarily added to/etc/sudoers.d/so PAM auth is actually invoked. Twelve phases with pass/fail output, an EXIT trap that always cleans up (sshd_config restored from backup, testpamuser deleted, /etc/pamsignal removed, mock webhook stopped, test CA removed from system trust store, sudoers.d entry removed). The script'sconfirm()reads from/dev/ttydirectly so it works under wrappers that capture stdout. Caught the sshd-session bug above on its first non-CI run. - CI mock webhook hardened for OpenSSL 3.5+ peers. The Python
BaseHTTPRequestHandlerdefaults to HTTP/1.0 + noContent-Length+ no explicit TLSclose_notify, which OpenSSL 3.5+ (Ubuntu 26.04, Fedora 41+) reports aserror:0A000126:SSL routines::unexpected eof while reading, breaking curl with exit 56 even though the HTTP response was successfully received. Forward-port theconnection.unwrap()+Content-Length+Connection: close+protocol_version='HTTP/1.1'fixes fromtests/scenario.shintorelease-packages.yml's test-deb mock so the workflow keeps passing when GitHub Actions promotes the runner image from ubuntu-24.04 (OpenSSL 3.0) to ubuntu-26.04 (OpenSSL 3.5+). Also adds aREADY-poll startup check with bounded retries so a Python-side bind error fails loudly with the captured stderr instead of silently hanging.
Repository hygiene
-
CONTRIBUTING.mdat the repo root documents the contributor workflow: clone+build quickstart, branch-per-change with Conventional Commits (with thefeat:/fix:/security:/refactor:/refactor!:/docs:/chore:/test:/perf:type table the project actually uses), coding standards (cross-referenced to.clang-format/.clang-tidy), the test requirement (every new function or changed behavior gets a CMocka test), the full pre-commit checklist (clang-format, clang-tidy, meson compile, meson test, optional sanitizer build), CHANGELOG conventions, code-review focus areas (threat-model alignment, test adequacy, API stability, style), and a packaging-changes section explicitly calling out thesystemd-analyzeCI gate at threshold 20 plus the el9-rpm%changelog-parsing trap. - Issue templates rewritten as Linux-daemon reports, not generic open-source-project forms.
.github/ISSUE_TEMPLATE/bug_report.ymlis a structured capture of the system state we'd ask the operator to gather anyway — a component dropdown (parser / brute-force tracker / alert dispatch / unit / packaging / journald integration / config parsing), distribution + version + kernel + systemd version + MAC-policy enforcement state, thesystemctl status pamsignaloutput, thejournalctl -u pamsignalexcerpt, the source-of-truth auth-event excerpt with the right per-service-unit filters, thesystemd-delta+ drop-in-overrides listing (frequent root cause for "directive X isn't behaving" reports), thesystemd-analyze securityscore (CI-gated at 20; a higher score on the operator's host suggests a drop-in or repackaging loosened a directive), the redacted config, and concrete operational reproduction steps (what auth events were generated, with what config values, in what order). The template includes the exact commands to run for each capture so an operator who doesn't know the daemon internals can still file a report we can act on.feature_request.ymlrewritten around the project's operator-facing surface area (config keys, journal fields, chat-text alert shape, ECS JSON webhook fields, unit directives, CLI flags, alert-channel additions) with a mandatory compatibility-commitment dropdown (additive / default-on-overridable / default-off opt-in / deprecation-cycle / breaking) referencing the PAMSIGNAL_* retirement precedent, and a threat-model-alignment field that distinguishes "strengthens an in-scope attack" from "argues for moving NS1–NS10 into scope" (the latter being the highest bar).config.ymlunchanged — disables blank issues, points security reports at GitHub Security Advisories, routes question traffic toquestion-labeled issues. - Pull-request template (
.github/pull_request_template.md) auto-populates new PRs with a summary / linked-issue / test-plan / threat-model-alignment structure plus the eight-item pre-commit checklist that mirrorsCONTRIBUTING.md. Reviewers can see at a glance whether the contributor ran the local checks.