Skip to content

ST 0902 MISMMS API

Policy inputs, current-state coverage, and bounded stream-cadence validation for the Minimum Metadata Set.

stanag4609.st0902

MISB ST 0902.8 minimum-metadata stream profile validation.

_BASE_REQUIREMENTS module-attribute

_BASE_REQUIREMENTS = (_RequirementGroup('checksum', (1,)), _RequirementGroup('precision_timestamp', (2,)), _RequirementGroup('mission_id', (3,)), _RequirementGroup('platform_heading', (5,)), _RequirementGroup('platform_pitch', (6, 90)), _RequirementGroup('platform_roll', (7, 91)), _RequirementGroup('platform_designation', (10,)), _RequirementGroup('image_source_sensor', (11,)), _RequirementGroup('image_coordinate_system', (12,)), _RequirementGroup('sensor_latitude', (13,)), _RequirementGroup('sensor_longitude', (14,)), _RequirementGroup('sensor_altitude', (15, 75, 104)), _RequirementGroup('sensor_horizontal_fov', (16,)), _RequirementGroup('sensor_vertical_fov', (17,)), _RequirementGroup('sensor_relative_azimuth', (18,)), _RequirementGroup('sensor_relative_elevation', (19,)), _RequirementGroup('sensor_relative_roll', (20,)), _RequirementGroup('slant_range', (21,)), _RequirementGroup('target_width', (22, 96)), _RequirementGroup('frame_center_latitude', (23,)), _RequirementGroup('frame_center_longitude', (24,)), _RequirementGroup('frame_center_elevation', (25, 78)), _RequirementGroup('uas_local_set_version', (65,)))

_SECURITY_CORE_TAGS module-attribute

_SECURITY_CORE_TAGS = (1, 2, 3, 12, 13, 22)

_SECURITY_REQUIREMENTS module-attribute

_SECURITY_REQUIREMENTS = {1: _RequirementGroup('security_classification', (1,), 48), 2: _RequirementGroup('security_country_coding_method', (2,), 48), 3: _RequirementGroup('security_classifying_country', (3,), 48), 4: _RequirementGroup('security_sci_shi_information', (4,), 48), 5: _RequirementGroup('security_caveats', (5,), 48), 6: _RequirementGroup('security_releasing_instructions', (6,), 48), 12: _RequirementGroup('security_object_country_coding_method', (12,), 48), 13: _RequirementGroup('security_object_country_codes', (13,), 48), 22: _RequirementGroup('security_metadata_version', (22,), 48)}

DecodeError

Bases: Stanag4609Error, ValueError

Input is complete enough to inspect but is not valid.

KLVPacket dataclass

KLVPacket(key: bytes, value: bytes, length_octets: bytes, offset: int = 0)

A Universal KLV packet with its original length encoding.

CountryCodingMethod

Bases: IntEnum

ST 0102 Tag 2 country-code vocabularies.

ObjectCountryCodingMethod

Bases: IntEnum

ST 0102 Tag 12 object-country-code vocabularies.

SecurityClassification

Bases: IntEnum

ST 0102 Local Set Tag 1 security-classification values.

SecurityLocalSet dataclass

SecurityLocalSet(packet: KLVPacket | None, local_set: LocalSet, fields: tuple[SecurityField, ...], standalone: bool)

Decoded standalone or ST 0601-embedded Security Metadata Local Set.

version property

version: int

Return the declared version, or the mandated legacy default of 3.

DecodedField dataclass

DecodedField(definition: FieldDefinition, value: Any, raw: bytes, item: LocalSetItem)

FieldDecodingIssue dataclass

FieldDecodingIssue(tag: int, name: str, message: str, raw: bytes, item: LocalSetItem)

A known field that could not be typed but remains available losslessly.

FieldDecodingMode

Bases: Enum

Policy for malformed values carried by otherwise valid known fields.

UASLocalSet dataclass

UASLocalSet(packet: KLVPacket, local_set: LocalSet, fields: tuple[DecodedField, ...], issues: tuple[FieldDecodingIssue, ...] = ())

misp_timestamp_microseconds property

misp_timestamp_microseconds: int | None

Return the exact Item 2 MISP count, without implying UTC.

effective_fields property

effective_fields: tuple[DecodedField, ...]

