Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
		
							parent
							
								
									ce8a0b9084
								
							
						
					
					
						commit
						dd4bee69b7
					
				|  | @ -10,17 +10,24 @@ | |||
| *.md @gl-docsteam | ||||
| 
 | ||||
| # Frontend maintainers should see everything in `app/assets/` | ||||
| app/assets/ @gitlab-org/maintainers/frontend | ||||
| *.scss @annabeldunstone @gitlab-org/maintainers/frontend | ||||
| /scripts/frontend/ @gitlab-org/maintainers/frontend | ||||
| *.js @gitlab-org/maintainers/frontend | ||||
| /app/assets/ @gitlab-org/maintainers/frontend | ||||
| /ee/app/assets/ @gitlab-org/maintainers/frontend | ||||
| /spec/javascripts/ @gitlab-org/maintainers/frontend | ||||
| /ee/spec/javascripts/ @gitlab-org/maintainers/frontend | ||||
| /spec/frontend/ @gitlab-org/maintainers/frontend | ||||
| /ee/spec/frontend/ @gitlab-org/maintainers/frontend | ||||
| 
 | ||||
| # Database maintainers should review changes in `db/` | ||||
| db/ @gitlab-org/maintainers/database | ||||
| lib/gitlab/background_migration/ @gitlab-org/maintainers/database | ||||
| lib/gitlab/database/ @gitlab-org/maintainers/database | ||||
| lib/gitlab/sql/ @gitlab-org/maintainers/database | ||||
| lib/gitlab/github_import/ @gitlab-org/maintainers/database | ||||
| /db/ @gitlab-org/maintainers/database | ||||
| /ee/db/ @gitlab-org/maintainers/database | ||||
| /lib/gitlab/background_migration/ @gitlab-org/maintainers/database | ||||
| /ee/lib/ee/gitlab/background_migration/ @gitlab-org/maintainers/database | ||||
| /lib/gitlab/database/ @gitlab-org/maintainers/database | ||||
| /ee/lib/gitlab/database/ @gitlab-org/maintainers/database | ||||
| /lib/gitlab/sql/ @gitlab-org/maintainers/database | ||||
| /lib/gitlab/github_import/ @gitlab-org/maintainers/database | ||||
| /app/finders/ @gitlab-org/maintainers/database | ||||
| /ee/app/finders/ @gitlab-org/maintainers/database | ||||
| 
 | ||||
|  | @ -40,14 +47,14 @@ lib/gitlab/github_import/ @gitlab-org/maintainers/database | |||
| # Engineering Productivity owned files | ||||
| /.gitlab-ci.yml @gl-quality/eng-prod | ||||
| /.gitlab/ci/ @gl-quality/eng-prod | ||||
| /.gitlab/ci/docs.gitlab-ci.yml @gl-quality/eng-prod @gl-docsteam | ||||
| /.gitlab/ci/releases.gitlab-ci.yml @gl-quality/eng-prod @gitlab-org/delivery | ||||
| /.gitlab/CODEOWNERS @gl-quality/eng-prod | ||||
| Dangerfile @gl-quality/eng-prod | ||||
| /danger/ @gl-quality/eng-prod | ||||
| /lib/gitlab/danger/ @gl-quality/eng-prod | ||||
| /scripts/ @gl-quality/eng-prod | ||||
| 
 | ||||
| # Delivery owner files | ||||
| /.gitlab/ci/releases.gitlab-ci.yml @gitlab-org/delivery | ||||
| /scripts/frontend/ @gl-quality/eng-prod @gitlab-org/maintainers/frontend | ||||
| 
 | ||||
| # Telemetry owner files | ||||
| /ee/lib/gitlab/usage_data_counters/ @gitlab-org/growth/telemetry | ||||
|  |  | |||
|  | @ -4,6 +4,9 @@ import Cookies from 'js-cookie'; | |||
| import { parseBoolean, scrollToElement } from '~/lib/utils/common_utils'; | ||||
| import { s__ } from '~/locale'; | ||||
| import { glEmojiTag } from '~/emoji'; | ||||
| import Tracking from '~/tracking'; | ||||
| 
 | ||||
| const trackingMixin = Tracking.mixin(); | ||||
| 
 | ||||
| const popoverStates = { | ||||
|   suggest_gitlab_ci_yml: { | ||||
|  | @ -27,6 +30,7 @@ export default { | |||
|     GlIcon, | ||||
|     GlButton, | ||||
|   }, | ||||
|   mixins: [trackingMixin], | ||||
|   props: { | ||||
|     target: { | ||||
|       type: String, | ||||
|  | @ -40,10 +44,18 @@ export default { | |||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|     humanAccess: { | ||||
|       type: String, | ||||
|       required: true, | ||||
|     }, | ||||
|   }, | ||||
|   data() { | ||||
|     return { | ||||
|       popoverDismissed: parseBoolean(Cookies.get(this.dismissKey)), | ||||
|       tracking: { | ||||
|         label: this.trackLabel, | ||||
|         property: this.humanAccess, | ||||
|       }, | ||||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|  | @ -60,12 +72,17 @@ export default { | |||
|   mounted() { | ||||
|     if (this.trackLabel === 'suggest_commit_first_project_gitlab_ci_yml' && !this.popoverDismissed) | ||||
|       scrollToElement(document.querySelector(this.target)); | ||||
| 
 | ||||
|     this.trackOnShow(); | ||||
|   }, | ||||
|   methods: { | ||||
|     onDismiss() { | ||||
|       this.popoverDismissed = true; | ||||
|       Cookies.set(this.dismissKey, this.popoverDismissed, { expires: 365 }); | ||||
|     }, | ||||
|     trackOnShow() { | ||||
|       if (!this.popoverDismissed) this.track(); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
| </script> | ||||
|  |  | |||
|  | @ -10,6 +10,7 @@ export default el => | |||
|           target: el.dataset.target, | ||||
|           trackLabel: el.dataset.trackLabel, | ||||
|           dismissKey: el.dataset.dismissKey, | ||||
|           humanAccess: el.dataset.humanAccess, | ||||
|         }, | ||||
|       }); | ||||
|     }, | ||||
|  |  | |||
|  | @ -21,7 +21,7 @@ export default { | |||
|     }; | ||||
|   }, | ||||
|   computed: { | ||||
|     ...mapState(['entries', 'promotionSvgPath', 'links']), | ||||
|     ...mapState(['entries', 'promotionSvgPath', 'links', 'codesandboxBundlerUrl']), | ||||
|     ...mapGetters(['packageJson', 'currentProject']), | ||||
|     normalizedEntries() { | ||||
|       return Object.keys(this.entries).reduce((acc, path) => { | ||||
|  | @ -106,12 +106,7 @@ export default { | |||
|       return this.loadFileContent(this.mainEntry) | ||||
|         .then(() => this.$nextTick()) | ||||
|         .then(() => { | ||||
|           this.initManager('#ide-preview', this.sandboxOpts, { | ||||
|             fileResolver: { | ||||
|               isFile: p => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])), | ||||
|               readFile: p => this.loadFileContent(createPathWithExt(p)).then(content => content), | ||||
|             }, | ||||
|           }); | ||||
|           this.initManager(); | ||||
| 
 | ||||
|           this.listener = listen(e => { | ||||
|             switch (e.type) { | ||||
|  | @ -139,8 +134,18 @@ export default { | |||
|         this.manager.updatePreview(this.sandboxOpts); | ||||
|       }, 250); | ||||
|     }, | ||||
|     initManager(el, opts, resolver) { | ||||
|       this.manager = new Manager(el, opts, resolver); | ||||
|     initManager() { | ||||
|       const { codesandboxBundlerUrl: bundlerURL } = this; | ||||
| 
 | ||||
|       const settings = { | ||||
|         fileResolver: { | ||||
|           isFile: p => Promise.resolve(Boolean(this.entries[createPathWithExt(p)])), | ||||
|           readFile: p => this.loadFileContent(createPathWithExt(p)).then(content => content), | ||||
|         }, | ||||
|         ...(bundlerURL ? { bundlerURL } : {}), | ||||
|       }; | ||||
| 
 | ||||
|       this.manager = new Manager('#ide-preview', this.sandboxOpts, settings); | ||||
|     }, | ||||
|   }, | ||||
| }; | ||||
|  |  | |||
|  | @ -53,6 +53,7 @@ export function initIde(el, options = {}) { | |||
|         clientsidePreviewEnabled: parseBoolean(el.dataset.clientsidePreviewEnabled), | ||||
|         renderWhitespaceInCode: parseBoolean(el.dataset.renderWhitespaceInCode), | ||||
|         editorTheme: window.gon?.user_color_scheme || DEFAULT_THEME, | ||||
|         codesandboxBundlerUrl: el.dataset.codesandboxBundlerUrl, | ||||
|       }); | ||||
|     }, | ||||
|     methods: { | ||||
|  |  | |||
|  | @ -34,4 +34,5 @@ export default () => ({ | |||
|   clientsidePreviewEnabled: false, | ||||
|   renderWhitespaceInCode: false, | ||||
|   editorTheme: DEFAULT_THEME, | ||||
|   codesandboxBundlerUrl: null, | ||||
| }); | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| <script> | ||||
| import $ from 'jquery'; | ||||
| import _ from 'underscore'; | ||||
| import { intersection } from 'lodash'; | ||||
| 
 | ||||
| import '~/smart_interval'; | ||||
| 
 | ||||
|  | @ -38,7 +38,7 @@ export default { | |||
|       } else { | ||||
|         changedCommands = []; | ||||
|       } | ||||
|       if (changedCommands && _.intersection(subscribedCommands, changedCommands).length) { | ||||
|       if (changedCommands && intersection(subscribedCommands, changedCommands).length) { | ||||
|         this.mediator.fetch(); | ||||
|       } | ||||
|     }, | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| import $ from 'jquery'; | ||||
| import '~/gl_dropdown'; | ||||
| import _ from 'underscore'; | ||||
| import { escape as esc } from 'lodash'; | ||||
| import { __ } from '~/locale'; | ||||
| 
 | ||||
| function isValidProjectId(id) { | ||||
|  | @ -49,7 +49,7 @@ class SidebarMoveIssue { | |||
|       renderRow: project => ` | ||||
|         <li> | ||||
|           <a href="#" class="js-move-issue-dropdown-item"> | ||||
|             ${_.escape(project.name_with_namespace)} | ||||
|             ${esc(project.name_with_namespace)} | ||||
|           </a> | ||||
|         </li> | ||||
|       `,
 | ||||
|  |  | |||
|  | @ -0,0 +1,17 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| module ClientsidePreviewCSP | ||||
|   extend ActiveSupport::Concern | ||||
| 
 | ||||
|   included do | ||||
|     content_security_policy do |p| | ||||
|       next if p.directives.blank? | ||||
|       next unless Gitlab::CurrentSettings.web_ide_clientside_preview_enabled? | ||||
| 
 | ||||
|       default_frame_src = p.directives['frame-src'] || p.directives['default-src'] | ||||
|       frame_src_values = Array.wrap(default_frame_src) | [Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url].compact | ||||
| 
 | ||||
|       p.frame_src(*frame_src_values) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -3,6 +3,7 @@ | |||
| class IdeController < ApplicationController | ||||
|   layout 'fullscreen' | ||||
| 
 | ||||
|   include ClientsidePreviewCSP | ||||
|   include StaticObjectExternalStorageCSP | ||||
| 
 | ||||
|   def index | ||||
|  |  | |||
|  | @ -353,4 +353,8 @@ module BlobHelper | |||
|   def suggest_pipeline_commit_cookie_name | ||||
|     "suggest_gitlab_ci_yml_commit_#{@project.id}" | ||||
|   end | ||||
| 
 | ||||
|   def human_access | ||||
|     @project.team.human_max_access(current_user&.id).try(:downcase) | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -10,8 +10,9 @@ module IdeHelper | |||
|       "promotion-svg-path": image_path('illustrations/web-ide_promotion.svg'), | ||||
|       "ci-help-page-path" => help_page_path('ci/quick_start/README'), | ||||
|       "web-ide-help-page-path" => help_page_path('user/project/web_ide/index.html'), | ||||
|       "clientside-preview-enabled": Gitlab::CurrentSettings.current_application_settings.web_ide_clientside_preview_enabled.to_s, | ||||
|       "render-whitespace-in-code": current_user.render_whitespace_in_code.to_s | ||||
|       "clientside-preview-enabled": Gitlab::CurrentSettings.web_ide_clientside_preview_enabled?.to_s, | ||||
|       "render-whitespace-in-code": current_user.render_whitespace_in_code.to_s, | ||||
|       "codesandbox-bundler-url": Gitlab::CurrentSettings.web_ide_clientside_preview_bundler_url | ||||
|     } | ||||
|   end | ||||
| end | ||||
|  |  | |||
|  | @ -351,6 +351,12 @@ module ApplicationSettingImplementation | |||
|     static_objects_external_storage_url.present? | ||||
|   end | ||||
| 
 | ||||
|   # This will eventually be configurable | ||||
|   # https://gitlab.com/gitlab-org/gitlab/issues/208161 | ||||
|   def web_ide_clientside_preview_bundler_url | ||||
|     'https://sandbox-prod.gitlab-static.net' | ||||
|   end | ||||
| 
 | ||||
|   private | ||||
| 
 | ||||
|   def separate_whitelists(string_array) | ||||
|  |  | |||
|  | @ -257,7 +257,7 @@ class WikiPage | |||
|   def title_changed? | ||||
|     if persisted? | ||||
|       old_title, old_dir = wiki.page_title_and_dir(self.class.unhyphenize(@page.url_path)) | ||||
|       new_title, new_dir = wiki.page_title_and_dir(title) | ||||
|       new_title, new_dir = wiki.page_title_and_dir(self.class.unhyphenize(title)) | ||||
| 
 | ||||
|       new_title != old_title || (title.include?('/') && new_dir != old_dir) | ||||
|     else | ||||
|  |  | |||
|  | @ -23,7 +23,8 @@ | |||
|         .js-suggest-gitlab-ci-yml{ data: { toggle: 'popover', | ||||
|           target: '#gitlab-ci-yml-selector', | ||||
|           track_label: 'suggest_gitlab_ci_yml', | ||||
|           dismiss_key: "suggest_gitlab_ci_yml_#{@project.id}" } } | ||||
|           dismiss_key: "suggest_gitlab_ci_yml_#{@project.id}", | ||||
|           human_access: human_access } } | ||||
| 
 | ||||
|     .file-buttons | ||||
|       - if is_markdown | ||||
|  |  | |||
|  | @ -17,4 +17,5 @@ | |||
|       .js-suggest-gitlab-ci-yml-commit-changes{ data: { toggle: 'popover', | ||||
|         target: '#commit-changes', | ||||
|         track_label: 'suggest_commit_first_project_gitlab_ci_yml', | ||||
|         dismiss_key: "suggest_commit_first_project_gitlab_ci_yml_#{@project.id}" } } | ||||
|         dismiss_key: "suggest_commit_first_project_gitlab_ci_yml_#{@project.id}", | ||||
|         human_access: human_access } } | ||||
|  |  | |||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Make hostname configurable for smartcard authentication | ||||
| merge_request: 26411 | ||||
| author: | ||||
| type: added | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Fix code search pagination on a custom branch | ||||
| merge_request: 25984 | ||||
| author: | ||||
| type: fixed | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Fix WikiPage#title_changed for paths with spaces | ||||
| merge_request: 27087 | ||||
| author: | ||||
| type: fixed | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| title: Update Web IDE clientside preview bundler to use GitLab managed server | ||||
| merge_request: 21520 | ||||
| author: | ||||
| type: changed | ||||
|  | @ -752,7 +752,9 @@ production: &base | |||
|     # Path to a file containing a CA certificate | ||||
|     ca_file: '/etc/ssl/certs/CA.pem' | ||||
| 
 | ||||
|     # Port where the client side certificate is requested by the webserver (NGINX/Apache) | ||||
|     # Host and port where the client side certificate is requested by the | ||||
|     # webserver (NGINX/Apache) | ||||
|     # client_certificate_required_host: smartcard.gitlab.example.com | ||||
|     # client_certificate_required_port: 3444 | ||||
| 
 | ||||
|     # Browser session with smartcard sign-in is required for Git access | ||||
|  |  | |||
|  | @ -77,6 +77,7 @@ end | |||
| Gitlab.ee do | ||||
|   Settings['smartcard'] ||= Settingslogic.new({}) | ||||
|   Settings.smartcard['enabled'] = false if Settings.smartcard['enabled'].nil? | ||||
|   Settings.smartcard['client_certificate_required_host'] = Settings.gitlab['host'] if Settings.smartcard['client_certificate_required_host'].nil? | ||||
|   Settings.smartcard['client_certificate_required_port'] = 3444 if Settings.smartcard['client_certificate_required_port'].nil? | ||||
|   Settings.smartcard['required_for_git_access'] = false if Settings.smartcard['required_for_git_access'].nil? | ||||
|   Settings.smartcard['san_extensions'] = false if Settings.smartcard['san_extensions'].nil? | ||||
|  |  | |||
|  | @ -60,7 +60,7 @@ | |||
|     "chart.js": "2.7.2", | ||||
|     "classlist-polyfill": "^1.2.0", | ||||
|     "clipboard": "^1.7.1", | ||||
|     "codesandbox-api": "^0.0.20", | ||||
|     "codesandbox-api": "0.0.23", | ||||
|     "compression-webpack-plugin": "^3.0.1", | ||||
|     "copy-webpack-plugin": "^5.0.5", | ||||
|     "core-js": "^3.6.4", | ||||
|  | @ -110,7 +110,7 @@ | |||
|     "raw-loader": "^4.0.0", | ||||
|     "sanitize-html": "^1.22.0", | ||||
|     "select2": "3.5.2-browserify", | ||||
|     "smooshpack": "^0.0.54", | ||||
|     "smooshpack": "^0.0.62", | ||||
|     "sortablejs": "^1.10.2", | ||||
|     "sql.js": "^0.4.0", | ||||
|     "stickyfilljs": "^2.1.0", | ||||
|  |  | |||
|  | @ -2,36 +2,41 @@ | |||
| 
 | ||||
| cd "$(dirname "$0")/.." | ||||
| echo "=> Linting documents at path $(pwd) as $(whoami)..." | ||||
| echo | ||||
| ERRORCODE=0 | ||||
| 
 | ||||
| # Use long options (e.g. --header instead of -H) for curl examples in documentation. | ||||
| echo '=> Checking for cURL short options...' | ||||
| echo | ||||
| grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ >/dev/null 2>&1 | ||||
| if [ $? -eq 0 ] | ||||
| then | ||||
|   echo '✖ ERROR: Short options for curl should not be used in documentation! | ||||
|          Use long options (e.g., --header instead of -H):' >&2 | ||||
|   grep --extended-regexp --recursive --color=auto 'curl (.+ )?-[^- ].*' doc/ | ||||
|   exit 1 | ||||
|   ((ERRORCODE++)) | ||||
| fi | ||||
| 
 | ||||
| # Ensure that the CHANGELOG.md does not contain duplicate versions | ||||
| DUPLICATE_CHANGELOG_VERSIONS=$(grep --extended-regexp '^## .+' CHANGELOG.md | sed -E 's| \(.+\)||' | sort -r | uniq -d) | ||||
| echo '=> Checking for CHANGELOG.md duplicate entries...' | ||||
| echo | ||||
| if [ "${DUPLICATE_CHANGELOG_VERSIONS}" != "" ] | ||||
| then | ||||
|   echo '✖ ERROR: Duplicate versions in CHANGELOG.md:' >&2 | ||||
|   echo "${DUPLICATE_CHANGELOG_VERSIONS}" >&2 | ||||
|   exit 1 | ||||
|   ((ERRORCODE++)) | ||||
| fi | ||||
| 
 | ||||
| # Make sure no files in doc/ are executable | ||||
| EXEC_PERM_COUNT=$(find doc/ -type f -perm 755 | wc -l) | ||||
| echo "=> Checking $(pwd)/doc for executable permissions..." | ||||
| echo | ||||
| if [ "${EXEC_PERM_COUNT}" -ne 0 ] | ||||
| then | ||||
|   echo '✖ ERROR: Executable permissions should not be used in documentation! Use `chmod 644` to the files in question:' >&2 | ||||
|   find doc/ -type f -perm 755 | ||||
|   exit 1 | ||||
|   ((ERRORCODE++)) | ||||
| fi | ||||
| 
 | ||||
| # Do not use 'README.md', instead use 'index.md' | ||||
|  | @ -39,13 +44,14 @@ fi | |||
| NUMBER_READMES=46 | ||||
| FIND_READMES=$(find doc/ -name "README.md" | wc -l) | ||||
| echo '=> Checking for new README.md files...' | ||||
| echo | ||||
| if [ ${FIND_READMES} -ne $NUMBER_READMES ] | ||||
| then | ||||
|   echo | ||||
|   echo '  ✖ ERROR: New README.md file(s) detected, prefer index.md over README.md.' >&2 | ||||
|   echo '  https://docs.gitlab.com/ee/development/documentation/styleguide.html#work-with-directories-and-files' | ||||
|   echo | ||||
|   exit 1 | ||||
|   ((ERRORCODE++)) | ||||
| fi | ||||
| 
 | ||||
| MD_DOC_PATH=${MD_DOC_PATH:-doc} | ||||
|  | @ -64,7 +70,7 @@ function run_locally_or_in_docker() { | |||
|     echo | ||||
|     echo "  ✖ ERROR: '${cmd}' not found. Install '${cmd}' or Docker to proceed." >&2 | ||||
|     echo | ||||
|     exit 1 | ||||
|     ((ERRORCODE++)) | ||||
|   fi | ||||
| 
 | ||||
|   if [ $? -ne 0 ] | ||||
|  | @ -72,15 +78,22 @@ function run_locally_or_in_docker() { | |||
|     echo | ||||
|     echo "  ✖ ERROR: '${cmd}' failed with errors." >&2 | ||||
|     echo | ||||
|     exit 1 | ||||
|     ((ERRORCODE++)) | ||||
|   fi | ||||
| } | ||||
| 
 | ||||
| echo '=> Linting markdown style...' | ||||
| echo | ||||
| run_locally_or_in_docker 'markdownlint' "--config .markdownlint.json ${MD_DOC_PATH}" | ||||
| 
 | ||||
| echo '=> Linting prose...' | ||||
| run_locally_or_in_docker 'vale' "--minAlertLevel error ${MD_DOC_PATH}" | ||||
| 
 | ||||
| echo "✔ Linting passed" | ||||
| exit 0 | ||||
| if [ $ERRORCODE -ne 0 ] | ||||
| then | ||||
|   echo "✖ ${ERRORCODE} lint test(s) failed. Review the log carefully to see full listing." | ||||
|   exit 1 | ||||
| else | ||||
|   echo "✔ Linting passed" | ||||
|   exit 0 | ||||
| fi | ||||
|  |  | |||
|  | @ -28,9 +28,9 @@ HOOK_DATA = <<~HOOK | |||
| 
 | ||||
|   if [ -e "$harness" ] | ||||
|   then | ||||
|     if [[ ("$url" != *"dev.gitlab.org"*) && ("$url" != *"gitlab-org/security/"*) ]] | ||||
|     if [["$url" != *"gitlab-org/security/"*]] | ||||
|     then | ||||
|       echo "Pushing to remotes other than dev.gitlab.org and gitlab.com/gitlab-org/security has been disabled!" | ||||
|       echo "Pushing to remotes other than gitlab.com/gitlab-org/security has been disabled!" | ||||
|       echo "Run scripts/security-harness to disable this check." | ||||
|       echo | ||||
| 
 | ||||
|  | @ -58,7 +58,7 @@ def toggle | |||
|   else | ||||
|     FileUtils.touch(harness_path) | ||||
| 
 | ||||
|     puts "#{SHELL_GREEN}Security harness installed -- you will only be able to push to dev.gitlab.org or gitlab.com/gitlab-org/security!#{SHELL_CLEAR}" | ||||
|     puts "#{SHELL_GREEN}Security harness installed -- you will only be able to push to gitlab.com/gitlab-org/security!#{SHELL_CLEAR}" | ||||
|   end | ||||
| end | ||||
| 
 | ||||
|  |  | |||
|  | @ -0,0 +1,35 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| require 'spec_helper' | ||||
| 
 | ||||
| describe 'IDE Clientside Preview CSP' do | ||||
|   let_it_be(:user) { create(:user) } | ||||
| 
 | ||||
|   shared_context 'disable feature' do | ||||
|     before do | ||||
|       allow_next_instance_of(ApplicationSetting) do |instance| | ||||
|         allow(instance).to receive(:web_ide_clientside_preview_enabled?).and_return(false) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   it_behaves_like 'setting CSP', 'frame-src' do | ||||
|     let(:whitelisted_url) { 'https://sandbox.gitlab-static.test' } | ||||
|     let(:extended_controller_class) { IdeController } | ||||
| 
 | ||||
|     subject do | ||||
|       visit ide_path | ||||
| 
 | ||||
|       response_headers['Content-Security-Policy'] | ||||
|     end | ||||
| 
 | ||||
|     before do | ||||
|       allow_next_instance_of(ApplicationSetting) do |instance| | ||||
|         allow(instance).to receive(:web_ide_clientside_preview_enabled?).and_return(true) | ||||
|         allow(instance).to receive(:web_ide_clientside_preview_bundler_url).and_return(whitelisted_url) | ||||
|       end | ||||
| 
 | ||||
|       sign_in(user) | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | @ -11,7 +11,7 @@ describe 'Static Object External Storage Content Security Policy' do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   it_behaves_like 'setting CSP connect-src' do | ||||
|   it_behaves_like 'setting CSP', 'connect-src' do | ||||
|     let_it_be(:whitelisted_url) { 'https://static-objects.test' } | ||||
|     let_it_be(:extended_controller_class) { IdeController } | ||||
| 
 | ||||
|  |  | |||
|  | @ -12,7 +12,7 @@ describe 'Sourcegraph Content Security Policy' do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   it_behaves_like 'setting CSP connect-src' do | ||||
|   it_behaves_like 'setting CSP', 'connect-src' do | ||||
|     let_it_be(:whitelisted_url) { 'https://sourcegraph.test' } | ||||
|     let_it_be(:extended_controller_class) { Projects::BlobController } | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,6 +1,7 @@ | |||
| import { shallowMount } from '@vue/test-utils'; | ||||
| import Popover from '~/blob/suggest_gitlab_ci_yml/components/popover.vue'; | ||||
| import Cookies from 'js-cookie'; | ||||
| import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; | ||||
| import * as utils from '~/lib/utils/common_utils'; | ||||
| 
 | ||||
| jest.mock('~/lib/utils/common_utils', () => ({ | ||||
|  | @ -11,6 +12,8 @@ jest.mock('~/lib/utils/common_utils', () => ({ | |||
| const target = 'gitlab-ci-yml-selector'; | ||||
| const dismissKey = 'suggest_gitlab_ci_yml_99'; | ||||
| const defaultTrackLabel = 'suggest_gitlab_ci_yml'; | ||||
| const commitTrackLabel = 'suggest_commit_first_project_gitlab_ci_yml'; | ||||
| const humanAccess = 'owner'; | ||||
| 
 | ||||
| describe('Suggest gitlab-ci.yml Popover', () => { | ||||
|   let wrapper; | ||||
|  | @ -21,6 +24,7 @@ describe('Suggest gitlab-ci.yml Popover', () => { | |||
|         target, | ||||
|         trackLabel, | ||||
|         dismissKey, | ||||
|         humanAccess, | ||||
|       }, | ||||
|     }); | ||||
|   } | ||||
|  | @ -50,15 +54,43 @@ describe('Suggest gitlab-ci.yml Popover', () => { | |||
|       expect(wrapper.vm.popoverDismissed).toEqual(true); | ||||
|     }); | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|     afterEach(() => { | ||||
|       Cookies.remove(dismissKey); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('tracking', () => { | ||||
|     let trackingSpy; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       createWrapper(commitTrackLabel); | ||||
|       trackingSpy = mockTracking('_category_', wrapper.element, jest.spyOn); | ||||
|     }); | ||||
| 
 | ||||
|     afterEach(() => { | ||||
|       unmockTracking(); | ||||
|     }); | ||||
| 
 | ||||
|     it('sends a tracking event with the expected properties for the popover being viewed', () => { | ||||
|       const expectedCategory = undefined; | ||||
|       const expectedAction = undefined; | ||||
|       const expectedLabel = 'suggest_commit_first_project_gitlab_ci_yml'; | ||||
|       const expectedProperty = 'owner'; | ||||
| 
 | ||||
|       document.body.dataset.page = 'projects:blob:new'; | ||||
| 
 | ||||
|       wrapper.vm.trackOnShow(); | ||||
| 
 | ||||
|       expect(trackingSpy).toHaveBeenCalledWith(expectedCategory, expectedAction, { | ||||
|         label: expectedLabel, | ||||
|         property: expectedProperty, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('when the popover is mounted with the trackLabel of the Confirm button popover at the bottom of the page', () => { | ||||
|     it('calls scrollToElement so that the Confirm button and popover will be in sight', () => { | ||||
|       const scrollToElementSpy = jest.spyOn(utils, 'scrollToElement'); | ||||
|       const commitTrackLabel = 'suggest_commit_first_project_gitlab_ci_yml'; | ||||
| 
 | ||||
|       createWrapper(commitTrackLabel); | ||||
| 
 | ||||
|  |  | |||
|  | @ -16,6 +16,17 @@ const dummyPackageJson = () => ({ | |||
|     main: 'index.js', | ||||
|   }), | ||||
| }); | ||||
| const expectedSandpackOptions = () => ({ | ||||
|   files: {}, | ||||
|   entry: '/index.js', | ||||
|   showOpenInCodeSandbox: true, | ||||
| }); | ||||
| const expectedSandpackSettings = () => ({ | ||||
|   fileResolver: { | ||||
|     isFile: expect.any(Function), | ||||
|     readFile: expect.any(Function), | ||||
|   }, | ||||
| }); | ||||
| 
 | ||||
| describe('IDE clientside preview', () => { | ||||
|   let wrapper; | ||||
|  | @ -84,6 +95,46 @@ describe('IDE clientside preview', () => { | |||
|       return waitForCalls(); | ||||
|     }); | ||||
| 
 | ||||
|     it('creates sandpack manager', () => { | ||||
|       expect(smooshpack.Manager).toHaveBeenCalledWith( | ||||
|         '#ide-preview', | ||||
|         expectedSandpackOptions(), | ||||
|         expectedSandpackSettings(), | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     it('pings usage', () => { | ||||
|       expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('with codesandboxBundlerUrl', () => { | ||||
|     const TEST_BUNDLER_URL = 'https://test.gitlab-static.test'; | ||||
| 
 | ||||
|     beforeEach(() => { | ||||
|       createComponent({ | ||||
|         getters: { packageJson: dummyPackageJson }, | ||||
|         state: { codesandboxBundlerUrl: TEST_BUNDLER_URL }, | ||||
|       }); | ||||
| 
 | ||||
|       return waitForCalls(); | ||||
|     }); | ||||
| 
 | ||||
|     it('creates sandpack manager with bundlerURL', () => { | ||||
|       expect(smooshpack.Manager).toHaveBeenCalledWith('#ide-preview', expectedSandpackOptions(), { | ||||
|         ...expectedSandpackSettings(), | ||||
|         bundlerURL: TEST_BUNDLER_URL, | ||||
|       }); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('with codesandboxBundlerURL', () => { | ||||
|     beforeEach(() => { | ||||
|       createComponent({ getters: { packageJson: dummyPackageJson } }); | ||||
| 
 | ||||
|       return waitForCalls(); | ||||
|     }); | ||||
| 
 | ||||
|     it('creates sandpack manager', () => { | ||||
|       expect(smooshpack.Manager).toHaveBeenCalledWith( | ||||
|         '#ide-preview', | ||||
|  | @ -100,10 +151,6 @@ describe('IDE clientside preview', () => { | |||
|         }, | ||||
|       ); | ||||
|     }); | ||||
| 
 | ||||
|     it('pings usage', () => { | ||||
|       expect(storeClientsideActions.pingUsage).toHaveBeenCalledTimes(1); | ||||
|     }); | ||||
|   }); | ||||
| 
 | ||||
|   describe('computed', () => { | ||||
|  |  | |||
|  | @ -480,8 +480,8 @@ describe WikiPage do | |||
| 
 | ||||
|     let(:untitled_page) { described_class.new(wiki) } | ||||
|     let(:directory_page) do | ||||
|       create_page('parent/child', 'test content') | ||||
|       wiki.find_page('parent/child') | ||||
|       create_page('parent directory/child page', 'test content') | ||||
|       wiki.find_page('parent directory/child page') | ||||
|     end | ||||
| 
 | ||||
|     where(:page, :title, :changed) do | ||||
|  | @ -494,15 +494,25 @@ describe WikiPage do | |||
| 
 | ||||
|       :existing_page  | nil                             | false | ||||
|       :existing_page  | 'test page'                     | false | ||||
|       :existing_page  | 'test-page'                     | false | ||||
|       :existing_page  | '/test page'                    | false | ||||
|       :existing_page  | '/test-page'                    | false | ||||
|       :existing_page  | ' test page '                   | true | ||||
|       :existing_page  | 'new title'                     | true | ||||
|       :existing_page  | 'new-title'                     | true | ||||
| 
 | ||||
|       :directory_page | nil                             | false | ||||
|       :directory_page | 'parent/child' | false | ||||
|       :directory_page | 'child'        | false | ||||
|       :directory_page | '/child'       | true | ||||
|       :directory_page | 'parent/other' | true | ||||
|       :directory_page | 'other/child'  | true | ||||
|       :directory_page | 'parent directory/child page'   | false | ||||
|       :directory_page | 'parent-directory/child page'   | false | ||||
|       :directory_page | 'parent-directory/child-page'   | false | ||||
|       :directory_page | 'child page'                    | false | ||||
|       :directory_page | 'child-page'                    | false | ||||
|       :directory_page | '/child page'                   | true | ||||
|       :directory_page | 'parent directory/other'        | true | ||||
|       :directory_page | 'parent-directory/other'        | true | ||||
|       :directory_page | 'parent-directory / child-page' | true | ||||
|       :directory_page | 'other directory/child page'    | true | ||||
|       :directory_page | 'other-directory/child page'    | true | ||||
|     end | ||||
| 
 | ||||
|     with_them do | ||||
|  |  | |||
|  | @ -1,6 +1,6 @@ | |||
| # frozen_string_literal: true | ||||
| 
 | ||||
| RSpec.shared_examples 'setting CSP connect-src' do | ||||
| RSpec.shared_examples 'setting CSP' do |rule_name| | ||||
|   let_it_be(:default_csp_values) { "'self' https://some-cdn.test" } | ||||
| 
 | ||||
|   shared_context 'csp config' do |csp_rule| | ||||
|  | @ -10,7 +10,7 @@ RSpec.shared_examples 'setting CSP connect-src' do | |||
|       end | ||||
| 
 | ||||
|       expect_next_instance_of(extended_controller_class) do |controller| | ||||
|         expect(controller).to receive(:current_content_security_policy).and_return(csp) | ||||
|         expect(controller).to receive(:current_content_security_policy).at_least(:once).and_return(csp) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
|  | @ -23,55 +23,55 @@ RSpec.shared_examples 'setting CSP connect-src' do | |||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'when a CSP config exists for connect-src' do | ||||
|     include_context 'csp config', :connect_src | ||||
|   describe "when a CSP config exists for #{rule_name}" do | ||||
|     include_context 'csp config', rule_name.parameterize.underscore.to_sym | ||||
| 
 | ||||
|     context 'when feature is enabled' do | ||||
|       it 'appends to connect-src' do | ||||
|         is_expected.to eql("connect-src #{default_csp_values} #{whitelisted_url}") | ||||
|       it "appends to #{rule_name}" do | ||||
|         is_expected.to eql("#{rule_name} #{default_csp_values} #{whitelisted_url}") | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when feature is disabled' do | ||||
|       include_context 'disable feature' | ||||
| 
 | ||||
|       it 'keeps original connect-src' do | ||||
|         is_expected.to eql("connect-src #{default_csp_values}") | ||||
|       it "keeps original #{rule_name}" do | ||||
|         is_expected.to eql("#{rule_name} #{default_csp_values}") | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'when a CSP config exists for default-src but not connect-src' do | ||||
|   describe "when a CSP config exists for default-src but not #{rule_name}" do | ||||
|     include_context 'csp config', :default_src | ||||
| 
 | ||||
|     context 'when feature is enabled' do | ||||
|       it 'uses default-src values in connect-src' do | ||||
|         is_expected.to eql("default-src #{default_csp_values}; connect-src #{default_csp_values} #{whitelisted_url}") | ||||
|       it "uses default-src values in #{rule_name}" do | ||||
|         is_expected.to eql("default-src #{default_csp_values}; #{rule_name} #{default_csp_values} #{whitelisted_url}") | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when feature is disabled' do | ||||
|       include_context 'disable feature' | ||||
| 
 | ||||
|       it 'does not add connect-src' do | ||||
|       it "does not add #{rule_name}" do | ||||
|         is_expected.to eql("default-src #{default_csp_values}") | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| 
 | ||||
|   describe 'when a CSP config exists for font-src but not connect-src' do | ||||
|   describe "when a CSP config exists for font-src but not #{rule_name}" do | ||||
|     include_context 'csp config', :font_src | ||||
| 
 | ||||
|     context 'when feature is enabled' do | ||||
|       it 'uses default-src values in connect-src' do | ||||
|         is_expected.to eql("font-src #{default_csp_values}; connect-src #{whitelisted_url}") | ||||
|       it "uses default-src values in #{rule_name}" do | ||||
|         is_expected.to eql("font-src #{default_csp_values}; #{rule_name} #{whitelisted_url}") | ||||
|       end | ||||
|     end | ||||
| 
 | ||||
|     context 'when feature is disabled' do | ||||
|       include_context 'disable feature' | ||||
| 
 | ||||
|       it 'does not add connect-src' do | ||||
|       it "does not add #{rule_name}" do | ||||
|         is_expected.to eql("font-src #{default_csp_values}") | ||||
|       end | ||||
|     end | ||||
|  |  | |||
							
								
								
									
										18
									
								
								yarn.lock
								
								
								
								
							
							
						
						
									
										18
									
								
								yarn.lock
								
								
								
								
							|  | @ -2779,10 +2779,10 @@ code-point-at@^1.0.0: | |||
|   resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" | ||||
|   integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= | ||||
| 
 | ||||
| codesandbox-api@^0.0.20: | ||||
|   version "0.0.20" | ||||
|   resolved "https://registry.yarnpkg.com/codesandbox-api/-/codesandbox-api-0.0.20.tgz#174bcd76c9f31521175c6bceabc37da6b1fbc30b" | ||||
|   integrity sha512-jhxZzAmjCKBZad8QWMeueiQVFE87igK6F2DBOEVFFJO6jgTXT8qjuzGYepr+B8bjgo/icN7bc/2xmEMBA63s2w== | ||||
| codesandbox-api@0.0.23: | ||||
|   version "0.0.23" | ||||
|   resolved "https://registry.yarnpkg.com/codesandbox-api/-/codesandbox-api-0.0.23.tgz#bf650a21b5f3c2369e03f0c19d10b4e2ba255b4f" | ||||
|   integrity sha512-fFGBkIghDkQILh7iHYlpZU5sfWncCDb92FQSFE4rR3VBcTfUsD5VZgpQi+JjZQuwWIdfl4cOhcIFrUYwshUezA== | ||||
| 
 | ||||
| codesandbox-import-util-types@^1.2.11: | ||||
|   version "1.2.11" | ||||
|  | @ -10334,12 +10334,12 @@ slugify@^1.3.1: | |||
|   resolved "https://registry.yarnpkg.com/slugify/-/slugify-1.3.1.tgz#f572127e8535329fbc6c1edb74ab856b61ad7de2" | ||||
|   integrity sha512-6BwyhjF5tG5P8s+0DPNyJmBSBePG6iMyhjvIW5zGdA3tFik9PtK+yNkZgTeiroCRGZYgkHftFA62tGVK1EI9Kw== | ||||
| 
 | ||||
| smooshpack@^0.0.54: | ||||
|   version "0.0.54" | ||||
|   resolved "https://registry.yarnpkg.com/smooshpack/-/smooshpack-0.0.54.tgz#9044358b85052d348b801f385678c8a0c76f2bb6" | ||||
|   integrity sha512-yIwEWb17hqoW5IaWyzO6O6nxY89I5UdRoGIZy5hihoqXP9OYcoMbBTxKwS57MeXSKdNA2rtk86rlCcOgAYIgrA== | ||||
| smooshpack@^0.0.62: | ||||
|   version "0.0.62" | ||||
|   resolved "https://registry.yarnpkg.com/smooshpack/-/smooshpack-0.0.62.tgz#cb31b9f808f73de3146b050f84d044eb353b5503" | ||||
|   integrity sha512-lFuJV2f504/U78sifWy0V2FyoE/8mTgOXM4DL918ncNxAxbtu236XSCLAH3SQwXZWn0JdmRnWs/XU4+sIUVVmQ== | ||||
|   dependencies: | ||||
|     codesandbox-api "^0.0.20" | ||||
|     codesandbox-api "0.0.23" | ||||
|     codesandbox-import-utils "^1.2.3" | ||||
|     lodash.isequal "^4.5.0" | ||||
| 
 | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue