-
Notifications
You must be signed in to change notification settings - Fork 6
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: container-registry vulnerabilities (#414)
* bumped cr sdk to v1.1 * run go vendor * added artifacts list and get cmds * added vulnerabilities commands and autocompletions * added info to artifacts autocompletions * added query params * added new repository cmds * regen docs * updated changelog * refactor redundant constants * fix typo * regen docs
- Loading branch information
Showing
124 changed files
with
11,961 additions
and
557 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package artifacts | ||
|
||
import ( | ||
"context" | ||
|
||
"github.com/ionos-cloud/ionosctl/v6/internal/client" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/completions" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/core" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths" | ||
"github.com/spf13/cobra" | ||
) | ||
|
||
var ( | ||
defaultCols = []string{"Id", "TotalVulnerabilities", "FixableVulnerabilities", "MediaType"} | ||
allCols = []string{ | ||
"Id", "Repository", "PushCount", "PullCount", "LastPushed", "TotalVulnerabilities", | ||
"FixableVulnerabilities", "MediaType", "URN", | ||
} | ||
) | ||
|
||
func ArtifactsCmd() *core.Command { | ||
cmd := &core.Command{ | ||
Command: &cobra.Command{ | ||
Use: "artifacts", | ||
Aliases: []string{"a", "art", "artifact"}, | ||
Short: "Artifacts Operations", | ||
Long: "Manage container registry artifacts. " + | ||
"Artifacts are the individual files stored in a repository.", | ||
TraverseChildren: true, | ||
}, | ||
} | ||
|
||
cmd.AddCommand(ArtifactsListCmd()) | ||
cmd.AddCommand(ArtifactsGetCmd()) | ||
|
||
return cmd | ||
} | ||
|
||
func ArtifactsIds(registryId string, repositoryName string) []string { | ||
artifacts, _, err := client.Must().RegistryClient.ArtifactsApi.RegistriesRepositoriesArtifactsGet( | ||
context.Background(), registryId, repositoryName, | ||
).Execute() | ||
if err != nil { | ||
return nil | ||
} | ||
|
||
artifactsConverted, err := json2table.ConvertJSONToTable("items", jsonpaths.ContainerRegistryArtifact, artifacts) | ||
if err != nil { | ||
return nil | ||
} | ||
|
||
return completions.NewCompleter(artifactsConverted, "Id").AddInfo("MediaType").ToString() | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
package artifacts | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/ionos-cloud/ionosctl/v6/commands/container-registry/registry" | ||
"github.com/ionos-cloud/ionosctl/v6/commands/container-registry/repository" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/client" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/constants" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/core" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/tabheaders" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func ArtifactsGetCmd() *core.Command { | ||
c := core.NewCommand( | ||
context.TODO(), nil, core.CommandBuilder{ | ||
Namespace: "container-registry", | ||
Resource: "artifacts", | ||
Verb: "get", | ||
ShortDesc: "Retrieve an artifacts", | ||
LongDesc: "Retrieve an artifact from a repository", | ||
Example: "ionosctl container-registry artifacts get", | ||
PreCmdRun: PreCmdGet, | ||
CmdRun: CmdGet, | ||
InitClient: true, | ||
}, | ||
) | ||
|
||
c.Command.Flags().StringSlice(constants.ArgCols, nil, tabheaders.ColsMessage(allCols)) | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
constants.ArgCols, | ||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return allCols, cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddStringFlag(constants.FlagRegistryId, constants.FlagRegistryIdShort, "", "Registry ID") | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
constants.FlagRegistryId, | ||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return registry.RegsIds(), cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddStringFlag("repository", "", "", "Name of the repository to retrieve artifact from") | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
"repository", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return repository.RepositoryNames(viper.GetString(core.GetFlagName(c.NS, constants.FlagRegistryId))), | ||
cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddStringFlag(constants.FlagArtifactId, "", "", "ID/digest of the artifact") | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
constants.FlagArtifactId, | ||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return ArtifactsIds( | ||
viper.GetString(core.GetFlagName(c.NS, constants.FlagRegistryId)), | ||
viper.GetString(core.GetFlagName(c.NS, "repository")), | ||
), | ||
cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
return c | ||
} | ||
|
||
func PreCmdGet(c *core.PreCommandConfig) error { | ||
return core.CheckRequiredFlags(c.Command, c.NS, constants.FlagRegistryId, "repository", constants.FlagArtifactId) | ||
} | ||
|
||
func CmdGet(c *core.CommandConfig) error { | ||
cols, _ := c.Command.Command.Flags().GetStringSlice(constants.ArgCols) | ||
regId := viper.GetString(core.GetFlagName(c.NS, constants.FlagRegistryId)) | ||
repo := viper.GetString(core.GetFlagName(c.NS, "repository")) | ||
artId := viper.GetString(core.GetFlagName(c.NS, constants.FlagArtifactId)) | ||
|
||
var arts interface{} | ||
var err error | ||
|
||
arts, _, err = client.Must().RegistryClient.ArtifactsApi.RegistriesRepositoriesArtifactsFindByDigest( | ||
c.Context, regId, repo, artId, | ||
).Execute() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
out, err := jsontabwriter.GenerateOutput( | ||
"", jsonpaths.ContainerRegistryArtifact, arts, | ||
tabheaders.GetHeaders(allCols, defaultCols, cols), | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Fprintf(c.Command.Command.OutOrStdout(), out) | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,191 @@ | ||
package artifacts | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
"github.com/fatih/structs" | ||
"github.com/ionos-cloud/ionosctl/v6/commands/cloudapi-v6/query" | ||
"github.com/ionos-cloud/ionosctl/v6/commands/container-registry/registry" | ||
"github.com/ionos-cloud/ionosctl/v6/commands/container-registry/repository" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/client" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/constants" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/core" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/json2table/jsonpaths" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/jsontabwriter" | ||
"github.com/ionos-cloud/ionosctl/v6/internal/printer/tabheaders" | ||
cloudapiv6 "github.com/ionos-cloud/ionosctl/v6/services/cloudapi-v6" | ||
"github.com/ionos-cloud/ionosctl/v6/services/cloudapi-v6/resources" | ||
ionoscloud "github.com/ionos-cloud/sdk-go-container-registry" | ||
"github.com/spf13/cobra" | ||
"github.com/spf13/viper" | ||
) | ||
|
||
func ArtifactsListCmd() *core.Command { | ||
c := core.NewCommand( | ||
context.TODO(), nil, core.CommandBuilder{ | ||
Namespace: "container-registry", | ||
Resource: "artifacts", | ||
Verb: "list", | ||
Aliases: []string{"l", "ls"}, | ||
ShortDesc: "List registry or repository artifacts", | ||
LongDesc: "List all artifacts in a registry or repository", | ||
Example: "ionosctl container-registry artifacts list", | ||
PreCmdRun: PreCmdList, | ||
CmdRun: CmdList, | ||
InitClient: true, | ||
}, | ||
) | ||
|
||
c.Command.Flags().StringSlice(constants.ArgCols, nil, tabheaders.ColsMessage(allCols)) | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
constants.ArgCols, | ||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return allCols, cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddStringFlag(constants.FlagRegistryId, constants.FlagRegistryIdShort, "", "Registry ID") | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
constants.FlagRegistryId, | ||
func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return registry.RegsIds(), cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddStringFlag("repository", "", "", "Name of the repository to list artifacts from") | ||
_ = c.Command.RegisterFlagCompletionFunc( | ||
"repository", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) { | ||
return repository.RepositoryNames(viper.GetString(core.GetFlagName(c.NS, constants.FlagRegistryId))), | ||
cobra.ShellCompDirectiveNoFileComp | ||
}, | ||
) | ||
|
||
c.AddBoolFlag(constants.ArgAll, constants.ArgAllShort, false, "List all artifacts in the registry") | ||
c.AddSetFlag( | ||
cloudapiv6.ArgOrderBy, "", "-pullcount", []string{ | ||
"-pullcount", "-pushcount", "-lastPush", | ||
"-lastPull", "-lastScan", "-vulnTotalCount", "-vulnFixableCount", "pullCount", "pushCount", "lastPush", | ||
"lastPull", "lastScan", "vulnTotalCount", "vulnFixableCount", | ||
}, cloudapiv6.ArgOrderByDescription, | ||
) | ||
c.AddStringSliceFlag( | ||
cloudapiv6.ArgFilters, cloudapiv6.ArgFiltersShort, []string{""}, cloudapiv6.ArgFiltersDescription, | ||
) | ||
c.AddInt32Flag(constants.FlagMaxResults, constants.FlagMaxResultsShort, 100, "Maximum number of results to display") | ||
|
||
return c | ||
} | ||
|
||
func PreCmdList(c *core.PreCommandConfig) error { | ||
if err := core.CheckRequiredFlagsSets( | ||
c.Command, c.NS, []string{constants.FlagRegistryId, "repository"}, | ||
[]string{constants.FlagRegistryId, constants.ArgAll}, | ||
); err != nil { | ||
return err | ||
} | ||
|
||
if !viper.IsSet(core.GetFlagName(c.NS, constants.ArgAll)) && viper.IsSet( | ||
core.GetFlagName( | ||
c.NS, cloudapiv6.ArgFilters, | ||
), | ||
) { | ||
return fmt.Errorf("flag --%s can only be used with --%s", cloudapiv6.ArgFilters, constants.ArgAll) | ||
} | ||
|
||
return query.ValidateFilters(c, []string{"vulnerabilityId"}, "Filters available: vulnerabilityId") | ||
} | ||
|
||
func CmdList(c *core.CommandConfig) error { | ||
cols, _ := c.Command.Command.Flags().GetStringSlice(constants.ArgCols) | ||
regId := viper.GetString(core.GetFlagName(c.NS, constants.FlagRegistryId)) | ||
defCols := defaultCols | ||
|
||
var arts interface{} | ||
var err error | ||
|
||
queryParams, err := query.GetListQueryParams(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if viper.IsSet(core.GetFlagName(c.NS, constants.ArgAll)) { | ||
arts, _, err = buildListAllRequest(regId, queryParams).Execute() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
defCols = append(defCols, "Repository") | ||
} else { | ||
repo := viper.GetString(core.GetFlagName(c.NS, "repository")) | ||
|
||
arts, _, err = buildListRequest(regId, repo, queryParams).Execute() | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
out, err := jsontabwriter.GenerateOutput( | ||
"items", jsonpaths.ContainerRegistryArtifact, arts, | ||
tabheaders.GetHeaders(allCols, defCols, cols), | ||
) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
fmt.Fprintf(c.Command.Command.OutOrStdout(), out) | ||
return nil | ||
} | ||
|
||
func buildListAllRequest( | ||
regId string, queryParams resources.ListQueryParams, | ||
) ionoscloud.ApiRegistriesArtifactsGetRequest { | ||
if structs.IsZero(queryParams) { | ||
return client.Must().RegistryClient.ArtifactsApi.RegistriesArtifactsGet( | ||
context.Background(), regId, | ||
) | ||
} | ||
|
||
req := client.Must().RegistryClient.ArtifactsApi.RegistriesArtifactsGet(context.Background(), regId) | ||
|
||
if queryParams.OrderBy != nil { | ||
req = req.OrderBy(*queryParams.OrderBy) | ||
} | ||
|
||
if queryParams.MaxResults != nil { | ||
req = req.Limit(*queryParams.MaxResults) | ||
} | ||
|
||
if queryParams.Filters != nil { | ||
vulnId, ok := (*queryParams.Filters)["vulnerabilityId"] | ||
if ok { | ||
req = req.FilterVulnerabilityId(vulnId[0]) | ||
} | ||
} | ||
|
||
return req | ||
} | ||
|
||
func buildListRequest( | ||
regId string, repo string, queryParams resources.ListQueryParams, | ||
) ionoscloud.ApiRegistriesRepositoriesArtifactsGetRequest { | ||
if structs.IsZero(queryParams) { | ||
return client.Must().RegistryClient.ArtifactsApi.RegistriesRepositoriesArtifactsGet( | ||
context.Background(), regId, repo, | ||
) | ||
} | ||
|
||
req := client.Must().RegistryClient.ArtifactsApi.RegistriesRepositoriesArtifactsGet( | ||
context.Background(), regId, repo, | ||
) | ||
|
||
if queryParams.OrderBy != nil { | ||
req = req.OrderBy(*queryParams.OrderBy) | ||
} | ||
|
||
if queryParams.MaxResults != nil { | ||
req = req.Limit(*queryParams.MaxResults) | ||
} | ||
|
||
return req | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.