Fields after applying ST 0601 preferred-representation rules.

utc_timestamp

utc_timestamp(*, leap_seconds: int | None = None, correction_offset: int | None = None) -> datetime

Convert Item 2 to UTC using packet Items 136/137 or overrides.

Item 136 is optional on the wire, so conversion deliberately fails when neither the packet nor the caller supplies the accumulated leap-second value. Item 137 defaults to zero when absent. Explicit arguments take precedence over packet values, which lets applications use a trusted external leap-second table or post-flight correction.

preferred_field

preferred_field(semantic: ST0601Semantic | str) -> ResolvedUASField | None

Resolve one logical value to its normative preferred representation.

target_elevation

target_elevation() -> ResolvedTargetElevation | None

Resolve Item 42's datum from current Items 25 and 78.

MISMMSValidationIssue dataclass

MISMMSValidationIssue(code: str, requirement: str, message: str, tags: tuple[int, ...])

One ST 0902.8 profile violation observed in a metadata stream.

MISMMSPopulationStatus

Bases: str, Enum

End-of-observation population state for one ST 0902 requirement.

MISMMSRequirementCoverage dataclass

MISMMSRequirementCoverage(requirement: str, tags: tuple[int, ...], status: MISMMSPopulationStatus, last_seen: datetime | None, age_seconds: float | None, parent_tag: int | None = None)

Population timing for one selected ST 0902 minimum-item group.

tag_paths property

tag_paths: tuple[tuple[int, ...], ...]

Return each root or nested Local Set path satisfying the group.

to_dict

to_dict() -> dict[str, object]

Return a JSON-compatible coverage entry.

MISMMSecurityContext dataclass

MISMMSecurityContext(sci_shi: bool = False, caveats: bool = False, releasing_instructions: bool = False, expected_classification: SecurityClassification | None = None, expected_country_coding_method: CountryCodingMethod | None = None, expected_classifying_country: str | None = None, expected_sci_shi: str | None = None, expected_caveats: str | None = None, required_releasing_countries: frozenset[str] = frozenset(), expected_object_country_coding_method: ObjectCountryCodingMethod | None = None, required_object_countries: frozenset[str] = frozenset(), minimum_security_metadata_version: int | None = None)

Declare which context-dependent ST 0102 markings apply to a stream.

ST 0902 Table 1 includes Security Local Set Items 4, 5, and 6, while ST 0102 makes each mandatory only when the corresponding marking applies. The default therefore requires the six unconditional Security sub-items without inventing mission-specific security policy.

required_tags property

required_tags: tuple[int, ...]

Return applicable context-dependent ST 0102 Local Set tags.

has_policy property

has_policy: bool

Return whether any caller-supplied marking constraint is active.

_RequirementGroup dataclass

_RequirementGroup(name: str, tags: tuple[int, ...], parent_tag: int | None = None)

MISMMSValidator

MISMMSValidator(*, require_security: bool = True, require_miis: bool = True, security_context: MISMMSecurityContext | None = None, maximum_interval: timedelta = timedelta(seconds=30), field_decoding: FieldDecodingMode = PRESERVE)

Validate ST 0902.8 minimum-item reporting across a timed packet stream.

Required fields may be spread across packets. A requirement becomes overdue only after more than the configured interval has elapsed, matching the standard's inclusive 30-second reporting window.

last_seen property

last_seen: Mapping[str, datetime]

Return an immutable snapshot of last valid observations by requirement.

coverage

coverage(at: datetime | None = None) -> tuple[MISMMSRequirementCoverage, ...]

Return the selected profile's population state at one stream time.

This is an end-state inventory. Historical violations remain available from :meth:observe and :meth:finish even if a later value is current.

reset

reset() -> None

Reset all stream state so the validator can observe a new stream.

observe

observe(packet: bytes | KLVPacket | UASLocalSet) -> tuple[MISMMSValidationIssue, ...]

Observe one packet and return profile issues at its timestamp.

A supplied :class:UASLocalSet is decoded again from its retained wire packet. This prevents a value originally decoded with relaxed packet checks from bypassing the ST 0107/ST 0601 conformance required by ST 0902.3-01 and ST 0902.3-03.

finish

