Skip to content

Commit aec7449

Browse files
committed
add tests
Signed-off-by: Jose I. Paris <jiparis@chainloop.dev>
1 parent 2ebf832 commit aec7449

3 files changed

Lines changed: 214 additions & 2 deletions

File tree

internal/schemavalidators/internal_schemas/aiagentconfig/ai-agent-config-0.1.schema.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
"config_files": {
6464
"type": "array",
6565
"description": "Array of discovered configuration files",
66-
"minItems": 1,
6766
"items": {
6867
"type": "object",
6968
"required": ["path", "sha256", "size", "content"],

internal/schemavalidators/schemavalidators_test.go

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,6 @@ func TestValidateAIAgentConfig(t *testing.T) {
255255
{
256256
name: "empty config_files array",
257257
filePath: "./testdata/ai_agent_config_empty_config_files.json",
258-
wantErr: "minimum 1 items required, but found 0",
259258
},
260259
{
261260
name: "config file missing required fields",
Lines changed: 214 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,214 @@
1+
//
2+
// Copyright 2026 The Chainloop Authors.
3+
//
4+
// Licensed under the Apache License, Version 2.0 (the "License");
5+
// you may not use this file except in compliance with the License.
6+
// You may obtain a copy of the License at
7+
//
8+
// http://www.apache.org/licenses/LICENSE-2.0
9+
//
10+
// Unless required by applicable law or agreed to in writing, software
11+
// distributed under the License is distributed on an "AS IS" BASIS,
12+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
// See the License for the specific language governing permissions and
14+
// limitations under the License.
15+
16+
package materials
17+
18+
import (
19+
"context"
20+
"encoding/json"
21+
"os"
22+
"path/filepath"
23+
"testing"
24+
25+
schemaapi "github.com/chainloop-dev/chainloop/app/controlplane/api/workflowcontract/v1"
26+
"github.com/chainloop-dev/chainloop/internal/aiagentconfig"
27+
"github.com/chainloop-dev/chainloop/internal/schemavalidators"
28+
"github.com/rs/zerolog"
29+
"github.com/stretchr/testify/assert"
30+
"github.com/stretchr/testify/require"
31+
)
32+
33+
func TestNewChainloopAIAgentConfigCrafter_WrongType(t *testing.T) {
34+
logger := zerolog.Nop()
35+
36+
schema := &schemaapi.CraftingSchema_Material{
37+
Type: schemaapi.CraftingSchema_Material_SBOM_CYCLONEDX_JSON,
38+
}
39+
40+
_, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
41+
require.Error(t, err)
42+
assert.Contains(t, err.Error(), "material type is not chainloop_ai_agent_config")
43+
}
44+
45+
func TestNewChainloopAIAgentConfigCrafter_CorrectType(t *testing.T) {
46+
logger := zerolog.Nop()
47+
48+
schema := &schemaapi.CraftingSchema_Material{
49+
Type: schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG,
50+
}
51+
52+
crafter, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
53+
require.NoError(t, err)
54+
assert.NotNil(t, crafter)
55+
}
56+
57+
func TestChainloopAIAgentConfigCrafter_Validation(t *testing.T) {
58+
testCases := []struct {
59+
name string
60+
data *aiagentconfig.Evidence
61+
wantErr bool
62+
}{
63+
{
64+
name: "valid full config",
65+
data: &aiagentconfig.Evidence{
66+
SchemaVersion: string(schemavalidators.AIAgentConfigVersion0_1),
67+
Agent: aiagentconfig.Agent{Name: "claude", Version: "4.0"},
68+
ConfigHash: "abc123",
69+
CapturedAt: "2026-03-13T10:00:00Z",
70+
GitContext: &aiagentconfig.GitContext{
71+
Repository: "https://github.com/org/repo",
72+
Branch: "main",
73+
CommitSHA: "abc123",
74+
},
75+
ConfigFiles: []aiagentconfig.ConfigFile{
76+
{
77+
Path: "CLAUDE.md",
78+
SHA256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
79+
Size: 42,
80+
Content: "IyBQcm9qZWN0IFJ1bGVz",
81+
},
82+
},
83+
},
84+
wantErr: false,
85+
},
86+
{
87+
name: "valid minimal config",
88+
data: &aiagentconfig.Evidence{
89+
SchemaVersion: string(schemavalidators.AIAgentConfigVersion0_1),
90+
Agent: aiagentconfig.Agent{Name: "claude"},
91+
ConfigHash: "abc123",
92+
CapturedAt: "2026-03-13T10:00:00Z",
93+
ConfigFiles: []aiagentconfig.ConfigFile{
94+
{
95+
Path: "CLAUDE.md",
96+
SHA256: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
97+
Size: 10,
98+
Content: "Y29udGVudA==",
99+
},
100+
},
101+
},
102+
wantErr: false,
103+
},
104+
{
105+
name: "missing required fields",
106+
data: &aiagentconfig.Evidence{},
107+
wantErr: true,
108+
},
109+
{
110+
name: "empty config files",
111+
data: &aiagentconfig.Evidence{
112+
SchemaVersion: string(schemavalidators.AIAgentConfigVersion0_1),
113+
Agent: aiagentconfig.Agent{Name: "claude"},
114+
ConfigHash: "abc123",
115+
CapturedAt: "2026-03-13T10:00:00Z",
116+
ConfigFiles: []aiagentconfig.ConfigFile{},
117+
},
118+
wantErr: false,
119+
},
120+
}
121+
122+
for _, tc := range testCases {
123+
t.Run(tc.name, func(t *testing.T) {
124+
dataBytes, err := json.Marshal(tc.data)
125+
require.NoError(t, err)
126+
127+
var rawData any
128+
require.NoError(t, json.Unmarshal(dataBytes, &rawData))
129+
130+
err = schemavalidators.ValidateAIAgentConfig(rawData, schemavalidators.AIAgentConfigVersion0_1)
131+
132+
if tc.wantErr {
133+
require.Error(t, err)
134+
} else {
135+
require.NoError(t, err)
136+
}
137+
})
138+
}
139+
}
140+
141+
func TestChainloopAIAgentConfigCrafter_InvalidJSON(t *testing.T) {
142+
logger := zerolog.Nop()
143+
schema := &schemaapi.CraftingSchema_Material{
144+
Type: schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG,
145+
}
146+
147+
crafter, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
148+
require.NoError(t, err)
149+
150+
tmpFile := filepath.Join(t.TempDir(), "invalid.json")
151+
require.NoError(t, os.WriteFile(tmpFile, []byte(`{invalid json}`), 0o600))
152+
153+
_, err = crafter.Craft(context.Background(), tmpFile)
154+
require.Error(t, err)
155+
assert.Contains(t, err.Error(), "invalid JSON format")
156+
}
157+
158+
func TestChainloopAIAgentConfigCrafter_InvalidSchema(t *testing.T) {
159+
logger := zerolog.Nop()
160+
schema := &schemaapi.CraftingSchema_Material{
161+
Type: schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG,
162+
}
163+
164+
crafter, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
165+
require.NoError(t, err)
166+
167+
// Valid JSON but missing required fields
168+
tmpFile := filepath.Join(t.TempDir(), "bad-schema.json")
169+
require.NoError(t, os.WriteFile(tmpFile, []byte(`{"foo": "bar"}`), 0o600))
170+
171+
_, err = crafter.Craft(context.Background(), tmpFile)
172+
require.Error(t, err)
173+
assert.Contains(t, err.Error(), "AI agent config validation failed")
174+
}
175+
176+
func TestChainloopAIAgentConfigCrafter_FileNotFound(t *testing.T) {
177+
logger := zerolog.Nop()
178+
schema := &schemaapi.CraftingSchema_Material{
179+
Type: schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG,
180+
}
181+
182+
crafter, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
183+
require.NoError(t, err)
184+
185+
_, err = crafter.Craft(context.Background(), "/nonexistent/file.json")
186+
require.Error(t, err)
187+
assert.Contains(t, err.Error(), "can't open the file")
188+
}
189+
190+
func TestChainloopAIAgentConfigCrafter_RejectsExtraFields(t *testing.T) {
191+
logger := zerolog.Nop()
192+
schema := &schemaapi.CraftingSchema_Material{
193+
Type: schemaapi.CraftingSchema_Material_CHAINLOOP_AI_AGENT_CONFIG,
194+
}
195+
196+
crafter, err := NewChainloopAIAgentConfigCrafter(schema, nil, &logger)
197+
require.NoError(t, err)
198+
199+
payload := `{
200+
"schema_version": "0.1",
201+
"agent": {"name": "claude"},
202+
"config_hash": "abc",
203+
"captured_at": "2026-03-13T10:00:00Z",
204+
"config_files": [{"path": "CLAUDE.md", "sha256": "abc", "size": 1, "content": "Yg=="}],
205+
"unknown_field": "should fail"
206+
}`
207+
208+
tmpFile := filepath.Join(t.TempDir(), "extra-fields.json")
209+
require.NoError(t, os.WriteFile(tmpFile, []byte(payload), 0o600))
210+
211+
_, err = crafter.Craft(context.Background(), tmpFile)
212+
require.Error(t, err)
213+
assert.Contains(t, err.Error(), "AI agent config validation failed")
214+
}

0 commit comments

Comments
 (0)