mirror of
https://github.com/Skyvern-AI/skyvern.git
synced 2025-09-15 17:59:42 +00:00
Introduce collectionid filter for bitwarden parameters (#454)
This commit is contained in:
parent
bb19a8ab8e
commit
0ede4fdfa0
9 changed files with 56 additions and 10 deletions
|
@ -0,0 +1,33 @@
|
||||||
|
"""Add collection id to bitwarden credential parameters
|
||||||
|
|
||||||
|
Revision ID: 2c163e606a3d
|
||||||
|
Revises: 312d305c6b18
|
||||||
|
Create Date: 2024-06-11 05:02:25.023252+00:00
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
from typing import Sequence, Union
|
||||||
|
|
||||||
|
import sqlalchemy as sa
|
||||||
|
|
||||||
|
from alembic import op
|
||||||
|
|
||||||
|
# revision identifiers, used by Alembic.
|
||||||
|
revision: str = "2c163e606a3d"
|
||||||
|
down_revision: Union[str, None] = "312d305c6b18"
|
||||||
|
branch_labels: Union[str, Sequence[str], None] = None
|
||||||
|
depends_on: Union[str, Sequence[str], None] = None
|
||||||
|
|
||||||
|
|
||||||
|
def upgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.add_column(
|
||||||
|
"bitwarden_login_credential_parameters", sa.Column("bitwarden_collection_id", sa.String(), nullable=True)
|
||||||
|
)
|
||||||
|
# ### end Alembic commands ###
|
||||||
|
|
||||||
|
|
||||||
|
def downgrade() -> None:
|
||||||
|
# ### commands auto generated by Alembic - please adjust! ###
|
||||||
|
op.drop_column("bitwarden_login_credential_parameters", "bitwarden_collection_id")
|
||||||
|
# ### end Alembic commands ###
|
|
@ -1026,6 +1026,7 @@ class AgentDB:
|
||||||
url_parameter_key: str,
|
url_parameter_key: str,
|
||||||
key: str,
|
key: str,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
bitwarden_collection_id: str | None = None,
|
||||||
) -> BitwardenLoginCredentialParameter:
|
) -> BitwardenLoginCredentialParameter:
|
||||||
async with self.Session() as session:
|
async with self.Session() as session:
|
||||||
bitwarden_login_credential_parameter = BitwardenLoginCredentialParameterModel(
|
bitwarden_login_credential_parameter = BitwardenLoginCredentialParameterModel(
|
||||||
|
@ -1036,6 +1037,7 @@ class AgentDB:
|
||||||
url_parameter_key=url_parameter_key,
|
url_parameter_key=url_parameter_key,
|
||||||
key=key,
|
key=key,
|
||||||
description=description,
|
description=description,
|
||||||
|
bitwarden_collection_id=bitwarden_collection_id,
|
||||||
)
|
)
|
||||||
session.add(bitwarden_login_credential_parameter)
|
session.add(bitwarden_login_credential_parameter)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
|
|
|
@ -278,6 +278,7 @@ class BitwardenLoginCredentialParameterModel(Base):
|
||||||
bitwarden_client_id_aws_secret_key = Column(String, nullable=False)
|
bitwarden_client_id_aws_secret_key = Column(String, nullable=False)
|
||||||
bitwarden_client_secret_aws_secret_key = Column(String, nullable=False)
|
bitwarden_client_secret_aws_secret_key = Column(String, nullable=False)
|
||||||
bitwarden_master_password_aws_secret_key = Column(String, nullable=False)
|
bitwarden_master_password_aws_secret_key = Column(String, nullable=False)
|
||||||
|
bitwarden_collection_id = Column(String, nullable=True, default=None)
|
||||||
url_parameter_key = Column(String, nullable=False)
|
url_parameter_key = Column(String, nullable=False)
|
||||||
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
|
created_at = Column(DateTime, default=datetime.datetime.utcnow, nullable=False)
|
||||||
modified_at = Column(
|
modified_at = Column(
|
||||||
|
|
|
@ -241,6 +241,7 @@ def convert_to_bitwarden_login_credential_parameter(
|
||||||
LOG.debug(
|
LOG.debug(
|
||||||
"Converting BitwardenLoginCredentialParameterModel to BitwardenLoginCredentialParameter",
|
"Converting BitwardenLoginCredentialParameterModel to BitwardenLoginCredentialParameter",
|
||||||
bitwarden_login_credential_parameter_id=bitwarden_login_credential_parameter_model.bitwarden_login_credential_parameter_id,
|
bitwarden_login_credential_parameter_id=bitwarden_login_credential_parameter_model.bitwarden_login_credential_parameter_id,
|
||||||
|
bitwarden_collection_id=bitwarden_login_credential_parameter_model.bitwarden_collection_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
return BitwardenLoginCredentialParameter(
|
return BitwardenLoginCredentialParameter(
|
||||||
|
@ -251,6 +252,7 @@ def convert_to_bitwarden_login_credential_parameter(
|
||||||
bitwarden_client_id_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_id_aws_secret_key,
|
bitwarden_client_id_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_id_aws_secret_key,
|
||||||
bitwarden_client_secret_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_secret_aws_secret_key,
|
bitwarden_client_secret_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_client_secret_aws_secret_key,
|
||||||
bitwarden_master_password_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_master_password_aws_secret_key,
|
bitwarden_master_password_aws_secret_key=bitwarden_login_credential_parameter_model.bitwarden_master_password_aws_secret_key,
|
||||||
|
bitwarden_collection_id=bitwarden_login_credential_parameter_model.bitwarden_collection_id,
|
||||||
url_parameter_key=bitwarden_login_credential_parameter_model.url_parameter_key,
|
url_parameter_key=bitwarden_login_credential_parameter_model.url_parameter_key,
|
||||||
created_at=bitwarden_login_credential_parameter_model.created_at,
|
created_at=bitwarden_login_credential_parameter_model.created_at,
|
||||||
modified_at=bitwarden_login_credential_parameter_model.modified_at,
|
modified_at=bitwarden_login_credential_parameter_model.modified_at,
|
||||||
|
|
|
@ -27,6 +27,7 @@ class BitwardenConstants(StrEnum):
|
||||||
CLIENT_SECRET = "BW_CLIENT_SECRET"
|
CLIENT_SECRET = "BW_CLIENT_SECRET"
|
||||||
MASTER_PASSWORD = "BW_MASTER_PASSWORD"
|
MASTER_PASSWORD = "BW_MASTER_PASSWORD"
|
||||||
URL = "BW_URL"
|
URL = "BW_URL"
|
||||||
|
BW_COLLECTION_ID = "BW_COLLECTION_ID"
|
||||||
|
|
||||||
USERNAME = "BW_USERNAME"
|
USERNAME = "BW_USERNAME"
|
||||||
PASSWORD = "BW_PASSWORD"
|
PASSWORD = "BW_PASSWORD"
|
||||||
|
@ -68,6 +69,7 @@ class BitwardenService:
|
||||||
client_secret: str,
|
client_secret: str,
|
||||||
master_password: str,
|
master_password: str,
|
||||||
url: str,
|
url: str,
|
||||||
|
collection_id: str | None = None,
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
"""
|
"""
|
||||||
Get the secret value from the Bitwarden CLI.
|
Get the secret value from the Bitwarden CLI.
|
||||||
|
@ -105,14 +107,6 @@ class BitwardenService:
|
||||||
f"Failed to unlock vault. stdout: {unlock_result.stdout} stderr: {unlock_result.stderr}"
|
f"Failed to unlock vault. stdout: {unlock_result.stdout} stderr: {unlock_result.stderr}"
|
||||||
)
|
)
|
||||||
|
|
||||||
# This is a part of Bitwarden's client-side telemetry
|
|
||||||
# TODO -- figure out how to disable this telemetry so we never get this error
|
|
||||||
# https://github.com/bitwarden/clients/blob/9d10825dbd891c0f41fe1b4c4dd3ca4171f63be5/libs/common/src/services/api.service.ts#L1473
|
|
||||||
if unlock_result.stderr and "Event post failed" not in unlock_result.stderr:
|
|
||||||
raise BitwardenUnlockError(
|
|
||||||
f"Failed to unlock vault. stdout: {unlock_result.stdout} stderr: {unlock_result.stderr}"
|
|
||||||
)
|
|
||||||
|
|
||||||
# Extract session key
|
# Extract session key
|
||||||
try:
|
try:
|
||||||
session_key = BitwardenService._extract_session_key(unlock_result.stdout)
|
session_key = BitwardenService._extract_session_key(unlock_result.stdout)
|
||||||
|
@ -132,6 +126,9 @@ class BitwardenService:
|
||||||
"--session",
|
"--session",
|
||||||
session_key,
|
session_key,
|
||||||
]
|
]
|
||||||
|
if collection_id:
|
||||||
|
LOG.info("Collection ID is provided, filtering items by collection ID", collection_id=collection_id)
|
||||||
|
list_command.extend(["--collectionid", collection_id])
|
||||||
items_result = BitwardenService.run_command(list_command)
|
items_result = BitwardenService.run_command(list_command)
|
||||||
|
|
||||||
if items_result.stderr and "Event post failed" not in items_result.stderr:
|
if items_result.stderr and "Event post failed" not in items_result.stderr:
|
||||||
|
@ -144,7 +141,8 @@ class BitwardenService:
|
||||||
raise BitwardenListItemsError("Failed to parse items JSON. Output: " + items_result.stdout)
|
raise BitwardenListItemsError("Failed to parse items JSON. Output: " + items_result.stdout)
|
||||||
|
|
||||||
if not items:
|
if not items:
|
||||||
raise BitwardenListItemsError("No items found in Bitwarden.")
|
collection_id_str = f" in collection with ID: {collection_id}" if collection_id else ""
|
||||||
|
raise BitwardenListItemsError(f"No items found in Bitwarden for URL: {url}{collection_id_str}")
|
||||||
|
|
||||||
totp_command = ["bw", "get", "totp", url, "--session", session_key]
|
totp_command = ["bw", "get", "totp", url, "--session", session_key]
|
||||||
totp_result = BitwardenService.run_command(totp_command)
|
totp_result = BitwardenService.run_command(totp_command)
|
||||||
|
|
|
@ -157,12 +157,14 @@ class WorkflowRunContext:
|
||||||
client_secret,
|
client_secret,
|
||||||
master_password,
|
master_password,
|
||||||
url,
|
url,
|
||||||
|
collection_id=parameter.bitwarden_collection_id,
|
||||||
)
|
)
|
||||||
if secret_credentials:
|
if secret_credentials:
|
||||||
self.secrets[BitwardenConstants.URL] = url
|
self.secrets[BitwardenConstants.URL] = url
|
||||||
self.secrets[BitwardenConstants.CLIENT_SECRET] = client_secret
|
self.secrets[BitwardenConstants.CLIENT_SECRET] = client_secret
|
||||||
self.secrets[BitwardenConstants.CLIENT_ID] = client_id
|
self.secrets[BitwardenConstants.CLIENT_ID] = client_id
|
||||||
self.secrets[BitwardenConstants.MASTER_PASSWORD] = master_password
|
self.secrets[BitwardenConstants.MASTER_PASSWORD] = master_password
|
||||||
|
self.secrets[BitwardenConstants.BW_COLLECTION_ID] = parameter.bitwarden_collection_id
|
||||||
|
|
||||||
random_secret_id = self.generate_random_secret_id()
|
random_secret_id = self.generate_random_secret_id()
|
||||||
# username secret
|
# username secret
|
||||||
|
@ -181,7 +183,6 @@ class WorkflowRunContext:
|
||||||
"totp": totp_secret_id,
|
"totp": totp_secret_id,
|
||||||
}
|
}
|
||||||
except BitwardenBaseError as e:
|
except BitwardenBaseError as e:
|
||||||
BitwardenService.logout()
|
|
||||||
LOG.error(f"Failed to get secret from Bitwarden. Error: {e}")
|
LOG.error(f"Failed to get secret from Bitwarden. Error: {e}")
|
||||||
raise e
|
raise e
|
||||||
elif isinstance(parameter, ContextParameter):
|
elif isinstance(parameter, ContextParameter):
|
||||||
|
|
|
@ -52,6 +52,9 @@ class BitwardenLoginCredentialParameter(Parameter):
|
||||||
bitwarden_master_password_aws_secret_key: str
|
bitwarden_master_password_aws_secret_key: str
|
||||||
# url to request the login credentials from bitwarden
|
# url to request the login credentials from bitwarden
|
||||||
url_parameter_key: str
|
url_parameter_key: str
|
||||||
|
# bitwarden collection id to filter the login credentials from,
|
||||||
|
# if not provided, no filtering will be done
|
||||||
|
bitwarden_collection_id: str | None = None
|
||||||
|
|
||||||
created_at: datetime
|
created_at: datetime
|
||||||
modified_at: datetime
|
modified_at: datetime
|
||||||
|
|
|
@ -36,6 +36,9 @@ class BitwardenLoginCredentialParameterYAML(ParameterYAML):
|
||||||
bitwarden_master_password_aws_secret_key: str
|
bitwarden_master_password_aws_secret_key: str
|
||||||
# parameter key for the url to request the login credentials from bitwarden
|
# parameter key for the url to request the login credentials from bitwarden
|
||||||
url_parameter_key: str
|
url_parameter_key: str
|
||||||
|
# bitwarden collection id to filter the login credentials from,
|
||||||
|
# if not provided, no filtering will be done
|
||||||
|
bitwarden_collection_id: str | None = None
|
||||||
|
|
||||||
|
|
||||||
class WorkflowParameterYAML(ParameterYAML):
|
class WorkflowParameterYAML(ParameterYAML):
|
||||||
|
|
|
@ -450,6 +450,7 @@ class WorkflowService:
|
||||||
url_parameter_key: str,
|
url_parameter_key: str,
|
||||||
key: str,
|
key: str,
|
||||||
description: str | None = None,
|
description: str | None = None,
|
||||||
|
bitwarden_collection_id: str | None = None,
|
||||||
) -> Parameter:
|
) -> Parameter:
|
||||||
return await app.DATABASE.create_bitwarden_login_credential_parameter(
|
return await app.DATABASE.create_bitwarden_login_credential_parameter(
|
||||||
workflow_id=workflow_id,
|
workflow_id=workflow_id,
|
||||||
|
@ -459,6 +460,7 @@ class WorkflowService:
|
||||||
url_parameter_key=url_parameter_key,
|
url_parameter_key=url_parameter_key,
|
||||||
key=key,
|
key=key,
|
||||||
description=description,
|
description=description,
|
||||||
|
bitwarden_collection_id=bitwarden_collection_id,
|
||||||
)
|
)
|
||||||
|
|
||||||
async def create_output_parameter(
|
async def create_output_parameter(
|
||||||
|
@ -833,6 +835,7 @@ class WorkflowService:
|
||||||
url_parameter_key=parameter.url_parameter_key,
|
url_parameter_key=parameter.url_parameter_key,
|
||||||
key=parameter.key,
|
key=parameter.key,
|
||||||
description=parameter.description,
|
description=parameter.description,
|
||||||
|
bitwarden_collection_id=parameter.bitwarden_collection_id,
|
||||||
)
|
)
|
||||||
elif parameter.parameter_type == ParameterType.WORKFLOW:
|
elif parameter.parameter_type == ParameterType.WORKFLOW:
|
||||||
parameters[parameter.key] = await self.create_workflow_parameter(
|
parameters[parameter.key] = await self.create_workflow_parameter(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue