Merge pull request #7281 from mabashian/7127-cred-input-details

Updates credential details to support plugin and prompt fields

Reviewed-by: John Hill <johill@redhat.com>
             https://github.com/unlikelyzero
This commit is contained in:
softwarefactory-project-zuul[bot]
2020-10-21 00:32:26 +00:00
committed by GitHub
5 changed files with 580 additions and 415 deletions

View File

@@ -20,10 +20,38 @@ class Credentials extends Base {
return this.http.options(`${this.baseUrl}${id}/access_list/`); return this.http.options(`${this.baseUrl}${id}/access_list/`);
} }
readInputSources(id, params) { readInputSources(id) {
return this.http.get(`${this.baseUrl}${id}/input_sources/`, { const maxRequests = 5;
params, let requestCounter = 0;
}); const fetchInputSources = async (pageNo = 1, inputSources = []) => {
try {
requestCounter++;
const { data } = await this.http.get(
`${this.baseUrl}${id}/input_sources/`,
{
params: {
page: pageNo,
page_size: 200,
},
}
);
if (data?.next && requestCounter <= maxRequests) {
return fetchInputSources(
pageNo + 1,
inputSources.concat(data.results)
);
}
return Promise.resolve({
data: {
results: inputSources.concat(data.results),
},
});
} catch (error) {
return Promise.reject(error);
}
};
return fetchInputSources();
} }
test(id, data) { test(id, data) {

View File

@@ -1,9 +1,9 @@
import React, { useState, useEffect, useCallback } from 'react'; import React, { Fragment, useEffect, useCallback } from 'react';
import { Link, useHistory } from 'react-router-dom'; import { Link, useHistory } from 'react-router-dom';
import { withI18n } from '@lingui/react'; import { withI18n } from '@lingui/react';
import { t } from '@lingui/macro'; import { t } from '@lingui/macro';
import { shape } from 'prop-types'; import { shape } from 'prop-types';
import styled from 'styled-components';
import { Button, List, ListItem } from '@patternfly/react-core'; import { Button, List, ListItem } from '@patternfly/react-core';
import AlertModal from '../../../components/AlertModal'; import AlertModal from '../../../components/AlertModal';
import { CardBody, CardActionsRow } from '../../../components/Card'; import { CardBody, CardActionsRow } from '../../../components/Card';
@@ -11,15 +11,26 @@ import ContentError from '../../../components/ContentError';
import ContentLoading from '../../../components/ContentLoading'; import ContentLoading from '../../../components/ContentLoading';
import DeleteButton from '../../../components/DeleteButton'; import DeleteButton from '../../../components/DeleteButton';
import { import {
DetailList,
Detail, Detail,
DetailList,
UserDateDetail, UserDateDetail,
} from '../../../components/DetailList'; } from '../../../components/DetailList';
import ChipGroup from '../../../components/ChipGroup';
import CodeMirrorInput from '../../../components/CodeMirrorInput';
import CredentialChip from '../../../components/CredentialChip';
import ErrorDetail from '../../../components/ErrorDetail'; import ErrorDetail from '../../../components/ErrorDetail';
import { CredentialsAPI, CredentialTypesAPI } from '../../../api'; import { CredentialsAPI, CredentialTypesAPI } from '../../../api';
import { Credential } from '../../../types'; import { Credential } from '../../../types';
import useRequest, { useDismissableError } from '../../../util/useRequest'; import useRequest, { useDismissableError } from '../../../util/useRequest';
const PluginInputMetadata = styled(CodeMirrorInput)`
grid-column: 1 / -1;
`;
const PluginFieldText = styled.p`
margin-top: 10px;
`;
function CredentialDetail({ i18n, credential }) { function CredentialDetail({ i18n, credential }) {
const { const {
id: credentialId, id: credentialId,
@@ -36,31 +47,44 @@ function CredentialDetail({ i18n, credential }) {
user_capabilities, user_capabilities,
}, },
} = credential; } = credential;
const [fields, setFields] = useState([]);
const [managedByTower, setManagedByTower] = useState([]);
const [contentError, setContentError] = useState(null);
const [hasContentLoading, setHasContentLoading] = useState(true);
const history = useHistory(); const history = useHistory();
useEffect(() => { const {
(async () => { result: { fields, managedByTower, inputSources },
setContentError(null); request: fetchDetails,
setHasContentLoading(true); isLoading: hasContentLoading,
try { error: contentError,
const { } = useRequest(
useCallback(async () => {
const [
{
data: { inputs: credentialTypeInputs, managed_by_tower }, data: { inputs: credentialTypeInputs, managed_by_tower },
} = await CredentialTypesAPI.readDetail(credential_type.id); },
{
setFields(credentialTypeInputs.fields || []); data: { results: loadedInputSources },
setManagedByTower(managed_by_tower); },
} catch (error) { ] = await Promise.all([
setContentError(error); CredentialTypesAPI.readDetail(credential_type.id),
} finally { CredentialsAPI.readInputSources(credentialId),
setHasContentLoading(false); ]);
} return {
})(); fields: credentialTypeInputs.fields || [],
}, [credential_type]); managedByTower: managed_by_tower,
inputSources: loadedInputSources.reduce(
(inputSourcesMap, inputSource) => {
inputSourcesMap[inputSource.input_field_name] = inputSource;
return inputSourcesMap;
},
{}
),
};
}, [credentialId, credential_type]),
{
fields: [],
managedByTower: true,
inputSources: {},
}
);
const { const {
request: deleteCredential, request: deleteCredential,
@@ -75,34 +99,84 @@ function CredentialDetail({ i18n, credential }) {
const { error, dismissError } = useDismissableError(deleteError); const { error, dismissError } = useDismissableError(deleteError);
const renderDetail = ({ id, label, type }) => { const renderDetail = ({ id, label, type, ask_at_runtime }) => {
let detail; if (inputSources[id]) {
return (
<Fragment key={id}>
<Detail
id={`credential-${id}-detail`}
fullWidth
label={<span>{label} *</span>}
value={
<ChipGroup numChips={1} totalChips={1}>
<CredentialChip
credential={inputSources[id].summary_fields.source_credential}
isReadOnly
/>
</ChipGroup>
}
/>
<PluginInputMetadata
id={`credential-${id}-metadata`}
mode="javascript"
readOnly
value={JSON.stringify(inputSources[id].metadata, null, 2)}
onChange={() => {}}
rows={5}
hasErrors={false}
/>
</Fragment>
);
}
if (type === 'boolean') { if (type === 'boolean') {
detail = ( return (
<Detail <Detail
id={`credential-${id}-detail`}
key={id} key={id}
label={i18n._(t`Options`)} label={i18n._(t`Options`)}
value={<List>{inputs[id] && <ListItem>{label}</ListItem>}</List>} value={<List>{inputs[id] && <ListItem>{label}</ListItem>}</List>}
/> />
); );
} else if (inputs[id] === '$encrypted$') { }
const isEncrypted = true;
detail = ( if (inputs[id] === '$encrypted$') {
return (
<Detail <Detail
id={`credential-${id}-detail`}
key={id} key={id}
label={label} label={label}
value={i18n._(t`Encrypted`)} value={i18n._(t`Encrypted`)}
isEncrypted={isEncrypted} isEncrypted
/> />
); );
} else {
detail = <Detail key={id} label={label} value={inputs[id]} />;
} }
return detail; if (ask_at_runtime && inputs[id] === 'ASK') {
return (
<Detail
id={`credential-${id}-detail`}
key={id}
label={label}
value={i18n._(t`Prompt on launch`)}
/>
);
}
return (
<Detail
id={`credential-${id}-detail`}
key={id}
label={label}
value={inputs[id]}
/>
);
}; };
useEffect(() => {
fetchDetails();
}, [fetchDetails]);
if (hasContentLoading) { if (hasContentLoading) {
return <ContentLoading />; return <ContentLoading />;
} }
@@ -114,10 +188,19 @@ function CredentialDetail({ i18n, credential }) {
return ( return (
<CardBody> <CardBody>
<DetailList> <DetailList>
<Detail label={i18n._(t`Name`)} value={name} /> <Detail
<Detail label={i18n._(t`Description`)} value={description} /> id="credential-name-detail"
label={i18n._(t`Name`)}
value={name}
/>
<Detail
id="credential-description-detail"
label={i18n._(t`Description`)}
value={description}
/>
{organization && ( {organization && (
<Detail <Detail
id="credential-organization-detail"
label={i18n._(t`Organization`)} label={i18n._(t`Organization`)}
value={ value={
<Link to={`/organizations/${organization.id}/details`}> <Link to={`/organizations/${organization.id}/details`}>
@@ -127,6 +210,7 @@ function CredentialDetail({ i18n, credential }) {
/> />
)} )}
<Detail <Detail
id="credential-credential_type-detail"
label={i18n._(t`Credential Type`)} label={i18n._(t`Credential Type`)}
value={ value={
managedByTower ? ( managedByTower ? (
@@ -142,16 +226,25 @@ function CredentialDetail({ i18n, credential }) {
{fields.map(field => renderDetail(field))} {fields.map(field => renderDetail(field))}
<UserDateDetail <UserDateDetail
id="credential-created-detail"
label={i18n._(t`Created`)} label={i18n._(t`Created`)}
date={created} date={created}
user={created_by} user={created_by}
/> />
<UserDateDetail <UserDateDetail
id="credential-last_modified-detail"
label={i18n._(t`Last Modified`)} label={i18n._(t`Last Modified`)}
date={modified} date={modified}
user={modified_by} user={modified_by}
/> />
</DetailList> </DetailList>
{Object.keys(inputSources).length > 0 && (
<PluginFieldText>
{i18n._(
t`* This field will be retrieved from an external secret management system using the specified credential.`
)}
</PluginFieldText>
)}
<CardActionsRow> <CardActionsRow>
{user_capabilities.edit && ( {user_capabilities.edit && (
<Button component={Link} to={`/credentials/${credentialId}/edit`}> <Button component={Link} to={`/credentials/${credentialId}/edit`}>

View File

@@ -12,10 +12,37 @@ jest.mock('../../../api');
const mockCredential = mockCredentials.results[0]; const mockCredential = mockCredentials.results[0];
const mockInputSource = {
id: 33,
type: 'credential_input_source',
url: '/api/v2/credential_input_sources/33/',
summary_fields: {
source_credential: {
id: 424,
name: 'External Credential',
description: '',
kind: 'conjur',
cloud: false,
credential_type_id: 20,
},
},
input_field_name: 'ssh_key_unlock',
metadata: {
secret_path: '/foo/bar/baz',
secret_version: '17',
},
};
CredentialTypesAPI.readDetail.mockResolvedValue({ CredentialTypesAPI.readDetail.mockResolvedValue({
data: mockCredentialType, data: mockCredentialType,
}); });
CredentialsAPI.readInputSources.mockResolvedValue({
data: {
results: [mockInputSource],
},
});
function expectDetailToMatch(wrapper, label, value) { function expectDetailToMatch(wrapper, label, value) {
const detail = wrapper.find(`Detail[label="${label}"]`); const detail = wrapper.find(`Detail[label="${label}"]`);
expect(detail).toHaveLength(1); expect(detail).toHaveLength(1);
@@ -52,6 +79,18 @@ describe('<CredentialDetail />', () => {
mockCredential.summary_fields.credential_type.name mockCredential.summary_fields.credential_type.name
); );
expectDetailToMatch(wrapper, 'Username', mockCredential.inputs.username); expectDetailToMatch(wrapper, 'Username', mockCredential.inputs.username);
expectDetailToMatch(wrapper, 'Password', 'Encrypted');
expectDetailToMatch(wrapper, 'SSH Private Key', 'Encrypted');
expectDetailToMatch(wrapper, 'Signed SSH Certificate', 'Encrypted');
const sshKeyUnlockDetail = wrapper.find(
'Detail#credential-ssh_key_unlock-detail'
);
expect(sshKeyUnlockDetail.length).toBe(1);
expect(sshKeyUnlockDetail.find('CredentialChip').length).toBe(1);
expect(
wrapper.find('CodeMirrorInput#credential-ssh_key_unlock-metadata').props()
.value
).toBe(JSON.stringify(mockInputSource.metadata, null, 2));
expectDetailToMatch( expectDetailToMatch(
wrapper, wrapper,
'Privilege Escalation Method', 'Privilege Escalation Method',
@@ -62,6 +101,11 @@ describe('<CredentialDetail />', () => {
'Privilege Escalation Username', 'Privilege Escalation Username',
mockCredential.inputs.become_username mockCredential.inputs.become_username
); );
expectDetailToMatch(
wrapper,
'Privilege Escalation Password',
'Prompt on launch'
);
expect(wrapper.find(`Detail[label="Options"] ListItem`).text()).toEqual( expect(wrapper.find(`Detail[label="Options"] ListItem`).text()).toEqual(
'Authorize' 'Authorize'
); );

View File

@@ -151,7 +151,7 @@ function CredentialEdit({ credential, me }) {
}; };
if (error) { if (error) {
return <ContentError />; return <ContentError error={error} />;
} }
if (isLoading) { if (isLoading) {

View File

@@ -3,394 +3,394 @@
"next": "/api/v2/credentials/", "next": "/api/v2/credentials/",
"previous": null, "previous": null,
"results": [ "results": [
{ {
"id": 1,
"type": "credential",
"url": "/api/v2/credentials/1/",
"related": {
"created_by": "/api/v2/users/1/",
"modified_by": "/api/v2/users/1/",
"activity_stream": "/api/v2/credentials/1/activity_stream/",
"access_list": "/api/v2/credentials/1/access_list/",
"object_roles": "/api/v2/credentials/1/object_roles/",
"owner_users": "/api/v2/credentials/1/owner_users/",
"owner_teams": "/api/v2/credentials/1/owner_teams/",
"copy": "/api/v2/credentials/1/copy/",
"input_sources": "/api/v2/credentials/1/input_sources/",
"credential_type": "/api/v2/credential_types/23/",
"user": "/api/v2/users/7/"
},
"summary_fields": {
"organization": {
"id": 1, "id": 1,
"type": "credential", "name": "Org",
"url": "/api/v2/credentials/1/", "description": ""
"related": {
"created_by": "/api/v2/users/1/",
"modified_by": "/api/v2/users/1/",
"activity_stream": "/api/v2/credentials/1/activity_stream/",
"access_list": "/api/v2/credentials/1/access_list/",
"object_roles": "/api/v2/credentials/1/object_roles/",
"owner_users": "/api/v2/credentials/1/owner_users/",
"owner_teams": "/api/v2/credentials/1/owner_teams/",
"copy": "/api/v2/credentials/1/copy/",
"input_sources": "/api/v2/credentials/1/input_sources/",
"credential_type": "/api/v2/credential_types/23/",
"user": "/api/v2/users/7/"
},
"summary_fields": {
"organization": {
"id": 1,
"name": "Org",
"description": ""
},
"credential_type": {
"id": 1,
"name": "Machine",
"description": ""
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 284
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 285
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 286
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
}
},
"created": "2019-12-17T16:12:25.258897Z",
"modified": "2019-12-17T16:12:25.258920Z",
"name": "Foo",
"description": "Foo Description",
"organization": 1,
"credential_type": 1,
"inputs": {
"password": "$encrypted$",
"username": "foo",
"ssh_key_data": "$encrypted$",
"become_method": "sudo",
"become_password": "$encrypted$",
"become_username": "bar",
"ssh_public_key_data": "$encrypted$",
"authorize": true
}, },
"kind": null, "credential_type": {
"cloud": true, "id": 1,
"kubernetes": false "name": "Machine",
"description": ""
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 284
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 285
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 286
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
}
}, },
{ "created": "2019-12-17T16:12:25.258897Z",
"modified": "2019-12-17T16:12:25.258920Z",
"name": "Foo",
"description": "Foo Description",
"organization": 1,
"credential_type": 1,
"inputs": {
"password": "$encrypted$",
"username": "foo",
"ssh_key_data": "$encrypted$",
"become_method": "sudo",
"become_password": "ASK",
"become_username": "bar",
"ssh_public_key_data": "$encrypted$",
"authorize": true
},
"kind": null,
"cloud": true,
"kubernetes": false
},
{
"id": 2,
"type": "credential",
"url": "/api/v2/credentials/2/",
"related": {
"created_by": "/api/v2/users/8/",
"modified_by": "/api/v2/users/12/",
"activity_stream": "/api/v2/credentials/2/activity_stream/",
"access_list": "/api/v2/credentials/2/access_list/",
"object_roles": "/api/v2/credentials/2/object_roles/",
"owner_users": "/api/v2/credentials/2/owner_users/",
"owner_teams": "/api/v2/credentials/2/owner_teams/",
"copy": "/api/v2/credentials/2/copy/",
"input_sources": "/api/v2/credentials/2/input_sources/",
"credential_type": "/api/v2/credential_types/1/",
"user": "/api/v2/users/7/"
},
"summary_fields": {
"credential_type": {
"id": 1,
"name": "Machine",
"description": ""
},
"created_by": {
"id": 8,
"username": "user-2",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 12,
"username": "user-6",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 81
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 82
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 83
}
},
"user_capabilities": {
"edit": false,
"delete": false,
"copy": false,
"use": false
},
"owners": [
{
"id": 7,
"type": "user",
"name": "user-1",
"description": " ",
"url": "/api/v2/users/7/"
}
]
},
"created": "2019-12-16T21:04:40.896097Z",
"modified": "2019-12-16T21:04:40.896121Z",
"name": "Bar",
"description": "",
"organization": null,
"credential_type": 1,
"inputs": {},
"kind": "ssh",
"cloud": false,
"kubernetes": false
},
{
"id": 3,
"type": "credential",
"url": "/api/v2/credentials/3/",
"related": {
"created_by": "/api/v2/users/9/",
"modified_by": "/api/v2/users/13/",
"activity_stream": "/api/v2/credentials/3/activity_stream/",
"access_list": "/api/v2/credentials/3/access_list/",
"object_roles": "/api/v2/credentials/3/object_roles/",
"owner_users": "/api/v2/credentials/3/owner_users/",
"owner_teams": "/api/v2/credentials/3/owner_teams/",
"copy": "/api/v2/credentials/3/copy/",
"input_sources": "/api/v2/credentials/3/input_sources/",
"credential_type": "/api/v2/credential_types/1/",
"user": "/api/v2/users/8/"
},
"summary_fields": {
"credential_type": {
"id": 1,
"name": "Machine",
"description": ""
},
"created_by": {
"id": 9,
"username": "user-3",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 13,
"username": "user-7",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 84
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 85
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 86
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
},
"owners": [
{
"id": 8,
"type": "user",
"name": "user-2",
"description": " ",
"url": "/api/v2/users/8/"
}
]
},
"created": "2019-12-16T21:04:40.955954Z",
"modified": "2019-12-16T21:04:40.955976Z",
"name": "Baz",
"description": "",
"organization": null,
"credential_type": 1,
"inputs": {},
"kind": "ssh",
"cloud": false,
"kubernetes": false
},
{
"id": 4,
"type": "credential",
"url": "/api/v2/credentials/4/",
"related": {
"created_by": "/api/v2/users/1/",
"modified_by": "/api/v2/users/1/",
"activity_stream": "/api/v2/credentials/4/activity_stream/",
"access_list": "/api/v2/credentials/4/access_list/",
"object_roles": "/api/v2/credentials/4/object_roles/",
"owner_users": "/api/v2/credentials/4/owner_users/",
"owner_teams": "/api/v2/credentials/4/owner_teams/",
"copy": "/api/v2/credentials/4/copy/",
"input_sources": "/api/v2/credentials/4/input_sources/",
"credential_type": "/api/v2/credential_types/25/",
"user": "/api/v2/users/1/"
},
"summary_fields": {
"credential_type": {
"id": 2, "id": 2,
"type": "credential", "name": "Vault",
"url": "/api/v2/credentials/2/", "description": ""
"related": {
"created_by": "/api/v2/users/8/",
"modified_by": "/api/v2/users/12/",
"activity_stream": "/api/v2/credentials/2/activity_stream/",
"access_list": "/api/v2/credentials/2/access_list/",
"object_roles": "/api/v2/credentials/2/object_roles/",
"owner_users": "/api/v2/credentials/2/owner_users/",
"owner_teams": "/api/v2/credentials/2/owner_teams/",
"copy": "/api/v2/credentials/2/copy/",
"input_sources": "/api/v2/credentials/2/input_sources/",
"credential_type": "/api/v2/credential_types/1/",
"user": "/api/v2/users/7/"
},
"summary_fields": {
"credential_type": {
"id": 1,
"name": "Machine",
"description": ""
},
"created_by": {
"id": 8,
"username": "user-2",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 12,
"username": "user-6",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 81
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 82
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 83
}
},
"user_capabilities": {
"edit": false,
"delete": false,
"copy": false,
"use": false
},
"owners": [
{
"id": 7,
"type": "user",
"name": "user-1",
"description": " ",
"url": "/api/v2/users/7/"
}
]
},
"created": "2019-12-16T21:04:40.896097Z",
"modified": "2019-12-16T21:04:40.896121Z",
"name": "Bar",
"description": "",
"organization": null,
"credential_type": 1,
"inputs": {},
"kind": "ssh",
"cloud": false,
"kubernetes": false
},
{
"id": 3,
"type": "credential",
"url": "/api/v2/credentials/3/",
"related": {
"created_by": "/api/v2/users/9/",
"modified_by": "/api/v2/users/13/",
"activity_stream": "/api/v2/credentials/3/activity_stream/",
"access_list": "/api/v2/credentials/3/access_list/",
"object_roles": "/api/v2/credentials/3/object_roles/",
"owner_users": "/api/v2/credentials/3/owner_users/",
"owner_teams": "/api/v2/credentials/3/owner_teams/",
"copy": "/api/v2/credentials/3/copy/",
"input_sources": "/api/v2/credentials/3/input_sources/",
"credential_type": "/api/v2/credential_types/1/",
"user": "/api/v2/users/8/"
},
"summary_fields": {
"credential_type": {
"id": 1,
"name": "Machine",
"description": ""
},
"created_by": {
"id": 9,
"username": "user-3",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 13,
"username": "user-7",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 84
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 85
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 86
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
},
"owners": [
{
"id": 8,
"type": "user",
"name": "user-2",
"description": " ",
"url": "/api/v2/users/8/"
}
]
},
"created": "2019-12-16T21:04:40.955954Z",
"modified": "2019-12-16T21:04:40.955976Z",
"name": "Baz",
"description": "",
"organization": null,
"credential_type": 1,
"inputs": {},
"kind": "ssh",
"cloud": false,
"kubernetes": false
},
{
"id": 4,
"type": "credential",
"url": "/api/v2/credentials/4/",
"related": {
"created_by": "/api/v2/users/1/",
"modified_by": "/api/v2/users/1/",
"activity_stream": "/api/v2/credentials/4/activity_stream/",
"access_list": "/api/v2/credentials/4/access_list/",
"object_roles": "/api/v2/credentials/4/object_roles/",
"owner_users": "/api/v2/credentials/4/owner_users/",
"owner_teams": "/api/v2/credentials/4/owner_teams/",
"copy": "/api/v2/credentials/4/copy/",
"input_sources": "/api/v2/credentials/4/input_sources/",
"credential_type": "/api/v2/credential_types/25/",
"user": "/api/v2/users/1/"
}, },
"summary_fields": { "created_by": {
"credential_type": { "id": 1,
"id": 2, "username": "admin",
"name": "Vault", "first_name": "",
"description": "" "last_name": ""
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 318
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 319
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 320
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
},
"owners": [
{
"id": 1,
"type": "user",
"name": "admin",
"description": " ",
"url": "/api/v2/users/1/"
}
]
}, },
"created": "2019-12-18T16:31:09.772005Z", "modified_by": {
"modified": "2019-12-18T16:31:09.832666Z", "id": 1,
"name": "FooBar", "username": "admin",
"description": "", "first_name": "",
"organization": null, "last_name": ""
"credential_type": 2, },
"inputs": {}, "object_roles": {
"kind": null, "admin_role": {
"cloud": true, "description": "Can manage all aspects of the credential",
"kubernetes": false "name": "Admin",
"id": 318
},
"use_role": {
"description": "Can use the credential in a job template",
"name": "Use",
"id": 319
},
"read_role": {
"description": "May view settings for the credential",
"name": "Read",
"id": 320
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
},
"owners": [
{
"id": 1,
"type": "user",
"name": "admin",
"description": " ",
"url": "/api/v2/users/1/"
}
]
},
"created": "2019-12-18T16:31:09.772005Z",
"modified": "2019-12-18T16:31:09.832666Z",
"name": "FooBar",
"description": "",
"organization": null,
"credential_type": 2,
"inputs": {},
"kind": null,
"cloud": true,
"kubernetes": false
}, },
{ {
"id": 5, "id": 5,
"type": "credential", "type": "credential",
"url": "/api/v2/credentials/5/", "url": "/api/v2/credentials/5/",
"related": { "related": {
"created_by": "/api/v2/users/1/", "created_by": "/api/v2/users/1/",
"modified_by": "/api/v2/users/1/", "modified_by": "/api/v2/users/1/",
"activity_stream": "/api/v2/credentials/5/activity_stream/", "activity_stream": "/api/v2/credentials/5/activity_stream/",
"access_list": "/api/v2/credentials/5/access_list/", "access_list": "/api/v2/credentials/5/access_list/",
"object_roles": "/api/v2/credentials/5/object_roles/", "object_roles": "/api/v2/credentials/5/object_roles/",
"owner_users": "/api/v2/credentials/5/owner_users/", "owner_users": "/api/v2/credentials/5/owner_users/",
"owner_teams": "/api/v2/credentials/5/owner_teams/", "owner_teams": "/api/v2/credentials/5/owner_teams/",
"copy": "/api/v2/credentials/5/copy/", "copy": "/api/v2/credentials/5/copy/",
"input_sources": "/api/v2/credentials/5/input_sources/", "input_sources": "/api/v2/credentials/5/input_sources/",
"credential_type": "/api/v2/credential_types/25/", "credential_type": "/api/v2/credential_types/25/",
"user": "/api/v2/users/1/" "user": "/api/v2/users/1/"
}, },
"summary_fields": { "summary_fields": {
"credential_type": { "credential_type": {
"id": 3, "id": 3,
"name": "Source Control", "name": "Source Control",
"description": "" "description": ""
},
"created_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"modified_by": {
"id": 1,
"username": "admin",
"first_name": "",
"last_name": ""
},
"object_roles": {
"admin_role": {
"description": "Can manage all aspects of the credential",
"name": "Admin",
"id": 290
}, },
"created_by": { "use_role": {
"id": 1, "description": "Can use the credential in a job template",
"username": "admin", "name": "Use",
"first_name": "", "id": 291
"last_name": ""
}, },
"modified_by": { "read_role": {
"id": 1, "description": "May view settings for the credential",
"username": "admin", "name": "Read",
"first_name": "", "id": 292
"last_name": "" }
}, },
"object_roles": { "user_capabilities": {
"admin_role": { "edit": true,
"description": "Can manage all aspects of the credential", "delete": true,
"name": "Admin", "copy": true,
"id": 290 "use": true
}, },
"use_role": { "owners": [
"description": "Can use the credential in a job template", {
"name": "Use", "id": 1,
"id": 291 "type": "user",
}, "name": "admin",
"read_role": { "description": " ",
"description": "May view settings for the credential", "url": "/api/v2/users/1/"
"name": "Read", }
"id": 292 ]
}
},
"user_capabilities": {
"edit": true,
"delete": true,
"copy": true,
"use": true
},
"owners": [
{
"id": 1,
"type": "user",
"name": "admin",
"description": " ",
"url": "/api/v2/users/1/"
}
]
}, },
"created": "2019-12-17T16:12:44.923123Z", "created": "2019-12-17T16:12:44.923123Z",
"modified": "2019-12-17T16:12:44.923151Z", "modified": "2019-12-17T16:12:44.923151Z",
@@ -404,4 +404,4 @@
"kubernetes": false "kubernetes": false
} }
] ]
} }