From ff755ea090917b7ba5d4325500ad06f115ccf8ef Mon Sep 17 00:00:00 2001 From: Kevin Heis Date: Tue, 6 Oct 2026 18:37:50 +0000 Subject: [PATCH 1/6] Remove dead localized short title swap (#63512) Copilot-Session: 7c52b57f-2c29-4aa1-8233-99d0d6e13571 --- .../context/current-product-tree.ts | 37 ++++--- src/frame/tests/current-product-tree.test.ts | 102 ++++++++++++++++++ 2 files changed, 123 insertions(+), 16 deletions(-) create mode 100644 src/frame/tests/current-product-tree.test.ts diff --git a/src/frame/middleware/context/current-product-tree.ts b/src/frame/middleware/context/current-product-tree.ts index c99b741c3b23..29899bc3511e 100644 --- a/src/frame/middleware/context/current-product-tree.ts +++ b/src/frame/middleware/context/current-product-tree.ts @@ -8,6 +8,7 @@ import findPageInSiteTree from '@/frame/lib/find-page-in-site-tree' import removeFPTFromPath from '@/versions/lib/remove-fpt-from-path' import { executeWithFallback } from '@/languages/lib/render-with-fallback' +// This module adds currentProductTree to the context object for use in layouts. export default async function currentProductTree( req: ExtendedRequest, res: Response, @@ -17,7 +18,7 @@ export default async function currentProductTree( if (!req.context.page) return next() if (req.context.page.documentType === 'homepage') return next() - // Keep the English tree available because localized pages can lag behind it. + // We need this so we can fall back to English if localized pages are out of sync. if (!req.context.siteTree) throw new Error('siteTree is required') if (!req.context.currentVersion) throw new Error('currentVersion is required') req.context.currentEnglishTree = req.context.siteTree.en[req.context.currentVersion] @@ -40,17 +41,22 @@ export default async function currentProductTree( currentProductPath, ) - // currentProductTreeTitles keeps href, title, shortTitle, documentType, and childPages. + // First make a slim tree of just the 'href', 'title', 'shortTitle' + // 'documentType' and 'childPages' (which is recursive). + // This gets used for subcategory and category pages. req.context.currentProductTreeTitles = await getCurrentProductTreeTitles( req.context.currentProductTree, req.context, ) - // Sidebar data excludes hidden pages. + // Now make an even slimmer version that excludes all hidden pages. + // This is used for sidebars. req.context.currentProductTreeTitlesExcludeHidden = excludeHidden( req.context.currentProductTreeTitles, ) - // Hidden pages leave sidebarTree unset because excludeHidden returns null for the root. + // Some pages, like hidden pages, don't have a tree. For example, + // the search page. That one uses the same items as the homepage + // for its sidebar. if (req.context.currentProductTreeTitlesExcludeHidden) { req.context.sidebarTree = sidebarTree(req.context.currentProductTreeTitlesExcludeHidden) } @@ -58,30 +64,26 @@ export default async function currentProductTree( return next() } +// Return a nested object that contains the bits and pieces we need +// for the tree which is used for sidebars and listing async function getCurrentProductTreeTitles(input: Tree, context: Context): Promise { const { page, href } = input const childPages = await Promise.all( (input.childPages || []).map((child) => getCurrentProductTreeTitles(child, context)), ) - // Translated pages need their English page for fallback rendering and short-title comparison. + // If the current page is a translation we're going to need the English + // equivalent for multiple things later in this function. const enPage = page.languageCode !== 'en' ? context.pages![href.replace(`/${page.languageCode}`, '/en')] : null - let rawShortTitle = page.rawShortTitle - // Swaps in rawTitle when shortTitle matches English, but the render below reads page.rawShortTitle. - if (page.languageCode !== 'en' && page.rawShortTitle) { - if (page.rawShortTitle === enPage!.shortTitle) { - rawShortTitle = page.rawTitle - } - } const renderedFullTitle = await executeWithFallback( context, () => liquid.parseAndRender(page.rawTitle, context), (enContext: Context) => liquid.parseAndRender(enPage!.rawTitle, enContext), ) let renderedShortTitle = '' - if (rawShortTitle) { + if (page.rawShortTitle) { renderedShortTitle = await executeWithFallback( context, () => liquid.parseAndRender(page.rawShortTitle!, context), @@ -89,7 +91,8 @@ async function getCurrentProductTreeTitles(input: Tree, context: Context): Promi ) } - // Empty duplicate short titles to avoid wasting sidebar space. + // If the short title was present but "useless" (same as the title), + // force it to be an empty string to not waste space. const shortTitle = renderedShortTitle && (renderedShortTitle || '') !== renderedFullTitle ? renderedShortTitle : '' @@ -124,10 +127,12 @@ function excludeHidden(tree: TitlesTree) { function sidebarTree(tree: TitlesTree) { const { href, title, shortTitle, childPages, sidebarLink } = tree - // Sidebars show only children from the current product. + // Filter out cross-product children from the sidebar const filteredChildPages = childPages.filter((child) => !child.crossProductChild) - // If siblings include a subdirectory and its articles, nest the articles under the subdirectory. + // Filter out children that are descendants of another sibling. + // When a page lists both a subdirectory and individual articles from it, + // the articles should only appear nested under the subdirectory in the sidebar. const siblingHrefs = filteredChildPages.map((c) => c.href) const dedupedChildPages = filteredChildPages.filter( (child) => !siblingHrefs.some((sh) => sh !== child.href && child.href.startsWith(`${sh}/`)), diff --git a/src/frame/tests/current-product-tree.test.ts b/src/frame/tests/current-product-tree.test.ts new file mode 100644 index 000000000000..4a90e697a3d8 --- /dev/null +++ b/src/frame/tests/current-product-tree.test.ts @@ -0,0 +1,102 @@ +import { describe, expect, test, vi } from 'vitest' +import type { Response, NextFunction } from 'express' +import type { ExtendedRequest, Page, Tree } from '@/types' +import currentProductTree from '@/frame/middleware/context/current-product-tree' + +const currentVersion = 'free-pro-team@latest' + +const createPage = (page: Partial): Page => + ({ + title: '', + rawTitle: '', + intro: '', + markdown: '', + mtime: 1, + permalinks: [], + versions: {}, + applicableVersions: [currentVersion], + render: vi.fn(), + renderProp: vi.fn(), + renderTitle: vi.fn(), + ...page, + }) as Page + +const createTree = (href: string, page: Page, childPages: Tree[] = []): Tree => ({ + href, + page, + children: undefined, + childPages, +}) + +const createRequest = (): ExtendedRequest => { + const englishProduct = createPage({ + title: 'Product', + rawTitle: 'Product', + languageCode: 'en', + documentType: 'product', + }) + const englishArticle = createPage({ + title: 'English full title', + rawTitle: 'English full title', + shortTitle: 'English short title', + rawShortTitle: 'English short title', + languageCode: 'en', + documentType: 'article', + }) + const translatedProduct = createPage({ + title: 'Producto', + rawTitle: 'Producto', + languageCode: 'es', + documentType: 'product', + }) + const translatedArticle = createPage({ + title: 'Título completo traducido', + rawTitle: 'Título completo traducido', + shortTitle: 'English short title', + rawShortTitle: 'English short title', + languageCode: 'es', + documentType: 'article', + }) + + const englishTree = createTree('/en/product', englishProduct, [ + createTree('/en/product/article', englishArticle), + ]) + const translatedTree = createTree('/es/product', translatedProduct, [ + createTree('/es/product/article', translatedArticle), + ]) + + return { + context: { + page: translatedArticle, + pages: { + '/en/product': englishProduct, + '/en/product/article': englishArticle, + '/es/product': translatedProduct, + '/es/product/article': translatedArticle, + }, + siteTree: { + en: { [currentVersion]: englishTree }, + es: { [currentVersion]: translatedTree }, + }, + currentLanguage: 'es', + currentVersion, + currentProduct: 'product', + }, + } as unknown as ExtendedRequest +} + +describe('currentProductTree middleware', () => { + test('uses the translated shortTitle even when it matches the English shortTitle', async () => { + const req = createRequest() + const next = vi.fn() as NextFunction + + await currentProductTree(req, {} as Response, next) + + expect(req.context!.currentProductTreeTitles!.childPages[0]).toMatchObject({ + title: 'Título completo traducido', + shortTitle: 'English short title', + }) + expect(req.context!.sidebarTree!.childPages[0].title).toBe('English short title') + expect(next).toHaveBeenCalled() + }) +}) From 98497bf77dc165049e916a6a6ee88eb4e3e34d1b Mon Sep 17 00:00:00 2001 From: "release-controller[bot]" <110195724+release-controller[bot]@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:40:54 +0000 Subject: [PATCH 2/6] Patch release notes for GitHub Enterprise Server (#63678) Co-authored-by: Release-Controller Co-authored-by: Isaac Brown Co-authored-by: Isaac Brown <101839405+isaacmbrown@users.noreply.github.com> Co-authored-by: jokego <100397366+jokego@users.noreply.github.com> --- .../enterprise-server/3-18/16.yml | 64 +++++++++++++++ .../enterprise-server/3-19/13.yml | 66 ++++++++++++++++ .../enterprise-server/3-20/9.yml | 69 +++++++++++++++++ .../enterprise-server/3-21/7.yml | 77 +++++++++++++++++++ .../enterprise-server/3-22/2.yml | 74 ++++++++++++++++++ 5 files changed, 350 insertions(+) create mode 100644 data/release-notes/enterprise-server/3-18/16.yml create mode 100644 data/release-notes/enterprise-server/3-19/13.yml create mode 100644 data/release-notes/enterprise-server/3-20/9.yml create mode 100644 data/release-notes/enterprise-server/3-21/7.yml create mode 100644 data/release-notes/enterprise-server/3-22/2.yml diff --git a/data/release-notes/enterprise-server/3-18/16.yml b/data/release-notes/enterprise-server/3-18/16.yml new file mode 100644 index 000000000000..fb8b177847bd --- /dev/null +++ b/data/release-notes/enterprise-server/3-18/16.yml @@ -0,0 +1,64 @@ +date: '2026-10-06' +sections: + security_fixes: + - | + **MEDIUM:** A repository collaborator with write access could use the GraphQL API to delete the current default branch and cause an attacker-controlled branch to become the new default. In repositories that required pull-request review but did not restrict branch deletion, this bypassed the review requirement and caused fresh clones and default-branch API requests to use attacker-controlled content. GitHub has requested CVE ID [CVE-2026-103620](https://www.cve.org/cverecord?id=CVE-2026-103620) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + On Microsoft Azure Eav6-series virtual machines with Accelerated Networking enabled, GitHub Enterprise Server could intermittently become unreachable after the virtual machine started. + - | + When site administrators configured custom OpenTelemetry Collector pipelines to export instance telemetry, the Management Console allowed them to save the settings without a valid configuration, causing the collector to enter a restart loop. + - | + Adding an existing user to an organization or team could take several seconds on large GitHub Enterprise Server instances due to redundant license seat calculations. + - | + Site administrators could receive a 404 error when selecting **Complete your GitHub Connect setup** after an interrupted setup attempt, preventing them from completing the connection while the pending setup session remained active. + - | + After an index repair completed, its status could remain paused. + - | + When organization owners updated the list of designated reviewers for push protection bypass requests, GitHub Enterprise Server could add, retain, or remove the wrong reviewer if different reviewer types shared the same identifier. + changes: + - | + To avoid data processing delays on instances with a large number of internal message topics, administrators can configure the network timeouts used during topic discovery via `app.github.topic-checker-connect-timeout-sec` and `app.github.topic-checker-socket-timeout-sec`. The default timeout has been increased from 10 to 30 seconds, and values between 1 and 300 seconds are accepted. + known_issues: + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + On an instance with the HTTP `X-Forwarded-For` header configured for use behind a load balancer, all client IP addresses in the instance's audit log erroneously appear as 127.0.0.1. + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may time out on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shut down the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + An organization-level code scanning configuration page is displayed on instances that do not use GitHub Advanced Security or code scanning. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + In a cluster, the host running restore requires access to the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + Unexpected elements may appear in the UI on the repository overview page for locked repositories. + - | + The setting to define private registries at the organization level for code scanning is only available if Dependabot is also enabled for the instance. + - | + Custom NTP settings are removed during the upgrade process. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. diff --git a/data/release-notes/enterprise-server/3-19/13.yml b/data/release-notes/enterprise-server/3-19/13.yml new file mode 100644 index 000000000000..136ebf847d85 --- /dev/null +++ b/data/release-notes/enterprise-server/3-19/13.yml @@ -0,0 +1,66 @@ +date: '2026-10-06' +sections: + security_fixes: + - | + **MEDIUM:** A repository collaborator with write access could use the GraphQL API to delete the current default branch and cause an attacker-controlled branch to become the new default. In repositories that required pull-request review but did not restrict branch deletion, this bypassed the review requirement and caused fresh clones and default-branch API requests to use attacker-controlled content. GitHub has requested CVE ID [CVE-2026-103620](https://www.cve.org/cverecord?id=CVE-2026-103620) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + In high availability configurations, administrators who had configured datacenter labels on replica nodes saw each node listed in a separate datacenter on the Management Console replication page after upgrading. The page grouped nodes by each node's internal Consul datacenter value instead of the customer-configured datacenter label. + - | + On Microsoft Azure Eav6-series virtual machines with Accelerated Networking enabled, GitHub Enterprise Server could intermittently become unreachable after the virtual machine started. + - | + On instances in a high availability or cluster configuration and with WireGuard enabled, `ghe-cluster-status-nodes --extended` could report false alarms for node connection checks. + - | + When site administrators configured custom OpenTelemetry Collector pipelines to export instance telemetry, the Management Console allowed them to save the settings without a valid configuration, causing the collector to enter a restart loop. + - | + When site administrators used Grafana to monitor storage usage and navigated using **Home**, the System & Application Insights dashboards displayed incomplete disk metric titles, omitted data from some panels, and did not display the node selector. + - | + Adding an existing user to an organization or team could take several seconds on large GitHub Enterprise Server instances due to redundant license seat calculations. + - | + Site administrators could not run the pre-upgrade stage of an upgrade outside the maintenance window. As a result, upgrades could require up to 20 additional minutes during the maintenance window. + - | + Site administrators could receive a 404 error when selecting **Complete your GitHub Connect setup** after an interrupted setup attempt, preventing them from completing the connection while the pending setup session remained active. + - | + After an index repair completed, its status could remain paused. + - | + When organization owners updated the list of designated reviewers for push protection bypass requests, GitHub Enterprise Server could add, retain, or remove the wrong reviewer if different reviewer types shared the same identifier. + changes: + - | + To avoid data processing delays on instances with a large number of internal message topics, administrators can configure the network timeouts used during topic discovery via `app.github.topic-checker-connect-timeout-sec` and `app.github.topic-checker-socket-timeout-sec`. The default timeout has been increased from 10 to 30 seconds, and values between 1 and 300 seconds are accepted. + known_issues: + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may time out on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shut down the node and repeat the steps. + - | + {% data reusables.release-notes.2024-06-possible-frontend-5-minute-outage-during-hotpatch-upgrade %} + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When enabling automatic update checks for the first time in the Management Console, the status is not dynamically reflected until the "Updates" page is reloaded. + - | + When restoring from a backup snapshot, a large number of `mapper_parsing_exception` errors may be displayed. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + In a cluster, the host running restore requires access to the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + The setting to define private registries at the organization level for code scanning is only available if Dependabot is also enabled for the instance. + - | + An issue in the Management Console means the Backups (Preview) and Updates tabs may fail to open and instead return an Internal Server Error. We recommend using the command line interface (CLI) for backups and updates. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. diff --git a/data/release-notes/enterprise-server/3-20/9.yml b/data/release-notes/enterprise-server/3-20/9.yml new file mode 100644 index 000000000000..bf6254c363f4 --- /dev/null +++ b/data/release-notes/enterprise-server/3-20/9.yml @@ -0,0 +1,69 @@ +date: '2026-10-06' +sections: + features: + - | + Site administrators can configure the GitHub Enterprise Server Backup Service to use native, incremental Elasticsearch snapshots with Azure Blob storage, Amazon S3, or Google Cloud Storage. This can reduce backup time and local storage usage. Snapshots are isolated by GitHub Enterprise Server patch version. For more information, see [AUTOTITLE](/admin/backing-up-and-restoring-your-instance/configuring-elasticsearch-snapshots). + security_fixes: + - | + **HIGH**: An attacker could cause a GitHub Enterprise Server instance to send requests to attacker-chosen internal addresses by committing crafted GCP service account credentials whose token endpoint specified an internal destination. When secret scanning performed a validity check, the appliance issued a request to that destination without adequately validating it. This server-side request forgery vulnerability could potentially lead to remote code execution on the appliance. Exploitation required push access to a repository on an instance with GitHub Advanced Security and secret scanning validity checks enabled. GitHub has requested CVE ID [CVE-2026-96890](https://www.cve.org/cverecord?id=CVE-2026-96890) for this vulnerability, which was reported through the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM:** A repository collaborator with write access could use the GraphQL API to delete the current default branch and cause an attacker-controlled branch to become the new default. In repositories that required pull-request review but did not restrict branch deletion, this bypassed the review requirement and caused fresh clones and default-branch API requests to use attacker-controlled content. GitHub has requested CVE ID [CVE-2026-103620](https://www.cve.org/cverecord?id=CVE-2026-103620) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + In high availability configurations, administrators who had configured datacenter labels on replica nodes saw each node listed in a separate datacenter on the Management Console replication page after upgrading. The page grouped nodes by each node's internal Consul datacenter value instead of the customer-configured datacenter label. + - | + On Microsoft Azure Eav6-series virtual machines with Accelerated Networking enabled, GitHub Enterprise Server could intermittently become unreachable after the virtual machine started. + - | + On instances in a high availability or cluster configuration and with WireGuard enabled, `ghe-cluster-status-nodes --extended` could report false alarms for node connection checks. + - | + When site administrators used Grafana to monitor storage usage and navigated using **Home**, the System & Application Insights dashboards displayed incomplete disk metric titles, omitted data from some panels, and did not display the node selector. + - | + When site administrators configured custom OpenTelemetry Collector pipelines to export instance telemetry, the Management Console allowed them to save the settings without a valid configuration, causing the collector to enter a restart loop. + - | + Adding an existing user to an organization or team could take several seconds on large GitHub Enterprise Server instances due to redundant license seat calculations. + - | + Site administrators could not run the pre-upgrade stage of an upgrade outside the maintenance window. As a result, upgrades could require up to 20 additional minutes during the maintenance window. + - | + Site administrators could receive a 404 error when selecting **Complete your GitHub Connect setup** after an interrupted setup attempt, preventing them from completing the connection while the pending setup session remained active. + - | + After an index repair completed, its status could remain paused. + - | + For some secret scanning alerts, validity checks failed for inactive Yandex Cloud API keys or Anthropic API keys associated with disabled organizations. + - | + When organization owners updated the list of designated reviewers for push protection bypass requests, GitHub Enterprise Server could add, retain, or remove the wrong reviewer if different reviewer types shared the same identifier. + changes: + - | + To avoid data processing delays on instances with a large number of internal message topics, administrators can configure the network timeouts used during topic discovery via `app.github.topic-checker-connect-timeout-sec` and `app.github.topic-checker-socket-timeout-sec`. The default timeout has been increased from 10 to 30 seconds, and values between 1 and 300 seconds are accepted. + known_issues: + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may time out on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shut down the node and repeat the steps. + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + In a cluster, the host running restore requires access to the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + On instances with multiple Git storage nodes in a voting configuration, including cluster and geo-replication high availability topologies, upgrading may fail to correctly install Actions that ship with the new version. In some cases, previous versions of these Actions remain on the instance. To resolve this issue, run the following commands on the primary node: `ghe-config --unset 'app.actions.actions-repos-sha1sum'`, `ghe-config-apply`, and `/usr/local/share/enterprise/ghe-run-init-actions-graph`. + - | + When restoring an instance with `ghe-restore` while the replication controller is enabled, the storage directory is not restored. diff --git a/data/release-notes/enterprise-server/3-21/7.yml b/data/release-notes/enterprise-server/3-21/7.yml new file mode 100644 index 000000000000..87cc989b25f4 --- /dev/null +++ b/data/release-notes/enterprise-server/3-21/7.yml @@ -0,0 +1,77 @@ +date: '2026-10-06' +sections: + features: + - | + Site administrators can configure the GitHub Enterprise Server Backup Service to use native, incremental Elasticsearch snapshots with Azure Blob storage, Amazon S3, or Google Cloud Storage. This can reduce backup time and local storage usage. Snapshots are isolated by GitHub Enterprise Server patch version. For more information, see [AUTOTITLE](/admin/backing-up-and-restoring-your-instance/configuring-elasticsearch-snapshots). + security_fixes: + - | + **HIGH**: An attacker could cause a GitHub Enterprise Server instance to send requests to attacker-chosen internal addresses by committing crafted GCP service account credentials whose token endpoint specified an internal destination. When secret scanning performed a validity check, the appliance issued a request to that destination without adequately validating it. This server-side request forgery vulnerability could potentially lead to remote code execution on the appliance. Exploitation required push access to a repository on an instance with GitHub Advanced Security and secret scanning validity checks enabled. GitHub has requested CVE ID [CVE-2026-96890](https://www.cve.org/cverecord?id=CVE-2026-96890) for this vulnerability, which was reported through the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM:** A repository collaborator with write access could use the GraphQL API to delete the current default branch and cause an attacker-controlled branch to become the new default. In repositories that required pull-request review but did not restrict branch deletion, this bypassed the review requirement and caused fresh clones and default-branch API requests to use attacker-controlled content. GitHub has requested CVE ID [CVE-2026-103620](https://www.cve.org/cverecord?id=CVE-2026-103620) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + In high availability configurations, administrators who had configured datacenter labels on replica nodes saw each node listed in a separate datacenter on the Management Console replication page after upgrading. The page grouped nodes by each node's internal Consul datacenter value instead of the customer-configured datacenter label. + - | + On Microsoft Azure Eav6-series virtual machines with Accelerated Networking enabled, GitHub Enterprise Server could intermittently become unreachable after the virtual machine started. + - | + On instances in a high availability or cluster configuration and with WireGuard enabled, `ghe-cluster-status-nodes --extended` could report false alarms for node connection checks. + - | + When site administrators configured custom OpenTelemetry Collector pipelines to export instance telemetry, the Management Console allowed them to save the settings without a valid configuration, causing the collector to enter a restart loop. + - | + Adding an existing user to an organization or team could take several seconds on large GitHub Enterprise Server instances due to redundant license seat calculations. + - | + Site administrators could not run the pre-upgrade stage of an upgrade outside the maintenance window. As a result, upgrades could require up to 20 additional minutes during the maintenance window. + - | + Some users could not view the command-line merge instructions in pull requests. + - | + Site administrators could receive a 404 error when selecting **Complete your GitHub Connect setup** after an interrupted setup attempt, preventing them from completing the connection while the pending setup session remained active. + - | + After an index repair completed, its status could remain paused. + - | + Repository administrators who were not designated reviewers for secret scanning bypass requests could access the bypass requests list, but opening an individual request returned a 404 error. + - | + For some secret scanning alerts, validity checks failed for inactive Yandex Cloud API keys, Anthropic API keys associated with disabled organizations, or active Unkey keys with insufficient permissions. + changes: + - | + To avoid data processing delays on instances with a large number of internal message topics, administrators can configure the network timeouts used during topic discovery via `app.github.topic-checker-connect-timeout-sec` and `app.github.topic-checker-socket-timeout-sec`. The default timeout has been increased from 10 to 30 seconds, and values between 1 and 300 seconds are accepted. + known_issues: + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may time out on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shut down the node and repeat the steps. + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + In a cluster, the host running restore requires access to the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + On instances with multiple Git storage nodes in a voting configuration, including cluster and geo-replication high availability topologies, upgrading may fail to correctly install Actions that ship with the new version. In some cases, previous versions of these Actions remain on the instance. To resolve this issue, run the following commands on the primary node: `ghe-config --unset 'app.actions.actions-repos-sha1sum'`, `ghe-config-apply`, and `/usr/local/share/enterprise/ghe-run-init-actions-graph`. + - | + In some cases, pull requests using auto-merge or merge queue may not merge automatically until mergeability is recalculated. + - | + After upgrading to GHES 3.21, scheduled Dependabot version updates may stop running for pre-existing configurations. If you have already upgraded and want to trigger scheduled version updates, save a change to each affected repository’s `.github/dependabot.yml` file. + - | + In a clustered GitHub Enterprise Server environment, a node that remained in the cluster after losing the `git-server`, `pages-server`, or `storage-server` role could continue to appear online and eligible for replication. This could cause replica placement failures, incorrect replica counts, or replication status to show a node without the relevant service as healthy. If you experience these symptoms, contact GitHub Support. + - | + When restoring an instance with `ghe-restore` while the replication controller is enabled, the storage directory is not restored. + - | + On a newly booted {% data variables.product.prodname_ghe_server %} instance, the merge box on a newly created pull request can stay on "Checking for the ability to merge automatically" and not show the merge status. If encountered, refreshing the page shows the correct merge status. diff --git a/data/release-notes/enterprise-server/3-22/2.yml b/data/release-notes/enterprise-server/3-22/2.yml new file mode 100644 index 000000000000..d055ac8133fc --- /dev/null +++ b/data/release-notes/enterprise-server/3-22/2.yml @@ -0,0 +1,74 @@ +date: '2026-10-06' +sections: + features: + - | + Site administrators can configure the GitHub Enterprise Server Backup Service to use native, incremental Elasticsearch snapshots with Azure Blob storage, Amazon S3, or Google Cloud Storage. This can reduce backup time and local storage usage. Snapshots are isolated by GitHub Enterprise Server patch version. For more information, see [AUTOTITLE](/admin/backing-up-and-restoring-your-instance/configuring-elasticsearch-snapshots). + security_fixes: + - | + **HIGH**: An attacker could cause a GitHub Enterprise Server instance to send requests to attacker-chosen internal addresses by committing crafted GCP service account credentials whose token endpoint specified an internal destination. When secret scanning performed a validity check, the appliance issued a request to that destination without adequately validating it. This server-side request forgery vulnerability could potentially lead to remote code execution on the appliance. Exploitation required push access to a repository on an instance with GitHub Advanced Security and secret scanning validity checks enabled. GitHub has requested CVE ID [CVE-2026-96890](https://www.cve.org/cverecord?id=CVE-2026-96890) for this vulnerability, which was reported through the [GitHub Bug Bounty program](https://bounty.github.com/). + - | + **MEDIUM:** A repository collaborator with write access could use the GraphQL API to delete the current default branch and cause an attacker-controlled branch to become the new default. In repositories that required pull-request review but did not restrict branch deletion, this bypassed the review requirement and caused fresh clones and default-branch API requests to use attacker-controlled content. GitHub has requested CVE ID [CVE-2026-103620](https://www.cve.org/cverecord?id=CVE-2026-103620) for this vulnerability, which was reported via the [GitHub Bug Bounty program](https://bounty.github.com/). + bugs: + - | + On Microsoft Azure Eav6-series virtual machines with Accelerated Networking enabled, GitHub Enterprise Server could intermittently become unreachable after the virtual machine started. + - | + On instances in a high availability or cluster configuration and with WireGuard enabled, `ghe-cluster-status-nodes --extended` could report false alarms for node connection checks. + - | + When site administrators configured custom OpenTelemetry Collector pipelines to export instance telemetry, the Management Console allowed them to save the settings without a valid configuration, causing the collector to enter a restart loop. + - | + Repository administrators who were not designated reviewers for secret scanning bypass requests could access the bypass requests list, but opening an individual request returned a 404 error. + - | + Adding an existing user to an organization or team could take several seconds on large GitHub Enterprise Server instances due to redundant license seat calculations. + - | + Site administrators could not run the pre-upgrade stage of an upgrade outside the maintenance window. As a result, upgrades could require up to 20 additional minutes during the maintenance window. + - | + Some users could not view the command-line merge instructions in pull requests. + - | + Site administrators could receive a 404 error when selecting **Complete your GitHub Connect setup** after an interrupted setup attempt, preventing them from completing the connection while the pending setup session remained active. + - | + For some secret scanning alerts, validity checks failed for inactive Yandex Cloud API keys, Anthropic API keys associated with disabled organizations, active Unkey keys with insufficient permissions, or Mistral API keys whose accounts required payment. + known_issues: + - | + During an upgrade of GitHub Enterprise Server, custom firewall rules are removed. If you use custom firewall rules, you must reapply them after upgrading. + - | + During the validation phase of a configuration run, a `No such object` error may occur for the Notebook and Viewscreen services. This error can be ignored as the services should still correctly start. + - | + If the root site administrator is locked out of the Management Console after failed login attempts, the account does not unlock automatically after the defined lockout time. Someone with administrative SSH access to the instance must unlock the account using the administrative shell. For more information, see [AUTOTITLE](/admin/administering-your-instance/administering-your-instance-from-the-web-ui/troubleshooting-access-to-the-management-console#unlocking-the-root-site-administrator-account). + - | + {% data reusables.release-notes.large-adoc-files-issue %} + - | + Admin stats REST API endpoints may time out on appliances with many users or repositories. Retrying the request until data is returned is advised. + - | + When following the steps for [Replacing the primary MySQL node](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-the-primary-mysql-node), step 14 (running `ghe-cluster-config-apply`) might fail with errors. If this occurs, re-running `ghe-cluster-config-apply` is expected to succeed. + - | + Running a config apply as part of the steps for [Replacing a node in an emergency](/admin/monitoring-managing-and-updating-your-instance/configuring-clustering/replacing-a-cluster-node#replacing-a-node-in-an-emergency) may fail with errors if the node being replaced is still reachable. If this occurs, shut down the node and repeat the steps. + - | + When restoring data originally backed up from a 3.13 or greater appliance version, the Elasticsearch indices need to be reindexed before some of the data will show up. This happens via a nightly scheduled job. It can also be forced by running `/usr/local/share/enterprise/ghe-es-search-repair`. + - | + When initializing a new GHES cluster, nodes with the `consul-server` role should be added to the cluster before adding additional nodes. Adding all nodes simultaneously creates a race condition between nomad server registration and nomad client registration. + - | + In a cluster, the host running restore requires access to the storage nodes via their private IPs. + - | + On an instance hosted on Azure, commenting on an issue via email meant the comment was not added to the issue. + - | + After a restore, existing outside collaborators cannot be added to repositories in a new organization. This issue can be resolved by running `/usr/local/share/enterprise/ghe-es-search-repair` on the appliance. + - | + After a geo-replica is promoted to be a primary by running `ghe-repl-promote`, the actions workflow of a repository does not have any suggested workflows. + - | + When publishing npm packages in a workflow after restoring from a backup to GitHub Enterprise Server 3.13.5.gm4 or 3.14.2.gm3, you may encounter a `401 Unauthorized` error from the GitHub Packages service. This can happen if the restore is from an N-1 or N-2 version and the workflow targets the npm endpoint on the backup instance. To avoid this issue, ensure the access token is valid and includes the correct scopes for publishing to GitHub Packages. + - | + When applying an enterprise security configuration to all repositories (for example, enabling Secret Scanning or Code Scanning across all repositories), the system immediately enqueues enablement jobs for every organization in the enterprise simultaneously. For enterprises with a large number of repositories, this can result in significant system load and potential performance degradation. If you manage a large enterprise with many organizations and repositories, we recommend applying security configurations at the organization level rather than at the enterprise level in the UI. This allows you to enable security features incrementally and monitor system performance as you roll out changes. + - | + On instances with multiple Git storage nodes in a voting configuration, including cluster and geo-replication high availability topologies, upgrading may fail to correctly install Actions that ship with the new version. In some cases, previous versions of these Actions remain on the instance. To resolve this issue, run the following commands on the primary node: `ghe-config --unset 'app.actions.actions-repos-sha1sum'`, `ghe-config-apply`, and `/usr/local/share/enterprise/ghe-run-init-actions-graph`. + - | + After creating a new branch via the `New branch` button, the `/branches` page doesn't automatically show the new branch. The page requires a manual refresh before the new branch appears + - | + In some cases, pull requests using auto-merge or merge queue may not merge automatically until mergeability is recalculated. + - | + After upgrading to GHES 3.21, scheduled Dependabot version updates may stop running for pre-existing configurations. If you have already upgraded and want to trigger scheduled version updates, save a change to each affected repository’s `.github/dependabot.yml` file. + - | + In a clustered GitHub Enterprise Server environment, a node that remained in the cluster after losing the `git-server`, `pages-server`, or `storage-server` role could continue to appear online and eligible for replication. This could cause replica placement failures, incorrect replica counts, or replication status to show a node without the relevant service as healthy. If you experience these symptoms, contact GitHub Support. + - | + When restoring an instance with `ghe-restore` while the replication controller is enabled, the storage directory is not restored. + - | + On a newly booted {% data variables.product.prodname_ghe_server %} instance, the merge box on a newly created pull request can stay on "Checking for the ability to merge automatically" and not show the merge status. If encountered, refreshing the page shows the correct merge status. From 77764b4236d08f5557062ac558526e67319e4a6c Mon Sep 17 00:00:00 2001 From: Jenni C <97056108+dihydroJenoxide@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:52:17 +0000 Subject: [PATCH 3/6] Stacked PRs GA (#63609) --- .../stack-ai-generated-code-in-pull-requests.md | 3 --- .../get-started/about-stacked-prs.md | 2 -- .../get-started/stacked-prs-quickstart.md | 2 -- .../creating-stacked-pull-requests.md | 2 -- .../managing-stacked-pull-requests.md | 2 -- .../merging-stacked-pull-requests.md | 6 ++---- .../optimizing-ci-for-stacked-pull-requests.md | 2 -- .../troubleshooting-stacked-pull-requests.md | 2 -- .../reviewing-stacked-pull-requests.md | 2 -- .../reference/stacked-prs-cli-commands.md | 2 -- .../stacked-pull-requests-apis-and-webhooks.md | 2 -- .../reference/stacked-pull-requests.md | 17 +++++++++++++---- ...se-other-tools-with-stacked-pull-requests.md | 2 -- .../tutorials/roll-out-stacked-prs.md | 3 --- .../stack-code-changes-in-pull-requests.md | 2 -- src/content-pipelines/config.yml | 1 - 16 files changed, 15 insertions(+), 37 deletions(-) diff --git a/content/copilot/tutorials/stack-ai-generated-code-in-pull-requests.md b/content/copilot/tutorials/stack-ai-generated-code-in-pull-requests.md index 15ac41aa89a1..00426d7bc5c7 100644 --- a/content/copilot/tutorials/stack-ai-generated-code-in-pull-requests.md +++ b/content/copilot/tutorials/stack-ai-generated-code-in-pull-requests.md @@ -10,9 +10,6 @@ category: - Team collaboration --- -> [!NOTE] -> Stacked pull requests are in {% data variables.release-phases.public_preview %} and subject to change. - Large pull requests are difficult to review and create bottlenecks, especially when AI helps you generate a high volume of code in a short time. Review quality also degrades as pull request size increases. Reviewers may skim the result, miss issues, or procrastinate and leave the pull request until it grows stale and develops merge conflicts. Stacked pull requests keep large code changes reviewable. diff --git a/content/pull-requests/get-started/about-stacked-prs.md b/content/pull-requests/get-started/about-stacked-prs.md index 0404968f4c36..3001eaa76ed5 100644 --- a/content/pull-requests/get-started/about-stacked-prs.md +++ b/content/pull-requests/get-started/about-stacked-prs.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - ## About stacked pull requests Stacked pull requests are two or more pull requests in the same repository, where: diff --git a/content/pull-requests/get-started/stacked-prs-quickstart.md b/content/pull-requests/get-started/stacked-prs-quickstart.md index 9d457fc17517..260d47d79764 100644 --- a/content/pull-requests/get-started/stacked-prs-quickstart.md +++ b/content/pull-requests/get-started/stacked-prs-quickstart.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - {% data reusables.pull_requests.pr-stack-invitation %} {% data reusables.pull_requests.pr-stack-definition %} diff --git a/content/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests.md b/content/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests.md index bc7cf980122f..55db98db6d2f 100644 --- a/content/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/create-pull-requests/creating-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - Create stacked pull requests with the `gh stack` extension in {% data variables.product.prodname_cli %} or on the {% data variables.product.github %} website. > [!NOTE] diff --git a/content/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests.md b/content/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests.md index b0f092ec8185..95c742af0cfb 100644 --- a/content/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/create-pull-requests/managing-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - As you iterate on a stack, you often need to make changes in a lower layer, rebase to keep a linear history, or restructure its branches. The `gh stack` extension in {% data variables.product.prodname_cli %} handles these tasks with cascading operations that update every affected branch. See [AUTOTITLE](/pull-requests/reference/stacked-prs-cli-commands). ## Making changes to a lower layer diff --git a/content/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests.md b/content/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests.md index b78c3a68d5c1..376b094daabf 100644 --- a/content/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/merge-and-close-pull-requests/merging-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Merge and close pull requests --- -{% data reusables.public-preview.public-preview %} - Stacked pull requests merge from the bottom (closest to the trunk) up. * You can merge any number of pull requests at once, as long as they form a contiguous group starting from the lowest unmerged pull request. @@ -24,7 +22,7 @@ The merge box for a stacked pull request shows the status of the entire stack, n * The stack has a linear history. * The current pull request meets all branch protection requirements for the stack base, such as `main`. -If the stack is not linear, for example, after changes were pushed to a lower branch or after the trunk moved ahead, a **Rebase stack** button will appear in the merge box and you'll need to rebase the stack before you can merge. +If the stack is not linear, for example, after changes were pushed to a lower branch or after the trunk moved ahead, a **Rebase stack** button will appear in the merge box and you'll need to rebase the stack before you can merge. Rebasing the stack will generate signed commits, and retain approvals if a diff has not changed, even if you have the **dismiss stale approvals** rule enabled. > [!NOTE] > * If you merge via the API and want to use stacked pull requests, you'll need use the asynchronous merge API for stacks. See [AUTOTITLE](/rest/pulls/pulls?apiVersion=2026-03-10#merge-a-pull-request-asynchronously). @@ -35,7 +33,7 @@ If the stack is not linear, for example, after changes were pushed to a lower br Stacks fully support merge queues. All pull requests in the stack are added to the queue in the correct order. If a pull request is removed or ejected from the queue, all pull requests above it in the stack are also removed. > [!NOTE] -> To keep a stack together, the merge queue allows the merge group to exceed its configured maximum size by up to 50 percent. If the stack is too large to fit within that buffer, it will automatically be split across consecutive merge groups. +> To keep a stack together, the merge queue allows the merge group to exceed its configured maximum size by up to 50 percent. If the stack is too large to fit within that buffer, it will automatically be put into the next merge group as a single unit. ## Merging from the bottom up diff --git a/content/pull-requests/how-tos/merge-and-close-pull-requests/optimizing-ci-for-stacked-pull-requests.md b/content/pull-requests/how-tos/merge-and-close-pull-requests/optimizing-ci-for-stacked-pull-requests.md index 5b501e2fb86c..468a59b91294 100644 --- a/content/pull-requests/how-tos/merge-and-close-pull-requests/optimizing-ci-for-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/merge-and-close-pull-requests/optimizing-ci-for-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Merge and close pull requests --- -{% data reusables.public-preview.public-preview %} - Every pull request in a stack is evaluated as if it targets the base of the stack, such as `main`. This keeps quality consistent across every layer, but it also means a workflow can run many times for a single stack. This article explains how workflows run for a stack and how to reduce redundant CI usage. ## How workflows run for a stack diff --git a/content/pull-requests/how-tos/merge-and-close-pull-requests/troubleshooting-stacked-pull-requests.md b/content/pull-requests/how-tos/merge-and-close-pull-requests/troubleshooting-stacked-pull-requests.md index c26a9e0bbd15..2abd5e47e2c4 100644 --- a/content/pull-requests/how-tos/merge-and-close-pull-requests/troubleshooting-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/merge-and-close-pull-requests/troubleshooting-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Merge and close pull requests --- -{% data reusables.public-preview.public-preview %} - This article covers common issues you may encounter when working with stacked pull requests and how to resolve them. ## A rebase reports a conflict diff --git a/content/pull-requests/how-tos/review-pull-requests/reviewing-stacked-pull-requests.md b/content/pull-requests/how-tos/review-pull-requests/reviewing-stacked-pull-requests.md index 2a0b2d8ec92f..c74e74b1df6d 100644 --- a/content/pull-requests/how-tos/review-pull-requests/reviewing-stacked-pull-requests.md +++ b/content/pull-requests/how-tos/review-pull-requests/reviewing-stacked-pull-requests.md @@ -10,8 +10,6 @@ category: - Review pull requests --- -{% data reusables.public-preview.public-preview %} - Each pull request in a stack shows only the diff for its layer. This means reviewers can request changes on any pull request independently. When a reviewer requests changes on a pull request mid-stack, you should make the fix on the branch that owns the change and rebase so the branches above it pick up your update. ## Addressing review feedback diff --git a/content/pull-requests/reference/stacked-prs-cli-commands.md b/content/pull-requests/reference/stacked-prs-cli-commands.md index 01c445d637cd..e9a8c92d816c 100644 --- a/content/pull-requests/reference/stacked-prs-cli-commands.md +++ b/content/pull-requests/reference/stacked-prs-cli-commands.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - The `gh stack` extension for {% data variables.product.prodname_cli %} creates and manages stacks of pull requests from your local repository. For an introduction to stacks, see [AUTOTITLE](/pull-requests/reference/stacked-pull-requests). ## Installation diff --git a/content/pull-requests/reference/stacked-pull-requests-apis-and-webhooks.md b/content/pull-requests/reference/stacked-pull-requests-apis-and-webhooks.md index 18a249a5b98b..70e672d5bee8 100644 --- a/content/pull-requests/reference/stacked-pull-requests-apis-and-webhooks.md +++ b/content/pull-requests/reference/stacked-pull-requests-apis-and-webhooks.md @@ -13,8 +13,6 @@ category: - Merge and close pull requests --- -{% data reusables.public-preview.public-preview %} - The {% data variables.product.github %} REST and GraphQL APIs both expose stacked pull requests. The REST API supports reading and managing stacks, while the GraphQL API supports read-only queries. Use the API to read a pull request's stack membership or to build your own automation and integrations for stacked pull requests. diff --git a/content/pull-requests/reference/stacked-pull-requests.md b/content/pull-requests/reference/stacked-pull-requests.md index 41769466084e..7bbe99ed3c37 100644 --- a/content/pull-requests/reference/stacked-pull-requests.md +++ b/content/pull-requests/reference/stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - {% data reusables.pull_requests.pr-stack-definition %} Every pull request in a stack is evaluated against rules for the **base of the stack** — typically `main` — regardless of which branch it directly targets. This means mid-stack pull requests are held to the same standard as the bottom pull request. @@ -57,6 +55,15 @@ Stack metadata, such as the stack's base branch, is available in workflow expres For the full set of metadata fields and patterns to reduce redundant CI usage, see [AUTOTITLE](/pull-requests/how-tos/merge-and-close-pull-requests/optimizing-ci-for-stacked-pull-requests). +## Rebasing + +When a rebase is available or needed, the merge box will indicate this by displaying a **Rebase stack** button. For example, this may happen when changes to a pull request make the stack non-linear. When the bottom pull request is merged, a rebase happens automatically and you typically won't need to rebase manually. + +When a stack is rebased, you can expect the following: + +* Rebasing the stack generates signed commits. +* Rebasing a stack doesn't count as a new, reviewable commit if the diff does not change. Approvals are retained in this situation, even when the **Dismiss stale pull request approvals when new commits are pushed** rule is enabled. + ## Merge requirements Before a pull request in a stack can merge, all of the following must be true: @@ -67,11 +74,13 @@ Before a pull request in a stack can merge, all of the following must be true: For example, in the stack `main ← PR1 ← PR2 ← PR3`, merging PR #3 requires PR #1 and PR #2 to also pass checks, have required reviews, and satisfy all branch protection rules. +> [!NOTE] Stacked pull requests support merging with **bypass rules**, but only the bottom pull request can be merged this way. You cannot merge the whole stack with bypass rules. See [AUTOTITLE](/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/creating-rulesets-for-a-repository#granting-bypass-permissions-for-your-branch-or-tag-ruleset) + ## Merge methods Stacks support all three merge methods. In each case, the pull requests land as a single atomic operation: -* **Merge commit** creates one merge commit for the entire group of pull requests being merged, preserving each pull request's full commit history. +* **Merge commit** creates one merge commit for each pull requests being merged, preserving each pull request's full commit history. * **Squash** creates one clean, squashed commit per pull request. Merging `n` pull requests creates `n` squashed commits on the base branch. * **Rebase** replays the commits from each pull request onto the base branch, creating a linear history without merge commits. @@ -80,7 +89,7 @@ Stacks support all three merge methods. In each case, the pull requests land as Stacks fully support merge queues. All pull requests in the stack are added to the queue in the correct order. If a pull request is removed or ejected from the queue, all pull requests above it in the stack are also removed. > [!NOTE] -> To keep a stack together, the merge queue allows the merge group to exceed its configured maximum size by up to 50 percent. If the stack is too large to fit within that buffer, it will automatically be split across consecutive merge groups. +> To keep a stack together, the merge queue allows the merge group to exceed its configured maximum size by up to 50 percent. If the stack is too large to fit within that buffer, it will automatically be put into the next merge group as a single unit. ## Linear history diff --git a/content/pull-requests/reference/use-other-tools-with-stacked-pull-requests.md b/content/pull-requests/reference/use-other-tools-with-stacked-pull-requests.md index 5fb3d5759948..f3d203aa6f97 100644 --- a/content/pull-requests/reference/use-other-tools-with-stacked-pull-requests.md +++ b/content/pull-requests/reference/use-other-tools-with-stacked-pull-requests.md @@ -9,8 +9,6 @@ category: - Create pull requests --- -{% data reusables.public-preview.public-preview %} - Stacked pull requests are built on standard Git branches and regular pull requests, so you can choose to use tools other than the `gh stack` CLI for your local workflow. If you manage branch chains with another tool, such as Jujutsu (jj), Sapling, or git-town, you can use the `gh stack link` command to open those branches as a stack on {% data variables.product.github %}. The `gh stack link` command only calls the {% data variables.product.github %} API to create the stacked pull requests — it does not create any local tracking. If a branch already has an open pull request, `link` uses it; otherwise it creates a draft pull request with the correct base branch. diff --git a/content/pull-requests/tutorials/roll-out-stacked-prs.md b/content/pull-requests/tutorials/roll-out-stacked-prs.md index 7e331e99aa54..ecb984334068 100644 --- a/content/pull-requests/tutorials/roll-out-stacked-prs.md +++ b/content/pull-requests/tutorials/roll-out-stacked-prs.md @@ -10,9 +10,6 @@ category: - Create pull requests --- -> [!NOTE] -> Stacked pull requests are in {% data variables.release-phases.public_preview %} and subject to change. - Stacked pull requests let developers break large changes into a chain of small, focused pull requests that build on each other. This approach can help your organization maintain review quality as developers produce more code, including with {% data variables.product.prodname_copilot_short %} and other coding agents. Stacked pull requests require **no setup or enablement**. If your team already uses pull requests, they can create a stack today. The steps below help you prepare your existing controls and support a smooth rollout, not turn a feature on. diff --git a/content/pull-requests/tutorials/stack-code-changes-in-pull-requests.md b/content/pull-requests/tutorials/stack-code-changes-in-pull-requests.md index 82e76d9bef84..899ea12f4f42 100644 --- a/content/pull-requests/tutorials/stack-code-changes-in-pull-requests.md +++ b/content/pull-requests/tutorials/stack-code-changes-in-pull-requests.md @@ -10,8 +10,6 @@ category: - Team collaboration --- -{% data reusables.public-preview.public-preview %} - Large pull requests are difficult to review and create bottlenecks, especially when you generate a high volume of code in a short time. Review quality also degrades as pull request size increases. Reviewers may skim the result, miss issues, or procrastinate and leave the pull request until it grows stale and develops merge conflicts. Stacked pull requests keep large code changes reviewable. diff --git a/src/content-pipelines/config.yml b/src/content-pipelines/config.yml index 7a364ca70798..793621d6e6b8 100644 --- a/src/content-pipelines/config.yml +++ b/src/content-pipelines/config.yml @@ -52,4 +52,3 @@ gh-stack: The source is an Astro Starlight site. Convert directives to GitHub Docs alerts: ":::note" becomes "> [!NOTE]", ":::tip" becomes "> [!TIP]", ":::caution" becomes "> [!WARNING]", ":::danger" becomes "> [!CAUTION]". Drop directive titles such as ":::note[Authentication]", because GitHub Docs alerts do not take titles. The source uses "sh" code fences and title-case headings; use "shell" and sentence case instead. Write "pull request" rather than "PR". - Do not remove the public preview reusable near the top of the article; it has no counterpart in the source docs. From b4af924e032ee080bae9f338dd38e9c78ea319e6 Mon Sep 17 00:00:00 2001 From: Aaron Waggener <73763104+aaronwaggener@users.noreply.github.com> Date: Tue, 6 Oct 2026 18:53:10 +0000 Subject: [PATCH 4/6] Remove partner reporting from validity checks overview (#63709) Copilot-Session: 4c737b12-72ac-4122-a9ab-fb85b26a45eb --- .../code-security/concepts/secret-security/secret-scanning.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/content/code-security/concepts/secret-security/secret-scanning.md b/content/code-security/concepts/secret-security/secret-scanning.md index 4adce1a6df34..f76e1faf7f63 100644 --- a/content/code-security/concepts/secret-security/secret-scanning.md +++ b/content/code-security/concepts/secret-security/secret-scanning.md @@ -69,9 +69,7 @@ Beyond the default detection of partner and provider secrets, you can expand and ### About validity checks -Validity checks help you prioritize which secrets to remediate first by verifying whether a detected secret is still active. When you enable validity checks, {% data variables.product.prodname_secret_scanning %} may contact the secret's issuing service to determine if the credential has been revoked. - -Validity checks are separate from {% data variables.product.prodname_secret_scanning %}'s partner program. While partner secrets are automatically reported to service providers for revocation, validity checks verify the status of secrets you manage in your own alerts. For more information, see [AUTOTITLE](/code-security/concepts/secret-security/validity-checks). +Validity checks help you prioritize which secrets to remediate first by verifying whether a detected secret is still active. When you enable validity checks, {% data variables.product.prodname_secret_scanning %} may contact the secret's issuing service to determine if the credential has been revoked. For more information, see [AUTOTITLE](/code-security/concepts/secret-security/validity-checks). {% endif %} From 43f709d1bd3d80284d1027451e820f21b434fd63 Mon Sep 17 00:00:00 2001 From: docs-bot <77750099+docs-bot@users.noreply.github.com> Date: Tue, 6 Oct 2026 19:34:49 +0000 Subject: [PATCH 5/6] Fix padded octicon names from French guillemets in translation corrector (#63716) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Kevin Heis Copilot-Session: 487ebd54-80b0-4d3d-bb7c-95f39bec45f3 --- .../lib/correct-translation-content.ts | 12 +++++++++ .../tests/correct-translation-content.ts | 26 +++++++++++++++++++ 2 files changed, 38 insertions(+) diff --git a/src/languages/lib/correct-translation-content.ts b/src/languages/lib/correct-translation-content.ts index a4bd951b6335..0256ef75e064 100644 --- a/src/languages/lib/correct-translation-content.ts +++ b/src/languages/lib/correct-translation-content.ts @@ -1611,6 +1611,18 @@ export function correctTranslatedContentStrings( return match.replace(/[«»“”„]/g, '"').replace(/[‘’‚]/g, "'") }) + // French « check » becomes " check " after quote normalization. + content = content.replace( + /\{%(-?)\s*octicon\s+"\s*([\w-]+)\s*"([^%]*?)(-?)%\}/g, + (_m, o, name, rest, c) => { + const fixedRest = rest.replace( + /(^|\s)(aria-label|aria-hidden|height|width|class)="\s*([^"]*?[^"\s])\s*"/g, + '$1$2="$3"', + ) + return `{%${o} octicon "${name}"${fixedRest.replace(/\s*$/, ' ')}${c}%}` + }, + ) + content = content.replace( /\{%(-?)\s+(ifversion|elsif|if)\s+([^%]*?)\s*(-?)%\}/g, (_m, dashOpen, tag, body, dashClose) => diff --git a/src/languages/tests/correct-translation-content.ts b/src/languages/tests/correct-translation-content.ts index 308be31db93f..e9e81b3b9c9c 100644 --- a/src/languages/tests/correct-translation-content.ts +++ b/src/languages/tests/correct-translation-content.ts @@ -3379,4 +3379,30 @@ Para más información, consulta "[AUTOTITLE](/path)". ).toBe(broken) }) }) + + describe('octicon with French guillemets', () => { + test('fr: trims padding left by « check » after quote normalization', () => { + expect(fix('{% octicon « check » aria-label="Included » %}', 'fr')).toBe( + '{% octicon "check" aria-label="Included" %}', + ) + expect(fix('{% octicon « x » aria-label="Non inclus" %}', 'fr')).toBe( + '{% octicon "x" aria-label="Non inclus" %}', + ) + }) + + test('fr: leaves a correct octicon unchanged', () => { + const ok = '{% octicon "check" aria-label="Included" %}' + expect(fix(ok, 'fr')).toBe(ok) + }) + + test('leaves padded values on other attributes unchanged', () => { + const custom = '{% octicon "x" data-aria-label=" a " myclass=" b " title=" c " %}' + expect(fix(custom, 'fr')).toBe(custom) + }) + + test('leaves whitespace-only attribute values unchanged', () => { + const blank = '{% octicon "x" class=" " width="64" aria-label="Supported" %}' + expect(fix(blank, 'fr')).toBe(blank) + }) + }) }) From a7c2de673ea756adf470049988144bfe6191c452 Mon Sep 17 00:00:00 2001 From: hubwriter Date: Tue, 6 Oct 2026 19:44:40 +0000 Subject: [PATCH 6/6] Change the titles of 2 BYOK articles (#63705) --- .../copilot-cli/customize-copilot/use-byok-models.md | 8 ++++---- .../copilot/how-tos/github-copilot-app/use-byok-models.md | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/content/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models.md b/content/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models.md index 815b9c6e0207..cb3be49a0846 100644 --- a/content/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models.md +++ b/content/copilot/how-tos/copilot-cli/customize-copilot/use-byok-models.md @@ -1,6 +1,6 @@ --- -title: Using your own LLM models in GitHub Copilot CLI -shortTitle: Use your own model provider +title: Adding LLM models to GitHub Copilot CLI +shortTitle: Add LLM models intro: 'Use a model from an external provider of your choice in {% data variables.product.prodname_copilot_short %} by supplying your own API key.' allowTitleToDifferFromFilename: true versions: @@ -14,7 +14,7 @@ docsTeamMetrics: - copilot-cli --- -You can configure {% data variables.copilot.copilot_cli_short %} to use your own LLM provider, also called BYOK (Bring Your Own Key), instead of {% data variables.product.github %}-hosted models. This lets you connect to OpenAI-compatible endpoints, Azure OpenAI, or Anthropic, including locally running models such as Ollama. +You can configure {% data variables.copilot.copilot_cli_short %} to include models from an LLM provider of your choice—using BYOK (Bring Your Own Key)—in addition to the {% data variables.product.github %}-hosted models. This lets you connect to OpenAI-compatible endpoints, Azure OpenAI, or Anthropic, including locally running models such as Ollama. > [!NOTE] > This article is for users who want to configure their own LLM provider API key on their local machine. To set up custom models for users in an enterprise, see [AUTOTITLE](/copilot/how-tos/administer-copilot/manage-for-enterprise/enable-custom-models). @@ -143,5 +143,5 @@ You can run {% data variables.copilot.copilot_cli_short %} in offline mode to pr ```shell export COPILOT_OFFLINE=true ``` - + 1. {% data reusables.copilot.copilot-cli.start-cli %} diff --git a/content/copilot/how-tos/github-copilot-app/use-byok-models.md b/content/copilot/how-tos/github-copilot-app/use-byok-models.md index c37cd8bbab85..4c26147fdde7 100644 --- a/content/copilot/how-tos/github-copilot-app/use-byok-models.md +++ b/content/copilot/how-tos/github-copilot-app/use-byok-models.md @@ -1,6 +1,6 @@ --- -title: Using your own LLM models in the GitHub Copilot app -shortTitle: Use your own model provider +title: Adding LLM models to the GitHub Copilot app +shortTitle: Add LLM models intro: 'Connect a model from an external provider of your choice by supplying your own API key, then use the model in agent sessions.' allowTitleToDifferFromFilename: true product: '{% data reusables.gated-features.github-app %}
Download {% data variables.copilot.github_copilot_app %} {% octicon "link-external" height:16 %}' @@ -15,7 +15,7 @@ category: > [!NOTE] > Support to use your own model provider in the {% data variables.copilot.github_copilot_app %} is in {% data variables.release-phases.public_preview %} and subject to change. -You can configure the {% data variables.copilot.github_copilot_app %} to use your own LLM provider, also called BYOK (Bring Your Own Key), instead of {% data variables.product.github %}-hosted models. You can set up your model provider when you first open the app or later in app settings. +You can configure the {% data variables.copilot.github_copilot_app %} to include models from an LLM provider of your choice—using BYOK (Bring Your Own Key)—in addition to the {% data variables.product.github %}-hosted models. You can set up your model provider when you first open the app or later in app settings. You must sign in with a {% data variables.product.github %} account to use the app, but you do not need a {% data variables.product.prodname_copilot_short %} plan if you use your own model provider. If you do have a {% data variables.product.prodname_copilot_short %} plan, you can use both your own model provider and {% data variables.product.github %}-hosted models in the same app.