joint-schema 0.1.0__tar.gz

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.
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: joint-schema
3
+ Version: 0.1.0
4
+ Summary: Multi-domain military operations schema: MIM operational concepts, DISARM influence operation TTPs, and STIX cyber threat intelligence
5
+ License: TBD
6
+ Project-URL: Homepage, https://github.com/tairnyn/joint-schema
7
+ Project-URL: Repository, https://github.com/tairnyn/joint-schema
8
+ Project-URL: Issues, https://github.com/tairnyn/joint-schema/issues
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: linkml>=1.8.0
12
+ Requires-Dist: linkml-runtime>=1.8.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: stix2>=3.0.0
15
+ Requires-Dist: PyYAML>=6.0
16
+ Requires-Dist: jsonschema>=4.0.0
17
+ Requires-Dist: click>=8.0.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: build>=1.0.0; extra == "dev"
20
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
21
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
22
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
23
+
24
+ # joint-schema
25
+
26
+ Multi-domain military operations schema covering three integrated knowledge domains:
27
+
28
+ | Domain | Description |
29
+ |--------|-------------|
30
+ | **MIM** | Military Information Model — operational concepts, units, tasks, effects |
31
+ | **DISARM** | Influence operation Tactics, Techniques & Procedures (TTPs) |
32
+ | **STIX** | Cyber threat intelligence objects bridged from STIX 2.1 |
33
+
34
+ ## Directory structure
35
+
36
+ ```
37
+ joint-schema/
38
+ ├── schema/
39
+ │ ├── core/ # Shared base classes, common types, enumerations
40
+ │ ├── mim/ # MIM operational concept schemas (LinkML YAML)
41
+ │ ├── disarm/ # DISARM TTP schemas (LinkML YAML)
42
+ │ └── bridge/ # Cross-domain linkage / alignment schemas
43
+ ├── generated/ # Auto-generated artifacts (JSON Schema, Pydantic, OWL, …)
44
+ ├── llm-context/ # Bundled context files for LLM tooling
45
+ ├── docs/ # Documentation source and build output
46
+ └── tests/ # Schema validation and integration tests
47
+ ```
48
+
49
+ ## Quickstart
50
+
51
+ ```bash
52
+ # Python toolchain
53
+ python -m venv .venv
54
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
55
+ pip install -r requirements.txt
56
+
57
+ # Node toolchain (DOCX generation)
58
+ npm install
59
+
60
+ # Run tests
61
+ pytest
62
+ ```
63
+
64
+ ## Generating artifacts
65
+
66
+ ```bash
67
+ # JSON Schema from a LinkML source file
68
+ gen-json-schema schema/core/core.yaml > generated/core.schema.json
69
+
70
+ # Pydantic models
71
+ gen-pydantic schema/core/core.yaml > generated/core_models.py
72
+ ```
@@ -0,0 +1,49 @@
1
+ # joint-schema
2
+
3
+ Multi-domain military operations schema covering three integrated knowledge domains:
4
+
5
+ | Domain | Description |
6
+ |--------|-------------|
7
+ | **MIM** | Military Information Model — operational concepts, units, tasks, effects |
8
+ | **DISARM** | Influence operation Tactics, Techniques & Procedures (TTPs) |
9
+ | **STIX** | Cyber threat intelligence objects bridged from STIX 2.1 |
10
+
11
+ ## Directory structure
12
+
13
+ ```
14
+ joint-schema/
15
+ ├── schema/
16
+ │ ├── core/ # Shared base classes, common types, enumerations
17
+ │ ├── mim/ # MIM operational concept schemas (LinkML YAML)
18
+ │ ├── disarm/ # DISARM TTP schemas (LinkML YAML)
19
+ │ └── bridge/ # Cross-domain linkage / alignment schemas
20
+ ├── generated/ # Auto-generated artifacts (JSON Schema, Pydantic, OWL, …)
21
+ ├── llm-context/ # Bundled context files for LLM tooling
22
+ ├── docs/ # Documentation source and build output
23
+ └── tests/ # Schema validation and integration tests
24
+ ```
25
+
26
+ ## Quickstart
27
+
28
+ ```bash
29
+ # Python toolchain
30
+ python -m venv .venv
31
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
32
+ pip install -r requirements.txt
33
+
34
+ # Node toolchain (DOCX generation)
35
+ npm install
36
+
37
+ # Run tests
38
+ pytest
39
+ ```
40
+
41
+ ## Generating artifacts
42
+
43
+ ```bash
44
+ # JSON Schema from a LinkML source file
45
+ gen-json-schema schema/core/core.yaml > generated/core.schema.json
46
+
47
+ # Pydantic models
48
+ gen-pydantic schema/core/core.yaml > generated/core_models.py
49
+ ```
@@ -0,0 +1,72 @@
1
+ Metadata-Version: 2.4
2
+ Name: joint-schema
3
+ Version: 0.1.0
4
+ Summary: Multi-domain military operations schema: MIM operational concepts, DISARM influence operation TTPs, and STIX cyber threat intelligence
5
+ License: TBD
6
+ Project-URL: Homepage, https://github.com/tairnyn/joint-schema
7
+ Project-URL: Repository, https://github.com/tairnyn/joint-schema
8
+ Project-URL: Issues, https://github.com/tairnyn/joint-schema/issues
9
+ Requires-Python: >=3.11
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: linkml>=1.8.0
12
+ Requires-Dist: linkml-runtime>=1.8.0
13
+ Requires-Dist: pydantic>=2.0.0
14
+ Requires-Dist: stix2>=3.0.0
15
+ Requires-Dist: PyYAML>=6.0
16
+ Requires-Dist: jsonschema>=4.0.0
17
+ Requires-Dist: click>=8.0.0
18
+ Provides-Extra: dev
19
+ Requires-Dist: build>=1.0.0; extra == "dev"
20
+ Requires-Dist: pytest>=8.0.0; extra == "dev"
21
+ Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
22
+ Requires-Dist: ruff>=0.4.0; extra == "dev"
23
+
24
+ # joint-schema
25
+
26
+ Multi-domain military operations schema covering three integrated knowledge domains:
27
+
28
+ | Domain | Description |
29
+ |--------|-------------|
30
+ | **MIM** | Military Information Model — operational concepts, units, tasks, effects |
31
+ | **DISARM** | Influence operation Tactics, Techniques & Procedures (TTPs) |
32
+ | **STIX** | Cyber threat intelligence objects bridged from STIX 2.1 |
33
+
34
+ ## Directory structure
35
+
36
+ ```
37
+ joint-schema/
38
+ ├── schema/
39
+ │ ├── core/ # Shared base classes, common types, enumerations
40
+ │ ├── mim/ # MIM operational concept schemas (LinkML YAML)
41
+ │ ├── disarm/ # DISARM TTP schemas (LinkML YAML)
42
+ │ └── bridge/ # Cross-domain linkage / alignment schemas
43
+ ├── generated/ # Auto-generated artifacts (JSON Schema, Pydantic, OWL, …)
44
+ ├── llm-context/ # Bundled context files for LLM tooling
45
+ ├── docs/ # Documentation source and build output
46
+ └── tests/ # Schema validation and integration tests
47
+ ```
48
+
49
+ ## Quickstart
50
+
51
+ ```bash
52
+ # Python toolchain
53
+ python -m venv .venv
54
+ source .venv/bin/activate # Windows: .venv\Scripts\activate
55
+ pip install -r requirements.txt
56
+
57
+ # Node toolchain (DOCX generation)
58
+ npm install
59
+
60
+ # Run tests
61
+ pytest
62
+ ```
63
+
64
+ ## Generating artifacts
65
+
66
+ ```bash
67
+ # JSON Schema from a LinkML source file
68
+ gen-json-schema schema/core/core.yaml > generated/core.schema.json
69
+
70
+ # Pydantic models
71
+ gen-pydantic schema/core/core.yaml > generated/core_models.py
72
+ ```
@@ -0,0 +1,16 @@
1
+ README.md
2
+ pyproject.toml
3
+ joint_schema.egg-info/PKG-INFO
4
+ joint_schema.egg-info/SOURCES.txt
5
+ joint_schema.egg-info/dependency_links.txt
6
+ joint_schema.egg-info/requires.txt
7
+ joint_schema.egg-info/top_level.txt
8
+ tests/__init__.py
9
+ tests/conftest.py
10
+ tests/test_core_actors.py
11
+ tests/test_core_events.py
12
+ tests/test_core_locations.py
13
+ tests/test_core_plans.py
14
+ tests/test_core_platforms.py
15
+ tests/test_core_resources.py
16
+ tests/test_core_time.py
@@ -0,0 +1,13 @@
1
+ linkml>=1.8.0
2
+ linkml-runtime>=1.8.0
3
+ pydantic>=2.0.0
4
+ stix2>=3.0.0
5
+ PyYAML>=6.0
6
+ jsonschema>=4.0.0
7
+ click>=8.0.0
8
+
9
+ [dev]
10
+ build>=1.0.0
11
+ pytest>=8.0.0
12
+ pytest-cov>=5.0.0
13
+ ruff>=0.4.0
@@ -0,0 +1,2 @@
1
+ schema
2
+ tests
@@ -0,0 +1,48 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "joint-schema"
7
+ version = "0.1.0"
8
+ description = "Multi-domain military operations schema: MIM operational concepts, DISARM influence operation TTPs, and STIX cyber threat intelligence"
9
+ readme = "README.md"
10
+ requires-python = ">=3.11"
11
+ license = { text = "TBD" }
12
+ dependencies = [
13
+ "linkml>=1.8.0",
14
+ "linkml-runtime>=1.8.0",
15
+ "pydantic>=2.0.0",
16
+ "stix2>=3.0.0",
17
+ "PyYAML>=6.0",
18
+ "jsonschema>=4.0.0",
19
+ "click>=8.0.0",
20
+ ]
21
+
22
+ [project.urls]
23
+ Homepage = "https://github.com/tairnyn/joint-schema"
24
+ Repository = "https://github.com/tairnyn/joint-schema"
25
+ Issues = "https://github.com/tairnyn/joint-schema/issues"
26
+
27
+ [project.optional-dependencies]
28
+ dev = [
29
+ "build>=1.0.0",
30
+ "pytest>=8.0.0",
31
+ "pytest-cov>=5.0.0",
32
+ "ruff>=0.4.0",
33
+ ]
34
+
35
+ [tool.setuptools.packages.find]
36
+ where = ["."]
37
+ include = ["schema*", "tests*"]
38
+
39
+ [tool.pytest.ini_options]
40
+ testpaths = ["tests"]
41
+ addopts = "-v --tb=short"
42
+
43
+ [tool.ruff]
44
+ line-length = 100
45
+ target-version = "py311"
46
+
47
+ [tool.ruff.lint]
48
+ select = ["E", "F", "I"]
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
File without changes
@@ -0,0 +1,21 @@
1
+ """
2
+ Shared pytest configuration for joint-schema tests.
3
+
4
+ Adds the generated Pydantic models directory to sys.path so every test
5
+ file can import generated models without package installation.
6
+
7
+ The directory is resolved (in priority order) from:
8
+ 1. GENERATED_PYTHON_DIR env var — set by CI to /tmp/gen-pr
9
+ 2. <repo_root>/generated/python/ — default for local development
10
+ """
11
+ import os
12
+ import sys
13
+ import pathlib
14
+
15
+ REPO_ROOT = pathlib.Path(__file__).parent.parent
16
+
17
+ env_override = os.environ.get("GENERATED_PYTHON_DIR")
18
+ GENERATED_PYTHON = pathlib.Path(env_override) if env_override else REPO_ROOT / "generated" / "python"
19
+
20
+ if str(GENERATED_PYTHON) not in sys.path:
21
+ sys.path.insert(0, str(GENERATED_PYTHON))
@@ -0,0 +1,162 @@
1
+ """
2
+ Tests for schema/core/actors.yaml — three-domain actor model.
3
+
4
+ Generated models: generated/python/core__actors_models.py
5
+ """
6
+ import pytest
7
+ from pydantic import ValidationError
8
+
9
+ from core__actors_models import (
10
+ MilitaryEchelon,
11
+ BranchOfService,
12
+ CombatantSide,
13
+ ThreatActorType,
14
+ ThreatActorSophistication,
15
+ ThreatActorMotivation,
16
+ InfluenceActorType,
17
+ MilitaryUnit,
18
+ ThreatActor,
19
+ InfluenceOperationActor,
20
+ )
21
+
22
+
23
+ # ── Test 1: MilitaryUnit — NATO/MIM compatible unit model ─────────────────────
24
+
25
+ def test_military_unit_minimal_valid():
26
+ """MilitaryUnit with only required fields (id, name, side) is valid."""
27
+ unit = MilitaryUnit(
28
+ id="jsc:unit/3-bn-69-ar",
29
+ name="3rd Battalion, 69th Armor Regiment",
30
+ side=CombatantSide.FRIENDLY,
31
+ )
32
+
33
+ assert unit.id == "jsc:unit/3-bn-69-ar"
34
+ assert unit.name == "3rd Battalion, 69th Armor Regiment"
35
+ assert unit.side == CombatantSide.FRIENDLY
36
+ # Optional fields absent
37
+ assert unit.echelon is None
38
+ assert unit.parent_unit_id is None
39
+ assert unit.branch_of_service is None
40
+
41
+
42
+ def test_military_unit_full_hierarchy():
43
+ """MilitaryUnit with echelon, branch, designation, and parent link is valid."""
44
+ battalion = MilitaryUnit(
45
+ id="jsc:unit/3-bn-69-ar",
46
+ name="3-69 AR",
47
+ side=CombatantSide.FRIENDLY,
48
+ echelon=MilitaryEchelon.BATTALION,
49
+ branch_of_service=BranchOfService.ARMY,
50
+ unit_designation="3rd Battalion, 69th Armor Regiment",
51
+ parent_unit_id="jsc:unit/3-abct",
52
+ aliases=["Task Force IRON", "TF 3-69"],
53
+ )
54
+
55
+ assert battalion.echelon == MilitaryEchelon.BATTALION
56
+ assert battalion.branch_of_service == BranchOfService.ARMY
57
+ assert battalion.unit_designation == "3rd Battalion, 69th Armor Regiment"
58
+ assert battalion.parent_unit_id == "jsc:unit/3-abct"
59
+ assert "Task Force IRON" in battalion.aliases
60
+
61
+
62
+ def test_military_unit_requires_side():
63
+ """MilitaryUnit without `side` must raise a ValidationError."""
64
+ with pytest.raises(ValidationError) as exc_info:
65
+ MilitaryUnit(id="jsc:unit/x", name="Unknown Unit")
66
+ fields = {e["loc"][0] for e in exc_info.value.errors()}
67
+ assert "side" in fields
68
+
69
+
70
+ def test_military_unit_requires_id_and_name():
71
+ """MilitaryUnit without id or name must fail validation."""
72
+ with pytest.raises(ValidationError):
73
+ MilitaryUnit(side=CombatantSide.FRIENDLY)
74
+
75
+
76
+ def test_military_unit_attribution_confidence_bounds():
77
+ """attribution_confidence must be in [0, 100]; values outside that range fail."""
78
+ # Boundary values are valid
79
+ lo = MilitaryUnit(id="jsc:unit/a", name="A", side=CombatantSide.HOSTILE, attribution_confidence=0)
80
+ hi = MilitaryUnit(id="jsc:unit/b", name="B", side=CombatantSide.HOSTILE, attribution_confidence=100)
81
+ assert lo.attribution_confidence == 0
82
+ assert hi.attribution_confidence == 100
83
+
84
+ with pytest.raises(ValidationError):
85
+ MilitaryUnit(id="jsc:unit/c", name="C", side=CombatantSide.HOSTILE, attribution_confidence=101)
86
+ with pytest.raises(ValidationError):
87
+ MilitaryUnit(id="jsc:unit/d", name="D", side=CombatantSide.HOSTILE, attribution_confidence=-1)
88
+
89
+
90
+ # ── Test 2: ThreatActor — STIX-mapped adversary model ─────────────────────────
91
+
92
+ def test_threat_actor_nation_state():
93
+ """ThreatActor of type NATION_STATE with sophistication and motivation."""
94
+ actor = ThreatActor(
95
+ id="stix:threat-actor--12345678-1234-1234-1234-123456789abc",
96
+ name="APT-X",
97
+ threat_actor_types=[ThreatActorType.NATION_STATE],
98
+ sophistication=ThreatActorSophistication.ADVANCED,
99
+ primary_motivation=ThreatActorMotivation.IDEOLOGY,
100
+ aliases=["Fancy Bear", "Sofacy", "APT28"],
101
+ )
102
+
103
+ assert ThreatActorType.NATION_STATE in actor.threat_actor_types
104
+ assert actor.sophistication == ThreatActorSophistication.ADVANCED
105
+ assert actor.primary_motivation == ThreatActorMotivation.IDEOLOGY
106
+ assert "Fancy Bear" in actor.aliases
107
+
108
+
109
+ def test_threat_actor_minimal():
110
+ """ThreatActor with only id and name is valid (all other fields optional)."""
111
+ actor = ThreatActor(
112
+ id="jsc:actor/unknown-threat",
113
+ name="Unknown Threat Actor",
114
+ )
115
+
116
+ assert actor.threat_actor_types is None
117
+ assert actor.sophistication is None
118
+
119
+
120
+ def test_threat_actor_stix_uri_id():
121
+ """ThreatActor id accepts a full STIX URN format."""
122
+ actor = ThreatActor(
123
+ id="stix:threat-actor--aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee",
124
+ name="STIX Actor",
125
+ )
126
+ assert actor.id.startswith("stix:")
127
+
128
+
129
+ # ── Test 3: InfluenceOperationActor — DISARM-mapped influence actor ────────────
130
+
131
+ def test_influence_actor_state_media():
132
+ """InfluenceOperationActor of type STATE_ALIGNED_MEDIA is valid."""
133
+ actor = InfluenceOperationActor(
134
+ id="jsc:actor/rt-network",
135
+ name="RT Network",
136
+ influence_actor_type=InfluenceActorType.STATE_ALIGNED,
137
+ active_platforms=["YouTube", "Telegram", "X/Twitter"],
138
+ attributed_to_state_id="jsc:actor/russian-federation",
139
+ attribution_confidence=78,
140
+ influence_capabilities=["broadcast television", "social media amplification"],
141
+ )
142
+
143
+ assert actor.influence_actor_type == InfluenceActorType.STATE_ALIGNED
144
+ assert "Telegram" in actor.active_platforms
145
+ assert actor.attribution_confidence == 78
146
+ assert "broadcast television" in actor.influence_capabilities
147
+
148
+
149
+ def test_influence_actor_requires_id_and_name():
150
+ """InfluenceOperationActor without id and name must fail."""
151
+ with pytest.raises(ValidationError):
152
+ InfluenceOperationActor()
153
+
154
+
155
+ def test_influence_actor_attribution_confidence_optional():
156
+ """attribution_confidence is optional; absent means unasserted."""
157
+ actor = InfluenceOperationActor(
158
+ id="jsc:actor/anon-troll-farm",
159
+ name="Anonymous Troll Farm",
160
+ )
161
+ assert actor.attribution_confidence is None
162
+ assert actor.attributed_to_state_id is None