2017-05-02 20:06:42 +02:00
|
|
|
import pytest
|
2017-05-09 21:10:53 +02:00
|
|
|
|
2017-05-02 20:25:01 +02:00
|
|
|
import stix2
|
2020-05-28 22:48:51 +02:00
|
|
|
import stix2.exceptions
|
2020-05-28 22:56:26 +02:00
|
|
|
import stix2.utils
|
2020-05-28 22:48:51 +02:00
|
|
|
import stix2.v20
|
|
|
|
import stix2.versioning
|
2017-05-02 20:25:01 +02:00
|
|
|
|
2017-08-31 18:28:07 +02:00
|
|
|
from .constants import CAMPAIGN_MORE_KWARGS
|
|
|
|
|
2017-05-02 20:06:42 +02:00
|
|
|
|
|
|
|
def test_making_new_version():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-02 20:06:42 +02:00
|
|
|
|
|
|
|
campaign_v2 = campaign_v1.new_version(name="fred")
|
|
|
|
|
|
|
|
assert campaign_v1.id == campaign_v2.id
|
|
|
|
assert campaign_v1.created_by_ref == campaign_v2.created_by_ref
|
|
|
|
assert campaign_v1.created == campaign_v2.created
|
|
|
|
assert campaign_v1.name != campaign_v2.name
|
|
|
|
assert campaign_v2.name == "fred"
|
|
|
|
assert campaign_v1.description == campaign_v2.description
|
|
|
|
assert campaign_v1.modified < campaign_v2.modified
|
|
|
|
|
|
|
|
|
2017-05-04 22:34:08 +02:00
|
|
|
def test_making_new_version_with_unset():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-04 22:34:08 +02:00
|
|
|
|
|
|
|
campaign_v2 = campaign_v1.new_version(description=None)
|
|
|
|
|
|
|
|
assert campaign_v1.id == campaign_v2.id
|
|
|
|
assert campaign_v1.created_by_ref == campaign_v2.created_by_ref
|
|
|
|
assert campaign_v1.created == campaign_v2.created
|
|
|
|
assert campaign_v1.name == campaign_v2.name
|
2017-06-07 17:06:20 +02:00
|
|
|
with pytest.raises(AttributeError):
|
|
|
|
assert campaign_v2.description
|
2017-05-04 22:34:08 +02:00
|
|
|
assert campaign_v1.modified < campaign_v2.modified
|
|
|
|
|
|
|
|
|
2017-05-03 18:14:09 +02:00
|
|
|
def test_making_new_version_with_embedded_object():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(
|
2017-05-03 18:14:09 +02:00
|
|
|
external_references=[{
|
|
|
|
"source_name": "capec",
|
2018-07-13 17:10:05 +02:00
|
|
|
"external_id": "CAPEC-163",
|
2017-05-03 18:14:09 +02:00
|
|
|
}],
|
2017-08-31 18:28:07 +02:00
|
|
|
**CAMPAIGN_MORE_KWARGS
|
2017-05-03 18:14:09 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
campaign_v2 = campaign_v1.new_version(external_references=[{
|
|
|
|
"source_name": "capec",
|
2018-07-13 17:10:05 +02:00
|
|
|
"external_id": "CAPEC-164",
|
|
|
|
}])
|
2017-05-03 18:14:09 +02:00
|
|
|
|
|
|
|
assert campaign_v1.id == campaign_v2.id
|
|
|
|
assert campaign_v1.created_by_ref == campaign_v2.created_by_ref
|
|
|
|
assert campaign_v1.created == campaign_v2.created
|
|
|
|
assert campaign_v1.name == campaign_v2.name
|
|
|
|
assert campaign_v1.description == campaign_v2.description
|
|
|
|
assert campaign_v1.modified < campaign_v2.modified
|
|
|
|
assert campaign_v1.external_references[0].external_id != campaign_v2.external_references[0].external_id
|
|
|
|
|
|
|
|
|
2017-05-02 20:06:42 +02:00
|
|
|
def test_revoke():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-02 20:06:42 +02:00
|
|
|
|
|
|
|
campaign_v2 = campaign_v1.revoke()
|
|
|
|
|
|
|
|
assert campaign_v1.id == campaign_v2.id
|
|
|
|
assert campaign_v1.created_by_ref == campaign_v2.created_by_ref
|
|
|
|
assert campaign_v1.created == campaign_v2.created
|
|
|
|
assert campaign_v1.name == campaign_v2.name
|
|
|
|
assert campaign_v1.description == campaign_v2.description
|
|
|
|
assert campaign_v1.modified < campaign_v2.modified
|
|
|
|
|
|
|
|
assert campaign_v2.revoked
|
|
|
|
|
|
|
|
|
|
|
|
def test_versioning_error_invalid_property():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-02 20:06:42 +02:00
|
|
|
|
2017-05-03 18:14:09 +02:00
|
|
|
with pytest.raises(stix2.exceptions.UnmodifiablePropertyError) as excinfo:
|
2017-05-02 21:53:07 +02:00
|
|
|
campaign_v1.new_version(type="threat-actor")
|
2017-05-02 20:06:42 +02:00
|
|
|
|
2017-05-04 22:34:08 +02:00
|
|
|
assert str(excinfo.value) == "These properties cannot be changed when making a new version: type."
|
|
|
|
|
|
|
|
|
|
|
|
def test_versioning_error_bad_modified_value():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-04 22:34:08 +02:00
|
|
|
|
|
|
|
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
|
|
|
|
campaign_v1.new_version(modified="2015-04-06T20:03:00.000Z")
|
|
|
|
|
2018-07-05 21:23:25 +02:00
|
|
|
assert excinfo.value.cls == stix2.v20.Campaign
|
2017-05-04 22:34:08 +02:00
|
|
|
assert excinfo.value.prop_name == "modified"
|
2017-11-29 18:03:10 +01:00
|
|
|
assert excinfo.value.reason == "The new modified datetime cannot be before than or equal to the current modified datetime." \
|
|
|
|
"It cannot be equal, as according to STIX 2 specification, objects that are different " \
|
|
|
|
"but have the same id and modified timestamp do not have defined consumer behavior."
|
2017-05-04 22:34:08 +02:00
|
|
|
|
2017-08-29 21:15:32 +02:00
|
|
|
msg = "Invalid value for {0} '{1}': {2}"
|
2018-07-13 17:10:05 +02:00
|
|
|
msg = msg.format(
|
|
|
|
stix2.v20.Campaign.__name__, "modified",
|
|
|
|
"The new modified datetime cannot be before than or equal to the current modified datetime."
|
|
|
|
"It cannot be equal, as according to STIX 2 specification, objects that are different "
|
|
|
|
"but have the same id and modified timestamp do not have defined consumer behavior.",
|
|
|
|
)
|
2017-08-29 21:15:32 +02:00
|
|
|
assert str(excinfo.value) == msg
|
|
|
|
|
2017-05-04 22:34:08 +02:00
|
|
|
|
|
|
|
def test_versioning_error_usetting_required_property():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-04 22:34:08 +02:00
|
|
|
|
2017-05-19 19:51:59 +02:00
|
|
|
with pytest.raises(stix2.exceptions.MissingPropertiesError) as excinfo:
|
2017-05-04 22:34:08 +02:00
|
|
|
campaign_v1.new_version(name=None)
|
|
|
|
|
2018-07-05 21:23:25 +02:00
|
|
|
assert excinfo.value.cls == stix2.v20.Campaign
|
2017-05-16 18:27:30 +02:00
|
|
|
assert excinfo.value.properties == ["name"]
|
2017-05-02 20:06:42 +02:00
|
|
|
|
2017-08-29 21:15:32 +02:00
|
|
|
msg = "No values for required properties for {0}: ({1})."
|
2018-07-05 21:23:25 +02:00
|
|
|
msg = msg.format(stix2.v20.Campaign.__name__, "name")
|
2017-08-29 21:15:32 +02:00
|
|
|
assert str(excinfo.value) == msg
|
|
|
|
|
2017-05-02 20:06:42 +02:00
|
|
|
|
|
|
|
def test_versioning_error_new_version_of_revoked():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-02 20:06:42 +02:00
|
|
|
campaign_v2 = campaign_v1.revoke()
|
|
|
|
|
2017-05-03 18:14:09 +02:00
|
|
|
with pytest.raises(stix2.exceptions.RevokeError) as excinfo:
|
2017-05-02 21:53:07 +02:00
|
|
|
campaign_v2.new_version(name="barney")
|
2017-08-24 23:53:43 +02:00
|
|
|
assert str(excinfo.value) == "Cannot create a new version of a revoked object."
|
2017-05-02 20:06:42 +02:00
|
|
|
|
2017-05-04 22:34:08 +02:00
|
|
|
assert excinfo.value.called_by == "new_version"
|
2017-08-29 21:15:32 +02:00
|
|
|
assert str(excinfo.value) == "Cannot create a new version of a revoked object."
|
2017-05-02 20:06:42 +02:00
|
|
|
|
|
|
|
|
|
|
|
def test_versioning_error_revoke_of_revoked():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2017-05-02 20:06:42 +02:00
|
|
|
campaign_v2 = campaign_v1.revoke()
|
|
|
|
|
2017-05-03 18:14:09 +02:00
|
|
|
with pytest.raises(stix2.exceptions.RevokeError) as excinfo:
|
2017-05-02 21:53:07 +02:00
|
|
|
campaign_v2.revoke()
|
2017-08-24 23:53:43 +02:00
|
|
|
assert str(excinfo.value) == "Cannot revoke an already revoked object."
|
2017-05-02 20:06:42 +02:00
|
|
|
|
2017-05-04 22:34:08 +02:00
|
|
|
assert excinfo.value.called_by == "revoke"
|
2017-08-29 21:15:32 +02:00
|
|
|
assert str(excinfo.value) == "Cannot revoke an already revoked object."
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
def test_making_new_version_dict():
|
|
|
|
campaign_v1 = CAMPAIGN_MORE_KWARGS
|
2020-05-28 22:48:51 +02:00
|
|
|
campaign_v2 = stix2.versioning.new_version(CAMPAIGN_MORE_KWARGS, name="fred")
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert campaign_v1['id'] == campaign_v2['id']
|
|
|
|
assert campaign_v1['created_by_ref'] == campaign_v2['created_by_ref']
|
|
|
|
assert campaign_v1['created'] == campaign_v2['created']
|
|
|
|
assert campaign_v1['name'] != campaign_v2['name']
|
|
|
|
assert campaign_v2['name'] == "fred"
|
|
|
|
assert campaign_v1['description'] == campaign_v2['description']
|
|
|
|
assert stix2.utils.parse_into_datetime(campaign_v1['modified'], precision='millisecond') < campaign_v2['modified']
|
|
|
|
|
|
|
|
|
|
|
|
def test_versioning_error_dict_bad_modified_value():
|
|
|
|
with pytest.raises(stix2.exceptions.InvalidValueError) as excinfo:
|
2020-05-28 22:48:51 +02:00
|
|
|
stix2.versioning.new_version(CAMPAIGN_MORE_KWARGS, modified="2015-04-06T20:03:00.000Z")
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert excinfo.value.cls == dict
|
|
|
|
assert excinfo.value.prop_name == "modified"
|
2017-11-29 18:03:10 +01:00
|
|
|
assert excinfo.value.reason == "The new modified datetime cannot be before than or equal to the current modified datetime." \
|
|
|
|
"It cannot be equal, as according to STIX 2 specification, objects that are different " \
|
|
|
|
"but have the same id and modified timestamp do not have defined consumer behavior."
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
|
|
|
|
def test_versioning_error_dict_no_modified_value():
|
|
|
|
campaign_v1 = {
|
|
|
|
'type': 'campaign',
|
|
|
|
'id': "campaign--8e2e2d2b-17d4-4cbf-938f-98ee46b3cd3f",
|
|
|
|
'created': "2016-04-06T20:03:00.000Z",
|
|
|
|
'name': "Green Group Attacks Against Finance",
|
|
|
|
}
|
2020-05-28 22:48:51 +02:00
|
|
|
campaign_v2 = stix2.versioning.new_version(campaign_v1, modified="2017-04-06T20:03:00.000Z")
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert str(campaign_v2['modified']) == "2017-04-06T20:03:00.000Z"
|
|
|
|
|
|
|
|
|
|
|
|
def test_making_new_version_invalid_cls():
|
|
|
|
campaign_v1 = "This is a campaign."
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2020-05-28 22:48:51 +02:00
|
|
|
stix2.versioning.new_version(campaign_v1, name="fred")
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert 'cannot create new version of object of this type' in str(excinfo.value)
|
|
|
|
|
|
|
|
|
|
|
|
def test_revoke_dict():
|
|
|
|
campaign_v1 = CAMPAIGN_MORE_KWARGS
|
2020-05-28 22:48:51 +02:00
|
|
|
campaign_v2 = stix2.versioning.revoke(campaign_v1)
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert campaign_v1['id'] == campaign_v2['id']
|
|
|
|
assert campaign_v1['created_by_ref'] == campaign_v2['created_by_ref']
|
|
|
|
assert campaign_v1['created'] == campaign_v2['created']
|
|
|
|
assert campaign_v1['name'] == campaign_v2['name']
|
|
|
|
assert campaign_v1['description'] == campaign_v2['description']
|
|
|
|
assert stix2.utils.parse_into_datetime(campaign_v1['modified'], precision='millisecond') < campaign_v2['modified']
|
|
|
|
|
|
|
|
assert campaign_v2['revoked']
|
|
|
|
|
|
|
|
|
2020-05-28 22:48:51 +02:00
|
|
|
def test_revoke_unversionable():
|
|
|
|
sco = stix2.v20.File(name="data.txt")
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
sco.revoke()
|
|
|
|
|
|
|
|
|
2017-08-31 18:28:07 +02:00
|
|
|
def test_versioning_error_revoke_of_revoked_dict():
|
|
|
|
campaign_v1 = CAMPAIGN_MORE_KWARGS
|
2020-05-28 22:48:51 +02:00
|
|
|
campaign_v2 = stix2.versioning.revoke(campaign_v1)
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
with pytest.raises(stix2.exceptions.RevokeError) as excinfo:
|
2020-05-28 22:48:51 +02:00
|
|
|
stix2.versioning.revoke(campaign_v2)
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert excinfo.value.called_by == "revoke"
|
|
|
|
|
|
|
|
|
|
|
|
def test_revoke_invalid_cls():
|
|
|
|
campaign_v1 = "This is a campaign."
|
|
|
|
with pytest.raises(ValueError) as excinfo:
|
2020-05-28 22:48:51 +02:00
|
|
|
stix2.versioning.revoke(campaign_v1)
|
2017-08-31 18:28:07 +02:00
|
|
|
|
|
|
|
assert 'cannot revoke object of this type' in str(excinfo.value)
|
2017-11-29 18:03:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_remove_custom_stix_property():
|
2018-07-13 17:10:05 +02:00
|
|
|
mal = stix2.v20.Malware(
|
|
|
|
name="ColePowers",
|
|
|
|
labels=["rootkit"],
|
|
|
|
x_custom="armada",
|
|
|
|
allow_custom=True,
|
|
|
|
)
|
2017-11-29 18:03:10 +01:00
|
|
|
|
2020-05-28 22:48:51 +02:00
|
|
|
mal_nc = stix2.versioning.remove_custom_stix(mal)
|
2017-11-29 18:03:10 +01:00
|
|
|
|
|
|
|
assert "x_custom" not in mal_nc
|
2018-07-12 20:33:00 +02:00
|
|
|
assert (stix2.utils.parse_into_datetime(mal["modified"], precision="millisecond") <
|
|
|
|
stix2.utils.parse_into_datetime(mal_nc["modified"], precision="millisecond"))
|
2017-11-29 18:03:10 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_remove_custom_stix_object():
|
2018-07-13 17:10:05 +02:00
|
|
|
@stix2.v20.CustomObject(
|
|
|
|
"x-animal", [
|
|
|
|
("species", stix2.properties.StringProperty(required=True)),
|
|
|
|
("animal_class", stix2.properties.StringProperty()),
|
|
|
|
],
|
|
|
|
)
|
2017-11-29 18:03:10 +01:00
|
|
|
class Animal(object):
|
2018-03-16 21:38:29 +01:00
|
|
|
pass
|
2017-11-29 18:03:10 +01:00
|
|
|
|
|
|
|
animal = Animal(species="lion", animal_class="mammal")
|
|
|
|
|
2020-05-28 22:48:51 +02:00
|
|
|
nc = stix2.versioning.remove_custom_stix(animal)
|
2017-11-29 18:03:10 +01:00
|
|
|
|
|
|
|
assert nc is None
|
2018-03-16 21:38:29 +01:00
|
|
|
|
|
|
|
|
|
|
|
def test_remove_custom_stix_no_custom():
|
2018-07-05 21:23:25 +02:00
|
|
|
campaign_v1 = stix2.v20.Campaign(**CAMPAIGN_MORE_KWARGS)
|
2020-05-28 22:48:51 +02:00
|
|
|
campaign_v2 = stix2.versioning.remove_custom_stix(campaign_v1)
|
2018-03-16 21:38:29 +01:00
|
|
|
|
|
|
|
assert len(campaign_v1.keys()) == len(campaign_v2.keys())
|
|
|
|
assert campaign_v1.id == campaign_v2.id
|
|
|
|
assert campaign_v1.description == campaign_v2.description
|
2020-05-28 22:48:51 +02:00
|
|
|
|
|
|
|
|
|
|
|
def test_version_unversionable_dict():
|
|
|
|
f = {
|
|
|
|
"type": "file",
|
|
|
|
"name": "data.txt",
|
|
|
|
}
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
stix2.versioning.new_version(f)
|
|
|
|
|
|
|
|
|
|
|
|
def test_version_sco_with_modified():
|
|
|
|
"""
|
|
|
|
Ensure new_version() doesn't get tripped up over unversionable objects with
|
|
|
|
properties not used for versioning, but whose names conflict with
|
|
|
|
versioning properties.
|
|
|
|
"""
|
|
|
|
|
|
|
|
file_sco = {
|
|
|
|
"type": "file",
|
|
|
|
"name": "data.txt",
|
|
|
|
"created": "1973-11-23T02:31:37Z",
|
|
|
|
"modified": "1991-05-13T19:24:57Z",
|
|
|
|
}
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
stix2.versioning.new_version(file_sco, name="newname.txt")
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
stix2.versioning.revoke(file_sco)
|
|
|
|
|
|
|
|
file_sco_obj = stix2.v20.File(
|
|
|
|
name="data.txt",
|
|
|
|
created="1973-11-23T02:31:37Z",
|
|
|
|
modified="1991-05-13T19:24:57Z",
|
|
|
|
)
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
stix2.versioning.new_version(file_sco_obj, name="newname.txt")
|
|
|
|
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
stix2.versioning.revoke(file_sco_obj)
|
|
|
|
|
|
|
|
|
|
|
|
def test_version_sco_with_custom():
|
|
|
|
"""
|
|
|
|
If we add custom properties named like versioning properties to an object
|
|
|
|
type which is otherwise unversionable, versioning should start working.
|
|
|
|
"""
|
|
|
|
|
|
|
|
file_sco_obj = stix2.v20.File(
|
|
|
|
name="data.txt",
|
|
|
|
created="1973-11-23T02:31:37Z",
|
|
|
|
modified="1991-05-13T19:24:57Z",
|
|
|
|
revoked=False, # the custom property
|
|
|
|
allow_custom=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
new_file_sco_obj = stix2.versioning.new_version(
|
|
|
|
file_sco_obj, name="newname.txt",
|
|
|
|
)
|
|
|
|
|
|
|
|
assert new_file_sco_obj.name == "newname.txt"
|
|
|
|
|
|
|
|
revoked_obj = stix2.versioning.revoke(new_file_sco_obj)
|
|
|
|
assert revoked_obj.revoked
|
|
|
|
|
|
|
|
|
|
|
|
def test_version_disable_custom():
|
|
|
|
m = stix2.v20.Malware(
|
|
|
|
name="foo", labels=["label"], description="Steals your identity!",
|
|
|
|
x_custom=123, allow_custom=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Remove the custom property, and disallow custom properties in the
|
|
|
|
# resulting object.
|
|
|
|
m2 = stix2.versioning.new_version(m, x_custom=None, allow_custom=False)
|
|
|
|
assert "x_custom" not in m2
|
|
|
|
|
|
|
|
# Remove a regular property and leave the custom one, disallow custom
|
|
|
|
# properties, and make sure we get an error.
|
|
|
|
with pytest.raises(stix2.exceptions.ExtraPropertiesError):
|
|
|
|
stix2.versioning.new_version(m, description=None, allow_custom=False)
|
|
|
|
|
|
|
|
|
|
|
|
def test_version_enable_custom():
|
|
|
|
m = stix2.v20.Malware(
|
|
|
|
name="foo", labels=["label"], description="Steals your identity!",
|
|
|
|
)
|
|
|
|
|
|
|
|
# Add a custom property to an object for which it was previously disallowed
|
|
|
|
m2 = stix2.versioning.new_version(m, x_custom=123, allow_custom=True)
|
|
|
|
assert "x_custom" in m2
|
|
|
|
|
|
|
|
# Add a custom property without enabling it, make sure we get an error
|
|
|
|
with pytest.raises(stix2.exceptions.ExtraPropertiesError):
|
|
|
|
stix2.versioning.new_version(m, x_custom=123, allow_custom=False)
|
|
|
|
|
|
|
|
|
|
|
|
def test_version_propagate_custom():
|
|
|
|
m = stix2.v20.Malware(
|
|
|
|
name="foo", labels=["label"],
|
|
|
|
)
|
|
|
|
|
|
|
|
# Remember custom-not-allowed setting from original; produce error
|
|
|
|
with pytest.raises(stix2.exceptions.ExtraPropertiesError):
|
|
|
|
stix2.versioning.new_version(m, x_custom=123)
|
|
|
|
|
|
|
|
m2 = stix2.versioning.new_version(m, description="Steals your identity!")
|
|
|
|
assert "description" in m2
|
|
|
|
assert m2.description == "Steals your identity!"
|
|
|
|
|
|
|
|
m_custom = stix2.v20.Malware(
|
|
|
|
name="foo", labels=["label"], x_custom=123, allow_custom=True,
|
|
|
|
)
|
|
|
|
|
|
|
|
# Remember custom-allowed setting from original; should work
|
|
|
|
m2_custom = stix2.versioning.new_version(m_custom, x_other_custom="abc")
|
|
|
|
assert "x_other_custom" in m2_custom
|
|
|
|
assert m2_custom.x_other_custom == "abc"
|