Class: Sigstore::TUF::Updater

Inherits:
Object
  • Object
show all
Includes:
Loggable
Defined in:
lib/sigstore/tuf/updater.rb

Instance Method Summary collapse

Methods included from Loggable

included, #logger

Constructor Details

#initialize(metadata_dir:, metadata_base_url:, target_base_url:, target_dir:, fetcher:, config: UpdaterConfig.new) ⇒ Updater

Returns a new instance of Updater.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/sigstore/tuf/updater.rb', line 28

def initialize(metadata_dir:, metadata_base_url:, target_base_url:, target_dir:, fetcher:,
               config: UpdaterConfig.new)
  @dir = 
  @metadata_base_url = "#{.to_s.chomp("/")}/"
  @target_dir = target_dir
  @target_base_url = target_base_url && "#{target_base_url.to_s.chomp("/")}/"

  @fetcher = fetcher
  @config = config

  unless %i[metadata simple].include? @config.envelope_type
    raise ArgumentError, "Unsupported envelope type: #{@config[:envelope_type].inspect}"
  end

  data = ("root")
  @trusted_set = TrustedMetadataSet.new(data, "metadata", reference_time: Time.now)
end

Instance Method Details

#download_target(target_info, filepath = nil, target_base_url = nil) ⇒ Object

Raises:

  • (ArgumentError)


71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/sigstore/tuf/updater.rb', line 71

def download_target(target_info, filepath = nil, target_base_url = nil)
  target_base_url ||= @target_base_url
  raise ArgumentError, "No target_base_url set" unless target_base_url

  if (cached_target = find_cached_target(target_info, filepath))
    return cached_target
  end

  filepath ||= generate_target_file_path(target_info)

  target_filepath = target_info.path
  consistent_snapshot = @trusted_set.root.consistent_snapshot

  if consistent_snapshot && @config.prefix_targets_with_hash
    hashes = target_info.hashes.values
    dir, sep, basename = target_filepath.rpartition("/")
    target_filepath = "#{dir}#{sep}#{hashes.first}.#{basename}"
  end

  full_url = URI.join(target_base_url, target_filepath)
  begin
    resp_body = @fetcher.call(full_url)
    target_info.verify_length_and_hashes(resp_body)

    # TODO: atomic write
    File.binwrite(filepath, resp_body)
  rescue Error::Fetch => e
    raise Error::Fetch,
          "Failed to download target #{target_info.inspect} #{target_filepath.inspect} from #{e.response.uri}: " \
          "#{e.message}"
  end
  logger.info { "Downloaded #{target_filepath} to #{filepath}" }
  filepath
end

#find_cached_target(target_info, filepath = nil) ⇒ Object



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/sigstore/tuf/updater.rb', line 58

def find_cached_target(target_info, filepath = nil)
  filepath ||= generate_target_file_path(target_info)

  begin
    data = File.binread(filepath)
    target_info.verify_length_and_hashes(data)
    filepath
  rescue Errno::ENOENT, Error::LengthOrHashMismatch => e
    logger.debug { "No cached target at #{filepath}: #{e.class} #{e.message}" }
    nil
  end
end

#get_targetinfo(target_path) ⇒ Object



53
54
55
56
# File 'lib/sigstore/tuf/updater.rb', line 53

def get_targetinfo(target_path)
  refresh unless @trusted_set.include? Targets::TYPE
  preorder_depth_first_walk(target_path)
end

#refreshObject



46
47
48
49
50
51
# File 'lib/sigstore/tuf/updater.rb', line 46

def refresh
  load_root
  load_timestamp
  load_snapshot
  load_targets(Targets::TYPE, Root::TYPE)
end