sigstore 0.2.3 → 0.3.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.
@@ -15,6 +15,7 @@
15
15
  # limitations under the License.
16
16
 
17
17
  require_relative "trusted_root"
18
+ require_relative "policy"
18
19
  require_relative "internal/keyring"
19
20
  require_relative "internal/merkle"
20
21
  require_relative "internal/set"
@@ -54,20 +55,36 @@ module Sigstore
54
55
  for_trust_root(trust_root:)
55
56
  end
56
57
 
57
- def verify(input:, policy:, offline:)
58
+ # +key+ is an out-of-band public key (an OpenSSL::PKey) used to verify "managed"
59
+ # (bring-your-own-key) bundles, which carry a public key hint instead of a Fulcio
60
+ # certificate. It must be supplied for, and only for, such bundles.
61
+ def verify(input:, policy:, offline:, key: nil)
58
62
  # First, establish a time for the signature. This timestamp is required to validate the certificate chain,
59
63
  # so this step comes first.
60
64
 
61
65
  bundle = input.sbundle
62
66
  materials = bundle.verification_material
63
67
 
68
+ if bundle.key_based?
69
+ unless key
70
+ return VerificationFailure.new("bundle is signed with a managed key but no verifying key was provided")
71
+ end
72
+ elsif key
73
+ return VerificationFailure.new("a verifying key was provided but the bundle contains a signing certificate")
74
+ end
75
+
64
76
  # 1)
65
77
  # If the verification policy uses the Timestamping Service, the Verifier MUST verify the timestamping response
66
78
  # using the Timestamping Service root key material, as described in Spec: Timestamping Service, with the raw bytes
67
79
  # of the signature as the timestamped data. The Verifier MUST then extract a timestamp from the timestamping
68
80
  # response. If verification or timestamp parsing fails, the Verifier MUST abort.
69
81
 
70
- timestamps = extract_timestamp_from_verification_data(materials.timestamp_verification_data) || []
82
+ # Only resolve the data the timestamp binds to (and enforce its constraints) when
83
+ # there is a timestamp to verify; absent timestamp data there is nothing to bind.
84
+ timestamp_data = materials.timestamp_verification_data
85
+ timestamps = extract_timestamp_from_verification_data(
86
+ timestamp_data, timestamp_data && timestamped_data(bundle)
87
+ ) || []
71
88
 
72
89
  # 2)
73
90
  # If the verification policy uses timestamps from the Transparency Service, the Verifier MUST verify the signature
@@ -79,7 +96,7 @@ module Sigstore
79
96
  begin
80
97
  # TODO: should this instead be an input to the verify method?
81
98
  # See https://docs.google.com/document/d/1kbhK2qyPPk8SLavHzYSDM8-Ueul9_oxIMVFuWMWKz0E/edit?disco=AAABQVV-gT0
82
- entry = find_rekor_entry(bundle, input.hashed_input, offline:)
99
+ entry = find_rekor_entry(bundle, input.hashed_input, offline:, signing_key: key)
83
100
  rescue Sigstore::Error::MissingRekorEntry
84
101
  return VerificationFailure.new("Rekor entry not found")
85
102
  else
@@ -95,7 +112,16 @@ module Sigstore
95
112
 
96
113
  Internal::SET.verify_set(keyring: @rekor_keyring, entry:) if entry.inclusion_promise
97
114
 
98
- timestamps << Time.at(entry.integrated_time).utc
115
+ # Rekor v1 entries carry an integrated time signed by the log; Rekor v2 (tiled)
116
+ # entries do not, and rely on a Timestamping Service response for the signing time.
117
+ integrated_time = entry.integrated_time
118
+ timestamps << Time.at(integrated_time).utc if integrated_time&.positive?
119
+
120
+ if timestamps.empty?
121
+ return VerificationFailure.new(
122
+ "no trusted signing time available (no timestamp authority response and no log integrated time)"
123
+ )
124
+ end
99
125
 
100
126
  # 3)
101
127
  # The Verifier MUST perform certification path validation (RFC 5280 §6) of the certificate chain with the
@@ -104,44 +130,60 @@ module Sigstore
104
130
  # timestamp from the Timestamping Service. If a timestamp from the Transparency Service is available, the Verifier
105
131
  # MUST perform path validation using the timestamp from the Transparency Service. If both are available, the
