From e064cd3f07fbc239fb46106a1eaf71379ea01603 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Fri, 29 Jul 2022 00:10:57 +0000 Subject: [PATCH] Add latest changes from gitlab-org/gitlab@master --- .gitlab/CODEOWNERS | 2 +- .../behaviors/components/json_table.vue | 71 ++++++ .../behaviors/markdown/render_gfm.js | 4 + .../behaviors/markdown/render_json_table.js | 70 ++++++ ...d_limit_allowlist_to_namespace_settings.rb | 11 + ...ownload_limit_allowlist_size_constraint.rb | 17 ++ db/schema_migrations/20220718083945 | 1 + db/schema_migrations/20220726025516 | 1 + db/structure.sql | 4 +- doc/administration/index.md | 2 +- .../troubleshooting/group_saml_scim.md | 210 +----------------- doc/administration/troubleshooting/index.md | 2 +- doc/api/groups.md | 10 + .../clusters/management_project_template.md | 13 +- .../group/saml_sso/example_saml_config.md | 207 +++++++++++++++++ doc/user/group/saml_sso/group_sync.md | 6 +- .../saml_sso}/img/AzureAD-basic_SAML.png | Bin .../group/saml_sso}/img/AzureAD-claims.png | Bin .../img/AzureAD-scim_attribute_mapping.png | Bin .../img/AzureAD-scim_provisioning.png | Bin .../img/GoogleWorkspace-basic-SAML_v14_10.png | Bin .../img/GoogleWorkspace-claims_v14_10.png | Bin .../img/GoogleWorkspace-linkscert_v14_10.png | Bin .../group/saml_sso}/img/Okta-SAMLsetup.png | Bin .../saml_sso}/img/Okta-advancedsettings.png | Bin .../group/saml_sso}/img/Okta-attributes.png | Bin .../group/saml_sso}/img/Okta-linkscert.png | Bin .../saml_sso}/img/OneLogin-SSOsettings.png | Bin .../saml_sso}/img/OneLogin-app_details.png | Bin .../saml_sso}/img/OneLogin-parameters.png | Bin .../group/saml_sso}/img/OneLogin-userAdd.png | Bin .../img/azure_configure_group_claim.png | Bin .../saml_sso}/img/okta_admin_panel_v13_9.png | Bin .../saml_sso}/img/okta_saml_settings.png | Bin .../saml_sso}/img/okta_setting_username.png | Bin doc/user/group/saml_sso/index.md | 6 +- doc/user/group/saml_sso/scim_setup.md | 2 +- doc/user/project/deploy_keys/index.md | 2 +- lib/api/entities/group_detail.rb | 3 +- locale/gitlab.pot | 9 + .../project/create_project_badge_spec.rb | 4 - spec/features/markdown/json_table_spec.rb | 40 ++++ spec/frontend/__helpers__/stub_component.js | 8 + .../behaviors/components/json_table_spec.js | 162 ++++++++++++++ .../markdown/render_json_table_spec.js | 119 ++++++++++ 45 files changed, 762 insertions(+), 224 deletions(-) create mode 100644 app/assets/javascripts/behaviors/components/json_table.vue create mode 100644 app/assets/javascripts/behaviors/markdown/render_json_table.js create mode 100644 db/migrate/20220718083945_add_unique_project_download_limit_allowlist_to_namespace_settings.rb create mode 100644 db/migrate/20220726025516_add_namespace_settings_unique_project_download_limit_allowlist_size_constraint.rb create mode 100644 db/schema_migrations/20220718083945 create mode 100644 db/schema_migrations/20220726025516 create mode 100644 doc/user/group/saml_sso/example_saml_config.md rename doc/{administration/troubleshooting => user/group/saml_sso}/img/AzureAD-basic_SAML.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/AzureAD-claims.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/AzureAD-scim_attribute_mapping.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/AzureAD-scim_provisioning.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/GoogleWorkspace-basic-SAML_v14_10.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/GoogleWorkspace-claims_v14_10.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/GoogleWorkspace-linkscert_v14_10.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/Okta-SAMLsetup.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/Okta-advancedsettings.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/Okta-attributes.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/Okta-linkscert.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/OneLogin-SSOsettings.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/OneLogin-app_details.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/OneLogin-parameters.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/OneLogin-userAdd.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/azure_configure_group_claim.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/okta_admin_panel_v13_9.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/okta_saml_settings.png (100%) rename doc/{administration/troubleshooting => user/group/saml_sso}/img/okta_setting_username.png (100%) create mode 100644 spec/features/markdown/json_table_spec.rb create mode 100644 spec/frontend/behaviors/components/json_table_spec.js create mode 100644 spec/frontend/behaviors/markdown/render_json_table_spec.js diff --git a/.gitlab/CODEOWNERS b/.gitlab/CODEOWNERS index 7fcbd782723..b7cc60d2f68 100644 --- a/.gitlab/CODEOWNERS +++ b/.gitlab/CODEOWNERS @@ -283,7 +283,6 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab /doc/administration/timezone.md @axil /doc/administration/troubleshooting/ @axil /doc/administration/troubleshooting/elasticsearch.md @sselhorn -/doc/administration/troubleshooting/group_saml_scim.md @eread /doc/administration/troubleshooting/postgresql.md @aqualls /doc/administration/uploads.md @axil /doc/administration/user_settings.md @eread @@ -710,6 +709,7 @@ lib/gitlab/checks/** @proglottis @toon @zj-gitlab /doc/user/group/saml_sso/group_managed_accounts.md @eread /doc/user/group/saml_sso/index.md @eread /doc/user/group/saml_sso/scim_setup.md @eread +/doc/user/group/saml_sso/example_saml_config.md @eread /doc/user/group/settings/group_access_tokens.md @eread /doc/user/group/settings/import_export.md @eread /doc/user/group/subgroups/index.md @fneill diff --git a/app/assets/javascripts/behaviors/components/json_table.vue b/app/assets/javascripts/behaviors/components/json_table.vue new file mode 100644 index 00000000000..bb38d80c1b5 --- /dev/null +++ b/app/assets/javascripts/behaviors/components/json_table.vue @@ -0,0 +1,71 @@ + + diff --git a/app/assets/javascripts/behaviors/markdown/render_gfm.js b/app/assets/javascripts/behaviors/markdown/render_gfm.js index c9ae3706383..ee5c0fe5ef3 100644 --- a/app/assets/javascripts/behaviors/markdown/render_gfm.js +++ b/app/assets/javascripts/behaviors/markdown/render_gfm.js @@ -5,6 +5,7 @@ import { renderKroki } from './render_kroki'; import renderMath from './render_math'; import renderSandboxedMermaid from './render_sandboxed_mermaid'; import renderMetrics from './render_metrics'; +import { renderJSONTable } from './render_json_table'; // Render GitLab flavoured Markdown // @@ -15,6 +16,9 @@ $.fn.renderGFM = function renderGFM() { renderKroki(this.find('.js-render-kroki[hidden]').get()); renderMath(this.find('.js-render-math')); renderSandboxedMermaid(this.find('.js-render-mermaid')); + renderJSONTable( + Array.from(this.find('[lang="json"][data-lang-params="table"]').get()).map((e) => e.parentNode), + ); highlightCurrentUser(this.find('.gfm-project_member').get()); diff --git a/app/assets/javascripts/behaviors/markdown/render_json_table.js b/app/assets/javascripts/behaviors/markdown/render_json_table.js new file mode 100644 index 00000000000..4d9ac1d266b --- /dev/null +++ b/app/assets/javascripts/behaviors/markdown/render_json_table.js @@ -0,0 +1,70 @@ +import { memoize } from 'lodash'; +import Vue from 'vue'; +import { __ } from '~/locale'; +import { createAlert } from '~/flash'; + +// Async import component since we might not need it... +const JSONTable = memoize(() => + import(/* webpackChunkName: 'gfm_json_table' */ '../components/json_table.vue'), +); + +const mountParseError = (element) => { + // Let the error container be a sibling to the element. + // Otherwise, dismissing the alert causes the copy button to be misplaced. + const container = document.createElement('div'); + element.insertAdjacentElement('beforebegin', container); + + // We need to create a child element with a known selector for `createAlert` + const el = document.createElement('div'); + el.classList.add('js-json-table-error'); + + container.insertAdjacentElement('afterbegin', el); + + return createAlert({ + message: __('Unable to parse JSON'), + variant: 'warning', + parent: container, + containerSelector: '.js-json-table-error', + }); +}; + +const mountJSONTableVueComponent = (userData, element) => { + const { fields = [], items = [], filter, caption } = userData; + + const container = document.createElement('div'); + element.innerHTML = ''; + element.appendChild(container); + + return new Vue({ + el: container, + render(h) { + return h(JSONTable, { + props: { + fields, + items, + hasFilter: filter, + caption, + }, + }); + }, + }); +}; + +const renderTable = (element) => { + // Avoid rendering multiple times + if (!element || element.classList.contains('js-json-table')) { + return; + } + + element.classList.add('js-json-table'); + + try { + mountJSONTableVueComponent(JSON.parse(element.textContent), element); + } catch (e) { + mountParseError(element); + } +}; + +export const renderJSONTable = (elements) => { + elements.forEach(renderTable); +}; diff --git a/db/migrate/20220718083945_add_unique_project_download_limit_allowlist_to_namespace_settings.rb b/db/migrate/20220718083945_add_unique_project_download_limit_allowlist_to_namespace_settings.rb new file mode 100644 index 00000000000..49d9a652472 --- /dev/null +++ b/db/migrate/20220718083945_add_unique_project_download_limit_allowlist_to_namespace_settings.rb @@ -0,0 +1,11 @@ +# frozen_string_literal: true + +class AddUniqueProjectDownloadLimitAllowlistToNamespaceSettings < Gitlab::Database::Migration[2.0] + def change + add_column :namespace_settings, :unique_project_download_limit_allowlist, + :text, + array: true, + default: [], + null: false + end +end diff --git a/db/migrate/20220726025516_add_namespace_settings_unique_project_download_limit_allowlist_size_constraint.rb b/db/migrate/20220726025516_add_namespace_settings_unique_project_download_limit_allowlist_size_constraint.rb new file mode 100644 index 00000000000..bded83f7941 --- /dev/null +++ b/db/migrate/20220726025516_add_namespace_settings_unique_project_download_limit_allowlist_size_constraint.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +class AddNamespaceSettingsUniqueProjectDownloadLimitAllowlistSizeConstraint < Gitlab::Database::Migration[2.0] + CONSTRAINT_NAME = 'namespace_settings_unique_project_download_limit_allowlist_size' + + disable_ddl_transaction! + + def up + add_check_constraint :namespace_settings, + 'CARDINALITY(unique_project_download_limit_allowlist) <= 100', + CONSTRAINT_NAME + end + + def down + remove_check_constraint :namespace_settings, CONSTRAINT_NAME + end +end diff --git a/db/schema_migrations/20220718083945 b/db/schema_migrations/20220718083945 new file mode 100644 index 00000000000..f1d247e5349 --- /dev/null +++ b/db/schema_migrations/20220718083945 @@ -0,0 +1 @@ +42b601de66244f527b8c40182b7c9c8ba3a6ea9863582be3c499ffe2491c8d4f \ No newline at end of file diff --git a/db/schema_migrations/20220726025516 b/db/schema_migrations/20220726025516 new file mode 100644 index 00000000000..58bab5467db --- /dev/null +++ b/db/schema_migrations/20220726025516 @@ -0,0 +1 @@ +326acd1c7e562056d29d5727869a0d0e5a5e9c387b0f54238c79c89f3947808b \ No newline at end of file diff --git a/db/structure.sql b/db/structure.sql index 301b5b50871..ff56ae202e8 100644 --- a/db/structure.sql +++ b/db/structure.sql @@ -17613,7 +17613,9 @@ CREATE TABLE namespace_settings ( unique_project_download_limit_interval_in_seconds integer DEFAULT 0 NOT NULL, project_import_level smallint DEFAULT 50 NOT NULL, include_for_free_user_cap_preview boolean DEFAULT false NOT NULL, - CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)) + unique_project_download_limit_allowlist text[] DEFAULT '{}'::text[] NOT NULL, + CONSTRAINT check_0ba93c78c7 CHECK ((char_length(default_branch_name) <= 255)), + CONSTRAINT namespace_settings_unique_project_download_limit_allowlist_size CHECK ((cardinality(unique_project_download_limit_allowlist) <= 100)) ); CREATE TABLE namespace_statistics ( diff --git a/doc/administration/index.md b/doc/administration/index.md index e618ce5f3bf..d5f59692173 100644 --- a/doc/administration/index.md +++ b/doc/administration/index.md @@ -241,4 +241,4 @@ who are aware of the risks. - [Testing with OpenSSL](https://www.feistyduck.com/library/openssl-cookbook/online/testing-with-openssl/index.html) - [`strace` zine](https://wizardzines.com/zines/strace/) - GitLab.com-specific resources: - - [Group SAML/SCIM setup](troubleshooting/group_saml_scim.md) + - [Example group SAML and SCIM configurations](../user/group/saml_sso/example_saml_config.md) diff --git a/doc/administration/troubleshooting/group_saml_scim.md b/doc/administration/troubleshooting/group_saml_scim.md index 145eb5f65ae..b5187504231 100644 --- a/doc/administration/troubleshooting/group_saml_scim.md +++ b/doc/administration/troubleshooting/group_saml_scim.md @@ -1,207 +1,11 @@ --- -stage: Manage -group: Authentication and Authorization -info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments -type: reference +redirect_to: '../../user/group/saml_sso/example_saml_config.md' +remove_date: '2022-10-29' --- -# Troubleshooting Group SAML and SCIM **(PREMIUM SAAS)** +This document was moved to [another location](../../user/group/saml_sso/example_saml_config.md). -These are notes and screenshots regarding Group SAML and SCIM that the GitLab Support Team sometimes uses while troubleshooting, but which do not fit into the official documentation. GitLab is making this public, so that anyone can make use of the Support team's collected knowledge. - -Please refer to the GitLab [Group SAML](../../user/group/saml_sso/index.md) docs for information on the feature and how to set it up. - -When troubleshooting a SAML configuration, GitLab team members will frequently start with the [SAML troubleshooting section](../../user/group/saml_sso/index.md#troubleshooting). - -They may then set up a test configuration of the desired identity provider. We include example screenshots in this section. - -## SAML and SCIM screenshots - -This section includes relevant screenshots of the following example configurations of [Group SAML](../../user/group/saml_sso/index.md) and [Group SCIM](../../user/group/saml_sso/scim_setup.md): - -- [Azure Active Directory](#azure-active-directory) -- [Google Workspace](#google-workspace) -- [Okta](#okta) -- [OneLogin](#onelogin) - -WARNING: -These screenshots are updated only as needed by GitLab Support. They are **not** official documentation. - -If you are currently having an issue with GitLab, you may want to check your [support options](https://about.gitlab.com/support/). - -## Azure Active Directory - -Basic SAML app configuration: - -![Azure AD basic SAML](img/AzureAD-basic_SAML.png) - -User claims and attributes: - -![Azure AD user claims](img/AzureAD-claims.png) - -SCIM mapping: - -![Azure AD SCIM Provisioning](img/AzureAD-scim_provisioning.png) -![Azure AD SCIM Attribute Mapping](img/AzureAD-scim_attribute_mapping.png) - -Group Sync: - -![Azure Group Claims](img/azure_configure_group_claim.png) - -## Google Workspace - -Basic SAML app configuration: - -![Google Workspace basic SAML](img/GoogleWorkspace-basic-SAML_v14_10.png) - -User claims and attributes: - -![Google Workspace user claims](img/GoogleWorkspace-claims_v14_10.png) - -IdP links and certificate: - -NOTE: -Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint required by GitLab for configuring SAML, download the certificate and calculate the SHA1 certificate -fingerprint. - -![Google Workspace Links and Certificate](img/GoogleWorkspace-linkscert_v14_10.png) - -## Okta - -Basic SAML app configuration: - -![Okta basic SAML](img/Okta-SAMLsetup.png) - -User claims and attributes: - -![Okta Attributes](img/Okta-attributes.png) - -Advanced SAML app settings (defaults): - -![Okta Advanced Settings](img/Okta-advancedsettings.png) - -IdP Links and Certificate: - -![Okta Links and Certificate](img/Okta-linkscert.png) - -Sign on settings: - -![Okta SAML settings](img/okta_saml_settings.png) - -Self-managed instance example: - -![Okta admin panel view](img/okta_admin_panel_v13_9.png) - -Setting the username for the newly provisioned users when assigning them the SCIM app: - -![Assigning SCIM app to users on Okta](img/okta_setting_username.png) - -## OneLogin - -Application details: - -![OneLogin application details](img/OneLogin-app_details.png) - -Parameters: - -![OneLogin application details](img/OneLogin-parameters.png) - -Adding a user: - -![OneLogin user add](img/OneLogin-userAdd.png) - -SSO settings: - -![OneLogin SSO settings](img/OneLogin-SSOsettings.png) - -## SAML response example - -When a user signs in using SAML, GitLab receives a SAML response. The SAML response can be found in `production.log` logs as a base64-encoded message. Locate the response by -searching for `SAMLResponse`. The decoded SAML response is in XML format. For example: - -```xml - - - http://www.okta.com/exk2y6j57o1Pdr2lI8qh7 - - - - - - - - - - - - - neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4= - - - dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7== - - - MIIDq...cptGr3vN9TQ== - - - - - - - - http://www.okta.com/exk2y6j57o1Pdr2lI8qh7 - - - - - - - - - - - - - MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs= - - - dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==< - - - MIIDq...cptGr3vN9TQ== - - - - - useremail@domain.com - - - - - - - https://gitlab.example.com/ - - - - - urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport - - - - - useremail@domain.com - - - John - - - Doe - - - Super-awesome-group - - - - -``` + + + + diff --git a/doc/administration/troubleshooting/index.md b/doc/administration/troubleshooting/index.md index 951ae8d9710..9c5e09b1d65 100644 --- a/doc/administration/troubleshooting/index.md +++ b/doc/administration/troubleshooting/index.md @@ -16,7 +16,7 @@ installation. - [Elasticsearch](elasticsearch.md) - [Sidekiq](sidekiq.md) - [GitLab Rails console cheat sheet](gitlab_rails_cheat_sheet.md) -- [Group SAML and SCIM troubleshooting](group_saml_scim.md) **(PREMIUM SAAS)** +- [Example group SAML and SCIM configurations](../../user/group/saml_sso/example_saml_config.md) - [Kubernetes cheat sheet](https://docs.gitlab.com/charts/troubleshooting/kubernetes_cheat_sheet.html) - [Linux cheat sheet](linux_cheat_sheet.md) - [Parsing GitLab logs with `jq`](../logs/log_parsing.md) diff --git a/doc/api/groups.md b/doc/api/groups.md index 7e1ad9d69db..6e6149e935b 100644 --- a/doc/api/groups.md +++ b/doc/api/groups.md @@ -901,6 +901,13 @@ curl --request POST --header "PRIVATE-TOKEN: " \ ## Update group +> `unique_project_download_limit`, `unique_project_download_limit_interval_in_seconds`, and `unique_project_download_limit_allowlist` [introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/92970) in GitLab 15.3 [with a flag](../administration/feature_flags.md) named `limit_unique_project_downloads_per_namespace_user`. Disabled by default. + +FLAG: +On self-managed GitLab, by default `unique_project_download_limit`, `unique_project_download_limit_interval_in_seconds`, and `unique_project_download_limit_allowlist` are not available. +To make them available, ask an administrator to [enable the feature flag](../administration/feature_flags.md) +named `limit_unique_project_downloads_per_namespace_user`. + Updates the project group. Only available to group owners and administrators. ```plaintext @@ -933,6 +940,9 @@ PUT /groups/:id | `membership_lock` **(PREMIUM)** | boolean | no | Users cannot be added to projects in this group. | | `prevent_forking_outside_group` **(PREMIUM)** | boolean | no | When enabled, users can **not** fork projects from this group to external namespaces. | | `shared_runners_minutes_limit` **(PREMIUM)** | integer | no | Can be set by administrators only. Maximum number of monthly CI/CD minutes for this group. Can be `nil` (default; inherit system default), `0` (unlimited), or `> 0`. | +| `unique_project_download_limit` **(ULTIMATE)** | integer | no | Maximum number of unique projects a user can download in the specified time period before they are banned. Available only on top-level groups. Default: 0, Maximum: 10,000. | +| `unique_project_download_limit_interval_in_seconds` **(ULTIMATE)** | integer | no | Time period during which a user can download a maximum amount of projects before they are banned. Available only on top-level groups. Default: 0, Maximum: 864,000 seconds (10 days). | +| `unique_project_download_limit_allowlist` **(ULTIMATE)** | array of strings | no | List of usernames excluded from the unique project download limit. Available only on top-level groups. Default: `[]`, Maximum: 100 usernames. | NOTE: The `projects` and `shared_projects` attributes in the response are deprecated and [scheduled for removal in API v5](https://gitlab.com/gitlab-org/gitlab/-/issues/213797). diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md index 7ab77c67bcc..4b00784a7ae 100644 --- a/doc/user/clusters/management_project_template.md +++ b/doc/user/clusters/management_project_template.md @@ -15,6 +15,9 @@ to create a project. The project includes cluster applications that integrate wi and extend GitLab functionality. You can use the pattern shown in the project to extend your custom cluster applications. +NOTE: +The project template works on GitLab.com without modifications. If you're on a self-managed instance, you must modify the `.gitlab-ci.yml` file. + ## Use one project for the agent and your manifests If you **have not yet** used the agent to connect your cluster with GitLab: @@ -47,10 +50,7 @@ To create a project from the cluster management project template: 1. From the list of templates, next to **GitLab Cluster Management**, select **Use template**. 1. Enter the project details. 1. Select **Create project**. - -If you use self-managed GitLab, your instance might not include the latest version of the template. -In that case, select **Import project**, **Repository by URL** and for the **Git repository URL**, enter -`https://gitlab.com/gitlab-org/project-templates/cluster-management.git`. +1. In the new project, [configure the files](#configure-the-project) as needed. ## Configure the project @@ -73,6 +73,11 @@ The base image used in the pipeline is built by the [cluster-applications](https://gitlab.com/gitlab-org/cluster-integration/cluster-applications) project. This image contains a set of Bash utility scripts to support [Helm v3 releases](https://helm.sh/docs/intro/using_helm/#three-big-concepts). +If you are on a self-managed instance of GitLab, you must modify the `.gitlab-ci.yml` file. +Specifically, the section that starts with the comment `Automatic package upgrades` will not +work on a self-managed instance, because the `include` refers to a GitLab.com project. +If you remove everything below this comment, the pipeline will succeed. + ### The main `helmfile.yml` file The template contains a [Helmfile](https://github.com/roboll/helmfile) you can use to manage diff --git a/doc/user/group/saml_sso/example_saml_config.md b/doc/user/group/saml_sso/example_saml_config.md new file mode 100644 index 00000000000..fc3d582a291 --- /dev/null +++ b/doc/user/group/saml_sso/example_saml_config.md @@ -0,0 +1,207 @@ +--- +stage: Manage +group: Authentication and Authorization +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments +type: reference +--- + +# Example group SAML and SCIM configurations **(PREMIUM SAAS)** + +These are notes and screenshots regarding Group SAML and SCIM that the GitLab Support Team sometimes uses while troubleshooting, but which do not fit into the official documentation. GitLab is making this public, so that anyone can make use of the Support team's collected knowledge. + +Please refer to the GitLab [Group SAML](index.md) docs for information on the feature and how to set it up. + +When troubleshooting a SAML configuration, GitLab team members will frequently start with the [SAML troubleshooting section](index.md#troubleshooting). + +They may then set up a test configuration of the desired identity provider. We include example screenshots in this section. + +## SAML and SCIM screenshots + +This section includes relevant screenshots of the following example configurations of [Group SAML](index.md) and [Group SCIM](scim_setup.md): + +- [Azure Active Directory](#azure-active-directory) +- [Google Workspace](#google-workspace) +- [Okta](#okta) +- [OneLogin](#onelogin) + +WARNING: +These screenshots are updated only as needed by GitLab Support. They are **not** official documentation. + +If you are currently having an issue with GitLab, you may want to check your [support options](https://about.gitlab.com/support/). + +## Azure Active Directory + +Basic SAML app configuration: + +![Azure AD basic SAML](img/AzureAD-basic_SAML.png) + +User claims and attributes: + +![Azure AD user claims](img/AzureAD-claims.png) + +SCIM mapping: + +![Azure AD SCIM Provisioning](img/AzureAD-scim_provisioning.png) +![Azure AD SCIM Attribute Mapping](img/AzureAD-scim_attribute_mapping.png) + +Group Sync: + +![Azure Group Claims](img/azure_configure_group_claim.png) + +## Google Workspace + +Basic SAML app configuration: + +![Google Workspace basic SAML](img/GoogleWorkspace-basic-SAML_v14_10.png) + +User claims and attributes: + +![Google Workspace user claims](img/GoogleWorkspace-claims_v14_10.png) + +IdP links and certificate: + +NOTE: +Google Workspace displays a SHA256 fingerprint. To retrieve the SHA1 fingerprint required by GitLab for configuring SAML, download the certificate and calculate the SHA1 certificate +fingerprint. + +![Google Workspace Links and Certificate](img/GoogleWorkspace-linkscert_v14_10.png) + +## Okta + +Basic SAML app configuration: + +![Okta basic SAML](img/Okta-SAMLsetup.png) + +User claims and attributes: + +![Okta Attributes](img/Okta-attributes.png) + +Advanced SAML app settings (defaults): + +![Okta Advanced Settings](img/Okta-advancedsettings.png) + +IdP Links and Certificate: + +![Okta Links and Certificate](img/Okta-linkscert.png) + +Sign on settings: + +![Okta SAML settings](img/okta_saml_settings.png) + +Self-managed instance example: + +![Okta admin panel view](img/okta_admin_panel_v13_9.png) + +Setting the username for the newly provisioned users when assigning them the SCIM app: + +![Assigning SCIM app to users on Okta](img/okta_setting_username.png) + +## OneLogin + +Application details: + +![OneLogin application details](img/OneLogin-app_details.png) + +Parameters: + +![OneLogin application details](img/OneLogin-parameters.png) + +Adding a user: + +![OneLogin user add](img/OneLogin-userAdd.png) + +SSO settings: + +![OneLogin SSO settings](img/OneLogin-SSOsettings.png) + +## SAML response example + +When a user signs in using SAML, GitLab receives a SAML response. The SAML response can be found in `production.log` logs as a base64-encoded message. Locate the response by +searching for `SAMLResponse`. The decoded SAML response is in XML format. For example: + +```xml + + + http://www.okta.com/exk2y6j57o1Pdr2lI8qh7 + + + + + + + + + + + + + neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4= + + + dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7== + + + MIIDq...cptGr3vN9TQ== + + + + + + + + http://www.okta.com/exk2y6j57o1Pdr2lI8qh7 + + + + + + + + + + + + + MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs= + + + dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==< + + + MIIDq...cptGr3vN9TQ== + + + + + useremail@domain.com + + + + + + + https://gitlab.example.com/ + + + + + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + + + + + useremail@domain.com + + + John + + + Doe + + + Super-awesome-group + + + + +``` diff --git a/doc/user/group/saml_sso/group_sync.md b/doc/user/group/saml_sso/group_sync.md index b8b7a16b31b..c3328331d1c 100644 --- a/doc/user/group/saml_sso/group_sync.md +++ b/doc/user/group/saml_sso/group_sync.md @@ -28,7 +28,7 @@ To configure SAML Group Sync: 1. Ensure your SAML identity provider sends an attribute statement with the same name as the value of the `groups_attribute` setting. - For GitLab.com: 1. See [SAML SSO for GitLab.com groups](index.md). - 1. Ensure your SAML identity provider sends an attribute statement named `Groups` or `groups`. + 1. Ensure your SAML identity provider sends an attribute statement named `Groups` or `groups`. NOTE: The value for `Groups` or `groups` in the SAML response can be either the group name or the group ID. @@ -44,8 +44,8 @@ The value for `Groups` or `groups` in the SAML response can be either the group Other attribute names such as `http://schemas.microsoft.com/ws/2008/06/identity/claims/groups` are not accepted as a source of groups. -See the [SAML troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md) -for examples on configuring the required attribute name in the SAML identity provider's settings. +See [examples](../../../user/group/saml_sso/example_saml_config.md) +for configuring the required attribute name in the SAML identity provider's settings. ## Configure SAML Group Links diff --git a/doc/administration/troubleshooting/img/AzureAD-basic_SAML.png b/doc/user/group/saml_sso/img/AzureAD-basic_SAML.png similarity index 100% rename from doc/administration/troubleshooting/img/AzureAD-basic_SAML.png rename to doc/user/group/saml_sso/img/AzureAD-basic_SAML.png diff --git a/doc/administration/troubleshooting/img/AzureAD-claims.png b/doc/user/group/saml_sso/img/AzureAD-claims.png similarity index 100% rename from doc/administration/troubleshooting/img/AzureAD-claims.png rename to doc/user/group/saml_sso/img/AzureAD-claims.png diff --git a/doc/administration/troubleshooting/img/AzureAD-scim_attribute_mapping.png b/doc/user/group/saml_sso/img/AzureAD-scim_attribute_mapping.png similarity index 100% rename from doc/administration/troubleshooting/img/AzureAD-scim_attribute_mapping.png rename to doc/user/group/saml_sso/img/AzureAD-scim_attribute_mapping.png diff --git a/doc/administration/troubleshooting/img/AzureAD-scim_provisioning.png b/doc/user/group/saml_sso/img/AzureAD-scim_provisioning.png similarity index 100% rename from doc/administration/troubleshooting/img/AzureAD-scim_provisioning.png rename to doc/user/group/saml_sso/img/AzureAD-scim_provisioning.png diff --git a/doc/administration/troubleshooting/img/GoogleWorkspace-basic-SAML_v14_10.png b/doc/user/group/saml_sso/img/GoogleWorkspace-basic-SAML_v14_10.png similarity index 100% rename from doc/administration/troubleshooting/img/GoogleWorkspace-basic-SAML_v14_10.png rename to doc/user/group/saml_sso/img/GoogleWorkspace-basic-SAML_v14_10.png diff --git a/doc/administration/troubleshooting/img/GoogleWorkspace-claims_v14_10.png b/doc/user/group/saml_sso/img/GoogleWorkspace-claims_v14_10.png similarity index 100% rename from doc/administration/troubleshooting/img/GoogleWorkspace-claims_v14_10.png rename to doc/user/group/saml_sso/img/GoogleWorkspace-claims_v14_10.png diff --git a/doc/administration/troubleshooting/img/GoogleWorkspace-linkscert_v14_10.png b/doc/user/group/saml_sso/img/GoogleWorkspace-linkscert_v14_10.png similarity index 100% rename from doc/administration/troubleshooting/img/GoogleWorkspace-linkscert_v14_10.png rename to doc/user/group/saml_sso/img/GoogleWorkspace-linkscert_v14_10.png diff --git a/doc/administration/troubleshooting/img/Okta-SAMLsetup.png b/doc/user/group/saml_sso/img/Okta-SAMLsetup.png similarity index 100% rename from doc/administration/troubleshooting/img/Okta-SAMLsetup.png rename to doc/user/group/saml_sso/img/Okta-SAMLsetup.png diff --git a/doc/administration/troubleshooting/img/Okta-advancedsettings.png b/doc/user/group/saml_sso/img/Okta-advancedsettings.png similarity index 100% rename from doc/administration/troubleshooting/img/Okta-advancedsettings.png rename to doc/user/group/saml_sso/img/Okta-advancedsettings.png diff --git a/doc/administration/troubleshooting/img/Okta-attributes.png b/doc/user/group/saml_sso/img/Okta-attributes.png similarity index 100% rename from doc/administration/troubleshooting/img/Okta-attributes.png rename to doc/user/group/saml_sso/img/Okta-attributes.png diff --git a/doc/administration/troubleshooting/img/Okta-linkscert.png b/doc/user/group/saml_sso/img/Okta-linkscert.png similarity index 100% rename from doc/administration/troubleshooting/img/Okta-linkscert.png rename to doc/user/group/saml_sso/img/Okta-linkscert.png diff --git a/doc/administration/troubleshooting/img/OneLogin-SSOsettings.png b/doc/user/group/saml_sso/img/OneLogin-SSOsettings.png similarity index 100% rename from doc/administration/troubleshooting/img/OneLogin-SSOsettings.png rename to doc/user/group/saml_sso/img/OneLogin-SSOsettings.png diff --git a/doc/administration/troubleshooting/img/OneLogin-app_details.png b/doc/user/group/saml_sso/img/OneLogin-app_details.png similarity index 100% rename from doc/administration/troubleshooting/img/OneLogin-app_details.png rename to doc/user/group/saml_sso/img/OneLogin-app_details.png diff --git a/doc/administration/troubleshooting/img/OneLogin-parameters.png b/doc/user/group/saml_sso/img/OneLogin-parameters.png similarity index 100% rename from doc/administration/troubleshooting/img/OneLogin-parameters.png rename to doc/user/group/saml_sso/img/OneLogin-parameters.png diff --git a/doc/administration/troubleshooting/img/OneLogin-userAdd.png b/doc/user/group/saml_sso/img/OneLogin-userAdd.png similarity index 100% rename from doc/administration/troubleshooting/img/OneLogin-userAdd.png rename to doc/user/group/saml_sso/img/OneLogin-userAdd.png diff --git a/doc/administration/troubleshooting/img/azure_configure_group_claim.png b/doc/user/group/saml_sso/img/azure_configure_group_claim.png similarity index 100% rename from doc/administration/troubleshooting/img/azure_configure_group_claim.png rename to doc/user/group/saml_sso/img/azure_configure_group_claim.png diff --git a/doc/administration/troubleshooting/img/okta_admin_panel_v13_9.png b/doc/user/group/saml_sso/img/okta_admin_panel_v13_9.png similarity index 100% rename from doc/administration/troubleshooting/img/okta_admin_panel_v13_9.png rename to doc/user/group/saml_sso/img/okta_admin_panel_v13_9.png diff --git a/doc/administration/troubleshooting/img/okta_saml_settings.png b/doc/user/group/saml_sso/img/okta_saml_settings.png similarity index 100% rename from doc/administration/troubleshooting/img/okta_saml_settings.png rename to doc/user/group/saml_sso/img/okta_saml_settings.png diff --git a/doc/administration/troubleshooting/img/okta_setting_username.png b/doc/user/group/saml_sso/img/okta_setting_username.png similarity index 100% rename from doc/administration/troubleshooting/img/okta_setting_username.png rename to doc/user/group/saml_sso/img/okta_setting_username.png diff --git a/doc/user/group/saml_sso/index.md b/doc/user/group/saml_sso/index.md index 80e7a5903fa..a442e909557 100644 --- a/doc/user/group/saml_sso/index.md +++ b/doc/user/group/saml_sso/index.md @@ -174,7 +174,7 @@ The recommended attributes and claims settings are: If using [Group Sync](#group-sync), customize the name of the group claim to match the required attribute. -See the [troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md#azure-active-directory) for an example configuration. +See our [example configuration page](example_saml_config.md#azure-active-directory). ### Google Workspace setup notes @@ -206,7 +206,7 @@ For NameID, the following settings are recommended: When selecting **Verify SAML Configuration** on the GitLab SAML SSO page, disregard the warning recommending setting the NameID format to "persistent". -See the [troubleshooting page](../../../administration/troubleshooting/group_saml_scim.md#google-workspace) for an example configuration. +See our [example configuration page](example_saml_config.md#google-workspace). ### Okta setup notes @@ -445,7 +445,7 @@ To generate a SAML Response: ### Verifying configuration -For convenience, we've included some [example resources](../../../administration/troubleshooting/group_saml_scim.md) used by our Support Team. While they may help you verify the SAML app configuration, they are not guaranteed to reflect the current state of third-party products. +For convenience, we've included some [example resources](../../../user/group/saml_sso/example_saml_config.md) used by our Support Team. While they may help you verify the SAML app configuration, they are not guaranteed to reflect the current state of third-party products. ### Verifying NameID diff --git a/doc/user/group/saml_sso/scim_setup.md b/doc/user/group/saml_sso/scim_setup.md index 04aa99e08af..e7c98e0ae08 100644 --- a/doc/user/group/saml_sso/scim_setup.md +++ b/doc/user/group/saml_sso/scim_setup.md @@ -82,7 +82,7 @@ For a list of required attributes, refer to the [SCIM API documentation](../../. | `userPrincipalName` | `emails[type eq "work"].value` | | | `mailNickname` | `userName` | | -For guidance, you can view [an example configuration in the troubleshooting reference](../../../administration/troubleshooting/group_saml_scim.md#azure-active-directory). +For guidance, you can view [an example configuration](example_saml_config.md#azure-active-directory). 1. Below the mapping list select **Show advanced options > Edit attribute list for AppName**. 1. Ensure the `id` is the primary and required field, and `externalId` is also required. diff --git a/doc/user/project/deploy_keys/index.md b/doc/user/project/deploy_keys/index.md index c64afd95d8d..c997d93b71b 100644 --- a/doc/user/project/deploy_keys/index.md +++ b/doc/user/project/deploy_keys/index.md @@ -9,7 +9,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w Use deploy keys to access repositories that are hosted in GitLab. In most cases, you use deploy keys to access a repository from an external host, like a build server or Continuous Integration (CI) server. -Depending on your needs, you might want to use a [deploy token](../deploy_tokens/) to access a repository instead. +Depending on your needs, you might want to use a [deploy token](../deploy_tokens/index.md) to access a repository instead. | Attribute | Deploy key | Deploy token | |------------------|-------------|--------------| diff --git a/lib/api/entities/group_detail.rb b/lib/api/entities/group_detail.rb index e521de0d572..7b05984421a 100644 --- a/lib/api/entities/group_detail.rb +++ b/lib/api/entities/group_detail.rb @@ -7,7 +7,8 @@ module API SharedGroupWithGroup.represent(group.shared_with_group_links_visible_to_user(options[:current_user])) end expose :runners_token, if: ->(_, options) { options[:user_can_admin_group] } - expose :prevent_sharing_groups_outside_hierarchy, if: ->(group) { group.root? } + expose :prevent_sharing_groups_outside_hierarchy, + if: ->(group) { group.root? && group.namespace_settings.present? } expose :projects, if: ->(_, options) { options[:with_projects] }, diff --git a/locale/gitlab.pot b/locale/gitlab.pot index a7a28880e63..8bf822378fd 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -16816,6 +16816,9 @@ msgstr "" msgid "Generate site and private keys at" msgstr "" +msgid "Generated with JSON data" +msgstr "" + msgid "Generic" msgstr "" @@ -41281,6 +41284,9 @@ msgstr "" msgid "Type" msgstr "" +msgid "Type to search" +msgstr "" + msgid "U2F Devices (%{length})" msgstr "" @@ -41401,6 +41407,9 @@ msgstr "" msgid "Unable to load the merge request widget. Try reloading the page." msgstr "" +msgid "Unable to parse JSON" +msgstr "" + msgid "Unable to parse the vulnerability report's options." msgstr "" diff --git a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb index 3921595204c..f624f2fb44f 100644 --- a/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb +++ b/qa/qa/specs/features/browser_ui/1_manage/project/create_project_badge_spec.rb @@ -42,10 +42,6 @@ module QA expect(project.asset_exists?(expected_badge_image_url)).to be_truthy end end - - after do - project&.remove_via_api! - end end end end diff --git a/spec/features/markdown/json_table_spec.rb b/spec/features/markdown/json_table_spec.rb new file mode 100644 index 00000000000..6b74dbac255 --- /dev/null +++ b/spec/features/markdown/json_table_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'Rendering json:table code block in markdown', :js do + let_it_be(:project) { create(:project, :public) } + + it 'creates table correctly' do + description = <<~JSONTABLE + Hello world! + + ```json:table + { + "fields" : [ + {"key": "a", "label": "AA"}, + {"key": "b", "label": "BB"} + ], + "items" : [ + {"a": "11", "b": "22"}, + {"a": "211", "b": "222"} + ] + } + ``` + JSONTABLE + + issue = create(:issue, project: project, description: description) + + visit project_issue_path(project, issue) + + wait_for_requests + + within ".js-json-table table" do + headers = all("thead th").collect { |column| column.text.strip } + data = all("tbody td").collect { |column| column.text.strip } + + expect(headers).to eql(%w[AA BB]) + expect(data).to eql(%w[11 22 211 222]) + end + end +end diff --git a/spec/frontend/__helpers__/stub_component.js b/spec/frontend/__helpers__/stub_component.js index 96fe3a8bc45..4f9d1ee6f5d 100644 --- a/spec/frontend/__helpers__/stub_component.js +++ b/spec/frontend/__helpers__/stub_component.js @@ -22,6 +22,14 @@ const createStubbedMethods = (methods = {}) => { ); }; +export const RENDER_ALL_SLOTS_TEMPLATE = `
+ +
`; + export function stubComponent(Component, options = {}) { return { props: Component.props, diff --git a/spec/frontend/behaviors/components/json_table_spec.js b/spec/frontend/behaviors/components/json_table_spec.js new file mode 100644 index 00000000000..42b4a051d4d --- /dev/null +++ b/spec/frontend/behaviors/components/json_table_spec.js @@ -0,0 +1,162 @@ +import { GlTable, GlFormInput } from '@gitlab/ui'; +import { nextTick } from 'vue'; +import { merge } from 'lodash'; +import { shallowMountExtended, mountExtended } from 'helpers/vue_test_utils_helper'; +import { stubComponent, RENDER_ALL_SLOTS_TEMPLATE } from 'helpers/stub_component'; +import JSONTable from '~/behaviors/components/json_table.vue'; + +const TEST_FIELDS = [ + 'A', + { + key: 'B', + label: 'Second', + sortable: true, + other: 'foo', + }, + { + key: 'C', + label: 'Third', + }, + 'D', +]; +const TEST_ITEMS = [ + { A: 1, B: 'lorem', C: 2, D: null, E: 'dne' }, + { A: 2, B: 'ipsum', C: 2, D: null, E: 'dne' }, + { A: 3, B: 'dolar', C: 2, D: null, E: 'dne' }, +]; + +describe('behaviors/components/json_table', () => { + let wrapper; + + const buildWrapper = ({ + fields = [], + items = [], + filter = undefined, + caption = undefined, + } = {}) => { + wrapper = shallowMountExtended(JSONTable, { + propsData: { + fields, + items, + hasFilter: filter, + caption, + }, + stubs: { + GlTable: merge(stubComponent(GlTable), { + props: { + fields: { + type: Array, + required: true, + }, + items: { + type: Array, + required: true, + }, + }, + template: RENDER_ALL_SLOTS_TEMPLATE, + }), + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findTable = () => wrapper.findComponent(GlTable); + const findTableCaption = () => wrapper.findByTestId('slot-table-caption'); + const findFilterInput = () => wrapper.findComponent(GlFormInput); + + describe('default', () => { + beforeEach(() => { + buildWrapper(); + }); + + it('renders gltable', () => { + expect(findTable().props()).toEqual({ + fields: [], + items: [], + }); + expect(findTable().attributes()).toMatchObject({ + filter: '', + 'show-empty': '', + }); + }); + + it('does not render filter input', () => { + expect(findFilterInput().exists()).toBe(false); + }); + + it('renders caption', () => { + expect(findTableCaption().text()).toBe('Generated with JSON data'); + }); + }); + + describe('with filter', () => { + beforeEach(() => { + buildWrapper({ + filter: true, + }); + }); + + it('renders filter input', () => { + expect(findFilterInput().attributes()).toMatchObject({ + value: '', + placeholder: 'Type to search', + }); + }); + + it('when input is changed, updates table filter', async () => { + findFilterInput().vm.$emit('input', 'New value!'); + + await nextTick(); + + expect(findTable().attributes('filter')).toBe('New value!'); + }); + }); + + describe('with fields', () => { + beforeEach(() => { + buildWrapper({ + fields: TEST_FIELDS, + items: TEST_ITEMS, + }); + }); + + it('passes cleaned fields and items to table', () => { + expect(findTable().props()).toEqual({ + fields: [ + 'A', + { + key: 'B', + label: 'Second', + sortable: true, + }, + { + key: 'C', + label: 'Third', + sortable: false, + }, + 'D', + ], + items: TEST_ITEMS, + }); + }); + }); + + describe('with full mount', () => { + beforeEach(() => { + wrapper = mountExtended(JSONTable, { + propsData: { + fields: [], + items: [], + }, + }); + }); + + // We want to make sure all the props are passed down nicely in integration + it('renders table without errors', () => { + expect(findTable().exists()).toBe(true); + }); + }); +}); diff --git a/spec/frontend/behaviors/markdown/render_json_table_spec.js b/spec/frontend/behaviors/markdown/render_json_table_spec.js new file mode 100644 index 00000000000..488492479f3 --- /dev/null +++ b/spec/frontend/behaviors/markdown/render_json_table_spec.js @@ -0,0 +1,119 @@ +import { nextTick } from 'vue'; +import { renderJSONTable } from '~/behaviors/markdown/render_json_table'; + +describe('behaviors/markdown/render_json_table', () => { + let element; + + const TEST_DATA = { + fields: [ + { label: 'Field 1', key: 'a' }, + { label: 'F 2', key: 'b' }, + { label: 'F 3', key: 'c' }, + ], + items: [ + { + a: '1', + b: 'b', + c: 'c', + }, + { + a: '2', + b: 'd', + c: 'e', + }, + ], + }; + const TEST_LABELS = TEST_DATA.fields.map((x) => x.label); + + const tableAsData = (table) => ({ + head: Array.from(table.querySelectorAll('thead th')).map((td) => td.textContent), + body: Array.from(table.querySelectorAll('tbody > tr')).map((tr) => + Array.from(tr.querySelectorAll('td')).map((x) => x.textContent), + ), + }); + + const createTestSubject = async (json) => { + if (element) { + throw new Error('element has already been initialized'); + } + + const parent = document.createElement('div'); + const pre = document.createElement('pre'); + + pre.textContent = json; + parent.appendChild(pre); + + document.body.appendChild(parent); + renderJSONTable([parent]); + + element = parent; + + jest.runAllTimers(); + + await nextTick(); + }; + + const findPres = () => document.querySelectorAll('pre'); + const findTables = () => document.querySelectorAll('table'); + const findAlerts = () => document.querySelectorAll('.gl-alert'); + const findInputs = () => document.querySelectorAll('.gl-form-input'); + + afterEach(() => { + document.body.innerHTML = ''; + element = null; + }); + + describe('default', () => { + beforeEach(async () => { + await createTestSubject(JSON.stringify(TEST_DATA, null, 2)); + }); + + it('removes pre', () => { + expect(findPres()).toHaveLength(0); + }); + + it('replaces pre with table', () => { + const tables = findTables(); + + expect(tables).toHaveLength(1); + expect(tableAsData(tables[0])).toEqual({ + head: TEST_LABELS, + body: [ + ['1', 'b', 'c'], + ['2', 'd', 'e'], + ], + }); + }); + + it('does not show filter', () => { + expect(findInputs()).toHaveLength(0); + }); + }); + + describe('with invalid json', () => { + beforeEach(() => { + createTestSubject('funky but not json'); + }); + + it('preserves pre', () => { + expect(findPres()).toHaveLength(1); + }); + + it('shows alert', () => { + const alerts = findAlerts(); + + expect(alerts).toHaveLength(1); + expect(alerts[0].textContent).toMatchInterpolatedText('Unable to parse JSON'); + }); + }); + + describe('with filter set', () => { + beforeEach(() => { + createTestSubject(JSON.stringify({ ...TEST_DATA, filter: true })); + }); + + it('shows filter', () => { + expect(findInputs()).toHaveLength(1); + }); + }); +});