stidantic 0.1.3__py3-none-any.whl → 0.2.1__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.

Potentially problematic release.


This version of stidantic might be problematic. Click here for more details.

stidantic/sco.py CHANGED
@@ -1,32 +1,33 @@
1
1
  import ipaddress
2
- from datetime import datetime
3
- from annotated_types import Ge, Le
4
- from typing_extensions import Annotated, TypedDict
5
- from typing import Any, Literal, Self
2
+ from typing import Annotated, Any, ClassVar, Literal, Self
6
3
 
4
+ from annotated_types import Ge, Le
5
+ from pydantic import Field
7
6
  from pydantic.functional_serializers import SerializeAsAny
8
- from pydantic.functional_validators import model_validator
7
+ from pydantic.functional_validators import AfterValidator, model_validator
9
8
  from pydantic.types import JsonValue
10
- from pydantic import Field
9
+ from typing_extensions import TypedDict
11
10
 
12
11
  from stidantic.types import (
13
12
  Extension,
13
+ Hashes,
14
+ Identifier,
15
+ StixBinary,
14
16
  StixCore,
15
17
  StixObservable,
16
- StixBinary,
18
+ StixTimestamp,
17
19
  StixUrl,
18
- Hashes,
19
- Identifier,
20
20
  )
21
+ from stidantic.validators import identifier_of_type
21
22
  from stidantic.vocab import (
22
23
  EncryptionAlgorithm,
23
24
  NetworkSocketAddressFamily,
24
25
  NetworkSocketType,
25
26
  WindowsIntegrityLevel,
27
+ WindowsRegistryDatatype,
26
28
  WindowsServiceStartType,
27
29
  WindowsServiceStatus,
28
30
  WindowsServiceType,
29
- WindowsRegistryDatatype,
30
31
  )
31
32
 
32
33
 
@@ -59,6 +60,7 @@ class Artifact(StixObservable):
59
60
  # Specifies the decryption key for the encrypted binary data (either via payload_bin or url). For example,
60
61
  # this may be useful in cases of sharing malware samples, which are often encoded in an encrypted archive.
61
62
  decryption_key: str | None = None
63
+ id_contributing_properties: ClassVar[list[str] | None] = ["hashes", "payload_bin"]
62
64
 
63
65
  @model_validator(mode="after")
64
66
  def at_least_one_of(self) -> Self:
@@ -75,9 +77,7 @@ class Artifact(StixObservable):
75
77
  The url property MUST NOT be present if payload_bin is provided.
76
78
  """
77
79
  if self.payload_bin and self.url:
78
- raise ValueError(
79
- "The url property MUST NOT be present if payload_bin is provided"
80
- )
80
+ raise ValueError("The url property MUST NOT be present if payload_bin is provided")
81
81
  return self
82
82
 
83
83
  @model_validator(mode="after")
@@ -95,16 +95,9 @@ class Artifact(StixObservable):
95
95
  The decryption_key property MUST NOT be present when the encryption_algorithm property is absent.
96
96
  """
97
97
  if not self.encryption_algorithm and self.decryption_key:
98
- raise ValueError(
99
- "The decryption_key MUST NOT be present when the encryption_algorithm property is absent"
100
- )
98
+ raise ValueError("The decryption_key MUST NOT be present when the encryption_algorithm property is absent")
101
99
  return self
102
100
 
103
- class Config:
104
- json_schema_extra: dict[str, list[str]] = {
105
- "id_contributing_properties": ["hashes", "payload_bin"]
106
- }
107
-
108
101
 
109
102
  # 6.2 Autonomous System
110
103
  class AutonomousSystem(StixObservable):
@@ -120,11 +113,7 @@ class AutonomousSystem(StixObservable):
120
113
  name: str | None = None
121
114
  # Specifies the name of the Regional Internet Registry (RIR) that assigned the number to the AS.
122
115
  rir: str | None = None
123
-
124
- class Config:
125
- json_schema_extra: dict[str, list[str]] = {
126
- "id_contributing_properties": ["number"]
127
- }
116
+ id_contributing_properties: ClassVar[list[str] | None] = ["number"]
128
117
 
129
118
 
130
119
  # 6.3 Directory Object
@@ -143,19 +132,22 @@ class Directory(StixObservable):
143
132
  # MUST be used instead.
144
133
  path_enc: str | None = None
145
134
  # Specifies the date/time the directory was created.
146
- ctime: datetime | None = None
135
+ ctime: StixTimestamp | None = None
147
136
  # Specifies the date/time the directory was last written to/modified.
