diff --git a/.golangci.yml b/.golangci.yml index f407800d..fe141823 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -40,7 +40,7 @@ linters: min-complexity: 16 goconst: min-len: 2 - min-occurrences: 3 + min-occurrences: 5 gocritic: disabled-checks: - dupImport diff --git a/internal/cli/cli.go b/internal/cli/cli.go index 31ac3764..238ac7d3 100644 --- a/internal/cli/cli.go +++ b/internal/cli/cli.go @@ -163,9 +163,14 @@ func PrintHelp(parser *kong.Kong, opts kong.HelpOptions, args []string) error { } // knownCommands lists the valid top-level command names for hasCommand detection. +const ( + cmdAmtInfo = "amtinfo" + cmdVersion = "version" +) + var knownCommands = map[string]bool{ - "amtinfo": true, "version": true, "activate": true, - "deactivate": true, "configure": true, "diagnostics": true, "diag": true, + cmdAmtInfo: true, cmdVersion: true, "activate": true, + "deactivate": true, "configure": true, "diagnostics": true, "diag": true, //nolint:goconst // command name literals; remaining occurrences are in tests } // hasCommand checks if args contain a recognized command name. @@ -201,7 +206,7 @@ func Execute(args []string) error { // but let --help/-h pass through so Kong shows the full command list. if !hasCommand(args) && !hasFlag(args, "--help", "-h") { newArgs := make([]string, 0, len(args)+1) - newArgs = append(newArgs, args[0], "amtinfo") + newArgs = append(newArgs, args[0], cmdAmtInfo) newArgs = append(newArgs, args[1:]...) args = newArgs } diff --git a/internal/commands/activate/keys.go b/internal/commands/activate/keys.go new file mode 100644 index 00000000..e94132cf --- /dev/null +++ b/internal/commands/activate/keys.go @@ -0,0 +1,14 @@ +/********************************************************************* + * Copyright (c) Intel Corporation 2024 + * SPDX-License-Identifier: Apache-2.0 + **********************************************************************/ + +package activate + +const ( + keyStatus = "status" + keyMessage = "message" + keyFriendlyName = "friendly_name" + keyProfile = "profile" + valSuccess = "success" +) diff --git a/internal/commands/activate/local.go b/internal/commands/activate/local.go index 9ed5a740..dd6fb9a0 100644 --- a/internal/commands/activate/local.go +++ b/internal/commands/activate/local.go @@ -190,8 +190,8 @@ func (cmd *LocalActivateCmd) handleStopConfiguration(ctx *commands.Context) erro if ctx.JsonOutput { result := map[string]interface{}{ - "status": "success", - "message": "AMT configuration stopped", + keyStatus: valSuccess, + keyMessage: "AMT configuration stopped", } jsonBytes, err := json.MarshalIndent(result, "", " ") @@ -390,10 +390,10 @@ func (service *LocalActivationService) activateCCM() error { // Output success result if service.context.JsonOutput { result := map[string]interface{}{ - "status": "success", + keyStatus: valSuccess, "mode": "CCM", - "message": "Device activated in Client Control Mode", - "friendly_name": service.config.FriendlyName, + keyMessage: "Device activated in Client Control Mode", + keyFriendlyName: service.config.FriendlyName, } jsonBytes, err := json.MarshalIndent(result, "", " ") @@ -477,10 +477,10 @@ func (service *LocalActivationService) activateACM() error { // Output success result if service.context.JsonOutput { result := map[string]interface{}{ - "status": "success", + keyStatus: valSuccess, "mode": "ACM", - "message": "Device activated in Admin Control Mode", - "friendly_name": service.config.FriendlyName, + keyMessage: "Device activated in Admin Control Mode", + keyFriendlyName: service.config.FriendlyName, } jsonBytes, err := json.MarshalIndent(result, "", " ") @@ -875,7 +875,7 @@ func (service *LocalActivationService) runStartHBCWithRetry(certsAndKeys CertsAn for attempt := 1; attempt <= hbcMaxAttempts; attempt++ { response, err = service.startSecureHostBasedConfiguration(certsAndKeys) - if err == nil && response.Status == "AMT_STATUS_SUCCESS" { + if err == nil && response.Status == "AMT_STATUS_SUCCESS" { //nolint:goconst // AMT response status; remaining occurrences are in tests return response, nil } diff --git a/internal/commands/activate/remote.go b/internal/commands/activate/remote.go index d36cc1d1..51acb546 100644 --- a/internal/commands/activate/remote.go +++ b/internal/commands/activate/remote.go @@ -140,7 +140,7 @@ func (service *RemoteActivationService) prepareDeviceInfo() map[string]interface log.Debug("Preparing device information...") deviceInfo := map[string]interface{}{ - "profile": service.config.Profile, + keyProfile: service.config.Profile, } // Add optional fields if provided if service.config.DNS != "" { @@ -156,7 +156,7 @@ func (service *RemoteActivationService) prepareDeviceInfo() map[string]interface } if service.config.FriendlyName != "" { - deviceInfo["friendly_name"] = service.config.FriendlyName + deviceInfo[keyFriendlyName] = service.config.FriendlyName } return deviceInfo @@ -194,15 +194,15 @@ func (service *RemoteActivationService) requestActivation(deviceInfo map[string] } // Create success result for our Kong CLI pattern result := map[string]interface{}{ - "status": "success", + keyStatus: valSuccess, - "message": "Device activated successfully via RPS", + keyMessage: "Device activated successfully via RPS", "rps_server": service.config.URL, - "profile": service.config.Profile, + keyProfile: service.config.Profile, - "friendly_name": service.config.FriendlyName, + keyFriendlyName: service.config.FriendlyName, "device_info": deviceInfo, } diff --git a/internal/commands/amtinfo.go b/internal/commands/amtinfo.go index 55c308b4..4e4a184b 100644 --- a/internal/commands/amtinfo.go +++ b/internal/commands/amtinfo.go @@ -103,7 +103,7 @@ func renderInfoRow(label, value string) string { func styledInfoValue(value string) string { switch strings.ToLower(strings.TrimSpace(value)) { - case "enabled", "connected", "up", "active", + case "enabled", "connected", "up", "active", //nolint:goconst // status string literals; remaining occurrences are in tests "post-provisioning", "admin control mode": return infoGreenStyle.Render(value) case "disabled", "not connected", "down", diff --git a/internal/commands/diagnostics/wsman.go b/internal/commands/diagnostics/wsman.go index 291f87de..9dc08868 100644 --- a/internal/commands/diagnostics/wsman.go +++ b/internal/commands/diagnostics/wsman.go @@ -103,7 +103,7 @@ var wsmanClassFetchers = map[string]classFetcher{ "AMT_EnvironmentDetectionSettingData": fetchAMTEnvironmentDetectionSettingData, "AMT_EventLogEntry": rawWSMANClassFetcher("AMT_EventLogEntry"), "AMT_EthernetPortSettings": fetchAMTEthernetPortSettings, - "AMT_GeneralSettings": fetchAMTGeneralSettings, + "AMT_GeneralSettings": fetchAMTGeneralSettings, //nolint:goconst // WSMAN class name; remaining occurrences are in tests "AMT_Hdr8021Filter": rawWSMANClassFetcher("AMT_Hdr8021Filter"), "AMT_ManagementPresenceRemoteSAP": fetchAMTManagementPresenceRemoteSAP, "AMT_MessageLog": fetchAMTMessageLog, diff --git a/internal/orchestrator/executor.go b/internal/orchestrator/executor.go index 26a71f11..57a54a2e 100644 --- a/internal/orchestrator/executor.go +++ b/internal/orchestrator/executor.go @@ -49,12 +49,12 @@ func (e *CLIExecutor) Execute(args []string) error { // Get the current executable path executable, err := os.Executable() if err != nil { - // Fallback to "rpc" if we can't determine the executable - executable = "rpc" + // Fallback to cmdRPC if we can't determine the executable + executable = cmdRPC } - // Replace the first "rpc" argument with the actual executable - if len(args) > 0 && args[0] == "rpc" { + // Replace the first cmdRPC argument with the actual executable + if len(args) > 0 && args[0] == cmdRPC { args = args[1:] } diff --git a/internal/orchestrator/orchestrator.go b/internal/orchestrator/orchestrator.go index b8054589..fcc1ebf1 100644 --- a/internal/orchestrator/orchestrator.go +++ b/internal/orchestrator/orchestrator.go @@ -23,6 +23,7 @@ var ErrCIRAConfiguration = errors.New("CIRA configuration failed") const ( ACMMODE = "acmactivate" + cmdRPC = "rpc" ) // ProfileOrchestrator orchestrates the execution of commands from a profile configuration @@ -59,7 +60,7 @@ func NewProfileOrchestrator(cfg config.Configuration, currentPassword, mebxPassw // baseArgs returns the common CLI arguments including global flags like password and skip-amt-cert-check. func (po *ProfileOrchestrator) baseArgs() []string { - args := []string{"rpc"} + args := []string{cmdRPC} if po.skipAMTCertCheck { args = append(args, "--skip-amt-cert-check") } @@ -203,7 +204,7 @@ func (po *ProfileOrchestrator) executeWithPasswordFallback(args []string) error // If caller supplied a currentPassword, try non-interactive rotation once if po.currentPassword != "" { - change := []string{"rpc", "configure", "amtpassword", "--password", po.currentPassword, "--newamtpassword", newPass} + change := []string{cmdRPC, "configure", "amtpassword", "--password", po.currentPassword, "--newamtpassword", newPass} if po.skipAMTCertCheck { change = append(change, "--skip-amt-cert-check") } @@ -243,7 +244,7 @@ func (po *ProfileOrchestrator) executeWithPasswordFallback(args []string) error } // Execute password change: configure amtpassword --password --newamtpassword - change := []string{"rpc", "configure", "amtpassword", "--password", oldPass, "--newamtpassword", newPass} + change := []string{cmdRPC, "configure", "amtpassword", "--password", oldPass, "--newamtpassword", newPass} if po.skipAMTCertCheck { change = append(change, "--skip-amt-cert-check") } @@ -691,7 +692,7 @@ func (po *ProfileOrchestrator) verifyAndAlignAMTPassword() error { // If a current password was supplied by the caller, try a direct non-interactive rotation first if po.currentPassword != "" { - change := []string{"rpc", "configure", "amtpassword", "--password", po.currentPassword, "--newamtpassword", newPass} + change := []string{cmdRPC, "configure", "amtpassword", "--password", po.currentPassword, "--newamtpassword", newPass} if po.skipAMTCertCheck { change = append(change, "--skip-amt-cert-check") } diff --git a/pkg/utils/constants.go b/pkg/utils/constants.go index 9988941d..206278de 100644 --- a/pkg/utils/constants.go +++ b/pkg/utils/constants.go @@ -6,6 +6,8 @@ package utils type ReturnCode int +const msgActivationFailed = "ActivationFailed" + var ( ProjectVersion string = "Development Build" BuildDate string = "unknown" @@ -119,7 +121,7 @@ var ( var ( AMTAuthenticationFailed = CustomError{Code: 100, Message: "AMTAuthenticationFailed"} WSMANMessageError = CustomError{Code: 101, Message: "WSMANMessageError"} - ActivationFailed = CustomError{Code: 102, Message: "ActivationFailed"} + ActivationFailed = CustomError{Code: 102, Message: msgActivationFailed} NetworkConfigurationFailed = CustomError{Code: 103, Message: "NetworkConfigurationFailed"} CIRAConfigurationFailed = CustomError{Code: 104, Message: "CIRAConfigurationFailed"} TLSConfigurationFailed = CustomError{Code: 105, Message: "TLSConfigurationFailed"} @@ -137,24 +139,24 @@ var ( SetMEBXPasswordFailed = CustomError{Code: 118, Message: "SetMEBXPasswordFailed"} ChangeAMTPasswordFailed = CustomError{Code: 119, Message: "ChangeAMTPasswordFailed"} UnableToConfigure = CustomError{Code: 120, Message: "UnableToConfigure"} - ActivationFailedDecode64 = CustomError{Code: 121, Message: "ActivationFailed", Details: "failed to decode the certificate from Base64 format"} - ActivationFailedWrongCertPass = CustomError{Code: 122, Message: "ActivationFailed", Details: "provisioning cert password incorrect"} - ActivationFailedInvalidProvCert = CustomError{Code: 123, Message: "ActivationFailed", Details: "invalid provisioning certificate"} - ActivationFailedNoCertFound = CustomError{Code: 124, Message: "ActivationFailed", Details: "no certificates found"} - ActivationFailedNoPrivKeys = CustomError{Code: 125, Message: "ActivationFailed", Details: "no private keys found"} - ActivationFailedNoRootCertFound = CustomError{Code: 126, Message: "ActivationFailed", Details: "root certificate not found in the pfx"} - ActivationFailedGetCertHash = CustomError{Code: 127, Message: "ActivationFailed", Details: "failed to get certificate hashes"} - ActivationFailedProvCertNoMatch = CustomError{Code: 128, Message: "ActivationFailed", Details: "the root of the provisioning certificate does not match any of the trusted roots in AMT"} - ActivationFailedGeneralSettings = CustomError{Code: 129, Message: "ActivationFailed", Details: "wsman message error, failed to get general settings"} - ActivationFailedSetupService = CustomError{Code: 130, Message: "ActivationFailed", Details: "wsman message error, failed to get host based setup service response"} - ActivationFailedAddCert = CustomError{Code: 131, Message: "ActivationFailed", Details: "wsman message error, failed to add certificate to AMT"} - ActivationFailedGenerateNonce = CustomError{Code: 132, Message: "ActivationFailed", Details: "failed to generate nonce"} - ActivationFailedSignString = CustomError{Code: 133, Message: "ActivationFailed", Details: "failed to create signed string"} - ActivationFailedGetControlMode = CustomError{Code: 134, Message: "ActivationFailed", Details: "failed to get control mode"} - ActivationFailedControlMode = CustomError{Code: 135, Message: "ActivationFailed", Details: "received invalid control mode"} + ActivationFailedDecode64 = CustomError{Code: 121, Message: msgActivationFailed, Details: "failed to decode the certificate from Base64 format"} + ActivationFailedWrongCertPass = CustomError{Code: 122, Message: msgActivationFailed, Details: "provisioning cert password incorrect"} + ActivationFailedInvalidProvCert = CustomError{Code: 123, Message: msgActivationFailed, Details: "invalid provisioning certificate"} + ActivationFailedNoCertFound = CustomError{Code: 124, Message: msgActivationFailed, Details: "no certificates found"} + ActivationFailedNoPrivKeys = CustomError{Code: 125, Message: msgActivationFailed, Details: "no private keys found"} + ActivationFailedNoRootCertFound = CustomError{Code: 126, Message: msgActivationFailed, Details: "root certificate not found in the pfx"} + ActivationFailedGetCertHash = CustomError{Code: 127, Message: msgActivationFailed, Details: "failed to get certificate hashes"} + ActivationFailedProvCertNoMatch = CustomError{Code: 128, Message: msgActivationFailed, Details: "the root of the provisioning certificate does not match any of the trusted roots in AMT"} + ActivationFailedGeneralSettings = CustomError{Code: 129, Message: msgActivationFailed, Details: "wsman message error, failed to get general settings"} + ActivationFailedSetupService = CustomError{Code: 130, Message: msgActivationFailed, Details: "wsman message error, failed to get host based setup service response"} + ActivationFailedAddCert = CustomError{Code: 131, Message: msgActivationFailed, Details: "wsman message error, failed to add certificate to AMT"} + ActivationFailedGenerateNonce = CustomError{Code: 132, Message: msgActivationFailed, Details: "failed to generate nonce"} + ActivationFailedSignString = CustomError{Code: 133, Message: msgActivationFailed, Details: "failed to create signed string"} + ActivationFailedGetControlMode = CustomError{Code: 134, Message: msgActivationFailed, Details: "failed to get control mode"} + ActivationFailedControlMode = CustomError{Code: 135, Message: msgActivationFailed, Details: "received invalid control mode"} DuplicateKey = CustomError{Code: 136, Message: "DuplicateKey", Details: "Key pair already exists"} WiredConfigurationFailed = CustomError{Code: 137, Message: "WiredConfigurationFailed"} - ActivationFailedCertHash = CustomError{Code: 138, Message: "ActivationFailed", Details: "leaf certificate hash too long"} + ActivationFailedCertHash = CustomError{Code: 138, Message: msgActivationFailed, Details: "leaf certificate hash too long"} UnsupportedAMTVersion = CustomError{Code: 138, Message: "UnsupportedAMTVersion"} LMSConnectionFailed = CustomError{Code: 139, Message: "LMSConnectionFailed", Details: "Failed to connect to LMS. Please install LMS for activation."} )