diff --git a/CHANGELOG.md b/CHANGELOG.md index 0804eb7..47de788 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. +## [v1.77.0] +- Added `kingfisher revoke` subcommand for revoking leaked credentials directly with the provider. +- Added optional `revocation` section to rules to support credential revocation (currently supporting AWS, GCP, GitHub, GitLab, and Slack). +- Added `kingfisher validate` subcommand to validate credentials without running a full scan. +- Refactored project into multiple crates for better modularity and maintainability. +- Ensured more CLI arguments are global and available across all subcommands. + ## [v1.76.0] - Fixed validation deduplication for rules with nested unnamed captures (e.g. `(?...(ABC|DEF)...)`) to use the primary capture for grouping, ensuring each unique match triggers a separate validation request. - Added trace-level (`-vv`) logging for internal validation dedup keys and grouping to aid debugging. diff --git a/src/main.rs b/src/main.rs index ae7fdea..8ed2a5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -93,7 +93,7 @@ fn main() -> anyhow::Result<()> { Command::SelfUpdate => 1, // Self-update doesn't need a thread pool Command::Rules(_) => num_cpus::get(), // Default for Rules commands Command::Validate(_) => 1, // Single validation request - Command::Revoke(_) => 1, // Single revocation request + Command::Revoke(_) => 1, // Single revocation request Command::AccessMap(_) => 1, Command::View(_) => 1, }; @@ -212,8 +212,7 @@ async fn async_main(args: CommandLineArgs) -> Result<()> { } } Command::Revoke(revoke_args) => { - let results = - direct_revoke::run_direct_revocation(&revoke_args, &global_args).await?; + let results = direct_revoke::run_direct_revocation(&revoke_args, &global_args).await?; let use_color = global_args.use_color(std::io::stdout()); direct_revoke::print_results(&results, &revoke_args.format, use_color); // Exit with code 0 if any result revoked, 1 if all failed diff --git a/src/rules.rs b/src/rules.rs index b6a28a8..1b1a7ac 100644 --- a/src/rules.rs +++ b/src/rules.rs @@ -8,8 +8,8 @@ pub mod rule { } // Re-export everything from the rules module -pub use kingfisher_rules::rules::{Rules, RulesError}; pub use kingfisher_rules::rule::Revocation; +pub use kingfisher_rules::rules::{Rules, RulesError}; pub use kingfisher_rules::{ ChecksumActual, ChecksumRequirement, Confidence, DependsOnRule, HttpRequest, HttpValidation, MultipartConfig, MultipartPart, PatternRequirementContext, PatternRequirements, diff --git a/src/validation/gcp.rs b/src/validation/gcp.rs index cc2d1fe..2dc8f56 100644 --- a/src/validation/gcp.rs +++ b/src/validation/gcp.rs @@ -108,9 +108,7 @@ pub async fn revoke_gcp_service_account_key( } if project_id.is_empty() || client_email.is_empty() || key_id.is_empty() { - return Err(anyhow!( - "Missing required GCP fields: project_id/client_email/private_key_id" - )); + return Err(anyhow!("Missing required GCP fields: project_id/client_email/private_key_id")); } let ctx = validator.get_access_token_from_sa_json(gcp_json).await?; @@ -122,18 +120,11 @@ pub async fn revoke_gcp_service_account_key( encode(&key_id), ); - let response = validator - .client() - .delete(url) - .bearer_auth(&ctx.access_token) - .send() - .await?; + let response = validator.client().delete(url).bearer_auth(&ctx.access_token).send().await?; let status = response.status(); - let body = response - .text() - .await - .unwrap_or_else(|e| format!("Failed to read response body: {}", e)); + let body = + response.text().await.unwrap_or_else(|e| format!("Failed to read response body: {}", e)); let message = if body.trim().is_empty() { status.to_string() } else { body }; Ok(GcpRevocationOutcome {