From 03b432e6d532db63f40312771e3ba8212d1995c0 Mon Sep 17 00:00:00 2001 From: hubwriter Date: Wed, 7 Oct 2026 19:11:23 +0100 Subject: [PATCH 1/4] [2026-10-07] Local Sandboxes in Copilot CLI, App, and VSCode [GA] (#63554) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: 780b4f08-fb48-49b0-9c02-580adc1b160b --- .../cloud-and-local-sandboxes.md | 2 +- .../understanding-local-sandboxing.md | 53 +++-- .../concepts/copilot-surfaces/copilot-cli.md | 6 +- .../about-cloud-and-local-sandboxes.md | 40 ++-- .../configuring-local-sandbox-settings.md | 221 +++++++++++++++--- ...g-cloud-sandboxes-for-your-organization.md | 2 +- .../cloud-and-local-sandboxes/index.md | 2 +- .../using-local-sandboxing.md | 152 ++++++++++-- .../github-copilot-app/agent-sessions.md | 4 +- .../configure-local-sandboxing.md | 132 ----------- .../how-tos/github-copilot-app/index.md | 1 - .../cli-command-reference.md | 56 +++-- .../cli-config-dir-reference.md | 18 +- .../enterprise-managed-settings.md | 45 +++- .../slash-commands.md | 2 +- .../reusables/cli/local-sandboxing-prereqs.md | 2 + ...box.md => public-preview-cloud-sandbox.md} | 2 +- data/reusables/cli/public-preview-sandbox.md | 1 - data/reusables/cli/sandbox-on-windows.md | 2 - src/content-pipelines/config.yml | 4 + 20 files changed, 469 insertions(+), 278 deletions(-) delete mode 100644 content/copilot/how-tos/github-copilot-app/configure-local-sandboxing.md create mode 100644 data/reusables/cli/local-sandboxing-prereqs.md rename data/reusables/cli/{public-preview-local-sandbox.md => public-preview-cloud-sandbox.md} (56%) delete mode 100644 data/reusables/cli/public-preview-sandbox.md delete mode 100644 data/reusables/cli/sandbox-on-windows.md diff --git a/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md b/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md index bb1eac2d7736..1c6bfcf6841f 100644 --- a/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md +++ b/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md @@ -11,7 +11,7 @@ category: --- > [!NOTE] -> {% data reusables.cli.public-preview-sandbox %} +> {% data reusables.cli.public-preview-cloud-sandbox %} ## How sandbox usage is measured diff --git a/content/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing.md b/content/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing.md index 2d96c67bfa9f..54e52570cf6e 100644 --- a/content/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing.md +++ b/content/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing.md @@ -13,28 +13,23 @@ docsTeamMetrics: - copilot-cli --- -> [!NOTE] -> {% data reusables.cli.public-preview-local-sandbox %} - -{% data reusables.cli.sandbox-on-windows %} - ## Introduction When you enable local sandboxing, {% data variables.copilot.copilot_cli_short %} runs the commands it invokes on your behalf inside an operating-system sandbox. The sandbox enforces a **filesystem policy**: a set of rules that decide which paths a sandboxed process or operation can read, which it can write, and which it cannot touch at all. Most of this policy is assembled automatically, so that everyday commands keep working without setup. This article explains how {% data variables.product.prodname_copilot_short %} arrives at the policy, and how to check the access it grants in a particular directory. -For an overview of local sandboxing, including how to turn it on and off, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) and [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). +For an overview of local sandboxing, including how to turn it on and off, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) and [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). For details of how to configure local sandboxing, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). ## What the policy applies to The filesystem policy covers the work {% data variables.product.prodname_copilot_short %} does on your behalf, but it is enforced in different ways depending on the kind of work: * **Shell commands and built-in searches** run as sandboxed child processes, so the operating system enforces the policy directly. The `grep` and `glob` tools, for example, run ripgrep as a sandboxed child process. -* **Local MCP and language server processes (LSP)** can also run inside the sandbox, so the operating system enforces the policy on them too. +* **Local MCP and language server processes (LSP)** run inside the sandbox by default, so the operating system enforces the policy on them too. You can change this in the sandbox settings unless a managed policy requires it. * **Built-in file-reading and file-editing tools** run as part of {% data variables.copilot.copilot_cli_short %} itself rather than as a sandboxed child process. They check the same filesystem policy before reading or writing a file, but because the operating-system sandbox never sees these operations, the check is a software-only safeguard rather than one the operating system enforces. -* **Remote MCP servers** run outside your machine, so there is no local child process to sandbox and the filesystem policy does not constrain them. -* **Subagents** do not act directly; they orchestrate other tools. Whether the policy applies, and how, depends on the tool a subagent invokes. +* **Remote MCP servers** run outside your machine, so there is no local child process to sandbox and the filesystem policy does not constrain them. Their connections from the CLI can still be restricted by the network policy when **Sandbox MCP servers** is enabled. +* **Subagents** use other tools to do their work. Whether the policy applies, and how, depends on the tool a subagent invokes. A sandboxed **process** is therefore constrained by the operating system, while an in-process **operation** enforces the same policy in software—which is why this article refers to a sandboxed process or operation rather than only to commands. @@ -53,7 +48,7 @@ Because access is denied unless granted, {% data variables.product.prodname_copi ## How the policy is built -Before each sandboxed process starts, {% data variables.copilot.copilot_cli_short %} resolves the effective policy for that process using the current working directory, environment, settings, and automatic grants. This restricts the process to only the access that it needs, and means you don't have to manage these common locations yourself. +Before each sandboxed process starts, {% data variables.copilot.copilot_cli_short %} resolves the effective policy for that process using the current working directory, environment, settings, and automatic grants. This includes common locations needed by tools, so you don't have to grant each one yourself. Tools can also receive access to selected session files and installed skills they need to use. ### Your working directory @@ -72,7 +67,11 @@ On macOS, standard system locations are granted read-only permission so that com ### Package-manager caches -To let installs and builds work inside the sandbox, {% data variables.product.prodname_copilot_short %} also grants access to the caches and registries used by common package managers and toolchains—read-only for most locations, and read/write for selected writable locations, such as build caches and package-manager dependency stores. In the `/sandbox policy` report, this appears as **dev-tool access**. +When **Allow dev tool access** is enabled, {% data variables.product.prodname_copilot_short %} grants access to the caches and registries used by common package managers and toolchains. Most locations are read-only. Selected locations, such as npm's cache, build caches, and some dependency stores, are writable so installs and builds can work. + +These grants depend on the command and the tools detected in your project. They can follow cache locations you have configured outside the usual directories. Some granted configuration files contain registry credentials, and writable caches can be shared with commands you run outside the sandbox. Turn off **Allow dev tool access** if you prefer to grant these locations yourself. + +In the `/sandbox policy` report, the **Dev tools** section lists the detected tools and their paths. Selected writable caches are created when a command needs them, so they may not appear in the report before the first use. ### Git repositories @@ -82,11 +81,11 @@ Because read access spans the whole repository, a sandboxed command can read fil ## When access rules overlap -Because {% data variables.product.prodname_copilot_short %} grants several locations, and you can add your own, the rules can overlap. When they do, the **more specific path wins**. For example, if `/project` is writable but you mark `/project/secrets` read-only, everything in `/project` stays writable except `/project/secrets`. This is a useful way to protect a sensitive subfolder. +Because {% data variables.product.prodname_copilot_short %} grants several locations, and you can add your own, the rules can overlap. When read-only and read/write grants overlap, the **more specific path wins**. For example, if `/project` is writable but you mark `/project/secrets` read-only, everything in `/project` stays writable except `/project/secrets`. Denied paths take precedence over both kinds of grant. -Overlaps are also resolved in your favor when a convenience grant would otherwise get in the way. Consider a Python project with a local virtual environment (`.venv`) that appears on your `PATH`. Treating that directory as an ordinary read-only tool location would make it read-only—even though it sits inside your writable project—and a command such as `pip install` could then fail when it tried to update the environment. {% data variables.product.prodname_copilot_short %} resolves this for you: a grant it added automatically (such as a tool directory on `PATH`) gives way to a broader read/write grant that already covers it. So a project-local `.venv`, `node_modules/.bin`, or similar directory stays writable as part of your workspace. +Discovered tool-directory grants give way to read/write access that already covers them. Consider a Python project with a local virtual environment (`.venv`) that appears on your `PATH`. Treating that directory as an ordinary read-only tool location would make it read-only—even though it sits inside your writable project—and a command such as `pip install` could then fail when it tried to update the environment. {% data variables.product.prodname_copilot_short %} leaves it writable as part of your workspace. Other read-only rules, including ones you configure yourself, are not discarded this way. -Rules that **you** configure are always kept. If you mark a path read-only, or you deny it, that decision stands even when the same path would otherwise be discovered and granted automatically. This gives you a reliable way to protect a sensitive location—for example, denying a `.env` file so that no sandboxed command can read your secrets. +Rules that **you** configure are not removed just because the same path was discovered automatically. You can use them to restrict access to a sensitive location, such as an existing `.env` file. Missing paths and symbolic links need additional care, as described in [Troubleshooting filesystem access](#troubleshooting-filesystem-access). ## Checking what the current policy allows @@ -96,16 +95,38 @@ Because the policy is assembled for each directory and command, the simplest way /sandbox policy ``` -{% data variables.product.prodname_copilot_short %} prints the **effective** policy for your current directory: the read/write, read-only, and denied paths that a command launched from here would actually receive, together with the network access and dev-tool access in force. This is the resolved result after the automatic grants and your own settings have been combined and any overlaps resolved—not just a copy of your saved settings. +{% data variables.product.prodname_copilot_short %} prints the **effective** policy for your current directory. Paths are grouped by source, such as **User-configured paths** and **Dev tools**, and by access level. The report also includes network settings and a **Capabilities** section covering settings such as bypass, MCP/LSP sandboxing, and authentication. This is the result after automatic grants, your settings, and managed restrictions have been combined—not just a copy of your saved settings. + +To inspect the developer-tool access for a particular command, add the command after `policy`. For example: + +```shell copy +/sandbox policy npm install +``` + +This does not run `npm install`. It shows the tool access the command would receive. The preview creates no directories, including missing denied paths and tool caches. A few things to keep in mind when you read the report: * It reflects your **current directory**. Because grants are discovered per directory, the same settings can resolve to different paths depending on where you run. -* If a path you configured does not exist on disk, it is left out of the policy and noted in a **Notes** section. This explains why a rule you added might appear to have no effect. +* Check **Notes** for configured paths that could not be included. Missing read/write or read-only grants are omitted. On Linux, missing denied paths are omitted from this preview, but launch preparation creates them before applying the policy. The preview retains them on macOS and on Windows hosts that support denied paths. * If sandboxing is turned off, `/sandbox policy` tells you so instead of printing a policy, because no restrictions are in force. To check only whether sandboxing is currently on, use `/sandbox status`. For more about these commands, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). +## Troubleshooting filesystem access + +If a configured read/write or read-only path does not exist, create it outside the sandbox before starting the command again. A running child process keeps the policy it received at launch. Creating a path later does not add a missing grant to that process. Restart a long-running server if it needs the updated access. + +Before a sandboxed process starts, {% data variables.copilot.copilot_cli_short %} creates missing denied paths and their parent directories on your machine. This includes paths intended for files, so a missing `.env` becomes a directory. The directories remain after the process exits. + +If a denied path cannot be prepared, the process does not start. The read-only `/sandbox policy` preview does not perform this preparation, which is why missing denied paths are omitted there on Linux. For troubleshooting, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing#troubleshooting-blocked-paths-that-do-not-exist). + +A symbolic link inside an allowed directory does not guarantee access to a target outside that directory. If a denial message names such a target, inspect it and grant access only if intended. Adding a resolvable symbolic link itself through `/sandbox config` also adds its current target for read/write or read-only access. Handwritten path rules and automatically discovered developer-tool grants do not automatically add that target. + +Denied paths are handled differently from grants: the CLI resolves their written path and current target. On Linux, a denied symbolic link protects its target, but does not reliably prevent the link itself from being replaced. Prefer denying the actual sensitive directory rather than relying on a symbolic-link rule alone. + +For network failures, managed restrictions, and bypass choices, see [Troubleshooting blocked commands](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing#troubleshooting-blocked-commands). + ## Customizing the policy You can grant extra read/write or read-only paths, deny paths, and change other filesystem behavior, either from the `/sandbox config` dialog or in your settings file. After you make a change, run `/sandbox policy` to confirm the result. For step-by-step instructions, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). diff --git a/content/copilot/concepts/copilot-surfaces/copilot-cli.md b/content/copilot/concepts/copilot-surfaces/copilot-cli.md index 3c6b91b78724..70ea8bb3950f 100644 --- a/content/copilot/concepts/copilot-surfaces/copilot-cli.md +++ b/content/copilot/concepts/copilot-surfaces/copilot-cli.md @@ -67,9 +67,6 @@ To use the CLI programmatically, include the `-p` or `--prompt` command-line opt ## Running {% data variables.copilot.copilot_cli_short %} commands in a sandbox -> [!NOTE] -> {% data reusables.cli.public-preview-sandbox %} - To prevent {% data variables.product.prodname_copilot_short %} from modifying files you don't want it to touch, you can force agents to run commands within a local sandboxed environment. Alternatively, you can run an entire CLI session in an isolated environment in the cloud. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). ### Local sandboxing @@ -78,6 +75,9 @@ You can enable local sandboxing inside a {% data variables.copilot.copilot_cli_s ### Cloud sandboxing +> [!NOTE] +> {% data reusables.cli.public-preview-cloud-sandbox %} + You can start a {% data variables.copilot.copilot_cli_short %} session inside an isolated, cloud-hosted environment with cloud sandboxes. This is useful when you want to run code without affecting your local machine, keep a session's state between uses, continue a session from a different machine, or run multiple tasks in parallel. Cloud sandbox policies inherit from {% data variables.copilot.copilot_cloud_agent %} policies, so existing security controls like firewall rules extend to cloud sandboxes without additional setup. To start a cloud-backed session, run: diff --git a/content/copilot/concepts/security-governance-and-network-settings/about-cloud-and-local-sandboxes.md b/content/copilot/concepts/security-governance-and-network-settings/about-cloud-and-local-sandboxes.md index 471c73b5aedf..7cf1d9aed1d5 100644 --- a/content/copilot/concepts/security-governance-and-network-settings/about-cloud-and-local-sandboxes.md +++ b/content/copilot/concepts/security-governance-and-network-settings/about-cloud-and-local-sandboxes.md @@ -17,7 +17,7 @@ docsTeamMetrics: --- > [!NOTE] -> {% data reusables.cli.public-preview-sandbox %} +> {% data reusables.cli.public-preview-cloud-sandbox %} ## Introduction @@ -37,11 +37,6 @@ With sandboxing, you can choose where {% data variables.product.prodname_copilot ## Local sandboxing -> [!NOTE] -> -> * In {% data variables.copilot.copilot_cli_short %}, local sandboxing is currently an experimental feature. To use it, start the CLI with the `‑‑experimental` command line option, or enter `/experimental on` during a session. -> * In the {% data variables.copilot.github_copilot_app %}, local sandboxing is in {% data variables.release-phases.public_preview %} and subject to change. - Local sandboxing lets {% data variables.product.prodname_copilot_short %} run in a sandboxed environment directly on your machine, with restricted access to your filesystem, network connectivity, and system capabilities. You can configure local sandboxing in {% data variables.copilot.copilot_cli_short %} or the {% data variables.copilot.github_copilot_app %}. Local sandboxing is turned off by default. Until you enable it, the shell commands that {% data variables.product.prodname_copilot_short %} runs execute directly on your machine with the same access as your user account: they can read, write, and delete wherever you can, reach any network your machine can reach, and use your credentials without restriction. Enabling local sandboxing constrains this access to a policy that you control. @@ -62,13 +57,15 @@ To enable local sandboxing inside a {% data variables.copilot.copilot_cli_short /sandbox enable ``` -After you enable local sandboxing, the commands and tools that an agent runs on your behalf—shell commands, file search, and, by default, the MCP and language (LSP) servers the CLI starts—run inside an operating-system-level sandbox, limiting their access to your system. The CLI continues to use local sandboxing whenever you use the CLI in future—for programmatic as well as interactive use—until you run `/sandbox disable` to disable it. If enterprise managed settings require sandboxing, ordinary settings, startup options, and `/sandbox disable` cannot turn it off. If the effective policy permits sandbox bypass, you can still explicitly disable sandboxing for the rest of the current session from an active bypass permission prompt. +After you enable local sandboxing, the commands and tools that an agent runs on your behalf run inside an operating-system-level sandbox that limits their access to your system. These include shell commands, file search, and, by default, any local MCP and language (LSP) servers. {% data variables.product.prodname_copilot_short %} continues to use local sandboxing, including in future sessions, until you run `/sandbox disable` to disable it. + +If enterprise managed settings require sandboxing, ordinary settings and startup options cannot turn it off. If the effective policy permits sandbox bypass, you can still disable sandboxing for the rest of the current session, either from a bypass permission prompt or by running `/sandbox disable`. This does not change the saved policy. The CLI's built-in file tools—first-party commands that are part of the CLI, rather than shell commands like `sed`—run in-process in the CLI. Because the CLI itself is not sandboxed, the operating-system sandbox never sees the file operations these tools perform and cannot constrain them. Instead, the built-in tools are coded to check the sandbox policy themselves and honor your configured settings on a best-effort basis. -For more information about enabling local sandboxing in {% data variables.copilot.copilot_cli_short %}, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). +In the {% data variables.copilot.github_copilot_app %}, project settings define the local sandboxing default for new local repository and working tree sessions. You can also change sandboxing for an active local session without changing the project default. -In the {% data variables.copilot.github_copilot_app %}, project settings define the local sandboxing default for new local repository and working tree sessions. You can also change sandboxing for an active local session without changing the project default. For more information, see [AUTOTITLE](/copilot/how-tos/github-copilot-app/configure-local-sandboxing). +For more information about enabling local sandboxing in {% data variables.copilot.copilot_cli_short %} and {% data variables.copilot.github_copilot_app_short %}, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). ### Configuring local sandboxing @@ -77,21 +74,19 @@ You can use the default local sandboxing behavior, or modify what {% data variab In {% data variables.copilot.copilot_cli_short %}, you can control several dimensions of access: * **Filesystem**: Grant read-only or read/write access to specific paths, or deny paths. -* **Network**: Allow or block outbound internet access and local network access independently. +* **Network**: Control outbound internet access and local network access, or allow and deny specific hosts. The restrictions available depend on your operating system. * **Credentials**: Choose whether your Git and {% data variables.product.prodname_cli %} (`gh`) credentials are made available inside the sandbox. * **Subprocesses**: Choose whether local MCP servers and language servers also run inside the sandbox. Remote MCP servers are never sandboxed. * **Keychain (macOS)**: Choose whether the system keychain is reachable from inside the sandbox. * **Per-command exceptions**: Allow or prevent individual commands from running outside the sandbox when they need broader access. -For more information about configuring local sandbox settings in {% data variables.copilot.copilot_cli_short %}, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). - In the {% data variables.copilot.github_copilot_app %}, project settings expose a subset of these controls: * **Filesystem**: Grant additional read-only or read/write access to specific paths, or deny paths. * **Network**: Allow or block outbound internet and local network access. * **Credentials**: Choose whether your Git and {% data variables.product.prodname_cli %} credentials are available inside the sandbox. -The app can also ask you to approve an individual command to run outside the sandbox. You cannot configure whether bypass requests are allowed in the project settings. For more information about configuring the project policy and changing sandboxing for an active local session, see [AUTOTITLE](/copilot/how-tos/github-copilot-app/configure-local-sandboxing). +The app can also ask you to approve an individual command to run outside the sandbox. You cannot configure whether bypass requests are allowed in the project settings. For more information about configuring local sandboxing in the app or CLI, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). ### Cross-platform support @@ -103,23 +98,26 @@ Local sandboxing is available on macOS, on Linux, and on recent Windows 11 build * `unshare` and `nsenter` from util-linux 2.35 or later, with `--map-current-user` and `--keep-caps` support. * `iptables`, `ip6tables`, and their restore binaries. Use the `nf_tables` backend. The legacy backend also operates, but only if you can write to `/run/xtables.lock`. * Access to `/dev/net/tun`. -* **Windows** uses the BaseContainer tier of the ProcessContainer backend. {% data variables.copilot.copilot_cli_short %} does not use the AppContainer fallback tiers. If your Windows build cannot supply BaseContainer, {% data variables.copilot.copilot_cli_short %} reports that sandboxing is not supported. To find the supported Windows versions, see [Windows OS support for Copilot sandboxing](https://aka.ms/ghcp-sandbox-os-support). +* **Windows** requires a recent Windows 11 update that supports sandboxing. Support for features such as denied paths, localhost connections, and proxying also depends on your Windows version. If your host cannot support a requested feature, {% data variables.copilot.copilot_cli_short %} reports the requirement instead of running the command with weaker restrictions. See [Windows update information for Copilot sandboxing](https://aka.ms/ghcp-sandbox-os-support). #### Proxy support -The sandbox proxy operates differently on each operating system: +In {% data variables.copilot.copilot_cli_short %}, host rules and HTTP proxy settings use a built-in local proxy. Their enforcement differs by operating system: + +* **macOS and Linux**: The sandbox restricts outbound connections to the local proxy. Programs that ignore proxy settings cannot connect directly instead. The Linux requirements for outbound traffic listed in [Cross-platform support](#cross-platform-support) also apply when you configure a proxy. +* **Windows**: Proxying and host rules require a supported Windows version and **Allow local network** to be turned on. On Windows, the sandbox relies on programs honoring the proxy settings. As a result, these controls do not provide the same protection against direct connections as on macOS and Linux. -* **macOS**: {% data variables.copilot.copilot_cli_short %} does not give the proxy to Seatbelt. It sets `HTTP_PROXY`, `HTTPS_PROXY`, and `ALL_PROXY` in the sandboxed environment instead. Only programs that obey these variables use the proxy. A program that ignores them connects directly. -* **Linux**: bubblewrap enforces the proxy. The sandbox gets a private network namespace, and only the proxy endpoint is permitted. The Linux requirements for outbound traffic listed in [Cross-platform support](#cross-platform-support) also apply when you configure an upstream proxy. The proxy must have an IPv4 address, because {% data variables.copilot.copilot_cli_short %} refuses a proxy that only IPv6 can reach. The proxy URL must not contain credentials, so give the credentials to the proxy itself. -* **Windows**: the proxy is not available. In {% data variables.copilot.copilot_cli_short %}, do not use denied paths either. If a CLI sandbox policy includes either setting, the sandboxed command fails with an error. In the {% data variables.copilot.github_copilot_app %}, you can save denied paths in the project settings. If the active BaseContainer capabilities cannot enforce a denied path, the sandboxed command fails instead of running with a weaker policy or without a sandbox. +In the {% data variables.copilot.github_copilot_app %}, you can save denied paths in the project settings. If the active BaseContainer capabilities cannot enforce a denied path, the sandboxed command fails instead of running with a weaker policy or without a sandbox. -On Linux, bubblewrap cannot control local network access independently for spawned processes, including shell commands and local MCP or LSP servers. In the {% data variables.copilot.github_copilot_app %}, the local network setting still applies to in-process operations, such as web requests and remote MCP connections. +On Linux, bubblewrap cannot control local network access independently for spawned processes, including shell commands and local MCP or LSP servers. The local network setting still applies to in-process operations, such as web requests and remote MCP connections, in both the CLI and the app. #### If your host does not support local sandboxing -In {% data variables.copilot.copilot_cli_short %}, the sandbox is turned off for the session and a notice is displayed. Shell commands and sandboxed services then run without a sandbox, and your `sandbox.enabled` setting does not change. If your enterprise enforces sandboxing through device-managed settings, the session fails closed instead: sandboxed commands do not run. +In {% data variables.copilot.copilot_cli_short %}, a saved user preference to enable sandboxing is turned off for the current session if the host does not support it. A notice explains that shell commands and services will run without a sandbox. Your saved `sandbox.enabled` setting remains unchanged. Running `/sandbox enable` on an unsupported host is refused. + +Enterprise settings can change this behavior. On an unsupported host, a server-managed request to enable sandboxing is declined unless effective managed settings also set `sandbox.failIfUnavailable` to `true`. Device-managed settings can require sandboxing even on an unsupported host. Commands and services that require sandboxing then fail rather than running without it. When effective managed settings set both `sandbox.enabled` and `sandbox.failIfUnavailable` to `true`, the CLI blocks model requests and tool execution for the session if it cannot enforce sandboxing. These requirements can come from server-managed settings, device-managed settings, or a combination of both. -In the {% data variables.copilot.github_copilot_app %}, host support is checked when the first sandboxed shell starts. If the host cannot enforce the requested policy, the shell fails with an unsupported-platform or unsupported-policy message and does not run unsandboxed. +For the {% data variables.copilot.github_copilot_app %}, on a host that does not support local sandboxing, a session configured to use local sandboxing may start normally, but shell commands and other sandboxed processes fail when {% data variables.product.prodname_copilot_short %} attempts to launch them. The {% data variables.copilot.github_copilot_app %} preserves the saved preference, and the failed operation reports that sandboxing is not supported on the platform. Device-managed settings may require this fail-closed behavior and can block model and tool execution. ### Enterprise policy enforcement diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md b/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md index ed07dff20f2a..3aed64b8da49 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings.md @@ -1,9 +1,11 @@ --- title: Configuring local sandbox settings shortTitle: Configure local sandbox -intro: 'Use the `/sandbox` slash command in {% data variables.copilot.copilot_cli_short %} to control how the local sandbox restricts filesystem access, network connectivity, and system capabilities.' +intro: 'Configure local sandboxing in the {% data variables.copilot.github_copilot_app %} or {% data variables.copilot.copilot_cli_short %} to restrict filesystem access, network connectivity, and credential use.' versions: feature: copilot +redirect_from: + - /copilot/how-tos/github-copilot-app/configure-local-sandboxing contentType: how-tos category: - Configure Copilot # Copilot discovery page @@ -12,28 +14,115 @@ docsTeamMetrics: - copilot-cli --- +## About local sandbox configuration + +You can use the settings in the {% data variables.copilot.github_copilot_app %} or the `/sandbox` slash command in {% data variables.copilot.copilot_cli_short %} to grant extra paths, adjust network access, or turn sandboxing on or off. + +Local sandboxing limits access to files, network resources, and credentials on your machine, reducing the potential impact of an unintended command. Settings are configured separately in the {% data variables.copilot.github_copilot_app_short %} and {% data variables.copilot.copilot_cli_short %}. Changing them in one does not change them in the other. + > [!NOTE] -> {% data reusables.cli.public-preview-local-sandbox %} +> If you get your {% data variables.product.prodname_copilot_short %} license from an enterprise, some or all sandbox settings may be controlled by enterprise managed settings. -{% data reusables.cli.sandbox-on-windows %} +For a conceptual overview of cloud and local sandboxes for {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). For detailed instructions on using local sandboxing, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). -## About local sandbox configuration +## Prerequisites -You can use the `/sandbox` slash command to grant extra paths, adjust network access, or turn sandboxing on or off. +{% data reusables.cli.local-sandboxing-prereqs %} -> [!NOTE] -> If you get your {% data variables.product.prodname_copilot_short %} license from an enterprise, some or all sandbox settings may be controlled by enterprise managed settings. A managed setting is labeled `(managed)` in the `/sandbox` interface and can't be changed. +## Configuring the {% data variables.copilot.github_copilot_app_short %} + +You configure local sandboxing separately for each project in the {% data variables.copilot.github_copilot_app %}. The configuration applies to local repository and working tree sessions. It does not apply to cloud sandbox sessions or sessions that run on a remote host. + +A working tree keeps the branches and files for concurrent sessions separate, but it does not restrict what a command can access elsewhere on your machine. Local sandboxing provides that additional protection. + +### Enabling local sandboxing for a project + +Local sandboxing is turned off by default unless enterprise managed settings require it. The sandbox settings are not available for remote-only projects. To enable sandboxing for new local sessions in a project: + +1. In the app sidebar, open **Settings**. +1. Under "Projects," select the project that you want to configure. +1. Under "Sandbox," turn on **Sandbox new sessions**. + +The setting applies to new sessions in the project. It does not change a session that is already running. For details of how to turn on local sandboxing for the current session, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing#enabling-and-disabling-sandboxing-for-your-session). + +For most projects, you can start with the default sandboxing policy. This allows access needed for common development tasks such as installing dependencies, connecting to a local development server, pushing a branch, and creating a pull request. Add restrictions when the project is next to sensitive folders, does not need network access, or should not use your credentials. + +### Configuring the sandbox policy for a project + +A sandbox policy is a set of rules that controls which files, networks, and credentials agent-run tools can access. The project settings describe the policy that the app requests when a sandboxed session starts. The effective policy can be more restrictive, for example, when enterprise managed settings apply. + +The "Configured policy summary" shows your selected folder, network, and credential settings. It does not confirm that the sandbox is running or show every restriction that applies. Changes are saved automatically. + +In the project settings, you can configure: + +* [**Filesystem access**](#configuring-filesystem-access): Grant additional read-only or read/write access to specific paths, or deny paths. +* [**Network access**](#configuring-network-access): Allow or block outbound internet and local network access. +* [**Credentials**](#configuring-credentials): Choose whether your Git and {% data variables.product.prodname_cli %} credentials are available inside the sandbox. + +#### Configuring filesystem access + +By default, a sandboxed session has read/write access to its workspace and current working directory. You can grant access to additional folders or prevent access to specific folders. + +In the "Sandbox" section of the project settings, configure any of the following lists: + +* **Additional read/write**: Folders that agent-run tools can read and modify. +* **Additional read-only**: Folders that agent-run tools can read but not modify. +* **Denied**: Folders that agent-run tools cannot access. + +To add a folder, click **Add folder** for the appropriate list, then choose the folder. To remove a folder, click the delete icon next to its path. + +A more-specific denied folder remains denied when a broader parent folder has read or write access. + +On Windows, you can save a denied path in the project settings. If the active Windows sandbox capabilities cannot guarantee the denial, a sandboxed command fails with an unsupported-policy message. The command does not run with the denied path accessible or without a sandbox. + +#### Configuring network access + +By default, both network settings are turned on in the app. In the "Sandbox" section of the project settings, you can change the following settings: + +* **Outbound internet**: Allow connections to internet services, such as {% data variables.product.github %} and package registries. +* **Local network**: Allow loopback and local-network connections, including connections to local development servers. + +Network restrictions can affect package installation, API calls, preview servers, and other tools that need a network connection. + +On Linux, sandboxed processes cannot connect directly to servers on your computer's localhost. The local network setting still controls requests through the built-in local proxy, as well as in-process operations such as web requests and remote MCP connections. + +The operating-system limitations described in [Configuring network settings](#configuring-network-settings) also apply to the app. Unlike the app's **Local network** setting, the CLI's **Allow local network** setting is turned off by default. + +#### Configuring credentials -For a conceptual overview of cloud and local sandboxes for {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +By default, authenticated Git and {% data variables.product.prodname_cli %} operations are available inside the sandbox. You can turn off either of the following settings: -## Opening the sandbox configuration +* **Git credentials**: Allow authenticated HTTPS Git operations. +* **{% data variables.product.prodname_cli %} credentials**: Allow {% data variables.product.prodname_cli %} (`gh`, not `copilot`) to authenticate. + +Turning off credential access can prevent operations such as pushing a branch or creating a pull request from inside the sandbox. + +### Applying policy changes + +Changes to filesystem, network, and credential settings apply to new sessions or when an existing session restarts. They do not change the policy of a currently running session. + +To restart a session while keeping its history, enter: + +```text +/restart-session +``` + +The app accepts sandbox settings before checking whether your operating system can enforce them. Support is checked when the first sandboxed shell starts. If the host cannot enforce the requested policy, the shell fails with an unsupported-platform or unsupported-policy message and does not run unsandboxed. To find the currently supported Windows versions, see [Windows OS support for Copilot sandboxing](https://aka.ms/ghcp-sandbox-os-support). + +If the app displays **Sandbox unavailable**, address the reported problem, then click **Retry sandbox**. + +## Configuring {% data variables.copilot.copilot_cli_short %} + +Use the `/sandbox` slash command to configure local sandboxing in the CLI. A managed setting is labeled `(managed)` in the `/sandbox` interface and can't be changed. + +### Opening the sandbox configuration 1. Start a {% data variables.copilot.copilot_cli_short %} session. 1. Enter the `/sandbox` slash command. - This opens an interactive configuration interface with four tabs: **General**, **Auth**, **Filesystem**, and **Network**. Use Tab to switch between tabs. Press Esc to save your changes and close the configuration. + This opens an interactive configuration interface with four tabs: **General**, **Credentials**, **Filesystem**, and **Network**. Use Tab to switch between tabs. Press Esc to save your changes and close the configuration. If you are in a path or host-rule list, press Esc first to return to its tab. -## Configuring general settings +### Configuring general settings The **General** tab controls the top-level sandbox behavior. When enterprise managed settings enforce a value, the dialog labels the setting as `(managed)` and prevents you from changing it. @@ -44,26 +133,31 @@ The **General** tab controls the top-level sandbox behavior. When enterprise man | **Sandbox MCP servers** | Run MCP servers inside the sandbox. Turned on by default. | | **Sandbox LSP servers** | Run language servers (LSP servers) inside the sandbox. Turned on by default. | -### Allowing sandbox bypass +#### Allowing sandbox bypass + +The **Allow sandbox bypass** setting controls whether {% data variables.product.prodname_copilot_short %} can ask for permission to retry a blocked command with broader access. + +* **On (default)**: For supported sandbox denials, the CLI offers an approval prompt describing the command and the proposed retry. Approval applies to that attempt. You can also choose to disable sandboxing for the rest of the session, if your enterprise permits it, or give {% data variables.product.prodname_copilot_short %} another instruction. +* **Off**: The command remains blocked. You can adjust settings you control or ask {% data variables.product.prodname_copilot_short %} to take a different approach. -The **Allow sandbox bypass** setting controls what happens when {% data variables.product.prodname_copilot_short %} can't run a command successfully inside the sandbox. +A bypass only removes {% data variables.product.prodname_copilot_short %}'s own sandbox limits, not your operating system's. The command still runs under your normal account, so it gains no administrator or root access and cannot reach anything your system already blocks. -* **On (default)**: If a command fails inside the sandbox, you are prompted to allow {% data variables.product.prodname_copilot_short %} to run the command outside the sandbox. Your response to this prompt applies to this specific attempt to run the command. Optionally, you can choose to disable the sandbox for the rest of the session (if permitted by your enterprise), or you can enter an instruction for {% data variables.product.prodname_copilot_short %} to work on instead. -* **Off**: If {% data variables.product.prodname_copilot_short %} can't run a command successfully in the sandbox, it stops working on the task and reports the failure. +On supported Windows hosts, an approved retry can first relax file and process restrictions while keeping network restrictions in place. Its result is labeled "sandbox relaxed." If the command is still blocked, the CLI can then use the full bypass described in the same approval prompt. That result is labeled "sandbox bypassed." If enterprise managed settings set `sandbox.allowBypass` to `false`, you cannot approve individual commands to run outside the sandbox or disable sandboxing for the rest of the session. If managed settings require sandboxing but the effective policy permits bypass, you cannot turn sandboxing off through ordinary settings, but you can disable it for the rest of the current session—either from an active bypass permission prompt or by running `/sandbox disable`—without loosening the saved policy. -## Configuring authentication settings +### Configuring authentication settings -The **Auth** tab controls whether your credentials are made available to commands running inside the sandbox. As on the other tabs, an enterprise-managed value is shown as `(managed)` and can't be changed. +The **Credentials** tab controls whether your credentials are made available to commands running inside the sandbox. As on the other tabs, an enterprise-managed value is shown as `(managed)` and can't be changed. | Setting | Description | | --- | --- | | **Authenticate git** | Inject a {% data variables.product.github %} token so authenticated HTTPS `git` works inside the sandbox without a credential helper. For non-GitHub hosts, your own stored credentials are made available to sandboxed `git` commands instead. Turned on by default. | | **Authenticate gh** | Export `GH_TOKEN` so that {% data variables.product.prodname_cli %} (note: the `gh` CLI, not `copilot`) works inside the sandbox without reaching its stored credentials (configuration directory or OS keychain), which the sandbox blocks. Turned on by default. | -| **Allow keychain access** | Available on macOS only. Let sandboxed commands use the macOS Keychain—for example, to access credentials used by `git` and `gh` credential helpers. Turned off by default. | -## Configuring filesystem settings +On macOS, keychain access is turned off by default. To allow sandboxed commands to use the system keychain, set `sandbox.userPolicy.seatbelt.keychainAccess` to `true` in your personal `settings.json` file. This option is not available through `/sandbox` or `/settings`. + +### Configuring filesystem settings The **Filesystem** tab controls which directories and files the sandboxed process can access. @@ -80,11 +174,12 @@ By default, {% data variables.product.prodname_copilot_short %} is granted read/ > [!IMPORTANT] > Unselecting **Include working directory** removes access to everything in and below the `.git` directory of a Git repository. As a result, Git operations such as `status`, `add`, `commit`, and `diff` will fail unless you manually add access for this directory. -### Adding filesystem path rules +#### Adding filesystem path rules You can specify paths that you want to add to the sandbox. This allows you to grant read-only or read/write access to directories and files outside the working directory. You can also deny access, to exclude directories and files from the sandbox. -1. In the **Filesystem** tab, press A to add a new path rule. +1. In the **Filesystem** tab, select **User-configured paths** and press Enter. +1. Press A to add a new path rule. 1. Type a file or directory path. Use an absolute path—for example, `/Users/octocat/projects/app` on macOS or Linux, or `C:\Users\octocat\projects\app` on Windows. Then press Enter. > [!NOTE] @@ -92,44 +187,97 @@ You can specify paths that you want to add to the sandbox. This allows you to gr 1. Use the left and right arrow keys on your keyboard to navigate between the permissions options: **Read/Write**, **Read-Only**, **Denied**. Then press Enter to select an option. +If the path itself is a symbolic link, selecting **Read/Write** or **Read-Only** also adds its current target when the CLI can resolve it. This does not automatically grant access to targets of other links inside an allowed directory. + After you have added filesystem paths, you can edit or delete them. 1. Use the up and down arrow keys to select a path. -1. Press Enter to edit the path, or D to delete it. +1. Press Enter to edit the path, or X to delete it. +1. Press Esc to return to the **Filesystem** tab. Press Esc again to save and close the configuration. -## Configuring network settings +On Windows, denied paths require a version that supports this restriction. If the host cannot enforce them, the command fails with an explanation rather than running with weaker protection. + +### Configuring network settings The **Network** tab controls whether sandboxed processes can make network connections. | Setting | Description | | --- | --- | -| **Allow outbound connections** | Turned on by default. When turned on, the sandboxed process can reach external hosts on the internet. Turn this off to fully isolate the sandbox from the network. | -| **Allow local network** | Turned on by default. When turned on, the sandboxed process can reach hosts on your local network (for example, `localhost` or other devices on your LAN). Turn this off to block the sandbox from reaching local or private network services. | -| **HTTP Proxy** | Route the sandbox's outbound traffic through an HTTP proxy. See [Routing traffic through an HTTP proxy](#routing-traffic-through-an-http-proxy). | +| **Allow outbound connections** | Turned on by default. Allows outbound internet connections, subject to any host rules. Turning it off also makes proxy settings and host rules inactive. | +| **Allow local network** | Turned off by default. Controls local access, such as connections to a development server on your machine. Its effect depends on your operating system, as described below. | +| **Host rules** | Allow or deny connections to specific hosts. See [Allowing or blocking specific hosts](#allowing-or-blocking-specific-hosts). | +| **Remote proxy** | Route the sandbox's outbound traffic through an HTTP proxy. See [Routing traffic through an HTTP proxy](#routing-traffic-through-an-http-proxy). | + +Local network access behaves differently on each operating system: + +| Operating system | Effect on sandboxed commands | +| --- | --- | +| macOS | With outbound access on and no proxy, host rules, or credential masking, turn on local access to let a command connect to a local development server. Leaving it off blocks localhost connections, including to a server the command starts itself. Turning outbound access off also blocks these connections. | +| Linux | Sandboxed commands use their own private network space. They can reach servers started there, but cannot connect directly to servers on your computer's localhost. With local access enabled and no remote proxy configured, requests through the built-in local proxy can reach your computer's localhost, subject to host rules. | +| Windows | Turning local access on permits private-network access. Connections to the host's localhost also require a Windows version that supports them. Proxying and host rules require this setting to be on. | + +The setting also applies to the CLI's built-in web requests on every platform. If **Sandbox MCP servers** is enabled, it applies to remote MCP connections too. Allowing local access lets the built-in `web_fetch` tool reach localhost, but does not remove its separate restrictions on other private-network addresses. + +Credential masking uses a local proxy even when you have not configured a remote proxy or host rules. This includes automatic masking for Git and `gh` authentication, which is enabled by default, and masked environment variables. + +When a local proxy is active on macOS, turning local access on lets a command listen on a port, but does not let it connect directly to that port itself. A server listening on all network interfaces can be reachable from other devices on your network. On Windows, do not assume a server inside a proxied sandbox is reachable from the host's localhost. + +#### Allowing or blocking specific hosts + +Use host rules to restrict which destinations sandboxed commands can reach. Host rules are active only while sandboxing and outbound connections are enabled. + +You can specify hostnames, wildcard subdomain patterns, or individual IPv4 or IPv6 addresses. IP address ranges in CIDR notation, such as `203.0.113.0/24`, are not supported. + +1. On the **Network** tab, select **Proxy and blocking** and press Enter. Then select **Host rules** and press Enter. +1. Press a to add a rule. +1. Type a hostname, wildcard subdomain pattern, or individual IP address. For example, use `example.com`, `*.example.com`, `203.0.113.10`, or `2001:db8::10`. Do not include a URL scheme, path, or port. Press Enter. +1. Use the left and right arrow keys to choose **Allow** or **Deny**, then press Enter to add the rule to the list. New rules default to **Deny**. +1. Press Esc to return to **Proxy and blocking**, then press Esc again to return to the **Network** tab. Press Esc once more to save your changes and close the configuration. + +To change a rule, select it and press Enter. To remove it, press x. Rules marked `(managed)` cannot be edited or removed. Changes are saved when you close the configuration. + +When choosing rules, keep the following in mind: + +* An allowed hostname matches that hostname only. Use `*.example.com` to match its subdomains, but not `example.com` itself. Use `*` to match every host. +* A denied domain also denies its subdomains. For example, denying `example.com` blocks both `example.com` and `api.example.com`. +* **Deny** takes precedence over **Allow**. +* Once you add an **Allow** rule, hosts that do not match an allowed entry are blocked, except for the automatic localhost entries described below. With no allow rules, other hosts remain allowed unless a deny rule or another network restriction blocks them. +* With at least one **Allow** rule, turning on both **Allow outbound connections** and **Allow local network** also permits `localhost`, `127.0.0.1`, and `::1`. These entries are added to the effective allowlist without changing your saved rules. Explicit **Deny** rules and enterprise allowlists can still block them. +* Enterprise rules can only narrow your allowlist, never widen it. A host is allowed only when both your rules and the enterprise rules permit it. If none of the hosts you allow are also allowed by the enterprise rules, nothing is left to permit. Every host is then denied. This is the one case where adding an **Allow** rule ends in a fully closed list. {% data variables.product.prodname_copilot_short %} shows this state in the sandbox dialog and in the policy details. + +Host rules use a local proxy, even if you have not configured an HTTP proxy. On macOS and Linux, the sandbox forces every connection through this proxy, so a program cannot avoid your host rules by connecting directly. On Windows, the sandbox relies on programs honoring the proxy settings. As a result, programs that ignore the proxy settings on Windows can connect directly and get around your host rules. + +#### Routing traffic through an HTTP proxy + +To send the sandbox's outbound traffic through a proxy server: -### Routing traffic through an HTTP proxy +1. On the **Network** tab, select **Proxy and blocking** and press Enter. Then select **Remote proxy** and press Enter. +1. Enter the proxy **URL**, and optionally a **Username** and **Password**. -Select **HTTP Proxy** on the **Network** tab to send the sandbox's outbound traffic through a proxy server. Enter the proxy **URL**, and optionally a **Username** and **Password**. To remove the proxy, clear the URL. +To remove the proxy, clear the URL. Keep the following in mind: * The proxy applies only while **Allow outbound connections** is turned on. If you turn outbound connections off, the proxy is kept in your settings but stays inactive. -* The password is stored securely in your operating system's credential store. You can also enter a `${VAR}` environment-variable reference instead of a literal password. -* On Linux and macOS, the proxy is cooperative: it is applied through standard proxy environment variables and depends on each tool honoring them. On Windows, the sandbox enforces the proxy. -* Your organization can enforce the proxy URL through managed settings. When it does, the URL is shown as `(managed)`, but you can still provide your own credentials, which are stored in your user settings. +* Use an HTTP or HTTPS URL without embedded credentials. Enter credentials in the separate **Username** and **Password** fields. On Linux, use an IPv4 address or a hostname with IPv4 support rather than an IPv6-only address. +* The CLI stores a literal password in your operating system's credential store when available, with a local file fallback. Your settings file holds a reference to the stored secret, not the password. +* You can enter `${VAR}` or `$VAR` as the entire **Password** value to use an environment variable instead. The variable must be available to the CLI. If it is unset, no password is supplied, and a proxy that requires authentication can reject the request. +* The CLI connects through a built-in local proxy, which keeps the upstream proxy credentials out of sandboxed child processes. Host rules also apply when you use an upstream proxy. +* On macOS and Linux, sandboxed programs cannot bypass the proxy by connecting directly. On Windows, the sandbox relies on programs honoring the proxy settings. Windows also requires a supported version and **Allow local network**, which permits private-network access as well. +* Your organization can enforce the proxy URL through managed settings. When it does, the URL is shown as `(managed)`, but you can still provide your own username and password. -## Enabling and disabling the sandbox quickly +### Enabling and disabling the sandbox quickly You can toggle the sandbox on or off without opening the full configuration interface: * **Enable**: Enter `/sandbox enable` in the {% data variables.copilot.copilot_cli_short %} session. * **Disable**: Enter `/sandbox disable` in the {% data variables.copilot.copilot_cli_short %} session. -These commands change the **Enable sandbox** setting on the **General** tab. +Ordinarily, these commands change the saved **Enable sandbox** setting. If managed settings require sandboxing and permit bypass, `/sandbox disable` instead turns sandboxing off only for the current session. Running `/sandbox enable` restores it for that session. -## Viewing your current sandbox settings +### Viewing your current sandbox settings -Settings are stored in `settings.json` under the `sandbox` key in your {% data variables.copilot.copilot_cli_short %} configuration directory. For more information about the configuration directory, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference). +Settings are stored in `settings.json` under the `sandbox` key in your {% data variables.copilot.copilot_cli_short %} configuration directory. Sandbox settings are not supported in repository-level settings files. Enterprise managed settings can restrict your choices. For more information about the configuration directory, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference). You can view your current sandbox settings from within a {% data variables.copilot.copilot_cli_short %} session. @@ -137,11 +285,10 @@ You can view your current sandbox settings from within a {% data variables.copil 1. Press / to search for settings. 1. Type `sandbox` to filter the list of settings. -The steps above show your saved settings. To see the **effective** filesystem policy—the read/write, read-only, and denied paths that result once your settings, the automatic grants, and any managed policy are combined—enter `/sandbox policy`. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). +The steps above show your saved settings. To see the **effective** policy—the paths, network settings, and capabilities that result once your settings, the automatic grants, and any managed policy are combined—enter `/sandbox policy`. You can add a command, such as `/sandbox policy npm install`, to inspect its developer-tool access without running it. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). ## Further reading -* [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) * [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing) * [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization) * [AUTOTITLE](/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli) diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md b/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md index fae69f376147..f81d585f6f5d 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization.md @@ -14,7 +14,7 @@ category: --- > [!NOTE] -> {% data reusables.cli.public-preview-sandbox %} +> {% data reusables.cli.public-preview-cloud-sandbox %} ## About enabling and disabling cloud sandboxes diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/index.md b/content/copilot/how-tos/cloud-and-local-sandboxes/index.md index 130997978f31..42c8ef0d1973 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/index.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/index.md @@ -1,7 +1,7 @@ --- title: Cloud and local sandboxes for GitHub Copilot shortTitle: Sandbox Copilot -intro: 'Configure local sandboxing for your {% data variables.copilot.copilot_cli_short %} sessions, and manage cloud sandbox access for your organization or enterprise.' +intro: 'Configure local sandboxing for your {% data variables.copilot.github_copilot_app %} and {% data variables.copilot.copilot_cli_short %} sessions, and manage cloud sandbox access for your organization or enterprise.' versions: feature: copilot children: diff --git a/content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md b/content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md index 566d5641a123..7adaec5fdd67 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md @@ -1,7 +1,7 @@ --- title: Using local sandboxing shortTitle: Use local sandboxing -intro: 'Enable local sandboxing so that {% data variables.copilot.copilot_cli_short %} runs the commands and tools it invokes on your behalf inside an operating-system sandbox.' +intro: 'Enable local sandboxing to restrict what {% data variables.product.prodname_copilot_short %} can access on your machine in {% data variables.copilot.copilot_cli_short %} or {% data variables.product.prodname_vscode_shortname %}.' versions: feature: copilot contentType: how-tos @@ -12,36 +12,45 @@ docsTeamMetrics: - copilot-cli --- -> [!NOTE] -> {% data reusables.cli.public-preview-local-sandbox %} +## Introduction + +Local sandboxing restricts access to files, network resources, and credentials on your machine. This article explains how to enable and disable local sandboxing in {% data variables.copilot.copilot_cli_short %} and the {% data variables.copilot.github_copilot_app_short %}. For a conceptual overview of cloud and local sandboxes for {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). For information on adjusting sandbox settings, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). -{% data reusables.cli.sandbox-on-windows %} +For information on using local sandboxing in {% data variables.product.prodname_vscode %}, see [Sandbox agent terminal commands](https://code.visualstudio.com/docs/agents/run/agent-sandboxing) in the {% data variables.product.prodname_vscode_shortname %} documentation. -## About local sandboxing +## Prerequisites -Sandboxing is currently an experimental feature. To use it, start {% data variables.copilot.copilot_cli_short %} with the `‑‑experimental` command line option, or enter `/experimental on` during a session. +{% data reusables.cli.local-sandboxing-prereqs %} + +## Using local sandboxing in {% data variables.copilot.copilot_cli_short %} When you enable local sandboxing, {% data variables.copilot.copilot_cli_short %} runs most of the commands and tools it invokes on your behalf inside an operating-system sandbox. After you enable local sandboxing, it is used for all your {% data variables.copilot.copilot_cli_short %} sessions until you disable it, or turn it off for a specific session. If enterprise managed settings require sandboxing, ordinary configuration and the `--no-sandbox` command line option cannot disable it. However, if the effective policy permits sandbox bypass, you can explicitly disable sandboxing for the rest of the current session, either from an active bypass permission prompt or by running `/sandbox disable`. This session opt-out does not loosen the saved policy. -By default, sandboxed commands and tools can write within your current working directory and temporary folders. Your user profile (home) directory, along with system and tool locations are read-only. Other disk locations are blocked. In a Git repository, the rest of the repository above your current working directory is readable but not writable. Access to your local and private network is permitted, as is outbound internet access. +By default, sandboxed commands and tools can write within your current working directory and temporary folders. In a Git repository, the repository's Git metadata is also writable, while the rest of the repository above your current working directory is readable but not writable. Selected system and developer-tool locations are readable, and some build and package caches are writable. This does not grant access to your entire home directory. Other paths are blocked unless you grant access. + +Outbound internet access is on by default. Local network access is off. How these settings affect commands depends on your operating system. See [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings#configuring-network-settings). -By default, authenticated Git and {% data variables.product.prodname_cli %} (`gh`) operations continue to work inside the sandbox, because {% data variables.copilot.copilot_cli_short %} makes your {% data variables.product.github %} credentials available to sandboxed commands. This allows actions such as `git push` and `gh pr create` to succeed. You can turn this off in your sandbox settings. +Authentication for Git and {% data variables.product.prodname_cli %} (`gh`) is enabled by default, but operations such as `git push` and `gh pr create` depend on your network settings and tool compatibility. Sandboxed commands and scripts receive placeholder Git and `gh` credentials. A local proxy replaces these with your real credentials only for approved HTTPS destinations. + +Git credentials retain their original host, port, and repository path restrictions. For `gh`, credentials are used only for `github.com`, `api.github.com`, and `uploads.github.com`. You can turn authentication off on the **Credentials** tab in `/sandbox config`. + +On Windows, this requires a version that supports connections from the sandbox to services on your computer (host loopback). You must also enable **Allow local network** on the **Network** tab in `/sandbox config`. This also permits private-network access, not just access to the credential proxy. For a conceptual overview of sandboxing in {% data variables.copilot.copilot_cli_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). -## Sandbox commands +### Sandbox commands You manage local sandboxing from within a {% data variables.copilot.copilot_cli_short %} session using the `/sandbox` slash command. It has the following subcommands. | Command | Description | | --- | --- | | `/sandbox status` | Show whether sandboxing is currently being used for the session. See [Checking whether sandboxing is being used](#checking-whether-sandboxing-is-being-used). | -| `/sandbox policy` | Show the effective filesystem policy for the current directory—the paths that are readable, writable, or blocked, and the network access in force. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). | +| `/sandbox policy [COMMAND]` | Show the effective paths, network settings, and capabilities for the current directory. Optionally include a command to inspect the developer-tool access it would receive, without running it. For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). | | `/sandbox config` | Open the interactive settings interface. Entering `/sandbox` on its own does the same thing. For more information, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). | | `/sandbox enable` | Turn local sandboxing on. See [Enabling local sandboxing](#enabling-local-sandboxing). | | `/sandbox disable` | Turn local sandboxing off. If enterprise managed settings require sandboxing, this is refused unless the effective policy permits sandbox bypass, in which case it disables sandboxing for the rest of the current session only. See [Disabling local sandboxing](#disabling-local-sandboxing). | -## Enabling local sandboxing +### Enabling local sandboxing To enable local sandboxing, enter the following command in an interactive {% data variables.copilot.copilot_cli_short %} session: @@ -59,7 +68,7 @@ After you enable local sandboxing, it continues to be used for the current and f > * Close the session and restart it, for example by running `copilot --continue`. > * Enter `/sandbox enable`. -## Disabling local sandboxing +### Disabling local sandboxing If enterprise managed settings require sandboxing, `/sandbox disable` is refused unless the effective policy permits sandbox bypass. When bypass is permitted, running `/sandbox disable`—or responding to an active bypass permission prompt—disables sandboxing for the rest of the current session only, without loosening the saved policy. @@ -69,11 +78,11 @@ To stop using local sandboxing, enter the following command in an interactive {% /sandbox disable ``` -Sandboxing is no longer used in the current session, or in new and restarted sessions. +Unless enterprise managed settings require sandboxing, this turns it off in the current session and in new and restarted sessions. Under a managed policy that permits bypass, it turns sandboxing off only for the current session. -Your choice of whether to use local sandboxing is saved as the `sandbox.enabled` setting in your personal settings file for the CLI (`~/.copilot/settings.json` by default). +An ordinary enable or disable command saves your choice as `sandbox.enabled` in your personal settings file (`~/.copilot/settings.json` by default). A managed session-only opt-out does not change this file. Run `/sandbox enable` to restore sandboxing in that session. -## Using sandboxing for a single session +### Using sandboxing for a single session You can use the `--sandbox` command line option to use sandboxing for a single session, without enabling sandboxing for your other sessions. If sandboxing is already enabled, you can disable it for a single session by using the `--no-sandbox` option. The `--no-sandbox` option cannot override enterprise managed settings that require sandboxing. @@ -83,13 +92,15 @@ You can combine these options with the `-p` command line option to control sandb copilot --sandbox -p "PROMPT" ``` -## Running a single command outside the sandbox +### Running a single command outside the sandbox + +When the sandbox blocks a command, {% data variables.product.prodname_copilot_short %} can ask you to approve another attempt with broader access. The prompt describes the command and the proposed retry. You can approve it, keep the blocked result, or disable sandboxing for the rest of the current session. Disabling sandboxing for the session is available only if the effective policy permits sandbox bypass. When it is permitted, you can also do this at any time by running `/sandbox disable`. -When a command needs broader access than the sandbox allows, {% data variables.product.prodname_copilot_short %} can request to run that single command outside the sandbox. You are shown a confirmation prompt describing the command. You can approve that single command, keep it inside the sandbox, or disable sandboxing for the rest of the current session. Disabling sandboxing for the session is available only if the effective policy permits sandbox bypass. When it is permitted, you can also do this at any time by running `/sandbox disable`. +Bypass requests are enabled by default and can be turned off in your sandbox settings. -This behavior is enabled by default and can be turned off in your sandbox settings. +The sandbox is only one of the reasons a command can fail. {% data variables.product.prodname_copilot_short %} offers a retry with broader access only when the sandbox is the likely cause and running outside it could actually help. Other failures show no bypass prompt. For platform-specific retry behavior, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings#allowing-sandbox-bypass). -## Checking whether sandboxing is being used +### Checking whether sandboxing is being used To check whether local sandboxing is being used for the current session, enter: @@ -107,6 +118,109 @@ You can also see sandbox status at a glance in the status line, which contains ` 1. Move the selection down the list of options to **sandbox**. 1. Press Enter to toggle the setting so that it shows a check mark. +### Troubleshooting + +Use the following guidance to troubleshoot blocked commands, PowerShell and Git problems on Windows, and authentication failures. + +#### Troubleshooting blocked commands + +If a command cannot access a file, use a tool, or connect to a host, check the sandbox policy before granting broader access. + +1. Run `/sandbox status` to confirm whether sandboxing is on for the current session. +1. Run `/sandbox policy` to inspect the effective policy. To see the additional paths available to tools used by a command, include the command after `/sandbox policy`. For example: + + ```shell copy + /sandbox policy npm install + ``` + + This previews the policy without running `npm install`. Review the listed paths and network settings. Check **Notes** for settings that could not be applied. + +1. If the policy blocks access you intend to allow, use `/sandbox config` to update the required path or host rules. Grant only the access the command needs. For missing paths and symbolic links, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing#troubleshooting-filesystem-access). Adding a directory with `/add-dir` does not grant sandbox access. +1. If the setting is managed by your organization, contact your administrator. If the error names a missing operating-system feature or Linux dependency, address that requirement, then restart {% data variables.copilot.copilot_cli_short %} before trying again. +1. Ask {% data variables.product.prodname_copilot_short %} to run the command again. If a one-command bypass is offered, approve it only if you are comfortable with the broader access described. Disabling sandboxing for the whole session gives subsequent commands broader access, not just the blocked command. + +#### Troubleshooting blocked paths that do not exist + +Your sandbox settings can block access to specific files or directories. If a blocked path does not exist on your computer, {% data variables.copilot.copilot_cli_short %} creates a directory at that location before starting a sandboxed command. It also creates any missing parent directories. These directories are not automatically removed afterward. + +For example, if you block access to `.env` before that file exists, {% data variables.copilot.copilot_cli_short %} creates a directory named `.env`, not a file. + +* If the blocked path is intended to be a file, create that file outside the sandbox before running a sandboxed command. +* If you see `Failed to prepare denied sandbox path`, the command has not started. Check that the configured path is correct and that your account has permission to create directories there. Use `/sandbox config` to correct an unintended path, or contact your administrator if the setting is managed. + +Running `/sandbox policy` does not create these directories. On Linux, paths that do not yet exist are omitted from the effective policy shown in the preview. They remain in your configured settings. + +#### Troubleshooting PowerShell and Git on Windows + +On Windows installations without the required updates, sandboxed PowerShell may report a drive root, such as `C:\`, as its current directory. `Set-Location` and Git commands that rely on the current directory can fail even though PowerShell starts. + +1. Install the September 2026 update or later for a supported Windows version. If your organization manages Windows updates, contact your administrator. +1. If you cannot update immediately, ask {% data variables.product.prodname_copilot_short %} to use an absolute repository path for Git commands. For example: + + ```shell copy + git -C "C:\PATH\TO\REPOSITORY" status + ``` + + This avoids relying on PowerShell's current directory. The sandbox must still allow access to the repository. It does not fix other filesystem or authentication failures. + +#### Troubleshooting authentication + +When credential masking is enabled, {% data variables.copilot.copilot_cli_short %} uses a local proxy to add the real credentials to outgoing requests. Tools using those credentials must support the proxy and trust its security certificate. + +{% data variables.copilot.copilot_cli_short %} automatically supplies a temporary certificate bundle to sandboxed tools. Some tools do not use this bundle and may report certificate or authentication errors. + +On macOS and Windows, you can optionally install the proxy's certificate authority in your operating system's trust store to improve compatibility. In a {% data variables.copilot.copilot_cli_short %} session, run `/sandbox ca create`, then `/sandbox ca trust`. On Windows, installing the certificate requires administrator approval. This also changes certificate trust for applications outside {% data variables.copilot.copilot_cli_short %}. + +Installing the certificate does not resolve every compatibility problem. Tools that require HTTP/2, accept only specific server certificates (certificate pinning), use client certificates, or use credentials to sign requests may still fail. + +## Using local sandboxing in the {% data variables.copilot.github_copilot_app_short %} + +Depending on any enterprise managed settings that may apply, you can use slash commands to enable or disable the local sandbox for the currently active session. + +### Enabling and disabling sandboxing for your session + +To turn on local sandboxing, enter: + +```text +/sandbox on +``` + +To turn off sandboxing, enter: + +```text +/sandbox off +``` + +These commands turn sandboxing on or off immediately, unless enterprise managed settings prevent the change. Your choice applies to the current session, including after a restart, and takes precedence over the project default. It does not change the project default for other sessions. + +When local sandboxing is off, agent-run commands can access the same files, networks, and credentials as your user account. + +You cannot use local sandboxing for a cloud sandbox session or a session that runs on a remote host. + +> [!NOTE] +> * If you enter either of the above commands before a session starts—for example, by clicking **New**, selecting a project, and then entering the command—the command changes the default sandboxing setting for the selected project. Alternatively, you can set the default in your settings. See [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings#enabling-local-sandboxing-for-a-project). +> * Unlike in the CLI, entering `/sandbox` without `on` or `off` does not open a configuration interface. + +### Running a tool outside the sandbox + +If a tool needs access that the sandbox policy does not allow, the app can display a **Run outside the sandbox?** prompt. Depending on the effective policy, you can: + +* Cancel the operation. +* Run the operation once outside the sandbox. +* Disable sandboxing for the remainder of the current session and run the operation. + +To disable sandboxing from this prompt, click **More options**, then **Disable sandbox and run**, and confirm your choice. + +If you disable sandboxing from this prompt, the app displays **Sandbox off for this session**. Click **Re-enable sandbox** to turn it back on. + +Temporarily disabling sandboxing does not change the project default or the session's saved setting. It ends when the session restarts or reattaches. + +An enterprise owner can prevent users from running tools outside the sandbox. For more information, see [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox). + + + + + ## Further reading * [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) diff --git a/content/copilot/how-tos/github-copilot-app/agent-sessions.md b/content/copilot/how-tos/github-copilot-app/agent-sessions.md index e05ade0c17d7..391aa02bbdcb 100644 --- a/content/copilot/how-tos/github-copilot-app/agent-sessions.md +++ b/content/copilot/how-tos/github-copilot-app/agent-sessions.md @@ -63,14 +63,14 @@ Use **Manage sessions** to view, search, and filter sessions and chats, includin ## Using cloud and local sandboxes > [!NOTE] -> {% data reusables.cli.public-preview-sandbox %} +> {% data reusables.cli.public-preview-cloud-sandbox %} Cloud and local sandboxes protect sessions in different ways: * **Cloud sandbox**: Runs the entire session in an isolated environment hosted by {% data variables.product.github %}. Use a cloud sandbox when you want to keep the session off your machine or run several resource-intensive tasks in parallel. Choose the cloud sandbox execution location when starting a session. * **Local sandbox**: Runs the session on your machine, but restricts the filesystem, network, and credential access available to agent-run tools. Use local sandboxing when the agent needs your local tools or development services, but you want to limit its access to the rest of your machine. Configure the default for new local repository and working tree sessions in the project settings, or use `/sandbox on` or `/sandbox off` to change an active local session. -Local sandboxing does not apply to cloud sandbox sessions or sessions that run on a remote host. For more information about how both types of sandbox work, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). To enable and configure local sandboxing, see [AUTOTITLE](/copilot/how-tos/github-copilot-app/configure-local-sandboxing). +Local sandboxing does not apply to cloud sandbox sessions or sessions that run on a remote host. For more information about how both types of sandbox work, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). To enable local sandboxing, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). ## Using `/security-review` in app sessions diff --git a/content/copilot/how-tos/github-copilot-app/configure-local-sandboxing.md b/content/copilot/how-tos/github-copilot-app/configure-local-sandboxing.md deleted file mode 100644 index f7b9c49116c0..000000000000 --- a/content/copilot/how-tos/github-copilot-app/configure-local-sandboxing.md +++ /dev/null @@ -1,132 +0,0 @@ ---- -title: Configuring local sandboxing in the GitHub Copilot app -shortTitle: Configure local sandboxing -intro: 'Use the `/sandbox` slash command and project settings in the {% data variables.copilot.github_copilot_app %} to control how local sandboxing restricts filesystem access, network connectivity, and credential use.' -product: '{% data reusables.gated-features.github-app %}
Download {% data variables.copilot.github_copilot_app %} {% octicon "link-external" height:16 %}' -versions: - feature: copilot -contentType: how-tos -category: - - Configure Copilot ---- - -> [!NOTE] -> {% data reusables.cli.public-preview-local-sandbox %} - -## About local sandboxing - -Local sandboxing runs the tools that an agent invokes on your behalf inside an operating-system sandbox. This reduces the potential impact of an unintended command by limiting access to files, network resources, and credentials on your machine. - -You configure local sandboxing separately for each project in the {% data variables.copilot.github_copilot_app %}. The configuration applies to local repository and working tree sessions. It does not apply to cloud sandbox sessions or sessions that run on a remote host. - -A working tree keeps the branches and files for concurrent sessions separate, but it does not restrict what a command can access elsewhere on your machine. Local sandboxing provides that additional protection. - -For an overview of cloud and local sandboxing for {% data variables.product.prodname_copilot_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). - -## Enabling local sandboxing in a project - -Local sandboxing is turned off by default. To enable it for new local sessions in a project: - -1. Open the app settings. -1. Select the project that you want to configure. -1. Under **Sandbox**, turn on **Sandbox new sessions**. - -The setting applies to new sessions in the project. It does not change a session that is already running. - -For most projects, start with the default policy. It allows common development tasks such as installing dependencies, connecting to a local development server, pushing a branch, and creating a pull request. Add restrictions when the project is next to sensitive folders, does not need network access, or should not use your credentials. - -## Configuring the sandbox policy for a project - -A sandbox policy is a set of rules that controls which files, networks, and credentials agent-run tools can access. The project settings describe the policy that the app requests when a sandboxed session starts. The effective policy can be more restrictive, for example, when enterprise managed settings apply. - -In the project settings, you can configure: - -* [**Filesystem access**](#configuring-filesystem-access): Grant additional read-only or read/write access to specific paths, or deny paths. -* [**Network access**](#configuring-network-access): Allow or block outbound internet and local network access. -* [**Credentials**](#configuring-credentials): Choose whether your Git and {% data variables.product.prodname_cli %} credentials are available inside the sandbox. - -### Configuring filesystem access - -By default, a sandboxed session has read/write access to its workspace and current working directory. You can grant access to additional folders or prevent access to specific folders. - -In the **Sandbox** section of the project settings, configure any of the following lists: - -* **Additional read/write**: Folders that agent-run tools can read and modify. -* **Additional read-only**: Folders that agent-run tools can read but not modify. -* **Denied**: Folders that agent-run tools cannot access. - -To add a folder, click **Add folder** for the appropriate list, then choose the folder. To remove a folder, click the delete icon next to its path. - -A more-specific denied folder remains denied when a broader parent folder has read or write access. - -On Windows, you can save a denied path in the project settings. If the active Windows sandbox capabilities cannot guarantee the denial, a sandboxed command fails with an unsupported-policy message. The command does not run with the denied path accessible or without a sandbox. - -### Configuring network access - -By default, sandboxed sessions can connect to the internet and your local network. In the **Sandbox** section of the project settings, you can change the following settings: - -* **Outbound internet**: Allow connections to internet services, such as {% data variables.product.github %} and package registries. -* **Local network**: Allow loopback and local-network connections, including connections to local development servers. - -Network restrictions can affect package installation, API calls, preview servers, and other tools that need a network connection. - -On Linux, the sandbox cannot control local network access independently for spawned processes, such as shell commands and local MCP or LSP servers. The setting still applies to in-process operations, such as web requests and remote MCP connections. - -### Configuring credentials - -By default, authenticated Git and {% data variables.product.prodname_cli %} operations are available inside the sandbox. You can turn off either of the following settings: - -* **Git credentials**: Allow authenticated HTTPS Git operations. -* **{% data variables.product.prodname_cli %} credentials**: Allow {% data variables.product.prodname_cli %} to authenticate. - -Turning off credential access can prevent operations such as pushing a branch or creating a pull request from inside the sandbox. - -## Applying policy changes - -Changes to filesystem, network, and credential settings apply to new sessions or when an existing session restarts. They do not change the policy of a currently running session. - -To restart a session while keeping its history, enter: - -```text -/restart-session -``` - -The app accepts sandbox settings before checking whether your operating system can enforce them. Support is checked when the first sandboxed shell starts. If the host cannot enforce the requested policy, the shell fails with an unsupported-platform or unsupported-policy message and does not run unsandboxed. To find the currently supported Windows versions, see [Windows OS support for Copilot sandboxing](https://aka.ms/ghcp-sandbox-os-support). - -If the app displays **Sandbox unavailable**, address the reported problem, then click **Retry sandbox**. - -## Changing sandboxing for a session - -To turn on local sandboxing for an active session, enter: - -```text -/sandbox on -``` - -To turn it off for the session, enter: - -```text -/sandbox off -``` - -During an active local session, the command creates a persistent override for that session and applies it immediately. The override does not change the project default for other sessions. - -If you enter either command before a session starts, the command changes the project default inherited by new sessions. - -When local sandboxing is off, agent-run commands can access the same files, networks, and credentials as your user account. - -You cannot use local sandboxing for a cloud sandbox session or a session that runs on a remote host. - -## Running a tool outside the sandbox - -If a tool needs access that the sandbox policy does not allow, the app can display a **Run outside the sandbox?** prompt. Depending on the effective policy, you can: - -* Cancel the operation. -* Run the operation once outside the sandbox. -* Disable sandboxing for the remainder of the current session and run the operation. - -If you disable sandboxing from this prompt, the app displays **Sandbox off for this session**. Click **Re-enable sandbox** to turn it back on. - -Temporarily disabling sandboxing does not change the project default or the session override. It ends when the session restarts or reattaches. - -An enterprise owner can prevent users from running tools outside the sandbox. For more information, see [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox). diff --git a/content/copilot/how-tos/github-copilot-app/index.md b/content/copilot/how-tos/github-copilot-app/index.md index a11e6138bb4b..9e1437367da0 100644 --- a/content/copilot/how-tos/github-copilot-app/index.md +++ b/content/copilot/how-tos/github-copilot-app/index.md @@ -19,7 +19,6 @@ children: - /customize-github-copilot-app - /agent-sessions - /computer-use - - /configure-local-sandboxing - /working-with-canvas-extensions - /managing-issues-and-pull-requests - /using-automations diff --git a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md index 474fc624ec19..ec13c7a5a532 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -601,7 +601,7 @@ These are the slash commands you can use from within an interactive CLI session. | `/resume [SESSION-ID]`, `/continue [SESSION-ID]` | Switch to a different session by choosing from a list (optionally specify a session ID). | | `/review [PROMPT]` | Run the code review agent to analyze changes. See [AUTOTITLE](/copilot/how-tos/copilot-cli/use-copilot-cli/agentic-code-review). | | `/rubber-duck [PROMPT]` | Consult the rubber duck agent for a second opinion on plans, code, and tests. See [AUTOTITLE](/copilot/concepts/agents/copilot-cli/rubber-duck). | -| `/sandbox [config\|status\|policy\|enable\|disable]` | Manage OS-level sandboxing that restricts filesystem and network access for shell commands, MCP/LSP servers, and built-in file/web tools. `config` (or bare `/sandbox`) opens the sandbox settings dialog. `status` shows whether sandboxing is enabled. `policy` shows the effective policy, with path grants grouped by source (user-configured, system, working directory, current session, and `~/.copilot`) and access type, plus the network stance and any detected developer tools. `enable`/`disable` turn sandboxing on or off directly. `status` and `policy` are read-only and can run while the agent is busy processing a turn. `config`, `enable`, and `disable` are queued until the turn finishes. {% data reusables.copilot.experimental %} | +| `/sandbox [config\|status\|policy [COMMAND]\|enable\|disable]` | Manage sandbox restrictions on filesystem and network access. `config` (or bare `/sandbox`) opens the settings dialog. `status` shows whether sandboxing is enabled for the current session. When sandboxing is enabled, `policy` shows path grants and restrictions grouped by source and access type, network settings, developer-tool access, and sandbox capabilities. Optionally add a command, such as `/sandbox policy npm install`, to inspect its developer-tool access without running it. `enable` and `disable` normally update your saved setting. If your organization requires sandboxing, `disable` is refused unless bypass is allowed. In that case, disabling applies only to the current session. | | `/sandbox ca [create\|trust\|rotate\|remove]` | Manage the sandbox's proxy certificate authority. `create` writes it without trusting it. `trust` adds it to OS trust. `rotate` replaces it while preserving its trust state. `remove` drops OS trust. See [Using `copilot sandbox ca`](#using-copilot-sandbox-ca) to run the same operations outside a session, for example on managed devices. | | `/search [QUERY]`, `/find [QUERY]` | Search the conversation timeline. | | `/security-review [PROMPT]` | Run a focused security review of active local code changes and return prioritized vulnerability findings with remediation suggestions. This command is not a full repository security audit. | @@ -730,8 +730,8 @@ Use `/collect-debug-logs [file|gist|share] [PATH]` to gather debug logs for trou | `--screen-reader` | Enable screen reader optimizations. | | `--secret-env-vars=VAR ...` | Redact an environment variable from shell and MCP server environments (can be used multiple times). For multiple variables, use a quoted, comma-separated list. The values in the `GITHUB_TOKEN` and `COPILOT_GITHUB_TOKEN` environment variables are redacted from output by default. | | `--session-id ID` | Use an exact session or task ID when you do not want `--resume`'s broader matching by ID prefix or session name. If the ID matches an existing session or task, that session or task is resumed. If nothing matches, a new session is created only when the value is a valid UUID. Names and ID prefixes do not create new sessions. Do not combine this option with other session-selection or session-starting options such as `--resume`, `--continue`, or `--connect`, because they compete to decide which session to open or create. | -| `--sandbox` | Enable the OS-level shell sandbox for this session only, without changing your saved sandbox setting. Useful with `-p`. {% data reusables.copilot.experimental %} | -| `--no-sandbox` | Disable local sandboxing for this session only, without changing your saved sandbox setting. This option is ignored if an enterprise-managed policy has been configured to enforce sandboxing. {% data reusables.copilot.experimental %} | +| `--sandbox` | Enable the OS-level shell sandbox for this session only, without changing your saved sandbox setting. Useful with `-p`. | +| `--no-sandbox` | Disable local sandboxing for this session only, without changing your saved sandbox setting. This option is ignored if an enterprise-managed policy has been configured to enforce sandboxing. | | `--share=PATH` | Share a session to a Markdown file after completion of a programmatic session (default path: `./copilot-session-.md`). | | `--share-gist` | Share a session to a secret {% data variables.product.github %} gist after completion of a programmatic session. | | `--stream=MODE` | Enable or disable streaming mode, which displays {% data variables.product.prodname_copilot_short %}'s response progressively as it is generated rather than waiting for the full response to arrive (mode choices: `on` or `off`, default: `on`). @@ -754,11 +754,11 @@ Plan-then-autopilot lets a session start in plan mode and automatically continue ### Enterprise-managed sandbox floor -An enterprise-managed policy can enforce OS-level shell sandboxing as a minimum floor. In other words, even if you pass `--no-sandbox`, the policy can still force sandboxing on. This is a policy override, not a failure of the flag itself. By contrast, `--sandbox` is unaffected because it only turns sandboxing on and never removes it. If the effective policy permits sandbox bypass, you can explicitly disable sandboxing for the rest of the current session while responding to an active bypass permission prompt. +An enterprise-managed policy can enforce OS-level shell sandboxing as a minimum floor. In other words, even if you pass `--no-sandbox`, the policy can still force sandboxing on. This is a policy override, not a failure of the option itself. By contrast, `--sandbox` is unaffected because it only turns sandboxing on and never removes it. If the effective policy permits sandbox bypass, you can explicitly disable sandboxing for the rest of the current session while responding to an active bypass permission prompt. When a managed floor forces sandboxing on with an effective `sandbox.allowBypass` of `true` (the default when a policy sets only `sandbox.enabled` to `true`), run `/sandbox disable` to opt out of the sandbox for the rest of the current session—no bypass prompt is required first. The opt-out is session-only: nothing is saved to `settings.json`, a new session starts sandboxed again, and `/sandbox enable` restores sandboxing immediately without waiting for a new session. If `allowBypass` is `false`, `/sandbox disable` refuses with a message that sandboxing is enforced by the managed policy and can't be disabled. -When a managed policy overrides your setting, the CLI shows a warning in the interactive timeline (or on stderr when using `-p`) so it is clear that the behavior comes from policy enforcement rather than the option failing to work. Contact your administrator if you need the policy changed. The `/sandbox` command is also registered whenever a managed policy forces sandboxing on, even without experimental features enabled, so you can still inspect the effective policy and status while the floor applies. {% data reusables.copilot.experimental %} +When a managed policy overrides your setting, the CLI shows a warning in the interactive timeline (or on stderr when using `-p`) so it is clear that the behavior comes from policy enforcement rather than the option failing to work. Contact your administrator if you need the policy changed. Use `/sandbox status` or `/sandbox policy` to inspect the session's effective restrictions. Adding the managed `sandbox.failIfUnavailable` setting set to `true`, alongside `sandbox.enabled` set to `true`, makes the sandbox mandatory when it cannot be established. Instead of falling back to running commands unsandboxed, {% data variables.product.prodname_copilot_short %} blocks model and tool execution if the policy can't be validated, compiled, or enforced by a usable sandbox backend. See [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox). @@ -987,7 +987,7 @@ For detailed information about hooks—including hook configuration formats, hoo MCP servers provide additional tools to the CLI agent. Configure persistent servers in `~/.copilot/mcp-config.json`. Use `--additional-mcp-config` to add servers for a single session. -Local (stdio) servers that spawn inside the sandbox (see the `/sandbox` slash command) show a `connected (sandboxed)` status in `copilot mcp list` and `/mcp list`, since remote (HTTP/SSE) servers are never sandboxed. {% data reusables.copilot.experimental %} +Local (stdio) servers that spawn inside the sandbox (see the `/sandbox` slash command) show a `connected (sandboxed)` status in `copilot mcp list` and `/mcp list`. Remote (HTTP/SSE) servers are not locally sandboxed, although their connections from the CLI can be restricted by the sandbox's network policy. `copilot mcp list` and `/mcp list` mark a disabled server with a `(disabled)` suffix in text output, or `"enabled": false` per server in `--json` output. `copilot mcp get` shows a `Status: Enabled`/`Disabled` line. @@ -1655,38 +1655,52 @@ export COPILOT_WEB_FETCH_ALLOW_LOCALHOST=1 When local sandboxing is enabled, {% data variables.copilot.copilot_cli_short %} discovers the tool directories a sandboxed command is likely to need and grants each one **read-only** access, so a command can run an installed toolchain without being able to modify it. Discovery runs for each command, before the process starts, and reads two kinds of source from the command's environment. * **`PATH`** (`Path` on Windows). Every directory listed is a candidate grant. -* **Named toolchain variables.** The CLI inspects the variables in the table below on every operating system. A variable that holds a single directory grants that directory; a variable that holds a path list is split on the operating system's path separator (`;` on Windows, `:` elsewhere), and each entry becomes a candidate grant. +* **Named toolchain variables.** The CLI inspects the variables in the table below. A directory value grants that directory. A path list is split on the operating system's path separator (a semicolon on Windows, a colon elsewhere), and each entry becomes a candidate grant. The Git file variables are inspected only on macOS and Linux. -A candidate is granted only when it is an absolute path that exists and resolves to a directory. Candidates are dropped—and the reason logged to the `sandbox_spawn` log target—when they are relative, do not exist, resolve to a filesystem root (such as `/` or `C:\`), or resolve under a system-critical location (`%WINDIR%` on Windows; `/bin`, `/sbin`, `/usr/bin`, `/usr/sbin`, `/boot`, `/proc`, `/sys`, and `/dev` on Linux and macOS). Symbolic links are resolved before these checks, and duplicate directories are removed (case-insensitively on Windows). +A directory candidate is granted only when it is an absolute path that exists as a directory. Relative paths, missing paths, filesystem roots (such as `/` or `C:\`), and system-critical locations are excluded from discovery. Examples of excluded locations are `%WINDIR%` on Windows and `/bin`, `/sbin`, `/usr/bin`, `/usr/sbin`, `/boot`, `/proc`, `/sys`, and `/dev` on macOS and Linux. The reason is logged to `sandbox_spawn`. + +These grants keep their path spelling rather than automatically adding a symbolic link's target. If access through a link is blocked, grant the intended target explicitly. Duplicate directories are removed, case-insensitively on Windows. | Variable | Toolchain | Value | Typically set on | |----------|-----------|-------|------------------| -| `PATH` / `Path` | Executables (all) | Path list | All | -| `PYTHONPATH` | Python | Path list | All | -| `PYTHONHOME` | Python | Single directory | All | -| `VIRTUAL_ENV` | Python (venv) | Single directory | All | -| `PYENV_ROOT` | Python (pyenv) | Single directory | All | +| `BAZEL_VC` | Bazel / Visual C++ | Single directory | Windows | +| `BAZEL_VS` | Bazel / Visual Studio | Single directory | Windows | +| `BAZELISK_HOME` | Bazelisk | Single directory | All | +| `BAZELISK_HOME_DARWIN` | Bazelisk | Single directory | macOS | +| `BAZELISK_HOME_LINUX` | Bazelisk | Single directory | Linux | +| `BAZELISK_HOME_WINDOWS` | Bazelisk | Single directory | Windows | | `CONDA_PREFIX` | Conda | Single directory | All | +| `DOTNET_ROOT` | .NET | Single directory | All | +| `GIT_CONFIG_SYSTEM` | Git system configuration | File | macOS and Linux | +| `GIT_EXEC_PATH` | Git helpers | Single directory | All | +| `GIT_SSL_CAINFO` | Git certificate bundle | File | macOS and Linux | +| `GIT_SSL_CAPATH` | Git certificates | Single directory | All | +| `GIT_TEMPLATE_DIR` | Git templates | Single directory | All | | `GOPATH` | Go | Path list | All | | `GOROOT` | Go | Single directory | All | -| `CARGO_HOME` | Rust (Cargo) | Single directory | All | -| `RUSTUP_HOME` | Rust (rustup) | Single directory | All | | `JAVA_HOME` | Java | Single directory | All | +| `LD_LIBRARY_PATH` | Shared libraries | Path list | Linux | | `NODE_PATH` | Node.js | Path list | All | | `NVM_HOME` | Node.js (nvm) | Single directory | Windows | | `NVM_SYMLINK` | Node.js (nvm) | Single directory | Windows | -| `DOTNET_ROOT` | .NET | Single directory | All | +| `PATH` / `Path` | Executables (all) | Path list | All | | `PSModulePath` | PowerShell | Path list | All | +| `PYENV_ROOT` | Python (pyenv) | Single directory | All | +| `PYTHONHOME` | Python | Single directory | All | +| `PYTHONPATH` | Python | Path list | All | +| `RUSTUP_HOME` | Rust (rustup) | Single directory | All | | `VCINSTALLDIR` | Visual C++ | Single directory | Windows | -| `VSINSTALLDIR` | Visual Studio | Single directory | Windows | | `VCPKG_ROOT` | vcpkg | Single directory | All | -| `LD_LIBRARY_PATH` | Shared libraries | Path list | Linux | +| `VIRTUAL_ENV` | Python (venv) | Single directory | All | +| `VSINSTALLDIR` | Visual Studio | Single directory | Windows | + +Except for the two Git file variables, each variable is read on every platform. The **Typically set on** column shows where each is normally populated. An unset variable contributes nothing. -Every variable is read on every platform; the **Typically set on** column shows where each is normally populated, not a restriction the CLI enforces. A variable that is unset simply contributes nothing. +`CARGO_HOME` is handled separately through tool-specific grants for selected Cargo directories and files. It does not grant access to the whole Cargo home. Developer-tool grants can also follow relocated caches, including Go and NuGet caches. -These are not the only read-only grants. {% data variables.copilot.copilot_cli_short %} also grants your user-profile application directories (`~/.local/bin` and `~/.local/lib` on Linux and macOS; the immediate subdirectories of `%LOCALAPPDATA%\Programs` on Windows), standard system and profile locations, and the caches and registries used by common package managers and toolchains (shown as **dev-tool access** in the `/sandbox policy` report). To see the fully resolved policy for your current directory—read/write, read-only, and denied paths—run `/sandbox policy` in a session. For the concepts behind how the policy is assembled, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). +These are not the only automatic grants. With **Allow dev tool access** enabled, {% data variables.copilot.copilot_cli_short %} grants selected user-profile application directories, including `~/.local/bin` and `~/.local/lib` on macOS and Linux and the immediate subdirectories of `%LOCALAPPDATA%\Programs` on Windows. It also grants tool-specific caches and registries, some of which are writable, such as npm's cache and shared build caches. -On Windows, `/sandbox policy` lists the directories on your `PATH` environment variable under **System** read-only grants; other developer-tool paths are grouped separately as detected project tool groups. +Run `/sandbox policy` to see the resolved paths grouped by source and access. The **Dev tools** section lists tools detected in the current directory and their paths. Add a command, such as `/sandbox policy npm install`, to inspect its developer-tool access without running it. The report does not create missing caches. For the concepts behind how the policy is assembled, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing). ## OpenTelemetry monitoring diff --git a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md index b8da1253bdc8..3a683cd6f483 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md @@ -499,12 +499,12 @@ These settings apply across all your sessions and repositories. You can use the | `sandbox.enabled` | `boolean` | `false` | Restrict shell commands, MCP/LSP servers, and built-in file/web tools to a sandboxed environment with limited file system and network access. Enable it from the `/sandbox` dialog or with `/sandbox enable`. | | `sandbox.auth.git` | `boolean` | `true` | Inject Git credentials into the sandbox so commands running inside it can authenticate with Git. Set to `false` to opt out. Renamed from `sandbox.gitAuth`; the old key has no migration and is ignored wherever it still appears. | | `sandbox.auth.gh` | `boolean` | `true` | Inject {% data variables.product.prodname_cli %} (`gh`) credentials into the sandbox so commands running inside it can authenticate with the {% data variables.product.prodname_cli %}. Set to `false` to opt out. Renamed from `sandbox.ghAuth`; the old key has no migration and is ignored wherever it still appears. | -| `sandbox.userPolicy.network.allowLocalNetwork` | `boolean` | `true` | Allow sandboxed commands to reach local network addresses (for example, local dev servers). Set to `false` to opt out. On Windows hosts whose ProcessContainer backend supports it, enabling this setting also lets a sandboxed command reach the host's loopback address (for example, `localhost`), matching macOS and Linux behavior. Older Windows versions keep host loopback denied even with this setting enabled. | -| `sandbox.userPolicy.network.proxy` | `object` | unset | Route sandboxed network traffic through an HTTP proxy. Fields: `url` (required), `username` (optional), `password` (optional). Configure it from the `/sandbox` dialog's **Network** tab, which masks the password field. The password itself is stored in the OS keychain rather than in `settings.json`, so it isn't editable via `/settings`. Enforcement differs by platform: on macOS the proxy is cooperative—{% data variables.copilot.copilot_cli_short %} sets `HTTP_PROXY`, `HTTPS_PROXY`, and `ALL_PROXY` in the sandbox, so only programs that honor those variables use it; on Linux it is strictly enforced through a private network namespace that permits only the proxy endpoint (the proxy must have an IPv4 address and must not embed credentials); on Windows the proxy is not supported, so a policy that sets it is rejected and the sandboxed command fails with an error. | -| `sandbox.userPolicy.network.allowedHosts` | `string[]` | `[]` | Hosts a sandboxed command is allowed to reach. Entries are exact hostnames, IP addresses, or `*.example.com` for strict subdomain matches (`*` matches every host). A non-empty list blocks any host that doesn't match. Configure from the `/sandbox` dialog's **Network** tab under **Host rules**. | +| `sandbox.userPolicy.network.allowLocalNetwork` | `boolean` | `false` | Control local network access, such as connections to local development servers. The effect on sandboxed commands depends on the operating system. On supported Windows hosts, enabling this setting also allows connections to the host's localhost. Older Windows versions keep localhost blocked even with this setting enabled. Windows proxying and host rules require this to be `true`. | +| `sandbox.userPolicy.network.proxy` | `object` | unset | Route sandboxed network traffic through an HTTP(S) proxy. Fields: `url` (required), `username` (optional), `password` (optional). The URL must not contain credentials. Configure credentials in the `/sandbox` dialog's **Network** tab, which masks the password field. Literal passwords use the OS credential store when available, with a local file fallback. `settings.json` holds a secret reference. The password can instead be a whole-field `${VAR}` or `$VAR` environment-variable reference. Proxy enforcement differs by platform, as described below. | +| `sandbox.userPolicy.network.allowedHosts` | `string[]` | `[]` | Hosts a sandboxed command is allowed to reach. Entries are exact hostnames, IP addresses, or `*.example.com` for subdomains but not the root domain (`*` matches every host). CIDR blocks are not supported. Do not include URLs or ports. A non-empty list blocks unmatched hosts, except for `localhost`, `127.0.0.1`, and `::1` when outbound and local network access are both enabled. These automatic entries do not change your saved list. Explicit deny rules and enterprise allowlists still apply. Configure from the `/sandbox` dialog's **Network** tab under **Host rules**. | | `sandbox.userPolicy.network.blockedHosts` | `string[]` | `[]` | Hosts a sandboxed command is denied from reaching, matched the same way as `allowedHosts`. `blockedHosts` always takes precedence over a matching `allowedHosts` entry, and denying a domain also denies its subdomains. Configure from the `/sandbox` dialog's **Network** tab under **Host rules**. | -| `sandbox.userPolicy.deniedPaths` | `string[]` | `[]` | Paths that sandboxed commands are denied access to. On Windows, the ProcessContainer (BaseContainer) backend cannot enforce per-path deny rules, so a policy that sets `deniedPaths` is rejected and the sandboxed command fails with an error—remove the denied paths, or use macOS or Linux, to run that policy. | -| `sandbox.userPolicy.seatbelt.keychainAccess` | `boolean` | `false` | macOS only. Grant sandboxed commands access to the system keychain. Can also be toggled from the `/sandbox` dialog. | +| `sandbox.userPolicy.filesystem.deniedPaths` | `string[]` | `[]` | Paths that sandboxed commands are denied access to. Windows requires a version that supports denied paths. If the host cannot enforce them, the command fails rather than running with weaker restrictions. Missing denied paths and their parents are created as directories before launch and are not automatically removed, even for a name such as `.env`. Preparation errors stop launch. The read-only `/sandbox policy` preview creates nothing and omits missing denied paths on Linux. | +| `sandbox.userPolicy.seatbelt.keychainAccess` | `boolean` | `false` | macOS only. Grant sandboxed commands access to the system keychain. Configurable only in `settings.json`, not through `/sandbox` or `/settings`. | | `screenReader` | `boolean` | `false` | Enable screen reader optimizations. | | `scrollbar` | `boolean` | `true` | Show the scrollbar in scrollable views. Set to `false` to hide it and use the full terminal width. | | `shellShortcut` | `boolean` | `true` | Let a lone `$` at the prompt, followed by Enter, open an interactive shell rooted at the session's working directory (activates only for a local, trusted, idle session on a real TTY). User- or managed-scoped only—not repo-overridable. | @@ -538,9 +538,13 @@ These settings apply across all your sessions and repositories. You can use the > [!TIP] > Run `copilot help sandbox` for the full sandbox reference, including supported hosts and all `sandbox` settings keys. -The `/sandbox` dialog groups `git`, `gh`, and keychain access under a dedicated **Auth** tab, and shows the `settings.json` path where the current sandbox configuration is stored. On the **Filesystem** tab, the configured path list is summarized by permission (for example, `2 read/write, 1 read-only`) behind a **Paths** row. Press Enter on that row to open the full list, which takes over the cursor and tab bar until you press Esc. Configured paths are displayed as absolute paths rather than `./`-relative or `~`-shortened forms. Typing `~/path` when adding a path still expands it to your home directory. Press Ctrl+E in the `/sandbox` dialog to save any pending changes and open `settings.json` in your editor (`COPILOT_EDITOR`, `VISUAL`, or `EDITOR`), matching the same shortcut in `/settings`. The dialog reloads its state from disk after you edit and save the file. +The `/sandbox` dialog groups Git authentication, `gh` authentication, and masked environment variables under a dedicated **Credentials** tab, and shows the `settings.json` path where the current sandbox configuration is stored. On the **Filesystem** tab, the configured path list is summarized by permission (for example, `2 read/write, 1 read-only`) behind a **User-configured paths** row. Press Enter on that row to open the full list, which takes over the cursor and tab bar until you press Esc. Configured paths are displayed as absolute paths rather than `./`-relative or `~`-shortened forms. Typing `~/path` when adding a path still expands it to your home directory. Press Ctrl+E in the `/sandbox` dialog to save any pending changes and open `settings.json` in your editor (`COPILOT_EDITOR`, `VISUAL`, or `EDITOR`), matching the same shortcut in `/settings`. The dialog reloads its state from disk after you edit and save the file. -`sandbox.userPolicy.network.allowedHosts` and `sandbox.userPolicy.network.blockedHosts` run through a built-in local proxy that enforces them strictly on every platform, unlike the cooperative `sandbox.userPolicy.network.proxy` setting on Linux and macOS. When both are configured, the local proxy uses `sandbox.userPolicy.network.proxy` as its upstream, so proxy credentials never reach the sandboxed child process. +Host rules and `sandbox.userPolicy.network.proxy` use a built-in local proxy. When both are configured, the local proxy applies the host rules before forwarding traffic to the upstream proxy. Upstream credentials stay outside the sandboxed child process. Host rules and proxy settings are inactive when outbound access is off. + +On macOS and Linux, the sandbox restricts direct connections so programs cannot avoid the proxy. On Windows, the sandbox relies on programs honoring the proxy settings. As a result, programs that ignore the proxy settings on Windows can connect directly and get around your host rules. Windows proxying and host rules also require a supported host and `allowLocalNetwork: true`, which permits private-network access. On Linux, proxy settings reject IPv6 address literals other than the `[::]` dual-stack wildcard. Use an IPv4 endpoint or a hostname with IPv4 support. + +Sandbox settings are user-level or enterprise-managed. They are not repository-overridable. For configuration steps and network limitations, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). Sandboxing is powered by [Microsoft eXecution Container (MXC)](https://github.com/microsoft/mxc), which provides platform-specific containment backends. {% data variables.copilot.copilot_cli_short %} uses Seatbelt on macOS, Bubblewrap on Linux, and ProcessContainer on Windows. diff --git a/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md b/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md index efb94bd980c2..6fd3fb498a2c 100644 --- a/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md +++ b/content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md @@ -10,7 +10,7 @@ category: - Configure Copilot --- -Use this reference to understand the currently supported keys in `{% data variables.copilot.managed_setting_file %}`. +Use this reference to understand enterprise managed settings for {% data variables.product.prodname_copilot_short %}. Most settings can be configured in `{% data variables.copilot.managed_setting_file %}`. Settings that require device management are noted below. For instructions on creating the file, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/use-managed-settings/get-started). @@ -34,11 +34,10 @@ For instructions on creating the file, see [AUTOTITLE](/copilot/how-tos/administ | `remoteControl` | Restricts whether sessions hosted on this device can be remotely controlled, based on the controlling client's SSO authorization status for the listed organizations. Doesn't affect the user's ability to remotely control sessions hosted on other devices | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | | `allowedMcpServers` | Defines an allowlist of MCP servers permitted to run. Any server not matched is blocked. Omit to allow all servers, subject to any deny rules | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | | `deniedMcpServers` | Defines MCP servers that are unconditionally blocked, even if they also match an entry in `allowedMcpServers` | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | -| `sandbox` | Enforces minimum local sandbox restrictions for command execution, filesystem and network access, credentials, and local MCP and LSP servers | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | +| `sandbox` | Enforces minimum local sandbox restrictions for command execution, filesystem and network access, credentials, and local MCP and LSP servers | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} (Agent Host, 1.138.0+) | {% octicon "check" aria-label="Supported" %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "x" aria-label="Not supported" %} | {% endrowheaders %} - ## Example configuration The following example shows these keys in one managed settings file. @@ -228,6 +227,16 @@ Set `autoTier` to a string other than `"unmanaged"` to lock the tier against use For example, a team settings file can set `"autoTier": "intelligence"`. If the team does not set `autoTier`, the enterprise default applies. +## forceRemoteSettingsRefresh + +Requires a fresh download of server-managed settings at startup in {% data variables.copilot.copilot_cli_short %} and {% data variables.product.prodname_vscode_shortname %}. Set `forceRemoteSettingsRefresh` to `true` to enable this requirement. + +In {% data variables.copilot.copilot_cli_short %}, this skips the normal one-hour cache and prevents fallback to an older cached policy if the download fails. An unsuccessful refresh leaves the policy unconfirmed, so affected operations are restricted. In {% data variables.product.prodname_vscode_shortname %}, {% data variables.product.prodname_copilot_short %} features are blocked until the required refresh succeeds. Users therefore need a network connection when starting the client. + +For the requirement to apply from a device's first startup, deliver it through device management or `{% data variables.copilot.managed_setting_file %}`. A server-delivered value can require refreshes on subsequent startups after the client has received it. Policy helper scripts cannot set this key. + +In `{% data variables.copilot.managed_setting_file %}`, use a JSON Boolean, for example `"forceRemoteSettingsRefresh": true`. When configuring {% data variables.copilot.copilot_cli_short %} through the Windows registry or macOS managed preferences, store this value as a string containing `true` or `false`. Do not use a DWORD or native Boolean. + ## permissions ### deny, ask, allow @@ -327,27 +336,32 @@ Each entry uses the same `serverName`, `serverUrl`, or `serverCommand` propertie ## `sandbox` -Enforces minimum local sandbox restrictions for {% data variables.copilot.copilot_cli_short %} and the {% data variables.copilot.github_copilot_app %}. Managed sandbox settings impose restrictions rather than defaults: +Enforces minimum local sandbox restrictions for {% data variables.copilot.copilot_cli_short %}, {% data variables.product.prodname_copilot_short %} Agent Host sessions in {% data variables.product.prodname_vscode_shortname %}, and the {% data variables.copilot.github_copilot_app %}. Managed sandbox settings impose restrictions rather than defaults: * For force-on settings, a managed value of `true` enforces the setting. `false` or omission leaves the user's configuration unchanged. * For capability settings, a managed value of `false` prohibits the capability. `true` or omission leaves the user's configuration unchanged. * Managed read/write and read-only path lists restrict user-configured grants, while managed denied paths add to user-configured denials. -In app sessions, the embedded runtime parses, combines, and enforces the complete managed `sandbox` object, including properties that are not available in the app's project settings. The app displays the user's project settings, not the complete effective managed policy, and does not show per-setting managed locks. +In {% data variables.product.prodname_vscode_shortname %} 1.138.0 and later, these settings apply to {% data variables.product.prodname_copilot_short %} sessions that use Agent Host's built-in sandbox. This support does not extend to every type of chat session or terminal in {% data variables.product.prodname_vscode_shortname %}. In {% data variables.product.prodname_vscode_shortname %} 1.140.0 and later, setting `sandbox.enabled` to `true` prevents users from turning sandboxing off with the session's sandbox toggle. If your policy permits bypass, users can still turn it off for the current session when responding to a sandbox-bypass permission prompt. This does not change your organization's policy. + +In {% data variables.copilot.github_copilot_app_short %} sessions, the embedded runtime parses, combines, and enforces the complete managed `sandbox` object, including properties that are not available in the app's project settings. The app displays the user's project settings, not the complete effective managed policy, and does not show per-setting managed locks. The following sub-properties are supported: -* `enabled`: `true` requires sandboxing by default. Users cannot disable it through their configuration. In {% data variables.copilot.copilot_cli_short %}, the `--no-sandbox` command line option and `/sandbox disable` command cannot override it. In the {% data variables.copilot.github_copilot_app %}, the project setting and `/sandbox off` command cannot override it. If the effective policy permits bypass, a user can still explicitly disable sandboxing for the rest of the current session from an active sandbox-bypass permission prompt. +* `enabled`: `true` requires sandboxing by default. Users cannot disable it through their configuration or the CLI's `--no-sandbox` option. In the {% data variables.copilot.github_copilot_app %}, the project setting and `/sandbox off` command cannot override it. If the effective policy permits bypass, a user can still disable sandboxing for the rest of the current session from an active sandbox-bypass permission prompt. In {% data variables.copilot.copilot_cli_short %}, they can also use `/sandbox disable` for this session-only opt-out. Neither changes the saved policy. * `failIfUnavailable`: `true`, combined with `enabled: true`, makes the managed sandbox mandatory. If {% data variables.product.prodname_copilot_short %} cannot validate, compile, or enforce the sandbox policy with an available sandbox backend, it blocks model and tool execution instead of allowing commands to fail or run unsandboxed. This property does not enable sandboxing by itself. * `allowBypass`: `false` prevents individual commands from running outside the sandbox and prevents users from disabling sandboxing for the rest of the current session from an active sandbox-bypass permission prompt. In {% data variables.copilot.copilot_cli_short %}, it also prevents users from disabling sandboxing with `/sandbox disable`. * `addCurrentWorkingDirectory`: `false` prevents the runtime from automatically adding the current working directory to the sandbox's read/write paths. * `sandboxMcpServers`: `true` requires local MCP servers started in the session to run in the sandbox. Remote MCP servers do not run in the local sandbox. * `sandboxLspServers`: `true` requires language servers started in the session to run in the sandbox. -* `gitAuth`: `false` prevents the runtime from injecting a {% data variables.product.github %} token for authenticated Git HTTPS operations in the sandbox. -* `ghAuth`: `false` prevents the runtime from injecting a {% data variables.product.github %} token for {% data variables.product.prodname_cli %} in the sandbox. +* `auth.git`: `false` prevents the runtime from injecting a {% data variables.product.github %} token for authenticated Git HTTPS operations in the sandbox. +* `auth.gh`: `false` prevents the runtime from injecting a {% data variables.product.github %} token for {% data variables.product.prodname_cli %} in the sandbox. * `allowDevToolAccess`: `false` prevents automatic access to development-tool configuration, caches, registries, and toolchains. These locations can contain package registry credentials or tokens. Disabling access can cause package restoration, authenticated registry operations, or builds that use shared caches to fail unless you explicitly grant the required paths. +* `learningMode`: Controls whether sandboxed commands on supported Windows hosts record blocked access or record and allow it. See [`sandbox.learningMode`](#sandboxlearningmode). * `userPolicy`: An object that configures filesystem, network, and macOS-specific Seatbelt restrictions. The supported properties are described in the following sections. +On an unsupported CLI host, server-managed `enabled: true` can be declined unless `failIfUnavailable: true` also requires enforcement. Native MDM, file-based managed settings, and policy-helper settings still enforce `enabled: true`, so sandboxed commands fail rather than running without a sandbox. When both `enabled` and `failIfUnavailable` are required, the CLI blocks model and tool execution if it cannot establish enforcement. Resolve the reported host or policy problem, then start a new session. + For server-managed enterprise team overrides, wrap the entire sandbox object in `overridable`: ```json @@ -363,6 +377,15 @@ For server-managed enterprise team overrides, wrap the entire sandbox object in The wrapper must be the only property directly inside `sandbox`. Individual sub-properties, such as `sandbox.enabled`, cannot use their own `overridable` wrappers. A team file's regular sandbox object replaces the entire wrapped default, so include every restriction that should remain. Omitting `sandbox` retains the enterprise default. +### `sandbox.learningMode` + +Controls access recording for sandboxed commands on Windows. This setting has no effect when sandboxing is off or the Windows host does not support access recording. + +* `"deny"` (default): Enforces filesystem and process restrictions and records blocked access. +* `"allow"`: Records and allows filesystem and process access that would otherwise be blocked. Network restrictions remain in place. This mode does not provide normal filesystem and process protection. + +The `"allow"` value is accepted only through native Windows device management, such as Intune or the Windows registry. It is ignored in `{% data variables.copilot.managed_setting_file %}`. A `"deny"` value from any managed source takes precedence. + ### `sandbox.userPolicy.filesystem` Configures filesystem access for sandboxed processes. Paths should be absolute. Managed grant lists are matched against user-configured lists by exact path string, not by parent or child path coverage. @@ -376,12 +399,12 @@ Configures filesystem access for sandboxed processes. Paths should be absolute. Configures network access for sandboxed processes. * `allowOutbound`: `false` blocks outbound network access. -* `allowLocalNetwork`: `false` prevents access to the local network. -* `allowedHosts`: An array of hostnames or IP addresses that sandboxed processes are allowed to reach. A non-empty list blocks hosts that do not match. Entries can be exact hostnames, exact IP addresses, `*.example.com` for subdomains, or `*` for every host. +* `allowLocalNetwork`: `false` restricts local network access. Its effect on sandboxed commands differs by operating system. Windows proxying and host rules require local network access, so a policy that combines them with `false` prevents those commands from starting. +* `allowedHosts`: An array of hostnames or IP addresses that sandboxed processes are allowed to reach. A non-empty list blocks hosts that do not match. Entries can be exact hostnames, exact IP addresses, `*.example.com` for subdomains but not the root domain, or `*` for every host. Do not include URLs or ports. User and managed allowlists are combined restrictively. If they have no overlapping hosts, all hosts are denied. * `blockedHosts`: An array of hostnames or IP addresses that sandboxed processes cannot reach. Blocked hosts take precedence over allowed hosts, and blocking a domain also blocks its subdomains. * `proxy`: An object that routes sandboxed network traffic through an upstream HTTP proxy. Set `proxy.url` to the proxy URL. Platform support and enforcement vary. -Network behavior varies by operating system. In particular, an upstream proxy is not a complete egress-control boundary because some applications can ignore proxy settings. +In {% data variables.copilot.copilot_cli_short %}, host rules and upstream proxies use a built-in local proxy. On macOS and Linux, the sandbox prevents programs from bypassing it with direct connections. On Windows, the sandbox relies on programs honoring the proxy settings. As a result, on Windows, these controls do not provide the same protection against direct connections. For platform requirements and limitations, see [Configuring network settings](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings#configuring-network-settings). ### `sandbox.userPolicy.seatbelt` diff --git a/content/copilot/reference/github-copilot-app-reference/slash-commands.md b/content/copilot/reference/github-copilot-app-reference/slash-commands.md index eebbfcc6cc52..6826c427680c 100644 --- a/content/copilot/reference/github-copilot-app-reference/slash-commands.md +++ b/content/copilot/reference/github-copilot-app-reference/slash-commands.md @@ -66,7 +66,7 @@ Some commands require specific context, such as an active session, session chang | `/restart-session` | **Requires an active session.** Restarts the current session and keeps its history. | | `/review` | **Requires an active session.** Reviews the current session's changes. | | `/rubber-duck [PROMPT]` | Requests critique on your approach or implementation by a model other than the one you have used in the session. See [AUTOTITLE](/copilot/how-tos/github-copilot-app/agent-sessions#using-the-rubber-duck-agent). | -| `/sandbox on` or `/sandbox off` | Enables or disables local sandboxing for the current session. If no session is active, changes the selected project's default for new sessions. Local sandboxing is not available for cloud sandbox or remote-host sessions. See [AUTOTITLE](/copilot/how-tos/github-copilot-app/configure-local-sandboxing#changing-sandboxing-for-a-session). | +| `/sandbox on` or `/sandbox off` | Enables or disables local sandboxing for the current session. If no session is active, changes the selected project's default for new sessions. Local sandboxing is not available for cloud sandbox or remote-host sessions. See [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing#using-local-sandboxing-in-the-copilot-app). | | `/security-review` | **Requires an active session with changes.** Runs a security-focused review against current diffs. See [AUTOTITLE](/copilot/how-tos/github-copilot-app/agent-sessions#using-security-review-in-app-sessions). | | `/skills` | Manages skills; use `/skills reload` to reload skills mid-session. | | `/spar [PROMPT]` | Runs adversarial reasoning to challenge your approach. | diff --git a/data/reusables/cli/local-sandboxing-prereqs.md b/data/reusables/cli/local-sandboxing-prereqs.md new file mode 100644 index 000000000000..a00a291efe55 --- /dev/null +++ b/data/reusables/cli/local-sandboxing-prereqs.md @@ -0,0 +1,2 @@ +* **Windows:** Local sandboxing on Windows requires Windows 11 version 25H2 with update [KB5124010](https://support.microsoft.com/en-us/servicing/os/windows-11/2026/09/kb5124010-windows-11-24h2-25h2-update) or later, or Windows 11 version 26H1 with update [KB5124006](https://support.microsoft.com/en-us/servicing/os/windows-11/2026/09/kb5124006-windows-11-26h1-update) or later, with support for the BaseContainer tier of the ProcessContainer backend. +* **Linux:** Bubblewrap (`bwrap`) version 0.5.0 or later, and `slirp4netns` must be installed and available on your PATH. diff --git a/data/reusables/cli/public-preview-local-sandbox.md b/data/reusables/cli/public-preview-cloud-sandbox.md similarity index 56% rename from data/reusables/cli/public-preview-local-sandbox.md rename to data/reusables/cli/public-preview-cloud-sandbox.md index 4167a20927d3..474a81e82626 100644 --- a/data/reusables/cli/public-preview-local-sandbox.md +++ b/data/reusables/cli/public-preview-cloud-sandbox.md @@ -1 +1 @@ -Local sandboxes for {% data variables.product.prodname_copilot %} are in {% data variables.release-phases.public_preview %} and subject to change. +Cloud sandboxes for {% data variables.product.prodname_copilot %} are in {% data variables.release-phases.public_preview %} and subject to change. diff --git a/data/reusables/cli/public-preview-sandbox.md b/data/reusables/cli/public-preview-sandbox.md deleted file mode 100644 index 7633a7a94222..000000000000 --- a/data/reusables/cli/public-preview-sandbox.md +++ /dev/null @@ -1 +0,0 @@ -Cloud and local sandboxes for {% data variables.product.prodname_copilot %} are in {% data variables.release-phases.public_preview %} and subject to change. diff --git a/data/reusables/cli/sandbox-on-windows.md b/data/reusables/cli/sandbox-on-windows.md deleted file mode 100644 index 33a5e512cec8..000000000000 --- a/data/reusables/cli/sandbox-on-windows.md +++ /dev/null @@ -1,2 +0,0 @@ -> [!IMPORTANT] -> Local sandboxing on Windows requires a Windows Insiders build. diff --git a/src/content-pipelines/config.yml b/src/content-pipelines/config.yml index 793621d6e6b8..0831f5abc3b3 100644 --- a/src/content-pipelines/config.yml +++ b/src/content-pipelines/config.yml @@ -23,13 +23,17 @@ copilot-cli: - content/copilot/reference/copilot-cli-reference/cli-programmatic-reference.md - content/copilot/reference/copilot-cli-reference/acp-server.md - content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md + - content/copilot/reference/github-copilot-app-reference/slash-commands.md - content/copilot/reference/hooks-reference.md + - content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md exclusions: - All mentions of, or information directly relating to, feature flags - enabledFeatureFlags configuration setting - COPILOT_CLI_ENABLED_FEATURE_FLAGS environment variable content-mapping: | content/copilot/reference/copilot-cli-reference/cli-plugin-reference.md covers only plugin-specific content. + content/copilot/reference/github-copilot-app-reference/slash-commands.md relates to the Copilot App specifically, not Copilot CLI. + In content/copilot/reference/enterprise-administrators/enterprise-managed-settings.md: only update information relating to Copilot CLI. All information relating to files in the ~/.copilot configuration directory, and settings in those files, should go in content/copilot/reference/copilot-cli-reference/cli-config-dir-reference.md. All reference details relating to hooks should go in content/copilot/reference/hooks-reference.md. All reference details relating to using Copilot CLI programmatically (e.g. command line options and environment variables) should go in content/copilot/reference/copilot-cli-referencecli-programmatic-reference.md. Tabular information (but not discursive explanatory text) about using the CLI programmatically should also go in the main content/copilot/reference/copilot-cli-reference/cli-command-reference.md article. From 98881a90f967339cb8a1da70f87677a62a3adfba Mon Sep 17 00:00:00 2001 From: Ria Gopu Date: Wed, 7 Oct 2026 19:40:51 +0000 Subject: [PATCH 2/4] Document Copilot code review setting to block external Copilot licenses (#63728) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Sophie <29382425+sophietheking@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: c0ff030a-2647-4a47-9826-d6f7c6a98a86 --- content/copilot/concepts/agents/code-review.md | 12 ++++++++++++ .../set-up-copilot/configure-code-review.md | 6 +++++- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/content/copilot/concepts/agents/code-review.md b/content/copilot/concepts/agents/code-review.md index 45f4cc6ecbf4..3da2b29f1371 100644 --- a/content/copilot/concepts/agents/code-review.md +++ b/content/copilot/concepts/agents/code-review.md @@ -110,6 +110,18 @@ For pull requests authored by {% data variables.copilot.copilot_cloud_agent %}, For pull requests authored by other bots, or when a bot requests the review, usage is billed directly to the organization. These pull requests are eligible for agentic review. +### Reviews requested with an external {% data variables.product.prodname_copilot_short %} license + +An external {% data variables.product.prodname_copilot_short %} license is one that is not provided by the organization or enterprise that owns the repository, such as a personal license or a license from another organization. By default, people can use an external license to request a review from {% data variables.product.prodname_copilot_short %}. + +To prevent this, organization owners and repository administrators can enable the **Only allow {% data variables.copilot.copilot_code-review_short %} to be triggered by authorized users** setting for an organization or a single repository. When the setting is enabled: + +* {% data variables.product.prodname_copilot_short %} is not offered as a reviewer to people who are not authorized, and API review requests from those people do not start a review. +* In personal repositories, only the repository owner or a direct collaborator can request a review. +* Automatic reviews from personal settings do not run for people who are not authorized. Automatic reviews configured by repository or organization rulesets still run. + +For configuration steps, see [AUTOTITLE](/copilot/how-tos/copilot-on-github/set-up-copilot/configure-code-review#customizing-copilot-code-review). + ### What happens when a budget is reached For {% data variables.copilot.copilot_business_short %} and {% data variables.copilot.copilot_enterprise_short %}, code review access is governed by budget controls. If a user reaches their user-level budget, or if the enterprise or cost center spending limit is exhausted, code reviews are blocked along with other {% data variables.product.prodname_ai_credits_short %}-consuming features. See [AUTOTITLE](/copilot/concepts/billing-and-usage/organizations-and-enterprises/budgets#what-happens-when-a-user-is-blocked). diff --git a/content/copilot/how-tos/copilot-on-github/set-up-copilot/configure-code-review.md b/content/copilot/how-tos/copilot-on-github/set-up-copilot/configure-code-review.md index 4350f97795ba..a632b9908be7 100644 --- a/content/copilot/how-tos/copilot-on-github/set-up-copilot/configure-code-review.md +++ b/content/copilot/how-tos/copilot-on-github/set-up-copilot/configure-code-review.md @@ -20,7 +20,7 @@ category: ## Introduction -You can configure {% data variables.copilot.copilot_code-review_short %} to review pull requests automatically, and you can set your {% data variables.product.prodname_copilot_short %} review effort. For an overview, see [AUTOTITLE](/copilot/concepts/agents/code-review#automatic-pull-request-reviews). +You can configure {% data variables.copilot.copilot_code-review_short %} to review pull requests automatically, set your {% data variables.product.prodname_copilot_short %} review effort, and control who can request reviews. For an overview, see [AUTOTITLE](/copilot/concepts/agents/code-review#automatic-pull-request-reviews). ## Configuring automatic code review for your own pull requests @@ -85,6 +85,8 @@ You can configure how {% data variables.copilot.copilot_code-review_short %} com > [!NOTE] > {% data reusables.copilot.automatic-approvals-public-preview %} +1. To prevent people from using an external {% data variables.product.prodname_copilot_short %} license to request reviews in this repository, enable **Only allow {% data variables.copilot.copilot_code-review_short %} to be triggered by authorized users**. If this setting is enabled for your organization, you cannot turn it off for the repository. See [AUTOTITLE](/copilot/concepts/agents/code-review#reviews-requested-with-an-external-copilot-license). + ## Configuring automatic code review for repositories in an organization You can enable automatic code reviews for repositories in your organization and customize how code reviews are performed. @@ -129,6 +131,8 @@ You can configure how {% data variables.copilot.copilot_code-review_short %} com > [!NOTE] > {% data reusables.copilot.automatic-approvals-public-preview %} +1. To prevent people from using an external {% data variables.product.prodname_copilot_short %} license to request reviews in your organization's repositories, enable **Only allow {% data variables.copilot.copilot_code-review_short %} to be triggered by authorized users**. This setting applies to every repository in the organization, and repository administrators cannot turn it off. + ## Configuring automatic code review for an enterprise You can enable automatic code reviews for your enterprise and customize how code reviews are performed. From d1a3effbebe44686297f72d0c97a81278b569a0e Mon Sep 17 00:00:00 2001 From: Hirsch Singhal <1666363+hpsin@users.noreply.github.com> Date: Wed, 7 Oct 2026 19:42:09 +0000 Subject: [PATCH 3/4] GitHub Apps updates omnibus (#63630) Co-authored-by: Laura Coursen --- ...github-apps-private-key-fingerprint-new.png | Bin 0 -> 97549 bytes ...best-practices-for-creating-a-github-app.md | 6 ++++++ ...ing-a-user-access-token-for-a-github-app.md | 17 +++++++++++++---- .../managing-private-keys-for-github-apps.md | 13 +++++++++---- .../refreshing-user-access-tokens.md | 10 +++++++++- .../choosing-permissions-for-a-github-app.md | 8 +++++++- .../making-a-github-app-public-or-private.md | 14 ++++++++++++++ ...stalling-a-github-app-from-a-third-party.md | 1 - ...wing-and-modifying-installed-github-apps.md | 2 ++ ...ub-app-access-requests-and-installations.md | 2 +- .../features/github-app-details-visibility.yml | 7 +++++++ data/features/github-app-offline-access.yml | 7 +++++++ ...-app-repository-permission-improvements.yml | 8 ++++++++ .../apps/repo-admin-install-restriction.md | 10 +++++++++- .../user-access-token-response-parameters.md | 6 +++--- 15 files changed, 95 insertions(+), 16 deletions(-) create mode 100644 assets/images/github-apps/github-apps-private-key-fingerprint-new.png create mode 100644 data/features/github-app-details-visibility.yml create mode 100644 data/features/github-app-offline-access.yml create mode 100644 data/features/github-app-repository-permission-improvements.yml diff --git a/assets/images/github-apps/github-apps-private-key-fingerprint-new.png b/assets/images/github-apps/github-apps-private-key-fingerprint-new.png new file mode 100644 index 0000000000000000000000000000000000000000..371a983bdacdbbf5f42288b6382127718f9d4d79 GIT binary patch literal 97549 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 VB4T@me-HSRl~j_b5Hkw+{{Zo(xxN4Z literal 0 HcmV?d00001 diff --git a/content/apps/creating-github-apps/about-creating-github-apps/best-practices-for-creating-a-github-app.md b/content/apps/creating-github-apps/about-creating-github-apps/best-practices-for-creating-a-github-app.md index fe4b29df4a07..16736c102e62 100644 --- a/content/apps/creating-github-apps/about-creating-github-apps/best-practices-for-creating-a-github-app.md +++ b/content/apps/creating-github-apps/about-creating-github-apps/best-practices-for-creating-a-github-app.md @@ -103,6 +103,12 @@ After signing in a user, app developers must take additional steps to ensure tha {% data variables.product.company_short %} strongly encourages you to use user access tokens that expire. If you previously opted out of using user access tokens that expire but want to re-enable this feature, see [AUTOTITLE](/apps/maintaining-github-apps/activating-optional-features-for-github-apps). +{% ifversion github-app-offline-access %} + +To test and gradually roll out support for expiring tokens, request the `offline_access` scope when you sign in a user. This scope gives you an expiring user access token and a refresh token for an individual authorization, even if your app is configured not to use expiring tokens. To confirm that you received an expiring token, check for the `expires_in` field in the token response. + +{% endif %} + Installation access tokens expire after one hour, expiring user access tokens expire after eight hours, and refresh tokens expire after six months. However, you can also revoke tokens as soon as you no longer need them. For more information, see [`DELETE /installation/token`](/rest/apps/installations#revoke-an-installation-access-token) to revoke an installation access token and [`DELETE /applications/{client_id}/token`](/rest/apps/oauth-applications#delete-an-app-token) to revoke a user access token. ## Cache tokens diff --git a/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.md b/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.md index 6b27d11f2d67..23f0f4f7bedb 100644 --- a/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.md +++ b/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app.md @@ -19,7 +19,7 @@ category: > {% data reusables.enterprise-data-residency.access-domain %} {% endif %} -A user access token is a type of OAuth token. Unlike a traditional OAuth token, the user access token does not use scopes. Instead, it uses fine-grained permissions. A user access token only has permissions that both the user and the app have. For example, if the app was granted permission to write the contents of a repository, but the user can only read the contents, then the user access token can only read the contents. +A user access token is a type of OAuth token. Unlike OAuth apps, GitHub Apps do not request scopes during authorization to decide which resources the resulting token can access. Instead, they use fine-grained permissions set on the application registration. A GitHub App user access token only has permissions that both the user and the app have. For example, if the app was granted permission to write the contents of a repository, but the user can only read the contents, then the user access token can only read the contents. Similarly, a user access token can only access resources that both the user and app can access. For example, if an app is granted access to repository `A` and `B`, and the user can access repository `B` and `C`, the user access token can access repository `B` but not `A` or `C`. You can use the REST API to check which installations and which repositories within an installation a user access token can access. For more information, see `GET /user/installations` and `GET /user/installations/{installation_id}/repositories` in [AUTOTITLE](/rest/apps/installations). @@ -42,6 +42,7 @@ If your app runs in the browser, you should use the web application flow to gene `client_id` | `string` | Required | The client ID for your {% data variables.product.prodname_github_app %}. The client ID is different from the app ID. You can find the client ID on the settings page for your app. For more information about navigating to the settings page for your {% data variables.product.prodname_github_app %}, see [AUTOTITLE](/apps/maintaining-github-apps/modifying-a-github-app-registration#navigating-to-your-github-app-settings). `redirect_uri` | `string` | Strongly recommended | The URL in your application where users will be sent after authorization. This must be a match to one of the URLs you provided as a "Callback URL" in your app's settings and can't contain any additional parameters. For more information, see [AUTOTITLE](/apps/creating-github-apps/registering-a-github-app/about-the-user-authorization-callback-url). `state` | `string` | Strongly recommended | When specified, the value should contain a random string to protect against forgery attacks, and it can also contain any other arbitrary data. +{% ifversion github-app-offline-access %} `scope` | `string` | Optional | To receive an expiring user access token and a refresh token for this authorization, set this value to `offline_access`. No other scopes are supported for {% data variables.product.prodname_github_apps %}. This parameter does not control permissions for the user access token.{% endif %} {% ifversion pkce_support %} `code_challenge` | `string` | Strongly recommended | Used to secure the authentication flow with PKCE (Proof Key for Code Exchange). Required if `code_challenge_method` is included. Must be a 43 character SHA-256 hash of a random string generated by the client. See the [PKCE RFC](https://datatracker.ietf.org/doc/html/rfc7636) for more details about this security extension. `code_challenge_method` | `string` | Strongly recommended | Used to secure the authentication flow with PKCE (Proof Key for Code Exchange). Required if `code_challenge` is included. Must be `S256` - the `plain` code challenge method is not supported.{% endif %} `login` | `string` | Optional | When specified, the web application flow will prompt users with a specific account they can use for signing in and authorizing your app. @@ -66,7 +67,9 @@ Before you can use the device flow, you must first enable it in your app's setti The device flow uses the [OAuth 2.0 Device Authorization Grant](https://datatracker.ietf.org/doc/html/rfc8628). -1. Send a `POST` request to `{% data variables.product.oauth_host_code %}/login/device/code` along with a `client_id` query parameter. The client ID is different from the app ID. You can find the client ID on the settings page for your app. For more information about navigating to the settings page for your {% data variables.product.prodname_github_app %}, see [AUTOTITLE](/apps/maintaining-github-apps/modifying-a-github-app-registration#navigating-to-your-github-app-settings). +1. Send a `POST` request to `{% data variables.product.oauth_host_code %}/login/device/code` along with a `client_id` query parameter. The client ID is different from the app ID. You can find the client ID on the settings page for your app. For more information about navigating to the settings page for your {% data variables.product.prodname_github_app %}, see [AUTOTITLE](/apps/maintaining-github-apps/modifying-a-github-app-registration#navigating-to-your-github-app-settings).{% ifversion github-app-offline-access %} + + To get to an expiring user access token and a refresh token for this authorization even if your app has them disabled, you can also send the `scope` query parameter with the value `offline_access`. No other scopes are supported for {% data variables.product.prodname_github_apps %}.{% endif %} 1. {% data variables.product.company_short %} will give a response that includes the following query parameters: Response parameter | Type | Description @@ -128,10 +131,16 @@ You can generate a user access token with this method regardless of whether the ## Using a refresh token to generate a user access token -By default, user access tokens expires after 8 hours. If you receive a user access token with an expiration, you will also receive a refresh token. The refresh token expire after 6 months. You can use this refresh token to regenerate a user access token. For more information, see [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens). +By default, user access tokens expire after 8 hours. If you receive a user access token with an expiration, you will also receive a refresh token. The refresh token expires after 6 months. You can use this refresh token to regenerate a user access token. For more information, see [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens). {% data variables.product.company_short %} strongly encourages you to use user access tokens that expire. If you previously opted out of using user access tokens that expire but want to re-enable this feature, see [AUTOTITLE](/apps/maintaining-github-apps/activating-optional-features-for-github-apps). +{% ifversion github-app-offline-access %} + +To test your app's support for expiring tokens before you re-enable token expiration for the entire app, request the `offline_access` scope when you request a user access token. To confirm that you received an expiring token, check for the `expires_in` field in the token response. + +{% endif %} + ## Troubleshooting The following sections outline some errors you may receive when generating a user access token. @@ -159,7 +168,7 @@ To resolve this error, you should start the device flow again to get a new code. If the refresh token that you specified is invalid or expired, you will receive a `bad_refresh_token` error. -To resolve this error, you must restart the web application flow or device flow to get a new user access token and refresh token. You will only receive a refresh token if your {% data variables.product.prodname_github_app %} has opted in to expiring user access tokens. For more information, see [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens). +To resolve this error, you must restart the web application flow or device flow to get a new user access token and refresh token. You will only receive a refresh token if your {% data variables.product.prodname_github_app %} has opted in to expiring user access tokens{% ifversion github-app-offline-access %} or uses the `offline_access` scope{% endif %}. For more information, see [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens). ### Unsupported grant type diff --git a/content/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps.md b/content/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps.md index 099418ac915b..f82fd935465b 100644 --- a/content/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps.md +++ b/content/apps/creating-github-apps/authenticating-with-a-github-app/managing-private-keys-for-github-apps.md @@ -29,7 +29,9 @@ To generate a private key: {% data reusables.apps.settings-step %} {% data reusables.apps.enterprise-apps-steps %} 1. Next to the {% data variables.product.prodname_github_app %} that you want to generate a private key for, click **Edit**. -1. Under "Private keys", click **Generate a private key**. +{% ifversion github-app-repository-permission-improvements %}1. In the left sidebar, click **{% octicon "key" aria-hidden="true" aria-label="code" %} Credentials**, then click **{% octicon "key" aria-hidden="true" aria-label="code" %} Key pairs**. +1. Click **New key**.{% else %} +1. Under "Private keys", click **Generate a private key**.{% endif %} 1. You will see a private key in PEM format downloaded to your computer. Make sure to store this file because GitHub only stores the public portion of the key. For more information about securely storing your key, see [Storing private keys](#storing-private-keys). > [!NOTE] @@ -41,9 +43,10 @@ To generate a private key: To verify a private key: -1. Find the fingerprint for the private and public key pair you want to verify in the "Private keys" section of the settings page for your {% data variables.product.prodname_github_app %}. For more information, see [Generating private keys](#generating-private-keys). +1. Find the fingerprint for the private and public key pair you want to verify in the {% ifversion github-app-repository-permission-improvements %}"Credentials"{% else %}"Private keys"{% endif %} section of the settings for your {% data variables.product.prodname_github_app %}. For more information, see [Generating private keys](#generating-private-keys). - ![Screenshot of a private key in a {% data variables.product.prodname_github_app %} settings page. The fingerprint, the part of the private key after the colon, is outlined in dark orange.](/assets/images/github-apps/github-apps-private-key-fingerprint.png) +{% ifversion github-app-repository-permission-improvements %} ![Screenshot of a private key in a {% data variables.product.prodname_github_app %} settings page.](/assets/images/github-apps/github-apps-private-key-fingerprint-new.png){% else %} + ![Screenshot of a private key in a {% data variables.product.prodname_github_app %} settings page. The fingerprint, the part of the private key after the colon, is outlined in dark orange.](/assets/images/github-apps/github-apps-private-key-fingerprint.png){% endif %} 1. Generate the fingerprint of your private key (PEM) locally by using the following command: ```shell @@ -60,7 +63,9 @@ You can remove a lost or compromised private key by deleting it, but you must re {% data reusables.user-settings.developer_settings %} {% data reusables.user-settings.github_apps %} 1. Next to the {% data variables.product.prodname_github_app %} that you want to delete a private key for, click **Edit**. -1. Under "Private keys", to the right of the private key you want to delete, click **Delete**. +{% ifversion github-app-repository-permission-improvements %}1. In the left sidebar, click **{% octicon "key" aria-hidden="true" aria-label="code" %} Credentials**, then click **{% octicon "key" aria-hidden="true" aria-label="code" %} Key pairs**. +1. Under "Key pairs", to the right of the private key you want to delete, click **Delete**.{% else %} +1. Under "Private keys", to the right of the private key you want to delete, click **Delete**.{% endif %} 1. When prompted, confirm you want to delete the private key by clicking **Delete**. If your {% data variables.product.prodname_github_app %} has only one key, you will need to generate a new key before deleting the old key. For more information, see [Generating private keys](#generating-private-keys). ## Storing private keys diff --git a/content/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens.md b/content/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens.md index c540effdb6dc..daeb99955815 100644 --- a/content/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens.md +++ b/content/apps/creating-github-apps/authenticating-with-a-github-app/refreshing-user-access-tokens.md @@ -25,6 +25,14 @@ You can use the refresh token to generate a new user access token and a new refr If your refresh token expires before you use it, you can regenerate a user access token and refresh token by sending users through the web application flow or device flow. For more information, see [AUTOTITLE](/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-user-access-token-for-a-github-app). +{% ifversion github-app-offline-access %} + +To test and gradually roll out support for expiring tokens, you can opt in for an individual user authorization by requesting the `offline_access` scope. When you request `offline_access`, you will receive an expiring user access token and a refresh token even if your app is configured not to use expiring user access tokens. + +The `scope` parameter does not grant permissions to a {% data variables.product.prodname_github_app %}. The only supported value is `offline_access`, which forces the user access token to expire. + +{% endif %} + ## Configuring your app to use user access tokens that expire When you create your app, expiration of user access tokens is enabled unless you opt out. For more information, see [AUTOTITLE](/apps/creating-github-apps/registering-a-github-app/registering-a-github-app). You can also configure this setting after your app has been created. @@ -37,7 +45,7 @@ When you create your app, expiration of user access tokens is enabled unless you {% data variables.product.company_short %} recommends that you opt in to this feature for improved security. -If you opt into user access tokens that expire after you have already generated user access tokens, the previously generated user access tokens will not expire. You can delete these tokens by using the `DELETE /applications/CLIENT_ID/token` endpoint. For more information, see [AUTOTITLE](/rest/apps/oauth-applications#delete-an-app-token). +If you re-enable expiring user access tokens after you've already signed in users and gotten their access token, those pre-existing user access tokens will not expire. You should delete these tokens by using the `DELETE /applications/CLIENT_ID/token` endpoint or have the users reauthenticate so that they get an expiring token. For more information, see [AUTOTITLE](/rest/apps/oauth-applications#delete-an-app-token). ## Refreshing a user access token with a refresh token diff --git a/content/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app.md b/content/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app.md index be2a81f05a95..816685508a17 100644 --- a/content/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app.md +++ b/content/apps/creating-github-apps/registering-a-github-app/choosing-permissions-for-a-github-app.md @@ -45,7 +45,13 @@ The success of an API request with a user access token depends on the user's per For more information about specifying permissions during {% data variables.product.prodname_github_app %} registration, see [AUTOTITLE](/apps/creating-github-apps/registering-a-github-app/registering-a-github-app). -Some webhooks and API access requires "Administration" permissions. If your app requires "Administration" permissions, consider explaining this requirement on your app's homepage. This will help users understand why your app needs a high level permission. +Some webhooks and API access require "Administration" permissions. If your app requires "Administration" permissions, consider explaining this requirement on your app's homepage. This will help users understand why your app needs a high level permission. + +{% ifversion github-app-repository-permission-improvements %} + +If your app only needs "Administration" permission to create repositories, request the "Repository creation" permission instead. This more limited permission lets your app create repositories without granting access to other repository administration features. Your app is automatically given access to repositories it creates. + +{% endif %} ## About changes to permissions diff --git a/content/apps/creating-github-apps/registering-a-github-app/making-a-github-app-public-or-private.md b/content/apps/creating-github-apps/registering-a-github-app/making-a-github-app-public-or-private.md index 24ce1d7d80c2..cd6d2b323883 100644 --- a/content/apps/creating-github-apps/registering-a-github-app/making-a-github-app-public-or-private.md +++ b/content/apps/creating-github-apps/registering-a-github-app/making-a-github-app-public-or-private.md @@ -37,6 +37,20 @@ If you want your {% data variables.product.prodname_github_app %} to be availabl If it is important for {% ifversion ghes %}other {% endif %}{% data variables.product.prodname_ghe_server %} users to be able to use your tool, consider using {% data variables.product.prodname_actions %} instead of a {% data variables.product.prodname_github_app %}. Public actions are available on {% data variables.product.prodname_ghe_server %} instances with GitHub Connect. For more information, see [AUTOTITLE]({% ifversion not ghes %}/enterprise-server@latest{% endif %}/admin/managing-github-actions-for-your-enterprise/managing-access-to-actions-from-githubcom/enabling-automatic-access-to-githubcom-actions-using-github-connect) and [AUTOTITLE]({% ifversion not ghes %}/enterprise-server@latest{% endif %}/admin/managing-github-actions-for-your-enterprise/getting-started-with-github-actions-for-your-enterprise/about-github-actions-for-enterprises){% ifversion ghes %}.{% else %} in the {% data variables.product.prodname_ghe_server %} documentation.{% endif %} For information about changing the visibility of a {% data variables.product.prodname_github_app %} registration, see [AUTOTITLE](/apps/maintaining-github-apps/modifying-a-github-app-registration). +{% ifversion github-app-details-visibility %} + +### Accessing details of other {% data variables.product.prodname_github_apps %} + +A {% data variables.product.prodname_github_app %} can use the "Get an app" REST API endpoint to access details of another app when one of these are true: + +* The target app is public. +* Both apps are owned by the same organization, regardless of the target app's visibility. +* The target app is internal, and both apps belong to the same enterprise. +* The requesting app is owned by an enterprise, and the target app is owned by an organization in that enterprise. + +For more information, see [AUTOTITLE](/rest/apps/apps#get-an-app). + +{% endif %} ### Public installation flow diff --git a/content/apps/using-github-apps/installing-a-github-app-from-a-third-party.md b/content/apps/using-github-apps/installing-a-github-app-from-a-third-party.md index 511d0cbc2bdf..3328da8cbee3 100644 --- a/content/apps/using-github-apps/installing-a-github-app-from-a-third-party.md +++ b/content/apps/using-github-apps/installing-a-github-app-from-a-third-party.md @@ -66,4 +66,3 @@ During the installation process, the app owner will direct you to a {% data vari If the app creates any repositories, the app will automatically be granted access to those repositories as well. 1. Review the permissions that the app is requesting. For more information about the REST API requests the {% data variables.product.prodname_github_app %} can make with those permissions, see [AUTOTITLE](/rest/authentication/permissions-required-for-github-apps). 1. Click **Install**, **Install and request**, or **Request**. The button that is presented depends on whether your organization owner must approve none, some, or all of the requested access for the app.{% ifversion enterprise-installed-apps %} Enterprise installations cannot be requested—the enterprise owner must install the app directly.{% endif %} For more information, see [Requirements to install a {% data variables.product.prodname_github_app %}](#requirements-to-install-a-github-app). - diff --git a/content/apps/using-github-apps/reviewing-and-modifying-installed-github-apps.md b/content/apps/using-github-apps/reviewing-and-modifying-installed-github-apps.md index 8ceccbd29039..43bb35abc490 100644 --- a/content/apps/using-github-apps/reviewing-and-modifying-installed-github-apps.md +++ b/content/apps/using-github-apps/reviewing-and-modifying-installed-github-apps.md @@ -58,6 +58,8 @@ In addition to reviewing {% data variables.product.prodname_github_apps %} that ## Modifying repository access +Organization owners can change the repository access for an app installed on their organization. Repository administrators can also add their repositories to an existing installation{% ifversion github-app-repository-permission-improvements %} regardless of the app's permissions. The organization owner approved these permissions when they installed the app.{% else %} if the application does not use organization permissions or the "repository administration" permission.{% endif %} + 1. Navigate to the {% data variables.product.prodname_github_app %} you want to modify. For more information, see [Navigating to the GitHub App you want to review or modify](#navigating-to-the-github-app-you-want-to-review-or-modify). 1. Under "Repository access," select **All repositories** or **Only select repositories**. 1. If you selected **Only select repositories** in the previous step, under the **Select repositories** dropdown, select the repositories that you want the {% data variables.product.prodname_github_app %} to access. diff --git a/content/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations.md b/content/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations.md index 13bd735f64dc..4c993924b163 100644 --- a/content/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations.md +++ b/content/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations.md @@ -35,7 +35,7 @@ By default, app access requests are enabled. If your organization has a large nu ## About {% data variables.product.prodname_github_app %} installation restrictions -By default, repository admins can install {% data variables.product.prodname_github_apps %} on repositories within your organization if the app does not request organization permissions or the "repository administration" permission. As an organization owner, you can restrict {% data variables.product.prodname_github_app %} installations to only organization owners. When this restriction is enabled: +By default, repository admins can install {% data variables.product.prodname_github_apps %} on repositories within your organization if the app does not request organization permissions or the "repository administration" permission{% ifversion github-app-offline-access %}, and add apps you've already installed to their repository, even if it includes organization or "repository administration" permissions{% endif %}. As an organization owner, you can restrict {% data variables.product.prodname_github_app %} installations to only organization owners. When this restriction is enabled: * Repository admins, including outside collaborators with repository admin access, cannot install {% data variables.product.prodname_github_apps %} on their repositories. * Repository admins must use the request flow to ask organization owners to install apps on their repositories. diff --git a/data/features/github-app-details-visibility.yml b/data/features/github-app-details-visibility.yml new file mode 100644 index 000000000000..a3c2e3099c8d --- /dev/null +++ b/data/features/github-app-details-visibility.yml @@ -0,0 +1,7 @@ +# https://github.com/github/releases/issues/10559 +# GitHub Apps can use the Get an app API to access details of private and +# internal apps in the same organization or enterprise. +versions: + fpt: '*' + ghec: '*' + ghes: '>=3.24' diff --git a/data/features/github-app-offline-access.yml b/data/features/github-app-offline-access.yml new file mode 100644 index 000000000000..3e9bb46ca3d6 --- /dev/null +++ b/data/features/github-app-offline-access.yml @@ -0,0 +1,7 @@ +# https://github.com/github/releases/issues/10567 +# GitHub Apps can request expiring user access tokens at runtime by using the +# offline_access scope. +versions: + fpt: '*' + ghec: '*' + ghes: '>=3.23' diff --git a/data/features/github-app-repository-permission-improvements.yml b/data/features/github-app-repository-permission-improvements.yml new file mode 100644 index 000000000000..6d1255526fb4 --- /dev/null +++ b/data/features/github-app-repository-permission-improvements.yml @@ -0,0 +1,8 @@ +# https://github.com/github/releases/issues/11043 +# GitHub Apps have a separate repository creation permission, and repository +# administrators can add repositories to an existing approved installation +# regardless of the app's permissions. +versions: + fpt: '*' + ghec: '*' + ghes: '>=3.24' diff --git a/data/reusables/apps/repo-admin-install-restriction.md b/data/reusables/apps/repo-admin-install-restriction.md index 799a30e3954a..9018b12e1e00 100644 --- a/data/reusables/apps/repo-admin-install-restriction.md +++ b/data/reusables/apps/repo-admin-install-restriction.md @@ -1 +1,9 @@ -Repository admins can install {% data variables.product.prodname_github_apps %} in the organization that owns the repository if the app does not request any organization permissions nor the "repository administration" permission. When doing so, they can only install the app with access to the repositories that they admin. {% ifversion fpt or ghec or ghes > 3.19 %}Organization owners can restrict {% data variables.product.prodname_github_app %} installation by repository admins. When this restriction is enabled, repository admins cannot install {% data variables.product.prodname_github_apps %} and must instead request that organization owners install the desired app. For more information, see [AUTOTITLE](/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations).{% endif %} +Repository admins can install {% data variables.product.prodname_github_apps %} in the organization that owns the repository if the app does not request any organization permissions or the "Repository administration" permission. When doing so, they can only install the app with access to the repositories that they administer. + +{% ifversion github-app-repository-permission-improvements %} + +If an organization owner has already installed an app, repository administrators can update the existing installation to give the app access to repositories that they administer. They can make this update regardless of the app's permissions because the organization owner approved those permissions when they installed the app. + +{% endif %} + +{% ifversion fpt or ghec or ghes > 3.19 %}Organization owners can restrict {% data variables.product.prodname_github_app %} installation by repository admins. When this restriction is enabled, repository admins cannot install or add {% data variables.product.prodname_github_apps %} for their repository and must instead request that organization owners install the desired app. For more information, see [AUTOTITLE](/organizations/managing-programmatic-access-to-your-organization/limiting-oauth-app-and-github-app-access-requests-and-installations).{% endif %} diff --git a/data/reusables/apps/user-access-token-response-parameters.md b/data/reusables/apps/user-access-token-response-parameters.md index b589afd4bcfe..7a87d649ad7c 100644 --- a/data/reusables/apps/user-access-token-response-parameters.md +++ b/data/reusables/apps/user-access-token-response-parameters.md @@ -1,8 +1,8 @@ Response parameter | Type | Description --- | --- | --- `access_token` | `string` | The user access token. The token starts with `ghu_`. -`expires_in` | `integer` | The number of seconds until `access_token` expires. If you disabled expiration of user access tokens, this parameter will be omitted. The value will always be `28800` (8 hours). -`refresh_token` | `string` | The refresh token. If you disabled expiration of user access tokens, this parameter will be omitted. The token starts with `ghr_`. -`refresh_token_expires_in` | `integer` | The number of seconds until `refresh_token` expires. If you disabled expiration of user access tokens, this parameter will be omitted. The value will always be `15897600` (6 months). +`expires_in` | `integer` | The number of seconds until `access_token` expires. If the token doesn't expire, this parameter will be omitted. The value will always be `28800` (8 hours). +`refresh_token` | `string` | The refresh token. If the access token doesn't expire, this parameter will be omitted. The token starts with `ghr_`. +`refresh_token_expires_in` | `integer` | The number of seconds until `refresh_token` expires. If the access token doesn't expire, this parameter will be omitted. The value will always be `15897600` (6 months). `scope` | `string` | The scopes that the token has. This value will always be an empty string. Unlike a traditional OAuth token, the user access token is limited to the permissions that both your app and the user have. `token_type` | `string` | The type of token. The value will always be `bearer`. From eb975b9c497b7f4bd04a020afe730565a1e33921 Mon Sep 17 00:00:00 2001 From: Sunbrye Ly <56200261+sunbrye@users.noreply.github.com> Date: Wed, 7 Oct 2026 20:11:06 +0000 Subject: [PATCH 4/4] Claude Haiku 5.5 model release (#63734) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 21c5f1b6-a7d3-4f52-973a-36d73d3130c0 --- .../github-copilot-with-data-residency.md | 1 + .../reference/ai-models/model-hosting.md | 1 + .../reference/ai-models/supported-models.md | 2 ++ .../copilot-billing/models-and-pricing.md | 8 +++-- .../copilot-cloud-agent-non-auto-models.md | 1 + .../copilot/model-compliance/us-models.md | 1 + data/tables/copilot/model-comparison.yml | 5 ++++ data/tables/copilot/model-release-status.yml | 4 +++ .../copilot/model-supported-clients.yml | 9 ++++++ data/tables/copilot/model-supported-plans.yml | 7 +++++ data/tables/copilot/models-and-pricing.yml | 29 +++++++++++++++++-- data/variables/copilot.yml | 1 + 12 files changed, 63 insertions(+), 6 deletions(-) diff --git a/content/admin/data-residency/github-copilot-with-data-residency.md b/content/admin/data-residency/github-copilot-with-data-residency.md index e5f29495cfb5..f782cc487dbe 100644 --- a/content/admin/data-residency/github-copilot-with-data-residency.md +++ b/content/admin/data-residency/github-copilot-with-data-residency.md @@ -66,6 +66,7 @@ The models available for {% data variables.product.prodname_copilot_short %} var * {% data variables.copilot.copilot_gpt_56_terra %} * {% data variables.copilot.copilot_gpt_6_astra %} * {% data variables.copilot.copilot_claude_haiku_45 %} +* {% data variables.copilot.copilot_claude_haiku_55 %} * {% data variables.copilot.copilot_claude_opus_48 %} * {% data variables.copilot.copilot_claude_opus_5 %} * {% data variables.copilot.copilot_claude_opus_55 %} diff --git a/content/copilot/reference/ai-models/model-hosting.md b/content/copilot/reference/ai-models/model-hosting.md index b27049759aa7..e7774d31634a 100644 --- a/content/copilot/reference/ai-models/model-hosting.md +++ b/content/copilot/reference/ai-models/model-hosting.md @@ -45,6 +45,7 @@ All input requests and output responses processed by {% data variables.product.p Used for: * {% data variables.copilot.copilot_claude_haiku_45 %} +* {% data variables.copilot.copilot_claude_haiku_55 %} * {% data variables.copilot.copilot_claude_sonnet_46 %} * {% data variables.copilot.copilot_claude_sonnet_5 %} * {% data variables.copilot.copilot_claude_sonnet_55 %} diff --git a/content/copilot/reference/ai-models/supported-models.md b/content/copilot/reference/ai-models/supported-models.md index 20260f1d8b0c..6754082045c1 100644 --- a/content/copilot/reference/ai-models/supported-models.md +++ b/content/copilot/reference/ai-models/supported-models.md @@ -84,6 +84,7 @@ Choosing a larger context window or higher reasoning will impact {% data variabl | {% data variables.copilot.copilot_claude_opus_55 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | {% data variables.copilot.copilot_claude_sonnet_5 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | {% data variables.copilot.copilot_claude_sonnet_55 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | +| {% data variables.copilot.copilot_claude_haiku_55 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | {% data variables.copilot.copilot_claude_opus_48_fast %} | {% octicon "x" aria-label="Not supported" %} | {% octicon "check" aria-label="Supported" %} | | {% data variables.copilot.copilot_claude_fable_5 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | | {% data variables.copilot.copilot_claude_fable_51 %} | {% octicon "check" aria-label="Supported" %} | {% octicon "check" aria-label="Supported" %} | @@ -144,6 +145,7 @@ Some {% data variables.product.prodname_copilot_short %} models require minimum | {% data variables.copilot.copilot_claude_opus_55 %} | TBD | `17.14.6` | TBD | TBD | TBD | | {% data variables.copilot.copilot_claude_sonnet_5 %} | `v1.124` | `17.14.6` | TBD | TBD | TBD | | {% data variables.copilot.copilot_claude_sonnet_55 %} | TBD | `17.14.6` | TBD | TBD | TBD | +| {% data variables.copilot.copilot_claude_haiku_55 %} | TBD | TBD | TBD | TBD | TBD | | {% data variables.copilot.copilot_claude_fable_5 %} | `v1.124` | `17.14.6` | TBD | TBD | TBD | | {% data variables.copilot.copilot_claude_fable_51 %} | TBD | TBD | TBD | TBD | TBD | | {% data variables.copilot.copilot_kimi_k3 %} | `v1.131` | TBD | TBD | TBD | TBD | diff --git a/content/copilot/reference/copilot-billing/models-and-pricing.md b/content/copilot/reference/copilot-billing/models-and-pricing.md index 26f6212371d5..7ee292ac7c29 100644 --- a/content/copilot/reference/copilot-billing/models-and-pricing.md +++ b/content/copilot/reference/copilot-billing/models-and-pricing.md @@ -43,12 +43,14 @@ All prices are **per 1 million tokens**. ### Anthropic +{% data reusables.copilot.extended-context-pricing %} + Anthropic models include a cache write cost in addition to cached input. -| Model | Release status | Category | Input | Cached input | Cache write | Output | -| --- | --- | --- | ---: | ---: | ---: | ---: | +| Model | Release status | Category | Tier | Threshold (input tokens) | Input | Cached input | Cache write | Output | +| --- | --- | --- | --- | --- | ---: | ---: | ---: | ---: | | {% for entry in tables.copilot.models-and-pricing %}{% if entry.provider == "anthropic" %} | -| {{ entry.model }} | {{ entry.release_status }} | {{ entry.category }} | {{ entry.input }} | {{ entry.cached_input }} | {{ entry.cache_write }} | {{ entry.output }} | +| {{ entry.model }} | {{ entry.release_status }} | {{ entry.category }} | {% if entry.tier %}{{ entry.tier }}{% else %}Default{% endif %} | {% if entry.threshold %}{{ entry.threshold }}{% else %}Not applicable{% endif %} | {{ entry.input }} | {{ entry.cached_input }} | {{ entry.cache_write }} | {{ entry.output }} | | {% endif %}{% endfor %} | ### Google diff --git a/data/reusables/copilot/copilot-cloud-agent-non-auto-models.md b/data/reusables/copilot/copilot-cloud-agent-non-auto-models.md index d79adb0fc0a6..b05ce787f8ba 100644 --- a/data/reusables/copilot/copilot-cloud-agent-non-auto-models.md +++ b/data/reusables/copilot/copilot-cloud-agent-non-auto-models.md @@ -2,6 +2,7 @@ * {% data variables.copilot.copilot_claude_opus_55 %} * {% data variables.copilot.copilot_claude_sonnet_55 %} * {% data variables.copilot.copilot_claude_haiku_45 %} +* {% data variables.copilot.copilot_claude_haiku_55 %} * {% data variables.copilot.copilot_gemini_37_flash %} * {% data variables.copilot.copilot_gemini_38_flash %} * {% data variables.copilot.copilot_gpt_54_mini %} diff --git a/data/reusables/copilot/model-compliance/us-models.md b/data/reusables/copilot/model-compliance/us-models.md index 58ab00ff56d6..d98fced64102 100644 --- a/data/reusables/copilot/model-compliance/us-models.md +++ b/data/reusables/copilot/model-compliance/us-models.md @@ -5,6 +5,7 @@ * GPT-5.2 * GPT-5.3-Codex * Claude Haiku 4.5 +* Claude Haiku 5.5 * Claude Sonnet 5 * Claude Sonnet 5.5 * Claude Opus 4.8 diff --git a/data/tables/copilot/model-comparison.yml b/data/tables/copilot/model-comparison.yml index 06364f7f7fbd..f8b701f935b4 100644 --- a/data/tables/copilot/model-comparison.yml +++ b/data/tables/copilot/model-comparison.yml @@ -84,6 +84,11 @@ excels_at: Fast, reliable answers to lightweight coding questions further_reading: '[Claude Haiku 4.5 model card](https://assets.anthropic.com/m/99128ddd009bdcb/Claude-Haiku-4-5-System-Card.pdf)' +- name: Claude Haiku 5.5 + task_area: Fast help with simple or repetitive tasks + excels_at: Fast, reliable answers to lightweight coding questions + further_reading: '[Claude Haiku 5.5 model card](https://www-cdn.anthropic.com/e1080d6bf5ae2018ea3c2f414064be03232f5be5/Claude%20Haiku%205.5%20System%20Card.pdf)' + - name: Claude Opus 4.8 task_area: Deep reasoning and debugging excels_at: Complex problem-solving challenges, sophisticated reasoning diff --git a/data/tables/copilot/model-release-status.yml b/data/tables/copilot/model-release-status.yml index f5384b36718e..f5ee420cd1dc 100644 --- a/data/tables/copilot/model-release-status.yml +++ b/data/tables/copilot/model-release-status.yml @@ -81,6 +81,10 @@ provider: 'Anthropic' release_status: 'GA' +- name: 'Claude Haiku 5.5' + provider: 'Anthropic' + release_status: 'GA' + - name: 'Claude Opus 4.8' provider: 'Anthropic' release_status: 'GA' diff --git a/data/tables/copilot/model-supported-clients.yml b/data/tables/copilot/model-supported-clients.yml index cc7e4e22b72b..0f06d75c521a 100644 --- a/data/tables/copilot/model-supported-clients.yml +++ b/data/tables/copilot/model-supported-clients.yml @@ -23,6 +23,15 @@ xcode: true jetbrains: true +- name: Claude Haiku 5.5 + dotcom: true + cli: true + vscode: true + vs: true + eclipse: true + xcode: true + jetbrains: true + - name: Claude Opus 4.8 dotcom: true cli: true diff --git a/data/tables/copilot/model-supported-plans.yml b/data/tables/copilot/model-supported-plans.yml index fe60448cbc0a..2718999edf55 100644 --- a/data/tables/copilot/model-supported-plans.yml +++ b/data/tables/copilot/model-supported-plans.yml @@ -19,6 +19,13 @@ business: true enterprise: true +- name: Claude Haiku 5.5 + pro: true + pro_plus: true + max: true + business: true + enterprise: true + - name: Claude Opus 4.8 pro: false pro_plus: true diff --git a/data/tables/copilot/models-and-pricing.yml b/data/tables/copilot/models-and-pricing.yml index 6a5ed1cf5852..7774c10a4b09 100644 --- a/data/tables/copilot/models-and-pricing.yml +++ b/data/tables/copilot/models-and-pricing.yml @@ -12,8 +12,9 @@ # - input: Input token price per 1M tokens. # - cached_input: Cached input token price per 1M tokens. # - output: Output token price per 1M tokens. -# - threshold: Input token threshold for pricing tier (OpenAI and Google only). -# - tier: Pricing tier label (OpenAI and Google only). +# - threshold: Input token threshold for pricing tier (OpenAI, Google, and xAI; Anthropic +# only for models with more than one pricing tier). +# - tier: Pricing tier label (same scope as threshold). # - cache_write: Cache write price per 1M tokens. Applies to Anthropic models and # to GPT-5.6 and later OpenAI model families. Use "Not applicable" for models # that have no cache write cost. @@ -272,6 +273,28 @@ output: $5.00 cache_write: $1.25 +- model: Claude Haiku 5.5 + provider: anthropic + release_status: GA + category: Lightweight + threshold: '≤ 100K' + tier: Default + input: $0.10 + cached_input: $0.01 + output: $0.50 + cache_write: $0.125 + +- model: Claude Haiku 5.5 + provider: anthropic + release_status: GA + category: Lightweight + threshold: '> 100K' + tier: Long context + input: $0.50 + cached_input: $0.05 + output: $2.50 + cache_write: $0.625 + - model: Claude Sonnet 4 provider: anthropic release_status: GA @@ -331,7 +354,7 @@ release_status: GA category: Versatile input: $2.00 - cached_input: $0.20 + cached_input: $0.10 output: $10.00 cache_write: $2.50 diff --git a/data/variables/copilot.yml b/data/variables/copilot.yml index 276aa274831f..1cbda8e30a5d 100644 --- a/data/variables/copilot.yml +++ b/data/variables/copilot.yml @@ -182,6 +182,7 @@ max-chat-indexed-repos: '50' # Claude: copilot_claude: 'Claude' copilot_claude_haiku_45: 'Claude Haiku 4.5' +copilot_claude_haiku_55: 'Claude Haiku 5.5' copilot_claude_opus: 'Claude Opus 4' copilot_claude_opus_41: 'Claude Opus 4.1' copilot_claude_opus_45: 'Claude Opus 4.5'