diff --git a/CHANGELOG.md b/CHANGELOG.md index c4cca58a4635..3ac56a41742e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,13 @@ # Docs changelog +**17 February 2026** + +We’ve added a new tutorial, "[Using hooks with Copilot CLI for predictable, policy-compliant execution](https://docs.github.com/en/copilot/tutorials/copilot-cli-hooks)", to help teams configure repository-scoped hooks that log prompts and tool usage, enforce guardrails with `preToolUse`, and roll out policies safely across repositories. + +This tutorial helps organizations adopt Copilot CLI automation with clear guardrails, improving security, auditability, and confidence, without blocking legitimate development workflows. + +
+ **4 February 2026** We've published a new tutorial on [using GitHub Copilot coding agent to improve a project](https://docs.github.com/copilot/tutorials/coding-agent/improve-a-project). diff --git a/Dockerfile b/Dockerfile index 35c61add1f54..613a97adba21 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,7 +8,7 @@ # --------------------------------------------------------------- # To update the sha: # https://github.com/github/gh-base-image/pkgs/container/gh-base-image%2Fgh-base-noble -FROM ghcr.io/github/gh-base-image/gh-base-noble:20260128-000359-ga6d0dc7c0@sha256:e2dd6aa64dc4b3fd0fee388a817b2ce0ce239f1da31fd628c359a74832abdfcb AS base +FROM ghcr.io/github/gh-base-image/gh-base-noble:20260213-184502-g77a9fd0b0@sha256:88c4a7176139d7ea917c7a30413af68bbf16672b16806a71451ada25d0ac78ff AS base # Install curl for Node install and determining the early access branch # Install git for cloning docs-early-access & translations repos diff --git a/content/actions/reference/limits.md b/content/actions/reference/limits.md index 0bb6be46a33c..dcc2c1cd360c 100644 --- a/content/actions/reference/limits.md +++ b/content/actions/reference/limits.md @@ -41,6 +41,7 @@ These limits are subject to change. | Larger runners | Static IP limits | 10 IPs | 10 IPs per enterprise and organization. | {% octicon "check" aria-label="Yes" %} Support ticket | | Larger runners | Private IP scaling for vnet injection | 30% buffer | You need a buffer to accommodate the maximum job concurrency you anticipate. See [Private IP scaling for vnet injection on larger runners](#private-ip-scaling-for-vnet-injection-on-larger-runners). | {% octicon "check" aria-label="Yes" %} Configurable Azure virtual network | | Dependency caching | Uploads per minute | 200 per minute | Each repository is limited to 200 cache entry uploads per minute. If this limit is exceeded, subsequent cache upload attempts will fail until the rate limit resets. | {% octicon "x" aria-label="No" %} | +| Dependency caching | Downloads per minute | 1500 per minute | Each repository is limited to 1500 cache entry downloads per minute. If this limit is exceeded, subsequent cache download attempts will fail until the rate limit resets. | {% octicon "x" aria-label="No" %} | ### Job concurrency limits for {% data variables.product.github %}-hosted runners @@ -89,4 +90,4 @@ When using larger runners with vnet injection, you need to determine the appropr * **{% data variables.product.github %}-hosted runners pulling public images:** Docker Hub's rate limit is not applied. * **{% data variables.product.github %}-hosted runners pulling private images:** Pulling private images from Docker Hub is subject to the rate limit. -* **Self-hosted runners pulling public or private images:** Pulling images from Docker Hub is always subject to the rate limit. \ No newline at end of file +* **Self-hosted runners pulling public or private images:** Pulling images from Docker Hub is always subject to the rate limit. diff --git a/content/actions/reference/workflows-and-actions/dependency-caching.md b/content/actions/reference/workflows-and-actions/dependency-caching.md index d738959f92bd..a652779cac72 100644 --- a/content/actions/reference/workflows-and-actions/dependency-caching.md +++ b/content/actions/reference/workflows-and-actions/dependency-caching.md @@ -275,7 +275,7 @@ Multiple workflow runs in a repository can share caches. A cache created for a b {% endif %} {% ifversion fpt or ghec %} -You can create cache entries at a rate of up to 200 uploads per minute per repository. If you exceed this rate, subsequent cache upload attempts will fail until the rate limit resets. The time until the rate limit resets is returned in the `Retry-After` header of the response. +You can create cache entries at a rate of up to 200 uploads per minute per repository, and download them at a rate of 1500 downloads per minute per repository. If you exceed this rate, subsequent cache upload or download attempts will fail until the relevant rate limit resets. The time until the rate limit resets is returned in the `Retry-After` header of the response. See [AUTOTITLE](/actions/reference/limits) for more information about {% data variables.product.prodname_actions %} rate limits. ### Increasing cache size @@ -286,6 +286,18 @@ For more information, see: * [AUTOTITLE](/organizations/managing-organization-settings/disabling-or-limiting-github-actions-for-your-organization#managing-github-actions-cache-storage-for-your-organization) * [AUTOTITLE](/admin/enforcing-policies/enforcing-policies-for-your-enterprise/enforcing-policies-for-github-actions-in-your-enterprise#artifact-and-log-retention) +Usage of additional storage is also controlled by budgets set for {% data variables.product.prodname_actions %} or the Actions Cache Storage SKU. If you have limits configured, and you exceed a budget, your cache will become read-only until your billing status is resolved, or your usage goes beneath the free limit of 10GB by caches expiring or being explicitly deleted. For more information on how to set up budgets, see [AUTOTITLE](/billing/how-tos/set-up-budgets). + +Setting your Actions Cache Storage SKU budgets lower than the total cost of using your configured storage over your billing period can lead to your cache frequently going into read-only mode. For example, if your budget for the SKU is $0, and you've configured your repository's maximum cache size at 20GB, your cache will enter read-only mode as soon as storage exceeds the free threshold. + +Below are some illustrative monthly costs to inform budgets you may wish to set for the Actions Cache Storage SKU. + +| Cache size | Monthly cost (if fully utilized) | +| ---------- | -------------------------------- | +| 50GB | $2.80 | +| 200GB | $13.30 | +| 1000GB | $69.30 | + {% endif %} ## Next steps diff --git a/content/admin/data-residency/feature-overview-for-github-enterprise-cloud-with-data-residency.md b/content/admin/data-residency/feature-overview-for-github-enterprise-cloud-with-data-residency.md index 18d9f515573b..e306528984cb 100644 --- a/content/admin/data-residency/feature-overview-for-github-enterprise-cloud-with-data-residency.md +++ b/content/admin/data-residency/feature-overview-for-github-enterprise-cloud-with-data-residency.md @@ -28,6 +28,7 @@ The following features are currently unavailable on {% data variables.enterprise | Certain features of {% data variables.product.prodname_github_connect %} | Although you can connect an enterprise on {% data variables.enterprise.data_residency_site %} to a {% data variables.product.prodname_ghe_server %} instance, certain features of {% data variables.product.prodname_github_connect %} are not available, including resolution of actions from {% data variables.product.prodname_dotcom_the_website %}. | [{% data variables.product.prodname_github_connect %}](#github-connect) | | Some features currently in {% data variables.release-phases.public_preview %} or {% data variables.release-phases.private_preview %} | Certain features that are in a preview phase on {% data variables.product.prodname_dotcom_the_website %} may not be available on {% data variables.enterprise.data_residency_site %} until GA. | | | Migrations REST API | Currently unavailable. | [AUTOTITLE](/rest/migrations) | +| Streaming audit logs to Amazon S3 with OpenID Connect (OIDC) | Currently unavailable. | [AUTOTITLE](/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/streaming-the-audit-log-for-your-enterprise) | ## Permanently unavailable features diff --git a/content/admin/monitoring-and-managing-your-instance/multiple-data-disks/configuring-multiple-data-disks.md b/content/admin/monitoring-and-managing-your-instance/multiple-data-disks/configuring-multiple-data-disks.md index b15f3bccd687..18ddd02c56b4 100644 --- a/content/admin/monitoring-and-managing-your-instance/multiple-data-disks/configuring-multiple-data-disks.md +++ b/content/admin/monitoring-and-managing-your-instance/multiple-data-disks/configuring-multiple-data-disks.md @@ -1,7 +1,7 @@ --- title: Configuring multiple data disks product: '{% data variables.product.prodname_ghe_server %}' -intro: 'You can configure additional data disks and use them to host MySQL and repositories data.' +intro: 'You can configure additional data disks and use them to host data of different services.' versions: ghes: '>= 3.19' type: overview @@ -25,6 +25,10 @@ topics: * Resources can be allocated in a targeted way, preventing critical services from being starved. * Scaling: * Customers on both standalone and high-availability topologies can scale out as needed. +{% ifversion ghes > 3.19 %} +* Resiliency: + * Isolating logs from the root disk enhances resiliency by preventing the volume of logs from flooding the root disk. +{%- endif %} ## Constraints @@ -34,12 +38,19 @@ topics: * You can minimize this by configuring a replica with multi-data disks, replicating data from the primary, and then failing over to the replica. * If you are adding multi-data disks directly to the primary, expect a much longer downtime. * During the public preview, multi-data disks should be used only in non-production environments. +{% ifversion ghes < 3.20 %} * It is not recommended to migrate MySQL and repositories to the same disk. * Currently, only MySQL and repositories can be migrated to additional disks. +{%- endif %} +{% ifversion ghes > 3.19 %} +* It is not recommended to migrate MySQL, repositories, system logs, or {% data variables.product.github %} logs to the same disk. Each additional disk should only contain one migration. +* Currently, only MySQL, repositories, system logs, and {% data variables.product.github %} logs can be migrated to additional disks. +* Rebooting the {% data variables.product.prodname_ghe_server %} node is required after migrating system logs to ensure it is working on a system level. It will take some time as config apply also runs during startup of the node. +{%- endif %} ## Resource recommendations -If you add disks that are as fast or faster than your current ones, you should see improved performance. Storage devices are typically measured by IOPS (Input/Output Operations Per Second), throughput, and latency. For MySQL, we recommend using a disk with lower latency and higher IOPS than your existing data disk. For repositories, choose a disk with higher IOPS and throughput than your current data disk. +If you add disks that are as fast or faster than your current ones, you should see improved performance. Storage devices are typically measured by IOPS (Input/Output Operations Per Second), throughput, and latency. For MySQL, we recommend using a disk with lower latency and higher IOPS than your existing data disk. For repositories, choose a disk with higher IOPS and throughput than your current data disk.{% ifversion ghes > 3.19 %} For logs, we recommend using a disk with higher IOPS and throughput than your existing data disk to handle continuous write operations from logging activities. {%- endif %} In high availability setups, it is best to use multi-data disks on both the primary and all replicas. Mixing configurations, where the primary has multi-data disks but the replica does not, is not recommended. @@ -72,7 +83,25 @@ In high availability setups, it is best to use multi-data disks on both the prim /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme3n1 git ``` + {% ifversion ghes > 3.19 %} + + ``` shell copy + /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme4n1 systemlogs + ``` + + + ``` shell copy + /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme5n1 githublogs + ``` + + {%- endif %} + + {% ifversion ghes < 3.20 %} Please note that `/dev/nvme2n1` and `/dev/nvme3n1` are example paths only. They might not match the paths on your system. Similarly, `db` and `git` are examples. You may choose different names. + {%- endif %} + {% ifversion ghes > 3.19 %} + Please note that `/dev/nvme2n1`, `/dev/nvme3n1`, `/dev/nvme4n1`, and `/dev/nvme5n1` are example paths only. They might not match the paths on your system. Similarly, `db`, `git`, `systemlogs`, and `githublogs` are examples. You may choose different names. + {%- endif %} 1. Switch to maintenance mode. @@ -94,6 +123,26 @@ In high availability setups, it is best to use multi-data disks on both the prim /usr/local/share/enterprise/ghe-storage-migrate-repositories git ``` + {% ifversion ghes > 3.19 %} + To migrate system logs: + + ``` shell copy + /usr/local/share/enterprise/ghe-storage-migrate-logs systemlogs + ``` + + After migrating system logs, reboot the instance: + + ``` shell copy + sudo reboot + ``` + + To migrate {% data variables.product.github %} logs: + + ``` shell copy + /usr/local/share/enterprise/ghe-storage-migrate-github-logs githublogs + ``` + {%- endif %} + 1. Exit maintenance mode. ``` shell copy @@ -101,7 +150,12 @@ In high availability setups, it is best to use multi-data disks on both the prim ``` 1. Test the instance for a period of time to make sure everything works as expected. +{% ifversion ghes < 3.20 %} 1. **Only after sufficient testing**, remove `/data/user/mysql-backup` and `/data/user/repositories-backup`. +{%- endif %} +{% ifversion ghes > 3.19 %} +1. **Only after sufficient testing**, remove `/data/user/mysql-backup`, `/data/user/repositories-backup`, `/var/log-backup`, `/data/github/current/log-backup`, and `/data/github/shared/log-backup`. +{%- endif %} Keeping these folders during testing allows you to roll back in an emergency. After sufficient testing, you should remove those backup folders to free up space. @@ -112,8 +166,12 @@ The following guidance helps reduce downtime in high availability (HA) topologie For HA topologies, the best approach is to stand up a new replica with multiple data disks configured, replicate data from the primary, and then promote the replica to primary. Migrating data to additional disks on the current primary is not recommended, as this process can lead to significant downtime. 1. Set up a new HA replica with better disks. - + {% ifversion ghes < 3.20 %} To plan for the data migration, use `du -sh /data/user/mysql` and `du -sh /data/user/repositories` on the primary to calculate disk space requirements for the new replica. + {%- endif %} + {% ifversion ghes > 3.19 %} + To plan for the data migration, use `du -sh /data/user/mysql`, `du -sh /data/user/repositories`, `du -sh /var/log`, `du -sh /data/github/current/log`, and `du -sh /data/github/shared/log` on the primary to calculate disk space requirements for the new replica. + {%- endif %} 1. Set up multi-disk on the new HA replica. 1. Allow the HA primary to replicate to the replica. @@ -121,9 +179,11 @@ For HA topologies, the best approach is to stand up a new replica with multiple While the replication process can take a long time, the advantage is that it runs in the background, so the actual disruption from maintenance mode is dramatically reduced. -## Example: configuring two additional disks +## Example: configuring additional disks + +This example demonstrates the required commands and outputs for disk initialization and data migration. Specifically, `/data/user/mysql` is migrated to `/data/multi-disk/db/mysql`, and `/data/user/repositories` is migrated to `/data/multi-disk/git/repositories`.{% ifversion ghes > 3.19 %} Additionally, system logs are migrated to `/data/multi-disk/systemlogs/log`, and {% data variables.product.github %} logs are migrated to `/data/multi-disk/githublogs`.{%- endif %} -This example demonstrates the required commands and outputs for disk initialization and data migration. Specifically, `/data/user/mysql` is migrated to `/data/multi-disk/db/mysql`, and `/data/user/repositories` is migrated to `/data/multi-disk/git/repositories`. +{% ifversion ghes < 3.20 %} ```shell admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk status @@ -139,7 +199,7 @@ admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk ini Starting initialization sequence for /dev/nvme3n1 at /data/multi-disk/git... admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-mysql db -Start mysql migration to /data/multi-disk/db... +Start MySQL migration to /data/multi-disk/db... Running checks.. Error: maintenance mode must be enabled before being able to proceed. ERROR: Last Command: return 1 LINE: 36 ghe-storage-migrate-mysql @@ -148,7 +208,7 @@ Script exited with exit code: 1 admin@ghe-test-primary:~$ ghe-maintenance -s admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-mysql db -Start repository migration to /data/multi-disk/db... +Start MySQL migration to /data/multi-disk/db... Success: /data/user/mysql moved to /data/multi-disk/db/mysql Script exited with exit code: 0 @@ -178,22 +238,159 @@ ghe-storage-init-db.log ghe-storage-init-git.log ghe-storage-migrate-mysql.log ``` +{%- endif %} + +{% ifversion ghes > 3.19 %} + +```shell +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk status +Checking system status... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk info +Dumping disk status and information... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme2n1 db +Starting initialization sequence for /dev/nvme2n1 at /data/multi-disk/db... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme3n1 git +Starting initialization sequence for /dev/nvme3n1 at /data/multi-disk/git... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme4n1 systemlogs +Starting initialization sequence for /dev/nvme4n1 at /data/multi-disk/systemlogs... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk init /dev/nvme5n1 githublogs +Starting initialization sequence for /dev/nvme5n1 at /data/multi-disk/githublogs... + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-mysql db +Start MySQL migration to /data/multi-disk/db... +Running checks.. +Error: maintenance mode must be enabled before being able to proceed. +ERROR: Last Command: return 1 LINE: 36 ghe-storage-migrate-mysql +Script exited with exit code: 1 + +admin@ghe-test-primary:~$ ghe-maintenance -s + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-mysql db +Start MySQL migration to /data/multi-disk/db... +Success: /data/user/mysql moved to /data/multi-disk/db/mysql +Script exited with exit code: 0 + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-repositories git +Start repository migration to /data/multi-disk/git... +Success: /data/user/repositories moved to /data/multi-disk/git +Script exited with exit code: 0 + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-logs systemlogs +Start log migration to /data/multi-disk/systemlogs... +Success: /var/log moved to /data/multi-disk/systemlogs/log +Please restart the GitHub Enterprise instance to apply the changes. +Script exited with exit code: 0 + +admin@ghe-test-primary:~$ sudo reboot + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-github-logs githublogs +Error: Config apply currently in progress. Please wait for it to finish... + +# Wait for config apply to finish + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-migrate-github-logs githublogs +Start github log migration to /data/multi-disk/githublogs... +Success: moved to /data/multi-disk/githublogs +Script exited with exit code: 0 + +admin@ghe-test-primary:~$ ghe-maintenance -u + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk status +Checking system status... +Multi disk setup is enabled... +Potential disks are automatically mounted on startup... +# Disk check +Detected multi disk path at /data/multi-disk/db... +/data/multi-disk/db is set up correctly for multi disk use. +Detected multi disk path at /data/multi-disk/git... +/data/multi-disk/git is set up correctly for multi disk use. +Detected multi disk path at /data/multi-disk/githublogs... +/data/multi-disk/githublogs is set up correctly for multi disk use. +Detected multi disk path at /data/multi-disk/systemlogs... +/data/multi-disk/systemlogs is set up correctly for multi disk use. +# Service migration check +MySQL migration was detected... +/data/user/mysql -> /data/multi-disk/db/mysql is correctly symlinked. +Repositories migration was detected... +/data/user/repositories -> /data/multi-disk/git/repositories is correctly symlinked. +GitHub current log migration was detected... +/data/github/current/log -> /data/multi-disk/githublogs/github-current-log is correctly symlinked. +GitHub shared log migration was detected... +/data/github/shared/log -> /data/multi-disk/githublogs/github-shared-log is correctly symlinked. +Logs migration was detected... +/var/log -> /data/multi-disk/systemlogs/log is correctly symlinked. + +admin@ghe-test-primary:~$ /usr/local/share/enterprise/ghe-storage-multi-disk info +Dumping disk status and information... +# Multi disk configuration /data/user/multi-disk-config: +DISK_DB="lvm" +DISK_GIT="lvm" +DISK_SYSTEMLOGS="lvm" +DISK_GITHUBLOGS="lvm" +MYSQL_MIGRATION_PATH="/data/multi-disk/db/mysql" +REPOSITORIES_MIGRATION_PATH="/data/multi-disk/git/repositories" +# Multi-disk logs path is stored in /etc/multi-disk/ghe-multi-disk-logs-mount +GHCURRENT_LOG_MIGRATION_PATH="/data/multi-disk/githublogs/github-current-log" +GHSHARED_LOG_MIGRATION_PATH="/data/multi-disk/githublogs/github-shared-log" +ENABLE_MULTI_DISK_LOGS_MOUNT=true + +LOGS_MIGRATION_PATH=/data/multi-disk/systemlogs/log + +admin@ghe-test-primary:~$ ls /var/log/multi-disk/ +ghe-storage-init-db.log ghe-storage-init-git.log ghe-storage-migrate-github-logs.log ghe-storage-migrate-mysql.log ghe-storage-init-githublogs.log ghe-storage-init-systemlogs.log ghe-storage-migrate-logs.log ghe-storage-migrate-repositories.log + +``` + +{%- endif %} + ## Hygiene checks Both `/usr/local/share/enterprise/ghe-storage-multi-disk status` and `/usr/local/share/enterprise/ghe-storage-multi-disk info` are helpful for checking your setup. To view the current multi-disk configuration, use: +{% ifversion ghes < 3.20 %} + +```shell +$ cat /data/user/multi-disk-config +DISK_DB="lvm" +DISK_GIT="lvm" +MYSQL_MIGRATION_PATH="/data/multi-disk/db/mysql" +REPOSITORIES_MIGRATION_PATH="/data/multi-disk/git/repositories" +``` + +{%- endif %} +{% ifversion ghes > 3.19 %} + ```shell $ cat /data/user/multi-disk-config DISK_DB="lvm" DISK_GIT="lvm" +DISK_SYSTEMLOGS="lvm" +DISK_GITHUBLOGS="lvm" MYSQL_MIGRATION_PATH="/data/multi-disk/db/mysql" REPOSITORIES_MIGRATION_PATH="/data/multi-disk/git/repositories" +# Multi-disk logs path is stored in /etc/multi-disk/ghe-multi-disk-logs-mount +GHCURRENT_LOG_MIGRATION_PATH="/data/multi-disk/githublogs/github-current-log" +GHSHARED_LOG_MIGRATION_PATH="/data/multi-disk/githublogs/github-shared-log" + +$ cat /etc/multi-disk/ghe-multi-disk-logs-mount +ENABLE_MULTI_DISK_LOGS_MOUNT=true + +LOGS_MIGRATION_PATH=/data/multi-disk/systemlogs/log ``` +{%- endif %} + To review multi-disk logs, including disk initialization and migration events, run: +{% ifversion ghes < 3.20 %} + ```shell $ ls -l /var/log/multi-disk/ total 56 @@ -203,6 +400,24 @@ total 56 -rw-r--r-- 1 root root 37296 Mar 3 13:30 ghe-storage-migrate-repositories.log ``` +{%- endif %} +{% ifversion ghes > 3.19 %} + +```shell +$ ls -l /var/log/multi-disk/ +total 64 +-rw-r--r-- 1 root root 2115 Feb 13 16:32 ghe-storage-init-db.log +-rw-r--r-- 1 root root 2478 Feb 13 16:36 ghe-storage-init-githublogs.log +-rw-r--r-- 1 root root 2114 Feb 13 16:36 ghe-storage-init-git.log +-rw-r--r-- 1 root root 2378 Feb 13 16:36 ghe-storage-init-systemlogs.log +-rw-r--r-- 1 root root 20450 Feb 13 17:27 ghe-storage-migrate-github-logs.log +-rw-r--r-- 1 root root 1053 Feb 13 17:15 ghe-storage-migrate-logs.log +-rw-r--r-- 1 root root 2460 Feb 13 16:38 ghe-storage-migrate-mysql.log +-rw-r--r-- 1 root root 19011 Feb 13 16:42 ghe-storage-migrate-repositories.log +``` + +{%- endif %} + ## Commands for managing multiple disks These commands make it possible to add multiple disks and migrate specific services or folder paths to those disks. The original folder paths are maintained and kept static. Other services are unaware that anything has changed. The static folder paths are symlinked to the newly migrated paths. @@ -220,3 +435,9 @@ The commands include: * Migrates `/data/user/repositories` to any disk path created using `ghe-storage-multi-disk init`. * ghe-storage-migrate-mysql * Migrates `/data/user/mysql` to any disk path created using `ghe-storage-multi-disk init`. +{% ifversion ghes > 3.19 %} +* ghe-storage-migrate-logs + * Migrates `/var/log` to any disk path created using `ghe-storage-multi-disk init`. +* ghe-storage-migrate-github-logs + * Migrates `/data/github/current/log` and `/data/github/shared/log` to any disk path created using `ghe-storage-multi-disk init`. +{%- endif %} diff --git a/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app.md b/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app.md index a009953a3e29..488c4ba38d32 100644 --- a/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app.md +++ b/content/apps/creating-github-apps/authenticating-with-a-github-app/generating-a-json-web-token-jwt-for-a-github-app.md @@ -130,7 +130,7 @@ encoded_jwt = jwt.encode(payload, signing_key, algorithm='RS256') print(f"JWT: {encoded_jwt}") ``` -This script will prompt you for the file path where your private key is stored and for the ID of your app. Alternatively, you can pass those values as inline arguments when you execute the script. +This script will prompt you for the file path where your private key is stored and for the {% ifversion client-id-for-app %}client ID{% else %}app ID{% endif %} of your app. Alternatively, you can pass those values as inline arguments when you execute the script. ### Example: Using Bash to generate a JWT diff --git a/content/code-security/concepts/supply-chain-security/best-practices-for-maintaining-dependencies.md b/content/code-security/concepts/supply-chain-security/best-practices-for-maintaining-dependencies.md index b01fe39fe2d6..201fb130c8c9 100644 --- a/content/code-security/concepts/supply-chain-security/best-practices-for-maintaining-dependencies.md +++ b/content/code-security/concepts/supply-chain-security/best-practices-for-maintaining-dependencies.md @@ -79,42 +79,17 @@ By following these practices, you can significantly reduce the risk posed by out ## How {% data variables.product.github %} can help -{% data variables.product.github %} offers several security features that can help maintain the security of your codebases: +{% data variables.product.github %} provides security features to help you maintain dependencies: -**Dependency graph** +**Dependency graph**: Tracks your project dependencies and identifies vulnerabilities. See [AUTOTITLE](/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph). - * Provides a tabular representation of your project's dependencies. - * The graph helps you understand the dependencies of your project and {% data variables.product.github %} uses this to identify vulnerable dependencies. - * For more information, see [AUTOTITLE](/code-security/supply-chain-security/understanding-your-software-supply-chain/about-the-dependency-graph). +**Dependency review**: Catches insecure dependencies in pull requests before they're merged. In addition, the {% data variables.dependency-review.action_name %} can fail checks and, when required by branch protection rules, prevent pull requests that introduce vulnerabilities from being merged. See [AUTOTITLE](/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review). -**Dependency review** +**{% data variables.product.prodname_dependabot %}**: Automatically scans for vulnerabilities, creates alerts, and opens pull requests to update vulnerable or outdated dependencies. You can group multiple updates into single pull requests to streamline reviews. See [AUTOTITLE](/code-security/dependabot/dependabot-alerts/about-dependabot-alerts). - * Is integrated into your CI/CD pipeline, and allows you to catch insecure dependencies in your code at every pull request. For more information, see [AUTOTITLE](/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review). +**{% data variables.product.prodname_advisory_database %}**: Provides security advisories that power {% data variables.product.prodname_dependabot %}'s vulnerability detection. See [AUTOTITLE](/code-security/security-advisories/working-with-global-security-advisories-from-the-github-advisory-database/about-the-github-advisory-database).{% ifversion fpt or ghec %} - * The {% data variables.dependency-review.action_name %} is a tool that can block the merging of pull requests if they introduce vulnerabilities or fail to update vulnerable dependencies. For more information, see "About the {% data variables.dependency-review.action_name %}" in [AUTOTITLE](/code-security/supply-chain-security/understanding-your-software-supply-chain/about-dependency-review#about-the-dependency-review-action). +**Private vulnerability reporting**: Enables maintainers to receive, discuss, and fix vulnerability reports in private before public disclosure. {% endif %} +**Security overview**: Shows your organization's security posture with dashboards for at-risk repositories, alert trends, and feature enablement status. See [AUTOTITLE](/code-security/security-overview/about-security-overview). -**{% data variables.product.prodname_dependabot %}** - - * **{% data variables.product.prodname_dependabot_alerts %}**: {% data variables.product.prodname_dependabot %} scans your dependencies for known vulnerabilities and automatically creates alerts when vulnerabilities are found in the repository. For more information, see [AUTOTITLE](/code-security/dependabot/dependabot-alerts/about-dependabot-alerts). - - * **{% data variables.product.prodname_dependabot_security_updates %}**: Automatically opens pull requests to update vulnerable dependencies to versions that do not have known vulnerabilities. This allows you to quickly review and merge fixes. For more information, see [AUTOTITLE](/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates). - - * **{% data variables.product.prodname_dependabot_version_updates %}**: Can also be configured to automatically open pull requests to update your dependencies to their latest versions regularly, ensuring you are always using current packages. For more information, see [AUTOTITLE](/code-security/dependabot/dependabot-version-updates/about-dependabot-version-updates). - - * **Grouped updates**: Makes it easier to review and deploy pull requests for {% data variables.product.prodname_dependabot_updates %} by grouping several updates into a single pull request, see [About grouped security updates](/code-security/dependabot/dependabot-security-updates/about-dependabot-security-updates#about-grouped-security-updates) and examples in [AUTOTITLE](/code-security/dependabot/dependabot-version-updates/optimizing-pr-creation-version-updates#reducing-the-volume-of-dependabot-pull-requests) - -**Security Advisories**{% ifversion fpt or ghec %} - - * **Private vulnerability reporting**: Allows maintainers to privately discuss, fix, and publish security advisories for their repositories. For more information, see [AUTOTITLE](/code-security/security-advisories/guidance-on-reporting-and-writing-information-about-vulnerabilities/privately-reporting-a-security-vulnerability).{% endif %} - - * **{% data variables.product.prodname_advisory_database %}**: A database of security advisories that is used by {% data variables.product.prodname_dependabot %} to identify vulnerabilities in your dependencies. For more information, see [AUTOTITLE](/code-security/security-advisories/working-with-global-security-advisories-from-the-github-advisory-database/about-the-github-advisory-database). - -**Security overview** - - * You can keep an eye on the dashboards on the security overview page, which provide insights about your organization or enterprise's security landscape and progress. It helps users identify repositories that need attention and monitor the health of their application security program. For example, you can see a summary of an organization's security risk, trends in detection, remediation, and prevention of security alerts, as well as the enablement status of {% data variables.product.github %}'s security features. For more information, see [AUTOTITLE](/code-security/security-overview/about-security-overview). - -**Security policy** - - * You can create a `SECURITY.md` file in your repository that outlines the security policies and procedures for reporting and handling security issues. For more information, see [AUTOTITLE](/code-security/getting-started/adding-a-security-policy-to-your-repository). - -For additional guidance across the whole supply chain using {% data variables.product.github %}'s security features, see [AUTOTITLE](/code-security/supply-chain-security/end-to-end-supply-chain/end-to-end-supply-chain-overview). +For end-to-end supply chain guidance, see [AUTOTITLE](/code-security/supply-chain-security/end-to-end-supply-chain/end-to-end-supply-chain-overview). diff --git a/content/code-security/reference/secret-security/supported-secret-scanning-patterns.md b/content/code-security/reference/secret-security/supported-secret-scanning-patterns.md index 286920ddaafb..4b466c4d72c8 100644 --- a/content/code-security/reference/secret-security/supported-secret-scanning-patterns.md +++ b/content/code-security/reference/secret-security/supported-secret-scanning-patterns.md @@ -66,7 +66,7 @@ Precision levels are estimated based on the pattern type's typical false positiv | Generic | http_basic_authentication_header | HTTP Basic Authentication credentials in request headers | Medium | | Generic | http_bearer_authentication_header | HTTP Bearer tokens used for API authentication | Medium | | Generic | mongodb_connection_string | Connection strings for MongoDB databases containing credentials | High | -| Generic | mysql_connection_string | Connection strings for MySQL databases containing credentials | High | +| Generic | mysql_connection_url | Connection strings for MySQL databases containing credentials | High | | Generic | openssh_private_key | OpenSSH format private keys used for SSH authentication | High | | Generic | pgp_private_key | PGP (Pretty Good Privacy) private keys used for encryption and signing | High | | Generic | postgres_connection_string | Connection strings for PostgreSQL databases containing credentials | High | @@ -88,7 +88,7 @@ Precision levels are estimated based on the pattern type's typical false positiv | Generic | http_basic_authentication_header | HTTP Basic Authentication credentials in request headers | Medium | | Generic | http_bearer_authentication_header | HTTP Bearer tokens used for API authentication | Medium | | Generic | mongodb_connection_string | Connection strings for MongoDB databases containing credentials | High | -| Generic | mysql_connection_string | Connection strings for MySQL databases containing credentials | High | +| Generic | mysql_connection_url | Connection strings for MySQL databases containing credentials | High | | Generic | openssh_private_key | OpenSSH format private keys used for SSH authentication | High | | Generic | pgp_private_key | PGP (Pretty Good Privacy) private keys used for encryption and signing | High | | Generic | postgres_connection_string | Connection strings for PostgreSQL databases containing credentials | High | 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 a1a413b85c37..3db80eba22db 100644 --- a/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md +++ b/content/copilot/concepts/agents/copilot-cli/about-copilot-cli.md @@ -187,20 +187,13 @@ You should therefore always keep security considerations in mind when using {% d ### Trusted directories -When you start a {% data variables.copilot.copilot_cli %} session, you'll be asked to confirm that you trust the files in, and below, the directory from which you launched the CLI. +Trusted directories control where {% data variables.copilot.copilot_cli_short %} can read, modify, and execute files. -> [!WARNING] -> * You should only launch {% data variables.copilot.copilot_cli_short %} from directories that you trust. You should not use {% data variables.copilot.copilot_cli_short %} in directories that may contain executable files you can't be sure you trust. Similarly, if you launch the CLI from a directory that contains sensitive or confidential data, or files that you don't want to be changed, you could inadvertently expose those files to risk. Typically, you should not launch {% data variables.copilot.copilot_cli_short %} from your home directory. -> * Scoping of permissions is heuristic and {% data variables.product.company_short %} does not guarantee that all files outside trusted directories will be protected. See [Risk mitigation](#risk-mitigation) later in this article. +You should only launch {% data variables.copilot.copilot_cli_short %} from directories that you trust. You should not use {% data variables.copilot.copilot_cli_short %} in directories that may contain executable files you can't be sure you trust. Similarly, if you launch the CLI from a directory that contains sensitive or confidential data, or files that you don't want to be changed, you could inadvertently expose those files to risk. Typically, you should not launch {% data variables.copilot.copilot_cli_short %} from your home directory. -You can choose to trust the current directory for: +Scoping of permissions is heuristic and {% data variables.product.company_short %} does not guarantee that all files outside trusted directories will be protected. See [Risk mitigation](#risk-mitigation). -* The currently running session only -* This and future sessions - -If you choose to trust the directory for future sessions, the trusted directory prompt will not be displayed again. You should only choose this second option if you are sure that this location will always be a safe place for {% data variables.product.prodname_copilot_short %} to operate. - -You can edit the list of permanently trusted directories by amending the contents of the `trusted_folders` array in the CLI's `config.json` file. This is located, by default, in the `~/.copilot` directory. You can change this location by setting the `XDG_CONFIG_HOME` environment variable. +When you start a {% data variables.copilot.copilot_cli %} session, you'll be asked to confirm that you trust the files in, and below, the directory from which you launched the CLI. See [AUTOTITLE](/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli#setting-trusted-directories). ### Allowed tools @@ -294,9 +287,20 @@ copilot --allow-tool 'My-MCP-Server' --deny-tool 'My-MCP-Server(tool_name)' It's important to be aware of the security implications of using the approval command-line options. These options allow {% data variables.product.prodname_copilot_short %} to execute commands needed to complete your request, without giving you the opportunity to review and approve those commands before they are run. While this streamlines workflows, and allows headless operation of the CLI, it increases the risk of unintended actions being taken that might result in data loss or corruption, or other security issues. +You can control which tools {% data variables.copilot.copilot_cli_short %} can use by responding to approval prompts when {% data variables.product.prodname_copilot_short %} attempts to use a tool, by specifying permissions with command-line flags, or (in an interactive session) by using slash commands (such as `/allow-all` and `/yolo`. See [AUTOTITLE](/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli#setting-allowed-tools). + ### Risk mitigation -You can mitigate the risks associated with using the automatic approval options by using {% data variables.copilot.copilot_cli_short %} in a restricted environment, such as a virtual machine, container, or dedicated system, without internet access. This confines any potential damage that could occur when allowing {% data variables.product.prodname_copilot_short %} to execute commands that you have not reviewed and verified. +You can mitigate the risks associated with using the automatic approval options by running {% data variables.copilot.copilot_cli_short %} in a restricted environment—such as a virtual machine, container, or dedicated system—with tightly controlled permissions and network access. This confines any potential damage that could occur when allowing {% data variables.product.prodname_copilot_short %} to execute commands that you have not reviewed and verified. + +### Known MCP server policy limitations + +{% data variables.copilot.copilot_cli_short %} can't currently support the following organization-level MCP server policies: + +* **MCP servers in {% data variables.product.prodname_copilot_short %}**, which controls whether MCP servers can be used at all by {% data variables.product.prodname_copilot_short %}. +* **MCP Registry URL**, which controls which MCP registry {% data variables.product.prodname_copilot_short %} will allow MCP servers to be used from. + +For more information about these policies, see [AUTOTITLE](/copilot/concepts/mcp-management#mcp-policy-settings). ## Model usage diff --git a/content/copilot/concepts/auto-model-selection.md b/content/copilot/concepts/auto-model-selection.md index b9fc161de7c2..3bd0cdd8c341 100644 --- a/content/copilot/concepts/auto-model-selection.md +++ b/content/copilot/concepts/auto-model-selection.md @@ -45,6 +45,7 @@ When you select **Auto** in {% data variables.copilot.copilot_chat_short %}, {% * {% data variables.copilot.copilot_gpt_41 %} * {% data variables.copilot.copilot_gpt_5_mini %} * {% data variables.copilot.copilot_gpt_52_codex %} + * {% data variables.copilot.copilot_gpt_53_codex %} * {% data variables.copilot.copilot_claude_haiku_45 %} * {% data variables.copilot.copilot_claude_sonnet_45 %} diff --git a/content/copilot/concepts/billing/copilot-requests.md b/content/copilot/concepts/billing/copilot-requests.md index 99ffd02044b9..a60aa89deee1 100644 --- a/content/copilot/concepts/billing/copilot-requests.md +++ b/content/copilot/concepts/billing/copilot-requests.md @@ -92,7 +92,6 @@ The available models vary depending on your {% data variables.product.prodname_c > * Discounted multipliers are available for using {% data variables.copilot.copilot_auto_model_selection %} in {% data variables.copilot.copilot_chat_short %} in {% data variables.product.prodname_vscode_shortname %}. See [AUTOTITLE](/copilot/concepts/auto-model-selection). > * {% data reusables.copilot.auto-model-multiplier-discount %} For example, Sonnet 4 would be billed at .9x rather than 1x when using {% data variables.copilot.copilot_auto_model_selection_short %}. > * Discounted multipliers are not available for {% data variables.copilot.copilot_free_short %}. -> * Promotional pricing for {% data variables.copilot.copilot_claude_opus_46_fast %} is available from February 7, 2026 through February 16, 2026. During this period, {% data variables.copilot.copilot_claude_opus_46_fast %} uses a 9x premium request multiplier. Each model has a premium request multiplier, based on its complexity and resource usage. If you are on a paid {% data variables.product.prodname_copilot_short %} plan, your premium request allowance is deducted according to this multiplier. diff --git a/content/copilot/how-tos/copilot-cli/index.md b/content/copilot/how-tos/copilot-cli/index.md index 375ada885e8a..f13818fed965 100644 --- a/content/copilot/how-tos/copilot-cli/index.md +++ b/content/copilot/how-tos/copilot-cli/index.md @@ -7,8 +7,8 @@ versions: children: - /cli-getting-started - /cli-best-practices + - /set-up-copilot-cli - /customize-copilot - - /install-copilot-cli - /use-copilot-cli contentType: how-tos --- 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 new file mode 100644 index 000000000000..b077e8d9ec4b --- /dev/null +++ b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/configure-copilot-cli.md @@ -0,0 +1,274 @@ +--- +title: Configure GitHub Copilot CLI +shortTitle: Configure Copilot CLI +intro: Configure trusted directories, tool access, and path and URL permissions for {% data variables.copilot.copilot_cli_short %} +versions: + feature: copilot +topics: + - Copilot + - CLI +contentType: how-tos +category: + - Configure Copilot +--- + +{% data reusables.cli.preview-note-cli %} + +## Introduction + +{% data variables.copilot.copilot_cli_short %} has several configuration options that control what it can access and do on your behalf. + +This article shows you how to set trusted directories, configure access for tools, and grant permissions to file paths and URLs. + +### Prerequisites + +* Install the {% data variables.copilot.copilot_cli_short %}. See [AUTOTITLE](/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli). + +## 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/about-copilot-cli#trusted-directories). + +### Choosing to trust a directory + +When you start a {% data variables.copilot.copilot_cli %} session, you'll be asked to confirm that you trust the files in, and below, the directory from which you launched the CLI. + +You can choose to trust the current directory for: + +* The currently running session only +* This and future sessions + +If you choose to trust the directory for future sessions, the trusted directory prompt will not be displayed again. You should only choose this second option if you are sure that this location will always be a safe place for {% data variables.product.prodname_copilot_short %} to operate. + +### Editing trusted directories + +You can edit the list of permanently trusted directories. + +1. Open the CLI’s `config.json` file. By default, it’s stored in a `.copilot` folder under your home directory: + * **macOS/Linux**: `~/.copilot/config.json` + * **Windows**: `$HOME\.copilot\config.json` + + You can change the config location by setting the `XDG_CONFIG_HOME` environment variable (primarily on macOS/Linux). +1. Edit the contents of the `trusted_folders` array. + +## Setting allowed tools + +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/about-copilot-cli#allowed-tools). + +In this section, you can learn how to: + +* [Allow a tool for the first time](#allowing-a-tool-for-the-first-time) +* [Allow tools to be used without manual approval](#allowing-tools-to-be-used-without-manual-approval) +* [Specify which tool you want to allow or deny](#specifying-which-tool-you-want-to-allow-or-deny) +* [Allow some tools while denying others](#allowing-some-tools-while-denying-others) +* [Limit available tools](#limiting-available-tools) + +### Allowing a tool for the first time + +The first time that {% data variables.product.prodname_copilot_short %} needs to use a tool that may require approval—for example, {% data reusables.cli.tools-needing-approval %}—it will ask you whether you want to allow it to run. Whether you’re prompted can depend on the tool and how it’s being used (such as the arguments provided or whether the tool has been previously approved). + +1. Prompt {% data variables.product.prodname_copilot_short %} to perform a task that requires a tool. For example: + + ```shell + copilot -p "Create a new file called README.md with a project description" + ``` + +1. Choose from one of the three options: + + * `1. Yes` + + Choose this option to allow {% data variables.product.prodname_copilot_short %} to run this particular command, this time only. The next time it needs to use this tool, it will ask you again. + + * `2. Yes, and approve TOOL for the rest of the running session` + + Choose this option to allow {% data variables.product.prodname_copilot_short %} to use this tool for the duration of the currently running session. It will ask for your approval again in new sessions, or if you resume the current session in the future. If you choose this option, you are allowing {% data variables.product.prodname_copilot_short %} to use this tool in any way it thinks is appropriate. + + For example, if {% data variables.product.prodname_copilot_short %} asks you to allow it to run the command `rm ./this-file.txt`, and you choose option 2, then {% data variables.product.prodname_copilot_short %} can run any `rm` command (for example, `rm -rf ./*`) during the current run of this session, without asking for your approval. + + * `3. No, and tell Copilot what to do differently (Esc)` + + Choose this option to cancel the proposed command and instruct {% data variables.product.prodname_copilot_short %} to try a different approach. + +### Allowing tools to be used without manual approval + +You can use command-line flags to designate tools that {% data variables.product.prodname_copilot_short %} can use without asking for your approval. + +#### Allowing all tools + +Use the `--allow-all-tools` to allow {% data variables.product.prodname_copilot_short %} to use any tool without asking for your approval. + +* For example: + + ```shell + copilot -p "Revert the last commit" --allow-all-tools + ``` + +#### Denying a tool + +Use `--deny-tool` to prevent {% data variables.product.prodname_copilot_short %} from using a specific tool. + +* For example: + + ```shell + copilot --deny-tool 'shell(git push)' + ``` + +This option takes precedence over the `--allow-all-tools` and `--allow-tool` options. + +#### Allowing a tool + +Use `--allow-tool` to allow {% data variables.product.prodname_copilot_short %} to use a specific tool without asking for your approval. + +* For example: + + ```shell + copilot --allow-tool 'shell' + ``` + +### Specifying which tool you want to allow or deny + +To use the `--deny-tool` and `--allow-tool` options, you must specify what type of tool you want to allow or deny: + +* [Shell commands](#allowing-or-denying-shell-commands) +* ['Write' tools](#allowing-or-denying-write-tools) +* [MCP server tools](#allowing-or-denying-mcp-server-tools) + +#### Allowing or denying shell commands + +Use `shell(COMMAND)` to allow or deny a specific shell command. + +* For example, to prevent {% data variables.product.prodname_copilot_short %} from using any `rm` command, use: + + ```shell + copilot --deny-tool 'shell(rm)' + ``` + +For `git` and `gh` commands, specify a particular first-level subcommand to allow or deny. + +* For example, to prevent {% data variables.product.prodname_copilot_short %} from using `git push`, use: + + ```shell + copilot --deny-tool 'shell(git push)' + ``` + +The tool specification is optional. For example, `copilot --allow-tool 'shell'` allows {% data variables.product.prodname_copilot_short %} to use any shell command without individual approval. + +#### Allowing or denying `'write'` tools + +Use `'write'` to allow or deny tools—other than shell commands—permission to modify files. + +* For example, to allow {% data variables.product.prodname_copilot_short %} to edit files without your individual approval, use: + + ```shell + copilot --allow-tool 'write' + ``` + +#### Allowing or denying MCP server tools + +Use `'MCP_SERVER_NAME'` to allow or deny a specific tool from the specified MCP server. + +* For example, to prevent {% data variables.product.prodname_copilot_short %} from using the tool called `tool_name` from the MCP server called `My-MCP-Server`, use: + + ```shell + copilot --deny-tool 'My-MCP-Server(tool_name)' + ``` + +`MCP_SERVER_NAME` is the name of an MCP server that you have configured. + +Tools from the server are specified in parentheses, using the tool name that is registered with the MCP server. + +Using the server name without specifying a tool allows or denies all tools from that server. + +You can find an MCP server's name by entering `/mcp` in the interactive mode of {% data variables.copilot.copilot_cli_short %} and selecting the server from the list that's displayed. + +### Allowing some tools while denying others + +To determine exactly which tools {% data variables.product.prodname_copilot_short %} can use without asking for your approval, you can use a combination of approval options. For example: + +* To prevent {% data variables.product.prodname_copilot_short %} from using the `rm` and `git push` commands, but automatically allow all other tools, use: + + ```shell + copilot --allow-all-tools --deny-tool 'shell(rm)' --deny-tool 'shell(git push)' + ``` + +* To prevent {% data variables.product.prodname_copilot_short %} from using the tool `tool_name` from the MCP server named `My-MCP-Server`, but allow all other tools from that server to be used without individual approval, use: + + ```shell + copilot --allow-tool 'My-MCP-Server' --deny-tool 'My-MCP-Server(tool_name)' + ``` + +### Limiting available tools + +To restrict {% data variables.product.prodname_copilot_short %} to a specific set of tools, use `--available-tools`. + +Tools not included in this list will not be available to {% data variables.product.prodname_copilot_short %}. + +## Setting path permissions + +Path permissions control which directories and files {% data variables.product.prodname_copilot_short %} can access. + +By default, {% data variables.copilot.copilot_cli_short %} can access the current working directory, its subdirectories, and the system temp directory. + +Path permissions apply to shell commands, file operations (create, edit, view), and search tools (such as `grep` and glob patterns). For shell commands, paths are heuristically extracted by tokenizing command text and identifying tokens that look like paths. + +> [!WARNING] +> Path detection for shell commands has limitations: +> +> * Paths embedded in complex shell constructs may not be detected. +> * Only a specific set of environment variables are expanded (`HOME`, `TMPDIR`, `PWD`, and similar). Custom variables like `$MY_PROJECT_DIR` are not expanded and may not be validated correctly. +> * Symlinks are resolved for existing files, but not for files being created. + +### Allowing access to all paths + +To disable path verification and allow access to any path, use the `--allow-all-paths` flag when starting {% data variables.copilot.copilot_cli_short %}. + +### Disallowing access to the temp directory + +To disallow access to the temp directory, use `--disallow-temp-dir`. + +## Setting URL permissions + +URL permissions control which external URLs {% data variables.product.prodname_copilot_short %} can access. By default, all URLs require approval before access is granted. + +URL permissions apply to the `web_fetch` tool and a curated list of shell commands that access the network (such as `curl`, `wget`, and `fetch`). For shell commands, URLs are extracted using regex patterns. + +> [!WARNING] +> URL detection for shell commands has limitations: +> +> * URLs in file contents, config files, or environment variables read by commands are not detected. +> * Obfuscated URLs (such as split strings or escape sequences) may not be detected. +> * HTTP and HTTPS are treated as different protocols and require separate approval. + +URL permissions can be persisted for the session or permanently. + +### Disabling URL verification + +To disable URL verification, use the `--allow-all-urls` flag. + +### Pre-approving specific domains + +To pre-approve specific domains, use `--allow-url `. + +* For example, `--allow-url github.com`. + +### Denying specific domains + +To deny specific domains, use `--deny-url `. + +* For example, `--deny-url github.com`. + +## Allowing all tools, paths, and URLs + +To allow all tools, paths and URLs, use `--allow-all`, or its alias, `--yolo`. + +This flag combines: +* `--allow-all-tools` (skip tool approval). +* `--allow-all-paths` (disable path verification). +* `--allow-all-urls` (disables URL verification). + +> [!TIP] During an interactive session, you can also enable all permissions with the `/allow-all` or `/yolo` slash commands. + +## Next steps + +* [AUTOTITLE](/copilot/how-tos/copilot-cli/customize-copilot) diff --git a/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/index.md b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/index.md new file mode 100644 index 000000000000..978e659e7e6b --- /dev/null +++ b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/index.md @@ -0,0 +1,11 @@ +--- +title: Setting up GitHub Copilot CLI +shortTitle: Set up Copilot CLI +intro: Learn how to install and configure {% data variables.product.prodname_copilot %} in your terminal. +versions: + feature: copilot +children: + - /install-copilot-cli + - /configure-copilot-cli +contentType: how-tos +--- \ No newline at end of file diff --git a/content/copilot/how-tos/copilot-cli/install-copilot-cli.md b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli.md similarity index 98% rename from content/copilot/how-tos/copilot-cli/install-copilot-cli.md rename to content/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli.md index 7614c916d7d7..7111bef3f9f1 100644 --- a/content/copilot/how-tos/copilot-cli/install-copilot-cli.md +++ b/content/copilot/how-tos/copilot-cli/set-up-copilot-cli/install-copilot-cli.md @@ -17,6 +17,7 @@ redirect_from: - /copilot/how-tos/personal-settings/installing-github-copilot-in-the-cli - /copilot/how-tos/set-up/installing-github-copilot-in-the-cli - /copilot/how-tos/set-up/install-copilot-cli + - /copilot/how-tos/copilot-cli/install-copilot-cli contentType: how-tos category: - Configure Copilot diff --git a/content/copilot/how-tos/copilot-cli/use-copilot-cli.md b/content/copilot/how-tos/copilot-cli/use-copilot-cli.md index 1fe2e252d868..9575f34033c2 100644 --- a/content/copilot/how-tos/copilot-cli/use-copilot-cli.md +++ b/content/copilot/how-tos/copilot-cli/use-copilot-cli.md @@ -77,40 +77,6 @@ Install {% data variables.copilot.copilot_cli_short %}. See [AUTOTITLE](/copilot When you reject a tool permission request, you can also give {% data variables.product.prodname_copilot_short %} inline feedback about the rejection so it can adapt its approach without stopping entirely. -## Permissions - -{% data variables.copilot.copilot_cli_short %} uses a permissions system to control access to paths and URLs. At times, path and URL permission checks utilize heuristic-based detection, which has limitations to be aware of. - -### Path permissions - -Path permissions control which directories and files {% data variables.product.prodname_copilot_short %} can access. By default, {% data variables.copilot.copilot_cli_short %} can access the current working directory, its subdirectories, and the system temp directory. - -Path permissions apply to shell commands, file operations (create, edit, view), and search tools (such as `grep` and glob patterns). For shell commands, paths are heuristically extracted by tokenizing command text and identifying tokens that look like paths. - -> [!WARNING] -> Path detection for shell commands has limitations: -> -> * Paths embedded in complex shell constructs may not be detected. -> * Only a specific set of environment variables are expanded (`HOME`, `TMPDIR`, `PWD`, and similar). Custom variables like `$MY_PROJECT_DIR` are not expanded and may not be validated correctly. -> * Symlinks are resolved for existing files, but not for files being created. - -To disable path verification, use the `--allow-all-paths` flag when starting {% data variables.copilot.copilot_cli_short %}. - -### URL permissions - -URL permissions control which external URLs {% data variables.product.prodname_copilot_short %} can access. By default, all URLs require approval before access is granted. - -URL permissions apply to the `web_fetch` tool and a curated list of shell commands that access the network (such as `curl`, `wget`, and `fetch`). For shell commands, URLs are extracted using regex patterns. - -> [!WARNING] -> URL detection for shell commands has limitations: -> -> * URLs in file contents, config files, or environment variables read by commands are not detected. -> * Obfuscated URLs (such as split strings or escape sequences) may not be detected. -> * HTTP and HTTPS are treated as different protocols and require separate approval. - -To disable URL verification, use the `--allow-all-urls` flag. To pre-approve specific domains, use `--allow-url ` (for example, `--allow-url github.com`). - ## Tips Optimize your experience with {% data variables.copilot.copilot_cli_short %} with the following tips. diff --git a/content/copilot/reference/ai-models/supported-models.md b/content/copilot/reference/ai-models/supported-models.md index 8fca4b9b7e6b..a4418116627f 100644 --- a/content/copilot/reference/ai-models/supported-models.md +++ b/content/copilot/reference/ai-models/supported-models.md @@ -92,8 +92,6 @@ The following table shows which AI models are available in each {% data variable ## Model multipliers -> [!NOTE] Promotional pricing for {% data variables.copilot.copilot_claude_opus_46_fast %} is available from February 7, 2026 through February 16, 2026. During this period, {% data variables.copilot.copilot_claude_opus_46_fast %} uses a 9x premium request multiplier. - Each model has a premium request multiplier, based on its complexity and resource usage. If you are on a paid {% data variables.product.prodname_copilot_short %} plan, your premium request allowance is deducted according to this multiplier. For more information about premium requests, see [AUTOTITLE](/copilot/managing-copilot/monitoring-usage-and-entitlements/about-premium-requests). diff --git a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md index 43e6d8a3d384..9b1ac46d0010 100644 --- a/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md +++ b/content/copilot/reference/copilot-usage-metrics/copilot-usage-metrics.md @@ -43,10 +43,10 @@ These metrics appear directly in the {% data variables.product.prodname_copilot_ | Language usage per day | Daily breakdown of languages used. | | Model usage | Distribution of AI models used for chat. | | Model usage per day | Daily breakdown of chat model usage. | -| Model usage per chat mode | Model usage by {% data variables.product.prodname_copilot_short %} feature (Ask, Edit, Agent). | +| Model usage per chat mode | Model usage by {% data variables.product.prodname_copilot_short %} feature (ask, edit, agent). | | Model usage per language | Distribution of languages broken down by model. | | Most used chat model | The most frequently used chat model in the last 28 days. | -| Requests per chat mode | Number of chat requests by mode (Ask, Edit, Agent). | +| Requests per chat mode | Number of chat requests by mode (ask, edit, agent). | ## Code generation dashboard metrics @@ -55,11 +55,11 @@ These metrics appear in the code generation dashboard and provide a breakdown of | Metric | Description | |:--|:--| | Lines of code changed with AI | Total lines of code added and deleted across all modes in the last 28 days. | -| Agent contribution | Percentage of lines of code added and deleted by agents (including Edit, Agent, and custom modes) in the last 28 days. | +| Agent contribution | Percentage of lines of code added and deleted by agents (including edit, agent, and custom modes) in the last 28 days. | | Average lines deleted by agent | Average number of lines automatically deleted by agents on behalf of active users during the current calendar month. | | Daily total of lines added and deleted | Total number of lines added to and deleted from the codebase across all modes for each day. | | User-initiated code changes | Lines suggested or manually added by users through code completions and chat panel actions (insert, copy, or apply). | -| Agent-initiated code changes | Lines automatically added to or deleted from the codebase by agents on behalf of users across Edit, Agent, and custom modes. | +| Agent-initiated code changes | Lines automatically added to or deleted from the codebase by agents on behalf of users across edit, agent, and custom modes. | | User-initiated code changes per model | User-initiated lines of code, grouped by model used in the IDE. | | Agent-initiated code changes per model | Agent-initiated lines of code, grouped by model performing the agent actions. | | User-initiated code changes per language | User-initiated lines of code, grouped by programming language. | @@ -71,19 +71,24 @@ These fields appear in the exported NDJSON reports and in the {% data variables. | Field | Description | |:--|:--| -| `agent_edit` | A dedicated bucket in the API and reports. Captures lines added and deleted directly by {% data variables.product.prodname_copilot_short %} Agent and Edit mode.
These are not included in suggested metrics, since agent edits don’t follow a simple suggestion to acceptance flow. | +| `agent_edit` | Captures lines added and deleted when {% data variables.product.prodname_copilot_short %} (in agent and edit mode) writes changes directly into your files in the IDE. `agent_edit` is not included in suggestion-based metrics and may not populate suggestion-style fields (for example, `user_initiated_interaction_count`). Counts edits from custom agents as well. | | `report_start_day` / `report_end_day` | Start and end dates for the 28-day reporting period. | | `day` | Calendar day this record represents. | | `enterprise_id` | Unique ID of the enterprise. | | `organization_id` (API only) | Unique ID of the organization. | | `user_id` / `user_login` | Unique identifier and {% data variables.product.github %} username for the user. | -| `user_initiated_interaction_count` | Number of explicit prompts sent to {% data variables.product.prodname_copilot_short %}.

