Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/confirm_modal.js53
-rw-r--r--app/assets/javascripts/filtered_search/dropdown_utils.js8
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js6
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_manager.js4
-rw-r--r--app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js4
-rw-r--r--app/assets/javascripts/filtered_search/stores/recent_searches_store.js4
-rw-r--r--app/assets/javascripts/filtered_search/visual_token_value.js4
-rw-r--r--app/assets/javascripts/vue_shared/components/confirm_modal.vue41
-rw-r--r--app/models/clusters/applications/cert_manager.rb4
-rw-r--r--changelogs/unreleased/196883-repository-link-grpc-graceful-failure.yml5
-rw-r--r--changelogs/unreleased/208678-packages-project-and-group-api-will-return-processing-nuget-packag.yml5
-rw-r--r--changelogs/unreleased/ee-insert-all-for-load-balancing.yml5
-rw-r--r--changelogs/unreleased/update-cert-manager-to-0-10-1.yml5
-rw-r--r--doc/user/application_security/container_scanning/index.md116
-rw-r--r--lib/api/project_container_repositories.rb9
-rw-r--r--lib/banzai/filter/repository_link_filter.rb7
-rw-r--r--locale/gitlab.pot12
-rw-r--r--spec/frontend/helpers/dom_shims/form_element.js1
-rw-r--r--spec/frontend/helpers/dom_shims/index.js1
-rw-r--r--spec/frontend/vue_shared/components/confirm_modal_spec.js66
-rw-r--r--spec/lib/banzai/filter/repository_link_filter_spec.rb28
-rw-r--r--spec/models/clusters/applications/cert_manager_spec.rb6
22 files changed, 257 insertions, 137 deletions
diff --git a/app/assets/javascripts/confirm_modal.js b/app/assets/javascripts/confirm_modal.js
index 1c9346e35e0..ff29d5fa355 100644
--- a/app/assets/javascripts/confirm_modal.js
+++ b/app/assets/javascripts/confirm_modal.js
@@ -1,26 +1,45 @@
import Vue from 'vue';
import ConfirmModal from '~/vue_shared/components/confirm_modal.vue';
-const mountConfirmModal = button => {
- const props = {
- path: button.dataset.path,
- method: button.dataset.method,
- modalAttributes: JSON.parse(button.dataset.modalAttributes),
- };
-
+const mountConfirmModal = () => {
return new Vue({
+ data() {
+ return {
+ path: '',
+ method: '',
+ modalAttributes: null,
+ showModal: false,
+ };
+ },
+ mounted() {
+ document.querySelectorAll('.js-confirm-modal-button').forEach(button => {
+ button.addEventListener('click', e => {
+ e.preventDefault();
+
+ this.path = button.dataset.path;
+ this.method = button.dataset.method;
+ this.modalAttributes = JSON.parse(button.dataset.modalAttributes);
+ this.showModal = true;
+ });
+ });
+ },
+ methods: {
+ dismiss() {
+ this.showModal = false;
+ },
+ },
render(h) {
- return h(ConfirmModal, { props });
+ return h(ConfirmModal, {
+ props: {
+ path: this.path,
+ method: this.method,
+ modalAttributes: this.modalAttributes,
+ showModal: this.showModal,
+ },
+ on: { dismiss: this.dismiss },
+ });
},
}).$mount();
};
-export default () => {
- document.getElementsByClassName('js-confirm-modal-button').forEach(button => {
- button.addEventListener('click', e => {
- e.preventDefault();
-
- mountConfirmModal(button);
- });
- });
-};
+export default () => mountConfirmModal();
diff --git a/app/assets/javascripts/filtered_search/dropdown_utils.js b/app/assets/javascripts/filtered_search/dropdown_utils.js
index 274c08e6955..43de86b09ee 100644
--- a/app/assets/javascripts/filtered_search/dropdown_utils.js
+++ b/app/assets/javascripts/filtered_search/dropdown_utils.js
@@ -1,4 +1,4 @@
-import _ from 'underscore';
+import { last } from 'lodash';
import FilteredSearchContainer from './container';
import FilteredSearchTokenizer from './filtered_search_tokenizer';
import FilteredSearchDropdownManager from './filtered_search_dropdown_manager';
@@ -70,11 +70,11 @@ export default class DropdownUtils {
if (!allowMultiple && itemInExistingTokens) {
updatedItem.droplab_hidden = true;
- } else if (!isSearchItem && (!lastKey || _.last(searchInput.split('')) === ' ')) {
+ } else if (!isSearchItem && (!lastKey || last(searchInput.split('')) === ' ')) {
updatedItem.droplab_hidden = false;
} else if (lastKey) {
const split = lastKey.split(':');
- const tokenName = _.last(split[0].split(' '));
+ const tokenName = last(split[0].split(' '));
const match = isSearchItem
? allowedKeys.some(key => key.startsWith(tokenName.toLowerCase()))
@@ -129,7 +129,7 @@ export default class DropdownUtils {
const values = [];
if (untilInput) {
- const inputIndex = _.findIndex(tokens, t => t.classList.contains('input-token'));
+ const inputIndex = tokens.findIndex(t => t.classList.contains('input-token'));
// Add one to include input-token to the tokens array
tokens.splice(inputIndex + 1);
}
diff --git a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
index 03f65612b60..d051b60814e 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_dropdown_manager.js
@@ -1,5 +1,5 @@
+import { last } from 'lodash';
import AvailableDropdownMappings from 'ee_else_ce/filtered_search/available_dropdown_mappings';
-import _ from 'underscore';
import DropLab from '~/droplab/drop_lab';
import FilteredSearchContainer from './container';
import FilteredSearchTokenKeys from './filtered_search_token_keys';
@@ -184,8 +184,8 @@ export default class FilteredSearchDropdownManager {
// Eg. token = 'label:'
const split = lastToken.split(':');
- const dropdownName = _.last(split[0].split(' '));
- const possibleOperatorToken = _.last(split[1]);
+ const dropdownName = last(split[0].split(' '));
+ const possibleOperatorToken = last(split[1]);
const hasOperator = FilteredSearchVisualTokens.permissibleOperatorValues.includes(
possibleOperatorToken && possibleOperatorToken.trim(),
diff --git a/app/assets/javascripts/filtered_search/filtered_search_manager.js b/app/assets/javascripts/filtered_search/filtered_search_manager.js
index 88737396113..7ea7313f648 100644
--- a/app/assets/javascripts/filtered_search/filtered_search_manager.js
+++ b/app/assets/javascripts/filtered_search/filtered_search_manager.js
@@ -1,4 +1,4 @@
-import _ from 'underscore';
+import { last } from 'lodash';
import recentSearchesStorageKeys from 'ee_else_ce/filtered_search/recent_searches_storage_keys';
import { getParameterByName, getUrlParamsArray } from '~/lib/utils/common_utils';
import IssuableFilteredSearchTokenKeys from '~/filtered_search/issuable_filtered_search_token_keys';
@@ -456,7 +456,7 @@ export default class FilteredSearchManager {
if (fragments.length > 1) {
const inputValues = fragments[0].split(' ');
- const tokenKey = _.last(inputValues);
+ const tokenKey = last(inputValues);
if (inputValues.length > 1) {
inputValues.pop();
diff --git a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
index 8722fc64b62..9bea7aa7b04 100644
--- a/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
+++ b/app/assets/javascripts/filtered_search/issuable_filtered_search_token_keys.js
@@ -1,4 +1,4 @@
-import { flatten } from 'underscore';
+import { flattenDeep } from 'lodash';
import FilteredSearchTokenKeys from './filtered_search_token_keys';
import { __ } from '~/locale';
@@ -73,7 +73,7 @@ export const alternativeTokenKeys = [
},
];
-export const conditions = flatten(
+export const conditions = flattenDeep(
[
{
url: 'assignee_id=None',
diff --git a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
index 76d40bfdaf8..b3eb0475d6f 100644
--- a/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
+++ b/app/assets/javascripts/filtered_search/stores/recent_searches_store.js
@@ -1,4 +1,4 @@
-import _ from 'underscore';
+import { uniq } from 'lodash';
class RecentSearchesStore {
constructor(initialState = {}, allowedKeys) {
@@ -20,7 +20,7 @@ class RecentSearchesStore {
setRecentSearches(searches = []) {
const trimmedSearches = searches.map(search => search.trim());
- this.state.recentSearches = _.uniq(trimmedSearches).slice(0, 5);
+ this.state.recentSearches = uniq(trimmedSearches).slice(0, 5);
return this.state.recentSearches;
}
}
diff --git a/app/assets/javascripts/filtered_search/visual_token_value.js b/app/assets/javascripts/filtered_search/visual_token_value.js
index b7ac655b619..b8f4cd8a1e1 100644
--- a/app/assets/javascripts/filtered_search/visual_token_value.js
+++ b/app/assets/javascripts/filtered_search/visual_token_value.js
@@ -1,4 +1,4 @@
-import _ from 'underscore';
+import { escape as esc } from 'lodash';
import { USER_TOKEN_TYPES } from 'ee_else_ce/filtered_search/constants';
import FilteredSearchContainer from '~/filtered_search/container';
import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens';
@@ -48,7 +48,7 @@ export default class VisualTokenValue {
tokenValueContainer.dataset.originalValue = tokenValue;
tokenValueElement.innerHTML = `
<img class="avatar s20" src="${user.avatar_url}" alt="">
- ${_.escape(user.name)}
+ ${esc(user.name)}
`;
/* eslint-enable no-param-reassign */
})
diff --git a/app/assets/javascripts/vue_shared/components/confirm_modal.vue b/app/assets/javascripts/vue_shared/components/confirm_modal.vue
index 21722f62133..c77827205d6 100644
--- a/app/assets/javascripts/vue_shared/components/confirm_modal.vue
+++ b/app/assets/javascripts/vue_shared/components/confirm_modal.vue
@@ -9,34 +9,43 @@ export default {
props: {
modalAttributes: {
type: Object,
- required: true,
+ required: false,
+ default: () => {
+ return {};
+ },
},
path: {
type: String,
- required: true,
+ required: false,
+ default: '',
},
method: {
type: String,
- required: true,
+ required: false,
+ default: '',
+ },
+ showModal: {
+ type: Boolean,
+ required: false,
+ default: false,
},
},
- data() {
- return {
- isDismissed: false,
- };
- },
- mounted() {
- this.openModal();
+ watch: {
+ showModal(val) {
+ if (val) {
+ // Wait for v-if to render
+ this.$nextTick(() => {
+ this.openModal();
+ });
+ }
+ },
},
methods: {
openModal() {
this.$refs.modal.show();
},
submitModal() {
- this.$refs.form.requestSubmit();
- },
- dismiss() {
- this.isDismissed = true;
+ this.$refs.form.submit();
},
},
csrf,
@@ -45,11 +54,11 @@ export default {
<template>
<gl-modal
- v-if="!isDismissed"
+ v-if="showModal"
ref="modal"
v-bind="modalAttributes"
@primary="submitModal"
- @canceled="dismiss"
+ @canceled="$emit('dismiss')"
>
<form ref="form" :action="path" method="post">
<!-- Rails workaround for <form method="delete" />
diff --git a/app/models/clusters/applications/cert_manager.rb b/app/models/clusters/applications/cert_manager.rb
index 7ba04d1a2de..1efa44c39c5 100644
--- a/app/models/clusters/applications/cert_manager.rb
+++ b/app/models/clusters/applications/cert_manager.rb
@@ -3,8 +3,8 @@
module Clusters
module Applications
class CertManager < ApplicationRecord
- VERSION = 'v0.9.1'
- CRD_VERSION = '0.9'
+ VERSION = 'v0.10.1'
+ CRD_VERSION = '0.10'
self.table_name = 'clusters_applications_cert_managers'
diff --git a/changelogs/unreleased/196883-repository-link-grpc-graceful-failure.yml b/changelogs/unreleased/196883-repository-link-grpc-graceful-failure.yml
new file mode 100644
index 00000000000..3cc335c7ee9
--- /dev/null
+++ b/changelogs/unreleased/196883-repository-link-grpc-graceful-failure.yml
@@ -0,0 +1,5 @@
+---
+title: Ensure RepositoryLinkFilter handles Gitaly failures gracefully
+merge_request: 26531
+author:
+type: performance
diff --git a/changelogs/unreleased/208678-packages-project-and-group-api-will-return-processing-nuget-packag.yml b/changelogs/unreleased/208678-packages-project-and-group-api-will-return-processing-nuget-packag.yml
new file mode 100644
index 00000000000..0596f0e4b85
--- /dev/null
+++ b/changelogs/unreleased/208678-packages-project-and-group-api-will-return-processing-nuget-packag.yml
@@ -0,0 +1,5 @@
+---
+title: Fixed bug where processing NuGet packages are returned from the Packages API
+merge_request: 26270
+author:
+type: fixed
diff --git a/changelogs/unreleased/ee-insert-all-for-load-balancing.yml b/changelogs/unreleased/ee-insert-all-for-load-balancing.yml
new file mode 100644
index 00000000000..135f97cb488
--- /dev/null
+++ b/changelogs/unreleased/ee-insert-all-for-load-balancing.yml
@@ -0,0 +1,5 @@
+---
+title: Support Rails 6 `insert_all!`
+merge_request: 26595
+author:
+type: fixed
diff --git a/changelogs/unreleased/update-cert-manager-to-0-10-1.yml b/changelogs/unreleased/update-cert-manager-to-0-10-1.yml
new file mode 100644
index 00000000000..886ab67dfc4
--- /dev/null
+++ b/changelogs/unreleased/update-cert-manager-to-0-10-1.yml
@@ -0,0 +1,5 @@
+---
+title: Use cert-manager 0.10 instead of 0.9 for new chart installations
+merge_request: 26345
+author:
+type: changed
diff --git a/doc/user/application_security/container_scanning/index.md b/doc/user/application_security/container_scanning/index.md
index e14e8ceb8c0..e51cda3c300 100644
--- a/doc/user/application_security/container_scanning/index.md
+++ b/doc/user/application_security/container_scanning/index.md
@@ -107,24 +107,20 @@ artifact available. Behind the scenes, the
[GitLab Klar analyzer](https://gitlab.com/gitlab-org/security-products/analyzers/klar/)
is used and runs the scans.
-### Example
-
-The following is a sample `.gitlab-ci.yml` that will build your Docker Image, push it to the container registry and run Container Scanning.
+The following is a sample `.gitlab-ci.yml` that will build your Docker image,
+push it to the Container Registry, and run Container Scanning:
```yaml
variables:
DOCKER_DRIVER: overlay2
services:
- - docker:stable-dind
+ - docker:19.03.5-dind
stages:
- build
- test
-include:
- - template: Container-Scanning.gitlab-ci.yml
-
build:
image: docker:stable
stage: build
@@ -135,40 +131,37 @@ build:
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
- docker build -t $IMAGE .
- docker push $IMAGE
+
+include:
+ - template: Container-Scanning.gitlab-ci.yml
```
-### Vulnerability Whitelisting
+### Customizing the Container Scanning settings
-If you want to whitelist specific vulnerabilities, you'll need to:
+You can change container scanning settings by using the [`variables`](../../../ci/yaml/README.md#variables)
+parameter in your `.gitlab-ci.yml` to change [environment variables](#available-variables).
- 1. Set [`GIT_STRATEGY: fetch`](../../../ci/yaml/README.md#git-strategy) in your `.gitlab-ci.yml` file by following the instructions described in the
- [overriding the Container Scanning template](#overriding-the-container-scanning-template) section of this document.
- 1. Define the whitelisted vulnerabilities in a YAML file named `clair-whitelist.yml` which must use the format described
- in the [following whitelist example file](https://github.com/arminc/clair-scanner/blob/v12/example-whitelist.yaml).
- 1. Add the `clair-whitelist.yml` file to the Git repository of your project
-
-### Overriding the Container Scanning template
-
-If you want to override the job definition (for example, change properties like
-`variables`), you need to declare a `container_scanning` job after the
-template inclusion and specify any additional keys under it. For example:
+In the following example, we [include](../../../ci/yaml/README.md#include) the template and also
+set the `CLAIR_OUTPUT` variable to `High`:
```yaml
include:
- - template: Container-Scanning.gitlab-ci.yml
+ template: Container-Scanning.gitlab-ci.yml
-container_scanning:
- variables:
- GIT_STRATEGY: fetch
+variables:
+ CLAIR_OUTPUT: High
```
+The `CLAIR_OUTPUT` variable defined in the main `gitlab-ci.yml` will overwrite what's
+defined in `Container-Scanning.gitlab-ci.yml`, changing the Container Scanning behavior.
+
[//]: # "NOTE: The container scanning tool references the following heading in the code, so if you"
[//]: # " make a change to this heading, make sure to update the documentation URLs used in the"
[//]: # " container scanning tool (https://gitlab.com/gitlab-org/security-products/analyzers/klar)"
-### Available variables
+#### Available variables
-Container Scanning can be [configured](#overriding-the-container-scanning-template)
+Container Scanning can be [configured](#customizing-the-container-scanning-settings)
using environment variables.
| Environment Variable | Description | Default |
@@ -187,36 +180,32 @@ using environment variables.
| `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [Postgres server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
| `DOCKERFILE_PATH` | The path to the `Dockerfile` to be used for generating remediations. By default, the scanner will look for a file named `Dockerfile` in the root directory of the project, so this variable should only be configured if your `Dockerfile` is in a non-standard location, such as a subdirectory. See [Solutions for vulnerabilities](#solutions-for-vulnerabilities-auto-remediation) for more details. | `Dockerfile` |
-## Security Dashboard
-
-The Security Dashboard is a good place to get an overview of all the security
-vulnerabilities in your groups, projects and pipelines. Read more about the
-[Security Dashboard](../security_dashboard/index.md).
-
-## Interacting with the vulnerabilities
-
-Once a vulnerability is found, you can interact with it. Read more on how to
-[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
+### Overriding the Container Scanning template
-## Solutions for vulnerabilities (auto-remediation)
+If you want to override the job definition (for example, change properties like
+`variables`), you need to declare a `container_scanning` job after the
+template inclusion and specify any additional keys under it. For example:
-Some vulnerabilities can be fixed by applying the solution that GitLab
-automatically generates.
+```yaml
+include:
+ template: Container-Scanning.gitlab-ci.yml
-To enable remediation support, the scanning tool _must_ have access to the `Dockerfile` specified by
-the `DOCKERFILE_PATH` environment variable. To ensure that the scanning tool has access to this
-file, it's necessary to set [`GIT_STRATEGY: fetch`](../../../ci/yaml/README.md#git-strategy) in
-your `.gitlab-ci.yml` file by following the instructions described in this document's
-[overriding the Container Scanning template](#overriding-the-container-scanning-template) section.
+container_scanning:
+ variables:
+ GIT_STRATEGY: fetch
+```
-Read more about the [solutions for vulnerabilities](../index.md#solutions-for-vulnerabilities-auto-remediation).
+### Vulnerability whitelisting
-## Vulnerabilities database update
+If you want to whitelist specific vulnerabilities, you'll need to:
-For more information about the vulnerabilities database update, check the
-[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+1. Set `GIT_STRATEGY: fetch` in your `.gitlab-ci.yml` file by following the instructions described in the
+ [overriding the Container Scanning template](#overriding-the-container-scanning-template) section of this document.
+1. Define the whitelisted vulnerabilities in a YAML file named `clair-whitelist.yml` which must use the format described
+ in the [whitelist example file](https://github.com/arminc/clair-scanner/blob/v12/example-whitelist.yaml).
+1. Add the `clair-whitelist.yml` file to the Git repository of your project.
-## Running Container Scanning in an offline air-gapped installation
+### Running Container Scanning in an offline, air-gapped installation
Container Scanning can be executed on an offline air-gapped GitLab Ultimate installation using the following process:
@@ -245,7 +234,7 @@ It may be worthwhile to set up a [scheduled pipeline](../../../ci/pipelines/sche
image: docker:stable
services:
- - docker:stable-dind
+ - docker:19.03.5-dind
stages:
- build
@@ -396,6 +385,33 @@ the report JSON unless stated otherwise. Presence of optional fields depends on
| `remediations[].summary` | Overview of how the vulnerabilities have been fixed. |
| `remediations[].diff` | base64-encoded remediation code diff, compatible with [`git apply`](https://git-scm.com/docs/git-format-patch#_discussion). |
+## Security Dashboard
+
+The [Security Dashboard](../security_dashboard/index.md) shows you an overview of all
+the security vulnerabilities in your groups, projects and pipelines.
+
+## Vulnerabilities database update
+
+For more information about the vulnerabilities database update, check the
+[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
+
+## Interacting with the vulnerabilities
+
+Once a vulnerability is found, you can [interact with it](../index.md#interacting-with-the-vulnerabilities).
+
+## Solutions for vulnerabilities (auto-remediation)
+
+Some vulnerabilities can be fixed by applying the solution that GitLab
+automatically generates.
+
+To enable remediation support, the scanning tool _must_ have access to the `Dockerfile` specified by
+the `DOCKERFILE_PATH` environment variable. To ensure that the scanning tool has access to this
+file, it's necessary to set [`GIT_STRATEGY: fetch`](../../../ci/yaml/README.md#git-strategy) in
+your `.gitlab-ci.yml` file by following the instructions described in this document's
+[overriding the Container Scanning template](#overriding-the-container-scanning-template) section.
+
+Read more about the [solutions for vulnerabilities](../index.md#solutions-for-vulnerabilities-auto-remediation).
+
## Troubleshooting
### docker: Error response from daemon: failed to copy xattrs
diff --git a/lib/api/project_container_repositories.rb b/lib/api/project_container_repositories.rb
index 0fd887f4458..555fd98b451 100644
--- a/lib/api/project_container_repositories.rb
+++ b/lib/api/project_container_repositories.rb
@@ -70,14 +70,9 @@ module API
params do
requires :repository_id, type: Integer, desc: 'The ID of the repository'
optional :name_regex_delete, type: String, desc: 'The tag name regexp to delete, specify .* to delete all'
- # require either name_regex (deprecated) or name_regex_delete, it is ok to have both
- given name_regex_delete: ->(val) { val.nil? } do
- requires :name_regex, type: String, desc: 'The tag name regexp to delete, specify .* to delete all'
- end
optional :name_regex, type: String, desc: 'The tag name regexp to delete, specify .* to delete all'
- given name_regex: ->(val) { val.nil? } do
- requires :name_regex_delete, type: String, desc: 'The tag name regexp to delete, specify .* to delete all'
- end
+ # require either name_regex (deprecated) or name_regex_delete, it is ok to have both
+ at_least_one_of :name_regex, :name_regex_delete
optional :name_regex_keep, type: String, desc: 'The tag name regexp to retain'
optional :keep_n, type: Integer, desc: 'Keep n of latest tags with matching name'
optional :older_than, type: String, desc: 'Delete older than: 1h, 1d, 1month'
diff --git a/lib/banzai/filter/repository_link_filter.rb b/lib/banzai/filter/repository_link_filter.rb
index d448238c6e4..e15201b05cb 100644
--- a/lib/banzai/filter/repository_link_filter.rb
+++ b/lib/banzai/filter/repository_link_filter.rb
@@ -80,6 +80,13 @@ module Banzai
end
Gitlab::GitalyClient::BlobService.new(repository).get_blob_types(revision_paths, 1)
+ rescue GRPC::Unavailable, GRPC::DeadlineExceeded => e
+ # Handle Gitaly connection issues gracefully
+ Gitlab::ErrorTracking.track_exception(e, project_id: project.id)
+ # Return all links as blob types
+ paths.collect do |path|
+ [path, :blob]
+ end
end
def get_uri(html_attr)
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 057f6a41980..cb9cff0b988 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -9250,6 +9250,12 @@ msgstr ""
msgid "Geo|Remove"
msgstr ""
+msgid "Geo|Remove entry"
+msgstr ""
+
+msgid "Geo|Remove tracking database entry"
+msgstr ""
+
msgid "Geo|Repository sync capacity"
msgstr ""
@@ -9301,13 +9307,13 @@ msgstr ""
msgid "Geo|This is a primary node"
msgstr ""
-msgid "Geo|Tracking entry for project (%{project_id}) was successfully removed."
+msgid "Geo|Tracking database entry will be removed. Are you sure?"
msgstr ""
-msgid "Geo|Tracking entry for upload (%{type}/%{id}) was successfully removed."
+msgid "Geo|Tracking entry for project (%{project_id}) was successfully removed."
msgstr ""
-msgid "Geo|Tracking entry will be removed. Are you sure?"
+msgid "Geo|Tracking entry for upload (%{type}/%{id}) was successfully removed."
msgstr ""
msgid "Geo|URL"
diff --git a/spec/frontend/helpers/dom_shims/form_element.js b/spec/frontend/helpers/dom_shims/form_element.js
new file mode 100644
index 00000000000..46ef0374848
--- /dev/null
+++ b/spec/frontend/helpers/dom_shims/form_element.js
@@ -0,0 +1 @@
+HTMLFormElement.prototype.submit = jest.fn();
diff --git a/spec/frontend/helpers/dom_shims/index.js b/spec/frontend/helpers/dom_shims/index.js
index 855b707a4cf..bcd5da0ce48 100644
--- a/spec/frontend/helpers/dom_shims/index.js
+++ b/spec/frontend/helpers/dom_shims/index.js
@@ -1,4 +1,5 @@
import './element_scroll_into_view';
+import './form_element';
import './get_client_rects';
import './inner_text';
import './window_scroll_to';
diff --git a/spec/frontend/vue_shared/components/confirm_modal_spec.js b/spec/frontend/vue_shared/components/confirm_modal_spec.js
index 722380d3383..d3dea73e4a6 100644
--- a/spec/frontend/vue_shared/components/confirm_modal_spec.js
+++ b/spec/frontend/vue_shared/components/confirm_modal_spec.js
@@ -3,6 +3,8 @@ import { GlModal } from '@gitlab/ui';
import { TEST_HOST } from 'helpers/test_constants';
import ConfirmModal from '~/vue_shared/components/confirm_modal.vue';
+jest.mock('~/lib/utils/csrf', () => ({ token: 'test-csrf-token' }));
+
describe('vue_shared/components/confirm_modal', () => {
const testModalProps = {
path: `${TEST_HOST}/1`,
@@ -39,45 +41,61 @@ describe('vue_shared/components/confirm_modal', () => {
});
const findModal = () => wrapper.find(GlModal);
+ const findForm = () => wrapper.find('form');
+ const findFormData = () =>
+ findForm()
+ .findAll('input')
+ .wrappers.map(x => ({ name: x.attributes('name'), value: x.attributes('value') }));
describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
+ describe('when showModal is false', () => {
+ beforeEach(() => {
+ createComponent();
+ });
- it('calls openModal on mount', () => {
- expect(actionSpies.openModal).toHaveBeenCalled();
+ it('does not render GlModal', () => {
+ expect(findModal().exists()).toBeFalsy();
+ });
});
- it('renders GlModal', () => {
- expect(findModal().exists()).toBeTruthy();
+ describe('when showModal is true', () => {
+ beforeEach(() => {
+ createComponent({ showModal: true });
+ });
+
+ it('renders GlModal', () => {
+ expect(findModal().exists()).toBeTruthy();
+ expect(findModal().attributes()).toEqual(
+ expect.objectContaining({
+ modalid: testModalProps.modalAttributes.modalId,
+ oktitle: testModalProps.modalAttributes.okTitle,
+ okvariant: testModalProps.modalAttributes.okVariant,
+ }),
+ );
+ });
});
});
describe('methods', () => {
beforeEach(() => {
- createComponent();
+ createComponent({ showModal: true });
});
- describe('submitModal', () => {
- beforeEach(() => {
- wrapper.vm.$refs.form.requestSubmit = jest.fn();
- });
-
- it('calls requestSubmit', () => {
- wrapper.vm.submitModal();
- expect(wrapper.vm.$refs.form.requestSubmit).toHaveBeenCalled();
- });
+ it('does not submit form', () => {
+ expect(findForm().element.submit).not.toHaveBeenCalled();
});
- describe('dismiss', () => {
- it('removes gl-modal', () => {
- expect(findModal().exists()).toBeTruthy();
- wrapper.vm.dismiss();
+ describe('when modal submitted', () => {
+ beforeEach(() => {
+ findModal().vm.$emit('primary');
+ });
- return wrapper.vm.$nextTick(() => {
- expect(findModal().exists()).toBeFalsy();
- });
+ it('submits form', () => {
+ expect(findFormData()).toEqual([
+ { name: '_method', value: testModalProps.method },
+ { name: 'authenticity_token', value: 'test-csrf-token' },
+ ]);
+ expect(findForm().element.submit).toHaveBeenCalled();
});
});
});
diff --git a/spec/lib/banzai/filter/repository_link_filter_spec.rb b/spec/lib/banzai/filter/repository_link_filter_spec.rb
index cf73c77ecb8..f093a5b0a79 100644
--- a/spec/lib/banzai/filter/repository_link_filter_spec.rb
+++ b/spec/lib/banzai/filter/repository_link_filter_spec.rb
@@ -149,6 +149,34 @@ describe Banzai::Filter::RepositoryLinkFilter do
end
shared_examples :valid_repository do
+ it 'handles Gitaly unavailable exceptions gracefully' do
+ allow_next_instance_of(Gitlab::GitalyClient::BlobService) do |blob_service|
+ allow(blob_service).to receive(:get_blob_types).and_raise(GRPC::Unavailable)
+ end
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ an_instance_of(GRPC::Unavailable), project_id: project.id
+ )
+ doc = ""
+ expect { doc = filter(link('doc/api/README.md')) }.not_to raise_error
+ expect(doc.at_css('a')['href'])
+ .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
+ end
+
+ it 'handles Gitaly timeout exceptions gracefully' do
+ allow_next_instance_of(Gitlab::GitalyClient::BlobService) do |blob_service|
+ allow(blob_service).to receive(:get_blob_types).and_raise(GRPC::DeadlineExceeded)
+ end
+
+ expect(Gitlab::ErrorTracking).to receive(:track_exception).with(
+ an_instance_of(GRPC::DeadlineExceeded), project_id: project.id
+ )
+ doc = ""
+ expect { doc = filter(link('doc/api/README.md')) }.not_to raise_error
+ expect(doc.at_css('a')['href'])
+ .to eq "/#{project_path}/-/blob/#{ref}/doc/api/README.md"
+ end
+
it 'rebuilds absolute URL for a file in the repo' do
doc = filter(link('/doc/api/README.md'))
expect(doc.at_css('a')['href'])
diff --git a/spec/models/clusters/applications/cert_manager_spec.rb b/spec/models/clusters/applications/cert_manager_spec.rb
index 31209a70018..d7fd0d06b05 100644
--- a/spec/models/clusters/applications/cert_manager_spec.rb
+++ b/spec/models/clusters/applications/cert_manager_spec.rb
@@ -46,11 +46,11 @@ describe Clusters::Applications::CertManager do
expect(subject.name).to eq('certmanager')
expect(subject.chart).to eq('certmanager/cert-manager')
expect(subject.repository).to eq('https://charts.jetstack.io')
- expect(subject.version).to eq('v0.9.1')
+ expect(subject.version).to eq('v0.10.1')
expect(subject).to be_rbac
expect(subject.files).to eq(cert_manager.files.merge(cluster_issuer_file))
expect(subject.preinstall).to eq([
- 'kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.9/deploy/manifests/00-crds.yaml',
+ 'kubectl apply -f https://raw.githubusercontent.com/jetstack/cert-manager/release-0.10/deploy/manifests/00-crds.yaml',
'kubectl label --overwrite namespace gitlab-managed-apps certmanager.k8s.io/disable-validation=true'
])
expect(subject.postinstall).to eq([
@@ -82,7 +82,7 @@ describe Clusters::Applications::CertManager do
let(:cert_manager) { create(:clusters_applications_cert_manager, :errored, version: '0.0.1') }
it 'is initialized with the locked version' do
- expect(subject.version).to eq('v0.9.1')
+ expect(subject.version).to eq('v0.10.1')
end
end
end