diff --git a/Cargo.toml b/Cargo.toml index 2000189..fef080a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -187,7 +187,7 @@ semver = "1.0.27" globset = "0.4.18" jsonwebtoken = "9.3.1" ipnet = "2.11.0" -jira_query = "1.6.0" +gouqi = { version = "0.20.0", features = ["async"] } oci-client = { version = "0.15", default-features = false, features = ["rustls-tls"] } walkdir = "2.5.0" p256 = "0.13.2" @@ -249,7 +249,6 @@ codegen-units = 256 [patch.crates-io] vectorscan-rs = { path = "vendor/vectorscan-rs/vectorscan-rs" } vectorscan-rs-sys = { path = "vendor/vectorscan-rs/vectorscan-rs-sys" } -jira_query = { path = "vendor/jira_query" } [profile.profiling] inherits = "release" diff --git a/data/rules/salesforce.yml b/data/rules/salesforce.yml index be3b544..c77b006 100644 --- a/data/rules/salesforce.yml +++ b/data/rules/salesforce.yml @@ -4,7 +4,7 @@ rules: pattern: | (?xi) \b - ( + ( 00 [A-Z0-9]{13} ! @@ -49,17 +49,198 @@ rules: id: kingfisher.salesforce.2 pattern: | (?xi) - \b + \b (?:https?://)? ( [0-9A-Z-]{5,128} ) - \. + \\ my\.salesforce\.com - \b + \b min_entropy: 2.5 confidence: medium visible: false examples: - https://example123.my.salesforce.com - - mydomainname.my.salesforce.com \ No newline at end of file + - mydomainname.my.salesforce.com + + - name: Salesforce Consumer Key and Secret with Token URL + id: kingfisher.salesforce.3 + pattern: | + (?xi)(?s) + (?:salesforce|sforce) + (?:.|[\n\r]){0,256}? + \bconsumer\s{0,8}key\b + (?:.|[\n\r]){0,32}? + \b + (?P + [A-Z0-9+/=._-]{16,256} + ) + \b.*? + (?:.|[\n\r]){0,256}? + \bconsumer\s{0,8}secret\b + (?:.|[\n\r]){0,32}? + \b + (?P + [A-Za-z0-9+/=._-]{16,256} + ) + .*? + \btoken\s{0,8}url\b + (?:.|[\n\r]){0,16}? + (?P + https?:// + [A-Za-z0-9.-]{3,253} + / + (?:services/oauth2/token|oauth/login/[\w-]+/token|oauth2/(?:v1/)?token|oauth/token|[\w]{1,10}/oauth/token) + ) + min_entropy: 3.3 + confidence: medium + examples: + - | + + + https://login.example.com/oauth/login/v2/authorize?authHint=SALESFORCE_OAUTH2&authType=oauth2&prompt=login + 012cbddfa6b05ec1941143c0d37a036291492be9f2df0b42c5c0c220198185de + REDACTED_CONSUMER_SECRET_1 + ExampleProviderOne + false + OpenIdConnect + true + false + true + https://login.example.com/oauth/login/v2/token + + - | + + + https://api.example.net/oauth/authorize + REDACTED_CONSUMER_KEY_2 + REDACTED_CONSUMER_SECRET_2 + ExampleBatchConnect + false + OpenIdConnect + true + false + true + https://api.example.net/oauth/token + + - | + + + https://api.example.net/oauth/authorize + REDACTED_CONSUMER_KEY_3 + REDACTED_CONSUMER_SECRET_3 + ExampleConnect + false + OpenIdConnect + true + false + true + https://api.example.net/oauth/token + + + validation: + type: Http + content: + request: + method: POST + url: "{{ TOKEN_URL | default: 'https://login.salesforce.com/services/oauth2/token' }}" + headers: + Content-Type: application/x-www-form-urlencoded + body: grant_type=client_credentials&client_id={{ CONSUMER_KEY | url_encode }}&client_secret={{ CONSUMER_SECRET | url_encode }} + response_matcher: + - report_response: true + - type: StatusMatch + status: [200] + - type: StatusMatch + status: [400, 401, 403] + negative: true + - type: JsonValid + - type: WordMatch + words: ["access_token", "token_type"] + match_all_words: true + - name: Salesforce Consumer Key and Secret + id: kingfisher.salesforce.4 + pattern: | + (?xi)(?s) + (?:salesforce|sforce) + (?:.|[\n\r]){0,256}? + \bconsumer\s{0,8}key\b + (?:.|[\n\r]){0,32}? + \b + (?P + [A-Z0-9+/=._-]{16,256} + ) + \b.*? + (?:.|[\n\r]){0,256}? + \bconsumer\s{0,8}secret\b + (?:.|[\n\r]){0,32}? + \b + (?P + [A-Za-z0-9+/=._-]{16,256} + ) + min_entropy: 3.3 + confidence: medium + examples: + - | + + + https://login.example.com/oauth/login/v2/authorize?authHint=SALESFORCE_OAUTH2&authType=oauth2&prompt=login + 012cbddfa6b05ec1941143c0d37a036291492be9f2df0b42c5c0c220198185de + REDACTED_CONSUMER_SECRET_1 + ExampleProviderOne + false + OpenIdConnect + true + false + true + https://login.example.com/oauth/login/v2/token + + - | + + + https://api.example.net/oauth/authorize + REDACTED_CONSUMER_KEY_2 + REDACTED_CONSUMER_SECRET_2 + ExampleBatchConnect + false + OpenIdConnect + true + false + true + https://api.example.net/oauth/token + + - | + + + https://api.example.net/oauth/authorize + REDACTED_CONSUMER_KEY_3 + REDACTED_CONSUMER_SECRET_3 + ExampleConnect + false + OpenIdConnect + true + false + true + https://api.example.net/oauth/token + + validation: + type: Http + content: + request: + method: POST + url: "https://login.salesforce.com/services/oauth2/token" + headers: + Content-Type: application/x-www-form-urlencoded + body: grant_type=client_credentials&client_id={{ CONSUMER_KEY | url_encode }}&client_secret={{ CONSUMER_SECRET | url_encode }} + response_matcher: + - report_response: true + - type: StatusMatch + status: [200] + - type: StatusMatch + status: [400, 401, 403] + negative: true + - type: JsonValid + - type: WordMatch + words: ["access_token", "token_type"] + match_all_words: true diff --git a/src/jira.rs b/src/jira.rs index e3c2adc..2fe0ef4 100644 --- a/src/jira.rs +++ b/src/jira.rs @@ -1,10 +1,11 @@ use anyhow::{Context, Result}; -use jira_query::{Auth, JiraInstance, Pagination}; +use gouqi::{r#async::Jira, Credentials, SearchOptions}; use reqwest::Client; +use std::path::PathBuf; use url::Url; -// Re-export the Issue type from jira_query so callers don't depend on the crate. -pub use jira_query::Issue as JiraIssue; +// Re-export the Issue type from gouqi so callers don't depend on the crate. +pub use gouqi::Issue as JiraIssue; pub async fn fetch_issues( jira_url: Url, jql: &str, @@ -19,20 +20,19 @@ pub async fn fetch_issues( .build() .context("Failed to build HTTP client")?; - let mut jira = JiraInstance::at(base.to_string())? // no trailing slash here - .with_client(client) - .paginate(Pagination::MaxResults(max_results as u32)); + let credentials = match std::env::var("KF_JIRA_TOKEN") { + Ok(token) => Credentials::Bearer(token), + Err(_) => Credentials::Anonymous, + }; - if let Ok(token) = std::env::var("KF_JIRA_TOKEN") { - jira = jira.authenticate(Auth::ApiKey(token)); - } + let jira = Jira::from_client(base.to_string(), credentials, client)?; - let issues = jira.search(jql).await?; - Ok(issues) + let search_options = SearchOptions::builder().max_results(max_results as u64).build(); + + let results = jira.search().list(jql, &search_options).await?; + Ok(results.issues) } -use std::path::PathBuf; - pub async fn download_issues_to_dir( jira_url: Url, jql: &str, diff --git a/src/main.rs b/src/main.rs index 3026579..ea751a0 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,27 +5,27 @@ // * Fallback - system allocator (`system-alloc` feature) // ──────────────────────────────────────────────────────────── -// --- jemalloc (opt-in) --- -#[cfg(feature = "use-jemalloc")] -#[global_allocator] -static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; +// // --- jemalloc (opt-in) --- +// #[cfg(feature = "use-jemalloc")] +// #[global_allocator] +// static GLOBAL: tikv_jemallocator::Jemalloc = tikv_jemallocator::Jemalloc; -// --- mimalloc (default) --- -#[cfg(all(not(feature = "use-jemalloc"), not(feature = "system-alloc")))] -#[global_allocator] -static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; - -// --- system allocator (explicit opt-out) --- -#[cfg(feature = "system-alloc")] -use std::alloc::System; -#[cfg(feature = "system-alloc")] -#[global_allocator] -static GLOBAL: System = System; +// // --- mimalloc (default) --- +// #[cfg(all(not(feature = "use-jemalloc"), not(feature = "system-alloc")))] +// #[global_allocator] +// static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc; +// // --- system allocator (explicit opt-out) --- +// #[cfg(feature = "system-alloc")] // use std::alloc::System; +// #[cfg(feature = "system-alloc")] // #[global_allocator] // static GLOBAL: System = System; +use std::alloc::System; +#[global_allocator] +static GLOBAL: System = System; + use std::{ io::{IsTerminal, Read, Write}, sync::{Arc, Mutex},