148
- mtime: datetime | None = None
137
+ mtime: StixTimestamp | None = None
149
138
  # Specifies the date/time the directory was last accessed.
150
- atime: datetime | None = None
139
+ atime: StixTimestamp | None = None
151
140
  # Specifies a list of references to other File and/or Directory objects contained within the directory.
152
- # The objects referenced in this list MUST be of type file or directory.
153
- contains_refs: list[Identifier] | None = None
154
-
155
- class Config:
156
- json_schema_extra: dict[str, list[str]] = {
157
- "id_contributing_properties": ["path"]
158
- }
141
+ contains_refs: (
142
+ list[
143
+ Annotated[
144
+ Identifier,
145
+ AfterValidator(identifier_of_type("file", "directory")),
146
+ ]
147
+ ]
148
+ | None
149
+ ) = None
150
+ id_contributing_properties: ClassVar[list[str] | None] = ["path"]
159
151
 
160
152
 
161
153
  # 6.4 Domain Name Object
@@ -174,14 +166,16 @@ class DomainName(StixObservable):
174
166
  # domain and sub-domain contained within the domain name MUST conform to [RFC5890].
175
167
  value: str
176
168
  # Specifies a list of references to one or more IP addresses or domain names that the domain name resolves to.
177
- # The objects referenced in this list MUST be of type ipv4-addr or ipv6-addr or domain-name
178
- # (for cases such as CNAME records).
179
- resolves_to_refs: list[Identifier] | None = None
180
-
181
- class Config:
182
- json_schema_extra: dict[str, list[str]] = {
183
- "id_contributing_properties": ["value"]
184
- }
169
+ resolves_to_refs: (
170
+ list[
171
+ Annotated[
172
+ Identifier,
173
+ AfterValidator(identifier_of_type("ipv4-addr", "ipv6-addr", "domain-name")),
174
+ ]
175
+ ]
176
+ | None
177
+ ) = None
178
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
185
179
 
186
180
 
187
181
  # 6.5 Email Address Object
@@ -198,13 +192,8 @@ class EmailAddress(StixObservable):
198
192
  # This property corresponds to the display-name construction in section 3.4 of [RFC5322].
199
193
  display_name: str | None = None
200
194
  # Specifies the user account that the email address belongs to, as a reference to a User Account object.
201
- # The object referenced in this property MUST be of type user-account.
202
- belongs_to_ref: Identifier | None = None
203
-
204
- class Config:
205
- json_schema_extra: dict[str, list[str]] = {
206
- "id_contributing_properties": ["value"]
207
- }
195
+ belongs_to_ref: Annotated[Identifier, AfterValidator(identifier_of_type("user-account"))] | None = None
196
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
208
197
 
209
198
 
210
199
  # 6.6.2 Email MIME Component Type
@@ -223,11 +212,10 @@ class EmailMimeComponent(StixCore):
223
212
  body: str | None = None
224
213
  # Specifies the contents of non-textual MIME parts, that is those whose content_type does not start with text/,
225
214
  # as a reference to an Artifact object or File object.
226
- # The object referenced in this property MUST be of type artifact or file.
227
215
  # For use cases where conveying the actual data contained in the MIME part is of primary importance,
228
216
  # artifact SHOULD be used. Otherwise, for use cases where conveying metadata about the file-like properties of the
229
217
  # MIME part is of primary importance, file SHOULD be used.
230
- body_raw_ref: Identifier | None = None
218
+ body_raw_ref: Annotated[Identifier, AfterValidator(identifier_of_type("file", "artifact"))] | None = None
231
219
  # Specifies the value of the "Content-Type" header field of the MIME part.
232
220
  # Any additional "Content-Type" header field parameters such as charset SHOULD be included in this property.
233
221
  content_type: str | None = None
@@ -261,24 +249,24 @@ class EmailMessage(StixObservable):
261
249
  # Indicates whether the email body contains multiple MIME parts.
262
250
  is_multipart: bool
263
251
  # Specifies the date/time that the email message was sent.
264
- date: datetime | None = None
252
+ date: StixTimestamp | None = None
265
253
  # Specifies the value of the "Content-Type" header of the email message.
266
254
  content_type: str | None = None
267
255
  # Specifies the value of the "From:" header of the email message.
268
256
  # The "From:" field specifies the author of the message, that is, the mailbox(es) of the person or system
269
257
  # responsible for the writing of the message.
270
- from_ref: Identifier | None = None
258
+ from_ref: Annotated[Identifier, AfterValidator(identifier_of_type("email-addr"))] | None = None
271
259
  # Specifies the value of the "Sender" field of the email message.
