tebako-release 0.2.1 → 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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 34b2e7ff86b5dcf3a3a56600ad664e32a7b2a7e114e234cc5b2a0f094ffe9010
4
- data.tar.gz: 866f3b422839db8d8dcee027cb840acadef89430e874e538946565939a7a954c
3
+ metadata.gz: da808fc0759260d4b29d60ffb1d51622cb07c3f8cf3125b4ea01025f1db4f927
4
+ data.tar.gz: 8d21389348ae2bb086aaf17f3901f386e62598be12bee027e653b76b361e8d1b
5
5
  SHA512:
6
- metadata.gz: 7a138c918d4387006dcf59e2b4771d0f39b3a49baffcf0c01505daacf08a608af24c1413195c123db112f764c5a8e25cf341188d5910f23ca4f909fd4ed7f5e7
7
- data.tar.gz: e9e9d4aae48992f997f6d2095ed7cedddfb1e37a27dd050117ae50b447d356b875df7aaa4ee36aa83e2de470e8939ed07860c57aa0211631802e27a39e285c22
6
+ metadata.gz: d73130a2cbd8d1de0df2bb1cf1d801bfe260db9b5569cc04e736eca3324d945576cf8ee9c13c22eb31000872e9229cfb5931c553a491e72188bf58d793206cba
7
+ data.tar.gz: c111f4d684714a0b03fbc92891b9e2f6640f8cc05369b77870e73bc04f34847367692c89cbaf06c48138fbf8d6172fe675c4124add72be2da7ba8c2bcd674915
data/README.md CHANGED
@@ -24,6 +24,14 @@ through a small adapter file and pin this gem — they never carry copies.
24
24
  yield identical bytes). A factory opts into the bundle-era publish shape
25
25
  through its adapter (`bundle_publish? → true`); the per-file shape stays
26
26
  the default for pre-bundle lines.