finish(at: datetime | None = None) -> tuple[MISMMSValidationIssue, ...]

Finalize a finite stream and report missing or trailing-overdue items.

observe reports cadence violations as packets arrive. finish also identifies requirements that never appeared, which cannot otherwise be diagnosed for recordings shorter than the reporting interval. Supplying at accounts for elapsed time after the final observed packet.

decode_uas_local_set

decode_uas_local_set(data: bytes | KLVPacket, *, verify_checksum: bool = True, require_timestamp: bool = True, require_version: bool = True, field_decoding: FieldDecodingMode = STRICT, context: ST0601ValidationContext | None = None) -> UASLocalSet

Decode one ST 0601 Universal KLV packet and its known fields.

PRESERVE retains an otherwise structurally valid packet when an individual known field cannot be decoded. The raw item remains in local_set and a diagnostic is added to issues; checksum, required tags, singleton rules, and Local Set structure remain strict.

_is_printable_ascii

_is_printable_ascii(value: str) -> bool

_validate_policy_country

_validate_policy_country(value: object, *, name: str) -> None

_security_value

_security_value(fields: Mapping[int, object], tag: int) -> object | None

_security_policy_issues

_security_policy_issues(fields: Mapping[int, object], context: MISMMSecurityContext) -> tuple[MISMMSValidationIssue, ...]

_selected_requirement_groups

_selected_requirement_groups(*, require_security: bool, require_miis: bool, security_context: MISMMSecurityContext) -> tuple[_RequirementGroup, ...]

validate_mismms_current_state

validate_mismms_current_state(fields: Iterable[DecodedField] | UASLocalSet, *, field_issues: Iterable[FieldDecodingIssue] = (), require_security: bool = True, require_miis: bool = True, security_context: MISMMSecurityContext | None = None, effective_security: Mapping[int, object] | None = None) -> tuple[MISMMSValidationIssue, ...]

Validate a reconstructed current ST 0902 minimum-metadata view.

A :class:UASLocalSet carries its preserve-mode diagnostics automatically. When passing a reconstructed field iterable, also pass the corresponding receiver-state field_issues. Malformed known fields are intentionally absent from the decoded field collection; retaining their diagnostics distinguishes invalid population from an item that was never populated.

ST 0102 Security types

The typed Security Local Set codec and classification vocabulary used by the ST 0902 policy layer.

stanag4609.st0102

MISB ST 0102.12 Security Metadata Local Set codec.

SECURITY_LOCAL_SET_KEY module-attribute

SECURITY_LOCAL_SET_KEY = bytes.fromhex('06 0E 2B 34 02 03 01 01 0E 01 03 03 02 00 00 00')

SECURITY_UNIVERSAL_SET_KEY module-attribute

SECURITY_UNIVERSAL_SET_KEY = bytes.fromhex('06 0E 2B 34 02 01 01 01 02 08 02 00 00 00 00 00')

_DEFINITIONS module-attribute

_DEFINITIONS = {1: _SecurityDefinition(1, 'Security Classification', 'uint', 1, minimum=1, maximum=5), 2: _SecurityDefinition(2, 'Classifying Country and Releasing Instructions Country Coding Method', 'uint', 1, minimum=1, maximum=16), 3: _SecurityDefinition(3, 'Classifying Country', 'ascii'), 4: _SecurityDefinition(4, 'Security-SCI/SHI Information', 'ascii'), 5: _SecurityDefinition(5, 'Caveats', 'ascii'), 6: _SecurityDefinition(6, 'Releasing Instructions', 'ascii'), 7: _SecurityDefinition(7, 'Classified By', 'ascii'), 8: _SecurityDefinition(8, 'Derived From', 'ascii'), 9: _SecurityDefinition(9, 'Classification Reason', 'ascii'), 10: _SecurityDefinition(10, 'Declassification Date', 'date8', 8), 11: _SecurityDefinition(11, 'Classification and Marking System', 'ascii'), 12: _SecurityDefinition(12, 'Object Country Coding Method', 'uint', 1, allowed=frozenset((*range(1, 16), 64))), 13: _SecurityDefinition(13, 'Object Country Codes', 'utf16'), 14: _SecurityDefinition(14, 'Classification Comments', 'ascii'), 22: _SecurityDefinition(22, 'Security Metadata Version', 'uint', 2), 23: _SecurityDefinition(23, 'Country Coding Method Version Date', 'date10', 10), 24: _SecurityDefinition(24, 'Object Country Coding Method Version Date', 'date10', 10)}