272
260
  # The "Sender:" field specifies the mailbox of the agent responsible for the actual transmission of the message.
273
- sender_ref: Identifier | None = None
261
+ sender_ref: Annotated[Identifier, AfterValidator(identifier_of_type("email-addr"))] | None = None
274
262
  # Specifies the mailboxes that are "To:" recipients of the email message.
275
- to_refs: list[Identifier] | None = None
263
+ to_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("email-addr"))]] | None = None
276
264
  # Specifies the mailboxes that are "CC:" recipients of the email message.
277
- cc_refs: list[Identifier] | None = None
265
+ cc_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("email-addr"))]] | None = None
278
266
  # Specifies the mailboxes that are "BCC:" recipients of the email message.
279
267
  # As per [RFC5322], the absence of this property should not be interpreted as semantically equivalent to an absent
280
268
  # BCC header on the message being characterized.
281
- bcc_refs: list[Identifier] | None = None
269
+ bcc_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("email-addr"))]] | None = None
282
270
  # Specifies the Message-ID field of the email message.
283
271
  message_id: str | None = None
284
272
  # Specifies the subject of the email message.
@@ -297,8 +285,9 @@ class EmailMessage(StixObservable):
297
285
  # Specifies a list of the MIME parts that make up the email body.
298
286
  body_multipart: list[EmailMimeComponent] | None = None
299
287
  # Specifies the raw binary contents of the email message, including both the headers and body, as a reference
300
- # to an Artifact object. The object referenced in this property MUST be of type artifact.
301
- raw_email_ref: Identifier | None = None
288
+ # to an Artifact object.
289
+ raw_email_ref: Annotated[Identifier, AfterValidator(identifier_of_type("artifact"))] | None = None
290
+ id_contributing_properties: ClassVar[list[str] | None] = ["from_ref", "subject", "body"]
302
291
 
303
292
  @model_validator(mode="after")
304
293
  def validate_body(self) -> Self:
@@ -312,11 +301,6 @@ class EmailMessage(StixObservable):
312
301
  raise ValueError("body_multipart MUST NOT be used if is_multipart is false")
313
302
  return self
314
303
 
315
- class Config:
316
- json_schema_extra: dict[str, list[str]] = {
317
- "id_contributing_properties": ["from_ref", "subject", "body"]
318
- }
319
-
320
304
 
321
305
  # 6.7.2 Archive File Extension
322
306
  class ArchiveFileExtension(Extension):
@@ -327,8 +311,8 @@ class ArchiveFileExtension(Extension):
327
311
  """
328
312
 
329
313
  # This property specifies the files that are contained in the archive. It MUST contain references to one or more
330
- # File objects. The objects referenced in this list MUST be of type file or directory.
331
- contains_refs: list[Identifier]
314
+ # File objects.
315
+ contains_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("file", "directory"))]]
332
316
  # Specifies a comment included as part of the archive file.
333
317
  comment: str | None = None
334
318
 
@@ -547,7 +531,7 @@ class WindowsPEOptionalHeader(StixCore):
547
531
 
548
532
  @model_validator(mode="before")
549
533
  @classmethod
550
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
534
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
551
535
  """
552
536
  An object using the Windows PE Optional Header Type MUST contain at least one property from this type.
