Skip to content

Commit 3944101

Browse files
authored
Merge pull request github#36618 from github/repo-sync
Repo sync
2 parents 516a4d2 + 2f4c6a4 commit 3944101

File tree

20 files changed

+158
-32
lines changed

20 files changed

+158
-32
lines changed

content/admin/managing-your-enterprise-account/about-enterprise-accounts.md

-6
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@ topics:
2222

2323
## What are enterprise accounts?
2424

25-
<!-- expires 2025-02-28 -->
26-
{% ifversion ghec %}
27-
> [!NOTE] Currently, {% data variables.product.prodname_ghe_cloud %} customers who use a single organization are being automatically upgraded to an enterprise account at no additional cost. For details, see [AUTOTITLE](/admin/managing-your-enterprise-account/creating-an-enterprise-account#what-will-happen-after-i-upgrade-my-organization).
28-
{% endif %}
29-
<!-- end expires 2025-02-28 -->
30-
3125
An enterprise account enables centralized management for **multiple organizations**.
3226

3327
Administrators for the enterprise account can:

content/admin/managing-your-enterprise-account/creating-an-enterprise-account.md

-4
Original file line numberDiff line numberDiff line change
@@ -15,10 +15,6 @@ redirect_from:
1515
- /admin/overview/creating-an-enterprise-account
1616
---
1717

18-
<!-- expires 2025-02-28 -->
19-
{% data reusables.enterprise.single-organizations-enterprise-migration %}
20-
<!-- end expires 2025-02-28 -->
21-
2218
## When should I create an enterprise account?
2319

2420
{% data variables.product.prodname_ghe_cloud %} allows you to create an enterprise account, which enables collaboration between **multiple organizations** and gives administrators a single point of visibility and management. See [AUTOTITLE](/admin/managing-your-enterprise-account/about-enterprise-accounts).

content/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/about-billing-for-github-advanced-security.md

+6
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,14 @@ If you have further questions about using {% data variables.product.prodname_GH_
7171
7272
For pricing details for {% data variables.product.prodname_GH_advanced_security %}, see our [pricing information](https://github.com/enterprise/advanced-security#pricing).
7373

74+
{% data reusables.advanced-security.ghas-products-tip %}
75+
7476
{% elsif ghec %}
7577

7678
If you want to use {% data variables.product.prodname_GH_advanced_security %} features on any repository apart from a public repository on {% data variables.product.prodname_dotcom_the_website %}, you will need a {% data variables.product.prodname_GH_advanced_security %} license. For more information about {% data variables.product.prodname_GH_advanced_security %}, see [AUTOTITLE](/get-started/learning-about-github/about-github-advanced-security).
7779

80+
{% data reusables.advanced-security.ghas-products-tip %}
81+
7882
{% ifversion security-configurations %}
7983
{% data reusables.security-configurations.managing-GHAS-licenses %}
8084

@@ -90,6 +94,8 @@ For other billing-related questions, contact {% data variables.contact.github_su
9094

9195
You can make extra features for code security available to users by buying and uploading a license for {% data variables.product.prodname_GH_advanced_security %}. For more information about {% data variables.product.prodname_GH_advanced_security %}, see [AUTOTITLE](/get-started/learning-about-github/about-github-advanced-security).
9296

97+
{% data reusables.advanced-security.ghas-products-tip %}
98+
9399
{% ifversion security-configurations %}
94100
{% data reusables.security-configurations.managing-GHAS-licenses %}
95101

content/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/managing-your-github-advanced-security-licensing.md

+2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ shortTitle: Manage Advanced Security licensing
1717

1818
Each license for {% data variables.product.prodname_GH_advanced_security %} specifies a maximum number of accounts that can use these features. Each active committer to at least one repository with the feature enabled uses one license. A committer is considered active if one of their commits has been pushed to the repository within the last 90 days, regardless of when it was originally authored. For more information about committer numbers, see [AUTOTITLE](/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/about-billing-for-github-advanced-security). For information about purchasing a license, see [AUTOTITLE](/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/signing-up-for-github-advanced-security).
1919

20+
{% data reusables.advanced-security.ghas-products-tip %}
21+
2022
## Managing the number of committers in your subscription
2123

2224
{% ifversion security-configurations %}

content/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/setting-up-a-trial-of-github-advanced-security.md

+2
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ shortTitle: Set up an Advanced Security trial
2323

2424
{% data variables.product.prodname_GH_advanced_security %} provides features that help you improve and maintain the security and quality of code, such as {% data variables.product.prodname_code_scanning %}, {% data variables.product.prodname_secret_scanning %}, and dependency review. For more information, see [AUTOTITLE](/get-started/learning-about-github/about-github-advanced-security).
2525

26+
{% data reusables.advanced-security.ghas-products-tip %}
27+
2628
## About trials of {% data variables.product.prodname_GH_advanced_security %}
2729

2830
There are a few ways to trial {% data variables.product.prodname_GH_advanced_security %}:

content/billing/managing-billing-for-your-products/managing-billing-for-github-advanced-security/signing-up-for-github-advanced-security.md

+2
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ shortTitle: Sign up for Advanced Security
2121

2222
## Purchasing {% data variables.product.prodname_GH_advanced_security %}
2323

24+
{% data reusables.advanced-security.ghas-products-tip %}
25+
2426
{% data reusables.enterprise-accounts.access-enterprise %}
2527
{% data reusables.enterprise-accounts.settings-tab %}
2628
{% data reusables.enterprise-accounts.license-tab %}

content/code-security/trialing-github-advanced-security/planning-a-trial-of-ghas.md

+2
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ You can trial {% data variables.product.prodname_GH_advanced_security %} as part
3131

3232
You can end your trial at any time by purchasing {% data variables.product.prodname_GH_advanced_security %}, and {% data variables.product.prodname_enterprise %} if you don't already use it, or by canceling the trial. For more information, see [What happens when the trial ends?](/enterprise-cloud@latest/admin/overview/setting-up-a-trial-of-github-enterprise-cloud#what-happens-when-the-trial-ends){% ifversion fpt %} in the {% data variables.product.prodname_ghe_cloud %} documentation{% endif %}.
3333

34+
{% data reusables.advanced-security.ghas-products-tip %}
35+
3436
## Define your company goals
3537

3638
Before you start a trial of {% data variables.product.prodname_GH_advanced_security %}, you should define the purpose of the trial and identify the key questions you need to answer. Maintaining a strong focus on these goals will enable you to plan a trial that maximizes discovery and ensures that you have the information needed to decide whether or not to upgrade.

content/copilot/rolling-out-github-copilot-at-scale/analyzing-usage-over-time-with-the-copilot-metrics-api.md

+3-1
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,13 @@ This guide demonstrates how to query the API, store data, and analyze a trend fo
3030

3131
## About endpoint availability
3232

33-
Endpoints are available to get data for an enterprise, organization, organization team, or enterprise team.
33+
Endpoints are available to get data for an enterprise, organization, organization team, or enterprise team on {% data variables.product.prodname_dotcom_the_website %}.
3434

3535
* If you have a {% data variables.product.prodname_copilot_for_business %} or {% data variables.product.prodname_copilot_enterprise %} subscription as part of a regular organization or enterprise, you can use the endpoints for **an enterprise, an organization, or an organization team**. You don't have access to enterprise teams unless you're enrolled in a preview.
3636
* If you use a dedicated enterprise for {% data variables.product.prodname_copilot_for_business %}—an enterprise account without the ability to create organizations—you can use the endpoints for **an enterprise or an enterprise team**.
3737

38+
{% data reusables.copilot.metrics-api-ghecom %}
39+
3840
## Prerequisites
3941

4042
* The **{% data variables.product.prodname_copilot_short %} metrics API access** policy must be enabled for your enterprise or organization. See [AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-policies-for-copilot-in-your-organization) or [AUTOTITLE](/enterprise-cloud@latest/copilot/managing-copilot/managing-copilot-for-your-enterprise/managing-policies-and-features-for-copilot-in-your-enterprise).

content/organizations/collaborating-with-groups-in-organizations/about-organizations.md

-6
Original file line numberDiff line numberDiff line change
@@ -38,12 +38,6 @@ To learn how to use organizations most effectively, see [AUTOTITLE](/organizatio
3838

3939
## Organizations and enterprise accounts
4040

41-
<!-- expires 2025-02-28 -->
42-
{% ifversion ghec %}
43-
> [!NOTE] Currently, {% data variables.product.prodname_ghe_cloud %} customers who use a single organization are being automatically upgraded to an enterprise account at no additional cost. For details, see [AUTOTITLE](/admin/managing-your-enterprise-account/creating-an-enterprise-account#what-will-happen-after-i-upgrade-my-organization).
44-
{% endif %}
45-
<!-- end expires 2025-02-28 -->
46-
4741
{% ifversion fpt %}
4842
Enterprise accounts are a feature of {% data variables.product.prodname_ghe_cloud %} that allow owners to centrally manage policy and billing for multiple organizations. For more information, see [the {% data variables.product.prodname_ghe_cloud %} documentation](/enterprise-cloud@latest/organizations/collaborating-with-groups-in-organizations/about-organizations).
4943
{% else %}

content/rest/copilot/copilot-metrics.md

+2
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,6 @@ If you currently use the [AUTOTITLE](/rest/copilot/copilot-usage), we recommend
2222

2323
For help getting started, see [AUTOTITLE](/copilot/managing-copilot/managing-github-copilot-in-your-organization/reviewing-activity-related-to-github-copilot-in-your-organization/analyzing-usage-over-time-with-the-copilot-metrics-api).
2424

25+
{% data reusables.copilot.metrics-api-ghecom %}
26+
2527
<!-- Content after this section is automatically generated -->

content/rest/copilot/copilot-usage.md

+1-8
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,5 @@ autogenerated: rest
1313
allowTitleToDifferFromFilename: true
1414
---
1515

16-
<!-- expires 2025-03-01 -->
17-
18-
<!-- When this expires, change the message to say they're no longer accessible at all -->
19-
20-
>[!WARNING] These endpoints are closing down. They will be accessible throughout February 2025, but will not return any new data after February 1st. They will be retired on March 1st. **Please migrate to the [AUTOTITLE](/rest/copilot/copilot-metrics) as soon as possible.**
21-
22-
<!-- end expires 2025-03-01 -->
23-
16+
>[!WARNING] These endpoints are retired. Use the [AUTOTITLE](/rest/copilot/copilot-metrics) endpoints instead.
2417
<!-- Content after this section is automatically generated -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<!-- expires 2025-04-01 -->
2+
3+
> [!TIP]
4+
> From April 1, 2025, you will be able to enable usage-based billing or buy licenses for selected features of {% data variables.product.prodname_GH_advanced_security %}. {% ifversion fpt or ghec %}The new products, GitHub Secret Protection and GitHub Code Security, will be available to users with {% data variables.product.prodname_team %} and {% data variables.product.prodname_enterprise %}. {% elsif ghes %}The new products, GitHub Secret Protection and GitHub Code Security, will be available to users with {% data variables.product.prodname_team %}, {% data variables.product.prodname_ghe_cloud %}, and {% data variables.product.prodname_ghe_server %} 3.17 onward.{% endif %}For full details, see [Evolving {% data variables.product.prodname_GH_advanced_security %}](https://resources.github.com/evolving-github-advanced-security/) in Executive Insights.
5+
6+
<!-- end expires 2025-04-01 -->
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
>[!NOTE] The {% data variables.product.prodname_copilot_short %} metrics endpoints are **not** available for {% data variables.enterprise.data_residency %} on {% data variables.enterprise.data_residency_site %}.

src/article-api/middleware/article.ts

+106
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import type { RequestHandler, Response } from 'express'
2+
import express from 'express'
3+
4+
import { defaultCacheControl } from '@/frame/middleware/cache-control.js'
5+
import { Context } from '#src/types.js'
6+
import catchMiddlewareError from '@/observability/middleware/catch-middleware-error.js'
7+
import { ExtendedRequestWithPageInfo } from '../types'
8+
import { pageValidationMiddleware, pathValidationMiddleware } from './validation'
9+
import contextualize from '#src/frame/middleware/context/context.js'
10+
11+
/** START helper functions */
12+
13+
// for now, we're just querying pageinfo, we'll likely replace /api/pageinfo
14+
// with /api/meta and move or reference that code here
15+
async function getArticleMetadata(req: ExtendedRequestWithPageInfo) {
16+
const queryString = new URLSearchParams(req.query as Record<string, string>).toString()
17+
const apiUrl = `${req.protocol}://${req.get('host')}/api/pageinfo${queryString ? `?${queryString}` : ''}`
18+
19+
// Fetch the data from the pageinfo API
20+
const response = await fetch(apiUrl)
21+
22+
// Check if the response is OK
23+
if (!response.ok) {
24+
const errorText = await response.text()
25+
throw new Error(`Failed to fetch metadata: ${response.status} ${errorText}`)
26+
}
27+
28+
return await response.json()
29+
}
30+
31+
async function getArticleBody(req: ExtendedRequestWithPageInfo) {
32+
// req.pageinfo is set from pageValidationMiddleware and pathValidationMiddleware
33+
// and is in the ExtendedRequestWithPageInfo
34+
const { page, pathname } = req.pageinfo
35+
36+
// these parts allow us to render the page
37+
const mockedContext: Context = {}
38+
const renderingReq = {
39+
path: pathname,
40+
language: page.languageCode,
41+
pagePath: pathname,
42+
cookies: {},
43+
context: mockedContext,
44+
headers: {
45+
'content-type': 'text/markdown',
46+
},
47+
}
48+
49+
// contextualize and render the page
50+
await contextualize(renderingReq as ExtendedRequestWithPageInfo, {} as Response, () => {})
51+
renderingReq.context.page = page
52+
renderingReq.context.markdownRequested = true
53+
return await page.render(renderingReq.context)
54+
}
55+
56+
/** END helper functions */
57+
58+
/** START routes */
59+
const router = express.Router()
60+
61+
// For all these routes:
62+
// - pathValidationMiddleware ensures the path is properly structured and handles errors when it's not
63+
// - pageValidationMiddleware fetches the page from the pagelist, returns 404 to the user if not found
64+
65+
router.get(
66+
'/',
67+
pathValidationMiddleware as RequestHandler,
68+
pageValidationMiddleware as RequestHandler,
69+
catchMiddlewareError(async function (req: ExtendedRequestWithPageInfo, res: Response) {
70+
// First, fetch metadata
71+
const metaData = await getArticleMetadata(req)
72+
const bodyContent = await getArticleBody(req)
73+
74+
defaultCacheControl(res)
75+
return res.json({
76+
meta: metaData,
77+
body: bodyContent,
78+
})
79+
}),
80+
)
81+
82+
router.get(
83+
'/body',
84+
pathValidationMiddleware as RequestHandler,
85+
pageValidationMiddleware as RequestHandler,
86+
catchMiddlewareError(async function (req: ExtendedRequestWithPageInfo, res: Response) {
87+
const rendered = await getArticleBody(req)
88+
defaultCacheControl(res)
89+
return res.type('text/markdown').send(rendered)
90+
}),
91+
)
92+
93+
router.get(
94+
'/meta',
95+
pathValidationMiddleware as RequestHandler,
96+
pageValidationMiddleware as RequestHandler,
97+
catchMiddlewareError(async function (req: ExtendedRequestWithPageInfo, res: Response) {
98+
const metaData = await getArticleMetadata(req)
99+
defaultCacheControl(res)
100+
return res.json(metaData)
101+
}),
102+
)
103+
104+
/** END routes */
105+
106+
export default router

src/article-api/middleware/validation.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { ExtendedRequestWithPageInfo } from '../types'
22
import type { NextFunction, Response } from 'express'
33
import { isArchivedVersionByPath } from '@/archives/lib/is-archived-version'
44
import getRedirect from '@/redirects/lib/get-redirect.js'
5+
import { Page } from '#src/types.js'
56

67
export const pathValidationMiddleware = (
78
req: ExtendedRequestWithPageInfo,
@@ -24,7 +25,9 @@ export const pathValidationMiddleware = (
2425
if (/\s/.test(pathname)) {
2526
return res.status(400).json({ error: `'pathname' cannot contain whitespace` })
2627
}
27-
req.pageinfo = { pathname }
28+
29+
// req.pageinfo.page will be defined later or it will throw
30+
req.pageinfo = { pathname, page: {} as Page }
2831
return next()
2932
}
3033

@@ -59,6 +62,9 @@ export const pageValidationMiddleware = (
5962
pathname = `/${req.context.currentLanguage}`
6063
}
6164

65+
// Initialize archived property to avoid it being undefined
66+
req.pageinfo.archived = { isArchived: false }
67+
6268
if (!(pathname in req.context.pages)) {
6369
// If a pathname is not a known page, it might *either* be a redirect,
6470
// or an archived enterprise version, or both.
@@ -76,6 +82,9 @@ export const pageValidationMiddleware = (
7682

7783
// Remember this might yield undefined if the pathname is not a page
7884
req.pageinfo.page = req.context.pages[pathname]
85+
if (!req.pageinfo.page && !req.pageinfo.archived.isArchived) {
86+
return res.status(404).json({ error: `No page found for '${pathname}'` })
87+
}
7988
// The pathname might have changed if it was a redirect
8089
req.pageinfo.pathname = pathname
8190

src/article-api/tests/pageinfo.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ describe('pageinfo api', () => {
5050

5151
test('a pathname that does not exist', async () => {
5252
const res = await get(makeURL('/en/never/heard/of'))
53-
expect(res.statusCode).toBe(400)
53+
expect(res.statusCode).toBe(404)
5454
const { error } = JSON.parse(res.body)
5555
expect(error).toBe("No page found for '/en/never/heard/of'")
5656
})

src/article-api/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export type ArchivedVersion = {
88
export type ExtendedRequestWithPageInfo = ExtendedRequest & {
99
pageinfo: {
1010
pathname: string
11-
page?: Page
11+
page: Page
1212
archived?: ArchivedVersion
1313
}
1414
}

src/frame/middleware/api.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import events from '@/events/middleware.js'
55
import anchorRedirect from '@/rest/api/anchor-redirect.js'
66
import aiSearch from '@/search/middleware/ai-search'
77
import search from '@/search/middleware/search-routes.js'
8-
import pageInfo from '#src/article-api/middleware/pageinfo.ts'
8+
import pageInfo from '@/article-api/middleware/pageinfo'
99
import pageList from '@/article-api/middleware/pagelist'
10+
import article from '@/article-api/middleware/article'
1011
import webhooks from '@/webhooks/middleware/webhooks.js'
1112
import { ExtendedRequest } from '@/types'
1213
import { noCacheControl } from './cache-control'
@@ -30,6 +31,7 @@ router.use('/webhooks', createAPIRateLimiter(internalRoutesRateLimit), webhooks)
3031
router.use('/anchor-redirect', createAPIRateLimiter(internalRoutesRateLimit), anchorRedirect)
3132
router.use('/pageinfo', createAPIRateLimiter(3), pageInfo)
3233
router.use('/pagelist', createAPIRateLimiter(publicRoutesRateLimit), pageList)
34+
router.use('/article', createAPIRateLimiter(publicRoutesRateLimit), article)
3335

3436
// The purpose of this is for convenience to everyone who runs this code
3537
// base locally but don't have an Elasticsearch server locally.

src/frame/middleware/context/context.ts

-2
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,6 @@ export default async function contextualize(
3939
req.context.process = { env: {} }
4040

4141
if (req.pagePath && req.pagePath.endsWith('.md')) {
42-
req.context.markdownRequested = true
43-
4442
// req.pagePath is used later in the rendering pipeline to
4543
// locate the file in the tree so it cannot have .md
4644
req.pagePath = req.pagePath.replace(/\/index\.md$/, '').replace(/\.md$/, '')

src/shielding/middleware/handle-invalid-paths.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,16 @@ export default function handleInvalidPaths(
8989
// E.g. `/en/foo.md?bar=baz`
9090
const newUrl = req.originalUrl.replace(req.path, req.path.replace(/\/index\.md$/, ''))
9191
return res.redirect(newUrl)
92+
} else if (req.path.endsWith('.md')) {
93+
// encode the query params but also make them pretty so we can see
94+
// them as `/` and `@` in the address bar
95+
// e.g. /api/article/body?pathname=/en/[email protected]/admin...
96+
// NOT: /api/article/body?pathname=%2Fen%2Fenterprise-server%403.16%2Fadmin...
97+
const encodedPath = encodeURIComponent(req.path.replace(/\.md$/, ''))
98+
.replace(/%2F/g, '/')
99+
.replace(/%40/g, '@')
100+
const newUrl = `/api/article/body?pathname=${encodedPath}`
101+
return res.redirect(newUrl)
92102
}
93-
94103
return next()
95104
}

0 commit comments

Comments
 (0)