106
132
  # Verifier performs path validation twice. If either fails, verification fails.
133
+ #
134
+ # Steps 3-5 are certificate-specific: a managed-key bundle has no certificate to do
135
+ # path validation, SCT verification, or identity-policy checks against, so they are
136
+ # skipped. The signature (and its binding to the Rekor entry) is still verified below
137
+ # against the supplied key.
107
138
 
108
- chains = timestamps.map do |ts|
109
- chain, err = Internal::X509.validate_chain(@fulcio_cert_chains, bundle.leaf_certificate, ts)
110
- return err if err
111
-
112
- chain
139
+ if bundle.key_based? && !policy.is_a?(Policy::UnsafeNoOp)
140
+ logger.warn do
141
+ "ignoring identity policy #{policy.class} for managed-key bundle: managed-key " \
142
+ "verification trusts the supplied key, not a certificate identity"
143
+ end
113
144
  end
114
145
 
115
- chains.uniq! { |chain| chain.map(&:to_der) }
116
- unless chains.size == 1
117
- raise "expected exactly one certificate chain, got #{chains.size} chains:\n" +
118
- chains.map do |chain|
119
- chain.map(&:to_text).join("\n")
120
- end.join("\n\n")
121
- end
146
+ unless bundle.key_based?
147
+ chains = timestamps.map do |ts|
148
+ chain, err = Internal::X509.validate_chain(@fulcio_cert_chains, bundle.leaf_certificate, ts)
149
+ return err if err
122
150
 
123
- # 4)
124
- # Unless performing online verification (see §Alternative Workflows), the Verifier MUST extract the
125
- # SignedCertificateTimestamp embedded in the leaf certificate, and verify it as in RFC 9162 §8.1.3,
126
- # using the verification key from the Certificate Transparency Log.
127
- chain = chains.first
128
- if (result = verify_scts(bundle.leaf_certificate, chain)) && !result.verified?
129
- return result
130
- end
151
+ chain
152
+ end
131
153
 
132
- # 5)
133
- # The Verifier MUST then check the certificate against the verification policy.
154
+ chains.uniq! { |chain| chain.map(&:to_der) }
155
+ unless chains.size == 1
156
+ raise "expected exactly one certificate chain, got #{chains.size} chains:\n" +
157
+ chains.map do |chain|
158
+ chain.map(&:to_text).join("\n")
159
+ end.join("\n\n")
160
+ end
134
161
 
135
- usage_ext = bundle.leaf_certificate.extension(Internal::X509::Extension::KeyUsage)
136
- return VerificationFailure.new("Key usage is not of type `digital signature`") unless usage_ext.digital_signature
162
+ # 4)
163
+ # Unless performing online verification (see §Alternative Workflows), the Verifier MUST extract the
164
+ # SignedCertificateTimestamp embedded in the leaf certificate, and verify it as in RFC 9162 §8.1.3,
165
+ # using the verification key from the Certificate Transparency Log.
166
+ chain = chains.first
167
+ if (result = verify_scts(bundle.leaf_certificate, chain)) && !result.verified?
168
+ return result
169
+ end
137
170
 
138
- extended_key_usage = bundle.leaf_certificate.extension(Internal::X509::Extension::ExtendedKeyUsage)
139
- unless extended_key_usage.code_signing?
140
- return VerificationFailure.new("Extended key usage is not of type `code signing`")
141
- end
171
+ # 5)
172
+ # The Verifier MUST then check the certificate against the verification policy.
173
+
174
+ usage_ext = bundle.leaf_certificate.extension(Internal::X509::Extension::KeyUsage)
175
+ unless usage_ext.digital_signature
176
+ return VerificationFailure.new("Key usage is not of type `digital signature`")
177
+ end
178
+
179
+ extended_key_usage = bundle.leaf_certificate.extension(Internal::X509::Extension::ExtendedKeyUsage)
180
+ unless extended_key_usage.code_signing?
181
+ return VerificationFailure.new("Extended key usage is not of type `code signing`")
182
+ end
142
183
 
143
- policy_check = policy.verify(bundle.leaf_certificate)
144
- return policy_check unless policy_check.verified?
184
+ policy_check = policy.verify(bundle.leaf_certificate)
185
+ return policy_check unless policy_check.verified?
186
+ end
145
187
 
146
188
  # 6)