553
537
  """
@@ -584,7 +568,7 @@ class WindowsPEBinaryExtension(Extension):
584
568
  number_of_sections: Annotated[int, Ge(0)] | None = None
585
569
  # Specifies the time when the PE binary was created.
586
570
  # The timestamp value MUST be precise to the second.
587
- time_date_stamp: datetime | None = None
571
+ time_date_stamp: StixTimestamp | None = None
588
572
  # Specifies the file offset of the COFF symbol table.
589
573
  pointer_to_symbol_table_hex: str | None = None
590
574
  # Specifies the number of entries in the symbol table of the PE binary, as a non-negative integer.
@@ -653,19 +637,25 @@ class File(StixObservable):
653
637
  # interoperability.
654
638
  mime_type: str | None = None
655
639
  # Specifies the date/time the file was created.
656
- ctime: datetime | None = None
640
+ ctime: StixTimestamp | None = None
657
641
  # Specifies the date/time the file was last written to/modified.
658
- mtime: datetime | None = None
642
+ mtime: StixTimestamp | None = None
659
643
  # Specifies the date/time the file was last accessed.
660
- atime: datetime | None = None
644
+ atime: StixTimestamp | None = None
661
645
  # Specifies the parent directory of the file, as a reference to a Directory object.
662
- parent_directory_ref: Identifier | None = None
646
+ parent_directory_ref: Annotated[Identifier, AfterValidator(identifier_of_type("directory"))] | None = None
663
647
  # Specifies a list of references to other Cyber-observable Objects contained within the file, such as another file
664
648
  # that is appended to the end of the file, or an IP address that is contained somewhere in the file.
665
649
  # This is intended for use cases other than those targeted by the Archive extension.
666
650
  contains_refs: list[Identifier] | None = None
667
651
  # Specifies the content of the file, represented as an Artifact object.
668
- content_ref: Identifier | None = None
652
+ content_ref: Annotated[Identifier, AfterValidator(identifier_of_type("artifact"))] | None = None
653
+ id_contributing_properties: ClassVar[list[str] | None] = [
654
+ "hashes",
655
+ "name",
656
+ "extensions",
657
+ "parent_directory_ref",
658
+ ]
669
659
 
670
660
  @model_validator(mode="after")
671
661
  def at_least_one_of(self) -> Self:
@@ -676,16 +666,6 @@ class File(StixObservable):
676
666
  raise ValueError("At least one of hashes or name must be present.")
677
667
  return self
678
668
 
679
- class Config:
680
- json_schema_extra: dict[str, list[str]] = {
681
- "id_contributing_properties": [
682
- "hashes",
683
- "name",
684
- "extensions",
685
- "parent_directory_ref",
686
- ]
687
- }
688
-
689
669
 
690
670
  # 6.8 IPv4 Address Object
691
671
  class IPv4Address(StixObservable):
@@ -699,14 +679,10 @@ class IPv4Address(StixObservable):
699
679
  value: ipaddress.IPv4Address | ipaddress.IPv4Network
700
680
  # Specifies a list of references to one or more Layer 2 Media Access Control (MAC) addresses that the IPv4
701
681
  # address resolves to.
702
- resolves_to_refs: list[Identifier] | None = None
682
+ resolves_to_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("mac-addr"))]] | None = None
703
683
  # Specifies a list of references to one or more autonomous systems (AS) that the IPv4 address belongs to.
704
- belongs_to_refs: list[Identifier] | None = None
705
-
706
- class Config:
707
- json_schema_extra: dict[str, list[str]] = {
708
- "id_contributing_properties": ["value"]
709
- }
684
+ belongs_to_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("autonomous-system"))]] | None = None
685
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
710
686
 
711
687
 
712
688
  # 6.9 IPv6 Address Object
@@ -721,14 +697,10 @@ class IPv6Address(StixObservable):
721
697
  value: ipaddress.IPv6Address | ipaddress.IPv6Network
722
698
  # Specifies a list of references to one or more Layer 2 Media Access Control (MAC) addresses that the IPv6
723
699
  # address resolves to.
724
- resolves_to_refs: list[Identifier] | None = None
700
+ resolves_to_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("mac-addr"))]] | None = None
725
701
  # Specifies a list of references to one or more autonomous systems (AS) that the IPv6 address belongs to.
726
- belongs_to_refs: list[Identifier] | None = None
727
-
728
- class Config:
729
- json_schema_extra: dict[str, list[str]] = {
730
- "id_contributing_properties": ["value"]
731
- }
702
+ belongs_to_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("autonomous-system"))]] | None = None
703
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
732
704
 
733
705
 
734
706
  # 6.10 MAC Address Object
@@ -743,11 +715,7 @@ class MACAddress(StixObservable):
743
715
  # include leading zeros for each octet.
744
716
  # TODO: check the following regex: ^([0-9a-f]{2}:){5}[0-9a-f]{2}$
745
717
  value: str
746
-
747
- class Config:
748
- json_schema_extra: dict[str, list[str]] = {
749
- "id_contributing_properties": ["value"]
750
- }
718
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
751
719
 
752
720
 
753
721
  # 6.11 Mutex Object
@@ -759,11 +727,7 @@ class Mutex(StixObservable):
759
727
  type: Literal["mutex"] = "mutex" # pyright: ignore[reportIncompatibleVariableOverride]
760
728
  # Specifies the name of the mutex object.
761
729
  name: str
762
-
763
- class Config:
764
- json_schema_extra: dict[str, list[str]] = {
765
- "id_contributing_properties": ["name"]
766
- }
730
+ id_contributing_properties: ClassVar[list[str] | None] = ["name"]
767
731
 
768
732
 
769
733
  # 6.12.2 HTTP Request Extension
@@ -788,7 +752,7 @@ class HTTPRequestExtension(Extension):
788
752
  # Specifies the length of the HTTP message body, if included, in bytes.
789
753
  message_body_length: int | None = None
790
754
  # Specifies the data contained in the HTTP message body, if included.
791
- message_body_data_ref: Identifier | None = None
755
+ message_body_data_ref: Annotated[Identifier, AfterValidator(identifier_of_type("artifact"))] | None = None
792
756
 
793
757
 
794
758
  # 6.12.3 ICMP Extension
@@ -897,19 +861,21 @@ class NetworkTraffic(StixObservable):
897
861
  # The corresponding dictionary values MUST contain the contents of the extension instance.
898
862
  extensions: NetworkTrafficExtensions | None = None # pyright: ignore[reportIncompatibleVariableOverride]
899
863
  # Specifies the date/time the network traffic was initiated, if known.
900
- start: datetime | None = None
864
+ start: StixTimestamp | None = None
901
865
  # Specifies the date/time the network traffic ended, if known.
902
- end: datetime | None = None
866
+ end: StixTimestamp | None = None
903
867
  # Indicates whether the network traffic is still ongoing.
904
868
  is_active: bool | None = None
905
869
  # Specifies the source of the network traffic, as a reference to a Cyber-observable Object.
906
- # The object referenced MUST be of type ipv4-addr, ipv6-addr, mac-addr, or domain-name
907
- # (for cases where the IP address for a domain name is unknown).
908
- src_ref: Identifier | None = None
870
+ src_ref: (
871
+ Annotated[Identifier, AfterValidator(identifier_of_type("ipv4-addr", "ipv6-addr", "mac-addr", "domain-name"))]
872
+ | None
873
+ ) = None
909
874
  # Specifies the destination of the network traffic, as a reference to a Cyber-observable Object.
910
- # The object referenced MUST be of type ipv4-addr, ipv6-addr, mac-addr, or domain-name
911
- # (for cases where the IP address for a domain name is unknown).
912
- dst_ref: Identifier | None = None
875
+ dst_ref: (
876
+ Annotated[Identifier, AfterValidator(identifier_of_type("ipv4-addr", "ipv6-addr", "mac-addr", "domain-name"))]
877
+ | None
878
+ ) = None
913
879
  # Specifies the source port used in the network traffic, as an integer.
914
880
  src_port: Annotated[int, Ge(0), Le(65535)] | None = None
915
881
  # Specifies the destination port used in the network traffic, as an integer.
@@ -940,13 +906,31 @@ class NetworkTraffic(StixObservable):
940
906
  # as well as a valid IPFIX property.
941
907
  ipfix: dict[str, int | str] | None = None
942
908
  # Specifies the bytes sent from the source to the destination.
943
- src_payload_ref: Identifier | None = None
909
+ src_payload_ref: Annotated[Identifier, AfterValidator(identifier_of_type("artifact"))] | None = None
944
910
  # Specifies the bytes sent from the destination to the source.
945
- dst_payload_ref: Identifier | None = None
911
+ dst_payload_ref: Annotated[Identifier, AfterValidator(identifier_of_type("artifact"))] | None = None
946
912
  # Links to other network-traffic objects encapsulated by this network-traffic object.
947
- encapsulates_refs: list[Identifier] | None = None
913
+ encapsulates_refs: (
914
+ list[
915
+ Annotated[
916
+ Identifier,
917
+ AfterValidator(identifier_of_type("network-traffic")),
918
+ ]
919
+ ]
920
+ | None
921
+ ) = None
948
922
  # Links to another network-traffic object which encapsulates this object.
949
- encapsulated_by_ref: Identifier | None = None
923
+ encapsulated_by_ref: Annotated[Identifier, AfterValidator(identifier_of_type("network-traffic"))] | None = None
924
+ id_contributing_properties: ClassVar[list[str] | None] = [
925
+ "start",
926
+ "end",
927
+ "src_ref",
928
+ "dst_ref",
929
+ "src_port",
930
+ "dst_port",
931
+ "protocols",
932
+ "extensions",
933
+ ]
950
934
 
951
935
  @model_validator(mode="after")
952
936
  def validate_end(self) -> Self:
@@ -956,9 +940,7 @@ class NetworkTraffic(StixObservable):
956
940
  If the is_active property is true, then the end property MUST NOT be included.
957
941
  """
