(CAT-2637) Enable Security/Open and Security/IoMethods cops#645
Merged
Conversation
Detect the pipe-based subprocess creation removed in Ruby 4.0 (Puppet 9)
per Ruby #19630. Enables both security cops in the strict profile:
- Security/Open flags open()/URI.open() with a pipe or dynamic argument
(literal pipe detection requires rubocop >= ~1.71; satisfied by the
pinned ~> 1.73.0). Previously PDK explicitly disabled this cop.
- Security/IoMethods flags IO.read/write/etc. file access, steering to
File.* equivalents; the deliberate IO.read("| cmd") pipe form is
intentionally left valid.
Documents the cop->replacement-API mapping and known gaps in README.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
Summary
Enables two RuboCop security cops in the
strictprofile (the defaultselected_profile) to detect the pipe-based subprocess creation removed in Ruby 4.0, which ships with Puppet 9 — see Ruby #19630. Parent: CAT-2630 (PDK | Puppet 9 Compatibility Testing).Security/Open— flagsopen()/URI.open()called with a pipe argument (open("| cmd")) or a dynamic argument (open(var)). Literal file paths such asopen("foo.txt")are not flagged. Recommended replacements:File.open,IO.popen,URI.parse(...).open. PDK was previously explicitly disabling this cop (it is enabled-by-default in RuboCop but was excluded from the profile lists); it is now active.Security/IoMethods— flagsIO.read/write/binread/binwrite/foreach/readlinesused for file access and steers them to theFile.*equivalents (autocorrectable). The deliberateIO.read("| cmd")pipe form is intentionally left valid.hardcorealready covered both viaall. Both cops remain overridable per module through.sync.yml.Additional Context
The ticket asked us to investigate before implementing. Empirically verifying the cops (reading the cop sources and running them at rubocop 1.50.2 and 1.73.2, and checking 1.87.0) corrected two claims from the original investigation:
Security/Openonly catches the literal pipe form (open("| cmd")) from rubocop ~1.71 onward — at 1.50.x the matcher is$!str(dynamic args only). We are fine because theGemfilepinsrubocop ~> 1.73.0, where the matcher is$_and both literal-pipe and dynamic forms are flagged. It covers bareopen/URI.openonly — notIO.openor explicit-receiverKernel.open(...).Security/IoMethodsdoes the inverse of what the ticket title's "IO.open pipe" wording implies (unchanged through 1.87.0): it flags file-accessIO.*and skips theIO.read("| cmd")pipe form. This was accepted on the ticket — intentional subprocess use stays valid, and theIO.* -> File.*nudge is a reasonable autocorrectable style enforcement.Verification (full ERB render of
moduleroot/.rubocop.yml.erb+ run at rubocop 1.73.2):open("| ls")open(var)open("foo.txt")IO.read("file.txt")File.readIO.read("| cmd")IO.popen("ls")Render confirms
Security/IoMethods: { Enabled: true };Security/Openis active via RuboCop's built-in default (same pattern as the existingSecurity/Eval).bundle exec rubocopon this repo is clean.Known residual gap (documented in the README, not statically detectable without a bespoke cop — scoped out):
IO.read("| cmd")subprocess use and the explicit-receiverKernel.open(...)form.Related Issues (if any)
Checklist