pray-cli 1.12.1 → 1.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 58da4ada7990f04bc2acf64b33bca633828a586f0918e1e3ff00cc50ddaeb7c5
4
- data.tar.gz: ffc0855f9f9dc6466fe1260905b23d9ab74a5d96905562f8307f472dde851849
3
+ metadata.gz: cc753f65405f7052d882da07b3293b66c69e60cb26b8fe865919000323f2da1a
4
+ data.tar.gz: 91586f374cc5a677b0f5d2b722a4ba5da5912d8bd3664eac0ccd48b864889c65
5
5
  SHA512:
6
- metadata.gz: 20cab97de54d753c4f7191f6a68469bbc7f4801e16999e7ca8ee13c0e1c5c27e53b8e0c436695a6f457cb169e7f4389d41407f9e56752cf7fed33c329b5fa94b
7
- data.tar.gz: 109496e4410f4bc43f63af51a73ec3439f87348a5c1e94dbed712799416d8e47286360f97bb50e37aaad096f8c0957fc3e2a9a26840167fefe7ea1d6dbb66abd
6
+ metadata.gz: a84c2945dba3386f31dfdfc08d603ecee88d2be1e9898c20a993cd9dba9149ae4966b9cf9e02ba8c28905b7a1c81e2f5158bdf2eff8b36fe7f470e0bbd82ab6a
7
+ data.tar.gz: 48f107b5721d69c62b83db0f99247f9c4821eea42f85d3459cac09b7441badc3fa092965f877b1d3ae3fb0d38f391e8f65ae76cc21a6fd1595799dd2de0c6324
data/CHANGELOG.md CHANGED
@@ -1,6 +1,15 @@
1
1
  # CHANGELOG
2
2
 
3
- ## Unreleased
3
+ ## 1.14.0 (2026-09-14)
4
+
5
+ - Keep an unchanged package version's artifact, first-publish time, and yank when `pray publish` runs again (RFC 0061).
6
+ - Write `published_at` as UTC Unix seconds in registry and federation JSON.
7
+ - Collapse trailing blank lines when composing so a composed file ends with a single newline, matching the other CLIs.
8
+ - Order `symbols` before `render` in the canonical manifest JSON so `manifest_hash` matches the other CLIs.
9
+
10
+ ## 1.13.0 (2026-09-08)
11
+
12
+ - Record and verify package upstream pins in `.prayspec` and `Prayfile.lock`. Refuse path-fork updates until this CLI can refresh the path tree safely (RFC 0114).
4
13
 
5
14
  ## 1.12.1 (2026-09-08)
6
15
 
@@ -100,6 +100,8 @@ module Pray
100
100
  raise Error.manifest("package #{package} not found")
101
101
  end
102
102
  end
103
+ current = resolve_current_project(ResolveOptions.new(offline: offline))
104
+ Upstream.ensure_update_supported!(current.packages, package)
103
105
  install_command({locked: false, frozen: false, offline: offline, refresh: true})
104
106
  end
105
107
 
data/lib/pray/lockfile.rb CHANGED
@@ -8,14 +8,15 @@ module Pray
8
8
  LockSource = Struct.new(:name, :kind, :url, :revision, :host_key_fingerprint)
9
9
  LockedPackage = Struct.new(
10
10
  :name, :version, :source, :path, :tree_hash, :artifact_hash, :artifact,
11
- :exports, :dependencies, :signer_fingerprint
11
+ :exports, :dependencies, :signer_fingerprint, :upstream
12
12
  ) do
13
- def initialize(exports: [], dependencies: [], signer_fingerprint: nil, source: nil, **kwargs)
14
- super(**kwargs, exports: exports, dependencies: dependencies, signer_fingerprint: signer_fingerprint, source: source)
13
+ def initialize(exports: [], dependencies: [], signer_fingerprint: nil, source: nil, upstream: nil, **kwargs)
14
+ super(**kwargs, exports: exports, dependencies: dependencies, signer_fingerprint: signer_fingerprint, source: source, upstream: upstream)
15
15
  end
16
16
  end
17
17
 
18
18
  LockedTarget = Struct.new(:name, :outputs)
