Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

enhance(executable): encrypt DB executable #304

Merged
merged 2 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 68 additions & 19 deletions database/build_executable.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package database

import (
"database/sql"
"encoding/base64"
"errors"

"github.com/go-vela/types/library"
Expand All @@ -28,15 +29,15 @@ type BuildExecutable struct {
// BuildExecutable by compressing that data. This produces
// a significantly smaller amount of data that is
// stored in the system.
func (c *BuildExecutable) Compress(level int) error {
func (b *BuildExecutable) Compress(level int) error {
// compress the database BuildExecutable data
data, err := compress(level, c.Data)
data, err := compress(level, b.Data)
if err != nil {
return err
}

// overwrite database BuildExecutable data with compressed BuildExecutable data
c.Data = data
b.Data = data

return nil
}
Expand All @@ -45,15 +46,63 @@ func (c *BuildExecutable) Compress(level int) error {
// BuildExecutable by decompressing that data. This allows us
// to have a significantly smaller amount of data that
// is stored in the system.
func (c *BuildExecutable) Decompress() error {
func (b *BuildExecutable) Decompress() error {
// decompress the database BuildExecutable data
data, err := decompress(c.Data)
data, err := decompress(b.Data)
if err != nil {
return err
}

// overwrite compressed BuildExecutable data with decompressed BuildExecutable data
c.Data = data
b.Data = data

return nil
}

// Decrypt will manipulate the existing executable data by
// base64 decoding that value. Then, a AES-256 cipher
// block is created from the encryption key in order to
// decrypt the base64 decoded secret value.
func (b *BuildExecutable) Decrypt(key string) error {
dst := make([]byte, base64.StdEncoding.DecodedLen(len(b.Data)))

// base64 decode the encrypted repo hash
n, err := base64.StdEncoding.Decode(dst, b.Data)
if err != nil {
return err
}

dst = dst[:n]

// decrypt the base64 decoded executable data
decrypted, err := decrypt(key, dst)
if err != nil {
return err
}

// set the decrypted executable
b.Data = decrypted

return nil
}

// Encrypt will manipulate the existing build executable by
// creating a AES-256 cipher block from the encryption
// key in order to encrypt the build executable. Then, the
// build executable is base64 encoded for transport across
// network boundaries.
func (b *BuildExecutable) Encrypt(key string) error {
// encrypt the executable data
encrypted, err := encrypt(key, b.Data)
if err != nil {
return err
}

// base64 encode the encrypted executable to make it network safe
dst := make([]byte, base64.StdEncoding.EncodedLen(len(encrypted)))
base64.StdEncoding.Encode(dst, encrypted)

b.Data = dst

return nil
}
Expand All @@ -64,41 +113,41 @@ func (c *BuildExecutable) Decompress() error {
// When a field within the BuildExecutable type is the zero
// value for the field, the valid flag is set to
// false causing it to be NULL in the database.
func (c *BuildExecutable) Nullify() *BuildExecutable {
if c == nil {
func (b *BuildExecutable) Nullify() *BuildExecutable {
if b == nil {
return nil
}

// check if the ID field should be false
if c.ID.Int64 == 0 {
c.ID.Valid = false
if b.ID.Int64 == 0 {
b.ID.Valid = false
}

// check if the BuildID field should be false
if c.BuildID.Int64 == 0 {
c.BuildID.Valid = false
if b.BuildID.Int64 == 0 {
b.BuildID.Valid = false
}

return c
return b
}

// ToLibrary converts the BuildExecutable type
// to a library BuildExecutable type.
func (c *BuildExecutable) ToLibrary() *library.BuildExecutable {
func (b *BuildExecutable) ToLibrary() *library.BuildExecutable {
buildExecutable := new(library.BuildExecutable)

buildExecutable.SetID(c.ID.Int64)
buildExecutable.SetBuildID(c.BuildID.Int64)
buildExecutable.SetData(c.Data)
buildExecutable.SetID(b.ID.Int64)
buildExecutable.SetBuildID(b.BuildID.Int64)
buildExecutable.SetData(b.Data)

return buildExecutable
}

// Validate verifies the necessary fields for
// the BuildExecutable type are populated correctly.
func (c *BuildExecutable) Validate() error {
func (b *BuildExecutable) Validate() error {
// verify the BuildID field is populated
if c.BuildID.Int64 <= 0 {
if b.BuildID.Int64 <= 0 {
return ErrEmptyBuildExecutableBuildID
}

Expand Down
91 changes: 91 additions & 0 deletions database/build_executable_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,97 @@ func TestDatabase_BuildExecutable_Decompress(t *testing.T) {
}
}

func TestDatabase_BuildExecutable_Decrypt(t *testing.T) {
// setup types
key := "C639A572E14D5075C526FDDD43E4ECF6"
encrypted := testBuildExecutable()

err := encrypted.Encrypt(key)
if err != nil {
t.Errorf("unable to encrypt repo: %v", err)
}

// setup tests
tests := []struct {
failure bool
key string
executable BuildExecutable
}{
{
failure: false,
key: key,
executable: *encrypted,
},
{
failure: true,
key: "",
executable: *encrypted,
},
{
failure: true,
key: key,
executable: *testBuildExecutable(),
},
}

// run tests
for _, test := range tests {
err := test.executable.Decrypt(test.key)

if test.failure {
if err == nil {
t.Errorf("Decrypt should have returned err")
}

continue
}

if err != nil {
t.Errorf("Decrypt returned err: %v", err)
}
}
}

func TestDatabase_BuildExecutable_Encrypt(t *testing.T) {
// setup types
key := "C639A572E14D5075C526FDDD43E4ECF6"

// setup tests
tests := []struct {
failure bool
key string
executable *BuildExecutable
}{
{
failure: false,
key: key,
executable: testBuildExecutable(),
},
{
failure: true,
key: "",
executable: testBuildExecutable(),
},
}

// run tests
for _, test := range tests {
err := test.executable.Encrypt(test.key)

if test.failure {
if err == nil {
t.Errorf("Encrypt should have returned err")
}

continue
}

if err != nil {
t.Errorf("Encrypt returned err: %v", err)
}
}
}

func TestDatabase_BuildExecutable_Nullify(t *testing.T) {
// setup types
var p *BuildExecutable
Expand Down
Loading