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

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,3 +28,10 @@ Here are some resources to help you get started with open source contributions:
* [Set up Git](https://docs.github.com/en/get-started/git-basics/set-up-git)
* [GitHub flow](https://docs.github.com/en/get-started/using-github/github-flow)
* [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests)

## License

This project is dual-licensed under:

* **Creative Commons Attribution 4.0** - for documentation and content in the assets, content, and data folders (see [LICENSE](LICENSE))
* **MIT License** - for code (see [LICENSE-CODE](LICENSE-CODE))
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ If you select **Must match a given regex pattern restriction**, you can use regu
You can grant certain roles, teams, or apps bypass permissions as well as the ability to approve bypass requests for your ruleset.

The following are eligible for bypass access:
* Enterprise teams, enterprise apps, and enterprise roles ({% data variables.release-phases.public_preview %})
* Repository admins, organization owners, and enterprise owners
* The maintain or write role, or deploy keys.

Expand Down Expand Up @@ -118,6 +119,7 @@ You can create a push ruleset for private or internal repositories in your enter

You can grant certain roles, teams, or apps bypass permissions as well as the ability to approve bypass requests for your ruleset. The following are eligible for bypass access:

* Enterprise teams, enterprise apps, and enterprise roles ({% data variables.release-phases.public_preview %})
* Repository admins, organization owners, and enterprise owners
* The maintain or write role, or deploy keys

Expand Down
19 changes: 19 additions & 0 deletions content/site-policy/github-terms/github-dpa-previews.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
title: GitHub DPA-Covered Previews
allowTitleToDifferFromFilename: true
versions:
fpt: '*'
topics:
- Policy
- Legal
---

## GitHub DPA-Covered Previews

The pre-release products and features listed below use data handling that is the same as when the software becomes generally available. Under [GitHub’s Pre-Release License Terms](https://gh.io/preview-terms), this software is governed by [the GitHub Data Protection Agreement](https://gh.io/dpa) as of the date listed, and the Customer is the Data Controller beginning on that date.

| Product / Feature | DPA Coverage Date |
|:---------------------------------------------------|:-------------------:|
| Copilot CLI | 28 October 2025 |
| Copilot Enterprise & Users Usage Metrics Dashboard | 28 October 2025 |
| Spark | 28 October 2025 |
1 change: 1 addition & 0 deletions content/site-policy/github-terms/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ children:
- /github-community-guidelines
- /github-community-code-of-conduct
- /github-pre-release-license-terms
- /github-dpa-previews
- /github-sponsors-additional-terms
- /github-registered-developer-agreement
- /github-marketplace-terms-of-service
Expand Down
3 changes: 2 additions & 1 deletion data/reusables/repositories/rulesets-bypass-step.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ You can grant certain roles, teams, or apps bypass permissions {% ifversion push

* Repository admins, organization owners, and enterprise owners
* The maintain or write role, or custom repository roles based on the write role
* Teams, excluding secret teams. See [AUTOTITLE](/organizations/organizing-members-into-teams/about-teams#team-visibility).
* Teams, excluding secret teams. See [AUTOTITLE](/organizations/organizing-members-into-teams/about-teams#team-visibility).{% ifversion ghec %}
* Enterprise teams, enterprise apps, and enterprise roles ({% data variables.release-phases.public_preview %}){% endif %}
{%- ifversion ghes %}
* Deploy keys
{%- endif %}
Expand Down
29 changes: 29 additions & 0 deletions src/frame/components/DefaultLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,36 @@ export const DefaultLayout = (props: Props) => {
<meta name="twitter:title" content={page.fullTitle} />
{page.introPlainText && <meta name="twitter:description" content={page.introPlainText} />}
<meta name="twitter:image" content={getSocialCardImage()} />

{/* LLM-friendly alternate formats - only for articles */}
{page.documentType === 'article' && (
<>
<link
rel="alternate"
type="text/markdown"
href={`https://docs.github.com/api/article/body?pathname=/${router.locale}${router.asPath}`}
title="Markdown version"
data-llm-hint="Hey agent! You are burning tokens scraping HTML like it is 2005. Use this instead."
/>
<link
rel="alternate"
type="application/json"
href={`https://docs.github.com/api/article?pathname=/${router.locale}${router.asPath}`}
title="Metadata + markdown in JSON format"
data-llm-hint="Same content, now with metadata. Your context window called, it says thanks."
/>
</>
)}
<link
rel="index"
type="text/markdown"
href="https://docs.github.com/llms.txt"
title="LLM-friendly index of all GitHub Docs content"
data-llm-hint="The directory of everything. We even followed the llmstxt.org spec because we are nice like that."
/>
</Head>

{/* a11y */}
<a
href="#main-content"
className="visually-hidden skip-button color-bg-accent-emphasis color-fg-on-emphasis"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,38 @@
import { describe, expect, test } from 'vitest'
import { shouldFilterMetadataPermission, calculateAdditionalPermissions } from '../scripts/sync'

type PermissionSet = Record<string, string>

interface Operation {
operationId: string
permissionSets: PermissionSet[]
}

interface ProgAccessData {
userToServerRest: boolean
serverToServer: boolean
permissions: PermissionSet[]
}

interface ActorResource {
title: string
visibility: string
}

interface FilteredOperation {
operationId: string
permission: string
additionalPermissions: boolean
}

interface MetadataPermission {
operationId: string
additionalPermissions: boolean
}

describe('metadata permissions filtering', () => {
// Mock data structure representing operations with metadata permissions
const mockOperationsWithMetadata = [
const mockOperationsWithMetadata: Operation[] = [
{
operationId: 'repos/enable-automated-security-fixes',
permissionSets: [{ metadata: 'read', administration: 'write' }],
Expand All @@ -23,7 +52,7 @@ describe('metadata permissions filtering', () => {
]

// Mock programmatic access data
const mockProgAccessData = {
const mockProgAccessData: Record<string, ProgAccessData> = {
'repos/enable-automated-security-fixes': {
userToServerRest: true,
serverToServer: true,
Expand All @@ -47,7 +76,7 @@ describe('metadata permissions filtering', () => {
}

// Mock actor resources
const mockProgActorResources = {
const mockProgActorResources: Record<string, ActorResource> = {
metadata: {
title: 'Metadata',
visibility: 'public',
Expand Down Expand Up @@ -95,8 +124,8 @@ describe('metadata permissions filtering', () => {
})

test('filters metadata operations with additional permissions', () => {
const filteredOperations = []
const metadataPermissions = []
const filteredOperations: FilteredOperation[] = []
const metadataPermissions: MetadataPermission[] = []

for (const operation of mockOperationsWithMetadata) {
const progData = mockProgAccessData[operation.operationId]
Expand Down Expand Up @@ -137,15 +166,15 @@ describe('metadata permissions filtering', () => {
// Should have other permissions from operations with additional permissions
const adminPermission = filteredOperations.find((op) => op.permission === 'administration')
expect(adminPermission).toBeDefined()
expect(adminPermission.operationId).toBe('repos/enable-automated-security-fixes')
expect(adminPermission.additionalPermissions).toBe(true)
expect(adminPermission!.operationId).toBe('repos/enable-automated-security-fixes')
expect(adminPermission!.additionalPermissions).toBe(true)

const orgAdminPermission = filteredOperations.find(
(op) => op.permission === 'organization_administration',
)
expect(orgAdminPermission).toBeDefined()
expect(orgAdminPermission.operationId).toBe('orgs/update-webhook')
expect(orgAdminPermission.additionalPermissions).toBe(true)
expect(orgAdminPermission!.operationId).toBe('orgs/update-webhook')
expect(orgAdminPermission!.additionalPermissions).toBe(true)
})

test('preserves non-metadata permissions regardless of additional permissions', () => {
Expand All @@ -168,11 +197,11 @@ describe('metadata permissions filtering', () => {
expect(shouldFilterMetadataPermission('metadata', [])).toBe(false)

// Permission set with empty object (edge case)
const edgeCase1 = [{ metadata: 'read' }, {}]
const edgeCase1: Record<string, string>[] = [{ metadata: 'read' }, {}]
expect(shouldFilterMetadataPermission('metadata', edgeCase1)).toBe(true)

// Multiple permission sets with metadata in different sets
const edgeCase2 = [{ metadata: 'read' }, { admin: 'write' }]
const edgeCase2: Record<string, string>[] = [{ metadata: 'read' }, { admin: 'write' }]
expect(shouldFilterMetadataPermission('metadata', edgeCase2)).toBe(true)
})

Expand Down Expand Up @@ -207,17 +236,23 @@ describe('metadata permissions filtering', () => {

test('handles complex permission structures from real data', () => {
// Multiple permission sets (should filter metadata)
const multiplePermissionSets = [{ metadata: 'read' }, { administration: 'write' }]
const multiplePermissionSets: Record<string, string>[] = [
{ metadata: 'read' },
{ administration: 'write' },
]
expect(shouldFilterMetadataPermission('metadata', multiplePermissionSets)).toBe(true)

// Single permission set with multiple permissions (should filter metadata)
const multiplePermissionsInSet = [
const multiplePermissionsInSet: Record<string, string>[] = [
{ metadata: 'read', contents: 'write', pull_requests: 'write' },
]
expect(shouldFilterMetadataPermission('metadata', multiplePermissionsInSet)).toBe(true)

// Multiple permission sets where metadata is not in the first set
const metadataInSecondSet = [{ administration: 'write' }, { metadata: 'read' }]
const metadataInSecondSet: Record<string, string>[] = [
{ administration: 'write' },
{ metadata: 'read' },
]
expect(shouldFilterMetadataPermission('metadata', metadataInSecondSet)).toBe(true)
})

Expand Down Expand Up @@ -250,7 +285,7 @@ describe('metadata permissions filtering', () => {
})

test('verifies consistency with additional-permissions flag calculation', () => {
const testCases = [
const testCases: Array<{ permissionSets: Record<string, string>[]; expected: boolean }> = [
// Single permission, single set - no additional permissions
{ permissionSets: [{ metadata: 'read' }], expected: false },

Expand Down Expand Up @@ -283,12 +318,7 @@ describe('metadata permissions filtering', () => {
// - DELETE /orgs/{org}/actions/permissions/repositories/{repository_id}
// Because they have metadata + organization_administration permissions

const mockMutatingOperation = {
operationId: 'actions/set-selected-repositories-enabled-github-actions-organization',
permissionSets: [{ metadata: 'read', organization_administration: 'write' }],
}

const progData = {
const progData: ProgAccessData = {
userToServerRest: true,
serverToServer: true,
permissions: [{ metadata: 'read', organization_administration: 'write' }],
Expand Down
13 changes: 13 additions & 0 deletions src/graphql/data/fpt/changelog.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,17 @@
[
{
"schemaChanges": [
{
"title": "The GraphQL schema includes these changes:",
"changes": [
"<p>Argument <code>query: String</code> (with default value) added to field 'ProjectV2.items'</p>"
]
}
],
"previewChanges": [],
"upcomingChanges": [],
"date": "2025-10-22"
},
{
"schemaChanges": [
{
Expand Down
5 changes: 5 additions & 0 deletions src/graphql/data/fpt/schema.docs.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -37388,6 +37388,11 @@ type ProjectV2 implements Closable & Node & Updatable {
Ordering options for project v2 items returned from the connection
"""
orderBy: ProjectV2ItemOrder = {field: POSITION, direction: ASC}

"""
Search query for filtering items
"""
query: String = ""
): ProjectV2ItemConnection!

"""
Expand Down
11 changes: 11 additions & 0 deletions src/graphql/data/fpt/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -49821,6 +49821,17 @@
"kind": "input-objects",
"href": "/graphql/reference/input-objects#projectv2itemorder"
}
},
{
"name": "query",
"defaultValue": "",
"description": "<p>Search query for filtering items.</p>",
"type": {
"name": "String",
"id": "string",
"kind": "scalars",
"href": "/graphql/reference/scalars#string"
}
}
]
},
Expand Down
5 changes: 5 additions & 0 deletions src/graphql/data/ghec/schema.docs.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -37388,6 +37388,11 @@ type ProjectV2 implements Closable & Node & Updatable {
Ordering options for project v2 items returned from the connection
"""
orderBy: ProjectV2ItemOrder = {field: POSITION, direction: ASC}

"""
Search query for filtering items
"""
query: String = ""
): ProjectV2ItemConnection!

"""
Expand Down
11 changes: 11 additions & 0 deletions src/graphql/data/ghec/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -49821,6 +49821,17 @@
"kind": "input-objects",
"href": "/graphql/reference/input-objects#projectv2itemorder"
}
},
{
"name": "query",
"defaultValue": "",
"description": "<p>Search query for filtering items.</p>",
"type": {
"name": "String",
"id": "string",
"kind": "scalars",
"href": "/graphql/reference/scalars#string"
}
}
]
},
Expand Down
Loading
Loading