Skip to content

Commit

Permalink
Add a show command to the Diki CLI (#412)
Browse files Browse the repository at this point in the history
* Add supported versions metadata for each ruleset instance

* Add ruleset version resolving methods to the provider definitions

* Add comments

* Add show command implementation

* Move JSON defined structures into a separate module

* Move ruleset user-friendly names into constant variables for broader access

* Add description comments for the new constants

* Add functions that showcase each provider's metadata

* Refactor showProvider command and additional tabulations

* formatting

* Rename variables and comments in the metadata and builder packages

* Add comment and reference changes to the app command

* Add additional comments to the ruleset files

* Refactor metadata initalizing builder methods

* Fix typo

* Add constants to the provider definition files

* Add constants to the metadata builder methods

* Declare and utilize a new string to Metadata map in main.go

* Simplify some code

* Tabulation

* Remove support for version v1r11

* Correct some nits

* Add suggestions

* Fix typo

* Tabulation

* Change comments
  • Loading branch information
georgibaltiev authored Jan 22, 2025
1 parent 7778256 commit 6e41ef6
Show file tree
Hide file tree
Showing 17 changed files with 382 additions and 18 deletions.
68 changes: 67 additions & 1 deletion cmd/diki/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,29 @@ 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/rule"
"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 @@ -126,6 +137,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 @@ -159,6 +192,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))
}
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

0 comments on commit 6e41ef6

Please sign in to comment.