958
942
  if self.is_active and self.end is not None:
959
- raise ValueError(
960
- "The end property MUST NOT be included if is_active is true"
961
- )
943
+ raise ValueError("The end property MUST NOT be included if is_active is true")
962
944
  if self.start and self.end and self.start > self.end:
963
945
  raise ValueError("The end property MUST be greater than or equal to start")
964
946
  return self
@@ -973,20 +955,6 @@ class NetworkTraffic(StixObservable):
973
955
  raise ValueError("At least one of src_ref or dst_ref must be present")
974
956
  return self
975
957
 
976
- class Config:
977
- json_schema_extra: dict[str, list[str]] = {
978
- "id_contributing_properties": [
979
- "start",
980
- "end",
981
- "src_ref",
982
- "dst_ref",
983
- "src_port",
984
- "dst_port",
985
- "protocols",
986
- "extensions",
987
- ]
988
- }
989
-
990
958
 
991
959
  # 6.13.2 Windows Process Extension
992
960
  class WindowsProcessExtension(Extension):
@@ -1018,7 +986,7 @@ class WindowsProcessExtension(Extension):
1018
986
 
1019
987
  @model_validator(mode="before")
1020
988
  @classmethod
1021
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
989
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1022
990
  """
1023
991
  An object using the Windows Process Extension MUST contain at least one property from this extension.
1024
992
  """
