Skip to content

Commit 7aadb70

Browse files
committed
Fix Agents.UnmarshalYAML to reject unknown fields
Agents.UnmarshalYAML re-marshals each agent value to bytes and calls yaml.Unmarshal to parse it into AgentConfig. This plain Unmarshal call does not enforce strict field validation, so unknown fields like 'instructions' (instead of 'instruction') are silently ignored — even though Parse() uses yaml.Strict() at the top level. Switch to yaml.UnmarshalWithOptions with DisallowUnknownField so that the strictness is propagated into agent blocks. Fixes #1683 Assisted-By: cagent
1 parent d7f1f6e commit 7aadb70

4 files changed

Lines changed: 70 additions & 2 deletions

File tree

pkg/config/latest/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (c *Agents) UnmarshalYAML(unmarshal func(any) error) error {
4545
}
4646

4747
var agent AgentConfig
48-
if err := yaml.Unmarshal(valueBytes, &agent); err != nil {
48+
if err := yaml.UnmarshalWithOptions(valueBytes, &agent, yaml.DisallowUnknownField()); err != nil {
4949
return fmt.Errorf("failed to unmarshal agent config for %s: %w", name, err)
5050
}
5151

pkg/config/latest/types_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,40 @@ func TestThinkingBudget_MarshalUnmarshal_Zero(t *testing.T) {
121121
require.Equal(t, "thinking_budget: 0\n", string(output))
122122
}
123123

124+
func TestAgents_UnmarshalYAML_RejectsUnknownFields(t *testing.T) {
125+
t.Parallel()
126+
127+
// "instructions" (plural) is not a valid field; the correct field is "instruction" (singular).
128+
// Agents.UnmarshalYAML must reject it so that typos don't silently drop config.
129+
input := []byte(`version: "5"
130+
agents:
131+
root:
132+
model: openai/gpt-4o
133+
instructions: "You are a helpful assistant."
134+
`)
135+
136+
_, err := Parse(input)
137+
require.Error(t, err)
138+
require.Contains(t, err.Error(), "instructions")
139+
}
140+
141+
func TestAgents_UnmarshalYAML_AcceptsValidConfig(t *testing.T) {
142+
t.Parallel()
143+
144+
input := []byte(`version: "5"
145+
agents:
146+
root:
147+
model: openai/gpt-4o
148+
instruction: "You are a helpful assistant."
149+
`)
150+
151+
cfg, err := Parse(input)
152+
require.NoError(t, err)
153+
require.Len(t, cfg.Agents, 1)
154+
require.Equal(t, "root", cfg.Agents[0].Name)
155+
require.Equal(t, "You are a helpful assistant.", cfg.Agents[0].Instruction)
156+
}
157+
124158
func TestRAGStrategyConfig_MarshalUnmarshal_FlattenedParams(t *testing.T) {
125159
t.Parallel()
126160

pkg/config/v4/types.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ func (c *Agents) UnmarshalYAML(unmarshal func(any) error) error {
4545
}
4646

4747
var agent AgentConfig
48-
if err := yaml.Unmarshal(valueBytes, &agent); err != nil {
48+
if err := yaml.UnmarshalWithOptions(valueBytes, &agent, yaml.DisallowUnknownField()); err != nil {
4949
return fmt.Errorf("failed to unmarshal agent config for %s: %w", name, err)
5050
}
5151

pkg/config/v4/types_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -121,6 +121,40 @@ func TestThinkingBudget_MarshalUnmarshal_Zero(t *testing.T) {
121121
require.Equal(t, "thinking_budget: 0\n", string(output))
122122
}
123123

124+
func TestAgents_UnmarshalYAML_RejectsUnknownFields(t *testing.T) {
125+
t.Parallel()
126+
127+
// "instructions" (plural) is not a valid field; the correct field is "instruction" (singular).
128+
// Agents.UnmarshalYAML must reject it so that typos don't silently drop config.
129+
input := []byte(`version: "4"
130+
agents:
131+
root:
132+
model: openai/gpt-4o
133+
instructions: "You are a helpful assistant."
134+
`)
135+
136+
_, err := Parse(input)
137+
require.Error(t, err)
138+
require.Contains(t, err.Error(), "instructions")
139+
}
140+
141+
func TestAgents_UnmarshalYAML_AcceptsValidConfig(t *testing.T) {
142+
t.Parallel()
143+
144+
input := []byte(`version: "4"
145+
agents:
146+
root:
147+
model: openai/gpt-4o
148+
instruction: "You are a helpful assistant."
149+
`)
150+
151+
cfg, err := Parse(input)
152+
require.NoError(t, err)
153+
require.Len(t, cfg.Agents, 1)
154+
require.Equal(t, "root", cfg.Agents[0].Name)
155+
require.Equal(t, "You are a helpful assistant.", cfg.Agents[0].Instruction)
156+
}
157+
124158
func TestRAGStrategyConfig_MarshalUnmarshal_FlattenedParams(t *testing.T) {
125159
t.Parallel()
126160

0 commit comments

Comments
 (0)