From ced20bab7d8c317a05823ebe804a51bc741cdad8 Mon Sep 17 00:00:00 2001 From: Mike Mwanje <41787587+123MwanjeMike@users.noreply.github.com> Date: Sat, 10 Jul 2021 17:42:24 +0300 Subject: [PATCH 01/24] Update migrating-oauth-apps-to-github-apps.md These changes are to include the 'Delete OAuth App' step in 'Migrating OAuth Apps to GitHub Apps' --- .../migrating-oauth-apps-to-github-apps.md | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/content/developers/apps/getting-started-with-apps/migrating-oauth-apps-to-github-apps.md b/content/developers/apps/getting-started-with-apps/migrating-oauth-apps-to-github-apps.md index 408e854582..a450696f00 100644 --- a/content/developers/apps/getting-started-with-apps/migrating-oauth-apps-to-github-apps.md +++ b/content/developers/apps/getting-started-with-apps/migrating-oauth-apps-to-github-apps.md @@ -40,7 +40,8 @@ These guidelines assume that you have a registered OAuth App{% ifversion fpt %} 1. [Understand the different methods of authentication](#understand-the-different-methods-of-authentication) 1. [Direct users to install your GitHub App on repositories](#direct-users-to-install-your-github-app-on-repositories) 1. [Remove any unnecessary repository hooks](#remove-any-unnecessary-repository-hooks) -1. [Encourage users to revoke access to your OAuth app](#encourage-users-to-revoke-access-to-your-oauth-app) +1. [Encourage users to revoke access to your OAuth App](#encourage-users-to-revoke-access-to-your-oauth-app) +1. [Delete the OAuth App](#delete-the-oauth-app) ### Review the available API endpoints for GitHub Apps @@ -100,4 +101,8 @@ Once your GitHub App has been installed on a repository, you should remove any u ### Encourage users to revoke access to your OAuth app -As your GitHub App installation base grows, consider encouraging your users to revoke access to the legacy OAuth integration. For more information, see [Authorizing OAuth Apps](/github/authenticating-to-github/keeping-your-account-and-data-secure/authorizing-oauth-apps) +As your GitHub App installation base grows, consider encouraging your users to revoke access to the legacy OAuth integration. For more information, see "[Authorizing OAuth Apps](/github/authenticating-to-github/keeping-your-account-and-data-secure/authorizing-oauth-apps)." + +### Delete the OAuth App + +To avoid abuse of the OAuth App's credentials, consider deleting the OAuth App. This action will also revoke all of the OAuth App's remaining authorizations. For more information, see "[Deleting an OAuth App](/developers/apps/managing-oauth-apps/deleting-an-oauth-app)." From 856d2cdf0d2b21fb28a5f55b7e721dafb6647644 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Sat, 26 Mar 2022 16:22:00 +0100 Subject: [PATCH 02/24] issue templates: remove preview_only attribute Remove the `preview_only` attribute because it doesn't exist. Example: https://github.com/ngrx/platform/blob/a812382d4a0b60c97f5141053a31d5880c0159c2/.github/ISSUE_TEMPLATE/bug-report.yml --- .../common-validation-errors-when-creating-issue-forms.md | 6 ------ 1 file changed, 6 deletions(-) diff --git a/content/communities/using-templates-to-encourage-useful-issues-and-pull-requests/common-validation-errors-when-creating-issue-forms.md b/content/communities/using-templates-to-encourage-useful-issues-and-pull-requests/common-validation-errors-when-creating-issue-forms.md index 19f3b86bcf..4ecbfdafc5 100644 --- a/content/communities/using-templates-to-encourage-useful-issues-and-pull-requests/common-validation-errors-when-creating-issue-forms.md +++ b/content/communities/using-templates-to-encourage-useful-issues-and-pull-requests/common-validation-errors-when-creating-issue-forms.md @@ -311,7 +311,6 @@ Errors with `body` will be prefixed with `body[i]` where `i` represents the zero body: - attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false ``` The error can be fixed by adding the key `type` with a valid input type as the value. For the available `body` input types and their syntaxes, see "[Syntax for {% data variables.product.prodname_dotcom %}'s form schema](/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema#keys)." @@ -321,7 +320,6 @@ body: - type: markdown attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false ``` ## Body[i]: `x` is not a valid input type @@ -337,7 +335,6 @@ body: - type: x attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false ``` The error can be fixed by changing `x` to one of the valid types. @@ -347,7 +344,6 @@ body: - type: markdown attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false ``` ## Body[i]: required attribute key `value` is missing @@ -363,7 +359,6 @@ body: - type: markdown attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false - type: markdown ``` @@ -374,7 +369,6 @@ body: - type: markdown attributes: value: "Thanks for taking the time to fill out this bug! If you need real-time help, join us on Discord." - preview_only: false - type: markdown attributes: value: "This is working now!" From 9a0cb726ad555efd7448d91d17b8fba0d00fe217 Mon Sep 17 00:00:00 2001 From: blue-jam Date: Wed, 4 May 2022 09:04:51 +0900 Subject: [PATCH 03/24] Typo: make container name consistent --- .../working-with-the-container-registry.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/packages/working-with-a-github-packages-registry/working-with-the-container-registry.md b/content/packages/working-with-a-github-packages-registry/working-with-the-container-registry.md index 48ed86228b..19ce6bdeba 100644 --- a/content/packages/working-with-a-github-packages-registry/working-with-the-container-registry.md +++ b/content/packages/working-with-a-github-packages-registry/working-with-the-container-registry.md @@ -35,14 +35,14 @@ When installing or publishing a Docker image, the {% data variables.product.prod ## Pushing container images -This example pushes the latest version of `IMAGE-NAME`. +This example pushes the latest version of `IMAGE_NAME`. ```shell $ docker push ghcr.io/OWNER/IMAGE_NAME:latest ``` This example pushes the `2.5` version of the image. ```shell - $ docker push ghcr.io/OWNER/IMAGE-NAME:2.5 + $ docker push ghcr.io/OWNER/IMAGE_NAME:2.5 ``` When you first publish a package, the default visibility is private. To change the visibility or set access permissions, see "[Configuring a package's access control and visibility](/packages/learn-github-packages/configuring-a-packages-access-control-and-visibility)." From 9fad5e6b7341a318cc3b74f3ccf75cd231f4d36b Mon Sep 17 00:00:00 2001 From: Lavanya Gupta Date: Wed, 11 May 2022 23:27:43 -0400 Subject: [PATCH 04/24] Incorrect Step 7 (adding upstream) Instead of `YOUR_USERNAME` it should be `ORIGINAL_OWNER`. --- content/get-started/quickstart/fork-a-repo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/get-started/quickstart/fork-a-repo.md b/content/get-started/quickstart/fork-a-repo.md index 4f88dbce63..08dad271e6 100644 --- a/content/get-started/quickstart/fork-a-repo.md +++ b/content/get-started/quickstart/fork-a-repo.md @@ -154,7 +154,7 @@ When you fork a project in order to propose changes to the original repository, 6. Type `git remote add upstream`, and then paste the URL you copied in Step 3 and press **Enter**. It will look like this: ```shell - $ git remote add upstream https://{% data variables.command_line.codeblock %}/YOUR_USERNAME/Spoon-Knife.git + $ git remote add upstream https://{% data variables.command_line.codeblock %}/ORIGINAL_OWNER/Spoon-Knife.git ``` 7. To verify the new upstream repository you have specified for your fork, type `git remote -v` again. You should see the URL for your fork as `origin`, and the URL for the original repository as `upstream`. From 256e5d0e3d5b944130057d426cb23091358a9396 Mon Sep 17 00:00:00 2001 From: Christos Karampatzakis <63047451+ckarampa@users.noreply.github.com> Date: Thu, 12 May 2022 10:56:40 +0300 Subject: [PATCH 05/24] Typo in adding upstream repository. --- content/get-started/quickstart/fork-a-repo.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/get-started/quickstart/fork-a-repo.md b/content/get-started/quickstart/fork-a-repo.md index 4f88dbce63..08dad271e6 100644 --- a/content/get-started/quickstart/fork-a-repo.md +++ b/content/get-started/quickstart/fork-a-repo.md @@ -154,7 +154,7 @@ When you fork a project in order to propose changes to the original repository, 6. Type `git remote add upstream`, and then paste the URL you copied in Step 3 and press **Enter**. It will look like this: ```shell - $ git remote add upstream https://{% data variables.command_line.codeblock %}/YOUR_USERNAME/Spoon-Knife.git + $ git remote add upstream https://{% data variables.command_line.codeblock %}/ORIGINAL_OWNER/Spoon-Knife.git ``` 7. To verify the new upstream repository you have specified for your fork, type `git remote -v` again. You should see the URL for your fork as `origin`, and the URL for the original repository as `upstream`. From 986e2aa0c1f6321e3bc40e047793e1940c7268d2 Mon Sep 17 00:00:00 2001 From: Josh Soref <2119212+jsoref@users.noreply.github.com> Date: Mon, 23 May 2022 18:04:27 -0400 Subject: [PATCH 06/24] Remove `Recent` from `Using global node IDs` --- content/graphql/guides/using-global-node-ids.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/content/graphql/guides/using-global-node-ids.md b/content/graphql/guides/using-global-node-ids.md index f91f917811..813f36d385 100644 --- a/content/graphql/guides/using-global-node-ids.md +++ b/content/graphql/guides/using-global-node-ids.md @@ -12,7 +12,7 @@ topics: - API --- -You can access most objects in GitHub (users, issues, pull requests, etc.) using either the REST API or the GraphQL API. With a [recent update](https://developer.github.com/changes/2017-12-19-graphql-node-id/), you can find the **global node ID** of many objects from within the REST API and use these IDs in your GraphQL operations. +You can access most objects in GitHub (users, issues, pull requests, etc.) using either the REST API or the GraphQL API. You can find the **global node ID** of many objects from within the REST API and use these IDs in your GraphQL operations. For more information, see "[Preview GraphQL API v4 Node IDs in REST API v3 resources](https://developer.github.com/changes/2017-12-19-graphql-node-id/)." {% note %} From cb2825aba8b60f9853f18dae6b4f2658ef1e284a Mon Sep 17 00:00:00 2001 From: de-oz <101826623+de-oz@users.noreply.github.com> Date: Tue, 24 May 2022 01:55:52 +0300 Subject: [PATCH 07/24] Fix link text and missing period --- .../about-github-campus-program.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-program.md b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-program.md index e99cae3fc8..1fe27aeab7 100644 --- a/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-program.md +++ b/content/education/explore-the-benefits-of-teaching-and-learning-with-github-education/use-github-at-your-educational-institution/about-github-campus-program.md @@ -19,7 +19,7 @@ shortTitle: GitHub Campus Program - Exclusive access to new features, GitHub Education-specific swag, and free developer tools from {% data variables.product.prodname_dotcom %} partners - Automated access to premium {% data variables.product.prodname_education %} features, like the {% data variables.product.prodname_student_pack %} -To read about how GitHub is used by educators, see [GitHub Education stories.](https://education.github.com/stories) +To read about how GitHub is used by educators, see [GitHub Education stories](https://education.github.com/stories). ## {% data variables.product.prodname_campus_program %} terms and conditions @@ -32,7 +32,7 @@ To read about how GitHub is used by educators, see [GitHub Education stories.](h - New organizations in your enterprise are automatically added to your enterprise account. To add organizations that existed before your school joined the {% data variables.product.prodname_campus_program %}, please contact [GitHub Education Support](https://support.github.com/contact/education). For more information about administrating your enterprise, see the [enterprise administrators documentation](/admin). New organizations in your enterprise are automatically added to your enterprise account. To add organizations that existed before your school joined the {% data variables.product.prodname_campus_program %}, please contact GitHub Education Support. -To read more about {% data variables.product.prodname_dotcom %}'s privacy practices, see ["Global Privacy Practices"](/github/site-policy/global-privacy-practices) +To read more about {% data variables.product.prodname_dotcom %}'s privacy practices, see ["Global Privacy Practices"](/github/site-policy/global-privacy-practices). ## {% data variables.product.prodname_campus_program %} Application Eligibility From e7c97b0ffb628b4c0b8f180b1f73027aa2a1faf5 Mon Sep 17 00:00:00 2001 From: Daniel Adams Date: Tue, 24 May 2022 14:01:40 +0200 Subject: [PATCH 08/24] Update theme context docs (#27909) * Update theme context docs * Update example description * Update content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md * Update content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md * Update content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md Co-authored-by: hubwriter --- .../basic-writing-and-formatting-syntax.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md b/content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md index 8abb878595..aaecc97fdc 100644 --- a/content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md +++ b/content/get-started/writing-on-github/getting-started-with-writing-and-formatting-on-github/basic-writing-and-formatting-syntax.md @@ -148,14 +148,19 @@ For more information, see "[Relative Links](#relative-links)." {% ifversion fpt or ghec or ghes > 3.3 or ghae-issue-5559 %} ### Specifying the theme an image is shown to -You can specify the theme an image is displayed to by appending `#gh-dark-mode-only` or `#gh-light-mode-only` to the end of an image URL, in Markdown. +You can specify the theme an image is displayed for in Markdown by using the HTML `` element in combination with the `prefers-color-scheme` media feature. We distinguish between light and dark color modes, so there are two options available. You can use these options to display images optimized for dark or light backgrounds. This is particularly helpful for transparent PNG images. -We distinguish between light and dark color modes, so there are two options available. You can use these options to display images optimized for dark or light backgrounds. This is particularly helpful for transparent PNG images. +For example, the following code displays a sun image for light themes and a moon for dark themes: -| Context | URL | -|--------|--------| -| Dark Theme | `![GitHub Light](https://github.com/github-light.png#gh-dark-mode-only)` | -| Light Theme | `![GitHub Dark](https://github.com/github-dark.png#gh-light-mode-only)` | +```HTML + + + + Shows an illustrated sun in light color mode and a moon with stars in dark color mode. + +``` + +The old method of specifying images based on the theme, by using a fragment appended to the URL (`#gh-dark-mode-only` or `#gh-light-mode-only`), is deprecated and will be removed in favor of the new method described above. {% endif %} ## Lists From cda2525c714ed3f7da2a9ca2e36d6e65995b0a2b Mon Sep 17 00:00:00 2001 From: Sho Mizutani Date: Tue, 24 May 2022 21:58:39 +0900 Subject: [PATCH 09/24] Correct GitHub Actions artifact and log retention policy for GHES (#27935) --- .../reusables/actions/about-artifact-log-retention.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/data/reusables/actions/about-artifact-log-retention.md b/data/reusables/actions/about-artifact-log-retention.md index 6f73937277..5cfff1f2ff 100644 --- a/data/reusables/actions/about-artifact-log-retention.md +++ b/data/reusables/actions/about-artifact-log-retention.md @@ -1,9 +1,12 @@ -By default, the artifacts and log files generated by workflows are retained for 90 days before they are automatically deleted. You can adjust the retention period, depending on the type of repository: +By default, the artifacts and log files generated by workflows are retained for 90 days before they are automatically deleted. + +{%- ifversion fpt or ghec %} +You can adjust the retention period, depending on the type of repository: -{%- ifversion fpt or ghec or ghes %} - For public repositories: you can change this retention period to anywhere between 1 day or 90 days. +- For private{% ifversion ghec %} and internal{% endif %} repositories: you can change this retention period to anywhere between 1 day or 400 days. +{%- else %} +You can change this retention period to anywhere between 1 day or 400 days. {%- endif %} -- For private{% ifversion ghec or ghes or ghae %} and internal{% endif %} repositories: you can change this retention period to anywhere between 1 day or 400 days. - When you customize the retention period, it only applies to new artifacts and log files, and does not retroactively apply to existing objects. For managed repositories and organizations, the maximum retention period cannot exceed the limit set by the managing organization or enterprise. From 5cf1d64c0bb092fdf9b2aa56c98261b9f3be13fb Mon Sep 17 00:00:00 2001 From: Laura Coursen Date: Tue, 24 May 2022 08:12:28 -0500 Subject: [PATCH 10/24] Enterprise bug fixes for the week of 2022-05-16 (#27868) --- .../tls-protocol-support.png | Bin 32462 -> 18701 bytes ...-audit-log-activity-for-your-enterprise.md | 4 +++- ...ing-the-audit-log-for-your-organization.md | 3 +++ ...he-visibility-of-your-github-pages-site.md | 6 ++++-- .../audit_log/git-events-export-limited.md | 7 +++++++ .../pages/about-private-publishing.md | 2 +- 6 files changed, 18 insertions(+), 4 deletions(-) create mode 100644 data/reusables/audit_log/git-events-export-limited.md diff --git a/assets/images/enterprise/management-console/tls-protocol-support.png b/assets/images/enterprise/management-console/tls-protocol-support.png index 70239703ea521dee85aad84960bc7f242139ef3d..a88f35d5f255b9183fb29136c1898233ce8c3563 100644 GIT binary patch literal 18701 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 GgeCwr6=56z literal 32462 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 KMNUMnLSTY8CF5`a diff --git a/content/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/exporting-audit-log-activity-for-your-enterprise.md b/content/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/exporting-audit-log-activity-for-your-enterprise.md index f861abb7f6..1d680a8e72 100644 --- a/content/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/exporting-audit-log-activity-for-your-enterprise.md +++ b/content/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/exporting-audit-log-activity-for-your-enterprise.md @@ -16,7 +16,9 @@ topics: You can export the audit log by downloading a JSON or CSV file from your enterprise on {% data variables.product.product_name %}. When you export audit log events, you can query by one or more of these supported qualifiers to filter for specific log events to export. For more information about search qualifiers, see "[Search based on the action performed](/admin/monitoring-activity-in-your-enterprise/reviewing-audit-logs-for-your-enterprise/searching-the-audit-log-for-your-enterprise#search-based-on-the-action-performed)." -You can export Git events data by downloading a JSON file from your enterprise audit log. Unlike audit log data, you cannot query for specific Git events to filter and export in the audit log user interface. +You can export Git events data by downloading a JSON file from your enterprise audit log. Unlike audit log data, you cannot query for specific Git events to filter and export in the audit log user interface. + +{% data reusables.audit_log.git-events-export-limited %} {% data reusables.audit_log.exported-log-keys-and-values %} diff --git a/content/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization.md b/content/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization.md index 401665144c..af66454765 100644 --- a/content/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization.md +++ b/content/organizations/keeping-your-organization-secure/managing-security-settings-for-your-organization/reviewing-the-audit-log-for-your-organization.md @@ -127,6 +127,9 @@ Using the qualifier `country`, you can filter events in the audit log based on t ## Exporting the audit log {% data reusables.audit_log.export-log %} + +{% data reusables.audit_log.git-events-export-limited %} + {% data reusables.audit_log.exported-log-keys-and-values %} {% endif %} diff --git a/content/pages/getting-started-with-github-pages/changing-the-visibility-of-your-github-pages-site.md b/content/pages/getting-started-with-github-pages/changing-the-visibility-of-your-github-pages-site.md index 93bdcf0bf1..a6bfddb0d8 100644 --- a/content/pages/getting-started-with-github-pages/changing-the-visibility-of-your-github-pages-site.md +++ b/content/pages/getting-started-with-github-pages/changing-the-visibility-of-your-github-pages-site.md @@ -11,13 +11,15 @@ shortTitle: Change visibility of site ## About access control for {% data variables.product.prodname_pages %} sites -With access control for {% data variables.product.prodname_pages %}, you can restrict access to your {% data variables.product.prodname_pages %} site by publishing the site privately. A privately published site can only be accessed by people with read access to the repository the site is published from. You can use privately published sites to share your internal documentation or knowledge base with members of your enterprise. +With access control for {% data variables.product.prodname_pages %}, you can restrict access to your project site by publishing the site privately. A privately published site can only be accessed by people with read access to the repository the site is published from. You can use privately published sites to share your internal documentation or knowledge base with members of your enterprise. {% data reusables.pages.privately-publish-ghec-only %} If your enterprise uses {% data variables.product.prodname_emus %}, access control is not available, and all {% data variables.product.prodname_pages %} sites are only accessible to other enterprise members. For more information about {% data variables.product.prodname_emus %}, see "[About {% data variables.product.prodname_pages %}](/pages/getting-started-with-github-pages/about-github-pages#limitations-for-enterprise-managed-users)." -If your organization uses {% data variables.product.prodname_ghe_cloud %} without {% data variables.product.prodname_emus %}, you can choose to publish your sites privately or publicly to anyone on the internet. Access control is available for project sites that are published from a private or internal repository that are owned by the organization. You cannot manage access control for an organization site. For more information about the types of {% data variables.product.prodname_pages %} sites, see "[About {% data variables.product.prodname_pages %}](/pages/getting-started-with-github-pages/about-github-pages#types-of-github-pages-sites)." +If your organization uses {% data variables.product.prodname_ghe_cloud %} without {% data variables.product.prodname_emus %}, you can choose to publish your project sites privately or publicly to anyone on the internet. + +Access control is available for project sites that are published from a private or internal repository that are owned by the organization. You cannot manage access control for an organization site. For more information about the types of {% data variables.product.prodname_pages %} sites, see "[About {% data variables.product.prodname_pages %}](/pages/getting-started-with-github-pages/about-github-pages#types-of-github-pages-sites)." ## About subdomains for privately published sites diff --git a/data/reusables/audit_log/git-events-export-limited.md b/data/reusables/audit_log/git-events-export-limited.md new file mode 100644 index 0000000000..aa63be28a5 --- /dev/null +++ b/data/reusables/audit_log/git-events-export-limited.md @@ -0,0 +1,7 @@ +{% ifversion ghec %} +{% note %} + +**Note:** When you export Git events, events that were initiated via the web browser or the REST or GraphQL APIs are not included. For example, when a user merges a pull request in the web browser, changes are pushed to the base branch, but the Git event for that push is not included in the export. + +{% endnote %} +{% endif %} \ No newline at end of file diff --git a/data/reusables/pages/about-private-publishing.md b/data/reusables/pages/about-private-publishing.md index f0018718a9..34ef179fd6 100644 --- a/data/reusables/pages/about-private-publishing.md +++ b/data/reusables/pages/about-private-publishing.md @@ -1,5 +1,5 @@ {% ifversion fpt %} You can create {% data variables.product.prodname_pages %} sites that are publicly available on the internet. Organizations that use {% data variables.product.prodname_ghe_cloud %} can also publish sites privately by managing access control for the site. {% elsif ghec %} -Unless your enterprise uses {% data variables.product.prodname_emus %}, you can choose to publish sites publicly or privately by managing access control for the site. +Unless your enterprise uses {% data variables.product.prodname_emus %}, you can choose to publish project sites publicly or privately by managing access control for the site. {% endif %} \ No newline at end of file From fac6d5a85c9c8215c89e2509a6861ed31f3d75e3 Mon Sep 17 00:00:00 2001 From: Mike Surowiec Date: Tue, 24 May 2022 09:49:19 -0500 Subject: [PATCH 11/24] feat: remove sigsci (#27932) --- .eslintrc.js | 2 +- docker-compose.prod.tmpl.yaml | 10 - lib/sigsci.js | 681 ---------------------------------- middleware/index.js | 14 - 4 files changed, 1 insertion(+), 706 deletions(-) delete mode 100644 lib/sigsci.js diff --git a/.eslintrc.js b/.eslintrc.js index 4819d950ce..2e7e063533 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -13,7 +13,7 @@ module.exports = { babelOptions: { configFile: './.babelrc' }, sourceType: 'module', }, - ignorePatterns: ['tmp/*', '!/.*', '/.next/', 'script/bookmarklets/*', 'lib/sigsci.js'], + ignorePatterns: ['tmp/*', '!/.*', '/.next/', 'script/bookmarklets/*'], rules: { 'import/no-extraneous-dependencies': ['error', { packageDir: '.' }], }, diff --git a/docker-compose.prod.tmpl.yaml b/docker-compose.prod.tmpl.yaml index e27c767445..e046064bfe 100644 --- a/docker-compose.prod.tmpl.yaml +++ b/docker-compose.prod.tmpl.yaml @@ -19,7 +19,6 @@ services: HEROKU_PRODUCTION_APP: true PORT: 4000 DD_AGENT_HOST: datadog-agent - SIGSCI_RPC_ADDRESS: sigsci-agent:8000 depends_on: - datadog-agent restart: always @@ -32,12 +31,3 @@ services: DD_API_KEY: ${DD_API_KEY} DD_AGENT_HOST: datadog-agent DD_HISTOGRAM_PERCENTILES: 0.99 0.95 0.50 - - sigsci-agent: - image: signalsciences/sigsci-agent - ports: - - '8000:8000' - environment: - SIGSCI_RPC_ADDRESS: 0.0.0.0:8000 - SIGSCI_ACCESSKEY: ${SIGSCI_ACCESSKEYID} - SIGSCI_SECRETACCESSKEY: ${SIGSCI_SECRETACCESSKEY} diff --git a/lib/sigsci.js b/lib/sigsci.js deleted file mode 100644 index 703d84a389..0000000000 --- a/lib/sigsci.js +++ /dev/null @@ -1,681 +0,0 @@ -/* - * NodeJS Module - * - * Copyright (c) 2019-2020 Signal Sciences Corp. - * - * Proprietary and Confidential - Do Not Distribute - * - */ - -/* jslint node: true */ -'use strict' - -/* jshint bitwise: true, curly: true, eqeqeq: true */ -/* jshint freeze: true, funcscope: true, futurehostile: true */ -/* jshint latedef: true, noarg: true, nocomma: true, nonbsp: true */ -/* jshint nonew: true, notypeof: true, singleGroups: true */ -/* jshint undef: true, unused: true */ -/* jshint asi:true */ - -import Session from 'msgpack5rpc' -import net from 'node:net' -import util from 'node:util' -import stream from 'node:stream' - -// default parameters -var defaultOptions = { - // path specifies the UDS to connect to the agent - path: '/var/run/sigsci.sock', - - // maxPostSize - if a POST body is larger than maxPostSize - // the post body is NOT sent to the agent. - maxPostSize: 100000, - - // socketTime - if the agent does not respond in this number of - // milliseconds, "fail open" and allow the request to pass - socketTimeout: 100 /* milliseconds */, - - // HTTP methods that can contain a body. Unlikely this needs to be - // changed. - bodyMethods: { - POST: true, - PUT: true, - PATCH: true, - }, - - // TK - anomalySize: 524288, - - // TK - anomalyDuration: 1000 /* milliseconds */, - - // Enable debug log - debug: false, - - // Inspect additional content types of body: ['text/plain','text/html'] - expectedContentTypes: [], - - // log function to use - log: function (msg) { - console.log(util.format('SIGSCI %s', msg)) - }, -} - -// Utility functinon to merge two objects into another. -// Used for setting default values. -// from http://stackoverflow.com/a/8625261 -var merge = function () { - var obj = {} - var i = 0 - var il = arguments.length - var key - for (; i < il; i++) { - for (key in arguments[i]) { - if (arguments[i].hasOwnProperty(key)) { - obj[key] = arguments[i][key] - } - } - } - return obj -} - -// rawHeadersToPairs converts a nodejs raw header list -// to a list of pairs expected in the protocol. -var rawHeadersToPairs = function (raw) { - var out = [] - var n = raw.length - for (var i = 0; i < n; i += 2) { - out.push([raw[i], raw[i + 1]]) - } - return out -} - -var headersToPairs = function (raw) { - var out = [] - for (var key in raw) { - out.push([key, raw[key]]) - } - return out -} - -var getRequestHeaders = function (req) { - // modern - if (req.rawHeaders) { - return rawHeadersToPairs(req.rawHeaders) - } - // old 0.10.X series - return headersToPairs(req.headers) -} - -var getPost = function (req, maxSize, bodyMethods, expectedContentTypes) { - // can this method even have a body? - if (bodyMethods[req.method] !== true) { - return false - } - - var contentLength = parseInt(req.headers['content-length']) - - // does content-length not exist or not make sense? - if (isNaN(contentLength) || contentLength <= 0) { - return false - } - - // too big? - if (contentLength >= maxSize) { - return false - } - - // something the agent can decode? - return isValidContentType(req, expectedContentTypes) -} - -var isValidContentType = function (req, expectedContentTypes) { - var contentType = ('' + req.headers['content-type']).toLowerCase() - - if ( - contentType.indexOf('application/x-www-form-urlencoded') !== -1 || - contentType.startsWith('multipart/form-data') || - contentType.startsWith('application/graphql') || - contentType.indexOf('json') !== -1 || - contentType.indexOf('javascript') !== -1 || - contentType.indexOf('xml') !== -1 - ) { - return true - } - - for (var i = 0; i < expectedContentTypes.length; i++) { - if (contentType.startsWith(expectedContentTypes[i])) { - return true - } - } - - if (req.rawHeaders) { - var headers = req.rawHeaders - for (var i = 0, count = 0; i < headers.length; i += 2) { - if (headers[i].toLowerCase() === 'content-type') { - if (++count > 1) { - return true - } - } - } - } - return false -} - -var isNotSpace = function (header) { - return header !== '' -} - -var isBlocking = function (responseCode) { - return responseCode >= 300 && responseCode <= 599 -} - -var isRedirect = function (responseCode) { - return responseCode >= 300 && responseCode <= 399 -} - -var splitHeader = function (line) { - var keyVal = line.split(':') - if (keyVal.length < 2) { - return [keyVal[0].trim(), ''] - } else { - return [keyVal[0].trim(), keyVal.splice(1).join(':').trim()] - } -} - -var getResponseHeaders = function (res) { - return (res._header || '').split('\r\n').filter(isNotSpace).map(splitHeader) -} - -var getRpcHeader = function (rpcResponse, header) { - var headers = rpcResponse.RequestHeaders - for (var i = 0; i < headers.length; i++) { - var entry = headers[i] - if (header === entry[0]) { - return entry[1] - } - } - return null -} - -var readPostBody = function (req, cb) { - // POST - async read - var postBody = [] - var fnOnData = function (chunk) { - // append the current chunk of data to the fullBody variable - postBody.push(chunk) - } - var fnOnEnd = function () { - setImmediate(function () { - // now we need to "push back" the postbody into a stream that - // so the raw application can continue to function no matter - // what - - // First remove the listeners we already set up - req.removeListener('data', fnOnData) - req.removeListener('end', fnOnEnd) - - // make new stream, copy it over into current request obj - var s = new stream.Readable() - s._read = function noop() {} - for (var attr in s) { - req[attr] = s[attr] - } - - // push in new body and EOF marker - postBody = Buffer.concat(postBody) - req.push(postBody) - req.push(null) - cb(postBody.toString()) - }) - } - - req.on('data', fnOnData) - req.on('end', fnOnEnd) -} - -const wafCode = { - WAF_CONNECT_ERROR: 'waf-connect-error', - WAF_CONNECT_TIMEOUT: 'waf-connect-timeout', - WAF_FAIL_OPEN: 'waf-fail-open', - WAF_OK: 'waf-ok', - WAF_BLOCKING: 'waf-blocking', - WAF_UNKNOWN: 'waf-unknown', -} - -function Sigsci(userOptions) { - this.options = merge(defaultOptions, userOptions) - - // Determine if we are UDS or TCP - // - // The default is to use UDS, so 'path' is set, and 'port' is unset. - // - // For TCP: - // 'port' must be specified - // 'host' is optional and defaults to 'localhost' - // - // For UDS: - // 'path' must be specified - // - // So: - // If 'port' is set after merge, then we are TCP, and - // delete the 'path' property to prevent node.js confusion. - // - // https://nodejs.org/api/net.html#net_socket_connect_options_connectlistener - // - if ('port' in this.options) { - delete this.options.path - } -} - -Sigsci.prototype.express = function () { - var self = this - return function (req, res, next) { - res.on('finish', function () { - onAfterResponse(req, res, self.options) - }) - middleware(req, res, self.options, function (wafResponse) { - var wafSignalCode = wafResponse.wafCode - var rpcResponse = wafResponse.response - if (shouldContinue(wafSignalCode)) { - next() - return - } else if (wafSignalCode == wafCode.WAF_BLOCKING) { - handleNativeBlocking(res, rpcResponse) - return - } - return - }) - } -} - -Sigsci.prototype.wrap = function (next) { - var self = this - return function (req, res) { - res.on('finish', function () { - onAfterResponse(req, res, self.options) - }) - middleware(req, res, self.options, function (wafResponse) { - var wafSignalCode = wafResponse.wafCode - var rpcResponse = wafResponse.response - if (shouldContinue(wafSignalCode)) { - next(req, res) - return - } else if (wafSignalCode == wafCode.WAF_BLOCKING) { - handleNativeBlocking(res, rpcResponse) - return - } - return - }) - } -} - -function handleNativeBlocking(res, rpcResponse) { - var responseCode = rpcResponse.WAFResponse - if (isRedirect(responseCode)) { - var redirectHeader = getRpcHeader(rpcResponse, 'X-Sigsci-Redirect') - if (redirectHeader) { - res.setHeader('Location', redirectHeader) - } - res.statusCode = responseCode - res.end('redirect') - } else { - res.writeHead(responseCode, { 'Content-Type': 'text/plain' }) - res.end('not acceptable') - } -} - -// this is to be used for HAPI 14 -Sigsci.prototype.hapi = function () { - var self = this - return function (request, reply) { - var req = request.raw.req - var res = request.raw.res - middleware(req, res, self.options, function (wafResponse) { - var wafSignalCode = wafResponse.wafCode - var rpcResponse = wafResponse.response - if (shouldContinue(wafSignalCode)) { - reply.continue() - return - } else if (wafSignalCode == wafCode.WAF_BLOCKING) { - var responseCode = rpcResponse.WAFResponse - if (isRedirect(responseCode)) { - var redirectHeader = getRpcHeader(rpcResponse, 'X-Sigsci-Redirect') - reply(responseCode).code(responseCode).header('Location', redirectHeader) - } else { - reply(rpcResponse.WAFResponse).code(rpcResponse.WAFResponse) - } - } - return - }) - } -} - -Sigsci.prototype.hapi18 = function () { - return this.hapi17() -} - -// this can be used for HAPI 17 and 18 -Sigsci.prototype.hapi17 = function () { - var self = this - return function (request, reply) { - var req = request.raw.req - var res = request.raw.res - return new Promise(function (resolve) { - middleware(req, res, self.options, function (wafResponse) { - var wafSignalCode = wafResponse.wafCode - var rpcResponse = wafResponse.response - if (shouldContinue(wafSignalCode)) { - resolve(reply.continue) - return - } else if (wafSignalCode == wafCode.WAF_BLOCKING) { - var responseCode = rpcResponse.WAFResponse - if (isRedirect(responseCode)) { - var redirectHeader = getRpcHeader(rpcResponse, 'X-Sigsci-Redirect') - resolve( - reply - .response(responseCode) - .code(responseCode) - .header('Location', redirectHeader) - .takeover() - ) - } else { - resolve(reply.response(responseCode).code(responseCode).takeover()) - } - return - } - return - }) - }) - } -} - -Sigsci.prototype.koa = function () { - var self = this - return function (ctx, next) { - var req = ctx.req - var res = ctx.res - return new Promise(function (resolve) { - middleware(req, res, self.options, function (wafResponse) { - res.on('finish', function () { - onAfterResponse(req, res, self.options) - }) - var wafSignalCode = wafResponse.wafCode - var rpcResponse = wafResponse.response - if (shouldContinue(wafSignalCode)) { - resolve(next()) - return - } else if (wafSignalCode == wafCode.WAF_BLOCKING) { - resolve(handleNativeBlocking(res, rpcResponse)) - return - } - return - }) - }) - } -} - -Sigsci.prototype.hapi17Ending = function () { - return this.hapiEnding() -} - -Sigsci.prototype.hapi18Ending = function () { - return this.hapiEnding() -} - -Sigsci.prototype.hapiEnding = function () { - var self = this - return function (request) { - onAfterResponse(request.raw.req, request.raw.res, self.options) - } -} - -function shouldContinue(wafSignalCode) { - return ( - wafSignalCode == wafCode.WAF_CONNECT_ERROR || - wafSignalCode == wafCode.WAF_CONNECT_TIMEOUT || - wafSignalCode == wafCode.WAF_FAIL_OPEN || - wafSignalCode == wafCode.WAF_OK || - wafSignalCode == wafCode.WAF_UNKNOWN - ) -} - -var makePre = function (req, postBody) { - var now = Date.now() - var sock = req.socket - - var scheme = 'http' - var tlsProtocol = '' - var tlsCipher = '' - if (typeof sock.getCipher === 'function') { - scheme = 'https' - var cipherStuff = sock.getCipher() - if (cipherStuff !== null) { - tlsProtocol = cipherStuff.version - tlsCipher = cipherStuff.name - } - } - - return { - ModuleVersion: 'sigsci-module-nodejs 2.1.1', - ServerVersion: 'nodejs ' + process.version, - ServerFlavor: '', - ServerName: req.headers.host, // TBD vs. require('os').hostname(); ? why include at all - Timestamp: Math.floor(req._sigsciRequestStart / 1000), - NowMillis: now, - RemoteAddr: req.connection.remoteAddress, - Method: req.method, - Scheme: scheme, - URI: req.url, - Protocol: req.httpVersion, - TLSProtocol: tlsProtocol, - TLSCipher: tlsCipher, - HeadersIn: getRequestHeaders(req), - PostBody: postBody, - } -} - -var middleware = function (req, res, options, processWafResponse) { - req._sigsciRequestStart = Date.now() - req._sigsciBytesWritten = req.socket.bytesWritten - - // GET or other method without body - if (!getPost(req, options.maxPostSize, options.bodyMethods, options.expectedContentTypes)) { - preRequest(req, '', options, processWafResponse) - return - } - - readPostBody(req, function (postBody) { - preRequest(req, postBody, options, processWafResponse) - return - }) -} - -var preRequest = function (req, postBody, options, processWafResponse) { - var client = new net.Socket() - - client.setTimeout(options.socketTimeout) - - client.connect(options, function () { - req._sigsciSession = new Session() - req._sigsciSession.attach(client, client) - req._sigsciClient = client - - var callback = function (err, rpcResponse) { - var wafResponse = onPre(req, err, options, rpcResponse) // this is resolved - processWafResponse(wafResponse) - } - req._sigsciSession.request('RPC.PreRequest', [makePre(req, postBody)], callback) - }) - - client.on('error', function (err) { - options.log(util.format('PreRequest connection error ' + JSON.stringify(err))) - client.destroy() // kill client after server's response - processWafResponse(new WAFResponse(wafCode.WAF_CONNECT_ERROR)) - }) - - client.on('timeout', function (err) { - // err is typically undefined here since its a timeout - // need to touch it to prevent lint error - err = null - options.log(util.format('PreRequest timeout after %d ms', Date.now() - req._sigsciRequestStart)) - client.destroy() // kill client after server's response - processWafResponse(new WAFResponse(wafCode.WAF_CONNECT_TIMEOUT)) - }) -} - -var onPre = function (req, err, options, rpcResponse) { - req._sigsciClient.destroy() - - if (err) { - // fail open. - options.log(util.format('onPre error: %s', err)) - return new WAFResponse(wafCode.WAF_FAIL_OPEN) - } - - // save agent response since we'll use it later. - req.SigSciAgent = rpcResponse - var responseCode = rpcResponse.WAFResponse - if (responseCode == 200) { - return new WAFResponse(wafCode.WAF_OK, rpcResponse) - } - if (isBlocking(responseCode)) { - return new WAFResponse(wafCode.WAF_BLOCKING, rpcResponse) - } - return new WAFResponse(wafCode.WAF_UNKNOWN, rpcResponse) -} - -var onAfterResponse = function (req, res, options) { - var obj - var rpcResponse = req.SigSciAgent - if (!rpcResponse) { - // something bad happened - return - } - - var duration = Date.now() - req._sigsciRequestStart - if (duration < 0) { - duration = 0 - } - - var headers = getResponseHeaders(res) - var contentLength = -1 - for (var i = 0; i < headers.length; i++) { - if (headers[i][0].toLowerCase() === 'content-length') { - contentLength = parseInt(headers[i][1]) - } - } - if (contentLength === -1 && req.socket && req.socket.bytesWritten) { - contentLength = req.socket.bytesWritten - req._sigsciBytesWritten - } - if (options.debug) { - options.log( - util.format('after,%s,%s,%s', req._sigsciRequestStart, Date.now(), rpcResponse.RequestID) - ) - } - if (rpcResponse.RequestID) { - obj = { - WAFResponse: rpcResponse.WAFResponse, - RequestID: rpcResponse.RequestID, - ResponseCode: res.statusCode, - ResponseMillis: duration, - ResponseSize: contentLength, - HeadersOut: getResponseHeaders(res), - } - send(req, res, 'RPC.UpdateRequest', obj, options, onUpdateResponse, null) - return - } - // full post response - if ( - res.statusCode >= 300 || - duration > options.anomalyDuration || - contentLength > options.anomalySize - ) { - obj = makePre(req, '') - obj.WAFResponse = rpcResponse.WAFResponse - obj.ResponseCode = res.statusCode - obj.ResponseMillis = duration - obj.ResponseSize = contentLength - obj.HeadersOut = getResponseHeaders(res) - - // do update or post request - send(req, res, 'RPC.PostRequest', obj, options, onPostResponse, null) - } - // - // no update or post request --> nothing to do - // -} - -// onUpdateResponse is triggered after a RPC.UpdateRequest -var onUpdateResponse = function (options, err /* , rpcResponse */) { - if (err !== null && err !== undefined) { - options.log(util.format('RPC.UpdateResponse error: %s', err)) - } -} - -// onPostResponse is triggered after a RPC.PostRequest -var onPostResponse = function (options, err /* , rpcResponse */) { - if (err !== null && err !== undefined) { - options.log(util.format('RPC.PostResponse error: %s', err)) - } -} - -var send = function (req, res, method, obj, options, callback, onerror) { - req._sigsciPostRequestStart = Date.now() - var client = new net.Socket() - var log = options.log - var debug = options.debug - - var destroyCallback = function (err) { - if (!client.destroyed) { - client.destroy() - } - if (callback) { - callback(options, err) - } - } - - client.setTimeout(options.socketTimeout) - client.connect(options, function () { - var session = new Session() - session.attach(client, client) - session.request(method, [obj], destroyCallback) - }) - - client.on('error', function (err) { - log(util.format('Update/PostRequest connection error: %s', err.message)) - client.destroy() // kill client after server's response - if (onerror) { - onerror(req, res) - } - }) - - client.on('timeout', function (err) { - var duration = Date.now() - req._sigsciPostRequestStart - if (debug) { - var rpcResponse = req.SigSciAgent - var requestId = '' - if (rpcResponse) { - requestId = rpcResponse.RequestID - } - log( - util.format( - 'send,%s,%s,%s,%s', - req._sigsciRequestStart, - Date.now(), - requestId, - req._sigsciPostRequestStart - ) - ) - } - log(util.format('Update/PostRequest timeout after %d ms', duration)) - client.destroy() // kill client after server's response - }) -} - -function WAFResponse(wafCode, response) { - this.wafCode = wafCode - this.response = response -} - -export default Sigsci diff --git a/middleware/index.js b/middleware/index.js index 213ccf376f..ed4320b9bf 100644 --- a/middleware/index.js +++ b/middleware/index.js @@ -3,7 +3,6 @@ import path from 'path' import express from 'express' -import Sigsci from '../lib/sigsci.js' import instrument from '../lib/instrument-middleware.js' import haltOnDroppedConnection from './halt-on-dropped-connection.js' import abort from './abort.js' @@ -144,19 +143,6 @@ export default function (app) { app.use(datadog) } - if (process.env.SIGSCI_RPC_ADDRESS) { - // Fastly Signal Sciences is a module that intercepts Express requests, - // and sends them to the Signal Science agent over TCP. That agent might - // then deem the request blockable and exits the request there. - // More information about the module here - // https://docs.fastly.com/signalsciences/install-guides/other-modules/nodejs-module/ - const sigsci = new Sigsci({ - host: process.env.SIGSCI_RPC_ADDRESS.split(':')[0], - port: process.env.SIGSCI_RPC_ADDRESS.split(':')[1], - }) - app.use(sigsci.express()) - } - // Must appear before static assets and all other requests // otherwise we won't be able to benefit from that functionality // for static assets as well. From 5874a9c13b4e78527e5fa6f100dfda8f253390c5 Mon Sep 17 00:00:00 2001 From: Peter Bengtsson Date: Tue, 24 May 2022 11:39:33 -0400 Subject: [PATCH 12/24] Don't bother render-caching if no next data script (#27944) --- middleware/cache-full-rendering.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/middleware/cache-full-rendering.js b/middleware/cache-full-rendering.js index cf64cc8b88..c05db22878 100644 --- a/middleware/cache-full-rendering.js +++ b/middleware/cache-full-rendering.js @@ -95,7 +95,10 @@ export default async function cacheFullRendering(req, res, next) { // and the NextJS data requests. These are not dependent on the // request cookie, so they're primed for caching in the CDN. const ct = res.get('content-type') - if (ct.startsWith('text/html')) { + // We also don't want to bother caching this if it doesn't + // appear to be a NextJS HTML output with + // its `