Add latest changes from gitlab-org/gitlab@master
|
@ -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
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
<script>
|
||||
import { GlTable, GlFormInput } from '@gitlab/ui';
|
||||
import { __ } from '~/locale';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlTable,
|
||||
GlFormInput,
|
||||
},
|
||||
props: {
|
||||
fields: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
items: {
|
||||
type: Array,
|
||||
required: true,
|
||||
},
|
||||
hasFilter: {
|
||||
type: Boolean,
|
||||
required: false,
|
||||
default: false,
|
||||
},
|
||||
caption: {
|
||||
type: String,
|
||||
required: false,
|
||||
default: __('Generated with JSON data'),
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
filterInput: '',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
cleanedFields() {
|
||||
return this.fields.map((field) => {
|
||||
if (typeof field === 'string') {
|
||||
return field;
|
||||
}
|
||||
return {
|
||||
key: field.key,
|
||||
label: field.label,
|
||||
sortable: field.sortable || false,
|
||||
};
|
||||
});
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
<template>
|
||||
<div class="gl-display-inline-block">
|
||||
<gl-form-input
|
||||
v-if="hasFilter"
|
||||
v-model="filterInput"
|
||||
:placeholder="__('Type to search')"
|
||||
class="gl-mb-2!"
|
||||
/>
|
||||
<gl-table
|
||||
:fields="cleanedFields"
|
||||
:items="items"
|
||||
:filter="filterInput"
|
||||
show-empty
|
||||
class="gl-mt-0!"
|
||||
>
|
||||
<template v-if="caption" #table-caption>
|
||||
<small>{{ caption }}</small>
|
||||
</template>
|
||||
</gl-table>
|
||||
</div>
|
||||
</template>
|
|
@ -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());
|
||||
|
||||
|
|
|
@ -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);
|
||||
};
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
42b601de66244f527b8c40182b7c9c8ba3a6ea9863582be3c499ffe2491c8d4f
|
|
@ -0,0 +1 @@
|
|||
326acd1c7e562056d29d5727869a0d0e5a5e9c387b0f54238c79c89f3947808b
|
|
@ -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 (
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://gitlabexample/-/saml/callback" ID="id4898983630840142426821432" InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference URI="#id4898983630840142426821432">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
|
||||
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==</ds:SignatureValue>
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature>
|
||||
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
|
||||
</saml2p:Status>
|
||||
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id489" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference URI="#id48989836309833801859473359">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
|
||||
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==<</ds:SignatureValue>
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature>
|
||||
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
|
||||
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">useremail@domain.com</saml2:NameID>
|
||||
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml2:SubjectConfirmationData InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" NotOnOrAfter="2022-05-30T21:35:35.696Z" Recipient="https://gitlab.example.com/-/saml/callback"/>
|
||||
</saml2:SubjectConfirmation>
|
||||
</saml2:Subject>
|
||||
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2022-05-30T21:25:35.696Z" NotOnOrAfter="2022-05-30T21:35:35.696Z">
|
||||
<saml2:AudienceRestriction>
|
||||
<saml2:Audience>https://gitlab.example.com/</saml2:Audience>
|
||||
</saml2:AudienceRestriction>
|
||||
</saml2:Conditions>
|
||||
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2022-05-30T21:30:35.696Z" SessionIndex="_c65e4c88-9425-4472-b42c-37f4186ac0ee">
|
||||
<saml2:AuthnContext>
|
||||
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
|
||||
</saml2:AuthnContext>
|
||||
</saml2:AuthnStatement>
|
||||
<saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
|
||||
<saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">useremail@domain.com</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="firtname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">John</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="lastname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Doe</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="Groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Super-awesome-group</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
</saml2:AttributeStatement>
|
||||
</saml2:Assertion>
|
||||
</saml2p:Response>
|
||||
```
|
||||
<!-- This redirect file can be deleted after <2022-10-29>. -->
|
||||
<!-- Redirects that point to other docs in the same project expire in three months. -->
|
||||
<!-- Redirects that point to docs in a different project or site (link is not relative and starts with `https:`) expire in one year. -->
|
||||
<!-- Before deletion, see: https://docs.gitlab.com/ee/development/documentation/redirects.html -->
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -901,6 +901,13 @@ curl --request POST --header "PRIVATE-TOKEN: <your_access_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).
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<saml2p:Response xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol" xmlns:xs="http://www.w3.org/2001/XMLSchema" Destination="https://gitlabexample/-/saml/callback" ID="id4898983630840142426821432" InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference URI="#id4898983630840142426821432">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
|
||||
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>neiQvv9d3OgS4GZW8Nptp4JhjpKs3GCefibn+vmRgk4=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==</ds:SignatureValue>
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature>
|
||||
<saml2p:Status xmlns:saml2p="urn:oasis:names:tc:SAML:2.0:protocol">
|
||||
<saml2p:StatusCode Value="urn:oasis:names:tc:SAML:2.0:status:Success"/>
|
||||
</saml2p:Status>
|
||||
<saml2:Assertion xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:xs="http://www.w3.org/2001/XMLSchema" ID="id489" IssueInstant="2022-05-30T21:30:35.696Z" Version="2.0">
|
||||
<saml2:Issuer xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" Format="urn:oasis:names:tc:SAML:2.0:nameid-format:entity">http://www.okta.com/exk2y6j57o1Pdr2lI8qh7</saml2:Issuer>
|
||||
<ds:Signature xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
|
||||
<ds:SignedInfo>
|
||||
<ds:CanonicalizationMethod Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#"/>
|
||||
<ds:SignatureMethod Algorithm="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"/>
|
||||
<ds:Reference URI="#id48989836309833801859473359">
|
||||
<ds:Transforms>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2000/09/xmldsig#enveloped-signature"/>
|
||||
<ds:Transform Algorithm="http://www.w3.org/2001/10/xml-exc-c14n#">
|
||||
<ec:InclusiveNamespaces xmlns:ec="http://www.w3.org/2001/10/xml-exc-c14n#" PrefixList="xs"/>
|
||||
</ds:Transform>
|
||||
</ds:Transforms>
|
||||
<ds:DigestMethod Algorithm="http://www.w3.org/2001/04/xmlenc#sha256"/>
|
||||
<ds:DigestValue>MaIsoi8hbT9gsi/mNZsz449mUuAcuEWY0q3bc4asOQs=</ds:DigestValue>
|
||||
</ds:Reference>
|
||||
</ds:SignedInfo>
|
||||
<ds:SignatureValue>dMsQX8ivi...HMuKGhyLRvabGU6CuPrf7==<</ds:SignatureValue>
|
||||
<ds:KeyInfo>
|
||||
<ds:X509Data>
|
||||
<ds:X509Certificate>MIIDq...cptGr3vN9TQ==</ds:X509Certificate>
|
||||
</ds:X509Data>
|
||||
</ds:KeyInfo>
|
||||
</ds:Signature>
|
||||
<saml2:Subject xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
|
||||
<saml2:NameID Format="urn:oasis:names:tc:SAML:2.0:nameid-format:persistent">useremail@domain.com</saml2:NameID>
|
||||
<saml2:SubjectConfirmation Method="urn:oasis:names:tc:SAML:2.0:cm:bearer">
|
||||
<saml2:SubjectConfirmationData InResponseTo="_c65e4c88-9425-4472-b42c-37f4186ac0ee" NotOnOrAfter="2022-05-30T21:35:35.696Z" Recipient="https://gitlab.example.com/-/saml/callback"/>
|
||||
</saml2:SubjectConfirmation>
|
||||
</saml2:Subject>
|
||||
<saml2:Conditions xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" NotBefore="2022-05-30T21:25:35.696Z" NotOnOrAfter="2022-05-30T21:35:35.696Z">
|
||||
<saml2:AudienceRestriction>
|
||||
<saml2:Audience>https://gitlab.example.com/</saml2:Audience>
|
||||
</saml2:AudienceRestriction>
|
||||
</saml2:Conditions>
|
||||
<saml2:AuthnStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion" AuthnInstant="2022-05-30T21:30:35.696Z" SessionIndex="_c65e4c88-9425-4472-b42c-37f4186ac0ee">
|
||||
<saml2:AuthnContext>
|
||||
<saml2:AuthnContextClassRef>urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport</saml2:AuthnContextClassRef>
|
||||
</saml2:AuthnContext>
|
||||
</saml2:AuthnStatement>
|
||||
<saml2:AttributeStatement xmlns:saml2="urn:oasis:names:tc:SAML:2.0:assertion">
|
||||
<saml2:Attribute Name="email" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">useremail@domain.com</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="firtname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">John</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="lastname" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Doe</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
<saml2:Attribute Name="Groups" NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified">
|
||||
<saml2:AttributeValue xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="xs:string">Super-awesome-group</saml2:AttributeValue>
|
||||
</saml2:Attribute>
|
||||
</saml2:AttributeStatement>
|
||||
</saml2:Assertion>
|
||||
</saml2p:Response>
|
||||
```
|
|
@ -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
|
||||
|
||||
|
|
Before Width: | Height: | Size: 99 KiB After Width: | Height: | Size: 99 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 78 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 38 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 5.4 KiB |
Before Width: | Height: | Size: 58 KiB After Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 9.8 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
@ -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
|
||||
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 |
|
||||
|------------------|-------------|--------------|
|
||||
|
|
|
@ -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] },
|
||||
|
|
|
@ -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 ""
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -22,6 +22,14 @@ const createStubbedMethods = (methods = {}) => {
|
|||
);
|
||||
};
|
||||
|
||||
export const RENDER_ALL_SLOTS_TEMPLATE = `<div>
|
||||
<template v-for="(_, name) in $scopedSlots">
|
||||
<div :data-testid="'slot-' + name">
|
||||
<slot :name="name" />
|
||||
</div>
|
||||
</template>
|
||||
</div>`;
|
||||
|
||||
export function stubComponent(Component, options = {}) {
|
||||
return {
|
||||
props: Component.props,
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|