class Dependabot::GithubActions::FileParser

Constants

GITHUB_REPO_REFERENCE

Public Instance Methods

parse() click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 26
def parse
  dependency_set = DependencySet.new

  workflow_files.each do |file|
    dependency_set += workfile_file_dependencies(file)
  end

  resolve_git_tags(dependency_set)
  dependency_set.dependencies
end

Private Instance Methods

build_github_dependency(file, string) click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 55
def build_github_dependency(file, string)
  details = string.match(GITHUB_REPO_REFERENCE).named_captures
  name = "#{details.fetch('owner')}/#{details.fetch('repo')}"
  url = "https://github.com/#{name}"

  ref = details.fetch("ref")
  version = version_class.new(ref).to_s if version_class.correct?(ref)
  Dependency.new(
    name: name,
    version: version,
    requirements: [{
      requirement: nil,
      groups: [],
      source: {
        type: "git",
        url: url,
        ref: ref,
        branch: nil
      },
      file: file.name,
      metadata: { declaration_string: string }
    }],
    package_manager: "github_actions"
  )
end
check_required_files() click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 130
def check_required_files
  # Just check if there are any files at all.
  return if dependency_files.any?

  raise "No workflow files!"
end
deep_fetch_uses(json_obj) click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 81
def deep_fetch_uses(json_obj)
  case json_obj
  when Hash then deep_fetch_uses_from_hash(json_obj)
  when Array then json_obj.flat_map { |o| deep_fetch_uses(o) }
  else []
  end
end
deep_fetch_uses_from_hash(json_object) click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 108
def deep_fetch_uses_from_hash(json_object)
  steps = json_object.fetch("steps", [])

  uses_strings =
    if steps.is_a?(Array) && steps.all? { |s| s.is_a?(Hash) }
      steps.
        map { |step| step.fetch("uses", nil) }.
        select { |use| use.is_a?(String) }
    else
      []
    end

  uses_strings +
    json_object.values.flat_map { |obj| deep_fetch_uses(obj) }
end
resolve_git_tags(dependency_set) click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 89
def resolve_git_tags(dependency_set)
  # Find deps that do not have an assigned (semver) version, but pin a commit that references a semver tag
  resolved = dependency_set.dependencies.map do |dep|
    next unless dep.version.nil?

    git_checker = Dependabot::GitCommitChecker.new(dependency: dep, credentials: credentials)
    next unless git_checker.pinned_ref_looks_like_commit_sha?

    resolved = git_checker.local_tag_for_pinned_version
    next if resolved.nil? || !version_class.correct?(resolved)

    # Build a Dependency with the resolved version, and rely on DependencySet's merge
    Dependency.new(name: dep.name, version: version_class.new(resolved).to_s,
                   package_manager: dep.package_manager, requirements: [])
  end

  resolved.compact.each { |dep| dependency_set << dep }
end
version_class() click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 137
def version_class
  GithubActions::Version
end
workfile_file_dependencies(file) click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 39
def workfile_file_dependencies(file)
  dependency_set = DependencySet.new

  json = YAML.safe_load(file.content, aliases: true)
  uses_strings = deep_fetch_uses(json).uniq

  uses_strings.each do |string|
    # TODO: Support Docker references and path references
    dependency_set << build_github_dependency(file, string) if string.match?(GITHUB_REPO_REFERENCE)
  end

  dependency_set
rescue Psych::SyntaxError, Psych::DisallowedClass, Psych::BadAlias
  raise Dependabot::DependencyFileNotParseable, file.path
end
workflow_files() click to toggle source
# File lib/dependabot/github_actions/file_parser.rb, line 124
def workflow_files
  # The file fetcher only fetches workflow files, so no need to
  # filter here
  dependency_files
end