This documentation presents guidelines and expected etiquettes to successfully contribute to the development of OCSF Schemas and the framework itself.
All contributors must submit their changes via pull requests. If you're not familiar with pull requests, please read the GitHub documentation. Following are a few guidelines and expectations for submitting a PR.
- Fork the repo that you want to contribute to (ocsf-schema, ocsf-docs, ocsf-server).
- Make desired changes in the forked repo, test if everything works as expected and is error-free, a local instance of the ocsf-server would be essential.
- Push the changes to the forked repo.
- Create a Pull Request to merge changes into the main repo, request at least 3 approvers.
- Follow the guidelines in the PR template.
- Limit the number of commits in a single PR to aid reviewers, be as specific with the change as possible. A single PR must contain related changes.
- Each commit must include a DCO Developer's Certificate of Origin.
- Add an entry to the
Unreleased
section in CHANGELOG.md. - Describe your change in as much detail as possible.
- Confirm that you have tested the changes, and the server run was error free.
- Check the Preview tab to ensure everything looks as expected.
- Once the PR is ready, add relevant labels, request approvers and submit it.
- Resolve any github action failures, warnings reported for your pull request, and stay involved in the conversation.
- Thank you for your contribution!
- Field: A field is a unique identifier name for a piece of data contained in OCSF. Each field also designates a corresponding data_type.
- Object: An object is a collection of contextually related fields and other objects. It is also a data_type in OCSF.
- Attribute: An attribute is the more generic name for both fields and objects in OCSF. A field is a scalar attribute while an object is a complex attribute.
- Event Class: An event is represented by an Event Class, which are a particular set of attributes (including fields & objects) representing a log line or telemetry submission at a point in time.
- Category: A Category organizes event classes that represent a particular domain.
More details about OCSF concepts, terminology and use-cases can be found in Understanding OCSF.
- Determine all the
attributes
(including fields and objects) you would want to add in theevent_class
. - Check the dictionary and the /objects folder, many of your desired attributes may already be present.
- Define the missing attributes → Adding/Modifying an
attribute
- Determine which category you would want to add your event_class in, note it’s
name
- Create a new file →
<event_class_name.json>
inside the category specific subfolder in the /events folder. Template available here - Define the
event_class
itself → Adding/Modifying anevent_class
- Finally, verify the changes are working as expected in your local ocsf-server.
-
All the available
attributes
-fields
&objects
in OCSF are and will need to be defined in the attribute dictionary, the dictionary.json file and /objects folder if defining an object. -
Determine if a new attribute is required for your change, it might already be defined in the attribute dictionary and/or the /objects folder.
-
Before adding a new attribute, review the following OCSF attribute conventions -
- Attribute names must be a valid UTF-8 sequence.
- Attribute names must be all lower case.
- Combine words using underscore.
- No special characters except underscore.
- Use present tense unless the attribute describes historical information.
- Use singular and plural names properly to reflect the field content. Example: use
events_per_sec
rather thanevent_per_sec
. - When attribute represents multiple entities, the attribute name should be pluralized and the value type should be an array. Example:
process.loaded_modules
includes multiple values -- a loaded module names list. - Avoid repetition of words. Example:
src_endpoint.src_ip
should besrc_endpoint.ip
. - Avoid abbreviations when possible. Some exceptions can be made for well-accepted abbreviation. Example:
ip
,os
,cve
etc.
To add a new field in OCSF, you need to define it in the dictionary.json file as described below.
Sample entry in the dictionary -
"uid":
{
"caption": "Unique ID", // "previously name"
"description": "The unique identifier. See specific usage.",
"type": "string_t"
}
Choose a unique field you want to add, uid
in the example above and populate it as described below.
caption
→ Add a user friendly name to the field.description
→ Add concise description to define the attributes.- Note that
field
descriptions can be overridden in theevent_class/object
, therefore if it’s a common field (like name, label, uid etc) feel free to add a generic description, specific descriptions can be added in theevent_class/object
definition. For example, - A generic definition of
uid
in the dictionary -uid
:The unique identifier. See specific usage.
- Specific description of
uid
in thevulnerability
object -uid
:Unique Identifier/s of the reported vulnerability. e.g. CVE ID/s"
- Note that
type
→ Review OCSF data_types and ensure you utilize appropriate types while defining new fields.- All the available data_types can be accessed here.
- They are also accessible in your local instance of the ocsf-server - http://localhost:8000/data_types
is_array
→ This a boolean key:value pair that you would need to add if the field you are defining is an array.- e.g.
"is_array": true
- e.g.
- All the available
objects
need to be defined as individual field entries in the dictionary, the dictionary.json file and as distinct .json files in the /objects folder. - Review existing Objects, determine if a modification of the existing object would be sufficient or if there’s a need for a completely new object.
- Use the template available here, to get started with .json file definition.
An example vulnerability.json
object file,
{
"caption": "Vulnerability Details",
"name": "vulnerability",
"description": "The vulnerability object describes details related to the observed vulnerability.",
"extends": "object",
"attributes": {
"desc": {
"description": "The description of the vulnerability",
"requirement": "recommended"
},
"kb_article_list": {
"requirement": "optional"
}
}
}
caption
→ Add a user friendly name to the object.description
→ Add a concise description to define the object.extends
→ Ensure the value isobject
or an existing object, e.g.entity
(All objects in OCSF must extend a base definition ofobject
or another existing object.)name
→ Add a unique name of the object.name
must match the filename of the actual.json
file.attributes
→ Add the attributes that you want to define in the object,requirement
→ For each attribute ensure you add a requirement value. Valid values areoptional
,required
,recommended
$include
→ You can include attributes from other places; to do so, specify a virtual attribute called$include
and give its value as the list of files (relative to the root of the schema repository) that should contribute their attributes to this object. e.g."attributes": { "$include": [ "profiles/host.json" ], ... }
Note: If you want to create an object which would act only as a base for other objects, you must prefix the object name
and the actual json
filename with an _
. The resultant object will not be visible in the OCSF Server. For example, take a look at the entity object.
Sample entry in the dictionary.json
,
"vulnerability":
{
"caption": "Vulnerability",
"description": "The vulnerability object describes details related to the observed vulnerability.",
"type": "vulnerability"
}
Choose a unique object you want to add, vulnerability
in the example above and populate it as described below.
caption
→ Add a user friendly name to the objectdescription
→ Add a concise description to define the object.type
→ Add the type of the object you are defining.is_array
→ This a boolean key:value pair that you would need to add if the object you are defining is an array.- e.g.
"is_array": true
- e.g.
- All the available Event Classes are defined as .json files in the /events folder.
- Review existing Event Classes, determine if a modification of the existing class would be sufficient or if there’s a need for a completely new event_class.
- To define a new class,
-
Create a new file →
<event_class_name.json>
inside the category specific subfolder in the /events folder. -
Use the template available here, to get started with the .json definition.
-
uid
→ Select an integer in the range 0 - 99. Ensure the integer is unique within the category.- Note: Without
uid
, an event_class won’t be visible in the ocsf-server.
- Note: Without
-
caption
→ Add a user friendly name to the event_class. -
description
→ Add a concise description to define the attributes. -
name
→ Add a unique name of the event_class. Ensure it matches the file name to maintain consistency. -
extends
→ Ensure the value isbase_event
. -
attributes
→ Add the attributes that you want to define in the event_class,group
→ For each attribute ensure you add a group value. Valid values are -classification
,context
,occurrence
,primary
requirement
→ For each attribute ensure you add a requirement value. Valid values areoptional
,required
,recommended
$include
→ As for objects, you can also include attributes from other places; to do so, specify the list of files (relative to the root of the schema repository) that should contribute their attributes to this object. e.g.
"attributes": { "$include": [ "profiles/cloud.json" ], ... }
-
constraints
→ For each class you can add constraints on the attribute requirements. Valid constraint types areat_least_one
,just_one
. e.g."constraints": { "at_least_one": [ "uid", "name" ] }
(A Constraint is a documented rule subject to validation that requires at least one of the specified recommended attributes of a class to be populated.)
-
To deprecate an attribute (field
, object
) follow the steps below -
- Create a github issue, explaining why an attribute needs to be deprecated and what the alternate solution is.
- Utilize the following flag to allow deprecation of attributes. This flag needs to be added a json property of the attribute that is the subject of deprecation.
"@deprecated": { "message": "Use the <code> ALTERNATE_ATTRIBUTE </code> attribute instead.", "since": "semver" }
- Example of a deprecated field
"packages": { "@deprecated": { "message": "Use the <code> affected_packages </code> attribute instead.", "since": "1.0.0" }, "caption": "Software Packages", "description": "List of vulnerable packages as identified by the security product", "is_array": true, "type": "package" }
- Example of a deprecated object
{ "caption": "Finding", "description": "The Finding object describes metadata related to a security finding generated by a security tool or system.", "extends": "object", "name": "finding", "@deprecated": { "message": "Use the new <code>finding_info</code> object.", "since": "1.0.0" }, "attributes": {...} }
Contributors should verify the changes before they submit the PR, the best method to test and verify their changes is to run a local instance of the ocsf-server. Follow the instructions here to set your own local ocsf-server.
If there are any problems with the newly made changes, the server will throw corresponding errors. Sample error messages -
[error] dictionary: missing attribute: event_uid for Network HTTP Activity
[error] dictionary: missing attribute: event_name for Container Orchestration
Address the errors before submitting the changes, your server run should be completely error free.
By making a contribution to this project, I certify that:
(a) The contribution was created in whole or in part by me and I have the right to submit it under the open source license indicated in the file; or
(b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate open source license and I have the right under that license to submit that work with modifications, whether created in whole or in part by me, under the same open source license (unless I am permitted to submit under a different license), as indicated in the file; or
(c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not modified it.
(d) I understand and agree that this project and the contribution are public and that a record of the contribution (including all personal information I submit with it, including my sign-off) is maintained indefinitely and may be redistributed consistent with this project or the open source license(s) involved.
We require that every contribution to this repository is signed with a Developer Certificate of Origin. Additionally, please use your real name. We do not accept anonymous contributors nor those utilizing pseudonyms.
Each commit must include a DCO which looks like this
Signed-off-by: Jane Smith [email protected]
You may type this line on your own when writing your commit messages. However, if your user.name and user.email are set in your git configs, you can use -s or --signoff to add the Signed-off-by line to the end of the commit message.
The OCSF Schema can be extended by adding an extension that defines additional attributes, objects, profiles, event classes and/or categories. Extensions allow one to create vendor/customer specific schemas or augment an existing schema to better suit their custom requirements. Extensions can also be used to factor out non-essential schema domains keeping the core schema succinct. Extensions use the framework in the same way as a new schema, optionally creating categories, profiles or event classes from the dictionary.
As with categories and event classes, extensions have unique IDs within the framework as well as their own versioning. The following sections provide guidelines to create extensions within OCSF.
In order to reserve an ID space, and make your extension public, add a unique identifier & a unique name for your extension in the OCSF Extensions Registry here. This is done to avoid collisions with core or other extension schemas. For example, a new sample extension would have a row in the table as follows:
Caption | Name | UID | Notes |
---|---|---|---|
New Extension | new_ex | 123 | The development schema extensions |
To extend the schema, create a new subdirectory in the extensions
directory, and add a new extension.json
file, which defines the extension's name
and uid
. For example:
{
"caption": "New Extension",
"name": "new_ex",
"uid": 123,
"version": "0.0.0"
}
The extension's directory structure is the same as the top level schema directory, and it may contain the following files and subdirectories, depending on what type of extension is desired:
Name | Description |
---|---|
categories.json |
Create it to define new categories. Note, to avoid collisions with the categories defined in the core schema, the category IDs must be greater than or equal to 30. |
dictionary.json |
Create it to define new attributes. |
events |
Create it to define new event classes. |
objects |
Create it to define new objects. |
profiles |
Create it to define new profiles. |
As a reference, take a look at the Linux Extension that is currently added to OCSF.
See the ocsf-server project documentation.