@@ -1050,7 +1018,7 @@ class WindowsServiceExtension(Extension):
1050
1018
  # Specifies the start options defined for the service.
1051
1019
  start_type: WindowsServiceStartType | None = None
1052
1020
  # Specifies the DLLs loaded by the service, as a reference to one or more File objects.
1053
- service_dll_refs: list[Identifier] | None = None
1021
+ service_dll_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("file"))]] | None = None
1054
1022
  # Specifies the type of the service.
1055
1023
  service_type: WindowsServiceType | None = None
1056
1024
  # Specifies the current status of the service.
@@ -1058,7 +1026,7 @@ class WindowsServiceExtension(Extension):
1058
1026
 
1059
1027
  @model_validator(mode="before")
1060
1028
  @classmethod
1061
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1029
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1062
1030
  """
1063
1031
  As all properties of this extension are optional, at least one of the properties defined below MUST be
1064
1032
  included when using this extension.
@@ -1101,7 +1069,7 @@ class Process(StixObservable):
1101
1069
  # Specifies the Process ID, or PID, of the process.
1102
1070
  pid: int | None = None
1103
1071
  # Specifies the date/time at which the process was created.
1104
- created_time: datetime | None = None
1072
+ created_time: StixTimestamp | None = None
1105
1073
  # Specifies the current working directory of the process.
1106
1074
  cwd: str | None = None
1107
1075
  # Specifies the full command line used in executing the process, including the process name (which may be
@@ -1113,20 +1081,28 @@ class Process(StixObservable):
1113
1081
  environment_variables: dict[str, str] | None = None
1114
1082
  # Specifies the list of network connections opened by the process, as a reference to one or more
1115
1083
  # Network Traffic objects.
1116
- opened_connection_refs: list[Identifier] | None = None
1084
+ opened_connection_refs: (
1085
+ list[
1086
+ Annotated[
1087
+ Identifier,
1088
+ AfterValidator(identifier_of_type("network-traffic")),
1089
+ ]
1090
+ ]
1091
+ | None
1092
+ ) = None
1117
1093
  # Specifies the user that created the process, as a reference to a User Account object.
1118
- creator_user_ref: Identifier | None = None
1094
+ creator_user_ref: Annotated[Identifier, AfterValidator(identifier_of_type("user-account"))] | None = None
1119
1095
  # Specifies the executable binary that was executed as the process image, as a reference to a File object.
1120
- image_ref: Identifier | None = None
1096
+ image_ref: Annotated[Identifier, AfterValidator(identifier_of_type("file"))] | None = None
1121
1097
  # Specifies the other process that spawned (i.e. is the parent of) this one, as a reference to a Process object.
1122
- parent_ref: Identifier | None = None
1098
+ parent_ref: Annotated[Identifier, AfterValidator(identifier_of_type("process"))] | None = None
1123
1099
  # Specifies the other processes that were spawned by (i.e. children of) this process, as a reference to one
1124
1100
  # or more other Process objects.
1125
- child_refs: list[Identifier] | None = None
1101
+ child_refs: list[Annotated[Identifier, AfterValidator(identifier_of_type("process"))]] | None = None
1126
1102
 
1127
1103
  @model_validator(mode="before")
1128
1104
  @classmethod
1129
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1105
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1130
1106
  """
1131
1107
  A Process object MUST contain at least one property (other than type)
