preparing for v1.99.0

This commit is contained in:
Mick Grove 2026-05-04 23:47:48 -07:00
commit aca11be36d
4 changed files with 473 additions and 41 deletions

View file

@ -425,11 +425,31 @@ kingfisher scan ./my-project \
### Project configuration file (`kingfisher.yaml`)
Most `kingfisher scan` flags can be set as project defaults via a
`kingfisher.yaml` file in the repo root (or any ancestor directory). CLI
flags always win; config values fill in defaults. Lists are concatenated.
`kingfisher.yaml` file. CLI flags always win; config values fill in
defaults. Lists are concatenated.
The config file is **never auto-discovered** — pass `--config FILE`
explicitly or it is not loaded.
**Step 1 — generate the config from your existing CLI command** (don't
write the YAML by hand):
```bash
kingfisher config init \
--confidence high \
--redact \
--exclude vendor/ \
--exclude '**/node_modules/**' \
--format sarif \
--output ./kingfisher.sarif \
--alert-webhook https://hooks.slack.com/services/T0/B0/AAA \
> kingfisher.yaml
```
The resulting `kingfisher.yaml`:
```yaml
# kingfisher.yaml
# kingfisher.yaml — generated by `kingfisher config init`.
scan:
confidence: high
redact: true
@ -443,21 +463,19 @@ filters:
alerts:
webhooks:
- url: https://hooks.slack.com/services/T0/B0/AAA
format: slack
```
**Step 2 — run the scan, passing the config explicitly:**
```bash
kingfisher scan . # auto-discovers ./kingfisher.yaml
kingfisher scan . --config /etc/kf.yaml # explicit path
kingfisher scan . --config ./kingfisher.yaml
```
Don't write the YAML by hand. If you already have a long `kingfisher scan`
command, run the same flags under `kingfisher config init` to generate it:
You can override any config value on the CLI for a single run:
```bash
kingfisher config init \
--confidence high --redact --exclude vendor/ --format sarif \
> kingfisher.yaml
kingfisher scan . --config ./kingfisher.yaml --confidence low
# scan.confidence: high in YAML → CLI flag wins, runs at low confidence
```
See [`docs/CONFIG.md`](../usage/configuration.md) for the full schema and precedence rules.
@ -728,6 +746,60 @@ kingfisher scan https://github.com/org/repo.git --repo-artifacts
KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://github.com/org/private_repo.git --repo-artifacts
```
### Scan a GitHub Enterprise / self-hosted GitHub instance
For GitHub Enterprise Server (GHES) or any self-hosted GitHub install, you
need two flags:
- `--github-api-url <URL>` — points the **enumeration / clone** flow at the
custom API root (typically `https://ghe.example.com/api/v3/`).
- `--endpoint github=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitHub PATs Kingfisher discovers in the
scanned source are checked against your GHE rather than `api.github.com`.
```bash
# 1. Scan every org repo on GHE and validate discovered tokens against the same instance
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 2. Scan a single GHE repo by URL (positional target)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://ghe.corp.example.com/org/repo.git \
--endpoint github=https://ghe.corp.example.com
# 3. Scan ALL orgs on a GHE instance (requires non-default --github-api-url)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--all-orgs \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 4. GHE on a private network — add --allow-internal-ips so the validator
# can reach RFC1918 / loopback hosts (SSRF guard is on by default).
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.internal/api/v3/ \
--endpoint github=https://ghe.internal \
--allow-internal-ips
# 5. Validate a single PAT against GHE without scanning anything
kingfisher validate --rule github \
--endpoint github=https://ghe.corp.example.com \
"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
# 6. Revoke (delete) a confirmed-leaked PAT against GHE
kingfisher revoke --rule github \
--endpoint github=https://ghe.corp.example.com \
"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
```
> **Why two URLs?** `--github-api-url` is the GHE *cloning* root that
> Kingfisher walks to enumerate orgs, repos, and contributors.
> `--endpoint github=…` is the *validator* root used to live-check
> discovered tokens. They are usually the same host, but they're separate
> flags because some deployments front-load auth (an SSO portal for repo
> access vs. a direct API endpoint for token validation).
---
## GitLab
@ -788,6 +860,99 @@ kingfisher scan https://gitlab.com/group/project.git --repo-artifacts
KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.com/group/private_project.git --repo-artifacts
```
### Scan a self-hosted (Omnibus / Cloud Native) GitLab instance
For GitLab self-hosted (Omnibus, Helm, or Cloud Native), pair the
enumeration flag with a matching validation endpoint, just like with GHE:
- `--gitlab-api-url <URL>` — points the **enumeration / clone** flow at
the custom GitLab root (typically `https://gitlab.example.com/`).
- `--endpoint gitlab=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitLab PATs found in the scanned
source are checked against your self-hosted GitLab rather than
`gitlab.com`.
```bash
# 1. Scan a self-hosted group and validate discovered tokens against the same instance
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--include-subgroups \
--gitlab-api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 2. Scan a single self-hosted GitLab project by URL
KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.corp.example.com/group/project.git \
--endpoint gitlab=https://gitlab.corp.example.com
# 3. Scan ALL groups on a self-hosted GitLab (requires non-default --gitlab-api-url)
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--all-groups \
--gitlab-api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 4. Self-hosted GitLab on a private network — add --allow-internal-ips so
# the validator can reach RFC1918 / loopback hosts.
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--gitlab-api-url https://gitlab.internal/ \
--endpoint gitlab=https://gitlab.internal \
--allow-internal-ips
# 5. Validate a single PAT against self-hosted GitLab without scanning anything
kingfisher validate --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"glpat-xxxxxxxxxxxxxxxxxxxx"
# 6. Revoke (delete) a confirmed-leaked PAT against self-hosted GitLab
kingfisher revoke --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"glpat-xxxxxxxxxxxxxxxxxxxx"
```
### Many endpoints at once: `--endpoint-config`
If you maintain a fleet of self-hosted instances (GHE, self-hosted GitLab,
Gitea, Jira DC, Confluence, Artifactory), put them in a single YAML file
and reference it instead of repeating `--endpoint` on every command:
```yaml
# kingfisher-endpoints.yml
endpoints:
github: https://ghe.corp.example.com
gitlab: https://gitlab.corp.example.com
gitea: https://gitea.corp.example.com
jira: https://jira.corp.example.com
confluence: https://wiki.corp.example.com
artifactory: http://artifactory.internal:8081
```
```bash
KF_GITHUB_TOKEN="ghp_…" KF_GITLAB_TOKEN="glpat-…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--endpoint-config ./kingfisher-endpoints.yml \
--allow-internal-ips
```
### Tip: bake the endpoints into `kingfisher.yaml`
Once you've worked out the right flags, capture them as project defaults
so every scan uses the same config:
```bash
kingfisher config init \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--gitlab-api-url https://gitlab.corp.example.com/ \
--endpoint github=https://ghe.corp.example.com \
--endpoint gitlab=https://gitlab.corp.example.com \
--allow-internal-ips \
> kingfisher.yaml
# Then every scan inherits the same self-hosted defaults:
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github --organization my-org \
--config ./kingfisher.yaml
```
### List GitLab repositories
```bash

