Commit cce8cf03 authored by GitLab Bot's avatar GitLab Bot

Add latest changes from gitlab-org/gitlab@master

parent f098e6d3
...@@ -31,6 +31,15 @@ Attach the screenshot and HTML snapshot of the page from the job's artifacts: ...@@ -31,6 +31,15 @@ Attach the screenshot and HTML snapshot of the page from the job's artifacts:
1. Open the `gitlab-qa-run-2020-*/gitlab-{ce,ee}-qa-*/{,ee}/{api,browser_ui}/<path to failed test>` folder. 1. Open the `gitlab-qa-run-2020-*/gitlab-{ce,ee}-qa-*/{,ee}/{api,browser_ui}/<path to failed test>` folder.
1. Select the `.png` and `.html` files that appears in the job logs (look for `HTML screenshot: /path/to/html/page.html` / `Image screenshot: `/path/to/html/page.png`). 1. Select the `.png` and `.html` files that appears in the job logs (look for `HTML screenshot: /path/to/html/page.html` / `Image screenshot: `/path/to/html/page.png`).
1. Drag and drop them here. 1. Drag and drop them here.
Note: You don't need to include a screenshot if the information it contains can be included as text. Include the text instead.
E.g., error 500/404, "Retry later" errors, etc.
If you include multiple screenshots it can be helpful to hide all but the first in a details/summary element, to avoid excessive scrolling:
<details><summary>Expand for screenshot</summary>
drag and drop the screenshot here
</details>
--> -->
### Possible fixes ### Possible fixes
......
# frozen_string_literal: true
class JiraImportState < ApplicationRecord
include AfterCommitQueue
self.table_name = 'jira_imports'
STATUSES = { initial: 0, scheduled: 1, started: 2, failed: 3, finished: 4 }.freeze
belongs_to :project
belongs_to :user
belongs_to :label
validates :project, presence: true
validates :jira_project_key, presence: true
validates :jira_project_name, presence: true
validates :jira_project_xid, presence: true
validates :project, uniqueness: {
conditions: -> { where.not(status: STATUSES.values_at(:failed, :finished)) },
message: _('Cannot have multiple Jira imports running at the same time')
}
state_machine :status, initial: :initial do
event :schedule do
transition initial: :scheduled
end
event :start do
transition scheduled: :started
end
event :finish do
transition started: :finished
end
event :do_fail do
transition [:initial, :scheduled, :started] => :failed
end
after_transition initial: :scheduled do |state, _|
state.run_after_commit do
job_id = Gitlab::JiraImport::Stage::StartImportWorker.perform_async(project.id)
state.update(jid: job_id) if job_id
end
end
after_transition any => :finished do |state, _|
if state.jid.present?
Gitlab::SidekiqStatus.unset(state.jid)
state.update_column(:jid, nil)
end
end
# Supress warning:
# both JiraImportState and its :status machine have defined a different default for "status".
# although both have same value but represented in 2 ways: integer(0) and symbol(:initial)
def owner_class_attribute_default
'initial'
end
end
enum status: STATUSES
def in_progress?
scheduled? || started?
end
def refresh_jid_expiration
return unless jid
Gitlab::SidekiqStatus.set(jid, StuckImportJobsWorker::IMPORT_JOBS_EXPIRATION)
end
def self.jid_by(project_id:, status:)
select(:jid).with_status(status).find_by(project_id: project_id)
end
end
...@@ -314,6 +314,7 @@ class Project < ApplicationRecord ...@@ -314,6 +314,7 @@ class Project < ApplicationRecord
has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', inverse_of: :project
has_many :import_failures, inverse_of: :project has_many :import_failures, inverse_of: :project
has_many :jira_imports, -> { order 'jira_imports.created_at' }, class_name: 'JiraImportState', inverse_of: :project
has_many :daily_report_results, class_name: 'Ci::DailyReportResult' has_many :daily_report_results, class_name: 'Ci::DailyReportResult'
...@@ -2424,6 +2425,10 @@ class Project < ApplicationRecord ...@@ -2424,6 +2425,10 @@ class Project < ApplicationRecord
environments.where("name LIKE (#{::Gitlab::SQL::Glob.to_like(quoted_scope)})") # rubocop:disable GitlabSecurity/SqlInjection environments.where("name LIKE (#{::Gitlab::SQL::Glob.to_like(quoted_scope)})") # rubocop:disable GitlabSecurity/SqlInjection
end end
def latest_jira_import
jira_imports.last
end
private private
def find_service(services, name) def find_service(services, name)
......
...@@ -30,7 +30,7 @@ You can find these nightly pipelines at `https://gitlab.com/gitlab-org/quality/s ...@@ -30,7 +30,7 @@ You can find these nightly pipelines at `https://gitlab.com/gitlab-org/quality/s
#### Using the `package-and-qa` job #### Using the `package-and-qa` job
It is possible to run end-to-end tests for a merge request, eventually being run in It is possible to run end-to-end tests for a merge request, eventually being run in
a pipeline in the [`gitlab-qa`](https://gitlab.com/gitlab-org/gitlab-qa/) project, a pipeline in the [`gitlab-qa-mirror`](https://gitlab.com/gitlab-org/gitlab-qa-mirror/) project,
by triggering the `package-and-qa` manual action in the `test` stage (not by triggering the `package-and-qa` manual action in the `test` stage (not
available for forks). available for forks).
...@@ -49,8 +49,8 @@ pipelines. ...@@ -49,8 +49,8 @@ pipelines.
```mermaid ```mermaid
graph LR graph LR
A1 -.->|1. Triggers an omnibus-gitlab pipeline and wait for it to be done| A2 A1 -.->|1. Triggers an omnibus-gitlab-mirror pipeline and wait for it to be done| A2
B2[`Trigger-qa` stage<br>`Trigger:qa-test` job] -.->|2. Triggers a gitlab-qa pipeline and wait for it to be done| A3 B2[`Trigger-qa` stage<br>`Trigger:qa-test` job] -.->|2. Triggers a gitlab-qa-mirror pipeline and wait for it to be done| A3
subgraph "gitlab-foss/gitlab pipeline" subgraph "gitlab-foss/gitlab pipeline"
A1[`test` stage<br>`package-and-qa` job] A1[`test` stage<br>`package-and-qa` job]
...@@ -60,7 +60,7 @@ subgraph "omnibus-gitlab pipeline" ...@@ -60,7 +60,7 @@ subgraph "omnibus-gitlab pipeline"
A2[`Trigger-docker` stage<br>`Trigger:gitlab-docker` job] -->|once done| B2 A2[`Trigger-docker` stage<br>`Trigger:gitlab-docker` job] -->|once done| B2
end end
subgraph "gitlab-qa pipeline" subgraph "gitlab-qa-mirror pipeline"
A3>QA jobs run] -.->|3. Reports back the pipeline result to the `package-and-qa` job<br>and post the result on the original commit tested| A1 A3>QA jobs run] -.->|3. Reports back the pipeline result to the `package-and-qa` job<br>and post the result on the original commit tested| A1
end end
``` ```
...@@ -68,7 +68,7 @@ subgraph "gitlab-qa pipeline" ...@@ -68,7 +68,7 @@ subgraph "gitlab-qa pipeline"
1. Developer triggers a manual action, that can be found in CE / EE merge 1. Developer triggers a manual action, that can be found in CE / EE merge
requests. This starts a chain of pipelines in multiple projects. requests. This starts a chain of pipelines in multiple projects.
1. The script being executed triggers a pipeline in [Omnibus GitLab][omnibus-gitlab] 1. The script being executed triggers a pipeline in [Omnibus GitLab Mirror][omnibus-gitlab-mirror]
and waits for the resulting status. We call this a _status attribution_. and waits for the resulting status. We call this a _status attribution_.
1. GitLab packages are being built in the [Omnibus GitLab][omnibus-gitlab] 1. GitLab packages are being built in the [Omnibus GitLab][omnibus-gitlab]
...@@ -76,7 +76,7 @@ subgraph "gitlab-qa pipeline" ...@@ -76,7 +76,7 @@ subgraph "gitlab-qa pipeline"
1. When packages are ready, and available in the registry, a final step in the 1. When packages are ready, and available in the registry, a final step in the
[Omnibus GitLab][omnibus-gitlab] pipeline, triggers a new [Omnibus GitLab][omnibus-gitlab] pipeline, triggers a new
GitLab QA pipeline (those with access can view them at `https://gitlab.com/gitlab-org/gitlab-qa/pipelines`). It also waits for a resulting status. GitLab QA pipeline (those with access can view them at `https://gitlab.com/gitlab-org/gitlab-qa-mirror/pipelines`). It also waits for a resulting status.
1. GitLab QA pulls images from the registry, spins-up containers and runs tests 1. GitLab QA pulls images from the registry, spins-up containers and runs tests
against a test environment that has been just orchestrated by the `gitlab-qa` against a test environment that has been just orchestrated by the `gitlab-qa`
...@@ -86,12 +86,12 @@ subgraph "gitlab-qa pipeline" ...@@ -86,12 +86,12 @@ subgraph "gitlab-qa pipeline"
propagated upstream, through Omnibus, back to the CE / EE merge request. propagated upstream, through Omnibus, back to the CE / EE merge request.
Please note, we plan to [add more specific information](https://gitlab.com/gitlab-org/quality/team-tasks/issues/156) Please note, we plan to [add more specific information](https://gitlab.com/gitlab-org/quality/team-tasks/issues/156)
about the tests included in each job/scenario that runs in `gitlab-qa`. about the tests included in each job/scenario that runs in `gitlab-qa-mirror`.
#### With Pipeline for Merged Results #### With Pipeline for Merged Results
In a Pipeline for Merged Results, the pipeline runs on a new ref that contains the merge result of the source and target branch. In a Pipeline for Merged Results, the pipeline runs on a new ref that contains the merge result of the source and target branch.
However, this ref is not available to the `gitlab-qa` pipeline. However, this ref is not available to the `gitlab-qa-mirror` pipeline.
For this reason, the end-to-end tests on a Pipeline for Merged Results would use the head of the merge request source branch. For this reason, the end-to-end tests on a Pipeline for Merged Results would use the head of the merge request source branch.
...@@ -112,7 +112,7 @@ C --> D["Pipeline for merged results"] ...@@ -112,7 +112,7 @@ C --> D["Pipeline for merged results"]
##### Running custom tests ##### Running custom tests
The [existing scenarios](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md) The [existing scenarios](https://gitlab.com/gitlab-org/gitlab-qa/blob/master/docs/what_tests_can_be_run.md)
that run in the downstream `gitlab-qa` pipeline include many tests, but there are times when you might want to run a that run in the downstream `gitlab-qa-mirror` pipeline include many tests, but there are times when you might want to run a
test or a group of tests that are different than the groups in any of the existing scenarios. test or a group of tests that are different than the groups in any of the existing scenarios.
For example, when we [dequarantine](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#dequarantining-tests) For example, when we [dequarantine](https://about.gitlab.com/handbook/engineering/quality/guidelines/debugging-qa-test-failures/#dequarantining-tests)
...@@ -197,6 +197,7 @@ you can find an issue you would like to work on in ...@@ -197,6 +197,7 @@ you can find an issue you would like to work on in
[the `gitlab-qa` issue tracker][gitlab-qa-issues]. [the `gitlab-qa` issue tracker][gitlab-qa-issues].
[omnibus-gitlab]: https://gitlab.com/gitlab-org/omnibus-gitlab [omnibus-gitlab]: https://gitlab.com/gitlab-org/omnibus-gitlab
[omnibus-gitlab-mirror]: https://gitlab.com/gitlab-org/omnibus-gitlab-mirror
[gitlab-qa]: https://gitlab.com/gitlab-org/gitlab-qa [gitlab-qa]: https://gitlab.com/gitlab-org/gitlab-qa
[gitlab-qa-readme]: https://gitlab.com/gitlab-org/gitlab-qa/tree/master/README.md [gitlab-qa-readme]: https://gitlab.com/gitlab-org/gitlab-qa/tree/master/README.md
[review-apps]: ../review_apps.md [review-apps]: ../review_apps.md
......
...@@ -64,7 +64,7 @@ source projects, GitLab grants access to **Gold** features for all GitLab.com ...@@ -64,7 +64,7 @@ source projects, GitLab grants access to **Gold** features for all GitLab.com
#### Self-managed #### Self-managed
A self-managed subscription uses a hybrid model. You pay for a subscription according to the maximum number of users enabled during the subscription period. For instances that aren't air-gapped or on a closed network, the maximum number of simultaneous users in the self-managed installation is checked each quarter, using [Seat Link](#seat-link). A self-managed subscription uses a hybrid model. You pay for a subscription according to the maximum number of users enabled during the subscription period. For instances that aren't offline or on a closed network, the maximum number of simultaneous users in the self-managed installation is checked each quarter, using [Seat Link](#seat-link).
Every occupied seat, whether by person, job, or bot is counted in the subscription, with the following exceptions: Every occupied seat, whether by person, job, or bot is counted in the subscription, with the following exceptions:
...@@ -255,7 +255,7 @@ Seat Link provides **only** the following information to GitLab: ...@@ -255,7 +255,7 @@ Seat Link provides **only** the following information to GitLab:
- Historical maximum user count - Historical maximum user count
- Active users count - Active users count
For air-gapped or closed network customers, the existing [true-up model](#users-over-license) will be used. Prorated charges are not possible without user count data. For offline or closed network customers, the existing [true-up model](#users-over-license) will be used. Prorated charges are not possible without user count data.
<details> <details>
<summary>Click here to view example content of a Seat Link POST request.</summary> <summary>Click here to view example content of a Seat Link POST request.</summary>
......
# Air-gapped GitLab # Offline GitLab
Computers in an air-gapped network are isolated from the public internet as a security measure. Computers in an offline environment are isolated from the public internet as a security measure. This
This page lists all the information available for running GitLab in an air-gapped environment. page lists all the information available for running GitLab in an offline environment.
## Quick start ## Quick start
...@@ -14,7 +14,7 @@ Follow these best practices to use GitLab's features in an offline environment: ...@@ -14,7 +14,7 @@ Follow these best practices to use GitLab's features in an offline environment:
- [Operating the GitLab Secure scanners in an offline environment](../../user/application_security/offline_deployments/index.md). - [Operating the GitLab Secure scanners in an offline environment](../../user/application_security/offline_deployments/index.md).
## Loading Docker images onto your air-gapped host ## Loading Docker images onto your offline host
To use many GitLab features, including To use many GitLab features, including
[security scans](../../user/application_security/index.md#working-in-an-offline-environment) [security scans](../../user/application_security/index.md#working-in-an-offline-environment)
...@@ -22,13 +22,13 @@ and [Auto Devops](../autodevops/), the GitLab Runner must be able to fetch the ...@@ -22,13 +22,13 @@ and [Auto Devops](../autodevops/), the GitLab Runner must be able to fetch the
relevant Docker images. relevant Docker images.
The process for making these images available without direct access to the public internet The process for making these images available without direct access to the public internet
involves downloading the images then packaging and transferring them to the air-gapped host. involves downloading the images then packaging and transferring them to the offline host. Here's an
Here's an example of such a transfer: example of such a transfer:
1. Download Docker images from public internet. 1. Download Docker images from public internet.
1. Package Docker images as tar archives. 1. Package Docker images as tar archives.
1. Transfer images to air-gapped environment. 1. Transfer images to offline environment.
1. Load transferred images into air-gapped Docker registry. 1. Load transferred images into offline Docker registry.
### Example image packager script ### Example image packager script
...@@ -51,7 +51,7 @@ done ...@@ -51,7 +51,7 @@ done
### Example image loader script ### Example image loader script
This example loads the images from a bastion host to an air-gapped host. In certain configurations, This example loads the images from a bastion host to an offline host. In certain configurations,
physical media may be needed for such a transfer: physical media may be needed for such a transfer:
```sh ```sh
......
# Getting started with an air-gapped GitLab Installation # Getting started with an offline GitLab Installation
This is a step-by-step guide that helps you install, configure, and use a self-managed GitLab This is a step-by-step guide that helps you install, configure, and use a self-managed GitLab
instance entirely offline. instance entirely offline.
......
...@@ -180,7 +180,7 @@ using environment variables. ...@@ -180,7 +180,7 @@ using environment variables.
| `CLAIR_DB_CONNECTION_STRING` | This variable represents the [connection string](https://www.postgresql.org/docs/9.3/libpq-connect.html#AEN39692) to the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) database and **shouldn't be changed** unless you're running the image locally as described in the [Running the standalone Container Scanning Tool](#running-the-standalone-container-scanning-tool) section. The host value for the connection string must match the [alias](https://gitlab.com/gitlab-org/gitlab/-/blob/898c5da43504eba87b749625da50098d345b60d6/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L23) value of the `Container-Scanning.gitlab-ci.yml` template file, which defaults to `clair-vulnerabilities-db`. | `postgresql://postgres:password@clair-vulnerabilities-db:5432/postgres?sslmode=disable&statement_timeout=60000` | | `CLAIR_DB_CONNECTION_STRING` | This variable represents the [connection string](https://www.postgresql.org/docs/9.3/libpq-connect.html#AEN39692) to the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db) database and **shouldn't be changed** unless you're running the image locally as described in the [Running the standalone Container Scanning Tool](#running-the-standalone-container-scanning-tool) section. The host value for the connection string must match the [alias](https://gitlab.com/gitlab-org/gitlab/-/blob/898c5da43504eba87b749625da50098d345b60d6/lib/gitlab/ci/templates/Security/Container-Scanning.gitlab-ci.yml#L23) value of the `Container-Scanning.gitlab-ci.yml` template file, which defaults to `clair-vulnerabilities-db`. | `postgresql://postgres:password@clair-vulnerabilities-db:5432/postgres?sslmode=disable&statement_timeout=60000` |
| `CI_APPLICATION_REPOSITORY` | Docker repository URL for the image to be scanned. | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` | | `CI_APPLICATION_REPOSITORY` | Docker repository URL for the image to be scanned. | `$CI_REGISTRY_IMAGE/$CI_COMMIT_REF_SLUG` |
| `CI_APPLICATION_TAG` | Docker respository tag for the image to be scanned. | `$CI_COMMIT_SHA` | | `CI_APPLICATION_TAG` | Docker respository tag for the image to be scanned. | `$CI_COMMIT_SHA` |
| `CLAIR_DB_IMAGE` | The Docker image name and tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes, or to refer to a locally hosted vulnerabilities database for an on-premise air-gapped installation. | `arminc/clair-db:latest` | | `CLAIR_DB_IMAGE` | The Docker image name and tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes, or to refer to a locally hosted vulnerabilities database for an on-premise offline installation. | `arminc/clair-db:latest` |
| `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` | | `CLAIR_DB_IMAGE_TAG` | (**DEPRECATED - use `CLAIR_DB_IMAGE` instead**) The Docker image tag for the [PostgreSQL server hosting the vulnerabilities definitions](https://hub.docker.com/r/arminc/clair-db). It can be useful to override this value with a specific version, for example, to provide a consistent set of vulnerabilities for integration testing purposes. | `latest` |
| `DOCKERFILE_PATH` | The path to the `Dockerfile` to be used for generating remediations. By default, the scanner will look for a file named `Dockerfile` in the root directory of the project, so this variable should only be configured if your `Dockerfile` is in a non-standard location, such as a subdirectory. See [Solutions for vulnerabilities](#solutions-for-vulnerabilities-auto-remediation) for more details. | `Dockerfile` | | `DOCKERFILE_PATH` | The path to the `Dockerfile` to be used for generating remediations. By default, the scanner will look for a file named `Dockerfile` in the root directory of the project, so this variable should only be configured if your `Dockerfile` is in a non-standard location, such as a subdirectory. See [Solutions for vulnerabilities](#solutions-for-vulnerabilities-auto-remediation) for more details. | `Dockerfile` |
| `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs that you want to trust. | "" | | `ADDITIONAL_CA_CERT_BUNDLE` | Bundle of CA certs that you want to trust. | "" |
...@@ -210,7 +210,7 @@ If you want to whitelist specific vulnerabilities, you'll need to: ...@@ -210,7 +210,7 @@ If you want to whitelist specific vulnerabilities, you'll need to:
in the [whitelist example file](https://github.com/arminc/clair-scanner/blob/v12/example-whitelist.yaml). in the [whitelist example file](https://github.com/arminc/clair-scanner/blob/v12/example-whitelist.yaml).
1. Add the `clair-whitelist.yml` file to the Git repository of your project. 1. Add the `clair-whitelist.yml` file to the Git repository of your project.
### Running Container Scanning in an offline environment deployment ### Running Container Scanning in an offline environment
Container Scanning can be executed on an offline GitLab Ultimate installation by using the following process: Container Scanning can be executed on an offline GitLab Ultimate installation by using the following process:
......
...@@ -461,7 +461,7 @@ dast: ...@@ -461,7 +461,7 @@ dast:
The DAST job does not require the project's repository to be present when running, so by default The DAST job does not require the project's repository to be present when running, so by default
[`GIT_STRATEGY`](../../../ci/yaml/README.md#git-strategy) is set to `none`. [`GIT_STRATEGY`](../../../ci/yaml/README.md#git-strategy) is set to `none`.
## Running DAST in an offline environment deployment ## Running DAST in an offline environment
DAST can be executed on an offline GitLab Ultimate installation by using the following process: DAST can be executed on an offline GitLab Ultimate installation by using the following process:
......
...@@ -167,7 +167,7 @@ The following variables are used for configuring specific analyzers (used for a ...@@ -167,7 +167,7 @@ The following variables are used for configuring specific analyzers (used for a
| `DS_PIP_DEPENDENCY_PATH` | `gemnasium-python` | | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12412) in GitLab 12.2) | | `DS_PIP_DEPENDENCY_PATH` | `gemnasium-python` | | Path to load Python pip dependencies from. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12412) in GitLab 12.2) |
| `DS_PYTHON_VERSION` | `retire.js` | | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12296) in GitLab 12.1)| | `DS_PYTHON_VERSION` | `retire.js` | | Version of Python. If set to 2, dependencies are installed using Python 2.7 instead of Python 3.6. ([Introduced](https://gitlab.com/gitlab-org/gitlab/issues/12296) in GitLab 12.1)|
| `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that will be passed to `maven` by the analyzer. See an example for [using private repos](#using-private-maven-repos). | | `MAVEN_CLI_OPTS` | `gemnasium-maven` | `"-DskipTests --batch-mode"` | List of command line arguments that will be passed to `maven` by the analyzer. See an example for [using private repos](#using-private-maven-repos). |
| `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `false` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline, air-gapped environment.| | `BUNDLER_AUDIT_UPDATE_DISABLED` | `bundler-audit` | `false` | Disable automatic updates for the `bundler-audit` analyzer. Useful if you're running Dependency Scanning in an offline environment. |
| `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. | | `BUNDLER_AUDIT_ADVISORY_DB_URL` | `bundler-audit` | `https://github.com/rubysec/ruby-advisory-db` | URL of the advisory database used by bundler-audit. |
| `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. | | `BUNDLER_AUDIT_ADVISORY_DB_REF_NAME` | `bundler-audit` | `master` | Git ref for the advisory database specified by `BUNDLER_AUDIT_ADVISORY_DB_URL`. |
| `RETIREJS_JS_ADVISORY_DB` | `retire.js` | `https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository.json` | Path or URL to Retire.js js vulnerability data file. | | `RETIREJS_JS_ADVISORY_DB` | `retire.js` | `https://raw.githubusercontent.com/RetireJS/retire.js/master/repository/jsrepository.json` | Path or URL to Retire.js js vulnerability data file. |
......
...@@ -2,15 +2,15 @@ ...@@ -2,15 +2,15 @@
type: reference, howto type: reference, howto
--- ---
# Offline environment deployments # Offline environments
It is possible to run most of the GitLab security scanners when not It's possible to run most of the GitLab security scanners when not connected to the internet.
connected to the internet.
This document describes how to operate Secure Categories (that is, scanner types) in an offline environment. These instructions also apply to This document describes how to operate Secure Categories (that is, scanner types) in an offline
self-managed installations that are secured, have security policies (for example, firewall policies), or are otherwise restricted from environment. These instructions also apply to self-managed installations that are secured, have
accessing the full internet. GitLab refers to these deployments as _offline environment deployments_. security policies (for example, firewall policies), or are otherwise restricted from accessing the
Other common names include: full internet. GitLab refers to these environments as _offline environments_. Other common names
include:
- Air-gapped environments - Air-gapped environments
- Limited connectivity environments - Limited connectivity environments
...@@ -21,13 +21,13 @@ These environments have physical barriers or security policies (for example, fir ...@@ -21,13 +21,13 @@ These environments have physical barriers or security policies (for example, fir
or limit internet access. These instructions are designed for physically disconnected networks, but or limit internet access. These instructions are designed for physically disconnected networks, but
can also be followed in these other use cases. can also be followed in these other use cases.
## Offline environments ## Defining offline environments
In this situation, the GitLab instance can be one or more servers and services that can communicate In an offline environment, the GitLab instance can be one or more servers and services that can
on a local network, but with no or very restricted access to the internet. Assume anything within communicate on a local network, but with no or very restricted access to the internet. Assume
the GitLab instance and supporting infrastructure (for example, a private Maven repository) can be anything within the GitLab instance and supporting infrastructure (for example, a private Maven
accessed through a local network connection. Assume any files from the internet must come in through repository) can be accessed through a local network connection. Assume any files from the internet
physical media (USB drive, hard drive, writeable DVD, etc.). must come in through physical media (USB drive, hard drive, writeable DVD, etc.).
## Overview ## Overview
...@@ -43,7 +43,7 @@ an internet-connected GitLab installation, GitLab checks the GitLab.com-hosted ...@@ -43,7 +43,7 @@ an internet-connected GitLab installation, GitLab checks the GitLab.com-hosted
container registry to check that you have the latest versions of these Docker images container registry to check that you have the latest versions of these Docker images
and possibly connect to package repositories to install necessary dependencies. and possibly connect to package repositories to install necessary dependencies.
In an air-gapped environment, these checks must be disabled so that GitLab.com is not In an offline environment, these checks must be disabled so that GitLab.com isn't
queried. Because the GitLab.com registry and repositories are not available, queried. Because the GitLab.com registry and repositories are not available,
you must update each of the scanners to either reference a different, you must update each of the scanners to either reference a different,
internally-hosted registry or provide access to the individual scanner images. internally-hosted registry or provide access to the individual scanner images.
...@@ -55,9 +55,11 @@ mirroring the packages inside your own offline network. ...@@ -55,9 +55,11 @@ mirroring the packages inside your own offline network.
### Interacting with the vulnerabilities ### Interacting with the vulnerabilities
Once a vulnerability is found, you can interact with it. Read more on how to [interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities). Once a vulnerability is found, you can interact with it. Read more on how to
[interact with the vulnerabilities](../index.md#interacting-with-the-vulnerabilities).
Please note that in some cases the reported vulnerabilities provide metadata that can contain external links exposed in the UI. These links might not be accessible within an air-gapped (or offline) environment. Please note that in some cases the reported vulnerabilities provide metadata that can contain
external links exposed in the UI. These links might not be accessible within an offline environment.
### Scanner signature and rule updates ### Scanner signature and rule updates
...@@ -73,6 +75,6 @@ hosted within your network. ...@@ -73,6 +75,6 @@ hosted within your network.
Each individual scanner may be slightly different than the steps described Each individual scanner may be slightly different than the steps described
above. You can find more info at each of the pages below: above. You can find more info at each of the pages below:
- [Container scanning offline directions](../container_scanning/index.md#running-container-scanning-in-an-offline-environment-deployment) - [Container scanning offline directions](../container_scanning/index.md#running-container-scanning-in-an-offline-environment)
- [SAST offline directions](../sast/index.md#gitlab-sast-in-an-offline-environment-deployment) - [SAST offline directions](../sast/index.md#gitlab-sast-in-an-offline-environment)
- [DAST offline directions](../dast/index.md#running-dast-in-an-offline-environment-deployment) - [DAST offline directions](../dast/index.md#running-dast-in-an-offline-environment)
...@@ -491,10 +491,10 @@ Once a vulnerability is found, you can interact with it. Read more on how to ...@@ -491,10 +491,10 @@ Once a vulnerability is found, you can interact with it. Read more on how to
For more information about the vulnerabilities database update, check the For more information about the vulnerabilities database update, check the
[maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database). [maintenance table](../index.md#maintenance-and-update-of-the-vulnerabilities-database).
## GitLab SAST in an offline environment deployment ## GitLab SAST in an offline environment
For self-managed GitLab instances in an environment with limited, restricted, or intermittent access For self-managed GitLab instances in an environment with limited, restricted, or intermittent access
to external resources via the internet, some adjustments are required for the SAST job to to external resources through the internet, some adjustments are required for the SAST job to
successfully run. successfully run.
### Requirements for offline SAST ### Requirements for offline SAST
......
...@@ -93,7 +93,7 @@ A single `git push` is limited to 5GB. LFS is not affected by this limit. ...@@ -93,7 +93,7 @@ A single `git push` is limited to 5GB. LFS is not affected by this limit.
## IP range ## IP range
GitLab.com is using the IP range `34.74.90.64/28` for traffic from its Web/API GitLab.com is using the IP range `34.74.90.64/28` for traffic from its Web/API
fleet. You can expect connections from webhooks or repository mirroring to come fleet. This whole range is solely allocated to GitLab. You can expect connections from webhooks or repository mirroring to come
from those IPs and whitelist them. from those IPs and whitelist them.
GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com you might need to whitelist CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4) and [IPv6](https://www.cloudflare.com/ips-v6)) GitLab.com is fronted by Cloudflare. For incoming connections to GitLab.com you might need to whitelist CIDR blocks of Cloudflare ([IPv4](https://www.cloudflare.com/ips-v4) and [IPv6](https://www.cloudflare.com/ips-v6))
......
...@@ -5,7 +5,6 @@ module API ...@@ -5,7 +5,6 @@ module API
module Internal module Internal
class Pages < Grape::API class Pages < Grape::API
before do before do
not_found! unless Feature.enabled?(:pages_internal_api)
authenticate_gitlab_pages_request! authenticate_gitlab_pages_request!
end end
......
...@@ -3353,6 +3353,9 @@ msgstr "" ...@@ -3353,6 +3353,9 @@ msgstr ""
msgid "Cannot create the abuse report. This user has been blocked." msgid "Cannot create the abuse report. This user has been blocked."
msgstr "" msgstr ""
msgid "Cannot have multiple Jira imports running at the same time"
msgstr ""
msgid "Cannot make epic confidential if it contains not-confidential issues" msgid "Cannot make epic confidential if it contains not-confidential issues"
msgstr "" msgstr ""
......
# frozen_string_literal: true
FactoryBot.define do
factory :jira_import_state do
project
user { project&.creator }
label
jira_project_name { generate(:name) }
jira_project_key { generate(:name) }
jira_project_xid { 1234 }
end
trait :scheduled do
status { :scheduled }
end
trait :started do
status { :started }
end
trait :failed do
status { :failed }
end
trait :finished do
status { :finished }
end
end
...@@ -476,6 +476,7 @@ project: ...@@ -476,6 +476,7 @@ project:
- requirements - requirements
- export_jobs - export_jobs
- daily_report_results - daily_report_results
- jira_imports
award_emoji: award_emoji:
- awardable - awardable
- user - user
......
# frozen_string_literal: true
require 'spec_helper'
describe JiraImportState do
describe "associations" do
it { is_expected.to belong_to(:project) }
it { is_expected.to belong_to(:user) }
it { is_expected.to belong_to(:label) }
end
describe 'modules' do
subject { described_class }
it { is_expected.to include_module(AfterCommitQueue) }
end
describe 'validations' do
it { is_expected.to validate_presence_of(:project) }
it { is_expected.to validate_presence_of(:jira_project_key) }
it { is_expected.to validate_presence_of(:jira_project_name) }
it { is_expected.to validate_presence_of(:jira_project_xid) }
context 'when trying to run multiple imports' do
let(:project) { create(:project) }
context 'when project has an initial jira_import' do
let!(:jira_import) { create(:jira_import_state, project: project)}
it_behaves_like 'multiple running imports not allowed'
end
context 'when project has a scheduled jira_import' do
let!(:jira_import) { create(:jira_import_state, :scheduled, project: project)}
it_behaves_like 'multiple running imports not allowed'
end
context 'when project has a started jira_import' do
let!(:jira_import) { create(:jira_import_state, :started, project: project)}
it_behaves_like 'multiple running imports not allowed'
end
context 'when project has a failed jira_import' do
let!(:jira_import) { create(:jira_import_state, :failed, project: project)}
it 'returns valid' do
new_import = build(:jira_import_state, project: project)
expect(new_import).to be_valid
expect(new_import.errors[:project]).to be_empty
end
end
context 'when project has a finished jira_import' do
let!(:jira_import) { create(:jira_import_state, :finished, project: project)}
it 'returns valid' do
new_import = build(:jira_import_state, project: project)
expect(new_import).to be_valid
expect(new_import.errors[:project]).to be_empty
end
end
end
end
describe '#in_progress?' do
context 'statuses that return in progress' do
it_behaves_like 'in progress', :scheduled
it_behaves_like 'in progress', :started
end
context 'statuses that return not in progress' do
it_behaves_like 'not in progress', :initial
it_behaves_like 'not in progress', :failed
it_behaves_like 'not in progress', :finished
end
end
describe 'states transition flow' do
let(:project) { create(:project) }
context 'when jira import is in initial state' do
let!(:jira_import) { build(:jira_import_state, project: project)}
it_behaves_like 'can transition', [:schedule, :do_fail]
it_behaves_like 'cannot transition', [:start, :finish]
end
context 'when jira import is in scheduled state' do
let!(:jira_import) { build(:jira_import_state, :scheduled, project: project)}
it_behaves_like 'can transition', [:start, :do_fail]
it_behaves_like 'cannot transition', [:finish]
end
context 'when jira import is in started state' do
let!(:jira_import) { build(:jira_import_state, :started, project: project)}
it_behaves_like 'can transition', [:finish, :do_fail]
it_behaves_like 'cannot transition', [:schedule]
end
context 'when jira import is in failed state' do
let!(:jira_import) { build(:jira_import_state, :failed, project: project)}
it_behaves_like 'cannot transition', [:schedule, :finish, :do_fail]
end
context 'when jira import is in finished state' do
let!(:jira_import) { build(:jira_import_state, :finished, project: project)}
it_behaves_like 'cannot transition', [:schedule, :do_fail, :start]
end
context 'after transition to scheduled' do
let!(:jira_import) { build(:jira_import_state, project: project)}
it 'triggers the import job' do
expect(Gitlab::JiraImport::Stage::StartImportWorker).to receive(:perform_async).and_return('some-job-id')
jira_import.schedule
expect(jira_import.jid).to eq('some-job-id')
end
end
context 'after transition to finished' do
let!(:jira_import) { build(:jira_import_state, :started, jid: 'some-other-jid', project: project)}
it 'triggers the import job' do
jira_import.finish
expect(jira_import.jid).to be_nil
end
it 'triggers the import job' do
jira_import.update!(status: :scheduled)
jira_import.finish
expect(jira_import.status).to eq('scheduled')
expect(jira_import.jid).to eq('some-other-jid')
end
end
end
end
...@@ -110,6 +110,7 @@ describe Project do ...@@ -110,6 +110,7 @@ describe Project do
it { is_expected.to have_many(:source_pipelines) } it { is_expected.to have_many(:source_pipelines) }
it { is_expected.to have_many(:prometheus_alert_events) } it { is_expected.to have_many(:prometheus_alert_events) }
it { is_expected.to have_many(:self_managed_prometheus_alert_events) } it { is_expected.to have_many(:self_managed_prometheus_alert_events) }
it { is_expected.to have_many(:jira_imports) }
it_behaves_like 'model with repository' do it_behaves_like 'model with repository' do
let_it_be(:container) { create(:project, :repository, path: 'somewhere') } let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
...@@ -5987,6 +5988,34 @@ describe Project do ...@@ -5987,6 +5988,34 @@ describe Project do
end end
end end
describe '#latest_jira_import' do
let_it_be(:project) { create(:project) }
context 'when no jira imports' do
it 'returns nil' do
expect(project.latest_jira_import).to be nil
end
end
context 'when single jira import' do
let!(:jira_import1) { create(:jira_import_state, project: project) }
it 'returns the jira import' do
expect(project.latest_jira_import).to eq(jira_import1)
end
end
context 'when multiple jira imports' do
let!(:jira_import1) { create(:jira_import_state, :finished, created_at: 1.day.ago, project: project) }
let!(:jira_import2) { create(:jira_import_state, :failed, created_at: 2.days.ago, project: project) }
let!(:jira_import3) { create(:jira_import_state, :started, created_at: 3.days.ago, project: project) }
it 'returns latest jira import by created_at' do
expect(project.jira_imports.pluck(:id)).to eq([jira_import3.id, jira_import2.id, jira_import1.id])
expect(project.latest_jira_import).to eq(jira_import1)
end
end
end
def finish_job(export_job) def finish_job(export_job)
export_job.start export_job.start
export_job.finish export_job.finish
......
...@@ -14,241 +14,227 @@ describe API::Internal::Pages do ...@@ -14,241 +14,227 @@ describe API::Internal::Pages do
get api("/internal/pages"), headers: headers, params: { host: host } get api("/internal/pages"), headers: headers, params: { host: host }
end end
context 'feature flag disabled' do context 'not authenticated' do
before do it 'responds with 401 Unauthorized' do
stub_feature_flags(pages_internal_api: false)
end
it 'responds with 404 Not Found' do
query_host('pages.gitlab.io') query_host('pages.gitlab.io')
expect(response).to have_gitlab_http_status(:not_found) expect(response).to have_gitlab_http_status(:unauthorized)
end end
end end
context 'feature flag enabled' do context 'authenticated' do
context 'not authenticated' do def query_host(host)
it 'responds with 401 Unauthorized' do jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
query_host('pages.gitlab.io') headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
expect(response).to have_gitlab_http_status(:unauthorized) super(host, headers)
end
end end
context 'authenticated' do def deploy_pages(project)
def query_host(host) project.mark_pages_as_deployed
jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256') end
headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
super(host, headers) context 'domain does not exist' do
end it 'responds with 204 no content' do
query_host('pages.gitlab.io')
def deploy_pages(project) expect(response).to have_gitlab_http_status(:no_content)
project.mark_pages_as_deployed expect(response.body).to be_empty
end end
end
context 'serverless domain' do
let(:namespace) { create(:namespace, name: 'gitlab-org') }
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
let(:environment) { create(:environment, project: project) }
let(:pages_domain) { create(:pages_domain, domain: 'serverless.gitlab.io') }
let(:knative_without_ingress) { create(:clusters_applications_knative) }
let(:knative_with_ingress) { create(:clusters_applications_knative, external_ip: '10.0.0.1') }
context 'without a knative ingress gateway IP' do
let!(:serverless_domain_cluster) do
create(
:serverless_domain_cluster,
uuid: 'abcdef12345678',
pages_domain: pages_domain,
knative: knative_without_ingress
)
end
let(:serverless_domain) do
create(
:serverless_domain,
serverless_domain_cluster: serverless_domain_cluster,
environment: environment
)
end
context 'domain does not exist' do
it 'responds with 204 no content' do it 'responds with 204 no content' do
query_host('pages.gitlab.io') query_host(serverless_domain.uri.host)
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
expect(response.body).to be_empty expect(response.body).to be_empty
end end
end end
context 'serverless domain' do context 'with a knative ingress gateway IP' do
let(:namespace) { create(:namespace, name: 'gitlab-org') } let!(:serverless_domain_cluster) do
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') } create(
let(:environment) { create(:environment, project: project) } :serverless_domain_cluster,
let(:pages_domain) { create(:pages_domain, domain: 'serverless.gitlab.io') } uuid: 'abcdef12345678',
let(:knative_without_ingress) { create(:clusters_applications_knative) } pages_domain: pages_domain,
let(:knative_with_ingress) { create(:clusters_applications_knative, external_ip: '10.0.0.1') } knative: knative_with_ingress
)
context 'without a knative ingress gateway IP' do
let!(:serverless_domain_cluster) do
create(
:serverless_domain_cluster,
uuid: 'abcdef12345678',
pages_domain: pages_domain,
knative: knative_without_ingress
)
end
let(:serverless_domain) do
create(
:serverless_domain,
serverless_domain_cluster: serverless_domain_cluster,
environment: environment
)
end
it 'responds with 204 no content' do
query_host(serverless_domain.uri.host)
expect(response).to have_gitlab_http_status(:no_content)
expect(response.body).to be_empty
end
end end
context 'with a knative ingress gateway IP' do let(:serverless_domain) do
let!(:serverless_domain_cluster) do create(
create( :serverless_domain,
:serverless_domain_cluster, serverless_domain_cluster: serverless_domain_cluster,
uuid: 'abcdef12345678', environment: environment
pages_domain: pages_domain, )
knative: knative_with_ingress end
)
end it 'responds with proxy configuration' do
query_host(serverless_domain.uri.host)
let(:serverless_domain) do
create( expect(response).to have_gitlab_http_status(:ok)
:serverless_domain, expect(response).to match_response_schema('internal/serverless/virtual_domain')
serverless_domain_cluster: serverless_domain_cluster,
environment: environment expect(json_response['certificate']).to eq(pages_domain.certificate)
) expect(json_response['key']).to eq(pages_domain.key)
end
expect(json_response['lookup_paths']).to eq(
it 'responds with proxy configuration' do [
query_host(serverless_domain.uri.host) {
'source' => {
expect(response).to have_gitlab_http_status(:ok) 'type' => 'serverless',
expect(response).to match_response_schema('internal/serverless/virtual_domain') 'service' => "test-function.#{project.name}-#{project.id}-#{environment.slug}.#{serverless_domain_cluster.knative.hostname}",
'cluster' => {
expect(json_response['certificate']).to eq(pages_domain.certificate) 'hostname' => serverless_domain_cluster.knative.hostname,
expect(json_response['key']).to eq(pages_domain.key) 'address' => serverless_domain_cluster.knative.external_ip,
'port' => 443,
expect(json_response['lookup_paths']).to eq( 'cert' => serverless_domain_cluster.certificate,
[ 'key' => serverless_domain_cluster.key
{
'source' => {
'type' => 'serverless',
'service' => "test-function.#{project.name}-#{project.id}-#{environment.slug}.#{serverless_domain_cluster.knative.hostname}",
'cluster' => {
'hostname' => serverless_domain_cluster.knative.hostname,
'address' => serverless_domain_cluster.knative.external_ip,
'port' => 443,
'cert' => serverless_domain_cluster.certificate,
'key' => serverless_domain_cluster.key
}
} }
} }
] }
) ]
end )
end end
end end
end
context 'custom domain' do context 'custom domain' do
let(:namespace) { create(:namespace, name: 'gitlab-org') } let(:namespace) { create(:namespace, name: 'gitlab-org') }
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') } let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) } let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) }
context 'when there are no pages deployed for the related project' do context 'when there are no pages deployed for the related project' do
it 'responds with 204 No Content' do it 'responds with 204 No Content' do
query_host('pages.io') query_host('pages.io')
expect(response).to have_gitlab_http_status(:no_content) expect(response).to have_gitlab_http_status(:no_content)
end
end end
end
context 'when there are pages deployed for the related project' do context 'when there are pages deployed for the related project' do
it 'domain lookup is case insensitive' do it 'domain lookup is case insensitive' do
deploy_pages(project) deploy_pages(project)
query_host('Pages.IO') query_host('Pages.IO')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
end end
it 'responds with the correct domain configuration' do it 'responds with the correct domain configuration' do
deploy_pages(project) deploy_pages(project)
query_host('pages.io') query_host('pages.io')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('internal/pages/virtual_domain') expect(response).to match_response_schema('internal/pages/virtual_domain')
expect(json_response['certificate']).to eq(pages_domain.certificate) expect(json_response['certificate']).to eq(pages_domain.certificate)
expect(json_response['key']).to eq(pages_domain.key) expect(json_response['key']).to eq(pages_domain.key)
expect(json_response['lookup_paths']).to eq( expect(json_response['lookup_paths']).to eq(
[ [
{ {
'project_id' => project.id, 'project_id' => project.id,
'access_control' => false, 'access_control' => false,
'https_only' => false, 'https_only' => false,
'prefix' => '/', 'prefix' => '/',
'source' => { 'source' => {
'type' => 'file', 'type' => 'file',
'path' => 'gitlab-org/gitlab-ce/public/' 'path' => 'gitlab-org/gitlab-ce/public/'
}
} }
] }
) ]
end )
end end
end end
end
context 'namespaced domain' do context 'namespaced domain' do
let(:group) { create(:group, name: 'mygroup') } let(:group) { create(:group, name: 'mygroup') }
before do before do
allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io') allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io')
allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io") allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io")
end end
context 'regular project' do context 'regular project' do
it 'responds with the correct domain configuration' do it 'responds with the correct domain configuration' do
project = create(:project, group: group, name: 'myproject') project = create(:project, group: group, name: 'myproject')
deploy_pages(project) deploy_pages(project)
query_host('mygroup.gitlab-pages.io') query_host('mygroup.gitlab-pages.io')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('internal/pages/virtual_domain') expect(response).to match_response_schema('internal/pages/virtual_domain')
expect(json_response['lookup_paths']).to eq( expect(json_response['lookup_paths']).to eq(
[ [
{ {
'project_id' => project.id, 'project_id' => project.id,
'access_control' => false, 'access_control' => false,
'https_only' => false, 'https_only' => false,
'prefix' => '/myproject/', 'prefix' => '/myproject/',
'source' => { 'source' => {
'type' => 'file', 'type' => 'file',
'path' => 'mygroup/myproject/public/' 'path' => 'mygroup/myproject/public/'
}
} }
] }
) ]
end )
end end
end
context 'group root project' do context 'group root project' do
it 'responds with the correct domain configuration' do it 'responds with the correct domain configuration' do
project = create(:project, group: group, name: 'mygroup.gitlab-pages.io') project = create(:project, group: group, name: 'mygroup.gitlab-pages.io')
deploy_pages(project) deploy_pages(project)
query_host('mygroup.gitlab-pages.io') query_host('mygroup.gitlab-pages.io')
expect(response).to have_gitlab_http_status(:ok) expect(response).to have_gitlab_http_status(:ok)
expect(response).to match_response_schema('internal/pages/virtual_domain') expect(response).to match_response_schema('internal/pages/virtual_domain')
expect(json_response['lookup_paths']).to eq( expect(json_response['lookup_paths']).to eq(
[ [
{ {
'project_id' => project.id, 'project_id' => project.id,
'access_control' => false, 'access_control' => false,
'https_only' => false, 'https_only' => false,
'prefix' => '/', 'prefix' => '/',
'source' => { 'source' => {
'type' => 'file', 'type' => 'file',
'path' => 'mygroup/mygroup.gitlab-pages.io/public/' 'path' => 'mygroup/mygroup.gitlab-pages.io/public/'
}
} }
] }
) ]
end )
end end
end end
end end
......
# frozen_string_literal: true
shared_examples 'multiple running imports not allowed' do
it 'returns not valid' do
new_import = build(:jira_import_state, project: project)
expect(new_import).not_to be_valid
expect(new_import.errors[:project]).not_to be_nil
end
end
shared_examples 'in progress' do |status|
it 'returns true' do
jira_import_state = build(:jira_import_state, status: status)
expect(jira_import_state).to be_in_progress
end
end
shared_examples 'not in progress' do |status|
it 'returns false' do
jira_import_state = build(:jira_import_state, status: status)
expect(jira_import_state).not_to be_in_progress
end
end
shared_examples 'can transition' do |states|
states.each do |state|
it 'returns true' do
expect(jira_import.send(state)).to be true
end
end
end
shared_examples 'cannot transition' do |states|
states.each do |state|
it 'returns false' do
expect(jira_import.send(state)).to be false
end
end
end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment