diff --git a/.gitlab/ci/docs.gitlab-ci.yml b/.gitlab/ci/docs.gitlab-ci.yml index 559d0749c96..eedfea994c4 100644 --- a/.gitlab/ci/docs.gitlab-ci.yml +++ b/.gitlab/ci/docs.gitlab-ci.yml @@ -71,6 +71,7 @@ ui-docs-links lint: extends: - .docs:rules:docs-lint - .static-analysis-base + - .ruby-cache stage: lint needs: [] script: diff --git a/.rubocop_manual_todo.yml b/.rubocop_manual_todo.yml index 9aa9aadd8c0..ae55f771fa4 100644 --- a/.rubocop_manual_todo.yml +++ b/.rubocop_manual_todo.yml @@ -2558,7 +2558,6 @@ Rails/IncludeUrlHelper: # TODO issue: https://gitlab.com/gitlab-org/gitlab/-/issues/344279 Style/OpenStructUse: Exclude: - - 'Guardfile' - 'app/finders/snippets_finder.rb' - 'app/helpers/application_settings_helper.rb' - 'ee/lib/gitlab/graphql/aggregations/epics/epic_node.rb' diff --git a/CHANGELOG.md b/CHANGELOG.md index 52d66b1ab22..6c670421d88 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3066,18 +3066,18 @@ No changes. ## 13.12.15 (2021-11-03) -No changes. - -## 13.12.14 (2021-11-03) - ### Fixed (2 changes) - [Allow nil for remaining ci cd settings](gitlab-org/gitlab@896fd7ecf23714fa9f710efa4af245a26c677dce) ([merge request](gitlab-org/gitlab!73522)) - [Allow nil on delegated CI/CD settings](gitlab-org/gitlab@d57a9ea79080fc473eb54c0ee696a50fd270e8a4) ([merge request](gitlab-org/gitlab!73522)) +## 13.12.14 (2021-11-03) + +This version has been skipped due to QA problems. + ## 13.12.13 (2021-10-29) -No changes. +This version has been skipped due to QA problems. ## 13.12.12 (2021-09-21) diff --git a/Guardfile b/Guardfile index 1d9ec406c1d..66a689ed978 100644 --- a/Guardfile +++ b/Guardfile @@ -9,7 +9,7 @@ cmd = ENV['GUARD_CMD'] || (ENV['SPRING'] ? 'spring rspec' : 'bundle exec rspec') directories %w(app ee lib rubocop tooling spec) rspec_context_for = proc do |context_path| - OpenStruct.new(to_s: "spec").tap do |rspec| + OpenStruct.new(to_s: "spec").tap do |rspec| # rubocop:disable Style/OpenStructUse rspec.spec_dir = "#{context_path}spec" rspec.spec = ->(m) { Guard::RSpec::Dsl.detect_spec_file_for(rspec, m) } rspec.spec_helper = "#{rspec.spec_dir}/spec_helper.rb" @@ -19,7 +19,7 @@ rspec_context_for = proc do |context_path| end rails_context_for = proc do |context_path, exts| - OpenStruct.new.tap do |rails| + OpenStruct.new.tap do |rails| # rubocop:disable Style/OpenStructUse rails.app_files = %r{^#{context_path}app/(.+)\.rb$} rails.views = %r{^#{context_path}app/(views/.+/[^/]*\.(?:#{exts}))$} diff --git a/app/graphql/types/evidence_type.rb b/app/graphql/types/evidence_type.rb index 26fb64d25d8..33f46c712f1 100644 --- a/app/graphql/types/evidence_type.rb +++ b/app/graphql/types/evidence_type.rb @@ -5,7 +5,7 @@ module Types graphql_name 'ReleaseEvidence' description 'Evidence for a release' - authorize :download_code + authorize :read_release_evidence present_using Releases::EvidencePresenter diff --git a/app/graphql/types/packages/file_metadata_type.rb b/app/graphql/types/packages/file_metadata_type.rb index 46ccb424218..0731fc897a2 100644 --- a/app/graphql/types/packages/file_metadata_type.rb +++ b/app/graphql/types/packages/file_metadata_type.rb @@ -14,6 +14,8 @@ module Types case object when ::Packages::Conan::FileMetadatum ::Types::Packages::Conan::FileMetadatumType + when ::Packages::Helm::FileMetadatum + ::Types::Packages::Helm::FileMetadatumType else # NOTE: This method must be kept in sync with `PackageFileType#file_metadata`, # which must never produce data that this discriminator cannot handle. @@ -21,7 +23,8 @@ module Types end end - orphan_types Types::Packages::Conan::FileMetadatumType + orphan_types Types::Packages::Conan::FileMetadatumType, + Types::Packages::Helm::FileMetadatumType end end end diff --git a/app/graphql/types/packages/helm/dependency_type.rb b/app/graphql/types/packages/helm/dependency_type.rb new file mode 100644 index 00000000000..35598c2b1d7 --- /dev/null +++ b/app/graphql/types/packages/helm/dependency_type.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Types + module Packages + module Helm + # rubocop: disable Graphql/AuthorizeTypes + class DependencyType < BaseObject + graphql_name 'PackageHelmDependencyType' + description 'Represents a Helm dependency' + + # Need to be synced with app/validators/json_schemas/helm_metadata.json#dependencies + field :name, GraphQL::Types::String, null: true, description: 'Name of the dependency.' + field :version, GraphQL::Types::String, null: true, description: 'Version of the dependency.' + field :repository, GraphQL::Types::String, null: true, description: 'Repository of the dependency.' + field :condition, GraphQL::Types::String, null: true, description: 'Condition of the dependency.' + field :tags, [GraphQL::Types::String], null: true, description: 'Tags of the dependency.' + field :enabled, GraphQL::Types::Boolean, null: true, description: 'Indicates the dependency is enabled.' + field :import_values, [GraphQL::Types::JSON], null: true, description: 'Import-values of the dependency.', hash_key: "import-values" # rubocop:disable Graphql/JSONType + field :alias, GraphQL::Types::String, null: true, description: 'Alias of the dependency.', resolver_method: :resolve_alias + + # field :alias` conflicts with a built-in method + def resolve_alias + object['alias'] + end + end + end + end +end diff --git a/app/graphql/types/packages/helm/file_metadatum_type.rb b/app/graphql/types/packages/helm/file_metadatum_type.rb new file mode 100644 index 00000000000..734ed52df40 --- /dev/null +++ b/app/graphql/types/packages/helm/file_metadatum_type.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +module Types + module Packages + module Helm + class FileMetadatumType < BaseObject + graphql_name 'HelmFileMetadata' + description 'Helm file metadata' + + implements Types::Packages::FileMetadataType + + authorize :read_package + + field :channel, GraphQL::Types::String, null: false, description: 'Channel of the Helm chart.' + field :metadata, Types::Packages::Helm::MetadataType, null: false, description: 'Metadata of the Helm chart.' + end + end + end +end diff --git a/app/graphql/types/packages/helm/maintainer_type.rb b/app/graphql/types/packages/helm/maintainer_type.rb new file mode 100644 index 00000000000..6d25a26c46b --- /dev/null +++ b/app/graphql/types/packages/helm/maintainer_type.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +module Types + module Packages + module Helm + # rubocop: disable Graphql/AuthorizeTypes + class MaintainerType < BaseObject + graphql_name 'PackageHelmMaintainerType' + description 'Represents a Helm maintainer' + + # Need to be synced with app/validators/json_schemas/helm_metadata.json#maintainers + field :name, GraphQL::Types::String, null: true, description: 'Name of the maintainer.' + field :email, GraphQL::Types::String, null: true, description: 'Email of the maintainer.' + field :url, GraphQL::Types::String, null: true, description: 'URL of the maintainer.' + end + end + end +end diff --git a/app/graphql/types/packages/helm/metadata_type.rb b/app/graphql/types/packages/helm/metadata_type.rb new file mode 100644 index 00000000000..eeb3e8087a8 --- /dev/null +++ b/app/graphql/types/packages/helm/metadata_type.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Types + module Packages + module Helm + # rubocop: disable Graphql/AuthorizeTypes + class MetadataType < BaseObject + graphql_name 'PackageHelmMetadataType' + description 'Represents the contents of a Helm Chart.yml file' + + # Need to be synced with app/validators/json_schemas/helm_metadata.json + field :name, GraphQL::Types::String, null: false, description: 'Name of the chart.' + field :home, GraphQL::Types::String, null: true, description: 'URL of the home page.' + field :sources, [GraphQL::Types::String], null: true, description: 'URLs of the source code for the chart.' + field :version, GraphQL::Types::String, null: false, description: 'Version of the chart.' + field :description, GraphQL::Types::String, null: true, description: 'Description of the chart.' + field :keywords, [GraphQL::Types::String], null: true, description: 'Keywords for the chart.' + field :maintainers, [Types::Packages::Helm::MaintainerType], null: true, description: 'Maintainers of the chart.' + field :icon, GraphQL::Types::String, null: true, description: 'URL to an SVG or PNG image for the chart.' + field :api_version, GraphQL::Types::String, null: false, description: 'API version of the chart.', hash_key: "apiVersion" + field :condition, GraphQL::Types::String, null: true, description: 'Condition for the chart.' + field :tags, GraphQL::Types::String, null: true, description: 'Tags for the chart.' + field :app_version, GraphQL::Types::String, null: true, description: 'App version of the chart.', hash_key: "appVersion" + field :deprecated, GraphQL::Types::Boolean, null: true, description: 'Indicates if the chart is deprecated.' + field :annotations, GraphQL::Types::JSON, null: true, description: 'Annotations for the chart.' # rubocop:disable Graphql/JSONType + field :kube_version, GraphQL::Types::String, null: true, description: 'Kubernetes versions for the chart.', hash_key: "kubeVersion" + field :dependencies, [Types::Packages::Helm::DependencyType], null: true, description: 'Dependencies of the chart.' + field :type, GraphQL::Types::String, null: true, description: 'Type of the chart.', hash_key: "appVersion" + end + end + end +end diff --git a/app/graphql/types/packages/package_file_type.rb b/app/graphql/types/packages/package_file_type.rb index 8cc0f9b984a..f90a0992bf8 100644 --- a/app/graphql/types/packages/package_file_type.rb +++ b/app/graphql/types/packages/package_file_type.rb @@ -27,6 +27,8 @@ module Types case object.package.package_type when 'conan' object.conan_file_metadatum + when 'helm' + object.helm_file_metadatum else nil end diff --git a/app/policies/packages/helm/file_metadatum_policy.rb b/app/policies/packages/helm/file_metadatum_policy.rb new file mode 100644 index 00000000000..4e0cb9046bf --- /dev/null +++ b/app/policies/packages/helm/file_metadatum_policy.rb @@ -0,0 +1,8 @@ +# frozen_string_literal: true +module Packages + module Helm + class FileMetadatumPolicy < BasePolicy + delegate { @subject.package_file.package } + end + end +end diff --git a/app/validators/json_schemas/helm_metadata.json b/app/validators/json_schemas/helm_metadata.json index 7ac36e956f3..a5ff6f0b33a 100644 --- a/app/validators/json_schemas/helm_metadata.json +++ b/app/validators/json_schemas/helm_metadata.json @@ -103,7 +103,23 @@ "import-values": { "type": "array", "items": { - + "oneOf": [ + { + "type": "string" + }, + { + "type": "object", + "properties": { + "child": { + "type": "string" + }, + "parent": { + "type": "string" + } + }, + "additionalProperties": false + } + ] } }, "alias": { diff --git a/config/feature_flags/development/linear_ee_group_ancestor_scopes.yml b/config/feature_flags/development/linear_ee_group_ancestor_scopes.yml deleted file mode 100644 index 46294b0aef0..00000000000 --- a/config/feature_flags/development/linear_ee_group_ancestor_scopes.yml +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: linear_ee_group_ancestor_scopes -introduced_by_url: https://gitlab.com/gitlab-org/gitlab/-/merge_requests/70708 -rollout_issue_url: https://gitlab.com/gitlab-org/gitlab/-/issues/341350 -milestone: '14.4' -type: development -group: group::access -default_enabled: false diff --git a/doc/api/graphql/reference/index.md b/doc/api/graphql/reference/index.md index 4b09907b9a8..ba199b01c56 100644 --- a/doc/api/graphql/reference/index.md +++ b/doc/api/graphql/reference/index.md @@ -10911,6 +10911,19 @@ Represents the Geo sync and verification state of a group wiki repository. | `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the GroupWikiRepositoryRegistry. | | `state` | [`RegistryState`](#registrystate) | Sync state of the GroupWikiRepositoryRegistry. | +### `HelmFileMetadata` + +Helm file metadata. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `channel` | [`String!`](#string) | Channel of the Helm chart. | +| `createdAt` | [`Time!`](#time) | Date of creation. | +| `metadata` | [`PackageHelmMetadataType!`](#packagehelmmetadatatype) | Metadata of the Helm chart. | +| `updatedAt` | [`Time!`](#time) | Date of most recent update. | + ### `IncidentManagementOncallRotation` Describes an incident management on-call rotation. @@ -12381,6 +12394,61 @@ Represents the Geo sync and verification state of a package file. | `retryCount` | [`Int`](#int) | Number of consecutive failed sync attempts of the PackageFileRegistry. | | `state` | [`RegistryState`](#registrystate) | Sync state of the PackageFileRegistry. | +### `PackageHelmDependencyType` + +Represents a Helm dependency. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `alias` | [`String`](#string) | Alias of the dependency. | +| `condition` | [`String`](#string) | Condition of the dependency. | +| `enabled` | [`Boolean`](#boolean) | Indicates the dependency is enabled. | +| `importValues` | [`[JSON!]`](#json) | Import-values of the dependency. | +| `name` | [`String`](#string) | Name of the dependency. | +| `repository` | [`String`](#string) | Repository of the dependency. | +| `tags` | [`[String!]`](#string) | Tags of the dependency. | +| `version` | [`String`](#string) | Version of the dependency. | + +### `PackageHelmMaintainerType` + +Represents a Helm maintainer. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `email` | [`String`](#string) | Email of the maintainer. | +| `name` | [`String`](#string) | Name of the maintainer. | +| `url` | [`String`](#string) | URL of the maintainer. | + +### `PackageHelmMetadataType` + +Represents the contents of a Helm Chart.yml file. + +#### Fields + +| Name | Type | Description | +| ---- | ---- | ----------- | +| `annotations` | [`JSON`](#json) | Annotations for the chart. | +| `apiVersion` | [`String!`](#string) | API version of the chart. | +| `appVersion` | [`String`](#string) | App version of the chart. | +| `condition` | [`String`](#string) | Condition for the chart. | +| `dependencies` | [`[PackageHelmDependencyType!]`](#packagehelmdependencytype) | Dependencies of the chart. | +| `deprecated` | [`Boolean`](#boolean) | Indicates if the chart is deprecated. | +| `description` | [`String`](#string) | Description of the chart. | +| `home` | [`String`](#string) | URL of the home page. | +| `icon` | [`String`](#string) | URL to an SVG or PNG image for the chart. | +| `keywords` | [`[String!]`](#string) | Keywords for the chart. | +| `kubeVersion` | [`String`](#string) | Kubernetes versions for the chart. | +| `maintainers` | [`[PackageHelmMaintainerType!]`](#packagehelmmaintainertype) | Maintainers of the chart. | +| `name` | [`String!`](#string) | Name of the chart. | +| `sources` | [`[String!]`](#string) | URLs of the source code for the chart. | +| `tags` | [`String`](#string) | Tags for the chart. | +| `type` | [`String`](#string) | Type of the chart. | +| `version` | [`String!`](#string) | Version of the chart. | + ### `PackageSettings` Namespace-level Package Registry settings. @@ -17759,6 +17827,7 @@ Represents metadata associated with a Package file. Implementations: - [`ConanFileMetadata`](#conanfilemetadata) +- [`HelmFileMetadata`](#helmfilemetadata) ##### Fields diff --git a/doc/ci/yaml/index.md b/doc/ci/yaml/index.md index 01e61679c0d..40bc41fa7e1 100644 --- a/doc/ci/yaml/index.md +++ b/doc/ci/yaml/index.md @@ -1652,10 +1652,12 @@ docker build: - docker/scripts/* - dockerfiles/**/* - more_scripts/*.{rb,py,sh} + - "**/*.json" ``` **Additional details**: +- If any of the matching files are changed (an `OR` operation), `changes` resolves to `true`. - If you use refs other than `branches`, `external_pull_requests`, or `merge_requests`, `changes` can't determine if a given file is new or old and always returns `true`. - If you use `only: changes` with other refs, jobs ignore the changes and always run. diff --git a/doc/development/gemfile.md b/doc/development/gemfile.md index e071aa4ffd9..221c8dfbf9d 100644 --- a/doc/development/gemfile.md +++ b/doc/development/gemfile.md @@ -55,7 +55,7 @@ to a gem, go through these steps: - For an example, see the [merge request !57805](https://gitlab.com/gitlab-org/gitlab/-/merge_requests/57805). 1. Once the gem is stable - we have been using it in production for a while with few, if any, changes - extract to its own project under - the `gitlab-org` namespace. + the [`gitlab-org/ruby/gems` namespace](https://gitlab.com/gitlab-org/ruby/gems/). 1. When creating the project, follow the [instructions for new projects](https://about.gitlab.com/handbook/engineering/#creating-a-new-project). 1. Follow the instructions for setting up a [CI/CD configuration](https://about.gitlab.com/handbook/engineering/#cicd-configuration). 1. Follow the instructions for [publishing a project](https://about.gitlab.com/handbook/engineering/#publishing-a-project). diff --git a/doc/development/go_guide/go_upgrade.md b/doc/development/go_guide/go_upgrade.md index 75a093a55ac..53f2d7d176a 100644 --- a/doc/development/go_guide/go_upgrade.md +++ b/doc/development/go_guide/go_upgrade.md @@ -89,10 +89,14 @@ if you need help finding the correct person or labels: 1. Schedule an update with the [GitLab Development Kit](https://gitlab.com/gitlab-org/gitlab-development-kit/-/issues): - Title the issue `Support using Go version `. - Set the issue as related to every issue created in the previous step. -1. Schedule one issue per Secure Stage team and add the `devops::secure` label to each: +1. Schedule one issue per Sec Section team that maintains Go based Security Analyzers and add the `section::sec` label to each: - [Static Analysis tracker](https://gitlab.com/gitlab-org/gitlab/-/issues). - [Composition Analysis tracker](https://gitlab.com/gitlab-org/gitlab/-/issues). - [Container Security tracker](https://gitlab.com/gitlab-org/gitlab/-/issues). + + NOTE: + Updates to these Security analyzers should not block upgrades to Charts or Omnibus since + the analyzers are built independently as separate container images. 1. Schedule builder updates with Distribution projects: - Dependency and GitLab Development Kit issues created in previous steps should be set as blockers. - Each issue should have the title `Support building with Go ` and description as noted: diff --git a/doc/development/secure_coding_guidelines.md b/doc/development/secure_coding_guidelines.md index 765370e35ec..98293eb21f7 100644 --- a/doc/development/secure_coding_guidelines.md +++ b/doc/development/secure_coding_guidelines.md @@ -540,6 +540,94 @@ out, _ = exec.Command("sh", "-c", "echo 1 | cat /etc/passwd").Output() This outputs `1` followed by the content of `/etc/passwd`. +## General recommendations + +### TLS minimum recommended version + +As we have [moved away from supporting TLS 1.0 and 1.1](https://about.gitlab.com/blog/2018/10/15/gitlab-to-deprecate-older-tls/), we should only use TLS 1.2 and above. + +#### Ciphers + +We recommend using the ciphers that Mozilla is providing in their [recommended SSL configuration generator](https://ssl-config.mozilla.org/#server=go&version=1.17&config=intermediate&guideline=5.6) for TLS 1.2: + +- `ECDHE-ECDSA-AES128-GCM-SHA256` +- `ECDHE-RSA-AES128-GCM-SHA256` +- `ECDHE-ECDSA-AES256-GCM-SHA384` +- `ECDHE-RSA-AES256-GCM-SHA384` +- `ECDHE-ECDSA-CHACHA20-POLY1305` +- `ECDHE-RSA-CHACHA20-POLY1305` + +And the following cipher suites (according to the [RFC 8446](https://datatracker.ietf.org/doc/html/rfc8446#appendix-B.4)) for TLS 1.3: + +- `TLS_AES_128_GCM_SHA256` +- `TLS_AES_256_GCM_SHA384` +- `TLS_CHACHA20_POLY1305_SHA256` + +*Note*: **Golang** does [not support](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676) all cipher suites with TLS 1.3. + +##### Implementation examples + +##### TLS 1.3 + +For TLS 1.3, **Golang** only supports [3 cipher suites](https://github.com/golang/go/blob/go1.17/src/crypto/tls/cipher_suites.go#L676), as such we only need to set the TLS version: + +```golang +cfg := &tls.Config{ + MinVersion: tls.VersionTLS13, +} +``` + +For **Ruby**, you can use [HTTParty](https://github.com/jnunemaker/httparty) and specify TLS 1.3 version as well as ciphers: + +Whenever possible this example should be **avoided** for security purposes: + +```ruby +response = HTTParty.get('https://gitlab.com', ssl_version: :TLSv1_3, ciphers: ['TLS_AES_128_GCM_SHA256', 'TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256']) +``` + +When using [`GitLab::HTTP`](#gitlab-http-library), the code looks like: + +This is the **recommended** implementation to avoid security issues such as SSRF: + +```ruby +response = GitLab::HTTP.perform_request(Net::HTTP::Get, 'https://gitlab.com', ssl_version: :TLSv1_3, ciphers: ['TLS_AES_128_GCM_SHA256', 'TLS_AES_256_GCM_SHA384', 'TLS_CHACHA20_POLY1305_SHA256']) +``` + +##### TLS 1.2 + +**Golang** does support multiple cipher suites that we do not want to use with TLS 1.2. We need to explicitly list authorised ciphers: + +```golang +func secureCipherSuites() []uint16 { + return []uint16{ + tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, + tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, + tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, + tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, + } +``` + +And then use `secureCipherSuites()` in `tls.Config`: + +```golang +tls.Config{ + (...), + CipherSuites: secureCipherSuites(), + MinVersion: tls.VersionTLS12, + (...), +} +``` + +This example was taken [here](https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/871b52dc700f1a66f6644fbb1e78a6d463a6ff83/internal/tool/tlstool/tlstool.go#L72). + +For **Ruby**, you can use again [HTTParty](https://github.com/jnunemaker/httparty) and specify this time TLS 1.2 version alongside with the recommended ciphers: + +```ruby +response = GitLab::HTTP.perform_request(Net::HTTP::Get, 'https://gitlab.com', ssl_version: :TLSv1_2, ciphers: ['ECDHE-ECDSA-AES128-GCM-SHA256', 'ECDHE-RSA-AES128-GCM-SHA256', 'ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305']) +``` + ## GitLab Internal Authorization ### Introduction diff --git a/doc/operations/error_tracking.md b/doc/operations/error_tracking.md index 88785196f6e..70e3115a98e 100644 --- a/doc/operations/error_tracking.md +++ b/doc/operations/error_tracking.md @@ -169,5 +169,6 @@ You can do so by managing client keys with the [error tracking API](../api/error #### Limitations -The Integrated Error Tracking feature was built and tested with Sentry SDK for Ruby. Other languages and frameworks -are not tested and might not work. Check [the compatibility issue](https://gitlab.com/gitlab-org/gitlab/-/issues/340178) for more information. +The Integrated Error Tracking feature was built and tested with Sentry SDK for Ruby on Rails. +Support for other languages and frameworks is not guaranteed. For up-to-date information, see the +[compatibility issue](https://gitlab.com/gitlab-org/gitlab/-/issues/340178). diff --git a/doc/user/clusters/management_project_template.md b/doc/user/clusters/management_project_template.md index 305f66c5ec5..ea364063758 100644 --- a/doc/user/clusters/management_project_template.md +++ b/doc/user/clusters/management_project_template.md @@ -109,6 +109,6 @@ The [built-in supported applications](https://gitlab.com/gitlab-org/project-temp #### How to customize your applications -Each app has an `applications/{app}/values.yaml` file (`applicaton/{app}/values.yaml.gotmpl` in case of GitLab Runner). This is the +Each app has an `applications/{app}/values.yaml` file (`applications/{app}/values.yaml.gotmpl` in case of GitLab Runner). This is the place where you can define default values for your app's Helm chart. Some apps already have defaults pre-defined by GitLab. diff --git a/lib/api/ci/jobs.rb b/lib/api/ci/jobs.rb index 7c9c4a7af12..30ce1454419 100644 --- a/lib/api/ci/jobs.rb +++ b/lib/api/ci/jobs.rb @@ -190,14 +190,25 @@ module API pipeline = current_authenticated_job.pipeline project = current_authenticated_job.project agent_authorizations = Clusters::AgentAuthorizationsFinder.new(project).execute + project_groups = project.group&.self_and_ancestor_ids&.map { |id| { id: id } } || [] + user_access_level = project.team.max_member_access(current_user.id) + roles_in_project = Gitlab::Access.sym_options_with_owner + .select { |_role, role_access_level| role_access_level <= user_access_level } + .map(&:first) + environment = if environment_slug = current_authenticated_job.deployment&.environment&.slug + { slug: environment_slug } + end + + # See https://gitlab.com/gitlab-org/cluster-integration/gitlab-agent/-/blob/master/doc/kubernetes_ci_access.md#apiv4joballowed_agents-api { allowed_agents: Entities::Clusters::AgentAuthorization.represent(agent_authorizations), - job: Entities::Ci::JobRequest::JobInfo.represent(current_authenticated_job), - pipeline: Entities::Ci::PipelineBasic.represent(pipeline), - project: Entities::ProjectIdentity.represent(project), - user: Entities::UserBasic.represent(current_user) - } + job: { id: current_authenticated_job.id }, + pipeline: { id: pipeline.id }, + project: { id: project.id, groups: project_groups }, + user: { id: current_user.id, username: current_user.username, roles_in_project: roles_in_project }, + environment: environment + }.compact end end diff --git a/lib/gitlab/diff/file.rb b/lib/gitlab/diff/file.rb index 4cd5e999027..30871a16e4e 100644 --- a/lib/gitlab/diff/file.rb +++ b/lib/gitlab/diff/file.rb @@ -44,7 +44,7 @@ module Gitlab new_blob_lazy old_blob_lazy - preprocess_before_diff(diff) if Feature.enabled?(:jupyter_clean_diffs, @project) + preprocess_before_diff(diff) if Feature.enabled?(:jupyter_clean_diffs, repository.project) end def position(position_marker, position_type: :text) diff --git a/spec/factories/packages/helm/file_metadatum.rb b/spec/factories/packages/helm/file_metadatum.rb index 3f599b5d5c0..590956e5d49 100644 --- a/spec/factories/packages/helm/file_metadatum.rb +++ b/spec/factories/packages/helm/file_metadatum.rb @@ -9,7 +9,11 @@ FactoryBot.define do package_file { association(:helm_package_file, without_loaded_metadatum: true) } sequence(:channel) { |n| "#{FFaker::Lorem.word}-#{n}" } metadata do - { 'name': package_file.package.name, 'version': package_file.package.version, 'apiVersion': 'v2' }.tap do |defaults| + { + 'name': package_file.package.name, + 'version': package_file.package.version, + 'apiVersion': 'v2' + }.tap do |defaults| defaults['description'] = description if description end end diff --git a/spec/features/issues/user_edits_issue_spec.rb b/spec/features/issues/user_edits_issue_spec.rb index 63c36a20adc..76cec2502e3 100644 --- a/spec/features/issues/user_edits_issue_spec.rb +++ b/spec/features/issues/user_edits_issue_spec.rb @@ -146,8 +146,7 @@ RSpec.describe "Issues > User edits issue", :js do fill_in 'Comment', with: '/label ~syzygy' click_button 'Comment' - - wait_for_requests + expect(page).to have_text('added syzygy label just now') page.within '.block.labels' do # Remove `verisimilitude` label @@ -155,8 +154,6 @@ RSpec.describe "Issues > User edits issue", :js do click_button end - wait_for_requests - expect(page).to have_text('syzygy') expect(page).not_to have_text('verisimilitude') end diff --git a/spec/fixtures/api/schemas/graphql/packages/package_details.json b/spec/fixtures/api/schemas/graphql/packages/package_details.json index 2824ca64325..9ef7f6c9271 100644 --- a/spec/fixtures/api/schemas/graphql/packages/package_details.json +++ b/spec/fixtures/api/schemas/graphql/packages/package_details.json @@ -12,7 +12,6 @@ "tags", "pipelines", "versions", - "metadata", "status", "canDestroy" ], @@ -47,7 +46,8 @@ "GENERIC", "GOLANG", "RUBYGEMS", - "DEBIAN" + "DEBIAN", + "HELM" ] }, "tags": { diff --git a/spec/graphql/types/evidence_type_spec.rb b/spec/graphql/types/evidence_type_spec.rb index 92134e74d51..be85724eac5 100644 --- a/spec/graphql/types/evidence_type_spec.rb +++ b/spec/graphql/types/evidence_type_spec.rb @@ -3,7 +3,7 @@ require 'spec_helper' RSpec.describe GitlabSchema.types['ReleaseEvidence'] do - it { expect(described_class).to require_graphql_authorizations(:download_code) } + specify { expect(described_class).to require_graphql_authorizations(:read_release_evidence) } it 'has the expected fields' do expected_fields = %w[ diff --git a/spec/graphql/types/packages/helm/dependency_type_spec.rb b/spec/graphql/types/packages/helm/dependency_type_spec.rb new file mode 100644 index 00000000000..2047205275f --- /dev/null +++ b/spec/graphql/types/packages/helm/dependency_type_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['PackageHelmDependencyType'] do + it { expect(described_class.graphql_name).to eq('PackageHelmDependencyType') } + + it 'includes helm dependency fields' do + expected_fields = %w[ + name version repository condition tags enabled import_values alias + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/packages/helm/file_metadatum_type_spec.rb b/spec/graphql/types/packages/helm/file_metadatum_type_spec.rb new file mode 100644 index 00000000000..b7bcd6213b4 --- /dev/null +++ b/spec/graphql/types/packages/helm/file_metadatum_type_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['HelmFileMetadata'] do + it { expect(described_class.graphql_name).to eq('HelmFileMetadata') } + + it 'includes helm file metadatum fields' do + expected_fields = %w[ + created_at updated_at channel metadata + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/packages/helm/maintainer_type_spec.rb b/spec/graphql/types/packages/helm/maintainer_type_spec.rb new file mode 100644 index 00000000000..9ad51427d42 --- /dev/null +++ b/spec/graphql/types/packages/helm/maintainer_type_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['PackageHelmMaintainerType'] do + it { expect(described_class.graphql_name).to eq('PackageHelmMaintainerType') } + + it 'includes helm maintainer fields' do + expected_fields = %w[ + name email url + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/graphql/types/packages/helm/metadata_type_spec.rb b/spec/graphql/types/packages/helm/metadata_type_spec.rb new file mode 100644 index 00000000000..04639450d9a --- /dev/null +++ b/spec/graphql/types/packages/helm/metadata_type_spec.rb @@ -0,0 +1,15 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe GitlabSchema.types['PackageHelmMetadataType'] do + it { expect(described_class.graphql_name).to eq('PackageHelmMetadataType') } + + it 'includes helm json fields' do + expected_fields = %w[ + name home sources version description keywords maintainers icon apiVersion condition tags appVersion deprecated annotations kubeVersion dependencies type + ] + + expect(described_class).to include_graphql_fields(*expected_fields) + end +end diff --git a/spec/requests/api/ci/jobs_spec.rb b/spec/requests/api/ci/jobs_spec.rb index a1a0086d96b..580f3d9e92d 100644 --- a/spec/requests/api/ci/jobs_spec.rb +++ b/spec/requests/api/ci/jobs_spec.rb @@ -177,11 +177,16 @@ RSpec.describe API::Ci::Jobs do end describe 'GET /job/allowed_agents' do - let_it_be(:group_authorization) { create(:agent_group_authorization) } - let_it_be(:associated_agent) { create(:cluster_agent, project: project) } + let_it_be(:group) { create(:group) } + let_it_be(:group_agent) { create(:cluster_agent, project: create(:project, group: group)) } + let_it_be(:group_authorization) { create(:agent_group_authorization, agent: group_agent, group: group) } + let_it_be(:project_agent) { create(:cluster_agent, project: project) } - let(:implicit_authorization) { Clusters::Agents::ImplicitAuthorization.new(agent: associated_agent) } - let(:authorizations_finder) { double(execute: [implicit_authorization, group_authorization]) } + before(:all) do + project.update!(group: group_authorization.group) + end + + let(:implicit_authorization) { Clusters::Agents::ImplicitAuthorization.new(agent: project_agent) } let(:headers) { { API::Ci::Helpers::Runner::JOB_TOKEN_HEADER => job.token } } let(:job) { create(:ci_build, :artifacts, pipeline: pipeline, user: api_user, status: job_status) } @@ -193,44 +198,22 @@ RSpec.describe API::Ci::Jobs do end before do - allow(Clusters::AgentAuthorizationsFinder).to receive(:new).with(project).and_return(authorizations_finder) - subject end context 'when token is valid and user is authorized' do - it 'returns agent info', :aggregate_failures do - expect(response).to have_gitlab_http_status(:ok) - - expect(json_response.dig('job', 'id')).to eq(job.id) - expect(json_response.dig('pipeline', 'id')).to eq(job.pipeline_id) - expect(json_response.dig('project', 'id')).to eq(job.project_id) - expect(json_response.dig('user', 'username')).to eq(api_user.username) - expect(json_response['allowed_agents']).to match_array([ - { - 'id' => implicit_authorization.agent_id, - 'config_project' => hash_including('id' => implicit_authorization.agent.project_id), - 'configuration' => implicit_authorization.config - }, - { - 'id' => group_authorization.agent_id, - 'config_project' => hash_including('id' => group_authorization.agent.project_id), - 'configuration' => group_authorization.config - } - ]) - end - - context 'when passing the token as params' do - let(:headers) { {} } - let(:params) { { job_token: job.token } } - + shared_examples_for 'valid allowed_agents request' do it 'returns agent info', :aggregate_failures do expect(response).to have_gitlab_http_status(:ok) expect(json_response.dig('job', 'id')).to eq(job.id) expect(json_response.dig('pipeline', 'id')).to eq(job.pipeline_id) expect(json_response.dig('project', 'id')).to eq(job.project_id) + expect(json_response.dig('project', 'groups')).to match_array([{ 'id' => group_authorization.group.id }]) + expect(json_response.dig('user', 'id')).to eq(api_user.id) expect(json_response.dig('user', 'username')).to eq(api_user.username) + expect(json_response.dig('user', 'roles_in_project')).to match_array %w(guest reporter developer) + expect(json_response).not_to include('environment') expect(json_response['allowed_agents']).to match_array([ { 'id' => implicit_authorization.agent_id, @@ -239,12 +222,29 @@ RSpec.describe API::Ci::Jobs do }, { 'id' => group_authorization.agent_id, - 'config_project' => a_hash_including('id' => group_authorization.agent.project_id), + 'config_project' => hash_including('id' => group_authorization.agent.project_id), 'configuration' => group_authorization.config } ]) end end + + it_behaves_like 'valid allowed_agents request' + + context 'when deployment' do + let(:job) { create(:ci_build, :artifacts, :with_deployment, environment: 'production', pipeline: pipeline, user: api_user, status: job_status) } + + it 'includes environment slug' do + expect(json_response.dig('environment', 'slug')).to eq('production') + end + end + + context 'when passing the token as params' do + let(:headers) { {} } + let(:params) { { job_token: job.token } } + + it_behaves_like 'valid allowed_agents request' + end end context 'when user is anonymous' do diff --git a/spec/requests/api/graphql/packages/helm_spec.rb b/spec/requests/api/graphql/packages/helm_spec.rb new file mode 100644 index 00000000000..397096f70db --- /dev/null +++ b/spec/requests/api/graphql/packages/helm_spec.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true +require 'spec_helper' + +RSpec.describe 'helm package details' do + include GraphqlHelpers + include_context 'package details setup' + + let_it_be(:package) { create(:helm_package, project: project) } + + let(:package_files_metadata) {query_graphql_fragment('HelmFileMetadata')} + + let(:query) do + graphql_query_for(:package, { id: package_global_id }, <<~FIELDS) + #{all_graphql_fields_for('PackageDetailsType', max_depth: depth, excluded: excluded)} + packageFiles { + nodes { + #{package_files} + fileMetadata { + #{package_files_metadata} + } + } + } + FIELDS + end + + subject { post_graphql(query, current_user: user) } + + before do + subject + end + + it_behaves_like 'a package detail' + it_behaves_like 'a package with files' + + it 'has the correct file metadata' do + expect(first_file_response_metadata).to include( + 'channel' => first_file.helm_file_metadatum.channel + ) + expect(first_file_response_metadata['metadata']).to include( + 'name' => first_file.helm_file_metadatum.metadata['name'], + 'home' => first_file.helm_file_metadatum.metadata['home'], + 'sources' => first_file.helm_file_metadatum.metadata['sources'], + 'version' => first_file.helm_file_metadatum.metadata['version'], + 'description' => first_file.helm_file_metadatum.metadata['description'], + 'keywords' => first_file.helm_file_metadatum.metadata['keywords'], + 'maintainers' => first_file.helm_file_metadatum.metadata['maintainers'], + 'icon' => first_file.helm_file_metadatum.metadata['icon'], + 'apiVersion' => first_file.helm_file_metadatum.metadata['apiVersion'], + 'condition' => first_file.helm_file_metadatum.metadata['condition'], + 'tags' => first_file.helm_file_metadatum.metadata['tags'], + 'appVersion' => first_file.helm_file_metadatum.metadata['appVersion'], + 'deprecated' => first_file.helm_file_metadatum.metadata['deprecated'], + 'annotations' => first_file.helm_file_metadatum.metadata['annotations'], + 'kubeVersion' => first_file.helm_file_metadatum.metadata['kubeVersion'], + 'dependencies' => first_file.helm_file_metadatum.metadata['dependencies'], + 'type' => first_file.helm_file_metadatum.metadata['type'] + ) + end +end