windoo 1.0.1

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.
Files changed (43) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGES.md +9 -0
  3. data/LICENSE.txt +177 -0
  4. data/README.md +222 -0
  5. data/lib/windoo/base_classes/array_manager.rb +335 -0
  6. data/lib/windoo/base_classes/criteria_manager.rb +327 -0
  7. data/lib/windoo/base_classes/criterion.rb +226 -0
  8. data/lib/windoo/base_classes/json_object.rb +472 -0
  9. data/lib/windoo/configuration.rb +221 -0
  10. data/lib/windoo/connection/actions.rb +152 -0
  11. data/lib/windoo/connection/attributes.rb +156 -0
  12. data/lib/windoo/connection/connect.rb +402 -0
  13. data/lib/windoo/connection/constants.rb +55 -0
  14. data/lib/windoo/connection/token.rb +489 -0
  15. data/lib/windoo/connection.rb +92 -0
  16. data/lib/windoo/converters.rb +31 -0
  17. data/lib/windoo/exceptions.rb +34 -0
  18. data/lib/windoo/mixins/api_collection.rb +408 -0
  19. data/lib/windoo/mixins/constants.rb +43 -0
  20. data/lib/windoo/mixins/default_connection.rb +75 -0
  21. data/lib/windoo/mixins/immutable.rb +34 -0
  22. data/lib/windoo/mixins/loading.rb +38 -0
  23. data/lib/windoo/mixins/patch/component.rb +102 -0
  24. data/lib/windoo/mixins/software_title/extension_attribute.rb +106 -0
  25. data/lib/windoo/mixins/utility.rb +23 -0
  26. data/lib/windoo/objects/capability.rb +82 -0
  27. data/lib/windoo/objects/capability_manager.rb +52 -0
  28. data/lib/windoo/objects/component.rb +99 -0
  29. data/lib/windoo/objects/component_criteria_manager.rb +26 -0
  30. data/lib/windoo/objects/component_criterion.rb +66 -0
  31. data/lib/windoo/objects/extension_attribute.rb +149 -0
  32. data/lib/windoo/objects/kill_app.rb +92 -0
  33. data/lib/windoo/objects/kill_app_manager.rb +89 -0
  34. data/lib/windoo/objects/patch.rb +235 -0
  35. data/lib/windoo/objects/patch_manager.rb +240 -0
  36. data/lib/windoo/objects/requirement.rb +85 -0
  37. data/lib/windoo/objects/requirement_manager.rb +52 -0
  38. data/lib/windoo/objects/software_title.rb +407 -0
  39. data/lib/windoo/validate.rb +548 -0
  40. data/lib/windoo/version.rb +15 -0
  41. data/lib/windoo/zeitwerk_config.rb +158 -0
  42. data/lib/windoo.rb +56 -0
  43. metadata +141 -0
@@ -0,0 +1,106 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Windoo
10
+
11
+ module Mixins
12
+
13
+ module SoftwareTitle
14
+
15
+ # An module that manages the ExtensionAttribute in a
16
+ # SoftwareTitle.
17
+ #
18
+ # Even though 'extensionAttributes' is plural, and
19
+ # they come from the server in an Array, at the moment there
20
+ # can only be one per SoftwareTitle.
21
+ #
22
+ # This module hides that confusion and allows you to work with
23
+ # just one
24
+ #
25
+ # If there's already an extension attribute, you can access it
26
+ # from the #extensionAttribute getter, and use that to directly
27
+ # update its values.
28
+ #
29
+ module ExtensionAttribute
30
+
31
+ # Construcor
32
+ ######################
33
+ def initialize(**init_data)
34
+ super
35
+ @extensionAttribute =
36
+ if @init_data[:extensionAttributes]&.first
37
+ Windoo::ExtensionAttribute.instantiate_from_container(
38
+ container: self,
39
+ **@init_data[:extensionAttributes].first
40
+ )
41
+ end
42
+ end
43
+
44
+ # Public Instance Methods
45
+ ####################################
46
+
47
+ # Add an ExtensionAttribute to this SoftwareTitle.
48
+ #
49
+ # NOTE: There can be only one EA per SoftwareTitle. You will
50
+ # get an error if one already exists.
51
+ #
52
+ # @param key [String] The name of the extension attribute as
53
+ # it appears in Jamf Pro
54
+ # NOTE: must be unique in the Title Editor AND Jamf Pro.
55
+ #
56
+ # @param displayName [String] The name of the extension
57
+ # attribute as it appears in Title Editor
58
+ #
59
+ # @param script [String] The script of that returns
60
+ # the value of the Extension Attribute on a computer.
61
+ # It must be a String that starts with '#!'
62
+ #
63
+ # @return [Integer] The id of the new Extension Attribute
64
+ #
65
+ def add_extensionAttribute(key:, displayName:, script:)
66
+ if @extensionAttribute
67
+ raise Windoo::AlreadyExistsError,
68
+ 'This SoftwareTitle already has an Extension Attribute. Either delete it before creating a new one, or update the existing one.'
69
+ end
70
+
71
+ @extensionAttribute = Windoo::ExtensionAttribute.create(
72
+ container: self,
73
+ key: key,
74
+ displayName: displayName,
75
+ script: script
76
+ )
77
+
78
+ @extensionAttribute.extensionAttributeId
79
+ end
80
+
81
+ # Delete the ExtensionAttribute from this SoftwareTitle
82
+ #
83
+ # When deleting an EA via this method, it is deleted
84
+ # from the server immediately, there is no need to #save
85
+ # the SoftwareTitle
86
+ #
87
+ # @return [Integer] The id of the deleted Extension Attribute
88
+ #
89
+ def delete_extensionAttribute
90
+ return unless @extensionAttribute
91
+
92
+ deleted_id = @extensionAttribute.delete
93
+ @extensionAttribute = nil
94
+
95
+ deleted_id
96
+ rescue Windoo::NoSuchItemError
97
+ nil
98
+ end
99
+
100
+ end # module ExtensionAttribute
101
+
102
+ end # module SoftwareTitle
103
+
104
+ end # module Mixins
105
+
106
+ end # module Windoo
@@ -0,0 +1,23 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module Windoo
9
+
10
+ module Mixins
11
+
12
+ # This should be extended into the Windoo module
13
+ module Utility
14
+
15
+ def self.extended(extender)
16
+ Windoo.verbose_extend extender, self
17
+ end
18
+
19
+ end # Utility
20
+
21
+ end # module Mixins
22
+
23
+ end # Windoo
@@ -0,0 +1,82 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Windoo
10
+
11
+ # The class for dealing with the capabilities of Patches in the
12
+ # Title Editor
13
+ #
14
+ # A capability is one criterion, a group of which define which computers
15
+ # are capable of running, and this allowed to install, a Patch.
16
+ class Capability < Windoo::BaseClasses::Criterion
17
+
18
+ # Mixins
19
+ ######################
20
+
21
+ include Windoo::Mixins::APICollection
22
+
23
+ # Constants
24
+ ######################
25
+
26
+ RSRC_PATH = 'capabilities'
27
+
28
+ CONTAINER_CLASS = Windoo::Patch
29
+
30
+ # Attributes
31
+ ######################
32
+
33
+ JSON_ATTRIBUTES = {
34
+
35
+ # @!attribute capabilityId
36
+ # @return [Integer] The id number of this capability
37
+ capabilityId: {
38
+ class: :Integer,
39
+ identifier: :primary,
40
+ do_not_send: true,
41
+ readonly: true
42
+ },
43
+
44
+ # @!attribute patchId
45
+ # @return [Integer] The id number of the Patch which uses this capability
46
+ patchId: {
47
+ class: :Integer,
48
+ do_not_send: true,
49
+ readonly: true
50
+ }
51
+
52
+ }.freeze
53
+
54
+ # Public Class Methods
55
+ ######################
56
+
57
+ ####
58
+ def self.fetch(*_args)
59
+ raise Windoo::UnsupportedError, 'Capabilities are fetched as part of the Patch that contains them'
60
+ end
61
+
62
+ # Private Instance Methods
63
+ ##########################################
64
+ private
65
+
66
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
67
+ # in the APICollection mixin.
68
+ def handle_create_response(post_response, container_id: nil)
69
+ @capabilityId = post_response[:capabilityId]
70
+ @patchId = post_response[:patchId]
71
+ @capabilityId
72
+ end
73
+
74
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
75
+ # in the APICollection mixin.
76
+ def handle_update_response(_put_response)
77
+ @capabilityId
78
+ end
79
+
80
+ end # class Capability
81
+
82
+ end # Module Windoo
@@ -0,0 +1,52 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Windoo
10
+
11
+ # A {Windoo::BaseClasses::CriteriaManager CriteriaManager} for dealing with the
12
+ # {Windoo::Capability Capabilities} of a {Windoo::Patch Patch}
13
+ #
14
+ # An instance of this is returned by {Patch#capabilities}
15
+ #
16
+ class CapabilityManager < Windoo::BaseClasses::CriteriaManager
17
+
18
+ # Constants
19
+ ######################
20
+
21
+ MEMBER_CLASS = Windoo::Capability
22
+
23
+ # Public Instance Methods
24
+ #################################
25
+
26
+ # Override this method to disable the containing patch
27
+ # if there are no more capabilities.
28
+ #
29
+ def delete_criterion(id)
30
+ deleted_id = super
31
+
32
+ # patches without a capabliity are not valid
33
+ # so must be disabled
34
+ @container.disable if @managed_array.empty?
35
+
36
+ deleted_id
37
+ end
38
+
39
+ # Delete all the criteria
40
+ #
41
+ # @return [void]
42
+ #
43
+ def delete_all_criteria
44
+ super
45
+ # patches without a capabliity are not valid
46
+ # so must be disabled
47
+ @container.disable
48
+ end
49
+
50
+ end # class RequirementManager
51
+
52
+ end # Module Windoo
@@ -0,0 +1,99 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ module Windoo
9
+
10
+ # A component holds a bunch of criteria defining which computers
11
+ # have a specific patch version installed.
12
+ class Component < Windoo::BaseClasses::JSONObject
13
+
14
+ # Mixins
15
+ ######################
16
+
17
+ include Windoo::Mixins::APICollection
18
+
19
+ # Constants
20
+ ######################
21
+
22
+ RSRC_PATH = 'components'
23
+
24
+ CONTAINER_CLASS = Windoo::Patch
25
+
26
+ # Attributes
27
+ ######################
28
+
29
+ JSON_ATTRIBUTES = {
30
+
31
+ # @!attribute componentId
32
+ # @return [Integer] The id number of this component
33
+ componentId: {
34
+ class: :Integer,
35
+ identifier: :primary,
36
+ do_not_send: true,
37
+ readonly: true
38
+ },
39
+
40
+ # @!attribute patchId
41
+ # @return [Integer] The id number of the patch which uses this component
42
+ patchId: {
43
+ class: :Integer,
44
+ do_not_send: true,
45
+ readonly: true
46
+ },
47
+
48
+ # @!attribute name
49
+ # @return [String] The name of the Software Title for this patch
50
+ name: {
51
+ class: :String
52
+ },
53
+
54
+ # @!attribute version
55
+ # @return [String] The version installed by this patch
56
+ version: {
57
+ class: :String
58
+ },
59
+
60
+ # @!attribute criteria
61
+ # @return [Array<Windoo::ComponentCriterion>] The criteria used by
62
+ # this component.
63
+ criteria: {
64
+ class: Windoo::ComponentCriteriaManager,
65
+ do_not_send: true
66
+ }
67
+
68
+ }.freeze
69
+
70
+ # Constructor
71
+ ######################
72
+
73
+ def initialize(**init_data)
74
+ super
75
+ @criteria ||= []
76
+ @criteria = Windoo::ComponentCriteriaManager.new @criteria, container: self
77
+ end
78
+
79
+ # Private Instance Methods
80
+ ##########################################
81
+ private
82
+
83
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
84
+ # in the APICollection mixin.
85
+ def handle_create_response(post_response, container_id: nil)
86
+ @componentId = post_response[:componentId]
87
+ @patchId = post_response[:patchId]
88
+ @componentId
89
+ end
90
+
91
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
92
+ # in the APICollection mixin.
93
+ def handle_update_response(_put_response)
94
+ @componentId
95
+ end
96
+
97
+ end # class Component
98
+
99
+ end # Module Windoo
@@ -0,0 +1,26 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Windoo
10
+
11
+ # A {Windoo::BaseClasses::CriteriaManager CriteriaManager} for dealing with the
12
+ # {Windoo::CompnentCriterion CompnentCriteria} of a {Windoo::Component Component}
13
+ # of a {Windoo::Patch Patch}
14
+ #
15
+ # An instance of this is returned by {Component#criteria}
16
+ #
17
+ class ComponentCriteriaManager < Windoo::BaseClasses::CriteriaManager
18
+
19
+ # Constants
20
+ ######################
21
+
22
+ MEMBER_CLASS = Windoo::ComponentCriterion
23
+
24
+ end # class RequirementManager
25
+
26
+ end # Module Windoo
@@ -0,0 +1,66 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+
6
+ # frozen_string_literal: true
7
+
8
+ # main module
9
+ module Windoo
10
+
11
+ # The class for dealing with the criteria of Patch Components
12
+ class ComponentCriterion < Windoo::BaseClasses::Criterion
13
+
14
+ # Mixins
15
+ ######################
16
+
17
+ include Windoo::Mixins::APICollection
18
+
19
+ # Constants
20
+ ######################
21
+
22
+ RSRC_PATH = 'criteria'
23
+
24
+ CONTAINER_CLASS = Windoo::Component
25
+
26
+ # Attributes
27
+ ######################
28
+
29
+ JSON_ATTRIBUTES = {
30
+
31
+ # @!attribute criteriaId
32
+ # @return [Integer] The id number of this criterion
33
+ criteriaId: {
34
+ class: :Integer,
35
+ identifier: :primary,
36
+ do_not_send: true,
37
+ readonly: true
38
+ },
39
+
40
+ # @!attribute componentId
41
+ # @return [Integer] The id number of the component which uses this criterion
42
+ componentId: {
43
+ class: :Integer,
44
+ do_not_send: true,
45
+ readonly: true
46
+ }
47
+
48
+ }.freeze
49
+
50
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
51
+ # in the APICollection mixin.
52
+ def handle_create_response(post_response, container_id: nil)
53
+ @criteriaId = post_response[:criteriaId]
54
+ @componentId = post_response[:componentId]
55
+ @componentId
56
+ end
57
+
58
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
59
+ # in the APICollection mixin.
60
+ def handle_update_response(_put_response)
61
+ @criteriaIds
62
+ end
63
+
64
+ end # class ComponentCriterion
65
+
66
+ end # module Windoo
@@ -0,0 +1,149 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+ #
7
+
8
+ module Windoo
9
+
10
+ # The class for dealing with Software Title ExtensionAttributes in the
11
+ # TitleEditor.
12
+ #
13
+ # NOTE: Do not create or delete instances of this class directly.
14
+ # use:
15
+ #
16
+ # - SoftwareTitle#add_extensionAttribute
17
+ # - From {SoftwareTitle#add_extensionAttribute}
18
+ # and
19
+ #
20
+ # - SoftwareTitle#delete_extensionAttribute
21
+ # - From {SoftwareTitle#delete_extensionAttribute}
22
+ #
23
+ class ExtensionAttribute < Windoo::BaseClasses::JSONObject
24
+
25
+ # Mixins
26
+ ######################
27
+
28
+ include Windoo::Mixins::APICollection
29
+
30
+ # Constants
31
+ ######################
32
+
33
+ RSRC_PATH = 'extensionattributes'
34
+
35
+ CONTAINER_CLASS = Windoo::SoftwareTitle
36
+
37
+ # Public Class Methods
38
+ ######################
39
+
40
+ # Override for APICollection.create to deal with raw scripts being
41
+ # passed in and converted to 'values'
42
+ def self.create(container: nil, **init_data)
43
+ if init_data[:script]
44
+ require 'base64'
45
+ init_data[:value] = Base64.encode64 init_data[:script]
46
+ init_data.delete :script
47
+ end
48
+
49
+ super container: container, cnx: container.cnx, **init_data
50
+ end
51
+
52
+ # Attributes
53
+ ######################
54
+
55
+ JSON_ATTRIBUTES = {
56
+
57
+ # @!attribute extensionAttributeId
58
+ # @return [Integer] The id number of this extension attribute in the Title Editor
59
+ extensionAttributeId: {
60
+ class: :Integer,
61
+ identifier: :primary,
62
+ do_not_send: true,
63
+ readonly: true
64
+ },
65
+
66
+ # @!attribute softwareTitleId
67
+ # @return [Integer] The id number of the title which uses this extension attribute
68
+ softwareTitleId: {
69
+ class: :Integer,
70
+ do_not_send: true,
71
+ readonly: true
72
+ },
73
+
74
+ # @!attribute key
75
+ # @return [String] The name of the extension attribute as it appears in Jamf Pro
76
+ # NOTE: must be unique in the Title Editor AND Jamf Pro.
77
+ key: {
78
+ class: :String,
79
+ required: true,
80
+ identifier: true
81
+ },
82
+
83
+ # @!attribute value
84
+ # @return [String] The Base64 encoded script for this extension attribute
85
+ value: {
86
+ class: :String
87
+ },
88
+
89
+ # @!attribute displayName
90
+ # @return [String] The name of the extension attribute as it appears in Title Editor
91
+ displayName: {
92
+ class: :String,
93
+ required: true
94
+ }
95
+
96
+ }.freeze
97
+
98
+ # Construcor
99
+ ######################
100
+ def initialize(**init_data)
101
+ # If we were given a raw script when creating a new
102
+ # EA, save it here and we'll process it in #create_on_server
103
+ @script = init_data[:script]
104
+
105
+ super
106
+ end
107
+
108
+ # Public Instance Methods
109
+ ######################
110
+
111
+ # @return [String] The script code for this extension attribute
112
+ def script
113
+ return if value.to_s.empty?
114
+
115
+ require 'base64'
116
+ Base64.decode64 value
117
+ end
118
+
119
+ # @param code [String] The script code for this extension attribute
120
+ # @return [void]
121
+ def script=(code)
122
+ raise ArgumentError, 'Code must be a string starting with #!' unless code.to_s.start_with?('#!')
123
+
124
+ require 'base64'
125
+ self.value = Base64.encode64(code)
126
+ end
127
+
128
+ # Private Instance Methods
129
+ ##########################################
130
+
131
+ private
132
+
133
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
134
+ # in the APICollection mixin.
135
+ def handle_create_response(post_response, container_id: nil)
136
+ @extensionAttributeId = post_response[:extensionAttributeId]
137
+ @softwareTitleId = container_id
138
+ @extensionAttributeId
139
+ end
140
+
141
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
142
+ # in the APICollection mixin.
143
+ def handle_update_response(_put_response)
144
+ @extensionAttributeId
145
+ end
146
+
147
+ end # class ExtensionAttribute
148
+
149
+ end # module Windoo
@@ -0,0 +1,92 @@
1
+ # Copyright 2025 Pixar
2
+ #
3
+ # Licensed under the terms set forth in the LICENSE.txt file available at
4
+ # at the root of this project.
5
+ #
6
+
7
+ # frozen_string_literal: true
8
+
9
+ module Windoo
10
+
11
+ # A class representing an Application that cannot be running when
12
+ # a Patch is installed.
13
+ #
14
+ # Patches can contain any number of these, and they are accessed using
15
+ # a {Windoo::KillAppManager} available from the {Patch#killApps} method.
16
+ #
17
+ class KillApp < Windoo::BaseClasses::JSONObject
18
+
19
+ # Mixins
20
+ ######################
21
+
22
+ include Windoo::Mixins::APICollection
23
+
24
+ # Constants
25
+ ######################
26
+
27
+ RSRC_PATH = 'killapps'
28
+
29
+ CONTAINER_CLASS = Windoo::Patch
30
+
31
+ # Attributes
32
+ ######################
33
+
34
+ JSON_ATTRIBUTES = {
35
+
36
+ # @!attribute killAppId
37
+ # @return [Integer] The id number of this kill app
38
+ killAppId: {
39
+ class: :Integer,
40
+ identifier: :primary,
41
+ do_not_send: true,
42
+ readonly: true
43
+ },
44
+
45
+ # @!attribute patchId
46
+ # @return [Integer] The id number of the patch which uses this
47
+ # kill app
48
+ patchId: {
49
+ class: :Integer,
50
+ do_not_send: true,
51
+ readonly: true
52
+ },
53
+
54
+ # @!attribute bundleId
55
+ # @return [String] The bundle id of the app that must be quit
56
+ # e.g. com.apple.Safari
57
+ bundleId: {
58
+ class: :String,
59
+ required: true
60
+ },
61
+
62
+ # @!attribute appName
63
+ # @return [String] The name of the app that must be quit
64
+ appName: {
65
+ class: :String,
66
+ required: true
67
+ }
68
+
69
+ }
70
+
71
+ # Private Instance Methods
72
+ ##########################################
73
+ private
74
+
75
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
76
+ # in the APICollection mixin.
77
+ def handle_create_response(post_response, container_id: nil)
78
+ @killAppId = post_response[:killAppId]
79
+ @patchId = post_response[:patchId]
80
+
81
+ @killAppId
82
+ end
83
+
84
+ # See the section 'REQUIRED ITEMS WHEN MIXING IN'
85
+ # in the APICollection mixin.
86
+ def handle_update_response(_put_response)
87
+ @killAppId
88
+ end
89
+
90
+ end # class KillApp
91
+
92
+ end # Module Windoo