diff --git a/assets/images/help/enterprises/click-advanced-security.png b/assets/images/help/enterprises/click-advanced-security.png new file mode 100644 index 0000000000..121742271f Binary files /dev/null and b/assets/images/help/enterprises/click-advanced-security.png differ diff --git a/assets/images/help/enterprises/select-advanced-security-individual-organization-policy.png b/assets/images/help/enterprises/select-advanced-security-individual-organization-policy.png new file mode 100644 index 0000000000..b29beb0f85 Binary files /dev/null and b/assets/images/help/enterprises/select-advanced-security-individual-organization-policy.png differ diff --git a/assets/images/help/enterprises/select-advanced-security-organization-policy.png b/assets/images/help/enterprises/select-advanced-security-organization-policy.png new file mode 100644 index 0000000000..ffa948bb54 Binary files /dev/null and b/assets/images/help/enterprises/select-advanced-security-organization-policy.png differ diff --git a/content/admin/policies/enforcing-policies-for-advanced-security-in-your-enterprise.md b/content/admin/policies/enforcing-policies-for-advanced-security-in-your-enterprise.md new file mode 100644 index 0000000000..7b9d29efd5 --- /dev/null +++ b/content/admin/policies/enforcing-policies-for-advanced-security-in-your-enterprise.md @@ -0,0 +1,22 @@ +--- +title: Enforcing policies for Advanced Security in your enterprise +intro: 'Enterprise owners can enforce policies to manage {% data variables.product.prodname_GH_advanced_security %} features for organizations on {% data variables.product.product_location %}.' +product: '{% data reusables.gated-features.ghas %}' +versions: + enterprise-server: '>=3.1' + github-ae: 'next' +--- + +### About {% data variables.product.prodname_GH_advanced_security %} + +{% data reusables.advanced-security.ghas-helps-developers %} + +### Enforcing a policy for {% data variables.product.prodname_advanced_security %} features + +{% data reusables.advanced-security.about-ghas-organization-policy %} + +{% data reusables.enterprise-accounts.access-enterprise %} +{% data reusables.enterprise-accounts.policies-tab %} +{% data reusables.enterprise-accounts.advanced-security-policies %} +{% data reusables.enterprise-accounts.advanced-security-organization-policy-drop-down %} +{% data reusables.enterprise-accounts.advanced-security-individual-organization-policy-drop-down %} diff --git a/content/admin/policies/index.md b/content/admin/policies/index.md index 2588b9ba09..a11386d423 100644 --- a/content/admin/policies/index.md +++ b/content/admin/policies/index.md @@ -16,6 +16,7 @@ topics: {% topic_link_in_list /enforcing-policies-for-your-enterprise %} {% link_in_list /enforcing-repository-management-policies-in-your-enterprise %} + {% link_in_list /enforcing-policies-for-advanced-security-in-your-enterprise %} {% topic_link_in_list /enforcing-policy-with-pre-receive-hooks %} {% link_in_list /about-pre-receive-hooks %} {% link_in_list /creating-a-pre-receive-hook-environment %} diff --git a/content/admin/user-management/audited-actions.md b/content/admin/user-management/audited-actions.md index eaf820e04b..c1b6e44a3e 100644 --- a/content/admin/user-management/audited-actions.md +++ b/content/admin/user-management/audited-actions.md @@ -53,9 +53,10 @@ Action | Description #### Enterprise configuration settings Action | Description ------------------------------------------------ | ------------------------------------------- -`business.update_member_repository_creation_permission` | A site admin restricts repository creation in organizations in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#setting-a-policy-for-repository-creation)." -`business.clear_members_can_create_repos` | A site admin clears a restriction on repository creation in organizations in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#setting-a-policy-for-repository-creation)."{% if enterpriseServerVersions contains currentVersion %} +----------------------------------------------- | -------------------------------------------{% if currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %} +`business.advanced_security_policy_update` | A site admin updates a policy for {% data variables.product.prodname_GH_advanced_security %}. For more information, see "[About {% data variables.product.prodname_GH_advanced_security %}](/github/getting-started-with-github/about-github-advanced-security)."{% endif %} +`business.clear_members_can_create_repos` | A site admin clears a restriction on repository creation in organizations in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#setting-a-policy-for-repository-creation)." +`business.update_member_repository_creation_permission` | A site admin restricts repository creation in organizations in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#setting-a-policy-for-repository-creation)."{% if enterpriseServerVersions contains currentVersion %} `enterprise.config.lock_anonymous_git_access` | A site admin locks anonymous Git read access to prevent repository admins from changing existing anonymous Git read access settings for repositories in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#configuring-anonymous-git-read-access)." `enterprise.config.unlock_anonymous_git_access` | A site admin unlocks anonymous Git read access to allow repository admins to change existing anonymous Git read access settings for repositories in the enterprise. For more information, see "[Enforcing repository management policies in your enterprise](/admin/policies/enforcing-repository-management-policies-in-your-enterprise#configuring-anonymous-git-read-access)."{% endif %} diff --git a/content/github/getting-started-with-github/about-github-advanced-security.md b/content/github/getting-started-with-github/about-github-advanced-security.md index 89ae0113f8..7edf187a7d 100644 --- a/content/github/getting-started-with-github/about-github-advanced-security.md +++ b/content/github/getting-started-with-github/about-github-advanced-security.md @@ -54,3 +54,17 @@ For other repositories, once you have a license for your enterprise account, you If you have an enterprise account, license use for the entire enterprise is shown on your enterprise license page. For more information, see "[Viewing your {% data variables.product.prodname_GH_advanced_security %} usage](/github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-github-advanced-security-usage)." {% endif %} + +{% if currentVersion == "free-pro-team@latest" %} + +### Further reading + +- "[Enforcing policies for {% data variables.product.prodname_advanced_security %} in your enterprise account](/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account)" + +{% elsif currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %} + +### Further reading + +- "[Enforcing policies for {% data variables.product.prodname_advanced_security %} in your enterprise](/admin/policies/enforcing-policies-for-advanced-security-in-your-enterprise)" + +{% endif %} diff --git a/content/github/setting-up-and-managing-billing-and-payments-on-github/about-licensing-for-github-advanced-security.md b/content/github/setting-up-and-managing-billing-and-payments-on-github/about-licensing-for-github-advanced-security.md index 732af53a92..86893eac64 100644 --- a/content/github/setting-up-and-managing-billing-and-payments-on-github/about-licensing-for-github-advanced-security.md +++ b/content/github/setting-up-and-managing-billing-and-payments-on-github/about-licensing-for-github-advanced-security.md @@ -37,7 +37,9 @@ If you are over your license limit, {% data variables.product.prodname_GH_advanc As soon as you free up some seats, by disabling {% data variables.product.prodname_GH_advanced_security %} for some repositories or by increasing your license size, the options for enabling {% data variables.product.prodname_GH_advanced_security %} will work again as normal. -For information on viewing usage, see "[Viewing your GitHub Advanced Security usage](/github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-github-advanced-security-usage)." +You can enforce policies to allow or disallow the use of {% data variables.product.prodname_advanced_security %} by organizations owned by your enterprise account. For more information, see "[Enforcing policies for {% data variables.product.prodname_advanced_security %} in your enterprise account](/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account)." + +For more information on viewing license usage, see "[Viewing your {% data variables.product.prodname_GH_advanced_security %} usage](/github/setting-up-and-managing-billing-and-payments-on-github/viewing-your-github-advanced-security-usage)." ### Getting the most out of your {% data variables.product.prodname_GH_advanced_security %} license diff --git a/content/github/setting-up-and-managing-organizations-and-teams/reviewing-the-audit-log-for-your-organization.md b/content/github/setting-up-and-managing-organizations-and-teams/reviewing-the-audit-log-for-your-organization.md index dfcc61501b..46b203d484 100644 --- a/content/github/setting-up-and-managing-organizations-and-teams/reviewing-the-audit-log-for-your-organization.md +++ b/content/github/setting-up-and-managing-organizations-and-teams/reviewing-the-audit-log-for-your-organization.md @@ -344,9 +344,9 @@ For more information, see "[Managing the publication of {% data variables.produc #### `org` category actions | Action | Description -|------------------|-------------------{% if currentVersion == "free-pro-team@latest"%} -| `advanced_security_disabled` | Triggered when an organization admin disables {% data variables.product.prodname_GH_advanced_security %} for all existing private and internal repositories. For more information, see "[Managing security and analysis settings for your organization](/github/setting-up-and-managing-organizations-and-teams/managing-security-and-analysis-settings-for-your-organization)." -| `advanced_security_enabled` | Triggered when an organization admin enables {% data variables.product.prodname_GH_advanced_security %} for all existing private and internal repositories. +|------------------|-------------------{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %} +| `advanced_security_policy_selected_member_disabled` | Triggered when an enterprise owner prevents {% data variables.product.prodname_GH_advanced_security %} features from being enabled for repositories owned by the organization. {% data reusables.advanced-security.more-information-about-enforcement-policy %} +| `advanced_security_policy_selected_member_enabled` | Triggered when an enterprise owner allows {% data variables.product.prodname_GH_advanced_security %} features to be enabled for repositories owned by the organization. {% data reusables.advanced-security.more-information-about-enforcement-policy %}{% endif %}{% if currentVersion == "free-pro-team@latest" %} | `audit_log_export` | Triggered when an organization admin [creates an export of the organization audit log](#exporting-the-audit-log). If the export included a query, the log will list the query used and the number of audit log entries matching that query. | `block_user` | Triggered when an organization owner [blocks a user from accessing the organization's repositories](/articles/blocking-a-user-from-your-organization). | `cancel_invitation` | Triggered when an organization invitation has been revoked. {% endif %}{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@2.21" %} @@ -490,9 +490,9 @@ For more information, see "[Managing the publication of {% data variables.produc | `access` | Triggered when a user [changes the visibility](/github/administering-a-repository/setting-repository-visibility) of a repository in the organization. | `actions_enabled` | Triggered when {% data variables.product.prodname_actions %} is enabled for a repository. Can be viewed using the UI. This event is not included when you access the audit log using the REST API. For more information, see "[Using the REST API](#using-the-rest-api)." | `add_member` | Triggered when a user accepts an [invitation to have collaboration access to a repository](/articles/inviting-collaborators-to-a-personal-repository). -| `add_topic` | Triggered when a repository admin [adds a topic](/articles/classifying-your-repository-with-topics) to a repository.{% if currentVersion == "free-pro-team@latest" %} -| `advanced_security_disabled` | Triggered when a repository owner disables {% data variables.product.prodname_GH_advanced_security %}. For more information, see "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)." -| `advanced_security_enabled` | Triggered when a repository owner enables {% data variables.product.prodname_GH_advanced_security %}.{% endif %} +| `add_topic` | Triggered when a repository admin [adds a topic](/articles/classifying-your-repository-with-topics) to a repository.{% if currentVersion == "free-pro-team@latest" or currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %} +| `advanced_security_disabled` | Triggered when a repository administrator disables {% data variables.product.prodname_GH_advanced_security %} features for the repository. For more information, see "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)." +| `advanced_security_enabled` | Triggered when a repository administrator enables {% data variables.product.prodname_GH_advanced_security %} features for the repository. For more information, see "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository).".{% endif %} | `archived` | Triggered when a repository admin [archives a repository](/articles/about-archiving-repositories).{% if enterpriseServerVersions contains currentVersion %} | `config.disable_anonymous_git_access` | Triggered when [anonymous Git read access is disabled](/enterprise/{{ currentVersion }}/user/articles/enabling-anonymous-git-read-access-for-a-repository) in a public repository. | `config.enable_anonymous_git_access` | Triggered when [anonymous Git read access is enabled](/enterprise/{{ currentVersion }}/user/articles/enabling-anonymous-git-read-access-for-a-repository) in a public repository. diff --git a/content/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account.md b/content/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account.md new file mode 100644 index 0000000000..1b9c6ea072 --- /dev/null +++ b/content/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account.md @@ -0,0 +1,21 @@ +--- +title: Enforcing policies for Advanced Security in your enterprise account +intro: 'Enterprise owners can enforce policies to manage {% data variables.product.prodname_GH_advanced_security %} features for organizations owned by an enterprise account.' +product: '{% data reusables.gated-features.ghas %}' +versions: + free-pro-team: '*' +--- + +### About {% data variables.product.prodname_GH_advanced_security %} + +{% data reusables.advanced-security.ghas-helps-developers %} + +### Enforcing a policy for {% data variables.product.prodname_advanced_security %} features + +{% data reusables.advanced-security.about-ghas-organization-policy %} + +{% data reusables.enterprise-accounts.access-enterprise %} +{% data reusables.enterprise-accounts.policies-tab %} +{% data reusables.enterprise-accounts.advanced-security-policies %} +{% data reusables.enterprise-accounts.advanced-security-organization-policy-drop-down %} +{% data reusables.enterprise-accounts.advanced-security-individual-organization-policy-drop-down %} diff --git a/content/github/setting-up-and-managing-your-enterprise/index.md b/content/github/setting-up-and-managing-your-enterprise/index.md index e6f5d91294..3247a26410 100644 --- a/content/github/setting-up-and-managing-your-enterprise/index.md +++ b/content/github/setting-up-and-managing-your-enterprise/index.md @@ -47,4 +47,4 @@ topics: {% link_in_list /enforcing-a-policy-on-dependency-insights-in-your-enterprise-account %} {% link_in_list /enforcing-github-actions-policies-in-your-enterprise-account %} {% link_in_list /configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-enterprise-account %} - + {% link_in_list /enforcing-policies-for-advanced-security-in-your-enterprise-account %} diff --git a/data/reusables/advanced-security/about-ghas-organization-policy.md b/data/reusables/advanced-security/about-ghas-organization-policy.md new file mode 100644 index 0000000000..baa32fddac --- /dev/null +++ b/data/reusables/advanced-security/about-ghas-organization-policy.md @@ -0,0 +1,5 @@ +{% data variables.product.company_short %} bills for {% data variables.product.prodname_advanced_security %} on a per-committer basis. {% if currentVersion == "free-pro-team@latest" %}For more information, see "[Managing licensing for {% data variables.product.prodname_GH_advanced_security %}](/github/setting-up-and-managing-billing-and-payments-on-github/managing-licensing-for-github-advanced-security)."{% endif %} + +You can enforce a policy that controls whether repository administrators are allowed to enable features for {% data variables.product.prodname_advanced_security %} in an organization's repositories. You can configure a policy for all organizations owned by your enterprise account, or for individual organizations that you choose. + +Disallowing {% data variables.product.prodname_advanced_security %} for an organization prevents repository administrators from enabling {% data variables.product.prodname_advanced_security %} features for additional repositories, but does not disable the features for repositories where the features are already enabled. For more information about configuration of {% data variables.product.prodname_advanced_security %} features, see "[Managing security and analysis settings for your organization](/github/setting-up-and-managing-organizations-and-teams/managing-security-and-analysis-settings-for-your-organization)" or "[Managing security and analysis settings for your repository](/github/administering-a-repository/managing-security-and-analysis-settings-for-your-repository)." diff --git a/data/reusables/advanced-security/ghas-helps-developers.md b/data/reusables/advanced-security/ghas-helps-developers.md new file mode 100644 index 0000000000..fcd5fb9586 --- /dev/null +++ b/data/reusables/advanced-security/ghas-helps-developers.md @@ -0,0 +1 @@ +{% data variables.product.prodname_GH_advanced_security %} helps developers improve and maintain the security and quality of code. For more information, see "[About {% data variables.product.prodname_GH_advanced_security %}](/github/getting-started-with-github/about-github-advanced-security)." diff --git a/data/reusables/advanced-security/more-information-about-enforcement-policy.md b/data/reusables/advanced-security/more-information-about-enforcement-policy.md new file mode 100644 index 0000000000..42e973aaac --- /dev/null +++ b/data/reusables/advanced-security/more-information-about-enforcement-policy.md @@ -0,0 +1 @@ +For more information, see "{% if currentVersion == "free-pro-team@latest" %}[Enforcing policies for {% data variables.product.prodname_advanced_security %} in your enterprise account](/github/setting-up-and-managing-your-enterprise/enforcing-policies-for-advanced-security-in-your-enterprise-account){% elsif currentVersion ver_gt "enterprise-server@3.0" or currentVersion == "github-ae@next" %}[Enforcing policies for {% data variables.product.prodname_advanced_security %} in your enterprise](/admin/policies/enforcing-policies-for-advanced-security-in-your-enterprise){% endif %}." diff --git a/data/reusables/enterprise-accounts/advanced-security-individual-organization-policy-drop-down.md b/data/reusables/enterprise-accounts/advanced-security-individual-organization-policy-drop-down.md new file mode 100644 index 0000000000..26f23496fb --- /dev/null +++ b/data/reusables/enterprise-accounts/advanced-security-individual-organization-policy-drop-down.md @@ -0,0 +1,2 @@ +1. Optionally, if you chose **Allow for selected organizations**, to the right of an organization, select the drop-down menu to allow or disallow {% data variables.product.prodname_advanced_security %} for the organization. + ![Drop-down to select Advanced Security policy for individual organization in the enterprise account](/assets/images/help/enterprises/select-advanced-security-individual-organization-policy.png) diff --git a/data/reusables/enterprise-accounts/advanced-security-organization-policy-drop-down.md b/data/reusables/enterprise-accounts/advanced-security-organization-policy-drop-down.md new file mode 100644 index 0000000000..e218baa9e6 --- /dev/null +++ b/data/reusables/enterprise-accounts/advanced-security-organization-policy-drop-down.md @@ -0,0 +1,2 @@ +1. Under "GitHub Advanced Security", select the drop-down menu and click a policy for the organizations owned by your enterprise. + ![Drop-down to select Advanced Security policy for organizations in the enterprise account](/assets/images/help/enterprises/select-advanced-security-organization-policy.png) diff --git a/data/reusables/enterprise-accounts/advanced-security-policies.md b/data/reusables/enterprise-accounts/advanced-security-policies.md new file mode 100644 index 0000000000..8d30974020 --- /dev/null +++ b/data/reusables/enterprise-accounts/advanced-security-policies.md @@ -0,0 +1,2 @@ +1. Under {% octicon "law" aria-label="The law icon" %} **Policies**, click "Advanced Security." + !["Advanced Security" policies in sidebar](/assets/images/help/enterprises/click-advanced-security.png) diff --git a/lib/check-if-next-version-only.js b/lib/check-if-next-version-only.js new file mode 100644 index 0000000000..2cf07d31e8 --- /dev/null +++ b/lib/check-if-next-version-only.js @@ -0,0 +1,13 @@ +const { next, latest } = require('./enterprise-server-releases') +const versionSatisfiesRange = require('./version-satisfies-range') + +// Special handling for frontmatter that evalues to the next GHES release number or a hardcoded `next`: +// we don't want to return it as an applicable version or it will become a permalink, +// but we also don't want to throw an error if no other versions are found. +module.exports = function checkIfNextVersionOnly (value) { + if (value === '*') return false + + const ghesNextVersionOnly = versionSatisfiesRange(next, value) && !versionSatisfiesRange(latest, value) + + return (ghesNextVersionOnly || value === 'next') +} diff --git a/lib/get-applicable-versions.js b/lib/get-applicable-versions.js index ec64f109ff..4d691db9ea 100644 --- a/lib/get-applicable-versions.js +++ b/lib/get-applicable-versions.js @@ -1,6 +1,6 @@ const allVersions = require('./all-versions') -const { next } = require('./enterprise-server-releases') const versionSatisfiesRange = require('./version-satisfies-range') +const checkIfNextVersionOnly = require('./check-if-next-version-only') // return an array of versions that an article's product versions encompasses function getApplicableVersions (frontmatterVersions, filepath) { @@ -16,7 +16,7 @@ function getApplicableVersions (frontmatterVersions, filepath) { // get an array like: [ 'free-pro-team@latest', 'enterprise-server@2.21', 'enterprise-cloud@latest' ] const applicableVersions = [] - let nextVersion = false + let isNextVersionOnly = false // where frontmatter is something like: // free-pro-team: '*' @@ -26,35 +26,24 @@ function getApplicableVersions (frontmatterVersions, filepath) { // ^ where each key corresponds to a plan Object.entries(frontmatterVersions) .forEach(([plan, planValue]) => { - // Special handling for frontmatter that evalues to the next GHES release number or a hardcoded `next`: - // we don't want to return it in the applicable versions array or it will become a permalink, - // but we also don't want to throw an error if no other versions are found. - if (planValue !== '*') { - if (versionSatisfiesRange(next, planValue) || planValue === 'next') { - nextVersion = true - } - } + // Special handling for frontmatter that evalues to the next GHES release number or a hardcoded `next`. + isNextVersionOnly = checkIfNextVersionOnly(planValue) - // for each plan (e.g., enterprise-server), get matching versions from allVersions object - const relevantVersions = Object.values(allVersions).filter(v => v.plan === plan) + // For each plan (e.g., enterprise-server), get matching versions from allVersions object + Object.values(allVersions) + .filter(relevantVersion => relevantVersion.plan === plan) + .forEach(relevantVersion => { + // Use a dummy value of '1.0' for non-numbered versions like free-pro-team and github-ae + // This will evaluate to true against '*' but false against 'next', which is what we want. + const versionToCompare = relevantVersion.hasNumberedReleases ? relevantVersion.currentRelease : '1.0' - if (!relevantVersions.length) { - throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`) - } - - relevantVersions.forEach(relevantVersion => { - // special handling for versions with numbered releases - if (relevantVersion.hasNumberedReleases) { - if (versionSatisfiesRange(relevantVersion.currentRelease, planValue)) { + if (versionSatisfiesRange(versionToCompare, planValue)) { applicableVersions.push(relevantVersion.version) } - } else { - applicableVersions.push(relevantVersion.version) - } - }) + }) }) - if (!applicableVersions.length && !nextVersion) { + if (!applicableVersions.length && !isNextVersionOnly) { throw new Error(`No applicable versions found for ${filepath}. Please double-check the page's \`versions\` frontmatter.`) } diff --git a/tests/unit/pages.js b/tests/unit/pages.js index 5a516e8a81..c2443730fe 100644 --- a/tests/unit/pages.js +++ b/tests/unit/pages.js @@ -8,6 +8,7 @@ const slugger = new GithubSlugger() const Entities = require('html-entities').XmlEntities const entities = new Entities() const { chain, difference } = require('lodash') +const checkIfNextVersionOnly = require('../../lib/check-if-next-version-only') describe('pages module', () => { jest.setTimeout(60 * 1000) @@ -30,7 +31,12 @@ describe('pages module', () => { }) test('every page has a non-empty `permalinks` array', async () => { - const brokenPages = pages.filter(page => !Array.isArray(page.permalinks) || page.permalinks.length === 0) + const brokenPages = pages + .filter(page => !Array.isArray(page.permalinks) || page.permalinks.length === 0) + // Ignore pages that only have "next" versions specified and therefore no permalinks; + // These pages are not broken, they just won't render in the currently supported versions. + .filter(page => !Object.values(page.versions).every(pageVersion => checkIfNextVersionOnly(pageVersion))) + const expectation = JSON.stringify(brokenPages.map(page => page.fullPath), null, 2) expect(brokenPages.length, expectation).toBe(0) })