forked from mirrors/kingfisher
Added support for HTTP request bodies in rule validation. Added mistral and perplexity rule
This commit is contained in:
parent
b13bdacb2f
commit
cd4f626502
11 changed files with 160 additions and 5 deletions
|
|
@ -2,6 +2,12 @@
|
|||
|
||||
All notable changes to this project will be documented in this file.
|
||||
|
||||
|
||||
## [1.20.0]
|
||||
- Removed confirmation prompt when user provides --self-update flag
|
||||
- Added support for HTTP request bodies in rule validation
|
||||
- Added rules for mistral, perplexity
|
||||
|
||||
## [1.19.0]
|
||||
- JSON output was missing committer name and email
|
||||
- Fixed Gitlab rule which was incorrectly identifying certain tokens as valid
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ publish = false
|
|||
|
||||
[package]
|
||||
name = "kingfisher"
|
||||
version = "1.19.0"
|
||||
version = "1.20.0"
|
||||
edition.workspace = true
|
||||
rust-version.workspace = true
|
||||
license.workspace = true
|
||||
|
|
|
|||
13
README.md
13
README.md
|
|
@ -230,7 +230,18 @@ _If no token is provided Kingfisher still works for public repositories._
|
|||
|
||||
### Update Checks
|
||||
|
||||
Kingfisher checks for newer releases on GitHub each time it starts and exits, printing whether a new version is available. Use `--self-update` to automatically download and replace the binary when an update is found. Add `--no-update-check` to disable these checks entirely.
|
||||
Kingfisher automatically queries GitHub for a newer release when it starts and tells you whether an update is available.
|
||||
|
||||
- **Hands-free updates** – Add `--self-update` to any Kingfisher command
|
||||
|
||||
If a newer version exists, Kingfisher will download it, replace the running
|
||||
binary, and re-launch itself with the **exact same arguments**.
|
||||
|
||||
If the update fails or no newer release is found, the current run
|
||||
proceeds as normal
|
||||
|
||||
- **Disable version checks** – Pass `--no-update-check` to skip both the
|
||||
startup and shutdown checks entirely
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ rules:
|
|||
(?xi)
|
||||
\b
|
||||
alibaba
|
||||
(?:.|[\n\r]){0,16}?
|
||||
(?:.|[\n\r]){0,32}?
|
||||
\b
|
||||
(
|
||||
[a-z0-9]{30}
|
||||
|
|
@ -30,4 +30,37 @@ rules:
|
|||
examples:
|
||||
- alibaba_secret = 7jkWdTjKLnSlGddwPR5gBn65PHcZG6
|
||||
- alibaba-token = aJHKLnSlGddwPR5g7jkWdTBn65PHc5
|
||||
|
||||
validation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: GET
|
||||
url: >
|
||||
{% assign nonce = "" | uuid | url_encode -%}
|
||||
{% assign ts = "" | iso_timestamp | url_encode -%}
|
||||
{% capture qs -%}
|
||||
AccessKeyId={{ AKID }}&
|
||||
Action=GetCallerIdentity&
|
||||
Format=JSON&
|
||||
SignatureMethod=HMAC-SHA1&
|
||||
SignatureNonce={{ nonce }}&
|
||||
SignatureVersion=1.0&
|
||||
Timestamp={{ ts }}&
|
||||
Version=2015-04-01
|
||||
{%- endcapture %}
|
||||
{% capture sts -%}GET&%2F&{{ qs | url_encode }}{%- endcapture %}
|
||||
{% assign key = TOKEN | append: '&' -%}
|
||||
{% assign sig = sts | hmac_sha256: key | b64enc | url_encode -%}
|
||||
https://sts.aliyuncs.com/?{{ qs }}&Signature={{ sig }}
|
||||
headers:
|
||||
Accept: application/json
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [200]
|
||||
- type: WordMatch
|
||||
words: ['"Arn"']
|
||||
match_all_words: true
|
||||
depends_on_rule:
|
||||
- rule_id: kingfisher.alibabacloud.1
|
||||
variable: AKID
|
||||
41
data/rules/mistral.yml
Normal file
41
data/rules/mistral.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
rules:
|
||||
- name: Mistral AI API Key
|
||||
id: kingfisher.mistral.1
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
mistral
|
||||
(?:.|[\n\r]){0,32}?
|
||||
(?:SECRET|PRIVATE|ACCESS|KEY|TOKEN)
|
||||
(?:.|[\n\r]){0,32}?
|
||||
\b
|
||||
(
|
||||
[A-Z0-9]{32}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.0
|
||||
confidence: medium
|
||||
examples:
|
||||
- mistral_token = 47cFZMzkoEo9DBapfvhrmMst3zfV2EIh
|
||||
- mistral_api_key = olI6zlb3F0jO8jjDQUi34skQLPzvox84
|
||||
- 'mistral secret: kMrbwHjG78fYzneT934Pn34NQxVSxniq'
|
||||
references:
|
||||
- https://docs.mistral.ai/getting-started/quickstart :contentReference[oaicite:1]{index=1}
|
||||
- https://docs.mistral.ai/api/ :contentReference[oaicite:2]{index=2}
|
||||
- https://medium.com/@stephane.giron/explore-mistral-ai-api-with-google-apps-script-d41b851c55e3 :contentReference[oaicite:3]{index=3}
|
||||
- https://apidog.com/blog/mistral-ai-api/ :contentReference[oaicite:4]{index=4}
|
||||
validation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: GET
|
||||
url: https://api.mistral.ai/v1/models
|
||||
headers:
|
||||
Authorization: "Bearer {{ TOKEN }}"
|
||||
Accept: application/json
|
||||
response_matcher:
|
||||
- report_response: true
|
||||
- type: StatusMatch
|
||||
status: [200]
|
||||
- type: WordMatch
|
||||
words: ['"data"']
|
||||
37
data/rules/perplexity.yml
Normal file
37
data/rules/perplexity.yml
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
rules:
|
||||
- name: Perplexity AI API Key
|
||||
id: kingfisher.perplexity.1
|
||||
pattern: |
|
||||
(?xi)
|
||||
\b
|
||||
(
|
||||
pplx-[A-Za-z0-9]{48}
|
||||
)
|
||||
\b
|
||||
min_entropy: 3.8
|
||||
confidence: medium
|
||||
examples:
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
- 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
|
||||
references:
|
||||
- https://docs.perplexity.ai/guides/getting-started
|
||||
- https://pplx.readme.io/reference/post_chat_completions
|
||||
- https://www.perplexity.ai/hub/blog/introducing-pplx-api
|
||||
- https://docs.litellm.ai/docs/providers/perplexity
|
||||
- https://developers.cloudflare.com/ai-gateway/providers/perplexity/
|
||||
validation:
|
||||
type: Http
|
||||
content:
|
||||
request:
|
||||
method: POST
|
||||
url: https://api.perplexity.ai/chat/completions
|
||||
headers:
|
||||
Authorization: "Bearer {{ TOKEN }}"
|
||||
Content-Type: application/json
|
||||
body: '{"model": "kingfisher", "messages": [{ "role": "user", "content": "." }]}'
|
||||
response_matcher:
|
||||
- report_response: false
|
||||
- type: WordMatch
|
||||
match_all_words: false
|
||||
|
|
@ -979,6 +979,7 @@ mod test {
|
|||
method: "GET".to_string(),
|
||||
url: "https://example.com".to_string(),
|
||||
headers: BTreeMap::new(),
|
||||
body: None,
|
||||
response_matcher: Some(vec![]),
|
||||
multipart: None,
|
||||
response_is_html: false,
|
||||
|
|
|
|||
|
|
@ -65,6 +65,8 @@ pub struct HttpRequest {
|
|||
#[serde(default)]
|
||||
pub headers: BTreeMap<String, String>,
|
||||
#[serde(default)]
|
||||
pub body: Option<String>,
|
||||
#[serde(default)]
|
||||
pub response_matcher: Option<Vec<ResponseMatcher>>,
|
||||
#[serde(default)]
|
||||
pub multipart: Option<MultipartConfig>,
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ pub fn check_for_update(global_args: &GlobalArgs, base_url: Option<&str>) -> Opt
|
|||
.repo_name("kingfisher")
|
||||
.bin_name("kingfisher")
|
||||
.show_download_progress(false)
|
||||
.no_confirm(true) // Don't prompt for confirmation when self‑updating
|
||||
.current_version(cargo_crate_version!());
|
||||
|
||||
// Allow tests to point at a mock HTTP server.
|
||||
|
|
|
|||
|
|
@ -353,6 +353,7 @@ async fn timed_validate_single_match<'a>(
|
|||
&http_validation.request.method,
|
||||
&url,
|
||||
&http_validation.request.headers,
|
||||
&http_validation.request.body,
|
||||
parser,
|
||||
&globals,
|
||||
) {
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ pub fn build_request_builder(
|
|||
method_str: &str,
|
||||
url: &Url,
|
||||
headers: &BTreeMap<String, String>,
|
||||
body: &Option<String>,
|
||||
parser: &liquid::Parser,
|
||||
globals: &liquid::Object,
|
||||
) -> Result<RequestBuilder, String> {
|
||||
|
|
@ -99,6 +100,19 @@ pub fn build_request_builder(
|
|||
}
|
||||
}
|
||||
request_builder = request_builder.headers(combined_headers);
|
||||
|
||||
// If a body template is provided, parse and render it
|
||||
if let Some(body_template) = body {
|
||||
let template = parser
|
||||
.parse(body_template)
|
||||
.map_err(|e| format!("Error parsing body template: {}", e))?;
|
||||
let rendered_body = template
|
||||
.render(globals)
|
||||
.map_err(|e| format!("Error rendering body template: {}", e))?;
|
||||
request_builder = request_builder.body(rendered_body);
|
||||
}
|
||||
|
||||
|
||||
Ok(request_builder)
|
||||
}
|
||||
|
||||
|
|
@ -427,7 +441,15 @@ mod tests {
|
|||
let headers =
|
||||
BTreeMap::from([("Content-Type".to_string(), "application/json".to_string())]);
|
||||
let url = Url::from_str("https://example.com").unwrap();
|
||||
let result = build_request_builder(&client, "GET", &url, &headers, &parser, &globals);
|
||||
let result = build_request_builder(
|
||||
&client,
|
||||
"GET",
|
||||
&url,
|
||||
&headers,
|
||||
&None,
|
||||
&parser,
|
||||
&globals,
|
||||
);
|
||||
assert!(result.is_ok());
|
||||
}
|
||||
#[tokio::test]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue