test: a sixth fuzz target for the cron parsers, and tailnet address coverage - #73
Merged
Conversation
…d test The rest of notifications.py's zero-coverage functions. The one that matters: save_settings treats a None secret as "keep what is stored", because the settings form never round-trips a real token back to the server. If that ever broke, every unrelated checkbox change would silently wipe the bot token and alerts would just stop — no error, nothing on screen. Asserted in both directions: None keeps the stored value, a real value replaces it AND is written encrypted (the plaintext must not appear in the config, and it must decrypt back). Also: thresholds clamp to their bounds rather than storing whatever was posted, and junk in a numeric field is ignored instead of overwriting a good value; the Telegram poller returns None for a malformed or empty token without building a URL; and Send test explains what is missing — five cases, each naming the field — rather than failing mute. update_config is stubbed throughout, so the real data/config.json is never written by these. Verified: the file's bytes are unchanged across a run. (Its mtime does move, but that predates this change — the suite already rewrote it byte-identically at HEAD.) Mutation-verified: making a None token overwrite fails 1, storing the secret in the clear fails 1, dropping the threshold clamp fails 1. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…overage ── fuzz: cron ──────────────────────────────────────────────────────────────── Everything the cron parsers read comes off a remote host — the game user's crontab, which anyone with shell access edits by hand, and the base64-framed status blob the panel's own wrapper writes, which carries whatever a LinuxGSM command printed to stderr (for an update, text fetched off the internet). That path has already produced one real bug this way: a `tr` that missed \r truncated every record at the transport, so errors silently read as empty. The Scheduled Tasks page renders all of it, and a raise here takes out the page rather than one row. Six parsers under test — _split_cron_line, _unwrap_cron_command, _cron_role, _cron_line_managed, _cron_log_text, _clean_cron_error — with 11 seeds covering a wrapped line, @reboot, name-form fields, a valid and a broken base64 blob, and an ANSI-laden error. Property-checked over 200k random inputs before committing: nothing raised. ── tailnet address recognition ─────────────────────────────────────────────── is_tailscale_ip decides whether the panel treats a host as being ON the tailnet, which changes how it connects and what it exempts from fail2ban and UFW — so a false positive exempts a PUBLIC address from the security rules. Nine near-misses are asserted alongside the six hits, including "example.ts.net.evil.com" and "1.100.0.1". get_magic_url too: 80 and 443 are left off, any other port is appended, and a node with no MagicDNS name yields None rather than "https://None". Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Up to standards ✅🟢 Issues
|
| Metric | Results |
|---|---|
| Coverage variation | ✅ +0.03% coverage variation (-1.00%) |
| Diff coverage | ✅ ∅ diff coverage |
Coverage variation details
Coverable lines Covered lines Coverage Common ancestor commit (74d11e8) 11965 5873 49.08% Head commit (24378ae) 11965 (+0) 5876 (+3) 49.11% (+0.03%) Coverage variation is the difference between the coverage for the head and common ancestor commits of the pull request branch:
<coverage of head commit> - <coverage of common ancestor commit>
Diff coverage details
Coverable lines Covered lines Diff coverage Pull request (#73) 0 0 ∅ (not applicable) Diff coverage is the percentage of lines that are covered by tests out of the coverable lines that the pull request added or modified:
<covered lines added or modified>/<coverable lines added or modified> * 100%
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.
…o both sides carried that block. Kept one copy; both test sets present, 889 checks.
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.
Fuzzing: the cron parsers
Everything these read comes off a remote host — the game user's crontab, which anyone with shell access edits by hand, and the base64-framed status blob the panel's own wrapper writes, carrying whatever a LinuxGSM command printed to stderr (for an update, text fetched off the internet).
That path has already produced one real bug this way: a
trthat missed\rtruncated every record at the transport, so errors silently read as empty. The Scheduled Tasks page renders all of it, and a raise here takes out the page rather than one row.Six parsers under test —
_split_cron_line,_unwrap_cron_command,_cron_role,_cron_line_managed,_cron_log_text,_clean_cron_error— with 11 seeds covering a wrapped line,@reboot, name-form fields, valid and broken base64, and an ANSI-laden error. Property-checked over 200,000 random inputs before committing; nothing raised.Fuzz matrix is now
[game_status, firewall, config, fail2ban, console, cron].Tailnet address recognition
is_tailscale_ipdecides whether the panel treats a host as being on the tailnet, which changes how it connects and what it exempts from fail2ban and UFW — so a false positive exempts a public address from the security rules. Nine near-misses asserted alongside the six hits, includingexample.ts.net.evil.comand1.100.0.1.get_magic_urltoo: 80 and 443 are left off, any other port appended, and a node with no MagicDNS name yieldsNonerather thanhttps://None.unit 867 → 889 · smoke 307 · manage 21 · template_actions 7 · lint clean.
🤖 Generated with Claude Code