opentofu/internal/encryption/plan.go
Christian Mesh 997e5fa46e
State Encryption Error Handling / Diagnostics (#1294)
Signed-off-by: Christian Mesh <christianmesh1@gmail.com>
2024-03-04 08:30:30 -05:00

70 lines
2.5 KiB
Go

// Copyright (c) The OpenTofu Authors
// SPDX-License-Identifier: MPL-2.0
// Copyright (c) 2023 HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0
package encryption
import (
"fmt"
"github.com/hashicorp/hcl/v2"
"github.com/opentofu/opentofu/internal/encryption/config"
)
// PlanEncryption describes the methods that you can use for encrypting a plan file. Plan files are opaque values with
// no standardized format, so the encrypted form should be treated equally an opaque value.
type PlanEncryption interface {
// EncryptPlan encrypts a plan file and returns the encrypted form.
//
// When implementing this function:
//
// Plan files are opaque values. You may expect a valid plan file on the input, but you can produce binary data
// that is not necessarily a valid plan file. If no encryption is configured, this function should pass through
// any data it receives without modification, even if the plan file is invalid.
//
// When using this function:
//
// Make sure that you pass a valid plan file as an input. Failing to provide a valid plan file may result in an
// error. However, output values may not be valid plan files and you should not pass the encrypted plan file to any
// additional functions that normally work with plan files.
EncryptPlan([]byte) ([]byte, error)
// DecryptPlan decrypts an encrypted plan file.
//
// When implementing this function:
//
// If the user has configured no encryption, pass through any input unmodified regardless if the input is a valid
// plan file. If the user configured encryption, decrypt the plan file and return the decrypted plan file as a
// binary without further evaluating its validity.
//
// When using this function:
//
// Pass a potentially encrypted plan file as an input, and you will receive the decrypted plan file or an error as
// a result.
DecryptPlan([]byte) ([]byte, error)
}
type planEncryption struct {
base *baseEncryption
}
func newPlanEncryption(enc *encryption, target *config.TargetConfig, enforced bool, name string) (PlanEncryption, hcl.Diagnostics) {
base, diags := newBaseEncryption(enc, target, enforced, name)
return &planEncryption{base}, diags
}
func (p planEncryption) EncryptPlan(data []byte) ([]byte, error) {
return p.base.encrypt(data)
}
func (p planEncryption) DecryptPlan(data []byte) ([]byte, error) {
return p.base.decrypt(data, func(data []byte) error {
// Check magic bytes
if len(data) < 4 || string(data[:4]) != "PK" {
return fmt.Errorf("Invalid plan file")
}
return nil
})
}