forked from mirrors/kingfisher
Improved Updater text. Cleaned up more rules and the examples included with them.
This commit is contained in:
parent
17acf2dccb
commit
37cdf1fb69
15 changed files with 180 additions and 66 deletions
|
|
@ -5,6 +5,8 @@ All notable changes to this project will be documented in this file.
|
|||
## [1.15.0]
|
||||
- Ensuring temp files are cleaned up
|
||||
- Applying visual style to the update check output
|
||||
- Fixed bug in --self-update where it was looking for the incorrect binary name on GitHub releases
|
||||
- Rule cleanup
|
||||
|
||||
## [1.14.0]
|
||||
- Fixed several malformed rules
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ publish = false
|
|||
|
||||
[package]
|
||||
name = "kingfisher"
|
||||
version = "1.14.0"
|
||||
version = "1.15.0"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
|||
|
|
@ -1,7 +1,13 @@
|
|||
rules:
|
||||
- name: Age Recipient (X25519 public key)
|
||||
id: kingfisher.age.1
|
||||
pattern: '\b(age1[0-9a-z]{58})\b'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
age1[0-9a-z]{58}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.3
|
||||
confidence: medium
|
||||
examples:
|
||||
|
|
@ -13,7 +19,13 @@ rules:
|
|||
|
||||
- name: Age Identity (X22519 secret key)
|
||||
id: kingfisher.age.2
|
||||
pattern: '\b(AGE-SECRET-KEY-1[0-9A-Z]{58})\b'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
AGE-SECRET-KEY-1[0-9A-Z]{58}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.3
|
||||
confidence: medium
|
||||
examples:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ rules:
|
|||
min_entropy: 3.3
|
||||
confidence: medium
|
||||
examples:
|
||||
- fileio SECRETKEY = Z9Y8X7W6V5U4T3S2R1Q0.P9O8N7M6L5K4J3H2G1F
|
||||
- fileio SECRETKEY = Z9Y8X7W6V5U4T3S2R1Q0.P9O8N7M6L5K4J3H2G1FV
|
||||
- fileio.PRIVATE.TOKEN = F0E1D2C3B4A596877869.5E4D3C2B1A0Z9Y8X7W6V
|
||||
- fileio_key = M8N6B4V2C0X9Z7L5K3J1.H2G4F6D8S0A9P7O5I3U1
|
||||
validation:
|
||||
|
|
|
|||
|
|
@ -88,7 +88,13 @@ rules:
|
|||
- '"login"'
|
||||
- name: GitHub App Token
|
||||
id: kingfisher.github.3
|
||||
pattern: '\b((?:ghu|ghs)_[A-Z0-9]{36})\b'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
(?:ghu|ghs)_[A-Z0-9]{36}
|
||||
)
|
||||
\b
|
||||
examples:
|
||||
- ' "token": "ghu_16C7e42F292c69C2E7C10c838347Ae178B4a",'
|
||||
- |
|
||||
|
|
@ -118,7 +124,13 @@ rules:
|
|||
- '"login"'
|
||||
- name: GitHub Refresh Token
|
||||
id: kingfisher.github.4
|
||||
pattern: '\b(ghr_[A-Z0-9]{76})\b'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
ghr_[A-Z0-9]{76}
|
||||
)
|
||||
\b
|
||||
examples:
|
||||
- ' "refresh_token": "ghr_1B4a2e77838347a7E420ce178F2E7c6912E169246c3CE1ccbF66C46812d16D5B1A9Dc86A1498",'
|
||||
references:
|
||||
|
|
|
|||
|
|
@ -36,7 +36,13 @@ rules:
|
|||
|
||||
- name: GitLab Runner Registration Token
|
||||
id: kingfisher.gitlab.2
|
||||
pattern: '\b(GR1348941[0-9A-Z_-]{20})(?:\b|$)'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
GR1348941[0-9A-Z_-]{20}
|
||||
)
|
||||
\b
|
||||
examples:
|
||||
- |
|
||||
sudo gitlab-runner register \
|
||||
|
|
@ -69,7 +75,13 @@ rules:
|
|||
|
||||
- name: GitLab Pipeline Trigger Token
|
||||
id: kingfisher.gitlab.3
|
||||
pattern: '\b(glptt-[0-9a-f]{40})\b'
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
glptt-[0-9a-f]{40}
|
||||
)
|
||||
\b
|
||||
examples:
|
||||
- |
|
||||
curl \
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ rules:
|
|||
- name: Google OAuth Client Secret
|
||||
id: kingfisher.google.2
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
\b
|
||||
(GOCSPX-[A-Z0-9_-]{28})
|
||||
(?:[^A-Z0-9_-] | $)
|
||||
|
|
@ -41,7 +41,7 @@ rules:
|
|||
- name: Google OAuth Access Token
|
||||
id: kingfisher.google.4
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
\b
|
||||
(ya29\.[0-9A-Z_-]{20,1024})
|
||||
(?: [^0-9A-Z_-]|$)
|
||||
|
|
@ -65,7 +65,7 @@ rules:
|
|||
- name: Google OAuth Credentials
|
||||
id: kingfisher.google.6
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
\b
|
||||
([0-9]+-[a-z0-9_]{32}\.apps\.googleusercontent\.com)
|
||||
(?:
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
rules:
|
||||
- name: Password Hash (md5crypt)
|
||||
id: kingfisher.pwhash.1
|
||||
pattern: '(\$1\$[./A-Z0-9]{8}\$[./A-Z0-9]{22})'
|
||||
pattern: '(\$1\$[./A-Za-z0-9]{8}\$[./A-Za-z0-9]{22})'
|
||||
references:
|
||||
- https://en.wikipedia.org/wiki/Crypt_(C)#MD5-based_scheme
|
||||
- https://unix.stackexchange.com/a/511017
|
||||
|
|
@ -16,7 +16,7 @@ rules:
|
|||
id: kingfisher.pwhash.2
|
||||
# Format from Wikipedia:
|
||||
# $2<a/b/x/y>$[cost]$[22 character salt][31 character hash]
|
||||
pattern: '(\$2[abxy]\$\d+\$[./A-Z0-9]{53})'
|
||||
pattern: '(\$2[abxy]\$\d+\$[./A-Za-z0-9]{53})'
|
||||
references:
|
||||
- https://en.wikipedia.org/wiki/Bcrypt
|
||||
- https://hashcat.net/wiki/doku.php?id=example_hashes
|
||||
|
|
@ -35,8 +35,8 @@ rules:
|
|||
(
|
||||
\$ 5
|
||||
(?: \$ rounds=\d+ )?
|
||||
\$ [./A-Z0-9]{8,16}
|
||||
\$ [./A-Z0-9]{43}
|
||||
\$ [./A-Za-z0-9]{8,16}
|
||||
\$ [./A-Za-z0-9]{43}
|
||||
)
|
||||
references:
|
||||
- https://en.wikipedia.org/wiki/Crypt_(C)#Key_derivation_functions_supported_by_crypt
|
||||
|
|
@ -55,8 +55,8 @@ rules:
|
|||
(
|
||||
\$ 6
|
||||
(?: \$ rounds=\d+ )?
|
||||
\$ [./A-Z0-9]{8,16}
|
||||
\$ [./A-Z0-9]{86}
|
||||
\$ [./A-Za-z0-9]{8,16}
|
||||
\$ [./A-Za-z0-9]{86}
|
||||
)
|
||||
references:
|
||||
- https://en.wikipedia.org/wiki/Crypt_(C)#Key_derivation_functions_supported_by_crypt
|
||||
|
|
@ -73,8 +73,8 @@ rules:
|
|||
(?x)
|
||||
(
|
||||
\$ 8
|
||||
\$ [./A-Z0-9]{8,16}
|
||||
\$ [./A-Z0-9]{43}
|
||||
\$ [./A-Za-z0-9]{8,16}
|
||||
\$ [./A-Za-z0-9]{43}
|
||||
)
|
||||
references:
|
||||
- https://en.wikipedia.org/wiki/Crypt_(C)#Key_derivation_functions_supported_by_crypt
|
||||
|
|
@ -106,4 +106,4 @@ rules:
|
|||
- '$krb5asrep$23$8cf8eb5287e28a4006c064892150c4fb$3e05ecc13548bec8e1eeb900dea5429cc6931bae9b8524490eb3a8801560871fe44355ed556202afbb39872e1bbb5c3c4f1b37dcd68fda89a23ebad917d4bbb0933edd94331598939e5d0c0c98c7e219a2e9dd6b877280d1bd7c51131413be577a167208bcc21e9fe7ae8f393278d740e72ca5c44c42d5cb0bf6bab0a36f1b88b7ddc4abbc6f152e652f6ba35c2955fb4132e11b7e566f3b422c3740f79847b77783d245a4e570b8a621b4ff6ff4815566446af70313ee78133707a76a4e4424783bd7c04920aa822a1a36b29f7e25cef186e6439fc46e42e23d6bd918969ef49b8388aef158e443b3a57dbde7ada631fbef7326f9046a9b'
|
||||
- '$krb5asrep$23$c447eddaebf22ebf006a8fc6f986488c$eb3a17eb56287b474cecad5d4e0490d949977ba3f5015220bcd3080444d5601d67b76c5453b678e8527624e40c273bea4cfe4a7303e136b9bc3b9e63b6fb492ee4b4d2f830c5fa5a55466b57a678f708438f6712354a2deb851792b09270f4941966b82a2fd5ad8fa1fbd95a60b0f9bcd57774b3e55467a02ffcb3f1379104c24e468342f83df20b571e6f34f9a9842b43735d58d94514dcefa76719c0f5c7c3a3bfa770380924625aa0a3472d7c02d10dbb278fd946f7efcfe59a4d4cb7bdb9c5dbddc027611fe333d3ac940ec5b4ed43b55ab54b03cd2df0a9a2a7b5d235c226b259bd5ff8e0e49680351d4f0c4d13e258bc8d383cad6fc2711be0'
|
||||
- '$krb5asrep$23$771adbc2397abddef676742924414f2b$2df6eb2d9c71820dc3fa2c098e071d920f0e412f5f12411632c5ee70e004da1be6f003b78661f8e4507e173552a52da751c45887c19bc1661ed334e0ccb4ef33975d4bd68b3d24746f281b4ca4fdf98fca0e50a8e845ad7d834e020c05b1495bc473b0295c6e9b94963cb912d3ff0f2f48c9075b0f52d9a31e5f4cc67c7af1d816b6ccfda0da5ccf35820a4d7d79073fa404726407ac840910357ef210fcf19ed81660106dfc3f4d9166a89d59d274f31619ddd9a1e2712c879a4e9c471965098842b44fae7ca6dd389d5d98b7fd7aca566ca399d072025e81cf0ef5075447687f80100307145fade7a8'
|
||||
- '$krb5asrep$23$user@domain.com:3e156ada591263b8aab0965f5aebd837$007497cb51b6c8116d6407a782ea0e1c5402b17db7afa6b05a6d30ed164a9933c754d720e279c6c573679bd27128fe77e5fea1f72334c1193c8ff0b370fadc6368bf2d49bbfdba4c5dccab95e8c8ebfdc75f438a0797dbfb2f8a1a5f4c423f9bfc1fea483342a11bd56a216f4d5158ccc4b224b52894fadfba3957dfe4b6b8f5f9f9fe422811a314768673e0c924340b8ccb84775ce9defaa3baa0910b676ad0036d13032b0dd94e3b13903cc738a7b6d00b0b3c210d1f972a6c7cae9bd3c959acf7565be528fc179118f28c679f6deeee1456f0781eb8154e18e49cb27b64bf74cd7112a0ebae2102ac'
|
||||
- '$krb5asrep$23$user@domain.com:3e156ada591263b8aab0965f5aebd837$007497cb51b6c8116d6407a782ea0e1c5402b17db7afa6b05a6d30ed164a9933c754d720e279c6c573679bd27128fe77e5fea1f72334c1193c8ff0b370fadc6368bf2d49bbfdba4c5dccab95e8c8ebfdc75f438a0797dbfb2f8a1a5f4c423f9bfc1fea483342a11bd56a216f4d5158ccc4b224b52894fadfba3957dfe4b6b8f5f9f9fe422811a314768673e0c924340b8ccb84775ce9defaa3baa0910b676ad0036d13032b0dd94e3b13903cc738a7b6d00b0b3c210d1f972a6c7cae9bd3c959acf7565be528fc179118f28c679f6deeee1456f0781eb8154e18e49cb27b64bf74cd7112a0ebae2102ac'
|
||||
|
|
@ -9,13 +9,13 @@ rules:
|
|||
(?:.|[\n\r]){0,16}?
|
||||
\b
|
||||
(
|
||||
A[A-Z0-9_-]{79,99}
|
||||
A[A-Z0-9_-]{78,99}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.5
|
||||
visible: false
|
||||
examples:
|
||||
- paypal_client_id=AZJ6y8Dpr1TYbqAIdhkPzyhjXoY6m8GplL7C3zZ3lPrkTIdhkPzyhjXo_Dx3
|
||||
- paypal_client_id=AZJ6y8Dpr1TYbqAIdhkPzyhjXoY6mIdhkPzyhjXoY6m8GplL7C3zZ3lPrkTIdhkPzyhjXo_Dx3IdhkPzyhjXoY6m
|
||||
|
||||
- name: PayPal OAuth Secret
|
||||
id: kingfisher.paypal.2
|
||||
|
|
@ -27,12 +27,12 @@ rules:
|
|||
(?:.|[\n\r]){0,32}?
|
||||
\b
|
||||
(
|
||||
[A-Z0-9_.-]{80,120}
|
||||
[A-Z0-9_.-]{78,120}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.5
|
||||
examples:
|
||||
- paypal_secret=EDe5J6y8Dpr1TYbqAIdhkPzyhjXoY6m8GplL7C3zZ3lPrkT1XlV6hYPSeJL5b1T1
|
||||
- paypal_secret=EP0uwUsACKVPcbDRaXFYerX2ij6nbsha71cSdynuQWoSt1pIy4qtIs7gJQRmHwKXu5Icv3g1YQZzAywf
|
||||
|
||||
validation:
|
||||
type: Http
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ rules:
|
|||
(?x)
|
||||
-----BEGIN\ .{0,20}\ ?PRIVATE\ KEY\ ?.{0,20}-----
|
||||
\s*
|
||||
( (?: [A-Z0-9+/=\s"',] | \\r | \\n ) {50,} )
|
||||
( (?: [a-zA-Z0-9+/=\s"',] | \\r | \\n ) {50,} )
|
||||
\s*
|
||||
-----END\ .{0,20}\ ?PRIVATE\ KEY\ ?.{0,20}-----
|
||||
min_entropy: 4.5
|
||||
|
|
@ -57,9 +57,9 @@ rules:
|
|||
| LS0tLS1CRUdJTiBEU0EgUFJJVkFURSBLRVktLS0t (?# prefix of base64 encoding of `-----BEGIN DSA PRIVATE KEY-----` )
|
||||
| LS0tLS1CRUdJTiBFQyBQUklWQVRFIEtFWS0tLS0t (?# prefix of base64 encoding of `-----BEGIN EC PRIVATE KEY-----` )
|
||||
)
|
||||
[A-Z0-9+/=]{50,}
|
||||
[a-zA-Z0-9+/=]{50,}
|
||||
)
|
||||
(?: [^A-Z0-9+/=] | $ )
|
||||
(?: [^a-zA-Z0-9+/=] | $ )
|
||||
min_entropy: 4.5
|
||||
confidence: high
|
||||
prevalidated: false
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ rules:
|
|||
- name: Postman API Key
|
||||
id: kingfisher.postman.1
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
PMAK-[A-Z0-9]{24}-[A-Z0-9]{34}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ rules:
|
|||
- name: Contains encrypted RSA private key
|
||||
id: kingfisher.privkey.1
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
(?msi)
|
||||
(
|
||||
-----BEGIN\s
|
||||
|
|
@ -45,7 +45,7 @@ rules:
|
|||
- name: Contains Private Key
|
||||
id: kingfisher.privkey.2
|
||||
pattern: |
|
||||
(?x)
|
||||
(?xi)
|
||||
(?ims)
|
||||
(
|
||||
-----BEGIN\s
|
||||
|
|
|
|||
|
|
@ -5,8 +5,9 @@ rules:
|
|||
pattern: |
|
||||
(?xi)
|
||||
(?:stripe|strp)
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
|
||||
(?:.|[\n\r]){0,32}?
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(
|
||||
pk_live_
|
||||
(?:[0-9A-Z]{6}){4,30}
|
||||
|
|
@ -21,11 +22,11 @@ rules:
|
|||
id: kingfisher.stripe.2
|
||||
|
||||
pattern: |
|
||||
(?ix)
|
||||
(?:^|[\s"'=])
|
||||
(?xi)
|
||||
(?:stripe|strp)
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
|
||||
(?:.|[\n\r]){0,32}?
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(
|
||||
(?:
|
||||
sk|rk
|
||||
|
|
|
|||
|
|
@ -10,13 +10,13 @@ rules:
|
|||
(?:.|[\n\r]){0,16}?
|
||||
\b
|
||||
(
|
||||
[a-z0-9-_]{22}
|
||||
[A-Z-_0-9]{22}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.0
|
||||
confidence: medium
|
||||
examples:
|
||||
- "travis_token splendid21RANDOMCONTENT_token"
|
||||
- "travis_token splendid21RANDOMCONTEN"
|
||||
validation:
|
||||
type: Http
|
||||
content:
|
||||
|
|
|
|||
141
src/update.rs
141
src/update.rs
|
|
@ -1,3 +1,20 @@
|
|||
// This module checks GitHub for a newer Kingfisher release and (optionally)
|
||||
// self‑updates. Our release assets use short, user‑friendly names such as
|
||||
// `kingfisher-linux-arm64.tgz`, `kingfisher-darwin-x64.tgz`, etc. Those names
|
||||
// do **not** match the full Rust target triple that the `self_update` crate
|
||||
// expects (e.g. `aarch64-unknown-linux-musl`). We therefore map the compile‑
|
||||
// time target to the corresponding asset suffix via `builder.target()`.
|
||||
//
|
||||
// Version handling logic covers three scenarios:
|
||||
// 1. Running version == latest release → "up to date".
|
||||
// 2. Running version > latest release → print a notice that the binary is
|
||||
// **newer** than anything on GitHub (e.g. a dev build).
|
||||
// 3. Latest release > running version → offer to self‑update.
|
||||
//
|
||||
// All informational messages are printed with the
|
||||
// `style_finding_active_heading` style so that they stand out alongside normal
|
||||
// scan output.
|
||||
|
||||
use std::{
|
||||
fs,
|
||||
io::{ErrorKind, IsTerminal},
|
||||
|
|
@ -5,9 +22,13 @@ use std::{
|
|||
};
|
||||
|
||||
use self_update::{backends::github::Update, cargo_crate_version, errors::Error as UpdError};
|
||||
use semver::Version;
|
||||
use tracing::{error, info, warn};
|
||||
|
||||
use crate::{cli::global::GlobalArgs, reporter::styles::Styles};
|
||||
use crate::{
|
||||
cli::global::GlobalArgs,
|
||||
reporter::styles::Styles,
|
||||
};
|
||||
|
||||
/// Return `true` when the canonical executable path lives inside a Homebrew Cellar.
|
||||
/// Works for Intel macOS (/usr/local/Cellar), Apple‑Silicon macOS (/opt/homebrew/Cellar)
|
||||
|
|
@ -17,31 +38,38 @@ fn installed_via_homebrew() -> bool {
|
|||
std::env::current_exe().ok().and_then(|p| fs::canonicalize(p).ok())
|
||||
}
|
||||
|
||||
canonical_exe().map(|p| p.components().any(|c| c.as_os_str() == "Cellar")).unwrap_or(false)
|
||||
canonical_exe()
|
||||
.map(|p| p.components().any(|c| c.as_os_str() == "Cellar"))
|
||||
.unwrap_or(false)
|
||||
}
|
||||
|
||||
/// Check GitHub for a newer Kingfisher release.
|
||||
/// Check GitHub for a newer Kingfisher release and optionally self‑update.
|
||||
///
|
||||
/// * `base_url` lets tests point at a mock server.
|
||||
/// * Self‑update is performed unless the user disabled it **or** the binary is a Homebrew install.
|
||||
/// * Self‑update is skipped when the user disabled it **or** the binary is a
|
||||
/// Homebrew install.
|
||||
pub fn check_for_update(global_args: &GlobalArgs, base_url: Option<&str>) -> Option<String> {
|
||||
if global_args.no_update_check {
|
||||
return None;
|
||||
}
|
||||
|
||||
let is_brew = installed_via_homebrew();
|
||||
if is_brew {
|
||||
info!("Homebrew install detected – will notify about updates but not self‑update");
|
||||
}
|
||||
|
||||
info!("Checking for updates…");
|
||||
|
||||
// -------------------------------------------------------------
|
||||
// Prepare colour/style helper so every message looks consistent
|
||||
// -------------------------------------------------------------
|
||||
// Decide once whether we want coloured output.
|
||||
let use_color = std::io::stderr().is_terminal() && !global_args.quiet;
|
||||
let styles = Styles::new(use_color);
|
||||
|
||||
let is_brew = installed_via_homebrew();
|
||||
if is_brew {
|
||||
info!(
|
||||
"{}",
|
||||
styles
|
||||
.style_finding_active_heading
|
||||
.apply_to("Homebrew install detected – will notify about updates but not self‑update")
|
||||
);
|
||||
}
|
||||
|
||||
info!(
|
||||
"{}","Checking for updates…");
|
||||
|
||||
let mut builder = Update::configure();
|
||||
builder
|
||||
.repo_owner("mongodb")
|
||||
|
|
@ -50,54 +78,101 @@ pub fn check_for_update(global_args: &GlobalArgs, base_url: Option<&str>) -> Opt
|
|||
.show_download_progress(false)
|
||||
.current_version(cargo_crate_version!());
|
||||
|
||||
// Allow tests to point at a mock HTTP server.
|
||||
if let Some(url) = base_url {
|
||||
builder.with_url(url);
|
||||
}
|
||||
|
||||
// ──────────────────────────────────────────────────────
|
||||
// Map the current Rust target triple to our simplified asset names.
|
||||
// ──────────────────────────────────────────────────────
|
||||
#[cfg(all(target_os = "linux", target_arch = "aarch64"))]
|
||||
builder.target("linux-arm64");
|
||||
|
||||
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
|
||||
builder.target("linux-x64");
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "aarch64"))]
|
||||
builder.target("darwin-arm64");
|
||||
|
||||
#[cfg(all(target_os = "macos", target_arch = "x86_64"))]
|
||||
builder.target("darwin-x64");
|
||||
|
||||
#[cfg(all(target_os = "windows", target_arch = "x86_64"))]
|
||||
builder.target("windows-x64");
|
||||
|
||||
// Build the updater.
|
||||
let Ok(updater) = builder.build() else {
|
||||
warn!("Failed to configure update checker");
|
||||
return None;
|
||||
};
|
||||
|
||||
// Query GitHub.
|
||||
let Ok(release) = updater.get_latest_release() else {
|
||||
warn!("Failed to check for updates");
|
||||
return None;
|
||||
};
|
||||
|
||||
// ----------------------------
|
||||
// Already on the latest version
|
||||
// ----------------------------
|
||||
if release.version == cargo_crate_version!() {
|
||||
let plain = format!("Kingfisher {} is up to date", release.version);
|
||||
let styled = styles.style_finding_active_heading.apply_to(&plain);
|
||||
info!("{}", styled);
|
||||
let running_v = cargo_crate_version!();
|
||||
|
||||
// ───────────── Case 1: running == latest ─────────────
|
||||
if release.version == running_v {
|
||||
let plain = format!("Kingfisher {running_v} is up to date");
|
||||
info!("{}", styles.style_finding_active_heading.apply_to(&plain));
|
||||
return Some(plain);
|
||||
}
|
||||
|
||||
// ----------------------------
|
||||
// A newer version is available
|
||||
// ----------------------------
|
||||
let plain = format!("New Kingfisher release {} available", release.version);
|
||||
let styled = styles.style_finding_active_heading.apply_to(&plain);
|
||||
info!("{}", styled);
|
||||
// Try semantic version comparison. If parsing fails, fall back to the
|
||||
// self‑update code‑path (which will treat the strings lexicographically).
|
||||
if let (Ok(curr), Ok(latest)) = (
|
||||
Version::parse(running_v),
|
||||
Version::parse(&release.version),
|
||||
) {
|
||||
// ───────── Case 2: running > latest (dev build) ─────────
|
||||
if curr > latest {
|
||||
let plain = format!(
|
||||
"Running Kingfisher {curr} which is newer than latest released {latest}"
|
||||
);
|
||||
info!("{}", styles.style_finding_active_heading.apply_to(&plain));
|
||||
return Some(plain);
|
||||
}
|
||||
// else fall through to Case 3 (latest > running)
|
||||
}
|
||||
|
||||
// Decide whether to perform the update in place.
|
||||
// ───────────── Case 3: latest > running ─────────────
|
||||
let plain = format!("New Kingfisher release {} available", release.version);
|
||||
info!("{}", styles.style_finding_active_heading.apply_to(&plain));
|
||||
|
||||
// Attempt self‑update when allowed and feasible.
|
||||
if global_args.self_update && !is_brew {
|
||||
match updater.update() {
|
||||
Ok(status) => info!("Updated to version {}", status.version()),
|
||||
Ok(status) => info!(
|
||||
"{}",
|
||||
styles
|
||||
.style_finding_active_heading
|
||||
.apply_to(&format!("Updated to version {}", status.version()))
|
||||
),
|
||||
Err(e) => match e {
|
||||
UpdError::Io(ref io_err) if io_err.kind() == ErrorKind::PermissionDenied => {
|
||||
warn!(
|
||||
"Cannot replace the current binary – permission denied.\n\
|
||||
If you installed via a package manager, run its upgrade command.\n\
|
||||
Otherwise reinstall to a user‑writable directory or re‑run with sudo."
|
||||
"{}",
|
||||
styles.style_finding_active_heading.apply_to(
|
||||
"Cannot replace the current binary – permission denied.\n\
|
||||
If you installed via a package manager, run its upgrade command.\n\
|
||||
Otherwise reinstall to a user‑writable directory or re‑run with sudo."
|
||||
)
|
||||
);
|
||||
}
|
||||
_ => error!("Failed to update: {e}"),
|
||||
},
|
||||
}
|
||||
} else if is_brew {
|
||||
info!("Run `brew upgrade kingfisher` to install the new version.");
|
||||
info!(
|
||||
"{}",
|
||||
styles
|
||||
.style_finding_active_heading
|
||||
.apply_to("Run `brew upgrade kingfisher` to install the new version.")
|
||||
);
|
||||
}
|
||||
|
||||
Some(plain)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue