diff --git a/pkg/cmd/create/create.go b/pkg/cmd/create/create.go index 5278254..31db116 100644 --- a/pkg/cmd/create/create.go +++ b/pkg/cmd/create/create.go @@ -96,6 +96,8 @@ func NewCommand(config *config.CLIConfig, streams io.ReadWriter, groupID string) cmd.AddCommand(newApplicationCommand(config, streams)) cmd.AddCommand(newIdentityAgentCommand(config, streams)) cmd.AddCommand(newPasswordPolicyCommand(config, streams)) + cmd.AddCommand(newPersonalCertCommand(config, streams)) + cmd.AddCommand(newSignerCertCommand(config, streams)) return cmd } @@ -174,6 +176,15 @@ func (o *options) Run(cmd *cobra.Command, args []string) error { case resource.ResourceTypePrefix + "PasswordPolicy": options := &passwordPolicyOptions{} err = options.createPasswordPolicyFromDataMap(cmd, resourceObject.Data.(map[string]interface{})) + + case resource.ResourceTypePrefix + "PersonalCert": + options := &personalCertOptions{} + err = options.createPersonalCertFromDataMap(cmd, resourceObject.Data.(map[string]interface{})) + + case resource.ResourceTypePrefix + "SignerCert": + options := &signerCertOptions{} + err = options.createSignerCertFromDataMap(cmd, resourceObject.Data.(map[string]interface{})) + } return err diff --git a/pkg/cmd/create/personal_cert.go b/pkg/cmd/create/personal_cert.go new file mode 100644 index 0000000..33215a1 --- /dev/null +++ b/pkg/cmd/create/personal_cert.go @@ -0,0 +1,192 @@ +package create + +import ( + "encoding/json" + "io" + "os" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + contextx "github.com/ibm-verify/verify-sdk-go/pkg/core/context" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/cmd/resource" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" +) + +const ( + personalCertUsage = `personalCert [options]` + personalCertMessagePrefix = "CreatepersonalCert" + personalCertEntitlements = "Manage personal certificates" + personalCertResourceName = "personalCert" +) + +var ( + personalCertShortDesc = cmdutil.TranslateShortDesc( + personalCertMessagePrefix, + "Create a personal certificate with specified options.", + ) + personalCertLongDesc = templates.LongDesc( + cmdutil.TranslateLongDesc( + personalCertMessagePrefix, + `Create a personal certificate resource. Resources managed on Verify require specific entitlements. + Ensure the application or API client used with the 'auth' command has the "Manage personal certificates" entitlement. + Generate an empty resource file with: verifyctl create personalCert --boilerplate + Check required entitlements with: verifyctl create personalCert --entitlements + Input files can be in YAML or JSON format.`, + ), + ) + personalCertExamples = templates.Examples( + cmdutil.TranslateExamples( + personalCertMessagePrefix, + `# Create an empty personal certificate resource. + verifyctl create personalCert --boilerplate + # Create a personal certificate using a YAML file. + verifyctl create -f=./personal_cert.yaml + # Create a personal certificate using a JSON file. + verifyctl create -f=./personal_cert.json`, + ), + ) +) + +type personalCertOptions struct { + options + file string +} + +func newPersonalCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &personalCertOptions{ + options: options{ + config: config, + }, + } + + cmd := &cobra.Command{ + Use: personalCertUsage, + Short: personalCertShortDesc, + Long: personalCertLongDesc, + Example: personalCertExamples, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + + o.AddFlags(cmd) + + return cmd +} + +func (o *personalCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd, personalCertResourceName) + cmd.Flags().StringVarP(&o.file, "file", "f", "", i18n.Translate("Path to the YAML file that contains the input data.")) +} + +func (o *personalCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *personalCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements || o.boilerplate { + return nil + } + + if len(o.file) == 0 { + return errorsx.G11NError(i18n.Translate("'file' option is required if no other options are used.")) + } + return nil +} + +func (o *personalCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+personalCertEntitlements) + return nil + } + + if o.boilerplate { + resourceObj := &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "PersonalCert", + APIVersion: "1.0", + Data: &security.PersonalCert{}, + } + + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + return o.createPersonalCert(cmd) +} + +func (o *personalCertOptions) createPersonalCert(cmd *cobra.Command) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + b, err := os.ReadFile(o.file) + if err != nil { + vc.Logger.Errorf("unable to read file; filename=%s, err=%v", o.file, err) + return err + } + + return o.createPersonalCertWithData(cmd, b) +} + +func (o *personalCertOptions) createPersonalCertWithData(cmd *cobra.Command, data []byte) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + personalCert := &security.PersonalCert{} + if err := yaml.Unmarshal(data, &personalCert); err != nil { + vc.Logger.Errorf("unable to unmarshal the personalCert; err=%v", err) + return err + } + + client := security.NewPersonalCertClient() + resourceURI, err := client.CreatePersonalCert(ctx, personalCert) + if err != nil { + return err + } + + cmdutil.WriteString(cmd, "Resource created: "+resourceURI) + return nil +} + +func (o *personalCertOptions) createPersonalCertFromDataMap(cmd *cobra.Command, data map[string]interface{}) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + personalCert := &security.PersonalCert{} + b, err := json.Marshal(data) + if err != nil { + vc.Logger.Errorf("failed to marshal the data map into json; err=%v", err) + return err + } + + if err := json.Unmarshal(b, personalCert); err != nil { + vc.Logger.Errorf("unable to unmarshal to an personalCert; err=%v", err) + return err + } + + client := security.NewPersonalCertClient() + resourceURI, err := client.CreatePersonalCert(ctx, personalCert) + if err != nil { + vc.Logger.Errorf("unable to create the personal certificate; err=%v, personalCert=%+v", err, personalCert) + return err + } + + cmdutil.WriteString(cmd, "Resource created: "+resourceURI) + return nil +} diff --git a/pkg/cmd/create/signer_cert.go b/pkg/cmd/create/signer_cert.go new file mode 100644 index 0000000..7edfac6 --- /dev/null +++ b/pkg/cmd/create/signer_cert.go @@ -0,0 +1,192 @@ +package create + +import ( + "encoding/json" + "io" + "os" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + contextx "github.com/ibm-verify/verify-sdk-go/pkg/core/context" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/cmd/resource" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" +) + +const ( + signerCertUsage = `signerCert [options]` + signerCertMessagePrefix = "CreatesignerCert" + signerCertEntitlements = "Manage signer certificates" + signerCertResourceName = "signerCert" +) + +var ( + signerCertShortDesc = cmdutil.TranslateShortDesc( + signerCertMessagePrefix, + "Create a signer certificate with specified options.", + ) + signerCertLongDesc = templates.LongDesc( + cmdutil.TranslateLongDesc( + signerCertMessagePrefix, + `Create a signer certificate resource. Resources managed on Verify require specific entitlements. + Ensure the application or API client used with the 'auth' command has the "Manage signer certificates" entitlement. + Generate an empty resource file with: verifyctl create signerCert --boilerplate + Check required entitlements with: verifyctl create signerCert --entitlements + Input files can be in YAML or JSON format.`, + ), + ) + signerCertExamples = templates.Examples( + cmdutil.TranslateExamples( + signerCertMessagePrefix, + `# Create an empty signer certificate resource. + verifyctl create signerCert --boilerplate + # Create a signer certificate using a YAML file. + verifyctl create -f=./signer_cert.yaml + # Create a signer certificate using a JSON file. + verifyctl create -f=./signer_cert.json`, + ), + ) +) + +type signerCertOptions struct { + options + file string +} + +func newSignerCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &signerCertOptions{ + options: options{ + config: config, + }, + } + + cmd := &cobra.Command{ + Use: signerCertUsage, + Short: signerCertShortDesc, + Long: signerCertLongDesc, + Example: signerCertExamples, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + + o.AddFlags(cmd) + + return cmd +} + +func (o *signerCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd, signerCertResourceName) + cmd.Flags().StringVarP(&o.file, "file", "f", "", i18n.Translate("Path to the YAML file that contains the input data.")) +} + +func (o *signerCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *signerCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements || o.boilerplate { + return nil + } + + if len(o.file) == 0 { + return errorsx.G11NError(i18n.Translate("'file' option is required if no other options are used.")) + } + return nil +} + +func (o *signerCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+signerCertEntitlements) + return nil + } + + if o.boilerplate { + resourceObj := &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "SignerCert", + APIVersion: "1.0", + Data: &security.SignerCert{}, + } + + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + return o.createSignerCert(cmd) +} + +func (o *signerCertOptions) createSignerCert(cmd *cobra.Command) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + b, err := os.ReadFile(o.file) + if err != nil { + vc.Logger.Errorf("unable to read file; filename=%s, err=%v", o.file, err) + return err + } + + return o.createSignerCertWithData(cmd, b) +} + +func (o *signerCertOptions) createSignerCertWithData(cmd *cobra.Command, data []byte) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + signerCert := &security.SignerCert{} + if err := yaml.Unmarshal(data, &signerCert); err != nil { + vc.Logger.Errorf("unable to unmarshal the signerCert; err=%v", err) + return err + } + + client := security.NewSignerCertClient() + resourceURI, err := client.CreateSignerCert(ctx, signerCert) + if err != nil { + return err + } + + cmdutil.WriteString(cmd, "Resource created: "+resourceURI) + return nil +} + +func (o *signerCertOptions) createSignerCertFromDataMap(cmd *cobra.Command, data map[string]interface{}) error { + ctx := cmd.Context() + vc := contextx.GetVerifyContext(ctx) + + signerCert := &security.SignerCert{} + b, err := json.Marshal(data) + if err != nil { + vc.Logger.Errorf("failed to marshal the data map into json; err=%v", err) + return err + } + + if err := json.Unmarshal(b, signerCert); err != nil { + vc.Logger.Errorf("unable to unmarshal to an signerCert; err=%v", err) + return err + } + + client := security.NewSignerCertClient() + resourceURI, err := client.CreateSignerCert(ctx, signerCert) + if err != nil { + vc.Logger.Errorf("unable to create the signer certificate; err=%v, signerCert=%+v", err, signerCert) + return err + } + + cmdutil.WriteString(cmd, "Resource created: "+resourceURI) + return nil +} diff --git a/pkg/cmd/delete/delete.go b/pkg/cmd/delete/delete.go index db4138a..310de9a 100644 --- a/pkg/cmd/delete/delete.go +++ b/pkg/cmd/delete/delete.go @@ -77,6 +77,8 @@ func NewCommand(config *config.CLIConfig, streams io.ReadWriter, groupID string) cmd.AddCommand(NewApplicationCommand(config, streams)) cmd.AddCommand(NewIdentityAgentCommand(config, streams)) cmd.AddCommand(NewPasswordPolicyCommand(config, streams)) + cmd.AddCommand(NewPersonalCertCommand(config, streams)) + cmd.AddCommand(NewSignerCertCommand(config, streams)) return cmd } diff --git a/pkg/cmd/delete/personal_cert.go b/pkg/cmd/delete/personal_cert.go new file mode 100644 index 0000000..976d9f4 --- /dev/null +++ b/pkg/cmd/delete/personal_cert.go @@ -0,0 +1,108 @@ +package delete + +import ( + "io" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" +) + +const ( + personalCertUsage = `personalCert [options]` + personalCertMessagePrefix = "DeletePersonalCert" + personalCertEntitlements = "Manage Personal Certs" + personalCertResourceName = "personalCert" +) + +var ( + personalCertLongDesc = templates.LongDesc(cmdutil.TranslateLongDesc(personalCertMessagePrefix, ` + Delete a personal certificate in IBM Security Verify based on label. + Resources managed on Verify have specific entitlements, so ensure that the application or API client used with the 'auth' command is configured with the appropriate entitlements. + You can identify the entitlement required by running: verifyctl delete personalCert --entitlements`)) + + personalCertExamples = templates.Examples(cmdutil.TranslateExamples(personalCertMessagePrefix, ` + # Delete a personal certificate by label + verifyctl delete personalCert --personalCertLabel=certificateLabel + `)) +) + +type personalCertOptions struct { + options + config *config.CLIConfig + label string +} + +func NewPersonalCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &personalCertOptions{ + config: config, + } + cmd := &cobra.Command{ + Use: personalCertUsage, + Short: cmdutil.TranslateShortDesc(personalCertMessagePrefix, "Delete Verify personal certificate based on a label."), + Long: personalCertLongDesc, + Example: personalCertExamples, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + o.AddFlags(cmd) + return cmd +} + +func (o *personalCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd) + cmd.Flags().StringVar(&o.label, "personalCertLabel", o.label, i18n.Translate("Label of the personal certificate to delete. (Required)")) +} + +func (o *personalCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *personalCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements { + return nil + } + calledAs := cmd.CalledAs() + if calledAs == "personalCert" && o.label == "" { + return errorsx.G11NError(i18n.Translate("The 'name' flag is required to delete a personal certificate")) + } + return nil +} + +func (o *personalCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+personalCertEntitlements) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + if cmd.CalledAs() == "personalCert" || len(o.label) > 0 { + return o.handleSinglePersonalCert(cmd, args) + } + return nil +} + +func (o *personalCertOptions) handleSinglePersonalCert(cmd *cobra.Command, _ []string) error { + c := security.NewPersonalCertClient() + err := c.DeletePersonalCert(cmd.Context(), o.label) + if err != nil { + return err + } + cmdutil.WriteString(cmd, "Resource deleted: "+o.label) + return nil +} diff --git a/pkg/cmd/delete/signer_cert.go b/pkg/cmd/delete/signer_cert.go new file mode 100644 index 0000000..7c530e4 --- /dev/null +++ b/pkg/cmd/delete/signer_cert.go @@ -0,0 +1,108 @@ +package delete + +import ( + "io" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" +) + +const ( + signerCertUsage = `signerCert [options]` + signerCertMessagePrefix = "DeleteSignerCert" + signerCertEntitlements = "Manage Signer Certs" + signerCertResourceName = "signerCert" +) + +var ( + signerCertLongDesc = templates.LongDesc(cmdutil.TranslateLongDesc(signerCertMessagePrefix, ` + Delete a signer certificate in IBM Security Verify based on label. + Resources managed on Verify have specific entitlements, so ensure that the application or API client used with the 'auth' command is configured with the appropriate entitlements. + You can identify the entitlement required by running: verifyctl delete signerCert --entitlements`)) + + signerCertExamples = templates.Examples(cmdutil.TranslateExamples(signerCertMessagePrefix, ` + # Delete a signer certificate by label + verifyctl delete signerCert --signerCertLabel=certificateLabel + `)) +) + +type signerCertOptions struct { + options + config *config.CLIConfig + label string +} + +func NewSignerCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &signerCertOptions{ + config: config, + } + cmd := &cobra.Command{ + Use: signerCertUsage, + Short: cmdutil.TranslateShortDesc(signerCertMessagePrefix, "Delete Verify signer certificate based on a label."), + Long: signerCertLongDesc, + Example: signerCertExamples, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + o.AddFlags(cmd) + return cmd +} + +func (o *signerCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd) + cmd.Flags().StringVar(&o.label, "signerCertLabel", o.label, i18n.Translate("Label of the signer certificate to delete. (Required)")) +} + +func (o *signerCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *signerCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements { + return nil + } + calledAs := cmd.CalledAs() + if calledAs == "signerCert" && o.label == "" { + return errorsx.G11NError(i18n.Translate("The 'name' flag is required to delete a signer certificate")) + } + return nil +} + +func (o *signerCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+signerCertEntitlements) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + if cmd.CalledAs() == "signerCert" || len(o.label) > 0 { + return o.handleSingleSignerCert(cmd, args) + } + return nil +} + +func (o *signerCertOptions) handleSingleSignerCert(cmd *cobra.Command, _ []string) error { + c := security.NewSignerCertClient() + err := c.DeleteSignerCert(cmd.Context(), o.label) + if err != nil { + return err + } + cmdutil.WriteString(cmd, "Resource deleted: "+o.label) + return nil +} diff --git a/pkg/cmd/get/get.go b/pkg/cmd/get/get.go index 6ed08c6..c6d13a9 100644 --- a/pkg/cmd/get/get.go +++ b/pkg/cmd/get/get.go @@ -90,6 +90,8 @@ func NewCommand(config *config.CLIConfig, streams io.ReadWriter, groupID string) cmd.AddCommand(NewApplicationsCommand(config, streams)) cmd.AddCommand(NewIdentityAgentsCommand(config, streams)) cmd.AddCommand(newPasswordPolicyCommand(config, streams)) + cmd.AddCommand(newPersonalCertCommand(config, streams)) + cmd.AddCommand(newSignerCertCommand(config, streams)) return cmd } diff --git a/pkg/cmd/get/personal_cert.go b/pkg/cmd/get/personal_cert.go new file mode 100644 index 0000000..50629ed --- /dev/null +++ b/pkg/cmd/get/personal_cert.go @@ -0,0 +1,193 @@ +package get + +import ( + "io" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/cmd/resource" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" +) + +const ( + personalCertUsage = `personalCerts [flags]` + personalCertMessagePrefix = "GetPersonalCerts" + personalCertEntitlements = "Manage Personal Certs" + personalCertResourceName = "personalCert" +) + +var ( + personalCertLongDesc = templates.LongDesc(cmdutil.TranslateLongDesc(personalCertMessagePrefix, ` + Get Verify personal certificate based on an optional filter or a specific personal certificate. + + Resources managed on Verify have specific entitlements, so ensure that the application or API client used with the 'auth' command is configured with the appropriate entitlements. + + You can identify the entitlement required by running: verifyctl get personalCert --entitlements`)) + + personalCertExamples = templates.Examples(cmdutil.TranslateExamples(personalCertMessagePrefix, ` + # Get a specific personal certificate by lable + verifyctl get personalCert -o=yaml --personalCertLabel=testpersonalCert + + # Get 2 policies based on a given search criteria and sort it in the ascending order by name. + verifyctl get personalCerts --count=2 --sort=personalCertLabel -o=yaml + `)) +) + +type personalCertOptions struct { + options + config *config.CLIConfig + label string +} + +func newPersonalCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &personalCertOptions{ + config: config, + } + cmd := &cobra.Command{ + Use: personalCertUsage, + Short: cmdutil.TranslateShortDesc(personalCertMessagePrefix, "Get Verify personal certificates based on an optional filter or a specific certificate."), + Long: personalCertLongDesc, + Example: personalCertExamples, + Aliases: []string{"personalCert"}, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + o.AddFlags(cmd) + return cmd +} + +func (o *personalCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd, personalCertResourceName) + cmd.Flags().StringVar(&o.label, "personalCertLabel", o.label, i18n.Translate("personalCertName to get details")) + o.addSortFlags(cmd, personalCertResourceName) + o.addCountFlags(cmd, personalCertResourceName) +} + +func (o *personalCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *personalCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements { + return nil + } + calledAs := cmd.CalledAs() + if calledAs == "personalCert" && o.label == "" { + return errorsx.G11NError(i18n.Translate("'personalCertName' flag is required.")) + } + return nil +} + +func (o *personalCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+personalCertEntitlements) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + if cmd.CalledAs() == "personalCert" || len(o.label) > 0 { + return o.handleSinglePersonalCert(cmd, args) + } + return o.handlePersonalCertList(cmd, args) +} + +func filterPersonalCertData(pcrt *security.PersonalCert, includeCert bool) map[string]interface{} { + data := map[string]interface{}{ + + "subject": pcrt.Subject, + "label": pcrt.Label, + "isDefault": pcrt.IsDefault, + "keysize": pcrt.KeySize, + "signature_algorithm": pcrt.SignatureAlgorithm, + } + if includeCert { + data["cert"] = pcrt.Cert + } + return data +} + +func (o *personalCertOptions) handleSinglePersonalCert(cmd *cobra.Command, _ []string) error { + c := security.NewPersonalCertClient() + pcrt, uri, err := c.GetPersonalCert(cmd.Context(), o.label) + if err != nil { + return err + } + + if o.output == "raw" { + cmdutil.WriteAsJSON(cmd, pcrt, cmd.OutOrStdout()) + return nil + } + + resourceObj := &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "PersonalCert", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + Name: pcrt.Label, + URI: uri, + }, + Data: filterPersonalCertData(pcrt, true), + } + + if o.output == "json" { + cmdutil.WriteAsJSON(cmd, resourceObj, cmd.OutOrStdout()) + } else { + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + } + return nil +} + +func (o *personalCertOptions) handlePersonalCertList(cmd *cobra.Command, _ []string) error { + c := security.NewPersonalCertClient() + pcrts, uri, err := c.GetPersonalCerts(cmd.Context(), o.sort, o.count) + if err != nil { + return err + } + + if o.output == "raw" { + cmdutil.WriteAsJSON(cmd, pcrts, cmd.OutOrStdout()) + return nil + } + + items := []*resource.ResourceObject{} + for _, pcrt := range pcrts.PersonalCerts { + items = append(items, &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "PersonalCert", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + Name: pcrt.Label, + }, + Data: filterPersonalCertData(&pcrt, false), + }) + } + + resourceObj := &resource.ResourceObjectList{ + Kind: resource.ResourceTypePrefix + "List", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + URI: uri, + }, + Items: items, + } + + if o.output == "raw" || o.output == "json" { + cmdutil.WriteAsJSON(cmd, resourceObj, cmd.OutOrStdout()) + } else { + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + } + return nil +} diff --git a/pkg/cmd/get/signer_cert.go b/pkg/cmd/get/signer_cert.go new file mode 100644 index 0000000..252a51f --- /dev/null +++ b/pkg/cmd/get/signer_cert.go @@ -0,0 +1,197 @@ +package get + +import ( + "io" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/cmd/resource" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" +) + +const ( + signerCertUsage = `signerCerts [flags]` + signerCertMessagePrefix = "GetSignerCerts" + signerCertEntitlements = "Manage Signer Certs" + signerCertResourceName = "signerCert" +) + +var ( + signerCertLongDesc = templates.LongDesc(cmdutil.TranslateLongDesc(signerCertMessagePrefix, ` + Get Verify Signer certificate based on an optional filter or a specific Signer certificate. + + Resources managed on Verify have specific entitlements, so ensure that the application or API client used with the 'auth' command is configured with the appropriate entitlements. + + You can identify the entitlement required by running: verifyctl get signerCert --entitlements`)) + + signerCertExamples = templates.Examples(cmdutil.TranslateExamples(signerCertMessagePrefix, ` + # Get a specific Signer certificate by lable + verifyctl get signerCert -o=yaml --signerCertLabel=testsignerCert + + # Get 2 policies based on a given search criteria and sort it in the ascending order by name. + verifyctl get signerCerts --count=2 --sort=signerCertLabel -o=yaml + `)) +) + +type signerCertOptions struct { + options + config *config.CLIConfig + label string +} + +func newSignerCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &signerCertOptions{ + config: config, + } + cmd := &cobra.Command{ + Use: signerCertUsage, + Short: cmdutil.TranslateShortDesc(signerCertMessagePrefix, "Get Verify Signer certificates based on an optional filter or a specific certificate."), + Long: signerCertLongDesc, + Example: signerCertExamples, + Aliases: []string{"signerCert"}, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + o.AddFlags(cmd) + return cmd +} + +func (o *signerCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd, signerCertResourceName) + cmd.Flags().StringVar(&o.label, "signerCertLabel", o.label, i18n.Translate("signerCertName to get details")) + o.addSortFlags(cmd, signerCertResourceName) + o.addCountFlags(cmd, signerCertResourceName) +} + +func (o *signerCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *signerCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements { + return nil + } + calledAs := cmd.CalledAs() + if calledAs == "signerCert" && o.label == "" { + return errorsx.G11NError(i18n.Translate("'signerCertName' flag is required.")) + } + return nil +} + +func (o *signerCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+signerCertEntitlements) + return nil + } + + _, err := o.config.SetAuthToContext(cmd.Context()) + if err != nil { + return err + } + + if cmd.CalledAs() == "signerCert" || len(o.label) > 0 { + return o.handleSingleSignerCert(cmd, args) + } + return o.handleSignerCertList(cmd, args) +} + +func filterSignerCertData(scrt *security.SignerCert, includeCert bool) map[string]interface{} { + data := map[string]interface{}{ + + "notbefore": scrt.Notbefore, + "subject": scrt.Subject, + "notafter": scrt.Notafter, + "serial_number": scrt.SerialNumber, + "label": scrt.Label, + "version": scrt.Version, + "issuer": scrt.Issuer, + "keysize": scrt.KeySize, + "signature_algorithm": scrt.SignatureAlgorithm, + } + if includeCert { + data["cert"] = scrt.Cert + } + return data +} + +func (o *signerCertOptions) handleSingleSignerCert(cmd *cobra.Command, _ []string) error { + c := security.NewSignerCertClient() + scrt, uri, err := c.GetSignerCert(cmd.Context(), o.label) + if err != nil { + return err + } + + if o.output == "raw" { + cmdutil.WriteAsJSON(cmd, scrt, cmd.OutOrStdout()) + return nil + } + + resourceObj := &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "SignerCert", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + Name: scrt.Label, + URI: uri, + }, + Data: filterSignerCertData(scrt, true), + } + + if o.output == "json" { + cmdutil.WriteAsJSON(cmd, resourceObj, cmd.OutOrStdout()) + } else { + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + } + return nil +} + +func (o *signerCertOptions) handleSignerCertList(cmd *cobra.Command, _ []string) error { + c := security.NewSignerCertClient() + scrts, uri, err := c.GetSignerCerts(cmd.Context(), o.sort, o.count) + if err != nil { + return err + } + + if o.output == "raw" { + cmdutil.WriteAsJSON(cmd, scrts, cmd.OutOrStdout()) + return nil + } + + items := []*resource.ResourceObject{} + for _, scrt := range scrts.SignerCerts { + items = append(items, &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "SignerCert", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + Name: scrt.Label, + }, + Data: filterSignerCertData(&scrt, false), + }) + } + + resourceObj := &resource.ResourceObjectList{ + Kind: resource.ResourceTypePrefix + "List", + APIVersion: "1.0", + Metadata: &resource.ResourceObjectMetadata{ + URI: uri, + }, + Items: items, + } + + if o.output == "raw" || o.output == "json" { + cmdutil.WriteAsJSON(cmd, resourceObj, cmd.OutOrStdout()) + } else { + cmdutil.WriteAsYAML(cmd, resourceObj, cmd.OutOrStdout()) + } + return nil +} diff --git a/pkg/cmd/replace/personal_cert.go b/pkg/cmd/replace/personal_cert.go new file mode 100644 index 0000000..077fecb --- /dev/null +++ b/pkg/cmd/replace/personal_cert.go @@ -0,0 +1,169 @@ +package replace + +import ( + "io" + "os" + + "github.com/ibm-verify/verify-sdk-go/pkg/config/security" + contextx "github.com/ibm-verify/verify-sdk-go/pkg/core/context" + errorsx "github.com/ibm-verify/verify-sdk-go/pkg/core/errors" + "github.com/ibm-verify/verify-sdk-go/pkg/i18n" + "github.com/ibm-verify/verifyctl/pkg/cmd/resource" + "github.com/ibm-verify/verifyctl/pkg/config" + cmdutil "github.com/ibm-verify/verifyctl/pkg/util/cmd" + "github.com/ibm-verify/verifyctl/pkg/util/templates" + "github.com/spf13/cobra" + "gopkg.in/yaml.v3" +) + +const ( + personalCertUsage = `personalCert [options]` + personalCertMessagePrefix = "UpdatePersonalCert" + personalCertEntitlements = "Manage Personal Certs" + personalCertResourceName = "personalCert" +) + +var ( + personalCertShortDesc = cmdutil.TranslateShortDesc(personalCertMessagePrefix, "Update a personal certificate resource.") + + personalCertLongDesc = templates.LongDesc(cmdutil.TranslateLongDesc(personalCertMessagePrefix, ` + Update a personal certificate resource. + Resources managed on Verify require specific entitlements, so ensure that the application or API client used with the 'auth' command is configured with the appropriate entitlements. + An empty resource file can be generated using: verifyctl replace personalCert --boilerplate + You can identify the entitlement required by running: verifyctl replace personalCert --entitlements`)) + + personalCertExamples = templates.Examples(cmdutil.TranslateExamples(personalCertMessagePrefix, ` + # Generate an empty personalCert resource template + verifyctl replace personalCert --boilerplate + # Update a personal certificate from a YAML file + verifyctl replace -f=./personal_cert.yaml + `)) +) + +type personalCertOptions struct { + options + config *config.CLIConfig +} + +func NewPersonalCertCommand(config *config.CLIConfig, streams io.ReadWriter) *cobra.Command { + o := &personalCertOptions{ + config: config, + } + cmd := &cobra.Command{ + Use: personalCertUsage, + Short: personalCertShortDesc, + Long: personalCertLongDesc, + Example: personalCertExamples, + DisableFlagsInUseLine: true, + Run: func(cmd *cobra.Command, args []string) { + cmdutil.ExitOnError(cmd, o.Complete(cmd, args)) + cmdutil.ExitOnError(cmd, o.Validate(cmd, args)) + cmdutil.ExitOnError(cmd, o.Run(cmd, args)) + }, + } + cmd.SetOut(streams) + cmd.SetErr(streams) + cmd.SetIn(streams) + o.AddFlags(cmd) + return cmd +} + +func (o *personalCertOptions) AddFlags(cmd *cobra.Command) { + o.addCommonFlags(cmd, personalCertResourceName) + cmd.Flags().StringVarP(&o.file, "file", "f", "", i18n.Translate("Path to the file that contains the input data. The contents of the file are expected to be formatted to match the API contract.")) +} + +func (o *personalCertOptions) Complete(cmd *cobra.Command, args []string) error { + return nil +} + +func (o *personalCertOptions) Validate(cmd *cobra.Command, args []string) error { + if o.entitlements || o.boilerplate { + return nil + } + if len(o.file) == 0 { + return errorsx.G11NError(i18n.Translate("'file' option is required if no other options are used.")) + } + return nil +} + +func (o *personalCertOptions) Run(cmd *cobra.Command, args []string) error { + if o.entitlements { + cmdutil.WriteString(cmd, entitlementsMessage+" "+personalCertEntitlements) + return nil + } + + if o.boilerplate { + resourceObj := &resource.ResourceObject{ + Kind: resource.ResourceTypePrefix + "PersonalCert", + APIVersion: "1.0", + Data: &security.PersonalCert{ + Label: "