Skip to content

Commit

Permalink
Skip docker compose images with env param (#11656)
Browse files Browse the repository at this point in the history
  • Loading branch information
robaiken authored Feb 21, 2025
1 parent 8cc7554 commit 654e465
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 7 deletions.
40 changes: 33 additions & 7 deletions docker_compose/lib/dependabot/docker_compose/file_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ module DockerCompose
class FileParser < Dependabot::Shared::SharedFileParser
extend T::Sig

ENV_VAR = /\${[^}]+}/
DIGEST = /(?<digest>[0-9a-f]{64})/
IMAGE_REGEX = %r{^(#{REGISTRY}/)?#{IMAGE}#{TAG}?(?:@sha256:#{DIGEST})?#{NAME}?}x

Expand Down Expand Up @@ -37,14 +38,13 @@ def parse

composefiles.each do |composefile|
yaml = YAML.safe_load(T.must(composefile.content), aliases: true)
next unless yaml["services"].is_a?(Hash)

yaml["services"].each do |_, service|
if service["image"]
parsed_from_image = T.must(IMAGE_REGEX.match(service["image"])).named_captures
elsif service["build"]["dockerfile_inline"]
parsed_from_image = T.must(FROM_LINE.match(service["build"]["dockerfile_inline"])).named_captures
else
next
end
next unless service.is_a?(Hash)

parsed_from_image = parse_image_spec(service)
next unless parsed_from_image

parsed_from_image["registry"] = nil if parsed_from_image["registry"] == "docker.io"

Expand All @@ -60,6 +60,32 @@ def parse

private

sig { params(service: T.untyped).returns(T.nilable(T::Hash[String, T.nilable(String)])) }
def parse_image_spec(service)
return nil unless service

if service["image"]
return nil if service["image"].match?(/^\${[^}]+}$/)

match = IMAGE_REGEX.match(service["image"])
return match&.named_captures
elsif service["build"].is_a?(Hash) && service["build"]["dockerfile_inline"]
return nil if service["build"]["dockerfile_inline"].match?(/^FROM\s+\${[^}]+}$/)

match = FROM_LINE.match(service["build"]["dockerfile_inline"])
return match&.named_captures
end

nil
end

sig { params(parsed_image: T::Hash[String, T.nilable(String)]).returns(T.nilable(String)) }
def version_from(parsed_image)
return nil if parsed_image["tag"]&.match?(ENV_VAR)

super
end

sig { override.returns(String) }
def package_manager
"docker_compose"
Expand Down
96 changes: 96 additions & 0 deletions docker_compose/spec/dependabot/docker_compose/file_parser_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -492,4 +492,100 @@
end
end
end

describe "version_from with environment variables" do
context "with a parameterized tag" do
let(:composefile) do
Dependabot::DependencyFile.new(
name: "docker-compose.yml",
content: <<~YAML
services:
api:
image: ubuntu:${TAG_VERSION}
YAML
)
end

it "returns no dependencies" do
expect(parser.parse).to be_empty
end
end

context "with mixed static and environment variable tags" do
let(:composefile) do
Dependabot::DependencyFile.new(
name: "docker-compose.yml",
content: <<~YAML
services:
api:
image: ubuntu:${TAG_VERSION}
db:
image: postgres:12.3
cache:
image: redis:${REDIS_VERSION}
YAML
)
end

it "returns only the static dependency" do
dependencies = parser.parse
expect(dependencies.length).to eq(1)
expect(dependencies.first.name).to eq("postgres")
expect(dependencies.first.version).to eq("12.3")
end
end

context "with inline Dockerfile and parameterized tag" do
let(:composefile) do
Dependabot::DependencyFile.new(
name: "docker-compose.yml",
content: <<~YAML
services:
api:
build:
dockerfile_inline: |
FROM ubuntu:${VERSION}
RUN apt-get update
YAML
)
end

it "returns no dependencies" do
expect(parser.parse).to be_empty
end
end

context "with static tag" do
let(:composefile) do
Dependabot::DependencyFile.new(
name: "docker-compose.yml",
content: <<~YAML
services:
api:
image: ubuntu:18.04
YAML
)
end

describe "the first dependency" do
subject(:dependency) { parser.parse.first }

let(:expected_requirements) do
[{
requirement: nil,
groups: [],
file: "docker-compose.yml",
source: { tag: "18.04" }
}]
end

it "has the right details" do
expect(dependency).to be_a(Dependabot::Dependency)
expect(dependency.name).to eq("ubuntu")
expect(dependency.version).to eq("18.04")
expect(dependency.requirements).to eq(expected_requirements)
end
end
end
end
end

0 comments on commit 654e465

Please sign in to comment.