Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions .github/workflows/auto-add-ready-for-doc-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,11 @@ jobs:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'technical-content',
// Team is addressed by numeric ID (org github = 9919, team docs = 325922)
// because IDs survive team renames and slugs do not.
await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', {
org_id: 9919,
team_id: 325922,
username: context.payload.sender.login,
});
return true
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/changelog-prompt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ jobs:
script: |
try {
const pr = context.payload.pull_request;
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs-content',
// Team is addressed by numeric ID (org github = 9919, team docs-content = 2796154)
// because IDs survive team renames and slugs do not.
await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', {
org_id: 9919,
team_id: 2796154,
username: pr.user.login,
});
core.exportVariable('CONTINUE_WORKFLOW', 'true');
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/confirm-internal-staff-work-in-docs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,11 @@ jobs:
// Don't perform this action with Docs team members
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'technical-content',
// Team is addressed by numeric ID (org github = 9919, team docs = 325922)
// because IDs survive team renames and slugs do not.
await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', {
org_id: 9919,
team_id: 325922,
username: context.payload.sender.login,
});
// If the user is a Docs team member, we should stop here and not send
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/copy-api-issue-to-internal.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,10 @@ jobs:
result-encoding: string
script: |
const triggerer_login = context.payload.sender.login
// Team is addressed by numeric ID (org github = 9919, team docs = 325922)
// because IDs survive team renames and slugs do not.
const teamMembers = await github.request(
`/orgs/github/teams/technical-content/members?per_page=100`
`/organizations/9919/team/325922/members?per_page=100`
)
const logins = teamMembers.data.map(member => member.login)
if (logins.includes(triggerer_login)) {
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/feedback-prompt.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,11 @@ jobs:
script: |
try {
const pr = context.payload.pull_request;
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'docs-content',
// Team is addressed by numeric ID (org github = 9919, team docs-content = 2796154)
// because IDs survive team renames and slugs do not.
await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', {
org_id: 9919,
team_id: 2796154,
username: pr.user.login,
});
// Author is in the team. Do nothing!
Expand Down
8 changes: 5 additions & 3 deletions .github/workflows/hubber-contribution-help.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,11 @@ jobs:
github-token: ${{ secrets.DOCS_BOT_PAT_BASE }}
script: |
try {
await github.rest.teams.getMembershipForUserInOrg({
org: 'github',
team_slug: 'technical-content',
// Team is addressed by numeric ID (org github = 9919, team docs = 325922)
// because IDs survive team renames and slugs do not.
await github.request('GET /organizations/{org_id}/team/{team_id}/memberships/{username}', {
org_id: 9919,
team_id: 325922,
username: context.payload.sender.login,
});
return true
Expand Down
4 changes: 3 additions & 1 deletion .github/workflows/os-ready-for-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@ jobs:
result-encoding: string
script: |
const triggerer_login = context.payload.sender.login
// Team is addressed by numeric ID (org github = 9919, team docs = 325922)
// because IDs survive team renames and slugs do not.
const teamMembers = await github.request(
`/orgs/github/teams/technical-content/members?per_page=100`
`/organizations/9919/team/325922/members?per_page=100`
)
const logins = teamMembers.data.map(member => member.login)
if (logins.includes(triggerer_login)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ The models available for {% data variables.product.prodname_copilot_short %} var
* {% data variables.copilot.copilot_gpt_54_mini %}
* {% data variables.copilot.copilot_gpt_54_nano %}
* {% data variables.copilot.copilot_gpt_55 %}
* {% data variables.copilot.copilot_gpt_56_luna %}
* {% data variables.copilot.copilot_gpt_56_sol %}
* {% data variables.copilot.copilot_gpt_56_terra %}
* {% data variables.copilot.copilot_claude_haiku_45 %}
* {% data variables.copilot.copilot_claude_opus_45 %}
* {% data variables.copilot.copilot_claude_opus_46 %}
Expand Down
2 changes: 2 additions & 0 deletions content/copilot/concepts/about-cloud-and-local-sandboxes.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ Local sandboxing is powered by Microsoft eXecution Container (MXC), a cross-plat

Isolation technologies exist on a spectrum, from strong isolation such as full hypervisors or containers, to lighter-weight isolation such as OS-level process and filesystem containment. Local sandboxing currently sits at the lighter-weight end of this spectrum: it restricts what a process can read, write, and reach on the network, but it does not run your commands inside a separate virtual machine or container. If you want to evaluate whether this level of isolation meets your security requirements, see the [microsoft/mxc repository](https://github.com/microsoft/mxc) for implementation details.

For more information, see [AUTOTITLE](/copilot/concepts/agents/copilot-cli/understanding-local-sandboxing).

### Enabling local sandboxing

To enable local sandboxing inside a {% data variables.copilot.copilot_cli_short %} session, run:
Expand Down
1 change: 1 addition & 0 deletions content/copilot/concepts/agents/copilot-cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ children:
- /lsp-servers
- /about-cli-extensions
- /tool-search
- /understanding-local-sandboxing
contentType: concepts
docsTeamMetrics:
- copilot-cli
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
---
title: Understanding filesystem policies for local sandboxing in {% data variables.copilot.copilot_cli %}
shortTitle: Understanding local sandboxing
allowTitleToDifferFromFilename: true
intro: 'When local sandboxing is enabled, {% data variables.copilot.copilot_cli_short %} runs each sandboxed process or operation under a filesystem policy that controls which files and directories it can read and write. Learn how that policy is built and how to check the access it grants.'
versions:
feature: copilot
contentType: concepts
category:
- Learn about Copilot
- Learn about Copilot CLI
docsTeamMetrics:
- copilot-cli
---

{% 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).

## 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.
* **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.

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.

## Permission levels

The sandbox is **deny-by-default**: unless a path is explicitly granted, a command cannot use it. Every path in the policy has one of three permission levels:

* **Read/write** — the command can read and modify files at this path.
* **Read-only** — the command can read files at this path, but not change them.
* **Denied** — the command cannot read or write at this path, even if a broader rule would otherwise allow it.

Because access is denied unless granted, {% data variables.product.prodname_copilot_short %} must grant a command everything it legitimately needs—your project files, the tools it runs, and supporting locations such as temporary directories—while keeping everything else off-limits.

> [!NOTE]
> These permission levels apply to every sandboxed process or operation, but they are enforced differently: for sandboxed child processes the operating system enforces them directly, while the CLI's own built-in file-reading and file-editing tools check the same levels in software, without an operating-system backstop.

## 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.

### Your working directory

When **Include working directory** is enabled in the filesystem settings for local sandboxing—as it is by default—the current working directory is granted read/write access. In a Git repository, {% data variables.product.prodname_copilot_short %} also adds the associated Git grants. Turning this setting off suppresses all of those automatic grants so you must add allow rules for the required project and Git paths manually. See [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings).

> [!NOTE]
> If you get {% data variables.product.prodname_copilot_short %} from an enterprise-owned organization, an administrator can turn off the **Include working directory** setting and lock it, so you can't turn it back on. See [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox).

### Tools on your PATH

To run a program such as `python` or `git`, the sandbox has to let the command see the directory the program lives in. Your `PATH` environment variable lists these directories, and {% data variables.product.prodname_copilot_short %} grants them **read-only** access, along with directories named by related tool variables such as `GOPATH`, `CARGO_HOME`, and `PYTHONPATH`. Read-only is the right level for external tools: a command needs to run `git`, not modify it. For the complete list of the `PATH` and toolchain environment variables the sandbox inspects, and how each one is interpreted, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-command-reference#sandbox-tool-directory-grants).

### System and profile locations

Standard system locations and your user profile (home) directory are granted read-only, so that commands can read configuration files and shared libraries without being able to change them.

### 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 registries and toolchains, and read/write for build caches. In the `/sandbox policy` report, this appears as **dev-tool access**.

### Git repositories

When you work in a subdirectory of a Git repository, {% data variables.product.prodname_copilot_short %} grants **read** access to the whole repository so that commands can see the full project, while limiting **writes** to your current working directory and the repository's Git metadata (its `.git` directory). This lets a command read across the repository but keeps changes focused on where you are working.

Because read access spans the whole repository, a sandboxed command can read files outside your current subdirectory, including anything sensitive stored elsewhere in the project. To keep specific paths out of reach, you can add deny rules. See [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings).

## 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.

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.

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.

## Checking what the current policy allows

Because the policy is assembled for each directory and command, the simplest way to see the access you have is to ask {% data variables.copilot.copilot_cli_short %}. In a session, enter:

```shell copy
/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.

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.
* 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).

## 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).

## Enterprise-managed policies

If you get {% data variables.product.prodname_copilot_short %} through an enterprise-owned organization, an administrator can enforce a filesystem policy through managed settings. Managed settings act as a baseline that you cannot loosen: they can require sandboxing, add denied paths, and limit which paths you are allowed to grant. Where a managed setting applies, the `/sandbox config` dialog shows it as a locked **(managed)** value, and `/sandbox policy` reflects it in the resolved policy.

Unlike most settings, where a single source wins, the sandbox policy is composed from every source in force at once. Managed settings can arrive through more than one channel simultaneously—server-managed, MDM, and file-based—and these combine with each other, and with your own settings, in the **most restrictive** direction rather than one source overriding another: a required toggle stays on, denied paths from all sources add up, and the paths you are allowed to grant can only be narrowed. For more information, see [AUTOTITLE](/copilot/reference/enterprise-administrators/enterprise-managed-settings#sandbox).

## 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/configuring-local-sandbox-settings)
10 changes: 0 additions & 10 deletions content/copilot/concepts/copilot-usage-metrics/copilot-metrics.md
Original file line number Diff line number Diff line change
Expand Up @@ -166,13 +166,3 @@ These metrics can be used together to answer key questions about your teams' usa
| How do I act on the insights from the dashboard? | See [AUTOTITLE](/copilot/reference/copilot-usage-metrics/interpret-copilot-metrics#reviewing-adoption-cohorts) |

Look for patterns across these signals rather than focusing on any single number. For example, a steady DAU paired with a rising acceptance rate indicates growing trust and value.

## Next steps

Now that you understand what each {% data variables.product.prodname_copilot_short %} metric measures and how to use them, you can explore the dashboards to see these metrics in action.

* To view adoption and usage trends across your enterprise and organizations, see [AUTOTITLE](/copilot/how-tos/administer-copilot/view-usage-and-adoption).
* To analyze how code is being generated by users and agents, see [AUTOTITLE](/copilot/how-tos/administer-copilot/view-code-generation).
* To view adoption cohorts and depth of adoption, see [AUTOTITLE](/copilot/how-tos/administer-copilot/view-impact-dashboard).
* To access {% data variables.product.prodname_copilot_short %} usage metrics programmatically, see [AUTOTITLE](/rest/copilot/copilot-usage-metrics).
* To construct team-level metrics by aggregating per-user records, see [AUTOTITLE](/copilot/reference/copilot-usage-metrics/team-level-metrics).
Loading
Loading