Skip to content

Commit fb7aff8

Browse files
joshspicerCopilot
andcommitted
test(sdk): harden managed-settings empty-array wire tests
Add Go and Java tests proving explicit empty permission arrays (allow/ask/deny) serialize as [] while nil/absent fields are omitted, so a present empty allow list (admits nothing) stays distinguishable from an absent one (no restriction) at both create and resume. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 326a5a5a-aa12-4d85-8b86-c7e392cf1b23
1 parent a078848 commit fb7aff8

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

go/client_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3583,4 +3583,57 @@ func TestSessionRequests_ManagedSettings(t *testing.T) {
35833583
}
35843584
}
35853585
})
3586+
3587+
t.Run("distinguishes explicit empty allow from an absent allow", func(t *testing.T) {
3588+
// Security-critical: a present empty allow list admits nothing, while an
3589+
// absent allow list imposes no allow restriction. The wire output must
3590+
// tell these apart per-field, so an explicit empty slice serializes as
3591+
// `[]` while a nil slice is omitted entirely.
3592+
req := createSessionRequest{ManagedSettings: &ManagedSettings{
3593+
Permissions: &ManagedSettingsPermissions{
3594+
Allow: []string{}, // present but empty: admit nothing
3595+
// Deny and Ask left nil: no such restriction supplied.
3596+
},
3597+
}}
3598+
data, err := json.Marshal(req)
3599+
if err != nil {
3600+
t.Fatalf("Failed to marshal: %v", err)
3601+
}
3602+
var m map[string]any
3603+
json.Unmarshal(data, &m)
3604+
perms := m["managedSettings"].(map[string]any)["permissions"].(map[string]any)
3605+
3606+
allow, ok := perms["allow"].([]any)
3607+
if !ok || len(allow) != 0 {
3608+
t.Errorf("Expected allow to be an explicit empty array, got %v", perms["allow"])
3609+
}
3610+
if _, present := perms["deny"]; present {
3611+
t.Errorf("Expected deny to be omitted when nil, got %v", perms["deny"])
3612+
}
3613+
if _, present := perms["ask"]; present {
3614+
t.Errorf("Expected ask to be omitted when nil, got %v", perms["ask"])
3615+
}
3616+
})
3617+
3618+
t.Run("distinguishes explicit empty arrays on resume", func(t *testing.T) {
3619+
req := resumeSessionRequest{SessionID: "s1", ManagedSettings: &ManagedSettings{
3620+
Permissions: &ManagedSettingsPermissions{
3621+
Deny: []string{},
3622+
Ask: []string{},
3623+
Allow: []string{},
3624+
},
3625+
}}
3626+
data, err := json.Marshal(req)
3627+
if err != nil {
3628+
t.Fatalf("Failed to marshal: %v", err)
3629+
}
3630+
var m map[string]any
3631+
json.Unmarshal(data, &m)
3632+
perms := m["managedSettings"].(map[string]any)["permissions"].(map[string]any)
3633+
for _, key := range []string{"deny", "ask", "allow"} {
3634+
if value, ok := perms[key].([]any); !ok || len(value) != 0 {
3635+
t.Errorf("Expected %s to be an explicit empty array on resume, got %v", key, perms[key])
3636+
}
3637+
}
3638+
})
35863639
}

java/src/test/java/com/github/copilot/ManagedSettingsTest.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,37 @@ void rejectsUnsupportedBypassValue() {
4242
assertThrows(IllegalArgumentException.class, () -> permissions.setDisableBypassPermissionsMode("enable"));
4343
}
4444

45+
@Test
46+
void preservesExplicitEmptyPermissionArrays() throws Exception {
47+
// Security-critical: a present empty allow list admits nothing, while an
48+
// absent (null) list imposes no such restriction. Jackson NON_NULL must
49+
// emit an explicit empty array as `[]` and omit null fields, so the two
50+
// remain distinguishable on the wire.
51+
var permissions = new ManagedSettingsPermissions().setDeny(List.of()).setAsk(List.of()).setAllow(List.of());
52+
var managedSettings = new ManagedSettings().setPermissions(permissions);
53+
var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig().setManagedSettings(managedSettings),
54+
"managed-empty");
55+
56+
var json = new ObjectMapper().writeValueAsString(create);
57+
assertEquals(true, json.contains("\"deny\":[]"), json);
58+
assertEquals(true, json.contains("\"ask\":[]"), json);
59+
assertEquals(true, json.contains("\"allow\":[]"), json);
60+
}
61+
62+
@Test
63+
void distinguishesExplicitEmptyAllowFromAbsentAllow() throws Exception {
64+
// Present empty allow admits nothing; the null deny/ask must be omitted.
65+
var permissions = new ManagedSettingsPermissions().setAllow(List.of());
66+
var managedSettings = new ManagedSettings().setPermissions(permissions);
67+
var create = SessionRequestBuilder.buildCreateRequest(new SessionConfig().setManagedSettings(managedSettings),
68+
"managed-mixed");
69+
70+
var json = new ObjectMapper().writeValueAsString(create);
71+
assertEquals(true, json.contains("\"allow\":[]"), json);
72+
assertEquals(false, json.contains("\"deny\""), json);
73+
assertEquals(false, json.contains("\"ask\""), json);
74+
}
75+
4576
@Test
4677
void directInjectionEnablesManagedSafeguards() throws Exception {
4778
var session = new CopilotSession("session-1", null);

0 commit comments

Comments
 (0)