_UNIVERSAL_KEYS module-attribute

_UNIVERSAL_KEYS = {1: bytes.fromhex('060E2B34010101030208020100000000'), 2: bytes.fromhex('060E2B34010101030701200102070000'), 3: bytes.fromhex('060E2B34010101030701200102080000'), 4: bytes.fromhex('060E2B34010101010E01020302000000'), 5: bytes.fromhex('060E2B34010101030208020200000000'), 6: bytes.fromhex('060E2B34010101030701200102090000'), 7: bytes.fromhex('060E2B34010101030208020300000000'), 8: bytes.fromhex('060E2B34010101030208020600000000'), 9: bytes.fromhex('060E2B34010101030208020400000000'), 10: bytes.fromhex('060E2B34010101030208020500000000'), 11: bytes.fromhex('060E2B34010101030208020800000000'), 12: bytes.fromhex('060E2B34010101030701200102060000'), 13: bytes.fromhex('060E2B34010101030701200102010100'), 14: bytes.fromhex('060E2B34010101030208020700000000'), 22: bytes.fromhex('060E2B34010101010E01020504000000'), 23: bytes.fromhex('060E2B34010101010E01040303000000'), 24: bytes.fromhex('060E2B34010101010E01040304000000')}

_UNIVERSAL_TAGS module-attribute

_UNIVERSAL_TAGS = {key: tag for tag, key in _UNIVERSAL_KEYS.items()}

_UNIVERSAL_CLASSIFICATIONS module-attribute

_UNIVERSAL_CLASSIFICATIONS = {SecurityClassification.UNCLASSIFIED: 'UNCLASSIFIED//', SecurityClassification.RESTRICTED: 'RESTRICTED//', SecurityClassification.CONFIDENTIAL: 'CONFIDENTIAL//', SecurityClassification.SECRET: 'SECRET//', SecurityClassification.TOP_SECRET: 'TOP SECRET//'}

_UNIVERSAL_COUNTRY_METHODS module-attribute

_UNIVERSAL_COUNTRY_METHODS = {CountryCodingMethod.ISO_3166_TWO_LETTER: 'ISO-3166 Two Letter', CountryCodingMethod.ISO_3166_THREE_LETTER: 'ISO-3166 Three Letter', CountryCodingMethod.FIPS_10_4_TWO_LETTER: 'FIPS 10-4 Two Letter', CountryCodingMethod.FIPS_10_4_FOUR_LETTER: 'FIPS 10-4 Four Letter', CountryCodingMethod.ISO_3166_NUMERIC: 'ISO-3166 Numeric', CountryCodingMethod.STANAG_1059_TWO_LETTER: '1059 Two Letter', CountryCodingMethod.STANAG_1059_THREE_LETTER: '1059 Three Letter', CountryCodingMethod.FIPS_10_4_MIXED: 'FIPS 10-4 Mixed', CountryCodingMethod.ISO_3166_MIXED: 'ISO 3166 Mixed', CountryCodingMethod.STANAG_1059_MIXED: 'STANAG 1059 Mixed', CountryCodingMethod.GENC_TWO_LETTER: 'GENC Two Letter', CountryCodingMethod.GENC_THREE_LETTER: 'GENC Three Letter', CountryCodingMethod.GENC_NUMERIC: 'GENC Numeric', CountryCodingMethod.GENC_MIXED: 'GENC Mixed'}

_UNIVERSAL_OBJECT_METHODS module-attribute

