diff options
49 files changed, 425 insertions, 159 deletions
diff --git a/app/assets/javascripts/static_site_editor/components/edit_area.vue b/app/assets/javascripts/static_site_editor/components/edit_area.vue index e602f26acdf..56f1a26f005 100644 --- a/app/assets/javascripts/static_site_editor/components/edit_area.vue +++ b/app/assets/javascripts/static_site_editor/components/edit_area.vue @@ -37,6 +37,10 @@ export default { required: false, default: '', }, + mounts: { + type: Array, + required: true, + }, imageRoot: { type: String, required: false, diff --git a/app/assets/javascripts/static_site_editor/graphql/index.js b/app/assets/javascripts/static_site_editor/graphql/index.js index cc68bc57bb0..a13f7d3ad53 100644 --- a/app/assets/javascripts/static_site_editor/graphql/index.js +++ b/app/assets/javascripts/static_site_editor/graphql/index.js @@ -25,11 +25,15 @@ const createApolloProvider = appData => { }, ); + // eslint-disable-next-line @gitlab/require-i18n-strings + const mounts = appData.mounts.map(mount => ({ __typename: 'Mount', ...mount })); + defaultClient.cache.writeData({ data: { appData: { __typename: 'AppData', ...appData, + mounts, }, }, }); diff --git a/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql b/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql index 9f4b0afe55f..3b377b9288a 100644 --- a/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql +++ b/app/assets/javascripts/static_site_editor/graphql/queries/app_data.query.graphql @@ -6,5 +6,9 @@ query appData { sourcePath username returnUrl + mounts { + source + target + } } } diff --git a/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql b/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql index 0ded1722d26..b8808f4e425 100644 --- a/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql +++ b/app/assets/javascripts/static_site_editor/graphql/typedefs.graphql @@ -14,6 +14,11 @@ type SavedContentMeta { branch: SavedContentField! } +type Mount { + source: String! + target: String +} + type AppData { isSupportedContent: Boolean! hasSubmittedChanges: Boolean! @@ -21,6 +26,7 @@ type AppData { returnUrl: String sourcePath: String! username: String! + mounts: [Mount]! } input HasSubmittedChangesInput { diff --git a/app/assets/javascripts/static_site_editor/index.js b/app/assets/javascripts/static_site_editor/index.js index fceef8f9084..ceb1d820c83 100644 --- a/app/assets/javascripts/static_site_editor/index.js +++ b/app/assets/javascripts/static_site_editor/index.js @@ -20,9 +20,6 @@ const initStaticSiteEditor = el => { imageUploadPath, mounts, } = el.dataset; - // NOTE that the object in 'mounts' is a JSON string from the data attribute, so it must be parsed into an object. - // eslint-disable-next-line no-unused-vars - const mountsObject = JSON.parse(mounts); const { current_username: username } = window.gon; const returnUrl = el.dataset.returnUrl || null; const router = createRouter(baseUrl); @@ -30,6 +27,7 @@ const initStaticSiteEditor = el => { isSupportedContent: parseBoolean(isSupportedContent), hasSubmittedChanges: false, project: `${namespace}/${project}`, + mounts: JSON.parse(mounts), // NOTE that the object in 'mounts' is a JSON string from the data attribute, so it must be parsed into an object. returnUrl, sourcePath, username, diff --git a/app/assets/javascripts/static_site_editor/pages/home.vue b/app/assets/javascripts/static_site_editor/pages/home.vue index 27bd1c99ae2..d7e52ef9c45 100644 --- a/app/assets/javascripts/static_site_editor/pages/home.vue +++ b/app/assets/javascripts/static_site_editor/pages/home.vue @@ -138,6 +138,7 @@ export default { :content="sourceContent.content" :saving-changes="isSavingChanges" :return-url="appData.returnUrl" + :mounts="appData.mounts" @submit="onPrepareSubmit" /> <edit-meta-modal diff --git a/changelogs/unreleased/257822-null-byes-in-url.yml b/changelogs/unreleased/257822-null-byes-in-url.yml new file mode 100644 index 00000000000..6d9ef42929a --- /dev/null +++ b/changelogs/unreleased/257822-null-byes-in-url.yml @@ -0,0 +1,5 @@ +--- +title: Handle malformed strings in URL +merge_request: 45701 +author: +type: fixed diff --git a/config/application.rb b/config/application.rb index 6f479468d6f..ab0bf061e47 100644 --- a/config/application.rb +++ b/config/application.rb @@ -28,7 +28,7 @@ module Gitlab require_dependency Rails.root.join('lib/gitlab/middleware/basic_health_check') require_dependency Rails.root.join('lib/gitlab/middleware/same_site_cookies') require_dependency Rails.root.join('lib/gitlab/middleware/handle_ip_spoof_attack_error') - require_dependency Rails.root.join('lib/gitlab/middleware/handle_null_bytes') + require_dependency Rails.root.join('lib/gitlab/middleware/handle_malformed_strings') require_dependency Rails.root.join('lib/gitlab/runtime') # Settings in config/environments/* take precedence over those specified here. @@ -257,7 +257,7 @@ module Gitlab config.middleware.insert_before ActionDispatch::RemoteIp, ::Gitlab::Middleware::HandleIpSpoofAttackError - config.middleware.use ::Gitlab::Middleware::HandleNullBytes + config.middleware.insert_after ActionDispatch::ActionableExceptions, ::Gitlab::Middleware::HandleMalformedStrings # Allow access to GitLab API from other domains config.middleware.insert_before Warden::Manager, Rack::Cors do diff --git a/doc/administration/raketasks/check.md b/doc/administration/raketasks/check.md index bdccd6d5fe9..f61a3107b3d 100644 --- a/doc/administration/raketasks/check.md +++ b/doc/administration/raketasks/check.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Integrity check Rake task **(CORE ONLY)** GitLab provides Rake tasks to check the integrity of various components. diff --git a/doc/administration/timezone.md b/doc/administration/timezone.md index 3cfee8630b7..4bedd219203 100644 --- a/doc/administration/timezone.md +++ b/doc/administration/timezone.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Changing your time zone The global time zone configuration parameter can be changed in `config/gitlab.yml`: diff --git a/doc/administration/uploads.md b/doc/administration/uploads.md index 91de089c45e..f0e126176b6 100644 --- a/doc/administration/uploads.md +++ b/doc/administration/uploads.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Uploads administration **(CORE ONLY)** Uploads represent all user data that may be sent to GitLab as a single file. As an example, avatars and notes' attachments are uploads. Uploads are integral to GitLab functionality, and therefore cannot be disabled. diff --git a/doc/administration/user_settings.md b/doc/administration/user_settings.md index 7a3e1d86712..94ce1debfea 100644 --- a/doc/administration/user_settings.md +++ b/doc/administration/user_settings.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Modifying global user settings GitLab administrators can modify user settings for the entire GitLab instance. diff --git a/doc/api/admin_sidekiq_queues.md b/doc/api/admin_sidekiq_queues.md index 22488d053b4..8e1f7260208 100644 --- a/doc/api/admin_sidekiq_queues.md +++ b/doc/api/admin_sidekiq_queues.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Sidekiq queues administration API **(CORE ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/25998) in GitLab 12.9 diff --git a/doc/api/api_resources.md b/doc/api/api_resources.md index 199b244b2c3..436a0eb93f1 100644 --- a/doc/api/api_resources.md +++ b/doc/api/api_resources.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # API resources Available resources for the [GitLab API](README.md) can be grouped in the following contexts: diff --git a/doc/api/appearance.md b/doc/api/appearance.md index 47a9d48a4ae..ad44c93ce32 100644 --- a/doc/api/appearance.md +++ b/doc/api/appearance.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Appearance API **(CORE ONLY)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/16647) in GitLab 12.7. diff --git a/doc/api/applications.md b/doc/api/applications.md index 379f346c019..a3216bdddde 100644 --- a/doc/api/applications.md +++ b/doc/api/applications.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Applications API > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/8160) in GitLab 10.5. diff --git a/doc/api/audit_events.md b/doc/api/audit_events.md index 5f31919c52b..5fdf0c20f1a 100644 --- a/doc/api/audit_events.md +++ b/doc/api/audit_events.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Audit Events API ## Instance Audit Events **(PREMIUM ONLY)** diff --git a/doc/api/avatar.md b/doc/api/avatar.md index 223704d3e6c..aec1ba67d45 100644 --- a/doc/api/avatar.md +++ b/doc/api/avatar.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Avatar API > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19121) in GitLab 11.0. diff --git a/doc/api/broadcast_messages.md b/doc/api/broadcast_messages.md index 37156186d03..3d243b2a03f 100644 --- a/doc/api/broadcast_messages.md +++ b/doc/api/broadcast_messages.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Broadcast Messages API > Introduced in GitLab 8.12. diff --git a/doc/api/custom_attributes.md b/doc/api/custom_attributes.md index 07ece99f9b1..76c8474ee95 100644 --- a/doc/api/custom_attributes.md +++ b/doc/api/custom_attributes.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Custom Attributes API Every API call to custom attributes must be authenticated as administrator. diff --git a/doc/api/dependencies.md b/doc/api/dependencies.md index 56d33bf151a..2f65ff7b8d9 100644 --- a/doc/api/dependencies.md +++ b/doc/api/dependencies.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Dependencies API **(ULTIMATE)** CAUTION: **Caution:** diff --git a/doc/api/dependency_proxy.md b/doc/api/dependency_proxy.md index a379f1481c1..fb100cc90d8 100644 --- a/doc/api/dependency_proxy.md +++ b/doc/api/dependency_proxy.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Dependency Proxy API **(PREMIUM)** ## Purge the dependency proxy for a group diff --git a/doc/api/epic_links.md b/doc/api/epic_links.md index 19c8dc78aed..c4afb1e7299 100644 --- a/doc/api/epic_links.md +++ b/doc/api/epic_links.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Epic Links API **(ULTIMATE)** > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/9188) in GitLab 11.8. diff --git a/doc/api/events.md b/doc/api/events.md index 3f4f11b9786..4da4bfe8bd4 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Events ## Filter parameters diff --git a/doc/api/geo_nodes.md b/doc/api/geo_nodes.md index 064bd26ee72..f198b4f4aa2 100644 --- a/doc/api/geo_nodes.md +++ b/doc/api/geo_nodes.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Geo Nodes API **(PREMIUM ONLY)** To interact with Geo node endpoints, you need to authenticate yourself as an diff --git a/doc/api/graphql/audit_report.md b/doc/api/graphql/audit_report.md index 36c3f44ff89..12663654026 100644 --- a/doc/api/graphql/audit_report.md +++ b/doc/api/graphql/audit_report.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Set up an Audit Report with GraphQL This page describes how you can use the GraphiQL explorer to set up an audit report diff --git a/doc/api/graphql/getting_started.md b/doc/api/graphql/getting_started.md index c2220403461..8501e76b5aa 100644 --- a/doc/api/graphql/getting_started.md +++ b/doc/api/graphql/getting_started.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Getting started with GitLab GraphQL API This guide demonstrates basic usage of GitLab's GraphQL API. diff --git a/doc/api/graphql/index.md b/doc/api/graphql/index.md index bda24a7e90a..e0557db6567 100644 --- a/doc/api/graphql/index.md +++ b/doc/api/graphql/index.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # GraphQL API > - [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/19008) in GitLab 11.0 (enabled by feature flag `graphql`). diff --git a/doc/api/graphql/sample_issue_boards.md b/doc/api/graphql/sample_issue_boards.md index 4ac9317b01a..27fd1f48aec 100644 --- a/doc/api/graphql/sample_issue_boards.md +++ b/doc/api/graphql/sample_issue_boards.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Identify issue boards with GraphQL This page describes how you can use the GraphiQL explorer to identify diff --git a/doc/api/group_activity_analytics.md b/doc/api/group_activity_analytics.md index 90920d1b25c..38394c6412d 100644 --- a/doc/api/group_activity_analytics.md +++ b/doc/api/group_activity_analytics.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Group Activity Analytics API > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/26460) in GitLab 12.9. diff --git a/doc/api/group_badges.md b/doc/api/group_badges.md index 43e1944226d..e13b9633da9 100644 --- a/doc/api/group_badges.md +++ b/doc/api/group_badges.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Group badges API > [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/merge_requests/17082) in GitLab 10.6. diff --git a/doc/api/group_import_export.md b/doc/api/group_import_export.md index 01d81eb62ac..dfd78e88233 100644 --- a/doc/api/group_import_export.md +++ b/doc/api/group_import_export.md @@ -1,3 +1,9 @@ +--- +stage: none +group: unassigned +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/#designated-technical-writers +--- + # Group Import/Export API > [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/20353) in GitLab 12.8. diff --git a/doc/user/group/epics/manage_epics.md b/doc/user/group/epics/manage_epics.md index c09032bffb2..a9a307dd89a 100644 --- a/doc/user/group/epics/manage_epics.md +++ b/doc/user/group/epics/manage_epics.md @@ -23,9 +23,9 @@ selected group. From your group page: To create an epic from the epic list, in a group: 1. Go to **{epic}** **Epics**. -1. Click **New epic**. +1. Select **New epic**. 1. Enter a descriptive title. -1. Click **Create epic**. +1. Select **Create epic**. ### Access the New Epic form @@ -33,8 +33,8 @@ To create an epic from the epic list, in a group: There are two ways to get to the New Epic form and create an epic in the group you're in: -- From an epic in your group, click **New Epic**. -- From anywhere, in the top menu, click **plus** (**{plus-square}**) **> New epic**. +- From an epic in your group, select **New Epic**. +- From anywhere, in the top menu, select **plus** (**{plus-square}**) **> New epic**. ![New epic from an open epic](img/new_epic_from_groups_v13.2.png) @@ -63,13 +63,13 @@ After you create an epic, you can edit change the following details: To edit an epic's title or description: -1. Click the **Edit title and description** **{pencil}** button. +1. Select the **Edit title and description** **{pencil}** button. 1. Make your changes. -1. Click **Save changes**. +1. Select **Save changes**. To edit an epics' start date, due date, or labels: -1. Click **Edit** next to each section in the epic sidebar. +1. Select **Edit** next to each section in the epic sidebar. 1. Select the dates or labels for your epic. ## Bulk-edit epics @@ -82,7 +82,7 @@ You can edit multiple epics at once. To learn how to do it, visit NOTE: **Note:** To delete an epic, you need to be an [Owner](../../permissions.md#group-members-permissions) of a group/subgroup. -When editing the description of an epic, click the **Delete** button to delete the epic. +When editing the description of an epic, select the **Delete** button to delete the epic. A modal appears to confirm your action. Deleting an epic releases all existing issues from their associated epic in the system. @@ -92,7 +92,7 @@ Deleting an epic releases all existing issues from their associated epic in the Whenever you decide that there is no longer need for that epic, close the epic by: -- Clicking the **Close epic** button. +- Selecting the **Close epic** button. ![close epic - button](img/button_close_epic.png) @@ -129,7 +129,7 @@ that of Issues and Merge Requests) based on following parameters: ![epics search](img/epics_search.png) -To search, go to the list of epics and click the field **Search or filter results**. +To search, go to the list of epics and select the field **Search or filter results**. It will display a dropdown menu, from which you can add an author. You can also enter plain text to search by epic title or description. When done, press <kbd>Enter</kbd> on your keyboard to filter the list. @@ -168,7 +168,7 @@ To make an epic confidential: ### Add a new issue to an epic -You can add an existing issue to an epic, or, create a new issue that's +You can add an existing issue to an epic, or create a new issue that's automatically added to the epic. #### Add an existing issue to an epic @@ -183,15 +183,15 @@ current parent. To add a new issue to an epic: -1. Click the **Add** dropdown button. -1. Click **Add a new issue**. +1. On the epic's page, under **Epics and Issues**, select the **Add** dropdown button. +1. Select **Add an existing issue**. 1. Identify the issue to be added, using either of the following methods: - Paste the link of the issue. - Search for the desired issue by entering part of the issue's title, then selecting the desired match (introduced in [GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/-/issues/9126)). If there are multiple issues to be added, press <kbd>Spacebar</kbd> and repeat this step. -1. Click **Add**. +1. Select **Add**. #### Create an issue from an epic @@ -202,11 +202,11 @@ while dividing work into smaller parts. To create an issue from an epic: -1. On the epic's page, under **Epics and Issues**, click the **Add** dropdown button and select - **Create new issue**. +1. On the epic's page, under **Epics and Issues**, select the **Add** dropdown button. +1. Select **Add a new issue**. 1. Under **Title**, enter the title for the new issue. 1. From the **Project** dropdown, select the project in which the issue should be created. -1. Click **Create issue**. +1. Select **Create issue**. ### Remove an issue from an epic @@ -215,9 +215,9 @@ After you remove an issue from an epic, the issue will no longer be associated w To remove an issue from an epic: -1. Click the **Remove** (**{close}**) button next to the issue you want to remove. +1. Select the **Remove** (**{close}**) button next to the issue you want to remove. The **Remove issue** warning appears. -1. Click **Remove**. +1. Select **Remove**. ![List of issues assigned to an epic](img/issue_list_v13_1.png) @@ -285,15 +285,15 @@ For more on epic templates, see [Epic Templates - Repeatable sets of issues](htt To add a child epic to an epic: -1. Click the **Add** dropdown button. -1. Click **Add a new epic**. +1. Select the **Add** dropdown button. +1. Select **Add a new epic**. 1. Identify the epic to be added, using either of the following methods: - Paste the link of the epic. - Search for the desired issue by entering part of the epic's title, then selecting the desired match (introduced in [GitLab 12.5](https://gitlab.com/gitlab-org/gitlab/-/issues/9126)). If there are multiple epics to be added, press <kbd>Spacebar</kbd> and repeat this step. -1. Click **Add**. +1. Select **Add**. ### Move child epics between epics @@ -325,5 +325,5 @@ To reorder child epics assigned to an epic: To remove a child epic from a parent epic: -1. Click on the <kbd>x</kbd> button in the parent epic's list of epics. -1. Click **Remove** in the **Remove epic** warning message. +1. Select the <kbd>x</kbd> button in the parent epic's list of epics. +1. Select **Remove** in the **Remove epic** warning message. diff --git a/lib/api/api.rb b/lib/api/api.rb index e6935d4e74a..358967c72d2 100644 --- a/lib/api/api.rb +++ b/lib/api/api.rb @@ -25,7 +25,8 @@ module API Gitlab::GrapeLogging::Loggers::QueueDurationLogger.new, Gitlab::GrapeLogging::Loggers::PerfLogger.new, Gitlab::GrapeLogging::Loggers::CorrelationIdLogger.new, - Gitlab::GrapeLogging::Loggers::ContextLogger.new + Gitlab::GrapeLogging::Loggers::ContextLogger.new, + Gitlab::GrapeLogging::Loggers::ContentLogger.new ] allow_access_with_scope :api diff --git a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml index 4418ff18d73..a51cb61da6d 100644 --- a/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml +++ b/lib/gitlab/ci/templates/Security/SAST.gitlab-ci.yml @@ -134,6 +134,7 @@ mobsf-android-sast: name: "$SAST_ANALYZER_IMAGE" variables: SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG" + MOBSF_API_KEY: key rules: - if: $SAST_DISABLED when: never @@ -152,6 +153,7 @@ mobsf-ios-sast: name: "$SAST_ANALYZER_IMAGE" variables: SAST_ANALYZER_IMAGE: "$SECURE_ANALYZERS_PREFIX/mobsf:$SAST_ANALYZER_IMAGE_TAG" + MOBSF_API_KEY: key rules: - if: $SAST_DISABLED when: never diff --git a/lib/gitlab/etag_caching/middleware.rb b/lib/gitlab/etag_caching/middleware.rb index 303e1a23e6b..81cfce6a3db 100644 --- a/lib/gitlab/etag_caching/middleware.rb +++ b/lib/gitlab/etag_caching/middleware.rb @@ -54,7 +54,13 @@ module Gitlab add_instrument_for_cache_hit(status_code, route, request) - [status_code, { 'ETag' => etag, 'X-Gitlab-From-Cache' => 'true' }, []] + new_headers = { + 'ETag' => etag, + 'X-Gitlab-From-Cache' => 'true', + ::Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER => route.feature_category + } + + [status_code, new_headers, []] end def track_cache_miss(if_none_match, cached_value_present, route) diff --git a/lib/gitlab/etag_caching/router.rb b/lib/gitlab/etag_caching/router.rb index 17d9cf08367..769ac2784d1 100644 --- a/lib/gitlab/etag_caching/router.rb +++ b/lib/gitlab/etag_caching/router.rb @@ -3,7 +3,7 @@ module Gitlab module EtagCaching class Router - Route = Struct.new(:regexp, :name) + Route = Struct.new(:regexp, :name, :feature_category) # We enable an ETag for every request matching the regex. # To match a regex the path needs to match the following: # - Don't contain a reserved word (expect for the words used in the @@ -20,59 +20,73 @@ module Gitlab ROUTES = [ Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/noteable/issue/\d+/notes\z), - 'issue_notes' + 'issue_notes', + 'issue_tracking' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/noteable/merge_request/\d+/notes\z), - 'merge_request_notes' + 'merge_request_notes', + 'code_review' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/issues/\d+/realtime_changes\z), - 'issue_title' + 'issue_title', + 'issue_tracking' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/commit/\S+/pipelines\.json\z), - 'commit_pipelines' + 'commit_pipelines', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/merge_requests/new\.json\z), - 'new_merge_request_pipelines' + 'new_merge_request_pipelines', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/pipelines\.json\z), - 'merge_request_pipelines' + 'merge_request_pipelines', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/pipelines\.json\z), - 'project_pipelines' + 'project_pipelines', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/pipelines/\d+\.json\z), - 'project_pipeline' + 'project_pipeline', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/builds/\d+\.json\z), - 'project_build' + 'project_build', + 'continuous_integration' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/clusters/\d+/environments\z), - 'cluster_environments' + 'cluster_environments', + 'continuous_delivery' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/environments\.json\z), - 'environments' + 'environments', + 'continuous_delivery' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/import/github/realtime_changes\.json\z), - 'realtime_changes_import_github' + 'realtime_changes_import_github', + 'importers' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/import/gitea/realtime_changes\.json\z), - 'realtime_changes_import_gitea' + 'realtime_changes_import_gitea', + 'importers' ), Gitlab::EtagCaching::Router::Route.new( %r(#{RESERVED_WORDS_PREFIX}/merge_requests/\d+/cached_widget\.json\z), - 'merge_request_widget' + 'merge_request_widget', + 'code_review' ) ].freeze diff --git a/lib/gitlab/grape_logging/loggers/content_logger.rb b/lib/gitlab/grape_logging/loggers/content_logger.rb new file mode 100644 index 00000000000..658953adc80 --- /dev/null +++ b/lib/gitlab/grape_logging/loggers/content_logger.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +module Gitlab + module GrapeLogging + module Loggers + class ContentLogger < ::GrapeLogging::Loggers::Base + def parameters(request, _) + { + content_length: request.env['CONTENT_LENGTH'], + content_range: request.env['HTTP_CONTENT_RANGE'] + }.compact + end + end + end + end +end diff --git a/lib/gitlab/middleware/handle_null_bytes.rb b/lib/gitlab/middleware/handle_malformed_strings.rb index c88dfb6ee0b..5fe3e6a1c73 100644 --- a/lib/gitlab/middleware/handle_null_bytes.rb +++ b/lib/gitlab/middleware/handle_malformed_strings.rb @@ -2,9 +2,9 @@ module Gitlab module Middleware - # There is no valid reason for a request to contain a null byte (U+0000) + # There is no valid reason for a request to contain a malformed string # so just return HTTP 400 (Bad Request) if we receive one - class HandleNullBytes + class HandleMalformedStrings NULL_BYTE_REGEX = Regexp.new(Regexp.escape("\u0000")).freeze attr_reader :app @@ -14,18 +14,20 @@ module Gitlab end def call(env) - return [400, {}, ["Bad Request"]] if request_has_null_byte?(env) + return [400, { 'Content-Type' => 'text/plain' }, ['Bad Request']] if request_contains_malformed_string?(env) app.call(env) end private - def request_has_null_byte?(request) - return false if ENV['REJECT_NULL_BYTES'] == "1" + def request_contains_malformed_string?(request) + return false if ENV['DISABLE_REQUEST_VALIDATION'] == '1' request = Rack::Request.new(request) + return true if string_malformed?(request.path) + request.params.values.any? do |value| param_has_null_byte?(value) end @@ -39,7 +41,7 @@ module Gitlab depth += 1 if value.respond_to?(:match) - string_contains_null_byte?(value) + string_malformed?(value) elsif value.respond_to?(:values) value.values.any? do |hash_value| param_has_null_byte?(hash_value, depth) @@ -53,8 +55,11 @@ module Gitlab end end - def string_contains_null_byte?(string) + def string_malformed?(string) string.match?(NULL_BYTE_REGEX) + rescue ArgumentError + # If we're here, we caught a malformed string. Return true + true end end end diff --git a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb index 9268190c7e0..1e1888cd826 100644 --- a/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb +++ b/spec/features/merge_request/user_suggests_changes_on_diff_spec.rb @@ -304,7 +304,7 @@ RSpec.describe 'User comments on a diff', :js do wait_for_requests end - it 'suggestion is presented' do + it 'suggestion is presented', quarantine: 'https://gitlab.com/gitlab-org/gitlab/-/issues/268240' do page.within('.diff-discussions') do expect(page).to have_button('Apply suggestion') expect(page).to have_content('Suggested change') diff --git a/spec/frontend/static_site_editor/components/edit_area_spec.js b/spec/frontend/static_site_editor/components/edit_area_spec.js index 7e90b53dd07..8013e712558 100644 --- a/spec/frontend/static_site_editor/components/edit_area_spec.js +++ b/spec/frontend/static_site_editor/components/edit_area_spec.js @@ -15,6 +15,7 @@ import { sourceContentHeaderObjYAML as headerSettings, sourceContentBody as body, returnUrl, + mounts, } from '../mock_data'; jest.mock('~/static_site_editor/services/formatter', () => jest.fn(str => `${str} format-pass`)); @@ -31,6 +32,7 @@ describe('~/static_site_editor/components/edit_area.vue', () => { title, content, returnUrl, + mounts, savingChanges, ...propsData, }, diff --git a/spec/frontend/static_site_editor/mock_data.js b/spec/frontend/static_site_editor/mock_data.js index 0b08e290227..ce7c52e8277 100644 --- a/spec/frontend/static_site_editor/mock_data.js +++ b/spec/frontend/static_site_editor/mock_data.js @@ -67,3 +67,10 @@ export const images = new Map([ ['path/to/image1.png', 'image1-content'], ['path/to/image2.png', 'image2-content'], ]); + +export const mounts = [ + { + source: 'some/source/', + target: '', + }, +]; diff --git a/spec/frontend/static_site_editor/pages/home_spec.js b/spec/frontend/static_site_editor/pages/home_spec.js index 2c69e884005..8fca8d0f2b9 100644 --- a/spec/frontend/static_site_editor/pages/home_spec.js +++ b/spec/frontend/static_site_editor/pages/home_spec.js @@ -23,6 +23,7 @@ import { submitChangesError, trackingCategory, images, + mounts, } from '../mock_data'; const localVue = createLocalVue(); @@ -41,6 +42,7 @@ describe('static_site_editor/pages/home', () => { project, username, sourcePath, + mounts, }; const hasSubmittedChangesMutationPayload = { data: { @@ -119,6 +121,7 @@ describe('static_site_editor/pages/home', () => { it('provides source content, returnUrl, and isSavingChanges to the edit area', () => { expect(findEditArea().props()).toMatchObject({ title, + mounts, content, returnUrl, savingChanges: false, diff --git a/spec/lib/gitlab/etag_caching/middleware_spec.rb b/spec/lib/gitlab/etag_caching/middleware_spec.rb index 361b2329e15..45916e78532 100644 --- a/spec/lib/gitlab/etag_caching/middleware_spec.rb +++ b/spec/lib/gitlab/etag_caching/middleware_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe Gitlab::EtagCaching::Middleware do +RSpec.describe Gitlab::EtagCaching::Middleware, :clean_gitlab_redis_shared_state do let(:app) { double(:app) } let(:middleware) { described_class.new(app) } let(:app_status_code) { 200 } @@ -17,10 +17,12 @@ RSpec.describe Gitlab::EtagCaching::Middleware do mock_app_response end - it 'does not add ETag header' do + it 'does not add ETag headers' do _, headers, _ = middleware.call(build_request(path, if_none_match)) expect(headers['ETag']).to be_nil + expect(headers['X-Gitlab-From-Cache']).to be_nil + expect(headers[::Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER]).to be_nil end it 'passes status code from app' do @@ -68,7 +70,7 @@ RSpec.describe Gitlab::EtagCaching::Middleware do mock_value_in_store('123') end - it 'returns this value as header' do + it 'returns the correct headers' do _, headers, _ = middleware.call(build_request(path, if_none_match)) expect(headers['ETag']).to eq 'W/"123"' @@ -126,6 +128,13 @@ RSpec.describe Gitlab::EtagCaching::Middleware do expect(status).to eq 304 end + it 'sets correct headers' do + _, headers, _ = middleware.call(build_request(path, if_none_match)) + + expect(headers).to include('X-Gitlab-From-Cache' => 'true', + ::Gitlab::Metrics::RequestsRackMiddleware::FEATURE_CATEGORY_HEADER => 'issue_tracking') + end + it_behaves_like 'sends a process_action.action_controller notification', 304 it 'returns empty body' do diff --git a/spec/lib/gitlab/etag_caching/router_spec.rb b/spec/lib/gitlab/etag_caching/router_spec.rb index 3e939e588ad..dbd9cc230f1 100644 --- a/spec/lib/gitlab/etag_caching/router_spec.rb +++ b/spec/lib/gitlab/etag_caching/router_spec.rb @@ -127,4 +127,12 @@ RSpec.describe Gitlab::EtagCaching::Router do expect(result).to be_present expect(result.name).to eq 'project_pipeline' end + + it 'has a valid feature category for every route', :aggregate_failures do + feature_categories = YAML.load_file(Rails.root.join('config', 'feature_categories.yml')).to_set + + described_class::ROUTES.each do |route| + expect(feature_categories).to include(route.feature_category), "#{route.name} has a category of #{route.feature_category}, which is not valid" + end + end end diff --git a/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb new file mode 100644 index 00000000000..6680720e403 --- /dev/null +++ b/spec/lib/gitlab/middleware/handle_malformed_strings_spec.rb @@ -0,0 +1,109 @@ +# frozen_string_literal: true + +require 'spec_helper' +require "rack/test" + +RSpec.describe Gitlab::Middleware::HandleMalformedStrings do + let(:null_byte) { "\u0000" } + let(:invalid_string) { "mal\xC0formed" } + let(:error_400) { [400, { 'Content-Type' => 'text/plain' }, ['Bad Request']] } + let(:app) { double(:app) } + + subject { described_class.new(app) } + + before do + allow(app).to receive(:call) do |args| + args + end + end + + def env_for(params = {}) + Rack::MockRequest.env_for('/', { params: params }) + end + + context 'in the URL' do + it 'rejects null bytes' do + # We have to create the env separately or Rack::MockRequest complains about invalid URI + env = env_for + env['PATH_INFO'] = "/someplace/witha#{null_byte}nullbyte" + + expect(subject.call(env)).to eq error_400 + end + + it 'rejects malformed strings' do + # We have to create the env separately or Rack::MockRequest complains about invalid URI + env = env_for + env['PATH_INFO'] = "/someplace/with_an/#{invalid_string}" + + expect(subject.call(env)).to eq error_400 + end + end + + context 'in params' do + shared_examples_for 'checks params' do + it 'rejects bad params in a top level param' do + env = env_for(name: "null#{problematic_input}byte") + + expect(subject.call(env)).to eq error_400 + end + + it "rejects bad params for hashes with strings" do + env = env_for(name: { inner_key: "I am #{problematic_input} bad" }) + + expect(subject.call(env)).to eq error_400 + end + + it "rejects bad params for arrays with strings" do + env = env_for(name: ["I am #{problematic_input} bad"]) + + expect(subject.call(env)).to eq error_400 + end + + it "rejects bad params for arrays containing hashes with string values" do + env = env_for(name: [ + { + inner_key: "I am #{problematic_input} bad" + } + ]) + + expect(subject.call(env)).to eq error_400 + end + + it "gives up and does not reject too deeply nested params" do + env = env_for(name: [ + { + inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{problematic_input} bad" }] } + } + ]) + + expect(subject.call(env)).not_to eq error_400 + end + end + + context 'with null byte' do + it_behaves_like 'checks params' do + let(:problematic_input) { null_byte } + end + end + + context 'with malformed strings' do + it_behaves_like 'checks params' do + let(:problematic_input) { invalid_string } + end + end + end + + context 'without problematic input' do + it "does not error for strings" do + env = env_for(name: "safe name") + + expect(subject.call(env)).not_to eq error_400 + end + + it "does not error with no params" do + env = env_for + + expect(subject.call(env)).not_to eq error_400 + end + end +end diff --git a/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb b/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb deleted file mode 100644 index 76a5174817e..00000000000 --- a/spec/lib/gitlab/middleware/handle_null_bytes_spec.rb +++ /dev/null @@ -1,88 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' -require "rack/test" - -RSpec.describe Gitlab::Middleware::HandleNullBytes do - let(:null_byte) { "\u0000" } - let(:error_400) { [400, {}, ["Bad Request"]] } - let(:app) { double(:app) } - - subject { described_class.new(app) } - - before do - allow(app).to receive(:call) do |args| - args - end - end - - def env_for(params = {}) - Rack::MockRequest.env_for('/', { params: params }) - end - - context 'with null bytes in params' do - it 'rejects null bytes in a top level param' do - env = env_for(name: "null#{null_byte}byte") - - expect(subject.call(env)).to eq error_400 - end - - it "responds with 400 BadRequest for hashes with strings" do - env = env_for(name: { inner_key: "I am #{null_byte} bad" }) - - expect(subject.call(env)).to eq error_400 - end - - it "responds with 400 BadRequest for arrays with strings" do - env = env_for(name: ["I am #{null_byte} bad"]) - - expect(subject.call(env)).to eq error_400 - end - - it "responds with 400 BadRequest for arrays containing hashes with string values" do - env = env_for(name: [ - { - inner_key: "I am #{null_byte} bad" - } - ]) - - expect(subject.call(env)).to eq error_400 - end - - it "gives up and does not 400 with too deeply nested params" do - env = env_for(name: [ - { - inner_key: { deeper_key: [{ hash_inside_array_key: "I am #{null_byte} bad" }] } - } - ]) - - expect(subject.call(env)).not_to eq error_400 - end - end - - context 'without null bytes in params' do - it "does not respond with a 400 for strings" do - env = env_for(name: "safe name") - - expect(subject.call(env)).not_to eq error_400 - end - - it "does not respond with a 400 with no params" do - env = env_for - - expect(subject.call(env)).not_to eq error_400 - end - end - - context 'when disabled via env flag' do - before do - stub_env('REJECT_NULL_BYTES', '1') - end - - it 'does not respond with a 400 no matter what' do - env = env_for(name: "null#{null_byte}byte") - - expect(subject.call(env)).not_to eq error_400 - end - end -end diff --git a/spec/requests/user_sends_malformed_strings_spec.rb b/spec/requests/user_sends_malformed_strings_spec.rb new file mode 100644 index 00000000000..b6eda9159bc --- /dev/null +++ b/spec/requests/user_sends_malformed_strings_spec.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe 'User sends malformed strings as params' do + let(:null_byte) { "\u0000" } + let(:invalid_string) { "mal\xC0formed" } + + it 'raises a 400 error with a null byte' do + post '/nonexistent', params: { a: "A #{null_byte} nasty string" } + + expect(response).to have_gitlab_http_status(:bad_request) + end + + it 'raises a 400 error with an invalid string' do + post '/nonexistent', params: { a: "A #{invalid_string} nasty string" } + + expect(response).to have_gitlab_http_status(:bad_request) + end +end diff --git a/spec/requests/user_sends_null_bytes_spec.rb b/spec/requests/user_sends_null_bytes_spec.rb deleted file mode 100644 index 1ddfad40996..00000000000 --- a/spec/requests/user_sends_null_bytes_spec.rb +++ /dev/null @@ -1,14 +0,0 @@ -# frozen_string_literal: true - -require 'spec_helper' - -RSpec.describe 'User sends null bytes as params' do - let(:null_byte) { "\u0000" } - - it 'raises a 400 error' do - post '/nonexistent', params: { a: "A #{null_byte} nasty string" } - - expect(response).to have_gitlab_http_status(:bad_request) - expect(response.body).to eq('Bad Request') - end -end |