From e61ec39f796e253d9bffd67ab9b56295ccbc54b4 Mon Sep 17 00:00:00 2001 From: maze Date: Tue, 9 Sep 2025 10:14:07 +0200 Subject: [PATCH] Updated tests to work in more CICD envs --- env_test.go | 14 ++++++++++---- provider.go | 24 ++++++++++++++++++++++++ provider_test.go | 40 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/env_test.go b/env_test.go index 59dd8f5..25eda7b 100644 --- a/env_test.go +++ b/env_test.go @@ -8,7 +8,7 @@ import ( func TestEnvironment(t *testing.T) { key := "USER" - if testInPipeline() { + if _, ci := testInPipeline(); ci { key = "CI" } @@ -24,9 +24,15 @@ func TestEnvironmentPrefix(t *testing.T) { prefix = "US" key = "ER" ) - if testInPipeline() { - prefix = "CI_" - key = "JOB_ID" + if platform, ci := testInPipeline(); ci { + switch platform { + case "gitea": + prefix = "GITEA_" + key = "ACTIONS" + case "gitlab": + prefix = "CI_" + key = "JOB_ID" + } } testProvider(t, EnvironmentPrefix(prefix), diff --git a/provider.go b/provider.go index 3a28b46..cdafeb7 100644 --- a/provider.go +++ b/provider.go @@ -1,6 +1,7 @@ package secret import ( + "context" "encoding/base64" "encoding/hex" "fmt" @@ -14,6 +15,29 @@ type Provider interface { GetSecret(key string) (value []byte, err error) } +// Crypter for in-transit encrypted secrets. +type Crypter interface { + // Encrypt a plaintext using the key specified in keyID. + Encrypt(ctx context.Context, keyID string, plaintext []byte) (ciphertext []byte, err error) + + // Decrypt a ciphertext using the key specified in keyID. + Decrypt(ctx context.Context, keyID string, ciphertext []byte) (plaintext []byte, err error) +} + +func Encrypt(ctx context.Context, p Provider, keyID string, plaintext []byte) (ciphertext []byte, err error) { + if c, ok := p.(Crypter); ok { + return c.Encrypt(ctx, keyID, plaintext) + } + return nil, fmt.Errorf("secret: %T doesn't implement Crypter", p) +} + +func Decrypt(ctx context.Context, p Provider, keyID string, ciphertext []byte) (plaintext []byte, err error) { + if c, ok := p.(Crypter); ok { + return c.Decrypt(ctx, keyID, ciphertext) + } + return nil, fmt.Errorf("secret: %T doesn't implement Crypter", p) +} + // AmbiguousKey is an error incdicating that the secret doesn't resolve to exactly one item. type AmbiguousKey struct { Key string diff --git a/provider_test.go b/provider_test.go index 03d923c..ae92308 100644 --- a/provider_test.go +++ b/provider_test.go @@ -2,10 +2,12 @@ package secret import ( "bytes" + "context" "errors" "fmt" "os" "testing" + "time" ) type mockProvider struct { @@ -54,6 +56,30 @@ func testProvider(t *testing.T, p Provider, tests ...testProviderCase) { } } +func testCrypter(t *testing.T, p Provider, keyID string) { + t.Helper() + + ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second) + defer cancel() + + vector := []byte("Hello, Gophers! ʕ◔ϖ◔ʔ") + ciphertext, err := Encrypt(ctx, p, keyID, vector) + if err != nil { + t.Error(err) + return + } + + plaintext, err := Decrypt(ctx, p, keyID, ciphertext) + if err != nil { + t.Error(err) + return + } + + if err = testEqual(vector)(plaintext); err != nil { + t.Error(err) + } +} + func testNotEmpty(v []byte) error { if len(v) > 0 { return nil @@ -74,6 +100,16 @@ func testEqualString(a string) func([]byte) error { return testEqual([]byte(a)) } -func testInPipeline() bool { - return os.Getenv("CI") != "" +func testInPipeline() (string, bool) { + if os.Getenv("CI") != "" { + switch { + case os.Getenv("GITEA_ACTIONS") != "": + return "gitea", true + case os.Getenv("GITHUB_ACTIONS") != "": + return "github", true + case os.Getenv("CI_RUNNER_ID") != "": + return "gitlab", true + } + } + return "", true }