_UNIVERSAL_OBJECT_METHODS = {ObjectCountryCodingMethod.ISO_3166_TWO_LETTER: 'ISO-3166 Two Letter', ObjectCountryCodingMethod.ISO_3166_THREE_LETTER: 'ISO-3166 Three Letter', ObjectCountryCodingMethod.ISO_3166_NUMERIC: 'ISO-3166 Numeric', ObjectCountryCodingMethod.FIPS_10_4_TWO_LETTER: 'FIPS 10-4 Two Letter', ObjectCountryCodingMethod.FIPS_10_4_FOUR_LETTER: 'FIPS 10-4 Four Letter', ObjectCountryCodingMethod.STANAG_1059_TWO_LETTER: '1059 Two Letter', ObjectCountryCodingMethod.STANAG_1059_THREE_LETTER: '1059 Three Letter', ObjectCountryCodingMethod.GENC_TWO_LETTER: 'GENC Two Letter', ObjectCountryCodingMethod.GENC_THREE_LETTER: 'GENC Three Letter', ObjectCountryCodingMethod.GENC_NUMERIC: 'GENC Numeric', ObjectCountryCodingMethod.GENC_ADMINISTRATIVE_SUBDIVISION: 'GENC AdminSub'}

_COUNTRY_METHODS module-attribute

_COUNTRY_METHODS: dict[int, tuple[str, str, int] | tuple[str, str, None]] = {1: ('ISO 3166 two-letter', 'alpha', 2), 2: ('ISO 3166 three-letter', 'alpha', 3), 3: ('FIPS 10-4 two-letter', 'alpha', 2), 4: ('FIPS 10-4 four-letter', 'alpha', 4), 5: ('ISO 3166 numeric', 'numeric', 3), 6: ('STANAG 1059 two-letter', 'alpha', 2), 7: ('STANAG 1059 three-letter', 'alpha', 3), 10: ('FIPS 10-4 mixed', 'mixed', None), 11: ('ISO 3166 mixed', 'mixed', None), 12: ('STANAG 1059 mixed', 'mixed', None), 13: ('GENC two-letter', 'alpha', 2), 14: ('GENC three-letter', 'alpha', 3), 15: ('GENC numeric', 'numeric', 3), 16: ('GENC mixed', 'mixed', None)}

_OBJECT_COUNTRY_METHODS module-attribute

_OBJECT_COUNTRY_METHODS: dict[int, tuple[str, str, int] | tuple[str, str, None]] = {1: ('ISO 3166 two-letter', 'alpha', 2), 2: ('ISO 3166 three-letter', 'alpha', 3), 3: ('ISO 3166 numeric', 'numeric', 3), 4: ('FIPS 10-4 two-letter', 'alpha', 2), 5: ('FIPS 10-4 four-letter', 'alpha', 4), 6: ('STANAG 1059 two-letter', 'alpha', 2), 7: ('STANAG 1059 three-letter', 'alpha', 3), 13: ('GENC two-letter', 'alpha', 2), 14: ('GENC three-letter', 'alpha', 3), 15: ('GENC numeric', 'numeric', 3), 64: ('GENC administrative-subdivision', 'subdivision', None)}

DecodeError

Bases: Stanag4609Error, ValueError

Input is complete enough to inspect but is not valid.

KLVPacket dataclass

KLVPacket(key: bytes, value: bytes, length_octets: bytes, offset: int = 0)

A Universal KLV packet with its original length encoding.

LocalSet dataclass

LocalSet(items: tuple[LocalSetItem, ...], raw: bytes)

Ordered Local Set items; duplicate and unknown tags are preserved.

LocalSetItem dataclass

LocalSetItem(tag: int, value: bytes, tag_octets: bytes, length_octets: bytes, offset: int)

One Local Set item, preserving the exact tag and length octets.

KLVStreamParser

KLVStreamParser(*, key_length: int = 16, key_prefix: bytes | None = b'\x06\x0e+4', canonical: bool = True, recover: bool = False, max_value_length: int = 64 * 1024 * 1024, validate_smpte_keys: bool | None = None)

Incrementally reconstruct fixed-width-key KLV packets.

Input chunks may split the key, BER length, or value at any byte boundary. Completed bytes are released immediately, and declared values are bounded.

feed

feed(data: bytes | bytearray | memoryview) -> list[KLVPacket]

Consume a chunk and return every newly completed packet.

finish

finish() -> list[KLVPacket]

Signal end of input and reject an incomplete trailing structure.

SecurityClassification

Bases: IntEnum

ST 0102 Local Set Tag 1 security-classification values.

CountryCodingMethod

Bases: IntEnum

ST 0102 Tag 2 country-code vocabularies.

ObjectCountryCodingMethod

Bases: IntEnum

ST 0102 Tag 12 object-country-code vocabularies.

