diff --git a/app/controlplane/pkg/biz/workflow.go b/app/controlplane/pkg/biz/workflow.go index 05add7665..149b6d93c 100644 --- a/app/controlplane/pkg/biz/workflow.go +++ b/app/controlplane/pkg/biz/workflow.go @@ -133,8 +133,13 @@ func (uc *WorkflowUseCase) Create(ctx context.Context, opts *WorkflowCreateOpts) return nil, errors.New("organization ID is required") } - // Set the empty contract by default - opts.DetectedContract = EmptyDefaultContract + contractName := fmt.Sprintf("%s-%s", opts.Project, opts.Name) + + defaultContract, err := createDefaultContract(contractName) + if err != nil { + return nil, fmt.Errorf("failed to create default contract: %w", err) + } + opts.DetectedContract = defaultContract // Take the raw contract bytes and identify the format and validate it if opts.ContractBytes != nil { diff --git a/app/controlplane/pkg/biz/workflowcontract.go b/app/controlplane/pkg/biz/workflowcontract.go index 8386bfef7..ce1792fd5 100644 --- a/app/controlplane/pkg/biz/workflowcontract.go +++ b/app/controlplane/pkg/biz/workflowcontract.go @@ -21,6 +21,7 @@ import ( "fmt" "time" + "github.com/bufbuild/protoyaml-go" "github.com/chainloop-dev/chainloop/app/controlplane/pkg/auditor/events" schemav1 "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1" @@ -209,9 +210,29 @@ type WorkflowContractCreateOpts struct { AddUniquePrefix bool } -// EmptyDefaultContract is the default contract that will be created if no contract is provided -var EmptyDefaultContract = &Contract{ - Raw: []byte("schemaVersion: v1"), Format: unmarshal.RawFormatYAML, +// createDefaultContract creates a new default contract with the specified name +func createDefaultContract(name string) (*Contract, error) { + defaultSchema := &schemav1.CraftingSchemaV2{ + ApiVersion: "chainloop.dev/v1", + Kind: "Contract", + Metadata: &schemav1.Metadata{Name: name}, + Spec: &schemav1.CraftingSchemaV2Spec{}, + } + + // Marshal to YAML using protoyaml + rawYAML, err := protoyaml.Marshal(defaultSchema) + if err != nil { + return nil, fmt.Errorf("failed to marshal default contract to YAML: %w", err) + } + + // Convert to v1 for backward compatibility with old CLIs + v1Schema := defaultSchema.ToV1() + return &Contract{ + Raw: rawYAML, + Format: unmarshal.RawFormatYAML, + Schema: v1Schema, + Schemav2: defaultSchema, + }, nil } func (uc *WorkflowContractUseCase) Create(ctx context.Context, opts *WorkflowContractCreateOpts) (*WorkflowContract, error) { @@ -232,16 +253,20 @@ func (uc *WorkflowContractUseCase) Create(ctx context.Context, opts *WorkflowCon return nil, NewErrValidation(err) } - // Create an empty contract by default - contract := EmptyDefaultContract - - // or load it if provided + var contract *Contract if len(opts.RawSchema) > 0 { + // Load the provided contract c, err := identifyUnMarshalAndValidateRawContract(opts.RawSchema) if err != nil { return nil, fmt.Errorf("failed to load contract: %w", err) } - + contract = c + } else { + // Use default contract with the user-provided name + c, err := createDefaultContract(opts.Name) + if err != nil { + return nil, fmt.Errorf("failed to create default contract: %w", err) + } contract = c } diff --git a/app/controlplane/pkg/biz/workflowcontract_integration_test.go b/app/controlplane/pkg/biz/workflowcontract_integration_test.go index 837690afa..3992ddf51 100644 --- a/app/controlplane/pkg/biz/workflowcontract_integration_test.go +++ b/app/controlplane/pkg/biz/workflowcontract_integration_test.go @@ -320,8 +320,9 @@ func (s *workflowContractIntegrationTestSuite) TestCreateWithCustomContract() { require.NoError(s.T(), err) contractWithVersion, err := s.WorkflowContract.Describe(ctx, s.org.ID, contract.ID.String(), 1) require.NoError(s.T(), err) - s.Equal(biz.EmptyDefaultContract.Format, unmarshal.RawFormatYAML) - s.Equal(biz.EmptyDefaultContract.Raw, contractWithVersion.Version.Schema.Raw) + c := contractWithVersion.Version.Schema + s.Equal(c.Format, unmarshal.RawFormatYAML) + s.Equal(c.Raw, contractWithVersion.Version.Schema.Raw) s.NotNil(contractWithVersion.Version.Schema.Schema) }) }