147
189
  # By this point, the Verifier has already verified the signature by the Transparency Service (§Establishing a Time
@@ -156,10 +198,17 @@ module Sigstore
156
198
  # * The key or certificate from the parsed body is the same as in the input certificate.
157
199
  # * The “subject” of the parsed body matches the artifact.
158
200
 
159
- signing_key = bundle.leaf_certificate.public_key
201
+ signing_key = bundle.key_based? ? key : bundle.leaf_certificate.public_key
160
202
 
161
203
  case bundle.content
162
204
  when :message_signature
205
+ # The messageDigest is an unauthenticated hint, but when present it must be
206
+ # consistent with the artifact being verified.
207
+ message_digest = bundle.message_signature.message_digest
208
+ if message_digest && !message_digest.digest.empty? && message_digest.digest != input.hashed_input.digest
209
+ return VerificationFailure.new("message digest does not match the artifact")
210
+ end
211
+
163
212
  verified = verify_raw(signing_key, bundle.message_signature.signature, input.hashed_input.digest)
164
213
  return VerificationFailure.new("Signature verification failed") unless verified
165
214
  when :dsse_envelope
@@ -203,12 +252,9 @@ module Sigstore
203
252
  end
204
253
 
205
254
  def verify_dsse(dsse_envelope, public_key)
206
- payload = dsse_envelope.payload
207
- payload_type = dsse_envelope.payloadType
208
255
  signatures = dsse_envelope.signatures
209
256
 
210
- pae = "DSSEv1 #{payload_type.bytesize} #{payload_type} " \
211
- "#{payload.bytesize} #{payload}".b
257
+ pae = dsse_pae(dsse_envelope)
212
258
 
213
259
  raise Error::InvalidBundle, "DSSEv1 envelope missing signatures" if signatures.empty?
214
260
 
@@ -217,6 +263,10 @@ module Sigstore
217
263
  end
218
264
  end
219
265
 
266
+ def dsse_pae(dsse_envelope)
267
+ Internal::Util.dsse_pae(dsse_envelope.payloadType, dsse_envelope.payload)
268
+ end
269
+
220
270
  def verify_in_toto(input, in_toto_payload)
221
271
  type = in_toto_payload["_type"]
222
272
  raise Error::InvalidBundle, "Expected in-toto statement, got #{type.inspect}" unless type == "https://in-toto.io/Statement/v1"
@@ -349,7 +399,24 @@ module Sigstore
349
399
  issuer
350
400
  end
351
401
 
352
- def extract_timestamp_from_verification_data(data)
402
+ # The raw bytes a Timestamping Service response is expected to be computed over: the
403
+ # signature in the bundle (RFC 3161 message imprint covers these bytes).
404
+ def timestamped_data(bundle)
405
+ case bundle.content
406
+ when :message_signature
407
+ bundle.message_signature.signature
408
+ when :dsse_envelope
409
+ # The timestamp binds to a single signature; with more than one envelope
410
+ # signature it is ambiguous which one the imprint covers, so refuse to bind
411
+ # only the first (mirrors the v2 consistency path, which requires exactly one).
412
+ signatures = bundle.dsse_envelope.signatures
413
+ raise Error::InvalidBundle, "expected exactly one DSSE signature to bind a timestamp to" if signatures.size > 1
414
+
415
+ signatures.first&.sig
416
+ end
417
+ end
418
+
419
+ def extract_timestamp_from_verification_data(data, signed_data)
353
420
  # TODO: allow requiring a verified timestamp
354
421
  unless data
355
422
  logger.debug { "no timestamp verification data" }
@@ -365,6 +432,13 @@ module Sigstore
365
432
  return
366
433
  end
367
434
 
435
+ # The timestamp MUST be computed over the bundle signature (the RFC 3161 message
436
+ # imprint covers it). Without signature bytes to bind it to we cannot perform that
437
+ # binding, so fail closed rather than accept a timestamp over arbitrary data.
438
+ if signed_data.nil? || signed_data.empty?
439
+ raise Error::InvalidTimestamp, "no signature available to bind the timestamp to"
440
+ end
441
+
368
442
  authorities = @timestamp_authorities.map do |ta|
369
443
  store = OpenSSL::X509::Store.new
370
444
  chain = ta.cert_chain.certificates.map do |cert|
@@ -381,19 +455,37 @@ module Sigstore
381
455
  resp = OpenSSL::Timestamp::Response.new(ts.signed_timestamp)
382
456
 
383
457
  req = OpenSSL::Timestamp::Request.new
384
- req.cert_requested = !resp.token.certificates.empty?
385
- # TODO: verify the message imprint against the signature in the bundle
458
+ req.cert_requested = !(resp.token.certificates.nil? || resp.token.certificates.empty?)
386
459
  req.message_imprint = resp.token_info.message_imprint
387
460
  req.algorithm = resp.token_info.algorithm
388
- req.policy_id = resp.token_info.policy_id
389
- req.nonce = resp.token_info.nonce
461
+ req.policy_id = resp.token_info.policy_id if resp.token_info.policy_id
462
+ req.nonce = resp.token_info.nonce if resp.token_info.nonce
390
463
  req.version = resp.token_info.version
391
464
 
392
- # TODO: verify the hashed message in the message imprint
393
- # against the signature in the bundle
465
+ # The message imprint must cover the bundle's signature; otherwise the timestamp
466
+ # attests to unrelated data and must be rejected.
467
+ expected_imprint =
468
+ begin
469
+ OpenSSL::Digest.new(resp.token_info.algorithm).digest(signed_data)
470
+ rescue StandardError => e
471
+ raise Error::InvalidTimestamp,
472
+ "unsupported timestamp digest algorithm #{resp.token_info.algorithm.inspect}: #{e}"
473
+ end
474
+ unless resp.token_info.message_imprint == expected_imprint
475
+ raise Error::InvalidTimestamp, "timestamp message imprint does not match the bundle signature"
476
+ end
477
+
478
+ verified = authorities.any? do |ta, chain, store|
479
+ # The timestamp must fall within the window the trusted root says this
480
+ # Timestamping Service was valid for, independent of cert-chain validity.
481
+ gen_time = resp.token_info.gen_time
482
+ valid_for = ta.valid_for
483
+ if valid_for
484
+ next false if valid_for.start && gen_time < valid_for.start.to_time
485
+ next false if valid_for.end && gen_time > valid_for.end.to_time
486
+ end
394
487
 
395
- authorities.any? do |ta, chain, store|
396
- store.time = resp.token_info.gen_time
488
+ store.time = gen_time
397
489
 
398
490
  resp.verify(req, store, chain) &&
399
491
  (logger.debug do
@@ -402,13 +494,14 @@ module Sigstore
402
494
  rescue OpenSSL::Timestamp::TimestampError => e
403
495
  logger.error { "timestamp verification failed (#{e})" }
404
496
  false
405
- end ||
406
- raise(OpenSSL::Timestamp::TimestampError, "timestamp verification failed")
497
+ end
498
+ raise Error::InvalidTimestamp, "timestamp verification failed" unless verified
499
+
407
500
  resp.token_info.gen_time
408
501
  end
409
502
  end
410
503
 
411
- def find_rekor_entry(bundle, hashed_input, offline:)
504
+ def find_rekor_entry(bundle, hashed_input, offline:, signing_key: nil)
412
505
  raise Error::InvalidBundle, "multiple tlog entries" if bundle.verification_material.tlog_entries.size > 1
413
506
 
414
507
  rekor_entry = bundle.verification_material.tlog_entries&.first
@@ -420,7 +513,25 @@ module Sigstore
420
513
  "has_inclusion_promise=#{has_inclusion_promise} has_inclusion_proof=#{has_inclusion_proof}"
421
514
  end
422
515
 
423
- expected_entry = bundle.expected_tlog_entry(hashed_input)
516
+ # Rekor v2 (tiled) entries always ship an inclusion proof in the bundle and have no
517
+ # online retrieval API; detect them from the embedded entry and verify consistency
518
+ # against the bundle directly, rather than reconstructing a v1 canonicalized body.
519
+ if rekor_entry && (v2_body = rekor_v2_body(rekor_entry))
520
+ # A v2 entry has no integrated time and no online retrieval API, so the only
521
+ # binding to the log is the Merkle inclusion proof and its checkpoint signature.
522
+ # Require them here so the v2 path can never reach the offline warn-and-skip
523
+ # branch in #verify (even though #validate_version! also enforces this for
524
+ # non-0.1 bundles): without a checkpoint there is nothing to verify against.
525
+ unless rekor_entry.inclusion_proof&.checkpoint
526
+ raise Error::InvalidBundle, "Rekor v2 entry must contain an inclusion proof with a checkpoint"
527
+ end
528
+
529
+ verify_rekor_v2_entry_consistency(bundle, hashed_input, v2_body, signing_key:)
530
+ return rekor_entry
531
+ end
532
+
533
+ verifier_pem = signing_key&.public_to_pem || bundle.leaf_certificate&.to_pem
534
+ expected_entry = bundle.expected_tlog_entry(hashed_input, verifier_pem)
424
535
 
425
536
  entry = if offline
426
537
  logger.debug { "Offline verification, skipping rekor" }
@@ -437,11 +548,7 @@ module Sigstore
437
548
 
438
549
  logger.debug { "Found rekor entry: #{entry}" }
439
550
 
440
- actual_body = begin
441
- JSON.parse(entry.canonicalized_body)
442
- rescue JSON::ParserError
443
- raise Error::InvalidRekorEntry, "invalid JSON in rekor entry canonicalized_body"
444
- end
551
+ actual_body = parse_canonicalized_body(entry)
445
552
  if bundle.dsse_envelope?
446
553
  # since the hash is over the uncanonicalized envelope, we need to remove it
447
554
  #
@@ -471,6 +578,96 @@ module Sigstore
471
578
  entry
472
579
  end
473
580
 
581
+ # Parsed canonicalized body if this is a Rekor v2 (hashedrekord 0.0.2) entry, else nil.
582
+ # A body that is not JSON returns nil so the v1 reconstruction path handles it.
583
+ def rekor_v2_body(entry)
584
+ body = parse_canonicalized_body(entry)
585
+ body if body.values_at("kind", "apiVersion") == ["hashedrekord", "0.0.2"]
586
+ rescue Error::InvalidRekorEntry
587
+ nil
588
+ end
589
+
590
+ def parse_canonicalized_body(entry)
591
+ JSON.parse(entry.canonicalized_body)
592
+ rescue JSON::ParserError
593
+ raise Error::InvalidRekorEntry, "invalid JSON in rekor entry canonicalized_body"
594
+ end
595
+
596
+ # Verify that a Rekor v2 hashedrekord (0.0.2) entry corresponds to the artifact,
597
+ # signature, and signing certificate in the bundle. The Merkle inclusion proof and
598
+ # checkpoint signature bind this body to the log; #find_rekor_entry has already
599
+ # confirmed both are present, and #verify performs that verification. Here we bind
600
+ # the body to the inputs we are verifying.
601
+ def verify_rekor_v2_entry_consistency(bundle, hashed_input, body, signing_key: nil)
602
+ spec = body.dig("spec", "hashedRekordV002")
603
+ raise Error::InvalidRekorEntry, "missing hashedRekordV002 spec" unless spec
604
+
605
+ logged_algorithm = spec.dig("data", "algorithm")
606
+ logged_digest = decode_base64_field(spec.dig("data", "digest"), "data.digest")
607
+ logged_signature = decode_base64_field(spec.dig("signature", "content"), "signature.content")
608
+
609
+ if bundle.key_based?
610
+ logged_key = decode_base64_field(
611
+ spec.dig("signature", "verifier", "publicKey", "rawBytes"),
612
+ "signature.verifier.publicKey.rawBytes"
613
+ )
614
+ unless logged_key == signing_key.public_to_der
615
+ raise Error::InvalidRekorEntry, "rekor entry public key does not match the supplied key"
616
+ end
617
+ else
618
+ logged_cert = decode_base64_field(
619
+ spec.dig("signature", "verifier", "x509Certificate", "rawBytes"),
620
+ "signature.verifier.x509Certificate.rawBytes"
621
+ )
622
+ unless logged_cert == bundle.leaf_certificate.to_der
623
+ raise Error::InvalidRekorEntry, "rekor entry certificate does not match the bundle certificate"
624
+ end
625
+ end
626
+
627
+ expected_algorithm, expected_digest, expected_signature =
628
+ rekor_v2_expected_data_and_signature(bundle, hashed_input)
629
+
630
+ unless logged_algorithm == expected_algorithm
631
+ raise Error::InvalidRekorEntry,
632
+ "rekor entry data algorithm #{logged_algorithm.inspect} does not match " \
633
+ "expected #{expected_algorithm.inspect}"
634
+ end
635
+ unless logged_digest == expected_digest
636
+ raise Error::InvalidRekorEntry, "rekor entry data digest does not match the artifact"
637
+ end
638
+ return if logged_signature == expected_signature
639
+
640
+ raise Error::InvalidRekorEntry, "rekor entry signature does not match the bundle signature"
641
+ end
642
+
643
+ # The expected [data.algorithm, data.digest, signature] for the bundle, named to match
644
+ # the Rekor v2 `hashedRekordV002` spec fields (algorithm uses the proto enum name).
645
+ def rekor_v2_expected_data_and_signature(bundle, hashed_input)
646
+ case bundle.content
647
+ when :message_signature
648
+ [hashed_input.algorithm.name, hashed_input.digest, bundle.message_signature.signature]
649
+ when :dsse_envelope
650
+ # "hashedrekord-over-DSSE": the logged data is SHA2-256 of PAE(payloadType, payload)
651
+ # and the logged signature is the (single) DSSE envelope signature.
652
+ signatures = bundle.dsse_envelope.signatures
653
+ unless signatures.size == 1
654
+ raise Error::InvalidRekorEntry, "expected exactly one DSSE signature for a Rekor v2 entry"
655
+ end
656
+
657
+ ["SHA2_256", OpenSSL::Digest::SHA256.digest(dsse_pae(bundle.dsse_envelope)), signatures.first.sig]
658
+ else
659
+ raise Error::InvalidBundle, "expected either message_signature or dsse_envelope"
660
+ end
661
+ end
662
+
663
+ def decode_base64_field(value, name)
664
+ raise Error::InvalidRekorEntry, "missing #{name} in rekor entry" unless value
665
+
666
+ Internal::Util.base64_decode(value)
667
+ rescue ArgumentError
668
+ raise Error::InvalidRekorEntry, "invalid base64 in #{name} of rekor entry"
669
+ end
670
+
474
671
  def diff_json(a, b) # rubocop:disable Naming/MethodParameterName
475
672
  return nil if a == b
476
673
 
@@ -15,6 +15,6 @@
15
15
  # limitations under the License.
16
16
 
17
17
  module Sigstore
18
- VERSION = "0.2.3"
18
+ VERSION = "0.3.0"
19
19
  USER_AGENT = "sigstore-ruby/#{VERSION}".freeze
20
20
  end
data/lib/sigstore.rb CHANGED
@@ -43,5 +43,6 @@ module Sigstore
43
43
  end
44
44
  end
45
45
 
46
+ require_relative "sigstore/signing_config"
46
47
  require_relative "sigstore/verifier"
47
48
  require_relative "sigstore/signer"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sigstore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.3
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - The Sigstore Authors
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: exe
11
11
  cert_chain: []
12
- date: 2026-03-10 00:00:00.000000000 Z
12
+ date: 2026-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: logger
@@ -39,20 +39,34 @@ dependencies:
39
39
  - - ">="
40
40
  - !ruby/object:Gem::Version
41
41
  version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: protobug_in_toto_attestation_protos
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: 0.2.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: 0.2.0
42
56
  - !ruby/object:Gem::Dependency
43
57
  name: protobug_sigstore_protos
44
58
  requirement: !ruby/object:Gem::Requirement
45
59
  requirements:
46
60
  - - "~>"
47
61
  - !ruby/object:Gem::Version
48
- version: 0.1.0
62
+ version: 0.2.0
49
63
  type: :runtime
50
64
  prerelease: false
51
65
  version_requirements: !ruby/object:Gem::Requirement
52
66
  requirements:
53
67
  - - "~>"
54
68
  - !ruby/object:Gem::Version
55
- version: 0.1.0
69
+ version: 0.2.0
56
70
  - !ruby/object:Gem::Dependency
57
71
  name: uri
58
72
  requirement: !ruby/object:Gem::Requirement
@@ -98,6 +112,7 @@ files:
98
112
  - lib/sigstore/rekor/checkpoint.rb
99
113
  - lib/sigstore/rekor/client.rb
100
114
  - lib/sigstore/signer.rb
115
+ - lib/sigstore/signing_config.rb
101
116
  - lib/sigstore/trusted_root.rb
102
117
  - lib/sigstore/tuf.rb
103
118
  - lib/sigstore/tuf/config.rb