19
+ LockedUpstream = Struct.new(:name, :version, :source, :tree_hash, :artifact_hash, keyword_init: true)
19
20
  ManagedSpanRecord = Struct.new(
20
21
  :id, :target, :open_line, :close_line, :ideal_checksum, :package, :export,
21
22
  :source_checksum, :silenced
@@ -98,6 +99,7 @@ module Pray
98
99
  }
99
100
  hash["source"] = entry.source unless entry.source.nil?
100
101
  hash["signer_fingerprint"] = entry.signer_fingerprint if entry.signer_fingerprint
102
+ hash["upstream"] = Upstream.to_lock_hash(entry.upstream) if entry.upstream
101
103
  hash
102
104
  end
103
105
 
@@ -185,7 +187,8 @@ module Pray
185
187
  artifact: normalize_lockfile_artifact(project_root, package.artifact, package.root),
186
188
  exports: package.selected_exports,
187
189
  dependencies: package.spec.dependencies.map(&:name),
188
- signer_fingerprint: package.signer_fingerprint
190
+ signer_fingerprint: package.signer_fingerprint,
191
+ upstream: package.upstream
189
192
  )
190
193
  end,
191
194
  target: manifest_targets.map { |target| LockedTarget.new(name: target.name, outputs: target.outputs) },
@@ -224,7 +227,8 @@ module Pray
224
227
  artifact: entry["artifact"],
225
228
  exports: entry["exports"] || [],
226
229
  dependencies: entry["dependencies"] || [],
227
- signer_fingerprint: entry["signer_fingerprint"]
230
+ signer_fingerprint: entry["signer_fingerprint"],
231
+ upstream: Upstream.from_lock_hash(entry["upstream"])
228
232
  )
229
233
  end,
230
234
  target: Array(data["target"]).map { |entry| LockedTarget.new(name: entry["name"], outputs: entry["outputs"] || []) },
@@ -66,6 +66,25 @@ module Pray
66
66
  lines << "exports = #{format_string_array(entry.exports)}"
67
67
  lines << "dependencies = #{format_string_array(entry.dependencies)}"
68
68
  lines << "signer_fingerprint = #{format_string(entry.signer_fingerprint)}" if entry.signer_fingerprint
69
+ if entry.upstream
70
+ lines << ""
71
+ lines << "[package.upstream]"
72
+ append_scalars(
73
+ lines,
74
+ [
75
+ ["name", entry.upstream.name],
76
+ ["version", entry.upstream.version]
77
+ ].tap do |scalars|
78
+ scalars << ["source", entry.upstream.source] unless entry.upstream.source.nil?
79
+ scalars.concat(
80
+ [
81
+ ["tree_hash", entry.upstream.tree_hash],
82
+ ["artifact_hash", entry.upstream.artifact_hash]
83
+ ]
84
+ )
85
+ end
86
+ )
87
+ end
69
88
  lines
70
89
  end
71
90
 
@@ -14,10 +14,10 @@ module Pray
14
14
  "sources" => manifest.sources.map { |source| source_fields(source) },
15
15
  "targets" => manifest.targets.map { |target| target_fields(target) },
16
16
  "packages" => manifest.packages.map { |package| package_fields(package) },
17
- "local" => manifest.local.map { |entry| local_fields(entry) },
18
- "render" => render_fields(manifest.render)
17
+ "local" => manifest.local.map { |entry| local_fields(entry) }
19
18
  }
20
19
  fields["symbols"] = manifest.symbols.sort.to_h unless manifest.symbols.empty?
20
+ fields["render"] = render_fields(manifest.render)
21
21
  fields
22
22
  end
23
23
 
@@ -9,17 +9,18 @@ module Pray
9
9
  PackageSkill = Struct.new(:path, :summary)
10
10
  PackageTemplate = Struct.new(:path, :summary)
11
11
  PackageDependency = Struct.new(:name, :constraint, :optional)
12
+ PackageUpstream = Struct.new(:name, :constraint, keyword_init: true)
12
13
 
13
14
  PackageSpec = Struct.new(
14
15
  :name, :version, :summary, :description, :authors, :license, :homepage,
15
16
  :source_code_uri, :changelog_uri, :prayfile_version, :files, :exports,
16
- :skills, :templates, :adapters, :targets, :dependencies, :metadata
17
+ :skills, :templates, :adapters, :targets, :dependencies, :metadata, :upstream
17
18
  ) do
