Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
f098e6d3d2
commit
cce8cf03d3
|
@ -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. 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.
|
||||
|
||||
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
|
||||
|
|
|
@ -0,0 +1,79 @@
|
|||
# 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
|
|||
has_one :pages_metadatum, class_name: 'ProjectPagesMetadatum', 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'
|
||||
|
||||
|
@ -2424,6 +2425,10 @@ class Project < ApplicationRecord
|
|||
environments.where("name LIKE (#{::Gitlab::SQL::Glob.to_like(quoted_scope)})") # rubocop:disable GitlabSecurity/SqlInjection
|
||||
end
|
||||
|
||||
def latest_jira_import
|
||||
jira_imports.last
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def find_service(services, name)
|
||||
|
|
|
@ -30,7 +30,7 @@ You can find these nightly pipelines at `https://gitlab.com/gitlab-org/quality/s
|
|||
#### Using the `package-and-qa` job
|
||||
|
||||
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
|
||||
available for forks).
|
||||
|
||||
|
@ -49,8 +49,8 @@ pipelines.
|
|||
|
||||
```mermaid
|
||||
graph LR
|
||||
A1 -.->|1. Triggers an omnibus-gitlab 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
|
||||
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-mirror pipeline and wait for it to be done| A3
|
||||
|
||||
subgraph "gitlab-foss/gitlab pipeline"
|
||||
A1[`test` stage<br>`package-and-qa` job]
|
||||
|
@ -60,7 +60,7 @@ subgraph "omnibus-gitlab pipeline"
|
|||
A2[`Trigger-docker` stage<br>`Trigger:gitlab-docker` job] -->|once done| B2
|
||||
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
|
||||
end
|
||||
```
|
||||
|
@ -68,7 +68,7 @@ subgraph "gitlab-qa pipeline"
|
|||
1. Developer triggers a manual action, that can be found in CE / EE merge
|
||||
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_.
|
||||
|
||||
1. GitLab packages are being built in the [Omnibus GitLab][omnibus-gitlab]
|
||||
|
@ -76,7 +76,7 @@ subgraph "gitlab-qa pipeline"
|
|||
|
||||
1. When packages are ready, and available in the registry, a final step in the
|
||||
[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
|
||||
against a test environment that has been just orchestrated by the `gitlab-qa`
|
||||
|
@ -86,12 +86,12 @@ subgraph "gitlab-qa pipeline"
|
|||
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)
|
||||
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
|
||||
|
||||
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.
|
||||
|
||||
|
@ -112,7 +112,7 @@ C --> D["Pipeline for merged results"]
|
|||
##### Running custom tests
|
||||
|
||||
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.
|
||||
|
||||
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
|
|||
[the `gitlab-qa` issue tracker][gitlab-qa-issues].
|
||||
|
||||
[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-readme]: https://gitlab.com/gitlab-org/gitlab-qa/tree/master/README.md
|
||||
[review-apps]: ../review_apps.md
|
||||
|
|
|
@ -64,7 +64,7 @@ source projects, GitLab grants access to **Gold** features for all GitLab.com
|
|||
|
||||
#### 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:
|
||||
|
||||
|
@ -255,7 +255,7 @@ Seat Link provides **only** the following information to GitLab:
|
|||
- Historical maximum user 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>
|
||||
<summary>Click here to view example content of a Seat Link POST request.</summary>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Air-gapped GitLab
|
||||
# Offline GitLab
|
||||
|
||||
Computers in an air-gapped network are isolated from the public internet as a security measure.
|
||||
This page lists all the information available for running GitLab in an air-gapped environment.
|
||||
Computers in an offline environment are isolated from the public internet as a security measure. This
|
||||
page lists all the information available for running GitLab in an offline environment.
|
||||
|
||||
## Quick start
|
||||
|
||||
|
@ -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).
|
||||
|
||||
## Loading Docker images onto your air-gapped host
|
||||
## Loading Docker images onto your offline host
|
||||
|
||||
To use many GitLab features, including
|
||||
[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
|
|||
relevant Docker images.
|
||||
|
||||
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.
|
||||
Here's an example of such a transfer:
|
||||
involves downloading the images then packaging and transferring them to the offline host. Here's an
|
||||
example of such a transfer:
|
||||
|
||||
1. Download Docker images from public internet.
|
||||
1. Package Docker images as tar archives.
|
||||
1. Transfer images to air-gapped environment.
|
||||
1. Load transferred images into air-gapped Docker registry.
|
||||
1. Transfer images to offline environment.
|
||||
1. Load transferred images into offline Docker registry.
|
||||
|
||||
### Example image packager script
|
||||
|
||||
|
@ -51,7 +51,7 @@ done
|
|||
|
||||
### 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:
|
||||
|
||||
```sh
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# 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
|
||||
instance entirely offline.
|
||||
|
|
|
@ -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` |
|
||||
| `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` |
|
||||
| `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` |
|
||||
| `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. | "" |
|
||||
|
@ -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).
|
||||
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:
|
||||
|
||||
|
|
|
@ -461,7 +461,7 @@ dast:
|
|||
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`.
|
||||
|
||||
## 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:
|
||||
|
||||
|
|
|
@ -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_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). |
|
||||
| `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_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. |
|
||||
|
|
|
@ -2,15 +2,15 @@
|
|||
type: reference, howto
|
||||
---
|
||||
|
||||
# Offline environment deployments
|
||||
# Offline environments
|
||||
|
||||
It is possible to run most of the GitLab security scanners when not
|
||||
connected to the internet.
|
||||
It's possible to run most of the GitLab security scanners when not 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
|
||||
self-managed installations that are secured, have security policies (for example, firewall policies), or are otherwise restricted from
|
||||
accessing the full internet. GitLab refers to these deployments as _offline environment deployments_.
|
||||
Other common names include:
|
||||
This document describes how to operate Secure Categories (that is, scanner types) in an offline
|
||||
environment. These instructions also apply to self-managed installations that are secured, have
|
||||
security policies (for example, firewall policies), or are otherwise restricted from accessing the
|
||||
full internet. GitLab refers to these environments as _offline environments_. Other common names
|
||||
include:
|
||||
|
||||
- Air-gapped environments
|
||||
- Limited connectivity environments
|
||||
|
@ -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
|
||||
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
|
||||
on a local network, but with no or very restricted access to the internet. Assume anything within
|
||||
the GitLab instance and supporting infrastructure (for example, a private Maven repository) can be
|
||||
accessed through a local network connection. Assume any files from the internet must come in through
|
||||
physical media (USB drive, hard drive, writeable DVD, etc.).
|
||||
In an offline environment, the GitLab instance can be one or more servers and services that can
|
||||
communicate on a local network, but with no or very restricted access to the internet. Assume
|
||||
anything within the GitLab instance and supporting infrastructure (for example, a private Maven
|
||||
repository) can be accessed through a local network connection. Assume any files from the internet
|
||||
must come in through physical media (USB drive, hard drive, writeable DVD, etc.).
|
||||
|
||||
## Overview
|
||||
|
||||
|
@ -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
|
||||
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,
|
||||
you must update each of the scanners to either reference a different,
|
||||
internally-hosted registry or provide access to the individual scanner images.
|
||||
|
@ -55,9 +55,11 @@ mirroring the packages inside your own offline network.
|
|||
|
||||
### 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
|
||||
|
||||
|
@ -73,6 +75,6 @@ hosted within your network.
|
|||
Each individual scanner may be slightly different than the steps described
|
||||
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)
|
||||
- [SAST offline directions](../sast/index.md#gitlab-sast-in-an-offline-environment-deployment)
|
||||
- [DAST offline directions](../dast/index.md#running-dast-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)
|
||||
- [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
|
|||
For more information about the vulnerabilities database update, check the
|
||||
[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
|
||||
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.
|
||||
|
||||
### Requirements for offline SAST
|
||||
|
|
|
@ -93,7 +93,7 @@ A single `git push` is limited to 5GB. LFS is not affected by this limit.
|
|||
## IP range
|
||||
|
||||
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.
|
||||
|
||||
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
|
|||
module Internal
|
||||
class Pages < Grape::API
|
||||
before do
|
||||
not_found! unless Feature.enabled?(:pages_internal_api)
|
||||
authenticate_gitlab_pages_request!
|
||||
end
|
||||
|
||||
|
|
|
@ -3353,6 +3353,9 @@ msgstr ""
|
|||
msgid "Cannot create the abuse report. This user has been blocked."
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot have multiple Jira imports running at the same time"
|
||||
msgstr ""
|
||||
|
||||
msgid "Cannot make epic confidential if it contains not-confidential issues"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
# 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:
|
|||
- requirements
|
||||
- export_jobs
|
||||
- daily_report_results
|
||||
- jira_imports
|
||||
award_emoji:
|
||||
- awardable
|
||||
- user
|
||||
|
|
|
@ -0,0 +1,149 @@
|
|||
# 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
|
|||
it { is_expected.to have_many(:source_pipelines) }
|
||||
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(:jira_imports) }
|
||||
|
||||
it_behaves_like 'model with repository' do
|
||||
let_it_be(:container) { create(:project, :repository, path: 'somewhere') }
|
||||
|
@ -5987,6 +5988,34 @@ describe Project do
|
|||
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)
|
||||
export_job.start
|
||||
export_job.finish
|
||||
|
|
|
@ -14,241 +14,227 @@ describe API::Internal::Pages do
|
|||
get api("/internal/pages"), headers: headers, params: { host: host }
|
||||
end
|
||||
|
||||
context 'feature flag disabled' do
|
||||
before do
|
||||
stub_feature_flags(pages_internal_api: false)
|
||||
end
|
||||
|
||||
it 'responds with 404 Not Found' do
|
||||
context 'not authenticated' do
|
||||
it 'responds with 401 Unauthorized' do
|
||||
query_host('pages.gitlab.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:not_found)
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
end
|
||||
end
|
||||
|
||||
context 'feature flag enabled' do
|
||||
context 'not authenticated' do
|
||||
it 'responds with 401 Unauthorized' do
|
||||
context 'authenticated' do
|
||||
def query_host(host)
|
||||
jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
|
||||
headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
|
||||
|
||||
super(host, headers)
|
||||
end
|
||||
|
||||
def deploy_pages(project)
|
||||
project.mark_pages_as_deployed
|
||||
end
|
||||
|
||||
context 'domain does not exist' do
|
||||
it 'responds with 204 no content' do
|
||||
query_host('pages.gitlab.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:unauthorized)
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
expect(response.body).to be_empty
|
||||
end
|
||||
end
|
||||
|
||||
context 'authenticated' do
|
||||
def query_host(host)
|
||||
jwt_token = JWT.encode({ 'iss' => 'gitlab-pages' }, Gitlab::Pages.secret, 'HS256')
|
||||
headers = { Gitlab::Pages::INTERNAL_API_REQUEST_HEADER => jwt_token }
|
||||
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') }
|
||||
|
||||
super(host, headers)
|
||||
end
|
||||
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
|
||||
|
||||
def deploy_pages(project)
|
||||
project.mark_pages_as_deployed
|
||||
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
|
||||
query_host('pages.gitlab.io')
|
||||
query_host(serverless_domain.uri.host)
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
expect(response.body).to be_empty
|
||||
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
|
||||
|
||||
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
|
||||
context 'with a knative ingress gateway IP' do
|
||||
let!(:serverless_domain_cluster) do
|
||||
create(
|
||||
:serverless_domain_cluster,
|
||||
uuid: 'abcdef12345678',
|
||||
pages_domain: pages_domain,
|
||||
knative: knative_with_ingress
|
||||
)
|
||||
end
|
||||
|
||||
context 'with a knative ingress gateway IP' do
|
||||
let!(:serverless_domain_cluster) do
|
||||
create(
|
||||
:serverless_domain_cluster,
|
||||
uuid: 'abcdef12345678',
|
||||
pages_domain: pages_domain,
|
||||
knative: knative_with_ingress
|
||||
)
|
||||
end
|
||||
let(:serverless_domain) do
|
||||
create(
|
||||
:serverless_domain,
|
||||
serverless_domain_cluster: serverless_domain_cluster,
|
||||
environment: environment
|
||||
)
|
||||
end
|
||||
|
||||
let(:serverless_domain) do
|
||||
create(
|
||||
:serverless_domain,
|
||||
serverless_domain_cluster: serverless_domain_cluster,
|
||||
environment: environment
|
||||
)
|
||||
end
|
||||
it 'responds with proxy configuration' do
|
||||
query_host(serverless_domain.uri.host)
|
||||
|
||||
it 'responds with proxy configuration' do
|
||||
query_host(serverless_domain.uri.host)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/serverless/virtual_domain')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/serverless/virtual_domain')
|
||||
expect(json_response['certificate']).to eq(pages_domain.certificate)
|
||||
expect(json_response['key']).to eq(pages_domain.key)
|
||||
|
||||
expect(json_response['certificate']).to eq(pages_domain.certificate)
|
||||
expect(json_response['key']).to eq(pages_domain.key)
|
||||
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'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
|
||||
}
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'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
|
||||
|
||||
context 'custom domain' do
|
||||
let(:namespace) { create(:namespace, name: 'gitlab-org') }
|
||||
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
|
||||
let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) }
|
||||
|
||||
context 'when there are no pages deployed for the related project' do
|
||||
it 'responds with 204 No Content' do
|
||||
query_host('pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:no_content)
|
||||
end
|
||||
end
|
||||
|
||||
context 'custom domain' do
|
||||
let(:namespace) { create(:namespace, name: 'gitlab-org') }
|
||||
let(:project) { create(:project, namespace: namespace, name: 'gitlab-ce') }
|
||||
let!(:pages_domain) { create(:pages_domain, domain: 'pages.io', project: project) }
|
||||
context 'when there are pages deployed for the related project' do
|
||||
it 'domain lookup is case insensitive' do
|
||||
deploy_pages(project)
|
||||
|
||||
context 'when there are no pages deployed for the related project' 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)
|
||||
end
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
|
||||
context 'when there are pages deployed for the related project' do
|
||||
it 'domain lookup is case insensitive' do
|
||||
deploy_pages(project)
|
||||
it 'responds with the correct domain configuration' do
|
||||
deploy_pages(project)
|
||||
|
||||
query_host('Pages.IO')
|
||||
query_host('pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
end
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
it 'responds with the correct domain configuration' do
|
||||
deploy_pages(project)
|
||||
expect(json_response['certificate']).to eq(pages_domain.certificate)
|
||||
expect(json_response['key']).to eq(pages_domain.key)
|
||||
|
||||
query_host('pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
expect(json_response['certificate']).to eq(pages_domain.certificate)
|
||||
expect(json_response['key']).to eq(pages_domain.key)
|
||||
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'gitlab-org/gitlab-ce/public/'
|
||||
}
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'gitlab-org/gitlab-ce/public/'
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'namespaced domain' do
|
||||
let(:group) { create(:group, name: 'mygroup') }
|
||||
|
||||
before do
|
||||
allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io')
|
||||
allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io")
|
||||
end
|
||||
|
||||
context 'regular project' do
|
||||
it 'responds with the correct domain configuration' do
|
||||
project = create(:project, group: group, name: 'myproject')
|
||||
deploy_pages(project)
|
||||
|
||||
query_host('mygroup.gitlab-pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/myproject/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'mygroup/myproject/public/'
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'namespaced domain' do
|
||||
let(:group) { create(:group, name: 'mygroup') }
|
||||
context 'group root project' do
|
||||
it 'responds with the correct domain configuration' do
|
||||
project = create(:project, group: group, name: 'mygroup.gitlab-pages.io')
|
||||
deploy_pages(project)
|
||||
|
||||
before do
|
||||
allow(Settings.pages).to receive(:host).and_return('gitlab-pages.io')
|
||||
allow(Gitlab.config.pages).to receive(:url).and_return("http://gitlab-pages.io")
|
||||
end
|
||||
query_host('mygroup.gitlab-pages.io')
|
||||
|
||||
context 'regular project' do
|
||||
it 'responds with the correct domain configuration' do
|
||||
project = create(:project, group: group, name: 'myproject')
|
||||
deploy_pages(project)
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
query_host('mygroup.gitlab-pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/myproject/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'mygroup/myproject/public/'
|
||||
}
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'mygroup/mygroup.gitlab-pages.io/public/'
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'group root project' do
|
||||
it 'responds with the correct domain configuration' do
|
||||
project = create(:project, group: group, name: 'mygroup.gitlab-pages.io')
|
||||
deploy_pages(project)
|
||||
|
||||
query_host('mygroup.gitlab-pages.io')
|
||||
|
||||
expect(response).to have_gitlab_http_status(:ok)
|
||||
expect(response).to match_response_schema('internal/pages/virtual_domain')
|
||||
|
||||
expect(json_response['lookup_paths']).to eq(
|
||||
[
|
||||
{
|
||||
'project_id' => project.id,
|
||||
'access_control' => false,
|
||||
'https_only' => false,
|
||||
'prefix' => '/',
|
||||
'source' => {
|
||||
'type' => 'file',
|
||||
'path' => 'mygroup/mygroup.gitlab-pages.io/public/'
|
||||
}
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
}
|
||||
]
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
# 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
|
Loading…
Reference in New Issue