Add latest changes from gitlab-org/gitlab@master
This commit is contained in:
parent
90156f527b
commit
20bd3b7d4e
|
@ -1 +1 @@
|
|||
6730c101d0be2db5155b6e2c4de689dc906337f4
|
||||
187f550dce577f1fb39503976a30a73a58b2b8e1
|
||||
|
|
|
@ -14,8 +14,6 @@ module Clusters
|
|||
end
|
||||
|
||||
def execute(artifact)
|
||||
return success unless Feature.enabled?(:cluster_applications_artifact, project)
|
||||
|
||||
raise ArgumentError, 'Artifact is not cluster_applications file type' unless artifact&.cluster_applications?
|
||||
|
||||
return error(too_big_error_message, :bad_request) unless artifact.file.size < MAX_ACCEPTABLE_ARTIFACT_SIZE
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
title: Enable state tracking for managed applications installed via the management project
|
||||
merge_request: 38759
|
||||
author:
|
||||
type: added
|
|
@ -2907,6 +2907,56 @@ type DastSiteProfilePermissions {
|
|||
createOnDemandDastScan: Boolean!
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated input type of DastSiteProfileUpdate
|
||||
"""
|
||||
input DastSiteProfileUpdateInput {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""
|
||||
The project the site profile belongs to.
|
||||
"""
|
||||
fullPath: ID!
|
||||
|
||||
"""
|
||||
ID of the site profile to be updated.
|
||||
"""
|
||||
id: DastSiteProfileID!
|
||||
|
||||
"""
|
||||
The name of the site profile.
|
||||
"""
|
||||
profileName: String!
|
||||
|
||||
"""
|
||||
The URL of the target to be scanned.
|
||||
"""
|
||||
targetUrl: String
|
||||
}
|
||||
|
||||
"""
|
||||
Autogenerated return type of DastSiteProfileUpdate
|
||||
"""
|
||||
type DastSiteProfileUpdatePayload {
|
||||
"""
|
||||
A unique identifier for the client performing the mutation.
|
||||
"""
|
||||
clientMutationId: String
|
||||
|
||||
"""
|
||||
Errors encountered during execution of the mutation.
|
||||
"""
|
||||
errors: [String!]!
|
||||
|
||||
"""
|
||||
ID of the site profile.
|
||||
"""
|
||||
id: DastSiteProfileID
|
||||
}
|
||||
|
||||
enum DastSiteProfileValidationStatusEnum {
|
||||
"""
|
||||
Site validation process finished but failed
|
||||
|
@ -9349,6 +9399,7 @@ type Mutation {
|
|||
dastScannerProfileCreate(input: DastScannerProfileCreateInput!): DastScannerProfileCreatePayload
|
||||
dastSiteProfileCreate(input: DastSiteProfileCreateInput!): DastSiteProfileCreatePayload
|
||||
dastSiteProfileDelete(input: DastSiteProfileDeleteInput!): DastSiteProfileDeletePayload
|
||||
dastSiteProfileUpdate(input: DastSiteProfileUpdateInput!): DastSiteProfileUpdatePayload
|
||||
deleteAnnotation(input: DeleteAnnotationInput!): DeleteAnnotationPayload
|
||||
designManagementDelete(input: DesignManagementDeleteInput!): DesignManagementDeletePayload
|
||||
designManagementMove(input: DesignManagementMoveInput!): DesignManagementMovePayload
|
||||
|
|
|
@ -7876,6 +7876,146 @@
|
|||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "DastSiteProfileUpdateInput",
|
||||
"description": "Autogenerated input type of DastSiteProfileUpdate",
|
||||
"fields": null,
|
||||
"inputFields": [
|
||||
{
|
||||
"name": "fullPath",
|
||||
"description": "The project the site profile belongs to.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "ID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"description": "ID of the site profile to be updated.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DastSiteProfileID",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "profileName",
|
||||
"description": "The name of the site profile.",
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "targetUrl",
|
||||
"description": "The URL of the target to be scanned.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
},
|
||||
{
|
||||
"name": "clientMutationId",
|
||||
"description": "A unique identifier for the client performing the mutation.",
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"interfaces": null,
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "OBJECT",
|
||||
"name": "DastSiteProfileUpdatePayload",
|
||||
"description": "Autogenerated return type of DastSiteProfileUpdate",
|
||||
"fields": [
|
||||
{
|
||||
"name": "clientMutationId",
|
||||
"description": "A unique identifier for the client performing the mutation.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "errors",
|
||||
"description": "Errors encountered during execution of the mutation.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "LIST",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "SCALAR",
|
||||
"name": "String",
|
||||
"ofType": null
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "id",
|
||||
"description": "ID of the site profile.",
|
||||
"args": [
|
||||
|
||||
],
|
||||
"type": {
|
||||
"kind": "SCALAR",
|
||||
"name": "DastSiteProfileID",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
}
|
||||
],
|
||||
"inputFields": null,
|
||||
"interfaces": [
|
||||
|
||||
],
|
||||
"enumValues": null,
|
||||
"possibleTypes": null
|
||||
},
|
||||
{
|
||||
"kind": "ENUM",
|
||||
"name": "DastSiteProfileValidationStatusEnum",
|
||||
|
@ -26800,6 +26940,33 @@
|
|||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "dastSiteProfileUpdate",
|
||||
"description": null,
|
||||
"args": [
|
||||
{
|
||||
"name": "input",
|
||||
"description": null,
|
||||
"type": {
|
||||
"kind": "NON_NULL",
|
||||
"name": null,
|
||||
"ofType": {
|
||||
"kind": "INPUT_OBJECT",
|
||||
"name": "DastSiteProfileUpdateInput",
|
||||
"ofType": null
|
||||
}
|
||||
},
|
||||
"defaultValue": null
|
||||
}
|
||||
],
|
||||
"type": {
|
||||
"kind": "OBJECT",
|
||||
"name": "DastSiteProfileUpdatePayload",
|
||||
"ofType": null
|
||||
},
|
||||
"isDeprecated": false,
|
||||
"deprecationReason": null
|
||||
},
|
||||
{
|
||||
"name": "deleteAnnotation",
|
||||
"description": null,
|
||||
|
|
|
@ -487,6 +487,16 @@ Check permissions for the current user on site profile
|
|||
| --- | ---- | ---------- |
|
||||
| `createOnDemandDastScan` | Boolean! | Indicates the user can perform `create_on_demand_dast_scan` on this resource |
|
||||
|
||||
## DastSiteProfileUpdatePayload
|
||||
|
||||
Autogenerated return type of DastSiteProfileUpdate
|
||||
|
||||
| Name | Type | Description |
|
||||
| --- | ---- | ---------- |
|
||||
| `clientMutationId` | String | A unique identifier for the client performing the mutation. |
|
||||
| `errors` | String! => Array | Errors encountered during execution of the mutation. |
|
||||
| `id` | DastSiteProfileID | ID of the site profile. |
|
||||
|
||||
## DeleteAnnotationPayload
|
||||
|
||||
Autogenerated return type of DeleteAnnotation
|
||||
|
|
|
@ -423,7 +423,10 @@ In the following example:
|
|||
|
||||
#### Custom collapsible sections
|
||||
|
||||
You can create collapsible sections in job logs by manually outputting special codes
|
||||
> [Introduced](https://gitlab.com/gitlab-org/gitlab-foss/-/issues/14664) in GitLab 12.0.
|
||||
|
||||
You can create [collapsible sections in job logs](../pipelines/index.md#expand-and-collapse-job-log-sections)
|
||||
by manually outputting special codes
|
||||
that GitLab uses to determine what sections to collapse:
|
||||
|
||||
- Section start marker: `section_start:UNIX_TIMESTAMP:SECTION_NAME\r\e[0K` + `TEXT_OF_SECTION_HEADER`
|
||||
|
|
|
@ -828,6 +828,10 @@ $ tr a-z A-Z << END_TEXT # collapsed multi-line command
|
|||
FOUR FIVE SIX
|
||||
```
|
||||
|
||||
#### Custom collapsible sections
|
||||
|
||||
See [custom collapsible sections](../pipelines/index.md#custom-collapsible-sections).
|
||||
|
||||
### `stage`
|
||||
|
||||
`stage` is defined per-job and relies on [`stages`](#stages) which is defined
|
||||
|
|
|
@ -946,6 +946,11 @@ management project. Refer to the
|
|||
[Cilium chart](https://github.com/cilium/cilium/tree/master/install/kubernetes/cilium)
|
||||
for the available configuration options.
|
||||
|
||||
You can check Cilium's installation status on the cluster management page:
|
||||
|
||||
- [Project-level cluster](../project/clusters/index.md): Navigate to your project's **Operations > Kubernetes** page.
|
||||
- [Group-level cluster](../group/clusters/index.md): Navigate to your group's **Kubernetes** page.
|
||||
|
||||
CAUTION: **Caution:**
|
||||
Installation and removal of the Cilium requires a **manual**
|
||||
[restart](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-gke/#restart-unmanaged-pods)
|
||||
|
|
|
@ -130,6 +130,67 @@ definition they will be able to execute privileged Docker commands on the Runner
|
|||
host. Having proper access control policies mitigates this attack vector by
|
||||
allowing access only to trusted actors.
|
||||
|
||||
### Disabling the code quality job
|
||||
|
||||
The `code_quality` job will not run if the `$CODE_QUALITY_DISABLED` environment
|
||||
variable is present. Please refer to the environment variables [documentation](../../../ci/variables/README.md)
|
||||
to learn more about how to define one.
|
||||
|
||||
To disable the `code_quality` job, add `CODE_QUALITY_DISABLED` as a custom environment
|
||||
variable. This can be done:
|
||||
|
||||
- For the whole project, [in the project settings](../../../ci/variables/README.md#create-a-custom-variable-in-the-ui)
|
||||
or [CI/CD configuration](../../../ci/variables/README.md#create-a-custom-variable-in-the-ui).
|
||||
- For a single pipeline run:
|
||||
|
||||
1. Go to **CI/CD > Pipelines**
|
||||
1. Click **Run Pipeline**
|
||||
1. Add `CODE_QUALITY_DISABLED` as the variable key, with any value.
|
||||
|
||||
### Using with merge request pipelines
|
||||
|
||||
The configuration provided by the Code Quality template does not let the `code_quality` job
|
||||
run on [pipelines for merge requests](../../../ci/merge_request_pipelines/index.md).
|
||||
|
||||
If pipelines for merge requests is enabled, the `code_quality:rules` must be redefined.
|
||||
|
||||
The template has these [`rules`](../../../ci/yaml/README.md#rules) for the `code quality` job:
|
||||
|
||||
```yaml
|
||||
code_quality:
|
||||
rules:
|
||||
- if: '$CODE_QUALITY_DISABLED'
|
||||
when: never
|
||||
- if: '$CI_COMMIT_TAG || $CI_COMMIT_BRANCH'
|
||||
```
|
||||
|
||||
If you are using merge request pipelines, your `rules` (or [`workflow: rules`](../../../ci/yaml/README.md#workflowrules))
|
||||
might look like this example:
|
||||
|
||||
```yaml
|
||||
job1:
|
||||
rules:
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # Run job1 in merge request pipelines
|
||||
- if: '$CI_COMMIT_BRANCH == "master"' # Run job1 in pipelines on the master branch (but not in other branch pipelines)
|
||||
- if: '$CI_COMMIT_TAG' # Run job1 in pipelines for tags
|
||||
```
|
||||
|
||||
To make these work together, you will need to overwrite the code quality `rules`
|
||||
so that they match your current `rules`. From the example above, it could look like:
|
||||
|
||||
```yaml
|
||||
include:
|
||||
- template: Code-Quality.gitlab-ci.yml
|
||||
|
||||
code_quality:
|
||||
rules:
|
||||
- if: '$CODE_QUALITY_DISABLED'
|
||||
when: never
|
||||
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"' # Run code quality job in merge request pipelines
|
||||
- if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' # Run code quality job in pipelines on the master branch (but not in other branch pipelines)
|
||||
- if: '$CI_COMMIT_TAG' # Run code quality job in pipelines for tags
|
||||
```
|
||||
|
||||
## Configuring jobs using variables
|
||||
|
||||
The Code Quality job supports environment variables that users can set to
|
||||
|
|
|
@ -1,9 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
module Gitlab
|
||||
class SidekiqLogger < Gitlab::Logger
|
||||
def self.file_name_noext
|
||||
'sidekiq'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -36,105 +36,89 @@ RSpec.describe Clusters::ParseClusterApplicationsArtifactService do
|
|||
let(:job) { deployment.deployable }
|
||||
let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job) }
|
||||
|
||||
context 'when cluster_applications_artifact feature flag is disabled' do
|
||||
before do
|
||||
stub_feature_flags(cluster_applications_artifact: false)
|
||||
it 'calls Gitlab::Kubernetes::Helm::Parsers::ListV2' do
|
||||
expect(Gitlab::Kubernetes::Helm::Parsers::ListV2).to receive(:new).and_call_original
|
||||
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:success)
|
||||
end
|
||||
|
||||
context 'artifact is not of cluster_applications type' do
|
||||
let(:artifact) { create(:ci_job_artifact, :archive) }
|
||||
let(:job) { artifact.job }
|
||||
|
||||
it 'raise ArgumentError' do
|
||||
expect do
|
||||
described_class.new(job, user).execute(artifact)
|
||||
end.to raise_error(ArgumentError, 'Artifact is not cluster_applications file type')
|
||||
end
|
||||
end
|
||||
|
||||
it 'does not call Gitlab::Kubernetes::Helm::Parsers::ListV2 and returns success immediately' do
|
||||
expect(Gitlab::Kubernetes::Helm::Parsers::ListV2).not_to receive(:new)
|
||||
context 'artifact exceeds acceptable size' do
|
||||
it 'returns an error' do
|
||||
stub_const("#{described_class}::MAX_ACCEPTABLE_ARTIFACT_SIZE", 1.byte)
|
||||
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('Cluster_applications artifact too big. Maximum allowable size: 1 Byte')
|
||||
end
|
||||
end
|
||||
|
||||
context 'job has no deployment' do
|
||||
let(:job) { build(:ci_build) }
|
||||
|
||||
it 'returns an error' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('No deployment found for this job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'job has no deployment cluster' do
|
||||
let(:deployment) { create(:deployment) }
|
||||
let(:job) { deployment.deployable }
|
||||
|
||||
it 'returns an error' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('No deployment cluster found for this job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'blob is empty' do
|
||||
let(:file) { fixture_file_upload(Rails.root.join("spec/fixtures/helm/helm_list_v2_empty_blob.json.gz")) }
|
||||
let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) }
|
||||
|
||||
it 'returns success' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:success)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when cluster_applications_artifact feature flag is enabled for project' do
|
||||
before do
|
||||
stub_feature_flags(cluster_applications_artifact: job.project)
|
||||
end
|
||||
|
||||
it 'calls Gitlab::Kubernetes::Helm::Parsers::ListV2' do
|
||||
expect(Gitlab::Kubernetes::Helm::Parsers::ListV2).to receive(:new).and_call_original
|
||||
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:success)
|
||||
end
|
||||
|
||||
context 'artifact is not of cluster_applications type' do
|
||||
let(:artifact) { create(:ci_job_artifact, :archive) }
|
||||
let(:job) { artifact.job }
|
||||
|
||||
it 'raise ArgumentError' do
|
||||
expect do
|
||||
described_class.new(job, user).execute(artifact)
|
||||
end.to raise_error(ArgumentError, 'Artifact is not cluster_applications file type')
|
||||
end
|
||||
end
|
||||
|
||||
context 'artifact exceeds acceptable size' do
|
||||
it 'returns an error' do
|
||||
stub_const("#{described_class}::MAX_ACCEPTABLE_ARTIFACT_SIZE", 1.byte)
|
||||
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('Cluster_applications artifact too big. Maximum allowable size: 1 Byte')
|
||||
end
|
||||
end
|
||||
|
||||
context 'job has no deployment' do
|
||||
let(:job) { build(:ci_build) }
|
||||
context 'job has deployment cluster' do
|
||||
context 'current user does not have access to deployment cluster' do
|
||||
let(:other_user) { create(:user) }
|
||||
|
||||
it 'returns an error' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('No deployment found for this job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'job has no deployment cluster' do
|
||||
let(:deployment) { create(:deployment) }
|
||||
let(:job) { deployment.deployable }
|
||||
|
||||
it 'returns an error' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
result = described_class.new(job, other_user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('No deployment cluster found for this job')
|
||||
end
|
||||
end
|
||||
|
||||
context 'blob is empty' do
|
||||
let(:file) { fixture_file_upload(Rails.root.join("spec/fixtures/helm/helm_list_v2_empty_blob.json.gz")) }
|
||||
let(:artifact) { create(:ci_job_artifact, :cluster_applications, job: job, file: file) }
|
||||
|
||||
it 'returns success' do
|
||||
result = described_class.new(job, user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:success)
|
||||
end
|
||||
it 'does not affect unpermitted cluster applications' do
|
||||
expect(Clusters::ParseClusterApplicationsArtifactService::RELEASE_NAMES).to contain_exactly('cilium')
|
||||
end
|
||||
|
||||
context 'job has deployment cluster' do
|
||||
context 'current user does not have access to deployment cluster' do
|
||||
let(:other_user) { create(:user) }
|
||||
|
||||
it 'returns an error' do
|
||||
result = described_class.new(job, other_user).execute(artifact)
|
||||
|
||||
expect(result[:status]).to eq(:error)
|
||||
expect(result[:message]).to eq('No deployment cluster found for this job')
|
||||
end
|
||||
end
|
||||
|
||||
Clusters::ParseClusterApplicationsArtifactService::RELEASE_NAMES.each do |release_name|
|
||||
context release_name do
|
||||
include_examples 'parse cluster applications artifact', release_name
|
||||
end
|
||||
Clusters::ParseClusterApplicationsArtifactService::RELEASE_NAMES.each do |release_name|
|
||||
context release_name do
|
||||
include_examples 'parse cluster applications artifact', release_name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue