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
8 changes: 6 additions & 2 deletions app/controlplane/cmd/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion app/controlplane/configs/config.devel.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ cas_server:
addr: 0.0.0.0:9001
insecure: true
download_url: http://0.0.0.0:8001/download

default_entry_max_size: 300MB
credentials_service:
vault:
address: ${VAULT_ADDRESS:http://0.0.0.0:8200}
Expand Down
1 change: 1 addition & 0 deletions app/controlplane/configs/samples/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ cas_server:
addr: 0.0.0.0:9001
# Where to redirect the user to download artifacts from the CAS
download_url: http://0.0.0.0:8001/download
default_entry_max_size: 1GB

# nats endpoint where to send events
nats_server:
Expand Down
336 changes: 175 additions & 161 deletions app/controlplane/internal/conf/controlplane/config/v1/conf.pb.go

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ message Bootstrap {
// In the form of [scheme]://[host]/path i.e https://cas.chainloop.dev/download
// https://github.com/chainloop-dev/chainloop/blob/126f47b6c0803eac844b8e3e1a21d582f00e4dc6/app/artifact-cas/internal/service/download.go#L34
string download_url = 3;

// Default max size for each entry in the CAS backend
// the format is a number followed by a unit, like 100MB, 1GB, etc
// Default is 100MB
string default_entry_max_size = 4;
}

// Configuration for onboarding users in organizations with specific roles
Expand Down
27 changes: 19 additions & 8 deletions app/controlplane/pkg/biz/casbackend.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"io"
"time"

"code.cloudfoundry.org/bytefmt"
conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
backend "github.com/chainloop-dev/chainloop/pkg/blobmanager"
"github.com/chainloop-dev/chainloop/pkg/blobmanager/azureblob"
"github.com/chainloop-dev/chainloop/pkg/blobmanager/oci"
Expand All @@ -36,7 +38,6 @@ import (
type CASBackendProvider string

const (
CASBackendDefaultMaxBytes int64 = 100 * 1024 * 1024 // 100MB
// Inline, embedded CAS backend
CASBackendInline CASBackendProvider = "INLINE"
CASBackendInlineDefaultMaxBytes int64 = 500 * 1024 // 500KB
Expand Down Expand Up @@ -111,18 +112,28 @@ type CASBackendReader interface {
}

type CASBackendUseCase struct {
repo CASBackendRepo
logger *log.Helper
credsRW credentials.ReaderWriter
providers backend.Providers
repo CASBackendRepo
logger *log.Helper
credsRW credentials.ReaderWriter
providers backend.Providers
MaxBytesDefault int64
}

func NewCASBackendUseCase(repo CASBackendRepo, credsRW credentials.ReaderWriter, providers backend.Providers, l log.Logger) *CASBackendUseCase {
func NewCASBackendUseCase(repo CASBackendRepo, credsRW credentials.ReaderWriter, providers backend.Providers, c *conf.Bootstrap_CASServer, l log.Logger) (*CASBackendUseCase, error) {
if l == nil {
l = log.NewStdLogger(io.Discard)
}

return &CASBackendUseCase{repo, servicelogger.ScopedHelper(l, "biz/CASBackend"), credsRW, providers}
var maxBytesDefault uint64 = 100 * 1024 * 1024 // 100MB
if c.GetDefaultEntryMaxSize() != "" {
var err error
maxBytesDefault, err = bytefmt.ToBytes(c.DefaultEntryMaxSize)
if err != nil {
return nil, fmt.Errorf("invalid CAS backend default max bytes: %w", err)
}
}

return &CASBackendUseCase{repo, servicelogger.ScopedHelper(l, "biz/CASBackend"), credsRW, providers, int64(maxBytesDefault)}, nil
}

func (uc *CASBackendUseCase) List(ctx context.Context, orgID string) ([]*CASBackend, error) {
Expand Down Expand Up @@ -253,7 +264,7 @@ func (uc *CASBackendUseCase) Create(ctx context.Context, orgID, name, location,
}

backend, err := uc.repo.Create(ctx, &CASBackendCreateOpts{
MaxBytes: CASBackendDefaultMaxBytes,
MaxBytes: uc.MaxBytesDefault,
Name: name,
CASBackendOpts: &CASBackendOpts{
Location: location, SecretName: secretName, Provider: provider, Default: defaultB,
Expand Down
100 changes: 98 additions & 2 deletions app/controlplane/pkg/biz/casbackend_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"errors"
"testing"

conf "github.com/chainloop-dev/chainloop/app/controlplane/internal/conf/controlplane/config/v1"
"github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz"
bizMocks "github.com/chainloop-dev/chainloop/app/controlplane/pkg/biz/mocks"
backends "github.com/chainloop-dev/chainloop/pkg/blobmanager"
Expand Down Expand Up @@ -171,6 +172,99 @@ func (s *casBackendTestSuite) TestPerformValidation() {
})
}

func (s *casBackendTestSuite) TestNewCASBackendUseCase() {
assert := assert.New(s.T())
const defaultErrorMsg = "byte quantity must be a positive integer with a unit of measurement like M, MB, MiB, G, GiB, or GB"

tests := []struct {
name string
config *conf.Bootstrap_CASServer
expectError bool
errorMsg string
wantSize int64 // Expected size in bytes after parsing
}{
{
name: "nil config uses default",
config: nil,
expectError: false,
wantSize: 100 * 1024 * 1024, // 100MB default
},
{
name: "valid size - megabytes",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100MB",
},
expectError: false,
wantSize: 100 * 1024 * 1024,
},
{
name: "valid size - gigabytes",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "2GB",
},
expectError: false,
wantSize: 2 * 1024 * 1024 * 1024,
},
{
name: "invalid size format",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "invalid",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "negative size",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "-100MB",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "zero size",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "0",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
{
name: "missing unit",
config: &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100",
},
expectError: true,
errorMsg: defaultErrorMsg,
wantSize: 0,
},
}

for _, tc := range tests {
s.Run(tc.name, func() {
useCase, err := biz.NewCASBackendUseCase(s.repo, s.credsRW,
backends.Providers{
"OCI": s.backendProvider,
}, tc.config, nil)

if tc.expectError {
assert.Error(err)
if tc.errorMsg != "" {
assert.Contains(err.Error(), tc.errorMsg)
}
assert.Nil(useCase)
} else {
assert.NoError(err)
assert.NotNil(useCase)
assert.Equal(tc.wantSize, useCase.MaxBytesDefault)
}
})
}
}

// Run all the tests
func TestCASBackend(t *testing.T) {
suite.Run(t, new(casBackendTestSuite))
Expand All @@ -188,9 +282,11 @@ func (s *casBackendTestSuite) SetupTest() {
s.repo = bizMocks.NewCASBackendRepo(s.T())
s.credsRW = credentialsM.NewReaderWriter(s.T())
s.backendProvider = blobM.NewProvider(s.T())
s.useCase = biz.NewCASBackendUseCase(s.repo, s.credsRW,
var err error
s.useCase, err = biz.NewCASBackendUseCase(s.repo, s.credsRW,
backends.Providers{
"OCI": s.backendProvider,
}, nil,
}, nil, nil,
)
s.Require().NoError(err)
}
6 changes: 6 additions & 0 deletions app/controlplane/pkg/biz/testhelpers/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,12 @@ func NewConfData(db *TestDatabase, t *testing.T) *conf.Data {
}
}

func NewCASBackendConfig() *conf.Bootstrap_CASServer {
return &conf.Bootstrap_CASServer{
DefaultEntryMaxSize: "100MB",
}
}

func NewPromSpec() []*conf.PrometheusIntegrationSpec {
return []*conf.PrometheusIntegrationSpec{}
}
Expand Down
1 change: 1 addition & 0 deletions app/controlplane/pkg/biz/testhelpers/wire.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func WireTestData(*TestDatabase, *testing.T, log.Logger, credentials.ReaderWrite
wire.FieldsOf(new(*conf.Data), "Database"),
newNatsConnection,
auditor.NewAuditLogPublisher,
NewCASBackendConfig,
),
)
}
Expand Down
7 changes: 6 additions & 1 deletion app/controlplane/pkg/biz/testhelpers/wire_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion deployment/chainloop/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ description: Chainloop is an open source software supply chain control plane, a

type: application
# Bump the patch (not minor, not major) version on each change in the Chart Source code
version: 1.157.0
version: 1.157.1
# Do not update appVersion, this is handled automatically by the release process
appVersion: v0.139.0

Expand Down
1 change: 1 addition & 0 deletions deployment/chainloop/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -725,6 +725,7 @@ chainloop config save \
| Name | Description | Value |
| ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| `cas.replicaCount` | Number of replicas | `2` |
| `cas.defaultMaxEntrySize` | Maximum size for each entry in the CAS backend, default 100MB | |
| `cas.image.registry` | Image registry | `REGISTRY_NAME` |
| `cas.image.repository` | Image repository | `REPOSITORY_NAME` |
| `cas.containerPorts.http` | controlplane HTTP container port | `8000` |
Expand Down
3 changes: 3 additions & 0 deletions deployment/chainloop/templates/controlplane/configmap.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ data:
addr: {{ printf "%s-api:%.0f" (include "chainloop.cas.fullname" .) (coalesce .Values.cas.serviceAPI.port .Values.cas.serviceAPI.ports.http) }}
insecure: {{ empty (include "controlplane.tls-secret-name" .) }}
download_url: {{ include "chainloop.cas.external_url" . }}/download
{{- if .Values.cas.defaultMaxEntrySize }}
default_entry_max_size: {{ .Values.cas.defaultMaxEntrySize | quote }}
{{- end }}
plugins_dir: {{ .Values.controlplane.pluginsDir }}
referrer_shared_index:
{{- toYaml .Values.controlplane.referrerSharedIndex | nindent 6 }}
Expand Down
3 changes: 3 additions & 0 deletions deployment/chainloop/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -927,6 +927,9 @@ cas:
## @param cas.replicaCount Number of replicas
replicaCount: 2

## @extra cas.defaultMaxEntrySize Maximum size for each entry in the CAS backend, default 100MB
# defaultMaxEntrySize: 100MB

## @param cas.image.registry [default: REGISTRY_NAME] Image registry
## @param cas.image.repository [default: REPOSITORY_NAME] Image repository
## @skip cas.image.tag
Expand Down
Loading