18
19
  def initialize(
19
20
  name: "", version: "", summary: nil, description: nil, authors: [], license: nil,
20
21
  homepage: nil, source_code_uri: nil, changelog_uri: nil, prayfile_version: nil,
21
22
  files: [], exports: {}, skills: {}, templates: {}, adapters: {}, targets: [],
22
- dependencies: [], metadata: {}
23
+ dependencies: [], metadata: {}, upstream: nil
23
24
  )
24
25
  super
25
26
  end
@@ -90,6 +91,13 @@ module Pray
90
91
  )
91
92
  end
92
93
 
94
+ def parse_upstream(rest)
95
+ values, _keywords = parse_call(rest)
96
+ name = string_from_value(values.first)
97
+ constraint = values[1] ? string_from_value(values[1]) : "*"
98
+ PackageUpstream.new(name: name, constraint: constraint)
99
+ end
100
+
93
101
  def parse_exports(value)
94
102
  map = Literal.parse_literal_map(value)
95
103
  exports = {}
@@ -208,6 +216,10 @@ module Pray
208
216
  spec.dependencies << parse_dependency(Regexp.last_match(1), false)
209
217
  when /\Aspec\.add_optional_dependency (.+)\z/
210
218
  spec.dependencies << parse_dependency(Regexp.last_match(1), true)
219
+ when /\Aspec\.upstream (.+)\z/
220
+ raise Error.parse("prayspec", "upstream may only be declared once") if spec.upstream
221
+
222
+ spec.upstream = parse_upstream(Regexp.last_match(1))
211
223
  when /\Aspec\.(.+) = (.+)\z/
212
224
  apply_assignment(spec, Regexp.last_match(1).strip, Regexp.last_match(2).strip)
213
225
  else
data/lib/pray/publish.rb CHANGED
@@ -20,13 +20,21 @@ module Pray
20
20
  package_names = index.packages.to_set
21
21
 
22
22
  project.packages.each do |package|
23
- archive_bytes = Archive.build_package_archive_bytes(package)
24
23
  artifact_path = registry_artifact_path(package.declaration.name, package.spec.version)
25
- artifact_output_path = File.join(root, artifact_path)
26
- write_output_bytes(artifact_output_path, archive_bytes)
27
-
28
24
  metadata_path = registry_metadata_path(root, package.declaration.name)
29
25
  metadata = load_registry_package_metadata(metadata_path, package.declaration.name)
26
+ existing = metadata.versions.find { |entry| entry.version == package.spec.version }
27
+ stored_artifact = stored_package_artifact(root, artifact_path, package, existing)
28
+ if stored_artifact && stored_publish_matches?(
29
+ stored_artifact, package, signer, signer_fingerprint, existing
30
+ )
31
+ package_names << package.declaration.name
32
+ write_registry_package_metadata(metadata_path, metadata)
33
+ next
34
+ end
35
+
36
+ archive_bytes = Archive.build_package_archive_bytes(package)
37
+ write_output_bytes(File.join(root, artifact_path), archive_bytes)
30
38
  version_entry = published_registry_package_version(
31
39
  package,
32
40
  signer,
@@ -34,6 +42,7 @@ module Pray
34
42
  archive_bytes,
35
43
  artifact_path
36
44
  )
45
+ preserve_existing_publish_metadata(metadata, version_entry, stored_artifact)
37
46
  metadata.versions.reject! { |entry| entry.version == version_entry.version }
38
47
  metadata.versions << version_entry
39
48
  write_registry_package_metadata(metadata_path, metadata)
@@ -81,11 +90,50 @@ module Pray
81
90
  exports: package.spec.exports.keys,
82
91
  signer: signer,
83
92
  signer_fingerprint: signer_fingerprint,
84
- published_at: Time.now.utc.iso8601,
93
+ published_at: Time.now.to_i,
85
94
  signature: Registry.registry_artifact_signature(archive_bytes, package.tree_hash, signer)
86
95
  )
87
96
  end
88
97
 
98
+ def stored_package_artifact(root, artifact_path, package, existing)
99
+ return unless existing&.artifact == artifact_path && existing.tree_hash == package.tree_hash
100
+
101
+ stored_path = File.join(root, artifact_path)
102
+ return unless File.file?(stored_path)
103
+
104
+ artifact_bytes = File.binread(stored_path)
105
+ return unless existing.artifact_hash == Hashing.sha256_prefixed(artifact_bytes)
106
+ return unless stored_prayspec_matches?(artifact_bytes, package.root)
107
+
108
+ artifact_bytes
109
+ end
110
+
111
+ def stored_publish_matches?(artifact_bytes, package, signer, signer_fingerprint, existing)
112
+ existing.signer == signer &&
113
+ existing.signer_fingerprint == signer_fingerprint &&
114
+ existing.signature == Registry.registry_artifact_signature(artifact_bytes, package.tree_hash, signer)
115
+ end
116
+
117
+ def stored_prayspec_matches?(artifact_bytes, package_root)
118
+ Dir.mktmpdir("pray-publish-check-") do |directory|
119
+ Archive.unpack_praypkg(artifact_bytes, directory)
120
+ stored_path = Resolve.find_prayspec_file(directory)
121
+ current_path = Resolve.find_prayspec_file(package_root)
122
+ File.basename(stored_path) == File.basename(current_path) &&
123
+ File.binread(stored_path) == File.binread(current_path)
124
+ end
125
+ rescue Error, SystemCallError
126
+ false
127
+ end
128
+
129
+ def preserve_existing_publish_metadata(metadata, version_entry, stored_artifact)
130
+ existing = metadata.versions.find { |entry| entry.version == version_entry.version }
131
+ return unless existing
132
+
133
+ version_entry.yanked = existing.yanked
134
+ version_entry.published_at = existing.published_at if stored_artifact
135
+ end
136
+
89
137
  def load_registry_index(root)
90
138
  path = File.join(root, "v1", "index.json")
91
139
  return RegistryIndex.new unless File.exist?(path)
data/lib/pray/registry.rb CHANGED
@@ -5,6 +5,7 @@ require "net/http"
5
5
  require "uri"
6
6
  require "fileutils"
7
7
  require "pathname"
8
+ require "time"
8
9
  require_relative "path_safety"
9
10
  require_relative "http_body"
10
11
 
@@ -145,11 +146,26 @@ module Pray
145
146
  exports: entry["exports"] || [],
146
147
  signer: entry["signer"],
147
148
  signer_fingerprint: entry["signer_fingerprint"],
148
- published_at: entry["published_at"],
149
+ published_at: entry.key?("published_at") ? publish_timestamp_from_value(entry["published_at"]) : nil,
149
150
  signature: entry["signature"]
150
151
  )
151
152
  end
152
153
 
154
+ def publish_timestamp_from_value(value)
155
+ timestamp = case value
156
+ when Integer then value
157
+ when String
158
+ value.match?(/\A\d+\z/) ? value.to_i : Time.iso8601(value).to_i
159
+ end
160
+ unless timestamp&.between?(0, 253_402_300_799)
161
+ raise Error.integrity("registry published_at must be whole UTC Unix seconds")
162
+ end
163
+
164
+ timestamp
165
+ rescue ArgumentError
166
+ raise Error.integrity("registry published_at must be whole UTC Unix seconds")
167
+ end
168
+
153
169
  def select_package_version(metadata, constraint, preferred_version)
154
170
  if preferred_version
155
171
  version = metadata.versions.find { |entry| entry.version == preferred_version && !entry.yanked }
@@ -27,7 +27,7 @@ module Pray
27
27
  end
28
28
 
29
29
  def finish
30
- @content.sub(/\n\n+\z/, "\n")
30
+ @content.sub!(/\n\n+\z/, "\n")
31
31
  @content << "\n" unless @content.end_with?("\n")
32
32
  @content
33
33
  end
data/lib/pray/resolve.rb CHANGED
@@ -13,7 +13,7 @@ module Pray
13
13
  ResolvedPackage = Struct.new(
14
14
  :declaration, :root, :spec, :tree_hash, :artifact_hash, :artifact,
15
15
  :selected_exports, :source_checksum, :export_bodies, :skill_files,
16
- :signer_fingerprint, :registry_latest_version
16
+ :signer_fingerprint, :registry_latest_version, :upstream
17
17
  )
18
18
 
19
19
  ResolvedLocalFile = Struct.new(
@@ -75,7 +75,7 @@ module Pray
75
75
  user_config,
76
76
  declaration,
77
77
  lockfile_hints,
78
- offline: options.offline
78
+ options: options
79
79
  )
80
80
  if seen[package.declaration.name]
81
81
  raise Error.resolution("duplicate package declaration: #{package.declaration.name}")
@@ -149,9 +149,10 @@ module Pray
149
149
  "Create the file or remove the entry from Prayfile, then run `pray install`."
150
150
  end
151
151
 
152
- def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false)
152
+ def resolve_package(project_root, sources, git_sources, user_config, declaration, lockfile, offline: false, options: nil)
153
+ options ||= ResolveOptions.new(offline: offline)
153
154
  root, registry_latest_version = resolve_package_root_with_metadata(
154
- project_root, sources, git_sources, user_config, declaration, lockfile, offline: offline
155
+ project_root, sources, git_sources, user_config, declaration, lockfile, offline: options.offline
155
156
  )
156
157
  spec_path = find_prayspec_file(root)
157
158
  spec_text = File.read(spec_path)
@@ -185,7 +186,10 @@ module Pray
185
186
  export_bodies: export_bodies,
186
187
  skill_files: skill_files,
187
188
  signer_fingerprint: nil,
188
- registry_latest_version: registry_latest_version
189
+ registry_latest_version: registry_latest_version,
190
+ upstream: Upstream.lock_path(
191
+ project_root, sources, git_sources, user_config, declaration, spec, lockfile, options
192
+ )
189
193
  )
190
194
  end
191
195
 
@@ -34,7 +34,7 @@ module Pray
34
34
  )
35
35
  next if metadata.versions.empty?
36
36
 
37
- updated_at = metadata.versions.map { |version| version.published_at.to_s }.max || "0"
37
+ updated_at = (metadata.versions.filter_map(&:published_at).max || 0).to_s
38
38
  {
39
39
  "name" => name,
40
40
  "updated_at" => updated_at,
@@ -57,7 +57,7 @@ module Pray
57
57
  metadata = Publish.load_registry_package_metadata(metadata_path, name)
58
58
  body = {
59
59
  "name" => metadata.name,
60
- "updated_at" => metadata.versions.map { |version| version.published_at.to_s }.max || "0",
60
+ "updated_at" => (metadata.versions.filter_map(&:published_at).max || 0).to_s,
61
61
  "versions" => metadata.versions.map { |version| transport_version(version) }
62
62
  }
63
63
  Serve.ok_response("application/json", JSON.pretty_generate(body))
@@ -78,9 +78,9 @@ module Pray
78
78
  "tree_hash" => version.tree_hash.to_s,
79
79
  "yanked" => version.yanked,
80
80
  "targets" => version.targets,
81
- "exports" => version.exports,
82
- "published_at" => version.published_at.to_s
81
+ "exports" => version.exports
83
82
  }
83
+ hash["published_at"] = version.published_at if version.published_at
84
84
  if version.signer || version.signer_fingerprint
