summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-05-26 13:52:02 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2020-05-26 13:52:02 +0000
commit846745cb0d327506fb313df61fc351c04134449d (patch)
treec6cd12c8bd35994c366e73fe32a4b712875063cc
parentdfc92d081ea0332d69c8aca2f0e745cb48ae5e6d (diff)
downloadgitlab-ce-846745cb0d327506fb313df61fc351c04134449d.tar.gz
Add latest changes from gitlab-org/security/gitlab@12-10-stable-ee
-rw-r--r--app/assets/javascripts/clusters/clusters_bundle.js16
-rw-r--r--app/assets/javascripts/issue.js6
-rw-r--r--app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue3
-rw-r--r--app/services/clusters/update_service.rb6
-rw-r--r--app/views/clusters/clusters/_provider_details_form.html.haml14
-rw-r--r--app/views/shared/issuable/_close_reopen_report_toggle.html.haml2
-rw-r--r--changelogs/unreleased/security-99-disable-caching-on-api-repo-blobs-raw.yml5
-rw-r--r--changelogs/unreleased/security-do-not-expose-kubernetes-token.yml5
-rw-r--r--changelogs/unreleased/security-fix-mermaid-issue.yml5
-rw-r--r--changelogs/unreleased/security-group-import-file-enuming.yml5
-rw-r--r--changelogs/unreleased/security-jivanvl-prevent-xss-duplicate-dashboard-modal.yml5
-rw-r--r--doc/api/projects.md2
-rw-r--r--lib/api/group_import.rb17
-rw-r--r--lib/api/repositories.rb4
-rw-r--r--locale/gitlab.pot18
-rw-r--r--spec/features/groups/clusters/user_spec.rb2
-rw-r--r--spec/features/projects/clusters/user_spec.rb2
-rw-r--r--spec/frontend/clusters/clusters_bundle_spec.js22
-rw-r--r--spec/frontend/fixtures/static/issue_with_mermaid_graph.html82
-rw-r--r--spec/frontend/issue_spec.js27
-rw-r--r--spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js36
-rw-r--r--spec/requests/api/group_import_spec.rb33
-rw-r--r--spec/requests/api/repositories_spec.rb6
-rw-r--r--spec/services/clusters/update_service_spec.rb33
-rw-r--r--spec/support/shared_examples/uncached_response_shared_examples.rb12
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/C++.gitignore0
-rw-r--r--[-rwxr-xr-x]vendor/gitignore/Java.gitignore0
27 files changed, 267 insertions, 101 deletions
diff --git a/app/assets/javascripts/clusters/clusters_bundle.js b/app/assets/javascripts/clusters/clusters_bundle.js
index 1b11ec355bb..3d2a9ae4c85 100644
--- a/app/assets/javascripts/clusters/clusters_bundle.js
+++ b/app/assets/javascripts/clusters/clusters_bundle.js
@@ -105,7 +105,6 @@ export default class Clusters {
});
this.installApplication = this.installApplication.bind(this);
- this.showToken = this.showToken.bind(this);
this.errorContainer = document.querySelector('.js-cluster-error');
this.successContainer = document.querySelector('.js-cluster-success');
@@ -116,7 +115,6 @@ export default class Clusters {
);
this.errorReasonContainer = this.errorContainer.querySelector('.js-error-reason');
this.successApplicationContainer = document.querySelector('.js-cluster-application-notice');
- this.showTokenButton = document.querySelector('.js-show-cluster-token');
this.tokenField = document.querySelector('.js-cluster-token');
this.ingressDomainHelpText = document.querySelector('.js-ingress-domain-help-text');
this.ingressDomainSnippet =
@@ -255,7 +253,6 @@ export default class Clusters {
}
addListeners() {
- if (this.showTokenButton) this.showTokenButton.addEventListener('click', this.showToken);
eventHub.$on('installApplication', this.installApplication);
eventHub.$on('updateApplication', data => this.updateApplication(data));
eventHub.$on('saveKnativeDomain', data => this.saveKnativeDomain(data));
@@ -271,7 +268,6 @@ export default class Clusters {
}
removeListeners() {
- if (this.showTokenButton) this.showTokenButton.removeEventListener('click', this.showToken);
eventHub.$off('installApplication', this.installApplication);
eventHub.$off('updateApplication', this.updateApplication);
eventHub.$off('saveKnativeDomain');
@@ -339,18 +335,6 @@ export default class Clusters {
}
}
- showToken() {
- const type = this.tokenField.getAttribute('type');
-
- if (type === 'password') {
- this.tokenField.setAttribute('type', 'text');
- this.showTokenButton.textContent = s__('ClusterIntegration|Hide');
- } else {
- this.tokenField.setAttribute('type', 'password');
- this.showTokenButton.textContent = s__('ClusterIntegration|Show');
- }
- }
-
hideAll() {
this.errorContainer.classList.add('hidden');
this.successContainer.classList.add('hidden');
diff --git a/app/assets/javascripts/issue.js b/app/assets/javascripts/issue.js
index 9136a47d542..0e20c96df8c 100644
--- a/app/assets/javascripts/issue.js
+++ b/app/assets/javascripts/issue.js
@@ -101,7 +101,11 @@ export default class Issue {
this.disableCloseReopenButton($button);
- const url = $button.attr('href');
+ const url = $button.data('close-reopen-url');
+ if (!url) {
+ return;
+ }
+
return axios
.put(url)
.then(({ data }) => {
diff --git a/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue b/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
index 58eb8a9df8e..001cd0d47f1 100644
--- a/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
+++ b/app/assets/javascripts/monitoring/components/duplicate_dashboard_form.vue
@@ -1,6 +1,7 @@
<script>
import { __, s__, sprintf } from '~/locale';
import { GlFormGroup, GlFormInput, GlFormRadioGroup, GlFormTextarea } from '@gitlab/ui';
+import { escape as esc } from 'lodash';
const defaultFileName = dashboard => dashboard.path.split('/').reverse()[0];
@@ -42,7 +43,7 @@ export default {
html: sprintf(
__('Commit to %{branchName} branch'),
{
- branchName: `<strong>${this.defaultBranch}</strong>`,
+ branchName: `<strong>${esc(this.defaultBranch)}</strong>`,
},
false,
),
diff --git a/app/services/clusters/update_service.rb b/app/services/clusters/update_service.rb
index 2315df612a1..ba20826848d 100644
--- a/app/services/clusters/update_service.rb
+++ b/app/services/clusters/update_service.rb
@@ -10,6 +10,12 @@ module Clusters
def execute(cluster)
if validate_params(cluster)
+ token = params.dig(:platform_kubernetes_attributes, :token)
+
+ if token.blank?
+ params[:platform_kubernetes_attributes]&.delete(:token)
+ end
+
cluster.update(params)
else
false
diff --git a/app/views/clusters/clusters/_provider_details_form.html.haml b/app/views/clusters/clusters/_provider_details_form.html.haml
index dd7d6182e3c..fcb5d4402d6 100644
--- a/app/views/clusters/clusters/_provider_details_form.html.haml
+++ b/app/views/clusters/clusters/_provider_details_form.html.haml
@@ -25,16 +25,10 @@
label: s_('ClusterIntegration|CA Certificate'), label_class: 'label-bold',
input_group_class: 'gl-field-error-anchor', append: copy_ca_cert_btn
- - show_token_btn = (platform_field.button s_('ClusterIntegration|Show'),
- type: 'button', class: 'js-show-cluster-token btn btn-default')
- - copy_token_btn = clipboard_button(text: platform.token, title: s_('ClusterIntegration|Copy Service Token'),
- class: 'input-group-text btn-default') if cluster.read_only_kubernetes_platform_fields?
-
- = platform_field.text_field :token, type: 'password', class: 'js-select-on-focus js-cluster-token',
- required: true, title: s_('ClusterIntegration|Service token is required.'),
- readonly: cluster.read_only_kubernetes_platform_fields?,
- label: s_('ClusterIntegration|Service Token'), label_class: 'label-bold',
- input_group_class: 'gl-field-error-anchor', append: show_token_btn + copy_token_btn
+ = platform_field.password_field :token, type: 'password', class: 'js-select-on-focus js-cluster-token',
+ readonly: cluster.read_only_kubernetes_platform_fields?, autocomplete: 'new-password',
+ label: s_('ClusterIntegration|Enter new Service Token'), label_class: 'label-bold',
+ input_group_class: 'gl-field-error-anchor'
= platform_field.form_group :authorization_type do
= platform_field.check_box :authorization_type, { disabled: true, label: s_('ClusterIntegration|RBAC-enabled cluster'),
diff --git a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
index 0d59c9304b4..db01eb24a79 100644
--- a/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
+++ b/app/views/shared/issuable/_close_reopen_report_toggle.html.haml
@@ -8,7 +8,7 @@
.float-left.btn-group.prepend-left-10.issuable-close-dropdown.droplab-dropdown.js-issuable-close-dropdown
= link_to "#{display_button_action} #{display_issuable_type}", close_reopen_issuable_path(issuable),
- method: button_method, class: "#{button_class} btn-#{button_action}", title: "#{display_button_action} #{display_issuable_type}"
+ method: button_method, class: "#{button_class} btn-#{button_action}", title: "#{display_button_action} #{display_issuable_type}", data: { 'close-reopen-url': close_reopen_issuable_path(issuable) }
= button_tag type: 'button', class: "#{toggle_class} btn-#{button_action}-color",
data: { 'dropdown-trigger' => '#issuable-close-menu' }, 'aria-label' => 'Toggle dropdown' do
diff --git a/changelogs/unreleased/security-99-disable-caching-on-api-repo-blobs-raw.yml b/changelogs/unreleased/security-99-disable-caching-on-api-repo-blobs-raw.yml
new file mode 100644
index 00000000000..1869e6ea039
--- /dev/null
+++ b/changelogs/unreleased/security-99-disable-caching-on-api-repo-blobs-raw.yml
@@ -0,0 +1,5 @@
+---
+title: Disable caching on repo/blobs/[sha]/raw endpoint
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-do-not-expose-kubernetes-token.yml b/changelogs/unreleased/security-do-not-expose-kubernetes-token.yml
new file mode 100644
index 00000000000..9297a4d927e
--- /dev/null
+++ b/changelogs/unreleased/security-do-not-expose-kubernetes-token.yml
@@ -0,0 +1,5 @@
+---
+title: Kubernetes cluster details page no longer exposes Service Token
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-fix-mermaid-issue.yml b/changelogs/unreleased/security-fix-mermaid-issue.yml
new file mode 100644
index 00000000000..4c254f8a4f5
--- /dev/null
+++ b/changelogs/unreleased/security-fix-mermaid-issue.yml
@@ -0,0 +1,5 @@
+---
+title: Disallow user to control PUT request using mermaid markdown in issue description
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-group-import-file-enuming.yml b/changelogs/unreleased/security-group-import-file-enuming.yml
new file mode 100644
index 00000000000..efdff7e84e9
--- /dev/null
+++ b/changelogs/unreleased/security-group-import-file-enuming.yml
@@ -0,0 +1,5 @@
+---
+title: Fix file enuming using Group Import
+merge_request:
+author:
+type: security
diff --git a/changelogs/unreleased/security-jivanvl-prevent-xss-duplicate-dashboard-modal.yml b/changelogs/unreleased/security-jivanvl-prevent-xss-duplicate-dashboard-modal.yml
new file mode 100644
index 00000000000..d4d7b1dbff6
--- /dev/null
+++ b/changelogs/unreleased/security-jivanvl-prevent-xss-duplicate-dashboard-modal.yml
@@ -0,0 +1,5 @@
+---
+title: Prevent XSS in the monitoring dashboard
+merge_request:
+author:
+type: security
diff --git a/doc/api/projects.md b/doc/api/projects.md
index 16c8569349c..d4f15706e9c 100644
--- a/doc/api/projects.md
+++ b/doc/api/projects.md
@@ -1197,7 +1197,7 @@ PUT /projects/:id
| `approvals_before_merge` | integer | no | **(STARTER)** How many approvers should approve merge request by default |
| `external_authorization_classification_label` | string | no | **(PREMIUM)** The classification label for the project |
| `mirror` | boolean | no | **(STARTER)** Enables pull mirroring in a project |
-| `mirror_user_id` | integer | no | **(STARTER)** User responsible for all the activity surrounding a pull mirror event |
+| `mirror_user_id` | integer | no | **(STARTER)** User responsible for all the activity surrounding a pull mirror event. Can only be set by admins. |
| `mirror_trigger_builds` | boolean | no | **(STARTER)** Pull mirroring triggers builds |
| `only_mirror_protected_branches` | boolean | no | **(STARTER)** Only mirror protected branches |
| `mirror_overwrites_diverged_branches` | boolean | no | **(STARTER)** Pull mirror overwrites diverged branches |
diff --git a/lib/api/group_import.rb b/lib/api/group_import.rb
index ed52506de14..ec51c2f44c3 100644
--- a/lib/api/group_import.rb
+++ b/lib/api/group_import.rb
@@ -4,6 +4,8 @@ module API
class GroupImport < Grape::API
MAXIMUM_FILE_SIZE = 50.megabytes.freeze
+ helpers Helpers::FileUploadHelpers
+
helpers do
def parent_group
find_group!(params[:parent_id]) if params[:parent_id].present?
@@ -48,29 +50,20 @@ module API
params do
requires :path, type: String, desc: 'Group path'
requires :name, type: String, desc: 'Group name'
+ requires :file, type: ::API::Validations::Types::WorkhorseFile, desc: 'The group export file to be imported'
optional :parent_id, type: Integer, desc: "The ID of the parent group that the group will be imported into. Defaults to the current user's namespace."
- optional 'file.path', type: String, desc: 'Path to locally stored body (generated by Workhorse)'
- optional 'file.name', type: String, desc: 'Real filename as send in Content-Disposition (generated by Workhorse)'
- optional 'file.type', type: String, desc: 'Real content type as send in Content-Type (generated by Workhorse)'
- optional 'file.size', type: Integer, desc: 'Real size of file (generated by Workhorse)'
- optional 'file.md5', type: String, desc: 'MD5 checksum of the file (generated by Workhorse)'
- optional 'file.sha1', type: String, desc: 'SHA1 checksum of the file (generated by Workhorse)'
- optional 'file.sha256', type: String, desc: 'SHA256 checksum of the file (generated by Workhorse)'
end
post 'import' do
authorize_create_group!
require_gitlab_workhorse!
-
- uploaded_file = UploadedFile.from_params(params, :file, ImportExportUploader.workhorse_local_upload_path)
-
- bad_request!('Unable to process group import file') unless uploaded_file
+ validate_file!
group_params = {
path: params[:path],
name: params[:name],
parent_id: params[:parent_id],
visibility_level: closest_allowed_visibility_level,
- import_export_upload: ImportExportUpload.new(import_file: uploaded_file)
+ import_export_upload: ImportExportUpload.new(import_file: params[:file])
}
group = ::Groups::CreateService.new(current_user, group_params).execute
diff --git a/lib/api/repositories.rb b/lib/api/repositories.rb
index 0b2df85f61f..bf4f08ce390 100644
--- a/lib/api/repositories.rb
+++ b/lib/api/repositories.rb
@@ -6,6 +6,8 @@ module API
class Repositories < Grape::API
include PaginationParams
+ helpers ::API::Helpers::HeadersHelpers
+
before { authorize! :download_code, user_project }
params do
@@ -67,6 +69,8 @@ module API
get ':id/repository/blobs/:sha/raw' do
assign_blob_vars!
+ no_cache_headers
+
send_git_blob @repo, @blob
end
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 24e4073d3af..18cde86f956 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -4362,9 +4362,6 @@ msgstr ""
msgid "ClusterIntegration|Copy Kubernetes cluster name"
msgstr ""
-msgid "ClusterIntegration|Copy Service Token"
-msgstr ""
-
msgid "ClusterIntegration|Could not load IAM roles"
msgstr ""
@@ -4443,6 +4440,9 @@ msgstr ""
msgid "ClusterIntegration|Enabled stack"
msgstr ""
+msgid "ClusterIntegration|Enter new Service Token"
+msgstr ""
+
msgid "ClusterIntegration|Enter the details for your Amazon EKS Kubernetes cluster"
msgstr ""
@@ -4518,9 +4518,6 @@ msgstr ""
msgid "ClusterIntegration|Helm streamlines installing and managing Kubernetes applications. Tiller runs inside of your Kubernetes Cluster, and manages releases of your charts."
msgstr ""
-msgid "ClusterIntegration|Hide"
-msgstr ""
-
msgid "ClusterIntegration|If you are setting up multiple clusters and are using Auto DevOps, %{help_link_start}read this first%{help_link_end}."
msgstr ""
@@ -4896,9 +4893,6 @@ msgstr ""
msgid "ClusterIntegration|Set the global mode for the WAF in this cluster. This can be overridden at the environmental level."
msgstr ""
-msgid "ClusterIntegration|Show"
-msgstr ""
-
msgid "ClusterIntegration|Something went wrong on our end."
msgstr ""
@@ -21248,9 +21242,6 @@ msgstr ""
msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
msgstr ""
-msgid "This user will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches. Upon creation or when reassigning you can only assign yourself to be the mirror user."
-msgstr ""
-
msgid "This variable can not be masked."
msgstr ""
@@ -23973,6 +23964,9 @@ msgstr ""
msgid "You will be removed from existing projects/groups"
msgstr ""
+msgid "You will be the author of all events in the activity feed that are the result of an update, like new branches being created or new commits being pushed to existing branches."
+msgstr ""
+
msgid "You will first need to set up Jira Integration to use this feature."
msgstr ""
diff --git a/spec/features/groups/clusters/user_spec.rb b/spec/features/groups/clusters/user_spec.rb
index e9ef66e31a2..a29afba99e4 100644
--- a/spec/features/groups/clusters/user_spec.rb
+++ b/spec/features/groups/clusters/user_spec.rb
@@ -39,7 +39,7 @@ describe 'User Cluster', :js do
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
+ .to be_empty
end
end
diff --git a/spec/features/projects/clusters/user_spec.rb b/spec/features/projects/clusters/user_spec.rb
index 79676927fa2..5c82d848563 100644
--- a/spec/features/projects/clusters/user_spec.rb
+++ b/spec/features/projects/clusters/user_spec.rb
@@ -46,7 +46,7 @@ describe 'User Cluster', :js do
expect(page.find_field('cluster[platform_kubernetes_attributes][api_url]').value)
.to have_content('http://example.com')
expect(page.find_field('cluster[platform_kubernetes_attributes][token]').value)
- .to have_content('my-token')
+ .to be_empty
end
it 'user sees RBAC is enabled by default' do
diff --git a/spec/frontend/clusters/clusters_bundle_spec.js b/spec/frontend/clusters/clusters_bundle_spec.js
index d7c648bcd20..9d0ed423759 100644
--- a/spec/frontend/clusters/clusters_bundle_spec.js
+++ b/spec/frontend/clusters/clusters_bundle_spec.js
@@ -82,28 +82,6 @@ describe('Clusters', () => {
});
});
- describe('showToken', () => {
- it('should update token field type', () => {
- cluster.showTokenButton.click();
-
- expect(cluster.tokenField.getAttribute('type')).toEqual('text');
-
- cluster.showTokenButton.click();
-
- expect(cluster.tokenField.getAttribute('type')).toEqual('password');
- });
-
- it('should update show token button text', () => {
- cluster.showTokenButton.click();
-
- expect(cluster.showTokenButton.textContent).toEqual('Hide');
-
- cluster.showTokenButton.click();
-
- expect(cluster.showTokenButton.textContent).toEqual('Show');
- });
- });
-
describe('checkForNewInstalls', () => {
const INITIAL_APP_MAP = {
helm: { status: null, title: 'Helm Tiller' },
diff --git a/spec/frontend/fixtures/static/issue_with_mermaid_graph.html b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
new file mode 100644
index 00000000000..4b60842a655
--- /dev/null
+++ b/spec/frontend/fixtures/static/issue_with_mermaid_graph.html
@@ -0,0 +1,82 @@
+<div class="description" updated-at="">
+ <div class="md issue-realtime-trigger-pulse">
+ <svg
+ id="mermaid-1587752414912"
+ width="100%"
+ xmlns="http://www.w3.org/2000/svg"
+ style="max-width: 185.35000610351562px;"
+ viewBox="0 0 185.35000610351562 50.5"
+ class="mermaid"
+ >
+ <g transform="translate(0, 0)">
+ <g class="output">
+ <g class="clusters"></g>
+ <g class="edgePaths"></g>
+ <g class="edgeLabels"></g>
+ <g class="nodes">
+ <g
+ class="node js-issuable-actions btn-close clickable"
+ style="opacity: 1;"
+ id="A"
+ transform="translate(92.67500305175781,25.25)"
+ title="click to PUT"
+ >
+ <a
+ class="js-issuable-actions btn-close clickable"
+ href="https://invalid"
+ rel="noopener"
+ >
+ <rect
+ rx="0"
+ ry="0"
+ x="-84.67500305175781"
+ y="-17.25"
+ width="169.35000610351562"
+ height="34.5"
+ class="label-container"
+ ></rect>
+ <g class="label" transform="translate(0,0)">
+ <g transform="translate(-74.67500305175781,-7.25)">
+ <text style="">
+ <tspan xml:space="preserve" dy="1em" x="1">Click to send a PUT request</tspan>
+ </text>
+ </g>
+ </g>
+ </a>
+ </g>
+ </g>
+ </g>
+ </g>
+ <text class="source" display="none">
+ Click to send a PUT request
+ </text>
+ </svg>
+ </div>
+ <textarea
+ data-update-url="/h5bp/html5-boilerplate/-/issues/35.json"
+ dir="auto"
+ class="hidden js-task-list-field"
+ ></textarea>
+ <div class="modal-open recaptcha-modal js-recaptcha-modal" style="display: none;">
+ <div role="dialog" tabindex="-1" class="modal d-block">
+ <div role="document" class="modal-dialog">
+ <div class="modal-content">
+ <div class="modal-header">
+ <h4 class="modal-title float-left">Please solve the reCAPTCHA</h4>
+ <button type="button" data-dismiss="modal" aria-label="Close" class="close float-right">
+ <span aria-hidden="true">×</span>
+ </button>
+ </div>
+ <div class="modal-body">
+ <div>
+ <p>We want to be sure it is you, please confirm you are not a robot.</p>
+ <div></div>
+ </div>
+ </div>
+ <!---->
+ </div>
+ </div>
+ </div>
+ <div class="modal-backdrop fade show"></div>
+ </div>
+</div>
diff --git a/spec/frontend/issue_spec.js b/spec/frontend/issue_spec.js
index 586bd7f8529..24020daf728 100644
--- a/spec/frontend/issue_spec.js
+++ b/spec/frontend/issue_spec.js
@@ -18,6 +18,7 @@ describe('Issue', () => {
preloadFixtures('issues/closed-issue.html');
preloadFixtures('issues/issue-with-task-list.html');
preloadFixtures('issues/open-issue.html');
+ preloadFixtures('static/issue_with_mermaid_graph.html');
function expectErrorMessage() {
const $flashMessage = $('div.flash-alert');
@@ -228,4 +229,30 @@ describe('Issue', () => {
});
});
});
+
+ describe('when not displaying blocked warning', () => {
+ describe('when clicking a mermaid graph inside an issue description', () => {
+ let mock;
+ let spy;
+
+ beforeEach(() => {
+ loadFixtures('static/issue_with_mermaid_graph.html');
+ mock = new MockAdapter(axios);
+ spy = jest.spyOn(axios, 'put');
+ });
+
+ afterEach(() => {
+ mock.restore();
+ jest.clearAllMocks();
+ });
+
+ it('does not make a PUT request', () => {
+ Issue.prototype.initIssueBtnEventListeners();
+
+ $('svg a.js-issuable-actions').trigger('click');
+
+ expect(spy).not.toHaveBeenCalled();
+ });
+ });
+ });
});
diff --git a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
index 10fd58f749d..61d5f7a99d3 100644
--- a/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
+++ b/spec/frontend/monitoring/components/duplicate_dashboard_form_spec.js
@@ -3,9 +3,17 @@ import DuplicateDashboardForm from '~/monitoring/components/duplicate_dashboard_
import { dashboardGitResponse } from '../mock_data';
-describe('DuplicateDashboardForm', () => {
- let wrapper;
+let wrapper;
+
+const createMountedWrapper = (props = {}) => {
+ // Use `mount` to render native input elements
+ wrapper = mount(DuplicateDashboardForm, {
+ propsData: { ...props },
+ sync: false,
+ });
+};
+describe('DuplicateDashboardForm', () => {
const defaultBranch = 'master';
const findByRef = ref => wrapper.find({ ref });
@@ -20,14 +28,7 @@ describe('DuplicateDashboardForm', () => {
};
beforeEach(() => {
- // Use `mount` to render native input elements
- wrapper = mount(DuplicateDashboardForm, {
- propsData: {
- dashboard: dashboardGitResponse[0],
- defaultBranch,
- },
- sync: false,
- });
+ createMountedWrapper({ dashboard: dashboardGitResponse[0], defaultBranch });
});
it('renders correctly', () => {
@@ -144,3 +145,18 @@ describe('DuplicateDashboardForm', () => {
});
});
});
+
+describe('DuplicateDashboardForm escapes elements', () => {
+ const branchToEscape = "<img/src='x'onerror=alert(document.domain)>";
+
+ beforeEach(() => {
+ createMountedWrapper({ dashboard: dashboardGitResponse[0], defaultBranch: branchToEscape });
+ });
+
+ it('should escape branch name data', () => {
+ const branchOptionHtml = wrapper.vm.branchOptions[0].html;
+ const escapedBranch = '&lt;img/src=&#39;x&#39;onerror=alert(document.domain)&gt';
+
+ expect(branchOptionHtml).toEqual(expect.stringContaining(escapedBranch));
+ });
+});
diff --git a/spec/requests/api/group_import_spec.rb b/spec/requests/api/group_import_spec.rb
index 58bff08dcbb..b60a1b3f119 100644
--- a/spec/requests/api/group_import_spec.rb
+++ b/spec/requests/api/group_import_spec.rb
@@ -11,7 +11,7 @@ describe API::GroupImport do
let(:file) { File.join('spec', 'fixtures', 'group_export.tar.gz') }
let(:export_path) { "#{Dir.tmpdir}/group_export_spec" }
let(:workhorse_token) { JWT.encode({ 'iss' => 'gitlab-workhorse' }, Gitlab::Workhorse.secret, 'HS256') }
- let(:workhorse_header) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
+ let(:workhorse_headers) { { 'GitLab-Workhorse' => '1.0', Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER => workhorse_token } }
before do
allow_next_instance_of(Gitlab::ImportExport) do |import_export|
@@ -35,7 +35,7 @@ describe API::GroupImport do
}
end
- subject { post api('/groups/import', user), params: params, headers: workhorse_header }
+ subject { upload_archive(file_upload, workhorse_headers, params) }
shared_examples 'when all params are correct' do
context 'when user is authorized to create new group' do
@@ -151,7 +151,7 @@ describe API::GroupImport do
params[:file] = file_upload
expect do
- post api('/groups/import', user), params: params, headers: workhorse_header
+ upload_archive(file_upload, workhorse_headers, params)
end.not_to change { Group.count }.from(1)
expect(response).to have_gitlab_http_status(:bad_request)
@@ -171,7 +171,7 @@ describe API::GroupImport do
context 'without a file from workhorse' do
it 'rejects the request' do
- subject
+ upload_archive(nil, workhorse_headers, params)
expect(response).to have_gitlab_http_status(:bad_request)
end
@@ -179,7 +179,7 @@ describe API::GroupImport do
context 'without a workhorse header' do
it 'rejects request without a workhorse header' do
- post api('/groups/import', user), params: params
+ upload_archive(file_upload, {}, params)
expect(response).to have_gitlab_http_status(:forbidden)
end
@@ -189,9 +189,7 @@ describe API::GroupImport do
let(:params) do
{
path: 'test-import-group',
- name: 'test-import-group',
- 'file.path' => file_upload.path,
- 'file.name' => file_upload.original_filename
+ name: 'test-import-group'
}
end
@@ -229,9 +227,7 @@ describe API::GroupImport do
{
path: 'test-import-group',
name: 'test-import-group',
- file: fog_file,
- 'file.remote_id' => file_name,
- 'file.size' => fog_file.size
+ file: fog_file
}
end
@@ -245,10 +241,21 @@ describe API::GroupImport do
include_examples 'when some params are missing'
end
end
+
+ def upload_archive(file, headers = {}, params = {})
+ workhorse_finalize(
+ api('/groups/import', user),
+ method: :post,
+ file_key: :file,
+ params: params.merge(file: file),
+ headers: headers,
+ send_rewritten_field: true
+ )
+ end
end
describe 'POST /groups/import/authorize' do
- subject { post api('/groups/import/authorize', user), headers: workhorse_header }
+ subject { post api('/groups/import/authorize', user), headers: workhorse_headers }
it 'authorizes importing group with workhorse header' do
subject
@@ -258,7 +265,7 @@ describe API::GroupImport do
end
it 'rejects requests that bypassed gitlab-workhorse' do
- workhorse_header.delete(Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER)
+ workhorse_headers.delete(Gitlab::Workhorse::INTERNAL_API_REQUEST_HEADER)
subject
diff --git a/spec/requests/api/repositories_spec.rb b/spec/requests/api/repositories_spec.rb
index 0c66bfd6c4d..bfc782c62e5 100644
--- a/spec/requests/api/repositories_spec.rb
+++ b/spec/requests/api/repositories_spec.rb
@@ -177,6 +177,12 @@ describe API::Repositories do
expect(headers['Content-Disposition']).to eq 'inline'
end
+ it_behaves_like 'uncached response' do
+ before do
+ get api(route, current_user)
+ end
+ end
+
context 'when sha does not exist' do
it_behaves_like '404 response' do
let(:request) { get api(route.sub(sample_blob.oid, 'abcd9876'), current_user) }
diff --git a/spec/services/clusters/update_service_spec.rb b/spec/services/clusters/update_service_spec.rb
index d487edd8850..5a7726eded8 100644
--- a/spec/services/clusters/update_service_spec.rb
+++ b/spec/services/clusters/update_service_spec.rb
@@ -47,6 +47,39 @@ describe Clusters::UpdateService do
expect(cluster.platform.namespace).to eq('custom-namespace')
end
end
+
+ context 'when service token is empty' do
+ let(:params) do
+ {
+ platform_kubernetes_attributes: {
+ token: ''
+ }
+ }
+ end
+
+ it 'does not update the token' do
+ current_token = cluster.platform.token
+ is_expected.to eq(true)
+ cluster.platform.reload
+
+ expect(cluster.platform.token).to eq(current_token)
+ end
+ end
+
+ context 'when service token is not empty' do
+ let(:params) do
+ {
+ platform_kubernetes_attributes: {
+ token: 'new secret token'
+ }
+ }
+ end
+
+ it 'updates the token' do
+ is_expected.to eq(true)
+ expect(cluster.platform.token).to eq('new secret token')
+ end
+ end
end
context 'when invalid params' do
diff --git a/spec/support/shared_examples/uncached_response_shared_examples.rb b/spec/support/shared_examples/uncached_response_shared_examples.rb
new file mode 100644
index 00000000000..3997017ff35
--- /dev/null
+++ b/spec/support/shared_examples/uncached_response_shared_examples.rb
@@ -0,0 +1,12 @@
+# frozen_string_literal: true
+#
+# Pairs with lib/gitlab/no_cache_headers.rb
+#
+
+RSpec.shared_examples 'uncached response' do
+ it 'defines an uncached header response' do
+ expect(response.headers["Cache-Control"]).to include("no-store", "no-cache")
+ expect(response.headers["Pragma"]).to eq("no-cache")
+ expect(response.headers["Expires"]).to eq("Fri, 01 Jan 1990 00:00:00 GMT")
+ end
+end
diff --git a/vendor/gitignore/C++.gitignore b/vendor/gitignore/C++.gitignore
index 259148fa18f..259148fa18f 100755..100644
--- a/vendor/gitignore/C++.gitignore
+++ b/vendor/gitignore/C++.gitignore
diff --git a/vendor/gitignore/Java.gitignore b/vendor/gitignore/Java.gitignore
index a1c2a238a96..a1c2a238a96 100755..100644
--- a/vendor/gitignore/Java.gitignore
+++ b/vendor/gitignore/Java.gitignore