feat(modernize): Add PreferRemoteFile, PreferArchiveFile cops + CI fixes#1051
feat(modernize): Add PreferRemoteFile, PreferArchiveFile cops + CI fixes#1051SuhasKumar01 wants to merge 5 commits intochef:mainfrom
Conversation
|
Hmm, this actually seems like it should be two different cops that this PR kind of wants as an end goal.
Trying to track and parse the flags for every single curl/wget tool is a losing game in the long run. But the two cops I suggest are much easier to implement and maintain :-) |
|
@dafyddcrosby, I agree that Cop #1 (Suggesting remote_file over curl/wget) is the cleaner, more "Chef-idiomatic" approach. I will refactor this PR right now to implement that specific check—flagging any use of curl/wget in execute blocks and recommending remote_file instead. Updating shortly! |
d707da9 to
e289a9b
Compare
|
@jaymzh Based on the feedback that parsing CLI flags is a "losing battle," I have refactored this PR into a complete Modernization Suite that encourages native Chef resources over shell commands.
Goal: Flag curl/wget usage in shell blocks. Fix: Suggests remote_file resource. Safety: Autocorrect disabled to preventing breaking piped commands (e.g., curl | bash).
Goal: Flag tar, unzip, 7z usage. Fix: Suggests archive_file resource (Chef 15+). Context: Since curl is usually followed by extraction, this completes the artifact handling pipeline. Summary: Performance: Both cops use RESTRICT_ON_SEND to limit scanning to shell resources. Verification: Added 57 tests covering download patterns, archive patterns, and false positive prevention. Looking forward to your thoughts on this architectural pivot! |
|
I haven't reviewed the code yet, I will, but just wanted to clarify here:
Just to be clear... piping commands like that in an execute block is bad practice. If you want to do that, you use an All of these things can and should be done with native resources, not with shell blocks. But yes, this is a hard one to autocorrect. |
| return unless curl_or_wget_command?(first_arg.value) | ||
|
|
||
| add_offense(first_arg) | ||
| end |
There was a problem hiding this comment.
again, these two are the same.
|
@jaymzh Thanks for the review! Garbage Files: My apologies, I've removed the extra markdown files and .gitignore. Refactoring: Good catch on the duplicate methods. I have collapsed check_resource_name and check_command_property into a single helper method to keep it DRY. Safety: And yes, agreed on the philosophy regarding "bad code." I've left the Autocorrect disabled as discussed. Pushed the fixes! Ready for another look. |
434b0e5 to
1e6a3ca
Compare
|
Thanks for the coaching. You were right—having duplicate check methods was sloppy, and "making bad code slightly less bad" is the wrong goal. Updates:
Ready for re-review! |
|
some of your tests are failing: https://github.com/chef/cookstyle/actions/runs/21899029929/job/63260614844?pr=1051 |
1e6a3ca to
915bba5
Compare
|
check again now i think everything has been resolved |
|
you still have many failures. Chef/Modernize/PreferRemoteFile is being triggered in a Rakefile, which it shouldn't. which is what was failing before. I see no delta between your last push and this one. There's line ending failures. |
|
check again now i think everything has been resolved. |
…chiveFile) Adds two new cops to discourage shell-based artifact handling in favor of native resources. Signed-off-by: Suhas Kumar <theshahmedia1@gmail.com>
Signed-off-by: Suhas Kumar <theshahmedia1@gmail.com>
481132c to
baebdaa
Compare
… spec - Add 6 missing cop entries to config/cookstyle.yml: Chef/Correctness/FileUtilsRMRF, Chef/Ruby/GemspecRequireRubygems, Chef/Ruby/LegacyPowershellOutMethods, Chef/Ruby/GemspecLicense, Chef/Ruby/RequireNetHttps, Chef/Ruby/UnlessDefinedRequire - Fix FileUtilsRMRF cop to highlight only the method call, not args - Fix FileUtilsRMRF spec to use :config metadata for RuboCop 1.84.2 - validate_config now passes; full suite: 1022 examples, 0 failures Signed-off-by: Suhas Kumar <theshahmedia1@gmail.com>
|
Hi, I updated my PR several times figuring out every possible error and solved it so please guide further. |
- Remove extra blank line in fileutils_rm_rf_spec.rb (Layout/EmptyLinesAroundBlockBody) - Exclude project infrastructure files from Chef/Ruby/UnlessDefinedRequire cop (Rakefile, cleanup_lint_roller.rb, tasks/) in .rubocop.yml Signed-off-by: Suhas Kumar <theshahmedia1@gmail.com>
- Change RSpec.describe -> describe in fileutils_rm_rf_spec.rb (match all cop specs) - Standardize @example comments to use # bad / # good across all new cops - Add missing StyleGuide key to FileUtilsRMRF config entry - Create missing doc YAML for Chef/Correctness/FileUtilsRMRF - Align VersionAdded to 8.6.5 for all new cops (matching current release) Signed-off-by: Suhas Kumar <theshahmedia1@gmail.com>
|
|
Thanks, looking much better. We'll give this a (hopefully) final review at next week's PR review meeting. |
|
Thank you very much @jaymzh |
| 'Native resources handle idempotence and multiple formats natively.' | ||
|
|
||
| # Performance: only trigger on_send for shell resources and command/code property setters | ||
| RESTRICT_ON_SEND = %i(execute bash sh csh perl python ruby zsh powershell_script command code).freeze |
There was a problem hiding this comment.
| RESTRICT_ON_SEND = %i(execute bash sh csh perl python ruby zsh powershell_script command code).freeze | |
| RESTRICT_ON_SEND = %i(execute bash csh perl python ruby powershell_script command code).freeze |
There was a problem hiding this comment.
I don't see sh or zsh as documented resources in docs.chef.io, am I missing something here?
This appears to be missing the ksh resource. There's no code resource, so this could end up in a false positive where code isn't a resource property.
|
|
||
| # Matches extraction tools as whole words. | ||
| # Excludes filenames like 'file.tar.gz' by ensuring a leading space/start and trailing space/end. | ||
| ARCHIVE_COMMAND_REGEX = /(?:^|\s)(?:tar|unzip|gunzip|gzip|7z)(?:\s|$)/.freeze |
There was a problem hiding this comment.
The benefit of having this as a constant is that you can test the strings directly against it
|
|
||
| # Matches 'curl' or 'wget' as whole words to avoid false positives (e.g., 'libcurl') | ||
| # Regex: start-of-string OR whitespace, then curl/wget, then whitespace OR end-of-string | ||
| DOWNLOAD_COMMAND_REGEX = /(?:^|\s)(?:curl|wget)(?:\s|$)/.freeze |
| 'Native resources ensure idempotence, support retries, and handle permissions correctly.' | ||
|
|
||
| # Performance: only trigger on_send for shell resources and command/code property setters | ||
| RESTRICT_ON_SEND = %i(execute bash sh csh perl python ruby zsh powershell_script command code).freeze |
| describe RuboCop::Cop::Chef::Modernize::PreferArchiveFile, :config do | ||
| let(:msg) { 'Use the `archive_file` resource instead of shell-based extraction (`tar`, `unzip`, etc.). Native resources handle idempotence and multiple formats natively.' } | ||
|
|
||
| # ========================================================================== |
There was a problem hiding this comment.
There's several permutations that are missing. If you loop this through the expected resources+shellout stings instead you can be exhaustive in your tests. See https://www.rubydoc.info/gems/rubocop/RuboCop/RSpec/ExpectOffense for how to do dynamic offense lengths
| context 'when using execute with curl' do | ||
| it 'registers an offense for execute resource with curl command' do | ||
| expect_offense(<<~RUBY) | ||
| execute 'curl https://example.com/file.tar.gz -o /tmp/file.tar.gz' |
|
@SuhasKumar01 - following up - do you still want to work on this? |
|
i would love too
…On Wed, Apr 22, 2026 at 2:18 AM Phil Dibowitz ***@***.***> wrote:
*jaymzh* left a comment (chef/cookstyle#1051)
<#1051?email_source=notifications&email_token=BTF2ZRY3BAKLSS2MBPKM56D4W7NC5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMRZGE3DOMZYHE4KM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJNLQOJPWG33NNVSW45C7N5YGK3S7MNWGSY3L#issuecomment-4291673898>
@SuhasKumar01 <https://github.com/SuhasKumar01> - following up - do you
still want to work on this?
—
Reply to this email directly, view it on GitHub
<#1051?email_source=notifications&email_token=BTF2ZRY3BAKLSS2MBPKM56D4W7NC5A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTIMRZGE3DOMZYHE4KM4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJNLQOJPWG33NNVSW45C7N5YGK3S7MNWGSY3L#issuecomment-4291673898>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/BTF2ZR6E33AFYNSBOSHEDHT4W7NC5AVCNFSM6AAAAACTUPLBRWVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DEOJRGY3TGOBZHA>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
@SuhasKumar01 - OK, then please address David's comments. I'll keep this open for a bit longer. |



Summary
Refactored based on maintainer feedback to replace the initial Security Cop with a comprehensive Modernization Suite, plus fixes CI/CD validation failures.
1. Chef/Modernize/PreferRemoteFile
curl/wget)remote_fileresource2. Chef/Modernize/PreferArchiveFile
tar,unzip,gunzip,gzip,7z)archive_fileresource (Chef Infra Client 15.0+)3. Chef/Correctness/FileUtilsRMRF (Fix)
FileUtils.rm_rf(not entire expression):configmetadata)4. CI/CD Fixes
Missing Cop Registrations
Registered 6 cops in
config/cookstyle.ymlthat causedrake validate_configto fail:Chef/Correctness/FileUtilsRMRFChef/Ruby/GemspecRequireRubygemsChef/Ruby/LegacyPowershellOutMethodsChef/Ruby/GemspecLicenseChef/Ruby/RequireNetHttpsChef/Ruby/UnlessDefinedRequireLint Fixes
fileutils_rm_rf_spec.rb(Layout/EmptyLinesAroundBlockBody).rubocop.ymlexclusions forChef/Ruby/UnlessDefinedRequireon infrastructure files (Rakefile,tasks/**/*)Deep Dive Cleanup (Standardization)
RSpec.describe→describeinfileutils_rm_rf_spec.rb(match all cop specs)@examplecomments to use# bad/# goodacross all new copsStyleGuidekey toFileUtilsRMRFconfig entryChef/Correctness/FileUtilsRMRFVersionAddedto8.6.5for all new cops (matching current release)Design Decisions
No Autocorrect
Both cops intentionally disable autocorrect to prevent breaking:
curl | bash)tar -xzfvstar -cvf)Performance
Both use
RESTRICT_ON_SENDto limit scanning to shell resources only:execute,bash,powershell_script,sh,csh,perl,python,ruby,zshFalse Positive Prevention
libcurl,curlcache,wgetrc.tar.gz,tarball,stargazer,guitarTest Results
rake validate_configFiles Changed
lib/rubocop/cop/chef/modernize/prefer_remote_file.rbspec/rubocop/cop/chef/modernize/prefer_remote_file_spec.rblib/rubocop/cop/chef/modernize/prefer_archive_file.rbspec/rubocop/cop/chef/modernize/prefer_archive_file_spec.rblib/rubocop/cop/chef/correctness/fileutils_rm_rf.rbspec/rubocop/cop/chef/correctness/fileutils_rm_rf_spec.rbconfig/cookstyle.yml.rubocop.ymldocs-chef-io/assets/cookstyle/cops_chef_modernize_preferremotefile.ymldocs-chef-io/assets/cookstyle/cops_chef_modernize_preferarchivefile.ymldocs-chef-io/assets/cookstyle/cops_chef_correctness_fileutilsrmrf.ymlChecklist
rake validate_configpasses — all cops registeredcookstyle.ymlwithStyleGuidekeysRESTRICT_ON_SENDfor performance@examplecomments use standard# bad/# goodformatVersionAddedaligned to8.6.5for all new cops