- Added support for scanning gitlab subgroups, with 'kingfisher scan --gitlab-group my-group --gitlab-include-subgroups'

This commit is contained in:
Mick Grove 2025-08-14 09:25:18 -07:00
commit 14fccc9cc6
14 changed files with 38 additions and 2 deletions

View file

@ -384,6 +384,8 @@ KF_GITHUB_TOKEN="ghp_…" kingfisher scan --git-url https://github.com/org/priva
```bash
kingfisher scan --gitlab-group my-group
# include repositories from all nested subgroups
kingfisher scan --gitlab-group my-group --gitlab-include-subgroups
```
### Scan GitLab user
@ -402,6 +404,8 @@ kingfisher scan --git-url https://gitlab.com/group/project.git
```bash
kingfisher gitlab repos list --group my-group
# include repositories from all nested subgroups
kingfisher gitlab repos list --group my-group --include-subgroups
```
## Scanning Jira

View file

@ -56,6 +56,10 @@ pub struct GitLabRepoSpecifiers {
/// Filter by repository type
#[arg(long, default_value_t = GitLabRepoType::All, alias = "gitlab-repo-type")]
pub repo_type: GitLabRepoType,
/// Include repositories from subgroups of the specified groups
#[arg(long, alias = "gitlab-include-subgroups")]
pub include_subgroups: bool,
}
impl GitLabRepoSpecifiers {

View file

@ -89,6 +89,10 @@ pub struct InputSpecifierArgs {
#[arg(long, default_value_t = GitLabRepoType::All)]
pub gitlab_repo_type: GitLabRepoType,
/// Include projects from GitLab subgroups when scanning groups
#[arg(long, alias = "include-subgroups")]
pub gitlab_include_subgroups: bool,
/// Jira base URL (e.g. https://jira.example.com)
#[arg(long, value_hint = ValueHint::Url, requires = "jql")]
pub jira_url: Option<Url>,

View file

@ -42,6 +42,7 @@ pub struct RepoSpecifiers {
pub user: Vec<String>,
pub group: Vec<String>,
pub all_groups: bool,
pub include_subgroups: bool,
pub repo_filter: RepoType,
}
@ -137,6 +138,9 @@ pub async fn enumerate_repo_urls(
if matches!(repo_specifiers.repo_filter, RepoType::Owner) {
gp_builder.owned(true);
}
if repo_specifiers.include_subgroups {
gp_builder.include_subgroups(true);
}
let gp_ep = gp_builder.build()?;
let projects: Vec<SimpleProject> = gp_ep.query(&client)?;
@ -162,10 +166,16 @@ pub async fn list_repositories(
users: &[String],
groups: &[String],
all_groups: bool,
include_subgroups: bool,
repo_filter: RepoType,
) -> Result<()> {
let repo_specifiers =
RepoSpecifiers { user: users.to_vec(), group: groups.to_vec(), all_groups, repo_filter };
let repo_specifiers = RepoSpecifiers {
user: users.to_vec(),
group: groups.to_vec(),
all_groups,
include_subgroups,
repo_filter,
};
// Create a progress bar for displaying status
let mut progress = if progress_enabled {

View file

@ -245,6 +245,7 @@ async fn async_main(args: CommandLineArgs) -> Result<()> {
&list_args.repo_specifiers.user,
&list_args.repo_specifiers.group,
list_args.repo_specifiers.all_groups,
list_args.repo_specifiers.include_subgroups,
list_args.repo_specifiers.repo_type.into(),
)
.await?;
@ -282,6 +283,7 @@ fn create_default_scan_args() -> cli::commands::scan::ScanArgs {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::All,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,

View file

@ -84,6 +84,7 @@ mod tests {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::All,
gitlab_include_subgroups: false,
// Jira options
jira_url: None,
jql: None,

View file

@ -182,6 +182,7 @@ pub async fn enumerate_gitlab_repos(
user: args.input_specifier_args.gitlab_user.clone(),
group: args.input_specifier_args.gitlab_group.clone(),
all_groups: args.input_specifier_args.all_gitlab_groups,
include_subgroups: args.input_specifier_args.gitlab_include_subgroups,
repo_filter: args.input_specifier_args.gitlab_repo_type.into(),
};

View file

@ -78,6 +78,7 @@ rules:
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,

View file

@ -65,6 +65,7 @@ fn test_github_remote_scan() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,

View file

@ -64,6 +64,7 @@ fn test_gitlab_remote_scan() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/")?,
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,
@ -169,6 +170,7 @@ fn test_gitlab_remote_scan_no_history() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/")?,
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,

View file

@ -49,6 +49,7 @@ async fn test_redact_hashes_finding_values() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,
confluence_url: None,

View file

@ -55,6 +55,7 @@ impl TestContext {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,
confluence_url: None,
@ -147,6 +148,7 @@ async fn test_scan_slack_messages() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,
confluence_url: None,

View file

@ -121,6 +121,7 @@ async fn test_validation_cache_and_depvars() -> Result<()> {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,

View file

@ -64,6 +64,7 @@ impl TestContext {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,
@ -142,6 +143,7 @@ impl TestContext {
all_gitlab_groups: false,
gitlab_api_url: Url::parse("https://gitlab.com/").unwrap(),
gitlab_repo_type: GitLabRepoType::Owner,
gitlab_include_subgroups: false,
jira_url: None,
jql: None,