Merged
jared
merged 5 commits from 2026-06-04 14:04:45 -04:00
fix/issues-1-3-5-misc-improvements into master
No Reviewers
Labels
Clear labels
bug
documentation
duplicate
enhancement
good first issue
help wanted
invalid
kodor
kodor/feature-proposal
kodor/fix
kodor/needs-review
kodor/triaged
question
wontfix
kodor
kodor/feature-proposal
kodor/fix
kodor/needs-review
kodor/triaged
Something isn't working
Improvements or additions to documentation
This issue or pull request already exists
New feature or request
Good for newcomers
Extra attention is needed
This doesn't seem right
Kodor should process this issue
Kodor has written a feature proposal
Kodor should implement a fix (assigned to Kodor)
Kodor's work or failure needs Jared's review
Kodor has already triaged this issue (skip)
Further information is requested
This will not be worked on
needs
human
Cannot move without a person -- a decision, a check an agent cannot make, something outside the repo
origin
client
Came from a client ask
origin
obligation
Created by a change elsewhere
origin
review
Came from human review
origin
roborev
Promoted from a roborev finding
type
chore
Maintenance with no behaviour change
type
debt
Owed work -- docs, tests, cleanup a change obligated
type
decision
Needs a decision before work can proceed
type
defect
Something is wrong
type
feature
New capability
ws
helpers
Analysis and workflow helpers
ws
logo
Logo and branded output composition
ws
packaging
Package infrastructure and release
ws
quarto
Quarto themes and publishing templates
ws
theme
Themes, palettes, and fonts
Assign a task to kodor
Kodor thinks this needs a feature.
Kodor should fix this
Kodor thinks the user is ready to review this.
Kodor is done with this issue.
No labels
Milestone
No items
No Milestone
Projects
Clear projects
No projects
No Assignees
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: Civilytics/civilyticsR#6
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Changes
Issue #5 —
_brand.ymlunwrapped for Quarto 1.9+ compatibilityThe shipped
inst/quarto/_brand.ymlhad itsmeta,logo,color, andtypographykeys nested under a top-levelbrand:wrapper. Quarto 1.9+ validates strictly and rejects this when auto-discovering a standalone_brand.yml.Fix: Removed the
brand:wrapper so all keys sit at the top level, matching the Quarto brand spec.Issue #1 —
na_sum()quiet parameterna_sum()always emitted amessage(), which is noisy when called inside loops ordplyrpipelines.Fix: Added
quiet = FALSEparameter. Whenquiet = TRUE, the message is suppressed.Issue #3 —
beep()notification functionNew
beep()function for CLI progress/completion alerts. Supports four notification types:"beep"\007)"notify"notify-send(Linux) orosascript(macOS)"webhook"curlorwget)"all"Testing
na_sum(quiet = TRUE)intest_utils.Rtest_notifications.Rwith tests forbeep()Related Issues
Closes #1, #3, #5
Code Review: PR #6 — Fix issues #1, #3, #5: misc improvements
Accuracy
beep()function (notifications.R): The function correctly implements all four notification types (beep, notify, webhook, all). Thematch.arg()call properly handles type disambiguation. Thegrepl()checks for "beep", "notify", and "webhook" in the type string work correctly for the "all" case.na_sum()function (utils.R): The newquietparameter is correctly implemented with a default ofFALSEto preserve backward compatibility. Theif (!quiet)guard properly suppresses the message._brand.yml: The YAML indentation fix (removing the extrabrand:nesting level) is correct — this matches the expected Quarto brand config format.Completeness
test_notifications.R: Tests cover invisibility, quiet mode, notify fallback, and webhook-without-URL. However, the tests are minimal — they don't test the actual notification delivery (which is expected since it depends on external tools). Consider adding a test that mocksSys.which()to verify the correct code path is taken.test_utils.R: The new test forna_sum(quiet=TRUE)is good and covers the key behavior. The existing tests forna_sumare preserved.beep()is thorough — covers all parameters, requirements, and examples. The@exporttag is present. The NAMESPACE and man pages are auto-generated correctly.jsonliteimport is correctly added to DESCRIPTION and theflush.consoleimport is added to NAMESPACE.Coherence
beep()function is a new feature that fits well with the existing utility pattern in the package.na_sum()change is a backward-compatible enhancement that doesn't break existing callers._brand.ymlfix is a standalone correction that doesn't affect functionality.Security
beep()/.send_webhook(): The webhook URL and payload are interpolated into shell commands viapaste0(). This is a potential command injection risk if the URL or message contains shell metacharacters. For example, a message containing"; rm -rf /; "would be executed by the shell.system2()instead ofsystem()with shell interpolation, or use R's built-inhttr2/curlpackage for HTTP requests. If sticking withsystem(), at minimum validate/sanitize the URL and message parameters..send_desktop_notify(): Similar shell injection risk viapaste0()for thenotify-sendandosascriptcommands. Thegsub()for single quotes innotify-sendis a good start but doesn't handle all shell metacharacters.Evaluation: ⚠️ Needs security fix before merge
Blocking issue:
.send_webhook()and.send_desktop_notify(). Both functions construct shell commands via string interpolation. Usesystem2()with separateargsparameters instead ofsystem()with interpolated strings. For example:Suggestions (non-blocking):
na_sum()returns the correct value (not just silence) whenquiet=TRUE.beep()withtype="all"to verify both beep and notify paths execute.flush.console()call in the beep path is good but should also be used after the terminal beep to ensure the bell character is flushed immediately.The code quality and documentation are excellent — the security fix is the only blocker.
Security fix pushed — replaced
system()withsystem2()in both.send_desktop_notify()and.send_webhook().What changed:
notify-send: now usessystem2("notify-send", args = c(status, msg))— no shell interpolationosascript: now usessystem2("osascript", args = c("-e", ...))— no shell interpolationcurl: now usessystem2("curl", args = c("-s", "-X", "POST", "-H", ..., "-d", payload, url, ...))— no shell interpolationwget: now usessystem2("wget", args = c("-q", "-O", "/dev/null", paste0("--post-data=", payload), ...))— no shell interpolationsystem2()passes arguments directly to the executable without going through a shell, so shell metacharacters inmsg,status,url, orpayloadare treated as literal data, not executable commands.The PR should now be safe to merge.
- Add test verifying .send_webhook() and .send_desktop_notify() use system2() (not system()) to prevent command injection. This test reads the function body and asserts system2 is present and system("...") is absent, so the vulnerability cannot be reintroduced by accident. - Add test for beep(type='all') exercising both beep and notify paths.Additional test coverage pushed:
Security regression test — verifies
.send_webhook()and.send_desktop_notify()usesystem2()(notsystem()with interpolated strings). The test reads the function body and assertssystem2is present andsystem("...")is absent, so the command injection vulnerability cannot be reintroduced by accident.beep(type='all')test — exercises both the beep and notify code paths to ensure they execute without error.Note: the
na_sum(quiet=TRUE)value test andflush.console()were already present in the codebase.PR #6 should now be fully ready to merge.