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

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/assets/javascripts/blob/notebook/notebook_viewer.vue3
-rw-r--r--app/assets/javascripts/ide/lib/mirror.js3
-rw-r--r--app/services/clusters/agents/refresh_authorization_service.rb6
-rw-r--r--db/post_migrate/20210604070207_retry_backfill_traversal_ids.rb21
-rw-r--r--db/schema_migrations/202106040702071
-rw-r--r--doc/development/architecture.md1
-rw-r--r--doc/development/sec/token_revocation_api.md118
-rw-r--r--doc/user/application_security/secret_detection/index.md7
-rw-r--r--doc/user/application_security/secret_detection/post_processing.md203
-rw-r--r--spec/frontend/badges/store/actions_spec.js12
-rw-r--r--spec/frontend/boards/mock_data.js3
-rw-r--r--spec/frontend/clusters_list/components/clusters_spec.js7
-rw-r--r--spec/frontend/environments/edit_environment_spec.js5
-rw-r--r--spec/frontend/environments/new_environment_spec.js5
-rw-r--r--spec/frontend/error_tracking_settings/store/actions_spec.js2
-rw-r--r--spec/frontend/ide/lib/mirror_spec.js9
-rw-r--r--spec/frontend/ide/services/terminals_spec.js3
-rw-r--r--spec/frontend/issues/show/components/app_spec.js11
-rw-r--r--spec/frontend/lib/utils/rails_ujs_spec.js3
-rw-r--r--spec/frontend/milestones/components/milestone_combobox_spec.js26
-rw-r--r--spec/frontend/notes/mock_data.js5
-rw-r--r--spec/frontend/profile/account/components/update_username_spec.js6
-rw-r--r--spec/frontend/ref/components/ref_selector_spec.js28
-rw-r--r--spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js11
-rw-r--r--spec/frontend_integration/test_helpers/mock_server/routes/emojis.js3
-rw-r--r--spec/migrations/retry_backfill_traversal_ids_spec.rb93
-rw-r--r--spec/services/clusters/agents/refresh_authorization_service_spec.rb12
27 files changed, 282 insertions, 325 deletions
diff --git a/app/assets/javascripts/blob/notebook/notebook_viewer.vue b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
index dc1a9cb865a..ade92f2562b 100644
--- a/app/assets/javascripts/blob/notebook/notebook_viewer.vue
+++ b/app/assets/javascripts/blob/notebook/notebook_viewer.vue
@@ -1,6 +1,7 @@
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import NotebookLab from '~/notebook/index.vue';
export default {
@@ -51,7 +52,7 @@ export default {
this.loading = false;
})
.catch((e) => {
- if (e.status !== 200) {
+ if (e.status !== HTTP_STATUS_OK) {
this.loadError = true;
}
this.error = true;
diff --git a/app/assets/javascripts/ide/lib/mirror.js b/app/assets/javascripts/ide/lib/mirror.js
index 78990953beb..f437965b25a 100644
--- a/app/assets/javascripts/ide/lib/mirror.js
+++ b/app/assets/javascripts/ide/lib/mirror.js
@@ -1,3 +1,4 @@
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { getWebSocketUrl, mergeUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale';
import createDiff from './create_diff';
@@ -26,7 +27,7 @@ const cancellableWait = (time) => {
const isErrorResponse = (error) => error && error.code !== 0;
-const isErrorPayload = (payload) => payload && payload.status_code !== 200;
+const isErrorPayload = (payload) => payload && payload.status_code !== HTTP_STATUS_OK;
const getErrorFromResponse = (data) => {
if (isErrorResponse(data.error)) {
diff --git a/app/services/clusters/agents/refresh_authorization_service.rb b/app/services/clusters/agents/refresh_authorization_service.rb
index 53b14ab54da..23ececef6a1 100644
--- a/app/services/clusters/agents/refresh_authorization_service.rb
+++ b/app/services/clusters/agents/refresh_authorization_service.rb
@@ -58,7 +58,7 @@ module Clusters
if project_entries
allowed_projects.where_full_path_in(project_entries.keys).map do |project|
- { project_id: project.id, config: project_entries[project.full_path] }
+ { project_id: project.id, config: project_entries[project.full_path.downcase] }
end
end
end
@@ -70,7 +70,7 @@ module Clusters
if group_entries
allowed_groups.where_full_path_in(group_entries.keys).map do |group|
- { group_id: group.id, config: group_entries[group.full_path] }
+ { group_id: group.id, config: group_entries[group.full_path.downcase] }
end
end
end
@@ -79,7 +79,7 @@ module Clusters
def extract_config_entries(entity:)
config.dig('ci_access', entity)
&.first(AUTHORIZED_ENTITY_LIMIT)
- &.index_by { |config| config.delete('id') }
+ &.index_by { |config| config.delete('id').downcase }
end
def allowed_projects
diff --git a/db/post_migrate/20210604070207_retry_backfill_traversal_ids.rb b/db/post_migrate/20210604070207_retry_backfill_traversal_ids.rb
deleted file mode 100644
index 5e540c7f359..00000000000
--- a/db/post_migrate/20210604070207_retry_backfill_traversal_ids.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-# frozen_string_literal: true
-
-class RetryBackfillTraversalIds < ActiveRecord::Migration[6.1]
- include Gitlab::Database::MigrationHelpers
-
- ROOTS_MIGRATION = 'BackfillNamespaceTraversalIdsRoots'
- CHILDREN_MIGRATION = 'BackfillNamespaceTraversalIdsChildren'
- DOWNTIME = false
- DELAY_INTERVAL = 2.minutes
-
- disable_ddl_transaction!
-
- def up
- duration = requeue_background_migration_jobs_by_range_at_intervals(ROOTS_MIGRATION, DELAY_INTERVAL)
- requeue_background_migration_jobs_by_range_at_intervals(CHILDREN_MIGRATION, DELAY_INTERVAL, initial_delay: duration)
- end
-
- def down
- # no-op
- end
-end
diff --git a/db/schema_migrations/20210604070207 b/db/schema_migrations/20210604070207
deleted file mode 100644
index 3531c9775bd..00000000000
--- a/db/schema_migrations/20210604070207
+++ /dev/null
@@ -1 +0,0 @@
-ec44b7f134de2ea6537c6fe3109fa9d7e32785233f3d1b8e9ea118474d21526a \ No newline at end of file
diff --git a/doc/development/architecture.md b/doc/development/architecture.md
index 2bb5ab6bca6..984ac49c514 100644
--- a/doc/development/architecture.md
+++ b/doc/development/architecture.md
@@ -378,6 +378,7 @@ Component statuses are linked to configuration documentation for each component.
| [Runner](#gitlab-runner) | Executes GitLab CI/CD jobs | ⤓ | ⤓ | ✅ | ⚙ | ✅ | ⚙ | ⚙ | CE & EE |
| [Sentry integration](#sentry) | Error tracking for deployed apps | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | ⤓ | CE & EE |
| [Sidekiq](#sidekiq) | Background jobs processor | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | CE & EE |
+| [Token Revocation API](sec/token_revocation_api.md) | Receives and revokes leaked secrets | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | EE Only |
### Component details
diff --git a/doc/development/sec/token_revocation_api.md b/doc/development/sec/token_revocation_api.md
new file mode 100644
index 00000000000..15d1d2d0ef3
--- /dev/null
+++ b/doc/development/sec/token_revocation_api.md
@@ -0,0 +1,118 @@
+---
+stage: Secure
+group: Static Analysis
+info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
+---
+
+# Token Revocation API
+
+The Token Revocation API is an externally-deployed HTTP API that interfaces with GitLab
+to receive and revoke API tokens and other secrets detected by GitLab Secret Detection.
+See the [high-level architecture](../../user/application_security/secret_detection/post_processing.md)
+to understand the Secret Detection post-processing and revocation flow.
+
+GitLab.com uses the internally-maintained [Secret Revocation Service](https://gitlab.com/gitlab-com/gl-security/engineering-and-research/automation-team/secret-revocation-service)
+(team-members only) as its Token Revocation API. For GitLab self-managed, you can create
+your own API and configure GitLab to use it.
+
+## Implement a Token Revocation API for self-managed
+
+GitLab self-managed instances interested in using the revocation capabilities must:
+
+- Implement and deploy your own Token Revocation API.
+- Configure the GitLab instance to use the Token Revocation API.
+
+Your service must:
+
+- Match the API specification below.
+- Provide two endpoints:
+ - Fetching revocable token types.
+ - Revoking leaked tokens.
+- Be rate-limited and idempotent.
+
+Requests to the documented endpoints are authenticated using API tokens passed in
+the `Authorization` header. Request and response bodies, if present, are
+expected to have the content type `application/json`.
+
+All endpoints may return these responses:
+
+- `401 Unauthorized`
+- `405 Method Not Allowed`
+- `500 Internal Server Error`
+
+### `GET /v1/revocable_token_types`
+
+Returns the valid `type` values for use in the `revoke_tokens` endpoint.
+
+NOTE:
+These values match the concatenation of [the `secrets` analyzer's](../../user/application_security/secret_detection/index.md)
+[primary identifier](../integrations/secure.md#identifiers) by means
+of concatenating the `primary_identifier.type` and `primary_identifier.value`.
+For example, the value `gitleaks_rule_id_gitlab_personal_access_token` matches the following finding identifier:
+
+```json
+{"type": "gitleaks_rule_id", "name": "Gitleaks rule ID GitLab Personal Access Token", "value": "GitLab Personal Access Token"}
+```
+
+| Status Code | Description |
+| ----- | --- |
+| `200` | The response body contains the valid token `type` values. |
+
+Example response body:
+
+```json
+{
+ "types": ["gitleaks_rule_id_gitlab_personal_access_token"]
+}
+```
+
+### `POST /v1/revoke_tokens`
+
+Accepts a list of tokens to be revoked by the appropriate provider. Your service is responsible for communicating
+with each provider to revoke the token.
+
+| Status Code | Description |
+| ----- | --- |
+| `204` | All submitted tokens have been accepted for eventual revocation. |
+| `400` | The request body is invalid or one of the submitted token types is not supported. The request should not be retried. |
+| `429` | The provider has received too many requests. The request should be retried later. |
+
+Example request body:
+
+```json
+[{
+ "type": "gitleaks_rule_id_gitlab_personal_access_token",
+ "token": "glpat--8GMtG8Mf4EnMJzmAWDU",
+ "location": "https://example.com/some-repo/blob/abcdefghijklmnop/compromisedfile1.java"
+},
+{
+ "type": "gitleaks_rule_id_gitlab_personal_access_token",
+ "token": "glpat--tG84EGK33nMLLDE70zU",
+ "location": "https://example.com/some-repo/blob/abcdefghijklmnop/compromisedfile2.java"
+}]
+```
+
+### Configure GitLab to interface with the Token Revocation API
+
+You must configure the following database settings in the GitLab instance:
+
+| Setting | Type | Description |
+| ------- | ---- | ----------- |
+| `secret_detection_token_revocation_enabled` | Boolean | Whether automatic token revocation is enabled |
+| `secret_detection_token_revocation_url` | String | A fully-qualified URL to the `/v1/revoke_tokens` endpoint of the Token Revocation API |
+| `secret_detection_revocation_token_types_url` | String | A fully-qualified URL to the `/v1/revocable_token_types` endpoint of the Token Revocation API |
+| `secret_detection_token_revocation_token` | String | A pre-shared token to authenticate requests to the Token Revocation API |
+
+For example, to configure these values in the
+[Rails console](../../administration/operations/rails_console.md#starting-a-rails-console-session):
+
+```ruby
+::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_token: 'MYSECRETTOKEN')
+::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_url: 'https://example.gitlab.com/revocation_service/v1/revoke_tokens')
+::Gitlab::CurrentSettings.update!(secret_detection_revocation_token_types_url: 'https://example.gitlab.com/revocation_service/v1/revocable_token_types')
+::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_enabled: true)
+```
+
+After you configure these values, the Token Revocation API will be called according to the
+[high-level architecture](../../user/application_security/secret_detection/post_processing.md#high-level-architecture)
+diagram.
diff --git a/doc/user/application_security/secret_detection/index.md b/doc/user/application_security/secret_detection/index.md
index d316ed7a9de..d6aab71a2c6 100644
--- a/doc/user/application_security/secret_detection/index.md
+++ b/doc/user/application_security/secret_detection/index.md
@@ -195,7 +195,12 @@ Pipelines now include a Secret Detection job.
## Responding to a leaked secret
-If the scanner detects a secret you should rotate it immediately. [Purging a file from the repository's history](../../project/repository/reducing_the_repo_size_using_git.md#purge-files-from-repository-history) may not be effective in removing all references to the file. Also, the secret remains in any forks of the repository.
+Secrets detected by the analyzer should be immediately rotated.
+[Purging a file from the repository's history](../../project/repository/reducing_the_repo_size_using_git.md#purge-files-from-repository-history)
+may not be effective in removing all references to the file. Additionally, the secret will remain in any existing
+forks or clones of the repository.
+
+GitLab will attempt to [automatically revoke](post_processing.md) some types of leaked secrets.
## Pinning to specific analyzer version
diff --git a/doc/user/application_security/secret_detection/post_processing.md b/doc/user/application_security/secret_detection/post_processing.md
index 6e9b77426ad..10742114b90 100644
--- a/doc/user/application_security/secret_detection/post_processing.md
+++ b/doc/user/application_security/secret_detection/post_processing.md
@@ -10,26 +10,28 @@ info: To determine the technical writer assigned to the Stage/Group associated w
> - [Disabled by default for GitLab personal access tokens](https://gitlab.com/gitlab-org/gitlab/-/issues/371658) in GitLab 15.6 [with a flag](../../../administration/feature_flags.md) named `gitlab_pat_auto_revocation`. Available to GitLab.com only.
> - [Enabled by default for GitLab personal access tokens](https://gitlab.com/gitlab-org/gitlab/-/issues/371658) in GitLab 15.9
-GitLab supports running post-processing hooks after detecting a secret. These
-hooks can perform actions, like notifying the cloud service that issued the secret.
-The cloud provider can then confirm the credentials and take remediation actions, like:
+GitLab.com and self-managed supports running post-processing hooks after detecting a secret. These
+hooks can perform actions, like notifying the vendor that issued the secret.
+The vendor can then confirm the credentials and take remediation actions, like:
- Revoking a secret.
- Reissuing a secret.
- Notifying the creator of the secret.
-GitLab SaaS supports post-processing for [GitLab personal access tokens](../../profile/personal_access_tokens.md) and Amazon Web Services (AWS).
-Post-processing workflows vary by supported cloud providers.
+GitLab supports post-processing for the following vendors and secrets:
-Post-processing is limited to a project's default branch. The epic
-[Post-processing of leaked secrets](https://gitlab.com/groups/gitlab-org/-/epics/4639).
-contains:
+| Vendor | Secret | GitLab.com | Self-managed |
+| ----- | --- | --- | --- |
+| GitLab | [Personal access tokens](../../profile/personal_access_tokens.md) | ✅ | ✅ 15.9 and later |
+| Amazon Web Services (AWS) | [IAM access keys](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_credentials_access-keys.html) | ✅ | ⚙ |
-- Technical details of post-processing secrets.
-- Discussions of efforts to support additional branches.
+**Component legend**
+
+- ✅ - Available by default
+- ⚙ - Requires manual integration using a [Token Revocation API](../../../development/sec/token_revocation_api.md)
NOTE:
-Post-processing is currently limited to a project's default branch
+Post-processing is limited to a project's default branch.
## High-level architecture
@@ -40,142 +42,51 @@ sequenceDiagram
autonumber
GitLab Rails->>+Sidekiq: gl-secret-detection-report.json
Sidekiq-->+Sidekiq: StoreSecurityReportsWorker
- Sidekiq-->+RevocationAPI: GET revocable keys types
- RevocationAPI-->>-Sidekiq: OK
- Sidekiq->>+RevocationAPI: POST revoke revocable keys
- RevocationAPI-->>-Sidekiq: ACCEPTED
- RevocationAPI-->>+Cloud Vendor: revoke revocable keys
- Cloud Vendor-->>+RevocationAPI: ACCEPTED
-```
-
-## Integrate your cloud provider service with GitLab SaaS
-
-Third party cloud and SaaS providers can [express integration interest by filling out this form](https://forms.gle/wWpvrtLRK21Q2WJL9).
-
-### Implement a vendor revocation receiver service
-
-A vendor revocation receiver service integrates with a GitLab instance to receive
-a web notification and respond to leaked token requests.
-
-To implement a receiver service to revoke leaked tokens:
-
-1. Create a publicly accessible HTTP service matching the corresponding API contract
- below. Your service should be idempotent and rate-limited.
-1. When a pipeline corresponding to its revocable token type (in the example, `my_api_token`)
- completes, GitLab sends a request to your receiver service.
-1. The included URL should be publicly accessible, and contain the commit where the
- leaked token can be found. For example:
-
- ```plaintext
- POST / HTTP/2
- Accept: */*
- Content-Type: application/json
- X-Gitlab-Token: MYSECRETTOKEN
-
- [
- {"type": "my_api_token", "token":"XXXXXXXXXXXXXXXX","url": "https://example.com/some-repo/blob/abcdefghijklmnop/compromisedfile1.java"}
- ]
- ```
-
-## Implement a revocation service for self-managed
-
-Self-managed instances interested in using the revocation capabilities must:
-
-- Deploy the [RevocationAPI](#high-level-architecture).
-- Configure the GitLab instance to use the RevocationAPI.
-
-A RevocationAPI must:
-
-- Match a minimal API specification.
-- Provide two endpoints:
- - Fetching revocable token types.
- - Revoking leaked tokens.
-- Be rate-limited and idempotent.
-
-Requests to the documented endpoints are authenticated via API tokens passed in
-the `Authorization` header. Request and response bodies, if present, are
-expected to have the content type `application/json`.
-
-All endpoints may return these responses:
-
-- `401 Unauthorized`
-- `405 Method Not Allowed`
-- `500 Internal Server Error`
-
-### `GET /v1/revocable_token_types`
-
-Returns the valid `type` values for use in the `revoke_tokens` endpoint.
-
-NOTE:
-These values match the concatenation of [the `secrets` analyzer's](index.md)
-[primary identifier](../../../development/integrations/secure.md#identifiers) by means
-of concatenating the `primary_identifier.type` and `primary_identifier.value`.
-In the case below, a finding identifier matches:
-
-```json
-{"type": "gitleaks_rule_id", "name": "Gitleaks rule ID GitLab Personal Access Token", "value": "GitLab Personal Access Token"}
+ Sidekiq-->+Token Revocation API: GET revocable keys types
+ Token Revocation API-->>-Sidekiq: OK
+ Sidekiq->>+Token Revocation API: POST revoke revocable keys
+ Token Revocation API-->>-Sidekiq: ACCEPTED
+ Token Revocation API-->>+Receiver Service: revoke revocable keys
+ Receiver Service-->>+Token Revocation API: ACCEPTED
```
-| Status Code | Description |
-| ----- | --- |
-| `200` | The response body contains the valid token `type` values. |
-
-Example response body:
-
-```json
-{
- "types": ["gitleaks_rule_id_gitlab_personal_access_token"]
-}
+1. A pipeline with a Secret Detection job completes on the project's default branch, producing a scan
+ report (**1**).
+1. The report is processed (**2**) by an asynchronous worker, which communicates with an externally
+ deployed HTTP service (**3** and **4**) to determine which kinds of secrets can be automatically
+ revoked.
+1. The worker sends (**5** and **6**) the list of detected secrets which the Token Revocation API is able to
+ revoke.
+1. The Token Revocation API sends (**7** and **8**) each revocable token to their respective vendor's [receiver service](#integrate-your-cloud-provider-service-with-gitlabcom).
+
+See the [Token Revocation API](../../../development/sec/token_revocation_api.md) documentation for more
+information.
+
+## Integrate your cloud provider service with GitLab.com
+
+Third-party cloud and SaaS vendors interested in automated token revocation can
+[express integration interest by filling out this form](https://forms.gle/wWpvrtLRK21Q2WJL9).
+Vendors must [implement a revocation receiver service](#implement-a-revocation-receiver-service)
+which will be called by the Token Revocation API.
+
+### Implement a revocation receiver service
+
+A revocation receiver service integrates with a GitLab instance's Token Revocation API to receive and respond
+to leaked token revocation requests. The service should be a publicly accessible HTTP API that is
+idempotent and rate-limited. Requests to your service from the Token Revocation API will follow the example
+below:
+
+```plaintext
+POST / HTTP/2
+Accept: */*
+Content-Type: application/json
+X-Gitlab-Token: MYSECRETTOKEN
+
+[
+ {"type": "my_api_token", "token":"XXXXXXXXXXXXXXXX","url": "https://example.com/some-repo/~/raw/abcdefghijklmnop/compromisedfile1.java"}
+]
```
-### `POST /v1/revoke_tokens`
-
-Accepts a list of tokens to be revoked by the appropriate provider.
-
-| Status Code | Description |
-| ----- | --- |
-| `204` | All submitted tokens have been accepted for eventual revocation. |
-| `400` | The request body is invalid or one of the submitted token types is not supported. The request should not be retried. |
-| `429` | The provider has received too many requests. The request should be retried later. |
-
-Example request body:
-
-```json
-[{
- "type": "gitleaks_rule_id_gitlab_personal_access_token",
- "token": "glpat--8GMtG8Mf4EnMJzmAWDU",
- "location": "https://example.com/some-repo/blob/abcdefghijklmnop/compromisedfile1.java"
-},
-{
- "type": "gitleaks_rule_id_gitlab_personal_access_token",
- "token": "glpat--tG84EGK33nMLLDE70zU",
- "location": "https://example.com/some-repo/blob/abcdefghijklmnop/compromisedfile2.java"
-}]
-```
-
-### Configure GitLab to interface with RevocationAPI
-
-You must configure the following database settings in the GitLab instance:
-
-- `secret_detection_token_revocation_enabled`
-- `secret_detection_token_revocation_url`
-- `secret_detection_token_revocation_token`
-- `secret_detection_revocation_token_types_url`
-
-For example, to configure these values in the
-[Rails console](../../../administration/operations/rails_console.md#starting-a-rails-console-session):
-
-```ruby
-::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_token: 'MYSECRETTOKEN')
-::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_url: 'https://example.gitlab.com/revocation_service/v1/revoke_tokens')
-::Gitlab::CurrentSettings.update!(secret_detection_revocation_token_types_url: 'https://example.gitlab.com/revocation_service/v1/revocable_token_types')
-::Gitlab::CurrentSettings.update!(secret_detection_token_revocation_enabled: true)
-```
-
-After you configure these values, completing a pipeline performs these actions:
-
-1. The revocation service is triggered once.
-1. A request is made to `secret_detection_revocation_token_types_url` to fetch a
- list of revocable tokens.
-1. Any Secret Detection findings matching the results of the `token_types` request
- are included in the subsequent revocation request.
+In this example, Secret Detection has determined that an instance of `my_api_token` has been leaked. The
+value of the token is provided to you, in addition to a publicly accessible URL to the raw content of the
+file containing the leaked token.
diff --git a/spec/frontend/badges/store/actions_spec.js b/spec/frontend/badges/store/actions_spec.js
index 4e8d7aaaca9..5ca199357f9 100644
--- a/spec/frontend/badges/store/actions_spec.js
+++ b/spec/frontend/badges/store/actions_spec.js
@@ -5,7 +5,7 @@ import actions, { transformBackendBadge } from '~/badges/store/actions';
import mutationTypes from '~/badges/store/mutation_types';
import createState from '~/badges/store/state';
import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { createDummyBadge, createDummyBadgeResponse } from '../dummy_badge';
describe('Badges store actions', () => {
@@ -99,7 +99,7 @@ describe('Badges store actions', () => {
expect(dispatch.mock.calls).toEqual([['requestNewBadge']]);
dispatch.mockClear();
- return [200, dummyResponse];
+ return [HTTP_STATUS_OK, dummyResponse];
});
const dummyBadge = transformBackendBadge(dummyResponse);
@@ -177,7 +177,7 @@ describe('Badges store actions', () => {
endpointMock.replyOnce(() => {
expect(dispatch.mock.calls).toEqual([['requestDeleteBadge', badgeId]]);
dispatch.mockClear();
- return [200, ''];
+ return [HTTP_STATUS_OK, ''];
});
await actions.deleteBadge({ state, dispatch }, { id: badgeId });
@@ -266,7 +266,7 @@ describe('Badges store actions', () => {
endpointMock.replyOnce(() => {
expect(dispatch.mock.calls).toEqual([['requestLoadBadges', dummyData]]);
dispatch.mockClear();
- return [200, dummyReponse];
+ return [HTTP_STATUS_OK, dummyReponse];
});
await actions.loadBadges({ state, dispatch }, dummyData);
@@ -381,7 +381,7 @@ describe('Badges store actions', () => {
endpointMock.replyOnce(() => {
expect(dispatch.mock.calls).toEqual([['requestRenderedBadge']]);
dispatch.mockClear();
- return [200, dummyReponse];
+ return [HTTP_STATUS_OK, dummyReponse];
});
await actions.renderBadge({ state, dispatch });
@@ -468,7 +468,7 @@ describe('Badges store actions', () => {
expect(dispatch.mock.calls).toEqual([['requestUpdatedBadge']]);
dispatch.mockClear();
- return [200, dummyResponse];
+ return [HTTP_STATUS_OK, dummyResponse];
});
const updatedBadge = transformBackendBadge(dummyResponse);
diff --git a/spec/frontend/boards/mock_data.js b/spec/frontend/boards/mock_data.js
index 0ab8a89bcca..1d011eacf1c 100644
--- a/spec/frontend/boards/mock_data.js
+++ b/spec/frontend/boards/mock_data.js
@@ -1,6 +1,7 @@
import { GlFilteredSearchToken } from '@gitlab/ui';
import { keyBy } from 'lodash';
import { ListType } from '~/boards/constants';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import {
OPERATORS_IS,
OPERATORS_IS_NOT,
@@ -460,7 +461,7 @@ export const BoardsMockData = {
export const boardsMockInterceptor = (config) => {
const body = BoardsMockData[config.method.toUpperCase()][config.url];
- return [200, body];
+ return [HTTP_STATUS_OK, body];
};
export const mockList = {
diff --git a/spec/frontend/clusters_list/components/clusters_spec.js b/spec/frontend/clusters_list/components/clusters_spec.js
index e8e705a6384..20dbff9df15 100644
--- a/spec/frontend/clusters_list/components/clusters_spec.js
+++ b/spec/frontend/clusters_list/components/clusters_spec.js
@@ -7,6 +7,7 @@ import Clusters from '~/clusters_list/components/clusters.vue';
import ClustersEmptyState from '~/clusters_list/components/clusters_empty_state.vue';
import ClusterStore from '~/clusters_list/store';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { apiData } from '../mock_data';
describe('Clusters', () => {
@@ -68,7 +69,7 @@ describe('Clusters', () => {
captureException = jest.spyOn(Sentry, 'captureException');
mock = new MockAdapter(axios);
- mockPollingApi(200, apiData, paginationHeader());
+ mockPollingApi(HTTP_STATUS_OK, apiData, paginationHeader());
return createWrapper({});
});
@@ -255,7 +256,7 @@ describe('Clusters', () => {
const totalSecondPage = 500;
beforeEach(() => {
- mockPollingApi(200, apiData, paginationHeader(totalFirstPage, perPage, 1));
+ mockPollingApi(HTTP_STATUS_OK, apiData, paginationHeader(totalFirstPage, perPage, 1));
return createWrapper({});
});
@@ -269,7 +270,7 @@ describe('Clusters', () => {
describe('when updating currentPage', () => {
beforeEach(() => {
- mockPollingApi(200, apiData, paginationHeader(totalSecondPage, perPage, 2));
+ mockPollingApi(HTTP_STATUS_OK, apiData, paginationHeader(totalSecondPage, perPage, 2));
// setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
// eslint-disable-next-line no-restricted-syntax
wrapper.setData({ currentPage: 2 });
diff --git a/spec/frontend/environments/edit_environment_spec.js b/spec/frontend/environments/edit_environment_spec.js
index ba4b4db54ff..57545c565b4 100644
--- a/spec/frontend/environments/edit_environment_spec.js
+++ b/spec/frontend/environments/edit_environment_spec.js
@@ -5,6 +5,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import EditEnvironment from '~/environments/components/edit_environment.vue';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility');
@@ -68,7 +69,7 @@ describe('~/environments/components/edit.vue', () => {
expect(showsLoading()).toBe(false);
- await submitForm(expected, [200, { path: '/test' }]);
+ await submitForm(expected, [HTTP_STATUS_OK, { path: '/test' }]);
expect(showsLoading()).toBe(true);
});
@@ -76,7 +77,7 @@ describe('~/environments/components/edit.vue', () => {
it('submits the updated environment on submit', async () => {
const expected = { url: 'https://google.ca' };
- await submitForm(expected, [200, { path: '/test' }]);
+ await submitForm(expected, [HTTP_STATUS_OK, { path: '/test' }]);
expect(visitUrl).toHaveBeenCalledWith('/test');
});
diff --git a/spec/frontend/environments/new_environment_spec.js b/spec/frontend/environments/new_environment_spec.js
index 5dd77759391..016d9571094 100644
--- a/spec/frontend/environments/new_environment_spec.js
+++ b/spec/frontend/environments/new_environment_spec.js
@@ -5,6 +5,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import NewEnvironment from '~/environments/components/new_environment.vue';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility');
@@ -79,7 +80,7 @@ describe('~/environments/components/new.vue', () => {
expect(showsLoading()).toBe(false);
- await submitForm(expected, [200, { path: '/test' }]);
+ await submitForm(expected, [HTTP_STATUS_OK, { path: '/test' }]);
expect(showsLoading()).toBe(true);
});
@@ -87,7 +88,7 @@ describe('~/environments/components/new.vue', () => {
it('submits the new environment on submit', async () => {
const expected = { name: 'test', url: 'https://google.ca' };
- await submitForm(expected, [200, { path: '/test' }]);
+ await submitForm(expected, [HTTP_STATUS_OK, { path: '/test' }]);
expect(visitUrl).toHaveBeenCalledWith('/test');
});
diff --git a/spec/frontend/error_tracking_settings/store/actions_spec.js b/spec/frontend/error_tracking_settings/store/actions_spec.js
index 40f82b58fe5..bad2bdfaa1a 100644
--- a/spec/frontend/error_tracking_settings/store/actions_spec.js
+++ b/spec/frontend/error_tracking_settings/store/actions_spec.js
@@ -29,7 +29,7 @@ describe('error tracking settings actions', () => {
});
it('should request and transform the project list', async () => {
- mock.onGet(TEST_HOST).reply(() => [200, { projects: projectList }]);
+ mock.onGet(TEST_HOST).reply(() => [HTTP_STATUS_OK, { projects: projectList }]);
await testAction(
actions.fetchProjects,
null,
diff --git a/spec/frontend/ide/lib/mirror_spec.js b/spec/frontend/ide/lib/mirror_spec.js
index 33dd0fefc6c..98e6b0deee6 100644
--- a/spec/frontend/ide/lib/mirror_spec.js
+++ b/spec/frontend/ide/lib/mirror_spec.js
@@ -7,7 +7,7 @@ import {
MSG_CONNECTION_ERROR,
SERVICE_DELAY,
} from '~/ide/lib/mirror';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { getWebSocketUrl } from '~/lib/utils/url_utility';
jest.mock('~/ide/lib/create_diff', () => jest.fn());
@@ -19,10 +19,13 @@ const TEST_DIFF = {
};
const TEST_ERROR = 'Something bad happened...';
const TEST_SUCCESS_RESPONSE = {
- data: JSON.stringify({ error: { code: 0 }, payload: { status_code: 200 } }),
+ data: JSON.stringify({ error: { code: 0 }, payload: { status_code: HTTP_STATUS_OK } }),
};
const TEST_ERROR_RESPONSE = {
- data: JSON.stringify({ error: { code: 1, Message: TEST_ERROR }, payload: { status_code: 200 } }),
+ data: JSON.stringify({
+ error: { code: 1, Message: TEST_ERROR },
+ payload: { status_code: HTTP_STATUS_OK },
+ }),
};
const TEST_ERROR_PAYLOAD_RESPONSE = {
data: JSON.stringify({
diff --git a/spec/frontend/ide/services/terminals_spec.js b/spec/frontend/ide/services/terminals_spec.js
index 788fdb6471c..5f752197e13 100644
--- a/spec/frontend/ide/services/terminals_spec.js
+++ b/spec/frontend/ide/services/terminals_spec.js
@@ -1,6 +1,7 @@
import MockAdapter from 'axios-mock-adapter';
import * as terminalService from '~/ide/services/terminals';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
const TEST_PROJECT_PATH = 'lorem/ipsum/dolar';
const TEST_BRANCH = 'ref';
@@ -11,7 +12,7 @@ describe('~/ide/services/terminals', () => {
const prevRelativeUrlRoot = gon.relative_url_root;
beforeEach(() => {
- axiosSpy = jest.fn().mockReturnValue([200, {}]);
+ axiosSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, {}]);
mock = new MockAdapter(axios);
mock.onPost(/.*/).reply((...args) => axiosSpy(...args));
diff --git a/spec/frontend/issues/show/components/app_spec.js b/spec/frontend/issues/show/components/app_spec.js
index acb04e0af56..863657b3547 100644
--- a/spec/frontend/issues/show/components/app_spec.js
+++ b/spec/frontend/issues/show/components/app_spec.js
@@ -23,6 +23,7 @@ import PinnedLinks from '~/issues/show/components/pinned_links.vue';
import { POLLING_DELAY } from '~/issues/show/constants';
import eventHub from '~/issues/show/event_hub';
import axios from '~/lib/utils/axios_utils';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { visitUrl } from '~/lib/utils/url_utility';
import {
appProps,
@@ -100,7 +101,7 @@ describe('Issuable output', () => {
mock
.onGet('/gitlab-org/gitlab-shell/-/issues/9/realtime_changes/realtime_changes')
.reply(() => {
- const res = Promise.resolve([200, REALTIME_REQUEST_STACK[realtimeRequestCount]]);
+ const res = Promise.resolve([HTTP_STATUS_OK, REALTIME_REQUEST_STACK[realtimeRequestCount]]);
realtimeRequestCount += 1;
return res;
});
@@ -336,7 +337,9 @@ describe('Issuable output', () => {
const mockData = {
test: [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }],
};
- mock.onGet('/issuable-templates-path').reply(() => Promise.resolve([200, mockData]));
+ mock
+ .onGet('/issuable-templates-path')
+ .reply(() => Promise.resolve([HTTP_STATUS_OK, mockData]));
return wrapper.vm.requestTemplatesAndShowForm().then(() => {
expect(formSpy).toHaveBeenCalledWith(mockData);
@@ -345,7 +348,9 @@ describe('Issuable output', () => {
it('shows the form if template names as array request is successful', () => {
const mockData = [{ name: 'test', id: 'test', project_path: '/', namespace_path: '/' }];
- mock.onGet('/issuable-templates-path').reply(() => Promise.resolve([200, mockData]));
+ mock
+ .onGet('/issuable-templates-path')
+ .reply(() => Promise.resolve([HTTP_STATUS_OK, mockData]));
return wrapper.vm.requestTemplatesAndShowForm().then(() => {
expect(formSpy).toHaveBeenCalledWith(mockData);
diff --git a/spec/frontend/lib/utils/rails_ujs_spec.js b/spec/frontend/lib/utils/rails_ujs_spec.js
index da9cc5c6f3c..8ca4dfc9340 100644
--- a/spec/frontend/lib/utils/rails_ujs_spec.js
+++ b/spec/frontend/lib/utils/rails_ujs_spec.js
@@ -1,5 +1,6 @@
import { setHTMLFixture } from 'helpers/fixtures';
import waitForPromises from 'helpers/wait_for_promises';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
beforeAll(async () => {
// @rails/ujs expects jQuery.ajaxPrefilter to exist if jQuery exists at
@@ -20,7 +21,7 @@ function mockXHRResponse({ responseText, responseContentType } = {}) {
jest.spyOn(global.XMLHttpRequest.prototype, 'send').mockImplementation(function send() {
Object.defineProperties(this, {
readyState: { value: XMLHttpRequest.DONE },
- status: { value: 200 },
+ status: { value: HTTP_STATUS_OK },
response: { value: responseText },
});
this.onreadystatechange();
diff --git a/spec/frontend/milestones/components/milestone_combobox_spec.js b/spec/frontend/milestones/components/milestone_combobox_spec.js
index 27485f3d51d..f8ddca1a2ad 100644
--- a/spec/frontend/milestones/components/milestone_combobox_spec.js
+++ b/spec/frontend/milestones/components/milestone_combobox_spec.js
@@ -4,7 +4,7 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import Vue, { nextTick } from 'vue';
import Vuex from 'vuex';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { ENTER_KEY } from '~/lib/utils/keys';
import MilestoneCombobox from '~/milestones/components/milestone_combobox.vue';
import createStore from '~/milestones/stores/';
@@ -64,15 +64,15 @@ describe('Milestone combobox component', () => {
projectMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, projectMilestones, { [X_TOTAL_HEADER]: '6' }]);
+ .mockReturnValue([HTTP_STATUS_OK, projectMilestones, { [X_TOTAL_HEADER]: '6' }]);
groupMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, groupMilestones, { [X_TOTAL_HEADER]: '6' }]);
+ .mockReturnValue([HTTP_STATUS_OK, groupMilestones, { [X_TOTAL_HEADER]: '6' }]);
searchApiCallSpy = jest
.fn()
- .mockReturnValue([200, projectMilestones, { [X_TOTAL_HEADER]: '6' }]);
+ .mockReturnValue([HTTP_STATUS_OK, projectMilestones, { [X_TOTAL_HEADER]: '6' }]);
mock
.onGet(`/api/v4/projects/${projectId}/milestones`)
@@ -248,9 +248,11 @@ describe('Milestone combobox component', () => {
beforeEach(() => {
projectMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
- groupMilestonesApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ groupMilestonesApiCallSpy = jest
+ .fn()
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
createComponent();
@@ -301,7 +303,7 @@ describe('Milestone combobox component', () => {
beforeEach(() => {
projectMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
createComponent();
@@ -366,7 +368,7 @@ describe('Milestone combobox component', () => {
createComponent();
projectMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, [{ title: 'v1.0' }], { [X_TOTAL_HEADER]: '1' }]);
+ .mockReturnValue([HTTP_STATUS_OK, [{ title: 'v1.0' }], { [X_TOTAL_HEADER]: '1' }]);
return waitForRequests();
});
@@ -430,7 +432,7 @@ describe('Milestone combobox component', () => {
beforeEach(() => {
groupMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
createComponent();
@@ -495,7 +497,11 @@ describe('Milestone combobox component', () => {
createComponent();
groupMilestonesApiCallSpy = jest
.fn()
- .mockReturnValue([200, [{ title: 'group-v1.0' }], { [X_TOTAL_HEADER]: '1' }]);
+ .mockReturnValue([
+ HTTP_STATUS_OK,
+ [{ title: 'group-v1.0' }],
+ { [X_TOTAL_HEADER]: '1' },
+ ]);
return waitForRequests();
});
diff --git a/spec/frontend/notes/mock_data.js b/spec/frontend/notes/mock_data.js
index 286f2adc1d8..d5b7ad73177 100644
--- a/spec/frontend/notes/mock_data.js
+++ b/spec/frontend/notes/mock_data.js
@@ -1,4 +1,5 @@
// Copied to ee/spec/frontend/notes/mock_data.js
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import { __ } from '~/locale';
export const notesDataMock = {
@@ -655,11 +656,11 @@ export const DISCUSSION_NOTE_RESPONSE_MAP = {
};
export function getIndividualNoteResponse(config) {
- return [200, INDIVIDUAL_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
+ return [HTTP_STATUS_OK, INDIVIDUAL_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
}
export function getDiscussionNoteResponse(config) {
- return [200, DISCUSSION_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
+ return [HTTP_STATUS_OK, DISCUSSION_NOTE_RESPONSE_MAP[config.method.toUpperCase()][config.url]];
}
export const notesWithDescriptionChanges = [
diff --git a/spec/frontend/profile/account/components/update_username_spec.js b/spec/frontend/profile/account/components/update_username_spec.js
index 575df9fb3c0..bb9ae01963e 100644
--- a/spec/frontend/profile/account/components/update_username_spec.js
+++ b/spec/frontend/profile/account/components/update_username_spec.js
@@ -5,7 +5,7 @@ import { nextTick } from 'vue';
import { TEST_HOST } from 'helpers/test_constants';
import { createAlert } from '~/flash';
import axios from '~/lib/utils/axios_utils';
-
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
import UpdateUsername from '~/profile/account/components/update_username.vue';
jest.mock('~/flash');
@@ -97,7 +97,7 @@ describe('UpdateUsername component', () => {
});
it('executes API call on confirmation button click', async () => {
- axiosMock.onPut(actionUrl).replyOnce(() => [200, { message: 'Username changed' }]);
+ axiosMock.onPut(actionUrl).replyOnce(() => [HTTP_STATUS_OK, { message: 'Username changed' }]);
jest.spyOn(axios, 'put');
await wrapper.vm.onConfirm();
@@ -114,7 +114,7 @@ describe('UpdateUsername component', () => {
expect(openModalBtn.props('disabled')).toBe(false);
expect(openModalBtn.props('loading')).toBe(true);
- return [200, { message: 'Username changed' }];
+ return [HTTP_STATUS_OK, { message: 'Username changed' }];
});
await wrapper.vm.onConfirm();
diff --git a/spec/frontend/ref/components/ref_selector_spec.js b/spec/frontend/ref/components/ref_selector_spec.js
index ec14d8bacb2..bfff0c2fedf 100644
--- a/spec/frontend/ref/components/ref_selector_spec.js
+++ b/spec/frontend/ref/components/ref_selector_spec.js
@@ -9,7 +9,11 @@ import commit from 'test_fixtures/api/commits/commit.json';
import branches from 'test_fixtures/api/branches/branches.json';
import tags from 'test_fixtures/api/tags/tags.json';
import { trimText } from 'helpers/text_helper';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_NOT_FOUND } from '~/lib/utils/http_status';
+import {
+ HTTP_STATUS_INTERNAL_SERVER_ERROR,
+ HTTP_STATUS_NOT_FOUND,
+ HTTP_STATUS_OK,
+} from '~/lib/utils/http_status';
import { ENTER_KEY } from '~/lib/utils/keys';
import { sprintf } from '~/locale';
import RefSelector from '~/ref/components/ref_selector.vue';
@@ -69,9 +73,11 @@ describe('Ref selector component', () => {
branchesApiCallSpy = jest
.fn()
- .mockReturnValue([200, fixtures.branches, { [X_TOTAL_HEADER]: '123' }]);
- tagsApiCallSpy = jest.fn().mockReturnValue([200, fixtures.tags, { [X_TOTAL_HEADER]: '456' }]);
- commitApiCallSpy = jest.fn().mockReturnValue([200, fixtures.commit]);
+ .mockReturnValue([HTTP_STATUS_OK, fixtures.branches, { [X_TOTAL_HEADER]: '123' }]);
+ tagsApiCallSpy = jest
+ .fn()
+ .mockReturnValue([HTTP_STATUS_OK, fixtures.tags, { [X_TOTAL_HEADER]: '456' }]);
+ commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, fixtures.commit]);
requestSpies = { branchesApiCallSpy, tagsApiCallSpy, commitApiCallSpy };
mock
@@ -309,8 +315,10 @@ describe('Ref selector component', () => {
describe('when no results are found', () => {
beforeEach(() => {
- branchesApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
- tagsApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ branchesApiCallSpy = jest
+ .fn()
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
+ tagsApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
commitApiCallSpy = jest.fn().mockReturnValue([HTTP_STATUS_NOT_FOUND]);
createComponent();
@@ -386,7 +394,9 @@ describe('Ref selector component', () => {
describe('when the branches search returns no results', () => {
beforeEach(() => {
- branchesApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ branchesApiCallSpy = jest
+ .fn()
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
createComponent();
@@ -451,7 +461,9 @@ describe('Ref selector component', () => {
describe('when the tags search returns no results', () => {
beforeEach(() => {
- tagsApiCallSpy = jest.fn().mockReturnValue([200, [], { [X_TOTAL_HEADER]: '0' }]);
+ tagsApiCallSpy = jest
+ .fn()
+ .mockReturnValue([HTTP_STATUS_OK, [], { [X_TOTAL_HEADER]: '0' }]);
createComponent();
diff --git a/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js b/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
index b62ea542488..13384e1efca 100644
--- a/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
+++ b/spec/frontend/vue_merge_request_widget/extentions/terraform/index_spec.js
@@ -3,7 +3,7 @@ import { mountExtended } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import api from '~/api';
import axios from '~/lib/utils/axios_utils';
-import { HTTP_STATUS_INTERNAL_SERVER_ERROR } from '~/lib/utils/http_status';
+import { HTTP_STATUS_INTERNAL_SERVER_ERROR, HTTP_STATUS_OK } from '~/lib/utils/http_status';
import Poll from '~/lib/utils/poll';
import extensionsContainer from '~/vue_merge_request_widget/components/extensions/container';
import { registerExtension } from '~/vue_merge_request_widget/components/extensions';
@@ -23,7 +23,6 @@ describe('Terraform extension', () => {
let mock;
const endpoint = '/path/to/terraform/report.json';
- const successStatusCode = 200;
const findListItem = (at) => wrapper.findAllByTestId('extension-list-item').at(at);
@@ -57,7 +56,7 @@ describe('Terraform extension', () => {
describe('while loading', () => {
const loadingText = 'Loading Terraform reports...';
it('should render loading text', async () => {
- mockPollingApi(successStatusCode, plans, {});
+ mockPollingApi(HTTP_STATUS_OK, plans, {});
createComponent();
expect(wrapper.text()).toContain(loadingText);
@@ -85,7 +84,7 @@ describe('Terraform extension', () => {
${'1 valid and 2 invalid reports'} | ${{ 0: validPlanWithName, 1: invalidPlanWithName, 2: invalidPlanWithName }} | ${'Terraform report was generated in your pipelines'} | ${'2 Terraform reports failed to generate'}
`('and received $responseType', ({ response, summaryTitle, summarySubtitle }) => {
beforeEach(async () => {
- mockPollingApi(successStatusCode, response, {});
+ mockPollingApi(HTTP_STATUS_OK, response, {});
return createComponent();
});
@@ -102,7 +101,7 @@ describe('Terraform extension', () => {
describe('expanded data', () => {
beforeEach(async () => {
- mockPollingApi(successStatusCode, plans, {});
+ mockPollingApi(HTTP_STATUS_OK, plans, {});
await createComponent();
wrapper.findByTestId('toggle-button').trigger('click');
@@ -164,7 +163,7 @@ describe('Terraform extension', () => {
describe('successful poll', () => {
beforeEach(() => {
- mockPollingApi(successStatusCode, plans, {});
+ mockPollingApi(HTTP_STATUS_OK, plans, {});
return createComponent();
});
diff --git a/spec/frontend_integration/test_helpers/mock_server/routes/emojis.js b/spec/frontend_integration/test_helpers/mock_server/routes/emojis.js
index 64e9006a710..83991ad5af9 100644
--- a/spec/frontend_integration/test_helpers/mock_server/routes/emojis.js
+++ b/spec/frontend_integration/test_helpers/mock_server/routes/emojis.js
@@ -1,9 +1,10 @@
import { Response } from 'miragejs';
import emojis from 'public/-/emojis/2/emojis.json';
import { EMOJI_VERSION } from '~/emoji';
+import { HTTP_STATUS_OK } from '~/lib/utils/http_status';
export default (server) => {
server.get(`/-/emojis/${EMOJI_VERSION}/emojis.json`, () => {
- return new Response(200, {}, emojis);
+ return new Response(HTTP_STATUS_OK, {}, emojis);
});
};
diff --git a/spec/migrations/retry_backfill_traversal_ids_spec.rb b/spec/migrations/retry_backfill_traversal_ids_spec.rb
deleted file mode 100644
index f3658d1b8a3..00000000000
--- a/spec/migrations/retry_backfill_traversal_ids_spec.rb
+++ /dev/null
@@ -1,93 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require_migration!
-
-RSpec.describe RetryBackfillTraversalIds, :migration, feature_category: :subgroups do
- include ReloadHelpers
-
- let!(:namespaces_table) { table(:namespaces) }
-
- context 'when BackfillNamespaceTraversalIdsRoots jobs are pending' do
- before do
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsRoots',
- arguments: [1, 4, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']
- )
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsRoots',
- arguments: [5, 9, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']
- )
- end
-
- it 'queues pending jobs' do
- migrate!
-
- expect(BackgroundMigrationWorker.jobs.length).to eq(1)
- expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['BackfillNamespaceTraversalIdsRoots', [1, 4, 100]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to be_nil
- end
- end
-
- context 'when BackfillNamespaceTraversalIdsChildren jobs are pending' do
- before do
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsChildren',
- arguments: [1, 4, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']
- )
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsRoots',
- arguments: [5, 9, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']
- )
- end
-
- it 'queues pending jobs' do
- migrate!
-
- expect(BackgroundMigrationWorker.jobs.length).to eq(1)
- expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['BackfillNamespaceTraversalIdsChildren', [1, 4, 100]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to be_nil
- end
- end
-
- context 'when BackfillNamespaceTraversalIdsRoots and BackfillNamespaceTraversalIdsChildren jobs are pending' do
- before do
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsRoots',
- arguments: [1, 4, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']
- )
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsChildren',
- arguments: [5, 9, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['pending']
- )
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsRoots',
- arguments: [11, 14, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']
- )
- table(:background_migration_jobs).create!(
- class_name: 'BackfillNamespaceTraversalIdsChildren',
- arguments: [15, 19, 100],
- status: Gitlab::Database::BackgroundMigrationJob.statuses['succeeded']
- )
- end
-
- it 'queues pending jobs' do
- freeze_time do
- migrate!
-
- expect(BackgroundMigrationWorker.jobs.length).to eq(2)
- expect(BackgroundMigrationWorker.jobs[0]['args']).to eq(['BackfillNamespaceTraversalIdsRoots', [1, 4, 100]])
- expect(BackgroundMigrationWorker.jobs[0]['at']).to be_nil
- expect(BackgroundMigrationWorker.jobs[1]['args']).to eq(['BackfillNamespaceTraversalIdsChildren', [5, 9, 100]])
- expect(BackgroundMigrationWorker.jobs[1]['at']).to eq(RetryBackfillTraversalIds::DELAY_INTERVAL.from_now.to_f)
- end
- end
- end
-end
diff --git a/spec/services/clusters/agents/refresh_authorization_service_spec.rb b/spec/services/clusters/agents/refresh_authorization_service_spec.rb
index fa38bc202e7..51c054ddc98 100644
--- a/spec/services/clusters/agents/refresh_authorization_service_spec.rb
+++ b/spec/services/clusters/agents/refresh_authorization_service_spec.rb
@@ -2,17 +2,17 @@
require 'spec_helper'
-RSpec.describe Clusters::Agents::RefreshAuthorizationService do
+RSpec.describe Clusters::Agents::RefreshAuthorizationService, feature_category: :kubernetes_management do
describe '#execute' do
let_it_be(:root_ancestor) { create(:group) }
let_it_be(:removed_group) { create(:group, parent: root_ancestor) }
let_it_be(:modified_group) { create(:group, parent: root_ancestor) }
- let_it_be(:added_group) { create(:group, parent: root_ancestor) }
+ let_it_be(:added_group) { create(:group, path: 'group-path-with-UPPERCASE', parent: root_ancestor) }
let_it_be(:removed_project) { create(:project, namespace: root_ancestor) }
let_it_be(:modified_project) { create(:project, namespace: root_ancestor) }
- let_it_be(:added_project) { create(:project, namespace: root_ancestor) }
+ let_it_be(:added_project) { create(:project, path: 'project-path-with-UPPERCASE', namespace: root_ancestor) }
let(:project) { create(:project, namespace: root_ancestor) }
let(:agent) { create(:cluster_agent, project: project) }
@@ -22,11 +22,13 @@ RSpec.describe Clusters::Agents::RefreshAuthorizationService do
ci_access: {
groups: [
{ id: added_group.full_path, default_namespace: 'default' },
- { id: modified_group.full_path, default_namespace: 'new-namespace' }
+ # Uppercase path verifies case-insensitive matching.
+ { id: modified_group.full_path.upcase, default_namespace: 'new-namespace' }
],
projects: [
{ id: added_project.full_path, default_namespace: 'default' },
- { id: modified_project.full_path, default_namespace: 'new-namespace' }
+ # Uppercase path verifies case-insensitive matching.
+ { id: modified_project.full_path.upcase, default_namespace: 'new-namespace' }
]
}
}.deep_stringify_keys