bt-cli 0.4.13__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bt_cli/__init__.py +3 -0
- bt_cli/cli.py +830 -0
- bt_cli/commands/__init__.py +1 -0
- bt_cli/commands/configure.py +415 -0
- bt_cli/commands/learn.py +229 -0
- bt_cli/commands/quick.py +784 -0
- bt_cli/core/__init__.py +1 -0
- bt_cli/core/auth.py +213 -0
- bt_cli/core/client.py +313 -0
- bt_cli/core/config.py +393 -0
- bt_cli/core/config_file.py +420 -0
- bt_cli/core/csv_utils.py +91 -0
- bt_cli/core/errors.py +247 -0
- bt_cli/core/output.py +205 -0
- bt_cli/core/prompts.py +87 -0
- bt_cli/core/rest_debug.py +221 -0
- bt_cli/data/CLAUDE.md +94 -0
- bt_cli/data/__init__.py +0 -0
- bt_cli/data/skills/bt/SKILL.md +108 -0
- bt_cli/data/skills/entitle/SKILL.md +170 -0
- bt_cli/data/skills/epmw/SKILL.md +144 -0
- bt_cli/data/skills/pra/SKILL.md +150 -0
- bt_cli/data/skills/pws/SKILL.md +198 -0
- bt_cli/entitle/__init__.py +1 -0
- bt_cli/entitle/client/__init__.py +5 -0
- bt_cli/entitle/client/base.py +443 -0
- bt_cli/entitle/commands/__init__.py +24 -0
- bt_cli/entitle/commands/accounts.py +53 -0
- bt_cli/entitle/commands/applications.py +39 -0
- bt_cli/entitle/commands/auth.py +68 -0
- bt_cli/entitle/commands/bundles.py +218 -0
- bt_cli/entitle/commands/integrations.py +60 -0
- bt_cli/entitle/commands/permissions.py +70 -0
- bt_cli/entitle/commands/policies.py +97 -0
- bt_cli/entitle/commands/resources.py +131 -0
- bt_cli/entitle/commands/roles.py +74 -0
- bt_cli/entitle/commands/users.py +123 -0
- bt_cli/entitle/commands/workflows.py +187 -0
- bt_cli/entitle/models/__init__.py +31 -0
- bt_cli/entitle/models/bundle.py +28 -0
- bt_cli/entitle/models/common.py +37 -0
- bt_cli/entitle/models/integration.py +30 -0
- bt_cli/entitle/models/permission.py +27 -0
- bt_cli/entitle/models/policy.py +25 -0
- bt_cli/entitle/models/resource.py +29 -0
- bt_cli/entitle/models/role.py +28 -0
- bt_cli/entitle/models/user.py +24 -0
- bt_cli/entitle/models/workflow.py +55 -0
- bt_cli/epmw/__init__.py +1 -0
- bt_cli/epmw/client/__init__.py +5 -0
- bt_cli/epmw/client/base.py +848 -0
- bt_cli/epmw/commands/__init__.py +33 -0
- bt_cli/epmw/commands/audits.py +250 -0
- bt_cli/epmw/commands/auth.py +55 -0
- bt_cli/epmw/commands/computers.py +140 -0
- bt_cli/epmw/commands/events.py +233 -0
- bt_cli/epmw/commands/groups.py +215 -0
- bt_cli/epmw/commands/policies.py +673 -0
- bt_cli/epmw/commands/quick.py +348 -0
- bt_cli/epmw/commands/requests.py +224 -0
- bt_cli/epmw/commands/roles.py +78 -0
- bt_cli/epmw/commands/tasks.py +38 -0
- bt_cli/epmw/commands/users.py +219 -0
- bt_cli/epmw/models/__init__.py +1 -0
- bt_cli/pra/__init__.py +1 -0
- bt_cli/pra/client/__init__.py +5 -0
- bt_cli/pra/client/base.py +618 -0
- bt_cli/pra/commands/__init__.py +30 -0
- bt_cli/pra/commands/auth.py +55 -0
- bt_cli/pra/commands/import_export.py +442 -0
- bt_cli/pra/commands/jump_clients.py +139 -0
- bt_cli/pra/commands/jump_groups.py +146 -0
- bt_cli/pra/commands/jump_items.py +638 -0
- bt_cli/pra/commands/jumpoints.py +95 -0
- bt_cli/pra/commands/policies.py +197 -0
- bt_cli/pra/commands/quick.py +470 -0
- bt_cli/pra/commands/teams.py +81 -0
- bt_cli/pra/commands/users.py +87 -0
- bt_cli/pra/commands/vault.py +564 -0
- bt_cli/pra/models/__init__.py +27 -0
- bt_cli/pra/models/common.py +12 -0
- bt_cli/pra/models/jump_client.py +25 -0
- bt_cli/pra/models/jump_group.py +15 -0
- bt_cli/pra/models/jump_item.py +72 -0
- bt_cli/pra/models/jumpoint.py +19 -0
- bt_cli/pra/models/team.py +14 -0
- bt_cli/pra/models/user.py +17 -0
- bt_cli/pra/models/vault.py +45 -0
- bt_cli/pws/__init__.py +1 -0
- bt_cli/pws/client/__init__.py +5 -0
- bt_cli/pws/client/base.py +356 -0
- bt_cli/pws/client/beyondinsight.py +869 -0
- bt_cli/pws/client/passwordsafe.py +1786 -0
- bt_cli/pws/commands/__init__.py +33 -0
- bt_cli/pws/commands/accounts.py +372 -0
- bt_cli/pws/commands/assets.py +311 -0
- bt_cli/pws/commands/auth.py +166 -0
- bt_cli/pws/commands/clouds.py +221 -0
- bt_cli/pws/commands/config.py +344 -0
- bt_cli/pws/commands/credentials.py +347 -0
- bt_cli/pws/commands/databases.py +306 -0
- bt_cli/pws/commands/directories.py +199 -0
- bt_cli/pws/commands/functional.py +298 -0
- bt_cli/pws/commands/import_export.py +452 -0
- bt_cli/pws/commands/platforms.py +118 -0
- bt_cli/pws/commands/quick.py +1646 -0
- bt_cli/pws/commands/search.py +256 -0
- bt_cli/pws/commands/secrets.py +1343 -0
- bt_cli/pws/commands/systems.py +389 -0
- bt_cli/pws/commands/users.py +415 -0
- bt_cli/pws/commands/workgroups.py +166 -0
- bt_cli/pws/config.py +18 -0
- bt_cli/pws/models/__init__.py +19 -0
- bt_cli/pws/models/account.py +186 -0
- bt_cli/pws/models/asset.py +102 -0
- bt_cli/pws/models/common.py +132 -0
- bt_cli/pws/models/system.py +121 -0
- bt_cli-0.4.13.dist-info/METADATA +417 -0
- bt_cli-0.4.13.dist-info/RECORD +121 -0
- bt_cli-0.4.13.dist-info/WHEEL +4 -0
- bt_cli-0.4.13.dist-info/entry_points.txt +2 -0
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
"""Managed Account models for Password Safe API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ManagedAccount(BaseModel):
|
|
9
|
+
"""Managed account in Password Safe."""
|
|
10
|
+
|
|
11
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
12
|
+
|
|
13
|
+
managed_account_id: int = Field(alias="ManagedAccountID")
|
|
14
|
+
managed_system_id: int = Field(alias="ManagedSystemID")
|
|
15
|
+
account_name: str = Field(alias="AccountName")
|
|
16
|
+
domain_name: Optional[str] = Field(default=None, alias="DomainName")
|
|
17
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
18
|
+
|
|
19
|
+
# System info (populated in some responses)
|
|
20
|
+
system_name: Optional[str] = Field(default=None, alias="SystemName")
|
|
21
|
+
platform_id: Optional[int] = Field(default=None, alias="PlatformID")
|
|
22
|
+
|
|
23
|
+
# API access
|
|
24
|
+
api_enabled: Optional[bool] = Field(default=None, alias="ApiEnabled")
|
|
25
|
+
|
|
26
|
+
# Password management flags
|
|
27
|
+
auto_management_flag: Optional[bool] = Field(default=None, alias="AutoManagementFlag")
|
|
28
|
+
check_password_flag: Optional[bool] = Field(default=None, alias="CheckPasswordFlag")
|
|
29
|
+
change_password_after_any_release_flag: Optional[bool] = Field(
|
|
30
|
+
default=None, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
31
|
+
)
|
|
32
|
+
reset_password_on_mismatch_flag: Optional[bool] = Field(
|
|
33
|
+
default=None, alias="ResetPasswordOnMismatchFlag"
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
# Password change schedule
|
|
37
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
38
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
39
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
40
|
+
next_change_date: Optional[datetime] = Field(default=None, alias="NextChangeDate")
|
|
41
|
+
last_change_date: Optional[datetime] = Field(default=None, alias="LastChangeDate")
|
|
42
|
+
|
|
43
|
+
# Password rules
|
|
44
|
+
password_rule_id: Optional[int] = Field(default=None, alias="PasswordRuleID")
|
|
45
|
+
dss_key_rule_id: Optional[int] = Field(default=None, alias="DSSKeyRuleID")
|
|
46
|
+
|
|
47
|
+
# Status
|
|
48
|
+
status: Optional[str] = Field(default=None, alias="Status")
|
|
49
|
+
is_subscribed_account: Optional[bool] = Field(default=None, alias="IsSubscribedAccount")
|
|
50
|
+
created_date: Optional[datetime] = Field(default=None, alias="CreatedDate")
|
|
51
|
+
|
|
52
|
+
@classmethod
|
|
53
|
+
def from_api(cls, data: dict[str, Any]) -> "ManagedAccount":
|
|
54
|
+
"""Create ManagedAccount from API response."""
|
|
55
|
+
return cls.model_validate(data)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def display_name(self) -> str:
|
|
59
|
+
"""Get a display name for the account."""
|
|
60
|
+
if self.domain_name:
|
|
61
|
+
return f"{self.domain_name}\\{self.account_name}"
|
|
62
|
+
return self.account_name
|
|
63
|
+
|
|
64
|
+
@property
|
|
65
|
+
def full_path(self) -> str:
|
|
66
|
+
"""Get the full path (system/account)."""
|
|
67
|
+
if self.system_name:
|
|
68
|
+
return f"{self.system_name}/{self.account_name}"
|
|
69
|
+
return f"System-{self.managed_system_id}/{self.account_name}"
|
|
70
|
+
|
|
71
|
+
@property
|
|
72
|
+
def id(self) -> int:
|
|
73
|
+
"""Alias for managed_account_id for convenience."""
|
|
74
|
+
return self.managed_account_id
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
class ManagedAccountCreate(BaseModel):
|
|
78
|
+
"""Data for creating a managed account."""
|
|
79
|
+
|
|
80
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
81
|
+
|
|
82
|
+
account_name: str = Field(alias="AccountName")
|
|
83
|
+
password: Optional[str] = Field(default=None, alias="Password")
|
|
84
|
+
domain_name: Optional[str] = Field(default=None, alias="DomainName")
|
|
85
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
86
|
+
api_enabled: bool = Field(default=True, alias="ApiEnabled")
|
|
87
|
+
auto_management_flag: bool = Field(default=True, alias="AutoManagementFlag")
|
|
88
|
+
check_password_flag: bool = Field(default=True, alias="CheckPasswordFlag")
|
|
89
|
+
change_password_after_any_release_flag: bool = Field(
|
|
90
|
+
default=False, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
91
|
+
)
|
|
92
|
+
reset_password_on_mismatch_flag: bool = Field(
|
|
93
|
+
default=False, alias="ResetPasswordOnMismatchFlag"
|
|
94
|
+
)
|
|
95
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
96
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
97
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
98
|
+
next_change_date: Optional[str] = Field(default=None, alias="NextChangeDate")
|
|
99
|
+
password_rule_id: Optional[int] = Field(default=None, alias="PasswordRuleID")
|
|
100
|
+
dss_key_rule_id: Optional[int] = Field(default=None, alias="DSSKeyRuleID")
|
|
101
|
+
|
|
102
|
+
def to_api_dict(self) -> dict[str, Any]:
|
|
103
|
+
"""Convert to API-compatible dictionary."""
|
|
104
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ManagedAccountUpdate(BaseModel):
|
|
108
|
+
"""Data for updating a managed account."""
|
|
109
|
+
|
|
110
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
111
|
+
|
|
112
|
+
account_name: Optional[str] = Field(default=None, alias="AccountName")
|
|
113
|
+
domain_name: Optional[str] = Field(default=None, alias="DomainName")
|
|
114
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
115
|
+
api_enabled: Optional[bool] = Field(default=None, alias="ApiEnabled")
|
|
116
|
+
auto_management_flag: Optional[bool] = Field(default=None, alias="AutoManagementFlag")
|
|
117
|
+
check_password_flag: Optional[bool] = Field(default=None, alias="CheckPasswordFlag")
|
|
118
|
+
change_password_after_any_release_flag: Optional[bool] = Field(
|
|
119
|
+
default=None, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
120
|
+
)
|
|
121
|
+
reset_password_on_mismatch_flag: Optional[bool] = Field(
|
|
122
|
+
default=None, alias="ResetPasswordOnMismatchFlag"
|
|
123
|
+
)
|
|
124
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
125
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
126
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
127
|
+
password_rule_id: Optional[int] = Field(default=None, alias="PasswordRuleID")
|
|
128
|
+
dss_key_rule_id: Optional[int] = Field(default=None, alias="DSSKeyRuleID")
|
|
129
|
+
|
|
130
|
+
def to_api_dict(self) -> dict[str, Any]:
|
|
131
|
+
"""Convert to API-compatible dictionary."""
|
|
132
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
class FunctionalAccount(BaseModel):
|
|
136
|
+
"""Functional account used for system management operations."""
|
|
137
|
+
|
|
138
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
139
|
+
|
|
140
|
+
functional_account_id: int = Field(alias="FunctionalAccountID")
|
|
141
|
+
account_name: str = Field(alias="AccountName")
|
|
142
|
+
domain_name: Optional[str] = Field(default=None, alias="DomainName")
|
|
143
|
+
platform_id: Optional[int] = Field(default=None, alias="PlatformID")
|
|
144
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
145
|
+
|
|
146
|
+
@classmethod
|
|
147
|
+
def from_api(cls, data: dict[str, Any]) -> "FunctionalAccount":
|
|
148
|
+
"""Create FunctionalAccount from API response."""
|
|
149
|
+
return cls.model_validate(data)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class PasswordRule(BaseModel):
|
|
153
|
+
"""Password complexity rule."""
|
|
154
|
+
|
|
155
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
156
|
+
|
|
157
|
+
password_rule_id: int = Field(alias="PasswordRuleID")
|
|
158
|
+
name: str = Field(alias="Name")
|
|
159
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
160
|
+
min_length: Optional[int] = Field(default=None, alias="MinLength")
|
|
161
|
+
max_length: Optional[int] = Field(default=None, alias="MaxLength")
|
|
162
|
+
require_upper: Optional[bool] = Field(default=None, alias="RequireUpper")
|
|
163
|
+
require_lower: Optional[bool] = Field(default=None, alias="RequireLower")
|
|
164
|
+
require_numeric: Optional[bool] = Field(default=None, alias="RequireNumeric")
|
|
165
|
+
require_special: Optional[bool] = Field(default=None, alias="RequireSpecial")
|
|
166
|
+
|
|
167
|
+
@classmethod
|
|
168
|
+
def from_api(cls, data: dict[str, Any]) -> "PasswordRule":
|
|
169
|
+
"""Create PasswordRule from API response."""
|
|
170
|
+
return cls.model_validate(data)
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
class Application(BaseModel):
|
|
174
|
+
"""Application that can be assigned to accounts."""
|
|
175
|
+
|
|
176
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
177
|
+
|
|
178
|
+
application_id: int = Field(alias="ApplicationID")
|
|
179
|
+
name: str = Field(alias="Name")
|
|
180
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
181
|
+
version: Optional[str] = Field(default=None, alias="Version")
|
|
182
|
+
|
|
183
|
+
@classmethod
|
|
184
|
+
def from_api(cls, data: dict[str, Any]) -> "Application":
|
|
185
|
+
"""Create Application from API response."""
|
|
186
|
+
return cls.model_validate(data)
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""Asset models for BeyondInsight API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Asset(BaseModel):
|
|
9
|
+
"""Asset (discovered or manually created system)."""
|
|
10
|
+
|
|
11
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
12
|
+
|
|
13
|
+
asset_id: int = Field(alias="AssetID")
|
|
14
|
+
asset_name: Optional[str] = Field(default=None, alias="AssetName")
|
|
15
|
+
ip_address: Optional[str] = Field(default=None, alias="IPAddress")
|
|
16
|
+
dns_name: Optional[str] = Field(default=None, alias="DnsName")
|
|
17
|
+
domain_name: Optional[str] = Field(default=None, alias="DomainName")
|
|
18
|
+
mac_address: Optional[str] = Field(default=None, alias="MACAddress")
|
|
19
|
+
asset_type: Optional[str] = Field(default=None, alias="AssetType")
|
|
20
|
+
workgroup_id: Optional[int] = Field(default=None, alias="WorkgroupID")
|
|
21
|
+
workgroup_name: Optional[str] = Field(default=None, alias="WorkgroupName")
|
|
22
|
+
operating_system: Optional[str] = Field(default=None, alias="OperatingSystem")
|
|
23
|
+
created_date: Optional[datetime] = Field(default=None, alias="CreatedDate")
|
|
24
|
+
last_updated_date: Optional[datetime] = Field(default=None, alias="LastUpdatedDate")
|
|
25
|
+
|
|
26
|
+
@classmethod
|
|
27
|
+
def from_api(cls, data: dict[str, Any]) -> "Asset":
|
|
28
|
+
"""Create Asset from API response."""
|
|
29
|
+
return cls.model_validate(data)
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def display_name(self) -> str:
|
|
33
|
+
"""Get a display name for the asset."""
|
|
34
|
+
return self.asset_name or self.dns_name or self.ip_address or f"Asset-{self.asset_id}"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class Workgroup(BaseModel):
|
|
38
|
+
"""Workgroup for organizing assets and systems."""
|
|
39
|
+
|
|
40
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
41
|
+
|
|
42
|
+
workgroup_id: int = Field(alias="WorkgroupID")
|
|
43
|
+
name: str = Field(alias="Name")
|
|
44
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
45
|
+
created_date: Optional[datetime] = Field(default=None, alias="CreatedDate")
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def from_api(cls, data: dict[str, Any]) -> "Workgroup":
|
|
49
|
+
"""Create Workgroup from API response."""
|
|
50
|
+
return cls.model_validate(data)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class Platform(BaseModel):
|
|
54
|
+
"""Platform (OS type) for managed systems."""
|
|
55
|
+
|
|
56
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
57
|
+
|
|
58
|
+
platform_id: int = Field(alias="PlatformID")
|
|
59
|
+
name: str = Field(alias="Name")
|
|
60
|
+
short_name: Optional[str] = Field(default=None, alias="ShortName")
|
|
61
|
+
platform_type: Optional[str] = Field(default=None, alias="PlatformType")
|
|
62
|
+
port_number: Optional[int] = Field(default=None, alias="PortNumber")
|
|
63
|
+
supports_sessions: Optional[bool] = Field(default=None, alias="SupportsSessions")
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_api(cls, data: dict[str, Any]) -> "Platform":
|
|
67
|
+
"""Create Platform from API response."""
|
|
68
|
+
return cls.model_validate(data)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class SmartRule(BaseModel):
|
|
72
|
+
"""Smart rule for automated system/account management."""
|
|
73
|
+
|
|
74
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
75
|
+
|
|
76
|
+
smart_rule_id: int = Field(alias="SmartRuleID")
|
|
77
|
+
name: str = Field(alias="Name")
|
|
78
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
79
|
+
category: Optional[str] = Field(default=None, alias="Category")
|
|
80
|
+
status: Optional[str] = Field(default=None, alias="Status")
|
|
81
|
+
created_date: Optional[datetime] = Field(default=None, alias="CreatedDate")
|
|
82
|
+
|
|
83
|
+
@classmethod
|
|
84
|
+
def from_api(cls, data: dict[str, Any]) -> "SmartRule":
|
|
85
|
+
"""Create SmartRule from API response."""
|
|
86
|
+
return cls.model_validate(data)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
class Attribute(BaseModel):
|
|
90
|
+
"""Custom attribute for assets, systems, or accounts."""
|
|
91
|
+
|
|
92
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
93
|
+
|
|
94
|
+
attribute_id: int = Field(alias="AttributeID")
|
|
95
|
+
name: str = Field(alias="Name")
|
|
96
|
+
attribute_type: Optional[str] = Field(default=None, alias="AttributeType")
|
|
97
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
98
|
+
|
|
99
|
+
@classmethod
|
|
100
|
+
def from_api(cls, data: dict[str, Any]) -> "Attribute":
|
|
101
|
+
"""Create Attribute from API response."""
|
|
102
|
+
return cls.model_validate(data)
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Common models and types shared across the API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Generic, Optional, TypeVar
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pydantic import BaseModel, ConfigDict
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
# Type variable for generic paginated responses
|
|
9
|
+
T = TypeVar("T", bound=BaseModel)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseAPIModel(BaseModel):
|
|
13
|
+
"""Base model for all API responses.
|
|
14
|
+
|
|
15
|
+
Allows extra fields to handle API changes gracefully.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
19
|
+
|
|
20
|
+
@classmethod
|
|
21
|
+
def from_api(cls, data: dict[str, Any]) -> "BaseAPIModel":
|
|
22
|
+
"""Create model instance from API response data.
|
|
23
|
+
|
|
24
|
+
Args:
|
|
25
|
+
data: Dictionary from API response
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
Model instance
|
|
29
|
+
"""
|
|
30
|
+
return cls.model_validate(data)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
class EntityRef(BaseModel):
|
|
34
|
+
"""Reference to an entity by ID and optional name."""
|
|
35
|
+
|
|
36
|
+
model_config = ConfigDict(extra="allow")
|
|
37
|
+
|
|
38
|
+
id: int
|
|
39
|
+
name: Optional[str] = None
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class PaginatedResponse(BaseModel, Generic[T]):
|
|
43
|
+
"""Generic paginated response wrapper."""
|
|
44
|
+
|
|
45
|
+
model_config = ConfigDict(extra="allow")
|
|
46
|
+
|
|
47
|
+
data: list[T]
|
|
48
|
+
total: Optional[int] = None
|
|
49
|
+
offset: Optional[int] = None
|
|
50
|
+
limit: Optional[int] = None
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class ApiError(BaseModel):
|
|
54
|
+
"""API error response."""
|
|
55
|
+
|
|
56
|
+
model_config = ConfigDict(extra="allow")
|
|
57
|
+
|
|
58
|
+
message: Optional[str] = None
|
|
59
|
+
error: Optional[str] = None
|
|
60
|
+
status_code: Optional[int] = None
|
|
61
|
+
details: Optional[dict[str, Any]] = None
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class Timestamp(BaseModel):
|
|
65
|
+
"""Timestamp wrapper for API datetime fields."""
|
|
66
|
+
|
|
67
|
+
model_config = ConfigDict(extra="allow")
|
|
68
|
+
|
|
69
|
+
value: Optional[datetime] = None
|
|
70
|
+
|
|
71
|
+
@classmethod
|
|
72
|
+
def from_api_string(cls, value: Optional[str]) -> "Timestamp":
|
|
73
|
+
"""Parse timestamp from API string format.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
value: ISO format datetime string or None
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
Timestamp instance
|
|
80
|
+
"""
|
|
81
|
+
if not value:
|
|
82
|
+
return cls(value=None)
|
|
83
|
+
try:
|
|
84
|
+
# Handle various datetime formats
|
|
85
|
+
return cls(value=datetime.fromisoformat(value.replace("Z", "+00:00")))
|
|
86
|
+
except (ValueError, AttributeError):
|
|
87
|
+
return cls(value=None)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# Common field aliases for API responses
|
|
91
|
+
COMMON_FIELD_ALIASES = {
|
|
92
|
+
"id": ["Id", "ID"],
|
|
93
|
+
"name": ["Name", "SystemName", "AccountName"],
|
|
94
|
+
"description": ["Description", "Desc"],
|
|
95
|
+
"created_at": ["CreatedDate", "DateCreated", "CreateDate"],
|
|
96
|
+
"updated_at": ["UpdatedDate", "DateUpdated", "ModifiedDate", "LastModifiedDate"],
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def normalize_api_response(data: dict[str, Any]) -> dict[str, Any]:
|
|
101
|
+
"""Normalize API response field names to lowercase with underscores.
|
|
102
|
+
|
|
103
|
+
Args:
|
|
104
|
+
data: API response dictionary
|
|
105
|
+
|
|
106
|
+
Returns:
|
|
107
|
+
Normalized dictionary with consistent field names
|
|
108
|
+
"""
|
|
109
|
+
if not data:
|
|
110
|
+
return data
|
|
111
|
+
|
|
112
|
+
result = {}
|
|
113
|
+
for key, value in data.items():
|
|
114
|
+
# Convert PascalCase to snake_case
|
|
115
|
+
normalized_key = ""
|
|
116
|
+
for i, char in enumerate(key):
|
|
117
|
+
if char.isupper() and i > 0:
|
|
118
|
+
normalized_key += "_"
|
|
119
|
+
normalized_key += char.lower()
|
|
120
|
+
|
|
121
|
+
# Recursively normalize nested objects
|
|
122
|
+
if isinstance(value, dict):
|
|
123
|
+
value = normalize_api_response(value)
|
|
124
|
+
elif isinstance(value, list):
|
|
125
|
+
value = [
|
|
126
|
+
normalize_api_response(item) if isinstance(item, dict) else item
|
|
127
|
+
for item in value
|
|
128
|
+
]
|
|
129
|
+
|
|
130
|
+
result[normalized_key] = value
|
|
131
|
+
|
|
132
|
+
return result
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
"""Managed System models for Password Safe API."""
|
|
2
|
+
|
|
3
|
+
from typing import Any, Optional
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
from pydantic import BaseModel, ConfigDict, Field
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class ManagedSystem(BaseModel):
|
|
9
|
+
"""Managed system in Password Safe."""
|
|
10
|
+
|
|
11
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
12
|
+
|
|
13
|
+
managed_system_id: int = Field(alias="ManagedSystemID")
|
|
14
|
+
system_name: str = Field(alias="SystemName")
|
|
15
|
+
platform_id: Optional[int] = Field(default=None, alias="PlatformID")
|
|
16
|
+
platform_name: Optional[str] = Field(default=None, alias="PlatformName")
|
|
17
|
+
workgroup_id: Optional[int] = Field(default=None, alias="WorkgroupID")
|
|
18
|
+
workgroup_name: Optional[str] = Field(default=None, alias="WorkgroupName")
|
|
19
|
+
asset_id: Optional[int] = Field(default=None, alias="AssetID")
|
|
20
|
+
contact_email: Optional[str] = Field(default=None, alias="ContactEmail")
|
|
21
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
22
|
+
port: Optional[int] = Field(default=None, alias="Port")
|
|
23
|
+
timeout: Optional[int] = Field(default=None, alias="Timeout")
|
|
24
|
+
|
|
25
|
+
# Functional account for management operations
|
|
26
|
+
functional_account_id: Optional[int] = Field(default=None, alias="FunctionalAccountID")
|
|
27
|
+
functional_account_name: Optional[str] = Field(default=None, alias="FunctionalAccountName")
|
|
28
|
+
|
|
29
|
+
# Elevation settings
|
|
30
|
+
elevation_command: Optional[str] = Field(default=None, alias="ElevationCommand")
|
|
31
|
+
|
|
32
|
+
# Password management settings
|
|
33
|
+
check_password_flag: Optional[bool] = Field(default=None, alias="CheckPasswordFlag")
|
|
34
|
+
change_password_after_any_release_flag: Optional[bool] = Field(
|
|
35
|
+
default=None, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
36
|
+
)
|
|
37
|
+
reset_password_on_mismatch_flag: Optional[bool] = Field(
|
|
38
|
+
default=None, alias="ResetPasswordOnMismatchFlag"
|
|
39
|
+
)
|
|
40
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
41
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
42
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
43
|
+
|
|
44
|
+
# Status and metadata
|
|
45
|
+
is_reachable: Optional[bool] = Field(default=None, alias="IsReachable")
|
|
46
|
+
last_change_date: Optional[datetime] = Field(default=None, alias="LastChangeDate")
|
|
47
|
+
created_date: Optional[datetime] = Field(default=None, alias="CreatedDate")
|
|
48
|
+
|
|
49
|
+
@classmethod
|
|
50
|
+
def from_api(cls, data: dict[str, Any]) -> "ManagedSystem":
|
|
51
|
+
"""Create ManagedSystem from API response."""
|
|
52
|
+
return cls.model_validate(data)
|
|
53
|
+
|
|
54
|
+
@property
|
|
55
|
+
def display_name(self) -> str:
|
|
56
|
+
"""Get a display name for the system."""
|
|
57
|
+
return self.system_name
|
|
58
|
+
|
|
59
|
+
@property
|
|
60
|
+
def id(self) -> int:
|
|
61
|
+
"""Alias for managed_system_id for convenience."""
|
|
62
|
+
return self.managed_system_id
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
class ManagedSystemCreate(BaseModel):
|
|
66
|
+
"""Data for creating a managed system."""
|
|
67
|
+
|
|
68
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
69
|
+
|
|
70
|
+
system_name: str = Field(alias="SystemName")
|
|
71
|
+
platform_id: int = Field(alias="PlatformID")
|
|
72
|
+
workgroup_id: Optional[int] = Field(default=None, alias="WorkgroupID")
|
|
73
|
+
asset_id: Optional[int] = Field(default=None, alias="AssetID")
|
|
74
|
+
contact_email: Optional[str] = Field(default=None, alias="ContactEmail")
|
|
75
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
76
|
+
port: Optional[int] = Field(default=None, alias="Port")
|
|
77
|
+
timeout: Optional[int] = Field(default=None, alias="Timeout")
|
|
78
|
+
functional_account_id: Optional[int] = Field(default=None, alias="FunctionalAccountID")
|
|
79
|
+
elevation_command: Optional[str] = Field(default=None, alias="ElevationCommand")
|
|
80
|
+
check_password_flag: Optional[bool] = Field(default=None, alias="CheckPasswordFlag")
|
|
81
|
+
change_password_after_any_release_flag: Optional[bool] = Field(
|
|
82
|
+
default=None, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
83
|
+
)
|
|
84
|
+
reset_password_on_mismatch_flag: Optional[bool] = Field(
|
|
85
|
+
default=None, alias="ResetPasswordOnMismatchFlag"
|
|
86
|
+
)
|
|
87
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
88
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
89
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
90
|
+
|
|
91
|
+
def to_api_dict(self) -> dict[str, Any]:
|
|
92
|
+
"""Convert to API-compatible dictionary."""
|
|
93
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class ManagedSystemUpdate(BaseModel):
|
|
97
|
+
"""Data for updating a managed system."""
|
|
98
|
+
|
|
99
|
+
model_config = ConfigDict(extra="allow", populate_by_name=True)
|
|
100
|
+
|
|
101
|
+
system_name: Optional[str] = Field(default=None, alias="SystemName")
|
|
102
|
+
contact_email: Optional[str] = Field(default=None, alias="ContactEmail")
|
|
103
|
+
description: Optional[str] = Field(default=None, alias="Description")
|
|
104
|
+
port: Optional[int] = Field(default=None, alias="Port")
|
|
105
|
+
timeout: Optional[int] = Field(default=None, alias="Timeout")
|
|
106
|
+
functional_account_id: Optional[int] = Field(default=None, alias="FunctionalAccountID")
|
|
107
|
+
elevation_command: Optional[str] = Field(default=None, alias="ElevationCommand")
|
|
108
|
+
check_password_flag: Optional[bool] = Field(default=None, alias="CheckPasswordFlag")
|
|
109
|
+
change_password_after_any_release_flag: Optional[bool] = Field(
|
|
110
|
+
default=None, alias="ChangePasswordAfterAnyReleaseFlag"
|
|
111
|
+
)
|
|
112
|
+
reset_password_on_mismatch_flag: Optional[bool] = Field(
|
|
113
|
+
default=None, alias="ResetPasswordOnMismatchFlag"
|
|
114
|
+
)
|
|
115
|
+
change_frequency_type: Optional[str] = Field(default=None, alias="ChangeFrequencyType")
|
|
116
|
+
change_frequency_days: Optional[int] = Field(default=None, alias="ChangeFrequencyDays")
|
|
117
|
+
change_time: Optional[str] = Field(default=None, alias="ChangeTime")
|
|
118
|
+
|
|
119
|
+
def to_api_dict(self) -> dict[str, Any]:
|
|
120
|
+
"""Convert to API-compatible dictionary."""
|
|
121
|
+
return self.model_dump(by_alias=True, exclude_none=True)
|