Skip to content

Add managed permission settings to session startup - #2139

Draft
joshspicer wants to merge 2 commits into
github:mainfrom
joshspicer:joshspicer-sdk-managed-settings-permissions
Draft

Add managed permission settings to session startup#2139
joshspicer wants to merge 2 commits into
github:mainfrom
joshspicer:joshspicer-sdk-managed-settings-permissions

Conversation

@joshspicer

@joshspicer joshspicer commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

Why

SDK hosts need a typed way to inject enterprise permission policy at session startup, independent of the runtime server/device managed-settings fetch path.

What

Adds optional managedSettings.permissions support alongside enableManagedSettings for create and resume across Node, Python, Go, .NET, Rust, and Java. The public types expose bypass disable plus deny/ask/allow rule arrays, and each client forwards the same camelCase JSON shape. Direct injection activates each SDK's managed-session safeguards even when runtime self-fetch is disabled.

The setting is startup-only and must be re-supplied on resume. It composes restrictively with runtime-fetched policy. The SDK protocol version remains unchanged because the field is optional.

Older runtimes may ignore the additive field, so hosts must not rely on injected policy until they ship a compatible runtime. This PR should publish only after github/copilot-agent-runtime#14000 is released, then downstream hosts such as VS Code can bump the SDK and remove temporary type shims.

Validation

  • Node format/lint/typecheck; 4 focused tests
  • Python Ruff; 5 focused tests
  • Go focused test and go vet
  • .NET format; 4 focused tests
  • Rust format and focused tests
  • Java Spotless; 3 focused tests

Copilot AI review requested due to automatic review settings July 29, 2026 19:38

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (2)
  • go/rpc/zrpc.go: Generated file
  • go/rpc/zrpc_encoding.go: Generated file
  • Files reviewed: 25/30 changed files
  • Comments generated: 1
  • Review effort level: Medium

Comment thread go/types.go
Comment on lines +1470 to +1472
// Allow lists operations permitted without prompting. Every declared allow
// list across managed layers must admit an operation for it to be allowed.
Allow []string `json:"allow,omitempty"`
Copilot AI review requested due to automatic review settings July 31, 2026 22:41
@joshspicer
joshspicer force-pushed the joshspicer-sdk-managed-settings-permissions branch from 135b25a to 3676a65 Compare July 31, 2026 22:41
Comment thread python/copilot/generated/rpc.py Fixed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (2)
  • go/rpc/zrpc.go: Generated file
  • go/rpc/zrpc_encoding.go: Generated file
Suppressed comments (5)

go/types.go:1485

  • An explicitly empty allow list is not equivalent to omitting allow: by this field's own contract, every present allow-list must admit an operation, so [] is a deny-all constraint. omitempty drops that value and therefore removes the host's restriction, weakening the managed policy. Preserve the nil-versus-empty distinction (for example with a pointer slice or custom marshaling) and update the test that currently asserts omission.
	Allow []string `json:"allow,omitempty"`

rust/src/types.rs:1763

  • This public field documents a single legal literal but accepts and serializes any string. That defeats the typed contract and lets invalid policy reach the runtime. Use a public enum for disable (the generated protocol already defines DisableBypassPermissionsMode) rather than String.
    pub disable_bypass_permissions_mode: Option<String>,

go/types.go:1478

  • The contract permits only the "disable" literal, but *string accepts and forwards arbitrary values. Expose a dedicated typed value/constant (the generated RPC package already has rpc.DisableBypassPermissionsMode) so callers cannot accidentally construct an invalid managed policy.
	DisableBypassPermissionsMode *string `json:"disableBypassPermissionsMode,omitempty"`

java/src/main/java/com/github/copilot/rpc/SessionConfig.java:108

  • The Java generated RPC surface was not regenerated for this schema addition. CopilotClient.getRpc().sessions.open(...) publicly consumes generated SessionOpenOptions, but that record still has no managedSettings field or generated managed-settings types, so this feature is unavailable through Java's typed RPC API while the other generated mirrors include it. Regenerate Java RPC sources from the updated schema rather than hand-editing them.
    private ManagedSettings managedSettings;

dotnet/src/Types.cs:3012

  • This property claims a single legal "disable" value but is an unrestricted string, so the new typed API accepts invalid policy and only fails later at runtime. Model it as a serialized enum/value type, consistent with other closed string-valued options in Types.cs.
    [JsonPropertyName("disableBypassPermissionsMode")]
    public string? DisableBypassPermissionsMode { get; set; }
  • Files reviewed: 25/30 changed files
  • Comments generated: 2
  • Review effort level: Balanced

