Skip to content
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
28 changes: 10 additions & 18 deletions .github/workflows/e2e.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ on:
env:
GO_VERSION: "1.26"

permissions: read-all

jobs:
e2e-tests:
name: E2E Tests
Expand All @@ -37,10 +39,10 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@7b8cf10d4e4a01d4992d18a89f4d7dc5a3e6d6f4 # v4
with:
go-version: ${{ matrix.go-version }}
cache: true
Expand Down Expand Up @@ -72,7 +74,7 @@ jobs:

- name: Run E2E tests with Ginkgo
run: |
go run github.com/onsi/ginkgo/v2/ginkgo run -v --timeout=10m --poll-progress-after=1m ./e2e
go run github.com/onsi/ginkgo/v2/ginkgo@v2.28.0 run -v --timeout=10m --poll-progress-after=1m ./e2e
env:
CGO_ENABLED: 1
continue-on-error: false
Expand All @@ -90,14 +92,14 @@ jobs:

- name: Upload coverage reports
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: e2e-coverage-${{ matrix.os }}
path: coverage-e2e.*

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: e2e-test-results-${{ matrix.os }}
path: |
Expand All @@ -119,30 +121,20 @@ jobs:
runs-on: ubuntu-latest
timeout-minutes: 30

services:
docker:
image: docker:latest
options: >-
--privileged
--health-cmd="docker ps"
--health-interval=10s
--health-timeout=5s
--health-retries=5

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Set up Go
uses: actions/setup-go@v4
uses: actions/setup-go@7b8cf10d4e4a01d4992d18a89f4d7dc5a3e6d6f4 # v4
with:
go-version: "1.26"
cache: true
cache-dependency-path: go.sum

- name: Run E2E tests with verbose output
run: |
go run github.com/onsi/ginkgo/v2/ginkgo run -v -r --timeout=10m --poll-progress-after=1m ./e2e
go run github.com/onsi/ginkgo/v2/ginkgo@v2.28.0 run -v -r --timeout=10m --poll-progress-after=1m ./e2e
env:
CGO_ENABLED: 1

Expand Down
11 changes: 6 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,28 +5,29 @@ on:
branches:
- main

permissions:
contents: write
permissions: read-all

jobs:
release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
fetch-depth: 0

- name: Calculate next version
id: version
uses: charlesthomas/github-action-svu@v1.1.4+3.2.3
uses: charlesthomas/github-action-svu@da0337f57ff7d77c58363c32e9f863bfb01c0098 # v1.1.4+3.2.3
with:
cmd: patch
pushTag: true

- name: Create GitHub Release
if: steps.version.outputs.changed == 'true'
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@3bb12739c298aeb8a4eeaf626c5b8d85266b0e65 # v2
with:
tag_name: ${{ steps.version.outputs.next }}
generate_release_notes: true
8 changes: 4 additions & 4 deletions .github/workflows/scorecard.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,12 @@ jobs:

steps:
- name: Checkout code
uses: actions/checkout@v4
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
with:
persist-credentials: false

- name: Run analysis
uses: ossf/scorecard-action@v2.4.3
uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a # v2.4.3
with:
results_file: results.sarif
results_format: sarif
Expand All @@ -44,14 +44,14 @@ jobs:

# Upload the results as artifacts (optional)
- name: Upload artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4
with:
name: SARIF file
path: results.sarif
retention-days: 5

# Upload the results to GitHub's code scanning dashboard
- name: Upload to code-scanning
uses: github/codeql-action/upload-sarif@v3
uses: github/codeql-action/upload-sarif@dd903d2e4f5405488e5ef1422510ee31c8b32357 # v3
with:
sarif_file: results.sarif
11 changes: 11 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Security Policy

## Reporting a Vulnerability

Please report suspected security vulnerabilities privately by emailing security@flanksource.com.

Include as much detail as possible, including affected versions, reproduction steps, impact, and any suggested remediation. We will acknowledge receipt and coordinate disclosure and fixes as appropriate.

## Supported Versions

Security fixes are provided for the current `main` branch and the latest released version.
6 changes: 3 additions & 3 deletions api/config.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package api

