diff options
-rw-r--r-- | app/helpers/search_helper.rb | 3 | ||||
-rw-r--r-- | doc/raketasks/backup_restore.md | 3 | ||||
-rw-r--r-- | doc/user/application_security/dast/browser_based.md | 44 | ||||
-rw-r--r-- | doc/user/application_security/dast/browser_based_troubleshooting.md | 300 | ||||
-rw-r--r-- | doc/user/application_security/dast/dast_troubleshooting.md | 2 | ||||
-rw-r--r-- | doc/user/application_security/dast_api/index.md | 3 | ||||
-rw-r--r-- | lib/version_check.rb | 15 | ||||
-rw-r--r-- | qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb | 4 | ||||
-rw-r--r-- | spec/features/projects/settings/repository_settings_spec.rb | 14 | ||||
-rw-r--r-- | spec/helpers/search_helper_spec.rb | 14 | ||||
-rw-r--r-- | spec/lib/version_check_spec.rb | 79 |
11 files changed, 399 insertions, 82 deletions
diff --git a/app/helpers/search_helper.rb b/app/helpers/search_helper.rb index 37b213a3185..1a9ac8d8206 100644 --- a/app/helpers/search_helper.rb +++ b/app/helpers/search_helper.rb @@ -356,9 +356,8 @@ module SearchHelper return [] unless current_user && Ability.allowed?(current_user, :read_users_list) SearchService - .new(current_user, { scope: 'users', search: term }) + .new(current_user, { scope: 'users', per_page: limit, search: term }) .search_objects - .limit(limit) .map do |user| { category: "Users", diff --git a/doc/raketasks/backup_restore.md b/doc/raketasks/backup_restore.md index 650f1504616..796cb71321a 100644 --- a/doc/raketasks/backup_restore.md +++ b/doc/raketasks/backup_restore.md @@ -85,6 +85,9 @@ In the following cases, consider using file system data transfer or snapshots as - Your GitLab instance has a lot of forked projects and the regular backup task duplicates the Git data for all of them. - Your GitLab instance has a problem and using the regular backup and import Rake tasks isn't possible. +WARNING: +Gitaly Cluster [does not support snapshot backups](../administration/gitaly/index.md#snapshot-backup-and-recovery-limitations). + When considering using file system data transfer or snapshots: - Don't use these methods to migrate from one operating system to another. The operating systems of the source and destination should be as similar as possible. For example, diff --git a/doc/user/application_security/dast/browser_based.md b/doc/user/application_security/dast/browser_based.md index 762c9b30acd..97f80313d3e 100644 --- a/doc/user/application_security/dast/browser_based.md +++ b/doc/user/application_security/dast/browser_based.md @@ -276,50 +276,6 @@ dast: NOTE: Adjusting these values may impact scan time because they adjust how long each browser waits for various activities to complete. -## Debugging scans using logging - -Logging can be used to help you troubleshoot a scan. - -The CI/CD variable `DAST_BROWSER_LOG` configures the logging level for particular modules of the crawler. Each module represents a component of the browser-based crawler and is separated so that debug logs can be configured just for the area of the crawler that requires further inspection. For more details, see [Crawler modules](#crawler-modules). - -For example, the following job definition enables the browsing module and the authentication module to be logged in debug-mode: - -```yaml -include: - - template: DAST.gitlab-ci.yml - -dast: - variables: - DAST_WEBSITE: "https://my.site.com" - DAST_BROWSER_SCAN: "true" - DAST_BROWSER_LOG: "brows:debug,auth:debug" -``` - -### Log message format - -Log messages have the format `[time] [log level] [log module] [message] [additional properties]`. For example, the following log entry has level `INFO`, is part of the `CRAWL` log module, and has the message `Crawled path`. - -```txt -2021-04-21T00:34:04.000 INF CRAWL Crawled path nav_id=0cc7fd path="LoadURL [https://my.site.com:8090]" -``` - -### Crawler modules - -The modules that can be configured for logging are as follows: - -| Log module | Component overview | -| ---------- | ----------- | -| `AUTH` | Used for creating an authenticated scan. | -| `BROWS` | Used for querying the state or page of the browser. | -| `BPOOL` | The set of browsers that are leased out for crawling. | -| `CRAWL` | Used for the core crawler algorithm. | -| `DATAB` | Used for persisting data to the internal database. | -| `LEASE` | Used to create browsers to add them to the browser pool. | -| `MAIN` | Used for the flow of the main event loop of the crawler. | -| `NAVDB` | Used for persistence mechanisms to store navigation entries. | -| `REPT` | Used for generating reports. | -| `STAT` | Used for general statistics while running the scan. | - ### Artifacts Using the latest version of the DAST [template](https://gitlab.com/gitlab-org/gitlab/-/blob/master/lib/gitlab/ci/templates/Security/DAST.latest.gitlab-ci.yml) these artifacts are exposed for download by default. diff --git a/doc/user/application_security/dast/browser_based_troubleshooting.md b/doc/user/application_security/dast/browser_based_troubleshooting.md new file mode 100644 index 00000000000..78f2723ee38 --- /dev/null +++ b/doc/user/application_security/dast/browser_based_troubleshooting.md @@ -0,0 +1,300 @@ +--- +stage: Secure +group: Dynamic Analysis +info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/product/ux/technical-writing/#assignments +type: reference, howto +--- + +# Troubleshooting DAST browser-based analyzer **(ULTIMATE)** + +The following troubleshooting scenarios have been collected from customer support cases. If you +experience a problem not addressed here, or the information here does not fix your problem, create a +support ticket. For more details, see the [GitLab Support](https://about.gitlab.com/support/) page. + +## When something goes wrong + +When something goes wrong with a DAST scan, if you have a particular error message then check [known problems](#known-problems). + +Otherwise, try to discover the problem by answering the following questions: + +- [What is the expected outcome?](#what-is-the-expected-outcome) +- [Is the outcome achievable by a human?](#is-the-outcome-achievable-by-a-human) +- [Any reason why DAST would not work?](#any-reason-why-dast-would-not-work) +- [How does your application work?](#how-does-your-application-work) +- [What is DAST doing?](#what-is-dast-doing) + +### What is the expected outcome? + +Many users who encounter issues with a DAST scan have a good high-level idea of what they think the scanner should be doing. For example, +it's not scanning particular pages, or it's not selecting a button on the page. + +As much as possible, try to isolate the problem to help narrow the search for a solution. For example, take the situation where DAST isn't scanning a particular page. +From where should DAST have found the page? What path did it take to navigate there? Were there elements on the referring page that DAST should have selected, but did not? + +### Is the outcome achievable by a human? + +DAST cannot scan an application if a human cannot manually traverse the application. + +Knowing the outcome you expect, try to replicate it manually using a browser on your machine. For example: + +- Open a new incognito/private browser window. +- Open Developer Tools. Keep an eye on the console for error messages. + - In Chrome: `View -> Developer -> Developer Tools`. + - In Firefox: `Tools -> Browser Tools -> Web Developer Tools`. +- If authenticating: + - Navigate to the `DAST_AUTH_URL`. + - Type in the `DAST_USERNAME` in the `DAST_USERNAME_FIELD`. + - Type in the `DAST_PASSWORD` in the `DAST_PASSWORD_FIELD`. + - Select the `DAST_SUBMIT_FIELD`. +- Select links and fill in forms. Navigate to the pages that aren't scanning correctly. +- Observe how your application behaves. Notice if there is anything that might cause problems for an automated scanner. + +### Any reason why DAST would not work? + +DAST cannot scan correctly when: + +- There is a CAPTCHA. Please turn these off in the testing environment for the application being scanned. +- It does not have access to the target application. Ensure the GitLab Runner can access the application using the URLs used in the DAST configuration. + +### How does your application work? + +Understanding how your application works is vital to figuring out why a DAST scan isn't working. For example, the following situations +may require additional configuration settings. + +- Is there a popup modal that hides elements? +- Does a loaded page change dramatically after a certain period of time? +- Is the application especially slow or fast to load? +- Is the target application jerky while loading? +- Does the application work differently based on the client's location? +- Is the application a single-page application? +- Does the application submit HTML forms, or does it use JavaScript and AJAX? +- Does the application use websockets? +- Does the application use a specific web framework? +- Does selecting buttons run JavaScript before continuing the form submit? Is it fast, slow? +- Is it possible DAST could be selecting or searching for elements before either the element or page is ready? + +### What is DAST doing? + +Logging remains the best way to understand what DAST is doing: + +- [Browser-based analyzer logging](#browser-based-analyzer-logging), useful for understanding what the analyzer is doing. +- [Chromium DevTools logging](#chromium-devtools-logging), useful to inspect the communication between DAST and Chromium. +- [Chromium Logs](#chromium-logs), useful for logging errors when Chromium crashes unexpectedly. + +## Browser-based analyzer logging + +The analyzer log is one of the most useful tools to help diagnose problems with a scan. Different parts of the analyzer can be logged at different levels. + +### Log message format + +Log messages have the format `[time] [log level] [log module] [message] [additional properties]`. + +For example, the following log entry has level `INFO`, is part of the `CRAWL` log module, has the message `Crawled path` and the additional properties `nav_id` and `path`. + +```txt +2021-04-21T00:34:04.000 INF CRAWL Crawled path nav_id=0cc7fd path="LoadURL [https://my.site.com:8090]" +``` + +### Log destination + +Logs are sent either to file or to console (the CI/CD job log). You can configure each destination to accept different logs using +the environment variables `DAST_BROWSER_LOG` for console logs and `DAST_BROWSER_FILE_LOG` for file logs. + +In the following example, the file log defaults to `DEBUG` level, the console log defaults to `INFO` level and logs the `AUTH` module at `DEBUG` level. + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_BROWSER_LOG: "auth:debug" + DAST_BROWSER_FILE_LOG: "loglevel:debug" + DAST_BROWSER_FILE_LOG_PATH: "/zap/wrk/dast-scan.log" + artifacts: + paths: + - dast-scan.log + when: always +``` + +### Log levels + +The log levels that can be configured are as follows: + +| Log module | Component overview | More | +|-------------------------|--------------------------------------------------------------------------|----------------------------------| +| `TRACE` | Used for specific, often noisy inner workings of a feature. | | +| `DEBUG` | Describes the inner-workings of a feature. Used for diagnostic purposes. | | +| `INFO` | Describes the high level flow of the scan and the results. | Default level if none specified. | +| `WARN` | Describes an error situation where DAST recovers and continues the scan. | | +| `FATAL`/`ERROR`/`PANIC` | Describes unrecoverable errors prior to exit. | | + +### Log modules + +`LOGLEVEL` configures the default log level for the log destination. If any of the following modules are configured, +DAST uses the log level for that module in preference to the default log level. + +The modules that can be configured for logging are as follows: + +| Log module | Component overview | +|------------|---------------------------------------------------------------------------------------------------| +| `ACTIV` | Used for active attacks. | +| `AUTH` | Used for creating an authenticated scan. | +| `BPOOL` | The set of browsers that are leased out for crawling. | +| `BROWS` | Used for querying the state or page of the browser. | +| `CACHE` | Used for reporting on cache hit and miss for cached HTTP resources. | +| `CHROM` | Used to log Chrome DevTools messages. | +| `CONTA` | Used for the container that collects parts of HTTP requests and responses from DevTools messages. | +| `CRAWL` | Used for the core crawler algorithm. | +| `DATAB` | Used for persisting data to the internal database. | +| `LEASE` | Used to create browsers to add them to the browser pool. | +| `MAIN` | Used for the flow of the main event loop of the crawler. | +| `NAVDB` | Used for persistence mechanisms to store navigation entries. | +| `REGEX` | Used for recording performance statistics when running regular expressions. | +| `REPT` | Used for generating reports. | +| `STAT` | Used for general statistics while running the scan. | +| `VLDFN` | Used for loading and parsing vulnerability definitions. | +| `WEBGW` | Used to log messages sent to the target application when running active checks. | + +### Example - log crawled paths + +Set the log module `CRAWL` to `DEBUG` to log navigation paths found during the crawl phase of the scan. This is useful for understanding +if DAST is crawling your target application correctly. + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_BROWSER_LOG: "crawl:debug" +``` + +For example, the following output shows that four anchor links we discovered during the crawl of the page at `https://example.com`. + +```plaintext +2022-11-17T11:18:05.578 DBG CRAWL executing step nav_id=6ec647d8255c729160dd31cb124e6f89 path="LoadURL [https://example.com]" step=1 +... +2022-11-17T11:18:11.900 DBG CRAWL found new navigations browser_id=2243909820020928961 nav_count=4 nav_id=6ec647d8255c729160dd31cb124e6f89 of=1 step=1 +2022-11-17T11:18:11.901 DBG CRAWL adding navigation action="LeftClick [a href=/page1.html]" nav=bd458cc1fc2d7c6fb984464b6d968866 parent_nav=6ec647d8255c729160dd31cb124e6f89 +2022-11-17T11:18:11.901 DBG CRAWL adding navigation action="LeftClick [a href=/page2.html]" nav=6dcb25f9f9ece3ee0071ac2e3166d8e6 parent_nav=6ec647d8255c729160dd31cb124e6f89 +2022-11-17T11:18:11.901 DBG CRAWL adding navigation action="LeftClick [a href=/page3.html]" nav=89efbb0c6154d6c6d85a63b61a7cdc6f parent_nav=6ec647d8255c729160dd31cb124e6f89 +2022-11-17T11:18:11.901 DBG CRAWL adding navigation action="LeftClick [a href=/page4.html]" nav=f29b4f4e0bdee70f5255de7fc080f04d parent_nav=6ec647d8255c729160dd31cb124e6f89 +``` + +## Chromium DevTools logging + +WARNING: +Logging DevTools messages is a security risk. The output contains secrets such as usernames, passwords and authentication tokens. +The output is uploaded to the GitLab server and may be visible in job logs. + +The DAST Browser-based scanner orchestrates a Chromium browser using the [Chrome DevTools Protocol](https://chromedevtools.github.io/devtools-protocol/). +Logging DevTools messages helps provide transparency into what the browser is doing. For example, if selecting a button does not work, a DevTools message might show that the cause is a CORS error in a browser console log. +Logs that contain DevTools messages can be very large in size. For this reason, it should only be enabled on jobs with a short duration. + +To log all DevTools messages, turn the `CHROM` log module to `trace` and configure logging levels. The following are examples of DevTools logs: + +```plaintext +2022-12-05T06:27:24.280 TRC CHROM event received {"method":"Fetch.requestPaused","params":{"requestId":"interception-job-3.0","request":{"url":"http://auth-auto:8090/font-awesome.min.css","method":"GET","headers":{"Accept":"text/css,*/*;q=0.1","Referer":"http://auth-auto:8090/login.html","User-Agent":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/105.0.5195.102 Safari/537.36"},"initialPriority":"VeryHigh","referrerPolicy":"strict-origin-when-cross-origin"},"frameId":"A706468B01C2FFAA2EB6ED365FF95889","resourceType":"Stylesheet","networkId":"39.3"}} method=Fetch.requestPaused +2022-12-05T06:27:24.280 TRC CHROM request sent {"id":47,"method":"Fetch.continueRequest","params":{"requestId":"interception-job-3.0","headers":[{"name":"Accept","value":"text/css,*/*;q=0.1"},{"name":"Referer","value":"http://auth-auto:8090/login.html"},{"name":"User-Agent","value":"Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) HeadlessChrome/105.0.5195.102 Safari/537.36"}]}} id=47 method=Fetch.continueRequest +2022-12-05T06:27:24.281 TRC CHROM response received {"id":47,"result":{}} id=47 method=Fetch.continueRequest +``` + +### Customizing DevTools log levels + +Chrome DevTools requests, responses and events are namespaced by domain. DAST allows each domain and each domain with message to have different logging configuration. +The environment variable `DAST_BROWSER_DEVTOOLS_LOG` accepts a semi-colon separated list of logging configurations. +Logging configurations are declared using the structure `[domain/message]:[what-to-log][,truncate:[max-message-size]]`. + +- `domain/message` references what is being logged. + - `Default` can be used as a value to represent all domains and messages. + - Can be a domain, for example, `Browser`, `CSS`, `Page`, `Network`. + - Can be a domain with a message, for example, `Network.responseReceived`. + - If multiple configurations apply, the most specific configuration is used. +- `what-to-log` references whether and what to log. + - `message` logs that a message was received and does not log the message content. + - `messageAndBody` logs the message with the message content. Recommended to be used with `truncate`. + - `suppress` does not log the message. Used to silence noisy domains and messages. +- `truncate` is an optional configuration to limit the size of the message printed. + +### Example - log all DevTools messages + +Used to log everything when you're not sure where to start. + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_BROWSER_FILE_LOG: "chrom:trace" + DAST_BROWSER_FILE_LOG_PATH: "/zap/wrk/dast-scan.log" + DAST_BROWSER_DEVTOOLS_LOG: "Default:messageAndBody,truncate:2000" + artifacts: + paths: + - dast-scan.log + when: always +``` + +### Example - log HTTP messages + +Useful for when a resource isn't loading correctly. HTTP message events are logged, as is the decision to continue or +fail the request. Any errors in the browser console are also logged. + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_BROWSER_FILE_LOG: "chrom:trace" + DAST_BROWSER_FILE_LOG_PATH: "/zap/wrk/dast-scan.log" + DAST_BROWSER_DEVTOOLS_LOG: "Default:suppress;Fetch:messageAndBody,truncate:2000;Network:messageAndBody,truncate:2000;Log:messageAndBody,truncate:2000;Console:messageAndBody,truncate:2000" + artifacts: + paths: + - dast-scan.log + when: always +``` + +## Chromium logs + +In the rare event that Chromium crashes, it can be helpful to write the Chromium process `STDOUT` and `STDERR` to log. +Setting the environment variable `DAST_BROWSER_LOG_CHROMIUM_OUTPUT` to `true` achieves this purpose. + +DAST starts and stops many Chromium processes. DAST sends each process output to all log destinations with the log module `LEASE` and log level `INFO`. + +For example: + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_BROWSER_LOG_CHROMIUM_OUTPUT: "true" +``` + +## Known problems + +### Logs contain `response body exceeds allowed size` + +By default DAST processes HTTP requests where the HTTP response body is 10 MB or less. Otherwise, DAST blocks the response +which can cause scans to fail. This constraint is intended to reduce memory consumption during a scan. + +An example log is as follows, where DAST blocked the JavaScript file found at `https://example.com/large.js` as it's size is greater than the limit: + +```plaintext +2022-12-05T06:28:43.093 WRN BROWS response body exceeds allowed size allowed_size_bytes=1000000 browser_id=752944257619431212 nav_id=ae23afe2acbce2c537657a9112926f1a of=1 request_id=interception-job-2.0 response_size_bytes=9333408 step=1 url=https://example.com/large.js +2022-12-05T06:28:58.104 WRN CONTA request failed, attempting to continue scan error=net::ERR_BLOCKED_BY_RESPONSE index=0 requestID=38.2 url=https://example.com/large.js +``` + +This can be changed using the configuration `DAST_MAX_RESPONSE_SIZE_MB`. For example, + +```yaml +include: + - template: DAST.gitlab-ci.yml + +dast: + variables: + DAST_MAX_RESPONSE_SIZE_MB: "25" +``` diff --git a/doc/user/application_security/dast/dast_troubleshooting.md b/doc/user/application_security/dast/dast_troubleshooting.md index 61a7520bf7c..0dcf203a3a9 100644 --- a/doc/user/application_security/dast/dast_troubleshooting.md +++ b/doc/user/application_security/dast/dast_troubleshooting.md @@ -5,7 +5,7 @@ info: To determine the technical writer assigned to the Stage/Group associated w type: reference, howto --- -# Troubleshooting Dynamic Application Security Testing (DAST) **(ULTIMATE)** +# Troubleshooting DAST proxy-based analyzer **(ULTIMATE)** The following troubleshooting scenarios have been collected from customer support cases. If you experience a problem not addressed here, or the information here does not fix your problem, create a diff --git a/doc/user/application_security/dast_api/index.md b/doc/user/application_security/dast_api/index.md index 609a7fe3b89..cf89c8edf65 100644 --- a/doc/user/application_security/dast_api/index.md +++ b/doc/user/application_security/dast_api/index.md @@ -217,8 +217,9 @@ DAST API supports testing GraphQL endpoints multiple ways: - Test using a Postman Collection containing GraphQL queries. This section documents how to test using a GraphQL schema. The GraphQL schema support in -DAST API is able to query the schema from endpoints that support introspection. +DAST API is able to query the schema from endpoints that support [introspection](https://graphql.org/learn/introspection/). Introspection is enabled by default to allow tools like GraphiQL to work. +For details on how to enable introspection, see your GraphQL framework documentation. #### DAST API scanning with a GraphQL endpoint URL diff --git a/lib/version_check.rb b/lib/version_check.rb index 35014f3ddf0..9b7ab440328 100644 --- a/lib/version_check.rb +++ b/lib/version_check.rb @@ -5,6 +5,9 @@ require "base64" class VersionCheck include ReactiveCaching + # Increment when format of cache value is changed + CACHE_VERSION = 1 + ## Version Check Reactive Caching ## This cache stores the external API response from https://version.gitlab.com ## @@ -61,7 +64,7 @@ class VersionCheck end def id - Gitlab::VERSION + [Gitlab::VERSION, Gitlab.revision, CACHE_VERSION].join('-') end def calculate_reactive_cache(*) @@ -69,13 +72,19 @@ class VersionCheck case response&.code when 200 - response.body + Gitlab::Json.parse(response.body) + else + { error: 'version check failed', status: response&.code } end + rescue JSON::ParserError + { error: 'parsing version check response failed', status: response&.code } end def response with_reactive_cache do |data| - Gitlab::Json.parse(data) if data + raise InvalidateReactiveCache if !data.is_a?(Hash) || data[:error] + + data end end end diff --git a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb index 057b4c15db1..d6446c9725d 100644 --- a/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb +++ b/qa/qa/specs/features/browser_ui/7_configure/auto_devops/create_project_with_auto_devops_spec.rb @@ -1,7 +1,9 @@ # frozen_string_literal: true module QA - RSpec.describe 'Configure', only: { subdomain: %i[staging staging-canary] }, product_group: :configure do + RSpec.describe 'Configure', + quarantine: { issue: 'https://gitlab.com/gitlab-org/gitlab/-/issues/381454', type: :flaky }, + only: { subdomain: %i[staging staging-canary] }, product_group: :configure do describe 'Auto DevOps with a Kubernetes Agent' do let!(:app_project) do Resource::Project.fabricate_via_api! do |project| diff --git a/spec/features/projects/settings/repository_settings_spec.rb b/spec/features/projects/settings/repository_settings_spec.rb index 50edfdc5ed8..6f0a3094849 100644 --- a/spec/features/projects/settings/repository_settings_spec.rb +++ b/spec/features/projects/settings/repository_settings_spec.rb @@ -8,6 +8,7 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p let(:role) { :developer } before do + stub_feature_flags(branch_rules: false) project.add_role(user, role) sign_in(user) end @@ -39,19 +40,18 @@ RSpec.describe 'Projects > Settings > Repository settings', feature_category: :p end context 'Branch rules', :js do - it 'renders branch rules settings' do - visit project_settings_repository_path(project) - expect(page).to have_content('Branch rules') - end - context 'branch_rules feature flag disabled', :js do it 'does not render branch rules settings' do - stub_feature_flags(branch_rules: false) visit project_settings_repository_path(project) - expect(page).not_to have_content('Branch rules') end end + + it 'renders branch rules settings' do + stub_feature_flags(branch_rules: true) + visit project_settings_repository_path(project) + expect(page).to have_content('Branch rules') + end end context 'Deploy Keys', :js do diff --git a/spec/helpers/search_helper_spec.rb b/spec/helpers/search_helper_spec.rb index 0450ecc0f21..3d98591ac76 100644 --- a/spec/helpers/search_helper_spec.rb +++ b/spec/helpers/search_helper_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' -RSpec.describe SearchHelper do +RSpec.describe SearchHelper, feature_category: :global_search do include MarkupHelper include BadgesHelper @@ -65,7 +65,8 @@ RSpec.describe SearchHelper do let(:term) { 'jane' } it 'makes a call to SearchService' do - expect(SearchService).to receive(:new).with(current_user, { search: term, scope: 'users' }).and_call_original + params = { search: term, per_page: 5, scope: 'users' } + expect(SearchService).to receive(:new).with(current_user, params).and_call_original search_autocomplete_opts(term) end @@ -86,6 +87,15 @@ RSpec.describe SearchHelper do expect(search_autocomplete_opts(term)).to eq([]) end end + + context 'with limiting' do + let!(:users) { create_list(:user, 6, name: 'Jane Doe') } + + it 'only returns the first 5 users' do + result = search_autocomplete_opts(term) + expect(result.size).to eq(5) + end + end end it "includes the required project attrs" do diff --git a/spec/lib/version_check_spec.rb b/spec/lib/version_check_spec.rb index 1803dd66ba7..4aa8975b7cf 100644 --- a/spec/lib/version_check_spec.rb +++ b/spec/lib/version_check_spec.rb @@ -2,7 +2,9 @@ require 'spec_helper' -RSpec.describe VersionCheck do +RSpec.describe VersionCheck, :use_clean_rails_memory_store_caching do + include ReactiveCachingHelpers + describe '.url' do it 'returns the correct URL' do expect(described_class.url).to match(%r{\A#{Regexp.escape(described_class.host)}/check\.json\?gitlab_info=\w+}) @@ -24,13 +26,25 @@ RSpec.describe VersionCheck do end describe '#calculate_reactive_cache' do - context 'response code is 200' do + context 'response code is 200 with valid body' do before do stub_request(:get, described_class.url).to_return(status: 200, body: '{ "status": "success" }', headers: {}) end it 'returns the response object' do - expect(described_class.new.calculate_reactive_cache).to eq("{ \"status\": \"success\" }") + expect(described_class.new.calculate_reactive_cache).to eq({ "status" => "success" }) + end + end + + context 'response code is 200 with invalid body' do + before do + stub_request(:get, described_class.url).to_return(status: 200, body: '{ "invalid: json" }', headers: {}) + end + + it 'returns an error hash' do + expect(described_class.new.calculate_reactive_cache).to eq( + { error: 'parsing version check response failed', status: 200 } + ) end end @@ -39,38 +53,61 @@ RSpec.describe VersionCheck do stub_request(:get, described_class.url).to_return(status: 500, body: nil, headers: {}) end - it 'returns nil' do - expect(described_class.new.calculate_reactive_cache).to be(nil) + it 'returns an error hash' do + expect(described_class.new.calculate_reactive_cache).to eq({ error: 'version check failed', status: 500 }) end end end describe '#response' do - context 'cache returns value' do - let(:response) { { "severity" => "success" }.to_json } - + # see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106254 + context "with old string value in cache" do before do - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:with_reactive_cache).and_return(response) - end + old_version_check = described_class.new + allow(old_version_check).to receive(:id).and_return(Gitlab::VERSION) + write_reactive_cache(old_version_check, + "{\"latest_stable_versions\":[],\"latest_version\":\"15.6.2\",\"severity\":\"success\",\"details\":\"\"}" + ) end - it 'returns the response object' do - expect(described_class.new.response).to be(response) + it 'returns nil' do + version_check = described_class.new + expect(version_check.response).to be_nil end end - context 'cache returns nil' do - let(:response) { nil } + # see https://gitlab.com/gitlab-org/gitlab/-/merge_requests/106254 + context "with non-hash value in cache" do + it 'returns nil and invalidates the reactive cache' do + version_check = described_class.new + stub_reactive_cache(version_check, + "{\"latest_stable_versions\":[],\"latest_version\":\"15.6.2\",\"severity\":\"success\",\"details\":\"\"}" + ) - before do - allow_next_instance_of(described_class) do |instance| - allow(instance).to receive(:with_reactive_cache).and_return(response) - end + expect(version_check).to receive(:refresh_reactive_cache!).and_call_original + expect(version_check.response).to be_nil + expect(read_reactive_cache(version_check)).to be_nil end + end - it 'returns nil' do - expect(described_class.new.response).to be(nil) + context 'cache returns value' do + it 'returns the response object' do + version_check = described_class.new + data = { status: 'success' } + stub_reactive_cache(version_check, data) + + expect(version_check.response).to eq(data) + end + end + + context 'cache returns error' do + it 'returns nil and invalidates the reactive cache' do + version_check = described_class.new + stub_reactive_cache(version_check, error: 'version check failed') + + expect(version_check).to receive(:refresh_reactive_cache!).and_call_original + expect(version_check.response).to be_nil + expect(read_reactive_cache(version_check)).to be_nil end end end |