85
85
  hash["publisher"] = {
86
86
  "id" => version.signer.to_s,
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Pray
4
+ module Upstream
5
+ module_function
6
+
7
+ def ensure_update_supported!(packages, selected = nil)
8
+ unsupported = packages.find do |package|
9
+ package.declaration.path && package.spec.upstream &&
10
+ (selected.nil? || package.declaration.name == selected)
11
+ end
12
+ return unless unsupported
13
+
14
+ raise Error.unsupported(
15
+ "this installation cannot refresh upstream package #{unsupported.declaration.name}; " \
16
+ "install pray with Cargo and retry"
17
+ )
18
+ end
19
+
20
+ def to_lock_hash(entry)
21
+ hash = {
22
+ "name" => entry.name,
23
+ "version" => entry.version,
24
+ "tree_hash" => entry.tree_hash,
25
+ "artifact_hash" => entry.artifact_hash
26
+ }
27
+ hash["source"] = entry.source unless entry.source.nil?
28
+ hash
29
+ end
30
+
31
+ def from_lock_hash(entry)
32
+ return nil if entry.nil?
33
+
34
+ LockedUpstream.new(
35
+ name: entry["name"],
36
+ version: entry["version"],
37
+ source: entry["source"],
38
+ tree_hash: entry["tree_hash"],
39
+ artifact_hash: entry["artifact_hash"]
40
+ )
41
+ end
42
+
43
+ def lock_path(project_root, sources, git_sources, user_config, declaration, spec, lockfile, options)
44
+ return nil unless spec.upstream
45
+ if spec.name == spec.upstream.name
46
+ raise Error.resolution("package #{spec.name} cannot use itself as upstream")
47
+ end
48
+ return nil unless declaration.path
49
+
50
+ refresh = options.ignore_locked_versions || options.unlocked_packages.include?(declaration.name)
51
+ locked = lockfile&.package&.find { |entry| entry.name == declaration.name }&.upstream
52
+ name, constraint, source = resolution_input(declaration, spec, sources, locked, refresh)
53
+ resolved = Resolve.resolve_package(
54
+ project_root,
55
+ sources,
56
+ git_sources,
57
+ user_config,
58
+ ManifestPackage.new(
59
+ name: name,
60
+ constraint: constraint,
61
+ source: source
62
+ ),
63
+ lockfile,
64
+ options: options
65
+ )
66
+ resolved_upstream = LockedUpstream.new(
67
+ name: name,
68
+ version: resolved.spec.version,
69
+ source: source,
70
+ tree_hash: resolved.tree_hash,
71
+ artifact_hash: resolved.artifact_hash
72
+ )
73
+ ensure_locked_match!(locked, resolved_upstream) if !refresh && locked
74
+ resolved_upstream
75
+ end
76
+
77
+ def resolution_input(declaration, spec, sources, locked, refresh)
78
+ if locked && !refresh
79
+ if locked.name != spec.upstream.name
80
+ raise Error.integrity(
81
+ "locked upstream name mismatch for #{declaration.name}: " \
82
+ "expected #{locked.name}, found #{spec.upstream.name}"
83
+ )
84
+ end
85
+ return [locked.name, "= #{locked.version}", locked.source]
86
+ end
87
+
88
+ name = spec.upstream.name
89
+ source = ResolveSource.implied_source_name(ManifestPackage.new(name: name), sources)
90
+ [name, spec.upstream.constraint, source]
91
+ end
92
+
93
+ def ensure_locked_match!(locked, resolved)
94
+ if locked.name != resolved.name || locked.version != resolved.version
95
+ raise Error.integrity("locked upstream identity mismatch")
96
+ end
97
+ raise Error.integrity("locked upstream source mismatch") if locked.source != resolved.source
98
+ raise Error.integrity("locked upstream tree hash mismatch") if locked.tree_hash != resolved.tree_hash
99
+ if locked.artifact_hash != resolved.artifact_hash
100
+ raise Error.integrity("locked upstream artifact hash mismatch")
101
+ end
102
+ end
103
+ end
104
+ end
data/lib/pray/version.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Pray
4
- VERSION = "1.12.1"
5
- GENERATED_BY = "pray 1.12.1"
4
+ VERSION = "1.14.0"
5
+ GENERATED_BY = "pray 1.14.0"
6
6
  end
data/lib/pray.rb CHANGED
@@ -24,6 +24,7 @@ require_relative "pray/resolve_exports"
24
24
  require_relative "pray/invocation"
25
25
  require_relative "pray/git_refresh"
26
26
  require_relative "pray/resolve"
27
+ require_relative "pray/upstream"
27
28
  require_relative "pray/compose_dest"
28
29
  require_relative "pray/render_patch"
29
30
  require_relative "pray/render"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pray-cli
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.1
4
+ version: 1.14.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrei Makarov
@@ -180,6 +180,7 @@ files:
180
180
  - lib/pray/trust.rb
181
181
  - lib/pray/trust_feed.rb
182
182
  - lib/pray/trust_ops.rb
183
+ - lib/pray/upstream.rb
183
184
  - lib/pray/verify.rb
184
185
  - lib/pray/verify_position.rb
185
186
  - lib/pray/verify_provisioned.rb