From 5d3c3687c40eb252b2cd69a1bcadcc8dc99ee111 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 07:52:09 -0700 Subject: [PATCH 1/8] Consolidate Octokit construction on retryingGithub() (#62509) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: 9fa62c70-6b0e-40df-8a9e-88ec6807a878 --- .../clean-up-old-branches.ts | 12 ++---------- .../post-pr-comment.ts | 12 ++---------- src/workflows/content-changes-table-comment.ts | 8 ++------ src/workflows/github.ts | 9 +++++---- 4 files changed, 11 insertions(+), 30 deletions(-) diff --git a/src/links/scripts/validate-github-github-docs-urls/clean-up-old-branches.ts b/src/links/scripts/validate-github-github-docs-urls/clean-up-old-branches.ts index c7e408f8a15e..fd0228341f76 100644 --- a/src/links/scripts/validate-github-github-docs-urls/clean-up-old-branches.ts +++ b/src/links/scripts/validate-github-github-docs-urls/clean-up-old-branches.ts @@ -1,5 +1,4 @@ -import { Octokit } from '@octokit/rest' -import { retry } from '@octokit/plugin-retry' +import { retryingGithub } from '@/workflows/github' const DEFAULT_MIN_DAYS = 30 @@ -15,7 +14,7 @@ export async function cleanUpOldBranches(options: Options) { if (!process.env.GITHUB_TOKEN) { throw new Error('You must set the GITHUB_TOKEN environment variable.') } - const octokit = retryingOctokit(process.env.GITHUB_TOKEN) + const octokit = retryingGithub(process.env.GITHUB_TOKEN) const [owner, repo] = options.repository.split('/') const { data: refs } = await octokit.request( @@ -53,10 +52,3 @@ export async function cleanUpOldBranches(options: Options) { } } } - -function retryingOctokit(token: string) { - const RetryingOctokit = Octokit.plugin(retry) - return new RetryingOctokit({ - auth: `token ${token}`, - }) -} diff --git a/src/links/scripts/validate-github-github-docs-urls/post-pr-comment.ts b/src/links/scripts/validate-github-github-docs-urls/post-pr-comment.ts index 0baf13af9bf5..c02e4e368ade 100644 --- a/src/links/scripts/validate-github-github-docs-urls/post-pr-comment.ts +++ b/src/links/scripts/validate-github-github-docs-urls/post-pr-comment.ts @@ -1,9 +1,8 @@ import fs from 'fs' import boxen from 'boxen' -import { Octokit } from '@octokit/rest' -import { retry } from '@octokit/plugin-retry' +import { retryingGithub } from '@/workflows/github' import { type Check } from '../../lib/validate-docs-urls' type PostPRCommentOptions = { @@ -238,7 +237,7 @@ async function updateIssueComment( if (!process.env.GITHUB_TOKEN) { throw new Error('When not in dry-run mode, you must set the GITHUB_TOKEN environment variable.') } - const octokit = retryingOctokit(process.env.GITHUB_TOKEN) + const octokit = retryingGithub(process.env.GITHUB_TOKEN) const [owner, repo] = repository.split('/') const { data: existingComments } = await octokit.issues.listComments({ @@ -277,10 +276,3 @@ async function updateIssueComment( body, }) } - -function retryingOctokit(token: string) { - const RetryingOctokit = Octokit.plugin(retry) - return new RetryingOctokit({ - auth: `token ${token}`, - }) -} diff --git a/src/workflows/content-changes-table-comment.ts b/src/workflows/content-changes-table-comment.ts index b643c82b6c99..2fb037b3b97a 100755 --- a/src/workflows/content-changes-table-comment.ts +++ b/src/workflows/content-changes-table-comment.ts @@ -14,10 +14,9 @@ import * as github from '@actions/github' import * as core from '@actions/core' import walk from 'walk-sync' -import { Octokit } from '@octokit/rest' -import { retry } from '@octokit/plugin-retry' import { getContents } from './git-utils' +import { retryingGithub } from '@/workflows/github' import getApplicableVersions from '@/versions/lib/get-applicable-versions' import nonEnterpriseDefaultVersion from '@/versions/lib/non-enterprise-default-version' import { allVersionShortnames } from '@/versions/lib/all-versions' @@ -56,10 +55,7 @@ async function main(owner: string, repo: string, baseSHA: string, headSHA: strin throw new Error(`APP_URL environment variable not set`) } - const RetryingOctokit = Octokit.plugin(retry) - const octokit = new RetryingOctokit({ - auth: `token ${GITHUB_TOKEN}`, - }) + const octokit = retryingGithub(GITHUB_TOKEN) // get the list of file changes from the PR // this works even if the head commit is from a fork diff --git a/src/workflows/github.ts b/src/workflows/github.ts index b089e44c2811..4e8a319aec27 100644 --- a/src/workflows/github.ts +++ b/src/workflows/github.ts @@ -17,14 +17,15 @@ const RetryingOctokit = Octokit.plugin(retry) const apiToken = process.env.GITHUB_TOKEN // See https://github.com/octokit/rest.js/issues/1207 -export default function github() { +// Pass `token` to authenticate as something other than GITHUB_TOKEN. +export default function github(token?: string) { return new Octokit({ - auth: `token ${apiToken}`, + auth: `token ${token || apiToken}`, }) } -export function retryingGithub() { +export function retryingGithub(token?: string) { return new RetryingOctokit({ - auth: `token ${apiToken}`, + auth: `token ${token || apiToken}`, }) } From d97bc2d0cd9963d9f3d4085ad5c8534007488a41 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 07:52:18 -0700 Subject: [PATCH 2/8] Match juliangruber/approve-pull-request-action to one pinned SHA (#62508) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9fa62c70-6b0e-40df-8a9e-88ec6807a878 --- .github/workflows/sync-secret-scanning.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sync-secret-scanning.yml b/.github/workflows/sync-secret-scanning.yml index fc7128be1e4c..0c52d1346be0 100644 --- a/.github/workflows/sync-secret-scanning.yml +++ b/.github/workflows/sync-secret-scanning.yml @@ -70,7 +70,7 @@ jobs: - if: ${{ steps.create-pull-request.outputs.pull-request-number }} name: Approve - uses: juliangruber/approve-pull-request-action@dcc4effb325c0b503408619918d56e40653dcc91 + uses: juliangruber/approve-pull-request-action@68fcc9a5a73b5641cadf757cf99d73720dcb05d0 # v2.1.0 with: github-token: ${{ secrets.GITHUB_TOKEN }} number: ${{ steps.create-pull-request.outputs.pull-request-number }} From 13e33971fb20b9ceb2be7c2221cc4e9b9dbcebab Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 07:52:34 -0700 Subject: [PATCH 3/8] Use node-npm-setup consistently across workflows (#62507) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9fa62c70-6b0e-40df-8a9e-88ec6807a878 --- .github/workflows/docs-review-collect.yml | 10 ++-------- .github/workflows/link-check-external.yml | 3 --- .github/workflows/link-check-internal.yml | 3 --- .github/workflows/os-ready-for-review.yml | 10 ++-------- .github/workflows/sync-sdk-docs.yml | 10 ++-------- 5 files changed, 6 insertions(+), 30 deletions(-) diff --git a/.github/workflows/docs-review-collect.yml b/.github/workflows/docs-review-collect.yml index d4b0af64226f..d34402f0295a 100644 --- a/.github/workflows/docs-review-collect.yml +++ b/.github/workflows/docs-review-collect.yml @@ -22,14 +22,8 @@ jobs: - name: Check out repo content uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version-file: 'package.json' - cache: npm - - - name: Install dependencies - run: npm ci + - name: Set up Node and dependencies + uses: ./.github/actions/node-npm-setup - name: Run script for audit-log-allowlists run: | diff --git a/.github/workflows/link-check-external.yml b/.github/workflows/link-check-external.yml index b5c4915a3e24..36e3ef3d6561 100644 --- a/.github/workflows/link-check-external.yml +++ b/.github/workflows/link-check-external.yml @@ -29,9 +29,6 @@ jobs: - uses: ./.github/actions/node-npm-setup - - name: Install dependencies - run: npm ci - - name: Check external links id: check env: diff --git a/.github/workflows/link-check-internal.yml b/.github/workflows/link-check-internal.yml index 05d7ec35ab67..47d465e43ff4 100644 --- a/.github/workflows/link-check-internal.yml +++ b/.github/workflows/link-check-internal.yml @@ -83,9 +83,6 @@ jobs: uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - uses: ./.github/actions/node-npm-setup - - name: Install dependencies - run: npm ci - # Clone translations if not English - name: Clone translations if: matrix.language != 'en' diff --git a/.github/workflows/os-ready-for-review.yml b/.github/workflows/os-ready-for-review.yml index e8450aceefac..3fc45ee40284 100644 --- a/.github/workflows/os-ready-for-review.yml +++ b/.github/workflows/os-ready-for-review.yml @@ -47,14 +47,8 @@ jobs: echo Aborting. This workflow must be triggered by a member of the docs team. exit 1 - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version-file: 'package.json' - cache: npm - - - name: Install dependencies - run: npm ci + - name: Set up Node and dependencies + uses: ./.github/actions/node-npm-setup - name: Run script run: | diff --git a/.github/workflows/sync-sdk-docs.yml b/.github/workflows/sync-sdk-docs.yml index 919a731db676..92b8679dbb09 100644 --- a/.github/workflows/sync-sdk-docs.yml +++ b/.github/workflows/sync-sdk-docs.yml @@ -64,14 +64,8 @@ jobs: echo "SDK_TMP=$tmp" >> "$GITHUB_ENV" echo "Fetched copilot-sdk@${SDK_SHA::7}" - - name: Setup Node.js - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 - with: - node-version: 22 - cache: npm - - - name: Install dependencies - run: npm ci + - name: Set up Node and dependencies + uses: ./.github/actions/node-npm-setup - name: Install mermaid-cli run: npm install -g @mermaid-js/mermaid-cli@11 From d9b660d4efbd62b87031313104f1e539ed3f7932 Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 07:52:47 -0700 Subject: [PATCH 4/8] Fix stale workflow outputs always reporting zero (#62506) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9fa62c70-6b0e-40df-8a9e-88ec6807a878 --- .github/workflows/needs-sme-stale-check.yaml | 1 + .github/workflows/no-response.yaml | 1 + .github/workflows/stale.yml | 1 + .github/workflows/triage-stale-check.yml | 1 + 4 files changed, 4 insertions(+) diff --git a/.github/workflows/needs-sme-stale-check.yaml b/.github/workflows/needs-sme-stale-check.yaml index 97288588f967..9163a33da6f4 100644 --- a/.github/workflows/needs-sme-stale-check.yaml +++ b/.github/workflows/needs-sme-stale-check.yaml @@ -20,6 +20,7 @@ jobs: steps: - uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0 + id: stale with: only-labels: needs SME days-before-stale: 28 # adds stale label if no activity for 7 days - temporarily changed to 28 days as we work through the backlog diff --git a/.github/workflows/no-response.yaml b/.github/workflows/no-response.yaml index 7c515f978b2a..ea61071a39d0 100644 --- a/.github/workflows/no-response.yaml +++ b/.github/workflows/no-response.yaml @@ -34,6 +34,7 @@ jobs: !endsWith(github.actor, '[bot]') steps: - uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0 + id: stale with: repo-token: ${{ secrets.GITHUB_TOKEN }} only-labels: 'more-information-needed' diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index c9fd9ffefe48..fcad7134430b 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -22,6 +22,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0 + id: stale with: repo-token: ${{ secrets.GITHUB_TOKEN }} stale-pr-message: "It looks as if this pull request has been inactive for 30 days. We want to check in with you to see if you plan to continue working on it. If you do, please add a comment to let us know. If we don't hear from you, we will close this pull request after 14 days. If the PR has been reviewed by a writer and you think it's ready to merge, drop into [#docs-content](https://github-grid.enterprise.slack.com/archives/C0E9DK082) and ask us to merge it." diff --git a/.github/workflows/triage-stale-check.yml b/.github/workflows/triage-stale-check.yml index 01ed5e79d491..48ce1eee5afa 100644 --- a/.github/workflows/triage-stale-check.yml +++ b/.github/workflows/triage-stale-check.yml @@ -67,6 +67,7 @@ jobs: pull-requests: write steps: - uses: actions/stale@3a9db7e6a41a89f618792c92c0e97cc736e1b13f # v10.0.0 + id: stale with: repo-token: ${{ secrets.GITHUB_TOKEN }} only-labels: 'waiting for review' From e9b563cd8825f6d2fc2689af0b00368bae96f9ef Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 07:52:51 -0700 Subject: [PATCH 5/8] Bump vulnerable transitive deps within existing ranges (#62498) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3993852f-89f9-401f-a2f8-2753a3d0ad43 --- package-lock.json | 192 ++++++++++++++++++++++++++++------------------ 1 file changed, 117 insertions(+), 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index e0c9cfc1b916..2ed6f5cfc4b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2203,15 +2203,15 @@ } }, "node_modules/@next/env": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.6.tgz", - "integrity": "sha512-gd8HoHN4ufj73WmR3JmVolrpJR47ILK6LouP5xElPglaVxir6e1a7VzvTvDWkOoPXT9rkkTzyCxBu4yeZfZwcw==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.2.11.tgz", + "integrity": "sha512-0do5A3BJ2gxWr0ZCMcD6BhW+e595jyxdTl3rXTS6lOtD8ektMiW6CO+EPwt1Eca1DBnm90r/7GdiKWBKxH++DA==", "license": "MIT" }, "node_modules/@next/swc-darwin-arm64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.6.tgz", - "integrity": "sha512-ZJGkkcNfYgrrMkqOdZ7zoLa1TOy0qpcMfk/z4Mh/FKUz40gVO+HNQWqmLxf67Z5WB64DRp0dhEbyHfel+6sJUg==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.2.11.tgz", + "integrity": "sha512-wryL4pjKmDwGv2ox6+GZDFxvmtSRLqApBR8kL1j4+vhB7Z5vJC/zAnXpiR9Xkfzl0AS8WLMnsuGV/UKI67/rrw==", "cpu": [ "arm64" ], @@ -2225,9 +2225,9 @@ } }, "node_modules/@next/swc-darwin-x64": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.6.tgz", - "integrity": "sha512-v/YLBHIY132Ced3puBJ7YJKw1lqsCrgcNo2aRJlCEyQrrCeRJlvGlnmxhPxNQI3KE3N1DN5r9TPNPvka3nq5RQ==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.2.11.tgz", + "integrity": "sha512-aZl2j4f/fLyjQvOhv0Oe9UaMAQHolYpKhctsoYzplSumKJKPUmgjcf6545aBtysLTcu994TREd0+pSgNE4ohmg==", "cpu": [ "x64" ], @@ -2241,12 +2241,15 @@ } }, "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.6.tgz", - "integrity": "sha512-RPOvqlYBbcQjkz9VQQDZ2T2bARIjXZV1KFlt+V2Mr6SW/e4I9fcKsaA0hdyf2FHoTlsV2xnBd5Y912rP/1Ce6w==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.2.11.tgz", + "integrity": "sha512-5jEriyEnH/LWFy27L2ZG0XaLlyEJIjhsImEsiS9P563PKEVp2BVups/xfOucIrsvVntp11oNcZwjHvaDPYVB5g==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2257,12 +2260,15 @@ } }, "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.6.tgz", - "integrity": "sha512-URUTu1+dMkxJsPFgm+OeEvq9wf5sujw0EvgYy80TDGHTSLTnIHeqb0Eu8A3sC95IRgjejQL+kC4mw+4yPxiAXA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.2.11.tgz", + "integrity": "sha512-eIjcpx2fnnFSSkZDbTxy74KnokUXDjfoLClpWelfgHLf621aTqswhwXQ7GkD5K5rplrS6LZ/Bj+mVuvzluBOEg==", "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2273,12 +2279,15 @@ } }, "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.6.tgz", - "integrity": "sha512-DOj182mPV8G3UkrayLoREM5YEYI+Dk5wv7Ox9xl1fFibAELEsFD0lDPfHIeILlutMMfdyhlzYPELG3peuKaurw==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.2.11.tgz", + "integrity": "sha512-8WgzpaWMs46qJT9kiV47cje86L0x/Mu9t8/Gwj+pnbgW3rETVfCnaScPjlYUwNScpOozdcIMHWmAvuZJUonR2w==", "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -2289,12 +2298,15 @@ } }, "node_modules/@next/swc-linux-x64-musl": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.6.tgz", - "integrity": "sha512-HKQ5SP/V/ub73UvF7n/zeJlxk2kLmtL7Wzrg4WfmkjmNos5onJ2tKu7yZOPdL18A6Svfn3max29ym+ry7NkK4g==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.2.11.tgz", + "integrity": "sha512-I3UgPds7G4ZYnTb/H+5GBGuUT2DhAk6j0mL6A4s63RjFs74wB2hOWP0vaxsK+3NJraExt3eYEPQ/UtT0x/64Nw==", "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -2305,9 +2317,9 @@ } }, "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.6.tgz", - "integrity": "sha512-LZXpTlPyS5v7HhSmnvsLGP3iIYgYOBnc8r8ArlT55sGHV89bR2HlDdBjWQ+PY6SJMmk8TuVGFuxalnP3k/0Dwg==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.2.11.tgz", + "integrity": "sha512-n89CjtcThnjrwgJMAiI5xbqwLY51zvwC9tSlArmVndAJLYVl9T9UAdlkXTmZvE++idoXe8KdglQlhNRdUp1c6g==", "cpu": [ "arm64" ], @@ -2321,9 +2333,9 @@ } }, "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.6.tgz", - "integrity": "sha512-F0+4i0h9J6C4eE3EAPWsoCk7UW/dbzOjyzxY0qnDUOYFu6FFmdZ6l97/XdV3/Nz3VYyO7UWjyEJUXkGqcoXfMA==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.2.11.tgz", + "integrity": "sha512-md8CLNggS1Dx9pUgApzps5uAf+N8GN9xywzmNx9vHAWo94HtBwCCqkSnhIrdfQe83Dhz8Lfo/20Nb1Zxal092w==", "cpu": [ "x64" ], @@ -5924,20 +5936,20 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.1.tgz", - "integrity": "sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.0", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" }, "engines": { "node": ">=18" @@ -5947,6 +5959,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/body-parser/node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -8529,9 +8554,9 @@ "dev": true }, "node_modules/fast-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", - "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.4.tgz", + "integrity": "sha512-8JnbkQ4juDyvYs4mgFGQqg4yCYtFDtUtmp2QIQq11ZZe5CFQ5wcqm1rqDgAh/QdMySuBnPzMUiJUNZG5N/AiQw==", "funding": [ { "type": "github", @@ -9684,9 +9709,9 @@ } }, "node_modules/iconv-lite": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.0.tgz", - "integrity": "sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.3.tgz", + "integrity": "sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==", "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" @@ -9734,9 +9759,9 @@ "license": "ISC" }, "node_modules/immutable": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.5.tgz", - "integrity": "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.9.tgz", + "integrity": "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg==", "devOptional": true, "license": "MIT" }, @@ -10680,9 +10705,9 @@ } }, "node_modules/linkify-it": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz", - "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==", + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", "dev": true, "funding": [ { @@ -10738,9 +10763,9 @@ } }, "node_modules/liquidjs": { - "version": "10.27.0", - "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.27.0.tgz", - "integrity": "sha512-tw/OA59K7aIBlMKIrKlumr37fiZUheShVHXY8cVctWisgY1p9mc5hreOvlreoS0wTiwlWk14Ya7305c2a/Cg5w==", + "version": "10.27.2", + "resolved": "https://registry.npmjs.org/liquidjs/-/liquidjs-10.27.2.tgz", + "integrity": "sha512-kvknfAEtOHjHkAAv7GxLEJh8ghpMQm3Fc4uWVyF7hERSTsSRsdC7saWs0p5aDG7GDcWsu5o+T4232O+8KZO55w==", "license": "MIT", "dependencies": { "commander": "^10.0.0" @@ -12294,9 +12319,9 @@ "optional": true }, "node_modules/nanoid": { - "version": "3.3.11", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", - "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "version": "3.3.16", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.16.tgz", + "integrity": "sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==", "funding": [ { "type": "github", @@ -12342,12 +12367,12 @@ } }, "node_modules/next": { - "version": "16.2.6", - "resolved": "https://registry.npmjs.org/next/-/next-16.2.6.tgz", - "integrity": "sha512-qOVgKJg1+At15NpeUP+eJgCHvTCgXsogweq87Ri/Ix7PkqQHg4sdaXmSFqKlgaIXE4kW0g25LE68W87UANlHtw==", + "version": "16.2.11", + "resolved": "https://registry.npmjs.org/next/-/next-16.2.11.tgz", + "integrity": "sha512-B339zaqbyK8cmxhoAvLrcwoabwCP1wz21zSzfqxqXAemTu2BXnH7tQnfcglKv1vnMUIDBc+Hth7XODQriTZiRQ==", "license": "MIT", "dependencies": { - "@next/env": "16.2.6", + "@next/env": "16.2.11", "@swc/helpers": "0.5.15", "baseline-browser-mapping": "^2.9.19", "caniuse-lite": "^1.0.30001579", @@ -12361,14 +12386,14 @@ "node": ">=20.9.0" }, "optionalDependencies": { - "@next/swc-darwin-arm64": "16.2.6", - "@next/swc-darwin-x64": "16.2.6", - "@next/swc-linux-arm64-gnu": "16.2.6", - "@next/swc-linux-arm64-musl": "16.2.6", - "@next/swc-linux-x64-gnu": "16.2.6", - "@next/swc-linux-x64-musl": "16.2.6", - "@next/swc-win32-arm64-msvc": "16.2.6", - "@next/swc-win32-x64-msvc": "16.2.6", + "@next/swc-darwin-arm64": "16.2.11", + "@next/swc-darwin-x64": "16.2.11", + "@next/swc-linux-arm64-gnu": "16.2.11", + "@next/swc-linux-arm64-musl": "16.2.11", + "@next/swc-linux-x64-gnu": "16.2.11", + "@next/swc-linux-x64-musl": "16.2.11", + "@next/swc-win32-arm64-msvc": "16.2.11", + "@next/swc-win32-x64-msvc": "16.2.11", "sharp": "^0.34.5" }, "peerDependencies": { @@ -13573,9 +13598,9 @@ } }, "node_modules/postcss": { - "version": "8.5.14", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.14.tgz", - "integrity": "sha512-SoSL4+OSEtR99LHFZQiJLkT59C5B1amGO1NzTwj7TT1qCUgUO6hxOvzkOYxD+vMrXBM3XJIKzokoERdqQq/Zmg==", + "version": "8.5.21", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.21.tgz", + "integrity": "sha512-v4sDNP3fdNiWMfabO7OwOQdOX8TiQSztKyT1Wj0w+j7LDallJThJRBBBmzVGyYj0crMh7jlV4zepPkiNu9UwDQ==", "funding": [ { "type": "opencollective", @@ -13592,7 +13617,7 @@ ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.11", + "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -15700,17 +15725,34 @@ } }, "node_modules/type-is": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.0.1.tgz", - "integrity": "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", "license": "MIT", "dependencies": { - "content-type": "^1.0.5", + "content-type": "^2.0.0", "media-typer": "^1.1.0", "mime-types": "^3.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/type-is/node_modules/mime-db": { From a3946c708f7c2c736e35579147281df2359c499c Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Wed, 29 Jul 2026 08:21:17 -0700 Subject: [PATCH 6/8] Fix always-false instanceof RequestError checks and dedupe retry logic (#62510) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: 9fa62c70-6b0e-40df-8a9e-88ec6807a878 --- src/workflows/git-utils.ts | 65 ++++------------------ src/workflows/github.ts | 15 +++++ src/workflows/secondary-ratelimit-retry.ts | 10 +--- src/workflows/tests/github.ts | 57 +++++++++++++++++++ 4 files changed, 85 insertions(+), 62 deletions(-) create mode 100644 src/workflows/tests/github.ts diff --git a/src/workflows/git-utils.ts b/src/workflows/git-utils.ts index 05e82e78a4df..ed328820e34f 100644 --- a/src/workflows/git-utils.ts +++ b/src/workflows/git-utils.ts @@ -1,9 +1,8 @@ import crypto from 'crypto' import fs from 'fs/promises' -import { RequestError } from '@octokit/request-error' - -import { retryingGithub } from './github' +import { isRequestError, retryingGithub } from '@/workflows/github' +import { octoSecondaryRatelimitRetry } from '@/workflows/secondary-ratelimit-retry' const github = retryingGithub() // https://docs.github.com/rest/reference/git#get-a-reference @@ -31,7 +30,7 @@ export async function hasMatchingRef(owner: string, repo: string, ref: string) { }) return true } catch (err) { - if (err instanceof RequestError && err.status === 404) { + if (isRequestError(err, 404)) { return false } console.log('error getting matching ref', owner, repo, ref) @@ -220,11 +219,13 @@ async function searchCode( } try { - const { data } = await secondaryRateLimitRetry(github.rest.search.code, { - q, - per_page: perPage, - page: currentPage, - }) + const { data } = await octoSecondaryRatelimitRetry(() => + github.rest.search.code({ + q, + per_page: perPage, + page: currentPage, + }), + ) if (cache) { await fs.writeFile(tempFilename, JSON.stringify(data)) console.log(`Wrote search results to ${tempFilename}`) @@ -237,52 +238,6 @@ async function searchCode( } } -async function secondaryRateLimitRetry>( - callable: (args: TArgs) => Promise, - args: TArgs, - maxAttempts = 10, - sleepTime = 1000, -): Promise { - try { - const response = await callable(args) - return response - } catch (err: unknown) { - // If you get a secondary rate limit error (403) you'll get a data - // response that includes: - // - // { - // documentation_url: 'https://docs.github.com/en/free-pro-team@latest/rest/overview/resources-in-the-rest-api#secondary-rate-limits', - // message: 'You have exceeded a secondary rate limit. Please wait a few minutes before you try again.' - // } - // - // Let's look for that an manually self-recurse, under certain conditions - const lookFor = 'You have exceeded a secondary rate limit.' - if ( - err instanceof RequestError && - err.status === 403 && - typeof err.response?.data === 'object' && - err.response?.data !== null && - 'message' in err.response.data && - typeof (err.response.data as Record).message === 'string' && - (err.response.data as Record).message.includes(lookFor) && - maxAttempts > 0 - ) { - console.warn( - `Got secondary rate limit blocked. Sleeping for ${ - sleepTime / 1000 - } seconds. (attempts left: ${maxAttempts})`, - ) - return new Promise((resolve) => { - setTimeout(() => { - resolve(secondaryRateLimitRetry(callable, args, maxAttempts - 1, sleepTime * 2)) - }, sleepTime) - }) - } - - throw err - } -} - // Recursively gets the contents of a directory within a repo. Returns an // array of file contents. This function could be modified to return an array // of objects that include the path and the content of the file if needed diff --git a/src/workflows/github.ts b/src/workflows/github.ts index 4e8a319aec27..33f48b665af4 100644 --- a/src/workflows/github.ts +++ b/src/workflows/github.ts @@ -29,3 +29,18 @@ export function retryingGithub(token?: string) { auth: `token ${token || apiToken}`, }) } + +// Duck-typing instead of `instanceof RequestError` on purpose. +// `@octokit/request` throws a RequestError built from its own nested copy of +// `@octokit/request-error`, which is a different module instance than the +// top-level one. The two classes are not identical, so `instanceof` always +// returns false across that boundary. +export function isRequestError( + error: unknown, + status?: number, +): error is Error & { status: number } { + if (!(error instanceof Error) || !('status' in error)) return false + const errorStatus = (error as { status: unknown }).status + if (typeof errorStatus !== 'number') return false + return status === undefined || errorStatus === status +} diff --git a/src/workflows/secondary-ratelimit-retry.ts b/src/workflows/secondary-ratelimit-retry.ts index c70cb8ab9370..33049015f401 100644 --- a/src/workflows/secondary-ratelimit-retry.ts +++ b/src/workflows/secondary-ratelimit-retry.ts @@ -1,3 +1,5 @@ +import { isRequestError } from '@/workflows/github' + const DEFAULT_SLEEPTIME = parseInt(process.env.SECONDARY_RATELIMIT_RETRY_SLEEPTIME || '30000', 10) const DEFAULT_ATTEMPTS = parseInt(process.env.SECONDARY_RATELIMIT_RETRY_ATTEMPTS || '5', 10) @@ -14,14 +16,8 @@ export async function octoSecondaryRatelimitRetry( try { return await fn() } catch (error) { - // Use duck-typing instead of `instanceof RequestError` because octokit - // bundles its own copy of @octokit/request-error in dist-bundle/index.js, - // so the class reference differs from the top-level package and instanceof - // always returns false across the module boundary. if ( - error instanceof Error && - 'status' in error && - (error as { status: number }).status === 403 && + isRequestError(error, 403) && /You have exceeded a secondary rate limit/.test(error.message) ) { if (tries < attempts) { diff --git a/src/workflows/tests/github.ts b/src/workflows/tests/github.ts new file mode 100644 index 000000000000..2a1f8310416d --- /dev/null +++ b/src/workflows/tests/github.ts @@ -0,0 +1,57 @@ +import { createRequire } from 'node:module' + +import { describe, expect, test } from 'vitest' +import { RequestError } from '@octokit/request-error' + +import { isRequestError } from '@/workflows/github' + +// `@octokit/request` throws errors built from whichever copy of +// `@octokit/request-error` resolves from its own location, which npm may or may +// not hoist to the top level. Resolve it the same way Node would so this test +// keeps working either way. When it is a separate copy, `instanceof` against the +// top-level class fails, and that is the whole reason `isRequestError` exists. +const requireFromRequest = createRequire(createRequire(import.meta.url).resolve('@octokit/request')) +const nested = await import(requireFromRequest.resolve('@octokit/request-error')) + +function makeError(RequestErrorClass: typeof RequestError, status: number, message: string): Error { + return new RequestErrorClass(message, status, { + request: { method: 'GET', url: 'https://api.github.com/x', headers: {} }, + response: { status, url: 'https://api.github.com/x', headers: {}, data: { message } }, + }) +} + +describe('isRequestError', () => { + test('matches an error thrown from the copy @octokit/request uses', () => { + const err = makeError(nested.RequestError, 404, 'Not Found') + // When npm does not hoist to a single copy, this is the case a plain + // `instanceof RequestError` gets wrong. + if (nested.RequestError !== RequestError) { + expect(err instanceof RequestError).toBe(false) + } + expect(isRequestError(err)).toBe(true) + expect(isRequestError(err, 404)).toBe(true) + }) + + test('matches an error from the top-level request-error copy', () => { + const err = makeError(RequestError, 403, 'Forbidden') + expect(isRequestError(err, 403)).toBe(true) + }) + + test('respects the status argument', () => { + const err = makeError(nested.RequestError, 404, 'Not Found') + expect(isRequestError(err, 403)).toBe(false) + }) + + test('rejects non-request errors and non-errors', () => { + expect(isRequestError(new Error('nope'))).toBe(false) + expect(isRequestError({ status: 404 })).toBe(false) + expect(isRequestError(undefined)).toBe(false) + expect(isRequestError(null)).toBe(false) + expect(isRequestError('404')).toBe(false) + }) + + test('rejects an error whose status is not a number', () => { + const err = Object.assign(new Error('weird'), { status: '404' }) + expect(isRequestError(err)).toBe(false) + }) +}) From 2e104a03197a608517b09f5968798760d1d182c3 Mon Sep 17 00:00:00 2001 From: Copilot <198982749+Copilot@users.noreply.github.com> Date: Wed, 29 Jul 2026 16:59:02 +0100 Subject: [PATCH 7/8] Clarify Copilot checkout authorization holds and activation (#61848) Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bot-digital-customer-success <121182491+bot-digital-customer-success@users.noreply.github.com> Co-authored-by: Daniel Klemm Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com> --- .../get-started-with-a-copilot-plan.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/content/copilot/how-tos/manage-your-account/get-started-with-a-copilot-plan.md b/content/copilot/how-tos/manage-your-account/get-started-with-a-copilot-plan.md index 723ddc65d3a6..dd8a72ce47d9 100644 --- a/content/copilot/how-tos/manage-your-account/get-started-with-a-copilot-plan.md +++ b/content/copilot/how-tos/manage-your-account/get-started-with-a-copilot-plan.md @@ -94,4 +94,19 @@ You can subscribe to {% data variables.copilot.copilot_pro_short %}, {% data var 1. To enable usage beyond your included allowance, select **Yes, I want to enable additional usage for {% data variables.product.prodname_copilot_short %}**. You can change this setting at any time. Click **Save & continue**. 1. Follow the steps to enter and confirm your billing information and payment details, then click **Submit**. + + During checkout, {% data variables.product.github %} may place a temporary authorization hold on your payment method to verify it. This hold is not the subscription charge. + + If payment method verification does not succeed, or if you do not complete the activation step on the next screen, your plan will not activate. + 1. After reviewing your plan details, click **Activate {% data variables.copilot.copilot_pro_short %}/{% data variables.copilot.copilot_pro_plus_short %}/{% data variables.copilot.copilot_max_short %}**. + +## Troubleshooting + +### Account still shows {% data variables.copilot.copilot_free_short %} after checkout + +If the plan does not appear after following the checkout steps [when subscribing](#subscribing-to-copilot-pro-copilot-pro-or-copilot-max), follow these further steps to confirm and recover your subscription. + +1. Confirm that the plan appears in your {% data variables.product.prodname_copilot %} settings or in your personal account settings under **Billing & licensing**. For more information, see [AUTOTITLE](/copilot/how-tos/manage-your-account/view-and-change-your-copilot-plan). +1. If payment method verification failed or you did not complete the activation step, retry the checkout flow. +1. If you completed activation and the plan still does not appear, contact {% data variables.contact.contact_support_page %}. From a0ac750ea52cc7505a9a23eb66a6c4725e11104d Mon Sep 17 00:00:00 2001 From: hubwriter Date: Wed, 29 Jul 2026 17:26:08 +0100 Subject: [PATCH 8/8] New Capabilities in Copilot CLI Local Sandboxes [updated public preview] (#62379) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> Copilot-Session: 39cc466b-6286-4c9e-8aa7-2cc0eb953158 --- .../style-guide-summary.instructions.md | 2 +- content/billing/concepts/billing-cycles.md | 7 -- .../cloud-and-local-sandboxes.md | 20 ++-- .../reference/product-and-sku-names.md | 10 +- .../about-cloud-and-local-sandboxes.md | 79 ++++++++++++---- .../copilot-cli/about-cli-extensions.md | 2 +- .../agents/copilot-cli/about-copilot-cli.md | 8 +- .../concepts/agents/copilot-cli/autopilot.md | 4 + .../concepts/agents/github-copilot-app.md | 2 +- .../configure-enterprise-managed-settings.md | 2 +- .../configuring-local-sandbox-settings.md | 92 +++++++++++-------- ...g-cloud-sandboxes-for-your-organization.md | 31 +++++-- .../cloud-and-local-sandboxes/index.md | 7 +- .../using-local-sandboxing.md | 90 ++++++++++++++++++ .../run-cli-programmatically.md | 2 +- .../automate-copilot-cli/schedule-prompts.md | 2 +- .../customize-copilot/add-mcp-servers.md | 2 +- .../configure-copilot-cli.md | 12 ++- .../use-copilot-cli/allowing-tools.md | 6 +- .../copilot-cli/use-copilot-cli/overview.md | 6 +- .../use-copilot-cli/roll-back-changes.md | 4 +- .../cli-command-reference.md | 7 +- .../enterprise-managed-settings-reference.md | 2 +- .../copilot/tutorials/create-an-extension.md | 6 +- .../cli/public-preview-local-sandbox.md | 2 + data/reusables/cli/public-preview-sandbox.md | 2 +- data/reusables/cli/sandbox-on-windows.md | 2 + data/reusables/copilot/disable-bypass.md | 2 +- data/variables/copilot.yml | 6 -- 29 files changed, 297 insertions(+), 122 deletions(-) create mode 100644 content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md create mode 100644 data/reusables/cli/public-preview-local-sandbox.md create mode 100644 data/reusables/cli/sandbox-on-windows.md diff --git a/.github/instructions/style-guide-summary.instructions.md b/.github/instructions/style-guide-summary.instructions.md index 6011bd1e808f..6e46a0ab1f11 100644 --- a/.github/instructions/style-guide-summary.instructions.md +++ b/.github/instructions/style-guide-summary.instructions.md @@ -59,7 +59,7 @@ For Liquid variable usage, reusables, linking conventions, bullet-list markers, ## Lists -* Capitalize the first letter of each list item. +* Capitalize the first letter of each list item, including the first letter after the colon in a term definition list (for example, `* **Filesystem**: Grant read-only access...`). * Use periods only if the item is a complete sentence. * Introduce lists with a descriptive sentence, not vague phrases like "the following" in isolation. diff --git a/content/billing/concepts/billing-cycles.md b/content/billing/concepts/billing-cycles.md index e284f9847a35..1e453badf5b6 100644 --- a/content/billing/concepts/billing-cycles.md +++ b/content/billing/concepts/billing-cycles.md @@ -35,13 +35,6 @@ For example, if you started a paid plan or converted from a trial on the 15th of > [!NOTE] > From **December 1, 2025**, all self-serve, metered {% data variables.product.prodname_ghe_cloud %} accounts that pay by credit card will migrate to a **billing date** of 1st of the month. See [Billing date standardized to the first of the month for self-serve credit card metered Enterprise customers](https://github.blog/changelog/2025-11-17-billing-date-standardized-to-the-first-of-the-month-for-self-serve-credit-card-metered-enterprise-customers-now-generally-available/) in the changelog. -## Billing cycle for {% data variables.copilot.sandbox %} during public preview - -During {% data variables.release-phases.public_preview %}, eligible accounts receive a **$10 monthly entitlement** for cloud sandbox usage through the end of **July 2026**. The entitlement applies as follows: - -* Usage above the entitlement is metered against your standard billing cycle and billed on your normal billing date. -* The entitlement is discontinued after July 2026. Pricing and packaging after the preview is subject to change. - ## Billing cycles for volume-based products Volume-based licenses may follow a different billing cycle. These products are often billed based on the anniversary date of your subscription rather than by calendar month. 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 c3ea3baecfa2..7121d03d3572 100644 --- a/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md +++ b/content/billing/concepts/product-billing/cloud-and-local-sandboxes.md @@ -1,7 +1,7 @@ --- -title: Billing for {% data variables.copilot.sandbox %} +title: Billing for cloud and local sandboxes for {% data variables.product.prodname_copilot %} shortTitle: Cloud and local sandboxes -intro: 'Learn how usage of {% data variables.copilot.sandbox %} is measured and billed.' +intro: 'Learn how usage of {% data variables.product.prodname_copilot_short %} cloud and local sandboxes is measured and billed.' versions: fpt: '*' ghec: '*' @@ -12,7 +12,7 @@ category: {% data reusables.cli.public-preview-sandbox %} -## How {% data variables.copilot.sandbox %} usage is measured +## How sandbox usage is measured Billing applies to cloud sandboxing only. Local sandboxing is included in the standard {% data variables.product.prodname_copilot %} seat at no additional cost. @@ -34,9 +34,9 @@ The memory meter tracks the memory allocated to a cloud sandbox while it is runn ### Storage -The storage meter tracks snapshot storage for stopped sessions. When you stop {% data variables.copilot.sandbox_short %}, {% data variables.product.github %} retains a snapshot of the sandbox's state so you can resume it later. Snapshot storage is metered from the time the sandbox is stopped until the sandbox is deleted. +The storage meter tracks snapshot storage for stopped sessions. When you stop a cloud sandbox, {% data variables.product.github %} retains a snapshot of the sandbox's state so you can resume it later. Snapshot storage is metered from the time the sandbox is stopped until the sandbox is deleted. -For more information about {% data variables.copilot.sandbox %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +For more information about cloud and local sandboxes, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). ## Free and billed use @@ -58,7 +58,11 @@ You pay for cloud sandboxes using the payment method set up for your {% data var ## How costs are assigned to a billable account -Cloud sandbox usage is billed to the organization that owns the sandbox. When you create a cloud sandbox session with `copilot --cloud`, you are prompted to select the owning organization. All usage for that session is billed to the selected organization. +Cloud sandbox usage is billed to the account that owns the sandbox. + +You are prompted to select an owner for the session only if you are not currently in a Git repository. In this case, when you create a cloud sandbox session with `copilot ‑‑cloud`, you are prompted to select an owner—your own personal account is listed first, ahead of any organizations you belong to. You must choose either your personal account or one of the listed organizations, and all usage for that session is billed to the account you select. + +If you are in a repository, the owner of the repository is billed and no owner selection is required. ## Managing your budget for cloud sandboxes @@ -74,9 +78,9 @@ When you create a budget for cloud sandboxes, you can choose between two budget If you enable **Stop usage when budget limit is reached**, additional cloud sandbox usage is blocked once the budget reaches 100%, and a banner notifies users in the affected scope. > [!NOTE] -> {% data variables.copilot.sandbox_caps %} is not part of the "Bundled AI credits" budget type. Bundled AI credits budgets apply only to SKUs that consume AI credits (such as {% data variables.product.prodname_copilot %} AI credits, cloud agent AI credits, and {% data variables.product.prodname_spark %} AI credits). To control cloud sandbox spending, use a product-level or SKU-level budget. +> Cloud sandboxes for {% data variables.product.prodname_copilot %} are not part of the "Bundled AI credits" budget type. Bundled AI credits budgets apply only to SKUs that consume AI credits (such as {% data variables.product.prodname_copilot %} AI credits, cloud agent AI credits, and {% data variables.product.prodname_spark %} AI credits). To control cloud sandbox spending, use a product-level or SKU-level budget. -## Viewing your {% data variables.copilot.sandbox %} usage +## Viewing your cloud sandbox usage To view your cloud sandbox usage, billable amounts, and the monthly preview entitlement, see [AUTOTITLE](/billing/how-tos/products/estimate-spending) and [AUTOTITLE](/billing/tutorials/gather-insights). diff --git a/content/billing/reference/product-and-sku-names.md b/content/billing/reference/product-and-sku-names.md index c218851b4f28..15262c6dfb6d 100644 --- a/content/billing/reference/product-and-sku-names.md +++ b/content/billing/reference/product-and-sku-names.md @@ -22,7 +22,7 @@ For **ProductPricing** budgets or to query usage by product, use one of the foll * `copilot` - {% data variables.product.prodname_copilot %} * `ghas` - {% data variables.product.prodname_GH_advanced_security %} * `ghec` - {% data variables.product.prodname_ghe_cloud %} -* `sandbox` - {% data variables.copilot.sandbox_caps %} +* `sandbox` - Cloud and local sandboxes for {% data variables.product.prodname_copilot %} ## SKU-level identifiers @@ -94,11 +94,11 @@ For **SkuPricing** budgets or to query usage by SKU, use one of the following va * `ghas_licenses` - GHAS licenses * `ghas_secret_protection_licenses` - GHAS secret protection licenses -### {% data variables.copilot.sandbox_caps %} SKUs +### Cloud and local sandboxes for {% data variables.product.prodname_copilot %} SKUs -* `sandbox_linux` - {% data variables.copilot.sandbox_short_caps %} Linux -* `sandbox_memory` - {% data variables.copilot.sandbox_short_caps %} Memory -* `sandbox_snapshot` - {% data variables.copilot.sandbox_short_caps %} Snapshot +* `sandbox_linux` - Sandboxes for {% data variables.product.prodname_copilot %}: Linux +* `sandbox_memory` - Sandboxes for {% data variables.product.prodname_copilot %}: Memory +* `sandbox_snapshot` - Sandboxes for {% data variables.product.prodname_copilot %}: Snapshot ### Other SKUs diff --git a/content/copilot/concepts/about-cloud-and-local-sandboxes.md b/content/copilot/concepts/about-cloud-and-local-sandboxes.md index 57a68ea8f409..6ce90a9c79ae 100644 --- a/content/copilot/concepts/about-cloud-and-local-sandboxes.md +++ b/content/copilot/concepts/about-cloud-and-local-sandboxes.md @@ -1,8 +1,8 @@ --- -title: About {% data variables.copilot.sandbox %} +title: About cloud and local sandboxes for {% data variables.product.prodname_copilot %} shortTitle: Cloud and local sandboxes allowTitleToDifferFromFilename: true -intro: '{% data variables.copilot.sandbox_caps %} provide isolated execution environments that let {% data variables.product.prodname_copilot_short %} safely interact with code, tools, filesystem, and network resources securely on your local machine or in fully isolated cloud environments.' +intro: 'Cloud and local sandboxes provide isolated execution environments that let {% data variables.product.prodname_copilot_short %} safely interact with code, tools, filesystem, and network resources securely on your local machine or in fully isolated cloud environments.' versions: feature: copilot redirect_from: @@ -19,17 +19,30 @@ docsTeamMetrics: ## Introduction -{% data variables.copilot.sandbox_caps %} are the execution platform powering secure sandboxed experiences for {% data variables.copilot.copilot_cli %}, both locally and in the cloud. As {% data variables.product.prodname_copilot_short %} takes more actions on your behalf—running tools, executing commands, and modifying files—{% data variables.copilot.sandbox_short %} provide the isolation, portability, and policy controls needed to adopt agentic workflows safely. {% data variables.copilot.sandbox_caps %} currently apply to {% data variables.copilot.copilot_cli_short %} sessions, and you can also use cloud sandboxes for sessions in the {% data variables.copilot.github_copilot_app %}. +{% data variables.product.prodname_copilot_short %} cloud and local sandboxes are the execution platform powering secure sandboxed experiences for {% data variables.copilot.copilot_cli %}, both locally and in the cloud. As {% data variables.product.prodname_copilot_short %} takes more actions on your behalf—running tools, executing commands, and modifying files—sandboxing provides the isolation, portability, and policy controls needed to adopt agentic workflows safely. -With {% data variables.copilot.sandbox %}, you can choose where {% data variables.product.prodname_copilot_short %} runs: +Sandboxing currently applies to {% data variables.copilot.copilot_cli_short %} sessions. You can also choose to use cloud sandboxing when you start a new session in the {% data variables.copilot.github_copilot_app %}. For more information, see [AUTOTITLE](/copilot/how-tos/github-copilot-app/agent-sessions#starting-a-session). -* **Local sandboxing**: Run {% data variables.product.prodname_copilot_short %} securely on your own machine, with restricted access to filesystem, network, and system capabilities. -* **Cloud sandboxing**: Run {% data variables.product.prodname_copilot_short %} inside fully isolated, ephemeral Linux environments hosted by {% data variables.product.github %}. +With sandboxing, you can choose where {% data variables.product.prodname_copilot_short %} runs: + +* **Local sandboxing**: Run {% data variables.product.prodname_copilot_short %} securely on your own machine. The commands that {% data variables.product.prodname_copilot_short %} runs have restricted access to your filesystem, network, and system capabilities. You can use local sandboxing at no extra charge. +* **Cloud sandboxing**: Run the entire {% data variables.copilot.copilot_cli_short %} session remotely, inside a fully isolated, ephemeral Linux environment hosted by {% data variables.product.github %}. Cloud sandboxing is billed based on usage. ## Local sandboxing +> [!NOTE] +> Local 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. + 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. +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. + +### How local sandboxing works + +Local sandboxing is powered by Microsoft eXecution Container (MXC), a cross-platform technology that provides a common interface to the isolation mechanisms available on each operating system. {% data variables.copilot.copilot_cli_short %} declares the sandbox policy it wants to enforce—which paths are readable or writable, whether network access is allowed, and so on—and MXC applies that policy using the appropriate isolation backend for your operating system. + +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. + ### Enabling local sandboxing To enable local sandboxing inside a {% data variables.copilot.copilot_cli_short %} session, run: @@ -38,15 +51,38 @@ To enable local sandboxing inside a {% data variables.copilot.copilot_cli_short /sandbox enable ``` -Once enabled, commands that {% data variables.product.prodname_copilot_short %} executes on your behalf run inside the sandbox, limiting their access to your system. +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. + +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, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing). + +### Configuring local sandboxing + +You can use the default local sandboxing behavior, or you can modify what {% data variables.product.prodname_copilot_short %} can access. When you configure local sandboxing, 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. +* **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, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). ### Cross-platform support -Local sandboxing is available on macOS and Linux. Sandboxing support and isolation behavior vary by platform because each operating system uses a different sandboxing backend. Windows is supported on Windows Insiders builds. For details on current limitations, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings). +Local sandboxing is available on macOS and Linux, and on Windows Insiders builds. Support and isolation behavior vary by platform because each operating system uses a different isolation backend: + +* **macOS** uses the Seatbelt backend (`sandbox-exec`). +* **Linux** uses the bubblewrap backend, which requires the `bwrap` command to be installed and available on your `PATH`. If `/sandbox` reports that sandboxing isn't supported on Linux, install bubblewrap. +* **Windows** uses the ProcessContainer backend. + +Because each platform uses a different backend, a few policy options behave differently. Most notably, on Windows the sandbox cannot block individual paths, so any denied-path rules you add are ignored there. Instead of denying a path on Windows, grant access only to the specific directories that {% data variables.product.prodname_copilot_short %} needs, rather than granting a broad directory and then trying to exclude part of it. This keeps a sensitive location out of the sandbox's reach even though denied paths aren't enforced. Denied paths are enforced on macOS and Linux. ### Enterprise policy enforcement -For organizations and enterprises, local sandbox policies can be centrally configured and enforced using Microsoft Intune and other MDM (mobile device management) platforms. This gives administrators control over how {% data variables.product.prodname_copilot_short %} interacts with local resources across managed devices. +For organizations and enterprises, local sandbox policies can be centrally configured and enforced using Microsoft Intune and other MDM (mobile device management) platforms. This gives administrators control over how {% data variables.product.prodname_copilot_short %} interacts with local resources across managed devices. See [Deploying MDM-managed settings](/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/configure-enterprise-managed-settings#deploying-mdm-managed-settings). ## Cloud sandboxing @@ -54,15 +90,26 @@ Cloud sandboxing lets you run {% data variables.copilot.copilot_cli_short %} ses Cloud sandboxing is built on Azure Container Apps Sandboxes, with {% data variables.product.github %} providing the identity, policy, and billing layer. +> [!NOTE] +> If you get {% data variables.product.prodname_copilot_short %} through an organization, access to cloud sandboxing depends on it being enabled in the organization or enterprise settings, where it is disabled by default. For more information, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization). + ### Starting a cloud sandbox session To start a cloud-backed session, run the following command: ```shell copy -copilot --cloud +copilot ‑‑cloud ‑‑experimental ``` -This launches an interactive {% data variables.copilot.copilot_cli_short %} session inside a cloud sandbox. You can prompt {% data variables.product.prodname_copilot_short %} to perform tasks, run shell commands, and iterate on code, the same way you would in a local session. The commands that {% data variables.product.prodname_copilot_short %} runs execute in the cloud environment, not on your local machine. +> [!NOTE] +> Cloud sandboxing is currently an experimental feature. To use it, you must have experimental features enabled for {% data variables.copilot.copilot_cli_short %}—for example, by using the `‑‑experimental` command line option when starting a CLI session, as shown above. + +The `‑‑cloud` command line option launches an interactive {% data variables.copilot.copilot_cli_short %} session inside a cloud sandbox. You can prompt {% data variables.product.prodname_copilot_short %} to perform tasks, run shell commands, and iterate on code, the same way you would in a local session. The commands that {% data variables.product.prodname_copilot_short %} runs execute in the cloud environment, not on your local machine. + +Running `copilot ‑‑cloud` starts a single {% data variables.copilot.copilot_cli_short %} session in a cloud sandbox. It does not affect future {% data variables.product.prodname_copilot_short %} sessions. Each time you want to run a new session in a cloud sandbox, you must start the CLI with the `‑‑cloud` option. + +> [!NOTE] +> Cloud sandboxing is only available for interactive {% data variables.copilot.copilot_cli_short %} sessions. You can't run the CLI programmatically in a cloud sandbox—that is, you can't combine the `‑‑cloud` option with the `-p` or `-i` options. ### Continue sessions across devices @@ -88,11 +135,11 @@ When you stop a session, the cloud sandbox creates a snapshot of its state so yo ## Authentication and access -{% data variables.copilot.sandbox_short_caps %} use your existing {% data variables.copilot.copilot_cli_short %} authentication. If you can sign in to {% data variables.copilot.copilot_cli_short %} and have access to {% data variables.product.prodname_copilot_short %}, you can use {% data variables.copilot.sandbox_short %}. You don't need to configure a separate cloud provider, manage API keys, or set up infrastructure. +Sandboxing uses your existing {% data variables.copilot.copilot_cli_short %} authentication. If you can sign in to {% data variables.copilot.copilot_cli_short %} and have access to {% data variables.product.prodname_copilot_short %}, you can use sandboxing. You don't need to configure a separate cloud provider, manage API keys, or set up infrastructure. -An organization or enterprise owner must enable the **Cloud Sandbox access** policy in the organization or enterprise settings before members can use {% data variables.copilot.sandbox_short %}. +An organization or enterprise owner must enable the **Cloud Sandbox access** policy in the organization or enterprise settings before members can use cloud sandboxes. -For information about signing in to {% data variables.copilot.copilot_cli_short %}, see [AUTOTITLE](/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli). +For information about enabling or disabling cloud sandboxes for members of your organization, see [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-sandboxes-for-your-organization). ## Billing @@ -111,5 +158,5 @@ For more information about how cloud sandbox usage is measured and billed, see [ ## Further reading * [AUTOTITLE](/copilot/concepts/agents/copilot-cli/about-copilot-cli) -* [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/install-copilot-cli) +* [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing) +* [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings) diff --git a/content/copilot/concepts/agents/copilot-cli/about-cli-extensions.md b/content/copilot/concepts/agents/copilot-cli/about-cli-extensions.md index 8b8899350785..03eb95a39b08 100644 --- a/content/copilot/concepts/agents/copilot-cli/about-cli-extensions.md +++ b/content/copilot/concepts/agents/copilot-cli/about-cli-extensions.md @@ -53,7 +53,7 @@ The two locations follow exactly the same structure—a named subdirectory conta Extensions are currently an experimental feature, so you need to turn on experimental features. You can do this by doing either of the following: -* Start the CLI with the `--experimental` flag. +* Start the CLI with the `‑‑experimental` flag. * Run the `/experimental on` slash command inside an interactive session. ## Changing how the CLI handles extensions diff --git a/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md b/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md index aec4b09e2426..21e2722c9be4 100644 --- a/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md +++ b/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md @@ -63,11 +63,11 @@ To use the CLI programmatically, include the `-p` or `--prompt` command-line opt > [!CAUTION] > If you use an automatic approval option such as `--allow-all-tools`, {% data variables.product.prodname_copilot_short %} has the same access as you do to files on your computer, and can run any shell commands that you can run, without getting your prior approval. See [Security considerations](#security-considerations), later in this article. -## Running in a sandbox with {% data variables.copilot.sandbox %} +## Running {% data variables.copilot.copilot_cli_short %} commands in a sandbox {% data reusables.cli.public-preview-sandbox %} -{% data variables.copilot.sandbox_caps %} provides isolated execution environments for {% data variables.copilot.copilot_cli_short %}, both locally and in the cloud. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +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 @@ -80,7 +80,7 @@ You can start a {% data variables.copilot.copilot_cli_short %} session inside an To start a cloud-backed session, run: ```bash copy -copilot --cloud +copilot ‑‑cloud ``` ## Use cases for {% data variables.copilot.copilot_cli %} @@ -310,7 +310,7 @@ You can control which tools {% data variables.copilot.copilot_cli_short %} can u ### Risk mitigation -You can mitigate the risks associated with using the automatic approval options by running {% data variables.copilot.copilot_cli_short %} in a sandboxed environment. {% data variables.copilot.sandbox_caps %} provides a first-party solution for this, with local sandboxing to restrict access on your machine and cloud sandboxing for fully isolated execution. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +You can mitigate the risks associated with using the automatic approval options by running {% data variables.copilot.copilot_cli_short %} in a sandboxed environment. {% data variables.product.github %} provides first-party sandboxing for this, with local sandboxing to restrict access on your machine and cloud sandboxing for fully isolated execution. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). Alternatively, you can run {% data variables.copilot.copilot_cli_short %} in a virtual machine, container, or dedicated system with tightly controlled permissions and network access. diff --git a/content/copilot/concepts/agents/copilot-cli/autopilot.md b/content/copilot/concepts/agents/copilot-cli/autopilot.md index 40ebc5ce1f2f..86d20c34f194 100644 --- a/content/copilot/concepts/agents/copilot-cli/autopilot.md +++ b/content/copilot/concepts/agents/copilot-cli/autopilot.md @@ -59,6 +59,10 @@ When entering autopilot mode, if you have not already granted {% data variables. You will get the best results from autopilot mode if you enable all permissions. If you choose to continue with limited permissions, {% data variables.product.prodname_copilot_short %} will automatically deny any tool requests that require approval, which may prevent it from completing certain tasks. You can change your mind later and grant full permissions, during an autopilot session, by using the `/allow-all` command (or its alias `/yolo`). +Before granting {% data variables.product.prodname_copilot_short %} wide-ranging permissions, consider using local sandboxing, or running the session in a cloud sandbox, to limit what {% data variables.product.prodname_copilot_short %} can access. + +If you enable local sandboxing while using autopilot mode, {% data variables.product.prodname_copilot_short %} completes anything it can achieve inside the sandbox without interruption. However, any step that needs to escape the sandbox—for example, writing to a file outside the current working directory—is denied. For more information about local sandboxing, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). + ## Staying in autopilot mode between tasks By default, autopilot mode is sticky: once {% data variables.product.prodname_copilot_short %} determines that a task is complete, {% data variables.copilot.copilot_cli_short %} remains in autopilot mode, so the next prompt you enter is also handled in autopilot mode. You can switch back to the standard interactive mode at any time by pressing Shift+Tab. diff --git a/content/copilot/concepts/agents/github-copilot-app.md b/content/copilot/concepts/agents/github-copilot-app.md index 027c826fbaeb..c57c2811150c 100644 --- a/content/copilot/concepts/agents/github-copilot-app.md +++ b/content/copilot/concepts/agents/github-copilot-app.md @@ -40,7 +40,7 @@ The {% data variables.copilot.github_copilot_app %} supports the following opera ## What can I do with the {% data variables.copilot.github_copilot_app %}? -* **Parallel workspaces:** Run multiple isolated agent sessions simultaneously, each with a dedicated git worktree and branch. You can also run sessions in cloud sandboxes (public preview) hosted by {% data variables.product.github %}. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +* **Parallel workspaces:** Run multiple isolated agent sessions simultaneously, each with a dedicated git worktree and branch. When you start a new agent session you can choose to run it in a cloud-based sandbox (public preview) hosted by {% data variables.product.github %}. For more information, see [AUTOTITLE](/copilot/how-tos/github-copilot-app/agent-sessions#starting-a-session). * **Session modes:** Choose how you work with agents: Interactive (collaborative), Plan (agent plans, you approve), or Autopilot (fully autonomous). You can also select from multiple LLMs and adjust reasoning effort for each session. * **Model selection:** Select from multiple LLMs, including models from your own provider using bring your own key (BYOK), and adjust reasoning effort for each session. * **{% data variables.product.github %} integration:** Browse and find issues, start sessions from them, create and close pull requests, review pull requests, view CI check results, and search across your repositories—all within the app. diff --git a/content/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/configure-enterprise-managed-settings.md b/content/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/configure-enterprise-managed-settings.md index 72b421d998cd..b15c6bb9b7bc 100644 --- a/content/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/configure-enterprise-managed-settings.md +++ b/content/copilot/how-tos/administer-copilot/manage-for-enterprise/manage-agents/configure-enterprise-managed-settings.md @@ -25,7 +25,7 @@ Supported clients are: These settings apply enterprise-wide, with no organization-level override. For each supported key, the `{% data variables.copilot.managed_setting_file %}` value takes precedence over any file-based configuration a user sets in their client. -Managed settings are loaded locally when the client starts, even if the device has no network connection. This means controls such as disabled bypass mode and restricted plugin configuration still apply before sign in or any server round trip, and remain active when users switch accounts. +Managed settings are loaded locally when the client starts, even if the device has no network connection. This means controls such as suppressing the `allow-all` permission options and restricting plugin configuration still apply before sign in or any server round trip, and remain active when users switch accounts. ## Defining settings 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 c522bd4f9db8..06dd1dddbb72 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 @@ -12,19 +12,15 @@ docsTeamMetrics: - copilot-cli --- -{% data reusables.cli.public-preview-sandbox %} - -> [!IMPORTANT] -> Local sandboxing on Windows requires a Windows Insiders build. +{% data reusables.cli.public-preview-local-sandbox %} +{% data reusables.cli.sandbox-on-windows %} ## About local sandbox configuration -When you enable local sandboxing in {% data variables.copilot.copilot_cli_short %}, shell commands that {% data variables.product.prodname_copilot_short %} runs on your behalf execute inside an isolated sandbox. You can fine-tune the sandbox's behavior—controlling filesystem paths, network access, and general settings—using the `/sandbox` slash command. - -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). +You can use the `/sandbox` slash command to grant extra paths, adjust network access, or turn sandboxing on or off. -For a conceptual overview of {% data variables.copilot.sandbox %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +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). ## Opening the sandbox configuration @@ -39,27 +35,54 @@ The **General** tab controls the top-level sandbox behavior. | Setting | Description | | --- | --- | -| **Sandboxing enabled** | When turned on, shell commands that {% data variables.product.prodname_copilot_short %} executes run inside the sandbox. You can also toggle this with `/sandbox enable` and `/sandbox disable`. | -| **Allow keychain access** | When turned on, sandboxed commands can use the macOS Keychain—for example, to access credentials used by `git` and `gh` credential helpers. Turn this off if you want to prevent sandboxed processes from reading stored credentials. | +| **Enable sandbox** | Run shell commands inside the sandbox. You can also toggle this with `/sandbox enable` and `/sandbox disable`. | +| **Allow sandbox bypass** | Let the model request that individual commands run outside the sandbox, subject to approval. Turned on by default. For more information, see [Allowing sandbox bypass](#allowing-sandbox-bypass). | +| **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. | +| **Authenticate git** | Inject a {% data variables.product.github %} token so authenticated HTTPS `git` works inside the sandbox without a credential helper. 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. | + +### Allowing sandbox bypass + +The **Allow sandbox bypass** setting controls what happens when {% data variables.product.prodname_copilot_short %} can't run a command successfully inside the sandbox. + +* **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, 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. ## Configuring filesystem settings -The **Filesystem** tab controls which directories and files the sandboxed process can access. By default, the sandbox restricts writes outside your working directory. +The **Filesystem** tab controls which directories and files the sandboxed process can access. + +By default, {% data variables.product.prodname_copilot_short %} is granted read/write permission to everything in and below the current working directory. If you are in a Git repository, {% data variables.product.prodname_copilot_short %} is also granted: + +* Read/write permission to everything in and below the repository's `.git` directory. +* On Windows and macOS, read permission for everything else in the repository above the current working directory. +* On Linux, read/write permission for files above the current working directory in the repository. | Setting | Description | | --- | --- | -| **Include working directory** | When turned on, the current working directory is automatically added to the list of read/write paths. This means sandboxed commands can read and write files in your project directory without manually adding it to the path list. | -| **Clear policy on exit** | When turned on, all filesystem permissions are reset when the sandbox exits. This ensures that each session starts with a clean set of permissions. | +| **Include working directory** | Turned on by default. The current working directory (and the enclosing repository's `.git` directory, if any) is automatically added to the list of read/write paths. Unselect this option if you don't want the working directory to be granted read/write access automatically, and then manually allow access to specific paths. | + +> [!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 -You can add specific path rules to grant the sandbox read-only or read/write access to directories and files outside the working directory. +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. Enter the file or directory path. -1. Set the permission level for the path. +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] + > Adding a directory includes it entire subtree. Wildcards are not supported. + +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. -Use Enter to edit an existing path rule, and D to delete one. +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. ## Configuring network settings @@ -67,26 +90,8 @@ The **Network** tab controls whether sandboxed processes can make network connec | Setting | Description | | --- | --- | -| **Allow outbound connections** | 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** | When turned on, the sandboxed process can reach hosts on your local network (for example, `localhost` or other devices on your LAN). | - -### Adding network host rules - -> [!WARNING] -> Per-host network filtering with `allowedHosts` and `blockedHosts` is currently not reliable across platforms. Do not rely on host rules to enforce network isolation. - -The `/sandbox` UI allows you to add host rules, but these rules have known platform limitations: - -* **macOS**: `allowedHosts` rules silently degrade to unrestricted outbound access, and `blockedHosts` rules are not supported. -* **Linux**: Host rules are not a reliable way to allow selected hosts when outbound connections are disabled. - -If the UI presents host rule options, you can add them using the steps below, but they are not suitable for security enforcement. - -1. In the **Network** tab, press A to add a new host rule. -1. Enter the hostname. -1. Set whether to allow or block access to the host. - -Use Enter to edit an existing host rule, and D to delete one. +| **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. | ## Enabling and disabling the sandbox quickly @@ -95,10 +100,21 @@ You can toggle the sandbox on or off without opening the full configuration inte * **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 **Sandboxing enabled** setting on the **General** tab. +These commands change the **Enable sandbox** setting on the **General** tab. + +## 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). + +You can view your current sandbox settings from within a {% data variables.copilot.copilot_cli_short %} session. + +1. Enter `/settings`. +1. Press / to search for settings. +1. Type `sandbox` to filter the list of settings. ## 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 ab6b380b2096..53a63a6089f0 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 @@ -1,9 +1,9 @@ --- -title: Enabling or disabling cloud sandboxes for your organization +title: Enabling or disabling cloud sandboxes for your organization or enterprise shortTitle: Enable or disable cloud sandboxes allowTitleToDifferFromFilename: true -intro: 'You can control whether members of your organization can use cloud sandboxes by managing the sandbox access policy in your organization settings.' -permissions: Organization owners +intro: 'You can control whether members of your organization or enterprise can use cloud sandboxes by managing the cloud sandbox access policy in your organization or enterprise settings.' +permissions: Enterprise owners and organization owners redirect_from: - /copilot/how-tos/cloud-and-local-sandboxes/enabling-or-disabling-cloud-and-local-sandboxes-for-your-organization versions: @@ -17,20 +17,31 @@ category: ## About enabling and disabling cloud sandboxes -Organization owners can control whether members of their organization have access to cloud sandboxes by configuring the sandbox access policy. By default, sandbox access is disabled for organization members. - -When cloud sandbox access is **Disabled**, cloud sandboxes are not available for any organization members. When cloud sandbox access is **Enabled for all members**, all organization members can use cloud sandboxes. +Organization owners can control whether members of their organization have access to cloud sandboxes by configuring the cloud sandbox access policy. Enterprise owners can control cloud sandbox access for all organizations in the enterprise. By default, cloud sandbox access is disabled. For more information about cloud sandboxes, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). -## Enabling or disabling cloud sandboxes +## Enabling or disabling cloud sandboxes for your organization {% data reusables.profile.access_org %} {% data reusables.profile.org_settings %} 1. {% data reusables.user-settings.code-planning-automation %} click **Sandboxes**. -1. Under "Sandbox access," select your preferred setting: - * **Disabled**: Sandboxes are not available for organization members. - * **Enabled for all members**: All organization members can use {% data variables.copilot.sandbox_short %}. +1. Under "Cloud sandbox access", select your preferred setting: + * **Disabled**: Cloud sandbox access is not available for organization members. + * **Enabled**: Members of this organization can use cloud sandboxes. +1. Click **Save**. + +## Enabling or disabling cloud sandboxes for your enterprise + +Enterprise owners can control cloud sandbox access for all organizations in the enterprise from the **Policies** tab of the enterprise settings. By default, cloud sandbox access is disabled for all organizations in the enterprise. + +{% data reusables.enterprise-accounts.access-enterprise %} +{% data reusables.enterprise-accounts.policies-tab %} +1. Click **Sandboxes**. +1. Under "Cloud sandbox access", select your preferred setting: + * **Disabled**: Cloud sandbox access is not available for any organizations in this enterprise. + * **Let organizations enable (opt-in)**: Organization owners can choose to enable cloud sandbox access for their members. New organizations default to disabled. + * **Enabled by default for all organizations (opt-out)**: Cloud sandbox access is enabled for all organizations. Organization owners can still disable access for their organization if needed. 1. Click **Save**. ## Further reading 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 709fb43ed4e7..130997978f31 100644 --- a/content/copilot/how-tos/cloud-and-local-sandboxes/index.md +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/index.md @@ -1,11 +1,12 @@ --- -title: '{% data variables.copilot.sandbox_caps %}' -shortTitle: '{% data variables.copilot.sandbox_caps %}' -intro: 'Manage {% data variables.copilot.sandbox %} for your organization.' +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.' versions: feature: copilot children: - /enabling-or-disabling-cloud-sandboxes-for-your-organization + - /using-local-sandboxing - /configuring-local-sandbox-settings contentType: how-tos --- 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 new file mode 100644 index 000000000000..23823a2b5686 --- /dev/null +++ b/content/copilot/how-tos/cloud-and-local-sandboxes/using-local-sandboxing.md @@ -0,0 +1,90 @@ +--- +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.' +versions: + feature: copilot +contentType: how-tos +category: + - Configure Copilot # Copilot discovery page + - Configure Copilot CLI # Copilot CLI bespoke page +docsTeamMetrics: + - copilot-cli +--- + +{% data reusables.cli.public-preview-local-sandbox %} + +{% data reusables.cli.sandbox-on-windows %} + +## About local sandboxing + +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. + +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. + +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, access above the current working directory varies by operating system. Access to your local and private network is permitted, as is outbound internet access. + +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. + +For a conceptual overview of sandboxing in {% data variables.copilot.copilot_cli_short %}, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). + +## Enabling local sandboxing + +To enable local sandboxing, enter the following command in an interactive {% data variables.copilot.copilot_cli_short %} session: + +```shell copy +/sandbox enable +``` + +Sandboxing starts being used immediately for the current session. + +After you enable local sandboxing, it continues to be used for the current and future interactive sessions, and for programmatic sessions. + +> [!NOTE] +> If you have other sessions open when you enter `/sandbox enable`, sandboxing is not immediately used in those sessions. To use sandboxing in an already-open session, do either of the following in that session: +> +> * Close the session and restart it, for example by running `copilot --continue`. +> * Enter `/sandbox enable`. + +## Disabling local sandboxing + +To stop using local sandboxing, enter the following command in an interactive {% data variables.copilot.copilot_cli_short %} session: + +```shell copy +/sandbox disable +``` + +Sandboxing is no longer used in the current session, or in new and restarted sessions. + +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). + +## 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. + +You can combine these options with the `-p` command line option to control sandboxing for programmatic use of the CLI. For example: + +```shell copy +copilot --sandbox -p "PROMPT" +``` + +## Running a single command outside the sandbox + +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, and it runs outside the sandbox only if you approve it; otherwise it stays sandboxed. The rest of your session remains sandboxed either way. + +This behavior is enabled by default and can be turned off in your sandbox settings. + +## Checking whether sandboxing is being used + +To check whether sandboxing is being used for the current session, look at the status line. If sandboxing is being used, the status line contains `sandbox enabled`. + +Display of sandbox information in the status line is turned on by default. If it is turned off, you can turn it back on: + +1. Enter `/statusline`. +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. + +## Further reading + +* [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes) +* [AUTOTITLE](/copilot/how-tos/cloud-and-local-sandboxes/configuring-local-sandbox-settings) diff --git a/content/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically.md b/content/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically.md index 984602bd13e7..1d13aff4285c 100644 --- a/content/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically.md +++ b/content/copilot/how-tos/copilot-cli/automate-copilot-cli/run-cli-programmatically.md @@ -38,7 +38,7 @@ To use {% data variables.copilot.copilot_cli_short %} programmatically you can d * **Provide precise prompts** — clear, unambiguous instructions produce better results than vague requests. The more context you give—file names, function names, the exact change—the less guesswork {% data variables.product.prodname_copilot_short %} has to do. * **Quote prompts carefully** — use single quotes around your prompt if you want to avoid shell interpretation of special characters. -* **Always give minimal permissions** — use the `--allow-tool=[TOOLS...]` and `--allow-url=[URLs...]` command-line options to give {% data variables.product.prodname_copilot_short %} permission to use only the tools and access that are necessary to complete the task. Avoid using overly permissive options (such as `--allow-all`) unless you are working in a sandbox environment. +* **Always give minimal permissions** — use the `--allow-tool=[TOOLS...]` and `--allow-url=[URLs...]` command-line options to give {% data variables.product.prodname_copilot_short %} permission to use only the tools and access that are necessary to complete the task. Avoid using overly permissive options (such as `--allow-all`) unless you are working in a sandbox environment. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). * **Use `-s` (silent)** when capturing output. This suppresses session metadata so you get clean text. * **Use `--no-ask-user`** to prevent the agent from attempting to ask clarifying questions. * **Set a model explicitly** with `--model` for consistent behavior across environments. diff --git a/content/copilot/how-tos/copilot-cli/automate-copilot-cli/schedule-prompts.md b/content/copilot/how-tos/copilot-cli/automate-copilot-cli/schedule-prompts.md index 1846c08d9323..d7b699f687cd 100644 --- a/content/copilot/how-tos/copilot-cli/automate-copilot-cli/schedule-prompts.md +++ b/content/copilot/how-tos/copilot-cli/automate-copilot-cli/schedule-prompts.md @@ -14,7 +14,7 @@ category: --- > [!NOTE] -> The `/every` and `/after` commands are currently experimental features and are only available if you have used the `/experimental on` slash command, or the `--experimental` command line option. +> The `/every` and `/after` commands are currently experimental features and are only available if you have used the `/experimental on` slash command, or the `‑‑experimental` command line option. In an interactive {% data variables.copilot.copilot_cli_short %} session you can schedule a prompt to be submitted automatically. This is useful when you want {% data variables.product.prodname_copilot_short %} to repeat a task at a regular cadence or to perform a one-off task after a delay, without you having to remember to submit the prompt manually. diff --git a/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md b/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md index fb767887fa73..1c61d00c76c6 100644 --- a/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md +++ b/content/copilot/how-tos/copilot-cli/customize-copilot/add-mcp-servers.md @@ -188,7 +188,7 @@ The `.vscode/mcp.json` file for {% data variables.product.prodname_vscode_shortn ### Searching and installing from the registry > [!NOTE] -> The `/mcp search` command 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. +> The `/mcp search` command 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. You can discover and install MCP servers directly from the [{% data variables.product.github %} MCP Registry](https://github.com/mcp) using the `/mcp search` command in interactive mode. This lets you browse available servers, view their details, and install them without manually filling out the configuration form. diff --git a/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli.md b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli.md index efc05ab0b1f5..36d59c5b3922 100644 --- a/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli.md +++ b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli.md @@ -24,7 +24,7 @@ This article shows you how to set trusted directories, configure access for tool ## Setting trusted directories -Trusted directories control where {% data variables.copilot.copilot_cli_short %} can read, modify, and execute files. Trusting a directory has security implications, see [Security considerations](/copilot/concepts/agents/copilot-cli/about-copilot-cli#trusted-directories). +Trusted directories control where {% data variables.copilot.copilot_cli_short %} can read, modify, and execute files. Trusting a directory has security implications, see [Security considerations](/copilot/concepts/agents/copilot-cli/about-copilot-cli#security-considerations). ### Choosing to trust a directory @@ -54,7 +54,7 @@ You can edit the list of permanently trusted directories. Trusted directories ar You can control which tools {% data variables.copilot.copilot_cli_short %} can use, either by responding to approval prompts when {% data variables.product.prodname_copilot_short %} attempts to use a tool, or by specifying permissions via command-line flags. -Be aware that allowing tool access has security implications, see [Security considerations](/copilot/concepts/agents/copilot-cli/about-copilot-cli#allowed-tools). +Be aware that allowing tool access has security implications, see [Security considerations](/copilot/concepts/agents/copilot-cli/about-copilot-cli#security-considerations). In this section, you can learn how to: @@ -269,7 +269,13 @@ This flag combines: During an interactive session, you can also enable all permissions with the `/allow-all` or `/yolo` slash commands. -{% data reusables.copilot.disable-bypass %} +> [!NOTE] {% data reusables.copilot.disable-bypass %} + +## Restrict access to files + +The various `--allow-all...` options save you from having to decide whether to allow {% data variables.product.prodname_copilot_short %} to access individual tools, files, and URLs. However, using them widens the scope for {% data variables.product.prodname_copilot_short %} to perform actions that you might not want it to—for example, altering files outside of the repository you are working in. + +To mitigate this risk, you can instruct the CLI to sandbox its commands (local sandboxing), or you can run the entire {% data variables.copilot.copilot_cli_short %} session within a remote, sandboxed environment (cloud sandboxing). For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). ## Further reading diff --git a/content/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools.md b/content/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools.md index 15ee96de7f70..3a8306fb296f 100644 --- a/content/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools.md +++ b/content/copilot/how-tos/copilot-cli/use-copilot-cli/allowing-tools.md @@ -93,14 +93,16 @@ The following command-line options give {% data variables.copilot.copilot_cli_sh {% data reusables.copilot.disable-bypass %} +Before you grant {% data variables.product.prodname_copilot_short %} wide-ranging permissions with an allow-all option, consider using local sandboxing, or running the session in a cloud sandbox, to limit what {% data variables.product.prodname_copilot_short %} can access. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). + * `--allow-all-tools` — Full access to the available tools. * `--allow-all` or `--yolo` — Equivalent to using all of the `--allow-all-tools`, `--allow-all-paths`, and `--allow-all-urls` options when starting the CLI. Within an interactive session, you can use the `/allow-all` or `/yolo` slash commands to allow all tools without needing to restart the session. - > [!NOTE] - > It is strongly recommended that you only use these options in an isolated environment. You should never use an alias to apply one of these options every time you start {% data variables.copilot.copilot_cli_short %}, as doing so would allow {% data variables.product.prodname_copilot_short %} to use any tool without your explicit permission every time you use the CLI, which could lead to unintended consequences. +> [!CAUTION] +> It is strongly recommended that you only use these options in an isolated environment. You should never use an alias to apply one of these options every time you start {% data variables.copilot.copilot_cli_short %}, as doing so would allow {% data variables.product.prodname_copilot_short %} to use any tool without your explicit permission every time you use the CLI, which could lead to unintended consequences. ## Resetting permissions diff --git a/content/copilot/how-tos/copilot-cli/use-copilot-cli/overview.md b/content/copilot/how-tos/copilot-cli/use-copilot-cli/overview.md index 525f0d94da9e..8a96504d3b22 100644 --- a/content/copilot/how-tos/copilot-cli/use-copilot-cli/overview.md +++ b/content/copilot/how-tos/copilot-cli/use-copilot-cli/overview.md @@ -295,9 +295,11 @@ Details of your configured MCP servers are stored in the `mcp-config.json` file, For situations where you trust {% data variables.product.prodname_copilot_short %} to run freely, you can use the `--allow-all` or `--yolo` flags to enable all permissions at once. -### Run in a sandbox +### Use sandboxing -You can run {% data variables.copilot.copilot_cli_short %} sessions inside a sandbox to restrict access to your filesystem, network, and system capabilities. To enable local sandboxing, enter `/sandbox enable` inside a session. To start a cloud-backed session instead, run `copilot --cloud`. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). +You can use sandboxing to restrict what {% data variables.product.prodname_copilot_short %} can access. Local sandboxing does not run the CLI itself in a sandbox; instead, the commands and tools that {% data variables.copilot.copilot_cli_short %} runs on your behalf are restricted, limiting their access to your filesystem, network, and system capabilities. To enable local sandboxing, enter `/sandbox enable` inside a session. + +Alternatively, with cloud sandboxing, the entire {% data variables.copilot.copilot_cli_short %} session runs remotely in an isolated environment. To start a {% data variables.copilot.copilot_cli_short %} session in the cloud, run `copilot ‑‑cloud`. For more information, see [AUTOTITLE](/copilot/concepts/about-cloud-and-local-sandboxes). ### Toggle reasoning visibility diff --git a/content/copilot/how-tos/copilot-cli/use-copilot-cli/roll-back-changes.md b/content/copilot/how-tos/copilot-cli/use-copilot-cli/roll-back-changes.md index 023c4efb4e76..6c959f9a548f 100644 --- a/content/copilot/how-tos/copilot-cli/use-copilot-cli/roll-back-changes.md +++ b/content/copilot/how-tos/copilot-cli/use-copilot-cli/roll-back-changes.md @@ -24,9 +24,9 @@ You can trigger a rewind by pressing Esc twice, or by using the `/und * **Git-based rewind**: rolls back to a workspace snapshot taken at the start of a prompt. * **Tools-based rewind**: lets you rewind conversation history only, or rewind conversation history and restore files that {% data variables.product.prodname_copilot_short %} changed. - + > [!NOTE] -> Tools-based rewind is currently an experimental feature and is only available if you have used the `/experimental on` slash command, or the `--experimental` command line option. +> Tools-based rewind is currently an experimental feature and is only available if you have used the `/experimental on` slash command, or the `‑‑experimental` command line option. {% data variables.copilot.copilot_cli_short %} automatically chooses one of these rewind behaviors based on your environment to provide the best possible rewind experience. 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 a30b83040650..bd9cbfcdad15 100644 --- a/content/copilot/reference/copilot-cli-reference/cli-command-reference.md +++ b/content/copilot/reference/copilot-cli-reference/cli-command-reference.md @@ -446,15 +446,16 @@ For a complete list of commands and options, run `copilot help`. You can use `--remote` with `--resume ` to resume a remote task locally. This works even when the task was originally created outside a Git repository. -> [!NOTE] -> When `permissions.disableBypassPermissionsMode` is set to `"disable"`, all allow-all flags (`--allow-all-tools`, `--allow-all-paths`, `--allow-all-urls`, `--allow-all`, `--yolo`) are suppressed at startup and cannot be used to grant elevated permissions. +### Restricting the --allow-all options + +When `permissions.disableBypassPermissionsMode` is set to `"disable"`, all of the command line options that allow all permissions (`--allow-all-tools`, `--allow-all-paths`, `--allow-all-urls`, `--allow-all`, `--yolo`) are suppressed at startup and cannot be used to grant elevated permissions. The `/allow-all` and `/yolo` slash commands are also suppressed in interactive mode. Three sources can set this restriction, in increasing order of permanence: | Source | Scope | Cleared by account switch? | |--------|-------|---------------------------| | User settings (`~/.copilot/settings.json`) | Machine | No — applies to all accounts | -| Managed settings (server-fetched per account) | Account | Yes — cleared when switching to a different account that does not disable bypass mode | +| Managed settings (server-fetched per account) | Account | Yes — cleared when switching to a different account that does not disable the allow-all options | | MDM policy (plist/registry/file) | Device | Never — device-level policy that cannot be overridden by account switches | For MDM configuration details, see [AUTOTITLE](/copilot/reference/copilot-cli-reference/cli-config-dir-reference#mdm-managed-settings). diff --git a/content/copilot/reference/enterprise-managed-settings-reference.md b/content/copilot/reference/enterprise-managed-settings-reference.md index 0f79148bef95..b67963769dba 100644 --- a/content/copilot/reference/enterprise-managed-settings-reference.md +++ b/content/copilot/reference/enterprise-managed-settings-reference.md @@ -116,7 +116,7 @@ Prevents users from enabling bypass mode (also known as "YOLO mode"). Bypass mod When you set `disableBypassPermissionsMode` to `"disable"`, users cannot turn on bypass mode: -* In {% data variables.copilot.copilot_cli_short %}, the `--yolo` and `--allow-all` command-line options and the `/yolo` and `/allow-all` slash commands are blocked. Individual flags such as `--allow-all-tools` and `--allow-all-paths` are not blocked. +* In {% data variables.copilot.copilot_cli_short %}, all of the command line options for allowing all permissions (`--yolo`, `--allow-all`, and the individual `--allow-all-tools`, `--allow-all-paths`, and `--allow-all-urls` options) are suppressed at startup and cannot grant elevated permissions. The `/yolo` and `/allow-all` slash commands are also blocked. * In {% data variables.product.prodname_vscode_shortname %}, the global auto-approve setting (`chat.tools.global.autoApprove`) is turned off and cannot be re-enabled. * In the {% data variables.copilot.github_copilot_app %}, the "Allow all" setting for "Tool Permissions" is blocked in the sessions settings. diff --git a/content/copilot/tutorials/create-an-extension.md b/content/copilot/tutorials/create-an-extension.md index 2d4073b2ff61..9ea564291c35 100644 --- a/content/copilot/tutorials/create-an-extension.md +++ b/content/copilot/tutorials/create-an-extension.md @@ -30,7 +30,7 @@ Both examples rely only on the SDK that's bundled with the {% data variables.cop ## Prerequisites * **{% data variables.copilot.copilot_cli %}**: You need {% data variables.copilot.copilot_cli_short %} installed and set up. See [AUTOTITLE](/copilot/how-tos/copilot-cli/cli-getting-started). -* **Experimental features enabled**: Extensions are currently an experimental feature. The steps in this tutorial turn on experimental features each time you start the CLI, using the `--experimental` command line option. +* **Experimental features enabled**: Extensions are currently an experimental feature. The steps in this tutorial turn on experimental features each time you start the CLI, using the `‑‑experimental` command line option. * **JavaScript**: Extensions are written in JavaScript, so you'll need to be familiar with this language to create your own extensions. * **A repository**: The second example adds a project-level extension, so you'll need a local copy of a Git repository in which to add the extension. @@ -126,7 +126,7 @@ To ensure a tool is used by the CLI, the tool must do something the CLI can't do 1. Start an interactive session with experimental features enabled: ```shell copy - copilot --experimental + copilot ‑‑experimental ``` Because the extension lives under `~/.copilot/extensions/`, you can start the CLI from any directory and the extension will be available. @@ -285,7 +285,7 @@ The extension keeps a running total of tokens used in the session by subscribing Start an interactive session from the same repository, with experimental features enabled: ```shell copy -copilot --experimental +copilot ‑‑experimental ``` If you already had a session open, you can run `/clear` to start a fresh session, which reloads extensions from disk. diff --git a/data/reusables/cli/public-preview-local-sandbox.md b/data/reusables/cli/public-preview-local-sandbox.md new file mode 100644 index 000000000000..1f3bc35b4ddd --- /dev/null +++ b/data/reusables/cli/public-preview-local-sandbox.md @@ -0,0 +1,2 @@ +> [!NOTE] +> 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/public-preview-sandbox.md b/data/reusables/cli/public-preview-sandbox.md index 89c2708fec4b..fee461494b0d 100644 --- a/data/reusables/cli/public-preview-sandbox.md +++ b/data/reusables/cli/public-preview-sandbox.md @@ -1,2 +1,2 @@ > [!NOTE] -> {% data variables.copilot.sandbox_caps %} is in {% data variables.release-phases.public_preview %} and subject to change. +> 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 new file mode 100644 index 000000000000..33a5e512cec8 --- /dev/null +++ b/data/reusables/cli/sandbox-on-windows.md @@ -0,0 +1,2 @@ +> [!IMPORTANT] +> Local sandboxing on Windows requires a Windows Insiders build. diff --git a/data/reusables/copilot/disable-bypass.md b/data/reusables/copilot/disable-bypass.md index f2984e2432c4..90a23519f52b 100644 --- a/data/reusables/copilot/disable-bypass.md +++ b/data/reusables/copilot/disable-bypass.md @@ -1 +1 @@ -> [!NOTE] If you have a {% data variables.copilot.copilot_business_short %} or {% data variables.copilot.copilot_enterprise_short %} license, these commands may be blocked by an enterprise administrator. +If you have a {% data variables.copilot.copilot_business_short %} or {% data variables.copilot.copilot_enterprise_short %} license, these commands may be blocked by an enterprise administrator. diff --git a/data/variables/copilot.yml b/data/variables/copilot.yml index 1b7a18ad4d94..5a910ecd417d 100644 --- a/data/variables/copilot.yml +++ b/data/variables/copilot.yml @@ -106,12 +106,6 @@ copilot_old-cli_short: 'Copilot in the CLI' copilot_old-cli: 'GitHub Copilot in the CLI' copilot_cli_npm_version: 'Node.js 22 or later' -## GitHub Sandbox -sandbox: 'cloud and local sandboxes for GitHub Copilot' -sandbox_caps: 'Cloud and local sandboxes for GitHub Copilot' -sandbox_short: 'sandboxes for GitHub Copilot' -sandbox_short_caps: 'Sandboxes for GitHub Copilot' - ## Copilot custom agents copilot_custom_agent: 'Copilot custom agent' copilot_custom_agents: 'Copilot custom agents'