Skip to content

Commit 0cfa261

Browse files
committed
Add JSON schema for Package and Vulnerability metadata
Signed-off-by: Keshav Priyadarshi <[email protected]>
1 parent a8b8653 commit 0cfa261

File tree

6 files changed

+388
-0
lines changed

6 files changed

+388
-0
lines changed
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
import json
11+
12+
from django.core.management.base import BaseCommand
13+
from pydantic.json_schema import GenerateJsonSchema
14+
15+
from fedcode import schemas
16+
17+
18+
class GenerateFederatedCodeJsonSchema(GenerateJsonSchema):
19+
def generate(self, schema, mode="validation"):
20+
json_schema = super().generate(schema, mode=mode)
21+
json_schema["$schema"] = self.schema_dialect
22+
return json_schema
23+
24+
25+
def get_ordered_schema(schema, schema_path):
26+
schema["$id"] = f"https://raw.githubusercontent.com/nexB/federatedcode/main/{schema_path}"
27+
desired_order = [
28+
"$schema",
29+
"$id",
30+
"title",
31+
"type",
32+
]
33+
34+
ordered_schema = {key: schema[key] for key in desired_order}
35+
ordered_schema.update({key: schema[key] for key in schema if key not in desired_order})
36+
return ordered_schema
37+
38+
39+
def gen_schema(model_schema, path):
40+
schema = model_schema.model_json_schema(schema_generator=GenerateFederatedCodeJsonSchema)
41+
ordered_schema = get_ordered_schema(schema=schema, schema_path=path)
42+
with open(path, "w", encoding="utf-8") as f:
43+
json.dump(ordered_schema, f, indent=2)
44+
45+
46+
class Command(BaseCommand):
47+
def handle(self, *args, **options):
48+
gen_schema(
49+
model_schema=schemas.Vulnerability,
50+
path="schemas/vulnerability.schema.json",
51+
)
52+
gen_schema(
53+
model_schema=schemas.Package,
54+
path="schemas/package.schema.json",
55+
)

fedcode/schemas.py

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
#
2+
# Copyright (c) nexB Inc. and others. All rights reserved.
3+
# VulnerableCode is a trademark of nexB Inc.
4+
# SPDX-License-Identifier: Apache-2.0
5+
# See http://www.apache.org/licenses/LICENSE-2.0 for the license text.
6+
# See https://github.com/nexB/vulnerablecode for support or download.
7+
# See https://aboutcode.org for more information about nexB OSS projects.
8+
#
9+
10+
from ninja import ModelSchema
11+
from typing import List
12+
13+
from fedcode import models
14+
15+
16+
class RemoteActor(ModelSchema):
17+
class Meta:
18+
model = models.RemoteActor
19+
fields = ["url", "username", "created_at", "updated_at"]
20+
21+
22+
class Repository(ModelSchema):
23+
"""
24+
A git repository used as a backing storage for Package and vulnerability data
25+
"""
26+
class Meta:
27+
model = models.Repository
28+
exclude = ["id", "admin"]
29+
30+
31+
class Vulnerability(ModelSchema):
32+
repo: Repository
33+
34+
class Meta:
35+
model = models.Vulnerability
36+
exclude = ["id"]
37+
38+
39+
class Reputation(ModelSchema):
40+
"""
41+
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like
42+
https://www.w3.org/ns/activitystreams#Dislike
43+
"""
44+
class Meta:
45+
model = models.Reputation
46+
fields = ["voter", "positive"]
47+
48+
49+
class Note(ModelSchema):
50+
"""
51+
A Note is a message send by a Person or Package.
52+
The content is either a plain text message or structured YAML.
53+
If the author is a Package actor then the content is always YAML
54+
If the author is a Person actor then the content is always plain text
55+
https://www.w3.org/TR/activitystreams-vocabulary/#dfn-note
56+
"""
57+
reputation: List[Reputation]
58+
reply_to: "Note"
59+
60+
class Meta:
61+
model = models.Note
62+
exclude = ["id"]
63+
64+
65+
Note.model_rebuild()
66+
67+
68+
class Package(ModelSchema):
69+
"""
70+
A software package identified by its package url ( PURL ) ignoring versions
71+
"""
72+
remote_actor: RemoteActor
73+
notes: List[Note]
74+
75+
class Meta:
76+
model = models.Package
77+
exclude = ["id", "service"]

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ django-environ==0.11.2
1919
django-oauth-toolkit==2.3.0
2020
django-rest-framework==0.1.0
2121
djangorestframework==3.14.0
22+
django-ninja==1.2.1
2223
docutils==0.20.1
2324
et-xmlfile==1.1.0
2425
exceptiongroup==1.1.1

