ruby_everywhere 0.12.0 → 0.13.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 +4 -4
- data/README.md +5 -3
- data/lib/everywhere/commands/build.rb +36 -6
- data/lib/everywhere/commands/release.rb +7 -3
- data/lib/everywhere/config/updates.rb +10 -0
- data/lib/everywhere/version.rb +1 -1
- data/support/desktop/src-tauri/src/updater.rs +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0afe4b448a6f964a0b013d31762aac332b71682717c04d25194271d9d1c92b67
|
|
4
|
+
data.tar.gz: '039d951d08c4d3be2d8a22c4de5a862d5dc1ca9635b978f989d4ba56807da148'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2656b49706209ee27c7aeb0410ea9ebff73ee833f58df43b9d51ceb2049b2e7540436b561e4a301fa89e6afb87c48056d1b0556598982cfaafb4367be55f8266
|
|
7
|
+
data.tar.gz: aca89fa867ba1aa8a1053e0d2324e358a02d9dd94e19129d984ca593e9598d3f031c91d95077b037fcb86a3a11d04535a0b70695f4eb3443ea7548f825617d83
|
data/README.md
CHANGED
|
@@ -324,11 +324,13 @@ the middle:
|
|
|
324
324
|
```sh
|
|
325
325
|
every updates keygen # once, per app
|
|
326
326
|
every release # build, sign, notarize, staple
|
|
327
|
-
every publish --notes-file NOTES.md # sign the
|
|
327
|
+
every publish --notes-file NOTES.md # sign the artifact, upload, flip latest.json
|
|
328
328
|
```
|
|
329
329
|
|
|
330
|
-
|
|
331
|
-
|
|
330
|
+
`every publish` signs the artifact and publishes that signature in the update
|
|
331
|
+
manifest, which the app checks the download against before installing. The
|
|
332
|
+
public key ships in the app; the secret key never leaves your machine. Apps can
|
|
333
|
+
check, install, and switch channels at runtime via `Everywhere.updates`.
|
|
332
334
|
|
|
333
335
|
## Hosted builds
|
|
334
336
|
|
|
@@ -41,6 +41,28 @@ module Everywhere
|
|
|
41
41
|
|
|
42
42
|
ANDROID_FORMATS = %w[apk aab].freeze
|
|
43
43
|
|
|
44
|
+
# Valid --channel per target os — the pairing the Platform accepts, minus
|
|
45
|
+
# nothing: macOS has no store channel (every macOS release signs with
|
|
46
|
+
# Developer ID and notarizes regardless), iOS `direct` exports an .ipa
|
|
47
|
+
# without the App Store Connect upload, and Android's `play` selects the
|
|
48
|
+
# .aab path even though the Play upload itself happens platform-side.
|
|
49
|
+
CHANNELS = {
|
|
50
|
+
"macos" => %w[direct],
|
|
51
|
+
"ios" => %w[direct testflight app_store],
|
|
52
|
+
"android" => %w[direct play]
|
|
53
|
+
}.freeze
|
|
54
|
+
|
|
55
|
+
# An os/channel pair nothing implements has to be refused before the
|
|
56
|
+
# build runs — it used to land in the receipt, where the only thing
|
|
57
|
+
# reading it (a store upload, a Platform distributor) has no idea what
|
|
58
|
+
# it means. Unknown os falls through: builder dispatch owns that error.
|
|
59
|
+
def self.check_channel!(os, channel)
|
|
60
|
+
allowed = CHANNELS[os] || return
|
|
61
|
+
return if allowed.include?(channel)
|
|
62
|
+
|
|
63
|
+
UI.die!("unsupported --channel #{channel} for #{os} — one of #{allowed.join(", ")}")
|
|
64
|
+
end
|
|
65
|
+
|
|
44
66
|
desc "Package the app natively — desktop (tebako press + shell + .app), iOS (--ios) or Android (--android)"
|
|
45
67
|
|
|
46
68
|
option :root, default: ".", desc: "App root directory"
|
|
@@ -52,7 +74,7 @@ module Everywhere
|
|
|
52
74
|
option :shell_dir, default: nil, desc: "Path to the shell's src-tauri directory"
|
|
53
75
|
option :template_dir, default: nil, desc: "Path to the mobile shell template (iOS/Android)"
|
|
54
76
|
option :format, default: nil, desc: "Android artifact format (#{ANDROID_FORMATS.join(" | ")}), default: apk"
|
|
55
|
-
option :channel, default: "direct", desc: "Distribution channel (
|
|
77
|
+
option :channel, default: "direct", desc: "Distribution channel (#{CHANNELS.map { |os, chs| "#{os}: #{chs.join("|")}" }.join(" · ")})"
|
|
56
78
|
option :ios, type: :boolean, default: false, desc: "Build the iOS shell (shorthand for --target #{IOS_TARGET})"
|
|
57
79
|
option :android, type: :boolean, default: false, desc: "Build the Android shell (shorthand for --target #{ANDROID_TARGET})"
|
|
58
80
|
option :device, type: :boolean, default: false, desc: "iOS: archive and export a device .ipa instead of a simulator .app"
|
|
@@ -62,6 +84,7 @@ module Everywhere
|
|
|
62
84
|
app_name: nil, target: nil, shell_dir: nil, template_dir: nil, format: nil,
|
|
63
85
|
channel: "direct", ios: false, android: false, device: false, skip_press: false, **)
|
|
64
86
|
target = resolve_target(target, ios: ios, android: android)
|
|
87
|
+
self.class.check_channel!(Everywhere::Config.os_of(target), channel)
|
|
65
88
|
root_path = File.expand_path(root)
|
|
66
89
|
config = Everywhere::Config.load(root_path)
|
|
67
90
|
|
|
@@ -70,11 +93,7 @@ module Everywhere
|
|
|
70
93
|
identity_errors = config.identity_errors
|
|
71
94
|
UI.die!("app: in config/everywhere.yml:\n#{identity_errors.join("\n")}") unless identity_errors.empty?
|
|
72
95
|
|
|
73
|
-
|
|
74
|
-
# feed URL can still be a message instead of a shipped app that never
|
|
75
|
-
# updates.
|
|
76
|
-
updates_errors = config.updates_errors
|
|
77
|
-
UI.die!("updates: in config/everywhere.yml:\n#{updates_errors.join("\n")}") unless updates_errors.empty?
|
|
96
|
+
check_updates!(config)
|
|
78
97
|
|
|
79
98
|
# Builder dispatch on the target's os (build-engine.md §5): macOS is
|
|
80
99
|
# the tebako+tauri path below; the mobile targets are Hotwire Native
|
|
@@ -150,6 +169,17 @@ module Everywhere
|
|
|
150
169
|
|
|
151
170
|
private
|
|
152
171
|
|
|
172
|
+
# The `updates:` section is baked into the shell during this build, so
|
|
173
|
+
# this is the last moment an unusable feed URL — or a missing signing key,
|
|
174
|
+
# which turns the updater off without failing anything — can still be a
|
|
175
|
+
# message instead of a shipped app that never updates. Once per build:
|
|
176
|
+
# every target stamps everywhere.json from the same config.
|
|
177
|
+
def check_updates!(config)
|
|
178
|
+
errors = config.updates_errors
|
|
179
|
+
UI.die!("updates: in config/everywhere.yml:\n#{errors.join("\n")}") unless errors.empty?
|
|
180
|
+
config.updates_warnings.each { |warning| UI.warn(warning) }
|
|
181
|
+
end
|
|
182
|
+
|
|
153
183
|
# `--ios` is the shorthand `every dev` already has; --target stays the
|
|
154
184
|
# general escape hatch. Both given is only an error when they disagree —
|
|
155
185
|
# `--ios --target ios-arm64` is redundant, not wrong.
|
|
@@ -33,7 +33,7 @@ module Everywhere
|
|
|
33
33
|
|
|
34
34
|
option :root, default: ".", desc: "App root directory"
|
|
35
35
|
option :target, default: Build::DEFAULT_TARGET, desc: "Build target (os-arch)"
|
|
36
|
-
option :channel, default: "direct", desc: "Distribution channel (
|
|
36
|
+
option :channel, default: "direct", desc: "Distribution channel (#{Build::CHANNELS.map { |os, chs| "#{os}: #{chs.join("|")}" }.join(" · ")})"
|
|
37
37
|
option :ruby, default: nil, desc: "Ruby version to package (default: build.ruby or 4.0.6)"
|
|
38
38
|
option :entry, default: "native_boot.rb", desc: "Entry point script relative to root"
|
|
39
39
|
option :app_name, default: nil, desc: "Bundle name (default from config)"
|
|
@@ -50,7 +50,7 @@ module Everywhere
|
|
|
50
50
|
ruby ||= config.build_ruby || "4.0.6"
|
|
51
51
|
os = Everywhere::Config.os_of(target)
|
|
52
52
|
|
|
53
|
-
preflight!(target, os)
|
|
53
|
+
preflight!(target, os, channel)
|
|
54
54
|
|
|
55
55
|
framework = config.remote? ? nil : Framework.detect(root_path)
|
|
56
56
|
dist_dir = File.expand_path("dist", root_path)
|
|
@@ -82,7 +82,7 @@ module Everywhere
|
|
|
82
82
|
|
|
83
83
|
private
|
|
84
84
|
|
|
85
|
-
def preflight!(target, os)
|
|
85
|
+
def preflight!(target, os, channel)
|
|
86
86
|
case os
|
|
87
87
|
when "macos"
|
|
88
88
|
UI.die!("`every release --target #{target}` runs on macOS only") unless Host.darwin?
|
|
@@ -94,6 +94,10 @@ module Everywhere
|
|
|
94
94
|
else
|
|
95
95
|
UI.die!("no release builder for #{target} — macos-*, ios-* and android-* are supported")
|
|
96
96
|
end
|
|
97
|
+
|
|
98
|
+
# After the os check: the channel table is keyed by os, so an unknown
|
|
99
|
+
# target has to die on the missing builder, not a nil channel list.
|
|
100
|
+
Build.check_channel!(os, channel)
|
|
97
101
|
end
|
|
98
102
|
|
|
99
103
|
|
|
@@ -44,6 +44,16 @@ module Everywhere
|
|
|
44
44
|
["updates.url #{url.inspect} is not a URL (#{e.message})"]
|
|
45
45
|
end
|
|
46
46
|
|
|
47
|
+
# Not an error — no `updates:` at all is a perfectly good app — but a feed
|
|
48
|
+
# URL without a key drops #updates_shell_hash to nil, so the app ships
|
|
49
|
+
# looking configured with the updater off.
|
|
50
|
+
def updates_warnings
|
|
51
|
+
return [] unless updates_url && updates_public_key.to_s.empty?
|
|
52
|
+
|
|
53
|
+
["updates.url is set but updates.public_key is missing — the updater will be disabled " \
|
|
54
|
+
"in this build; run `every updates keygen`"]
|
|
55
|
+
end
|
|
56
|
+
|
|
47
57
|
# The client subset for the shell; nil (and thus absent from
|
|
48
58
|
# everywhere.json) until both url and public_key are configured — an
|
|
49
59
|
# unsigned update feed is not a thing.
|
data/lib/everywhere/version.rb
CHANGED
|
@@ -480,7 +480,7 @@ fn verify_signature(path: &Path, signature: &str, public_key: &str) -> Result<()
|
|
|
480
480
|
let pk = minisign_verify::PublicKey::from_base64(public_key)
|
|
481
481
|
.map_err(|e| format!("bad updates.public_key: {e}"))?;
|
|
482
482
|
let sig = minisign_verify::Signature::decode(signature)
|
|
483
|
-
.map_err(|e| format!("
|
|
483
|
+
.map_err(|e| format!("unreadable artifact signature: {e}"))?;
|
|
484
484
|
let data = std::fs::read(path).map_err(|e| e.to_string())?;
|
|
485
485
|
pk.verify(&data, &sig, false)
|
|
486
486
|
.map_err(|_| "signature verification FAILED — artifact does not match the app's signing key".to_string())
|