oasis-open / cti-python-stix2

OASIS TC Open Repository: Python APIs for STIX 2
https://stix2.readthedocs.io/
BSD 3-Clause "New" or "Revised" License
356 stars 113 forks source link

Question: How to... Granular Markings, Eternal References, Update Modified timestamp? #579

Open brettforbes opened 7 months ago

brettforbes commented 7 months ago

Hi,

Your library is great, but I have 3 questions, how do I:

  1. Create Granular Markings for an arbitrary SDO?
  2. Create External References for an arbitrary SDO?
  3. Update the modified field for an arbitrary SDO?

Can you help please?

chisholm commented 7 months ago

I think you're basically asking how to "change" the SDO. Perhaps you realize that the spec disallows this, and that you get a similar effect by creating a new version of the object with changed properties. So the question boils down to how to create a new version of an object.

The library has a new_version() function for this purpose. E.g.

new_obj = stix2.new_version(old_obj, foo="bar")

You can pass in your own value for modified if you wish, but it automatically uses the current timestamp by default. Pass None for a property value to cause the property to be removed from the new version.

Hope I understood the question!

brettforbes commented 7 months ago

thats great, does it change the Stix-ID, or just update?

The spec does enable me to make a non-material change, like adding an extra linked object to an observed-data object, or adding additional references to an incident-core-ext object, as long as I dont change the meaning of it. As I understand it I have to create an entirely new object if I make a material change, which changes the meaning of the object. I really want to know how to make non-material changes., so I hope the method you proposed is correct for this?

Also, how do i create a new SDO with:

  1. Granular Markings
  2. External References

can be of any type, but it seems tricky. Like with an Extension, I can create the extension class first and then add it in to the object,, but how to do the Granular Marking or External References?

rpiazza commented 7 months ago

I think you are asking about a new SDO object type that your defining using an extension definition?

Extensions for new SDO objects MUST be contain the SDO common properties, so assuming you defined it correctly, it is no different than creating any SDO an populating those properties.

chisholm commented 7 months ago

Spec section 3.6.2 discusses "material changes" with respect to whether to create a new version of an existing object, or a new object. Those are your two choices: new version or new object. You may never modify an existing object. The guidance says if you want to make a material change, you should make a new object (i.e. one with a different ID). If a non-material change, create a new version of an existing object (i.e. reuse the same STIX ID but bump the modified property). Only the object creator may create a new version.

The new_version() function creates new versions, so it never changes object IDs.

There are no merge strategies when it comes to collection-valued properties, so you'd just have to create a new collection. The following is an example which uses external references, and shows use of both plain dicts and the ExternalReference class. Either one works.

import sys
import stix2

ident = stix2.Identity(
    name="someone"
)

ident_v2 = stix2.new_version(
    ident, external_references=[
        {
            "source_name": "my_source",
            "external_id": "id01"
        }
    ]
)

ident_v3 = stix2.new_version(
    ident_v2, external_references=ident_v2.external_references + [
        stix2.ExternalReference(
            source_name="another_source",
            external_id="abc-123"
        )
    ]
)

ident.fp_serialize(sys.stdout, pretty=True)
ident_v2.fp_serialize(sys.stdout, pretty=True)
ident_v3.fp_serialize(sys.stdout, pretty=True)

Here, I just used list concatenation to create the v3 list of external references: the v2 list plus another one-entry list.