diff --git a/cmd/validateContract.go b/cmd/validateContract.go index 789096d..b7e6668 100644 --- a/cmd/validateContract.go +++ b/cmd/validateContract.go @@ -36,13 +36,21 @@ var validateContractCmd = &cobra.Command{ log.Fatal(err) } - contractData, err := common.ReadDataFromFile(contractPath) - if err != nil { - log.Fatal(err) - } - - if !common.CheckFileFolderExists(contractPath) { - log.Fatal("The path to contract doesn't exist") + var contractData string + // Handle stdin input + if contractPath == "-" { + contractData, err = common.ReadDataFromStdin() + if err != nil { + log.Fatalf("unable to read input from standard input: %v", err) + } + } else { + if !common.CheckFileFolderExists(contractPath) { + log.Fatal("The path to contract doesn't exist") + } + contractData, err = common.ReadDataFromFile(contractPath) + if err != nil { + log.Fatal(err) + } } err = contract.HpcrVerifyContract(contractData, version) diff --git a/cmd/validateEncryptionCertificate.go b/cmd/validateEncryptionCertificate.go index fc7a7e2..b93c55a 100644 --- a/cmd/validateEncryptionCertificate.go +++ b/cmd/validateEncryptionCertificate.go @@ -55,7 +55,7 @@ func init() { requiredFlags := map[string]bool{ "in": true, } - validateEncryptionCertificateCmd.PersistentFlags().String(validateEncryptionCertificate.InputFlagName, "", validateEncryptionCertificate.CertVersionFlagDescription) + validateEncryptionCertificateCmd.PersistentFlags().String(validateEncryptionCertificate.InputFlagName, "", validateEncryptionCertificate.InputFlagDescription) common.SetCustomHelpTemplate(validateEncryptionCertificateCmd, requiredFlags) common.SetCustomErrorTemplate(validateEncryptionCertificateCmd) } diff --git a/cmd/validateNetwork.go b/cmd/validateNetwork.go index 01e452d..bc95f38 100644 --- a/cmd/validateNetwork.go +++ b/cmd/validateNetwork.go @@ -36,13 +36,21 @@ var validateNetworkConfigCmd = &cobra.Command{ log.Fatal(err) } - if !common.CheckFileFolderExists(networkConfigPath) { - log.Fatal("The path to network-config doesn't exist") - } + var networkConfigData string + if networkConfigPath == "-" { + networkConfigData, err = common.ReadDataFromStdin() + if err != nil { + log.Fatalf("unable to read input from standard input: %v", err) + } + } else { + if !common.CheckFileFolderExists(networkConfigPath) { + log.Fatal("The path to network-config doesn't exist") + } - networkConfigData, err := common.ReadDataFromFile(networkConfigPath) - if err != nil { - log.Fatal(err) + networkConfigData, err = common.ReadDataFromFile(networkConfigPath) + if err != nil { + log.Fatal(err) + } } err = network.HpcrVerifyNetworkConfig(networkConfigData) diff --git a/common/common.go b/common/common.go index bdb677c..c6f73dc 100644 --- a/common/common.go +++ b/common/common.go @@ -49,6 +49,44 @@ func ReadDataFromFile(filePath string) (string, error) { return string(content), nil } +// ReadDataFromStdin - function to read data from stdin +func ReadDataFromStdin() (string, error) { + content, err := io.ReadAll(os.Stdin) + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + return string(content), nil +} + +// IsStdinAvailable - function to check if stdin has data available (piped or redirected) +func IsStdinAvailable() bool { + stat, err := os.Stdin.Stat() + if err != nil { + return false + } + // Check if stdin is a pipe or file (not a character device like terminal) + // This returns true when data is piped: echo "data" | command + // This returns false when running interactively in terminal + mode := stat.Mode() + return (mode&os.ModeCharDevice) == 0 && stat.Size() > 0 +} + +// ValidateStdinInput - function to validate stdin input conflicts +// Returns error if there's a conflict between stdin and input parameter +func ValidateStdinInput(cmd *cobra.Command, inputData string) { + // Check if "-" is specified but no stdin is available + if inputData == "-" && !IsStdinAvailable() { + err := fmt.Errorf("Error: '--in -' specified but no standard input data detected. Pipe data to standard input or use a file path instead") + SetMandatoryFlagError(cmd, err) + } + + // Check if stdin has data when input data (not "-") is specified + if inputData != "-" && IsStdinAvailable() { + err := fmt.Errorf("Error: standard input data detected but --in specifies a file path '%s'. Use '--in -' to read from standard input or remove piped input to read from file", inputData) + SetMandatoryFlagError(cmd, err) + } +} + // WriteDataToFile - function to write data to file (create file if doesn't exists) func WriteDataToFile(filePath, data string) error { DataFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644) diff --git a/docs/README.md b/docs/README.md index 1e0c97b..9be8715 100644 --- a/docs/README.md +++ b/docs/README.md @@ -126,7 +126,7 @@ contract-cli base64 [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Input data to encode (text or JSON) | +| `--in` | string | Yes | Input data to encode (text or JSON) (use '-' for standard input) | | `--format` | string | No | Input data format (text or json) | | `--out` | string | No | Path to save Base64 encoded output | | `-h, --help` | - | No | Display help information | @@ -148,6 +148,11 @@ contract-cli base64 --in '{"type": "workload"}' --format json contract-cli base64 --in "Hello World" --format text --out encoded.txt ``` +**Using standard input (pipe input):** +```bash +echo "Hello World" | contract-cli base64 --in - --format text +``` + --- ### base64-tgz @@ -164,7 +169,7 @@ contract-cli base64-tgz [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to folder containing `docker-compose.yaml` or `pods.yaml` | +| `--in` | string | Yes | Path to folder containing `docker-compose.yaml` or `pods.yaml` (use '-' for standard input) | | `--output` | string | No | Output type: `plain` or `encrypted` (default: `plain`) | | `--cert` | string | No | Path to encryption certificate (for encrypted output) | | `--os` | string | No | Target Hyper Protect platform: `hpvs`, `hpcr-rhvs`, or `hpcc-peerpod` (default: `hpvs`) | @@ -212,6 +217,11 @@ contract-cli base64-tgz \ contract-cli base64-tgz --in ./compose-folder --out archive.txt ``` +**Using standard input (pipe input):** +```bash +echo "pods-folder" | contract-cli base64-tgz --in - +``` + --- ### decrypt-attestation @@ -228,7 +238,7 @@ contract-cli decrypt-attestation [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to encrypted attestation file | +| `--in` | string | Yes | Path to encrypted attestation file (use '-' for standard input) | | `--priv` | string | Yes | Path to private key used for decryption | | `--out` | string | No | Path to save decrypted attestation records | | `-h, --help` | - | No | Display help information | @@ -250,6 +260,13 @@ contract-cli decrypt-attestation \ --out decrypted-attestation.txt ``` +**Using standard input:** +```bash +cat se-checksums.txt.enc | contract-cli decrypt-attestation \ + --in - \ + --priv private.pem +``` + --- ### download-certificate @@ -312,7 +329,7 @@ contract-cli encrypt [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to unencrypted Hyper Protect contract YAML file | +| `--in` | string | Yes | Path to unencrypted Hyper Protect contract YAML file (use '-' for standard input) | | `--priv` | string | No* | Path to private key for signing | | `--cert` | string | No | Path to encryption certificate (uses latest if not specified) | | `--os` | string | No | Target Hyper Protect platform: `hpvs`, `hpcr-rhvs`, or `hpcc-peerpod` (default: `hpvs`) | @@ -379,6 +396,13 @@ contract-cli encrypt \ --os hpcc-peerpod ``` +**Using standard input:** +```bash +echo "test-string" | contract-cli encrypt \ + --in - \ + --priv private.pem +``` + --- ### encrypt-string @@ -395,7 +419,7 @@ contract-cli encrypt-string [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | String data to encrypt | +| `--in` | string | Yes | String data to encrypt (use '-' for standard input) | | `--format` | string | No | Input data format (text or json) | | `--cert` | string | No | Path to encryption certificate (uses latest if not specified) | | `--os` | string | No | Target Hyper Protect platform: `hpvs`, `hpcr-rhvs`, or `hpcc-peerpod` (default: `hpvs`) | @@ -430,6 +454,11 @@ contract-cli encrypt-string \ --out encrypted-secret.txt ``` +**Using standard input:** +```bash +echo "my-secret-password" | contract-cli encrypt-string --in - +``` + --- ### get-certificate @@ -446,7 +475,7 @@ contract-cli get-certificate [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to download-certificate JSON output | +| `--in` | string | Yes | Path to download-certificate JSON output (use '-' for standard input) | | `--version` | string | Yes | Certificate version to extract (e.g., 1.0.23) | | `--out` | string | No | Path to save extracted encryption certificate | | `-h, --help` | - | No | Display help information | @@ -468,6 +497,11 @@ contract-cli get-certificate \ --out cert-1.0.23.crt ``` +**Using standard input:** +```bash +cat "cert.json" | contract-cli get-certificate --in - --version 1.0.23 +``` + --- ### image @@ -484,7 +518,7 @@ contract-cli image [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to IBM Cloud images JSON (from API, CLI, or Terraform) | +| `--in` | string | Yes | Path to IBM Cloud images JSON (from API, CLI, or Terraform) (use '-' for standard input) | | `--version` | string | No | Specific HPCR version to retrieve (returns latest if not specified) | | `--format` | string | No | Output format for data (json, yaml, or text) | | `--out` | string | No | Path to save HPCR image details | @@ -518,6 +552,12 @@ contract-cli image \ --out hpcr-image.json ``` +**Using standard input:** +```bash +cat "ibm-cloud-images.json" | contract-cli image --in - +``` + + --- ### validate-contract @@ -534,7 +574,7 @@ contract-cli validate-contract [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to unencrypted Hyper Protect contract YAML file | +| `--in` | string | Yes | Path to unencrypted Hyper Protect contract YAML file (use '-' for standard input) | | `--os` | string | No | Target Hyper Protect platform: `hpvs`, `hpcr-rhvs`, or `hpcc-peerpod` (default: `hpvs`) | | `-h, --help` | - | No | Display help information | @@ -555,6 +595,11 @@ contract-cli validate-contract --in contract.yaml --os hpcr-rhvs contract-cli validate-contract --in contract.yaml --os hpcc-peerpod ``` +**Using standard input:** +```bash +cat contract.yaml | contract-cli validate-contract --in - --os hpvs +``` + --- ### validate-network @@ -571,7 +616,7 @@ contract-cli validate-network [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to network-config YAML file | +| `--in` | string | Yes | Path to network-config YAML file (use '-' for standard input) | | `-h, --help` | - | No | Display help information | #### Examples @@ -581,6 +626,11 @@ contract-cli validate-network [flags] contract-cli validate-network --in network-config.yaml ``` +**Using standard input:** +```bash +cat network-config.yaml | contract-cli validate-network --in - +``` + --- @@ -598,16 +648,21 @@ contract-cli validate-encryption-certificate [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to encryption certificate file | +| `--in` | string | Yes | Path to encryption certificate file (use '-' for standard input) | | `-h, --help` | - | No | Display help information | #### Examples -**Validate encryption certifacte configuration:** +**Validate encryption certificate configuration:** ```bash contract-cli validate-encryption-certificate --in encryption-cert.crt ``` +**Using standard input:** +```bash +cat encryption-cert.crt | contract-cli validate-encryption-certificate --in - +``` + --- ### initdata @@ -623,17 +678,22 @@ contract-cli initdata [flags] | Flag | Type | Required | Description | |------|------|----------|-------------| -| `--in` | string | Yes | Path to signed & encrypted contract YAML file | +| `--in` | string | Yes | Path to signed & encrypted contract YAML file (use '-' for standard input) | | `--out` | string | No | Path to store gzipped & encoded initdata value | | `-h, --help` | - | No | Display help information | #### Examples -**Create Hpcc Initdata from signed & encrypted contract** +**Create Hpcc Initdata from signed & encrypted contract:** ```bash contract-cli initdata --in signed_encrypted_contract.yaml ``` +**Using standard input:** +```bash +cat signed_encrypted_contract.yaml | contract-cli initdata --in - +``` + --- ## Common Workflows diff --git a/lib/base64/base64.go b/lib/base64/base64.go index 2058ddf..2d11280 100644 --- a/lib/base64/base64.go +++ b/lib/base64/base64.go @@ -31,7 +31,7 @@ const ( Useful for encoding data that needs to be included in contracts or configurations.` InputFlagName = "in" - InputFlagDescription = "Input data to encode (text or JSON)" + InputFlagDescription = "Input data to encode (text or JSON, use '-' for standard input)" FormatFlagName = "format" FormatFlagDescription = "Input data format (text or json)" @@ -59,6 +59,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, error) { common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input conflicts + common.ValidateStdinInput(cmd, inputData) + formatType, err := cmd.Flags().GetString(FormatFlagName) if err != nil { return "", "", "", err @@ -76,14 +79,25 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, error) { func Process(inputData, formatType string) (string, error) { var base64String string var err error + var data string + + // Check if input is from stdin + if inputData == "-" { + data, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + data = inputData + } if formatType == TextFormat { - base64String, _, _, err = contract.HpcrText(inputData) + base64String, _, _, err = contract.HpcrText(data) if err != nil { return "", err } } else if formatType == JsonFormat { - base64String, _, _, err = contract.HpcrJson(inputData) + base64String, _, _, err = contract.HpcrJson(data) if err != nil { return "", err } diff --git a/lib/base64Tgz/base64Tgz.go b/lib/base64Tgz/base64Tgz.go index c1965fb..8bcd91b 100644 --- a/lib/base64Tgz/base64Tgz.go +++ b/lib/base64Tgz/base64Tgz.go @@ -17,6 +17,7 @@ package base64Tgz import ( "fmt" + "strings" "github.com/ibm-hyper-protect/contract-cli/common" "github.com/ibm-hyper-protect/contract-go/v2/contract" @@ -32,10 +33,10 @@ const ( Creates a compressed archive of your container configuration files, encoded as Base64 for inclusion in Hyper Protect contracts. Supports both plain and encrypted output.` InputFlagName = "in" - InputFlagDescription = "Path to folder containing docker-compose.yaml or pods.yaml" + InputFlagDescription = "Path to folder containing docker-compose.yaml or pods.yaml (use '-' for standard input)" OutputFlagName = "out" OutputFormatFlag = "output" - OutputFlagDescription = "Output format (plain or encrypted)" + OutputFlagDescription = "Output format (plain or encrypt)" OutputFormatUnencrypted = "plain" OutputFormatEncrypted = "encrypt" DefaultOutput = OutputFormatUnencrypted @@ -58,6 +59,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, string, common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, inputData) + outputFormat, err := cmd.Flags().GetString(OutputFormatFlag) if err != nil { return "", "", "", "", "", err @@ -83,12 +87,25 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, string, // Process - function to process base64-tgz inputs func Process(inputData, outputFormat, hyperProtectVersion, encCertPath string) (string, error) { + var folderPath string + + // Handle stdin input + if inputData == "-" { + path, err := common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + folderPath = strings.TrimSpace(path) + } else { + folderPath = inputData + } + if outputFormat == OutputFormatUnencrypted { - if !common.CheckFileFolderExists(inputData) { + if !common.CheckFileFolderExists(folderPath) { return "", fmt.Errorf("the path to docker-compose.yaml or pods.yaml is not accessible") } - base64Data, _, _, err := contract.HpcrTgz(inputData) + base64Data, _, _, err := contract.HpcrTgz(folderPath) if err != nil { return "", fmt.Errorf("failed to generate base64 tar - %v", err) } @@ -100,7 +117,7 @@ func Process(inputData, outputFormat, hyperProtectVersion, encCertPath string) ( return "", err } - encryptedBase64Data, _, _, err := contract.HpcrTgzEncrypted(inputData, hyperProtectVersion, encCert) + encryptedBase64Data, _, _, err := contract.HpcrTgzEncrypted(folderPath, hyperProtectVersion, encCert) if err != nil { return "", fmt.Errorf("failed to generate encrypted base64 tar - %v", err) } diff --git a/lib/decryptAttestation/decryptAttestation.go b/lib/decryptAttestation/decryptAttestation.go index ee9157c..43afa6b 100644 --- a/lib/decryptAttestation/decryptAttestation.go +++ b/lib/decryptAttestation/decryptAttestation.go @@ -33,7 +33,7 @@ const ( Attestation records are typically found at /var/hyperprotect/se-checksums.txt.enc and contain cryptographic hashes for verifying workload integrity.` - DecryptAttestFileInDescription = "Path to encrypted attestation file (se-checksums.txt.enc)" + DecryptAttestFileInDescription = "Path to encrypted attestation file (se-checksums.txt.enc, use '-' for standard input)" DecryptAttestFlagDescription = "Path to save decrypted attestation records" successMessageDecryptAttestation = "Successfully decrypted attestation records" InputFlagName = "in" @@ -83,23 +83,37 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, error) { } } + // Validate stdin input + common.ValidateStdinInput(cmd, encAttestPath) + return encAttestPath, privateKeyPath, decryptedAttestPath, nil } // DecryptAttestationRecords - function to decrypt attestation records func DecryptAttestationRecords(encryptedAttestationRecordsPath, privateKeyPath string) (string, error) { - if !common.CheckFileFolderExists(encryptedAttestationRecordsPath) { - log.Fatal("The path to encrypted attestation records file doesn't exists") + var encryptedChecksum string + var err error + + // Handle stdin input + if encryptedAttestationRecordsPath == "-" { + encryptedChecksum, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(encryptedAttestationRecordsPath) { + log.Fatal("The path to encrypted attestation records file doesn't exists") + } + encryptedChecksum, err = common.ReadDataFromFile(encryptedAttestationRecordsPath) + if err != nil { + return "", err + } } + if !common.CheckFileFolderExists(privateKeyPath) { log.Fatal("The path to private key doesn't exists") } - encryptedChecksum, err := common.ReadDataFromFile(encryptedAttestationRecordsPath) - if err != nil { - return "", err - } - privateKey, err := common.ReadDataFromFile(privateKeyPath) if err != nil { return "", err diff --git a/lib/encrypt/encrypt.go b/lib/encrypt/encrypt.go index 7ef6055..ff465dc 100644 --- a/lib/encrypt/encrypt.go +++ b/lib/encrypt/encrypt.go @@ -31,7 +31,7 @@ const ( Creates a cryptographically signed contract using your private key and encrypts it with the platform's encryption certificate. Supports optional contract expiry for enhanced security.` - InputFlagDescription = "Path to unencrypted contract YAML file" + InputFlagDescription = "Path to unencrypted contract YAML file (use '-' for standard input)" OutputFlagDescription = "Path to save signed and encrypted contract" ContractExpiryFlag = "contract-expiry" DefaultContractExpiryFlag = false @@ -68,6 +68,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, string, common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input conflicts + common.ValidateStdinInput(cmd, inputData) + osVersion, err := cmd.Flags().GetString(OsVersionFlagName) if err != nil { return "", "", "", "", "", err @@ -179,13 +182,23 @@ func GenerateSignedEncryptContractExpiry(inputDataPath, osVersion, certPath, pri // commonParameters - function to fetch common details func commonParameters(inputDataPath, certPath, privateKeyPath string) (string, string, string, error) { - if !common.CheckFileFolderExists(inputDataPath) { - return "", "", "", fmt.Errorf("the contract path doesn't exist") - } + var inputData string + var err error - inputData, err := common.ReadDataFromFile(inputDataPath) - if err != nil { - return "", "", "", err + if inputDataPath == "-" { + inputData, err = common.ReadDataFromStdin() + if err != nil { + return "", "", "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(inputDataPath) { + return "", "", "", fmt.Errorf("the contract path doesn't exist") + } + + inputData, err = common.ReadDataFromFile(inputDataPath) + if err != nil { + return "", "", "", err + } } cert, err := common.GetDataFromFile(certPath) diff --git a/lib/encryptString/encryptString.go b/lib/encryptString/encryptString.go index 8d5fdce..3a9b21e 100644 --- a/lib/encryptString/encryptString.go +++ b/lib/encryptString/encryptString.go @@ -30,7 +30,7 @@ const ( Output format: hyper-protect-basic.. Use this to encrypt sensitive data like passwords or API keys for contracts.` - InputFlagDescription = "String data to encrypt (text or JSON)" + InputFlagDescription = "String data to encrypt (text or JSON, use '-' for standard input)" FormatFlagDescription = "Input data format (text or json)" OutputFlagDescription = "Path to save encrypted output" successMessageEncryptString = "Successfully stored encrypted text" @@ -56,6 +56,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, string, common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, inputData) + inputFormat, err := cmd.Flags().GetString(FormatFlag) if err != nil { return "", "", "", "", "", err @@ -81,6 +84,19 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, string, // Process - function to generate encrypted string of plain or JSON text func Process(inputData, inputFormat, hyperProtectVersion, encCertPath string) (string, error) { + var data string + var err error + + // Handle stdin input + if inputData == "-" { + data, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + data = inputData + } + encCert, err := common.GetDataFromFile(encCertPath) if err != nil { return "", err @@ -88,12 +104,12 @@ func Process(inputData, inputFormat, hyperProtectVersion, encCertPath string) (s var encryptedString string if inputFormat == TextFormat { - encryptedString, _, _, err = contract.HpcrTextEncrypted(inputData, hyperProtectVersion, encCert) + encryptedString, _, _, err = contract.HpcrTextEncrypted(data, hyperProtectVersion, encCert) if err != nil { return "", err } } else if inputFormat == JsonFormat { - encryptedString, _, _, err = contract.HpcrJsonEncrypted(inputData, hyperProtectVersion, encCert) + encryptedString, _, _, err = contract.HpcrJsonEncrypted(data, hyperProtectVersion, encCert) if err != nil { return "", err } diff --git a/lib/getCertificate/getCertificate.go b/lib/getCertificate/getCertificate.go index 0d05c7d..0fe1148 100644 --- a/lib/getCertificate/getCertificate.go +++ b/lib/getCertificate/getCertificate.go @@ -31,7 +31,7 @@ const ( Parses the JSON output from download-certificate and extracts the certificate for the specified version.` - FileInFlagDescription = "Path to download-certificate JSON output" + FileInFlagDescription = "Path to download-certificate JSON output (use '-' for standard input)" VersionFlagDescription = "Certificate version to extract (e.g., 1.0.23)" FileOutFlagDescription = "Path to save extracted encryption certificate" InputFlagName = "in" @@ -80,18 +80,31 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, error) { } } + // Validate stdin input + common.ValidateStdinInput(cmd, encryptionCertsPath) + return encryptionCertsPath, version, encryptionCertificatePath, nil } // Process - function to get encryption certificate func Process(encryptionCertsPath, version string) (string, error) { - if !common.CheckFileFolderExists(encryptionCertsPath) { - return "", fmt.Errorf("the path to encryption certificates doesn't exist") - } + var encryptionCertsJson string + var err error - encryptionCertsJson, err := common.ReadDataFromFile(encryptionCertsPath) - if err != nil { - return "", err + // Handle stdin input + if encryptionCertsPath == "-" { + encryptionCertsJson, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(encryptionCertsPath) { + return "", fmt.Errorf("the path to encryption certificates doesn't exist") + } + encryptionCertsJson, err = common.ReadDataFromFile(encryptionCertsPath) + if err != nil { + return "", err + } } _, outputCertificate, _, _, _, err := certificate.HpcrGetEncryptionCertificateFromJson(encryptionCertsJson, version) diff --git a/lib/image/image.go b/lib/image/image.go index 6a5949b..575349b 100644 --- a/lib/image/image.go +++ b/lib/image/image.go @@ -40,7 +40,7 @@ const ( Parses image information from IBM Cloud API, CLI, or Terraform output to extract image ID, name, checksum, and version. Supports filtering by specific HPCR version.` - IbmCloudJsonInputDescription = "Path to IBM Cloud images JSON (from API, CLI, or Terraform)" + IbmCloudJsonInputDescription = "Path to IBM Cloud images JSON (from API, CLI, or Terraform, use '-' for standard input)" HpcrVersionFlagDescription = "Specific HPCR version to retrieve (returns latest if not specified)" OutputFlagDescription = "Path to save HPCR image details" invalidImagePathMessage = "The Image details path doesn't exists" @@ -65,6 +65,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, error) { common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, imageListJsonPath) + versionName, err := cmd.Flags().GetString(VersionFlagName) if err != nil { return "", "", "", "", err @@ -83,13 +86,23 @@ func ValidateInput(cmd *cobra.Command) (string, string, string, string, error) { // Process - function to get HPCR image details from JSON input func Process(imageDetailsJsonPath, versionName string) (ImageDetails, error) { - if !common.CheckFileFolderExists(imageDetailsJsonPath) { - log.Fatal(invalidImagePathMessage) - } + var imageDataJson string + var err error - imageDataJson, err := common.ReadDataFromFile(imageDetailsJsonPath) - if err != nil { - log.Fatal(err) + // Handle stdin input + if imageDetailsJsonPath == "-" { + imageDataJson, err = common.ReadDataFromStdin() + if err != nil { + return ImageDetails{}, fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(imageDetailsJsonPath) { + log.Fatal(invalidImagePathMessage) + } + imageDataJson, err = common.ReadDataFromFile(imageDetailsJsonPath) + if err != nil { + log.Fatal(err) + } } imageId, imageName, imageChecksum, ImageVersion, err := image.HpcrSelectImage(imageDataJson, versionName) diff --git a/lib/initdata/initdata.go b/lib/initdata/initdata.go index 7109b40..ab2d856 100644 --- a/lib/initdata/initdata.go +++ b/lib/initdata/initdata.go @@ -29,7 +29,7 @@ const ( ParameterLongDescription = `Gzip and Encoded initdata annotation` InputFlagName = "in" - InputFlagDescription = "Path of Signed and Encrypted contract" + InputFlagDescription = "Path of Signed and Encrypted contract (use '-' for standard input)" OutputFlagName = "out" OutputFlagDescription = "Path to save Gzipped and encoded initdata value" @@ -47,6 +47,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, error) { common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, inputData) + outputPath, err := cmd.Flags().GetString(OutputFlagName) if err != nil { return "", "", err @@ -56,13 +59,25 @@ func ValidateInput(cmd *cobra.Command) (string, string, error) { // GenerateInitdata - function to generate gzipped initdata func GenerateInitdata(inputDataPath string) (string, error) { - if !common.CheckFileFolderExists(inputDataPath) { - return "", fmt.Errorf("the contract path doesn't exist") - } - inputData, err := common.ReadDataFromFile(inputDataPath) - if err != nil { - return "", err + var inputData string + var err error + + // Handle stdin input + if inputDataPath == "-" { + inputData, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(inputDataPath) { + return "", fmt.Errorf("the contract path doesn't exist") + } + inputData, err = common.ReadDataFromFile(inputDataPath) + if err != nil { + return "", err + } } + gzipInitdata, _, _, err := contract.HpccInitdata(inputData) if err != nil { return "", err diff --git a/lib/validateContract/validateContract.go b/lib/validateContract/validateContract.go index 69eeab3..56e8dc4 100644 --- a/lib/validateContract/validateContract.go +++ b/lib/validateContract/validateContract.go @@ -29,7 +29,7 @@ const ( Checks contract structure, required fields, and data types before encryption. Helps catch errors early in the development process.` - InputFlagDescription = "Path to unencrypted Hyper Protect contract YAML file" + InputFlagDescription = "Path to unencrypted Hyper Protect contract YAML file (use '-' for standard input)" InputFlagName = "in" OsVersionFlagName = "os" OsVersionFlagDescription = "Target Hyper Protect platform (hpvs, hpcr-rhvs, or hpcc-peerpod)" @@ -46,6 +46,9 @@ func ValidateInput(cmd *cobra.Command) (string, string, error) { common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, contract) + version, err := cmd.Flags().GetString(OsVersionFlagName) if err != nil { return "", "", err diff --git a/lib/validateEncryptionCertificate/validateEncryptionCertificate.go b/lib/validateEncryptionCertificate/validateEncryptionCertificate.go index 9dc4b10..596eeb1 100644 --- a/lib/validateEncryptionCertificate/validateEncryptionCertificate.go +++ b/lib/validateEncryptionCertificate/validateEncryptionCertificate.go @@ -30,6 +30,7 @@ const ( Validates encryption certificate for on-premise, VPC deployment. It will check encryption certificate validity` + InputFlagDescription = "Path to encryption certificate file (use '-' for standard input)" CertVersionFlagDescription = "Versions of Encryption Certificates to validate, Seperated by coma(,)" InputFlagName = "in" ) @@ -45,18 +46,31 @@ func ValidateInput(cmd *cobra.Command) (string, error) { common.SetMandatoryFlagError(cmd, err) } + // Validate stdin input + common.ValidateStdinInput(cmd, encryptionCertsPath) + return encryptionCertsPath, nil } // GetEncryptionCertfile - function to get encryption certificate func GetEncryptionCertfile(encryptionCertsPath string) (string, error) { - if !common.CheckFileFolderExists(encryptionCertsPath) { - return "", fmt.Errorf("The specified path does not contain the encryption certificates.") - } + var encryptionCert string + var err error - encryptionCert, err := common.ReadDataFromFile(encryptionCertsPath) - if err != nil { - return "", err + // Handle stdin input + if encryptionCertsPath == "-" { + encryptionCert, err = common.ReadDataFromStdin() + if err != nil { + return "", fmt.Errorf("unable to read input from standard input: %w", err) + } + } else { + if !common.CheckFileFolderExists(encryptionCertsPath) { + return "", fmt.Errorf("The specified path does not contain the encryption certificates.") + } + encryptionCert, err = common.ReadDataFromFile(encryptionCertsPath) + if err != nil { + return "", err + } } return encryptionCert, nil diff --git a/lib/validateNetwork/validateNetwork.go b/lib/validateNetwork/validateNetwork.go index 6765567..104055b 100644 --- a/lib/validateNetwork/validateNetwork.go +++ b/lib/validateNetwork/validateNetwork.go @@ -29,7 +29,7 @@ const ( Validates network configuration for on-premise deployments, ensuring all required fields are present and properly formatted.` - InputFlagDescription = "Path to network-config YAML file" + InputFlagDescription = "Path to network-config YAML file (use '-' for standard input)" InputFlagName = "in" ) @@ -44,5 +44,7 @@ func ValidateInput(cmd *cobra.Command) (string, error) { common.SetMandatoryFlagError(cmd, err) } + common.ValidateStdinInput(cmd, networkConfig) + return networkConfig, nil }