Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a show command to the Diki CLI #412

Merged
merged 27 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
70446dc
Add supported versions metadata for each ruleset instance
georgibaltiev Dec 23, 2024
5c608f6
Add ruleset version resolving methods to the provider definitions
georgibaltiev Dec 23, 2024
a69a4d4
Add comments
georgibaltiev Dec 23, 2024
d8ae1c3
Add show command implementation
georgibaltiev Dec 23, 2024
30719f1
Move JSON defined structures into a separate module
georgibaltiev Dec 27, 2024
686523d
Move ruleset user-friendly names into constant variables for broader …
georgibaltiev Dec 27, 2024
1de2bb0
Add description comments for the new constants
georgibaltiev Dec 27, 2024
619ac19
Add functions that showcase each provider's metadata
georgibaltiev Dec 27, 2024
6a31e32
Refactor showProvider command and additional tabulations
georgibaltiev Dec 27, 2024
d4a4f1c
formatting
georgibaltiev Dec 27, 2024
c5e8f5e
Rename variables and comments in the metadata and builder packages
georgibaltiev Jan 3, 2025
688fadc
Add comment and reference changes to the app command
georgibaltiev Jan 3, 2025
99e3b2e
Add additional comments to the ruleset files
georgibaltiev Jan 3, 2025
683c7b5
Refactor metadata initalizing builder methods
georgibaltiev Jan 3, 2025
98adb5e
Fix typo
georgibaltiev Jan 3, 2025
9011efd
Add constants to the provider definition files
georgibaltiev Jan 3, 2025
ff6f2e6
Add constants to the metadata builder methods
georgibaltiev Jan 3, 2025
03bc32a
Declare and utilize a new string to Metadata map in main.go
georgibaltiev Jan 3, 2025
95bc6bd
Simplify some code
georgibaltiev Jan 3, 2025
98131a6
Tabulation
georgibaltiev Jan 6, 2025
7e20b39
Merge branch 'gardener:main' into add-show-command
georgibaltiev Jan 7, 2025
afe1993
Remove support for version v1r11
georgibaltiev Jan 7, 2025
d5ac7d0
Correct some nits
georgibaltiev Jan 7, 2025
94a0128
Add suggestions
georgibaltiev Jan 21, 2025
271e590
Fix typo
georgibaltiev Jan 21, 2025
7ca3599
Tabulation
georgibaltiev Jan 21, 2025
8fbdbce
Change comments
georgibaltiev Jan 21, 2025
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
68 changes: 67 additions & 1 deletion cmd/diki/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,28 @@ import (
"k8s.io/component-base/version"

"github.com/gardener/diki/pkg/config"
"github.com/gardener/diki/pkg/metadata"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/report"
"github.com/gardener/diki/pkg/ruleset"
)

// NewDikiCommand creates a new command that is used to start Diki.
func NewDikiCommand(providerCreateFuncs map[string]provider.ProviderFromConfigFunc) *cobra.Command {
func NewDikiCommand(providerOptions map[string]provider.ProviderOption) *cobra.Command {
handler := slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo})
logger := slog.New(handler)
slog.SetDefault(logger)

providerCreateFuncs := map[string]provider.ProviderFromConfigFunc{}
for providerID, providerOption := range providerOptions {
providerCreateFuncs[providerID] = providerOption.ProviderFromConfigFunc
}

metadataFuncs := map[string]provider.MetadataFunc{}
for providerID, providerOption := range providerOptions {
metadataFuncs[providerID] = providerOption.MetadataFunc
}