Only counts messages or prompts actively sent to the model. Does **not** include opening the chat panel, switching modes (for example, Ask, Edit, or Agent), using keyboard shortcuts to open the inline UI, or making configuration changes. | +| `user_initiated_interaction_count` | Number of explicit prompts sent to {% data variables.product.prodname_copilot_short %}.

Only counts messages or prompts actively sent to the model. Does **not** include opening the chat panel, switching modes (for example, ask, edit, or agent), using keyboard shortcuts to open the inline UI, or making configuration changes. | +| `chat_panel_agent_mode` | Captures user-initiated interactions in the chat panel with agent mode selected. | +| `chat_panel_ask_mode` | Captures user-initiated interactions in the chat panel with ask mode selected. | +| `chat_panel_custom_mode` | Captures user-initiated interactions in the chat panel with a custom agent selected. | +| `chat_panel_edit_mode` | Captures user-initiated interactions in the chat panel with edit mode selected. | +| `chat_panel_unknown_mode` | Captures user-initiated interactions in the chat panel where the mode is unknown. | | `code_generation_activity_count` | Number of distinct {% data variables.product.prodname_copilot_short %} output events generated.

**Includes:** All generated content, including comments and docstrings.
**Multiple blocks:** Each distinct code block from a single user prompt counts as a separate generation.
**Note:** This metric is not directly comparable to `user_initiated_interaction_count`, since one prompt can produce multiple generations. | | `code_acceptance_activity_count` | Number of suggestions or code blocks accepted by users.

