Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add new boolean property anchor_package_regex to resource apt_package resource #13873

Merged
merged 4 commits into from Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 5 additions & 5 deletions Gemfile.lock
@@ -1,9 +1,9 @@
GIT
remote: https://github.com/chef/ohai.git
revision: c63a8dca74db3fd542a082c7b6626ff497904290
revision: d5d03240e6ee1130ef38441c1d25a7ca08df0cab
branch: main
specs:
ohai (18.1.4)
ohai (18.1.11)
chef-config (>= 14.12, < 19)
chef-utils (>= 16.0, < 19)
ffi (~> 1.9)
Expand Down Expand Up @@ -222,8 +222,8 @@ GEM
faraday-net_http (3.0.2)
fauxhai-ng (9.3.0)
net-ssh
ffi (1.15.5)
ffi (1.15.5-x64-mingw-ucrt)
ffi (1.16.2)
ffi (1.16.2-x64-mingw-ucrt)
ffi-libarchive (1.1.3)
ffi (~> 1.0)
ffi-win32-extensions (1.0.4)
Expand Down Expand Up @@ -427,7 +427,7 @@ GEM
uuidtools (2.2.0)
vault (0.17.0)
aws-sigv4
webmock (3.18.1)
webmock (3.19.1)
addressable (>= 2.8.0)
crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0)
Expand Down
13 changes: 11 additions & 2 deletions lib/chef/provider/package/apt.rb
Expand Up @@ -124,6 +124,11 @@ def unlock_package(name, version)

private

# @return [String] package name with or without anchors attached to it.
def resolve_package(pkg)
new_resource.anchor_package_regex ? "^#{pkg}$" : pkg
end

# @return [String] version of apt-get which is installed
def apt_version
@apt_version ||= shell_out("apt-get --version").stdout.match(/^apt (\S+)/)[1]
Expand Down Expand Up @@ -174,10 +179,12 @@ def config_file_options
end

def resolve_package_versions(pkg)
# apt-cache considers package names as regex by default. The anchor_package_regex flag will decide whether to match name exact string or not
pkg_name = resolve_package(pkg)
current_version = nil
candidate_version = nil
all_versions = []
run_noninteractive("apt-cache", default_release_options, "policy", pkg).stdout.each_line do |line|
run_noninteractive("apt-cache", default_release_options, "policy", pkg_name).stdout.each_line do |line|
case line
when /^\s{2}Installed: (.+)$/
current_version = ( $1 != "(none)" ) ? $1 : nil
Expand Down Expand Up @@ -216,7 +223,9 @@ def resolve_package_versions(pkg)
end