View file

@ -219,8 +219,9 @@ KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://github.com/org/private_repo.gi
For GitHub Enterprise Server (GHES) or any self-hosted GitHub install, you
need two flags:
- `--github-api-url <URL>` — points the **enumeration / clone** flow at the
custom API root (typically `https://ghe.example.com/api/v3/`).
- `--api-url <URL>` (on `kingfisher scan github`) — points the
**enumeration / clone** flow at the custom API root (typically
`https://ghe.example.com/api/v3/`).
- `--endpoint github=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitHub PATs Kingfisher discovers in the
scanned source are checked against your GHE rather than `api.github.com`.
@ -229,43 +230,43 @@ need two flags:
# 1. Scan every org repo on GHE and validate discovered tokens against the same instance
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 2. Scan a single GHE repo by URL (positional target)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://ghe.corp.example.com/org/repo.git \
--endpoint github=https://ghe.corp.example.com
# 3. Scan ALL orgs on a GHE instance (requires non-default --github-api-url)
# 3. Scan ALL orgs on a GHE instance (requires non-default --api-url)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--all-orgs \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 4. GHE on a private network — add --allow-internal-ips so the validator
# can reach RFC1918 / loopback hosts (SSRF guard is on by default).
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.internal/api/v3/ \
--api-url https://ghe.internal/api/v3/ \
--endpoint github=https://ghe.internal \
--allow-internal-ips
# 5. Validate a single PAT against GHE without scanning anything
kingfisher validate --rule github \
--endpoint github=https://ghe.corp.example.com \
"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"<your-github-pat>"
# 6. Revoke (delete) a confirmed-leaked PAT against GHE
kingfisher revoke --rule github \
--endpoint github=https://ghe.corp.example.com \
"ghp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
"<your-github-pat>"
```
`--github-api-url` is the GHE *cloning* root that Kingfisher walks to
enumerate orgs, repos, and contributors. `--endpoint github=…` is the
*validator* root used to live-check discovered tokens. They are usually the
same host, but they're separate flags because some deployments front-load
auth (an SSO portal for repo access vs. a direct API endpoint for token
`--api-url` is the GHE *cloning* root that Kingfisher walks to enumerate
orgs, repos, and contributors. `--endpoint github=…` is the *validator*
root used to live-check discovered tokens. They are usually the same host,
but they're separate flags because some deployments front-load auth (an
SSO portal for repo access vs. a direct API endpoint for token
validation).
## GitLab
@ -343,8 +344,9 @@ KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.com/group/private_pro
For GitLab self-hosted (Omnibus, Helm, or Cloud Native), pair the
enumeration flag with a matching validation endpoint:
- `--gitlab-api-url <URL>` — points the **enumeration / clone** flow at
the custom GitLab root (typically `https://gitlab.example.com/`).
- `--api-url <URL>` (on `kingfisher scan gitlab`) — points the
**enumeration / clone** flow at the custom GitLab root (typically
`https://gitlab.example.com/`).
- `--endpoint gitlab=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitLab PATs found in the scanned
source are checked against your self-hosted GitLab rather than
@ -355,36 +357,36 @@ enumeration flag with a matching validation endpoint:
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--include-subgroups \
--gitlab-api-url https://gitlab.corp.example.com/ \
--api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 2. Scan a single self-hosted GitLab project by URL
KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.corp.example.com/group/project.git \
--endpoint gitlab=https://gitlab.corp.example.com
# 3. Scan ALL groups on a self-hosted GitLab (requires non-default --gitlab-api-url)
# 3. Scan ALL groups on a self-hosted GitLab (requires non-default --api-url)
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--all-groups \
--gitlab-api-url https://gitlab.corp.example.com/ \
--api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 4. Self-hosted GitLab on a private network — add --allow-internal-ips so
# the validator can reach RFC1918 / loopback hosts.
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--gitlab-api-url https://gitlab.internal/ \
--api-url https://gitlab.internal/ \
--endpoint gitlab=https://gitlab.internal \
--allow-internal-ips
# 5. Validate a single PAT against self-hosted GitLab without scanning anything
kingfisher validate --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"glpat-xxxxxxxxxxxxxxxxxxxx"
"<your-gitlab-pat>"
# 6. Revoke (delete) a confirmed-leaked PAT against self-hosted GitLab
kingfisher revoke --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"glpat-xxxxxxxxxxxxxxxxxxxx"
"<your-gitlab-pat>"
```
### Many endpoints at once: `--endpoint-config`
@ -407,7 +409,7 @@ endpoints:
```bash
KF_GITHUB_TOKEN="ghp_…" KF_GITLAB_TOKEN="glpat-…" kingfisher scan github \
--organization my-org \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint-config ./kingfisher-endpoints.yml \
--allow-internal-ips
```
@ -716,10 +718,10 @@ To use basic authentication instead, also set `KF_CONFLUENCE_USER` to your Confl
### Scan Slack messages matching a search query
```bash
KF_SLACK_TOKEN="xoxp-1234..." kingfisher scan slack "from:username has:link" \
KF_SLACK_TOKEN="<your-slack-user-token>" kingfisher scan slack "from:username has:link" \
--max-results 1000
KF_SLACK_TOKEN="xoxp-1234..." kingfisher scan slack "akia" \
KF_SLACK_TOKEN="<your-slack-user-token>" kingfisher scan slack "akia" \
--max-results 1000
```
@ -805,7 +807,7 @@ The token is sent as the `X-Api-Key` header. Either `KF_POSTMAN_TOKEN` or `POSTM
> Top-level `kingfisher scan --postman-*` flags remain accepted as hidden aliases for backward compatibility, but new usage should prefer the `kingfisher scan postman` subcommand shown above.
**Out of scope:** Postman Vault secrets are client-side and not reachable via the API. The Postman API Network does not expose a search endpoint; supply specific public-workspace IDs via `--postman-workspace` to scan public surfaces.
**Out of scope:** Postman Vault secrets are client-side and not reachable via the API. The Postman API Network does not expose a search endpoint; supply specific public-workspace IDs via `kingfisher scan postman --workspace` to scan public surfaces.
## Environment Variables

View file

@ -211,6 +211,61 @@ kingfisher scan https://github.com/org/repo.git --repo-artifacts
KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://github.com/org/private_repo.git --repo-artifacts
```
### Scan a GitHub Enterprise / self-hosted GitHub instance
For GitHub Enterprise Server (GHES) or any self-hosted GitHub install, you
need two flags:
- `--api-url <URL>` (on `kingfisher scan github`) — points the
**enumeration / clone** flow at the custom API root (typically
`https://ghe.example.com/api/v3/`).
- `--endpoint github=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitHub PATs Kingfisher discovers in the
scanned source are checked against your GHE rather than `api.github.com`.
```bash
# 1. Scan every org repo on GHE and validate discovered tokens against the same instance
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 2. Scan a single GHE repo by URL (positional target)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan https://ghe.corp.example.com/org/repo.git \
--endpoint github=https://ghe.corp.example.com
# 3. Scan ALL orgs on a GHE instance (requires non-default --api-url)
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--all-orgs \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint github=https://ghe.corp.example.com
# 4. GHE on a private network — add --allow-internal-ips so the validator
# can reach RFC1918 / loopback hosts (SSRF guard is on by default).
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github \
--organization my-org \
--api-url https://ghe.internal/api/v3/ \
--endpoint github=https://ghe.internal \
--allow-internal-ips
# 5. Validate a single PAT against GHE without scanning anything
kingfisher validate --rule github \
--endpoint github=https://ghe.corp.example.com \
"<your-github-pat>"
# 6. Revoke (delete) a confirmed-leaked PAT against GHE
kingfisher revoke --rule github \
--endpoint github=https://ghe.corp.example.com \
"<your-github-pat>"
```
`--api-url` is the GHE *cloning* root that Kingfisher walks to enumerate
orgs, repos, and contributors. `--endpoint github=…` is the *validator*
root used to live-check discovered tokens. They are usually the same host,
but they're separate flags because some deployments front-load auth (an
SSO portal for repo access vs. a direct API endpoint for token
validation).
## GitLab
### Scan GitLab group (requires `KF_GITLAB_TOKEN`)
@ -281,6 +336,100 @@ kingfisher scan https://gitlab.com/group/project.git --repo-artifacts
KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.com/group/private_project.git --repo-artifacts
```
### Scan a self-hosted (Omnibus / Cloud Native) GitLab instance
For GitLab self-hosted (Omnibus, Helm, or Cloud Native), pair the
enumeration flag with a matching validation endpoint:
- `--api-url <URL>` (on `kingfisher scan gitlab`) — points the
**enumeration / clone** flow at the custom GitLab root (typically
`https://gitlab.example.com/`).
- `--endpoint gitlab=<URL>` — points the **token validation / revocation**
flow at the same instance, so any GitLab PATs found in the scanned
source are checked against your self-hosted GitLab rather than
`gitlab.com`.
```bash
# 1. Scan a self-hosted group and validate discovered tokens against the same instance
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--include-subgroups \
--api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 2. Scan a single self-hosted GitLab project by URL
KF_GITLAB_TOKEN="glpat-…" kingfisher scan https://gitlab.corp.example.com/group/project.git \
--endpoint gitlab=https://gitlab.corp.example.com
# 3. Scan ALL groups on a self-hosted GitLab (requires non-default --api-url)
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--all-groups \
--api-url https://gitlab.corp.example.com/ \
--endpoint gitlab=https://gitlab.corp.example.com
# 4. Self-hosted GitLab on a private network — add --allow-internal-ips so
# the validator can reach RFC1918 / loopback hosts.
KF_GITLAB_TOKEN="glpat-…" kingfisher scan gitlab \
--group my-group \
--api-url https://gitlab.internal/ \
--endpoint gitlab=https://gitlab.internal \
--allow-internal-ips
# 5. Validate a single PAT against self-hosted GitLab without scanning anything
kingfisher validate --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"<your-gitlab-pat>"
# 6. Revoke (delete) a confirmed-leaked PAT against self-hosted GitLab
kingfisher revoke --rule gitlab \
--endpoint gitlab=https://gitlab.corp.example.com \
"<your-gitlab-pat>"
```
### Many endpoints at once: `--endpoint-config`
If you maintain a fleet of self-hosted instances (GHE, self-hosted GitLab,
Gitea, Jira DC, Confluence, Artifactory), put them in a single YAML file
and reference it instead of repeating `--endpoint` on every command:
```yaml
# kingfisher-endpoints.yml
endpoints:
github: https://ghe.corp.example.com
gitlab: https://gitlab.corp.example.com
gitea: https://gitea.corp.example.com
jira: https://jira.corp.example.com
confluence: https://wiki.corp.example.com
artifactory: http://artifactory.internal:8081
```
```bash
KF_GITHUB_TOKEN="ghp_…" KF_GITLAB_TOKEN="glpat-…" kingfisher scan github \
--organization my-org \
--api-url https://ghe.corp.example.com/api/v3/ \
--endpoint-config ./kingfisher-endpoints.yml \
--allow-internal-ips
```
### Tip: bake the endpoints into `kingfisher.yaml`
Once you've worked out the right flags, capture them as project defaults
so every scan uses the same config:
```bash
kingfisher config init \
--github-api-url https://ghe.corp.example.com/api/v3/ \
--gitlab-api-url https://gitlab.corp.example.com/ \
--endpoint github=https://ghe.corp.example.com \
--endpoint gitlab=https://gitlab.corp.example.com \
--allow-internal-ips \
> kingfisher.yaml
# Then every scan inherits the same self-hosted defaults:
KF_GITHUB_TOKEN="ghp_…" kingfisher scan github --organization my-org \
--config ./kingfisher.yaml
```
### List GitLab repositories
```bash
@ -566,10 +715,10 @@ To use basic authentication instead, also set `KF_CONFLUENCE_USER` to your Confl
### Scan Slack messages matching a search query
```bash
KF_SLACK_TOKEN="xoxp-1234..." kingfisher scan slack "from:username has:link" \
KF_SLACK_TOKEN="<your-slack-user-token>" kingfisher scan slack "from:username has:link" \
--max-results 1000
KF_SLACK_TOKEN="xoxp-1234..." kingfisher scan slack "akia" \
KF_SLACK_TOKEN="<your-slack-user-token>" kingfisher scan slack "akia" \
--max-results 1000
```
@ -655,7 +804,7 @@ The token is sent as the `X-Api-Key` header. Either `KF_POSTMAN_TOKEN` or `POSTM
> Top-level `kingfisher scan --postman-*` flags remain accepted as hidden aliases for backward compatibility, but new usage should prefer the `kingfisher scan postman` subcommand shown above.
**Out of scope:** Postman Vault secrets are client-side and not reachable via the API. The Postman API Network does not expose a search endpoint; supply specific public-workspace IDs via `--postman-workspace` to scan public surfaces.
**Out of scope:** Postman Vault secrets are client-side and not reachable via the API. The Postman API Network does not expose a search endpoint; supply specific public-workspace IDs via `kingfisher scan postman --workspace` to scan public surfaces.
## Environment Variables

