Skip to content

Commit 42f2848

Browse files
fix: remove CUE workflow-contract support
- unmarshal: drop all CUE compilation. IdentifyFormat no longer detects CUE, FromRaw and LoadJSONBytes reject the CUE format with a clear error, and the cuelang.org/go dependency is removed. - The RawFormatCUE constant and the wire enum value are retained (unused) so contracts already stored with that format and the existing API stay valid; no database migration is required. - Remove CUE test cases and fixtures across unmarshal, biz and crafter, and the CUE contract example under docs. Signed-off-by: Matías Insaurralde <matias@chainloop.dev>
1 parent e7ebb3e commit 42f2848

12 files changed

Lines changed: 41 additions & 232 deletions

File tree

app/cli/pkg/action/util.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -123,11 +123,6 @@ func extractNameFromMetadata(content []byte) (string, error) {
123123
if err != nil {
124124
return "", err
125125
}
126-
case unmarshal.RawFormatCUE:
127-
jsonData, err = unmarshal.LoadJSONBytes(content, ".cue")
128-
if err != nil {
129-
return "", err
130-
}
131126
default:
132127
return "", fmt.Errorf("unsupported format: %s", format)
133128
}

app/controlplane/pkg/biz/testdata/contracts/contract.cue

Lines changed: 0 additions & 48 deletions
This file was deleted.

