diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..f9e6292da --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,5 @@ +#/ AUTHOR: @IAmHughes{ + "image": "mcr.microsoft.com/devcontainers/universal:2", + "features": { + } +} diff --git a/SUPPORT.md b/SUPPORT.md new file mode 100644 index 000000000..cecc2a771 --- /dev/null +++ b/SUPPORT.md @@ -0,0 +1,8 @@ +# Support + +This repository contains sample code provided by GitHub for demonstration purposes. + +- **No Official Support**: These samples are provided "as-is" without official support. +- **Use at Your Own Risk**: Intended for learning and experimentation, not for production use. + +Thank you for understanding. diff --git a/api/javascript/es2015-nodejs/package.json b/api/javascript/es2015-nodejs/package.json index efb437a13..68b6cdd18 100644 --- a/api/javascript/es2015-nodejs/package.json +++ b/api/javascript/es2015-nodejs/package.json @@ -6,6 +6,6 @@ }, "author": "@k33g", "dependencies": { - "node-fetch": "^1.6.3" + "node-fetch": "^3.3.2" } } diff --git a/api/javascript/gha-cleanup/package-lock.json b/api/javascript/gha-cleanup/package-lock.json index ff83ade48..e54c0d7bf 100644 --- a/api/javascript/gha-cleanup/package-lock.json +++ b/api/javascript/gha-cleanup/package-lock.json @@ -1261,9 +1261,9 @@ "integrity": "sha512-Jx5lPaaLdIaOsj2mVLWMWulXF6GQVdyLvNSxmiYCvZ8Ma2hfKX0POoR2kgKOqz+oFsRreq0yYZjQ2wjE9VNzCA==" }, "node-fetch": { - "version": "2.6.8", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.8.tgz", - "integrity": "sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", "requires": { "whatwg-url": "^5.0.0" } diff --git a/api/ruby/building-a-ci-server/Gemfile b/api/ruby/building-a-ci-server/Gemfile index 7b33ee79d..e3fe9b810 100644 --- a/api/ruby/building-a-ci-server/Gemfile +++ b/api/ruby/building-a-ci-server/Gemfile @@ -3,4 +3,4 @@ source "https://rubygems.org" gem "json", "~> 2.3" gem "octokit", "~> 3.0" gem "shotgun" -gem "sinatra", "~> 2.2.3" +gem "sinatra", "~> 4.0.0" diff --git a/api/ruby/building-a-ci-server/Gemfile.lock b/api/ruby/building-a-ci-server/Gemfile.lock index 9c6cc66e2..978bde915 100644 --- a/api/ruby/building-a-ci-server/Gemfile.lock +++ b/api/ruby/building-a-ci-server/Gemfile.lock @@ -2,29 +2,34 @@ GEM remote: https://rubygems.org/ specs: addressable (2.3.6) + base64 (0.2.0) faraday (0.9.0) multipart-post (>= 1.2, < 3) json (2.3.0) multipart-post (2.0.0) - mustermann (2.0.2) + mustermann (3.0.3) ruby2_keywords (~> 0.0.1) octokit (3.0.0) sawyer (~> 0.5.3) - rack (2.2.8.1) - rack-protection (2.2.3) - rack + rack (3.1.7) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) ruby2_keywords (0.0.5) sawyer (0.5.4) addressable (~> 2.3.5) faraday (~> 0.8, < 0.10) shotgun (0.9) rack (>= 1.0) - sinatra (2.2.3) - mustermann (~> 2.0) - rack (~> 2.2) - rack-protection (= 2.2.3) + sinatra (4.0.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.0.0) + rack-session (>= 2.0.0, < 3) tilt (~> 2.0) - tilt (2.0.11) + tilt (2.4.0) PLATFORMS ruby @@ -33,7 +38,7 @@ DEPENDENCIES json (~> 2.3) octokit (~> 3.0) shotgun - sinatra (~> 2.2.3) + sinatra (~> 4.0.0) BUNDLED WITH 1.11.2 diff --git a/api/ruby/delivering-deployments/Gemfile b/api/ruby/delivering-deployments/Gemfile index 7b33ee79d..e3fe9b810 100644 --- a/api/ruby/delivering-deployments/Gemfile +++ b/api/ruby/delivering-deployments/Gemfile @@ -3,4 +3,4 @@ source "https://rubygems.org" gem "json", "~> 2.3" gem "octokit", "~> 3.0" gem "shotgun" -gem "sinatra", "~> 2.2.3" +gem "sinatra", "~> 4.0.0" diff --git a/api/ruby/delivering-deployments/Gemfile.lock b/api/ruby/delivering-deployments/Gemfile.lock index 5ec12f7c8..978bde915 100644 --- a/api/ruby/delivering-deployments/Gemfile.lock +++ b/api/ruby/delivering-deployments/Gemfile.lock @@ -2,29 +2,34 @@ GEM remote: https://rubygems.org/ specs: addressable (2.3.6) + base64 (0.2.0) faraday (0.9.0) multipart-post (>= 1.2, < 3) json (2.3.0) multipart-post (2.0.0) - mustermann (2.0.2) + mustermann (3.0.3) ruby2_keywords (~> 0.0.1) octokit (3.0.0) sawyer (~> 0.5.3) - rack (2.2.8.1) - rack-protection (2.2.3) - rack + rack (3.1.7) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) ruby2_keywords (0.0.5) sawyer (0.5.4) addressable (~> 2.3.5) faraday (~> 0.8, < 0.10) shotgun (0.9) rack (>= 1.0) - sinatra (2.2.3) - mustermann (~> 2.0) - rack (~> 2.2) - rack-protection (= 2.2.3) + sinatra (4.0.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.0.0) + rack-session (>= 2.0.0, < 3) tilt (~> 2.0) - tilt (2.1.0) + tilt (2.4.0) PLATFORMS ruby @@ -33,7 +38,7 @@ DEPENDENCIES json (~> 2.3) octokit (~> 3.0) shotgun - sinatra (~> 2.2.3) + sinatra (~> 4.0.0) BUNDLED WITH 1.11.2 diff --git a/api/ruby/rendering-data-as-graphs/Gemfile.lock b/api/ruby/rendering-data-as-graphs/Gemfile.lock index dab0aa41d..bfaee71e9 100644 --- a/api/ruby/rendering-data-as-graphs/Gemfile.lock +++ b/api/ruby/rendering-data-as-graphs/Gemfile.lock @@ -6,8 +6,8 @@ GEM i18n (>= 1.6, < 2) minitest (>= 5.1) tzinfo (~> 2.0) - addressable (2.8.1) - public_suffix (>= 2.0.2, < 6.0) + addressable (2.8.7) + public_suffix (>= 2.0.2, < 7.0) concurrent-ruby (1.2.2) faraday (1.10.3) faraday-em_http (~> 1.0) @@ -39,7 +39,7 @@ GEM multipart-post (2.3.0) octokit (4.7.0) sawyer (~> 0.8.0, >= 0.5.3) - public_suffix (5.0.1) + public_suffix (6.0.1) rack (1.6.13) rack-protection (1.5.5) rack diff --git a/graphql/enterprise/yarn.lock b/graphql/enterprise/yarn.lock index a2ea79604..a2f2125e4 100644 --- a/graphql/enterprise/yarn.lock +++ b/graphql/enterprise/yarn.lock @@ -316,11 +316,11 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" +braces@^3.0.2, braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" dependencies: - fill-range "^7.0.1" + fill-range "^7.1.1" busboy@^1.6.0: version "1.6.0" @@ -473,9 +473,9 @@ fbjs@^0.8.9: setimmediate "^1.0.5" ua-parser-js "^0.7.9" -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" dependencies: to-regex-range "^5.0.1" @@ -695,10 +695,10 @@ meros@^1.1.4, meros@^1.2.1: resolved "https://registry.yarnpkg.com/meros/-/meros-1.2.1.tgz#056f7a76e8571d0aaf3c7afcbe7eb6407ff7329e" micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" minimatch@4.2.1: diff --git a/graphql/queries/emu-list-scim-accounts.graphql b/graphql/queries/emu-list-scim-accounts.graphql new file mode 100644 index 000000000..3ac1e9f2f --- /dev/null +++ b/graphql/queries/emu-list-scim-accounts.graphql @@ -0,0 +1,32 @@ +# This GraphQL query can be used to generate a list of enterprise members and their SCIM account details in a GitHub Enterprise Cloud with Managed Users (EMU) enterprise account. +# +# Please ensure that your Personal Access Token (PAT) has the "read:enterprise" scope to access enterprise-level data. +# Replace `ENTEPRISE_SLUG` with the slug of your enterprise. To get more than 10 members, you can adjust the "first" parameter. +# +# Note: the output will include suspended users (identified with their obfuscated account name), but it will not include personal user accounts that are not part of the EMU (Enterprise Managed Users) system. + +query ListAllEnterpriseUsers { +# Replace `ENTERPRISE_SLUG` with the slug of your enterprise. To get more than 10 members, you can adjust the "first" parameter. +# +# Note: the output will include suspended users (identified with their obfuscated account name), but it will not include personal user accounts that are not part of the EMU (Enterprise Managed Users) system. + +query ListAllEnterpriseUsers { + enterprise(slug: "ENTERPRISE_SLUG") { + ownerInfo { + samlIdentityProvider { + externalIdentities(first: 10) { + nodes { + user { + login + name + } + scimIdentity { + username + groups + } + } + } + } + } + } +} diff --git a/graphql/queries/scim-emu-list-enterprise-scim-identities.graphql b/graphql/queries/emu-scim-list-scim-identities.graphql similarity index 100% rename from graphql/queries/scim-emu-list-enterprise-scim-identities.graphql rename to graphql/queries/emu-scim-list-scim-identities.graphql diff --git a/graphql/queries/scim-emu-enterprises-list-scim-identities.graphql b/graphql/queries/emu-scim-oidc-list-scim-identities.graphql similarity index 100% rename from graphql/queries/scim-emu-enterprises-list-scim-identities.graphql rename to graphql/queries/emu-scim-oidc-list-scim-identities.graphql diff --git a/graphql/queries/enterprise-get-ip-allow-list.graphql b/graphql/queries/enterprise-get-ip-allow-list.graphql new file mode 100644 index 000000000..1ad6a35c9 --- /dev/null +++ b/graphql/queries/enterprise-get-ip-allow-list.graphql @@ -0,0 +1,25 @@ +# Grab current IP allow list settings for an enterprise. +# This includes: +# - The IP allow list entries +# - The IP allow list enabled setting +# - The IP allow list for GitHub Apps enabled setting + +query GetEnterpriseIPAllowList { + enterprise(slug: "ENTERPRISE_SLUG") { + owner_id: id + enterprise_slug: slug + enterprise_owner_info: ownerInfo { + is_ip_allow_list_enabled: ipAllowListEnabledSetting + is_ip_allow_list_for_github_apps_enabled: ipAllowListForInstalledAppsEnabledSetting + ipAllowListEntries(first: 100) { + nodes { + ip_allow_list_entry_id: id + ip_allow_list_entry_name: name + ip_allow_list_entry_value: allowListValue + ip_allow_list_entry_created: createdAt + is_ip_allow_list_entry_active: isActive + } + } + } + } +} diff --git a/graphql/queries/enterprise-members-2fa-disabled.graphql b/graphql/queries/enterprise-members-2fa-disabled.graphql new file mode 100644 index 000000000..207ebeeb0 --- /dev/null +++ b/graphql/queries/enterprise-members-2fa-disabled.graphql @@ -0,0 +1,28 @@ +# This GraphQL query will list any enterprise members who have yet to enable 2FA on their personal GitHub account. +# This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user. + +query GetEnterpriseMembersWith2faDisabled { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + members_with_no_2fa: members( + first: 100 + twoFactorMethodSecurity: DISABLED + ) { + num_of_members: totalCount + edges { + node { + ... on EnterpriseUserAccount { + login + } + } + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-members-2fa-insecure.graphql b/graphql/queries/enterprise-members-2fa-insecure.graphql new file mode 100644 index 000000000..b30757f17 --- /dev/null +++ b/graphql/queries/enterprise-members-2fa-insecure.graphql @@ -0,0 +1,28 @@ +# This GraphQL query will list any enterprise members who have enabled 2FA on their GitHub account, but amongst their 2FA methods is SMS (which is deemed insecure). +# This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user. + +query GetEnterpriseMembersWithInsecure2fa { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + members_with_insecure_2fa: members( + first: 100 + twoFactorMethodSecurity: INSECURE + ) { + num_of_members: totalCount + edges { + node { + ... on EnterpriseUserAccount { + login + } + } + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-members-2fa-secure.graphql b/graphql/queries/enterprise-members-2fa-secure.graphql new file mode 100644 index 000000000..0c02797bd --- /dev/null +++ b/graphql/queries/enterprise-members-2fa-secure.graphql @@ -0,0 +1,28 @@ +# This GraphQL query will list any enterprise members who have enabled 2FA on their GitHub account with a secure (non-SMS) method. +# This does not list any outside collaborators, and will not work with Enterprise Managed Users other than the setup user. + +query GetEnterpriseMembersWithSecure2fa { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + members_with_secure_2fa: members( + first: 100 + twoFactorMethodSecurity: SECURE + ) { + num_of_members: totalCount + edges { + node { + ... on EnterpriseUserAccount { + login + } + } + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-outside-collaborators-2fa-disabled.graphql b/graphql/queries/enterprise-outside-collaborators-2fa-disabled.graphql new file mode 100644 index 000000000..e778b6f6d --- /dev/null +++ b/graphql/queries/enterprise-outside-collaborators-2fa-disabled.graphql @@ -0,0 +1,25 @@ +# This GraphQL query will list any outside collaborators in an enterprise who have yet to enable 2FA on their GitHub account. + +query GetEnterpriseollaboratorsWith2faDisabled { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + enterprise_owner_info: ownerInfo { + collaborators_with_no_2fa: outsideCollaborators( + twoFactorMethodSecurity: DISABLED + first: 100 + ) { + num_of_collaborators: totalCount + nodes { + login + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-outside-collaborators-2fa-insecure.graphql b/graphql/queries/enterprise-outside-collaborators-2fa-insecure.graphql new file mode 100644 index 000000000..b691eddbd --- /dev/null +++ b/graphql/queries/enterprise-outside-collaborators-2fa-insecure.graphql @@ -0,0 +1,25 @@ +# This GraphQL query will list any outside collaborators in an enterprise who have enabled 2FA on their GitHub account, but amongst the 2FA methods is SMS (which is deemed insecure). + +query GetEnterpriseCollaboratorsWithInsecure2fa { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + enterprise_owner_info: ownerInfo { + collaborators_with_insecure_2fa: outsideCollaborators( + twoFactorMethodSecurity: INSECURE + first: 100 + ) { + num_of_collaborators: totalCount + nodes { + login + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-outside-collaborators-2fa-secure.graphql b/graphql/queries/enterprise-outside-collaborators-2fa-secure.graphql new file mode 100644 index 000000000..a3565196e --- /dev/null +++ b/graphql/queries/enterprise-outside-collaborators-2fa-secure.graphql @@ -0,0 +1,25 @@ +# This GraphQL query will list any outside collaborators in an enterprise who have enabled 2FA on their GitHub account with a secure (non-SMS) method. + +query GetEnterpriseCollaboratorsWithSecure2fa { + enterprise(slug: "ENTERPRISE_SLUG") { + enterprise_id: id + enterprise_slug: slug + enterprise_owner_info: ownerInfo { + collaborators_with_secure_2fa: outsideCollaborators( + twoFactorMethodSecurity: SECURE + first: 100 + ) { + num_of_collaborators: totalCount + nodes { + login + } + pageInfo { + endCursor + startCursor + hasNextPage + hasPreviousPage + } + } + } + } +} \ No newline at end of file diff --git a/graphql/queries/enterprise-saml-identities-filtered-by-nameid.graphql b/graphql/queries/enterprise-saml-identities-filtered-by-nameid.graphql new file mode 100644 index 000000000..b5cbe92e5 --- /dev/null +++ b/graphql/queries/enterprise-saml-identities-filtered-by-nameid.graphql @@ -0,0 +1,35 @@ +# You will need to replace and with the actual GitHub enterprise slug and the SAML `NameID` value that you're searching stored external identities for in the GitHub enterprise. +# For GitHub Enterprise Cloud enterprises that have SAML configured at the enterprise level, this will query the stored SAML `nameId` external identity values in the GitHub enterprise, and if one is found that matches the value specified for ``, it will print out the SAML `nameId` and GitHub username for that stored external identity. + +# Note that the query below will not tell you if the GitHub username/account associated with this linked identity is still a member of the enterprise. Enterprise owners can navigate to the Enterprise > People > Members UI and search for the user to determine this, or perform a different GraphQL query using the https://docs.github.com/en/enterprise-cloud@latest/graphql/reference/objects#enterprise object with the members(query:"") filter. + +# This query will not print out a user username (`login`) value if there is not a GitHub user account linked to this SAML identity. +# Pagination shouldn't be needed since there shouldn't be multiple entries in the enterprise that have the same SAML `NameID` or SCIM `userName`. However, for more information on pagination. There is also an example of pagination in simple-pagination-example.graphql. + + +query EnterpriseIdentitiesBySAMLNameID { + enterprise(slug: "") { + ownerInfo { + samlIdentityProvider { + externalIdentities(userName:"", first: 25) { + totalCount + edges { + node { + guid + samlIdentity { + nameId + } + user { + login + } + } + } + pageInfo { + hasNextPage + endCursor + } + } + } + } + } +} diff --git a/graphql/queries/saml-identities-enterprise-level.graphql b/graphql/queries/enterprise-saml-identities.graphql similarity index 93% rename from graphql/queries/saml-identities-enterprise-level.graphql rename to graphql/queries/enterprise-saml-identities.graphql index 22a7b4b94..fb136c86e 100644 --- a/graphql/queries/saml-identities-enterprise-level.graphql +++ b/graphql/queries/enterprise-saml-identities.graphql @@ -3,8 +3,8 @@ # If the Identity Provider has sent an `emails` attribute/value in a previous SAML response for enterprise member(s), it also possible to add the `emails` attribute in the `samlIdentity` section right below `nameID` and query for this SAML identity attribute value as well. # If there are a large number of identities/users (greater than 100), pagination will need to be used. See https://graphql.org/learn/pagination/ for details on pagination. There is an example of pagination in simple-pagination-example.graphql. -query listSSOUserIdentities($enterpriseSlug: String!) { - enterprise(slug: $enterpriseSlug) { +query listSSOUserIdentities { + enterprise(slug: "ENTERPRISE_SLUG") { ownerInfo { samlIdentityProvider { externalIdentities(first: 100) { diff --git a/graphql/queries/scim-identities-all-orgs-in-enterprise.graphql b/graphql/queries/enterprise-scim-identities-all-orgs.graphql similarity index 100% rename from graphql/queries/scim-identities-all-orgs-in-enterprise.graphql rename to graphql/queries/enterprise-scim-identities-all-orgs.graphql diff --git a/graphql/queries/ip-allow-list-add-ip.graphql b/graphql/queries/ip-allow-list-add-ip.graphql new file mode 100644 index 000000000..ab977164f --- /dev/null +++ b/graphql/queries/ip-allow-list-add-ip.graphql @@ -0,0 +1,29 @@ +# This query is used to add an IP address to the IP allow list. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation AddIPAddressToIPAllowList { + createIpAllowListEntry( + input: { + ownerId: "OWNER_ID" + name: "DESCRIPTION_OF_IP_ADDRESS" + allowListValue: "IP_ADDRESS" + isActive: true + } + ) { + ipAllowListEntry { + ip_allow_list_entry_id: id + ip_allow_list_entry_name: name + ip_allow_list_entry_ip_address: allowListValue + ip_allow_list_entry_created: createdAt + ip_allow_list_entry_updated: updatedAt + is_ip_allow_list_entry_active: isActive + } + } +} diff --git a/graphql/queries/ip-allow-list-disable-github-apps-only.graphql b/graphql/queries/ip-allow-list-disable-github-apps-only.graphql new file mode 100644 index 000000000..0a27a261e --- /dev/null +++ b/graphql/queries/ip-allow-list-disable-github-apps-only.graphql @@ -0,0 +1,17 @@ +# This query is used to disable the IP allow list feature. This will apply to GitHub Apps only. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation DisableIPAllowListForGitHubAppsOnly { + updateIpAllowListForInstalledAppsEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: DISABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-disable-ip-address-only.graphql b/graphql/queries/ip-allow-list-disable-ip-address-only.graphql new file mode 100644 index 000000000..0fe79f496 --- /dev/null +++ b/graphql/queries/ip-allow-list-disable-ip-address-only.graphql @@ -0,0 +1,17 @@ +# This query is used to disable the IP allow list feature. This will apply to IP addresses only. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation DisableAllowListForIpsOnly { + updateIpAllowListEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: DISABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-disable.graphql b/graphql/queries/ip-allow-list-disable.graphql new file mode 100644 index 000000000..2b1ecab85 --- /dev/null +++ b/graphql/queries/ip-allow-list-disable.graphql @@ -0,0 +1,22 @@ +# This query is used to disable the IP allow list feature. This will apply to both IP addresses and GitHub Apps. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation DisableIPAllowList { + updateIpAllowListEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: DISABLED } + ) { + clientMutationId + } + updateIpAllowListForInstalledAppsEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: DISABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-enable-github-apps-only.graphql b/graphql/queries/ip-allow-list-enable-github-apps-only.graphql new file mode 100644 index 000000000..8d3e1ead2 --- /dev/null +++ b/graphql/queries/ip-allow-list-enable-github-apps-only.graphql @@ -0,0 +1,17 @@ +# This query is used to enable the IP allow list feature. This will apply to GitHub Apps only. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation EnableIPAllowListForGitHubAppsOnly { + updateIpAllowListForInstalledAppsEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: ENABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-enable-ip-address-only.graphql b/graphql/queries/ip-allow-list-enable-ip-address-only.graphql new file mode 100644 index 000000000..e1eff4e79 --- /dev/null +++ b/graphql/queries/ip-allow-list-enable-ip-address-only.graphql @@ -0,0 +1,17 @@ +# This query is used to enable the IP allow list feature. This will apply to IP addresses only. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation EnableAllowListForIpsOnly { + updateIpAllowListEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: ENABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-enable.graphql b/graphql/queries/ip-allow-list-enable.graphql new file mode 100644 index 000000000..293062536 --- /dev/null +++ b/graphql/queries/ip-allow-list-enable.graphql @@ -0,0 +1,22 @@ +# This query is used to enable the IP allow list feature. This will apply to both IP addresses and GitHub Apps. +# This can be used on both organizations and enterprise accounts. +# +# The `OWNER_ID` is the ID of the organization or enterprise account. You can +# get the ID of an organization or enterprise account by executing either of +# the following queries and referring to the value from `owner_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation EnableIPAllowList { + updateIpAllowListEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: ENABLED } + ) { + clientMutationId + } + updateIpAllowListForInstalledAppsEnabledSetting( + input: { ownerId: "OWNER_ID", settingValue: ENABLED } + ) { + clientMutationId + } +} diff --git a/graphql/queries/ip-allow-list-remove-ip-entry.graphql b/graphql/queries/ip-allow-list-remove-ip-entry.graphql new file mode 100644 index 000000000..fb900a9ed --- /dev/null +++ b/graphql/queries/ip-allow-list-remove-ip-entry.graphql @@ -0,0 +1,15 @@ +# This query is used to remove an IP allow list entry from the IP allow list. +# This can be used on both organizations and enterprise accounts. +# +# The `IP_ENTRY_ID` is the ID of the IP allow list entry. You can +# get the ID for this by executing either of the following queries +# and referring to the value from `ip_allow_list_entry_id` field: +# +# - organizations: https://github.com/github/platform-samples/blob/master/graphql/queries/org-get-ip-allow-list.graphql +# - enterprise accounts: https://github.com/github/platform-samples/blob/master/graphql/queries/enterprise-get-ip-allow-list.graphql + +mutation DeleteIPAddressFromIPAllowList { + deleteIpAllowListEntry(input: { ipAllowListEntryId: "IP_ENTRY_ID" }) { + clientMutationId + } +} diff --git a/graphql/queries/11-mutation-issue-comment-add.graphql b/graphql/queries/issue-add-comment.graphql similarity index 68% rename from graphql/queries/11-mutation-issue-comment-add.graphql rename to graphql/queries/issue-add-comment.graphql index 58a19361d..864f55a83 100644 --- a/graphql/queries/11-mutation-issue-comment-add.graphql +++ b/graphql/queries/issue-add-comment.graphql @@ -1,4 +1,4 @@ -# Get ISSUE_ID from graphql/queries/10-query-issue-comment-get-issue.graphql +# Get ISSUE_ID from graphql/queries/repos-get-last-issue-comment.graphql mutation { addComment ( diff --git a/graphql/queries/search-for-issue-or-bug-requests.graphql b/graphql/queries/issue-search-for-issue-or-bug-requests.graphql similarity index 100% rename from graphql/queries/search-for-issue-or-bug-requests.graphql rename to graphql/queries/issue-search-for-issue-or-bug-requests.graphql diff --git a/graphql/queries/branches-and-commits-by-repository.graphql b/graphql/queries/org-branches-and-commits-by-repository.graphql similarity index 82% rename from graphql/queries/branches-and-commits-by-repository.graphql rename to graphql/queries/org-branches-and-commits-by-repository.graphql index e22788236..63f0c7865 100644 --- a/graphql/queries/branches-and-commits-by-repository.graphql +++ b/graphql/queries/org-branches-and-commits-by-repository.graphql @@ -1,7 +1,7 @@ -query getCommitsByBranchByRepo($orgName:String!, $repoName:String!) { - organization(login:$orgName) { +query getCommitsByBranchByRepo { + organization(login: "ORG_NAME") { name - repository(name:$repoName) { + repository(name: "REPO_NAME") { name refs(refPrefix: "refs/heads/", first: 10) { nodes { diff --git a/graphql/queries/org-get-ip-allow-list.graphql b/graphql/queries/org-get-ip-allow-list.graphql new file mode 100644 index 000000000..3921d569d --- /dev/null +++ b/graphql/queries/org-get-ip-allow-list.graphql @@ -0,0 +1,24 @@ +# Grab current IP allow list settings for an organization. +# This includes: +# - The IP allow list entries +# - The IP allow list enabled setting +# - The IP allow list for GitHub Apps enabled setting + +query GetOrganizationIPAllowList { + organization(login: "ORG_NAME") { + owner_id: id + organization_slug: login + is_ip_allow_list_enabled: ipAllowListEnabledSetting + is_ip_allow_list_for_github_apps_enabled: ipAllowListForInstalledAppsEnabledSetting + ipAllowListEntries(first: 100) { + totalCount + nodes { + ip_allow_list_entry_id: id + ip_allow_list_entry_name: name + ip_allow_list_entry_ip_address: allowListValue + ip_allow_list_entry_created: createdAt + is_ip_allow_list_entry_active: isActive + } + } + } +} diff --git a/graphql/queries/org-list-outside-collaborators-by-repo.graphql b/graphql/queries/org-list-outside-collaborators-by-repo.graphql new file mode 100644 index 000000000..672dff719 --- /dev/null +++ b/graphql/queries/org-list-outside-collaborators-by-repo.graphql @@ -0,0 +1,25 @@ +query( $cursor: String) { + organization(login: "ORG_NAME") { + url + login + repositories(first: 100, after: $cursor) { + pageInfo { + endCursor + hasNextPage + } + nodes { + name + collaborators(affiliation: OUTSIDE, first: 100) { + + nodes { + url + login + } + edges { + permission + } + } + } + } + } + } diff --git a/graphql/queries/org-members-by-team.graphql b/graphql/queries/org-members-by-team.graphql index 2083c785f..e2410b000 100644 --- a/graphql/queries/org-members-by-team.graphql +++ b/graphql/queries/org-members-by-team.graphql @@ -1,8 +1,8 @@ -query getMembersByTeam($orgName: String!, $teamName: String!) { - organization(login: $orgName) { +query getMembersByTeam { + organization(login: "ORG_NAME") { id name - teams(first: 1, query: $teamName) { + teams(first: 1, query: "TEAM_NAME") { edges { node { id diff --git a/graphql/queries/3-org-members-commit-msgs.graphql b/graphql/queries/org-members-commit-msgs.graphql similarity index 100% rename from graphql/queries/3-org-members-commit-msgs.graphql rename to graphql/queries/org-members-commit-msgs.graphql diff --git a/graphql/queries/2-org-members-variable.graphql b/graphql/queries/org-members-with-role.graphql similarity index 100% rename from graphql/queries/2-org-members-variable.graphql rename to graphql/queries/org-members-with-role.graphql diff --git a/graphql/queries/1-org-members.graphql b/graphql/queries/org-members.graphql similarity index 100% rename from graphql/queries/1-org-members.graphql rename to graphql/queries/org-members.graphql diff --git a/graphql/queries/pr-merged-info-by-repository.graphql b/graphql/queries/org-pr-merged-info-by-repository.graphql similarity index 85% rename from graphql/queries/pr-merged-info-by-repository.graphql rename to graphql/queries/org-pr-merged-info-by-repository.graphql index 5a2f74c4a..c7912af54 100644 --- a/graphql/queries/pr-merged-info-by-repository.graphql +++ b/graphql/queries/org-pr-merged-info-by-repository.graphql @@ -1,5 +1,5 @@ -query getRepoMergedPRDetails($orgName: String!, $repoName: String!) { - repository(owner: $orgName, name: $repoName) { +query getRepoMergedPRDetails { + repository(owner: "ORG_NAME, name: "REPO_NAME") { pullRequests(first: 100, states: MERGED) { pageInfo { endCursor #use this value in the pullRequests argument list diff --git a/graphql/queries/5-org-repos-fragment-2.graphql b/graphql/queries/org-repos-fragment-2.graphql similarity index 100% rename from graphql/queries/5-org-repos-fragment-2.graphql rename to graphql/queries/org-repos-fragment-2.graphql diff --git a/graphql/queries/9-org-repos-fragment-directive-2.graphql b/graphql/queries/org-repos-fragment-directive-2.graphql similarity index 87% rename from graphql/queries/9-org-repos-fragment-directive-2.graphql rename to graphql/queries/org-repos-fragment-directive-2.graphql index 170e7836f..a5927ed56 100644 --- a/graphql/queries/9-org-repos-fragment-directive-2.graphql +++ b/graphql/queries/org-repos-fragment-directive-2.graphql @@ -1,5 +1,5 @@ query orgInfo($showRepoInfo: Boolean!) { - organization(login: "github") { + organization(login: "ORG_NAME") { ...orgFrag } } diff --git a/graphql/queries/8-org-repos-fragment-directive.graphql b/graphql/queries/org-repos-fragment-directive.graphql similarity index 88% rename from graphql/queries/8-org-repos-fragment-directive.graphql rename to graphql/queries/org-repos-fragment-directive.graphql index 12e5bed4a..465df0653 100644 --- a/graphql/queries/8-org-repos-fragment-directive.graphql +++ b/graphql/queries/org-repos-fragment-directive.graphql @@ -1,5 +1,5 @@ query orgInfo($showRepoInfo: Boolean!) { - organization(login: "github") { + organization(login: "ORG_NAME") { login name repositories @include(if: $showRepoInfo) { diff --git a/graphql/queries/4-org-repos-fragment.graphql b/graphql/queries/org-repos-fragment.graphql similarity index 100% rename from graphql/queries/4-org-repos-fragment.graphql rename to graphql/queries/org-repos-fragment.graphql diff --git a/graphql/queries/org-saml-identities-filtered-by-nameid-username.graphql b/graphql/queries/org-saml-identities-filtered-by-nameid-username.graphql new file mode 100644 index 000000000..61749ebd8 --- /dev/null +++ b/graphql/queries/org-saml-identities-filtered-by-nameid-username.graphql @@ -0,0 +1,29 @@ +# You will need to replace and with the actual GitHub organization name and the SAML `NameID` value that you're searching stored external identities for in the GitHub organization. +# For GitHub Enterprise Cloud organizations that have SAML configured at the organization level, this will query the stored SAML `nameId` and SCIM `userName` external identity values in the GitHub organization, and if one is found that matches the value specified for ``, it will print out the SAML `nameId` and GitHub username for that stored external identity. + +# Note that the query below will not tell you if the GitHub username/account associated with this linked identity is still a member of the organization. Organization owners can navigate to the Organization > People > Members UI and search for the user to determine this. + +# This query will not print out a user username (`login`) value if there is not a GitHub user account linked to this SAML identity. +# Pagination shouldn't be needed since there shouldn't be multiple entries in the organization that have the same SAML `NameID` or SCIM `userName`. However, for more information on pagination. There is also an example of pagination in simple-pagination-example.graphql. + +query OrganizationIdentitiesBySAMLNameID { + organization(login: "") { + samlIdentityProvider { + externalIdentities(userName:"", first: 25) { + edges { + node { + samlIdentity { + nameId + } + user { + login + } + } + } + pageInfo { + endCursor + } + } + } + } +} diff --git a/graphql/queries/saml-identities-single-organization.graphql b/graphql/queries/org-saml-identities.graphql similarity index 100% rename from graphql/queries/saml-identities-single-organization.graphql rename to graphql/queries/org-saml-identities.graphql diff --git a/graphql/queries/scim-identities-single-organization.graphql b/graphql/queries/org-scim-identities.graphql similarity index 100% rename from graphql/queries/scim-identities-single-organization.graphql rename to graphql/queries/org-scim-identities.graphql diff --git a/graphql/queries/6-org-with-alias.graphql b/graphql/queries/org-with-alias.graphql similarity index 100% rename from graphql/queries/6-org-with-alias.graphql rename to graphql/queries/org-with-alias.graphql diff --git a/graphql/queries/7-org-with-variables.graphql b/graphql/queries/org-with-variables.graphql similarity index 100% rename from graphql/queries/7-org-with-variables.graphql rename to graphql/queries/org-with-variables.graphql diff --git a/graphql/queries/repo-get-all-branches.graphql b/graphql/queries/repo-get-all-branches.graphql index 5563877ee..2fccaf98d 100644 --- a/graphql/queries/repo-get-all-branches.graphql +++ b/graphql/queries/repo-get-all-branches.graphql @@ -1,6 +1,6 @@ -query getExistingRepoBranches($orgName: String!, $repoName: String!) { - organization(login: $orgName) { - repository(name: $repoName) { +query getExistingRepoBranches { + organization(login: "ORG_NAME") { + repository(name: "REPO_NAME") { id name refs(refPrefix: "refs/heads/", first: 10) { diff --git a/graphql/queries/10-query-issue-comment-get-issue.graphql b/graphql/queries/repos-get-last-issue-comment.graphql similarity index 53% rename from graphql/queries/10-query-issue-comment-get-issue.graphql rename to graphql/queries/repos-get-last-issue-comment.graphql index 96a19cc3c..5d5f52264 100644 --- a/graphql/queries/10-query-issue-comment-get-issue.graphql +++ b/graphql/queries/repos-get-last-issue-comment.graphql @@ -1,5 +1,5 @@ -query getRepoIssue($orgName: String!, $repoName: String!) { - repository(owner: $orgName, name: $repoName) { +query getRepoIssue { + repository(owner: "ORG_NAME", name: "REPO_NAME") { issues(last: 1) { edges { node { diff --git a/graphql/queries/user-org-membership.graphql b/graphql/queries/user-org-membership.graphql new file mode 100644 index 000000000..2f6486510 --- /dev/null +++ b/graphql/queries/user-org-membership.graphql @@ -0,0 +1,15 @@ +# This GraphQL query can be used to generate a list of organizations a user belongs to on GitHub.com +# replace GITHUB_LOGIN with the username that you would like to view +# +# Note: the organizations listed are only ones that the calling user is a member of. If the calling member is not part of any organizations that the searched user belong to, it will not be shown here. + +query GetUserOrganizations { + user(login: "GITHUB_LOGIN") { + organizations(first: 100) { + nodes { + organization_name: name + organization_slug: login + } + } + } +} diff --git a/pre-receive-hooks/README.md b/pre-receive-hooks/README.md index 21dd07d82..f09dd2c31 100644 --- a/pre-receive-hooks/README.md +++ b/pre-receive-hooks/README.md @@ -1,8 +1,11 @@ ## Pre-receive hooks +> [!IMPORTANT] +> Many of the hooks mentioned in this article can now be natively implemented through GitHub Enterprise's [Rulesets](https://docs.github.com/en/enterprise-server@3.16/repositories/configuring-branches-and-merges-in-your-repository/managing-rulesets/about-rulesets) and [Secret Protection](https://docs.github.com/en/enterprise-server@3.16/code-security/secret-scanning/introduction/about-secret-scanning) (requires GitHub Advanced Security) features. With it, you have the same effect as hooks, but in a more controlled, auditable and performant fashion, so we highly recommend looking at these before you implement pre-receive hooks. + ### tl;dr -This directory contains examples for [pre-receive hooks ](https://help.github.com/enterprise/user/articles/working-with-pre-receive-hooks/) which are a [GitHub Enterprise feature](https://developer.github.com/v3/enterprise/pre_receive_hooks/) to block unwanted commits before they even reach your repository. +This directory contains examples for [pre-receive hooks ](https://docs.github.com/enterprise-server/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/working-with-pre-receive-hooks) which are a [GitHub Enterprise feature](https://developer.github.com/v3/enterprise/pre_receive_hooks/) to block unwanted commits before they even reach your repository. If you have a great example for a pre-receive hook you used with GitHub Enterprise that is not yet part of this directory, create a pull request and we will happily review it. @@ -10,9 +13,9 @@ While blocking commits at push time using pre-receive-hooks seems like an awesom ### Pre-receive hooks - The longer story -As of GitHub Enterprise 2.6 we [support pre-receive hooks](https://help.github.com/enterprise/user/articles/working-with-pre-receive-hooks/). [Pre-receive hooks](https://help.github.com/enterprise/user/articles/working-with-pre-receive-hooks/) run tests on code pushed to a repository to ensure contributions meet repository or organization policy. If the commits pass the tests, the push will be accepted into the repository. If the commits do not pass the tests, the push will not be accepted. +As of GitHub Enterprise 2.6 we [support pre-receive hooks](https://docs.github.com/enterprise-server/pull-requests/collaborating-with-pull-requests/collaborating-on-repositories-with-code-quality-features/working-with-pre-receive-hooks). Pre-receive hooks run tests on code pushed to a repository to ensure contributions meet repository or organization policy. If the commits pass the tests, the push will be accepted into the repository. If the commits do not pass the tests, the push will not be accepted. -Your GitHub Enterprise site administrator can [create and remove pre-receive hooks](https://help.github.com/enterprise/admin/guides/developer-workflow/managing-pre-receive-hooks-on-the-github-enterprise-appliance/) for your organization or repository, and may allow organization or repository administrators to enable or disable pre-receive hooks. GitHub Enterprise allows you to [develop and test](https://help.github.com/enterprise/admin/guides/developer-workflow/creating-a-pre-receive-hook-script/) all scripts locally in a [pre-receive hook environment](https://help.github.com/enterprise/2.6/admin/guides/developer-workflow/creating-a-pre-receive-hook-environment/). +Your GitHub Enterprise site administrator can [create and remove pre-receive hooks](https://docs.github.com/enterprise-server/admin/enforcing-policies/enforcing-policy-with-pre-receive-hooks/managing-pre-receive-hooks-on-your-instance) for your organization or repository, and may allow organization or repository administrators to enable or disable pre-receive hooks. GitHub Enterprise allows you to [develop and test](https://docs.github.com/enterprise-server/admin/enforcing-policies/enforcing-policy-with-pre-receive-hooks/creating-a-pre-receive-hook-script) all scripts locally in a [pre-receive hook environment](https://docs.github.com/enterprise-server/admin/enforcing-policies/enforcing-policy-with-pre-receive-hooks/creating-a-pre-receive-hook-environment). Examples of pre-receive hooks: * Require commit messages to follow a specific pattern or format, such as including a valid ticket number or being over a certain length. @@ -25,13 +28,13 @@ You can find examples on how to write pre-receive hooks on the [Pro Git website] ### Think twice before you deploy a pre-receive hook -GitHub recommends a cautious and thoughtful approach when applying mechanisms like pre-receive hooks that can block Git push operations. Blocking pushes right away typically prevents contribution and visibility into proposed changes. We think it's best that individuals collaborate with each other to identify and fix any problems after changes have been proposed. Even some of our largest customers have found that a subtle shift to [non-blocking web-hooks](https://help.github.com/enterprise/admin/guides/developer-workflow/using-webhooks-for-continuous-integration/) allowed more individuals to contribute and provided more opportunities for learning and collaboration. Combined with asynchronous collaboration workflows like [GitHubFlow](https://guides.github.com/introduction/flow/), non-blocking web-hooks typically resulted in higher-quality output. +GitHub recommends a cautious and thoughtful approach when applying mechanisms like pre-receive hooks that can block Git push operations. Blocking pushes right away typically prevents contribution and visibility into proposed changes. We think it's best that individuals collaborate with each other to identify and fix any problems after changes have been proposed. Even some of our largest customers have found that a subtle shift to [non-blocking web-hooks](https://docs.github.com/enterprise-server/webhooks/about-webhooks) allowed more individuals to contribute and provided more opportunities for learning and collaboration. Combined with asynchronous collaboration workflows like [GitHubFlow](https://guides.github.com/introduction/flow/), non-blocking web-hooks typically resulted in higher-quality output. That said, we understand there may be compliance or other organizational reasons to incorporate pre-receive hooks into a development workflow, e.g. ensuring that sensitive information is not included as part of pushed commits. ### Performance, stability and workflow implications of pre-receive hooks -Pre-receive hooks can have unintended effects on the performance of the GitHub Enterprise appliance and should be carefully [implemented and reviewed](https://help.github.com/enterprise/admin/guides/developer-workflow/creating-a-pre-receive-hook-script/). A misconfigured pre-receive hook may block all developers from contributing/pushing to a repository or consume all system resources on the appliance. +Pre-receive hooks can have unintended effects on the performance of the GitHub Enterprise appliance and should be carefully [created in a pre-receive hook environment](https://docs.github.com/enterprise-server/admin/enforcing-policies/enforcing-policy-with-pre-receive-hooks/creating-a-pre-receive-hook-environment). A misconfigured pre-receive hook may block all developers from contributing/pushing to a repository or consume all system resources on the appliance. Running scripts will be automatically terminated after 5 seconds (blocking the push). Consequently, pre-receive hooks should not rely on the results of external systems that may not be always available or on any other potentially blocking resource. As any negative exit code of a pre-receive hook will reject the associated push attempt, your scripts should handle unforeseen standard input and environment variable values in a robust way.