Skip to content

Commit e4c367a

Browse files
committed
feat(endpoint): list configured security items in 'endpoint show'
The dotted security.* rows only carry an enabled mark and a count; the items themselves (token values, filter methods, referrer URLs, item ids needed by the remove commands) required either --format json or a separate 'security show' call. Extract that command's item-section renderer into a shared security_item_sections helper and append the same TOKENS/JWTS/REFERRERS/DOMAIN_MASKS/IPS/REQUEST_FILTERS sections to 'endpoint show'. Empty lists still render no section.
1 parent 4929fed commit e4c367a

4 files changed

Lines changed: 108 additions & 85 deletions

File tree

src/commands/endpoint/render.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,11 @@ impl Render for SingleEndpointView {
190190
t.add_row(vec![Cell::new("rate_limits.rpm"), opt_cell(&rl.rpm)]);
191191
t.add_row(vec![Cell::new("rate_limits.rpd"), opt_cell(&rl.rpd)]);
192192
}
193-
write_table(w, &t)
193+
write_table(w, &t)?;
194+
if let Some(sec) = &e.security {
195+
super::security::security_item_sections(w, ctx, sec)?;
196+
}
197+
Ok(())
194198
}
195199
}
196200

src/commands/endpoint/security.rs

Lines changed: 87 additions & 78 deletions
Original file line numberDiff line numberDiff line change
@@ -487,86 +487,95 @@ impl Render for SecurityShowView {
487487
.and_then(|h| h.value.clone());
488488
t.add_row(vec![Cell::new("ip_custom_header"), opt_cell(&ip_header)]);
489489
write_table(w, &t)?;
490+
security_item_sections(w, ctx, data)
491+
}
492+
}
490493

491-
// One section per configured item list; lists with no items render
492-
// no section so the common single-feature case stays compact.
493-
let section = |w: &mut dyn std::io::Write,
494-
title: &str,
495-
headers: Vec<&str>,
496-
rows: Vec<Vec<Cell>>|
497-
-> std::io::Result<()> {
498-
if rows.is_empty() {
499-
return Ok(());
500-
}
501-
writeln!(w)?;
502-
writeln!(w, "{} ({})", title, rows.len())?;
503-
let mut t = new_table(ctx);
504-
set_header_bold(&mut t, ctx, headers);
505-
for row in rows {
506-
t.add_row(row);
507-
}
508-
write_table(w, &t)
509-
};
494+
/// Renders one titled table per configured security item list (TOKENS, JWTS,
495+
/// ...). Lists with no items render no section so lightly-configured
496+
/// endpoints stay compact. Shared between `endpoint security show` and
497+
/// `endpoint show`.
498+
pub(crate) fn security_item_sections(
499+
w: &mut dyn std::io::Write,
500+
ctx: &crate::output::OutputCtx,
501+
data: &quicknode_sdk::admin::EndpointSecurity,
502+
) -> std::io::Result<()> {
503+
let section = |w: &mut dyn std::io::Write,
504+
title: &str,
505+
headers: Vec<&str>,
506+
rows: Vec<Vec<Cell>>|
507+
-> std::io::Result<()> {
508+
if rows.is_empty() {
509+
return Ok(());
510+
}
511+
writeln!(w)?;
512+
writeln!(w, "{} ({})", title, rows.len())?;
513+
let mut t = new_table(ctx);
514+
set_header_bold(&mut t, ctx, headers);
515+
for row in rows {
516+
t.add_row(row);
517+
}
518+
write_table(w, &t)
519+
};
510520

511-
let tokens = data.tokens.as_deref().unwrap_or(&[]);
512-
section(
513-
w,
514-
"TOKENS",
515-
vec!["ID", "TOKEN"],
516-
tokens
517-
.iter()
518-
.map(|t| vec![Cell::new(&t.id), Cell::new(&t.token)])
519-
.collect(),
520-
)?;
521-
let jwts = data.jwts.as_deref().unwrap_or(&[]);
522-
section(
523-
w,
524-
"JWTS",
525-
vec!["ID", "NAME", "KID"],
526-
jwts.iter()
527-
.map(|j| vec![Cell::new(&j.id), Cell::new(&j.name), Cell::new(&j.kid)])
528-
.collect(),
529-
)?;
530-
let referrers = data.referrers.as_deref().unwrap_or(&[]);
531-
section(
532-
w,
533-
"REFERRERS",
534-
vec!["ID", "REFERRER"],
535-
referrers
536-
.iter()
537-
.map(|r| vec![Cell::new(&r.id), opt_cell(&r.referrer)])
538-
.collect(),
539-
)?;
540-
let masks = data.domain_masks.as_deref().unwrap_or(&[]);
541-
section(
542-
w,
543-
"DOMAIN_MASKS",
544-
vec!["ID", "DOMAIN"],
545-
masks
546-
.iter()
547-
.map(|d| vec![Cell::new(&d.id), Cell::new(&d.domain)])
548-
.collect(),
549-
)?;
550-
let ips = data.ips.as_deref().unwrap_or(&[]);
551-
section(
552-
w,
553-
"IPS",
554-
vec!["ID", "IP"],
555-
ips.iter()
556-
.map(|i| vec![Cell::new(&i.id), Cell::new(&i.ip)])
557-
.collect(),
558-
)?;
559-
let filters = data.request_filters.as_deref().unwrap_or(&[]);
560-
section(
561-
w,
562-
"REQUEST_FILTERS",
563-
vec!["ID", "METHODS"],
564-
filters
565-
.iter()
566-
.map(|f| vec![Cell::new(&f.id), Cell::new(f.method.join(", "))])
567-
.collect(),
568-
)
569-
}
521+
let tokens = data.tokens.as_deref().unwrap_or(&[]);
522+
section(
523+
w,
524+
"TOKENS",
525+
vec!["ID", "TOKEN"],
526+
tokens
527+
.iter()
528+
.map(|t| vec![Cell::new(&t.id), Cell::new(&t.token)])
529+
.collect(),
530+
)?;
531+
let jwts = data.jwts.as_deref().unwrap_or(&[]);
532+
section(
533+
w,
534+
"JWTS",
535+
vec!["ID", "NAME", "KID"],
536+
jwts.iter()
537+
.map(|j| vec![Cell::new(&j.id), Cell::new(&j.name), Cell::new(&j.kid)])
538+
.collect(),
539+
)?;
540+
let referrers = data.referrers.as_deref().unwrap_or(&[]);
541+
section(
542+
w,
543+
"REFERRERS",
544+
vec!["ID", "REFERRER"],
545+
referrers
546+
.iter()
547+
.map(|r| vec![Cell::new(&r.id), opt_cell(&r.referrer)])
548+
.collect(),
549+
)?;
550+
let masks = data.domain_masks.as_deref().unwrap_or(&[]);
551+
section(
552+
w,
553+
"DOMAIN_MASKS",
554+
vec!["ID", "DOMAIN"],
555+
masks
556+
.iter()
557+
.map(|d| vec![Cell::new(&d.id), Cell::new(&d.domain)])
558+
.collect(),
559+
)?;
560+
let ips = data.ips.as_deref().unwrap_or(&[]);
561+
section(
562+
w,
563+
"IPS",
564+
vec!["ID", "IP"],
565+
ips.iter()
566+
.map(|i| vec![Cell::new(&i.id), Cell::new(&i.ip)])
567+
.collect(),
568+
)?;
569+
let filters = data.request_filters.as_deref().unwrap_or(&[]);
570+
section(
571+
w,
572+
"REQUEST_FILTERS",
573+
vec!["ID", "METHODS"],
574+
filters
575+
.iter()
576+
.map(|f| vec![Cell::new(&f.id), Cell::new(f.method.join(", "))])
577+
.collect(),
578+
)
570579
}
571580

