mirror of
https://github.com/awatertrevi/infisical.git
synced 2026-09-22 13:39:35 +00:00
feat(secret-sync): Allow custom field label on 1pass sync
This commit is contained in:
@@ -2394,7 +2394,8 @@ export const SecretSyncs = {
|
|||||||
keyOcid: "The OCID (Oracle Cloud Identifier) of the encryption key to use when creating secrets in the vault."
|
keyOcid: "The OCID (Oracle Cloud Identifier) of the encryption key to use when creating secrets in the vault."
|
||||||
},
|
},
|
||||||
ONEPASS: {
|
ONEPASS: {
|
||||||
vaultId: "The ID of the 1Password vault to sync secrets to."
|
vaultId: "The ID of the 1Password vault to sync secrets to.",
|
||||||
|
valueLabel: "The label of the entry that holds the secret value."
|
||||||
},
|
},
|
||||||
HEROKU: {
|
HEROKU: {
|
||||||
app: "The ID of the Heroku app to sync secrets to.",
|
app: "The ID of the Heroku app to sync secrets to.",
|
||||||
|
|||||||
@@ -6,7 +6,6 @@ import {
|
|||||||
TOnePassListVariablesResponse,
|
TOnePassListVariablesResponse,
|
||||||
TOnePassSyncWithCredentials,
|
TOnePassSyncWithCredentials,
|
||||||
TOnePassVariable,
|
TOnePassVariable,
|
||||||
TOnePassVariableDetails,
|
|
||||||
TPostOnePassVariable,
|
TPostOnePassVariable,
|
||||||
TPutOnePassVariable
|
TPutOnePassVariable
|
||||||
} from "@app/services/secret-sync/1password/1password-sync-types";
|
} from "@app/services/secret-sync/1password/1password-sync-types";
|
||||||
@@ -14,7 +13,10 @@ import { SecretSyncError } from "@app/services/secret-sync/secret-sync-errors";
|
|||||||
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
import { matchesSchema } from "@app/services/secret-sync/secret-sync-fns";
|
||||||
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
import { TSecretMap } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const listOnePassItems = async ({ instanceUrl, apiToken, vaultId }: TOnePassListVariables) => {
|
// This should not be changed or it may break existing logic
|
||||||
|
const VALUE_LABEL_DEFAULT = "value";
|
||||||
|
|
||||||
|
const listOnePassItems = async ({ instanceUrl, apiToken, vaultId, valueLabel }: TOnePassListVariables) => {
|
||||||
const { data } = await request.get<TOnePassListVariablesResponse>(`${instanceUrl}/v1/vaults/${vaultId}/items`, {
|
const { data } = await request.get<TOnePassListVariablesResponse>(`${instanceUrl}/v1/vaults/${vaultId}/items`, {
|
||||||
headers: {
|
headers: {
|
||||||
Authorization: `Bearer ${apiToken}`,
|
Authorization: `Bearer ${apiToken}`,
|
||||||
@@ -22,36 +24,49 @@ const listOnePassItems = async ({ instanceUrl, apiToken, vaultId }: TOnePassList
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
const result: Record<string, TOnePassVariable & { value: string; fieldId: string }> = {};
|
const items: Record<string, TOnePassVariable & { value: string; fieldId: string }> = {};
|
||||||
|
const duplicates: Record<string, string> = {};
|
||||||
|
|
||||||
for await (const s of data) {
|
for await (const s of data) {
|
||||||
const { data: secret } = await request.get<TOnePassVariableDetails>(
|
// eslint-disable-next-line no-continue
|
||||||
`${instanceUrl}/v1/vaults/${vaultId}/items/${s.id}`,
|
if (s.category !== "API_CREDENTIAL") continue;
|
||||||
{
|
|
||||||
headers: {
|
|
||||||
Authorization: `Bearer ${apiToken}`,
|
|
||||||
Accept: "application/json"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
const value = secret.fields.find((f) => f.label === "value")?.value;
|
if (items[s.title]) {
|
||||||
const fieldId = secret.fields.find((f) => f.label === "value")?.id;
|
duplicates[s.id] = s.title;
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data: secret } = await request.get<TOnePassVariable>(`${instanceUrl}/v1/vaults/${vaultId}/items/${s.id}`, {
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${apiToken}`,
|
||||||
|
Accept: "application/json"
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const valueField = secret.fields.find((f) => f.label === valueLabel);
|
||||||
|
|
||||||
// eslint-disable-next-line no-continue
|
// eslint-disable-next-line no-continue
|
||||||
if (!value || !fieldId) continue;
|
if (!valueField || !valueField.value || !valueField.id) continue;
|
||||||
|
|
||||||
result[s.title] = {
|
items[s.title] = {
|
||||||
...secret,
|
...secret,
|
||||||
value,
|
value: valueField.value,
|
||||||
fieldId
|
fieldId: valueField.id
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return { items, duplicates };
|
||||||
};
|
};
|
||||||
|
|
||||||
const createOnePassItem = async ({ instanceUrl, apiToken, vaultId, itemTitle, itemValue }: TPostOnePassVariable) => {
|
const createOnePassItem = async ({
|
||||||
|
instanceUrl,
|
||||||
|
apiToken,
|
||||||
|
vaultId,
|
||||||
|
itemTitle,
|
||||||
|
itemValue,
|
||||||
|
valueLabel
|
||||||
|
}: TPostOnePassVariable) => {
|
||||||
return request.post(
|
return request.post(
|
||||||
`${instanceUrl}/v1/vaults/${vaultId}/items`,
|
`${instanceUrl}/v1/vaults/${vaultId}/items`,
|
||||||
{
|
{
|
||||||
@@ -63,7 +78,7 @@ const createOnePassItem = async ({ instanceUrl, apiToken, vaultId, itemTitle, it
|
|||||||
tags: ["synced-from-infisical"],
|
tags: ["synced-from-infisical"],
|
||||||
fields: [
|
fields: [
|
||||||
{
|
{
|
||||||
label: "value",
|
label: valueLabel,
|
||||||
value: itemValue,
|
value: itemValue,
|
||||||
type: "CONCEALED"
|
type: "CONCEALED"
|
||||||
}
|
}
|
||||||
@@ -85,7 +100,9 @@ const updateOnePassItem = async ({
|
|||||||
itemId,
|
itemId,
|
||||||
fieldId,
|
fieldId,
|
||||||
itemTitle,
|
itemTitle,
|
||||||
itemValue
|
itemValue,
|
||||||
|
valueLabel,
|
||||||
|
otherFields
|
||||||
}: TPutOnePassVariable) => {
|
}: TPutOnePassVariable) => {
|
||||||
return request.put(
|
return request.put(
|
||||||
`${instanceUrl}/v1/vaults/${vaultId}/items/${itemId}`,
|
`${instanceUrl}/v1/vaults/${vaultId}/items/${itemId}`,
|
||||||
@@ -98,9 +115,10 @@ const updateOnePassItem = async ({
|
|||||||
},
|
},
|
||||||
tags: ["synced-from-infisical"],
|
tags: ["synced-from-infisical"],
|
||||||
fields: [
|
fields: [
|
||||||
|
...otherFields,
|
||||||
{
|
{
|
||||||
id: fieldId,
|
id: fieldId,
|
||||||
label: "value",
|
label: valueLabel,
|
||||||
value: itemValue,
|
value: itemValue,
|
||||||
type: "CONCEALED"
|
type: "CONCEALED"
|
||||||
}
|
}
|
||||||
@@ -128,13 +146,18 @@ export const OnePassSyncFns = {
|
|||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
environment,
|
environment,
|
||||||
destinationConfig: { vaultId }
|
destinationConfig: { vaultId, valueLabel }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = await getOnePassInstanceUrl(connection);
|
const instanceUrl = await getOnePassInstanceUrl(connection);
|
||||||
const { apiToken } = connection.credentials;
|
const { apiToken } = connection.credentials;
|
||||||
|
|
||||||
const items = await listOnePassItems({ instanceUrl, apiToken, vaultId });
|
const { items, duplicates } = await listOnePassItems({
|
||||||
|
instanceUrl,
|
||||||
|
apiToken,
|
||||||
|
vaultId,
|
||||||
|
valueLabel: valueLabel || VALUE_LABEL_DEFAULT
|
||||||
|
});
|
||||||
|
|
||||||
for await (const entry of Object.entries(secretMap)) {
|
for await (const entry of Object.entries(secretMap)) {
|
||||||
const [key, { value }] = entry;
|
const [key, { value }] = entry;
|
||||||
@@ -148,10 +171,19 @@ export const OnePassSyncFns = {
|
|||||||
itemTitle: key,
|
itemTitle: key,
|
||||||
itemValue: value,
|
itemValue: value,
|
||||||
itemId: items[key].id,
|
itemId: items[key].id,
|
||||||
fieldId: items[key].fieldId
|
fieldId: items[key].fieldId,
|
||||||
|
valueLabel: valueLabel || VALUE_LABEL_DEFAULT,
|
||||||
|
otherFields: items[key].fields.filter((field) => field.label !== (valueLabel || VALUE_LABEL_DEFAULT))
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
await createOnePassItem({ instanceUrl, apiToken, vaultId, itemTitle: key, itemValue: value });
|
await createOnePassItem({
|
||||||
|
instanceUrl,
|
||||||
|
apiToken,
|
||||||
|
vaultId,
|
||||||
|
itemTitle: key,
|
||||||
|
itemValue: value,
|
||||||
|
valueLabel: valueLabel || VALUE_LABEL_DEFAULT
|
||||||
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new SecretSyncError({
|
throw new SecretSyncError({
|
||||||
@@ -163,7 +195,28 @@ export const OnePassSyncFns = {
|
|||||||
|
|
||||||
if (secretSync.syncOptions.disableSecretDeletion) return;
|
if (secretSync.syncOptions.disableSecretDeletion) return;
|
||||||
|
|
||||||
for await (const [key, variable] of Object.entries(items)) {
|
// Delete duplicate item entries
|
||||||
|
for await (const [itemId, key] of Object.entries(duplicates)) {
|
||||||
|
// eslint-disable-next-line no-continue
|
||||||
|
if (!matchesSchema(key, environment?.slug || "", secretSync.syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deleteOnePassItem({
|
||||||
|
instanceUrl,
|
||||||
|
apiToken,
|
||||||
|
vaultId,
|
||||||
|
itemId
|
||||||
|
});
|
||||||
|
} catch (error) {
|
||||||
|
throw new SecretSyncError({
|
||||||
|
error,
|
||||||
|
secretKey: key
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete item entries that are not in secretMap
|
||||||
|
for await (const [key, item] of Object.entries(items)) {
|
||||||
// eslint-disable-next-line no-continue
|
// eslint-disable-next-line no-continue
|
||||||
if (!matchesSchema(key, environment?.slug || "", secretSync.syncOptions.keySchema)) continue;
|
if (!matchesSchema(key, environment?.slug || "", secretSync.syncOptions.keySchema)) continue;
|
||||||
|
|
||||||
@@ -173,7 +226,7 @@ export const OnePassSyncFns = {
|
|||||||
instanceUrl,
|
instanceUrl,
|
||||||
apiToken,
|
apiToken,
|
||||||
vaultId,
|
vaultId,
|
||||||
itemId: variable.id
|
itemId: item.id
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new SecretSyncError({
|
throw new SecretSyncError({
|
||||||
@@ -187,13 +240,18 @@ export const OnePassSyncFns = {
|
|||||||
removeSecrets: async (secretSync: TOnePassSyncWithCredentials, secretMap: TSecretMap) => {
|
removeSecrets: async (secretSync: TOnePassSyncWithCredentials, secretMap: TSecretMap) => {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
destinationConfig: { vaultId }
|
destinationConfig: { vaultId, valueLabel }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = await getOnePassInstanceUrl(connection);
|
const instanceUrl = await getOnePassInstanceUrl(connection);
|
||||||
const { apiToken } = connection.credentials;
|
const { apiToken } = connection.credentials;
|
||||||
|
|
||||||
const items = await listOnePassItems({ instanceUrl, apiToken, vaultId });
|
const { items } = await listOnePassItems({
|
||||||
|
instanceUrl,
|
||||||
|
apiToken,
|
||||||
|
vaultId,
|
||||||
|
valueLabel: valueLabel || VALUE_LABEL_DEFAULT
|
||||||
|
});
|
||||||
|
|
||||||
for await (const [key, item] of Object.entries(items)) {
|
for await (const [key, item] of Object.entries(items)) {
|
||||||
if (key in secretMap) {
|
if (key in secretMap) {
|
||||||
@@ -216,12 +274,12 @@ export const OnePassSyncFns = {
|
|||||||
getSecrets: async (secretSync: TOnePassSyncWithCredentials) => {
|
getSecrets: async (secretSync: TOnePassSyncWithCredentials) => {
|
||||||
const {
|
const {
|
||||||
connection,
|
connection,
|
||||||
destinationConfig: { vaultId }
|
destinationConfig: { vaultId, valueLabel }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
const instanceUrl = await getOnePassInstanceUrl(connection);
|
const instanceUrl = await getOnePassInstanceUrl(connection);
|
||||||
const { apiToken } = connection.credentials;
|
const { apiToken } = connection.credentials;
|
||||||
|
|
||||||
return listOnePassItems({ instanceUrl, apiToken, vaultId });
|
return listOnePassItems({ instanceUrl, apiToken, vaultId, valueLabel: valueLabel || VALUE_LABEL_DEFAULT });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,7 +11,8 @@ import {
|
|||||||
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
import { TSyncOptionsConfig } from "@app/services/secret-sync/secret-sync-types";
|
||||||
|
|
||||||
const OnePassSyncDestinationConfigSchema = z.object({
|
const OnePassSyncDestinationConfigSchema = z.object({
|
||||||
vaultId: z.string().trim().min(1, "Vault required").describe(SecretSyncs.DESTINATION_CONFIG.ONEPASS.vaultId)
|
vaultId: z.string().trim().min(1, "Vault required").describe(SecretSyncs.DESTINATION_CONFIG.ONEPASS.vaultId),
|
||||||
|
valueLabel: z.string().trim().optional().describe(SecretSyncs.DESTINATION_CONFIG.ONEPASS.valueLabel)
|
||||||
});
|
});
|
||||||
|
|
||||||
const OnePassSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
const OnePassSyncOptionsConfig: TSyncOptionsConfig = { canImportSecrets: true };
|
||||||
|
|||||||
@@ -14,29 +14,32 @@ export type TOnePassSyncWithCredentials = TOnePassSync & {
|
|||||||
connection: TOnePassConnection;
|
connection: TOnePassConnection;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type Field = {
|
||||||
|
id: string;
|
||||||
|
type: string; // CONCEALED, STRING
|
||||||
|
label: string;
|
||||||
|
value: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type TOnePassVariable = {
|
export type TOnePassVariable = {
|
||||||
id: string;
|
id: string;
|
||||||
title: string;
|
title: string;
|
||||||
category: string; // API_CREDENTIAL, SECURE_NOTE, LOGIN, etc
|
category: string; // API_CREDENTIAL, SECURE_NOTE, LOGIN, etc
|
||||||
};
|
fields: Field[];
|
||||||
|
|
||||||
export type TOnePassVariableDetails = TOnePassVariable & {
|
|
||||||
fields: {
|
|
||||||
id: string;
|
|
||||||
type: string; // CONCEALED, STRING
|
|
||||||
label: string;
|
|
||||||
value: string;
|
|
||||||
}[];
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TOnePassListVariablesResponse = TOnePassVariable[];
|
export type TOnePassListVariablesResponse = TOnePassVariable[];
|
||||||
|
|
||||||
export type TOnePassListVariables = {
|
type TOnePassBase = {
|
||||||
apiToken: string;
|
apiToken: string;
|
||||||
instanceUrl: string;
|
instanceUrl: string;
|
||||||
vaultId: string;
|
vaultId: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export type TOnePassListVariables = TOnePassBase & {
|
||||||
|
valueLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
export type TPostOnePassVariable = TOnePassListVariables & {
|
export type TPostOnePassVariable = TOnePassListVariables & {
|
||||||
itemTitle: string;
|
itemTitle: string;
|
||||||
itemValue: string;
|
itemValue: string;
|
||||||
@@ -47,8 +50,9 @@ export type TPutOnePassVariable = TOnePassListVariables & {
|
|||||||
fieldId: string;
|
fieldId: string;
|
||||||
itemTitle: string;
|
itemTitle: string;
|
||||||
itemValue: string;
|
itemValue: string;
|
||||||
|
otherFields: Field[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export type TDeleteOnePassVariable = TOnePassListVariables & {
|
export type TDeleteOnePassVariable = TOnePassBase & {
|
||||||
itemId: string;
|
itemId: string;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -94,7 +94,8 @@ description: "Learn how to configure a 1Password Sync for Infisical."
|
|||||||
"initialSyncBehavior": "overwrite-destination"
|
"initialSyncBehavior": "overwrite-destination"
|
||||||
},
|
},
|
||||||
"destinationConfig": {
|
"destinationConfig": {
|
||||||
"vaultId": "..."
|
"vaultId": "...",
|
||||||
|
"valueLabel": "value"
|
||||||
}
|
}
|
||||||
}'
|
}'
|
||||||
```
|
```
|
||||||
@@ -145,7 +146,8 @@ description: "Learn how to configure a 1Password Sync for Infisical."
|
|||||||
},
|
},
|
||||||
"destination": "1password",
|
"destination": "1password",
|
||||||
"destinationConfig": {
|
"destinationConfig": {
|
||||||
"vaultId": "..."
|
"vaultId": "...",
|
||||||
|
"valueLabel": "value"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { faCircleInfo } from "@fortawesome/free-solid-svg-icons";
|
|||||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||||
|
|
||||||
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
|
import { SecretSyncConnectionField } from "@app/components/secret-syncs/forms/SecretSyncConnectionField";
|
||||||
import { FilterableSelect, FormControl, Tooltip } from "@app/components/v2";
|
import { FilterableSelect, FormControl, Input, Tooltip } from "@app/components/v2";
|
||||||
import {
|
import {
|
||||||
TOnePassVault,
|
TOnePassVault,
|
||||||
useOnePassConnectionListVaults
|
useOnePassConnectionListVaults
|
||||||
@@ -32,6 +32,7 @@ export const OnePassSyncFields = () => {
|
|||||||
<SecretSyncConnectionField
|
<SecretSyncConnectionField
|
||||||
onChange={() => {
|
onChange={() => {
|
||||||
setValue("destinationConfig.vaultId", "");
|
setValue("destinationConfig.vaultId", "");
|
||||||
|
setValue("destinationConfig.valueLabel", "");
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
@@ -69,6 +70,22 @@ export const OnePassSyncFields = () => {
|
|||||||
</FormControl>
|
</FormControl>
|
||||||
)}
|
)}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Controller
|
||||||
|
render={({ field: { value, onChange }, fieldState: { error } }) => (
|
||||||
|
<FormControl
|
||||||
|
isError={Boolean(error)}
|
||||||
|
errorText={error?.message}
|
||||||
|
isOptional
|
||||||
|
label="Value Label"
|
||||||
|
tooltipText="The label of the item entry which will hold your secret value. For example, if you were to sync secret 'foo: bar', the 1Password item equivalent would have an item title 'foo', and an entry on that item called 'value: bar'. The entry label 'value' is what gets changed by this option."
|
||||||
|
>
|
||||||
|
<Input value={value} onChange={onChange} placeholder="value" />
|
||||||
|
</FormControl>
|
||||||
|
)}
|
||||||
|
control={control}
|
||||||
|
name="destinationConfig.valueLabel"
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,6 +7,12 @@ import { SecretSync } from "@app/hooks/api/secretSyncs";
|
|||||||
export const OnePassSyncReviewFields = () => {
|
export const OnePassSyncReviewFields = () => {
|
||||||
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.OnePass }>();
|
const { watch } = useFormContext<TSecretSyncForm & { destination: SecretSync.OnePass }>();
|
||||||
const vaultId = watch("destinationConfig.vaultId");
|
const vaultId = watch("destinationConfig.vaultId");
|
||||||
|
const valueLabel = watch("destinationConfig.valueLabel");
|
||||||
|
|
||||||
return <GenericFieldLabel label="Vault ID">{vaultId}</GenericFieldLabel>;
|
return (
|
||||||
|
<>
|
||||||
|
<GenericFieldLabel label="Vault ID">{vaultId}</GenericFieldLabel>
|
||||||
|
<GenericFieldLabel label="Value Key">{valueLabel || "value"}</GenericFieldLabel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ export const OnePassSyncDestinationSchema = BaseSecretSyncSchema().merge(
|
|||||||
z.object({
|
z.object({
|
||||||
destination: z.literal(SecretSync.OnePass),
|
destination: z.literal(SecretSync.OnePass),
|
||||||
destinationConfig: z.object({
|
destinationConfig: z.object({
|
||||||
vaultId: z.string().trim().min(1, "Vault ID required")
|
vaultId: z.string().trim().min(1, "Vault ID required"),
|
||||||
|
valueLabel: z.string().trim().optional()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ export type TOnePassSync = TRootSecretSync & {
|
|||||||
destination: SecretSync.OnePass;
|
destination: SecretSync.OnePass;
|
||||||
destinationConfig: {
|
destinationConfig: {
|
||||||
vaultId: string;
|
vaultId: string;
|
||||||
|
valueLabel?: string;
|
||||||
};
|
};
|
||||||
connection: {
|
connection: {
|
||||||
app: AppConnection.OnePass;
|
app: AppConnection.OnePass;
|
||||||
|
|||||||
@@ -7,8 +7,13 @@ type Props = {
|
|||||||
|
|
||||||
export const OnePassSyncDestinationSection = ({ secretSync }: Props) => {
|
export const OnePassSyncDestinationSection = ({ secretSync }: Props) => {
|
||||||
const {
|
const {
|
||||||
destinationConfig: { vaultId }
|
destinationConfig: { vaultId, valueLabel }
|
||||||
} = secretSync;
|
} = secretSync;
|
||||||
|
|
||||||
return <GenericFieldLabel label="Vault ID">{vaultId}</GenericFieldLabel>;
|
return (
|
||||||
|
<>
|
||||||
|
<GenericFieldLabel label="Vault ID">{vaultId}</GenericFieldLabel>
|
||||||
|
<GenericFieldLabel label="Value Key">{valueLabel || "value"}</GenericFieldLabel>
|
||||||
|
</>
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user