SecuritySpecialValue

Bases: Enum

ST 0107 zero-length Unknown value within a Security Local Set.

SecurityMarkingContext dataclass

SecurityMarkingContext(sci_shi: bool = False, caveats: bool = False, releasing_instructions: bool = False)

External marking facts that make ST 0102 fields mandatory by context.

required_tags property

required_tags: tuple[int, ...]

Return the Local Set tags required by the declared marking context.

_SecurityDefinition dataclass

_SecurityDefinition(tag: int, name: str, kind: Literal['uint', 'ascii', 'utf16', 'date8', 'date10'], length: int | None = None, minimum: int | None = None, maximum: int | None = None, allowed: frozenset[int] | None = None)

SecurityField dataclass

SecurityField(tag: int, name: str, value: Any, raw: bytes, item: LocalSetItem | KLVPacket)

SecurityLocalSet dataclass

SecurityLocalSet(packet: KLVPacket | None, local_set: LocalSet, fields: tuple[SecurityField, ...], standalone: bool)

Decoded standalone or ST 0601-embedded Security Metadata Local Set.

version property

version: int

Return the declared version, or the mandated legacy default of 3.

SecurityUniversalSet dataclass

SecurityUniversalSet(packet: KLVPacket, items: tuple[KLVPacket, ...], fields: tuple[SecurityField, ...])

Decoded standalone ST 0102.12 Security Metadata Universal Set.

version property

version: int

Return the declared version, or the mandated legacy default of 3.

encode_ber_length

encode_ber_length(value: int) -> bytes

Encode a non-negative length using minimal definite-form BER.

encode_ber_oid

encode_ber_oid(value: int) -> bytes

Encode a non-negative integer using minimal base-128 BER-OID form.

parse_local_set

parse_local_set(data: Buffer, *, canonical: bool = True, max_item_length: int = 64 * 1024 * 1024) -> LocalSet

Parse all Local Set items while preserving byte-for-byte encodings.

_validate_ascii

_validate_ascii(value: str, *, tag: int) -> bytes

_validate_semantics

_validate_semantics(tag: int, value: str) -> None

_marking_context

_marking_context(value: SecurityMarkingContext | None) -> SecurityMarkingContext

_validate_country_code

_validate_country_code(code: str, *, method: tuple[str, str, int] | tuple[str, str, None], field_name: str) -> None

_validate_mixed_code_lengths

_validate_mixed_code_lengths(codes: tuple[str, ...], *, method_name: str) -> None

_validate_country_fields

_validate_country_fields(values: Mapping[int, Any]) -> None

_decode_date

_decode_date(raw: bytes, *, separated: bool, tag: int) -> date

_decode_value

_decode_value(item: LocalSetItem, definition: _SecurityDefinition) -> SecurityField

_encode_value

_encode_value(tag: int, value: Any) -> bytes

_required_tags

_required_tags(declared_version: int) -> set[int]

_validate_required_values

_validate_required_values(values: Mapping[int, Any], *, context: SecurityMarkingContext) -> None

_encode_universal_value

_encode_universal_value(tag: int, value: Any) -> bytes

encode_security_universal_set

encode_security_universal_set(values: Mapping[int, Any], *, context: SecurityMarkingContext | None = None) -> bytes

Encode an ST 0102.12 Security Metadata Universal Set.

encode_security_local_set

encode_security_local_set(values: Mapping[int, Any], *, standalone: bool = False, context: SecurityMarkingContext | None = None) -> bytes

Encode an ST 0102.12 Security Metadata Local Set.

_parse_single_packet

_parse_single_packet(data: bytes) -> KLVPacket

decode_security_local_set

decode_security_local_set(data: bytes | KLVPacket, *, standalone: bool = True, require_required: bool = True, context: SecurityMarkingContext | None = None) -> SecurityLocalSet

Decode one standalone or nested ST 0102.12 Security Metadata Local Set.

_decode_universal_value

_decode_universal_value(packet: KLVPacket, tag: int) -> SecurityField

decode_security_universal_set

decode_security_universal_set(data: bytes | KLVPacket, *, require_required: bool = True, context: SecurityMarkingContext | None = None) -> SecurityUniversalSet

Decode one ST 0102.12 Security Metadata Universal Set.