572581
#[derive(Serialize)]

tests/snapshots/table_snapshots__endpoint_show_full_table.snap

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,18 @@ security.jwts ✗ (0)
1616
security.domain_masks ✗ (0)
1717
security.ips ✗ (0)
1818
security.referrers ✗ (0)
19-
security.request_filters ✗ (0)
20-
security.ip_custom_header
19+
security.request_filters ✓ (1)
20+
security.ip_custom_header x-real-ip
2121
rate_limits.by_ip
2222
rate_limits.account -1
2323
rate_limits.rps -1
2424
rate_limits.rpm -1
25-
rate_limits.rpd -1
25+
rate_limits.rpd -1
26+
27+
TOKENS (1)
28+
ID TOKEN
29+
tok-1 0xabc
30+
31+
REQUEST_FILTERS (1)
32+
ID METHODS
33+
rf-1 eth_blockNumber, eth_call

tests/table_snapshots.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ async fn endpoint_show_full_table() {
6262
"domainMasks": false,
6363
"ips": false,
6464
"referrers": false,
65-
"requestFilters": false,
66-
"ipCustomHeader": { "value": null }
65+
"requestFilters": true,
66+
"ipCustomHeader": { "value": "x-real-ip" }
6767
},
6868
"tokens": [
6969
{ "id": "tok-1", "token": "0xabc" }
@@ -72,7 +72,9 @@ async fn endpoint_show_full_table() {
7272
"referrers": null,
7373
"domain_masks": null,
7474
"ips": null,
75-
"request_filters": null
75+
"request_filters": [
76+
{ "id": "rf-1", "method": ["eth_blockNumber", "eth_call"] }
77+
]
7678
},
7779
"rate_limits": {
7880
"rate_limit_by_ip": false,

0 commit comments

Comments
 (0)