mirror of
https://github.com/anchore/syft.git
synced 2025-11-17 16:33:21 +01:00
Merge pull request #276 from anchore/generate-json-schema
Generate json schema from struct definitions
This commit is contained in:
commit
c42b036f46
20
Makefile
20
Makefile
@ -153,17 +153,9 @@ fixtures:
|
|||||||
cd syft/cataloger/java/test-fixtures/java-builds && make
|
cd syft/cataloger/java/test-fixtures/java-builds && make
|
||||||
|
|
||||||
.PHONY: generate-json-schema
|
.PHONY: generate-json-schema
|
||||||
generate-json-schema: clean-json-schema-examples integration ## Generate a new json schema for the json presenter, derived from integration test cases
|
generate-json-schema: ## Generate a new json schema
|
||||||
docker run \
|
cd schema/json
|
||||||
-i \
|
go run generate.go
|
||||||
--rm \
|
|
||||||
-v $(shell pwd)/schema/json:/work \
|
|
||||||
-w /work \
|
|
||||||
python:3.8 \
|
|
||||||
bash -x -c "\
|
|
||||||
pip install -r requirements.txt && \
|
|
||||||
python generate.py \
|
|
||||||
"
|
|
||||||
|
|
||||||
.PHONY: clear-test-cache
|
.PHONY: clear-test-cache
|
||||||
clear-test-cache: ## Delete all test cache (built docker image tars)
|
clear-test-cache: ## Delete all test cache (built docker image tars)
|
||||||
@ -288,7 +280,7 @@ release: clean-dist ci-bootstrap-mac changelog-release ## Build and publish fina
|
|||||||
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
|
.github/scripts/update-version-file.sh "$(DISTDIR)" "$(VERSION)"
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean: clean-dist clean-snapshot clean-json-schema-examples ## Remove previous builds and result reports
|
clean: clean-dist clean-snapshot ## Remove previous builds and result reports
|
||||||
rm -rf $(RESULTSDIR)/*
|
rm -rf $(RESULTSDIR)/*
|
||||||
|
|
||||||
.PHONY: clean-snapshot
|
.PHONY: clean-snapshot
|
||||||
@ -298,7 +290,3 @@ clean-snapshot:
|
|||||||
.PHONY: clean-dist
|
.PHONY: clean-dist
|
||||||
clean-dist:
|
clean-dist:
|
||||||
rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml
|
rm -rf $(DISTDIR) $(TEMPDIR)/goreleaser.yaml
|
||||||
|
|
||||||
.PHONY: clean-json-schema-examples
|
|
||||||
clean-json-schema-examples:
|
|
||||||
rm -f schema/json/examples/*
|
|
||||||
|
|||||||
1
go.mod
1
go.mod
@ -4,6 +4,7 @@ go 1.14
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/adrg/xdg v0.2.1
|
github.com/adrg/xdg v0.2.1
|
||||||
|
github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921
|
||||||
github.com/anchore/go-rpmdb v0.0.0-20201106153645-0043963c2e12
|
github.com/anchore/go-rpmdb v0.0.0-20201106153645-0043963c2e12
|
||||||
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
github.com/anchore/go-testutils v0.0.0-20200925183923-d5f45b0d3c04
|
||||||
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
github.com/anchore/go-version v1.2.2-0.20200701162849-18adb9c92b9b
|
||||||
|
|||||||
5
go.sum
5
go.sum
@ -119,6 +119,8 @@ github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdko
|
|||||||
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
github.com/StackExchange/wmi v0.0.0-20180116203802-5d049714c4a6/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg=
|
||||||
github.com/adrg/xdg v0.2.1 h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=
|
github.com/adrg/xdg v0.2.1 h1:VSVdnH7cQ7V+B33qSJHTCRlNgra1607Q8PzEmnvb2Ic=
|
||||||
github.com/adrg/xdg v0.2.1/go.mod h1:ZuOshBmzV4Ta+s23hdfFZnBsdzmoR3US0d7ErpqSbTQ=
|
github.com/adrg/xdg v0.2.1/go.mod h1:ZuOshBmzV4Ta+s23hdfFZnBsdzmoR3US0d7ErpqSbTQ=
|
||||||
|
github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921 h1:T3+cD5fYvuH36h7EZq+TDpm+d8a6FSD4pQsbmuGGQ8o=
|
||||||
|
github.com/alecthomas/jsonschema v0.0.0-20200530073317-71f438968921/go.mod h1:/n6+1/DWPltRLWL/VKyUxg6tzsl5kHUCcraimt4vr60=
|
||||||
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
|
github.com/alecthomas/kingpin v2.2.6+incompatible/go.mod h1:59OFYbFVLKQKq+mqrL6Rw5bR0c3ACQaawgXx0QYndlE=
|
||||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||||
@ -501,6 +503,8 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p
|
|||||||
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc=
|
||||||
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI=
|
||||||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
|
||||||
|
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0 h1:i462o439ZjprVSFSZLZxcsoAe592sZB1rci2Z8j4wdk=
|
||||||
|
github.com/iancoleman/orderedmap v0.0.0-20190318233801-ac98e3ecb4b0/go.mod h1:N0Wam8K1arqPXNWjMo21EXnBPOPp36vB07FNRdD2geA=
|
||||||
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
|
||||||
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
github.com/imdario/mergo v0.3.8/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
|
||||||
@ -787,6 +791,7 @@ github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoH
|
|||||||
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v0.0.0-20151208002404-e3a8ff8ce365/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
|
github.com/stretchr/testify v1.3.1-0.20190311161405-34c6fa2dc709/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
|
|||||||
@ -1,9 +0,0 @@
|
|||||||
## Updating the JSON schema
|
|
||||||
Today the JSON schema is generated from integration test data. Specifically, when integration tests are run, the `/schema/json/examples` directory is populated with syft JSON output data. This examples directory is used to drive automatically generating the JSON schema.
|
|
||||||
The caveats with this approach is:
|
|
||||||
1) the JSON schema is only as good as the examples provided
|
|
||||||
2) there is an integration test that ensures that the JSON schema is valid relative to what the code currently generates.
|
|
||||||
This means to update the JSON schema you need to
|
|
||||||
1) Open up `test/integration/json_schema_test.go` and comment out invocations of the `validateAgainstV1Schema` function.
|
|
||||||
2) From the root of the repo run `generate-json-schema`. Now there should be a new schema generated at `/schema/json/schema.json`
|
|
||||||
3) Uncomment the `validateAgainstV1Schema` function.
|
|
||||||
1
schema/json/.gitignore
vendored
1
schema/json/.gitignore
vendored
@ -1 +0,0 @@
|
|||||||
examples/
|
|
||||||
35
schema/json/generate.go
Normal file
35
schema/json/generate.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/alecthomas/jsonschema"
|
||||||
|
jsonPresenter "github.com/anchore/syft/syft/presenter/json"
|
||||||
|
)
|
||||||
|
|
||||||
|
/*
|
||||||
|
This method of creating the JSON schema only captures strongly typed fields for the purpose of integrations between syft
|
||||||
|
JSON output and integrations. The downside to this approach is that any values and types used on weakly typed fields
|
||||||
|
are not captured (empty interfaces). This means that pkg.Package.Metadata is not validated at this time. This approach
|
||||||
|
can be extended to include specific package metadata struct shapes in the future.
|
||||||
|
*/
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
j := jsonschema.Reflect(&jsonPresenter.Document{})
|
||||||
|
filename := "schema.json"
|
||||||
|
fh, err := os.OpenFile("schema.json", os.O_RDWR|os.O_CREATE, 0755)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
enc := json.NewEncoder(fh)
|
||||||
|
// prevent > and < from being escaped in the payload
|
||||||
|
enc.SetEscapeHTML(false)
|
||||||
|
enc.SetIndent("", " ")
|
||||||
|
err = enc.Encode(&j)
|
||||||
|
if err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
fmt.Printf("wrote new schema to %q\n", filename)
|
||||||
|
}
|
||||||
@ -1,30 +0,0 @@
|
|||||||
#!/usr/env/bin python3
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import json
|
|
||||||
|
|
||||||
from genson import SchemaBuilder
|
|
||||||
|
|
||||||
EXAMPLES_DIR = "examples/"
|
|
||||||
OUTPUT = "schema.json"
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
builder = SchemaBuilder()
|
|
||||||
|
|
||||||
print("Generating new Syft json schema...")
|
|
||||||
for filepath in glob.glob(os.path.join(EXAMPLES_DIR, '*.json')):
|
|
||||||
with open(filepath, 'r') as f:
|
|
||||||
print(f" adding {filepath}")
|
|
||||||
builder.add_object(json.loads(f.read()))
|
|
||||||
|
|
||||||
print("Building schema...")
|
|
||||||
new_schema = builder.to_schema()
|
|
||||||
with open(OUTPUT, 'w') as f:
|
|
||||||
f.write(json.dumps(new_schema, sort_keys=True, indent=4))
|
|
||||||
|
|
||||||
print(f"New schema written to '{OUTPUT}'")
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@ -1 +0,0 @@
|
|||||||
genson
|
|
||||||
@ -1,455 +1,165 @@
|
|||||||
{
|
{
|
||||||
"$schema": "http://json-schema.org/schema#",
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Document",
|
||||||
|
"definitions": {
|
||||||
|
"Descriptor": {
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Distribution": {
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version",
|
||||||
|
"idLike"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"idLike": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Document": {
|
||||||
|
"required": [
|
||||||
|
"artifacts",
|
||||||
|
"source",
|
||||||
|
"distro",
|
||||||
|
"descriptor"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
"artifacts": {
|
"artifacts": {
|
||||||
"items": {
|
"items": {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Package"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"source": {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Source"
|
||||||
|
},
|
||||||
|
"distro": {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Distribution"
|
||||||
|
},
|
||||||
|
"descriptor": {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Descriptor"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Location": {
|
||||||
|
"required": [
|
||||||
|
"path"
|
||||||
|
],
|
||||||
"properties": {
|
"properties": {
|
||||||
|
"path": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"layerID": {
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Package": {
|
||||||
|
"required": [
|
||||||
|
"name",
|
||||||
|
"version",
|
||||||
|
"type",
|
||||||
|
"foundBy",
|
||||||
|
"locations",
|
||||||
|
"licenses",
|
||||||
|
"language",
|
||||||
|
"cpes",
|
||||||
|
"purl",
|
||||||
|
"metadataType"
|
||||||
|
],
|
||||||
|
"properties": {
|
||||||
|
"name": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"version": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
"foundBy": {
|
"foundBy": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
|
"locations": {
|
||||||
|
"items": {
|
||||||
|
"$schema": "http://json-schema.org/draft-04/schema#",
|
||||||
|
"$ref": "#/definitions/Location"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
|
"licenses": {
|
||||||
|
"items": {
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"type": "array"
|
||||||
|
},
|
||||||
"language": {
|
"language": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"licenses": {
|
"cpes": {
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"locations": {
|
|
||||||
"items": {
|
|
||||||
"properties": {
|
|
||||||
"layerID": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"path"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"metadata": {
|
|
||||||
"properties": {
|
|
||||||
"architecture": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"author": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"authorEmail": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"description": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"epoch": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"files": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "null"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"items": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"checksum": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"digest": {
|
|
||||||
"properties": {
|
|
||||||
"algorithm": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"value": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"algorithm",
|
|
||||||
"value"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"ownerGid": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"ownerUid": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"permissions": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"path"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"gitCommitOfApkPort": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"homepage": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"installedSize": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"license": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"licenses": {
|
|
||||||
"items": {
|
"items": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"type": "array"
|
"type": "array"
|
||||||
},
|
},
|
||||||
"maintainer": {
|
"purl": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"manifest": {
|
|
||||||
"properties": {
|
|
||||||
"main": {
|
|
||||||
"properties": {
|
|
||||||
"Archiver-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Build-Jdk": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Built-By": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Created-By": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Extension-Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Group-Id": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Hudson-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Implementation-Title": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Implementation-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Jenkins-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Long-Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Main-Class": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Manifest-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Minimum-Java-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-Dependencies": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-Developers": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-License-Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-License-Url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-ScmUrl": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Plugin-Version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Short-Name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"Specification-Title": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"Archiver-Version",
|
|
||||||
"Build-Jdk",
|
|
||||||
"Built-By",
|
|
||||||
"Created-By",
|
|
||||||
"Manifest-Version"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"main"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"originPackage": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"package": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"platform": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"pomProperties": {
|
|
||||||
"properties": {
|
|
||||||
"artifactId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"extraFields": {
|
|
||||||
"type": "null"
|
|
||||||
},
|
|
||||||
"groupId": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"path": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"artifactId",
|
|
||||||
"extraFields",
|
|
||||||
"groupId",
|
|
||||||
"name",
|
|
||||||
"path",
|
|
||||||
"version"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"pullChecksum": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"pullDependencies": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"release": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sitePackagesRootPath": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"sourceRpm": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"topLevelPackages": {
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"url": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"vendor": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"virtualPath": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"metadataType": {
|
"metadataType": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
},
|
},
|
||||||
"name": {
|
"metadata": {
|
||||||
"type": "string"
|
"additionalProperties": true
|
||||||
},
|
|
||||||
"type": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"additionalProperties": false,
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"Source": {
|
||||||
"required": [
|
"required": [
|
||||||
"foundBy",
|
|
||||||
"language",
|
|
||||||
"licenses",
|
|
||||||
"locations",
|
|
||||||
"metadataType",
|
|
||||||
"name",
|
|
||||||
"type",
|
"type",
|
||||||
"version"
|
"target"
|
||||||
],
|
],
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"descriptor": {
|
|
||||||
"properties": {
|
"properties": {
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"name",
|
|
||||||
"version"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"distro": {
|
|
||||||
"properties": {
|
|
||||||
"idLike": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"name": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"version": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"idLike",
|
|
||||||
"name",
|
|
||||||
"version"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"source": {
|
|
||||||
"properties": {
|
|
||||||
"target": {
|
|
||||||
"anyOf": [
|
|
||||||
{
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"properties": {
|
|
||||||
"digest": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"layers": {
|
|
||||||
"items": {
|
|
||||||
"properties": {
|
|
||||||
"digest": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"mediaType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "integer"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"digest",
|
|
||||||
"mediaType",
|
|
||||||
"size"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"mediaType": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"scope": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"size": {
|
|
||||||
"type": "integer"
|
|
||||||
},
|
|
||||||
"tags": {
|
|
||||||
"items": {
|
|
||||||
"type": "string"
|
|
||||||
},
|
|
||||||
"type": "array"
|
|
||||||
},
|
|
||||||
"userInput": {
|
|
||||||
"type": "string"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"required": [
|
|
||||||
"digest",
|
|
||||||
"layers",
|
|
||||||
"mediaType",
|
|
||||||
"scope",
|
|
||||||
"size",
|
|
||||||
"tags",
|
|
||||||
"userInput"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
"type": {
|
"type": {
|
||||||
"type": "string"
|
"type": "string"
|
||||||
|
},
|
||||||
|
"target": {
|
||||||
|
"additionalProperties": true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"additionalProperties": false,
|
||||||
"target",
|
|
||||||
"type"
|
|
||||||
],
|
|
||||||
"type": "object"
|
"type": "object"
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
"required": [
|
|
||||||
"artifacts",
|
|
||||||
"descriptor",
|
|
||||||
"distro",
|
|
||||||
"source"
|
|
||||||
],
|
|
||||||
"type": "object"
|
|
||||||
}
|
}
|
||||||
@ -24,7 +24,7 @@ type PackageJSON struct {
|
|||||||
Latest []string `json:"latest"`
|
Latest []string `json:"latest"`
|
||||||
Author Author `json:"author"`
|
Author Author `json:"author"`
|
||||||
License json.RawMessage `json:"license"`
|
License json.RawMessage `json:"license"`
|
||||||
Licenses []license `json:"licenses,omitempty"`
|
Licenses []license `json:"licenses"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Homepage string `json:"homepage"`
|
Homepage string `json:"homepage"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
|
|||||||
@ -30,7 +30,7 @@ type packageBasicMetadata struct {
|
|||||||
// packageCustomMetadata contains ambiguous values (type-wise) from pkg.Package.
|
// packageCustomMetadata contains ambiguous values (type-wise) from pkg.Package.
|
||||||
type packageCustomMetadata struct {
|
type packageCustomMetadata struct {
|
||||||
MetadataType pkg.MetadataType `json:"metadataType"`
|
MetadataType pkg.MetadataType `json:"metadataType"`
|
||||||
Metadata interface{} `json:"metadata,omitempty"`
|
Metadata interface{} `json:"metadata"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// packageMetadataUnpacker is all values needed from Package to disambiguate ambiguous fields during json unmarshaling.
|
// packageMetadataUnpacker is all values needed from Package to disambiguate ambiguous fields during json unmarshaling.
|
||||||
@ -45,14 +45,27 @@ func NewPackage(p *pkg.Package) (Package, error) {
|
|||||||
for i, c := range p.CPEs {
|
for i, c := range p.CPEs {
|
||||||
cpes[i] = c.BindToFmtString()
|
cpes[i] = c.BindToFmtString()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ensure collections are never nil for presentation reasons
|
||||||
|
|
||||||
|
var locations = make([]source.Location, 0)
|
||||||
|
if p.Locations != nil {
|
||||||
|
locations = p.Locations
|
||||||
|
}
|
||||||
|
|
||||||
|
var licenses = make([]string, 0)
|
||||||
|
if p.Licenses != nil {
|
||||||
|
licenses = p.Licenses
|
||||||
|
}
|
||||||
|
|
||||||
return Package{
|
return Package{
|
||||||
packageBasicMetadata: packageBasicMetadata{
|
packageBasicMetadata: packageBasicMetadata{
|
||||||
Name: p.Name,
|
Name: p.Name,
|
||||||
Version: p.Version,
|
Version: p.Version,
|
||||||
Type: p.Type,
|
Type: p.Type,
|
||||||
FoundBy: p.FoundBy,
|
FoundBy: p.FoundBy,
|
||||||
Locations: p.Locations,
|
Locations: locations,
|
||||||
Licenses: p.Licenses,
|
Licenses: licenses,
|
||||||
Language: p.Language,
|
Language: p.Language,
|
||||||
CPEs: cpes,
|
CPEs: cpes,
|
||||||
PURL: p.PURL,
|
PURL: p.PURL,
|
||||||
|
|||||||
@ -39,7 +39,7 @@
|
|||||||
"path": "/some/path/pkg1"
|
"path": "/some/path/pkg1"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"licenses": null,
|
"licenses": [],
|
||||||
"language": "",
|
"language": "",
|
||||||
"cpes": [
|
"cpes": [
|
||||||
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
|
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
|
||||||
|
|||||||
@ -41,7 +41,7 @@
|
|||||||
"layerID": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf"
|
"layerID": "sha256:da21056e7bf4308ecea0c0836848a7fe92f38fdcf35bc09ee6d98e7ab7beeebf"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"licenses": null,
|
"licenses": [],
|
||||||
"language": "",
|
"language": "",
|
||||||
"cpes": [
|
"cpes": [
|
||||||
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
|
"cpe:2.3:*:some:package:2:*:*:*:*:*:*:*"
|
||||||
|
|||||||
@ -82,6 +82,11 @@ func TestCatalogFromJSON(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, d := range deep.Equal(a, e) {
|
for _, d := range deep.Equal(a, e) {
|
||||||
|
// ignore errors for empty collections vs nil for select fields
|
||||||
|
// TODO: this is brittle, but not dangerously so. We should still find a better way to do this.
|
||||||
|
if d == "Licenses: [] != <nil slice>" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
t.Errorf(" package %d (name=%s) diff: %+v", i, e.Name, d)
|
t.Errorf(" package %d (name=%s) diff: %+v", i, e.Name, d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,6 @@ package integration
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
|
||||||
"os/exec"
|
"os/exec"
|
||||||
"path"
|
"path"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@ -20,7 +19,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
const jsonSchemaPath = "schema/json"
|
const jsonSchemaPath = "schema/json"
|
||||||
const jsonSchemaExamplesPath = jsonSchemaPath + "/examples"
|
|
||||||
|
|
||||||
func repoRoot(t *testing.T) string {
|
func repoRoot(t *testing.T) string {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
@ -54,11 +52,6 @@ func validateAgainstV1Schema(t *testing.T, json string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope source.Source, prefix string) {
|
func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope source.Source, prefix string) {
|
||||||
// make the json output example dir if it does not exist
|
|
||||||
absJsonSchemaExamplesPath := path.Join(repoRoot(t), jsonSchemaExamplesPath)
|
|
||||||
if _, err := os.Stat(absJsonSchemaExamplesPath); os.IsNotExist(err) {
|
|
||||||
os.Mkdir(absJsonSchemaExamplesPath, 0755)
|
|
||||||
}
|
|
||||||
|
|
||||||
output := bytes.NewBufferString("")
|
output := bytes.NewBufferString("")
|
||||||
|
|
||||||
@ -77,21 +70,6 @@ func testJsonSchema(t *testing.T, catalog *pkg.Catalog, theScope source.Source,
|
|||||||
t.Fatalf("unable to present: %+v", err)
|
t.Fatalf("unable to present: %+v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// we use the examples dir as a way to use integration tests to drive what valid examples are in case we
|
|
||||||
// want to update the json schema. We do not want to validate the output of the presentation format as the
|
|
||||||
// contents may change regularly, making the integration tests brittle.
|
|
||||||
testFileName := prefix + "_" + path.Base(t.Name()) + ".json"
|
|
||||||
testFilePath := path.Join(absJsonSchemaExamplesPath, testFileName)
|
|
||||||
|
|
||||||
fh, err := os.OpenFile(testFilePath, os.O_WRONLY|os.O_CREATE, 0644)
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to open json example path: %+v", err)
|
|
||||||
}
|
|
||||||
_, err = fh.WriteString(output.String())
|
|
||||||
if err != nil {
|
|
||||||
t.Fatalf("unable to write json example: %+v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
validateAgainstV1Schema(t, output.String())
|
validateAgainstV1Schema(t, output.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user