app/controlplane/pkg/biz/workflowcontract_integration_test.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -349,11 +349,6 @@ func (s *workflowContractIntegrationTestSuite) TestCreateWithCustomContract() {
349349
wantErrMsg string
350350
format unmarshal.RawFormat
351351
}{
352-
{
353-
name: "from-cue",
354-
contractPath: "testdata/contracts/contract.cue",
355-
format: unmarshal.RawFormatCUE,
356-
},
357352
{
358353
name: "from-yaml",
359354
contractPath: "testdata/contracts/contract.yaml",

app/controlplane/pkg/biz/workflowcontract_test.go

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,6 @@ func TestIdentifyAndValidateRawContract(t *testing.T) {
3131
wantValidationErr bool
3232
wantFormatErr bool
3333
}{
34-
{
35-
filename: "contract.cue",
36-
wantFormat: unmarshal.RawFormatCUE,
37-
},
3834
{
3935
filename: "contract.json",
4036
wantFormat: unmarshal.RawFormatJSON,

app/controlplane/pkg/unmarshal/testdata/contracts/contract.cue

Lines changed: 0 additions & 48 deletions
This file was deleted.

app/controlplane/pkg/unmarshal/unmarshal.go

Lines changed: 16 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import (
2222

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

43+
// errCUENotSupported is returned wherever a CUE document would previously have
44+
// been compiled and evaluated. CUE support was removed to close the unbounded
45+
// server-side evaluation DoS.
46+
var errCUENotSupported = errors.New("CUE contract format is no longer supported; use JSON or YAML")
47+
4048
// Implements https://pkg.go.dev/entgo.io/ent/schema/field#EnumValues
4149
func (RawFormat) Values() (kinds []string) {
4250
for _, s := range []RawFormat{RawFormatJSON, RawFormatYAML, RawFormatCUE} {
@@ -82,16 +90,7 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
8290
return fmt.Errorf("error unmarshalling raw message: %w", err)
8391
}
8492
case RawFormatCUE:
85-
ctx := cuecontext.New()
86-
v := ctx.CompileBytes(body)
87-
jsonRawData, err := v.MarshalJSON()
88-
if err != nil {
89-
return fmt.Errorf("error unmarshalling raw message: %w", err)
90-
}
91-
92-
if err := jsonOpts.Unmarshal(jsonRawData, out); err != nil {
93-
return fmt.Errorf("error unmarshalling raw message: %w", err)
94-
}
93+
return errCUENotSupported
9594
default:
9695
return fmt.Errorf("unsupported format: %s", format)
9796
}
@@ -106,23 +105,17 @@ func FromRaw(body []byte, format RawFormat, out proto.Message, doValidate bool)
106105
}
107106

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

119-
// cue marshalling next
120-
ctx := cuecontext.New()
121-
v := ctx.CompileBytes(raw)
122-
if _, err := v.MarshalJSON(); err == nil {
123-
return RawFormatCUE, nil
124-
}
125-
126119
// yaml marshalling last
127120
if err := yaml.Unmarshal(raw, &sink); err == nil {
128121
return RawFormatYAML, nil
@@ -131,7 +124,7 @@ func IdentifyFormat(raw []byte) (RawFormat, error) {
131124
return "", errors.New("format not found")
132125
}
133126

134-
// LoadJSONBytes Extracts raw data in JSON format from different sources, i.e cue or yaml files
127+
// LoadJSONBytes Extracts raw data in JSON format from different sources, i.e yaml or json files
135128
func LoadJSONBytes(rawData []byte, extension string) ([]byte, error) {
136129
var jsonRawData []byte
137130
var err error
@@ -143,12 +136,7 @@ func LoadJSONBytes(rawData []byte, extension string) ([]byte, error) {
143136
return nil, err
144137
}
145138
case ".cue":
146-
ctx := cuecontext.New()
147-
v := ctx.CompileBytes(rawData)
148-
jsonRawData, err = v.MarshalJSON()
149-
if err != nil {
150-
return nil, err
151-
}
139+
return nil, errCUENotSupported
152140
case ".json":
153141
jsonRawData = rawData
154142
default:

app/controlplane/pkg/unmarshal/unmarshal_test.go

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -48,23 +48,13 @@ spec:
4848
{"name": "b", "type": "ARTIFACT", "group": "choice"}
4949
]}
5050
}`)
51-
cueContract := []byte(`apiVersion: "chainloop.dev/v1"
52-
kind: "Contract"
53-
metadata: name: "test-contract"
54-
spec: materials: [
55-
{name: "a", type: "ARTIFACT", group: "choice"},
56-
{name: "b", type: "ARTIFACT", group: "choice"},
57-
]
58-
`)
59-
6051
formats := []struct {
6152
name string
6253
format RawFormat
6354
body []byte
6455
}{
6556
{"yaml", RawFormatYAML, yamlContract},
6657
{"json", RawFormatJSON, jsonContract},
67-
{"cue", RawFormatCUE, cueContract},
6858
}
6959

7060
t.Run("group round-trips", func(t *testing.T) {
@@ -123,10 +113,6 @@ func TestIdentifyFormat(t *testing.T) {
123113
wantFormat RawFormat
124114
wantErr bool
125115
}{
126-
{
127-
filename: "contract.cue",
128-
wantFormat: RawFormatCUE,
129-
},
130116
{
131117
filename: "contract.json",
132118
wantFormat: RawFormatJSON,
@@ -166,3 +152,27 @@ func TestIdentifyFormat(t *testing.T) {
166152
})
167153
}
168154
}
155+
156+
// TestCUEIsRejected locks in the removal of CUE support: the DoS payload from the
157+
// security finding (a tiny CUE document whose evaluation is unbounded) must be
158+
// rejected immediately, without ever being compiled or evaluated.
159+
func TestCUEIsRejected(t *testing.T) {
160+
// ~55-byte CUE bomb: evaluating it used to allocate a multi-million-element list.
161+
cuePayload := []byte("import \"list\"\na: [for x in list.Range(0,1000000,1) {x}]\n")
162+
163+
t.Run("IdentifyFormat no longer detects CUE", func(t *testing.T) {
164+
_, err := IdentifyFormat(cuePayload)
165+
require.Error(t, err)
166+
})
167+
168+
t.Run("FromRaw rejects the CUE format", func(t *testing.T) {
169+
out := &schemav1.CraftingSchemaV2{}
170+
err := FromRaw(cuePayload, RawFormatCUE, out, false)
171+
require.ErrorIs(t, err, errCUENotSupported)
172+
})
173+
174+
t.Run("LoadJSONBytes rejects .cue", func(t *testing.T) {
175+
_, err := LoadJSONBytes(cuePayload, ".cue")
176+
require.ErrorIs(t, err, errCUENotSupported)
177+
})
178+
}

docs/examples/contracts/skynet/contract.cue

Lines changed: 0 additions & 56 deletions
This file was deleted.

go.mod

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ go 1.26.4
55
require (
66
cloud.google.com/go/secretmanager v1.20.0
77
code.cloudfoundry.org/bytefmt v0.75.0
8-
cuelang.org/go v0.16.1
98
entgo.io/ent v0.14.6
109
github.com/adrg/xdg v0.5.3
1110
github.com/aws/aws-sdk-go-v2 v1.41.11
@@ -164,7 +163,6 @@ require (
164163
github.com/charmbracelet/lipgloss v0.5.0 // indirect
165164
github.com/clipperhouse/uax29/v2 v2.6.0 // indirect
166165
github.com/cncf/xds/go v0.0.0-20260202195803-dba9d589def2 // indirect
167-
github.com/cockroachdb/apd/v3 v3.2.1 // indirect
168166
github.com/containerd/errdefs v1.0.0 // indirect
169167
github.com/containerd/errdefs/pkg v0.3.0 // indirect
170168
github.com/containerd/log v0.1.0 // indirect
@@ -180,7 +178,6 @@ require (
180178
github.com/dustin/go-humanize v1.0.1 // indirect
181179
github.com/dylibso/observe-sdk/go v0.0.0-20240819160327-2d926c5d788a // indirect
182180
github.com/ebitengine/purego v0.8.4 // indirect
183-
github.com/emicklei/proto v1.14.3 // indirect
184181
github.com/emirpasic/gods v1.18.1 // indirect
185182
github.com/envoyproxy/go-control-plane/envoy v1.37.0 // indirect
186183
github.com/envoyproxy/protoc-gen-validate v1.3.3 // indirect
@@ -274,7 +271,6 @@ require (
274271
github.com/pkg/xattr v0.4.12 // indirect
275272
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10 // indirect
276273
github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect
277-
github.com/protocolbuffers/txtpbfmt v0.0.0-20260217160748-a481f6a22f94 // indirect
278274
github.com/rcrowley/go-metrics v0.0.0-20250401214520-65e299d6c5c9 // indirect
279275
github.com/rs/xid v1.6.0 // indirect
280276
github.com/russross/blackfriday/v2 v2.1.0 // indirect
@@ -358,7 +354,7 @@ require (
358354
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
359355
github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f // indirect
360356
github.com/digitorus/pkcs7 v0.0.0-20230818184609-3a137a874352 // indirect
361-
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7 // indirect
357+
github.com/digitorus/timestamp v0.0.0-20231217203849-220c5c2851b7
362358
github.com/docker/cli v29.4.3+incompatible // indirect
363359
github.com/docker/docker v28.5.2+incompatible // indirect
364360
github.com/docker/docker-credential-helpers v0.9.5 // indirect

0 commit comments

Comments
 (0)