1132
1108
  from this object (or one of its extensions).
@@ -1163,11 +1139,7 @@ class Software(StixObservable):
1163
1139
  vendor: str | None = None
1164
1140
  # Specifies the version of the software.
1165
1141
  version: str | None = None
1166
-
1167
- class Config:
1168
- json_schema_extra: dict[str, list[str]] = {
1169
- "id_contributing_properties": ["name", "cpe", "swid", "vendor", "version"]
1170
- }
1142
+ id_contributing_properties: ClassVar[list[str] | None] = ["name", "cpe", "swid", "vendor", "version"]
1171
1143
 
1172
1144
 
1173
1145
  # 6.15 URL Object
@@ -1180,11 +1152,7 @@ class URL(StixObservable):
1180
1152
  # Specifies the value of the URL. The value of this property MUST conform to [RFC3986], more specifically
1181
1153
  # section 1.1.3 with reference to the definition for "Uniform Resource Locator".
1182
1154
  value: StixUrl
1183
-
1184
- class Config:
1185
- json_schema_extra: dict[str, list[str]] = {
1186
- "id_contributing_properties": ["value"]
1187
- }
1155
+ id_contributing_properties: ClassVar[list[str] | None] = ["value"]
1188
1156
 
1189
1157
 
1190
1158
  # 6.16.2 UNIX Account Extension
@@ -1207,7 +1175,7 @@ class UnixAccountExtension(Extension):
1207
1175
 
1208
1176
  @model_validator(mode="before")
1209
1177
  @classmethod
1210
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1178
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1211
1179
  """
1212
1180
  An object using the UNIX Account Extension MUST contain at least one property from this extension.
1213
1181
  """
@@ -1271,19 +1239,20 @@ class UserAccount(StixObservable):
1271
1239
  # Specifies if the account is disabled.
1272
1240
  is_disabled: bool | None = None
1273
1241
  # Specifies when the account was created.
1274
- account_created: datetime | None = None
1242
+ account_created: StixTimestamp | None = None
1275
1243
  # Specifies the expiration date of the account.
1276
- account_expires: datetime | None = None
1244
+ account_expires: StixTimestamp | None = None
1277
1245
  # Specifies when the account credential was last changed.
1278
- credential_last_changed: datetime | None = None
1246
+ credential_last_changed: StixTimestamp | None = None
1279
1247
  # Specifies when the account was first accessed.
1280
- account_first_login: datetime | None = None
1248
+ account_first_login: StixTimestamp | None = None
1281
1249
  # Specifies when the account was last accessed.
1282
- account_last_login: datetime | None = None
1250
+ account_last_login: StixTimestamp | None = None
1251
+ id_contributing_properties: ClassVar[list[str] | None] = ["account_type", "user_id", "account_login"]
1283
1252
 
1284
1253
  @model_validator(mode="before")
1285
1254
  @classmethod
1286
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1255
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1287
1256
  """
1288
1257
  As all properties of this object are optional, at least one of the properties defined below
1289
1258
  MUST be included when using this object.
@@ -1295,11 +1264,6 @@ class UserAccount(StixObservable):
1295
1264
  raise ValueError("At least one property must be present")
1296
1265
  raise TypeError("Input data must be a dictionary")
1297
1266
 
1298
- class Config:
1299
- json_schema_extra: dict[str, list[str]] = {
1300
- "id_contributing_properties": ["account_type", "user_id", "account_login"]
1301
- }
1302
-
1303
1267
 
1304
1268
  # 6.17.2 Windows Registry Value Type
1305
1269
  class WindowsRegistryValueType(StixCore):
@@ -1317,7 +1281,7 @@ class WindowsRegistryValueType(StixCore):
1317
1281
 
1318
1282
  @model_validator(mode="before")
1319
1283
  @classmethod
1320
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1284
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1321
1285
  """
1322
1286
  As all properties of this object are optional, at least one of the properties defined below
1323
1287
  MUST be included when using this object.
@@ -1344,16 +1308,16 @@ class WindowsRegistryKey(StixObservable):
1344
1308
  # fully expanded and not truncated; e.g., HKEY_LOCAL_MACHINE must be used instead of HKLM.
1345
1309
  values: list[WindowsRegistryValueType] | None = None
1346
1310
  # Specifies the last date/time that the registry key was modified.
1347
- modified_time: datetime | None = None
1311
+ modified_time: StixTimestamp | None = None
1348
1312
  # Specifies a reference to the user account that created the registry key.
