Skip to content

Commit

Permalink
Merge pull request #91 from dwango/feature/issue-63
Browse files Browse the repository at this point in the history
Wrap package errors
  • Loading branch information
s-dwinter authored Jun 14, 2024
2 parents e89dd6a + 5a36088 commit 5444bbf
Show file tree
Hide file tree
Showing 7 changed files with 160 additions and 14 deletions.
4 changes: 2 additions & 2 deletions internal/client/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (c awsClient) GetValues(ctx context.Context, ignoreNotFound bool) (values.V
if ignoreNotFound && errors.As(err, &notFoundErr) {
continue
}
return nil, err
return nil, gettingValueError(v.Name, err)
}

if err := values.SetValue(v, output.Parameter.Value); err != nil {
Expand All @@ -103,7 +103,7 @@ func (c awsClient) GetValues(ctx context.Context, ignoreNotFound bool) (values.V
if ignoreNotFound && errors.As(err, &notFoundErr) {
continue
}
return nil, err
return nil, gettingValueError(v.Name, err)
}

if err := values.SetValue(v, output.SecretString); err != nil {
Expand Down
9 changes: 9 additions & 0 deletions internal/client/cache/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (

var (
ErrInvalidCacheType = errors.New("invalid cache type")
ErrCacheProcessing = errors.New("cache processing error")
)

type Cache interface {
Expand Down Expand Up @@ -58,3 +59,11 @@ func New(cfg config.CacheConfig, options ...Option) (Cache, error) {
func keyToHex(key string) string {
return hex.EncodeToString([]byte(key))
}

func cacheProcessingError(msg string, err error) error {
if err != nil {
return fmt.Errorf("%w: %s: %w", ErrCacheProcessing, msg, err)
}

return fmt.Errorf("%w: %s", ErrCacheProcessing, msg)
}
17 changes: 8 additions & 9 deletions internal/client/cache/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ import (
"crypto/aes"
"crypto/cipher"
"crypto/rand"
"errors"
"io"
"os"
"path/filepath"
Expand Down Expand Up @@ -66,7 +65,7 @@ func newFileCache(cfg config.FileCacheConfig, expireDuration time.Duration, opti

// create cache directory
if err := os.MkdirAll(fc.cachePath, 0777); err != nil {
return nil, err
return nil, cacheProcessingError("failed to create cache directory", err)
}

// read or create key
Expand All @@ -77,7 +76,7 @@ func newFileCache(cfg config.FileCacheConfig, expireDuration time.Duration, opti

fc.cipherBlock, err = aes.NewCipher(key)
if err != nil {
return nil, err
return nil, cacheProcessingError("failed to create cipher block", err)
}

return fc, nil
Expand Down Expand Up @@ -145,7 +144,7 @@ func (f *fileCache) readOrCreateKey() ([]byte, error) {

// create key file
if _, err := rand.Read(key); err != nil {
return nil, err
return nil, cacheProcessingError("failed to create key", err)
}
if err := f.writeToFile(keyFileName, key, false); err != nil {
return nil, err
Expand Down Expand Up @@ -178,15 +177,15 @@ func (f *fileCache) readOrCreateKey() ([]byte, error) {

// check key is not tampered
if err := bcrypt.CompareHashAndPassword(keyHash, key); err != nil {
return nil, err
return nil, cacheProcessingError("key is tampered", err)
}

return key, nil
}

func (f *fileCache) decryptCache(cipherText []byte) ([]byte, error) {
if len(cipherText) < aes.BlockSize {
return nil, errors.New("ciphertext too short")
return nil, cacheProcessingError("cipher text is too short", nil)
}

iv := cipherText[:aes.BlockSize]
Expand All @@ -202,7 +201,7 @@ func (f *fileCache) encryptCache(plainText []byte) ([]byte, error) {
cipherText := make([]byte, aes.BlockSize+len(plainText))
iv := cipherText[:aes.BlockSize]
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
return nil, err
return nil, cacheProcessingError("failed to create initialization vector", err)
}

stream := cipher.NewCFBEncrypter(f.cipherBlock, iv)
Expand All @@ -228,7 +227,7 @@ func (f fileCache) readFile(filename string, hidden bool) ([]byte, error) {

data, err := os.ReadFile(filepath.Join(f.cachePath, filename))
if err != nil {
return nil, err
return nil, cacheProcessingError("failed to read file", err)
}
data = data[:len(data)-1]

Expand All @@ -243,7 +242,7 @@ func (f fileCache) writeToFile(filename string, data []byte, hidden bool) error

file, err := os.Create(filepath.Join(f.cachePath, filename))
if err != nil {
return err
return cacheProcessingError("failed to create file", err)
}
defer file.Close()

Expand Down
6 changes: 6 additions & 0 deletions internal/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package client
import (
"context"
"errors"
"fmt"

"github.com/dwango/yashiro/internal/values"
"github.com/dwango/yashiro/pkg/config"
Expand All @@ -27,6 +28,7 @@ import (
// Define errors
var (
ErrNotfoundValueConfig = errors.New("not found value config")
ErrGettingValue = errors.New("failed to get value")
)

// Client is the external stores client.
Expand All @@ -52,3 +54,7 @@ func New(cfg *config.Config) (Client, error) {

return client, nil
}

func gettingValueError(name string, err error) error {
return fmt.Errorf("%w: name='%s': %w", ErrGettingValue, name, err)
}
12 changes: 9 additions & 3 deletions pkg/engine/engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package engine
import (
"bytes"
"context"
"errors"
"fmt"
"io"
"text/template"

Expand All @@ -27,6 +29,10 @@ import (
"github.com/dwango/yashiro/pkg/engine/encoding"
)

var (
ErrRendering = errors.New("failed to render")
)

// Engine is a template engine.
type Engine interface {
Render(ctx context.Context, text string, dest io.Writer) error
Expand Down Expand Up @@ -81,12 +87,12 @@ func (e engine) Render(ctx context.Context, text string, dest io.Writer) error {

func (e engine) render(text string, dest io.Writer, data any) error {
if _, err := e.template.Parse(text); err != nil {
return err
return fmt.Errorf("%w: %w", ErrRendering, err)
}

tmp := &bytes.Buffer{}
if err := e.template.Execute(tmp, data); err != nil {
return err
return fmt.Errorf("%w: %w", ErrRendering, err)
}

b, err := e.encodeAndDecoder.EncodeAndDecode(tmp.Bytes())
Expand All @@ -96,7 +102,7 @@ func (e engine) render(text string, dest io.Writer, data any) error {

_, err = io.Copy(dest, bytes.NewReader(b))
if err != nil {
return err
return fmt.Errorf("%w: %w", ErrRendering, err)
}

return nil
Expand Down
34 changes: 34 additions & 0 deletions pkg/errors/errors.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/**
* Copyright 2024 DWANGO Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package errors

import (
"errors"

"github.com/dwango/yashiro/internal/client/cache"
"github.com/dwango/yashiro/pkg/engine"
)

// IsCacheProcessingError returns true if the error is a cache processing error.
func IsCacheProcessingError(err error) bool {
return errors.Is(err, cache.ErrCacheProcessing)
}

// IsRenderingError returns true if the error is a rendering error.
func IsRenderingError(err error) bool {
return errors.Is(err, engine.ErrRendering)
}
92 changes: 92 additions & 0 deletions pkg/errors/errors_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/**
* Copyright 2024 DWANGO Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package errors

import (
"errors"
"fmt"
"testing"

"github.com/dwango/yashiro/internal/client/cache"
"github.com/dwango/yashiro/pkg/engine"
)

func TestIsCacheProcessingError(t *testing.T) {
type args struct {
err error
}
tests := []struct {
name string
args args
want bool
}{
{
name: "true",
args: args{
err: fmt.Errorf("test: %w", cache.ErrCacheProcessing),
},
want: true,
},
{
name: "false",
args: args{
err: fmt.Errorf("test: %w", errors.New("different error")),
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsCacheProcessingError(tt.args.err); got != tt.want {
t.Errorf("IsCacheProcessingError() = %v, want %v", got, tt.want)
}
})
}
}

func TestIsRenderingError(t *testing.T) {
type args struct {
err error
}
tests := []struct {
name string
args args
want bool
}{
{
name: "true",
args: args{
err: fmt.Errorf("test: %w", engine.ErrRendering),
},
want: true,
},
{
name: "false",
args: args{
err: fmt.Errorf("test: %w", errors.New("different error")),
},
want: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := IsRenderingError(tt.args.err); got != tt.want {
t.Errorf("IsRenderingError() = %v, want %v", got, tt.want)
}
})
}
}

0 comments on commit 5444bbf

Please sign in to comment.