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
5 changes: 0 additions & 5 deletions app/cli/pkg/action/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,11 +123,6 @@ func extractNameFromMetadata(content []byte) (string, error) {
if err != nil {
return "", err
}
case unmarshal.RawFormatCUE:
jsonData, err = unmarshal.LoadJSONBytes(content, ".cue")
if err != nil {
return "", err
}
default:
return "", fmt.Errorf("unsupported format: %s", format)
}
Expand Down
48 changes: 0 additions & 48 deletions app/controlplane/pkg/biz/testdata/contracts/contract.cue

This file was deleted.

5 changes: 0 additions & 5 deletions app/controlplane/pkg/biz/workflowcontract_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -349,11 +349,6 @@ func (s *workflowContractIntegrationTestSuite) TestCreateWithCustomContract() {
wantErrMsg string
format unmarshal.RawFormat
}{
{
name: "from-cue",
contractPath: "testdata/contracts/contract.cue",
format: unmarshal.RawFormatCUE,
},
{
name: "from-yaml",
contractPath: "testdata/contracts/contract.yaml",
Expand Down
4 changes: 0 additions & 4 deletions app/controlplane/pkg/biz/workflowcontract_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,6 @@ func TestIdentifyAndValidateRawContract(t *testing.T) {
wantValidationErr bool
wantFormatErr bool
}{
{
filename: "contract.cue",
wantFormat: unmarshal.RawFormatCUE,
},
{
filename: "contract.json",
wantFormat: unmarshal.RawFormatJSON,
Expand Down
48 changes: 0 additions & 48 deletions app/controlplane/pkg/unmarshal/testdata/contracts/contract.cue

This file was deleted.

44 changes: 16 additions & 28 deletions app/controlplane/pkg/unmarshal/unmarshal.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ import (

"buf.build/go/protovalidate"
"buf.build/go/protoyaml"
"cuelang.org/go/cue/cuecontext"
"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"
"gopkg.in/yaml.v2"
Expand All @@ -34,9 +33,18 @@ type RawFormat string
const (
RawFormatJSON RawFormat = "json"
RawFormatYAML RawFormat = "yaml"
RawFormatCUE RawFormat = "cue"
// RawFormatCUE is retained only so contracts already stored with this format
// (and the wire enum) remain valid. CUE is no longer accepted or evaluated:
// evaluating attacker-supplied CUE server-side is an unbounded, uncancellable
// operation and was a DoS vector. New contracts must be JSON or YAML.
RawFormatCUE RawFormat = "cue"
)

// errCUENotSupported is returned wherever a CUE document would previously have
// been compiled and evaluated. CUE support was removed to close the unbounded
// server-side evaluation DoS.
var errCUENotSupported = errors.New("CUE contract format is no longer supported; use JSON or YAML")

// Implements https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues
func (RawFormat) Values() (kinds []string) {
for _, s := range []RawFormat{RawFormatJSON, RawFormatYAML, RawFormatCUE} {
Expand Down Expand Up @@ -82,16 +90,7 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
return fmt.Errorf("error unmarshalling raw message: %w", err)
}
case RawFormatCUE:
ctx := cuecontext.New()
v := ctx.CompileBytes(body)
jsonRawData, err := v.MarshalJSON()
if err != nil {
return fmt.Errorf("error unmarshalling raw message: %w", err)
}

if err := jsonOpts.Unmarshal(jsonRawData, out); err != nil {
return fmt.Errorf("error unmarshalling raw message: %w", err)
}
return errCUENotSupported
default:
return fmt.Errorf("unsupported format: %s", format)
}
Expand All @@ -106,23 +105,17 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
}

// IdentifyFormat does best effort to identify the format of the raw contract
// by going the unmarshalling path in the following order: json, cue, yaml
// by going the unmarshalling path in the following order: json, yaml.
// NOTE that we are just validating the format, not the content using regular marshalling
// not even proto marshalling, that comes later once we know the format
// not even proto marshalling, that comes later once we know the format.
// CUE is intentionally not detected: it is no longer a supported contract format.
func IdentifyFormat(raw []byte) (RawFormat, error) {
// json marshalling first
var sink any
if err := json.Unmarshal(raw, &sink); err == nil {
return RawFormatJSON, nil
}

// cue marshalling next
ctx := cuecontext.New()
v := ctx.CompileBytes(raw)
if _, err := v.MarshalJSON(); err == nil {
return RawFormatCUE, nil
}

// yaml marshalling last
if err := yaml.Unmarshal(raw, &sink); err == nil {
return RawFormatYAML, nil
Expand All @@ -131,7 +124,7 @@ func IdentifyFormat(raw []byte) (RawFormat, error) {
return "", errors.New("format not found")
}

// LoadJSONBytes Extracts raw data in JSON format from different sources, i.e cue or yaml files
// LoadJSONBytes Extracts raw data in JSON format from different sources, i.e yaml or json files
func LoadJSONBytes(rawData []byte, extension string) ([]byte, error) {
var jsonRawData []byte
var err error
Expand All @@ -143,12 +136,7 @@ func LoadJSONBytes(rawData []byte, extension string) ([]byte, error) {
return nil, err
}
case ".cue":
ctx := cuecontext.New()
v := ctx.CompileBytes(rawData)
jsonRawData, err = v.MarshalJSON()
if err != nil {
return nil, err
}
return nil, errCUENotSupported
case ".json":
jsonRawData = rawData
default:
Expand Down
38 changes: 24 additions & 14 deletions app/controlplane/pkg/unmarshal/unmarshal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,23 +48,13 @@ spec:
{"name": "b", "type": "ARTIFACT", "group": "choice"}
]}
}`)
cueContract := []byte(`apiVersion: "chainloop.dev/v1"
kind: "Contract"
metadata: name: "test-contract"
spec: materials: [
{name: "a", type: "ARTIFACT", group: "choice"},
{name: "b", type: "ARTIFACT", group: "choice"},
]
`)

formats := []struct {
name string
format RawFormat
body []byte
}{
{"yaml", RawFormatYAML, yamlContract},
{"json", RawFormatJSON, jsonContract},
{"cue", RawFormatCUE, cueContract},
}

t.Run("group round-trips", func(t *testing.T) {
Expand Down Expand Up @@ -123,10 +113,6 @@ func TestIdentifyFormat(t *testing.T) {
wantFormat RawFormat
wantErr bool
}{
{
filename: "contract.cue",
wantFormat: RawFormatCUE,
},
{
filename: "contract.json",
wantFormat: RawFormatJSON,
Expand Down Expand Up @@ -166,3 +152,27 @@ func TestIdentifyFormat(t *testing.T) {
})
}
}

// TestCUEIsRejected locks in the removal of CUE support: the DoS payload from the
// security finding (a tiny CUE document whose evaluation is unbounded) must be
// rejected immediately, without ever being compiled or evaluated.
func TestCUEIsRejected(t *testing.T) {
// ~55-byte CUE bomb: evaluating it used to allocate a multi-million-element list.
cuePayload := []byte("import \"list\"\na: [for x in list.Range(0,1000000,1) {x}]\n")

t.Run("IdentifyFormat no longer detects CUE", func(t *testing.T) {
_, err := IdentifyFormat(cuePayload)
require.Error(t, err)
})

t.Run("FromRaw rejects the CUE format", func(t *testing.T) {
out := &schemav1.CraftingSchemaV2{}
err := FromRaw(cuePayload, RawFormatCUE, out, false)
require.ErrorIs(t, err, errCUENotSupported)
})

t.Run("LoadJSONBytes rejects .cue", func(t *testing.T) {
_, err := LoadJSONBytes(cuePayload, ".cue")
require.ErrorIs(t, err, errCUENotSupported)
})
}
56 changes: 0 additions & 56 deletions docs/examples/contracts/skynet/contract.cue

This file was deleted.

4 changes: 0 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ go 1.26.4
require (
cloud.google.com/go/secretmanager v1.20.0
code.cloudfoundry.org/bytefmt v0.75.0
cuelang.org/go v0.16.1
entgo.io/ent v0.14.6
github.com/adrg/xdg v0.5.3
github.com/aws/aws-sdk-go-v2 v1.41.11
Expand Down Expand Up @@ -164,7 +163,6 @@ require (
github.com/charmbracelet/lipgloss v0.5.0 // indirect
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
github.com/containerd/errdefs v1.0.0 // indirect
github.com/containerd/errdefs/pkg v0.3.0 // indirect
github.com/containerd/log v0.1.0 // indirect
Expand All @@ -180,7 +178,6 @@ require (
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
github.com/ebitengine/purego v0.8.4 // indirect
github.com/emicklei/proto v1.14.3 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
Expand Down Expand Up @@ -274,7 +271,6 @@ require (
github.com/pkg/xattr v0.4.12 // indirect
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
github.com/protocolbuffers/txtpbfmt v0.0.0-20260217160748-a481f6a22f94 // indirect
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
github.com/rs/xid v1.6.0 // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
Expand Down
Loading
Loading