Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/copilot-instructions.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,7 @@ func CommandRun(cmd *cobra.Command, args []string) {
**Migration policy (mandatory):**
- When modifying an existing command, migrate that touched command to `config.NewCommandSetup`.
- Do not leave mixed setup styles in the same command implementation.
- `config.AutoBindFlags` is still an internal building block, but command code should use `NewCommandSetup`.
- Use `config.NewCommandSetup` for command binding and validation.

**Key naming convention:**
- Platform settings: `<platform>.<key>` (e.g., `github.url`, `gitlab.token`)
Expand All @@ -239,7 +239,7 @@ func CommandRun(cmd *cobra.Command, args []string) {

**DO NOT:**
- Read flags directly with `cmd.Flags().GetString()` - always use config system
- Use `config.BindCommandFlags` - it's deprecated
- Use legacy binder APIs removed from `pkg/config`
- Skip required key validation for mandatory config values

### Package Organization
Expand Down
28 changes: 15 additions & 13 deletions internal/cmd/bitbucket/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,18 @@ var options = BitBucketScanOptions{
}
var maxArtifactSize string

var flagBindings = map[string]string{
"url": "bitbucket.url",
"token": "bitbucket.token",
"email": "bitbucket.email",
"cookie": "bitbucket.cookie",
"threads": "common.threads",
"truffle-hog-verification": "common.trufflehog_verification",
"max-artifact-size": "common.max_artifact_size",
"confidence": "common.confidence_filter",
"hit-timeout": "common.hit_timeout",
}

func NewScanCmd() *cobra.Command {
scanCmd := &cobra.Command{
Use: "scan",
Expand Down Expand Up @@ -63,19 +75,9 @@ pipeleek bb scan --token ATATTxxxxxx --email auser@example.com --public --maxPip
}

func Scan(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, map[string]string{
"url": "bitbucket.url",
"token": "bitbucket.token",
"email": "bitbucket.email",
"cookie": "bitbucket.cookie",
"threads": "common.threads",
"truffle-hog-verification": "common.trufflehog_verification",
"max-artifact-size": "common.max_artifact_size",
"confidence": "common.confidence_filter",
"hit-timeout": "common.hit_timeout",
}); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
MustBind()

options.BitBucketURL = config.GetString("bitbucket.url")
options.AccessToken = config.GetString("bitbucket.token")
Expand Down
10 changes: 5 additions & 5 deletions internal/cmd/circle/scan/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ func TestCircleScanFlagBindings(t *testing.T) {
t.Fatalf("Failed to set artifacts flag: %v", err)
}

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("circle.scan.org"); got != "my-org" {
Expand All @@ -95,11 +95,11 @@ func TestCircleScanEnvVarBinding(t *testing.T) {

cmd := NewScanCmd()

if err := config.AutoBindFlags(cmd, map[string]string{
if err := config.NewCommandSetup(cmd).WithFlagBindings(map[string]string{
"org": "circle.scan.org",
"artifacts": "circle.scan.artifacts",
}); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
}).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("circle.scan.org"); got != "env-org" {
Expand Down
12 changes: 4 additions & 8 deletions internal/cmd/devops/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,10 @@ pipeleek ad scan --token <azdo_pat> --username auser --artifacts --organization
}

func Scan(cmd *cobra.Command, args []string) {
// #nosec G101 -- "token" is a configuration key name, not a hardcoded credential
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("azure_devops.token", "azure_devops.username"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("azure_devops.token", "azure_devops.username").
MustBind()

options.DevOpsURL = config.GetString("azure_devops.url")
options.AccessToken = config.GetString("azure_devops.token")
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/devops/scan/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,8 @@ func TestDevOpsScanFlagBindings(t *testing.T) {
t.Fatalf("Failed to set owned flag: %v", err)
}

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("azure_devops.scan.organization"); got != "my-org" {
Expand Down Expand Up @@ -66,8 +66,8 @@ func TestDevOpsScanEnvVarBinding(t *testing.T) {

cmd := NewScanCmd()

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("azure_devops.scan.organization"); got != "env-org" {
Expand Down
11 changes: 4 additions & 7 deletions internal/cmd/gitea/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,10 @@ pipeleek gitea scan --token gitea_token_xxxxx --url https://gitea.example.com --
}

func Scan(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("gitea.url", "gitea.token"); err != nil {
log.Fatal().Err(err).Msg("Missing required configuration")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitea.url", "gitea.token").
MustBind()

giteaURL := config.GetString("gitea.url")
giteaToken := config.GetString("gitea.token")
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/gitea/scan/scan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,8 +72,8 @@ func TestGiteaScanFlagBindings(t *testing.T) {
t.Fatalf("Failed to set owned flag: %v", err)
}

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("gitea.scan.organization"); got != "my-org" {
Expand Down Expand Up @@ -101,8 +101,8 @@ func TestGiteaScanEnvVarBinding(t *testing.T) {

cmd := NewScanCmd()

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("gitea.scan.organization"); got != "env-org" {
Expand Down
11 changes: 4 additions & 7 deletions internal/cmd/github/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,13 +87,10 @@ pipeleek gh scan --token github_pat_xxxxxxxxxxx --artifacts --repo owner/repo
}

func Scan(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("github.token"); err != nil {
log.Fatal().Err(err).Msg("Missing required configuration")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("github.token").
MustBind()

options.GitHubURL = config.GetString("github.url")
options.AccessToken = config.GetString("github.token")
Expand Down
8 changes: 4 additions & 4 deletions internal/cmd/github/scan/scan_flag_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,8 @@ func TestGitHubScanFlagBindings(t *testing.T) {
t.Fatalf("Failed to set owned flag: %v", err)
}

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("github.scan.org"); got != "my-org" {
Expand Down Expand Up @@ -80,8 +80,8 @@ func TestGitHubScanEnvVarBinding(t *testing.T) {

cmd := NewScanCmd()

if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
t.Fatalf("AutoBindFlags failed: %v", err)
if err := config.NewCommandSetup(cmd).WithFlagBindings(flagBindings).Bind(); err != nil {
t.Fatalf("Bind failed: %v", err)
}

if got := config.GetString("github.scan.org"); got != "env-org" {
Expand Down
12 changes: 4 additions & 8 deletions internal/cmd/gitlab/container/artipacked/artipacked.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package artipacked
import (
"github.com/CompassSecurity/pipeleek/pkg/config"
pkgcontainer "github.com/CompassSecurity/pipeleek/pkg/gitlab/container/artipacked"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
gitlab "gitlab.com/gitlab-org/api/client-go"
)
Expand Down Expand Up @@ -36,17 +35,14 @@ func NewArtipackedCmd() *cobra.Command {
Short: "Audit for artipacked misconfiguration (secrets in container images)",
Long: "Scan for dangerous container build patterns that leak secrets like COPY . /path without .dockerignore",
Run: func(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token").
MustBind()

gitlabUrl := config.GetString("gitlab.url")
gitlabApiToken := config.GetString("gitlab.token")

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}

owned = config.GetBool("gitlab.container.artipacked.owned")
member = config.GetBool("gitlab.container.artipacked.member")
repository = config.GetString("gitlab.container.artipacked.repo")
Expand Down
15 changes: 5 additions & 10 deletions internal/cmd/gitlab/renovate/autodiscovery/autodiscovery.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package autodiscovery

import (
"github.com/rs/zerolog/log"

"github.com/CompassSecurity/pipeleek/pkg/config"
pkgrenovate "github.com/CompassSecurity/pipeleek/pkg/gitlab/renovate/autodiscovery"
"github.com/spf13/cobra"
Expand All @@ -11,7 +9,7 @@ import (
var (
autodiscoveryProjectName string
autodiscoveryUsername string
autodiscoveryAddCICD bool
autodiscoveryAddCICD bool
)

var flagBindings = map[string]string{
Expand All @@ -35,13 +33,10 @@ pipeleek gl renovate autodiscovery --token glpat-xxxxxxxxxxx --url https://gitla
pipeleek gl renovate autodiscovery --token glpat-xxxxxxxxxxx --url https://gitlab.mydomain.com --project-name my-exploit-project --add-renovate-cicd-for-debugging
`,
Run: func(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token").
MustBind()

gitlabUrl := config.GetString("gitlab.url")
gitlabApiToken := config.GetString("gitlab.token")
Expand Down
18 changes: 7 additions & 11 deletions internal/cmd/gitlab/renovate/bots/bots.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package bots
import (
"github.com/CompassSecurity/pipeleek/pkg/config"
pkgbots "github.com/CompassSecurity/pipeleek/pkg/gitlab/renovate/bots"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
)

Expand All @@ -12,9 +11,9 @@ var (
)

var flagBindings = map[string]string{
"url": "gitlab.url",
"token": "gitlab.token",
"term": "gitlab.renovate.bots.term",
"url": "gitlab.url",
"token": "gitlab.token",
"term": "gitlab.renovate.bots.term",
}

func NewBotsCmd() *cobra.Command {
Expand All @@ -23,13 +22,10 @@ func NewBotsCmd() *cobra.Command {
Short: "Enumerate potential Renovate bot user accounts",
Long: "Search GitLab users by term, inspect their profile visibility and activity, and highlight potential Renovate bot accounts.",
Run: func(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token", "gitlab.renovate.bots.term"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token", "gitlab.renovate.bots.term").
MustBind()

gitlabUrl := config.GetString("gitlab.url")
gitlabApiToken := config.GetString("gitlab.token")
Expand Down
13 changes: 4 additions & 9 deletions internal/cmd/gitlab/renovate/enum/enum.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package enum
import (
"github.com/CompassSecurity/pipeleek/pkg/config"
pkgrenovate "github.com/CompassSecurity/pipeleek/pkg/gitlab/renovate/enum"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
gitlab "gitlab.com/gitlab-org/api/client-go"
)
Expand Down Expand Up @@ -41,18 +40,14 @@ func NewEnumCmd() *cobra.Command {
Use: "enum [no options!]",
Short: "Enumerate Renovate configurations",
Run: func(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token").
MustBind()

// Get gitlab URL and token from config (supports all three methods)
gitlabUrl := config.GetString("gitlab.url")
gitlabApiToken := config.GetString("gitlab.token")

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}

// All flags can come from config, CLI flags, or env vars via Viper
owned = config.GetBool("gitlab.renovate.enum.owned")
member = config.GetBool("gitlab.renovate.enum.member")
Expand Down
11 changes: 4 additions & 7 deletions internal/cmd/gitlab/renovate/privesc/privesc.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,10 @@ func NewPrivescCmd() *cobra.Command {
Long: "Inject a job into the CI/CD pipeline of the project's default branch by adding a commit (race condition) to a Renovate Bot branch, which is then auto-merged into the main branch. Assumes the Renovate Bot has owner/maintainer access whereas you only have developer access. See https://blog.compass-security.com/2025/05/renovate-keeping-your-updates-secure/",
Example: `pipeleek gl renovate privesc --token glpat-xxxxxxxxxxx --url https://gitlab.mydomain.com --repo mygroup/myproject --renovate-branches-regex 'renovate/.*'`,
Run: func(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token", "gitlab.renovate.privesc.repo"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token", "gitlab.renovate.privesc.repo").
MustBind()

privescRenovateBranchesRegex = config.GetString("gitlab.renovate.privesc.renovate_branches_regex")
privescProject = config.GetString("gitlab.renovate.privesc.repo")
Expand Down
11 changes: 4 additions & 7 deletions internal/cmd/gitlab/scan/scan.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,13 +98,10 @@ pipeleek gl scan --token glpat-xxxxxxxxxxx --url https://gitlab.example.com --na
}

func Scan(cmd *cobra.Command, args []string) {
if err := config.AutoBindFlags(cmd, flagBindings); err != nil {
log.Fatal().Err(err).Msg("Failed to bind command flags to configuration keys")
}

if err := config.RequireConfigKeys("gitlab.url", "gitlab.token"); err != nil {
log.Fatal().Err(err).Msg("required configuration missing")
}
config.NewCommandSetup(cmd).
WithFlagBindings(flagBindings).
RequireKeys("gitlab.url", "gitlab.token").
MustBind()

gitlabUrl := config.GetString("gitlab.url")
gitlabApiToken := config.GetString("gitlab.token")
Expand Down
Loading
Loading