diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-23 09:07:43 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-23 09:07:43 +0300 |
commit | 9d15ef5c5caf584ae16398940c16f2bdafd6f3e2 (patch) | |
tree | 7ae2422c4415ed9da8aba67391c5640fad0d9da8 | |
parent | 26eeb803e0a3412f0b098d5c5a23f32b763f44c2 (diff) |
Add latest changes from gitlab-org/gitlab@master
42 files changed, 289 insertions, 90 deletions
diff --git a/app/assets/javascripts/editor/schema/ci.json b/app/assets/javascripts/editor/schema/ci.json index 45f063a2048..4c4ad81fed7 100644 --- a/app/assets/javascripts/editor/schema/ci.json +++ b/app/assets/javascripts/editor/schema/ci.json @@ -585,6 +585,36 @@ ] } }, + "id_tokens": { + "type": "object", + "markdownDescription": "Defines JWTs to be injected as environment variables.", + "patternProperties": { + ".*": { + "type": "object", + "properties": { + "aud": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + ] + } + }, + "required": [ + "aud" + ], + "additionalProperties": false + } + } + }, "secrets": { "type": "object", "markdownDescription": "Defines secrets to be injected as environment variables. [Learn More](https://docs.gitlab.com/ee/ci/yaml/#secrets).", @@ -1209,6 +1239,9 @@ "cache": { "$ref": "#/definitions/cache" }, + "id_tokens": { + "$ref": "#/definitions/id_tokens" + }, "secrets": { "$ref": "#/definitions/secrets" }, diff --git a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js index 0c01220a7be..4994559e923 100644 --- a/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js +++ b/app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js @@ -1,5 +1,6 @@ import { spriteIcon } from '~/lib/utils/common_utils'; import { objectToQuery } from '~/lib/utils/url_utility'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchContainer from './container'; import VisualTokenValue from './visual_token_value'; @@ -38,7 +39,7 @@ export default class FilteredSearchVisualTokens { lastVisualToken, isLastVisualTokenValid: lastVisualToken === null || - lastVisualToken.className.indexOf('filtered-search-term') !== -1 || + lastVisualToken.className.indexOf(FILTERED_SEARCH_TERM) !== -1 || (lastVisualToken && lastVisualToken.querySelector('.operator') !== null && lastVisualToken.querySelector('.value') !== null), @@ -113,7 +114,7 @@ export default class FilteredSearchVisualTokens { } = options; const li = document.createElement('li'); li.classList.add('js-visual-token'); - li.classList.add(isSearchTerm ? 'filtered-search-term' : 'filtered-search-token'); + li.classList.add(isSearchTerm ? FILTERED_SEARCH_TERM : 'filtered-search-token'); if (!isSearchTerm) { li.classList.add(tokenClass); @@ -239,7 +240,7 @@ export default class FilteredSearchVisualTokens { static addSearchVisualToken(searchTerm) { const { lastVisualToken } = FilteredSearchVisualTokens.getLastVisualTokenBeforeInput(); - if (lastVisualToken && lastVisualToken.classList.contains('filtered-search-term')) { + if (lastVisualToken && lastVisualToken.classList.contains(FILTERED_SEARCH_TERM)) { lastVisualToken.querySelector('.name').textContent += ` ${searchTerm}`; } else { FilteredSearchVisualTokens.addVisualTokenElement({ diff --git a/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue b/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue index cb7b963b698..76b286f94ad 100644 --- a/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue +++ b/app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue @@ -7,11 +7,11 @@ import { redirectTo, } from '~/lib/utils/url_utility'; import { - SEARCH_TOKEN_TYPE, SORT_QUERY_PARAM_NAME, ACTIVE_TAB_QUERY_PARAM_NAME, AVAILABLE_FILTERED_SEARCH_TOKENS, } from 'ee_else_ce/members/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; export default { @@ -65,7 +65,7 @@ export default { if (query[this.filteredSearchBar.searchParam]) { tokens.push({ - type: SEARCH_TOKEN_TYPE, + type: FILTERED_SEARCH_TERM, value: { data: query[this.filteredSearchBar.searchParam], }, @@ -83,7 +83,7 @@ export default { return accumulator; } - if (type === SEARCH_TOKEN_TYPE) { + if (type === FILTERED_SEARCH_TERM) { if (value.data !== '') { const { searchParam } = this.filteredSearchBar; const { [searchParam]: searchParamValue } = accumulator; diff --git a/app/assets/javascripts/members/constants.js b/app/assets/javascripts/members/constants.js index 47bd042b001..dab544c7cbc 100644 --- a/app/assets/javascripts/members/constants.js +++ b/app/assets/javascripts/members/constants.js @@ -187,8 +187,6 @@ export const LEAVE_MODAL_ID = 'member-leave-modal'; export const REMOVE_GROUP_LINK_MODAL_ID = 'remove-group-link-modal-id'; -export const SEARCH_TOKEN_TYPE = 'filtered-search-term'; - export const SORT_QUERY_PARAM_NAME = 'sort'; export const ACTIVE_TAB_QUERY_PARAM_NAME = 'tab'; diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue index 597df2b9bc3..c10d8be69a0 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue @@ -6,8 +6,8 @@ import { joinPaths } from '~/lib/utils/url_utility'; import RegistryList from '~/packages_and_registries/shared/components/registry_list.vue'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import TagsLoader from '~/packages_and_registries/shared/components/tags_loader.vue'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import { REMOVE_TAGS_BUTTON_TITLE, TAGS_LIST_TITLE, diff --git a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue index 794be8d5195..8a038d7c974 100644 --- a/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue +++ b/app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue @@ -11,9 +11,9 @@ import { import { get } from 'lodash'; import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql'; import { createAlert } from '~/flash'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import Tracking from '~/tracking'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import DeleteImage from '../components/delete_image.vue'; import RegistryHeader from '../components/list_page/registry_header.vue'; diff --git a/app/assets/javascripts/packages_and_registries/harbor_registry/utils.js b/app/assets/javascripts/packages_and_registries/harbor_registry/utils.js index 13df303cffe..2ae5957343b 100644 --- a/app/assets/javascripts/packages_and_registries/harbor_registry/utils.js +++ b/app/assets/javascripts/packages_and_registries/harbor_registry/utils.js @@ -3,8 +3,8 @@ import { SORT_FIELD_MAPPING, TOKEN_TYPE_TAG_NAME, } from '~/packages_and_registries/harbor_registry/constants'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import { normalizeHeaders, parseIntPagination } from '~/lib/utils/common_utils'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; export const extractSortingDetail = (parsedSorting = '') => { const [orderBy, sortOrder] = parsedSorting.split('_'); diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue index 2adf6187c4b..0aeeb2c3d15 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue @@ -4,16 +4,14 @@ import { mapActions, mapState } from 'vuex'; import { createAlert, VARIANT_INFO } from '~/flash'; import { historyReplaceState } from '~/lib/utils/common_utils'; import { s__ } from '~/locale'; -import { - SHOW_DELETE_SUCCESS_ALERT, - FILTERED_SEARCH_TERM, -} from '~/packages_and_registries/shared/constants'; +import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants'; import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils'; import InfrastructureTitle from '~/packages_and_registries/infrastructure_registry/list/components/infrastructure_title.vue'; import InfrastructureSearch from '~/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue'; import PackageList from '~/packages_and_registries/infrastructure_registry/list/components/packages_list.vue'; import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages_and_registries/infrastructure_registry/list/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; export default { components: { diff --git a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js index 37b51797490..7a452abdc26 100644 --- a/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js +++ b/app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js @@ -2,6 +2,7 @@ import Api from '~/api'; import { createAlert, VARIANT_SUCCESS } from '~/flash'; import axios from '~/lib/utils/axios_utils'; import { DELETE_PACKAGE_ERROR_MESSAGE } from '~/packages_and_registries/shared/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import { FETCH_PACKAGES_LIST_ERROR_MESSAGE, DELETE_PACKAGE_SUCCESS_MESSAGE, @@ -31,7 +32,7 @@ export const requestPackagesList = ({ dispatch, state }, params = {}) => { const type = state.config.forceTerraform ? TERRAFORM_SEARCH_TYPE : state.filter.find((f) => f.type === 'type'); - const name = state.filter.find((f) => f.type === 'filtered-search-term'); + const name = state.filter.find((f) => f.type === FILTERED_SEARCH_TERM); const packageFilters = { package_type: type?.value?.data, package_name: name?.value?.data }; const apiMethod = state.config.isGroupPage ? 'groupPackages' : 'projectPackages'; diff --git a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue index c9f64ec35b8..0cf49b25bf2 100644 --- a/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue +++ b/app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue @@ -1,14 +1,14 @@ <script> -import { s__ } from '~/locale'; import { sortableFields } from '~/packages_and_registries/package_registry/utils'; -import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants'; +import { + FILTERED_SEARCH_TERM, + OPERATORS_IS, + TOKEN_TITLE_TYPE, + TOKEN_TYPE_TYPE, +} from '~/vue_shared/components/filtered_search_bar/constants'; import RegistrySearch from '~/vue_shared/components/registry/registry_search.vue'; import UrlSync from '~/vue_shared/components/url_sync.vue'; import { getQueryParams, extractFilterAndSorting } from '~/packages_and_registries/shared/utils'; -import { - FILTERED_SEARCH_TERM, - FILTERED_SEARCH_TYPE, -} from '~/packages_and_registries/shared/constants'; import { LIST_KEY_CREATED_AT } from '~/packages_and_registries/package_registry/constants'; import LocalStorageSync from '~/vue_shared/components/local_storage_sync.vue'; import PackageTypeToken from './tokens/package_type_token.vue'; @@ -16,9 +16,9 @@ import PackageTypeToken from './tokens/package_type_token.vue'; export default { tokens: [ { - type: 'type', + type: TOKEN_TYPE_TYPE, icon: 'package', - title: s__('PackageRegistry|Type'), + title: TOKEN_TITLE_TYPE, unique: true, token: PackageTypeToken, operators: OPERATORS_IS, @@ -51,7 +51,7 @@ export default { }; return this.filters.reduce((acc, filter) => { - if (filter.type === FILTERED_SEARCH_TYPE && filter.value?.data) { + if (filter.type === TOKEN_TYPE_TYPE && filter.value?.data) { return { ...acc, packageType: filter.value.data.toUpperCase(), diff --git a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js index f3ce967b756..fe6e06ad830 100644 --- a/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js +++ b/app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js @@ -1,7 +1,5 @@ import { s__ } from '~/locale'; -export const FILTERED_SEARCH_TERM = 'filtered-search-term'; -export const FILTERED_SEARCH_TYPE = 'type'; export const HISTORY_PIPELINES_LIMIT = 5; export const DELETE_PACKAGE_TRACKING_ACTION = 'delete_package'; diff --git a/app/assets/javascripts/packages_and_registries/shared/utils.js b/app/assets/javascripts/packages_and_registries/shared/utils.js index 7e963cd0b08..76623377d90 100644 --- a/app/assets/javascripts/packages_and_registries/shared/utils.js +++ b/app/assets/javascripts/packages_and_registries/shared/utils.js @@ -1,6 +1,6 @@ import Vue from 'vue'; import { queryToObject } from '~/lib/utils/url_utility'; -import { FILTERED_SEARCH_TERM } from './constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; export const getQueryParams = (query) => queryToObject(query, { gatherArrays: true, legacySpacesDecode: true }); diff --git a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js index 6438ecf3868..2e295f7565b 100644 --- a/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js +++ b/app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js @@ -50,7 +50,6 @@ export const SORT_DIRECTION = { ascending: 'ascending', }; -export const FILTERED_SEARCH_LABELS = 'labels'; export const FILTERED_SEARCH_TERM = 'filtered-search-term'; export const TOKEN_TITLE_APPROVED_BY = __('Approved-By'); diff --git a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue index ea043f86619..31dc803cb4e 100644 --- a/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue +++ b/app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue @@ -5,6 +5,7 @@ import Api from '~/api'; import { updateHistory, setUrlParams } from '~/lib/utils/url_utility'; import Tracking from '~/tracking'; import { + FILTERED_SEARCH_TERM, OPERATORS_IS, TOKEN_TITLE_ASSIGNEE, TOKEN_TITLE_AUTHOR, @@ -226,7 +227,7 @@ export default { case 'assignee_username': filterParams.assigneeUsername = isAny(filter.value.data); break; - case 'filtered-search-term': + case FILTERED_SEARCH_TERM: if (filter.value.data !== '') filterParams.search = filter.value.data; break; default: diff --git a/app/assets/javascripts/vue_shared/components/registry/registry_search.vue b/app/assets/javascripts/vue_shared/components/registry/registry_search.vue index 8c9c7c63db1..c990baaa2f3 100644 --- a/app/assets/javascripts/vue_shared/components/registry/registry_search.vue +++ b/app/assets/javascripts/vue_shared/components/registry/registry_search.vue @@ -1,7 +1,7 @@ <script> import { GlSorting, GlSortingItem, GlFilteredSearch } from '@gitlab/ui'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import { SORT_DIRECTION_UI } from '~/search/sort/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; const ASCENDING_ORDER = 'asc'; const DESCENDING_ORDER = 'desc'; diff --git a/app/models/ci/build.rb b/app/models/ci/build.rb index f44ba124fe2..6441928835c 100644 --- a/app/models/ci/build.rb +++ b/app/models/ci/build.rb @@ -1208,11 +1208,11 @@ module Ci if project.ci_cd_settings.opt_in_jwt? id_tokens_variables else - legacy_jwt_variables.concat(id_tokens_variables) + predefined_jwt_variables.concat(id_tokens_variables) end end - def legacy_jwt_variables + def predefined_jwt_variables Gitlab::Ci::Variables::Collection.new.tap do |variables| jwt = Gitlab::Ci::Jwt.for_build(self) jwt_v2 = Gitlab::Ci::JwtV2.for_build(self) @@ -1229,7 +1229,7 @@ module Ci Gitlab::Ci::Variables::Collection.new.tap do |variables| id_tokens.each do |var_name, token_data| - token = Gitlab::Ci::JwtV2.for_build(self, aud: token_data['id_token']['aud']) + token = Gitlab::Ci::JwtV2.for_build(self, aud: token_data['aud']) variables.append(key: var_name, value: token, public: false, masked: true) end diff --git a/app/validators/json_schemas/build_metadata_id_tokens.json b/app/validators/json_schemas/build_metadata_id_tokens.json index 7f39c7274f3..d97b2241ca3 100644 --- a/app/validators/json_schemas/build_metadata_id_tokens.json +++ b/app/validators/json_schemas/build_metadata_id_tokens.json @@ -5,18 +5,27 @@ "patternProperties": { ".*": { "type": "object", - "patternProperties": { - "^id_token$": { - "type": "object", - "required": ["aud"], - "properties": { - "aud": { "type": "string" }, - "field": { "type": "string" } - }, - "additionalProperties": false + "required": [ + "aud" + ], + "properties": { + "aud": { + "oneOf": [ + { + "type": "string" + }, + { + "type": "array", + "items": { + "type": "string" + }, + "minItems": 1, + "uniqueItems": true + } + ] } }, "additionalProperties": false } } -} +}
\ No newline at end of file diff --git a/lib/gitlab/ci/config/entry/id_token.rb b/lib/gitlab/ci/config/entry/id_token.rb new file mode 100644 index 00000000000..12e0975d1b1 --- /dev/null +++ b/lib/gitlab/ci/config/entry/id_token.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module Gitlab + module Ci + class Config + module Entry + ## + # Entry that represents a JWT definition. + # + class IdToken < ::Gitlab::Config::Entry::Node + include ::Gitlab::Config::Entry::Attributable + include ::Gitlab::Config::Entry::Validatable + + attributes %i[aud] + + validations do + validates :config, required_keys: %i[aud], allowed_keys: %i[aud] + validates :aud, array_of_strings_or_string: true + end + + def value + { aud: aud } + end + end + end + end + end +end diff --git a/lib/gitlab/ci/config/entry/job.rb b/lib/gitlab/ci/config/entry/job.rb index 8e7f6ba4326..ab17e1e3870 100644 --- a/lib/gitlab/ci/config/entry/job.rb +++ b/lib/gitlab/ci/config/entry/job.rb @@ -14,7 +14,7 @@ module Gitlab ALLOWED_KEYS = %i[tags script image services start_in artifacts cache dependencies before_script after_script environment coverage retry parallel interruptible timeout - release].freeze + release id_tokens].freeze validations do validates :config, allowed_keys: Gitlab::Ci::Config::Entry::Job.allowed_keys + PROCESSABLE_ALLOWED_KEYS @@ -116,6 +116,11 @@ module Gitlab description: 'Indicates whether this job is allowed to fail or not.', inherit: false + entry :id_tokens, ::Gitlab::Config::Entry::ComposableHash, + description: 'Configured JWTs for this job', + inherit: false, + metadata: { composable_class: ::Gitlab::Ci::Config::Entry::IdToken } + attributes :script, :tags, :when, :dependencies, :needs, :retry, :parallel, :start_in, :interruptible, :timeout, @@ -158,7 +163,8 @@ module Gitlab ignore: ignored?, allow_failure_criteria: allow_failure_criteria, needs: needs_defined? ? needs_value : nil, - scheduling_type: needs_defined? ? :dag : :stage + scheduling_type: needs_defined? ? :dag : :stage, + id_tokens: id_tokens_value ).compact end diff --git a/lib/gitlab/ci/yaml_processor/result.rb b/lib/gitlab/ci/yaml_processor/result.rb index ff255543d3b..31a4e10a535 100644 --- a/lib/gitlab/ci/yaml_processor/result.rb +++ b/lib/gitlab/ci/yaml_processor/result.rb @@ -107,6 +107,7 @@ module Gitlab cache: job[:cache], resource_group_key: job[:resource_group], scheduling_type: job[:scheduling_type], + id_tokens: job[:id_tokens], options: { image: job[:image], services: job[:services], diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 95ac10704e2..15273a1b99a 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -13907,6 +13907,9 @@ msgstr "" msgid "DevOps adoption" msgstr "" +msgid "DevOps metrics comparison (Alpha)" +msgstr "" + msgid "Developer" msgstr "" @@ -16206,9 +16209,6 @@ msgstr "" msgid "Execution time" msgstr "" -msgid "Executive Dashboard" -msgstr "" - msgid "Existing branch name, tag, or commit SHA" msgstr "" @@ -29295,9 +29295,6 @@ msgstr "" msgid "PackageRegistry|To widen your search, change or remove the filters above." msgstr "" -msgid "PackageRegistry|Type" -msgstr "" - msgid "PackageRegistry|Unable to fetch package version information." msgstr "" diff --git a/spec/frontend/__helpers__/filtered_search_spec_helper.js b/spec/frontend/__helpers__/filtered_search_spec_helper.js index ecf10694a16..f76fdfca229 100644 --- a/spec/frontend/__helpers__/filtered_search_spec_helper.js +++ b/spec/frontend/__helpers__/filtered_search_spec_helper.js @@ -1,3 +1,5 @@ +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; + export default class FilteredSearchSpecHelper { static createFilterVisualTokenHTML(name, operator, value, isSelected) { return FilteredSearchSpecHelper.createFilterVisualToken(name, operator, value, isSelected) @@ -43,7 +45,7 @@ export default class FilteredSearchSpecHelper { static createSearchVisualToken(name) { const li = document.createElement('li'); - li.classList.add('js-visual-token', 'filtered-search-term'); + li.classList.add('js-visual-token', FILTERED_SEARCH_TERM); li.innerHTML = `<div class="name">${name}</div>`; return li; } diff --git a/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js b/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js index 496c144083e..408750e646f 100644 --- a/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js +++ b/spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js @@ -13,6 +13,7 @@ import { DEFAULT_SORT, CONTACTED_DESC, } from '~/ci/runner/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearch from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import BaseToken from '~/vue_shared/components/filtered_search_bar/tokens/base_token.vue'; @@ -34,7 +35,7 @@ describe('RunnerList', () => { const mockOtherSort = CONTACTED_DESC; const mockFilters = [ { type: PARAM_KEY_STATUS, value: { data: STATUS_ONLINE, operator: '=' } }, - { type: 'filtered-search-term', value: { data: '' } }, + { type: FILTERED_SEARCH_TERM, value: { data: '' } }, ]; const expectToHaveLastEmittedInput = (value) => { diff --git a/spec/frontend/ci/runner/mock_data.js b/spec/frontend/ci/runner/mock_data.js index eff5abc21b5..525756ed513 100644 --- a/spec/frontend/ci/runner/mock_data.js +++ b/spec/frontend/ci/runner/mock_data.js @@ -18,6 +18,7 @@ import groupRunnersDataPaginated from 'test_fixtures/graphql/ci/runner/list/grou import groupRunnersCountData from 'test_fixtures/graphql/ci/runner/list/group_runners_count.query.graphql.json'; import { DEFAULT_MEMBERSHIP, RUNNER_PAGE_SIZE } from '~/ci/runner/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; const emptyPageInfo = { __typename: 'PageInfo', @@ -73,7 +74,7 @@ export const mockSearchExamples = [ membership: DEFAULT_MEMBERSHIP, filters: [ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'something' }, }, ], @@ -95,11 +96,11 @@ export const mockSearchExamples = [ membership: DEFAULT_MEMBERSHIP, filters: [ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'something' }, }, { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'else' }, }, ], diff --git a/spec/frontend/ci/runner/runner_search_utils_spec.js b/spec/frontend/ci/runner/runner_search_utils_spec.js index 1db8fa1829b..c5c6a29cd6c 100644 --- a/spec/frontend/ci/runner/runner_search_utils_spec.js +++ b/spec/frontend/ci/runner/runner_search_utils_spec.js @@ -6,6 +6,7 @@ import { fromSearchToVariables, isSearchFiltered, } from 'ee_else_ce/ci/runner/runner_search_utils'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import { mockSearchExamples } from './mock_data'; describe('search_params.js', () => { @@ -48,8 +49,8 @@ describe('search_params.js', () => { it('When search params appear as array, they are concatenated', () => { expect(fromUrlQueryToSearch('?search[]=my&search[]=text').filters).toEqual([ - { type: 'filtered-search-term', value: { data: 'my' } }, - { type: 'filtered-search-term', value: { data: 'text' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'my' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'text' } }, ]); }); }); @@ -93,7 +94,7 @@ describe('search_params.js', () => { fromSearchToVariables({ filters: [ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: '' }, }, ], @@ -106,11 +107,11 @@ describe('search_params.js', () => { fromSearchToVariables({ filters: [ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'something' }, }, { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: '' }, }, ], diff --git a/spec/frontend/editor/schema/ci/ci_schema_spec.js b/spec/frontend/editor/schema/ci/ci_schema_spec.js index 32126a5fd9a..9c622d49db9 100644 --- a/spec/frontend/editor/schema/ci/ci_schema_spec.js +++ b/spec/frontend/editor/schema/ci/ci_schema_spec.js @@ -30,6 +30,7 @@ import RulesYaml from './yaml_tests/positive_tests/rules.yml'; import ProjectPathYaml from './yaml_tests/positive_tests/project_path.yml'; import VariablesYaml from './yaml_tests/positive_tests/variables.yml'; import JobWhenYaml from './yaml_tests/positive_tests/job_when.yml'; +import IdTokensYaml from './yaml_tests/positive_tests/id_tokens.yml'; // YAML NEGATIVE TEST import ArtifactsNegativeYaml from './yaml_tests/negative_tests/artifacts.yml'; @@ -45,6 +46,7 @@ import RulesNegativeYaml from './yaml_tests/negative_tests/rules.yml'; import TriggerNegative from './yaml_tests/negative_tests/trigger.yml'; import VariablesInvalidSyntaxDescYaml from './yaml_tests/negative_tests/variables/invalid_syntax_desc.yml'; import VariablesWrongSyntaxUsageExpand from './yaml_tests/negative_tests/variables/wrong_syntax_usage_expand.yml'; +import IdTokensNegativeYaml from './yaml_tests/negative_tests/id_tokens.yml'; const ajv = new Ajv({ strictTypes: false, @@ -80,6 +82,7 @@ describe('positive tests', () => { RulesYaml, VariablesYaml, ProjectPathYaml, + IdTokensYaml, }), )('schema validates %s', (_, input) => { // We construct a new "JSON" from each main key that is inside a @@ -103,6 +106,7 @@ describe('negative tests', () => { // YAML ArtifactsNegativeYaml, CacheKeyNeative, + IdTokensNegativeYaml, IncludeNegativeYaml, JobWhenNegativeYaml, RulesNegativeYaml, diff --git a/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/id_tokens.yml b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/id_tokens.yml new file mode 100644 index 00000000000..aff2611f16c --- /dev/null +++ b/spec/frontend/editor/schema/ci/yaml_tests/negative_tests/id_tokens.yml @@ -0,0 +1,11 @@ +id_token_with_wrong_aud_type: + id_tokens: + INVALID_ID_TOKEN: + aud: + invalid_prop: invalid + +id_token_with_extra_properties: + id_tokens: + INVALID_ID_TOKEN: + aud: 'https://gitlab.com' + sub: 'not a valid property' diff --git a/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/id_tokens.yml b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/id_tokens.yml new file mode 100644 index 00000000000..169b09ee56f --- /dev/null +++ b/spec/frontend/editor/schema/ci/yaml_tests/positive_tests/id_tokens.yml @@ -0,0 +1,11 @@ +valid_id_tokens: + script: + - echo $ID_TOKEN_1 + - echo $ID_TOKEN_2 + id_tokens: + ID_TOKEN_1: + aud: 'https://gitlab.com' + ID_TOKEN_2: + aud: + - 'https://aws.com' + - 'https://google.com' diff --git a/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js b/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js index 0e5c94edd05..28fcf0b7ec7 100644 --- a/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js +++ b/spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js @@ -4,6 +4,7 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import FilteredSearchSpecHelper from 'helpers/filtered_search_spec_helper'; import waitForPromises from 'helpers/wait_for_promises'; import FilteredSearchVisualTokens from '~/filtered_search/filtered_search_visual_tokens'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; describe('Filtered Search Visual Tokens', () => { let mock; @@ -302,7 +303,7 @@ describe('Filtered Search Visual Tokens', () => { }); const token = tokensContainer.querySelector('.js-visual-token'); - expect(token.classList.contains('filtered-search-term')).toEqual(true); + expect(token.classList.contains(FILTERED_SEARCH_TERM)).toEqual(true); expect(token.querySelector('.name').innerText).toEqual('search term'); expect(token.querySelector('.operator').innerText).toEqual('='); expect(token.querySelector('.value')).toEqual(null); @@ -430,7 +431,7 @@ describe('Filtered Search Visual Tokens', () => { subject.addSearchVisualToken('search term'); const token = tokensContainer.querySelector('.js-visual-token'); - expect(token.classList.contains('filtered-search-term')).toEqual(true); + expect(token.classList.contains(FILTERED_SEARCH_TERM)).toEqual(true); expect(token.querySelector('.name').innerText).toEqual('search term'); expect(token.querySelector('.value')).toEqual(null); }); diff --git a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js index 4580fdb06f2..f346967121c 100644 --- a/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js +++ b/spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js @@ -9,6 +9,7 @@ import { FILTERED_SEARCH_TOKEN_TWO_FACTOR, FILTERED_SEARCH_TOKEN_WITH_INHERITED_PERMISSIONS, } from '~/members/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; jest.mock('~/lib/utils/url_utility', () => { @@ -130,7 +131,7 @@ describe('MembersFilteredSearchBar', () => { expect(findFilteredSearchBar().props('initialFilterValue')).toEqual([ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'foobar', }, @@ -145,7 +146,7 @@ describe('MembersFilteredSearchBar', () => { expect(findFilteredSearchBar().props('initialFilterValue')).toEqual([ { - type: 'filtered-search-term', + type: FILTERED_SEARCH_TERM, value: { data: 'foo bar baz', }, @@ -174,7 +175,7 @@ describe('MembersFilteredSearchBar', () => { findFilteredSearchBar().vm.$emit('onFilter', [ { type: FILTERED_SEARCH_TOKEN_TWO_FACTOR.type, value: { data: 'enabled', operator: '=' } }, - { type: 'filtered-search-term', value: { data: 'foobar' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'foobar' } }, ]); expect(redirectTo).toHaveBeenCalledWith( @@ -187,7 +188,7 @@ describe('MembersFilteredSearchBar', () => { findFilteredSearchBar().vm.$emit('onFilter', [ { type: FILTERED_SEARCH_TOKEN_TWO_FACTOR.type, value: { data: 'enabled', operator: '=' } }, - { type: 'filtered-search-term', value: { data: 'foo bar baz' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'foo bar baz' } }, ]); expect(redirectTo).toHaveBeenCalledWith( @@ -202,7 +203,7 @@ describe('MembersFilteredSearchBar', () => { findFilteredSearchBar().vm.$emit('onFilter', [ { type: FILTERED_SEARCH_TOKEN_TWO_FACTOR.type, value: { data: 'enabled', operator: '=' } }, - { type: 'filtered-search-term', value: { data: 'foobar' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'foobar' } }, ]); expect(redirectTo).toHaveBeenCalledWith( @@ -216,7 +217,7 @@ describe('MembersFilteredSearchBar', () => { createComponent(); findFilteredSearchBar().vm.$emit('onFilter', [ - { type: 'filtered-search-term', value: { data: 'foobar' } }, + { type: FILTERED_SEARCH_TERM, value: { data: 'foobar' } }, ]); expect(redirectTo).toHaveBeenCalledWith('https://localhost/?search=foobar&tab=invited'); diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js index b163557618e..1017ff06a25 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js @@ -18,7 +18,7 @@ import { NO_TAGS_MATCHING_FILTERS_TITLE, NO_TAGS_MATCHING_FILTERS_DESCRIPTION, } from '~/packages_and_registries/container_registry/explorer/constants/index'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import { tagsMock, imageTagsMock, tagsPageInfo } from '../../mock_data'; describe('Tags List', () => { diff --git a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js index 79403d29d18..1e514d85e82 100644 --- a/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js +++ b/spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js @@ -6,7 +6,6 @@ import VueApollo from 'vue-apollo'; import createMockApollo from 'helpers/mock_apollo_helper'; import waitForPromises from 'helpers/wait_for_promises'; import getContainerRepositoriesQuery from 'shared_queries/container_registry/get_container_repositories.query.graphql'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import DeleteImage from '~/packages_and_registries/container_registry/explorer/components/delete_image.vue'; import CliCommands from '~/packages_and_registries/shared/components/cli_commands.vue'; import GroupEmptyState from '~/packages_and_registries/container_registry/explorer/components/list_page/group_empty_state.vue'; @@ -23,6 +22,7 @@ import getContainerRepositoriesDetails from '~/packages_and_registries/container import component from '~/packages_and_registries/container_registry/explorer/pages/list.vue'; import Tracking from '~/tracking'; import PersistedSearch from '~/packages_and_registries/shared/components/persisted_search.vue'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import TitleArea from '~/vue_shared/components/registry/title_area.vue'; import { $toast } from 'jest/packages_and_registries/shared/mocks'; diff --git a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js index dff95364d7d..d237023d0cd 100644 --- a/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js +++ b/spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js @@ -7,13 +7,11 @@ import { createAlert, VARIANT_INFO } from '~/flash'; import * as commonUtils from '~/lib/utils/common_utils'; import PackageListApp from '~/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue'; import { DELETE_PACKAGE_SUCCESS_MESSAGE } from '~/packages_and_registries/infrastructure_registry/list/constants'; -import { - SHOW_DELETE_SUCCESS_ALERT, - FILTERED_SEARCH_TERM, -} from '~/packages_and_registries/shared/constants'; +import { SHOW_DELETE_SUCCESS_ALERT } from '~/packages_and_registries/shared/constants'; import * as packageUtils from '~/packages_and_registries/shared/utils'; import InfrastructureSearch from '~/packages_and_registries/infrastructure_registry/list/components/infrastructure_search.vue'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; jest.mock('~/lib/utils/common_utils'); jest.mock('~/flash'); diff --git a/spec/frontend/packages_and_registries/shared/utils_spec.js b/spec/frontend/packages_and_registries/shared/utils_spec.js index 962cb2257ce..d81cdbfd8bd 100644 --- a/spec/frontend/packages_and_registries/shared/utils_spec.js +++ b/spec/frontend/packages_and_registries/shared/utils_spec.js @@ -1,4 +1,3 @@ -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; import { getQueryParams, keyValueToFilterToken, @@ -7,6 +6,7 @@ import { beautifyPath, getCommitLink, } from '~/packages_and_registries/shared/utils'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import { packageList } from 'jest/packages_and_registries/infrastructure_registry/components/mock_data'; diff --git a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js index e5ad735bf66..ba7262353f0 100644 --- a/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js +++ b/spec/frontend/pipelines/components/pipelines_filtered_search_spec.js @@ -6,7 +6,10 @@ import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; import Api from '~/api'; import axios from '~/lib/utils/axios_utils'; import PipelinesFilteredSearch from '~/pipelines/components/pipelines_list/pipelines_filtered_search.vue'; -import { OPERATORS_IS } from '~/vue_shared/components/filtered_search_bar/constants'; +import { + FILTERED_SEARCH_TERM, + OPERATORS_IS, +} from '~/vue_shared/components/filtered_search_bar/constants'; import { TRACKING_CATEGORIES } from '~/pipelines/constants'; import { users, mockSearch, branches, tags } from '../mock_data'; @@ -111,7 +114,7 @@ describe('Pipelines filtered search', () => { it('disables tag name token when branch name token is active', async () => { findFilteredSearch().vm.$emit('input', [ { type: 'ref', value: { data: 'branch-1', operator: '=' } }, - { type: 'filtered-search-term', value: { data: '' } }, + { type: FILTERED_SEARCH_TERM, value: { data: '' } }, ]); await nextTick(); @@ -122,7 +125,7 @@ describe('Pipelines filtered search', () => { it('disables branch name token when tag name token is active', async () => { findFilteredSearch().vm.$emit('input', [ { type: 'tag', value: { data: 'tag-1', operator: '=' } }, - { type: 'filtered-search-term', value: { data: '' } }, + { type: FILTERED_SEARCH_TERM, value: { data: '' } }, ]); await nextTick(); @@ -139,7 +142,7 @@ describe('Pipelines filtered search', () => { }); it('resets tokens disabled state when clearing tokens by backspace', async () => { - findFilteredSearch().vm.$emit('input', [{ type: 'filtered-search-term', value: { data: '' } }]); + findFilteredSearch().vm.$emit('input', [{ type: FILTERED_SEARCH_TERM, value: { data: '' } }]); await nextTick(); expect(findBranchToken().disabled).toBe(false); @@ -172,7 +175,7 @@ describe('Pipelines filtered search', () => { operator: '=', }, }, - { type: 'filtered-search-term', value: { data: '' } }, + { type: FILTERED_SEARCH_TERM, value: { data: '' } }, ]; expect(findFilteredSearch().props('value')).toMatchObject(expectedValueProp); diff --git a/spec/frontend/vue_shared/components/registry/registry_search_spec.js b/spec/frontend/vue_shared/components/registry/registry_search_spec.js index fa7fabfaef6..591447a37c2 100644 --- a/spec/frontend/vue_shared/components/registry/registry_search_spec.js +++ b/spec/frontend/vue_shared/components/registry/registry_search_spec.js @@ -1,6 +1,6 @@ import { GlSorting, GlSortingItem, GlFilteredSearch } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; -import { FILTERED_SEARCH_TERM } from '~/packages_and_registries/shared/constants'; +import { FILTERED_SEARCH_TERM } from '~/vue_shared/components/filtered_search_bar/constants'; import component from '~/vue_shared/components/registry/registry_search.vue'; describe('Registry Search', () => { diff --git a/spec/lib/gitlab/ci/config/entry/id_token_spec.rb b/spec/lib/gitlab/ci/config/entry/id_token_spec.rb new file mode 100644 index 00000000000..12585d662ec --- /dev/null +++ b/spec/lib/gitlab/ci/config/entry/id_token_spec.rb @@ -0,0 +1,58 @@ +# frozen_string_literal: true + +require 'spec_helper' + +RSpec.describe Gitlab::Ci::Config::Entry::IdToken do + context 'when given `aud` as a string' do + it 'is valid' do + config = { aud: 'https://gitlab.com' } + id_token = described_class.new(config) + + id_token.compose! + + expect(id_token).to be_valid + expect(id_token.value).to eq(aud: 'https://gitlab.com') + end + end + + context 'when given `aud` as an array' do + it 'is valid and concatenates the values' do + config = { aud: ['https://gitlab.com', 'https://aws.com'] } + id_token = described_class.new(config) + + id_token.compose! + + expect(id_token).to be_valid + expect(id_token.value).to eq(aud: ['https://gitlab.com', 'https://aws.com']) + end + end + + context 'when not given an `aud`' do + it 'is invalid' do + config = {} + id_token = described_class.new(config) + + id_token.compose! + + expect(id_token).not_to be_valid + expect(id_token.errors).to match_array([ + 'id token config missing required keys: aud', + 'id token aud should be an array of strings or a string' + ]) + end + end + + context 'when given an unknown keyword' do + it 'is invalid' do + config = { aud: 'https://gitlab.com', unknown: 'test' } + id_token = described_class.new(config) + + id_token.compose! + + expect(id_token).not_to be_valid + expect(id_token.errors).to match_array([ + 'id token config contains unknown keys: unknown' + ]) + end + end +end diff --git a/spec/lib/gitlab/ci/config/entry/job_spec.rb b/spec/lib/gitlab/ci/config/entry/job_spec.rb index acf60a6cdda..22cb1f480c5 100644 --- a/spec/lib/gitlab/ci/config/entry/job_spec.rb +++ b/spec/lib/gitlab/ci/config/entry/job_spec.rb @@ -716,7 +716,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do let(:config) do { before_script: %w[ls pwd], script: 'rspec', - after_script: %w[cleanup] } + after_script: %w[cleanup], + id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } } } end it 'returns correct value' do @@ -730,7 +731,8 @@ RSpec.describe Gitlab::Ci::Config::Entry::Job do only: { refs: %w[branches tags] }, job_variables: {}, root_variables_inheritance: true, - scheduling_type: :stage) + scheduling_type: :stage, + id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } }) end end end diff --git a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb index 7f203168706..5c9f156e054 100644 --- a/spec/lib/gitlab/ci/yaml_processor/result_spec.rb +++ b/spec/lib/gitlab/ci/yaml_processor/result_spec.rb @@ -12,6 +12,20 @@ module Gitlab let(:ci_config) { Gitlab::Ci::Config.new(config_content, user: user) } let(:result) { described_class.new(ci_config: ci_config, warnings: ci_config&.warnings) } + describe '#builds' do + context 'when a job has ID tokens' do + let(:config_content) do + YAML.dump( + test: { stage: 'test', script: 'echo', id_tokens: { TEST_ID_TOKEN: { aud: 'https://gitlab.com' } } } + ) + end + + it 'includes `id_tokens`' do + expect(result.builds.first[:id_tokens]).to eq({ TEST_ID_TOKEN: { aud: 'https://gitlab.com' } }) + end + end + end + describe '#config_metadata' do subject(:config_metadata) { result.config_metadata } diff --git a/spec/models/ci/build_metadata_spec.rb b/spec/models/ci/build_metadata_spec.rb index e728ce0f474..3028f49a49c 100644 --- a/spec/models/ci/build_metadata_spec.rb +++ b/spec/models/ci/build_metadata_spec.rb @@ -107,9 +107,7 @@ RSpec.describe Ci::BuildMetadata do } metadata.id_tokens = { TEST_JWT_TOKEN: { - id_token: { - aud: 'https://gitlab.test' - } + aud: 'https://gitlab.test' } } diff --git a/spec/models/ci/build_spec.rb b/spec/models/ci/build_spec.rb index 813b4b3faa6..9269b341627 100644 --- a/spec/models/ci/build_spec.rb +++ b/spec/models/ci/build_spec.rb @@ -3539,8 +3539,8 @@ RSpec.describe Ci::Build do rsa_key = OpenSSL::PKey::RSA.generate(3072).to_s stub_application_setting(ci_jwt_signing_key: rsa_key) build.metadata.update!(id_tokens: { - 'ID_TOKEN_1' => { id_token: { aud: 'developers' } }, - 'ID_TOKEN_2' => { id_token: { aud: 'maintainers' } } + 'ID_TOKEN_1' => { aud: 'developers' }, + 'ID_TOKEN_2' => { aud: 'maintainers' } }) end diff --git a/spec/services/ci/create_pipeline_service_spec.rb b/spec/services/ci/create_pipeline_service_spec.rb index 67c13649c6f..afa9ab81851 100644 --- a/spec/services/ci/create_pipeline_service_spec.rb +++ b/spec/services/ci/create_pipeline_service_spec.rb @@ -710,6 +710,29 @@ RSpec.describe Ci::CreatePipelineService, :yaml_processor_feature_flag_corectnes end end + context 'when the configuration includes ID tokens' do + it 'creates variables for the ID tokens' do + config = YAML.dump({ + job_with_id_tokens: { + script: 'ls', + id_tokens: { + 'TEST_ID_TOKEN' => { + aud: 'https://gitlab.com' + } + } + } + }) + stub_ci_pipeline_yaml_file(config) + + result = execute_service.payload + + expect(result).to be_persisted + expect(result.builds.first.id_tokens).to eq({ + 'TEST_ID_TOKEN' => { 'aud' => 'https://gitlab.com' } + }) + end + end + context 'with manual actions' do before do config = YAML.dump({ deploy: { script: 'ls', when: 'manual' } }) |