27
+ - **`TebakoRelease::Blksum`** — the spec 39 §3 block-group digest sidecar
28
+ (`<image>.blksum.json`: one sha256 per 4 MiB group of env-image bytes,
29
+ the lazy mount's range-GET trust anchor). The uploader derives it
30
+ in-process from the staged image at entry-build time — a pure function
31
+ of the served bytes, the same class as the `.sha256` sidecars — pins it
32
+ in the shard (`image.blksum {filename, sha256}`), and uploads it as a
33
+ standalone asset in both publish eras. The render is byte-exact with
34
+ `tpkg::lazy::Blksum::render`, golden-pinned in `spec/blksum_spec.rb`.
27
35
  - **`TebakoRelease::Platform`** — the release-side platform vocabulary
28
36
  (the `(os, arch) → host_id` table; mirrors `tpkg::Platform`, drift fails
29
37
  loudly in factory CI).
@@ -0,0 +1,98 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Copyright (c) 2026 [Ribose Inc](https://www.ribose.com).
4
+ # All rights reserved.
5
+ # This file is a part of tamatebako
6
+
7
+ require "digest"
8
+ require "json"
9
+ require "pathname"
10
+
11
+ module TebakoRelease
12
+ # The spec 39 §3 block-group digest sidecar (`<image>.blksum.json`): one
13
+ # sha256 per 4 MiB group of image bytes plus the whole-image sha256,
14
+ # authored by the PUBLISHER in-process (a resolver never derives one).
15
+ # For the factories the publisher invocation is `tebako-release upload`,
16
+ # so the derivation lives here — a pure function of the staged image
17
+ # bytes, the same derivable-metadata class as the `.sha256` sidecars.
18
+ #
19
+ # The render is byte-exact with tpkg::lazy::Blksum::render (the product's
20
+ # single owner of the grammar): compact machine JSON, keys in schema
21
+ # order, lowercase hex, no trailing newline. spec/blksum_spec.rb pins
22
+ # tpkg-minted golden vectors against this render — a drift fails the
23
+ # suite, never ships.
24
+ class Blksum
25
+ # The locked fetch unit (spec 39 §11.3): 4 MiB of image bytes; the
26
+ # final group is short. Tunable only by a measured product follow-up.
27
+ GROUP_SIZE = 4 * 1024 * 1024
28
+
29
+ # `schema_version` of the v1 document.
30
+ SCHEMA_VERSION = 1
31
+
32
+ # The served asset name is the image's name plus this suffix.
33
+ SIDECAR_SUFFIX = ".blksum.json"
34
+
35
+ # The sidecar asset name for an image name (or an image path).
36
+ def self.sidecar_name(image)
37
+ "#{Pathname.new(image).basename}#{SIDECAR_SUFFIX}"
38
+ end
39
+
40
+ def self.blksum_file?(path)
41
+ path.basename.to_s.end_with?(SIDECAR_SUFFIX)
42
+ end
43
+
44
+ # Derive the sidecar of a staged image: streams the file in GROUP_SIZE
45
+ # chunks (the runtime env images are 50–200 MB — never held whole),
46
+ # one sha256 per group plus the whole-image sha256. An absent or empty
47
+ # image is a named refusal (spec 39 §3: size_bytes >= 1).
48
+ def self.for_image(image_path)
49
+ path = Pathname.new(image_path)
50
+ assert_derivable!(path)
51
+ whole, groups = hash_stream(path)
52
+ new(size_bytes: path.size, sha256: whole.hexdigest, groups: groups)
53
+ end
54
+
55
+ def self.assert_derivable!(path)
56
+ raise Error, "the blksum sidecar cannot be derived: #{path} does not exist" unless path.file?
57
+ raise Error, "the blksum sidecar cannot be derived: #{path} is empty (size_bytes >= 1)" if path.empty?
58
+ end
59
+
60
+ def self.hash_stream(path)
61
+ whole = Digest::SHA256.new
62
+ groups = []
63
+ path.open("rb") do |io|
64
+ while (chunk = io.read(GROUP_SIZE))
65
+ whole.update(chunk)
66
+ groups << Digest::SHA256.hexdigest(chunk)
67
+ end
68
+ end
69
+ [whole, groups]
70
+ end
71
+
72
+ attr_reader :size_bytes, :sha256, :groups
73
+
74
+ def initialize(size_bytes:, sha256:, groups:)
75
+ @size_bytes = size_bytes
76
+ @sha256 = sha256
77
+ @groups = groups
78
+ end
79
+
80
+ # The machine JSON form (keys in schema order) — byte-exact with
81
+ # tpkg::lazy::Blksum::render, golden-pinned in spec/blksum_spec.rb.
82
+ def render
83
+ JSON.generate(
84
+ schema_version: SCHEMA_VERSION,
85
+ group_size: GROUP_SIZE,
86
+ size_bytes: size_bytes,
87
+ sha256: sha256,
88
+ groups: groups
89
+ )
90
+ end
91
+
92
+ # The sidecar document's own sha256 (the manifest's
93
+ # `image.blksum.sha256` pin — spec 39 §3).
94
+ def digest
95
+ Digest::SHA256.hexdigest(render)
96
+ end
97
+ end
98
+ end
@@ -442,7 +442,8 @@ module TebakoRelease
442
442
  contract = contract_sidecar(package)
443
443
  filename = package.basename.to_s
444
444
  sha256 = Digest::SHA256.file(package).hexdigest
445
- register_current_shas(package, image, dll, bundle)
445
+ blksum = derive_blksum(image) if image
446
+ register_current_shas(package, image, dll, bundle, blksum)
446
447
  {
447
448
  tebako_version: @version,
448
449
  contract_era: contract.fetch("contract_era"),
@@ -466,7 +467,7 @@ module TebakoRelease
466
467
  # selector axis. Sourced from the factory's adapter (the same truth
467
468
  # its boot smoke asserts), so manifest and smoke can never disagree.
468
469
  entry[:capabilities] = @config.adapter.capabilities(version: runtime_version, platform_id: platform)
469
- entry[:image] = image_entry(image) if image
470
+ entry[:image] = image_entry(image, blksum) if image
470
471
  entry[:dll] = dll_entry(dll, runtime_version, platform) if dll
471
472
  entry[:bundle] = bundle_entry(bundle) if bundle
472
473
  declare_signatures(entry)
@@ -486,12 +487,36 @@ module TebakoRelease
486
487
  end
487
488
 
488
489
  # The idempotent upload skip reads these (same name + same sha = kept):
489
- # the exe, its facets, and the bundle (spec 36's bundle-era asset).
490
- def register_current_shas(package, image, dll, bundle) # rubocop:disable Metrics/AbcSize
490
+ # the exe, its facets, the derived blksum sidecar (spec 39 §3), and the
491
+ # bundle (spec 36's bundle-era asset).
492
+ def register_current_shas(package, image, dll, bundle, blksum = nil) # rubocop:disable Metrics/AbcSize
491
493
  current_shas[package.basename.to_s] = Digest::SHA256.file(package).hexdigest
492
494
  current_shas[image_name_for(package)] = Digest::SHA256.file(image).hexdigest if image
493
495
  current_shas[dll_name_for(package)] = Digest::SHA256.file(dll).hexdigest if dll
494
496
  current_shas[bundle.basename.to_s] = Digest::SHA256.file(bundle).hexdigest if bundle
497
+ current_shas[Blksum.sidecar_name(image)] = blksum.digest if blksum
498
+ end
499
+
500
+ # The spec 39 §3 derivation: the publisher authors the block-group
501
+ # digest sidecar in-process from the staged image bytes (a pure
502
+ # function of them — the same derivable-metadata class as the .sha256
503
+ # sidecars), stages it BESIDE the image so the leg's attestation glob
504
+ # (runtime-packages/*) covers it, and the entry's `image.blksum` block
505
+ # pins the document's own sha256. support_file? keeps a staged sidecar
506
+ # from classifying as a package on a re-run validation.
507
+ def derive_blksum(image)
508
+ blksum = Blksum.for_image(image)
509
+ path = Pathname.new("#{image}#{Blksum::SIDECAR_SUFFIX}")
510
+ path.write(blksum.render)
511
+ staged_blksums[path.basename.to_s] = path
512
+ blksum
513
+ end
514
+
515
+ # The derived sidecar paths this invocation staged, keyed by asset
516
+ # name — the upload leg's source (entries are built before uploads in
517
+ # every publish shape, so a declared sidecar is always staged).
518
+ def staged_blksums
519
+ @staged_blksums ||= {}
495
520
  end
496
521
 
497
522
  # Spec 13 §2a / spec 09 §5: on signing-enabled lines every artifact the
@@ -573,12 +598,19 @@ module TebakoRelease
573
598
  end
574
599
 
575
600
  # The additive image metadata: name, sha256, size (consumers ignoring the
576
- # `image` key keep working; item 30's compat rule).
577
- def image_entry(image)
601
+ # `image` key keep working; item 30's compat rule) — plus the additive
602
+ # `blksum` pin (spec 39 §3: {filename, sha256} of the derived block-group
603
+ # digest sidecar; consumers that predate the key ignore it, and the
604
+ # loader's lazy arm falls back to eager loudly when it is absent).
605
+ def image_entry(image, blksum)
578
606
  {
579
607
  filename: image.basename.to_s,
580
608
  sha256: Digest::SHA256.file(image).hexdigest,
581
- size_bytes: image.size
609
+ size_bytes: image.size,
610
+ blksum: {
611
+ filename: Blksum.sidecar_name(image),
612
+ sha256: blksum.digest
613
+ }
582
614
  }
583
615
  end
584
616
 
@@ -805,6 +837,7 @@ module TebakoRelease
805
837
  bundles = build_bundles(packages)
806
838
  entries = build_manifest_entries(packages, bundles: bundles)
807
839
  bundles.each_value { |bundle| upload_package(release, bundle) }
840
+ upload_blksum_sidecars(release, entries)
808
841
  entries.each { |entry| ensure_package_metadata(release, entry) }
809
842
  print_settled_summary
810
843
  end
@@ -867,10 +900,32 @@ module TebakoRelease
867
900
  # the release notes are written once at creation.
868
901
  def publish_release(release, packages, entries)
869
902
  packages.each { |package| upload_package(release, package) }
903
+ upload_blksum_sidecars(release, entries)
870
904
  entries.each { |entry| ensure_package_metadata(release, entry) }
871
905
  print_settled_summary
872
906
  end
873
907
 
908
+ # The spec 39 §3 sidecars ride along in BOTH publish eras as STANDALONE
909
+ # assets — never bundle members: the lazy resolver fetches the sidecar
910
+ # with a plain GET against its own release-asset URL
911
+ # (`{dir_url}/{image.blksum.filename}`), in the bundle era too. Derived
912
+ # at entry-build time and staged beside the images; uploaded before the
913
+ # metadata so the shard that pins them never precedes them.
914
+ def upload_blksum_sidecars(release, entries)
915
+ entries.each do |entry|
916
+ name = entry.dig(:image, :blksum, :filename)
917
+ next unless name
918
+
919
+ path = staged_blksums[name]
920
+ unless path
921
+ raise Error, "the blksum sidecar #{name} was declared but never staged — " \
922
+ "the derivation runs at entry-build time; this is a machinery bug"
923
+ end
924
+
925
+ upload_package(release, path)
926
+ end
927
+ end
928
+
874
929
  # The package's metadata assets, byte-truthful for the SERVED bytes: a
875
930
  # settled package (the byte-immutable keep, or a wedged recovery
876
931
  # replace) publishes the PREVIOUS entry's shard and sidecars — the
@@ -888,13 +943,18 @@ module TebakoRelease
888
943
  # era: the exe, its .tfs image and its .dll facet. Bundle era (spec 36
889
944
  # §3): the bundle is the ONE served payload asset — the entry's
890
945
  # exe/image/dll fields are member pins, not served names, so they earn
891
- # no sidecar.
946
+ # no sidecar. Both eras: the derived blksum sidecar (spec 39 §3) IS a
947
+ # served standalone asset, so it earns its own .sha256 sidecar like
948
+ # every served name.
892
949
  def metadata_assets(entry)
893
- return { entry[:bundle][:filename] => entry[:bundle][:sha256] } if entry[:bundle]
894
-
895
- { entry[:filename] => entry[:sha256] }
896
- .merge(facet_metadata(entry, :image))
897
- .merge(facet_metadata(entry, :dll))
950
+ served = if entry[:bundle]
951
+ { entry[:bundle][:filename] => entry[:bundle][:sha256] }
952
+ else
953
+ { entry[:filename] => entry[:sha256] }
954
+ .merge(facet_metadata(entry, :image))
955
+ .merge(facet_metadata(entry, :dll))
956
+ end
957
+ served.merge(blksum_metadata(entry))
898
958
  end
899
959
 
900
960
  def facet_metadata(entry, facet)
@@ -902,6 +962,14 @@ module TebakoRelease
902
962
  block ? { block[:filename] => block[:sha256] } : {}
903
963
  end
904
964
 
965
+ # The blksum sidecar's name -> sha256 pair when the entry declares it
966
+ # (spec 39 §3's `image.blksum` pin); a pre-blksum previous entry
967
+ # declares nothing and earns nothing (byte-truthful metadata).
968
+ def blksum_metadata(entry)
969
+ block = entry.dig(:image, :blksum)
970
+ block ? { block[:filename] => block[:sha256] } : {}
971
+ end
972
+
905
973
  def shard_name_for(entry)
906
974
  "#{package_stem(entry[:filename])}#{SHARD_SUFFIX}"
907
975
  end
@@ -910,7 +978,8 @@ module TebakoRelease
910
978
  # with the previous entry's voice; a never-published settle has nothing
911
979
  # truthful to keep and never reaches here (upload_package re-raised).
912
980
  def effective_entry(entry)
913
- names = [entry[:filename], entry.dig(:image, :filename), entry.dig(:dll, :filename)].compact
981
+ names = [entry[:filename], entry.dig(:image, :filename), entry.dig(:dll, :filename),
982
+ entry.dig(:image, :blksum, :filename)].compact
914
983
  return entry unless names.any? { |name| settled?(name) }
915
984
 
916
985
  previous_entry_for(entry[:filename]) || entry
@@ -1095,7 +1164,9 @@ module TebakoRelease
1095
1164
 
1096
1165
  def missing_assets(release, packages, require_signatures: false)
1097
1166
  present = all_assets(release).map(&:name)
1098
- packages.flat_map { |name| missing_package_assets(present, name, require_signatures: require_signatures) }
1167
+ packages.flat_map do |name|
1168
+ missing_package_assets(release, present, name, require_signatures: require_signatures)
1169
+ end
1099
1170
  end
1100
1171
 
1101
1172
  # One expected package's gaps. Windows executables may or may not carry
@@ -1103,11 +1174,16 @@ module TebakoRelease
1103
1174
  # expectation matches both. Metadata expectations ride on what actually
1104
1175
  # landed — a package whose exe never landed reports its own name only,
1105
1176
  # never a cascade of secondary sidecar/shard gaps (one error per gap).
1106
- def missing_package_assets(present, name, require_signatures: false)
1107
- return missing_bundle_assets(present, name, require_signatures: require_signatures) if bundle_publish?
1177
+ # The blksum sidecar (spec 39 §3) is expected ONLY when the package's
1178
+ # shard declares the `image.blksum` pin — a pre-blksum release's audit
1179
+ # stays green (the additive-key compat rule), and a missing shard
1180
+ # reports its own gap only.
1181
+ def missing_package_assets(release, present, name, require_signatures: false)
1182
+ return missing_bundle_assets(release, present, name, require_signatures: require_signatures) if bundle_publish?
1108
1183
 
1109
1184
  exe = [name, "#{name}.exe"].find { |candidate| present.include?(candidate) }
1110
1185
  landed, missing = expected_facets(name).partition { |facet| present.include?(facet) }
1186
+ landed, missing = split_blksum_expectation(release, present, name, landed, missing)
1111
1187
  missing.unshift(name) unless exe
1112
1188
  return missing if exe.nil?
1113
1189
 
@@ -1116,12 +1192,49 @@ module TebakoRelease
1116
1192
 
1117
1193
  # Spec 36's completeness shape: the bundle is the leg's ONE payload
1118
1194
  # asset; a landed bundle owes its sidecar and the package's shard
1119
- # (plus an .asc of each on signing-enabled audits).
1120
- def missing_bundle_assets(present, name, require_signatures: false)
1195
+ # (plus an .asc of each on signing-enabled audits). The declared
1196
+ # blksum sidecar (spec 39 §3) is a standalone served asset in this
1197
+ # era too — expected, with its own metadata, when the shard pins it.
1198
+ def missing_bundle_assets(release, present, name, require_signatures: false)
1121
1199
  bundle = "#{name}#{Bundler::BUNDLE_SUFFIX}"
1122
1200
  return [bundle] unless present.include?(bundle)
1123
1201
 
1124
- missing_metadata(present, name, [bundle], require_signatures: require_signatures)
1202
+ landed, missing = split_blksum_expectation(release, present, name, [bundle], [])
1203
+ missing + missing_metadata(present, name, landed, require_signatures: require_signatures)
1204
+ end
1205
+
1206
+ # The shard-declared blksum expectation (spec 39 §3): the shard is the
1207
+ # declaration's only authority (the additive `image.blksum` key), so
1208
+ # the audit reads it. A shard that declares no pin expects nothing (a
1209
+ # pre-blksum release audits green); a shard that never landed already
1210
+ # reports its own gap, so it adds no secondary blksum gaps; an
1211
+ # unreadable shard warns and expects nothing (never a silent failure —
1212
+ # the shard's own gap is the gate's business). A DECLARED sidecar that
1213
+ # never landed reports its own name only — its sidecar/.asc cascade
1214
+ # rides the landed set, one error per gap.
1215
+ def split_blksum_expectation(release, present, name, landed, missing)
1216
+ declared = declared_blksum_name(release, present, name)
1217
+ return [landed, missing] unless declared
1218
+
1219
+ if present.include?(declared)
1220
+ [landed + [declared], missing]
1221
+ else
1222
+ [landed, missing + [declared]]
1223
+ end
1224
+ end
1225
+
1226
+ # The sidecar name the package's shard declares (`image.blksum`),
1227
+ # nil when undeclared, when the shard never landed, or when it cannot
1228
+ # be read (loudly — the audit never guesses an expectation).
1229
+ def declared_blksum_name(release, present, name)
1230
+ shard = "#{name}#{SHARD_SUFFIX}"
1231
+ return nil unless present.include?(shard)
1232
+
1233
+ download_asset_json(find_asset(release, shard)).dig("image", "blksum", "filename")
1234
+ rescue StandardError => e
1235
+ puts "::warning::could not read #{shard} for the blksum expectation (#{e.class}: #{e.message}) — " \
1236
+ "no blksum sidecar is expected of this package"
1237
+ nil
1125
1238
  end
1126
1239
 
1127
1240
  # The non-executable artifacts a package is expected to carry: the
@@ -1448,12 +1561,13 @@ module TebakoRelease
1448
1561
  end
1449
1562
 
1450
1563
  # The package stem an asset name belongs to: the exe (with or without
1451
- # .exe), its .tfs image, its .dll facet and its .tar.gz bundle (spec 36)
1452
- # share one stem — settling is package-scoped so a wedged exe also
1453
- # stands down its facets (a fresh facet over previous package bytes
1454
- # would be a mixed-version package).
1564
+ # .exe), its .tfs image, its .dll facet, the derived blksum sidecar
1565
+ # (spec 39 §3) and its .tar.gz bundle (spec 36) share one stem —
1566
+ # settling is package-scoped so a wedged exe also stands down its
1567
+ # facets (a fresh facet over previous package bytes would be a
1568
+ # mixed-version package). Longest suffix first.
1455
1569
  def package_stem(filename)
1456
- filename.sub(/\.tar\.gz\z/, "").sub(/\.(exe|tfs|dll)\z/, "")
1570
+ filename.sub(/\.tar\.gz\z/, "").sub(/\.tfs\.blksum\.json\z/, "").sub(/\.(exe|tfs|dll)\z/, "")
1457
1571
  end
1458
1572
 
1459
1573
  def settled?(filename)
@@ -1586,18 +1700,13 @@ module TebakoRelease
1586
1700
 
1587
1701
  # The sha256 the previous manifest records for this asset: the entry's
1588
1702
  # own sha for the executable, the image/dll facet block's sha for a
1589
- # facet (facets key under their package's entry), the bundle block's
1590
- # sha for the bundle (spec 36 — the bundle-era served asset).
1703
+ # facet (facets key under their package's entry), the image's blksum
1704
+ # pin for the derived sidecar (spec 39 §3), the bundle block's sha for
1705
+ # the bundle (spec 36 — the bundle-era served asset).
1591
1706
  def previous_sha_for(entry, filename)
1592
- if entry.dig(:image, :filename) == filename
1593
- entry.dig(:image, :sha256)
1594
- elsif entry.dig(:dll, :filename) == filename
1595
- entry.dig(:dll, :sha256)
1596
- elsif entry.dig(:bundle, :filename) == filename
1597
- entry.dig(:bundle, :sha256)
1598
- else
1599
- entry[:sha256]
1600
- end
1707
+ blocks = [entry.dig(:image, :blksum), entry[:image], entry[:dll], entry[:bundle]]
1708
+ block = blocks.find { |candidate| candidate && candidate[:filename] == filename }
1709
+ block ? block[:sha256] : entry[:sha256]
1601
1710
  end
1602
1711
 
1603
1712
  def validate_environment
@@ -1624,13 +1733,16 @@ module TebakoRelease
1624
1733
  end
1625
1734
 
1626
1735
  # `.abi` sidecars (the runtime's platform string), `.contract.yaml`
1627
- # sidecars (the era-2 release card provenance) and `.sha256` markers
1736
+ # sidecars (the era-2 release card provenance), `.sha256` markers
1628
1737
  # (the image's store-layout trust anchor, spec 22 §6 — the boot
1629
- # smoke's image-key input) are manifest inputs / build outputs read
1630
- # in place — never packages of their own.
1738
+ # smoke's image-key input) and `.blksum.json` sidecars (the spec 39 §3
1739
+ # derivation staged beside its image at entry-build time — still in
1740
+ # the directory when a re-run validates) are manifest inputs / build
1741
+ # outputs read in place — never packages of their own.
1631
1742
  def support_file?(path)
1632
1743
  path.extname == ".abi" || path.extname == ".sha256" ||
1633
- path.basename.to_s.end_with?(CONTRACT_SIDECAR_SUFFIX)
1744
+ path.basename.to_s.end_with?(CONTRACT_SIDECAR_SUFFIX) ||
1745
+ Blksum.blksum_file?(path)
1634
1746
  end
1635
1747
  end
1636
1748
  end
@@ -5,5 +5,5 @@
5
5
  # This file is a part of tamatebako
6
6
 
7
7
  module TebakoRelease
8
- VERSION = "0.2.1"
8
+ VERSION = "0.3.0"
9
9
  end
@@ -10,6 +10,7 @@ require_relative "tebako_release/adapter"
10
10
  require_relative "tebako_release/config"
11
11
  require_relative "tebako_release/platform"
12
12
  require_relative "tebako_release/bundler"
13
+ require_relative "tebako_release/blksum"
13
14
  require_relative "tebako_release/uploader"
14
15
  require_relative "tebako_release/signer"
15
16
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tebako-release
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc
@@ -39,6 +39,7 @@ files:
39
39
  - exe/tebako-release
40
40
  - lib/tebako_release.rb
41
41
  - lib/tebako_release/adapter.rb
42
+ - lib/tebako_release/blksum.rb
42
43
  - lib/tebako_release/bundler.rb
43
44
  - lib/tebako_release/config.rb
44
45
  - lib/tebako_release/error.rb