**Counts:** All built-in accept actions, such as “apply to file,” “insert at cursor,” “insert into terminal,” and use of the **Copy** button.
**Does not count:** Manual OS clipboard actions (for example, Ctrl+C).
**Granularity:** Each acceptance action increments the count once, regardless of how many code blocks were generated by the initial prompt. | -| `loc_suggested_to_add_sum` | Lines of code {% data variables.product.prodname_copilot_short %} suggested to add (completions, inline chat, chat panel, etc.; **excludes** Agent edits). | +| `loc_suggested_to_add_sum` | Lines of code {% data variables.product.prodname_copilot_short %} suggested to add (completions, inline chat, chat panel, etc.; **excludes** agent edits). | | `loc_suggested_to_delete_sum` | Lines of code {% data variables.product.prodname_copilot_short %} suggested to delete (future support planned). | | `loc_added_sum` | Lines of code actually added to the editor (accepted completions, applied code blocks, agent/edit mode). | -| `loc_deleted_sum` | Lines of code deleted from the editor (currently from Agent edits). | +| `loc_deleted_sum` | Lines of code deleted from the editor (currently from agent edits). | | `totals_by_ide` | Breakdown of metrics by IDE used. | | `totals_by_feature` | Breakdown of metrics by {% data variables.product.prodname_copilot_short %} feature (e.g., inline chat, chat panel). | | `totals_by_language_feature` | Breakdown combining language and feature dimensions. | diff --git a/content/copilot/tutorials/copilot-cli-hooks.md b/content/copilot/tutorials/copilot-cli-hooks.md new file mode 100644 index 000000000000..3b79078feb15 --- /dev/null +++ b/content/copilot/tutorials/copilot-cli-hooks.md @@ -0,0 +1,697 @@ +--- +title: Using hooks with Copilot CLI for predictable, policy-compliant execution +shortTitle: Use hooks with Copilot CLI +intro: Use hooks to log user prompts and control which tools {% data variables.copilot.copilot_cli_short %} can run in a repository, so teams can automate safely within your organization’s security and compliance requirements. +topics: + - Copilot +versions: + feature: copilot +contentType: tutorials +category: + - Accelerate PR velocity + - Author and optimize with Copilot +allowTitleToDifferFromFilename: true +--- + +This tutorial is for DevOps engineers, platform teams, and engineering leaders who support developers using {% data variables.copilot.copilot_cli_short %}. + +Hooks are custom scripts that run at specific points during a {% data variables.copilot.copilot_cli_short %} session. They can inspect prompts and tool calls, log information for auditing, and even block execution of certain commands. + +You’ll configure repository-scoped hooks that: + +* Provide visibility into prompts and tool use. +* Block high-risk command patterns before execution. +* Help developers understand organizational policies with clear messaging. + +## Prerequisites + +* Familiarity with shell scripting (Bash or PowerShell) +* Basic understanding of JSON configuration files +* Access to a repository where {% data variables.copilot.copilot_cli_short %} is used +* `jq` installed (for the Bash examples) + +## 1. Define an organizational policy + +Before you write any hook scripts, decide which actions should be allowed automatically and which should require human review. + +A clear policy helps you avoid over-blocking while still reducing risk. + +### Identify commands that always require review + +Start by identifying patterns that should never be auto-executed by {% data variables.copilot.copilot_cli_short %}. Common examples include: + +* **Privilege escalation**: `sudo`, `su`, `runas` +* **Destructive system operations**: `rm -rf /`, `mkfs`, `dd`, `format` +* **Download-and-execute patterns**: `curl ... | bash`, `wget ... | sh`, PowerShell `iex (irm ...)` + +These commands can have irreversible effects if executed unintentionally. + +### Decide what to log + +When you use hooks, you can capture information about how {% data variables.copilot.copilot_cli_short %} is used in a repository, including prompts submitted by users and tools that {% data variables.copilot.copilot_cli_short %} attempts to run. + +At minimum, most organizations log: + +* The timestamp and repository path +* The prompt text (or a redacted form) +* The tool name and tool arguments +* Any policy decision (for example, a denied command and its reason) + +Avoid logging secrets or credentials. If prompts or commands may contain sensitive data, apply redaction before writing logs. + +This tutorial uses a local `.github/hooks/logs` directory as a simple, illustrative example. These log files are **not intended to be committed to the repository** and typically live only on a developer’s machine. + +In production environments, many organizations forward hook events to a centralized logging or observability system instead of writing logs locally. This allows teams to apply consistent redaction, access controls, retention policies, and monitoring across repositories and users. + +### Align with stakeholders + +Before enforcing policies, review them with: + +* Security or compliance teams, to confirm risk boundaries +* Platform or infrastructure teams, who may need broader permissions +* Development teams, so they understand what will be blocked and why + +Clear expectations make policy enforcement easier to adopt and maintain. + +## 2. Set up repository hook files + +Throughout this tutorial, you’ll use **repository-scoped hooks** stored in the repository under `.github/hooks/`. These hooks apply whenever {% data variables.copilot.copilot_cli_short %} runs from within this repository. + +> [!NOTE] +> {% data variables.product.prodname_copilot_short %} agents load hook configuration files from `.github/hooks/*.json` in the repository. Hooks run synchronously and can block execution. + +### Create the directory structure + +From the repository root, create directories for your hook configuration, scripts, and logs: + +```bash copy +mkdir -p .github/hooks/scripts +mkdir -p .github/hooks/logs +``` + +Add `.github/hooks/logs/` to .gitignore so local audit logs aren’t committed: + +```bash copy +echo ".github/hooks/logs/" >> .gitignore +``` + +This tutorial uses the following structure: + +```text +.github/ +└── hooks/ + ├── copilot-cli-policy.json + ├── logs/ + │ └── audit.jsonl + └── scripts/ + ├── session-banner.sh + ├── session-banner.ps1 + ├── log-prompt.sh + ├── log-prompt.ps1 + ├── pre-tool-policy.sh + └── pre-tool-policy.ps1 +``` + +### Create a hook configuration file + +Create a hook configuration file at `.github/hooks/copilot-cli-policy.json`. + +This file defines which hooks run, when they run, and which scripts they execute. + +```json copy +{ + "version": 1, + "hooks": { + "sessionStart": [ + { + "type": "command", + "bash": "./scripts/session-banner.sh", + "powershell": "./scripts/session-banner.ps1", + "cwd": ".github/hooks", + "timeoutSec": 10 + } + ], + "userPromptSubmitted": [ + { + "type": "command", + "bash": "./scripts/log-prompt.sh", + "powershell": "./scripts/log-prompt.ps1", + "cwd": ".github/hooks", + "timeoutSec": 10 + } + ], + "preToolUse": [ + { + "type": "command", + "bash": "./scripts/pre-tool-policy.sh", + "powershell": "./scripts/pre-tool-policy.ps1", + "cwd": ".github/hooks", + "timeoutSec": 15 + } + ] + } +} +``` + +### Understand what this configuration does + +This configuration sets up three hooks: + +* `sessionStart`: Shows an informational message when a new agent session starts or resumes. +* `userPromptSubmitted`: Runs whenever a user submits a prompt. +* `preToolUse`: Runs before a tool executes and can explicitly allow or deny execution. + +### Commit and share the hook configuration + +When you’re ready to share the hook configuration with collaborators (for example, via a pull request or in a test repository), commit the hook configuration and scripts. Don’t commit any local audit logs. + +```bash copy +git add .github/hooks/copilot-cli-policy.json .github/hooks/scripts +git commit -m "Add Copilot CLI hook configuration" +git push +``` + +At this point, {% data variables.copilot.copilot_cli_short %} can discover your hook configuration, even though you haven’t created the hook scripts yet. + +## 3. Add a policy banner at session start + +Use a `sessionStart` hook to display a banner whenever a new {% data variables.copilot.copilot_cli_short %} session starts or resumes. This makes it clear to developers that organizational policies are active. + +The `sessionStart` hook receives contextual information such as the current working directory and the initial prompt. Any output from this hook is ignored by {% data variables.copilot.copilot_cli_short %}, which makes it suitable for informational messages. + +### Create the session banner script (Bash) + +Create `.github/hooks/scripts/session-banner.sh`: + +```bash copy +#!/bin/bash +set -euo pipefail + +cat << 'EOF' +COPILOT CLI POLICY ACTIVE +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +• Prompts and tool use may be logged for auditing +• High-risk commands may be blocked automatically +• If something is blocked, follow the guidance shown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +EOF +exit 0 +``` + +### Create the session banner script (PowerShell) + +Create `.github/hooks/scripts/session-banner.ps1`: + +```powershell copy +$ErrorActionPreference = "Stop" + +Write-Host @" +COPILOT CLI POLICY ACTIVE +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +• Prompts and tool use may be logged for auditing +• High-risk commands may be blocked automatically +• If something is blocked, follow the guidance shown +━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ +"@ +exit 0 +``` + +### Test the session banner + +You can test the banner scripts directly: + +```bash +.github/hooks/scripts/session-banner.sh +# or, for PowerShell +.github/hooks/scripts/session-banner.ps1 +``` + +When you run either script, you should see the policy banner displayed in your terminal. + +## 4. Log prompts for auditing + +Use the `userPromptSubmitted` hook to record when users submit prompts to {% data variables.copilot.copilot_cli_short %}. This hook runs whenever a prompt is sent, before any tools are invoked. + +The hook receives structured JSON input that includes the timestamp, current working directory, and full prompt text. The output of this hook is ignored. + +> [!IMPORTANT] +> Prompts may contain sensitive information. Apply redaction and follow your organization’s data handling and retention policies when logging this data. + +### Create the prompt logging script (Bash) + +Create `.github/hooks/scripts/log-prompt.sh`: + +```bash copy +#!/bin/bash +set -euo pipefail + +INPUT="$(cat)" + +TIMESTAMP_MS="$(echo "$INPUT" | jq -r '.timestamp // empty')" +CWD="$(echo "$INPUT" | jq -r '.cwd // empty')" + +# This example logs only metadata, not the full prompt, to avoid storing +# potentially sensitive data. Adjust to match your organization’s needs. +LOG_DIR=".github/hooks/logs" +mkdir -p "$LOG_DIR" +chmod 700 "$LOG_DIR" + +jq -n \ + --arg ts "$TIMESTAMP_MS" \ + --arg cwd "$CWD" \ + '{event:"userPromptSubmitted", timestampMs:$ts, cwd:$cwd}' \ + >> "$LOG_DIR/audit.jsonl" + +exit 0 +``` + +### Create the prompt logging script (PowerShell) + +Create `.github/hooks/scripts/log-prompt.ps1`: + +```powershell copy +$ErrorActionPreference = "Stop" + +$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json + +$timestampMs = $inputObj.timestamp +$cwd = $inputObj.cwd +$prompt = $inputObj.prompt + +# Optional example redaction. Adjust to match your organization’s needs. +$redactedPrompt = $prompt -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' + +$logDir = ".github/hooks/logs" +if (-not (Test-Path $logDir)) { + New-Item -ItemType Directory -Path $logDir -Force | Out-Null +} + +$logEntry = @{ + event = "userPromptSubmitted" + timestampMs = $timestampMs + cwd = $cwd + prompt = $redactedPrompt +} | ConvertTo-Json -Compress + +Add-Content -Path "$logDir/audit.jsonl" -Value $logEntry +exit 0 +``` + +### Test the prompt logging script + +You can test the scripts directly by piping example input. + +```bash +echo '{"timestamp":1704614500000,"cwd":"/repo","prompt":"List all branches"}' \ + | .github/hooks/scripts/log-prompt.sh +# or, for PowerShell +echo '{"timestamp":1704614500000,"cwd":"/repo","prompt":"List all branches"}' | + .github/hooks/scripts/log-prompt.ps1 +``` + +After running the script, check `.github/hooks/logs/audit.jsonl` for a new log entry. + +```bash copy +cat .github/hooks/logs/audit.jsonl +``` + +At this point, prompts submitted to {% data variables.copilot.copilot_cli_short %} in this repository are recorded for auditing. + +## 5. Enforce policies with `preToolUse` + +Use the `preToolUse` hook to evaluate a tool call **before it runs**. This hook can allow execution (by doing nothing) or deny execution (by returning a structured response). + +### Understand the `preToolUse` input + +The `preToolUse` hook input includes: + +* `toolName`: The tool that {% data variables.copilot.copilot_cli_short %} is about to run (for example, `bash`) +* `toolArgs`: A **JSON string** containing that tool’s arguments + +Because `toolArgs` is a JSON string, your script must parse it before reading fields like `command`. + +> [!IMPORTANT] +> Tool arguments and commands may contain sensitive information such as API tokens, passwords, or other credentials. Apply redaction before logging this data and follow your organization's security policies. Consider logging only non-sensitive metadata (tool name, timestamp, policy decision) and directing audit events to a secured, centralized logging system with appropriate access controls and retention policies. + +### Create the policy script + +Next, create a policy script. This example: + +* Logs all attempted tool usage. +* Applies deny rules only to bash commands. +* Blocks high-risk patterns such as privilege escalation, destructive operations, and download-and-execute commands. + +To let you validate the deny flow safely, the script also includes a temporary demo rule that blocks a harmless test command. After confirming that hooks work as expected, remove the demo rule and replace it with patterns that reflect your organization’s policies. + +#### Example script (Bash) + +Create `.github/hooks/scripts/pre-tool-policy.sh`: + +```bash copy +#!/bin/bash +set -euo pipefail + +INPUT="$(cat)" + +TOOL_NAME="$(echo "$INPUT" | jq -r '.toolName // empty')" +TOOL_ARGS_RAW="$(echo "$INPUT" | jq -r '.toolArgs // empty')" # JSON string + +LOG_DIR=".github/hooks/logs" +mkdir -p "$LOG_DIR" + +# Example redaction logic. +# GitHub does not currently provide built-in secret redaction for hooks. +# This example shows one possible approach; many organizations prefer to +# forward events to a centralized logging system that handles redaction. +# Redact sensitive patterns before logging. +# Adjust these patterns to match your organization's needs. +REDACTED_TOOL_ARGS="$(echo "$TOOL_ARGS_RAW" | \ + sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/ghs_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/Bearer [A-Za-z0-9_\-\.]+/Bearer [REDACTED]/g' | \ + sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \ + sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')" + +# Log attempted tool use with redacted toolArgs. +jq -n \ + --arg tool "$TOOL_NAME" \ + --arg toolArgs "$REDACTED_TOOL_ARGS" \ + '{event:"preToolUse", toolName:$tool, toolArgs:$toolArgs}' \ + >> "$LOG_DIR/audit.jsonl" + +# Only enforce command rules for bash. +if [ "$TOOL_NAME" != "bash" ]; then + exit 0 +fi + +# Parse toolArgs JSON string. +# If toolArgs isn't valid JSON for some reason, allow (and rely on logs). +if ! echo "$TOOL_ARGS_RAW" | jq -e . >/dev/null 2>&1; then + exit 0 +fi + +COMMAND="$(echo "$TOOL_ARGS_RAW" | jq -r '.command // empty')" + +# --------------------------------------------------------------------------- +# Demo-only deny rule for safe testing. +# This blocks a harmless test command so you can validate the deny flow. +# Remove this rule after confirming your hooks work as expected. +# --------------------------------------------------------------------------- +if echo "$COMMAND" | grep -q "COPILOT_HOOKS_DENY_DEMO"; then + deny "Blocked demo command (test rule). Remove this rule after validating hooks." +fi + +deny() { + local reason="$1" + + # Redact sensitive patterns from command before logging. + local redacted_cmd="$(echo "$COMMAND" | \ + sed -E 's/ghp_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/gho_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/ghu_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/ghs_[A-Za-z0-9]{20,}/[REDACTED_TOKEN]/g' | \ + sed -E 's/Bearer [A-Za-z0-9_\-\.]+/Bearer [REDACTED]/g' | \ + sed -E 's/--password[= ][^ ]+/--password=[REDACTED]/g' | \ + sed -E 's/--token[= ][^ ]+/--token=[REDACTED]/g')" + + # Log the denial decision with redacted command. + jq -n \ + --arg cmd "$redacted_cmd" \ + --arg r "$reason" \ + '{event:"policyDeny", toolName:"bash", command:$cmd, reason:$r}' \ + >> "$LOG_DIR/audit.jsonl" + + # Return a denial response. + jq -n \ + --arg r "$reason" \ + '{permissionDecision:"deny", permissionDecisionReason:$r}' + + exit 0 +} + +# Privilege escalation +if echo "$COMMAND" | grep -qE '\b(sudo|su|runas)\b'; then + deny "Privilege escalation requires manual approval." +fi + +# Destructive filesystem operations targeting root +if echo "$COMMAND" | grep -qE 'rm\s+-rf\s*/($|\s)|rm\s+.*-rf\s*/($|\s)'; then + deny "Destructive operations targeting the filesystem root require manual approval." +fi + +# System-level destructive operations +if echo "$COMMAND" | grep -qE '\b(mkfs|dd|format)\b'; then + deny "System-level destructive operations are not allowed via automated execution." +fi + +# Download-and-execute patterns +if echo "$COMMAND" | grep -qE 'curl.*\|\s*(bash|sh)|wget.*\|\s*(bash|sh)'; then + deny "Download-and-execute patterns require manual approval." +fi + +# Allow by default +exit 0 +``` + +#### Create the policy script (PowerShell) + +Create `.github/hooks/scripts/pre-tool-policy.ps1`: + +```powershell copy +$ErrorActionPreference = "Stop" + +$inputObj = [Console]::In.ReadToEnd() | ConvertFrom-Json +$toolName = $inputObj.toolName +$toolArgsRaw = $inputObj.toolArgs # JSON string + +$logDir = ".github/hooks/logs" +if (-not (Test-Path $logDir)) { New-Item -ItemType Directory -Path $logDir -Force | Out-Null } + +# Example redaction logic. +# GitHub does not currently provide built-in secret redaction for hooks. +# This example shows one possible approach; many organizations prefer to +# forward events to a centralized logging system that handles redaction. +# Redact sensitive patterns before logging. +# Adjust these patterns to match your organization's needs. +$redactedToolArgs = $toolArgsRaw ` + -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'Bearer [A-Za-z0-9_\-\.]+', 'Bearer [REDACTED]' ` + -replace '--password[= ][^ ]+', '--password=[REDACTED]' ` + -replace '--token[= ][^ ]+', '--token=[REDACTED]' + +# Log attempted tool use with redacted toolArgs. +(@{ + event = "preToolUse" + toolName = $toolName + toolArgs = $redactedToolArgs +} | ConvertTo-Json -Compress) | Add-Content -Path "$logDir/audit.jsonl" + +if ($toolName -ne "bash") { exit 0 } + +# Parse toolArgs JSON string. +$toolArgs = $null +try { $toolArgs = $toolArgsRaw | ConvertFrom-Json } catch { exit 0 } + +$command = $toolArgs.command + +# --------------------------------------------------------------------------- +# Demo-only deny rule for safe testing. +# This blocks a harmless test command so you can validate the deny flow. +# Remove this rule after confirming your hooks work as expected. +# --------------------------------------------------------------------------- +if ($command -match 'COPILOT_HOOKS_DENY_DEMO') { + Deny "Blocked demo command (test rule). Remove this rule after validating hooks." +} + +function Deny([string]$reason) { + # Redact sensitive patterns from command before logging. + $redactedCommand = $command ` + -replace 'ghp_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'gho_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'ghu_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'ghs_[A-Za-z0-9]{20,}', '[REDACTED_TOKEN]' ` + -replace 'Bearer [A-Za-z0-9_\-\.]+', 'Bearer [REDACTED]' ` + -replace '--password[= ][^ ]+', '--password=[REDACTED]' ` + -replace '--token[= ][^ ]+', '--token=[REDACTED]' + + # Log the denial decision with redacted command. + (@{ + event = "policyDeny" + toolName = "bash" + command = $redactedCommand + reason = $reason + } | ConvertTo-Json -Compress) | Add-Content -Path "$logDir/audit.jsonl" + + (@{ + permissionDecision = "deny" + permissionDecisionReason = $reason + } | ConvertTo-Json -Compress) + + exit 0 +} + +if ($command -match '\b(sudo|su|runas)\b') { Deny "Privilege escalation requires manual approval." } +if ($command -match 'rm\s+-rf\s*/(\s|$)|rm\s+.*-rf\s*/(\s|$)') { Deny "Destructive operations targeting the filesystem root require manual approval." } +if ($command -match '\b(mkfs|dd|format)\b') { Deny "System-level destructive operations are not allowed via automated execution." } +if ($command -match 'curl.*\|\s*(bash|sh)|wget.*\|\s*(bash|sh)') { Deny "Download-and-execute patterns require manual approval." } + +exit 0 +``` + +### Test the policy script + +You can test the scripts by piping example `preToolUse` input. + +Allow example: + +```bash +echo '{"toolName":"bash","toolArgs":"{\"command\":\"git status\"}"}' \ + | .github/hooks/scripts/pre-tool-policy.sh +# or, for PowerShell +echo '{"toolName":"bash","toolArgs":"{\"command\":\"git status\"}"}' | + .github/hooks/scripts/pre-tool-policy.ps1 +``` + +Deny example: + +```bash +echo '{"toolName":"bash","toolArgs":"{\"command\":\"sudo rm -rf /\"}"}' \ + | .github/hooks/scripts/pre-tool-policy.sh +# or, for PowerShell +echo '{"toolName":"bash","toolArgs":"{\"command\":\"sudo rm -rf /\"}"}' | + .github/hooks/scripts/pre-tool-policy.ps1 +``` + +After running the deny example, check `.github/hooks/logs/audit.jsonl` for a new denial log entry. + +```json +{"permissionDecision":"deny","permissionDecisionReason":"Privilege escalation requires manual approval."} +``` + +At this point, high-risk `bash` commands are blocked from auto-execution in this repository. + +## 6. Test end-to-end in the repository + +Once you’ve created the configuration file and scripts, verify that hooks run as expected when you use {% data variables.copilot.copilot_cli_short %} in this repository. + +### Validate your hook configuration file + +Check that your hook configuration file is valid JSON: + +```bash copy +jq '.' < .github/hooks/copilot-cli-policy.json +``` + +### Verify script permissions (Unix-based systems) + +On macOS and Linux, confirm your Bash scripts are executable: + +```bash copy +chmod +x .github/hooks/scripts/*.sh +``` + +### Run a basic session + +Start a new {% data variables.copilot.copilot_cli_short %} session in the repository: + +```bash copy +copilot -p "Show me the status of this repository" +``` + +Expected results: + +* You see the policy banner (from `sessionStart`). +* A new entry is added to `.github/hooks/logs/audit.jsonl` (from `userPromptSubmitted`). + +### Trigger tool use and verify logging + +Run a prompt that causes {% data variables.copilot.copilot_cli_short %} to use a tool (for example, bash): + +```bash copy +copilot -p "Show me the last 5 git commits" +``` + +Expected results: + +* A `preToolUse` entry is added to `.github/hooks/logs/audit.jsonl`. +* If the tool call is allowed, execution proceeds normally. + +### Test a denied command + +The example policy script includes a temporary demo rule that blocks commands containing the string `COPILOT_HOOKS_DENY_DEMO`. This allows you to validate the deny flow safely without running destructive commands. + +Run a prompt that would trigger a denied command: + +```bash copy +copilot -p "Run a test command: echo COPILOT_HOOKS_DENY_DEMO" +``` + +Expected results: + +* {% data variables.copilot.copilot_cli_short %} does not execute the command. +* Your hook returns a denial response with a clear reason. +* A `policyDeny` entry is written to `.github/hooks/logs/audit.jsonl`. + +After confirming that the deny flow works correctly, remove the demo rule from your script and replace it with deny patterns that reflect your organization’s policies. + +### Inspect your audit logs + +To view recent entries: + +```bash copy +tail -n 50 .github/hooks/logs/audit.jsonl +``` + +To filter only denied decisions: + +```bash copy +jq 'select(.event=="policyDeny")' .github/hooks/logs/audit.jsonl +``` + +## 7. Roll out safely across teams + +After validating your hooks in a single repository, roll them out gradually to avoid disrupting development workflows. + +### Choose a rollout strategy + +Common rollout approaches include: + +* **Logging-first rollout (recommended)**: Start by logging prompts and tool usage without denying execution. Review logs for a period of time, then introduce deny rules once you understand common usage patterns. +* **Team-by-team rollout**: Deploy hooks to one team or repository at a time, gather feedback, then expand to additional teams. +* **Risk-based rollout**: Start with repositories that handle sensitive systems or production infrastructure, then expand to lower-risk repositories. + +### Communicate expectations + +Before enforcing deny rules, make sure developers understand: + +* That hooks are active in the repository +* Which types of commands may be blocked +* How to proceed if a command is denied + +Clear communication reduces confusion and support requests. + +### Keep policies maintainable + +As usage evolves: + +* Store hook configuration and scripts in version control. +* Review audit logs periodically to detect new risk patterns. +* Update deny rules incrementally rather than adding broad matches. +* Document why each deny rule exists, especially for high-impact restrictions. + +### Handle exceptions carefully + +Some teams (for example, infrastructure or platform teams) may require broader permissions. To handle this safely: + +* Maintain separate hook configurations for different repositories. +* Keep exceptions narrow and well-documented. +* Avoid ad-hoc local bypasses that undermine auditability. + +## Further reading + +For troubleshooting hooks, see [AUTOTITLE](/copilot/how-tos/use-copilot-agents/coding-agent/use-hooks#troubleshooting). diff --git a/content/copilot/tutorials/index.md b/content/copilot/tutorials/index.md index 09ed26940a01..c16d70b23d49 100644 --- a/content/copilot/tutorials/index.md +++ b/content/copilot/tutorials/index.md @@ -31,6 +31,7 @@ children: - /plan-a-project - /vibe-coding - /upgrade-projects + - /copilot-cli-hooks redirect_from: - /copilot/using-github-copilot/guides-on-using-github-copilot contentType: tutorials diff --git a/content/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization.md b/content/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization.md index 4d9e9019ffdd..e80852b10540 100644 --- a/content/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization.md +++ b/content/organizations/managing-organization-settings/managing-custom-properties-for-repositories-in-your-organization.md @@ -38,6 +38,7 @@ You can add custom properties to your organization and set values for those prop 1. Under "Type", select the type of property you'd like to add. This can either be a text string{% ifversion ghes < 3.15 %} or a single select field{% else %}, a single select field, a multi select field, {% ifversion ghes > 3.20 %}a URL, {% endif %}or a true/false boolean{% endif %}. 1. Optionally, you can select **Allow repository actors to set this property**. When enabled, repository users and apps with the repository-level "custom properties" fine-grained permission will be able to set and update the property value for their repository. 1. Optionally, you can select **Require this property for all repositories** and add a default value. This means that you require that all repositories in your organization have a value for this property. Repositories that don’t have an explicit value for this property will inherit the default value. +{% data reusables.organizations.custom-properties-required-values %} 1. Click **Save property**. ## Setting values for repositories in your organization diff --git a/data/features/custom-properties-required-explicit-values.yml b/data/features/custom-properties-required-explicit-values.yml new file mode 100644 index 000000000000..3b5e3df1a796 --- /dev/null +++ b/data/features/custom-properties-required-explicit-values.yml @@ -0,0 +1,6 @@ +# Reference: #21297 +# Custom properties with required explicit values [GA] +versions: + fpt: '*' + ghec: '*' + ghes: '> 3.20' diff --git a/data/reusables/enterprise-onboarding/creating-custom-properties.md b/data/reusables/enterprise-onboarding/creating-custom-properties.md index 11a4856beeb6..d090a71424ff 100644 --- a/data/reusables/enterprise-onboarding/creating-custom-properties.md +++ b/data/reusables/enterprise-onboarding/creating-custom-properties.md @@ -28,4 +28,5 @@ You can add custom properties to your enterprise to make those properties availa 1. Enter a name, description, and type for the custom property. The name must be unique across all of your organizations, can't contain spaces, and cannot exceed 75 characters in length. 1. Optionally, select **Allow repository actors to set this property**. When enabled, repository users and apps with the repository-level `custom properties` fine-grained permission will be able to set and update the property value for their repository. Additionally, any actor creating a repository can set the property on the repository. 1. Optionally, select **Require this property for all repositories** and add a default value. This means that you require that all repositories in your enterprise have a value for this property. Repositories that don’t have an explicit value for this property will inherit the default value. +{% data reusables.organizations.custom-properties-required-values %} 1. Click **Save property**. diff --git a/data/reusables/organizations/custom-properties-required-values.md b/data/reusables/organizations/custom-properties-required-values.md new file mode 100644 index 000000000000..22bdce212983 --- /dev/null +++ b/data/reusables/organizations/custom-properties-required-values.md @@ -0,0 +1,5 @@ +{% ifversion custom-properties-required-explicit-values %} + + * Optionally, you can select **Require explicit user-specified values**. When this option is enabled, users and apps with permission to set property values must provide an explicit value when setting properties, creating repositories, or transferring repositories. Repositories that don't yet have an explicit value will still inherit the default value. + +{% endif %} diff --git a/data/tables/copilot/model-multipliers.yml b/data/tables/copilot/model-multipliers.yml index 4283c91a8f53..535ee6f59eb2 100644 --- a/data/tables/copilot/model-multipliers.yml +++ b/data/tables/copilot/model-multipliers.yml @@ -26,7 +26,7 @@ multiplier_free: Not applicable - name: Claude Opus 4.6 (fast mode) (preview) - multiplier_paid: 9 during promotional period + multiplier_paid: 30 multiplier_free: Not applicable - name: Claude Sonnet 4