Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
c608e2662b
commit
ffb0a89712
18
CHANGELOG.md
18
CHANGELOG.md
|
@ -2,6 +2,12 @@
|
|||
documentation](doc/development/changelog.md) for instructions on adding your own
|
||||
entry.
|
||||
|
||||
## 14.0.4 (2021-07-07)
|
||||
|
||||
### Security (1 change)
|
||||
|
||||
- [Disable file and network premailer strategies](gitlab-org/security/gitlab@4af58e3d8ee1b25048f34208db6e685cf0bf1411) ([merge request](gitlab-org/security/gitlab!1544))
|
||||
|
||||
## 14.0.3 (2021-07-06)
|
||||
|
||||
### Fixed (7 changes)
|
||||
|
@ -684,6 +690,12 @@ entry.
|
|||
- [Add missing metrics information](gitlab-org/gitlab@89cd7fe3b95323e635b2d73e08549b2e6153dc4d) ([merge request](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61772/edit))
|
||||
- [Track usage of the resolve UI](gitlab-org/gitlab@35c8e30fce288cecefcf2f7c0077d4608e696519) ([merge request](gitlab-org/gitlab!61654))
|
||||
|
||||
## 13.12.8 (2021-07-07)
|
||||
|
||||
### Security (1 change)
|
||||
|
||||
- [Disable file and network premailer strategies](gitlab-org/security/gitlab@ee69d6d6950bb116cb31523ca805e78af431c25c) ([merge request](gitlab-org/security/gitlab!1545))
|
||||
|
||||
## 13.12.7 (2021-07-05)
|
||||
|
||||
### Fixed (2 changes)
|
||||
|
@ -1357,6 +1369,12 @@ entry.
|
|||
- Change wording for design management upload. !61782
|
||||
|
||||
|
||||
## 13.11.7 (2021-07-07)
|
||||
|
||||
### Security (1 change)
|
||||
|
||||
- [Disable file and network premailer strategies](gitlab-org/security/gitlab@511ed3746b48a26e95c851f76ac6fdcd44c28fd8) ([merge request](gitlab-org/security/gitlab!1546))
|
||||
|
||||
## 13.11.6 (2021-07-01)
|
||||
|
||||
### Added (1 change)
|
||||
|
|
|
@ -1 +1 @@
|
|||
8cc6bb1ffb6830fa416c8d0e32f9edebf6573730
|
||||
ed9300c34897316f98e93d909b964828cb4e5879
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
<script>
|
||||
import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui';
|
||||
import Papa from 'papaparse';
|
||||
|
||||
export default {
|
||||
components: {
|
||||
GlTable,
|
||||
GlAlert,
|
||||
GlLoadingIcon,
|
||||
},
|
||||
props: {
|
||||
csv: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
items: [],
|
||||
errorMessage: null,
|
||||
loading: true,
|
||||
};
|
||||
},
|
||||
mounted() {
|
||||
const parsed = Papa.parse(this.csv, { skipEmptyLines: true });
|
||||
this.items = parsed.data;
|
||||
|
||||
if (parsed.errors.length) {
|
||||
this.errorMessage = parsed.errors.map((e) => e.message).join('. ');
|
||||
}
|
||||
|
||||
this.loading = false;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div class="container-fluid md gl-mt-3 gl-mb-3">
|
||||
<div v-if="loading" class="gl-text-center loading">
|
||||
<gl-loading-icon class="gl-mt-5" size="lg" />
|
||||
</div>
|
||||
<div v-else>
|
||||
<gl-alert v-if="errorMessage" variant="danger" :dismissible="false">
|
||||
{{ errorMessage }}
|
||||
</gl-alert>
|
||||
<gl-table
|
||||
:empty-text="__('No CSV data to display.')"
|
||||
:items="items"
|
||||
:fields="$options.fields"
|
||||
show-empty
|
||||
thead-class="gl-display-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
|
@ -0,0 +1,17 @@
|
|||
import Vue from 'vue';
|
||||
import CsvViewer from './csv_viewer.vue';
|
||||
|
||||
export default () => {
|
||||
const el = document.getElementById('js-csv-viewer');
|
||||
|
||||
return new Vue({
|
||||
el,
|
||||
render(createElement) {
|
||||
return createElement(CsvViewer, {
|
||||
props: {
|
||||
csv: el.dataset.data,
|
||||
},
|
||||
});
|
||||
},
|
||||
});
|
||||
};
|
|
@ -0,0 +1,3 @@
|
|||
import renderCSV from './csv';
|
||||
|
||||
export default renderCSV;
|
|
@ -21,6 +21,8 @@ const loadRichBlobViewer = (type) => {
|
|||
return import(/* webpackChunkName: 'notebook_viewer' */ '../notebook_viewer');
|
||||
case 'openapi':
|
||||
return import(/* webpackChunkName: 'openapi_viewer' */ '../openapi_viewer');
|
||||
case 'csv':
|
||||
return import(/* webpackChunkName: 'csv_viewer' */ '../csv_viewer');
|
||||
case 'pdf':
|
||||
return import(/* webpackChunkName: 'pdf_viewer' */ '../pdf_viewer');
|
||||
case 'sketch':
|
||||
|
|
|
@ -373,8 +373,6 @@ class ProjectsController < Projects::ApplicationController
|
|||
.new(projects, offset: params[:offset].to_i, filter: event_filter)
|
||||
.to_a
|
||||
.map(&:present)
|
||||
|
||||
Events::RenderService.new(current_user).execute(@events, atom_request: request.format.atom?)
|
||||
end
|
||||
# rubocop: enable CodeReuse/ActiveRecord
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ class Blob < SimpleDelegator
|
|||
# type. LFS pointers to `.stl` files are assumed to always be the binary kind,
|
||||
# and use the `BinarySTL` viewer.
|
||||
RICH_VIEWERS = [
|
||||
BlobViewer::CSV,
|
||||
BlobViewer::Markup,
|
||||
BlobViewer::Notebook,
|
||||
BlobViewer::SVG,
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module BlobViewer
|
||||
class CSV < Base
|
||||
include Rich
|
||||
include ClientSide
|
||||
|
||||
self.binary = false
|
||||
self.extensions = %w(csv)
|
||||
self.partial_name = 'csv'
|
||||
self.switcher_icon = 'table'
|
||||
end
|
||||
end
|
|
@ -0,0 +1 @@
|
|||
.file-content#js-csv-viewer{ data: { data: viewer.blob.data } }
|
|
@ -7,5 +7,6 @@ Premailer::Rails.config.merge!(
|
|||
remove_comments: true,
|
||||
remove_ids: false,
|
||||
remove_scripts: false,
|
||||
output_encoding: 'US-ASCII'
|
||||
output_encoding: 'US-ASCII',
|
||||
strategies: [:asset_pipeline]
|
||||
)
|
||||
|
|
|
@ -49,6 +49,7 @@ Rails.autoloaders.each do |autoloader|
|
|||
'ldap_key' => 'LDAPKey',
|
||||
'mr_note' => 'MRNote',
|
||||
'pdf' => 'PDF',
|
||||
'csv' => 'CSV',
|
||||
'rsa_token' => 'RSAToken',
|
||||
'san_extension' => 'SANExtension',
|
||||
'sca' => 'SCA',
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
---
|
||||
stage: Package
|
||||
group: Package
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Helm API
|
||||
|
||||
This is the API documentation for [Helm](../../user/packages/helm_repository/index.md).
|
||||
|
||||
WARNING:
|
||||
This API is used by the Helm-related package clients such as [Helm](https://helm.sh/)
|
||||
and [`helm-push`](https://github.com/chartmuseum/helm-push/#readme),
|
||||
and is generally not meant for manual consumption. This API is under development and is not ready
|
||||
for production use due to limited functionality.
|
||||
|
||||
For instructions on how to upload and install Helm packages from the GitLab
|
||||
Package Registry, see the [Helm registry documentation](../../user/packages/helm_repository/index.md).
|
||||
|
||||
NOTE:
|
||||
These endpoints do not adhere to the standard API authentication methods.
|
||||
See the [Helm registry documentation](../../user/packages/helm_repository/index.md)
|
||||
for details on which headers and token types are supported.
|
||||
|
||||
## Enable the Helm API
|
||||
|
||||
The Helm API for GitLab is behind a feature flag that is disabled by default. GitLab
|
||||
administrators with access to the GitLab Rails console can enable this API for your instance.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:helm_packages)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:helm_packages)
|
||||
```
|
||||
|
||||
## Download a chart index
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/62757) in GitLab 14.1.
|
||||
|
||||
Download a chart index:
|
||||
|
||||
```plaintext
|
||||
GET projects/:id/packages/helm/:channel/index.yaml
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------ | -------- | ----------- |
|
||||
| `id` | string | yes | The ID or full path of the project. |
|
||||
| `channel` | string | yes | Helm repository channel. |
|
||||
|
||||
```shell
|
||||
curl --user <username>:<personal_access_token> \
|
||||
https://gitlab.example.com/api/v4/projects/1/packages/helm/stable/index.yaml
|
||||
```
|
||||
|
||||
Write the output to a file:
|
||||
|
||||
```shell
|
||||
curl --user <username>:<personal_access_token> \
|
||||
https://gitlab.example.com/api/v4/projects/1/packages/helm/stable/index.yaml \
|
||||
--remote-name
|
||||
```
|
||||
|
||||
## Download a chart
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/61014) in GitLab 14.0.
|
||||
|
||||
Download a chart:
|
||||
|
||||
```plaintext
|
||||
GET projects/:id/packages/helm/:channel/charts/:file_name.tgz
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| ----------- | ------ | -------- | ----------- |
|
||||
| `id` | string | yes | The ID or full path of the project. |
|
||||
| `channel` | string | yes | Helm repository channel. |
|
||||
| `file_name` | string | yes | Chart file name. |
|
||||
|
||||
```shell
|
||||
curl --user <username>:<personal_access_token> \
|
||||
https://gitlab.example.com/api/v4/projects/1/packages/helm/stable/charts/mychart.tgz \
|
||||
--remote-name
|
||||
```
|
||||
|
||||
## Upload a chart
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/64814) in GitLab 14.1.
|
||||
|
||||
Upload a chart:
|
||||
|
||||
```plaintext
|
||||
POST projects/:id/packages/helm/api/:channel/charts
|
||||
```
|
||||
|
||||
| Attribute | Type | Required | Description |
|
||||
| --------- | ------ | -------- | ----------- |
|
||||
| `id` | string | yes | The ID or full path of the project. |
|
||||
| `channel` | string | yes | Helm repository channel. |
|
||||
| `chart` | file | yes | Chart (as `multipart/form-data`). |
|
||||
|
||||
```shell
|
||||
curl --request POST \
|
||||
--form 'chart=@mychart.tgz' \
|
||||
--user <username>:<personal_access_token> \
|
||||
https://gitlab.example.com/api/v4/projects/1/packages/helm/api/stable/charts
|
||||
```
|
|
@ -39,6 +39,12 @@ Now when a user tries to push a commit with a message `Bugfix`, their push is
|
|||
declined. Only pushing commits with messages like `Bugfix according to JIRA-123`
|
||||
is accepted.
|
||||
|
||||
The error message includes the rejected commit's SHA.
|
||||
To resolve such errors, commit again with a matching message,
|
||||
[rebase and reword](../topics/git/numerous_undo_possibilities_in_git/index.md#how-to-change-history),
|
||||
or [amend](https://git-scm.com/docs/git-commit#Documentation/git-commit.txt---amend)
|
||||
that commit's message locally.
|
||||
|
||||
### Restrict branch names
|
||||
|
||||
If your company has a strict policy for branch names, you may want the branches to start
|
||||
|
|
|
@ -314,6 +314,19 @@ The version of the chart used to provision PostgreSQL:
|
|||
GitLab encourages users to [migrate their database](upgrading_postgresql.md)
|
||||
to the newer PostgreSQL.
|
||||
|
||||
### Customize values for PostgreSQL Helm Chart
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/cluster-integration/auto-deploy-image/-/issues/113) in auto-deploy-image v2, in GitLab 13.8.
|
||||
|
||||
To set custom values, do one of the following:
|
||||
|
||||
- Add a file named `.gitlab/auto-deploy-postgres-values.yaml` to your repository. If found, this
|
||||
file is used automatically. This file is used by default for PostgreSQL Helm upgrades.
|
||||
- Add a file with a different name or path to the repository, and set the
|
||||
`POSTGRES_HELM_UPGRADE_VALUES_FILE` [environment variable](#database) with the path
|
||||
and name.
|
||||
- Set the `POSTGRES_HELM_UPGRADE_EXTRA_ARGS` [environment variable](#database).
|
||||
|
||||
### Using external PostgreSQL database providers
|
||||
|
||||
While Auto DevOps provides out-of-the-box support for a PostgreSQL container for
|
||||
|
@ -408,6 +421,8 @@ The following table lists CI/CD variables related to the database.
|
|||
| `POSTGRES_PASSWORD` | The PostgreSQL password. Defaults to `testing-password`. Set it to use a custom password. |
|
||||
| `POSTGRES_DB` | The PostgreSQL database name. Defaults to the value of [`$CI_ENVIRONMENT_SLUG`](../../ci/variables/index.md#predefined-cicd-variables). Set it to use a custom database name. |
|
||||
| `POSTGRES_VERSION` | Tag for the [`postgres` Docker image](https://hub.docker.com/_/postgres) to use. Defaults to `9.6.16` for tests and deployments as of GitLab 13.0 (previously `9.6.2`). If `AUTO_DEVOPS_POSTGRES_CHANNEL` is set to `1`, deployments uses the default version `9.6.2`. |
|
||||
| `POSTGRES_HELM_UPGRADE_VALUES_FILE` | In GitLab 13.8 and later, and when using [auto-deploy-image v2](upgrading_auto_deploy_dependencies.md), this variable allows the `helm upgrade` values file for PostgreSQL to be overridden. Defaults to `.gitlab/auto-deploy-postgres-values.yaml`. |
|
||||
| `POSTGRES_HELM_UPGRADE_EXTRA_ARGS` | In GitLab 13.8 and later, and when using [auto-deploy-image v2](upgrading_auto_deploy_dependencies.md), this variable allows extra PostgreSQL options in `helm upgrade` commands when deploying the application. Note that using quotes doesn't prevent word splitting. |
|
||||
|
||||
### Disable jobs
|
||||
|
||||
|
|
|
@ -0,0 +1,80 @@
|
|||
---
|
||||
stage: Package
|
||||
group: Package
|
||||
info: To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#assignments
|
||||
---
|
||||
|
||||
# Helm charts in the Package Registry **(FREE)**
|
||||
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab/-/issues/18997) in GitLab 14.1.
|
||||
|
||||
WARNING:
|
||||
The Helm package registry for GitLab is under development and isn't ready for production use due to
|
||||
limited functionality.
|
||||
|
||||
Publish Helm packages in your project's Package Registry. Then install the
|
||||
packages whenever you need to use them as a dependency.
|
||||
|
||||
For documentation of the specific API endpoints that Helm package manager
|
||||
clients use, see the [Helm API documentation](../../../api/packages/helm.md).
|
||||
|
||||
## Enable the Helm repository feature
|
||||
|
||||
Helm repository support is still a work in progress. It's gated behind a feature flag that's
|
||||
**disabled by default**. [GitLab administrators with access to the GitLab Rails console](../../../administration/feature_flags.md)
|
||||
can opt to enable it.
|
||||
|
||||
To enable it:
|
||||
|
||||
```ruby
|
||||
Feature.enable(:helm_packages)
|
||||
```
|
||||
|
||||
To disable it:
|
||||
|
||||
```ruby
|
||||
Feature.disable(:helm_packages)
|
||||
```
|
||||
|
||||
## Build a Helm package
|
||||
|
||||
Creating a Helm package is documented [in the Helm documentation](https://helm.sh/docs/intro/using_helm/#creating-your-own-charts).
|
||||
|
||||
## Authenticate to the Helm repository
|
||||
|
||||
To authenticate to the Helm repository, you need either:
|
||||
|
||||
- A [personal access token](../../../api/index.md#personalproject-access-tokens).
|
||||
- A [deploy token](../../project/deploy_tokens/index.md).
|
||||
- A [CI/CD job token](../../../api/index.md#gitlab-cicd-job-token).
|
||||
|
||||
## Publish a package
|
||||
|
||||
Once built, a chart can be uploaded to the `stable` channel with `curl` or `helm-push`:
|
||||
|
||||
- With `curl`:
|
||||
|
||||
```shell
|
||||
curl --request POST \
|
||||
--form 'chart=@mychart.tgz' \
|
||||
--user <username>:<personal_access_token> \
|
||||
https://gitlab.example.com/api/v4/projects/1/packages/helm/api/stable/charts
|
||||
```
|
||||
|
||||
- With the [`helm-push`](https://github.com/chartmuseum/helm-push/#readme) plugin:
|
||||
|
||||
```shell
|
||||
helm repo add --username <username> --password <personal_access_token> project-1 https://gitlab.example.com/api/v4/projects/1/packages/helm/stable
|
||||
helm push mychart.tgz project-1
|
||||
```
|
||||
|
||||
## Install a package
|
||||
|
||||
To install the latest version of a chart, use the following command:
|
||||
|
||||
```shell
|
||||
helm repo add project-1 https://gitlab.example.com/api/v4/projects/1/packages/helm/stable
|
||||
helm install my-release project-1/mychart
|
||||
```
|
||||
|
||||
See [Using Helm](https://helm.sh/docs/intro/using_helm/) for more information.
|
|
@ -0,0 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
class Analyzer
|
||||
attr_reader :id, :name, :version, :vendor
|
||||
|
||||
def initialize(id:, name:, version:, vendor:)
|
||||
@id = id
|
||||
@name = name
|
||||
@version = version
|
||||
@vendor = vendor
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
module Concerns
|
||||
module FingerprintPathFromFile
|
||||
extend ActiveSupport::Concern
|
||||
|
||||
def fingerprint_path
|
||||
File.basename(file_path.to_s)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,69 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
class Identifier
|
||||
attr_reader :external_id
|
||||
attr_reader :external_type
|
||||
attr_reader :fingerprint
|
||||
attr_reader :name
|
||||
attr_reader :url
|
||||
|
||||
def initialize(external_id:, external_type:, name:, url: nil)
|
||||
@external_id = external_id
|
||||
@external_type = external_type
|
||||
@name = name
|
||||
@url = url
|
||||
|
||||
@fingerprint = generate_fingerprint
|
||||
end
|
||||
|
||||
def key
|
||||
fingerprint
|
||||
end
|
||||
|
||||
def to_hash
|
||||
%i[
|
||||
external_id
|
||||
external_type
|
||||
fingerprint
|
||||
name
|
||||
url
|
||||
].each_with_object({}) do |key, hash|
|
||||
hash[key] = public_send(key) # rubocop:disable GitlabSecurity/PublicSend
|
||||
end
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
other.external_type == external_type &&
|
||||
other.external_id == external_id
|
||||
end
|
||||
|
||||
def type_identifier?
|
||||
cwe? || wasc?
|
||||
end
|
||||
|
||||
def cve?
|
||||
external_type.to_s.casecmp?('cve')
|
||||
end
|
||||
|
||||
def cwe?
|
||||
external_type.to_s.casecmp?('cwe')
|
||||
end
|
||||
|
||||
def wasc?
|
||||
external_type.to_s.casecmp?('wasc')
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def generate_fingerprint
|
||||
Digest::SHA1.hexdigest("#{external_type}:#{external_id}")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
class Link
|
||||
attr_accessor :name, :url
|
||||
|
||||
def initialize(name: nil, url: nil)
|
||||
@name = name
|
||||
@url = url
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
name: name,
|
||||
url: url
|
||||
}.compact
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,25 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
class ScannedResource
|
||||
include Gitlab::Utils::StrongMemoize
|
||||
|
||||
attr_reader :request_method
|
||||
attr_reader :request_uri
|
||||
|
||||
delegate :scheme, :host, :port, :path, :query, to: :request_uri, prefix: :url
|
||||
|
||||
def initialize(uri, request_method)
|
||||
raise ArgumentError unless uri.is_a?(URI)
|
||||
|
||||
@request_method = request_method
|
||||
@request_uri = uri
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,60 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
module Ci
|
||||
module Reports
|
||||
module Security
|
||||
class Scanner
|
||||
ANALYZER_ORDER = {
|
||||
"bundler_audit" => 1,
|
||||
"retire.js" => 2,
|
||||
"gemnasium" => 3,
|
||||
"gemnasium-maven" => 3,
|
||||
"gemnasium-python" => 3,
|
||||
"bandit" => 1,
|
||||
"semgrep" => 2
|
||||
}.freeze
|
||||
|
||||
attr_accessor :external_id, :name, :vendor, :version
|
||||
|
||||
alias_method :key, :external_id
|
||||
|
||||
def initialize(external_id:, name:, vendor:, version:)
|
||||
@external_id = external_id
|
||||
@name = name
|
||||
@vendor = vendor
|
||||
@version = version
|
||||
end
|
||||
|
||||
def to_hash
|
||||
{
|
||||
external_id: external_id.to_s,
|
||||
name: name.to_s,
|
||||
vendor: vendor.presence
|
||||
}.compact
|
||||
end
|
||||
|
||||
def ==(other)
|
||||
other.external_id == external_id
|
||||
end
|
||||
|
||||
def <=>(other)
|
||||
sort_keys <=> other.sort_keys
|
||||
end
|
||||
|
||||
protected
|
||||
|
||||
def sort_keys
|
||||
@sort_keys ||= [order, external_id, name, vendor]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def order
|
||||
ANALYZER_ORDER.fetch(external_id, Float::INFINITY)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -22029,6 +22029,9 @@ msgstr ""
|
|||
msgid "No %{providerTitle} repositories found"
|
||||
msgstr ""
|
||||
|
||||
msgid "No CSV data to display."
|
||||
msgstr ""
|
||||
|
||||
msgid "No Epic"
|
||||
msgstr ""
|
||||
|
||||
|
|
|
@ -148,6 +148,7 @@
|
|||
"monaco-editor-webpack-plugin": "^4.0.0",
|
||||
"monaco-yaml": "^2.5.1",
|
||||
"mousetrap": "1.6.5",
|
||||
"papaparse": "^5.3.1",
|
||||
"pdfjs-dist": "^2.0.943",
|
||||
"pikaday": "^1.8.0",
|
||||
"popper.js": "^1.16.1",
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :ci_reports_security_identifier, class: '::Gitlab::Ci::Reports::Security::Identifier' do
|
||||
external_id { 'PREDICTABLE_RANDOM' }
|
||||
external_type { 'find_sec_bugs_type' }
|
||||
name { "#{external_type}-#{external_id}" }
|
||||
|
||||
skip_create
|
||||
|
||||
initialize_with do
|
||||
::Gitlab::Ci::Reports::Security::Identifier.new(**attributes)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :ci_reports_security_link, class: '::Gitlab::Ci::Reports::Security::Link' do
|
||||
name { 'CVE-2020-0202' }
|
||||
url { 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0202' }
|
||||
|
||||
skip_create
|
||||
|
||||
initialize_with do
|
||||
::Gitlab::Ci::Reports::Security::Link.new(**attributes)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,29 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
FactoryBot.define do
|
||||
factory :ci_reports_security_scanner, class: '::Gitlab::Ci::Reports::Security::Scanner' do
|
||||
external_id { 'find_sec_bugs' }
|
||||
name { 'Find Security Bugs' }
|
||||
vendor { 'Security Scanner Vendor' }
|
||||
version { '1.0.0' }
|
||||
|
||||
skip_create
|
||||
|
||||
initialize_with do
|
||||
::Gitlab::Ci::Reports::Security::Scanner.new(**attributes)
|
||||
end
|
||||
end
|
||||
|
||||
factory :ci_reports_security_scan, class: '::Gitlab::Ci::Reports::Security::Scan' do
|
||||
status { 'success' }
|
||||
type { 'sast' }
|
||||
start_time { 'placeholder' }
|
||||
end_time { 'placeholder' }
|
||||
|
||||
skip_create
|
||||
|
||||
initialize_with do
|
||||
::Gitlab::Ci::Reports::Security::Scan.new(attributes)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,75 @@
|
|||
import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui';
|
||||
import { getAllByRole } from '@testing-library/dom';
|
||||
import { shallowMount, mount } from '@vue/test-utils';
|
||||
import { nextTick } from 'vue';
|
||||
import CSVViewer from '~/blob/csv/csv_viewer.vue';
|
||||
|
||||
const validCsv = 'one,two,three';
|
||||
const brokenCsv = '{\n "json": 1,\n "key": [1, 2, 3]\n}';
|
||||
|
||||
describe('app/assets/javascripts/blob/csv/csv_viewer.vue', () => {
|
||||
let wrapper;
|
||||
|
||||
const createComponent = ({ csv = validCsv, mountFunction = shallowMount } = {}) => {
|
||||
wrapper = mountFunction(CSVViewer, {
|
||||
propsData: {
|
||||
csv,
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const findCsvTable = () => wrapper.findComponent(GlTable);
|
||||
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
|
||||
const findAlert = () => wrapper.findComponent(GlAlert);
|
||||
|
||||
afterEach(() => {
|
||||
wrapper.destroy();
|
||||
});
|
||||
|
||||
it('should render loading spinner', () => {
|
||||
createComponent();
|
||||
|
||||
expect(findLoadingIcon().props()).toMatchObject({
|
||||
size: 'lg',
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the CSV contains errors', () => {
|
||||
it('should render alert', async () => {
|
||||
createComponent({ csv: brokenCsv });
|
||||
await nextTick;
|
||||
|
||||
expect(findAlert().props()).toMatchObject({
|
||||
variant: 'danger',
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when the CSV contains no errors', () => {
|
||||
it('should not render alert', async () => {
|
||||
createComponent();
|
||||
await nextTick;
|
||||
|
||||
expect(findAlert().exists()).toBe(false);
|
||||
});
|
||||
|
||||
it('renders the CSV table with the correct attributes', async () => {
|
||||
createComponent();
|
||||
await nextTick;
|
||||
|
||||
expect(findCsvTable().attributes()).toMatchObject({
|
||||
'empty-text': 'No CSV data to display.',
|
||||
items: validCsv,
|
||||
});
|
||||
});
|
||||
|
||||
it('renders the CSV table with the correct content', async () => {
|
||||
createComponent({ mountFunction: mount });
|
||||
await nextTick;
|
||||
|
||||
expect(getAllByRole(wrapper.element, 'row', { name: /One/i })).toHaveLength(1);
|
||||
expect(getAllByRole(wrapper.element, 'row', { name: /Two/i })).toHaveLength(1);
|
||||
expect(getAllByRole(wrapper.element, 'row', { name: /Three/i })).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,125 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Reports::Security::Identifier do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
describe '#initialize' do
|
||||
subject { described_class.new(**params) }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
external_type: 'brakeman_warning_code',
|
||||
external_id: '107',
|
||||
name: 'Brakeman Warning Code 107',
|
||||
url: 'https://brakemanscanner.org/docs/warning_types/cross_site_scripting/'
|
||||
}
|
||||
end
|
||||
|
||||
context 'when all params are given' do
|
||||
it 'initializes an instance' do
|
||||
expect { subject }.not_to raise_error
|
||||
|
||||
expect(subject).to have_attributes(
|
||||
external_type: 'brakeman_warning_code',
|
||||
external_id: '107',
|
||||
fingerprint: 'aa2254904a69148ad14b6ac5db25b355da9c987f',
|
||||
name: 'Brakeman Warning Code 107',
|
||||
url: 'https://brakemanscanner.org/docs/warning_types/cross_site_scripting/'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
%i[external_type external_id name].each do |attribute|
|
||||
context "when attribute #{attribute} is missing" do
|
||||
before do
|
||||
params.delete(attribute)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#key' do
|
||||
let(:identifier) { create(:ci_reports_security_identifier) }
|
||||
|
||||
subject { identifier.key }
|
||||
|
||||
it 'returns fingerprint' do
|
||||
is_expected.to eq(identifier.fingerprint)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#type_identifier?' do
|
||||
where(:external_type, :expected_result) do
|
||||
'cve' | false
|
||||
'foo' | false
|
||||
'cwe' | true
|
||||
'wasc' | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:identifier) { create(:ci_reports_security_identifier, external_type: external_type) }
|
||||
|
||||
subject { identifier.type_identifier? }
|
||||
|
||||
it { is_expected.to be(expected_result) }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'external type check methods' do
|
||||
where(:external_type, :is_cve?, :is_cwe?, :is_wasc?) do
|
||||
'Foo' | false | false | false
|
||||
'Cve' | true | false | false
|
||||
'Cwe' | false | true | false
|
||||
'Wasc' | false | false | true
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:identifier) { create(:ci_reports_security_identifier, external_type: external_type) }
|
||||
|
||||
it 'returns correct result for the type check method' do
|
||||
expect(identifier.cve?).to be(is_cve?)
|
||||
expect(identifier.cwe?).to be(is_cwe?)
|
||||
expect(identifier.wasc?).to be(is_wasc?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_hash' do
|
||||
let(:identifier) { create(:ci_reports_security_identifier) }
|
||||
|
||||
subject { identifier.to_hash }
|
||||
|
||||
it 'returns expected hash' do
|
||||
is_expected.to eq({
|
||||
external_type: identifier.external_type,
|
||||
external_id: identifier.external_id,
|
||||
fingerprint: identifier.fingerprint,
|
||||
name: identifier.name,
|
||||
url: identifier.url
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
where(:type_1, :id_1, :type_2, :id_2, :equal, :case_name) do
|
||||
'CVE' | '2018-1234' | 'CVE' | '2018-1234' | true | 'when external_type and external_id are equal'
|
||||
'CVE' | '2018-1234' | 'brakeman_code' | '2018-1234' | false | 'when external_type is different'
|
||||
'CVE' | '2018-1234' | 'CVE' | '2019-6789' | false | 'when external_id is different'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:identifier_1) { create(:ci_reports_security_identifier, external_type: type_1, external_id: id_1) }
|
||||
let(:identifier_2) { create(:ci_reports_security_identifier, external_type: type_2, external_id: id_2) }
|
||||
|
||||
it "returns #{params[:equal]}" do
|
||||
expect(identifier_1 == identifier_2).to eq(equal)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,31 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Reports::Security::Link do
|
||||
subject(:security_link) { described_class.new(name: 'CVE-2020-0202', url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0202') }
|
||||
|
||||
describe '#initialize' do
|
||||
context 'when all params are given' do
|
||||
it 'initializes an instance' do
|
||||
expect { subject }.not_to raise_error
|
||||
|
||||
expect(subject).to have_attributes(
|
||||
name: 'CVE-2020-0202',
|
||||
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0202'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_hash' do
|
||||
it 'returns expected hash' do
|
||||
expect(security_link.to_hash).to eq(
|
||||
{
|
||||
name: 'CVE-2020-0202',
|
||||
url: 'https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-0202'
|
||||
}
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,30 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Reports::Security::ScannedResource do
|
||||
let(:url) { 'http://example.com:3001/1?foo=bar' }
|
||||
let(:request_method) { 'GET' }
|
||||
|
||||
context 'when the URI is not a URI' do
|
||||
subject { ::Gitlab::Ci::Reports::Security::ScannedResource.new(url, request_method) }
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the URL is valid' do
|
||||
subject { ::Gitlab::Ci::Reports::Security::ScannedResource.new(URI.parse(url), request_method) }
|
||||
|
||||
it 'sets the URL attributes' do
|
||||
expect(subject.request_method).to eq(request_method)
|
||||
expect(subject.request_uri.to_s).to eq(url)
|
||||
expect(subject.url_scheme).to eq('http')
|
||||
expect(subject.url_host).to eq('example.com')
|
||||
expect(subject.url_port).to eq(3001)
|
||||
expect(subject.url_path).to eq('/1')
|
||||
expect(subject.url_query).to eq('foo=bar')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,145 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require 'spec_helper'
|
||||
|
||||
RSpec.describe Gitlab::Ci::Reports::Security::Scanner do
|
||||
describe '#initialize' do
|
||||
subject { described_class.new(**params) }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
external_id: 'brakeman',
|
||||
name: 'Brakeman',
|
||||
vendor: 'GitLab',
|
||||
version: '1.0.1'
|
||||
}
|
||||
end
|
||||
|
||||
context 'when all params are given' do
|
||||
it 'initializes an instance' do
|
||||
expect { subject }.not_to raise_error
|
||||
|
||||
expect(subject).to have_attributes(
|
||||
external_id: 'brakeman',
|
||||
name: 'Brakeman',
|
||||
vendor: 'GitLab'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
%i[external_id name].each do |attribute|
|
||||
context "when attribute #{attribute} is missing" do
|
||||
before do
|
||||
params.delete(attribute)
|
||||
end
|
||||
|
||||
it 'raises an error' do
|
||||
expect { subject }.to raise_error(ArgumentError)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#key' do
|
||||
let(:scanner) { create(:ci_reports_security_scanner) }
|
||||
|
||||
subject { scanner.key }
|
||||
|
||||
it 'returns external_id' do
|
||||
is_expected.to eq(scanner.external_id)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#to_hash' do
|
||||
let(:scanner) { create(:ci_reports_security_scanner) }
|
||||
|
||||
subject { scanner.to_hash }
|
||||
|
||||
it 'returns expected hash' do
|
||||
is_expected.to eq({
|
||||
external_id: scanner.external_id,
|
||||
name: scanner.name,
|
||||
vendor: scanner.vendor
|
||||
})
|
||||
end
|
||||
|
||||
context 'when vendor is not defined' do
|
||||
let(:scanner) { create(:ci_reports_security_scanner, vendor: nil) }
|
||||
|
||||
it 'returns expected hash' do
|
||||
is_expected.to eq({
|
||||
external_id: scanner.external_id,
|
||||
name: scanner.name
|
||||
})
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#==' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
where(:id_1, :id_2, :equal, :case_name) do
|
||||
'brakeman' | 'brakeman' | true | 'when external_id is equal'
|
||||
'brakeman' | 'bandit' | false | 'when external_id is different'
|
||||
end
|
||||
|
||||
with_them do
|
||||
let(:scanner_1) { create(:ci_reports_security_scanner, external_id: id_1) }
|
||||
let(:scanner_2) { create(:ci_reports_security_scanner, external_id: id_2) }
|
||||
|
||||
it "returns #{params[:equal]}" do
|
||||
expect(scanner_1 == scanner_2).to eq(equal)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#<=>' do
|
||||
using RSpec::Parameterized::TableSyntax
|
||||
|
||||
let(:scanner_1) { create(:ci_reports_security_scanner, **scanner_1_attributes) }
|
||||
let(:scanner_2) { create(:ci_reports_security_scanner, **scanner_2_attributes) }
|
||||
|
||||
subject { scanner_1 <=> scanner_2 }
|
||||
|
||||
context 'when the `external_id` of the scanners are different' do
|
||||
where(:scanner_1_attributes, :scanner_2_attributes, :expected_comparison_result) do
|
||||
{ external_id: 'bundler_audit', name: 'foo', vendor: 'bar' } | { external_id: 'retire.js', name: 'foo', vendor: 'bar' } | -1
|
||||
{ external_id: 'retire.js', name: 'foo', vendor: 'bar' } | { external_id: 'gemnasium', name: 'foo', vendor: 'bar' } | -1
|
||||
{ external_id: 'gemnasium', name: 'foo', vendor: 'bar' } | { external_id: 'gemnasium-maven', name: 'foo', vendor: 'bar' } | -1
|
||||
{ external_id: 'gemnasium-maven', name: 'foo', vendor: 'bar' } | { external_id: 'gemnasium-python', name: 'foo', vendor: 'bar' } | -1
|
||||
{ external_id: 'gemnasium-python', name: 'foo', vendor: 'bar' } | { external_id: 'bandit', name: 'foo', vendor: 'bar' } | 1
|
||||
{ external_id: 'bandit', name: 'foo', vendor: 'bar' } | { external_id: 'semgrep', name: 'foo', vendor: 'bar' } | -1
|
||||
{ external_id: 'semgrep', name: 'foo', vendor: 'bar' } | { external_id: 'unknown', name: 'foo', vendor: 'bar' } | -1
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { is_expected.to eq(expected_comparison_result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the `external_id` of the scanners are equal' do
|
||||
context 'when the `name` of the scanners are different' do
|
||||
where(:scanner_1_attributes, :scanner_2_attributes, :expected_comparison_result) do
|
||||
{ external_id: 'gemnasium', name: 'a', vendor: 'bar' } | { external_id: 'gemnasium', name: 'b', vendor: 'bar' } | -1
|
||||
{ external_id: 'gemnasium', name: 'd', vendor: 'bar' } | { external_id: 'gemnasium', name: 'c', vendor: 'bar' } | 1
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { is_expected.to eq(expected_comparison_result) }
|
||||
end
|
||||
end
|
||||
|
||||
context 'when the `name` of the scanners are equal' do
|
||||
where(:scanner_1_attributes, :scanner_2_attributes, :expected_comparison_result) do
|
||||
{ external_id: 'gemnasium', name: 'foo', vendor: 'a' } | { external_id: 'gemnasium', name: 'foo', vendor: 'a' } | 0 # rubocop:disable Lint/BinaryOperatorWithIdenticalOperands
|
||||
{ external_id: 'gemnasium', name: 'foo', vendor: 'a' } | { external_id: 'gemnasium', name: 'foo', vendor: 'b' } | -1
|
||||
{ external_id: 'gemnasium', name: 'foo', vendor: 'b' } | { external_id: 'gemnasium', name: 'foo', vendor: 'a' } | 1
|
||||
end
|
||||
|
||||
with_them do
|
||||
it { is_expected.to eq(expected_comparison_result) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -9154,6 +9154,11 @@ pako@~1.0.2, pako@~1.0.5:
|
|||
resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.6.tgz#0101211baa70c4bca4a0f63f2206e97b7dfaf258"
|
||||
integrity sha512-lQe48YPsMJAig+yngZ87Lus+NF+3mtu7DVOBu6b/gHO1YpKwIj5AWjZ/TOS7i46HD/UixzWb1zeWDZfGZ3iYcg==
|
||||
|
||||
papaparse@^5.3.1:
|
||||
version "5.3.1"
|
||||
resolved "https://registry.yarnpkg.com/papaparse/-/papaparse-5.3.1.tgz#770b7a9124d821d4b2132132b7bd7dce7194b5b1"
|
||||
integrity sha512-Dbt2yjLJrCwH2sRqKFFJaN5XgIASO9YOFeFP8rIBRG2Ain8mqk5r1M6DkfvqEVozVcz3r3HaUGw253hA1nLIcA==
|
||||
|
||||
parallel-transform@^1.1.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
|
||||
|
|
Loading…
Reference in New Issue