зеркало из https://github.com/getsops/sops.git
Merge pull request #491 from adrianosela/golint
Address Go Lint messages
This commit is contained in:
Коммит
9998e16c3e
|
@ -45,6 +45,7 @@ type Cipher struct {
|
|||
stash map[stashKey][]byte
|
||||
}
|
||||
|
||||
// NewCipher is the constructor for a new Cipher object
|
||||
func NewCipher() Cipher {
|
||||
return Cipher{
|
||||
stash: make(map[stashKey][]byte),
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
|
||||
"github.com/pkg/errors"
|
||||
|
||||
// empty import as per https://godoc.org/github.com/lib/pq
|
||||
_ "github.com/lib/pq"
|
||||
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.mozilla.org/sops/logging"
|
||||
"gopkg.in/yaml.v2"
|
||||
|
@ -67,36 +69,52 @@ type config struct {
|
|||
|
||||
var auditors []Auditor
|
||||
|
||||
// SubmitEvent handles an event for all auditors
|
||||
func SubmitEvent(event interface{}) {
|
||||
for _, auditor := range auditors {
|
||||
auditor.Handle(event)
|
||||
}
|
||||
}
|
||||
|
||||
// Register registers a new Auditor in the global auditor list
|
||||
func Register(auditor Auditor) {
|
||||
auditors = append(auditors, auditor)
|
||||
}
|
||||
|
||||
// Auditor is notified when noteworthy events happen,
|
||||
// for example when a file is encrypted or decrypted.
|
||||
type Auditor interface {
|
||||
// Handle() takes an audit event and attempts to persists it;
|
||||
// how it is persisted and how errors are handled is up to the
|
||||
// implementation of this interface.
|
||||
Handle(event interface{})
|
||||
}
|
||||
|
||||
// DecryptEvent contains fields relevant to a decryption event
|
||||
type DecryptEvent struct {
|
||||
File string
|
||||
}
|
||||
|
||||
// EncryptEvent contains fields relevant to an encryption event
|
||||
type EncryptEvent struct {
|
||||
File string
|
||||
}
|
||||
|
||||
// RotateEvent contains fields relevant to a key rotation event
|
||||
type RotateEvent struct {
|
||||
File string
|
||||
}
|
||||
|
||||
// PostgresAuditor is a Postgres SQL DB implementation of the Auditor interface.
|
||||
// It persists the audit event by writing a row to the 'audit_event' table.
|
||||
// Errors with writing to the database will output a log message and the
|
||||
// process will exit with status set to 1
|
||||
type PostgresAuditor struct {
|
||||
DB *sql.DB
|
||||
}
|
||||
|
||||
// NewPostgresAuditor is the constructor for a new PostgresAuditor struct
|
||||
// initialized with the given db connection string
|
||||
func NewPostgresAuditor(connStr string) (*PostgresAuditor, error) {
|
||||
db, err := sql.Open("postgres", connStr)
|
||||
pg := &PostgresAuditor{DB: db}
|
||||
|
@ -113,6 +131,8 @@ func NewPostgresAuditor(connStr string) (*PostgresAuditor, error) {
|
|||
return pg, nil
|
||||
}
|
||||
|
||||
// Handle persists the audit event by writing a row to the
|
||||
// 'audit_event' postgres table
|
||||
func (p *PostgresAuditor) Handle(event interface{}) {
|
||||
u, err := user.Current()
|
||||
if err != nil {
|
||||
|
|
|
@ -73,7 +73,7 @@ func MasterKeysFromURLs(urls string) ([]*MasterKey, error) {
|
|||
return keys, nil
|
||||
}
|
||||
|
||||
// NewMasterKeyFromResourceID takes an Azure Key Vault key URL and returns a new MasterKey
|
||||
// NewMasterKeyFromURL takes an Azure Key Vault key URL and returns a new MasterKey
|
||||
// URL format is {vaultUrl}/keys/{key-name}/{key-version}
|
||||
func NewMasterKeyFromURL(url string) (*MasterKey, error) {
|
||||
k := &MasterKey{}
|
||||
|
|
|
@ -92,16 +92,16 @@ func TestKeyToMap(t *testing.T) {
|
|||
}, key.ToMap())
|
||||
}
|
||||
|
||||
var azureKeyAcceptanceTestUrl = flag.String("azure-key", "", "URL to Azure Key Vault (note that this can incur real costs!)")
|
||||
var azureKeyAcceptanceTestURL = flag.String("azure-key", "", "URL to Azure Key Vault (note that this can incur real costs!)")
|
||||
|
||||
func TestRoundtrip(t *testing.T) {
|
||||
if *azureKeyAcceptanceTestUrl == "" {
|
||||
if *azureKeyAcceptanceTestURL == "" {
|
||||
t.Skip("Azure URL not provided, skipping acceptance test")
|
||||
}
|
||||
|
||||
input := []byte("test-string")
|
||||
|
||||
key, err := NewMasterKeyFromURL(*azureKeyAcceptanceTestUrl)
|
||||
key, err := NewMasterKeyFromURL(*azureKeyAcceptanceTestURL)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
|
|
@ -24,10 +24,13 @@ import (
|
|||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// ExampleFileEmitter emits example files. This is used by the `sops` binary
|
||||
// whenever a new file is created, in order to present the user with a non-empty file
|
||||
type ExampleFileEmitter interface {
|
||||
EmitExample() []byte
|
||||
}
|
||||
|
||||
// Store handles marshaling and unmarshaling from SOPS files
|
||||
type Store interface {
|
||||
sops.Store
|
||||
ExampleFileEmitter
|
||||
|
@ -107,6 +110,8 @@ func LoadEncryptedFile(loader sops.EncryptedFileLoader, inputPath string) (*sops
|
|||
return &tree, err
|
||||
}
|
||||
|
||||
// NewExitError returns a cli.ExitError given an error (wrapped in a generic interface{})
|
||||
// and an exit code to represent the failure
|
||||
func NewExitError(i interface{}, exitCode int) *cli.ExitError {
|
||||
if userErr, ok := i.(sops.UserError); ok {
|
||||
return NewExitError(userErr.UserError(), exitCode)
|
||||
|
@ -114,22 +119,28 @@ func NewExitError(i interface{}, exitCode int) *cli.ExitError {
|
|||
return cli.NewExitError(i, exitCode)
|
||||
}
|
||||
|
||||
// IsYAMLFile returns true if a given file path corresponds to a YAML file
|
||||
func IsYAMLFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".yaml") || strings.HasSuffix(path, ".yml")
|
||||
}
|
||||
|
||||
// IsJSONFile returns true if a given file path corresponds to a JSON file
|
||||
func IsJSONFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".json")
|
||||
}
|
||||
|
||||
// IsEnvFile returns true if a given file path corresponds to a .env file
|
||||
func IsEnvFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".env")
|
||||
}
|
||||
|
||||
// IsIniFile returns true if a given file path corresponds to a INI file
|
||||
func IsIniFile(path string) bool {
|
||||
return strings.HasSuffix(path, ".ini")
|
||||
}
|
||||
|
||||
// DefaultStoreForPath returns the correct format-specific implementation
|
||||
// of the Store interface given the path to a file
|
||||
func DefaultStoreForPath(path string) Store {
|
||||
if IsYAMLFile(path) {
|
||||
return &yaml.Store{}
|
||||
|
@ -143,8 +154,12 @@ func DefaultStoreForPath(path string) Store {
|
|||
return &json.BinaryStore{}
|
||||
}
|
||||
|
||||
// KMS_ENC_CTX_BUG_FIXED_VERSION represents the SOPS version in which the
|
||||
// encryption context bug was fixed
|
||||
const KMS_ENC_CTX_BUG_FIXED_VERSION = "3.3.0"
|
||||
|
||||
// DetectKMSEncryptionContextBug returns true if the encryption context bug is detected
|
||||
// in a given runtime sops.Tree object
|
||||
func DetectKMSEncryptionContextBug(tree *sops.Tree) (bool, error) {
|
||||
versionCheck, err := version.AIsNewerThanB(KMS_ENC_CTX_BUG_FIXED_VERSION, tree.Metadata.Version)
|
||||
if err != nil {
|
||||
|
@ -161,6 +176,7 @@ func DetectKMSEncryptionContextBug(tree *sops.Tree) (bool, error) {
|
|||
return false, nil
|
||||
}
|
||||
|
||||
// GetKMSKeyWithEncryptionCtx returns the first KMS key affected by the encryption context bug as well as its location in the key groups.
|
||||
func GetKMSKeyWithEncryptionCtx(tree *sops.Tree) (keyGroupIndex int, keyIndex int, key *kms.MasterKey) {
|
||||
for i, kg := range tree.Metadata.KeyGroups {
|
||||
for n, k := range kg {
|
||||
|
@ -181,6 +197,7 @@ func GetKMSKeyWithEncryptionCtx(tree *sops.Tree) (keyGroupIndex int, keyIndex in
|
|||
return 0, 0, nil
|
||||
}
|
||||
|
||||
// GenericDecryptOpts represents decryption options and config
|
||||
type GenericDecryptOpts struct {
|
||||
Cipher sops.Cipher
|
||||
InputStore sops.Store
|
||||
|
@ -235,10 +252,9 @@ func FixAWSKMSEncryptionContextBug(opts GenericDecryptOpts, tree *sops.Tree) (*s
|
|||
}
|
||||
}
|
||||
if response == "n" {
|
||||
return nil, fmt.Errorf("Exiting. User responded no.")
|
||||
} else {
|
||||
persistFix = true
|
||||
return nil, fmt.Errorf("Exiting. User responded no")
|
||||
}
|
||||
persistFix = true
|
||||
}
|
||||
|
||||
// If there is another key, then we should be able to just decrypt
|
||||
|
@ -341,6 +357,7 @@ func RecoverDataKeyFromBuggyKMS(opts GenericDecryptOpts, tree *sops.Tree) []byte
|
|||
return nil
|
||||
}
|
||||
|
||||
// Diff represents a key diff
|
||||
type Diff struct {
|
||||
Common []keys.MasterKey
|
||||
Added []keys.MasterKey
|
||||
|
@ -354,6 +371,7 @@ func max(a, b int) int {
|
|||
return b
|
||||
}
|
||||
|
||||
// DiffKeyGroups returns the list of diffs found in two sops.keyGroup slices
|
||||
func DiffKeyGroups(ours, theirs []sops.KeyGroup) []Diff {
|
||||
var diffs []Diff
|
||||
for i := 0; i < max(len(ours), len(theirs)); i++ {
|
||||
|
@ -388,6 +406,7 @@ func DiffKeyGroups(ours, theirs []sops.KeyGroup) []Diff {
|
|||
return diffs
|
||||
}
|
||||
|
||||
// PrettyPrintDiffs prints a slice of Diff objects to stdout
|
||||
func PrettyPrintDiffs(diffs []Diff) {
|
||||
for i, diff := range diffs {
|
||||
color.New(color.Underline).Printf("Group %d\n", i+1)
|
||||
|
|
|
@ -24,6 +24,7 @@ func init() {
|
|||
log = logging.NewLogger("PUBLISH")
|
||||
}
|
||||
|
||||
// Opts represents publish options and config
|
||||
type Opts struct {
|
||||
Interactive bool
|
||||
Cipher sops.Cipher
|
||||
|
@ -33,6 +34,7 @@ type Opts struct {
|
|||
InputStore sops.Store
|
||||
}
|
||||
|
||||
// Run publish operation
|
||||
func Run(opts Opts) error {
|
||||
var fileContents []byte
|
||||
path, err := filepath.Abs(opts.InputPath)
|
||||
|
|
|
@ -12,6 +12,7 @@ import (
|
|||
"go.mozilla.org/sops/keyservice"
|
||||
)
|
||||
|
||||
// Opts represents key operation options and config
|
||||
type Opts struct {
|
||||
InputPath string
|
||||
GroupQuorum int
|
||||
|
@ -20,6 +21,7 @@ type Opts struct {
|
|||
ConfigPath string
|
||||
}
|
||||
|
||||
// UpdateKeys update the keys for a given file
|
||||
func UpdateKeys(opts Opts) error {
|
||||
path, err := filepath.Abs(opts.InputPath)
|
||||
if err != nil {
|
||||
|
|
|
@ -17,12 +17,14 @@ type TextFormatter struct {
|
|||
logrus.TextFormatter
|
||||
}
|
||||
|
||||
// Format formats a log entry onto bytes
|
||||
func (f *TextFormatter) Format(entry *logrus.Entry) ([]byte, error) {
|
||||
bytes, err := f.TextFormatter.Format(entry)
|
||||
name := color.New(color.Bold).Sprintf("[%s]", f.LoggerName)
|
||||
return []byte(fmt.Sprintf("%s\t %s", name, bytes)), err
|
||||
}
|
||||
|
||||
// NewLogger is the constructor for a new Logger object with the given name
|
||||
func NewLogger(name string) *logrus.Logger {
|
||||
log := logrus.New()
|
||||
log.SetLevel(logrus.WarnLevel)
|
||||
|
@ -33,10 +35,12 @@ func NewLogger(name string) *logrus.Logger {
|
|||
return log
|
||||
}
|
||||
|
||||
// SetLevel sets the given level for all current Loggers
|
||||
func SetLevel(level logrus.Level) {
|
||||
for k := range Loggers {
|
||||
Loggers[k].SetLevel(level)
|
||||
}
|
||||
}
|
||||
|
||||
// Loggers is the runtime map of logger name to logger object
|
||||
var Loggers map[string]*logrus.Logger
|
||||
|
|
|
@ -7,19 +7,23 @@ import (
|
|||
"cloud.google.com/go/storage"
|
||||
)
|
||||
|
||||
// GCSDestination represents the Google Cloud Storage destination
|
||||
type GCSDestination struct {
|
||||
gcsBucket string
|
||||
gcsPrefix string
|
||||
}
|
||||
|
||||
// NewGCSDestination is the constructor for a Google Cloud Storage destination
|
||||
func NewGCSDestination(gcsBucket string, gcsPrefix string) *GCSDestination {
|
||||
return &GCSDestination{gcsBucket, gcsPrefix}
|
||||
}
|
||||
|
||||
// Path returns a the GCS path for a file within this GCS Destination
|
||||
func (gcsd *GCSDestination) Path(fileName string) string {
|
||||
return fmt.Sprintf("gcs://%s/%s%s", gcsd.gcsBucket, gcsd.gcsPrefix, fileName)
|
||||
}
|
||||
|
||||
// Upload uploads contents to a file in GCS
|
||||
func (gcsd *GCSDestination) Upload(fileContents []byte, fileName string) error {
|
||||
ctx := context.Background()
|
||||
client, err := storage.NewClient(ctx)
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package publish
|
||||
|
||||
// Destination represents actions which all destination types
|
||||
// must implement in order to be used by SOPS
|
||||
type Destination interface {
|
||||
Upload(fileContents []byte, fileName string) error
|
||||
Path(fileName string) string
|
||||
|
|
|
@ -9,19 +9,23 @@ import (
|
|||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
)
|
||||
|
||||
// S3Destination is the AWS S3 implementation of the Destination interface
|
||||
type S3Destination struct {
|
||||
s3Bucket string
|
||||
s3Prefix string
|
||||
}
|
||||
|
||||
// NewS3Destination is the constructor for an S3 Destination
|
||||
func NewS3Destination(s3Bucket string, s3Prefix string) *S3Destination {
|
||||
return &S3Destination{s3Bucket, s3Prefix}
|
||||
}
|
||||
|
||||
// Path returns the S3 path of a file in an S3 Destination (bucket)
|
||||
func (s3d *S3Destination) Path(fileName string) string {
|
||||
return fmt.Sprintf("s3://%s/%s%s", s3d.s3Bucket, s3d.s3Prefix, fileName)
|
||||
}
|
||||
|
||||
// Upload uploads contents to a file in an S3 Destination (bucket)
|
||||
func (s3d *S3Destination) Upload(fileContents []byte, fileName string) error {
|
||||
sess := session.Must(session.NewSession())
|
||||
svc := s3.New(sess)
|
||||
|
|
|
@ -73,8 +73,8 @@ func (p *polynomial) evaluate(x uint8) uint8 {
|
|||
// An implementation of Lagrange interpolation
|
||||
// <https://en.wikipedia.org/wiki/Lagrange_polynomial>
|
||||
// For this particular implementation, x is always 0
|
||||
func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
|
||||
limit := len(x_samples)
|
||||
func interpolatePolynomial(xSamples, ySamples []uint8, x uint8) uint8 {
|
||||
limit := len(xSamples)
|
||||
var result, basis uint8
|
||||
for i := 0; i < limit; i++ {
|
||||
basis = 1
|
||||
|
@ -82,12 +82,12 @@ func interpolatePolynomial(x_samples, y_samples []uint8, x uint8) uint8 {
|
|||
if i == j {
|
||||
continue
|
||||
}
|
||||
num := add(x, x_samples[j])
|
||||
denom := add(x_samples[i], x_samples[j])
|
||||
num := add(x, xSamples[j])
|
||||
denom := add(xSamples[i], xSamples[j])
|
||||
term := div(num, denom)
|
||||
basis = mult(basis, term)
|
||||
}
|
||||
group := mult(y_samples[i], basis)
|
||||
group := mult(ySamples[i], basis)
|
||||
result = add(result, group)
|
||||
}
|
||||
return result
|
||||
|
@ -103,9 +103,9 @@ func div(a, b uint8) uint8 {
|
|||
}
|
||||
|
||||
var goodVal, zero uint8
|
||||
log_a := logTable[a]
|
||||
log_b := logTable[b]
|
||||
diff := (int(log_a) - int(log_b)) % 255
|
||||
logA := logTable[a]
|
||||
logB := logTable[b]
|
||||
diff := (int(logA) - int(logB)) % 255
|
||||
if diff < 0 {
|
||||
diff += 255
|
||||
}
|
||||
|
@ -258,8 +258,8 @@ func Combine(parts [][]byte) ([]byte, error) {
|
|||
secret := make([]byte, firstPartLen-1)
|
||||
|
||||
// Buffer to store the samples
|
||||
x_samples := make([]uint8, len(parts))
|
||||
y_samples := make([]uint8, len(parts))
|
||||
xSamples := make([]uint8, len(parts))
|
||||
ySamples := make([]uint8, len(parts))
|
||||
|
||||
// Set the x value for each sample and ensure no x_sample values are the same,
|
||||
// otherwise div() can be unhappy
|
||||
|
@ -272,19 +272,19 @@ func Combine(parts [][]byte) ([]byte, error) {
|
|||
return nil, fmt.Errorf("duplicate part detected")
|
||||
}
|
||||
checkMap[samp] = true
|
||||
x_samples[i] = samp
|
||||
xSamples[i] = samp
|
||||
}
|
||||
|
||||
// Reconstruct each byte
|
||||
for idx := range secret {
|
||||
// Set the y value for each sample
|
||||
for i, part := range parts {
|
||||
y_samples[i] = part[idx]
|
||||
ySamples[i] = part[idx]
|
||||
}
|
||||
|
||||
// Use Lagrange interpolation to retrieve the free term
|
||||
// of the original polynomial
|
||||
val := interpolatePolynomial(x_samples, y_samples, 0)
|
||||
val := interpolatePolynomial(xSamples, ySamples, 0)
|
||||
|
||||
// Evaluate the 0th value to get the intercept
|
||||
secret[idx] = val
|
||||
|
|
|
@ -188,9 +188,9 @@ func TestInterpolate_Rand(t *testing.T) {
|
|||
t.Fatalf("err: %v", err)
|
||||
}
|
||||
|
||||
x_vals := []uint8{1, 2, 3}
|
||||
y_vals := []uint8{p.evaluate(1), p.evaluate(2), p.evaluate(3)}
|
||||
out := interpolatePolynomial(x_vals, y_vals, 0)
|
||||
xVals := []uint8{1, 2, 3}
|
||||
yVals := []uint8{p.evaluate(1), p.evaluate(2), p.evaluate(3)}
|
||||
out := interpolatePolynomial(xVals, yVals, 0)
|
||||
if out != uint8(i) {
|
||||
t.Fatalf("Bad: %v %d", out, i)
|
||||
}
|
||||
|
|
38
sops.go
38
sops.go
|
@ -100,6 +100,7 @@ type TreeItem struct {
|
|||
// TreeBranch is a branch inside sops's tree. It is a slice of TreeItems and is therefore ordered
|
||||
type TreeBranch []TreeItem
|
||||
|
||||
// TreeBranches is a collection of TreeBranch
|
||||
// Trees usually have more than one branch
|
||||
type TreeBranches []TreeBranch
|
||||
|
||||
|
@ -110,10 +111,9 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
|||
return []interface{}{
|
||||
leaf,
|
||||
}
|
||||
} else {
|
||||
return []interface{}{
|
||||
valueFromPathAndLeaf(path[1:], leaf),
|
||||
}
|
||||
}
|
||||
return []interface{}{
|
||||
valueFromPathAndLeaf(path[1:], leaf),
|
||||
}
|
||||
default:
|
||||
if len(path) == 1 {
|
||||
|
@ -123,13 +123,12 @@ func valueFromPathAndLeaf(path []interface{}, leaf interface{}) interface{} {
|
|||
Value: leaf,
|
||||
},
|
||||
}
|
||||
} else {
|
||||
return TreeBranch{
|
||||
TreeItem{
|
||||
Key: component,
|
||||
Value: valueFromPathAndLeaf(path[1:], leaf),
|
||||
},
|
||||
}
|
||||
}
|
||||
return TreeBranch{
|
||||
TreeItem{
|
||||
Key: component,
|
||||
Value: valueFromPathAndLeaf(path[1:], leaf),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -150,31 +149,28 @@ func set(branch interface{}, path []interface{}, value interface{}) interface{}
|
|||
// Not found, need to add the next path entry to the branch
|
||||
if len(path) == 1 {
|
||||
return append(branch, TreeItem{Key: path[0], Value: value})
|
||||
} else {
|
||||
return valueFromPathAndLeaf(path, value)
|
||||
}
|
||||
return valueFromPathAndLeaf(path, value)
|
||||
case []interface{}:
|
||||
position := path[0].(int)
|
||||
if len(path) == 1 {
|
||||
if position >= len(branch) {
|
||||
return append(branch, value)
|
||||
} else {
|
||||
branch[position] = value
|
||||
}
|
||||
return branch
|
||||
branch[position] = value
|
||||
} else {
|
||||
if position >= len(branch) {
|
||||
branch = append(branch, valueFromPathAndLeaf(path[1:], value))
|
||||
} else {
|
||||
branch[position] = set(branch[position], path[1:], value)
|
||||
}
|
||||
return branch
|
||||
branch[position] = set(branch[position], path[1:], value)
|
||||
}
|
||||
return branch
|
||||
default:
|
||||
return valueFromPathAndLeaf(path, value)
|
||||
}
|
||||
}
|
||||
|
||||
// Set sets a value on a given tree for the specified path
|
||||
func (branch TreeBranch) Set(path []interface{}, value interface{}) TreeBranch {
|
||||
return set(branch, path, value).(TreeBranch)
|
||||
}
|
||||
|
@ -486,6 +482,8 @@ type PlainFileEmitter interface {
|
|||
EmitPlainFile(TreeBranches) ([]byte, error)
|
||||
}
|
||||
|
||||
// ValueEmitter is the interface for emitting a value. It provides a way to emit
|
||||
// values from the internal SOPS representation so that they can be shown
|
||||
type ValueEmitter interface {
|
||||
EmitValue(interface{}) ([]byte, error)
|
||||
}
|
||||
|
@ -634,7 +632,7 @@ func decryptKeyGroup(group KeyGroup, svcs []keyservice.KeyServiceClient) ([]byte
|
|||
// of the key services, returning as soon as one key service succeeds.
|
||||
func decryptKey(key keys.MasterKey, svcs []keyservice.KeyServiceClient) ([]byte, error) {
|
||||
svcKey := keyservice.KeyFromMasterKey(key)
|
||||
var part []byte = nil
|
||||
var part []byte
|
||||
decryptErr := decryptKeyError{
|
||||
keyName: key.ToString(),
|
||||
}
|
||||
|
|
|
@ -10,12 +10,14 @@ import (
|
|||
"go.mozilla.org/sops/stores"
|
||||
)
|
||||
|
||||
// SopsPrefix is the prefix for all metadatada entry keys
|
||||
const SopsPrefix = "sops_"
|
||||
|
||||
// Store handles storage of dotenv data
|
||||
type Store struct {
|
||||
}
|
||||
|
||||
// LoadEncryptedFile loads an encrypted file's bytes onto a sops.Tree runtime object
|
||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
branches, err := store.LoadPlainFile(in)
|
||||
if err != nil {
|
||||
|
@ -57,6 +59,8 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// LoadPlainFile returns the contents of a plaintext file loaded onto a
|
||||
// sops runtime object
|
||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
var branches sops.TreeBranches
|
||||
var branch sops.TreeBranch
|
||||
|
@ -86,6 +90,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
|||
return branches, nil
|
||||
}
|
||||
|
||||
// EmitEncryptedFile returns the encrypted file's bytes corresponding to a sops
|
||||
// runtime object
|
||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
metadata := stores.MetadataFromInternal(in.Metadata)
|
||||
mdItems, err := metadataToMap(metadata)
|
||||
|
@ -101,6 +107,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
|||
return store.EmitPlainFile(in.Branches)
|
||||
}
|
||||
|
||||
// EmitPlainFile returns the plaintext file's bytes corresponding to a sops
|
||||
// runtime object
|
||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||
buffer := bytes.Buffer{}
|
||||
for _, item := range in[0] {
|
||||
|
@ -118,6 +126,7 @@ func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
|||
return buffer.Bytes(), nil
|
||||
}
|
||||
|
||||
// EmitValue returns a single value as bytes
|
||||
func (Store) EmitValue(v interface{}) ([]byte, error) {
|
||||
if s, ok := v.(string); ok {
|
||||
return []byte(s), nil
|
||||
|
@ -125,6 +134,7 @@ func (Store) EmitValue(v interface{}) ([]byte, error) {
|
|||
return nil, fmt.Errorf("the dotenv store only supports emitting strings, got %T", v)
|
||||
}
|
||||
|
||||
// EmitExample returns the bytes corresponding to an example Flat Tree runtime object
|
||||
func (store *Store) EmitExample() []byte {
|
||||
bytes, err := store.EmitPlainFile(stores.ExampleFlatTree.Branches)
|
||||
if err != nil {
|
||||
|
|
|
@ -106,7 +106,7 @@ func tokenize(path string) []token {
|
|||
state = StateList
|
||||
i += len(listSeparator)
|
||||
} else {
|
||||
i += 1
|
||||
i++
|
||||
}
|
||||
}
|
||||
finishPrevToken()
|
||||
|
|
|
@ -136,6 +136,7 @@ func (store Store) treeItemFromSection(section *ini.Section) (sops.TreeItem, err
|
|||
return sectionItem, nil
|
||||
}
|
||||
|
||||
// LoadEncryptedFile loads encrypted INI file's bytes onto a sops.Tree runtime object
|
||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
iniFileOuter, err := ini.Load(in)
|
||||
if err != nil {
|
||||
|
@ -192,6 +193,7 @@ func (store *Store) iniSectionToMetadata(sopsSection *ini.Section) (stores.Metad
|
|||
return md, err
|
||||
}
|
||||
|
||||
// LoadPlainFile loads a plaintext INI file's bytes onto a sops.TreeBranches runtime object
|
||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
branches, err := store.treeBranchesFromIni(in)
|
||||
if err != nil {
|
||||
|
@ -200,6 +202,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
|||
return branches, nil
|
||||
}
|
||||
|
||||
// EmitEncryptedFile returns encrypted INI file bytes corresponding to a sops.Tree
|
||||
// runtime object
|
||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
|
||||
metadata := stores.MetadataFromInternal(in.Metadata)
|
||||
|
@ -298,6 +302,7 @@ func encodeMetadataItem(prefix string, kind reflect.Kind, field reflect.Value) (
|
|||
return result, nil
|
||||
}
|
||||
|
||||
// EmitPlainFile returns the plaintext INI file bytes corresponding to a sops.TreeBranches object
|
||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||
out, err := store.iniFromTreeBranches(in)
|
||||
if err != nil {
|
||||
|
@ -315,10 +320,12 @@ func (store Store) encodeValue(v interface{}) ([]byte, error) {
|
|||
}
|
||||
}
|
||||
|
||||
// EmitValue returns a single value encoded in a generic interface{} as bytes
|
||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||
return store.encodeValue(v)
|
||||
}
|
||||
|
||||
// EmitExample returns the plaintext INI file bytes corresponding to the SimpleTree example
|
||||
func (store *Store) EmitExample() []byte {
|
||||
bytes, err := store.EmitPlainFile(stores.ExampleSimpleTree.Branches)
|
||||
if err != nil {
|
||||
|
|
|
@ -19,10 +19,13 @@ type BinaryStore struct {
|
|||
store Store
|
||||
}
|
||||
|
||||
// LoadEncryptedFile loads an encrypted json file onto a sops.Tree object
|
||||
func (store BinaryStore) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
return store.store.LoadEncryptedFile(in)
|
||||
}
|
||||
|
||||
// LoadPlainFile loads a plaintext json file onto a sops.Tree encapsulated
|
||||
// within a sops.TreeBranches object
|
||||
func (store BinaryStore) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
return sops.TreeBranches{
|
||||
sops.TreeBranch{
|
||||
|
@ -34,10 +37,12 @@ func (store BinaryStore) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// EmitEncryptedFile produces an encrypted json file's bytes from its corresponding sops.Tree object
|
||||
func (store BinaryStore) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
return store.store.EmitEncryptedFile(in)
|
||||
}
|
||||
|
||||
// EmitPlainFile produces plaintext json file's bytes from its corresponding sops.TreeBranches object
|
||||
func (store BinaryStore) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||
// JSON stores a single object per file
|
||||
for _, item := range in[0] {
|
||||
|
@ -48,10 +53,13 @@ func (store BinaryStore) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
|||
return nil, fmt.Errorf("No binary data found in tree")
|
||||
}
|
||||
|
||||
// EmitValue extracts a value from a generic interface{} object representing a structured set
|
||||
// of binary files
|
||||
func (store BinaryStore) EmitValue(v interface{}) ([]byte, error) {
|
||||
return nil, fmt.Errorf("Binary files are not structured and extracting a single value is not possible")
|
||||
}
|
||||
|
||||
// EmitExample returns the example's plaintext json file bytes
|
||||
func (store BinaryStore) EmitExample() []byte {
|
||||
return []byte("Welcome to SOPS! Edit this file as you please!")
|
||||
}
|
||||
|
@ -207,6 +215,7 @@ func (store Store) reindentJSON(in []byte) ([]byte, error) {
|
|||
return out.Bytes(), err
|
||||
}
|
||||
|
||||
// LoadEncryptedFile loads an encrypted secrets file onto a sops.Tree object
|
||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
// Because we don't know what fields the input file will have, we have to
|
||||
// load the file in two steps.
|
||||
|
@ -252,6 +261,7 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// LoadPlainFile loads plaintext json file bytes onto a sops.TreeBranches object
|
||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
branch, err := store.treeBranchFromJSON(in)
|
||||
if err != nil {
|
||||
|
@ -262,6 +272,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// EmitEncryptedFile returns the encrypted bytes of the json file corresponding to a
|
||||
// sops.Tree runtime object
|
||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
tree := append(in.Branches[0], sops.TreeItem{Key: "sops", Value: stores.MetadataFromInternal(in.Metadata)})
|
||||
out, err := store.jsonFromTreeBranch(tree)
|
||||
|
@ -271,6 +283,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// EmitPlainFile returns the plaintext bytes of the json file corresponding to a
|
||||
// sops.TreeBranches runtime object
|
||||
func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
||||
out, err := store.jsonFromTreeBranch(in[0])
|
||||
if err != nil {
|
||||
|
@ -279,6 +293,8 @@ func (store *Store) EmitPlainFile(in sops.TreeBranches) ([]byte, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// EmitValue returns bytes corresponding to a single encoded value
|
||||
// in a generic interface{} object
|
||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||
s, err := store.encodeValue(v)
|
||||
if err != nil {
|
||||
|
@ -287,6 +303,7 @@ func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
|||
return store.reindentJSON(s)
|
||||
}
|
||||
|
||||
// EmitExample returns the bytes corresponding to an example complex tree
|
||||
func (store *Store) EmitExample() []byte {
|
||||
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
||||
if err != nil {
|
||||
|
|
|
@ -309,6 +309,7 @@ func (pgpKey *pgpkey) toInternal() (*pgp.MasterKey, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// ExampleComplexTree is an example sops.Tree object exhibiting complex relationships
|
||||
var ExampleComplexTree = sops.Tree{
|
||||
Branches: sops.TreeBranches{
|
||||
sops.TreeBranch{
|
||||
|
@ -343,6 +344,8 @@ var ExampleComplexTree = sops.Tree{
|
|||
},
|
||||
}
|
||||
|
||||
// ExampleSimpleTree is an example sops.Tree object exhibiting only simple relationships
|
||||
// with only one nested branch and only simple string values
|
||||
var ExampleSimpleTree = sops.Tree{
|
||||
Branches: sops.TreeBranches{
|
||||
sops.TreeBranch{
|
||||
|
@ -367,6 +370,8 @@ var ExampleSimpleTree = sops.Tree{
|
|||
},
|
||||
}
|
||||
|
||||
// ExampleFlatTree is an example sops.Tree object exhibiting only simple relationships
|
||||
// with no nested branches and only simple string values
|
||||
var ExampleFlatTree = sops.Tree{
|
||||
Branches: sops.TreeBranches{
|
||||
sops.TreeBranch{
|
||||
|
|
|
@ -101,6 +101,8 @@ func (store Store) treeBranchToYamlMap(in sops.TreeBranch) yaml.MapSlice {
|
|||
return branch
|
||||
}
|
||||
|
||||
// LoadEncryptedFile loads the contents of an encrypted yaml file onto a
|
||||
// sops.Tree runtime object
|
||||
func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
||||
var data []yaml.MapSlice
|
||||
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
||||
|
@ -136,6 +138,8 @@ func (store *Store) LoadEncryptedFile(in []byte) (sops.Tree, error) {
|
|||
}, nil
|
||||
}
|
||||
|
||||
// LoadPlainFile loads the contents of a plaintext yaml file onto a
|
||||
// sops.Tree runtime obejct
|
||||
func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
||||
var data []yaml.MapSlice
|
||||
if err := (yaml.CommentUnmarshaler{}).UnmarshalDocuments(in, &data); err != nil {
|
||||
|
@ -149,6 +153,8 @@ func (store *Store) LoadPlainFile(in []byte) (sops.TreeBranches, error) {
|
|||
return branches, nil
|
||||
}
|
||||
|
||||
// EmitEncryptedFile returns the encrypted bytes of the yaml file corresponding to a
|
||||
// sops.Tree runtime object
|
||||
func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
||||
out := []byte{}
|
||||
for i, branch := range in.Branches {
|
||||
|
@ -166,6 +172,8 @@ func (store *Store) EmitEncryptedFile(in sops.Tree) ([]byte, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// EmitPlainFile returns the plaintext bytes of the yaml file corresponding to a
|
||||
// sops.TreeBranches runtime object
|
||||
func (store *Store) EmitPlainFile(branches sops.TreeBranches) ([]byte, error) {
|
||||
var out []byte
|
||||
for i, branch := range branches {
|
||||
|
@ -182,11 +190,14 @@ func (store *Store) EmitPlainFile(branches sops.TreeBranches) ([]byte, error) {
|
|||
return out, nil
|
||||
}
|
||||
|
||||
// EmitValue returns bytes corresponding to a single encoded value
|
||||
// in a generic interface{} object
|
||||
func (store *Store) EmitValue(v interface{}) ([]byte, error) {
|
||||
v = store.treeValueToYamlValue(v)
|
||||
return (&yaml.YAMLMarshaler{Indent: 4}).Marshal(v)
|
||||
}
|
||||
|
||||
// EmitExample returns the bytes corresponding to an example complex tree
|
||||
func (store *Store) EmitExample() []byte {
|
||||
bytes, err := store.EmitPlainFile(stores.ExampleComplexTree.Branches)
|
||||
if err != nil {
|
||||
|
|
|
@ -10,8 +10,10 @@ import (
|
|||
"gopkg.in/urfave/cli.v1"
|
||||
)
|
||||
|
||||
// Version represents the value of the current semantic version
|
||||
const Version = "3.3.1"
|
||||
|
||||
// PrintVersion handles the version command for sops
|
||||
func PrintVersion(c *cli.Context) {
|
||||
out := fmt.Sprintf("%s %s", c.App.Name, c.App.Version)
|
||||
upstreamVersion, err := RetrieveLatestVersionFromUpstream()
|
||||
|
|
Загрузка…
Ссылка в новой задаче