def resolve_virtual_package_name(pkg)
showpkg = run_noninteractive("apt-cache", "showpkg", pkg).stdout
# apt-cache considers package names as regex by default. The anchor_package_regex flag will decide whether to match name exact string or not
pkg_name = resolve_package(pkg)
showpkg = run_noninteractive("apt-cache", "showpkg", pkg_name).stdout
partitions = showpkg.rpartition(/Reverse Provides: ?#{$/}/)
return nil if partitions[0] == "" && partitions[1] == "" # not found in output

Expand Down
19 changes: 19 additions & 0 deletions lib/chef/resource/apt_package.rb
Expand Up @@ -52,6 +52,21 @@ class AptPackage < Chef::Resource::Package
options '--no-install-recommends'
end
```

**Prevent the apt_package resource from installing packages with pattern matching names**:

By default, the apt_package resource will install the named package.
If it can't find a package with the exact same name, it will treat the package name as regex string and match with any package that matches that regex.
johnmccrae marked this conversation as resolved.
Show resolved Hide resolved
This may lead Chef Infra Client to install one or more packages with names that match that regex.
johnmccrae marked this conversation as resolved.
Show resolved Hide resolved
Comment on lines +59 to +60
Copy link
Contributor

@IanMadd IanMadd Sep 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

https://developers.google.com/style/word-list#regex

Suggested change
If it can't find a package with the exact same name, it will treat the package name as regex string and match with any package that matches that regex.
This may lead Chef Infra Client to install one or more packages with names that match that regex.
If it can't find a package with the exact same name, it will treat the package name as regular expression string and match with any package that matches that regular expression.
This may lead Chef Infra Client to install one or more packages with names that match that regular expression.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This pr was merged without this change. Addressing that in a separate pr #13991


In this example, `anchor_package_regex true` prevents the apt_package resource from installing matching packages if it can't find the `lua5.3` package.
johnmccrae marked this conversation as resolved.
Show resolved Hide resolved

```ruby
apt_package 'lua5.3' do
version '5.3.3-1.1ubuntu2'
anchor_package_regex true
end
```
DOC

description "Use the **apt_package** resource to manage packages on Debian, Ubuntu, and other platforms that use the APT package system."
Expand All @@ -75,6 +90,10 @@ class AptPackage < Chef::Resource::Package
description: "A Hash of response file variables in the form of {'VARIABLE' => 'VALUE'}.",
default: {}, desired_state: false

property :anchor_package_regex, [TrueClass, FalseClass],
introduced: "18.3",
description: "A Boolean flag that allows (`false`) or prevents (`true`) apt_package from matching the named package with packages by regular expression if it can't find a package with the exact same name.",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
description: "A Boolean flag that allows (`false`) or prevents (`true`) apt_package from matching the named package with packages by regular expression if it can't find a package with the exact same name.",
description: "A Boolean flag that wraps a package name in regex anchors to help prevent `apt_package` from installing packages with similar names.",

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How does this prevent this? What do true and false do?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because the regex anchors specify that the regex pattern must include the entire package name.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The larger description above provides lots of other context. But anything treated like a regular expression means it'll match substrings, so "apache" which would match "apache-mycoolthing" or whatever. This is the short-description, suggestions welcome

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR was merged with this change as well, and the description is not accurate as it stands. It claims it's not a regex anymore, but it still is, it's just an anchored one. If someone passes in foo.*bar that'll still work.

default: false
end
end
end
17 changes: 10 additions & 7 deletions omnibus/Gemfile.lock
@@ -1,23 +1,23 @@
GIT
remote: https://github.com/chef/omnibus-software.git
revision: f06bbea744458f2cb63c98e6891f9cfb904a1f90
revision: c44dea9a73e9cc12097e32edbc8d3f965b7d7474
branch: main
specs:
omnibus-software (23.5.289)
omnibus-software (23.9.296)
omnibus (>= 9.0.0)

GIT
remote: https://github.com/chef/omnibus.git
revision: 9c0643a3a44f3e7119789c2093bfc8edd78c74ff
revision: 82dae896a066542f1b66dc866186f856f37e518e
branch: main
specs:
omnibus (9.0.21)
omnibus (9.0.23)
aws-sdk-s3 (~> 1.116.0)
chef-cleanroom (~> 1.0)
chef-utils (>= 15.4)
contracts (>= 0.16.0, < 0.17.0)
ffi-yajl (~> 2.2)
license_scout (~> 1.3)
license_scout (~> 1.0)
mixlib-shellout (>= 2.0, < 4.0)
mixlib-versioning
ohai (>= 16, < 19)
Expand Down Expand Up @@ -53,7 +53,7 @@ GEM
aws-sigv4 (1.5.2)
aws-eventstream (~> 1, >= 1.0.2)
bcrypt_pbkdf (1.1.0)
berkshelf (8.0.5)
berkshelf (8.0.9)
chef (>= 15.7.32)
chef-config
cleanroom (~> 1.0)
Expand Down Expand Up @@ -192,6 +192,9 @@ GEM
faraday (>= 1, < 3)
faraday-net_http (3.0.2)
ffi (1.15.5)
ffi (1.15.5-x64-mingw-ucrt)
ffi (1.15.5-x64-mingw32)
ffi (1.15.5-x86-mingw32)
ffi-libarchive (1.1.3)
ffi (~> 1.0)
ffi-win32-extensions (1.0.4)
Expand Down Expand Up @@ -453,7 +456,7 @@ GEM
vault (0.17.0)
aws-sigv4
webrick (1.8.1)
win32-api (1.10.1-universal-mingw32)
win32-api (1.10.1)
win32-certstore (0.6.15)
chef-powershell (>= 1.0.12)
ffi
Expand Down
31 changes: 18 additions & 13 deletions spec/unit/provider/package/apt_spec.rb
Expand Up @@ -63,11 +63,16 @@ def ubuntu1404downgrade_stubs
allow(@provider).to receive(:shell_out).with("dpkg", "--compare-versions", "1.0.1ubuntu2", "eq", "1.1.0").and_return(so2)
end

def get_pkg_name_str(name)
# Package name with or without anchors attached to it based on the flag.
@new_resource.anchor_package_regex ? "^#{name}$" : name
end

describe "when loading current resource" do

it "should create a current resource with the name of the new_resource" do
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", @new_resource.package_name,
"apt-cache", "policy", get_pkg_name_str(@new_resource.package_name),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(@shell_out)
Expand Down Expand Up @@ -107,7 +112,7 @@ def ubuntu1404downgrade_stubs
POLICY_STDOUT
policy = double(stdout: policy_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", "conic-smarms",
"apt-cache", "policy", get_pkg_name_str("conic-smarms"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(policy)
Expand All @@ -116,7 +121,7 @@ def ubuntu1404downgrade_stubs
SHOWPKG_STDOUT
showpkg = double(stdout: showpkg_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "showpkg", "conic-smarms",
"apt-cache", "showpkg", get_pkg_name_str("conic-smarms"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(showpkg)
Expand All @@ -135,7 +140,7 @@ def ubuntu1404downgrade_stubs
VPKG_STDOUT
virtual_package = double(stdout: virtual_package_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", "libmysqlclient15-dev",
"apt-cache", "policy", get_pkg_name_str("libmysqlclient15-dev"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(virtual_package)
Expand All @@ -159,7 +164,7 @@ def ubuntu1404downgrade_stubs
SHOWPKG_STDOUT
showpkg = double(stdout: showpkg_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "showpkg", "libmysqlclient15-dev",
"apt-cache", "showpkg", get_pkg_name_str("libmysqlclient15-dev"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(showpkg)
Expand All @@ -178,7 +183,7 @@ def ubuntu1404downgrade_stubs
RPKG_STDOUT
real_package = double(stdout: real_package_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", "libmysqlclient-dev",
"apt-cache", "policy", get_pkg_name_str("libmysqlclient-dev"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(real_package)
Expand All @@ -195,7 +200,7 @@ def ubuntu1404downgrade_stubs
VPKG_STDOUT
virtual_package = double(stdout: virtual_package_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", "mp3-decoder",
"apt-cache", "policy", get_pkg_name_str("mp3-decoder"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(virtual_package)
Expand All @@ -222,7 +227,7 @@ def ubuntu1404downgrade_stubs
SHOWPKG_STDOUT
showpkg = double(stdout: showpkg_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "showpkg", "mp3-decoder",
"apt-cache", "showpkg", get_pkg_name_str("mp3-decoder"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(showpkg)
Expand All @@ -236,7 +241,7 @@ def ubuntu1404downgrade_stubs
@new_resource.default_release("lenny-backports")
@new_resource.provider(nil)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "-o", "APT::Default-Release=lenny-backports", "policy", "irssi",
"apt-cache", "-o", "APT::Default-Release=lenny-backports", "policy", get_pkg_name_str("irssi"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(@shell_out)
Expand All @@ -246,7 +251,7 @@ def ubuntu1404downgrade_stubs
it "raises an exception if a source is specified (CHEF-5113)" do
@new_resource.source "pluto"
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", @new_resource.package_name,
"apt-cache", "policy", get_pkg_name_str(@new_resource.package_name),
env: { "DEBIAN_FRONTEND" => "noninteractive" } ,
timeout: @timeout
).and_return(@shell_out)
Expand Down Expand Up @@ -277,7 +282,7 @@ def ubuntu1404downgrade_stubs
RPKG_STDOUT
real_package = double(stdout: real_package_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", "libmysqlclient-dev",
"apt-cache", "policy", get_pkg_name_str("libmysqlclient-dev"),
env: { "DEBIAN_FRONTEND" => "noninteractive" },
timeout: @timeout
).and_return(real_package)
Expand Down Expand Up @@ -307,12 +312,12 @@ def ubuntu1404downgrade_stubs
RPKG_STDOUT
real_package = double(stdout: real_package_out, exitstatus: 0)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "policy", @new_resource.package_name,
"apt-cache", "policy", get_pkg_name_str(@new_resource.package_name),
env: { "DEBIAN_FRONTEND" => "noninteractive" } ,
timeout: @timeout
).and_return(real_package)
expect(@provider).to receive(:shell_out_compacted!).with(
"apt-cache", "showpkg", @new_resource.package_name,
"apt-cache", "showpkg", get_pkg_name_str(@new_resource.package_name),
env: { "DEBIAN_FRONTEND" => "noninteractive" } ,
timeout: @timeout
).and_return(real_package)
Expand Down