Skip to content

Commit 528fcc7

Browse files
SamMorrowDrumspatrick-knightCopilot
committed
fix(governance): reject unknown custom property fields
Co-authored-by: Patrick Knight <patrick-knight@github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1e886867-a922-419a-b02c-ac643716aea8
1 parent 81f801c commit 528fcc7

3 files changed

Lines changed: 30 additions & 1 deletion

File tree

pkg/github/__toolsnaps__/custom_properties_write.snap

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
"properties": {
3232
"description": "The custom properties to create or update. At the repository level each item assigns a value ('property_name' and 'value'); at the organization and enterprise levels each item defines the schema ('property_name' and 'value_type', plus optional definition fields).",
3333
"items": {
34+
"additionalProperties": false,
3435
"properties": {
3536
"allowed_values": {
3637
"description": "Organization and enterprise levels only: the ordered list of allowed values for single_select and multi_select properties.",

pkg/github/custom_properties.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,8 @@ func customPropertiesWriteEnterprise(ctx context.Context, client *github.Client,
279279
// customPropertyItemSchema combines repository values with organization and enterprise definitions.
280280
func customPropertyItemSchema() *jsonschema.Schema {
281281
return &jsonschema.Schema{
282-
Type: "object",
282+
Type: "object",
283+
AdditionalProperties: &jsonschema.Schema{Not: &jsonschema.Schema{}},
283284
Properties: map[string]*jsonschema.Schema{
284285
"property_name": {
285286
Type: "string",

pkg/github/custom_properties_test.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,33 @@ func Test_CustomPropertiesWrite(t *testing.T) {
134134
require.True(t, ok, "InputSchema should be *jsonschema.Schema")
135135
assert.ElementsMatch(t, schema.Required, []string{"level", "properties"})
136136

137+
t.Run("property items reject unknown fields", func(t *testing.T) {
138+
itemSchema := schema.Properties["properties"].Items
139+
require.NotNil(t, itemSchema.AdditionalProperties)
140+
require.NotNil(t, itemSchema.AdditionalProperties.Not)
141+
142+
resolved, err := itemSchema.Resolve(nil)
143+
require.NoError(t, err)
144+
require.NoError(t, resolved.Validate(map[string]any{
145+
"property_name": "environment",
146+
"value_type": "single_select",
147+
"required": true,
148+
"default_value": "production",
149+
"description": "Deployment environment",
150+
"allowed_values": []any{"production", "staging"},
151+
"values_editable_by": "org_and_repo_actors",
152+
}))
153+
require.NoError(t, resolved.Validate(map[string]any{
154+
"property_name": "environment",
155+
"value": []any{"production", "staging"},
156+
}))
157+
require.Error(t, resolved.Validate(map[string]any{
158+
"property_name": "environment",
159+
"value_type": "string",
160+
"require": true,
161+
}))
162+
})
163+
137164
t.Run("value schemas enforce documented JSON types", func(t *testing.T) {
138165
defaultValueSchema := schema.Properties["properties"].Items.Properties["default_value"]
139166
require.Len(t, defaultValueSchema.OneOf, 2)

0 commit comments

Comments
 (0)