Azure Vault credential support (#3394)

This commit is contained in:
stenn930
2025-09-12 11:01:57 -06:00
committed by GitHub
parent c876566c57
commit 8df506660e
23 changed files with 624 additions and 74 deletions

View File

@@ -50,6 +50,7 @@ import {
ContextParameterYAML,
CredentialParameterYAML,
OnePasswordCredentialParameterYAML,
AzureVaultCredentialParameterYAML,
ParameterYAML,
WorkflowParameterYAML,
} from "../types/workflowYamlTypes";
@@ -65,6 +66,7 @@ import {
parameterIsSkyvernCredential,
parameterIsOnePasswordCredential,
parameterIsBitwardenCredential,
parameterIsAzureVaultCredential,
} from "./types";
import "./reactFlowOverrideStyles.css";
import {
@@ -90,6 +92,7 @@ function convertToParametersYAML(
| BitwardenSensitiveInformationParameterYAML
| BitwardenCreditCardDataParameterYAML
| OnePasswordCredentialParameterYAML
| AzureVaultCredentialParameterYAML
| CredentialParameterYAML
> {
return parameters
@@ -103,6 +106,7 @@ function convertToParametersYAML(
| BitwardenSensitiveInformationParameterYAML
| BitwardenCreditCardDataParameterYAML
| OnePasswordCredentialParameterYAML
| AzureVaultCredentialParameterYAML
| CredentialParameterYAML
| undefined => {
if (parameter.parameterType === WorkflowEditorParameterTypes.Workflow) {
@@ -191,6 +195,16 @@ function convertToParametersYAML(
vault_id: parameter.vaultId,
item_id: parameter.itemId,
};
} else if (parameterIsAzureVaultCredential(parameter)) {
return {
parameter_type: WorkflowParameterTypes.Azure_Vault_Credential,
key: parameter.key,
description: parameter.description || null,
vault_name: parameter.vaultName,
username_key: parameter.usernameKey,
password_key: parameter.passwordKey,
totp_secret_key: parameter.totpSecretKey,
};
}
}
return undefined;
@@ -205,6 +219,7 @@ function convertToParametersYAML(
| BitwardenSensitiveInformationParameterYAML
| BitwardenCreditCardDataParameterYAML
| OnePasswordCredentialParameterYAML
| AzureVaultCredentialParameterYAML
| CredentialParameterYAML
| undefined,
): param is
@@ -214,6 +229,7 @@ function convertToParametersYAML(
| BitwardenSensitiveInformationParameterYAML
| BitwardenCreditCardDataParameterYAML
| OnePasswordCredentialParameterYAML
| AzureVaultCredentialParameterYAML
| CredentialParameterYAML => param !== undefined,
);
}

View File

@@ -1,4 +1,3 @@
import { SwitchBar } from "@/components/SwitchBar";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
@@ -81,7 +80,7 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
>(undefined);
const [credentialType, setCredentialType] = useState<
"bitwarden" | "skyvern" | "onepassword"
"bitwarden" | "skyvern" | "onepassword" | "azurevault"
>("skyvern");
const [vaultId, setVaultId] = useState("");
const [itemId, setItemId] = useState("");
@@ -93,6 +92,11 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
const [credentialId, setCredentialId] = useState("");
const [azureVaultName, setAzureVaultName] = useState("");
const [azureUsernameKey, setAzureUsernameKey] = useState("");
const [azurePasswordKey, setAzurePasswordKey] = useState("");
const [azureTotpSecretKey, setAzureTotpKey] = useState("");
return (
<ScrollArea>
<ScrollAreaViewport className="max-h-[500px]">
@@ -199,19 +203,37 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
</>
)}
{type === "credential" && (
<SwitchBar
value={credentialType}
onChange={(value) => {
setCredentialType(
value as "bitwarden" | "skyvern" | "onepassword",
);
}}
options={[
{ label: "Skyvern", value: "skyvern" },
{ label: "Bitwarden", value: "bitwarden" },
{ label: "1Password", value: "onepassword" },
]}
/>
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
Credential Type
</Label>
<Select
value={credentialType}
onValueChange={(value) => {
setCredentialType(
value as
| "bitwarden"
| "skyvern"
| "onepassword"
| "azurevault",
);
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="skyvern">Skyvern</SelectItem>
<SelectItem value="bitwarden">Bitwarden</SelectItem>
<SelectItem value="onepassword">1Password</SelectItem>
<SelectItem value="azurevault">Azure Vault</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</>
)}
{type === "credential" && credentialType === "bitwarden" && (
<>
@@ -260,6 +282,41 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
</div>
</>
)}
{type === "credential" && credentialType === "azurevault" && (
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Vault Name</Label>
<Input
value={azureVaultName}
onChange={(e) => setAzureVaultName(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Username Key</Label>
<Input
autoComplete="off"
value={azureUsernameKey}
onChange={(e) => setAzureUsernameKey(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Password Key</Label>
<Input
value={azurePasswordKey}
onChange={(e) => setAzurePasswordKey(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
TOTP Secret Key
</Label>
<Input
value={azureTotpSecretKey}
onChange={(e) => setAzureTotpKey(e.target.value)}
/>
</div>
</>
)}
{type === "context" && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Source Parameter</Label>
@@ -427,6 +484,31 @@ function WorkflowParameterAddPanel({ type, onClose, onSave }: Props) {
description,
});
}
if (type === "credential" && credentialType === "azurevault") {
if (
azureVaultName.trim() === "" ||
azureUsernameKey.trim() === "" ||
azurePasswordKey.trim() === ""
) {
toast({
variant: "destructive",
title: "Failed to add parameter",
description:
"Azure Vault Name, Username Key and Password Key are required",
});
return;
}
onSave({
key,
parameterType: "credential",
vaultName: azureVaultName,
usernameKey: azureUsernameKey,
passwordKey: azurePasswordKey,
totpSecretKey:
azureTotpSecretKey === "" ? null : azureTotpSecretKey,
description: description,
});
}
if (type === "secret" || type === "creditCardData") {
if (!bitwardenCollectionId) {
toast({

View File

@@ -1,4 +1,3 @@
import { SwitchBar } from "@/components/SwitchBar";
import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox";
import { Input } from "@/components/ui/input";
@@ -28,6 +27,7 @@ import {
parameterIsSkyvernCredential,
parameterIsOnePasswordCredential,
ParametersState,
parameterIsAzureVaultCredential,
} from "../types";
import { getDefaultValueForParameterType } from "../workflowEditorUtils";
import { validateBitwardenLoginCredential } from "./util";
@@ -82,14 +82,19 @@ function WorkflowParameterEditPanel({
const isOnePasswordCredential =
initialValues.parameterType === "onepassword" &&
parameterIsOnePasswordCredential(initialValues);
const isAzureVaultCredential =
initialValues.parameterType === "credential" &&
parameterIsAzureVaultCredential(initialValues);
const [credentialType, setCredentialType] = useState<
"bitwarden" | "skyvern" | "onepassword"
"bitwarden" | "skyvern" | "onepassword" | "azurevault"
>(
isBitwardenCredential
? "bitwarden"
: isOnePasswordCredential
? "onepassword"
: "skyvern",
: isAzureVaultCredential
? "azurevault"
: "skyvern",
);
const [urlParameterKey, setUrlParameterKey] = useState(
isBitwardenCredential ? initialValues.urlParameterKey ?? "" : "",
@@ -163,6 +168,19 @@ function WorkflowParameterEditPanel({
const [bitwardenLoginCredentialItemId, setBitwardenLoginCredentialItemId] =
useState(isBitwardenCredential ? initialValues.itemId ?? "" : "");
const [azureVaultName, setAzureVaultName] = useState(
isAzureVaultCredential ? initialValues.vaultName : "",
);
const [azureUsernameKey, setAzureUsernameKey] = useState(
isAzureVaultCredential ? initialValues.usernameKey : "",
);
const [azurePasswordKey, setAzurePasswordKey] = useState(
isAzureVaultCredential ? initialValues.passwordKey : "",
);
const [azureTotpSecretKey, setAzureTotpKey] = useState(
isAzureVaultCredential ? initialValues.totpSecretKey ?? "" : "",
);
return (
<ScrollArea>
<ScrollAreaViewport className="max-h-[500px]">
@@ -269,19 +287,37 @@ function WorkflowParameterEditPanel({
</>
)}
{type === "credential" && (
<SwitchBar
value={credentialType}
onChange={(value) => {
setCredentialType(
value as "bitwarden" | "skyvern" | "onepassword",
);
}}
options={[
{ label: "Skyvern", value: "skyvern" },
{ label: "Bitwarden", value: "bitwarden" },
{ label: "1Password", value: "onepassword" },
]}
/>
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
Credential Type
</Label>
<Select
value={credentialType}
onValueChange={(value) => {
setCredentialType(
value as
| "bitwarden"
| "skyvern"
| "onepassword"
| "azurevault",
);
}}
>
<SelectTrigger className="w-full">
<SelectValue placeholder="Select a type" />
</SelectTrigger>
<SelectContent>
<SelectGroup>
<SelectItem value="skyvern">Skyvern</SelectItem>
<SelectItem value="bitwarden">Bitwarden</SelectItem>
<SelectItem value="onepassword">1Password</SelectItem>
<SelectItem value="azurevault">Azure Vault</SelectItem>
</SelectGroup>
</SelectContent>
</Select>
</div>
</>
)}
{type === "credential" && credentialType === "bitwarden" && (
<>
@@ -330,6 +366,41 @@ function WorkflowParameterEditPanel({
</div>
</>
)}
{type === "credential" && credentialType === "azurevault" && (
<>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Vault Name</Label>
<Input
value={azureVaultName}
onChange={(e) => setAzureVaultName(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Username Key</Label>
<Input
autoComplete="off"
value={azureUsernameKey}
onChange={(e) => setAzureUsernameKey(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">Password Key</Label>
<Input
value={azurePasswordKey}
onChange={(e) => setAzurePasswordKey(e.target.value)}
/>
</div>
<div className="space-y-1">
<Label className="text-xs text-slate-300">
TOTP Secret Key
</Label>
<Input
value={azureTotpSecretKey}
onChange={(e) => setAzureTotpKey(e.target.value)}
/>
</div>
</>
)}
{type === "context" && (
<div className="space-y-1">
<Label className="text-xs text-slate-300">Source Parameter</Label>
@@ -484,6 +555,31 @@ function WorkflowParameterEditPanel({
description,
});
}
if (type === "credential" && credentialType === "azurevault") {
if (
azureVaultName.trim() === "" ||
azureUsernameKey.trim() === "" ||
azurePasswordKey.trim() === ""
) {
toast({
variant: "destructive",
title: "Failed to add parameter",
description:
"Azure Vault Name, Username Key and Password Key are required",
});
return;
}
onSave({
key,
parameterType: "credential",
vaultName: azureVaultName,
usernameKey: azureUsernameKey,
passwordKey: azurePasswordKey,
totpSecretKey:
azureTotpSecretKey === "" ? null : azureTotpSecretKey,
description: description,
});
}
if (type === "secret" || type === "creditCardData") {
if (!collectionId) {
toast({

View File

@@ -24,6 +24,16 @@ export type OnePasswordCredential = {
itemId: string;
};
export type AzureVaultCredential = {
key: string;
description?: string | null;
parameterType: "credential";
vaultName: string;
usernameKey: string;
passwordKey: string;
totpSecretKey: string | null;
};
export function parameterIsBitwardenCredential(
parameter: CredentialParameterState,
): parameter is BitwardenLoginCredential {
@@ -42,10 +52,21 @@ export function parameterIsOnePasswordCredential(
return "vaultId" in parameter && "itemId" in parameter;
}
export function parameterIsAzureVaultCredential(
parameter: CredentialParameterState,
): parameter is AzureVaultCredential {
return (
"vaultName" in parameter &&
"usernameKey" in parameter &&
"passwordKey" in parameter
);
}
export type CredentialParameterState =
| BitwardenLoginCredential
| SkyvernCredential
| OnePasswordCredential;
| OnePasswordCredential
| AzureVaultCredential;
export type ParametersState = Array<
| {

View File

@@ -79,6 +79,19 @@ const getInitialParameters = (workflow: WorkflowApiResponse) => {
itemId: parameter.item_id,
description: parameter.description,
};
} else if (
parameter.parameter_type ===
WorkflowParameterTypes.Azure_Vault_Credential
) {
return {
key: parameter.key,
parameterType: WorkflowEditorParameterTypes.Credential,
vaultName: parameter.vault_name,
usernameKey: parameter.username_key,
passwordKey: parameter.password_key,
totpSecretKey: parameter.totp_secret_key,
description: parameter.description,
};
} else if (
parameter.parameter_type ===
WorkflowParameterTypes.Bitwarden_Login_Credential

View File

@@ -1805,6 +1805,16 @@ function convertParametersToParameterYAML(
item_id: parameter.item_id,
};
}
case WorkflowParameterTypes.Azure_Vault_Credential: {
return {
...base,
parameter_type: WorkflowParameterTypes.Azure_Vault_Credential,
vault_name: parameter.vault_name,
username_key: parameter.username_key,
password_key: parameter.password_key,
totp_secret_key: parameter.totp_secret_key,
};
}
}
})
.filter(Boolean);