fluidattacks_core_contextualizes 2.0.0__tar.gz → 3.0.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.
Files changed (48) hide show
  1. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/PKG-INFO +1 -1
  2. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/__init__.py +3 -7
  3. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/components.py +0 -14
  4. fluidattacks_core_contextualizes-3.0.0/fluidattacks_core/contextualizes/entries.py +55 -0
  5. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/envelope.py +9 -15
  6. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/schema.py +4 -3
  7. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/schemas/contextualizer_output.schema.json +50 -90
  8. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/import-linter.cfg +1 -1
  9. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/pyproject.toml +1 -1
  10. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/discovers_output.json +14 -16
  11. fluidattacks_core_contextualizes-3.0.0/tests/data/explores_output.json +50 -0
  12. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_traversal_path.json → fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_absolute_path.json +11 -15
  13. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_attributed_observation.json +9 -13
  14. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_backslash_path.json +10 -14
  15. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_coerced_schema_version.json +50 -0
  16. fluidattacks_core_contextualizes-2.0.0/tests/data/explores_output.json → fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_component_with_line.json +12 -15
  17. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_absolute_path.json → fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_control_character_path.json +11 -15
  18. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_dot_segment_path.json +10 -14
  19. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_duplicate_component.json +50 -0
  20. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_duplicate_normalization.json +50 -0
  21. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_empty_segment_path.json +10 -14
  22. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_coerced_schema_version.json → fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_enriched_observation.json +10 -13
  23. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_missing_ecosystem.json +49 -0
  24. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_missing_enrichment.json +10 -14
  25. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_missing_name.json +49 -0
  26. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_missing_status.json +10 -14
  27. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/data/invalid_trailing_separator_path.json +10 -14
  28. fluidattacks_core_contextualizes-3.0.0/tests/data/invalid_traversal_path.json +50 -0
  29. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/test_envelope.py +66 -14
  30. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/test_schema.py +6 -3
  31. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/uv.lock +2 -2
  32. fluidattacks_core_contextualizes-2.0.0/build/default.nix +0 -19
  33. fluidattacks_core_contextualizes-2.0.0/build/filter.nix +0 -13
  34. fluidattacks_core_contextualizes-2.0.0/flake.lock +0 -303
  35. fluidattacks_core_contextualizes-2.0.0/flake.nix +0 -29
  36. fluidattacks_core_contextualizes-2.0.0/fluidattacks_core/contextualizes/observations.py +0 -28
  37. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_control_character_path.json +0 -54
  38. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_duplicate_component.json +0 -67
  39. fluidattacks_core_contextualizes-2.0.0/tests/data/invalid_duplicate_normalization.json +0 -67
  40. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/.envrc +0 -0
  41. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/.gitignore +0 -0
  42. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/paths.py +0 -0
  43. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/fluidattacks_core/contextualizes/py.typed +0 -0
  44. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/mypy.ini +0 -0
  45. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/ruff.toml +0 -0
  46. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/__init__.py +0 -0
  47. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/test_components.py +0 -0
  48. {fluidattacks_core_contextualizes-2.0.0 → fluidattacks_core_contextualizes-3.0.0}/tests/test_paths.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: fluidattacks_core_contextualizes
3
- Version: 2.0.0
3
+ Version: 3.0.0
4
4
  Summary: Fluid Attacks Core Contextualizes Library
5
5
  Author-email: Development <development@fluidattacks.com>
6
6
  License: MPL-2.0
@@ -1,17 +1,15 @@
1
1
  from fluidattacks_core.contextualizes.components import (
2
2
  MANIFEST_KINDS,
3
- Component,
4
3
  ComponentKind,
5
4
  Enrichment,
6
5
  kind_for_manifests,
7
6
  )
7
+ from fluidattacks_core.contextualizes.entries import Entry, EntryKind
8
8
  from fluidattacks_core.contextualizes.envelope import (
9
9
  SCHEMA_VERSION,
10
10
  ContextualizerOutput,
11
- Repository,
12
11
  RunStatus,
13
12
  )
14
- from fluidattacks_core.contextualizes.observations import Observation, ObservationKind
15
13
  from fluidattacks_core.contextualizes.paths import (
16
14
  MAX_PATH_LENGTH,
17
15
  REPOSITORY_ROOT,
@@ -31,14 +29,12 @@ __all__ = [
31
29
  "REPOSITORY_ROOT",
32
30
  "SCHEMA_PATH",
33
31
  "SCHEMA_VERSION",
34
- "Component",
35
32
  "ComponentKind",
36
33
  "ContextualizerOutput",
37
34
  "Enrichment",
38
- "Observation",
39
- "ObservationKind",
35
+ "Entry",
36
+ "EntryKind",
40
37
  "RelativePath",
41
- "Repository",
42
38
  "RunStatus",
43
39
  "build_schema",
44
40
  "ensure_relative_path",
@@ -1,13 +1,9 @@
1
1
  from collections.abc import Iterable
2
2
  from enum import StrEnum
3
3
  from pathlib import PurePosixPath
4
- from typing import Annotated, ClassVar
5
4
 
6
5
  from fluidattacks_core.filesystem.defaults import MANIFEST_MARKERS, WORKSPACE_MARKERS
7
6
  from fluidattacks_core.filesystem.language import Language
8
- from pydantic import BaseModel, ConfigDict, Field, StringConstraints
9
-
10
- from fluidattacks_core.contextualizes.paths import RelativePath
11
7
 
12
8
 
13
9
  class ComponentKind(StrEnum):
@@ -99,13 +95,3 @@ class Enrichment(StrEnum):
99
95
  ABSENT = "absent"
100
96
  FAILED = "failed"
101
97
  PRESENT = "present"
102
-
103
-
104
- class Component(BaseModel):
105
- model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid", strict=True)
106
-
107
- path: RelativePath
108
- name: Annotated[str, StringConstraints(min_length=1, max_length=512)]
109
- kind: ComponentKind
110
- enrichment: Enrichment
111
- properties: dict[str, object] = Field(default_factory=dict)
@@ -0,0 +1,55 @@
1
+ from enum import StrEnum
2
+ from typing import Annotated, ClassVar
3
+
4
+ from pydantic import BaseModel, ConfigDict, Field, StringConstraints, model_validator
5
+
6
+ from fluidattacks_core.contextualizes.components import ComponentKind, Enrichment
7
+ from fluidattacks_core.contextualizes.paths import RelativePath
8
+
9
+
10
+ class EntryKind(StrEnum):
11
+ """What an entry is, not what ecosystem it belongs to."""
12
+
13
+ AI_MODEL = "ai_model"
14
+ COMPONENT = "component"
15
+ ENDPOINT = "endpoint"
16
+ PACKAGE = "package"
17
+
18
+
19
+ class Entry(BaseModel):
20
+ """Something found at a path; only a component says a part exists there."""
21
+
22
+ model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid", strict=True)
23
+
24
+ path: RelativePath
25
+ kind: EntryKind
26
+ name: Annotated[str, StringConstraints(min_length=1, max_length=512)] | None = None
27
+ ecosystem: ComponentKind | None = None
28
+ enrichment: Enrichment | None = None
29
+ line: Annotated[int, Field(ge=1)] | None = None
30
+ properties: dict[str, object] = Field(default_factory=dict)
31
+ seen_by: Annotated[str, StringConstraints(min_length=1, max_length=128)] | None = None
32
+
33
+ @model_validator(mode="after")
34
+ def _reject_fields_foreign_to_the_kind(self) -> "Entry":
35
+ if self.kind is EntryKind.COMPONENT:
36
+ missing = [
37
+ field
38
+ for field, value in (
39
+ ("name", self.name),
40
+ ("ecosystem", self.ecosystem),
41
+ ("enrichment", self.enrichment),
42
+ )
43
+ if value is None
44
+ ]
45
+ if missing:
46
+ msg = f"a component must declare {', '.join(missing)}"
47
+ raise ValueError(msg)
48
+ if self.line is not None:
49
+ msg = "a component must not carry a line"
50
+ raise ValueError(msg)
51
+ elif self.enrichment is not None:
52
+ msg = "only a component may carry enrichment"
53
+ raise ValueError(msg)
54
+
55
+ return self
@@ -4,10 +4,9 @@ from typing import Annotated, ClassVar
4
4
 
5
5
  from pydantic import BaseModel, ConfigDict, Field, StringConstraints, model_validator
6
6
 
7
- from fluidattacks_core.contextualizes.components import Component
8
- from fluidattacks_core.contextualizes.observations import Observation
7
+ from fluidattacks_core.contextualizes.entries import Entry, EntryKind
9
8
 
10
- SCHEMA_VERSION = 1
9
+ SCHEMA_VERSION = 2
11
10
 
12
11
 
13
12
  class RunStatus(StrEnum):
@@ -22,13 +21,6 @@ class RunStatus(StrEnum):
22
21
  PARTIAL = "partial"
23
22
 
24
23
 
25
- class Repository(BaseModel):
26
- model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid", strict=True)
27
-
28
- url: Annotated[str, StringConstraints(min_length=1, max_length=2048)]
29
- branch: Annotated[str, StringConstraints(min_length=1, max_length=512)] | None = None
30
-
31
-
32
24
  class ContextualizerOutput(BaseModel):
33
25
  """One contextualizer's report over one repository.
34
26
 
@@ -38,18 +30,20 @@ class ContextualizerOutput(BaseModel):
38
30
 
39
31
  model_config: ClassVar[ConfigDict] = ConfigDict(extra="forbid", strict=True)
40
32
 
41
- schema_version: int = Field(ge=1, le=SCHEMA_VERSION)
33
+ schema_version: int = Field(ge=SCHEMA_VERSION, le=SCHEMA_VERSION)
42
34
  producer: Annotated[str, StringConstraints(min_length=1, max_length=64)]
43
- repository: Repository
44
35
  status: RunStatus
45
- components: tuple[Component, ...] = ()
46
- observations: tuple[Observation, ...] = ()
36
+ entries: tuple[Entry, ...] = ()
37
+
38
+ @property
39
+ def components(self) -> tuple[Entry, ...]:
40
+ return tuple(entry for entry in self.entries if entry.kind is EntryKind.COMPONENT)
47
41
 
48
42
  @model_validator(mode="after")
49
43
  def _reject_duplicate_component_paths(self) -> "ContextualizerOutput":
50
44
  # Folded: two normalization forms are two files here, but a consumer
51
45
  # keying on the normalized path sees one, and loses an entry.
52
- paths = [unicodedata.normalize("NFC", component.path) for component in self.components]
46
+ paths = [unicodedata.normalize("NFC", entry.path) for entry in self.components]
53
47
  if len(set(paths)) != len(paths):
54
48
  msg = "components must not repeat a path"
55
49
  raise ValueError(msg)
@@ -15,9 +15,10 @@ _SCHEMA_DIALECT = "https://json-schema.org/draft/2020-12/schema"
15
15
  def build_schema() -> dict[str, object]:
16
16
  """Render the canonical JSONSchema the Rust producer validates against.
17
17
 
18
- Structural only. Neither `ensure_relative_path` nor the unique-component
19
- rule can be expressed here, so each producer implements both and the
20
- fixtures are what prove the implementations agree.
18
+ Structural only. The path grammar, component uniqueness and the rules
19
+ conditional on `kind` are not expressed here, so each producer
20
+ implements them and the fixtures are what prove the implementations
21
+ agree.
21
22
  """
22
23
  schema = ContextualizerOutput.model_json_schema()
23
24
 
@@ -1,41 +1,5 @@
1
1
  {
2
2
  "$defs": {
3
- "Component": {
4
- "additionalProperties": false,
5
- "properties": {
6
- "enrichment": {
7
- "$ref": "#/$defs/Enrichment"
8
- },
9
- "kind": {
10
- "$ref": "#/$defs/ComponentKind"
11
- },
12
- "name": {
13
- "maxLength": 512,
14
- "minLength": 1,
15
- "title": "Name",
16
- "type": "string"
17
- },
18
- "path": {
19
- "maxLength": 4096,
20
- "minLength": 1,
21
- "title": "Path",
22
- "type": "string"
23
- },
24
- "properties": {
25
- "additionalProperties": true,
26
- "title": "Properties",
27
- "type": "object"
28
- }
29
- },
30
- "required": [
31
- "path",
32
- "name",
33
- "kind",
34
- "enrichment"
35
- ],
36
- "title": "Component",
37
- "type": "object"
38
- },
39
3
  "ComponentKind": {
40
4
  "description": "Ecosystem of a component, decided by a filename, never by a model.\n\nSpelled as the platform's package ecosystem ids so a component joins the\npackage inventory without a translation table. `gradle` and `sbt` have no\nid of their own there; both resolve from the maven registry.",
41
5
  "enum": [
@@ -66,12 +30,34 @@
66
30
  "title": "Enrichment",
67
31
  "type": "string"
68
32
  },
69
- "Observation": {
33
+ "Entry": {
70
34
  "additionalProperties": false,
71
- "description": "Something found at a path, with no statement of which component owns it.\n\nUnattributed so a producer need not run the partitioner, and a\nrepartition re-attributes everything with no rewrite here.",
35
+ "description": "Something found at a path; only a component says a part exists there.",
72
36
  "properties": {
37
+ "ecosystem": {
38
+ "anyOf": [
39
+ {
40
+ "$ref": "#/$defs/ComponentKind"
41
+ },
42
+ {
43
+ "type": "null"
44
+ }
45
+ ],
46
+ "default": null
47
+ },
48
+ "enrichment": {
49
+ "anyOf": [
50
+ {
51
+ "$ref": "#/$defs/Enrichment"
52
+ },
53
+ {
54
+ "type": "null"
55
+ }
56
+ ],
57
+ "default": null
58
+ },
73
59
  "kind": {
74
- "$ref": "#/$defs/ObservationKind"
60
+ "$ref": "#/$defs/EntryKind"
75
61
  },
76
62
  "line": {
77
63
  "anyOf": [
@@ -86,6 +72,20 @@
86
72
  "default": null,
87
73
  "title": "Line"
88
74
  },
75
+ "name": {
76
+ "anyOf": [
77
+ {
78
+ "maxLength": 512,
79
+ "minLength": 1,
80
+ "type": "string"
81
+ },
82
+ {
83
+ "type": "null"
84
+ }
85
+ ],
86
+ "default": null,
87
+ "title": "Name"
88
+ },
89
89
  "path": {
90
90
  "maxLength": 4096,
91
91
  "minLength": 1,
@@ -116,48 +116,20 @@
116
116
  "path",
117
117
  "kind"
118
118
  ],
119
- "title": "Observation",
119
+ "title": "Entry",
120
120
  "type": "object"
121
121
  },
122
- "ObservationKind": {
122
+ "EntryKind": {
123
+ "description": "What an entry is, not what ecosystem it belongs to.",
123
124
  "enum": [
124
125
  "ai_model",
126
+ "component",
125
127
  "endpoint",
126
128
  "package"
127
129
  ],
128
- "title": "ObservationKind",
130
+ "title": "EntryKind",
129
131
  "type": "string"
130
132
  },
131
- "Repository": {
132
- "additionalProperties": false,
133
- "properties": {
134
- "branch": {
135
- "anyOf": [
136
- {
137
- "maxLength": 512,
138
- "minLength": 1,
139
- "type": "string"
140
- },
141
- {
142
- "type": "null"
143
- }
144
- ],
145
- "default": null,
146
- "title": "Branch"
147
- },
148
- "url": {
149
- "maxLength": 2048,
150
- "minLength": 1,
151
- "title": "Url",
152
- "type": "string"
153
- }
154
- },
155
- "required": [
156
- "url"
157
- ],
158
- "title": "Repository",
159
- "type": "object"
160
- },
161
133
  "RunStatus": {
162
134
  "description": "How much of the repository the run covered.\n\nA consumer reconciles by deleting what the output omits, so it must be\nable to refuse anything but `complete`.",
163
135
  "enum": [
@@ -169,25 +141,17 @@
169
141
  "type": "string"
170
142
  }
171
143
  },
172
- "$id": "https://fluidattacks.com/schemas/contextualizer_output/v1.json",
144
+ "$id": "https://fluidattacks.com/schemas/contextualizer_output/v2.json",
173
145
  "$schema": "https://json-schema.org/draft/2020-12/schema",
174
146
  "additionalProperties": false,
175
147
  "description": "One contextualizer's report over one repository.\n\nContextualizer vocabulary only: nothing about scope, groups or asset\ntypes, none of which is observable from a bare checkout.",
176
148
  "properties": {
177
- "components": {
178
- "default": [],
179
- "items": {
180
- "$ref": "#/$defs/Component"
181
- },
182
- "title": "Components",
183
- "type": "array"
184
- },
185
- "observations": {
149
+ "entries": {
186
150
  "default": [],
187
151
  "items": {
188
- "$ref": "#/$defs/Observation"
152
+ "$ref": "#/$defs/Entry"
189
153
  },
190
- "title": "Observations",
154
+ "title": "Entries",
191
155
  "type": "array"
192
156
  },
193
157
  "producer": {
@@ -196,12 +160,9 @@
196
160
  "title": "Producer",
197
161
  "type": "string"
198
162
  },
199
- "repository": {
200
- "$ref": "#/$defs/Repository"
201
- },
202
163
  "schema_version": {
203
- "maximum": 1,
204
- "minimum": 1,
164
+ "maximum": 2,
165
+ "minimum": 2,
205
166
  "title": "Schema Version",
206
167
  "type": "integer"
207
168
  },
@@ -212,7 +173,6 @@
212
173
  "required": [
213
174
  "schema_version",
214
175
  "producer",
215
- "repository",
216
176
  "status"
217
177
  ],
218
178
  "title": "ContextualizerOutput",
@@ -11,6 +11,6 @@
11
11
  layers =
12
12
  schema
13
13
  envelope
14
- observations
14
+ entries
15
15
  components
16
16
  paths
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "fluidattacks_core_contextualizes"
3
- version = "2.0.0"
3
+ version = "3.0.0"
4
4
  description = "Fluid Attacks Core Contextualizes Library"
5
5
  authors = [{ name = "Development", email = "development@fluidattacks.com" }]
6
6
  license = { text = "MPL-2.0" }
@@ -1,41 +1,39 @@
1
1
  {
2
- "schema_version": 1,
2
+ "schema_version": 2,
3
3
  "producer": "discovers",
4
- "repository": {
5
- "url": "https://example.com/acme/store",
6
- "branch": "main"
7
- },
8
4
  "status": "complete",
9
- "components": [],
10
- "observations": [
5
+ "entries": [
11
6
  {
12
7
  "path": "services/checkout/src/main/java/AssistantController.java",
13
8
  "kind": "endpoint",
14
9
  "line": 13,
15
10
  "properties": {
16
11
  "entry_point": "/api/v1/assistant/completions",
12
+ "framework": "java_spring_boot",
17
13
  "http_method": "POST"
18
14
  },
19
- "seen_by": "java_spring_boot"
15
+ "seen_by": "api_discovery"
20
16
  },
21
17
  {
22
18
  "path": "services/checkout/src/main/java/AssistantController.java",
23
19
  "kind": "ai_model",
24
- "line": 15,
20
+ "line": 42,
25
21
  "properties": {
26
- "model": "gpt-4o"
22
+ "model": "gpt-4o",
23
+ "sdk": "OpenAI"
27
24
  },
28
- "seen_by": "Spring AI"
25
+ "seen_by": "ai_models_discovery"
29
26
  },
30
27
  {
31
- "path": "web/src/api/AccountController.java",
28
+ "path": "web/src/api/account.ts",
32
29
  "kind": "endpoint",
33
- "line": 16,
30
+ "line": 15,
34
31
  "properties": {
35
- "entry_point": "/api/v1/accounts/{id}",
36
- "http_method": "GET"
32
+ "entry_point": "/proxy/{id}",
33
+ "framework": "express",
34
+ "http_method": "DELETE"
37
35
  },
38
- "seen_by": "java_spring_boot"
36
+ "seen_by": "api_discovery"
39
37
  }
40
38
  ]
41
39
  }
@@ -0,0 +1,50 @@
1
+ {
2
+ "schema_version": 2,
3
+ "producer": "explores",
4
+ "status": "complete",
5
+ "entries": [
6
+ {
7
+ "path": ".",
8
+ "kind": "component",
9
+ "name": "store",
10
+ "ecosystem": "unknown",
11
+ "enrichment": "absent",
12
+ "properties": {
13
+ "title": "Store monorepo",
14
+ "type": "unknown"
15
+ }
16
+ },
17
+ {
18
+ "path": "services/checkout",
19
+ "kind": "component",
20
+ "name": "checkout",
21
+ "ecosystem": "gradle",
22
+ "enrichment": "present",
23
+ "properties": {
24
+ "api_protocol": "rest",
25
+ "framework": "spring_boot",
26
+ "language": "Java",
27
+ "title": "Checkout service",
28
+ "type": "api"
29
+ }
30
+ },
31
+ {
32
+ "path": "web",
33
+ "kind": "component",
34
+ "name": "web",
35
+ "ecosystem": "npm",
36
+ "enrichment": "failed",
37
+ "properties": {
38
+ "title": "Storefront"
39
+ }
40
+ },
41
+ {
42
+ "path": "services/checkout/src/main/java/AssistantController.java",
43
+ "kind": "endpoint",
44
+ "properties": {
45
+ "entry_point": "/api/v1/assistant/completions",
46
+ "http_method": "POST"
47
+ }
48
+ }
49
+ ]
50
+ }
@@ -1,16 +1,13 @@
1
1
  {
2
- "schema_version": 1,
2
+ "schema_version": 2,
3
3
  "producer": "explores",
4
- "repository": {
5
- "url": "https://example.com/acme/store",
6
- "branch": "main"
7
- },
8
4
  "status": "complete",
9
- "components": [
5
+ "entries": [
10
6
  {
11
7
  "path": ".",
8
+ "kind": "component",
12
9
  "name": "store",
13
- "kind": "unknown",
10
+ "ecosystem": "unknown",
14
11
  "enrichment": "absent",
15
12
  "properties": {
16
13
  "title": "Store monorepo",
@@ -19,8 +16,9 @@
19
16
  },
20
17
  {
21
18
  "path": "services/checkout",
19
+ "kind": "component",
22
20
  "name": "checkout",
23
- "kind": "gradle",
21
+ "ecosystem": "gradle",
24
22
  "enrichment": "present",
25
23
  "properties": {
26
24
  "api_protocol": "rest",
@@ -32,23 +30,21 @@
32
30
  },
33
31
  {
34
32
  "path": "web",
33
+ "kind": "component",
35
34
  "name": "web",
36
- "kind": "npm",
35
+ "ecosystem": "npm",
37
36
  "enrichment": "failed",
38
37
  "properties": {
39
38
  "title": "Storefront"
40
39
  }
41
- }
42
- ],
43
- "observations": [
40
+ },
44
41
  {
45
- "path": "services/checkout/../../etc/passwd",
42
+ "path": "/services/checkout/src/main/java/AssistantController.java",
46
43
  "kind": "endpoint",
47
44
  "properties": {
48
45
  "entry_point": "/api/v1/assistant/completions",
49
46
  "http_method": "POST"
50
- },
51
- "seen_by": "explores"
47
+ }
52
48
  }
53
49
  ]
54
50
  }
@@ -1,16 +1,13 @@
1
1
  {
2
- "schema_version": 1,
2
+ "schema_version": 2,
3
3
  "producer": "explores",
4
- "repository": {
5
- "url": "https://example.com/acme/store",
6
- "branch": "main"
7
- },
8
4
  "status": "complete",
9
- "components": [
5
+ "entries": [
10
6
  {
11
7
  "path": ".",
8
+ "kind": "component",
12
9
  "name": "store",
13
- "kind": "unknown",
10
+ "ecosystem": "unknown",
14
11
  "enrichment": "absent",
15
12
  "properties": {
16
13
  "title": "Store monorepo",
@@ -19,8 +16,9 @@
19
16
  },
20
17
  {
21
18
  "path": "services/checkout",
19
+ "kind": "component",
22
20
  "name": "checkout",
23
- "kind": "gradle",
21
+ "ecosystem": "gradle",
24
22
  "enrichment": "present",
25
23
  "properties": {
26
24
  "api_protocol": "rest",
@@ -32,15 +30,14 @@
32
30
  },
33
31
  {
34
32
  "path": "web",
33
+ "kind": "component",
35
34
  "name": "web",
36
- "kind": "npm",
35
+ "ecosystem": "npm",
37
36
  "enrichment": "failed",
38
37
  "properties": {
39
38
  "title": "Storefront"
40
39
  }
41
- }
42
- ],
43
- "observations": [
40
+ },
44
41
  {
45
42
  "path": "services/checkout/src/main/java/AssistantController.java",
46
43
  "kind": "endpoint",
@@ -48,7 +45,6 @@
48
45
  "entry_point": "/api/v1/assistant/completions",
49
46
  "http_method": "POST"
50
47
  },
51
- "seen_by": "explores",
52
48
  "component": "services/checkout"
53
49
  }
54
50
  ]