schemas/package.schema.json

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,162 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://raw.githubusercontent.com/nexB/federatedcode/main/schemas/package.schema.json",
4+
"title": "Package",
5+
"type": "object",
6+
"$defs": {
7+
"Note": {
8+
"description": "A Note is a message send by a Person or Package.\nThe content is either a plain text message or structured YAML.\nIf the author is a Package actor then the content is always YAML\nIf the author is a Person actor then the content is always plain text\nhttps://www.w3.org/TR/activitystreams-vocabulary/#dfn-note",
9+
"properties": {
10+
"reputation": {
11+
"items": {
12+
"$ref": "#/$defs/Reputation"
13+
},
14+
"title": "Reputation",
15+
"type": "array"
16+
},
17+
"reply_to": {
18+
"$ref": "#/$defs/Note"
19+
},
20+
"acct": {
21+
"maxLength": 200,
22+
"title": "Acct",
23+
"type": "string"
24+
},
25+
"content": {
26+
"title": "Content",
27+
"type": "string"
28+
},
29+
"mediaType": {
30+
"default": "text/plain",
31+
"maxLength": 20,
32+
"title": "mediaType",
33+
"type": "string"
34+
},
35+
"created_at": {
36+
"description": "A field to track when notes are created",
37+
"format": "date-time",
38+
"title": "Created At",
39+
"type": "string"
40+
},
41+
"updated_at": {
42+
"description": "A field to track when notes are updated",
43+
"format": "date-time",
44+
"title": "Updated At",
45+
"type": "string"
46+
}
47+
},
48+
"required": [
49+
"reputation",
50+
"reply_to",
51+
"acct",
52+
"content",
53+
"created_at",
54+
"updated_at"
55+
],
56+
"title": "Note",
57+
"type": "object"
58+
},
59+
"RemoteActor": {
60+
"properties": {
61+
"url": {
62+
"anyOf": [
63+
{
64+
"type": "string"
65+
},
66+
{
67+
"type": "null"
68+
}
69+
],
70+
"default": null,
71+
"title": "Url"
72+
},
73+
"username": {
74+
"maxLength": 100,
75+
"title": "Username",
76+
"type": "string"
77+
},
78+
"created_at": {
79+
"description": "A field to track when remote actor are created",
80+
"format": "date-time",
81+
"title": "Created At",
82+
"type": "string"
83+
},
84+
"updated_at": {
85+
"description": "A field to track when remote actor are updated",
86+
"format": "date-time",
87+
"title": "Updated At",
88+
"type": "string"
89+
}
90+
},
91+
"required": [
92+
"username",
93+
"created_at",
94+
"updated_at"
95+
],
96+
"title": "RemoteActor",
97+
"type": "object"
98+
},
99+
"Reputation": {
100+
"description": "https://www.w3.org/TR/activitystreams-vocabulary/#dfn-like\nhttps://www.w3.org/ns/activitystreams#Dislike",
101+
"properties": {
102+
"voter": {
103+
"description": "security@vcio",
104+
"maxLength": 100,
105+
"title": "Voter",
106+
"type": "string"
107+
},
108+
"positive": {
109+
"default": true,
110+
"title": "Positive",
111+
"type": "boolean"
112+
}
113+
},
114+
"required": [
115+
"voter"
116+
],
117+
"title": "Reputation",
118+
"type": "object"
119+
}
120+
},
121+
"description": "A software package identified by its package url ( PURL ) ignoring versions",
122+
"properties": {
123+
"remote_actor": {
124+
"$ref": "#/$defs/RemoteActor"
125+
},
126+
"notes": {
127+
"items": {
128+
"$ref": "#/$defs/Note"
129+
},
130+
"title": "Notes",
131+
"type": "array"
132+
},
133+
"summary": {
134+
"description": "profile summary",
135+
"maxLength": 100,
136+
"title": "Summary",
137+
"type": "string"
138+
},
139+
"public_key": {
140+
"title": "Public Key",
141+
"type": "string"
142+
},
143+
"local": {
144+
"default": true,
145+
"title": "Local",
146+
"type": "boolean"
147+
},
148+
"purl": {
149+
"description": "PURL (no version) ex: @pkg:maven/org.apache.logging",
150+
"maxLength": 300,
151+
"title": "Purl",
152+
"type": "string"
153+
}
154+
},
155+
"required": [
156+
"remote_actor",
157+
"notes",
158+
"summary",
159+
"public_key",
160+
"purl"
161+
]
162+
}

schemas/vulnerability.schema.json

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
{
2+
"$schema": "https://json-schema.org/draft/2020-12/schema",
3+
"$id": "https://raw.githubusercontent.com/nexB/federatedcode/main/schemas/vulnerability.schema.json",
4+
"title": "Vulnerability",
5+
"type": "object",
6+
"$defs": {
7+
"Repository": {
8+
"description": "A git repository used as a backing storage for Package and vulnerability data",
9+
"properties": {
10+
"url": {
11+
"description": "Git Repository url ex: https://github.com/nexB/vulnerablecode-data",
12+
"title": "Url",
13+
"type": "string"
14+
},
15+
"path": {
16+
"description": "path of the repository",
17+
"maxLength": 200,
18+
"title": "Path",
19+
"type": "string"
20+
},
21+
"remote_url": {
22+
"anyOf": [
23+
{
24+
"maxLength": 300,
25+
"type": "string"
26+
},
27+
{
28+
"type": "null"
29+
}
30+
],
31+
"default": null,
32+
"description": "the url of the repository if this repository is remote",
33+
"title": "Remote Url"
34+
},
35+
"last_imported_commit": {
36+
"anyOf": [
37+
{
38+
"maxLength": 64,
39+
"type": "string"
40+
},
41+
{
42+
"type": "null"
43+
}
44+
],
45+
"default": null,
46+
"title": "Last Imported Commit"
47+
},
48+
"created_at": {
49+
"description": "A field to track when repository are created",
50+
"format": "date-time",
51+
"title": "Created At",
52+
"type": "string"
53+
},
54+
"updated_at": {
55+
"description": "A field to track when repository are updated",
56+
"format": "date-time",
57+
"title": "Updated At",
58+
"type": "string"
59+
}
60+
},
61+
"required": [
62+
"url",
63+
"path",
64+
"created_at",
65+
"updated_at"
66+
],
67+
"title": "Repository",
68+
"type": "object"
69+
}
70+
},
71+
"properties": {
72+
"repo": {
73+
"$ref": "#/$defs/Repository"
74+
},
75+
"remote_url": {
76+
"anyOf": [
77+
{
78+
"maxLength": 300,
79+
"type": "string"
80+
},
81+
{
82+
"type": "null"
83+
}
84+
],
85+
"default": null,
86+
"title": "Remote Url"
87+
}
88+
},
89+
"required": [
90+
"repo"
91+
]
92+
}

0 commit comments

Comments
 (0)