1349
- # The object referenced in this property MUST be of type user-account.
1350
- creator_user_ref: Identifier | None = None
1313
+ creator_user_ref: Annotated[Identifier, AfterValidator(identifier_of_type("user-account"))] | None = None
1351
1314
  # Specifies the number of subkeys contained under the registry key.
1352
1315
  number_of_subkeys: int | None = None
1316
+ id_contributing_properties: ClassVar[list[str] | None] = ["key", "values"]
1353
1317
 
1354
1318
  @model_validator(mode="before")
1355
1319
  @classmethod
1356
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1320
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1357
1321
  """
1358
1322
  As all properties of this object are optional, at least one of the properties defined below
1359
1323
  MUST be included when using this object.
@@ -1365,11 +1329,6 @@ class WindowsRegistryKey(StixObservable):
1365
1329
  raise ValueError("At least one property must be present")
1366
1330
  raise TypeError("Input data must be a dictionary")
1367
1331
 
1368
- class Config:
1369
- json_schema_extra: dict[str, list[str]] = {
1370
- "id_contributing_properties": ["key", "values"]
1371
- }
1372
-
1373
1332
 
1374
1333
  # 6.18.2 X.509 v3 Extensions Type
1375
1334
  class X509v3ExtensionsType(Extension):
@@ -1420,10 +1379,10 @@ class X509v3ExtensionsType(Extension):
1420
1379
  inhibit_any_policy: str | None = None
1421
1380
  # Specifies the date on which the validity period begins for the private key, if it is different from the
1422
1381
  # validity period of the certificate.
1423
- private_key_usage_period_not_before: datetime | None = None
1382
+ private_key_usage_period_not_before: StixTimestamp | None = None
1424
1383
  # Specifies the date on which the validity period ends for the private key, if it is different from the
1425
1384
  # validity period of the certificate.
1426
- private_key_usage_period_not_after: datetime | None = None
1385
+ private_key_usage_period_not_after: StixTimestamp | None = None
1427
1386
  # Specifies a sequence of one or more policy information terms, each of which consists of an object identifier
1428
1387
  # (OID) and optional qualifiers. Also equivalent to the object ID (OID) value of 2.5.29.32.
1429
1388
  certificate_policies: str | None = None
@@ -1433,7 +1392,7 @@ class X509v3ExtensionsType(Extension):
1433
1392
  policy_mappings: str | None = None
1434
1393
 
1435
1394
  @classmethod
1436
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1395
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1437
1396
  """
1438
1397
  An object using the X.509 v3 Extensions type MUST contain at least one property from this type.
1439
1398
  """
@@ -1467,9 +1426,9 @@ class X509Certificate(StixObservable):
1467
1426
  # Specifies the name of the Certificate Authority that issued the certificate.
1468
1427
  issuer: str | None = None
1469
1428
  # Specifies the date on which the certificate validity period begins.
1470
- validity_not_before: datetime | None = None
1429
+ validity_not_before: StixTimestamp | None = None
1471
1430
  # Specifies the date on which the certificate validity period ends.
1472
- validity_not_after: datetime | None = None
1431
+ validity_not_after: StixTimestamp | None = None
1473
1432
  # Specifies the name of the entity associated with the public key stored in the subject public key field of the
1474
1433
  # certificate.
1475
1434
  subject: str | None = None
@@ -1481,9 +1440,10 @@ class X509Certificate(StixObservable):
1481
1440
  subject_public_key_exponent: int | None = None
1482
1441
  # Specifies any standard X.509 v3 extensions that may be used in the certificate.
1483
1442
  x509_v3_extensions: X509v3ExtensionsType | None = None
1443
+ id_contributing_properties: ClassVar[list[str] | None] = ["hashes", "serial_number"]
1484
1444
 
1485
1445
  @classmethod
1486
- def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny]
1446
+ def at_least_one(cls, data: Any) -> Any: # pyright: ignore[reportExplicitAny, reportAny] # noqa: ANN401
1487
1447
  """
1488
1448
  An X.509 Certificate object MUST contain at least one object specific property (other than type)
1489
1449
  from this object.
@@ -1495,11 +1455,6 @@ class X509Certificate(StixObservable):
1495
1455
  raise ValueError("At least one property must be present")
1496
1456
  raise TypeError("Input data must be a dictionary")
1497
1457
 
1498
- class Config:
1499
- json_schema_extra: dict[str, list[str]] = {
1500
- "id_contributing_properties": ["hashes", "serial_number"]
1501
- }
1502
-
1503
1458
 
1504
1459
  SCOs = Annotated[
1505
1460
  (