From bb1cacb63ac8f22ab8c06df7ea2ee6a9209d7b67 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 09:30:09 +0200 Subject: [PATCH 1/6] Accept any Trigger or Retry (policy) value for the Policy details response --- src/openhound_jamf/models/policy.py | 42 ++++++++++++++--------------- 1 file changed, 20 insertions(+), 22 deletions(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index d78a684..f9b38e8 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from enum import Enum from typing import Any from openhound.core.asset import BaseAsset @@ -8,22 +7,21 @@ from openhound_jamf.graph import JAMFNodeProperties from openhound_jamf.main import app +# class Trigger(Enum): +# CHECKIN = "CHECKIN" +# LOGIN = "LOGIN" +# OTHER = "OTHER" +# STARTUP = "STARTUP" +# ENROLLMENT_COMPLETE = "ENROLLMENT_COMPLETE" +# NETWORK_STATE_CHANGED = "NETWORK_STATE_CHANGED" +# EVENT = "EVENT" +# USER_INITIATED = "USER_INITIATED" -class Trigger(Enum): - CHECKIN = "CHECKIN" - LOGIN = "LOGIN" - OTHER = "OTHER" - STARTUP = "STARTUP" - ENROLLMENT_COMPLETE = "ENROLLMENT_COMPLETE" - NETWORK_STATE_CHANGED = "NETWORK_STATE_CHANGED" - EVENT = "EVENT" - USER_INITIATED = "USER_INITIATED" - -class Retry(Enum): - none = "none" - immediate = "immediate" - interval = "interval" +# class Retry(Enum): +# none = "none" +# immediate = "immediate" +# interval = "interval" class BasePolicy(BaseModel): @@ -68,14 +66,14 @@ class Computer(BaseModel): class LimitToUsers(BaseModel): - user_groups: list[dict[str, Any]] = Field(default_factory=list) + user_groups: list[dict[str, str]] | list[str] = Field(default_factory=list) class Limitations(BaseModel): - users: list[dict[str, Any]] = Field(default_factory=list) - user_groups: list[dict[str, Any]] = Field(default_factory=list) - network_segments: list[dict[str, Any]] = Field(default_factory=list) - ibeacons: list[dict[str, Any]] = Field(default_factory=list) + users: list[dict[str, str]] = Field(default_factory=list) + user_groups: list[dict[str, str]] = Field(default_factory=list) + network_segments: list[dict[str, str]] = Field(default_factory=list) + ibeacons: list[dict[str, str]] = Field(default_factory=list) class Exclusions(BaseModel): @@ -217,7 +215,7 @@ class Policy(BaseAsset): id: int name: str enabled: bool - trigger: Trigger | None = None + trigger: str | None = None trigger_checkin: bool | None = None trigger_enrollment_complete: bool | None = None trigger_login: bool | None = None @@ -225,7 +223,7 @@ class Policy(BaseAsset): trigger_startup: bool | None = None trigger_other: str | None = None frequency: str - retry_event: Retry | None = None + retry_event: str | None = None retry_attempts: int | None = None notify_on_each_failed_retry: bool | None = None location_user_only: bool | None = None From 5d4024c3e3449757e7678ad465047e3b045aabfb Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 09:43:58 +0200 Subject: [PATCH 2/6] Remove open interpretation of model values (Any) and force values to be read and written as a string --- src/openhound_jamf/models/policy.py | 103 ++++++++++++++++++---------- 1 file changed, 68 insertions(+), 35 deletions(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index f9b38e8..40e5fbd 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -1,5 +1,4 @@ from dataclasses import dataclass -from typing import Any from openhound.core.asset import BaseAsset from pydantic import BaseModel, Field @@ -7,22 +6,6 @@ from openhound_jamf.graph import JAMFNodeProperties from openhound_jamf.main import app -# class Trigger(Enum): -# CHECKIN = "CHECKIN" -# LOGIN = "LOGIN" -# OTHER = "OTHER" -# STARTUP = "STARTUP" -# ENROLLMENT_COMPLETE = "ENROLLMENT_COMPLETE" -# NETWORK_STATE_CHANGED = "NETWORK_STATE_CHANGED" -# EVENT = "EVENT" -# USER_INITIATED = "USER_INITIATED" - - -# class Retry(Enum): -# none = "none" -# immediate = "immediate" -# interval = "interval" - class BasePolicy(BaseModel): id: int @@ -41,7 +24,7 @@ class DateTimeLimitations(BaseModel): expiration_date: str | None = None expiration_date_epoch: int | None = None expiration_date_utc: str | None = None - no_execute_on: dict[str, Any] = Field(default_factory=dict) + # no_execute_on: dict[str, Any] = Field(default_factory=dict) no_execute_start: str | None = None no_execute_end: str | None = None @@ -49,7 +32,7 @@ class DateTimeLimitations(BaseModel): class NetworkLimitations(BaseModel): minimum_network_connection: str | None = None any_ip_address: bool | None = None - network_segments: list[dict[str, Any]] = Field(default_factory=list) + network_segments: list[dict[str, str]] = Field(default_factory=list) class OverrideDefaultSettings(BaseModel): @@ -78,26 +61,33 @@ class Limitations(BaseModel): class Exclusions(BaseModel): computers: list[Computer] - computer_groups: list[dict[str, Any]] = Field(default_factory=list) - buildings: list[dict[str, Any]] = Field(default_factory=list) - departments: list[dict[str, Any]] = Field(default_factory=list) - users: list[dict[str, Any]] = Field(default_factory=list) - user_groups: list[dict[str, Any]] = Field(default_factory=list) - network_segments: list[dict[str, Any]] = Field(default_factory=list) - ibeacons: list[dict[str, Any]] = Field(default_factory=list) + computer_groups: list[dict[str, str]] = Field(default_factory=list) + buildings: list[dict[str, str]] = Field(default_factory=list) + departments: list[dict[str, str]] = Field(default_factory=list) + users: list[dict[str, str]] = Field(default_factory=list) + user_groups: list[dict[str, str]] = Field(default_factory=list) + network_segments: list[dict[str, str]] = Field(default_factory=list) + ibeacons: list[dict[str, str]] = Field(default_factory=list) class Scope(BaseModel): all_computers: bool computers: list[Computer] - computer_groups: list[dict[str, Any]] = Field(default_factory=list) - buildings: list[dict[str, Any]] = Field(default_factory=list) - departments: list[dict[str, Any]] = Field(default_factory=list) + computer_groups: list[dict[str, str]] = Field(default_factory=list) + buildings: list[dict[str, str]] = Field(default_factory=list) + departments: list[dict[str, str]] = Field(default_factory=list) limit_to_users: LimitToUsers | None = None limitations: Limitations | None = None exclusions: Exclusions +class Category(BaseModel): + id: int | None = None + name: str | None = None + display_index: bool | None = None + feature_in: bool | None = None + + class SelfService(BaseModel): use_for_self_service: bool | None = None self_service_display_name: str | None = None @@ -105,13 +95,23 @@ class SelfService(BaseModel): reinstall_button_text: str | None = None self_service_description: str | None = None force_users_to_view_description: bool | None = None - self_service_icon: dict[str, Any] = Field(default_factory=dict) + self_service_icon: dict[str, str] = Field(default_factory=dict) feature_on_main_page: bool | None = None - self_service_categories: list[dict[str, Any]] = Field(default_factory=list) + self_service_categories: list[Category] = Field(default_factory=list) + + +class Package(BaseModel): + id: int | None = None + name: str | None = None + + +class Packages(BaseModel): + size: int | None = None + package: Package | None = None class PackageConfiguration(BaseModel): - packages: list[dict[str, Any]] = Field(default_factory=list) + packages: list[Package] = Field(default_factory=list) distribution_point: str | None = None @@ -138,9 +138,31 @@ class OpenFirmwareEfiPassword(BaseModel): of_password_sha256: str | None = None +class DBinding(BaseModel): + id: int | None = None + name: str | None = None + + +class DBindings(BaseModel): + size: int | None = None + binding: DBinding | None = None + + +class MaintenanceAccount(BaseModel): + action: str | None = None + username: str | None = None + admin: bool | None = None + home: str | None = None + + +class MaintenanceAccounts(BaseModel): + size: int | None = None + account: MaintenanceAccount | None = None + + class AccountMaintenance(BaseModel): - accounts: list[dict[str, Any]] = Field(default_factory=list) - directory_bindings: list[dict[str, Any]] = Field(default_factory=list) + accounts: list[MaintenanceAccounts] = Field(default_factory=list) + directory_bindings: list[DBindings] = Field(default_factory=list) management_account: ManagementAccount | None = None open_firmware_efi_password: OpenFirmwareEfiPassword | None = None @@ -192,6 +214,17 @@ class DiskEncryption(BaseModel): action: str | None = None +class DockItem(BaseModel): + id: int | None = None + name: str | None = None + action: str | None = None + + +class DockItems(BaseModel): + size: int | None = None + dock_item: DockItem | None = None + + @dataclass class PolicyProperties(JAMFNodeProperties): """JAMF Policy node properties""" @@ -241,7 +274,7 @@ class Policy(BaseAsset): package_configuration: PackageConfiguration | None = None scripts: list[Script] printers: list | None = Field(default_factory=list) - dock_items: list[dict[str, Any]] = Field(default_factory=list) + dock_items: list[DockItems] = Field(default_factory=list) account_maintenance: AccountMaintenance | None = None reboot: Reboot | None = None maintenance: Maintenance | None = None From d3f598b179abec39b031ccbf7b4b4b3f8a330269 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 09:56:01 +0200 Subject: [PATCH 3/6] Remove unused field --- src/openhound_jamf/models/policy.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index 40e5fbd..fdf9ef6 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -24,7 +24,6 @@ class DateTimeLimitations(BaseModel): expiration_date: str | None = None expiration_date_epoch: int | None = None expiration_date_utc: str | None = None - # no_execute_on: dict[str, Any] = Field(default_factory=dict) no_execute_start: str | None = None no_execute_end: str | None = None From 2fc8899d465c0639110ae5f953c079bf9ec7f854 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 10:13:24 +0200 Subject: [PATCH 4/6] Modified overrides/lookups based on new test data/responses --- src/openhound_jamf/models/policy.py | 38 +++++++++++++++++------------ 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index fdf9ef6..38e6dd8 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -31,7 +31,7 @@ class DateTimeLimitations(BaseModel): class NetworkLimitations(BaseModel): minimum_network_connection: str | None = None any_ip_address: bool | None = None - network_segments: list[dict[str, str]] = Field(default_factory=list) + network_segments: list[dict[str, IdName]] = Field(default_factory=list) class OverrideDefaultSettings(BaseModel): @@ -52,29 +52,29 @@ class LimitToUsers(BaseModel): class Limitations(BaseModel): - users: list[dict[str, str]] = Field(default_factory=list) - user_groups: list[dict[str, str]] = Field(default_factory=list) - network_segments: list[dict[str, str]] = Field(default_factory=list) - ibeacons: list[dict[str, str]] = Field(default_factory=list) + users: list[dict[str, IdName]] = Field(default_factory=list) + user_groups: list[dict[str, IdName]] = Field(default_factory=list) + network_segments: list[dict[str, IdName]] = Field(default_factory=list) + ibeacons: list[dict[str, IdName]] = Field(default_factory=list) class Exclusions(BaseModel): computers: list[Computer] - computer_groups: list[dict[str, str]] = Field(default_factory=list) - buildings: list[dict[str, str]] = Field(default_factory=list) - departments: list[dict[str, str]] = Field(default_factory=list) - users: list[dict[str, str]] = Field(default_factory=list) - user_groups: list[dict[str, str]] = Field(default_factory=list) - network_segments: list[dict[str, str]] = Field(default_factory=list) - ibeacons: list[dict[str, str]] = Field(default_factory=list) + computer_groups: list[dict[str, IdName]] = Field(default_factory=list) + buildings: list[dict[str, IdName]] = Field(default_factory=list) + departments: list[dict[str, IdName]] = Field(default_factory=list) + users: list[dict[str, IdName]] = Field(default_factory=list) + user_groups: list[dict[str, IdName]] = Field(default_factory=list) + network_segments: list[dict[str, IdName]] = Field(default_factory=list) + ibeacons: list[dict[str, IdName]] = Field(default_factory=list) class Scope(BaseModel): all_computers: bool computers: list[Computer] - computer_groups: list[dict[str, str]] = Field(default_factory=list) - buildings: list[dict[str, str]] = Field(default_factory=list) - departments: list[dict[str, str]] = Field(default_factory=list) + computer_groups: list[dict[str, IdName]] = Field(default_factory=list) + buildings: list[dict[str, IdName]] = Field(default_factory=list) + departments: list[dict[str, IdName]] = Field(default_factory=list) limit_to_users: LimitToUsers | None = None limitations: Limitations | None = None exclusions: Exclusions @@ -87,6 +87,12 @@ class Category(BaseModel): feature_in: bool | None = None +class SelfServiceIcon(BaseModel): + id: int | None = None + filename: str | None = None + uri: str | None = None + + class SelfService(BaseModel): use_for_self_service: bool | None = None self_service_display_name: str | None = None @@ -94,7 +100,7 @@ class SelfService(BaseModel): reinstall_button_text: str | None = None self_service_description: str | None = None force_users_to_view_description: bool | None = None - self_service_icon: dict[str, str] = Field(default_factory=dict) + self_service_icon: SelfServiceIcon = Field(default_factory=dict) feature_on_main_page: bool | None = None self_service_categories: list[Category] = Field(default_factory=list) From bfd10e0b2b005ca498e94c6d9b5270711af5004f Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 10:14:56 +0200 Subject: [PATCH 5/6] Fixed display_in field --- src/openhound_jamf/models/policy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index 38e6dd8..8468a45 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -83,7 +83,7 @@ class Scope(BaseModel): class Category(BaseModel): id: int | None = None name: str | None = None - display_index: bool | None = None + display_in: bool | None = None feature_in: bool | None = None From 909fc92d62ca0639beedde7acafe8cbb94787196 Mon Sep 17 00:00:00 2001 From: Joey Dreijer Date: Thu, 18 Jun 2026 10:16:18 +0200 Subject: [PATCH 6/6] Accept multiple Packages as part of PackageConfiguration model --- src/openhound_jamf/models/policy.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/openhound_jamf/models/policy.py b/src/openhound_jamf/models/policy.py index 8468a45..ec1ffb0 100644 --- a/src/openhound_jamf/models/policy.py +++ b/src/openhound_jamf/models/policy.py @@ -116,7 +116,7 @@ class Packages(BaseModel): class PackageConfiguration(BaseModel): - packages: list[Package] = Field(default_factory=list) + packages: list[Packages] = Field(default_factory=list) distribution_point: str | None = None