1
0
mirror of synced 2025-12-19 18:10:59 -05:00

rai review enforcement (#47237)

Co-authored-by: Peter Bengtsson <peterbe@github.com>
This commit is contained in:
Rachael Sewell
2023-12-18 14:52:31 -08:00
committed by GitHub
parent a0b43ecea2
commit 117caeaa9c
9 changed files with 199 additions and 80 deletions

14
.github/CODEOWNERS vendored
View File

@@ -14,16 +14,4 @@ src/ghes-releases/lib/enterprise-dates.json @github/docs-content-enterprise
content/actions/deployment/security-hardening-your-deployments/** @github/oidc
# RAI - CELA
data/reusables/copilot/about-copilot-chat.md @github/legal-product
content/copilot/github-copilot-in-the-cli/about-github-copilot-in-the-cli.md @github/legal-product
content/code-security/secret-scanning/about-the-regular-expression-generator-for-custom-patterns @github/legal-product
data/reusables/secret-scanning/beta-custom-pattern-regular-expression-generator.md @github/legal-product
content/code-security/secret-scanning/about-the-detection-of-generic-secrets-with-secret-scanning.md @github/legal-product
data/reusables/secret-scanning/generic-secret-detection-ai.md @github/legal-product
content/code-security/code-scanning/managing-code-scanning-alerts/about-autofix-for-codeql-code-scanning.md @github/legal-product
data/reusables/rai/ @github/legal-product
content/copilot/github-copilot-enterprise/copilot-pull-request-summaries/about-copilot-pull-request-summaries.md @github/legal-product
data/reusables/rai/** @github/legal-product

73
.github/workflows/codeowners-legal.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
name: Codeowners - Legal
# **What it does**: Enforces reviews of Responsible AI (RAI) content by the GitHub legal team. Because RAI content can live anywhere in the content directory, it becomes a maintenance problem to use CODEOWNERS to enforce review on each article.
# **Why we have it**: RAI content must be reviewed by the GitHub legal team.
# **Who does it impact**: Content writers and the GitHub legal team.
on:
pull_request:
types:
- edited
- opened
- ready_for_review
- reopened
- synchronize
paths:
- 'content/**'
permissions:
contents: read
pull-requests: write
jobs:
codeowners-legal:
if: >-
${{ github.repository == 'github/docs-internal' &&
!github.event.pull_request.draft &&
github.event.pull_request.head.ref != 'repo-sync' }}
runs-on: ubuntu-latest
steps:
- name: Get files changed
uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
id: filter
with:
# Base branch used to get changed files
base: 'main'
# Enables setting an output in the format in `${FILTER_NAME}_files
# with the names of the matching files formatted as JSON array
list-files: json
# Returns list of changed files matching each filter
filters: |
rai:
- 'content/**'
- name: Check out repo
if: ${{ steps.filter.outputs.rai}}
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- name: Check content type
id: checkContentType
if: ${{ steps.filter.outputs.rai}}
run: npm run check-content-type
env:
FILE_PATHS_CONTENT_TYPES: ${{ steps.filter.outputs.rai_files }}
CONTENT_TYPE: 'rai'
- name: Add Legal team as a reviewer
if: ${{ steps.checkContentType.outputs.contentType }}
env:
# The GH CLI uses a slightly different env name for
# the token than the GITHUB_TOKEN used by actions
GH_TOKEN: ${{ github.token }}
PR: ${{ github.event.pull_request.html_url }}
run: |
has_reviewer=$(
gh pr view $PR --json reviews |
jq 'any(.reviews[]; select(length > 0))'
)
if ! $has_reviewer
then
gh pr edit $PR --add-reviewer github/legal-product
fi

View File

@@ -7,19 +7,6 @@ name: Check unallowed file changes
on:
# Needed in lieu of `pull_request` so that PRs from a fork can be notified of unallowed changes.
pull_request_target:
paths:
- '.devcontainer/**'
- '.github/workflows/**'
- '.github/CODEOWNERS'
- 'assets/fonts/**'
- 'data/graphql/**'
- 'Dockerfile*'
- 'src/*/scripts/**'
- 'src/**.json'
- 'src/workflows/**'
- 'lib/redirects/**'
- 'package*.json'
- 'content/actions/deployment/security-hardening-your-deployments/**'
permissions:
contents: read
@@ -35,6 +22,9 @@ jobs:
}}
runs-on: ubuntu-latest
steps:
- name: Check out repo
uses: actions/checkout@3df4ab11eba7bda6032a0b82a6bb43b11571feac # v4.0.0
- name: Get files changed
uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50
id: filter
@@ -47,61 +37,16 @@ jobs:
list-files: json
# Returns list of changed files matching each filter
filters: |
openapi:
- 'src/rest/data/**'
notAllowed:
- '.devcontainer/**'
- '.github/workflows/**'
- '.github/CODEOWNERS'
- 'assets/fonts/**'
- 'data/graphql/**'
- 'Dockerfile*'
- 'src/*/scripts/**'
- 'src/**.json'
- 'src/workflows/**'
- 'lib/redirects/**'
- 'package*.json'
- 'content/actions/deployment/security-hardening-your-deployments/**'
filters: 'src/workflows/unallowed-contribution-filters.yml'
# When there are changes to files we can't accept, leave a comment
# explaining this to the PR author
- name: "Comment about changes we can't accept"
if: ${{ steps.filter.outputs.notAllowed }}
uses: actions/github-script@e69ef5462fd455e02edcaf4dd7708eda96b9eda0
with:
script: |
const badFilesArr = [
'.devcontainer/**',
'.github/workflows/**',
'.github/CODEOWNERS',
'assets/fonts/**',
'data/graphql/**',
'Dockerfile*',
'src/*/scripts/**',
'src/**.json',
'src/workflows/**',
'lib/redirects/**',
'package*.json',
'content/actions/deployment/security-hardening-your-deployments/**',
]
const badFiles = badFilesArr.join('\n')
let reviewMessage = `👋 Hey there spelunker. It looks like you've modified some files that we can't accept as contributions. The complete list of files we can't accept are:\n${badFiles}\n\nYou'll need to revert all of the files you changed in that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit-in-github-desktop) or \`git checkout origin/main <file name>\`. Once you get those files reverted, we can continue with the review process. :octocat:`
let workflowFailMessage = "It looks like you've modified some files that we can't accept as contributions."
try {
createdComment = await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.number,
body: reviewMessage,
})
workflowFailMessage = `${workflowFailMessage} Please see ${createdComment.data.html_url} for details.`
} catch(err) {
console.log("Error creating comment.", err)
}
core.setFailed(workflowFailMessage)
if: ${{ steps.filter.outputs.notAllowed || steps.filter.outputs.contentTypes}}
run: npm run unallowed-contributions
env:
REPO_OWNER_AND_NAME: ${{ github.repository }}
PR_NUMBER: ${{ github.event.number }}
FILE_PATHS_NOT_ALLOWED: ${{ steps.filter.outputs.notAllowed_files }}
FILE_PATHS_CONTENT_TYPES: ${{ steps.filter.outputs.contentTypes_files }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -19,6 +19,7 @@
"analyze-text": "node src/search/scripts/analyze-text.js",
"archive-version": "node src/ghes-releases/scripts/archive-version.js",
"build": "next build",
"check-content-type": "node src/workflows/check-content-type.js",
"check-github-github-links": "node src/links/scripts/check-github-github-links.js",
"copy-fixture-data": "node src/tests/scripts/copy-fixture-data.js",
"create-translation-health-report": "node src/languages/scripts/create-translation-health-report.js",
@@ -63,6 +64,7 @@
"test-watch": "cross-env NODE_OPTIONS=--experimental-vm-modules jest --watch --notify --notifyMode=change --coverage",
"toggle-ghae-feature-flags": "node src/versions/scripts/toggle-ghae-feature-flags.js",
"tsc": "tsc --noEmit",
"unallowed-contributions": "node src/workflows/unallowed-contributions.js",
"update-data-and-image-paths": "node src/early-access/scripts/update-data-and-image-paths.js",
"update-internal-links": "node src/links/scripts/update-internal-links.js",
"validate-asset-images": "node src/assets/scripts/validate-asset-images.js",

View File

@@ -15,6 +15,11 @@ const secureFiles = [
path: 'content/actions/deployment/security-hardening-your-deployments/**',
requiredCodeOwner: 'github/oidc',
},
{
name: 'RAI transparency note reusable directory',
path: 'data/reusables/rai',
requiredCodeOwner: 'github/legal-product',
},
]
const codeOwnersFile = await fs.readFile('.github/CODEOWNERS', 'utf8')

View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
import coreLib from '@actions/core'
import { checkContentType } from '#src/workflows/fm-utils.js'
const { FILE_PATHS_CONTENT_TYPES, CONTENT_TYPE } = process.env
main()
async function main() {
const filePaths = JSON.parse(FILE_PATHS_CONTENT_TYPES)
const containsRai = checkContentType(filePaths, CONTENT_TYPE)
if (containsRai.length === 0) {
coreLib.setOutput('contentType', false)
} else {
coreLib.setOutput('contentType', true)
}
}

16
src/workflows/fm-utils.js Normal file
View File

@@ -0,0 +1,16 @@
import { readFileSync } from 'fs'
import matter from 'gray-matter'
// Filters out files from a list of filePaths
// that have a type property in their frontmatter
// where the type value matches the type argument
export function checkContentType(filePaths, type) {
const unallowedChangedFiles = []
for (const filePath of filePaths) {
const { data } = matter(readFileSync(filePath, 'utf8'))
if (data.type === type) {
unallowedChangedFiles.push(filePath)
}
}
return unallowedChangedFiles
}

View File

@@ -0,0 +1,15 @@
notAllowed:
- '.devcontainer/**'
- '.github/workflows/**'
- '.github/CODEOWNERS'
- 'assets/fonts/**'
- 'data/graphql/**'
- 'Dockerfile*'
- 'src/*/scripts/**'
- 'src/**.json'
- 'src/workflows/**'
- 'lib/redirects/**'
- 'package*.json'
- 'content/actions/deployment/security-hardening-your-deployments/**'
contentTypes:
- 'content/**'

View File

@@ -0,0 +1,56 @@
#!/usr/bin/env node
import coreLib from '@actions/core'
import { readFileSync } from 'fs'
import yaml from 'js-yaml'
import { checkContentType } from '#src/workflows/fm-utils.js'
import github from '#src/workflows/github.js'
const core = coreLib
const octokit = github()
const { PR_NUMBER, REPO_OWNER_AND_NAME, FILE_PATHS_NOT_ALLOWED, FILE_PATHS_CONTENT_TYPES } =
process.env
const [owner, repo] = REPO_OWNER_AND_NAME.split('/')
const filters = yaml.load(readFileSync('src/workflows/unallowed-contribution-filters.yml', 'utf8'))
main()
async function main() {
// Files in the diff that match specific paths we don't allow
const unallowedChangedFiles = [...JSON.parse(FILE_PATHS_NOT_ALLOWED)]
// Any changes to a file in the content directory could potentially
// have `type: rai` so each changed content file's frontmatter needs
// to be checked.
unallowedChangedFiles.push(
...(await checkContentType(JSON.parse(FILE_PATHS_CONTENT_TYPES), 'rai')),
)
if (unallowedChangedFiles.length === 0) return
// Format into Markdown bulleted list to use in the PR comment
const listUnallowedChangedFiles = unallowedChangedFiles.map((file) => `\n - ${file}`).join('')
const listUnallowedFiles = filters.notAllowed.map((file) => `\n - ${file}`).join('')
const reviewMessage = `👋 Hey there spelunker. It looks like you've modified some files that we can't accept as contributions:${listUnallowedChangedFiles}\n\nYou'll need to revert all of the files you changed that match that list using [GitHub Desktop](https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/managing-commits/reverting-a-commit-in-github-desktop) or \`git checkout origin/main <file name>\`. Once you get those files reverted, we can continue with the review process. :octocat:\n\nThe complete list of files we can't accept are:${listUnallowedFiles}\n\nWe also can't accept contributions to files in the content directory with frontmatter \`type: rai\`.`
let workflowFailMessage =
"It looks like you've modified some files that we can't accept as contributions."
let createdComment
try {
createdComment = await octokit.rest.issues.createComment({
owner,
repo,
issue_number: PR_NUMBER,
body: reviewMessage,
})
workflowFailMessage = `${workflowFailMessage} Please see ${createdComment.data.html_url} for details.`
} catch (err) {
console.log('Error creating comment.', err)
}
core.setFailed(workflowFailMessage)
}