import (
"crypto/md5"
"crypto/sha256"
"encoding/hex"
"fmt"
"net/url"
Expand Down Expand Up @@ -75,9 +75,9 @@ func PrintableSecret(secret string) string {
if len(secret) == 0 {
return "<nil>"
} else if len(secret) > 30 {
sum := md5.Sum([]byte(secret))
sum := sha256.Sum256([]byte(secret))
hash := hex.EncodeToString(sum[:])
return fmt.Sprintf("md5(%s),length=%d", hash[0:8], len(secret))
return fmt.Sprintf("sha256(%s),length=%d", hash[0:8], len(secret))
} else if len(secret) > 16 {
return fmt.Sprintf("%s****%s", secret[0:1], secret[len(secret)-2:])
} else if len(secret) > 10 {
Expand Down
79 changes: 72 additions & 7 deletions connection/awskms.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package connection

import (
"context"
"errors"
"fmt"

"github.com/flanksource/commons-db/context"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/kms"
"github.com/aws/aws-sdk-go-v2/service/kms/types"
"github.com/aws/smithy-go"
commonsContext "github.com/flanksource/commons-db/context"
"github.com/flanksource/commons-db/models"
"gocloud.dev/gcerrors"
"gocloud.dev/secrets"
"gocloud.dev/secrets/awskms"
"gocloud.dev/secrets/driver"
)

type AWSKMS struct {
Expand All @@ -25,17 +32,75 @@ func (t *AWSKMS) FromModel(conn models.Connection) {
t.KeyID = conn.Properties["keyID"]
}

func (t *AWSKMS) SecretKeeper(ctx context.Context) (*secrets.Keeper, error) {
func (t *AWSKMS) SecretKeeper(ctx commonsContext.Context) (*secrets.Keeper, error) {
awsConfig, err := t.AWSConnection.Client(ctx)
if err != nil {
return nil, fmt.Errorf("failed to create AWS client: %w", err)
}

kmsClient, err := awskms.DialV2(awsConfig)
keeper := secrets.NewKeeper(&awsKMSKeeper{
keyID: t.KeyID,
client: kms.NewFromConfig(awsConfig),
})
return keeper, nil
}

type awsKMSKeeper struct {
keyID string
client *kms.Client
}

var _ driver.Keeper = (*awsKMSKeeper)(nil)

func (k *awsKMSKeeper) Decrypt(ctx context.Context, ciphertext []byte) ([]byte, error) {
result, err := k.client.Decrypt(ctx, &kms.DecryptInput{
CiphertextBlob: ciphertext,
})
if err != nil {
return nil, fmt.Errorf("failed to create AWS KMS client: %w", err)
return nil, err
}
return result.Plaintext, nil
}

keeper := awskms.OpenKeeperV2(kmsClient, t.KeyID, nil)
return keeper, nil
func (k *awsKMSKeeper) Encrypt(ctx context.Context, plaintext []byte) ([]byte, error) {
result, err := k.client.Encrypt(ctx, &kms.EncryptInput{
KeyId: aws.String(k.keyID),
Plaintext: plaintext,
})
if err != nil {
return nil, err
}
return result.CiphertextBlob, nil
}

func (k *awsKMSKeeper) Close() error { return nil }

func (k *awsKMSKeeper) ErrorAs(err error, i any) bool {
return errors.As(err, i)
}

func (k *awsKMSKeeper) ErrorCode(err error) gcerrors.ErrorCode {
var apiErr smithy.APIError
if !errors.As(err, &apiErr) {
return gcerrors.Unknown
}

switch apiErr.ErrorCode() {
case (&types.NotFoundException{}).ErrorCode():
return gcerrors.NotFound
case (&types.InvalidCiphertextException{}).ErrorCode(), (&types.InvalidKeyUsageException{}).ErrorCode():
return gcerrors.InvalidArgument
case (&types.KMSInternalException{}).ErrorCode():
return gcerrors.Internal
case (&types.KMSInvalidStateException{}).ErrorCode():
return gcerrors.FailedPrecondition
case (&types.DisabledException{}).ErrorCode(), (&types.InvalidGrantTokenException{}).ErrorCode():
return gcerrors.PermissionDenied
case (&types.KeyUnavailableException{}).ErrorCode():
return gcerrors.ResourceExhausted
case (&types.DependencyTimeoutException{}).ErrorCode():
return gcerrors.DeadlineExceeded
default:
return gcerrors.Unknown
}
}
Loading
Loading