View file

@ -346,6 +346,24 @@ fn apply_config(
}
}
/// Like `config_wins`, but also inspects a nested provider subcommand's
/// `--api-url` flag. The github/gitlab provider subcommands carry their
/// own `api_url` arg (id `api_url`) that gets propagated to
/// `scan_args.input_specifier_args.{github,gitlab}_api_url` in
/// `into_operation()`. If that nested flag was user-supplied, the config
/// must NOT clobber it.
fn api_url_config_wins(
matches: Option<&clap::ArgMatches>,
outer_id: &str,
subcommand: &str,
) -> bool {
if !config_wins(matches, outer_id) {
return false;
}
let sub = matches.and_then(|m| m.subcommand_matches(subcommand));
config_wins(sub, "api_url")
}
// ---------- Filters: existing v1 list-typed merges ----------------------
scan_args.skip_word.extend(cfg.filters.skip_words.iter().cloned());
scan_args.skip_regex.extend(cfg.filters.skip_regex.iter().cloned());
@ -631,14 +649,21 @@ fn apply_config(
// field. parse_str() already validated this — `unwrap_or_default()`
// would mask a real config bug, so we re-parse and *fail loud* if the
// string somehow does not parse here.
//
// The provider subcommands (`scan github`, `scan gitlab`) expose their
// own `--api-url` flag whose value is propagated into the same runtime
// field by `into_operation()`. `api_url_config_wins` checks both the
// outer hidden alias and the nested subcommand flag so an explicit
// `kingfisher scan github --api-url ...` is never overridden by the
// config file.
if let Some(u) = &cfg.git.github_api_url
&& config_wins(scan_matches, "github_api_url")
&& api_url_config_wins(scan_matches, "github_api_url", "github")
&& let Ok(parsed) = url::Url::parse(u)
{
scan_args.input_specifier_args.github_api_url = parsed;
}
if let Some(u) = &cfg.git.gitlab_api_url
&& config_wins(scan_matches, "gitlab_api_url")
&& api_url_config_wins(scan_matches, "gitlab_api_url", "gitlab")
&& let Ok(parsed) = url::Url::parse(u)
{
scan_args.input_specifier_args.gitlab_api_url = parsed;
@ -2268,4 +2293,95 @@ global:
assert!(global_args.allow_internal_ips);
assert_eq!(global_args.endpoint.len(), 1);
}
/// Regression test: an explicit `--api-url` on the `scan github`
/// subcommand must beat `git.github_api_url` from the config file. The
/// flag lives on `GithubScanArgs` (id `api_url`), not on the outer scan
/// command — checking only the outer matches misses it and the config
/// silently overrode the CLI value.
#[test]
fn github_subcommand_api_url_beats_config() {
let yaml = r#"
git:
github_api_url: https://ghe-from-config.example.com/api/v3/
"#;
let cfg = parse_str(yaml).unwrap();
let (args, matches) = parse(&[
"kingfisher",
"scan",
"github",
"--organization",
"my-org",
"--api-url",
"https://ghe-from-cli.example.com/api/v3/",
]);
let mut global_args = args.global_args.clone();
let mut scan_args = into_scan(args);
super::apply_config(
&mut scan_args,
&mut global_args,
&cfg,
matches.subcommand_matches("scan"),
);
assert_eq!(
scan_args.input_specifier_args.github_api_url.as_str(),
"https://ghe-from-cli.example.com/api/v3/",
);
}
/// And the inverse: when the user did NOT pass `--api-url` at all,
/// `git.github_api_url` from the config should still win over the
/// built-in default `https://api.github.com/`.
#[test]
fn github_config_wins_when_subcommand_api_url_default() {
let yaml = r#"
git:
github_api_url: https://ghe-from-config.example.com/api/v3/
"#;
let cfg = parse_str(yaml).unwrap();
let (args, matches) = parse(&["kingfisher", "scan", "github", "--organization", "my-org"]);
let mut global_args = args.global_args.clone();
let mut scan_args = into_scan(args);
super::apply_config(
&mut scan_args,
&mut global_args,
&cfg,
matches.subcommand_matches("scan"),
);
assert_eq!(
scan_args.input_specifier_args.github_api_url.as_str(),
"https://ghe-from-config.example.com/api/v3/",
);
}
/// Same precedence story for `scan gitlab --api-url`.
#[test]
fn gitlab_subcommand_api_url_beats_config() {
let yaml = r#"
git:
gitlab_api_url: https://gitlab-from-config.example.com/
"#;
let cfg = parse_str(yaml).unwrap();
let (args, matches) = parse(&[
"kingfisher",
"scan",
"gitlab",
"--group",
"my-group",
"--api-url",
"https://gitlab-from-cli.example.com/",
]);
let mut global_args = args.global_args.clone();
let mut scan_args = into_scan(args);
super::apply_config(
&mut scan_args,
&mut global_args,
&cfg,
matches.subcommand_matches("scan"),
);
assert_eq!(
scan_args.input_specifier_args.gitlab_api_url.as_str(),
"https://gitlab-from-cli.example.com/",
);
}
}