Comment thread go/rpc/zrpc.go
type SessionManagedPermissions struct {
// Permission rules that allow matching operations unless another managed source, deny, or
// ask rule restricts them.
Allow []string `json:"allow,omitzero"`
Comment thread go/client_test.go
Comment on lines +3439 to +3441
t.Run("omits empty permission arrays (omitempty idiom)", func(t *testing.T) {
// Go's `omitempty` drops both nil and empty slices; an empty rule list
// is semantically equivalent to no rules for that key.
joshspicer and others added 2 commits August 3, 2026 08:08
…/resume

Add an optional per-session `managedSettings` field (permissions-only
contract) across all six language SDKs, alongside the existing
`enableManagedSettings` boolean. Hosts can inject enterprise permission
policy at session startup via:

  managedSettings.permissions = {
    disableBypassPermissionsMode?: "disable",
    deny?: string[],
    ask?: string[],
    allow?: string[],
  }

Semantics: startup-only (not persisted), must be re-supplied on resume,
composes restrictively with runtime-managed settings, and older runtimes
fail closed. Wired through hand-written wire types at both create and
resume in Node, Python, Go, .NET, Rust, and Java, plus tests, docs, and
a CHANGELOG entry. Generated RPC mirror types regenerated from the
runtime schema (TS/Python/Go/Rust; C# unaffected as it does not mirror
SessionOpenOptions). No SDK protocol bump.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Treat direct managedSettings injection as a managed session in every language SDK and document the compatible-runtime requirement.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

Copilot-Session: d5d4d699-33e2-4a55-9d48-57d2e483dd3d
Copilot AI review requested due to automatic review settings August 3, 2026 15:16
@joshspicer
joshspicer force-pushed the joshspicer-sdk-managed-settings-permissions branch from 3676a65 to 5411c88 Compare August 3, 2026 15:16

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review details

Files not reviewed (2)
  • go/rpc/zrpc.go: Generated file
  • go/rpc/zrpc_encoding.go: Generated file
Suppressed comments (7)

rust/src/wire.rs:331

  • This optional field is serialized as "managedSettings": null on every resume when unset because it is missing the neighboring skip_serializing_if attribute. That violates the startup option's omission contract and may cause schema-validating runtimes to reject normal resumes.
    pub managed_settings: Option<crate::types::ManagedSettings>,

go/types.go:1489

  • omitempty drops a non-nil empty Allow slice, but these states are not equivalent: an explicitly present empty allow list admits no operation under the documented intersection semantics, while an omitted list imposes no constraint. This can silently broaden an injected enterprise policy. Preserve non-nil empty slices (for example with Go 1.24's omitzero, as the generated RPC type does) and update the serialization test accordingly.
	Allow []string `json:"allow,omitempty"`

go/client_test.go:3507

  • This test codifies an unsafe equivalence for allow: an explicit empty allow list admits nothing, whereas omitting allow contributes no restriction. Update the test to require "allow": [] after changing serialization to preserve non-nil empty slices.
		// Go's `omitempty` drops both nil and empty slices; an empty rule list
		// is semantically equivalent to no rules for that key.

java/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java:69

  • @return is currently parsed as part of the rules parameter text rather than as a Javadoc block tag. Move it to a separate line.
     *            ask rules; @return this policy

java/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java:83

  • @return is embedded in the parameter description, leaving the fluent setter's return value undocumented in generated Javadoc. Use a separate block tag.
     *            allow rules; @return this policy

java/src/main/java/com/github/copilot/rpc/ManagedSettingsPermissions.java:55

  • @return is embedded in the @param description, so generated Javadoc does not document the method's return value. Put it on its own block-tag line.

This issue also appears in the following locations of the same file:

  • line 69
  • line 83
     *            deny rules; @return this policy

java/src/main/java/com/github/copilot/rpc/ManagedSettings.java:27

  • The inline @return text is part of the parameter description, not a Javadoc return tag. Split it onto its own block-tag line so the public fluent API is documented correctly.
     *            managed permission policy; @return this settings object
  • Files reviewed: 26/31 changed files
  • Comments generated: 1
  • Review effort level: Balanced

Comment thread rust/src/wire.rs
pub enable_managed_settings: Option<bool>,
#[serde(skip_serializing_if = "Option::is_none")]
pub is_experimental_mode: Option<bool>,
pub managed_settings: Option<crate::types::ManagedSettings>,
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants