Skip to content

Commit 1f1eb0b

Browse files
committed
Refactoring
1 parent 49cabf8 commit 1f1eb0b

31 files changed

Lines changed: 1926 additions & 1740 deletions

.github/workflows/ci.yml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
8+
env:
9+
CARGO_TERM_COLOR: always
10+
11+
jobs:
12+
test:
13+
name: Test (stable)
14+
runs-on: ubuntu-latest
15+
steps:
16+
- uses: actions/checkout@v4
17+
18+
- uses: dtolnay/rust-toolchain@stable
19+
with:
20+
components: rustfmt, clippy
21+
22+
- uses: Swatinem/rust-cache@v2
23+
24+
- name: cargo fmt
25+
run: cargo fmt --all -- --check
26+
27+
- name: cargo clippy
28+
run: cargo clippy --all-targets -- -D warnings
29+
30+
- name: cargo test
31+
run: cargo test --all

.gitignore

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,16 @@
11
/target
2+
3+
# Environment / secrets
4+
.env
5+
.env.*
6+
7+
# Editor / IDE
8+
.idea/
9+
.vscode/
10+
*.swp
11+
12+
# OS
13+
.DS_Store
14+
15+
# Logs
16+
*.log

Cargo.lock

Lines changed: 1 addition & 91 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ edition = "2021"
55
description = "Command-line interface for the Quicknode SDK"
66
license = "MIT"
77
repository = "https://github.com/quicknode/qn"
8+
homepage = "https://www.quicknode.com/docs/welcome"
9+
authors = ["Quicknode <support@quicknode.com>"]
10+
readme = "README.md"
11+
keywords = ["quicknode", "cli", "blockchain", "web3"]
12+
categories = ["command-line-utilities"]
813
rust-version = "1.75"
914

1015
[[bin]]
@@ -25,15 +30,14 @@ serde_json = "1"
2530
serde_yml = "0.0.12"
2631
toon-format = { version = "0.5", default-features = false }
2732
comfy-table = { version = "7", default-features = false, features = ["tty"] }
28-
owo-colors = { version = "4", features = ["supports-colors"] }
29-
supports-color = "3"
3033
dialoguer = "0.11"
3134
toml = "0.8"
32-
anyhow = "1"
3335
thiserror = "1"
3436
humantime = "2"
3537
time = { version = "0.3", features = ["formatting", "parsing", "macros"] }
3638
base64 = "0.22"
39+
tempfile = "3"
40+
url = "2"
3741

3842
[dev-dependencies]
3943
reqwest = { version = "0.12", default-features = false }
@@ -42,4 +46,3 @@ assert_cmd = "2"
4246
predicates = "3"
4347
insta = { version = "1", features = ["yaml"] }
4448
tempfile = "3"
45-
serial_test = "3"

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ error: null
3030
## Installation
3131

3232
```sh
33-
git clone git@github.com:quicknode/cli.git && cd cli
33+
git clone git@github.com:quicknode/qn.git && cd qn
3434
cargo install --path .
3535
```
3636

src/commands/auth.rs

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
//! calling a low-cost API (chain list).
77
//! Status: same as whoami minus the network round-trip.
88
9+
use std::io::{IsTerminal, Write};
10+
911
use clap::{Args as ClapArgs, Subcommand};
1012
use quicknode_sdk::{QuicknodeSdk, SdkFullConfig};
1113

@@ -120,13 +122,14 @@ fn resolve_non_interactive(global: &GlobalArgs) -> Result<(String, KeySource), C
120122
)
121123
}
122124

123-
/// Show the last 4 chars only.
125+
/// Show the last 4 chars only. Char-based slicing — never panics on multi-byte input.
124126
fn redact(key: &str) -> String {
125-
let n = key.chars().count();
126-
if n <= 4 {
127+
let chars: Vec<char> = key.chars().collect();
128+
if chars.len() <= 4 {
127129
"****".to_string()
128130
} else {
129-
format!("****{}", &key[key.len().saturating_sub(4)..])
131+
let tail: String = chars[chars.len() - 4..].iter().collect();
132+
format!("****{tail}")
130133
}
131134
}
132135

@@ -157,4 +160,27 @@ fn print_status(global: &GlobalArgs, source: KeySource, redacted: &str, validate
157160
}
158161
}
159162

160-
use std::io::{IsTerminal, Write};
163+
#[cfg(test)]
164+
mod tests {
165+
use super::redact;
166+
167+
#[test]
168+
fn redact_short_keys_returns_just_stars() {
169+
assert_eq!(redact(""), "****");
170+
assert_eq!(redact("abcd"), "****");
171+
}
172+
173+
#[test]
174+
fn redact_ascii_shows_last_four() {
175+
assert_eq!(redact("abcdefgh"), "****efgh");
176+
}
177+
178+
#[test]
179+
fn redact_multibyte_does_not_panic() {
180+
// αβγδεζη — each char is 2 bytes in UTF-8. Byte-slicing the last 4
181+
// bytes would land in the middle of a char and panic.
182+
let out = redact("αβγδεζη");
183+
assert_eq!(out.chars().count(), 8); // "****" + last 4 chars
184+
assert!(out.ends_with("δεζη"));
185+
}
186+
}

0 commit comments

Comments
 (0)