Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-11-23 09:07:43 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-11-23 09:07:43 +0300
commit9d15ef5c5caf584ae16398940c16f2bdafd6f3e2 (patch)
tree7ae2422c4415ed9da8aba67391c5640fad0d9da8
parent26eeb803e0a3412f0b098d5c5a23f32b763f44c2 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--app/assets/javascripts/editor/schema/ci.json33
-rw-r--r--app/assets/javascripts/filtered_search/filtered_search_visual_tokens.js7
-rw-r--r--app/assets/javascripts/members/components/filter_sort/members_filtered_search_bar.vue6
-rw-r--r--app/assets/javascripts/members/constants.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/components/details_page/tags_list.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/container_registry/explorer/pages/list.vue2
-rw-r--r--app/assets/javascripts/packages_and_registries/harbor_registry/utils.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/components/packages_list_app.vue6
-rw-r--r--app/assets/javascripts/packages_and_registries/infrastructure_registry/list/stores/actions.js3
-rw-r--r--app/assets/javascripts/packages_and_registries/package_registry/components/list/package_search.vue18
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/constants/package_registry.js2
-rw-r--r--app/assets/javascripts/packages_and_registries/shared/utils.js2
-rw-r--r--app/assets/javascripts/vue_shared/components/filtered_search_bar/constants.js1
-rw-r--r--app/assets/javascripts/vue_shared/components/paginated_table_with_search_and_tabs/paginated_table_with_search_and_tabs.vue3
-rw-r--r--app/assets/javascripts/vue_shared/components/registry/registry_search.vue2
-rw-r--r--app/models/ci/build.rb6
-rw-r--r--app/validators/json_schemas/build_metadata_id_tokens.json29
-rw-r--r--lib/gitlab/ci/config/entry/id_token.rb28
-rw-r--r--lib/gitlab/ci/config/entry/job.rb10
-rw-r--r--lib/gitlab/ci/yaml_processor/result.rb1
-rw-r--r--locale/gitlab.pot9
-rw-r--r--spec/frontend/__helpers__/filtered_search_spec_helper.js4
-rw-r--r--spec/frontend/ci/runner/components/runner_filtered_search_bar_spec.js3
-rw-r--r--spec/frontend/ci/runner/mock_data.js7
-rw-r--r--spec/frontend/ci/runner/runner_search_utils_spec.js11
-rw-r--r--spec/frontend/editor/schema/ci/ci_schema_spec.js4
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/negative_tests/id_tokens.yml11
-rw-r--r--spec/frontend/editor/schema/ci/yaml_tests/positive_tests/id_tokens.yml11
-rw-r--r--spec/frontend/filtered_search/filtered_search_visual_tokens_spec.js5
-rw-r--r--spec/frontend/members/components/filter_sort/members_filtered_search_bar_spec.js13
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/components/details_page/tags_list_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/container_registry/explorer/pages/list_spec.js2
-rw-r--r--spec/frontend/packages_and_registries/infrastructure_registry/components/list/components/packages_list_app_spec.js6
-rw-r--r--spec/frontend/packages_and_registries/shared/utils_spec.js2
-rw-r--r--spec/frontend/pipelines/components/pipelines_filtered_search_spec.js13
-rw-r--r--spec/frontend/vue_shared/components/registry/registry_search_spec.js2
-rw-r--r--spec/lib/gitlab/ci/config/entry/id_token_spec.rb58
-rw-r--r--spec/lib/gitlab/ci/config/entry/job_spec.rb6
-rw-r--r--spec/lib/gitlab/ci/yaml_processor/result_spec.rb14
-rw-r--r--spec/models/ci/build_metadata_spec.rb4
-rw-r--r--spec/models/ci/build_spec.rb4
-rw-r--r--spec/services/ci/create_pipeline_service_spec.rb23
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' } })