rootCmd := &cobra.Command{
Use: "diki",
Short: "Diki a \"compliance checker\" or sorts, a detective control framework.",
Expand Down Expand Up @@ -124,6 +135,28 @@ e.g. to check compliance of your hyperscaler accounts.`,
addReportGenerateDiffFlags(generateDiffCmd, &generateDiffOpts)
generateCmd.AddCommand(generateDiffCmd)

showCmd := &cobra.Command{
Use: "show",
Short: "Show metadata information for different diki internals, i.e. providers.",
Long: "Show metadata information for different diki internals, i.e. providers.",
RunE: func(_ *cobra.Command, _ []string) error {
return errors.New("show subcommand not selected")
},
}

rootCmd.AddCommand(showCmd)

showProviderCmd := &cobra.Command{
Use: "provider",
Short: "Show detailed information for providers.",
Long: "Show detailed information for providers.",
RunE: func(_ *cobra.Command, args []string) error {
return showProviderCmd(args, metadataFuncs)
},
}

showCmd.AddCommand(showProviderCmd)

return rootCmd
}

Expand Down Expand Up @@ -156,6 +189,39 @@ func addReportGenerateDiffFlags(cmd *cobra.Command, opts *generateDiffOptions) {
cmd.PersistentFlags().Var(cliflag.NewMapStringString(&opts.identityAttributes), "identity-attributes", "The keys are the IDs of the providers that will be present in the generated difference report and the values are metadata attributes to be used as identifiers.")
}

func showProviderCmd(args []string, metadataFuncs map[string]provider.MetadataFunc) error {
if len(args) > 1 {
return errors.New("command 'show provider' accepts at most one provider")
}

if len(args) == 0 {
var providersMetadata []metadata.Provider

for providerID := range metadataFuncs {
providersMetadata = append(providersMetadata, metadata.Provider{ID: providerID, Name: metadataFuncs[providerID]().Name})
}

if bytes, err := json.Marshal(providersMetadata); err != nil {
return err
} else {
fmt.Println(string(bytes))
}
dimityrmirchev marked this conversation as resolved.
Show resolved Hide resolved
return nil
}

metadataFunc, ok := metadataFuncs[args[0]]
if !ok {
return fmt.Errorf("unknown provider: %s", args[0])
}

if bytes, err := json.Marshal(metadataFunc()); err != nil {
return err
} else {
fmt.Println(string(bytes))
}
return nil
}

func generateDiffCmd(args []string, generateDiffOpts generateDiffOptions, rootOpts reportOptions, logger *slog.Logger) error {
if len(args) == 0 {
return errors.New("generate diff command requires a minimum of one filepath argument")
Expand Down
18 changes: 12 additions & 6 deletions cmd/diki/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,21 @@ import (
"github.com/gardener/diki/cmd/diki/app"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/provider/builder"
"github.com/gardener/diki/pkg/provider/garden"
"github.com/gardener/diki/pkg/provider/gardener"
"github.com/gardener/diki/pkg/provider/managedk8s"
"github.com/gardener/diki/pkg/provider/virtualgarden"
)

func main() {
cmd := app.NewDikiCommand(map[string]provider.ProviderFromConfigFunc{
"garden": builder.GardenProviderFromConfig,
"gardener": builder.GardenerProviderFromConfig,
"managedk8s": builder.ManagedK8SProviderFromConfig,
"virtualgarden": builder.VirtualGardenProviderFromConfig,
})
cmd := app.NewDikiCommand(
map[string]provider.ProviderOption{
garden.ProviderID: {ProviderFromConfigFunc: builder.GardenProviderFromConfig, MetadataFunc: builder.GardenProviderMetadata},
gardener.ProviderID: {ProviderFromConfigFunc: builder.GardenerProviderFromConfig, MetadataFunc: builder.GardenerProviderMetadata},
managedk8s.ProviderID: {ProviderFromConfigFunc: builder.ManagedK8SProviderFromConfig, MetadataFunc: builder.ManagedK8SProviderMetadata},
virtualgarden.ProviderID: {ProviderFromConfigFunc: builder.VirtualGardenProviderFromConfig, MetadataFunc: builder.VirtualGardenProviderMetadata},
},
)

if err := cmd.ExecuteContext(controllerruntime.SetupSignalHandler()); err != nil {
log.Fatal(err)
Expand Down
37 changes: 37 additions & 0 deletions pkg/metadata/metadata.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: 2025 SAP SE or an SAP affiliate company and Gardener contributors
//
// SPDX-License-Identifier: Apache-2.0

package metadata

// Version is used to represent a specific version of a ruleset.
type Version struct {
// Version is the name of the ruleset release.
Version string `json:"version"`
// Latest shows if the specific version is the latest one.
Latest bool `json:"latest"`
}

// Ruleset is used to represent a specific ruleset and it's metadata.
type Ruleset struct {
// ID is the unique identifier of the ruleset.
ID string `json:"id"`
// Name is the user-friendly name of the ruleset.
Name string `json:"name"`
// Versions is used to showcase the supported versions of the specific ruleset.
Versions []Version `json:"versions"`
}

// Provider is used to represent an available provider by it's name and unique identifier.
type Provider struct {
// ID is the unique identifier of the provider.
ID string `json:"id"`
// Name is the user-friendly name of the provider.
Name string `json:"name"`
}

// ProviderDetailed is used to represent a specific provider and it's metadata.
type ProviderDetailed struct {
Provider
Rulesets []Ruleset `json:"rulesets"`
}
44 changes: 44 additions & 0 deletions pkg/provider/builder/garden.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"log/slog"

"github.com/gardener/diki/pkg/config"
"github.com/gardener/diki/pkg/metadata"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/provider/garden"
"github.com/gardener/diki/pkg/provider/garden/ruleset/securityhardenedshoot"
Expand Down Expand Up @@ -48,3 +49,46 @@ func GardenProviderFromConfig(conf config.ProviderConfig) (provider.Provider, er

return p, nil
}

// gardenGetSupportedVersions returns the Supported Versions of a specific ruleset that is supported by the Garden provider.
func gardenGetSupportedVersions(ruleset string) []string {
switch ruleset {
case securityhardenedshoot.RulesetID:
return securityhardenedshoot.SupportedVersions
default:
return nil
}
}

// GardenProviderMetadata returns available metadata for the Garden Provider and it's supported rulesets.
func GardenProviderMetadata() metadata.ProviderDetailed {
providerMetadata := metadata.ProviderDetailed{
Provider: metadata.Provider{
ID: garden.ProviderID,
Name: garden.ProviderName,
},
Rulesets: []metadata.Ruleset{
{
ID: securityhardenedshoot.RulesetID,
Name: securityhardenedshoot.RulesetName,
},
},
}

for i := range providerMetadata.Rulesets {
supportedVersions := gardenGetSupportedVersions(providerMetadata.Rulesets[i].ID)
for _, supportedVersion := range supportedVersions {
providerMetadata.Rulesets[i].Versions = append(
providerMetadata.Rulesets[i].Versions,
metadata.Version{Version: supportedVersion, Latest: false},
)
}

// Mark the first version as latest as the versions are sorted from newest to oldest
if len(providerMetadata.Rulesets[i].Versions) > 0 {
providerMetadata.Rulesets[i].Versions[0].Latest = true
}
}

return providerMetadata
}
44 changes: 44 additions & 0 deletions pkg/provider/builder/gardener.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"k8s.io/client-go/rest"

"github.com/gardener/diki/pkg/config"
"github.com/gardener/diki/pkg/metadata"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/provider/gardener"
"github.com/gardener/diki/pkg/provider/gardener/ruleset/disak8sstig"
Expand Down Expand Up @@ -61,3 +62,46 @@ func setConfigDefaults(config *rest.Config) {
config.Burst = 40
}
}

// gardenerGetSupportedVersions returns the Supported Versions of a specific ruleset that is supported by the Gardener provider.
func gardenerGetSupportedVersions(ruleset string) []string {
switch ruleset {
case disak8sstig.RulesetID:
return disak8sstig.SupportedVersions
default:
return nil
}
}

// GardenerProviderMetadata returns available metadata for the Gardener Provider and it's supported rulesets.
func GardenerProviderMetadata() metadata.ProviderDetailed {
providerMetadata := metadata.ProviderDetailed{
Provider: metadata.Provider{
ID: gardener.ProviderID,
Name: gardener.ProviderName,
},
Rulesets: []metadata.Ruleset{
{
ID: disak8sstig.RulesetID,
Name: disak8sstig.RulesetName,
},
},
}

for i := range providerMetadata.Rulesets {
supportedVersions := gardenerGetSupportedVersions(providerMetadata.Rulesets[i].ID)
for _, supportedVersion := range supportedVersions {
providerMetadata.Rulesets[i].Versions = append(
providerMetadata.Rulesets[i].Versions,
metadata.Version{Version: supportedVersion, Latest: false},
)
}

// Mark the first version as latest as the versions are sorted from newest to oldest
if len(providerMetadata.Rulesets[i].Versions) > 0 {
providerMetadata.Rulesets[i].Versions[0].Latest = true
}
}

return providerMetadata
}
50 changes: 50 additions & 0 deletions pkg/provider/builder/managedk8s.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"log/slog"

"github.com/gardener/diki/pkg/config"
"github.com/gardener/diki/pkg/metadata"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/provider/managedk8s"
"github.com/gardener/diki/pkg/provider/managedk8s/ruleset/disak8sstig"
Expand Down Expand Up @@ -57,3 +58,52 @@ func ManagedK8SProviderFromConfig(conf config.ProviderConfig) (provider.Provider

return p, nil
}

// managedK8SGetSupportedVersions returns the supported versions of a specific ruleset that is supported by the Managed K8S provider.
func managedK8SGetSupportedVersions(ruleset string) []string {
switch ruleset {
case securityhardenedk8s.RulesetID:
return securityhardenedk8s.SupportedVersions
case disak8sstig.RulesetID:
return disak8sstig.SupportedVersions
default:
return nil
}
}

// ManagedK8SProviderMetadata returns available metadata for the Managed Kubernetes Provider and it's supported rulesets.
func ManagedK8SProviderMetadata() metadata.ProviderDetailed {
providerMetadata := metadata.ProviderDetailed{
Provider: metadata.Provider{
ID: managedk8s.ProviderID,
Name: managedk8s.ProviderName,
},
Rulesets: []metadata.Ruleset{
{
ID: securityhardenedk8s.RulesetID,
Name: securityhardenedk8s.RulesetName,
},
{
ID: disak8sstig.RulesetID,
Name: disak8sstig.RulesetName,
},
},
}

for i := range providerMetadata.Rulesets {
supportedVersions := managedK8SGetSupportedVersions(providerMetadata.Rulesets[i].ID)
for _, supportedVersion := range supportedVersions {
providerMetadata.Rulesets[i].Versions = append(
providerMetadata.Rulesets[i].Versions,
metadata.Version{Version: supportedVersion, Latest: false},
)
}

// Mark the first version as latest as the versions are sorted from newest to oldest
if len(providerMetadata.Rulesets[i].Versions) > 0 {
providerMetadata.Rulesets[i].Versions[0].Latest = true
}
}

return providerMetadata
}
44 changes: 44 additions & 0 deletions pkg/provider/builder/virtualgarden.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"log/slog"

"github.com/gardener/diki/pkg/config"
"github.com/gardener/diki/pkg/metadata"
"github.com/gardener/diki/pkg/provider"
"github.com/gardener/diki/pkg/provider/virtualgarden"
"github.com/gardener/diki/pkg/provider/virtualgarden/ruleset/disak8sstig"
Expand Down Expand Up @@ -48,3 +49,46 @@ func VirtualGardenProviderFromConfig(conf config.ProviderConfig) (provider.Provi

return p, nil
}

// virtualGardenGetSupportedVersions returns the supported versions of a specific ruleset that is supported by the Virtual Garden provider.
func virtualGardenGetSupportedVersions(ruleset string) []string {
switch ruleset {
case disak8sstig.RulesetID:
return disak8sstig.SupportedVersions
default:
return nil
}
}

// VirtualGardenProviderMetadata returns available metadata for the Virtual Garden Provider and it's supported rulesets.
func VirtualGardenProviderMetadata() metadata.ProviderDetailed {
providerMetadata := metadata.ProviderDetailed{
Provider: metadata.Provider{
ID: virtualgarden.ProviderID,
Name: virtualgarden.ProviderName,
},
Rulesets: []metadata.Ruleset{
{
ID: disak8sstig.RulesetID,
Name: disak8sstig.RulesetName,
},
},
}

for i := range providerMetadata.Rulesets {
supportedVersions := virtualGardenGetSupportedVersions(providerMetadata.Rulesets[i].ID)
for _, supportedVersion := range supportedVersions {
providerMetadata.Rulesets[i].Versions = append(
providerMetadata.Rulesets[i].Versions,
metadata.Version{Version: supportedVersion, Latest: false},
)
}

// Mark the first version as latest as the versions are sorted from newest to oldest
if len(providerMetadata.Rulesets[i].Versions) > 0 {
providerMetadata.Rulesets[i].Versions[0].Latest = true
}
}

return providerMetadata
}
Loading
Loading