Skip to content

fix(install): tag the secondary installer's journalctl grants NOEXEC too - #491

Merged
ChuckBuilds merged 1 commit into
mainfrom
fix/web-sudo-noexec
Aug 21, 2026
Merged

fix(install): tag the secondary installer's journalctl grants NOEXEC too#491
ChuckBuilds merged 1 commit into
mainfrom
fix/web-sudo-noexec

Conversation

@ChuckBuilds

Copy link
Copy Markdown
Owner

Why this is a new PR

This change was reviewed and written for #472, but it never reached that PR's branch — I pushed it to a local branch that was never published, so #472 merged (fe5a3aa9) carrying only the first_time_install.sh half of the fix. scripts/install/configure_web_sudo.sh on main today still writes the untagged grants:

$WEB_USER ALL=(ALL) NOPASSWD: $JOURNALCTL_PATH -u ledmatrix.service *
$WEB_USER ALL=(ALL) NOPASSWD: $JOURNALCTL_PATH -u ledmatrix *
$WEB_USER ALL=(ALL) NOPASSWD: $JOURNALCTL_PATH -t ledmatrix *

So this re-lands it against main. My mistake, not a review miss.

The fix

configure_web_sudo.sh writes the same three wildcard journalctl grants that #472 tagged in first_time_install.sh. Each rule ends in *, so the web user controls the tail of the command line, and journalctl pages through less by default — and less will run a shell via !command. NOPASSWD:NOEXEC: stops the granted command from executing anything of its own.

All three are now NOPASSWD:NOEXEC:, matching first_time_install.sh.

Why the existing suite didn't catch it

test/test_sudoers_noexec_on_pagers.py only walked first_time_install.sh and configure_wifi_permissions.sh. configure_web_sudo.sh was simply not in INSTALLERS, so the suite was green while three untagged wildcard rules sat in it. It is now listed.

The suite also only recognised rules written literally into a heredoc — this installer echos them instead, and an echoed rule ends in a quote, so the trailing-* check skipped it and the rule was never examined at all. Echoed rules are now unwrapped before matching.

Verification

Mutation-checked — untagging the three grants fails the suite:

=== with NOPASSWD:NOEXEC: reverted to NOPASSWD: ===
FAILED test_each_journalctl_rule_is_tagged[-u ledmatrix.service]
FAILED test_each_journalctl_rule_is_tagged[-u ledmatrix]
FAILED test_each_journalctl_rule_is_tagged[-t ledmatrix]
4 failed, 3 passed

And a renamed installer path fails rather than silently dropping out of the walk (test_the_installers_are_present already covers this — I checked before adding a duplicate):

=== INSTALLERS entry pointed at a nonexistent file ===
FAILED test_the_installers_are_present

Clean: test_sudoers_noexec_on_pagers.py + test_sudo_allowlist_covers_calls.py all pass.

Review was right on all three counts, and the first is the one that matters:
scripts/install/configure_web_sudo.sh writes the same three wildcard
journalctl rules as first_time_install.sh and none of them carried NOEXEC. So
this PR closed the pager escape on one installer path and left it open on the
other, which is close to no fix at all -- a rig configured through that script
still hands out a root shell via less's "!command".
The test could not have caught it, for two independent reasons. INSTALLERS
did not list the file. And even listed, _grant_lines() kept the raw source
line: that installer echoes its rules, so each one ends in a quote rather
than the wildcard, and the trailing-* check skipped every one of them. Either
alone would have hidden it.
Both fixed: the file is covered, and an echoed rule is unwrapped to the
sudoers line it actually emits.
The selector test now covers -t ledmatrix as well. It asserted only the two
-u forms, so deleting the -t rule would have passed.
Verified by removing NOEXEC again from the secondary installer: four of the
six tests fail, where before the suite passed with the vulnerability present.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01STMbQE4YctTacQXfbYqKuW
@coderabbitai

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@ChuckBuilds, you've reached your PR review limit, so we couldn't start this review.

Next review available in:23 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d0a95382-f163-4648-bcce-a1a7c5559599

📥 Commits

Reviewing files that changed from the base of the PR and between fe5a3aa and c78e36c.

📒 Files selected for processing (2)
  • scripts/install/configure_web_sudo.sh
  • test/test_sudoers_noexec_on_pagers.py

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.

@codacy-production

Copy link
Copy Markdown

Up to standards ✅

🟢 Issues0 issues

Results:
0 new issues

View in Codacy

NEW Get contextual insights on your PRs based on Codacy's metrics, along with PR and Jira context, without leaving GitHub. Enable AI reviewer
TIP This summary will be updated as you push new changes.

@ChuckBuilds
ChuckBuilds merged commit cc258aa into mainAug 21, 2026
9 checks passed
@ChuckBuilds
ChuckBuilds deleted the fix/web-sudo-noexec branch August 21, 2026 18:28
Sign up for freeto 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.

1 participant

@ChuckBuilds