├── CODEOWNERS ├── .golangci.yml ├── .gitpod.yml ├── NOTICE ├── testdata ├── valid-empty-components.json ├── valid-empty-components.xml ├── snapshots │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-empty-components.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-empty-components.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-timestamp.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-timestamp.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-minimal-viable.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-minimal-viable.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-license.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-license.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-service-empty-objects.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-author.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-author.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-swhid.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-supplier.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-omniborId.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-ref.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacturer.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-service-empty-objects.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-supplier.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-swid.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-license-id.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-lifecycle.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-license-expression.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacture.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-swid.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacturer.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-swhid.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-license-name.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-lifecycle.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-omniborId.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacture.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-tool-deprecated.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-authors.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-manufacturer.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-manufacturer.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-assembly.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-definitions.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-ref.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-authors.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-tool-deprecated.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-definitions.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-assembly.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-dependency.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-types.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-license-id.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-license-expression.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-types.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-license-name.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-external-reference.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-external-reference.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-metadata-tool.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-swid-full.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-tool.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-swid-full.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-properties.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-component-hashes.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-properties.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-license-licensing.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-license-licensing.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-compositions.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-component-hashes.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-compositions.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-service.xml │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-patch.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-patch.json │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-service.json │ ├── cyclonedx-go-TestXmlBOMEncoder_EncodeVersion-func1-1.0.bom.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-annotation.json │ ├── cyclonedx-go-TestRoundTripXML-func1-valid-annotation.xml │ ├── cyclonedx-go-TestRoundTripJSON-func1-valid-evidence.json │ └── cyclonedx-go-TestRoundTripXML-func1-valid-evidence.xml ├── valid-metadata-timestamp.json ├── valid-metadata-timestamp.xml ├── valid-minimal-viable.json ├── valid-minimal-viable.xml ├── valid-metadata-license.json ├── valid-metadata-license.xml ├── valid-component-swhid.json ├── valid-metadata-author.json ├── valid-component-omniborId.json ├── valid-component-ref.json ├── valid-metadata-author.xml ├── valid-metadata-supplier.json ├── valid-lifecycle.json ├── valid-license-id.json ├── valid-service-empty-objects.json ├── valid-license-expression.json ├── valid-metadata-supplier.xml ├── valid-component-swid.xml ├── valid-component-swid.json ├── valid-metadata-manufacturer.json ├── valid-metadata-manufacturer.xml ├── valid-service-empty-objects.xml ├── valid-component-swhid.xml ├── valid-license-name.json ├── valid-metadata-manufacture.xml ├── valid-metadata-manufacture.json ├── valid-component-manufacturer.xml ├── valid-component-omniborId.xml ├── valid-component-authors.json ├── valid-component-manufacturer.json ├── valid-assembly.json ├── valid-lifecycle.xml ├── valid-definitions.json ├── valid-metadata-tool-deprecated.json ├── valid-metadata-tool-deprecated.xml ├── valid-component-ref.xml ├── valid-component-authors.xml ├── valid-definitions.xml ├── valid-dependency.json ├── valid-assembly.xml ├── valid-dependency.xml ├── valid-component-types.json ├── valid-external-reference.json ├── valid-license-expression.xml ├── valid-license-id.xml ├── valid-license-name.xml ├── valid-metadata-tool.json ├── valid-component-types.xml ├── valid-component-swid-full.xml ├── valid-external-reference.xml ├── valid-component-swid-full.json ├── valid-metadata-tool.xml ├── valid-license-licensing.json ├── valid-properties.xml ├── valid-properties.json ├── valid-component-hashes.xml ├── valid-compositions.json ├── valid-license-licensing.xml ├── valid-component-hashes.json ├── valid-compositions.xml ├── valid-patch.json ├── valid-service.json ├── valid-service.xml ├── valid-annotation.json ├── valid-patch.xml ├── valid-evidence.json └── valid-annotation.xml ├── Makefile ├── .gitignore ├── go.mod ├── .github ├── dependabot.yml └── workflows │ ├── goreleaser.yml │ └── ci.yml ├── Dockerfile.gitpod ├── validate_test.go ├── .goreleaser.yml ├── .licenserc.yml ├── copy.go ├── cyclonedx_string.go ├── link_example_test.go ├── decode.go ├── .idea └── icon.svg ├── validate_json_test.go ├── cyclonedx_test.go ├── validate_xml_test.go ├── go.sum ├── roundtrip_test.go ├── decode_test.go ├── README.md └── encode.go /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @CycloneDX/go-maintainers 2 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | linters: 2 | enable: 3 | - asciicheck 4 | - errorlint 5 | - gofmt 6 | - gosec 7 | - wastedassign 8 | -------------------------------------------------------------------------------- /.gitpod.yml: -------------------------------------------------------------------------------- 1 | image: 2 | file: Dockerfile.gitpod 3 | 4 | tasks: 5 | - init: make build 6 | 7 | vscode: 8 | extensions: 9 | - golang.Go -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | CycloneDX Go 2 | Copyright (c) OWASP Foundation 3 | 4 | This product includes software developed by the 5 | CycloneDX community (https://cyclonedx.org/). -------------------------------------------------------------------------------- /testdata/valid-empty-components.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /testdata/valid-empty-components.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-empty-components.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-empty-components.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [] 7 | } 8 | 9 | -------------------------------------------------------------------------------- /testdata/valid-metadata-timestamp.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "timestamp": "2020-04-13T20:20:39+00:00" 8 | }, 9 | "components": [] 10 | } 11 | -------------------------------------------------------------------------------- /testdata/valid-metadata-timestamp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2020-04-07T07:01:00Z 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /testdata/valid-minimal-viable.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-library" 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | go build -v 3 | .PHONY: build 4 | 5 | test: 6 | go test -v -cover 7 | .PHONY: test 8 | 9 | clean: 10 | go clean 11 | .PHONY: clean 12 | 13 | generate: 14 | go generate 15 | .PHONY: generate 16 | 17 | lint: 18 | golangci-lint run 19 | .PHONY: lint 20 | 21 | all: clean build test 22 | .PHONY: all 23 | -------------------------------------------------------------------------------- /testdata/valid-minimal-viable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-timestamp.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 2020-04-07T07:01:00Z 5 | 6 | 7 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-timestamp.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "timestamp": "2020-04-13T20:20:39+00:00" 8 | }, 9 | "components": [] 10 | } 11 | 12 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-minimal-viable.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-library" 10 | } 11 | ] 12 | } 13 | 14 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-minimal-viable.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /testdata/valid-metadata-license.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "licenses": [ 8 | { 9 | "license": { 10 | "id": "Apache-2.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "components": [] 16 | } 17 | -------------------------------------------------------------------------------- /testdata/valid-metadata-license.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Apache-2.0 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-license.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Apache-2.0 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-license.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "licenses": [ 8 | { 9 | "license": { 10 | "id": "Apache-2.0" 11 | } 12 | } 13 | ] 14 | }, 15 | "components": [] 16 | } 17 | 18 | -------------------------------------------------------------------------------- /testdata/valid-component-swhid.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swhid": ["swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2"] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /testdata/valid-metadata-author.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "authors": [ 8 | { 9 | "bom-ref": "author-1", 10 | "name": "Samantha Wright", 11 | "email": "samantha.wright@example.com", 12 | "phone": "800-555-1212" 13 | } 14 | ] 15 | }, 16 | "components": [] 17 | } 18 | -------------------------------------------------------------------------------- /testdata/valid-component-omniborId.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "omniborId": ["gitoid:blob:sha1:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3"] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, built with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | 14 | # Dependency directories (remove the comment below to include it) 15 | # vendor/ 16 | 17 | # IntelliJ / GoLand 18 | .idea/* 19 | !.idea/icon.svg 20 | *.iml 21 | 22 | # SBOMs generated during CI 23 | /bom.json 24 | /bom.xml 25 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-service-empty-objects.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Stock ticker service 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/valid-component-ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "bom-ref": "123", 10 | "name": "acme-library", 11 | "version": "1.0.0" 12 | }, 13 | { 14 | "type": "library", 15 | "bom-ref": "456", 16 | "name": "acme-library", 17 | "version": "1.0.0" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-author.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "authors": [ 8 | { 9 | "bom-ref": "author-1", 10 | "name": "Samantha Wright", 11 | "email": "samantha.wright@example.com", 12 | "phone": "800-555-1212" 13 | } 14 | ] 15 | }, 16 | "components": [] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-author.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samantha Wright 7 | samantha.wright@example.com 8 | 800-555-1212 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/valid-metadata-author.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Samantha Wright 7 | samantha.wright@example.com 8 | 800-555-1212 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-swhid.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swhid": [ 13 | "swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2" 14 | ] 15 | } 16 | ] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-supplier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Distribution 9 | distribution@example.com 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/valid-metadata-supplier.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "supplier": { 8 | "name": "Acme, Inc.", 9 | "url": [ 10 | "https://example.com" 11 | ], 12 | "contact": [ 13 | { 14 | "name": "Acme Distribution", 15 | "email": "distribution@example.com" 16 | } 17 | ] 18 | } 19 | }, 20 | "components": [] 21 | } 22 | -------------------------------------------------------------------------------- /testdata/valid-lifecycle.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "lifecycles": [ 8 | { 9 | "phase": "build" 10 | }, 11 | { 12 | "phase": "post-build" 13 | }, 14 | { 15 | "name": "platform-integration-testing", 16 | "description": "Integration testing specific to the runtime platform" 17 | } 18 | ] 19 | }, 20 | "components": [] 21 | } -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-omniborId.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "omniborId": [ 13 | "gitoid:blob:sha1:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3" 14 | ] 15 | } 16 | ] 17 | } 18 | 19 | -------------------------------------------------------------------------------- /testdata/valid-license-id.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "id": "Apache-2.0" 17 | } 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /testdata/valid-service-empty-objects.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "services": [ 7 | { 8 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 9 | "provider": { 10 | "contact": [ 11 | ] 12 | }, 13 | "name": "Stock ticker service", 14 | "endpoints": [ 15 | ], 16 | "data": [ 17 | ], 18 | "externalReferences": [ 19 | ] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /testdata/valid-license-expression.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0" 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /testdata/valid-metadata-supplier.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Distribution 9 | distribution@example.com 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-ref.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "123", 9 | "type": "library", 10 | "name": "acme-library", 11 | "version": "1.0.0" 12 | }, 13 | { 14 | "bom-ref": "456", 15 | "type": "library", 16 | "name": "acme-library", 17 | "version": "1.0.0" 18 | } 19 | ] 20 | } 21 | 22 | -------------------------------------------------------------------------------- /testdata/valid-component-swid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/valid-component-swid.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swid": { 13 | "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", 14 | "name": "Acme Application", 15 | "version": "9.1.1" 16 | } 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /testdata/valid-metadata-manufacturer.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "manufacturer": { 8 | "name": "Acme, Inc.", 9 | "url": [ 10 | "https://example.com" 11 | ], 12 | "contact": [ 13 | { 14 | "name": "Acme Professional Services", 15 | "email": "professional.services@example.com" 16 | } 17 | ] 18 | } 19 | }, 20 | "components": [] 21 | } 22 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacturer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Professional Services 9 | professional.services@example.com 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-service-empty-objects.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "services": [ 7 | { 8 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 9 | "provider": { 10 | "name": "", 11 | "contact": [] 12 | }, 13 | "name": "Stock ticker service", 14 | "endpoints": [], 15 | "data": [], 16 | "externalReferences": [] 17 | } 18 | ] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /testdata/valid-metadata-manufacturer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Professional Services 9 | professional.services@example.com 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-supplier.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "supplier": { 8 | "name": "Acme, Inc.", 9 | "url": [ 10 | "https://example.com" 11 | ], 12 | "contact": [ 13 | { 14 | "name": "Acme Distribution", 15 | "email": "distribution@example.com" 16 | } 17 | ] 18 | } 19 | }, 20 | "components": [] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-swid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /testdata/valid-service-empty-objects.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stock ticker service 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/valid-component-swhid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2 9 | swh:1:cnt:618152ea559a168bbcbb5e294a9ed024d3859793 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-license-id.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "id": "Apache-2.0" 17 | } 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | 24 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-lifecycle.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "lifecycles": [ 8 | { 9 | "phase": "build" 10 | }, 11 | { 12 | "phase": "post-build" 13 | }, 14 | { 15 | "name": "platform-integration-testing", 16 | "description": "Integration testing specific to the runtime platform" 17 | } 18 | ] 19 | }, 20 | "components": [] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-license-expression.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "expression": "EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0" 16 | } 17 | ] 18 | } 19 | ] 20 | } 21 | 22 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-manufacture.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Professional Services 9 | professional.services@example.com 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/valid-license-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "name": "Apache License 2.0", 17 | "acknowledgement": "concluded" 18 | } 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/CycloneDX/cyclonedx-go 2 | 3 | go 1.20 4 | 5 | require ( 6 | github.com/bradleyjkemp/cupaloy/v2 v2.8.0 7 | github.com/stretchr/testify v1.10.0 8 | github.com/terminalstatic/go-xsd-validate v0.1.6 9 | github.com/xeipuuv/gojsonschema v1.2.0 10 | ) 11 | 12 | require ( 13 | github.com/davecgh/go-spew v1.1.1 // indirect 14 | github.com/pmezard/go-difflib v1.0.0 // indirect 15 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect 16 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect 17 | gopkg.in/yaml.v3 v3.0.1 // indirect 18 | ) 19 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-swid.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swid": { 13 | "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", 14 | "name": "Acme Application", 15 | "version": "9.1.1" 16 | } 17 | } 18 | ] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacturer.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "manufacturer": { 8 | "name": "Acme, Inc.", 9 | "url": [ 10 | "https://example.com" 11 | ], 12 | "contact": [ 13 | { 14 | "name": "Acme Professional Services", 15 | "email": "professional.services@example.com" 16 | } 17 | ] 18 | } 19 | }, 20 | "components": [] 21 | } 22 | 23 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-swhid.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | swh:1:cnt:94a9ed024d3859793618152ea559a168bbcbb5e2 9 | swh:1:cnt:618152ea559a168bbcbb5e294a9ed024d3859793 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/valid-metadata-manufacture.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme, Inc. 6 | https://example.com 7 | 8 | Acme Professional Services 9 | professional.services@example.com 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /testdata/valid-metadata-manufacture.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "manufacture": { 8 | "bom-ref": "manufacture-1", 9 | "name": "Acme, Inc.", 10 | "url": [ 11 | "https://example.com" 12 | ], 13 | "contact": [ 14 | { 15 | "bom-ref": "contact-1", 16 | "name": "Acme Professional Services", 17 | "email": "professional.services@example.com" 18 | } 19 | ] 20 | } 21 | }, 22 | "components": [] 23 | } 24 | -------------------------------------------------------------------------------- /testdata/valid-component-manufacturer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Acme, Inc. 7 | https://example.com 8 | 9 | Acme Professional Services 10 | professional.services@example.com 11 | 12 | 13 | Acme Application 14 | 9.1.1 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/valid-component-omniborId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | gitoid:blob:sha1:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 9 | gitoid:blob:sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-license-name.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "tomcat-catalina", 12 | "version": "9.0.14", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "name": "Apache License 2.0", 17 | "acknowledgement": "concluded" 18 | } 19 | } 20 | ] 21 | } 22 | ] 23 | } 24 | 25 | -------------------------------------------------------------------------------- /testdata/valid-component-authors.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "name": "Acme Application", 10 | "version": "9.1.1", 11 | "authors": [ 12 | { 13 | "name": "Anthony Edward Stark", 14 | "phone": "555-212-970-4133", 15 | "email": "ironman@example.org" 16 | }, 17 | { 18 | "name": "Peter Benjamin Parker", 19 | "email": "spiderman@example.org" 20 | } 21 | ] 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "docker" 4 | directory: "/" 5 | reviewers: 6 | - "CycloneDX/go-maintainers" 7 | schedule: 8 | # We only have one Dockerfile for the Gitpod workspace 9 | # right now, and it's not critical to be super up-to-date. 10 | interval: "monthly" 11 | - package-ecosystem: "gomod" 12 | directory: "/" 13 | reviewers: 14 | - "CycloneDX/go-maintainers" 15 | schedule: 16 | interval: "daily" 17 | - package-ecosystem: "github-actions" 18 | directory: "/" 19 | reviewers: 20 | - "CycloneDX/go-maintainers" 21 | schedule: 22 | interval: "daily" 23 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-lifecycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | build 7 | 8 | 9 | post-build 10 | 11 | 12 | platform-integration-testing 13 | Integration testing specific to the runtime platform 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-omniborId.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | gitoid:blob:sha1:a94a8fe5ccb19ba61c4c0873d391e987982fbbd3 9 | gitoid:blob:sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-manufacture.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "manufacture": { 8 | "bom-ref": "manufacture-1", 9 | "name": "Acme, Inc.", 10 | "url": [ 11 | "https://example.com" 12 | ], 13 | "contact": [ 14 | { 15 | "bom-ref": "contact-1", 16 | "name": "Acme Professional Services", 17 | "email": "professional.services@example.com" 18 | } 19 | ] 20 | } 21 | }, 22 | "components": [] 23 | } 24 | 25 | -------------------------------------------------------------------------------- /testdata/valid-component-manufacturer.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "name": "Acme Application", 10 | "version": "9.1.1", 11 | "manufacturer": { 12 | "name": "Acme, Inc.", 13 | "url": [ 14 | "https://example.com" 15 | ], 16 | "contact": [ 17 | { 18 | "name": "Acme Professional Services", 19 | "email": "professional.services@example.com" 20 | } 21 | ] 22 | } 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /testdata/valid-assembly.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-library-a", 10 | "version": "1.0.0", 11 | "components": [ 12 | { 13 | "type": "library", 14 | "name": "acme-library-b", 15 | "version": "2.0.0" 16 | } 17 | ] 18 | } 19 | ], 20 | "services": [ 21 | { 22 | "name": "acme-service-a", 23 | "services": [ 24 | { 25 | "name": "acme-service-b" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-tool-deprecated.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Awesome Vendor 7 | Awesome Tool 8 | 9.1.2 9 | 10 | 25ed8e31b995bb927966616df2a42b979a2717f0 11 | a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/valid-lifecycle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | build 7 | 8 | 9 | post-build 10 | 11 | 12 | platform-integration-testing 13 | Integration testing specific to the runtime platform 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/valid-definitions.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "definitions": { 7 | "standards": [ 8 | { 9 | "bom-ref": "std-ref-1", 10 | "name": "CycloneDX", 11 | "version": "1.6", 12 | "description": "A full-stack Bill of Materials standard that provides advanced supply chain capabilities for cyber risk reduction.", 13 | "owner": "OWASP", 14 | "externalReferences": [ 15 | { 16 | "type": "website", 17 | "url": "https://cyclonedx.org" 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-authors.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "authors": [ 10 | { 11 | "name": "Anthony Edward Stark", 12 | "email": "ironman@example.org", 13 | "phone": "555-212-970-4133" 14 | }, 15 | { 16 | "name": "Peter Benjamin Parker", 17 | "email": "spiderman@example.org" 18 | } 19 | ], 20 | "name": "Acme Application", 21 | "version": "9.1.1" 22 | } 23 | ] 24 | } 25 | 26 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-manufacturer.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Acme, Inc. 7 | https://example.com 8 | 9 | Acme Professional Services 10 | professional.services@example.com 11 | 12 | 13 | Acme Application 14 | 9.1.1 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-manufacturer.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "manufacturer": { 10 | "name": "Acme, Inc.", 11 | "url": [ 12 | "https://example.com" 13 | ], 14 | "contact": [ 15 | { 16 | "name": "Acme Professional Services", 17 | "email": "professional.services@example.com" 18 | } 19 | ] 20 | }, 21 | "name": "Acme Application", 22 | "version": "9.1.1" 23 | } 24 | ] 25 | } 26 | 27 | -------------------------------------------------------------------------------- /testdata/valid-metadata-tool-deprecated.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "tools": [ 8 | { 9 | "vendor": "Awesome Vendor", 10 | "name": "Awesome Tool", 11 | "version": "9.1.2", 12 | "hashes": [ 13 | { 14 | "alg": "SHA-1", 15 | "content": "25ed8e31b995bb927966616df2a42b979a2717f0" 16 | }, 17 | { 18 | "alg": "SHA-256", 19 | "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df" 20 | } 21 | ] 22 | } 23 | ] 24 | }, 25 | "components": [] 26 | } -------------------------------------------------------------------------------- /testdata/valid-metadata-tool-deprecated.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Awesome Vendor 7 | Awesome Tool 8 | 9.1.2 9 | 10 | 25ed8e31b995bb927966616df2a42b979a2717f0 11 | a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-assembly.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-library-a", 10 | "version": "1.0.0", 11 | "components": [ 12 | { 13 | "type": "library", 14 | "name": "acme-library-b", 15 | "version": "2.0.0" 16 | } 17 | ] 18 | } 19 | ], 20 | "services": [ 21 | { 22 | "name": "acme-service-a", 23 | "services": [ 24 | { 25 | "name": "acme-service-b" 26 | } 27 | ] 28 | } 29 | ] 30 | } 31 | 32 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-definitions.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "definitions": { 7 | "standards": [ 8 | { 9 | "bom-ref": "std-ref-1", 10 | "name": "CycloneDX", 11 | "version": "1.6", 12 | "description": "A full-stack Bill of Materials standard that provides advanced supply chain capabilities for cyber risk reduction.", 13 | "owner": "OWASP", 14 | "externalReferences": [ 15 | { 16 | "url": "https://cyclonedx.org", 17 | "type": "website" 18 | } 19 | ] 20 | } 21 | ] 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-ref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library 6 | 1.0.0 7 | 8 | 9 | acme-library 10 | 1.0.0 11 | 12 | 13 | 14 | 15 | acme-library 16 | 1.0.0 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-authors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Anthony Edward Stark 8 | ironman@example.org 9 | 555-212-970-4133 10 | 11 | 12 | Peter Benjamin Parker 13 | spiderman@example.org 14 | 15 | 16 | Acme Application 17 | 9.1.1 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-tool-deprecated.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "tools": [ 8 | { 9 | "vendor": "Awesome Vendor", 10 | "name": "Awesome Tool", 11 | "version": "9.1.2", 12 | "hashes": [ 13 | { 14 | "alg": "SHA-1", 15 | "content": "25ed8e31b995bb927966616df2a42b979a2717f0" 16 | }, 17 | { 18 | "alg": "SHA-256", 19 | "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df" 20 | } 21 | ] 22 | } 23 | ] 24 | }, 25 | "components": [] 26 | } 27 | 28 | -------------------------------------------------------------------------------- /testdata/valid-component-ref.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library 6 | 1.0.0 7 | 8 | 9 | acme-library 10 | 1.0.0 11 | 12 | 13 | 14 | 15 | acme-library 16 | 1.0.0 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-definitions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CycloneDX 7 | 1.6 8 | A full-stack Bill of Materials standard that provides advanced supply chain capabilities for cyber risk reduction. 9 | OWASP 10 | 11 | 12 | https://cyclonedx.org 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /testdata/valid-component-authors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Anthony Edward Stark 8 | ironman@example.org 9 | 555-212-970-4133 10 | 11 | 12 | Peter Benjamin Parker 13 | spiderman@example.org 14 | 15 | 16 | Acme Application 17 | 9.1.1 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library-a 6 | 1.0.0 7 | 8 | 9 | acme-library-b 10 | 2.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | acme-service-a 18 | 19 | 20 | acme-service-b 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Dockerfile.gitpod: -------------------------------------------------------------------------------- 1 | # This file is part of CycloneDX Go 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the “License”); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an “AS IS” BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | # 15 | # SPDX-License-Identifier: Apache-2.0 16 | # Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | FROM gitpod/workspace-go:latest@sha256:8985eb7cf5f155eb83f07294e9bd1a7e8066f969711f51a166ef60d17d409eb0 19 | -------------------------------------------------------------------------------- /testdata/valid-definitions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | CycloneDX 7 | 1.6 8 | A full-stack Bill of Materials standard that provides advanced supply chain capabilities for cyber risk reduction. 9 | OWASP 10 | 11 | 12 | https://cyclonedx.org 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /testdata/valid-dependency.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "library-a", 9 | "type": "library", 10 | "name": "library-a", 11 | "version": "1.0.0" 12 | }, 13 | { 14 | "bom-ref": "library-b", 15 | "type": "library", 16 | "name": "library-b", 17 | "version": "1.0.0" 18 | }, 19 | { 20 | "bom-ref": "library-c", 21 | "type": "library", 22 | "name": "library-c", 23 | "version": "1.0.0" 24 | } 25 | ], 26 | "dependencies": [ 27 | { 28 | "ref": "library-a", 29 | "dependsOn": [] 30 | }, 31 | { 32 | "ref": "library-b", 33 | "dependsOn": [ 34 | "library-c" 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /validate_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | type validator interface { 21 | Validate(bom []byte, specVersion SpecVersion) error 22 | } 23 | -------------------------------------------------------------------------------- /testdata/valid-assembly.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library-a 6 | 1.0.0 7 | 8 | 9 | acme-library-b 10 | 2.0.0 11 | 12 | 13 | 14 | 15 | 16 | 17 | acme-service-a 18 | 19 | 20 | acme-service-b 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-dependency.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "library-a", 9 | "type": "library", 10 | "name": "library-a", 11 | "version": "1.0.0" 12 | }, 13 | { 14 | "bom-ref": "library-b", 15 | "type": "library", 16 | "name": "library-b", 17 | "version": "1.0.0" 18 | }, 19 | { 20 | "bom-ref": "library-c", 21 | "type": "library", 22 | "name": "library-c", 23 | "version": "1.0.0" 24 | } 25 | ], 26 | "dependencies": [ 27 | { 28 | "ref": "library-a", 29 | "dependsOn": [] 30 | }, 31 | { 32 | "ref": "library-b", 33 | "dependsOn": [ 34 | "library-c" 35 | ] 36 | } 37 | ] 38 | } 39 | 40 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-dependency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library-a 6 | 1.0.0 7 | 8 | 9 | acme-library-b 10 | 1.0.0 11 | 12 | 13 | acme-library-b 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/valid-dependency.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-library-a 6 | 1.0.0 7 | 8 | 9 | acme-library-b 10 | 1.0.0 11 | 12 | 13 | acme-library-b 14 | 1.0.0 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.goreleaser.yml: -------------------------------------------------------------------------------- 1 | builds: 2 | # This is a library project, we don't want to build any binaries. 3 | # Building and testing is performed in the CI workflow 4 | - skip: true 5 | 6 | release: 7 | prerelease: auto 8 | 9 | source: 10 | enabled: true 11 | 12 | sboms: 13 | - artifacts: source 14 | documents: 15 | - "${artifact}.cdx.sbom" 16 | cmd: cyclonedx-gomod 17 | args: [ "mod", "-licenses", "-json", "-output", "$document", "./.." ] 18 | 19 | milestones: 20 | - name_template: "{{ .Tag }}" 21 | close: true 22 | 23 | changelog: 24 | use: github 25 | sort: asc 26 | groups: 27 | - title: Features 28 | regexp: "^.*feat[(\\w)]*:+.*$" 29 | order: 0 30 | - title: Fixes 31 | regexp: "^.*fix[(\\w)]*:+.*$" 32 | order: 1 33 | - title: Building and Packaging 34 | regexp: "^.*build[(\\w)]*:+.*$" 35 | order: 2 36 | - title: Documentation 37 | regexp: "^.*docs[(\\w)]*:+.*$" 38 | order: 3 39 | - title: Others 40 | order: 999 41 | filters: 42 | exclude: 43 | - '^test:' 44 | - '^Merge ' -------------------------------------------------------------------------------- /.github/workflows/goreleaser.yml: -------------------------------------------------------------------------------- 1 | name: GoReleaser 2 | 3 | on: 4 | push: 5 | tags: 6 | - 'v*' 7 | 8 | permissions: { } 9 | 10 | jobs: 11 | goreleaser: 12 | name: Release 13 | timeout-minutes: 5 14 | runs-on: ubuntu-latest 15 | permissions: 16 | contents: write 17 | steps: 18 | - name: Checkout Repository 19 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 20 | with: 21 | fetch-depth: 0 22 | - name: Setup Go 23 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 24 | with: 25 | go-version: "1.22" 26 | check-latest: true 27 | - name: Install cyclonedx-gomod 28 | uses: CycloneDX/gh-gomod-generate-sbom@efc74245d6802c8cefd925620515442756c70d8f # tag=v2.0.0 29 | with: 30 | version: v1 31 | - name: Run GoReleaser 32 | uses: goreleaser/goreleaser-action@9c156ee8a17a598857849441385a2041ef570552 # tag=v6.3.0 33 | with: 34 | version: latest 35 | args: release --clean 36 | env: 37 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 38 | -------------------------------------------------------------------------------- /testdata/valid-component-types.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "name": "application-a", 10 | "version": "1.0" 11 | }, 12 | { 13 | "type": "library", 14 | "name": "library-a", 15 | "version": "1.0" 16 | }, 17 | { 18 | "type": "framework", 19 | "name": "framework-a", 20 | "version": "1.0" 21 | }, 22 | { 23 | "type": "container", 24 | "name": "container-a", 25 | "version": "1.0" 26 | }, 27 | { 28 | "type": "operating-system", 29 | "name": "operating-system-a", 30 | "version": "1.0" 31 | }, 32 | { 33 | "type": "firmware", 34 | "name": "firmware-a", 35 | "version": "1.0" 36 | }, 37 | { 38 | "type": "device", 39 | "name": "device-a", 40 | "version": "1.0" 41 | }, 42 | { 43 | "type": "file", 44 | "name": "file-a", 45 | "version": "1.0" 46 | } 47 | ] 48 | } 49 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-types.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "name": "application-a", 10 | "version": "1.0" 11 | }, 12 | { 13 | "type": "library", 14 | "name": "library-a", 15 | "version": "1.0" 16 | }, 17 | { 18 | "type": "framework", 19 | "name": "framework-a", 20 | "version": "1.0" 21 | }, 22 | { 23 | "type": "container", 24 | "name": "container-a", 25 | "version": "1.0" 26 | }, 27 | { 28 | "type": "operating-system", 29 | "name": "operating-system-a", 30 | "version": "1.0" 31 | }, 32 | { 33 | "type": "firmware", 34 | "name": "firmware-a", 35 | "version": "1.0" 36 | }, 37 | { 38 | "type": "device", 39 | "name": "device-a", 40 | "version": "1.0" 41 | }, 42 | { 43 | "type": "file", 44 | "name": "file-a", 45 | "version": "1.0" 46 | } 47 | ] 48 | } 49 | 50 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-license-id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | 19 | Apache-2.0 20 | 21 | 22 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-license-expression.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 19 | 20 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-types.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-a 6 | 1.0 7 | 8 | 9 | library-a 10 | 1.0 11 | 12 | 13 | framework-a 14 | 1.0 15 | 16 | 17 | container-a 18 | 1.0 19 | 20 | 21 | operating-system-a 22 | 1.0 23 | 24 | 25 | firmware-a 26 | 1.0 27 | 28 | 29 | device-a 30 | 1.0 31 | 32 | 33 | file-a 34 | 1.0 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-license-name.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | 19 | Apache License 2.0 20 | 21 | 22 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/valid-external-reference.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "org.example", 11 | "name": "mylibrary", 12 | "version": "1.0.0", 13 | "externalReferences": [ 14 | { 15 | "type": "advisories", 16 | "url": "https://example.org/security/feed/csaf", 17 | "comment": "Security advisories from the vendor" 18 | }, 19 | { 20 | "type": "bom", 21 | "url": "https://example.org/support/sbom/portal-server/1.0.0", 22 | "comment": "An external SBOM that describes what this component includes", 23 | "hashes": [ 24 | { 25 | "alg": "SHA-256", 26 | "content": "708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313" 27 | } 28 | ] 29 | }, 30 | { 31 | "type": "documentation", 32 | "url": "https://example.org/support/documentation/portal-server/1.0.0", 33 | "comment": "Vendor provided documentation for the product" 34 | } 35 | ] 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /testdata/valid-license-expression.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 19 | 20 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.licenserc.yml: -------------------------------------------------------------------------------- 1 | header: 2 | license: 3 | spdx-id: Apache-2.0 4 | copyright-owner: OWASP Foundation 5 | content: | 6 | This file is part of CycloneDX Go 7 | 8 | Licensed under the Apache License, Version 2.0 (the “License”); 9 | you may not use this file except in compliance with the License. 10 | You may obtain a copy of the License at 11 | 12 | http://www.apache.org/licenses/LICENSE-2.0 13 | 14 | Unless required by applicable law or agreed to in writing, software 15 | distributed under the License is distributed on an “AS IS” BASIS, 16 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | See the License for the specific language governing permissions and 18 | limitations under the License. 19 | 20 | SPDX-License-Identifier: Apache-2.0 21 | Copyright (c) OWASP Foundation. All Rights Reserved. 22 | paths-ignore: 23 | - "**/*.md" 24 | - "**/go.mod" 25 | - "**/go.sum" 26 | - "**/testdata/**" 27 | - ".github/**" 28 | - ".idea/**" 29 | - ".gitignore" 30 | - ".gitpod.yml" 31 | - ".golangci.yml" 32 | - ".goreleaser.yml" 33 | - ".licenserc.yml" 34 | - "CODEOWNERS" 35 | - "LICENSE" 36 | - "Makefile" 37 | - "NOTICE" 38 | - "cyclonedx_string.go" 39 | - "schema/**" -------------------------------------------------------------------------------- /testdata/valid-license-id.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | 19 | Apache-2.0 20 | 21 | 22 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-external-reference.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | org.example 6 | mylibrary 7 | 1.0.0 8 | 9 | 10 | https://example.org/security/feed/csaf 11 | Security advisories from the vendor 12 | 13 | 14 | https://example.org/support/sbom/portal-server/1.0.0 15 | An external SBOM that describes what this component includes 16 | 17 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 18 | 19 | 20 | 21 | https://example.org/support/documentation/portal-server/1.0.0 22 | Vendor provided documentation for the product 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-external-reference.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "org.example", 11 | "name": "mylibrary", 12 | "version": "1.0.0", 13 | "externalReferences": [ 14 | { 15 | "url": "https://example.org/security/feed/csaf", 16 | "comment": "Security advisories from the vendor", 17 | "type": "advisories" 18 | }, 19 | { 20 | "url": "https://example.org/support/sbom/portal-server/1.0.0", 21 | "comment": "An external SBOM that describes what this component includes", 22 | "hashes": [ 23 | { 24 | "alg": "SHA-256", 25 | "content": "708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313" 26 | } 27 | ], 28 | "type": "bom" 29 | }, 30 | { 31 | "url": "https://example.org/support/documentation/portal-server/1.0.0", 32 | "comment": "Vendor provided documentation for the product", 33 | "type": "documentation" 34 | } 35 | ] 36 | } 37 | ] 38 | } 39 | 40 | -------------------------------------------------------------------------------- /testdata/valid-license-name.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | 19 | Apache License 2.0 20 | 21 | 22 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /testdata/valid-metadata-tool.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "tools": { 8 | "components": [ 9 | { 10 | "type": "application", 11 | "group": "Awesome Vendor", 12 | "name": "Awesome Tool", 13 | "version": "9.1.2", 14 | "hashes": [ 15 | { 16 | "alg": "SHA-1", 17 | "content": "25ed8e31b995bb927966616df2a42b979a2717f0" 18 | }, 19 | { 20 | "alg": "SHA-256", 21 | "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df" 22 | } 23 | ] 24 | } 25 | ], 26 | "services": [ 27 | { 28 | "provider": { 29 | "name": "Acme Org", 30 | "url": [ 31 | "https://example.com" 32 | ] 33 | }, 34 | "group": "com.example", 35 | "name": "Acme Signing Server", 36 | "description": "Signs artifacts", 37 | "endpoints": [ 38 | "https://example.com/sign", 39 | "https://example.com/verify", 40 | "https://example.com/tsa" 41 | ] 42 | } 43 | ] 44 | } 45 | }, 46 | "components": [] 47 | } -------------------------------------------------------------------------------- /testdata/valid-component-types.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | application-a 6 | 1.0 7 | 8 | 9 | library-a 10 | 1.0 11 | 12 | 13 | framework-a 14 | 1.0 15 | 16 | 17 | container-a 18 | 1.0 19 | 20 | 21 | operating-system-a 22 | 1.0 23 | 24 | 25 | firmware-a 26 | 1.0 27 | 28 | 29 | device-a 30 | 1.0 31 | 32 | 33 | file-a 34 | 1.0 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-metadata-tool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Awesome Vendor 8 | Awesome Tool 9 | 9.1.2 10 | 11 | 25ed8e31b995bb927966616df2a42b979a2717f0 12 | a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df 13 | 14 | 15 | 16 | 17 | 18 | 19 | Acme Org 20 | https://example.com 21 | 22 | com.example 23 | Acme Signing Server 24 | Signs artifacts 25 | 26 | https://example.com/sign 27 | https://example.com/verify 28 | https://example.com/tsa 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /testdata/valid-component-swid-full.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | 9 | PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg== 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-swid-full.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Super Heros 6 | Acme Application 7 | 9.1.1 8 | 9 | PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg== 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-metadata-tool.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "tools": { 8 | "components": [ 9 | { 10 | "type": "application", 11 | "group": "Awesome Vendor", 12 | "name": "Awesome Tool", 13 | "version": "9.1.2", 14 | "hashes": [ 15 | { 16 | "alg": "SHA-1", 17 | "content": "25ed8e31b995bb927966616df2a42b979a2717f0" 18 | }, 19 | { 20 | "alg": "SHA-256", 21 | "content": "a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df" 22 | } 23 | ] 24 | } 25 | ], 26 | "services": [ 27 | { 28 | "provider": { 29 | "name": "Acme Org", 30 | "url": [ 31 | "https://example.com" 32 | ] 33 | }, 34 | "group": "com.example", 35 | "name": "Acme Signing Server", 36 | "description": "Signs artifacts", 37 | "endpoints": [ 38 | "https://example.com/sign", 39 | "https://example.com/verify", 40 | "https://example.com/tsa" 41 | ] 42 | } 43 | ] 44 | } 45 | }, 46 | "components": [] 47 | } 48 | 49 | -------------------------------------------------------------------------------- /testdata/valid-external-reference.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | org.example 6 | mylibrary 7 | 1.0.0 8 | 9 | 10 | https://example.org/security/feed/csaf 11 | Security advisories from the vendor 12 | 13 | 14 | https://example.org/support/sbom/portal-server/1.0.0 15 | An external SBOM that describes what this component includes 16 | 17 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 18 | 19 | 20 | 21 | https://example.org/support/documentation/portal-server/1.0.0 22 | Vendor provided documentation for the product 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /testdata/valid-component-swid-full.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swid": { 13 | "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", 14 | "name": "Acme Application", 15 | "version": "9.1.1", 16 | "text": { 17 | "contentType": "text/xml", 18 | "encoding": "base64", 19 | "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==" 20 | } 21 | } 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /copy.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "bytes" 22 | "encoding/gob" 23 | "fmt" 24 | ) 25 | 26 | // copy creates a deep copy of the BOM in a given destination. 27 | // Copying is currently done by encoding and decoding the BOM struct using gob. 28 | // In the future we may choose to switch to a more efficient strategy, 29 | // and consider to export this API. 30 | func (b BOM) copy(dst *BOM) error { 31 | buf := bytes.Buffer{} 32 | err := gob.NewEncoder(&buf).Encode(b) 33 | if err != nil { 34 | return fmt.Errorf("failed to encode bom: %w", err) 35 | } 36 | 37 | err = gob.NewDecoder(&buf).Decode(dst) 38 | if err != nil { 39 | return fmt.Errorf("failed to decode bom: %w", err) 40 | } 41 | 42 | return nil 43 | } 44 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-swid-full.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "author": "Acme Super Heros", 10 | "name": "Acme Application", 11 | "version": "9.1.1", 12 | "swid": { 13 | "text": { 14 | "content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiID8+CjxTb2Z0d2FyZUlkZW50aXR5IHhtbDpsYW5nPSJFTiIgbmFtZT0iQWNtZSBBcHBsaWNhdGlvbiIgdmVyc2lvbj0iOS4xLjEiIAogdmVyc2lvblNjaGVtZT0ibXVsdGlwYXJ0bnVtZXJpYyIgCiB0YWdJZD0ic3dpZGdlbi1iNTk1MWFjOS00MmMwLWYzODItM2YxZS1iYzdhMmE0NDk3Y2JfOS4xLjEiIAogeG1sbnM9Imh0dHA6Ly9zdGFuZGFyZHMuaXNvLm9yZy9pc28vMTk3NzAvLTIvMjAxNS9zY2hlbWEueHNkIj4gCiB4bWxuczp4c2k9Imh0dHA6Ly93d3cudzMub3JnLzIwMDEvWE1MU2NoZW1hLWluc3RhbmNlIiAKIHhzaTpzY2hlbWFMb2NhdGlvbj0iaHR0cDovL3N0YW5kYXJkcy5pc28ub3JnL2lzby8xOTc3MC8tMi8yMDE1LWN1cnJlbnQvc2NoZW1hLnhzZCBzY2hlbWEueHNkIiA+CiAgPE1ldGEgZ2VuZXJhdG9yPSJTV0lEIFRhZyBPbmxpbmUgR2VuZXJhdG9yIHYwLjEiIC8+IAogIDxFbnRpdHkgbmFtZT0iQWNtZSwgSW5jLiIgcmVnaWQ9ImV4YW1wbGUuY29tIiByb2xlPSJ0YWdDcmVhdG9yIiAvPiAKPC9Tb2Z0d2FyZUlkZW50aXR5Pg==", 15 | "contentType": "text/xml", 16 | "encoding": "base64" 17 | }, 18 | "tagId": "swidgen-242eb18a-503e-ca37-393b-cf156ef09691_9.1.1", 19 | "name": "Acme Application", 20 | "version": "9.1.1" 21 | } 22 | } 23 | ] 24 | } 25 | 26 | -------------------------------------------------------------------------------- /testdata/valid-metadata-tool.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Awesome Vendor 8 | Awesome Tool 9 | 9.1.2 10 | 11 | 25ed8e31b995bb927966616df2a42b979a2717f0 12 | a74f733635a19aefb1f73e5947cef59cd7440c6952ef0f03d09d974274cbd6df 13 | 14 | 15 | 16 | 17 | 18 | 19 | Acme Org 20 | https://example.com 21 | 22 | com.example 23 | Acme Signing Server 24 | Signs artifacts 25 | 26 | https://example.com/sign 27 | https://example.com/verify 28 | https://example.com/tsa 29 | 30 | 31 | 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-properties.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bar 6 | You 7 | Two 8 | Foo 9 | 10 | 11 | 12 | 13 | acme-library 14 | 1.0.0 15 | 16 | 17 | Apache-2.0 18 | 19 | Bar 20 | You 21 | Two 22 | Foo 23 | 24 | 25 | 26 | 27 | Bar 28 | Foo 29 | 30 | 31 | 32 | 33 | 34 | org.partner 35 | Stock ticker service 36 | 37 | https://partner.org/api/v1/stock 38 | 39 | 40 | Bar 41 | Foo 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /cyclonedx_string.go: -------------------------------------------------------------------------------- 1 | // Code generated by "stringer -linecomment -output cyclonedx_string.go -type MediaType,SpecVersion"; DO NOT EDIT. 2 | 3 | package cyclonedx 4 | 5 | import "strconv" 6 | 7 | func _() { 8 | // An "invalid array index" compiler error signifies that the constant values have changed. 9 | // Re-run the stringer command to generate them again. 10 | var x [1]struct{} 11 | _ = x[MediaTypeJSON-1] 12 | _ = x[MediaTypeXML-2] 13 | _ = x[MediaTypeProtobuf-3] 14 | } 15 | 16 | const _MediaType_name = "application/vnd.cyclonedx+jsonapplication/vnd.cyclonedx+xmlapplication/x.vnd.cyclonedx+protobuf" 17 | 18 | var _MediaType_index = [...]uint8{0, 30, 59, 95} 19 | 20 | func (i MediaType) String() string { 21 | i -= 1 22 | if i < 0 || i >= MediaType(len(_MediaType_index)-1) { 23 | return "MediaType(" + strconv.FormatInt(int64(i+1), 10) + ")" 24 | } 25 | return _MediaType_name[_MediaType_index[i]:_MediaType_index[i+1]] 26 | } 27 | func _() { 28 | // An "invalid array index" compiler error signifies that the constant values have changed. 29 | // Re-run the stringer command to generate them again. 30 | var x [1]struct{} 31 | _ = x[SpecVersion1_0-1] 32 | _ = x[SpecVersion1_1-2] 33 | _ = x[SpecVersion1_2-3] 34 | _ = x[SpecVersion1_3-4] 35 | _ = x[SpecVersion1_4-5] 36 | _ = x[SpecVersion1_5-6] 37 | _ = x[SpecVersion1_6-7] 38 | } 39 | 40 | const _SpecVersion_name = "1.01.11.21.31.41.51.6" 41 | 42 | var _SpecVersion_index = [...]uint8{0, 3, 6, 9, 12, 15, 18, 21} 43 | 44 | func (i SpecVersion) String() string { 45 | i -= 1 46 | if i < 0 || i >= SpecVersion(len(_SpecVersion_index)-1) { 47 | return "SpecVersion(" + strconv.FormatInt(int64(i+1), 10) + ")" 48 | } 49 | return _SpecVersion_name[_SpecVersion_index[i]:_SpecVersion_index[i+1]] 50 | } 51 | -------------------------------------------------------------------------------- /testdata/valid-license-licensing.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "cryptographic-provider", 12 | "version": "2.2.0", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "bom-ref": "acme-license-1", 17 | "name": "Acme Commercial License", 18 | "acknowledgement": "concluded", 19 | "licensing": { 20 | "altIds": [ 21 | "acme", "acme-license" 22 | ], 23 | "licensor": { 24 | "organization": { 25 | "name": "Acme Inc", 26 | "contact": [ 27 | { 28 | "name": "Acme Licensing Fulfillment", 29 | "email": "licensing@example.com" 30 | } 31 | ] 32 | } 33 | }, 34 | "licensee": { 35 | "organization": { 36 | "name": "Example Co." 37 | } 38 | }, 39 | "purchaser": { 40 | "individual": { 41 | "name": "Samantha Wright", 42 | "email": "samantha.wright@gmail.com", 43 | "phone": "800-555-1212" 44 | } 45 | }, 46 | "purchaseOrder": "PO-12345", 47 | "licenseTypes": ["appliance"], 48 | "lastRenewal": "2022-04-13T20:20:39+00:00", 49 | "expiration": "2023-04-13T20:20:39+00:00" 50 | } 51 | } 52 | } 53 | ] 54 | } 55 | ] 56 | } -------------------------------------------------------------------------------- /testdata/valid-properties.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Bar 6 | You 7 | Two 8 | Foo 9 | 10 | 11 | 12 | 13 | acme-library 14 | 1.0.0 15 | 16 | 17 | Apache-2.0 18 | 19 | Bar 20 | You 21 | Two 22 | Foo 23 | 24 | 25 | 26 | 27 | Bar 28 | Foo 29 | 30 | 31 | 32 | 33 | 34 | org.partner 35 | Stock ticker service 36 | 37 | https://partner.org/api/v1/stock 38 | 39 | 40 | Bar 41 | Foo 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | branches: 9 | - master 10 | 11 | permissions: { } 12 | 13 | jobs: 14 | licensecheck: 15 | name: License Check 16 | timeout-minutes: 5 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout Repository 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 21 | - name: Check license headers 22 | uses: apache/skywalking-eyes@5c5b974209f0de5d905f37deb69369068ebfc15c # tag=v0.7.0 23 | with: 24 | config: .licenserc.yml 25 | 26 | lint: 27 | name: Lint 28 | timeout-minutes: 5 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout Repository 32 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 33 | - name: Setup Go 34 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 35 | with: 36 | go-version: "1.22" 37 | check-latest: true 38 | cache: false 39 | - name: Run golangci-lint 40 | uses: golangci/golangci-lint-action@ec5d18412c0aeab7936cb16880d708ba2a64e1ae # tag=v6.2.0 41 | with: 42 | version: latest 43 | args: --verbose 44 | 45 | test: 46 | name: Test 47 | timeout-minutes: 5 48 | runs-on: ubuntu-latest 49 | strategy: 50 | matrix: 51 | go: 52 | - "1.20" 53 | - "1.21" 54 | - "1.22" 55 | steps: 56 | - name: Setup Go 57 | uses: actions/setup-go@d35c59abb061a4a6fb18e82ac0862c26744d6ab5 # tag=v5.5.0 58 | with: 59 | go-version: ${{ matrix.go }} 60 | check-latest: true 61 | - name: Checkout Repository 62 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=v4.2.2 63 | - name: Test 64 | run: make test 65 | -------------------------------------------------------------------------------- /link_example_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx_test 19 | 20 | import ( 21 | "fmt" 22 | 23 | cdx "github.com/CycloneDX/cyclonedx-go" 24 | ) 25 | 26 | func ExampleNewBOMLink() { 27 | bom := cdx.NewBOM() 28 | bom.SerialNumber = "urn:uuid:bd064d10-4238-4a2e-9517-216f79ed77ad" 29 | bom.Version = 2 30 | bom.Metadata = &cdx.Metadata{ 31 | Component: &cdx.Component{ 32 | BOMRef: "pkg:golang/github.com/CycloneDX/cyclonedx-go@v0.5.0?type=module", 33 | Type: cdx.ComponentTypeLibrary, 34 | Name: "github.com/CycloneDX/cyclonedx-go", 35 | Version: "v0.5.0", 36 | PackageURL: "pkg:golang/github.com/CycloneDX/cyclonedx-go@v0.5.0?type=module", 37 | }, 38 | } 39 | 40 | link, _ := cdx.NewBOMLink(bom.SerialNumber, bom.Version, nil) 41 | deepLink, _ := cdx.NewBOMLink(bom.SerialNumber, bom.Version, bom.Metadata.Component) 42 | 43 | fmt.Println(link.String()) 44 | fmt.Println(deepLink.String()) 45 | 46 | // Output: 47 | // urn:cdx:bd064d10-4238-4a2e-9517-216f79ed77ad/2 48 | // urn:cdx:bd064d10-4238-4a2e-9517-216f79ed77ad/2#pkg%3Agolang%2Fgithub.com%2FCycloneDX%2Fcyclonedx-go%40v0.5.0%3Ftype%3Dmodule 49 | } 50 | -------------------------------------------------------------------------------- /testdata/valid-properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "properties": [ 8 | { 9 | "name": "Foo", 10 | "value": "Bar" 11 | }, 12 | { 13 | "name": "Foo", 14 | "value": "You" 15 | }, 16 | { 17 | "name": "Foo", 18 | "value": "Two" 19 | }, 20 | { 21 | "name": "Bar", 22 | "value": "Foo" 23 | } 24 | ] 25 | }, 26 | "components": [ 27 | { 28 | "type": "library", 29 | "name": "acme-library", 30 | "version": "1.0.0", 31 | "licenses": [ 32 | { 33 | "license": { 34 | "id": "Apache-2.0", 35 | "properties": [ 36 | { 37 | "name": "Foo", 38 | "value": "Bar" 39 | }, 40 | { 41 | "name": "Foo", 42 | "value": "You" 43 | }, 44 | { 45 | "name": "Foo", 46 | "value": "Two" 47 | }, 48 | { 49 | "name": "Bar", 50 | "value": "Foo" 51 | } 52 | ] 53 | } 54 | } 55 | ], 56 | "properties": [ 57 | { 58 | "name": "Foo", 59 | "value": "Bar" 60 | } 61 | ] 62 | } 63 | ], 64 | "services": [ 65 | { 66 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 67 | "group": "org.partner", 68 | "name": "Stock ticker service", 69 | "endpoints": [ 70 | "https://partner.org/api/v1/stock" 71 | ], 72 | "properties": [ 73 | { 74 | "name": "Foo", 75 | "value": "Bar" 76 | } 77 | ] 78 | } 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /decode.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "encoding/json" 22 | "encoding/xml" 23 | "io" 24 | ) 25 | 26 | type BOMDecoder interface { 27 | Decode(bom *BOM) error 28 | } 29 | 30 | func NewBOMDecoder(reader io.Reader, format BOMFileFormat) BOMDecoder { 31 | if format == BOMFileFormatJSON { 32 | return &jsonBOMDecoder{reader: reader} 33 | } 34 | return &xmlBOMDecoder{reader: reader} 35 | } 36 | 37 | type jsonBOMDecoder struct { 38 | reader io.Reader 39 | } 40 | 41 | // Decode implements the BOMDecoder interface. 42 | func (j jsonBOMDecoder) Decode(bom *BOM) error { 43 | bytes, err := io.ReadAll(j.reader) 44 | if err != nil { 45 | return err 46 | } 47 | return json.Unmarshal(bytes, bom) 48 | } 49 | 50 | type xmlBOMDecoder struct { 51 | reader io.Reader 52 | } 53 | 54 | // Decode implements the BOMDecoder interface. 55 | func (x xmlBOMDecoder) Decode(bom *BOM) error { 56 | err := xml.NewDecoder(x.reader).Decode(bom) 57 | if err != nil { 58 | return err 59 | } 60 | 61 | for specVersion, xmlNs := range xmlNamespaces { 62 | if xmlNs == bom.XMLNS { 63 | bom.SpecVersion = specVersion 64 | break 65 | } 66 | } 67 | 68 | return nil 69 | } 70 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-component-hashes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-example 6 | 1.0.0 7 | 8 | 641b6e166f8b33c5e959e2adcc18b1c7 9 | 9188560f22e0b73070d2efce670c74af2bdf30af 10 | d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964 11 | d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad 12 | 74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6 13 | 7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa 14 | a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5 15 | 7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20 16 | d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237 17 | e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a 18 | f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d 19 | 26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "properties": [ 8 | { 9 | "name": "Foo", 10 | "value": "Bar" 11 | }, 12 | { 13 | "name": "Foo", 14 | "value": "You" 15 | }, 16 | { 17 | "name": "Foo", 18 | "value": "Two" 19 | }, 20 | { 21 | "name": "Bar", 22 | "value": "Foo" 23 | } 24 | ] 25 | }, 26 | "components": [ 27 | { 28 | "type": "library", 29 | "name": "acme-library", 30 | "version": "1.0.0", 31 | "licenses": [ 32 | { 33 | "license": { 34 | "id": "Apache-2.0", 35 | "properties": [ 36 | { 37 | "name": "Foo", 38 | "value": "Bar" 39 | }, 40 | { 41 | "name": "Foo", 42 | "value": "You" 43 | }, 44 | { 45 | "name": "Foo", 46 | "value": "Two" 47 | }, 48 | { 49 | "name": "Bar", 50 | "value": "Foo" 51 | } 52 | ] 53 | } 54 | } 55 | ], 56 | "properties": [ 57 | { 58 | "name": "Foo", 59 | "value": "Bar" 60 | } 61 | ] 62 | } 63 | ], 64 | "services": [ 65 | { 66 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 67 | "group": "org.partner", 68 | "name": "Stock ticker service", 69 | "endpoints": [ 70 | "https://partner.org/api/v1/stock" 71 | ], 72 | "properties": [ 73 | { 74 | "name": "Foo", 75 | "value": "Bar" 76 | } 77 | ] 78 | } 79 | ] 80 | } 81 | 82 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-license-licensing.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "publisher": "Acme Inc", 10 | "group": "com.acme", 11 | "name": "cryptographic-provider", 12 | "version": "2.2.0", 13 | "licenses": [ 14 | { 15 | "license": { 16 | "bom-ref": "acme-license-1", 17 | "name": "Acme Commercial License", 18 | "acknowledgement": "concluded", 19 | "licensing": { 20 | "altIds": [ 21 | "acme", 22 | "acme-license" 23 | ], 24 | "licensor": { 25 | "organization": { 26 | "name": "Acme Inc", 27 | "contact": [ 28 | { 29 | "name": "Acme Licensing Fulfillment", 30 | "email": "licensing@example.com" 31 | } 32 | ] 33 | } 34 | }, 35 | "licensee": { 36 | "organization": { 37 | "name": "Example Co." 38 | } 39 | }, 40 | "purchaser": { 41 | "individual": { 42 | "name": "Samantha Wright", 43 | "email": "samantha.wright@gmail.com", 44 | "phone": "800-555-1212" 45 | } 46 | }, 47 | "purchaseOrder": "PO-12345", 48 | "licenseTypes": [ 49 | "appliance" 50 | ], 51 | "lastRenewal": "2022-04-13T20:20:39+00:00", 52 | "expiration": "2023-04-13T20:20:39+00:00" 53 | } 54 | } 55 | } 56 | ] 57 | } 58 | ] 59 | } 60 | 61 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-license-licensing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | cryptographic-provider 8 | 2.2.0 9 | 10 | 11 | Acme Commercial License 12 | 13 | 14 | acme 15 | acme-license 16 | 17 | 18 | 19 | Acme Inc 20 | 21 | Acme Licensing Fulfillment 22 | licensing@example.com 23 | 24 | 25 | 26 | 27 | 28 | Example Co. 29 | 30 | 31 | 32 | 33 | Samantha Wright 34 | samantha.wright@gmail.com 35 | 800-555-1212 36 | 37 | 38 | PO-12345 39 | 40 | appliance 41 | 42 | 2022-04-13T20:20:39+00:00 43 | 2023-04-13T20:20:39+00:00 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /testdata/valid-component-hashes.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | acme-example 6 | 1.0.0 7 | 8 | 641b6e166f8b33c5e959e2adcc18b1c7 9 | 9188560f22e0b73070d2efce670c74af2bdf30af 10 | d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964 11 | d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad 12 | 74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6 13 | 7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa 14 | a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5 15 | 7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20 16 | d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237 17 | e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a 18 | f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d 19 | 26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.idea/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /testdata/valid-compositions.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "component": { 8 | "bom-ref": "acme-application-1.0", 9 | "type": "application", 10 | "name": "Acme Application", 11 | "version": "1.0" 12 | } 13 | }, 14 | "components": [ 15 | { 16 | "bom-ref": "pkg:maven/partner/shaded-library@1.0", 17 | "type": "library", 18 | "name": "Partner Shaded Library", 19 | "version": "1.0", 20 | "purl": "pkg:maven/partner/shaded-library@1.0", 21 | "components": [ 22 | { 23 | "bom-ref": "pkg:maven/ossproject/library@2.0", 24 | "type": "library", 25 | "name": "Some Opensource Library", 26 | "version": "2.0", 27 | "purl": "pkg:maven/ossproject/library@2.0" 28 | } 29 | ] 30 | }, 31 | { 32 | "type": "library", 33 | "name": "Acme Library", 34 | "version": "3.0", 35 | "purl": "pkg:maven/acme/library@3.0" 36 | } 37 | ], 38 | "dependencies": [ 39 | { 40 | "ref": "acme-application-1.0", 41 | "dependsOn": [ 42 | "pkg:maven/partner/shaded-library@1.0", 43 | "pkg:maven/acme/library@3.0" 44 | ] 45 | } 46 | ], 47 | "vulnerabilities": [ 48 | { 49 | "bom-ref": "vulnerability-1", 50 | "id": "ACME-12345", 51 | "source": { 52 | "name": "Acme Inc" 53 | } 54 | } 55 | ], 56 | "compositions": [ 57 | { 58 | "bom-ref": "composition-1", 59 | "aggregate": "complete", 60 | "assemblies": [ 61 | "pkg:maven/partner/shaded-library@1.0" 62 | ], 63 | "dependencies": [ 64 | "acme-application-1.0" 65 | ] 66 | }, 67 | { 68 | "aggregate": "unknown", 69 | "assemblies": [ 70 | "pkg:maven/acme/library@3.0" 71 | ] 72 | }, 73 | { 74 | "aggregate": "incomplete_first_party_only", 75 | "vulnerabilities": [ 76 | "vulnerability-1" 77 | ] 78 | } 79 | ] 80 | } 81 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-compositions.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "metadata": { 7 | "component": { 8 | "bom-ref": "acme-application-1.0", 9 | "type": "application", 10 | "name": "Acme Application", 11 | "version": "1.0" 12 | } 13 | }, 14 | "components": [ 15 | { 16 | "bom-ref": "pkg:maven/partner/shaded-library@1.0", 17 | "type": "library", 18 | "name": "Partner Shaded Library", 19 | "version": "1.0", 20 | "purl": "pkg:maven/partner/shaded-library@1.0", 21 | "components": [ 22 | { 23 | "bom-ref": "pkg:maven/ossproject/library@2.0", 24 | "type": "library", 25 | "name": "Some Opensource Library", 26 | "version": "2.0", 27 | "purl": "pkg:maven/ossproject/library@2.0" 28 | } 29 | ] 30 | }, 31 | { 32 | "type": "library", 33 | "name": "Acme Library", 34 | "version": "3.0", 35 | "purl": "pkg:maven/acme/library@3.0" 36 | } 37 | ], 38 | "dependencies": [ 39 | { 40 | "ref": "acme-application-1.0", 41 | "dependsOn": [ 42 | "pkg:maven/partner/shaded-library@1.0", 43 | "pkg:maven/acme/library@3.0" 44 | ] 45 | } 46 | ], 47 | "compositions": [ 48 | { 49 | "bom-ref": "composition-1", 50 | "aggregate": "complete", 51 | "assemblies": [ 52 | "pkg:maven/partner/shaded-library@1.0" 53 | ], 54 | "dependencies": [ 55 | "acme-application-1.0" 56 | ] 57 | }, 58 | { 59 | "aggregate": "unknown", 60 | "assemblies": [ 61 | "pkg:maven/acme/library@3.0" 62 | ] 63 | }, 64 | { 65 | "aggregate": "incomplete_first_party_only", 66 | "vulnerabilities": [ 67 | "vulnerability-1" 68 | ] 69 | } 70 | ], 71 | "vulnerabilities": [ 72 | { 73 | "bom-ref": "vulnerability-1", 74 | "id": "ACME-12345", 75 | "source": { 76 | "name": "Acme Inc" 77 | } 78 | } 79 | ] 80 | } 81 | 82 | -------------------------------------------------------------------------------- /validate_json_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "errors" 22 | "fmt" 23 | 24 | "github.com/xeipuuv/gojsonschema" 25 | ) 26 | 27 | var jsonSchemaFiles = map[SpecVersion]string{ 28 | SpecVersion1_2: "file://./schema/bom-1.2.schema.json", 29 | SpecVersion1_3: "file://./schema/bom-1.3.schema.json", 30 | SpecVersion1_4: "file://./schema/bom-1.4.schema.json", 31 | SpecVersion1_5: "file://./schema/bom-1.5.schema.json", 32 | SpecVersion1_6: "file://./schema/bom-1.6.schema.json", 33 | } 34 | 35 | type jsonValidator struct{} 36 | 37 | func newJSONValidator() validator { 38 | return &jsonValidator{} 39 | } 40 | 41 | func (jv jsonValidator) Validate(bom []byte, specVersion SpecVersion) error { 42 | schemaFilePath, ok := jsonSchemaFiles[specVersion] 43 | if !ok { 44 | return fmt.Errorf("no json schema known for spec version %s", specVersion) 45 | } 46 | 47 | schemaLoader := gojsonschema.NewReferenceLoader(schemaFilePath) 48 | documentLoader := gojsonschema.NewBytesLoader(bom) 49 | 50 | result, err := gojsonschema.Validate(schemaLoader, documentLoader) 51 | if err != nil { 52 | return fmt.Errorf("failed to validate: %w", err) 53 | } 54 | 55 | if result.Valid() { 56 | return nil 57 | } 58 | 59 | errSummary := fmt.Sprintf("encountered %d validation errors:", len(result.Errors())) 60 | for _, verr := range result.Errors() { 61 | errSummary += fmt.Sprintf("\n - %s", verr.String()) 62 | } 63 | 64 | return errors.New(errSummary) 65 | } 66 | -------------------------------------------------------------------------------- /cyclonedx_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "testing" 22 | 23 | "github.com/bradleyjkemp/cupaloy/v2" 24 | "github.com/stretchr/testify/assert" 25 | "github.com/stretchr/testify/require" 26 | ) 27 | 28 | var snapShooter = cupaloy.NewDefaultConfig(). 29 | WithOptions(cupaloy.SnapshotSubdirectory("./testdata/snapshots")) 30 | 31 | func TestBool(t *testing.T) { 32 | assert.Equal(t, true, *Bool(true)) 33 | assert.Equal(t, false, *Bool(false)) 34 | } 35 | 36 | func TestMediaType_WithVersion(t *testing.T) { 37 | t.Run("ShouldReturnVersionedMediaType", func(t *testing.T) { 38 | res, err := MediaTypeJSON.WithVersion(SpecVersion1_2) 39 | require.NoError(t, err) 40 | require.Equal(t, "application/vnd.cyclonedx+json; version=1.2", res) 41 | }) 42 | 43 | t.Run("ShouldReturnErrorForSpecLowerThan1.2AndJSON", func(t *testing.T) { 44 | _, err := MediaTypeJSON.WithVersion(SpecVersion1_1) 45 | require.Error(t, err) 46 | }) 47 | } 48 | 49 | func TestVulnerability_Properties(t *testing.T) { 50 | // GIVEN 51 | properties := []Property{} 52 | vuln := Vulnerability{ 53 | Properties: &properties, 54 | } 55 | 56 | // EXPECT 57 | assert.Equal(t, 0, len(*vuln.Properties)) 58 | } 59 | 60 | func assertValidBOM(t *testing.T, bomBytes []byte, format BOMFileFormat, version SpecVersion) { 61 | var v validator 62 | if format == BOMFileFormatJSON { 63 | v = newJSONValidator() 64 | } else { 65 | v = newXMLValidator() 66 | } 67 | err := v.Validate(bomBytes, version) 68 | require.NoError(t, err) 69 | } 70 | -------------------------------------------------------------------------------- /validate_xml_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "fmt" 22 | "sync" 23 | 24 | "github.com/terminalstatic/go-xsd-validate" 25 | ) 26 | 27 | var xmlSchemaFiles = map[SpecVersion]string{ 28 | SpecVersion1_0: "./schema/bom-1.0.xsd", 29 | SpecVersion1_1: "./schema/bom-1.1.xsd", 30 | SpecVersion1_2: "./schema/bom-1.2.xsd", 31 | SpecVersion1_3: "./schema/bom-1.3.xsd", 32 | SpecVersion1_4: "./schema/bom-1.4.xsd", 33 | SpecVersion1_5: "./schema/bom-1.5.xsd", 34 | SpecVersion1_6: "./schema/bom-1.6.xsd", 35 | } 36 | 37 | var xsdValidateInitOnce sync.Once 38 | 39 | type xmlValidator struct{} 40 | 41 | func newXMLValidator() validator { 42 | var initErr error 43 | xsdValidateInitOnce.Do(func() { 44 | initErr = xsdvalidate.Init() 45 | }) 46 | if initErr != nil { 47 | panic(initErr) 48 | } 49 | 50 | return &xmlValidator{} 51 | } 52 | 53 | func (xv xmlValidator) Validate(bom []byte, specVersion SpecVersion) error { 54 | schemaFilePath, ok := xmlSchemaFiles[specVersion] 55 | if !ok { 56 | return fmt.Errorf("no xml schema known for spec version %s", specVersion) 57 | } 58 | 59 | xsdHandler, err := xsdvalidate.NewXsdHandlerUrl(schemaFilePath, xsdvalidate.ParsErrVerbose) 60 | if err != nil { 61 | return fmt.Errorf("failed to parse schema: %w", err) 62 | } 63 | defer xsdHandler.Free() 64 | 65 | xmlHandler, err := xsdvalidate.NewXmlHandlerMem(bom, xsdvalidate.ParsErrVerbose) 66 | if err != nil { 67 | return fmt.Errorf("failed to parse bom xml: %w", err) 68 | } 69 | defer xmlHandler.Free() 70 | 71 | return xsdHandler.Validate(xmlHandler, xsdvalidate.ValidErrDefault) 72 | } 73 | -------------------------------------------------------------------------------- /testdata/valid-license-licensing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | cryptographic-provider 8 | 2.2.0 9 | 10 | 11 | Acme Commercial License 12 | 13 | 14 | acme 15 | acme-license 16 | 17 | 18 | 19 | Acme Inc 20 | 21 | Acme Licensing Fulfillment 22 | licensing@example.com 23 | 24 | 25 | 26 | 27 | 28 | Example Co. 29 | 30 | 31 | 32 | 33 | Samantha Wright 34 | samantha.wright@gmail.com 35 | 800-555-1212 36 | 37 | 38 | PO-12345 39 | 40 | appliance 41 | 42 | 2022-04-13T20:20:39+00:00 43 | 2023-04-13T20:20:39+00:00 44 | 45 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /testdata/valid-component-hashes.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-example", 10 | "version": "1.0.0", 11 | "hashes": [ 12 | { 13 | "alg": "MD5", 14 | "content": "641b6e166f8b33c5e959e2adcc18b1c7" 15 | }, 16 | { 17 | "alg": "SHA-1", 18 | "content": "9188560f22e0b73070d2efce670c74af2bdf30af" 19 | }, 20 | { 21 | "alg": "SHA-256", 22 | "content": "d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964" 23 | }, 24 | { 25 | "alg": "SHA-384", 26 | "content": "d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad" 27 | }, 28 | { 29 | "alg": "SHA-512", 30 | "content": "74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6" 31 | }, 32 | { 33 | "alg": "SHA3-256", 34 | "content": "7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa" 35 | }, 36 | { 37 | "alg": "SHA3-384", 38 | "content": "a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5" 39 | }, 40 | { 41 | "alg": "SHA3-512", 42 | "content": "7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20" 43 | }, 44 | { 45 | "alg": "BLAKE2b-256", 46 | "content": "d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237" 47 | }, 48 | { 49 | "alg": "BLAKE2b-384", 50 | "content": "e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a" 51 | }, 52 | { 53 | "alg": "BLAKE2b-512", 54 | "content": "f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d" 55 | }, 56 | { 57 | "alg": "BLAKE3", 58 | "content": "26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-component-hashes.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "name": "acme-example", 10 | "version": "1.0.0", 11 | "hashes": [ 12 | { 13 | "alg": "MD5", 14 | "content": "641b6e166f8b33c5e959e2adcc18b1c7" 15 | }, 16 | { 17 | "alg": "SHA-1", 18 | "content": "9188560f22e0b73070d2efce670c74af2bdf30af" 19 | }, 20 | { 21 | "alg": "SHA-256", 22 | "content": "d88bc4e70bfb34d18b5542136639acbb26a8ae2429aa1e47489332fb389cc964" 23 | }, 24 | { 25 | "alg": "SHA-384", 26 | "content": "d4835048a0f57c74b8fb617d5366ab81376fc92bebe9a93bf24ba7f9da6c9aeeb6179f5d1361f6533211b15f3224cbad" 27 | }, 28 | { 29 | "alg": "SHA-512", 30 | "content": "74a51ff45e4c11df9ba1f0094282c80489649cb157a75fa337992d2d4592a5a1b8cb4525de8db0ae25233553924d76c36e093ea7fa9df4e5b8b07fd2e074efd6" 31 | }, 32 | { 33 | "alg": "SHA3-256", 34 | "content": "7478c7cf41c883a04ee89f1813f687886d53fa86f791fff90690c6221e3853aa" 35 | }, 36 | { 37 | "alg": "SHA3-384", 38 | "content": "a1eea7229716487ad2ebe96b2f997a8408f32f14047994fbcc99b49012cf86c96dbd518e5d57a61b0e57dd37dd0b48f5" 39 | }, 40 | { 41 | "alg": "SHA3-512", 42 | "content": "7d584825bc1767dfabe7e82b45ccb7a1119b145fa17e76b885e71429c706cef0a3171bc6575b968eec5da56a7966c02fec5402fcee55097ac01d40c550de9d20" 43 | }, 44 | { 45 | "alg": "BLAKE2b-256", 46 | "content": "d8779633380c050bccf4e733b763ab2abd8ad2db60b517d47fd29bbf76433237" 47 | }, 48 | { 49 | "alg": "BLAKE2b-384", 50 | "content": "e728ba56c2da995a559a178116c594e8bee4894a79ceb4399d8f479e5563cb1942b85936f646d14170717c576b14db7a" 51 | }, 52 | { 53 | "alg": "BLAKE2b-512", 54 | "content": "f8ce8d612a6c85c96cf7cebc230f6ddef26e6cedcfbc4a41c766033cc08c6ba097d1470948226807fb2d88d2a2b6fc0ff5e5440e93a603086fdd568bafcd1a9d" 55 | }, 56 | { 57 | "alg": "BLAKE3", 58 | "content": "26cdc7fb3fd65fc3b621a4ef70bc7d2489d5c19e70c76cf7ec20e538df0047cf" 59 | } 60 | ] 61 | } 62 | ] 63 | } 64 | 65 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-compositions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Application 6 | 1.0 7 | 8 | 9 | 10 | 11 | Partner Shaded Library 12 | 1.0 13 | pkg:maven/partner/shaded-library@1.0 14 | 15 | 16 | Some Opensource Library 17 | 2.0 18 | pkg:maven/ossproject/library@2.0 19 | 20 | 21 | 22 | 23 | Acme Library 24 | 2.0 25 | pkg:maven/acme/library@3.0 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | complete 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | unknown 46 | 47 | 48 | 49 | 50 | 51 | incomplete_first_party_only 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | ACME-12345 60 | 61 | Acme Inc 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/bradleyjkemp/cupaloy/v2 v2.8.0 h1:any4BmKE+jGIaMpnU8YgH/I2LPiLBufr6oMMlVBbn9M= 2 | github.com/bradleyjkemp/cupaloy/v2 v2.8.0/go.mod h1:bm7JXdkRd4BHJk9HpwqAI8BoAY1lps46Enkdqw6aRX0= 3 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 4 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 5 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 6 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 7 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 8 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 9 | github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 10 | github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= 11 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 12 | github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= 13 | github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= 14 | github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo= 15 | github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw= 16 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= 17 | github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= 18 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= 19 | github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= 20 | github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= 21 | github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= 22 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 23 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 24 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 25 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 26 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 27 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.acme 6 | stock-java-client 7 | 1.0.12 8 | 9 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 10 | 11 | 12 | 13 | Apache-2.0 14 | 15 | 16 | pkg:maven/com.acme/stock-java-client@1.0.12 17 | 18 | 19 | 20 | 21 | 22 | Partner Org 23 | https://partner.org 24 | 25 | Support 26 | support@partner 27 | 800-555-1212 28 | 29 | 30 | org.partner 31 | Stock ticker service 32 | 2020-Q2 33 | Provides real-time stock information 34 | 35 | https://partner.org/api/v1/lookup 36 | https://partner.org/api/v1/stock 37 | 38 | true 39 | true 40 | 41 | PII 42 | PIFI 43 | pubic 44 | partner-data 45 | 46 | 47 | 48 | Partner license 49 | 50 | 51 | 52 | 53 | http://partner.org 54 | 55 | 56 | http://api.partner.org/swagger 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /testdata/valid-compositions.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Application 6 | 1.0 7 | 8 | 9 | 10 | 11 | Partner Shaded Library 12 | 1.0 13 | pkg:maven/partner/shaded-library@1.0 14 | 15 | 16 | Some Opensource Library 17 | 2.0 18 | pkg:maven/ossproject/library@2.0 19 | 20 | 21 | 22 | 23 | Acme Library 24 | 2.0 25 | pkg:maven/acme/library@3.0 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | ACME-12345 37 | 38 | Acme Inc 39 | 40 | 41 | 42 | 43 | 44 | complete 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | unknown 54 | 55 | 56 | 57 | 58 | 59 | incomplete_first_party_only 60 | 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-patch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.acme 6 | sample-library 7 | 1.0.0 8 | 9 | 10 | 11 | org.example 12 | sample-library 13 | 1.0.0 14 | 15 | 16 | 17 | 18 | 19 | blah 20 | uri/to/changes.diff 21 | 22 | 23 | 24 | JIRA-17240 25 | Great new feature that does something 26 | 27 | Acme Org 28 | https://issues.acme.org/17240 29 | 30 | 31 | 32 | 33 | 34 | 35 | blah 36 | uri/to/changes.diff 37 | 38 | 39 | 40 | CVE-2019-9997 41 | CVE-2019-9997 42 | blah blah 43 | 44 | NVD 45 | https://nvd.nist.gov/vuln/detail/CVE-2019-9997 46 | 47 | 48 | http://some/other/site-1 49 | http://some/other/site-2 50 | 51 | 52 | 53 | JIRA-874319 54 | Enable to do something 55 | 56 | Example Org 57 | https://issues.example.org/874319 58 | 59 | 60 | http://some/other/site-1 61 | http://some/other/site-2 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /testdata/valid-patch.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "group": "com.acme", 10 | "name": "sample-library", 11 | "version": "1.0.0", 12 | "pedigree": { 13 | "ancestors": [ 14 | { 15 | "type": "library", 16 | "group": "org.example", 17 | "name": "sample-library", 18 | "version": "1.0.0" 19 | } 20 | ], 21 | "patches": [ 22 | { 23 | "type": "unofficial", 24 | "diff": { 25 | "text": { 26 | "contentType": "text/plain", 27 | "encoding": "base64", 28 | "content": "blah" 29 | }, 30 | "url": "uri/to/changes.diff" 31 | }, 32 | "resolves": [ 33 | { 34 | "type": "enhancement", 35 | "id": "JIRA-17240", 36 | "description": "Great new feature that does something", 37 | "source": { 38 | "name": "Acme Org", 39 | "url": "https://issues.acme.org/17240" 40 | } 41 | } 42 | ] 43 | }, 44 | { 45 | "type": "backport", 46 | "diff": { 47 | "text": { 48 | "contentType": "text/plain", 49 | "encoding": "base64", 50 | "content": "blah" 51 | }, 52 | "url": "uri/to/changes.diff" 53 | }, 54 | "resolves": [ 55 | { 56 | "type": "security", 57 | "id": "CVE-2019-9997", 58 | "name": "CVE-2019-9997", 59 | "description": "blah blah", 60 | "source": { 61 | "name": "NVD", 62 | "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997" 63 | }, 64 | "references": [ 65 | "http://some/other/site-1", 66 | "http://some/other/site-2" 67 | ] 68 | }, 69 | { 70 | "type": "defect", 71 | "id": "JIRA-874319", 72 | "description": "Enable to do something", 73 | "source": { 74 | "name": "Example Org", 75 | "url": "https://issues.example.org/874319" 76 | }, 77 | "references": [ 78 | "http://some/other/site-1", 79 | "http://some/other/site-2" 80 | ] 81 | } 82 | ] 83 | } 84 | ] 85 | } 86 | } 87 | ] 88 | } 89 | -------------------------------------------------------------------------------- /testdata/valid-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "pkg:npm/acme/component@1.0.0", 9 | "type": "library", 10 | "publisher": "Acme Inc", 11 | "group": "com.acme", 12 | "name": "stock-java-client", 13 | "version": "1.0.12", 14 | "hashes": [ 15 | { 16 | "alg": "SHA-1", 17 | "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a" 18 | } 19 | ], 20 | "licenses": [ 21 | { 22 | "license": { 23 | "id": "Apache-2.0" 24 | } 25 | } 26 | ], 27 | "purl": "pkg:maven/com.acme/stock-java-client@1.0.12" 28 | } 29 | ], 30 | "services": [ 31 | { 32 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 33 | "provider": { 34 | "name": "Partner Org", 35 | "url": [ 36 | "https://partner.org" 37 | ], 38 | "contact": [ 39 | { 40 | "name": "Support", 41 | "email": "support@partner.com", 42 | "phone": "800-555-1212" 43 | } 44 | ] 45 | }, 46 | "group": "org.partner", 47 | "name": "Stock ticker service", 48 | "version": "2020-Q2", 49 | "description": "Provides real-time stock information", 50 | "endpoints": [ 51 | "https://partner.org/api/v1/lookup", 52 | "https://partner.org/api/v1/stock" 53 | ], 54 | "authenticated": true, 55 | "x-trust-boundary": true, 56 | "data": [ 57 | { 58 | "classification": "PII", 59 | "flow": "inbound" 60 | }, 61 | { 62 | "classification": "PIFI", 63 | "flow": "outbound" 64 | }, 65 | { 66 | "classification": "pubic", 67 | "flow": "bi-directional" 68 | }, 69 | { 70 | "classification": "partner-data", 71 | "flow": "unknown" 72 | } 73 | ], 74 | "licenses": [ 75 | { 76 | "license": { 77 | "name": "Partner license" 78 | } 79 | } 80 | ], 81 | "externalReferences": [ 82 | { 83 | "type": "website", 84 | "url": "http://partner.org" 85 | }, 86 | { 87 | "type": "documentation", 88 | "url": "http://api.partner.org/swagger" 89 | } 90 | ] 91 | } 92 | ], 93 | "dependencies": [ 94 | { 95 | "ref": "pkg:maven/com.acme/stock-java-client@1.0.12", 96 | "dependsOn": [ 97 | "b2a46a4b-8367-4bae-9820-95557cfe03a8" 98 | ] 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-patch.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "library", 9 | "group": "com.acme", 10 | "name": "sample-library", 11 | "version": "1.0.0", 12 | "pedigree": { 13 | "ancestors": [ 14 | { 15 | "type": "library", 16 | "group": "org.example", 17 | "name": "sample-library", 18 | "version": "1.0.0" 19 | } 20 | ], 21 | "patches": [ 22 | { 23 | "diff": { 24 | "text": { 25 | "content": "blah", 26 | "contentType": "text/plain", 27 | "encoding": "base64" 28 | }, 29 | "url": "uri/to/changes.diff" 30 | }, 31 | "resolves": [ 32 | { 33 | "id": "JIRA-17240", 34 | "description": "Great new feature that does something", 35 | "source": { 36 | "name": "Acme Org", 37 | "url": "https://issues.acme.org/17240" 38 | }, 39 | "type": "enhancement" 40 | } 41 | ], 42 | "type": "unofficial" 43 | }, 44 | { 45 | "diff": { 46 | "text": { 47 | "content": "blah", 48 | "contentType": "text/plain", 49 | "encoding": "base64" 50 | }, 51 | "url": "uri/to/changes.diff" 52 | }, 53 | "resolves": [ 54 | { 55 | "id": "CVE-2019-9997", 56 | "name": "CVE-2019-9997", 57 | "description": "blah blah", 58 | "source": { 59 | "name": "NVD", 60 | "url": "https://nvd.nist.gov/vuln/detail/CVE-2019-9997" 61 | }, 62 | "references": [ 63 | "http://some/other/site-1", 64 | "http://some/other/site-2" 65 | ], 66 | "type": "security" 67 | }, 68 | { 69 | "id": "JIRA-874319", 70 | "description": "Enable to do something", 71 | "source": { 72 | "name": "Example Org", 73 | "url": "https://issues.example.org/874319" 74 | }, 75 | "references": [ 76 | "http://some/other/site-1", 77 | "http://some/other/site-2" 78 | ], 79 | "type": "defect" 80 | } 81 | ], 82 | "type": "backport" 83 | } 84 | ] 85 | } 86 | } 87 | ] 88 | } 89 | 90 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-service.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "pkg:npm/acme/component@1.0.0", 9 | "type": "library", 10 | "publisher": "Acme Inc", 11 | "group": "com.acme", 12 | "name": "stock-java-client", 13 | "version": "1.0.12", 14 | "hashes": [ 15 | { 16 | "alg": "SHA-1", 17 | "content": "e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a" 18 | } 19 | ], 20 | "licenses": [ 21 | { 22 | "license": { 23 | "id": "Apache-2.0" 24 | } 25 | } 26 | ], 27 | "purl": "pkg:maven/com.acme/stock-java-client@1.0.12" 28 | } 29 | ], 30 | "services": [ 31 | { 32 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 33 | "provider": { 34 | "name": "Partner Org", 35 | "url": [ 36 | "https://partner.org" 37 | ], 38 | "contact": [ 39 | { 40 | "name": "Support", 41 | "email": "support@partner.com", 42 | "phone": "800-555-1212" 43 | } 44 | ] 45 | }, 46 | "group": "org.partner", 47 | "name": "Stock ticker service", 48 | "version": "2020-Q2", 49 | "description": "Provides real-time stock information", 50 | "endpoints": [ 51 | "https://partner.org/api/v1/lookup", 52 | "https://partner.org/api/v1/stock" 53 | ], 54 | "authenticated": true, 55 | "x-trust-boundary": true, 56 | "data": [ 57 | { 58 | "flow": "inbound", 59 | "classification": "PII" 60 | }, 61 | { 62 | "flow": "outbound", 63 | "classification": "PIFI" 64 | }, 65 | { 66 | "flow": "bi-directional", 67 | "classification": "pubic" 68 | }, 69 | { 70 | "flow": "unknown", 71 | "classification": "partner-data" 72 | } 73 | ], 74 | "licenses": [ 75 | { 76 | "license": { 77 | "name": "Partner license" 78 | } 79 | } 80 | ], 81 | "externalReferences": [ 82 | { 83 | "url": "http://partner.org", 84 | "type": "website" 85 | }, 86 | { 87 | "url": "http://api.partner.org/swagger", 88 | "type": "documentation" 89 | } 90 | ] 91 | } 92 | ], 93 | "dependencies": [ 94 | { 95 | "ref": "pkg:maven/com.acme/stock-java-client@1.0.12", 96 | "dependsOn": [ 97 | "b2a46a4b-8367-4bae-9820-95557cfe03a8" 98 | ] 99 | } 100 | ] 101 | } 102 | 103 | -------------------------------------------------------------------------------- /testdata/valid-service.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.acme 6 | stock-java-client 7 | 1.0.12 8 | 9 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 10 | 11 | 12 | 13 | Apache-2.0 14 | 15 | 16 | pkg:maven/com.acme/stock-java-client@1.0.12 17 | 18 | 19 | 20 | 21 | 22 | Partner Org 23 | https://partner.org 24 | 25 | Support 26 | support@partner 27 | 800-555-1212 28 | 29 | 30 | org.partner 31 | Stock ticker service 32 | 2020-Q2 33 | Provides real-time stock information 34 | 35 | https://partner.org/api/v1/lookup 36 | https://partner.org/api/v1/stock 37 | 38 | true 39 | true 40 | 41 | PII 42 | PIFI 43 | pubic 44 | partner-data 45 | 46 | 47 | 48 | Partner license 49 | 50 | 51 | 52 | 53 | http://partner.org 54 | 55 | 56 | http://api.partner.org/swagger 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /roundtrip_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "bytes" 22 | "os" 23 | "path/filepath" 24 | "testing" 25 | 26 | "github.com/stretchr/testify/assert" 27 | "github.com/stretchr/testify/require" 28 | ) 29 | 30 | func TestRoundTripJSON(t *testing.T) { 31 | bomFilePaths, err := filepath.Glob("./testdata/*.json") 32 | require.NoError(t, err) 33 | 34 | for _, bomFilePath := range bomFilePaths { 35 | t.Run(filepath.Base(bomFilePath), func(t *testing.T) { 36 | // Read original BOM JSON 37 | inputFile, err := os.Open(bomFilePath) 38 | require.NoError(t, err) 39 | 40 | // Decode BOM 41 | var bom BOM 42 | require.NoError(t, NewBOMDecoder(inputFile, BOMFileFormatJSON).Decode(&bom)) 43 | inputFile.Close() 44 | 45 | // Prepare encoding destination 46 | buf := bytes.Buffer{} 47 | 48 | // Encode BOM again 49 | err = NewBOMEncoder(&buf, BOMFileFormatJSON). 50 | SetPretty(true). 51 | Encode(&bom) 52 | require.NoError(t, err) 53 | 54 | // Sanity checks: BOM has to be valid 55 | assertValidBOM(t, buf.Bytes(), BOMFileFormatJSON, SpecVersion1_6) 56 | 57 | // Compare with snapshot 58 | assert.NoError(t, snapShooter.SnapshotMulti(filepath.Base(bomFilePath), buf.String())) 59 | }) 60 | } 61 | } 62 | 63 | func TestRoundTripXML(t *testing.T) { 64 | bomFilePaths, err := filepath.Glob("./testdata/*.xml") 65 | require.NoError(t, err) 66 | 67 | for _, bomFilePath := range bomFilePaths { 68 | t.Run(filepath.Base(bomFilePath), func(t *testing.T) { 69 | // Read original BOM XML 70 | inputFile, err := os.Open(bomFilePath) 71 | require.NoError(t, err) 72 | 73 | // Decode BOM 74 | var bom BOM 75 | require.NoError(t, NewBOMDecoder(inputFile, BOMFileFormatXML).Decode(&bom)) 76 | inputFile.Close() 77 | 78 | // Prepare encoding destination 79 | buf := bytes.Buffer{} 80 | 81 | // Encode BOM again 82 | err = NewBOMEncoder(&buf, BOMFileFormatXML). 83 | SetPretty(true). 84 | Encode(&bom) 85 | require.NoError(t, err) 86 | 87 | // Sanity check: BOM has to be valid 88 | assertValidBOM(t, buf.Bytes(), BOMFileFormatXML, SpecVersion1_6) 89 | 90 | // Compare with snapshot 91 | assert.NoError(t, snapShooter.SnapshotMulti(filepath.Base(bomFilePath), buf.String())) 92 | }) 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /testdata/valid-annotation.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "component-a", 9 | "type": "library", 10 | "name": "Component A", 11 | "version": "1.0.0" 12 | } 13 | ], 14 | "annotations": [ 15 | { 16 | "bom-ref": "annotation-1", 17 | "subjects": [ 18 | "component-a" 19 | ], 20 | "annotator": { 21 | "organization": { 22 | "name": "Acme, Inc.", 23 | "url": [ 24 | "https://example.com" 25 | ], 26 | "contact": [ 27 | { 28 | "name": "Acme Professional Services", 29 | "email": "professional.services@example.com" 30 | } 31 | ] 32 | } 33 | }, 34 | "timestamp": "2022-01-01T00:00:00Z", 35 | "text": "This is a sample annotation made by an organization" 36 | }, 37 | { 38 | "bom-ref": "annotation-2", 39 | "subjects": [ 40 | "component-a" 41 | ], 42 | "annotator": { 43 | "individual": { 44 | "name": "Samantha Wright", 45 | "email": "samantha.wright@example.com", 46 | "phone": "800-555-1212" 47 | } 48 | }, 49 | "timestamp": "2022-01-01T00:00:00Z", 50 | "text": "This is a sample annotation made by a person" 51 | }, 52 | { 53 | "bom-ref": "annotation-3", 54 | "subjects": [ 55 | "component-a" 56 | ], 57 | "annotator": { 58 | "component": { 59 | "type": "application", 60 | "name": "Awesome Tool", 61 | "version": "9.1.2" 62 | } 63 | }, 64 | "timestamp": "2022-01-01T00:00:00Z", 65 | "text": "This is a sample annotation made by a component" 66 | }, 67 | { 68 | "bom-ref": "annotation-4", 69 | "subjects": [ 70 | "component-a" 71 | ], 72 | "annotator": { 73 | "service": { 74 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 75 | "provider": { 76 | "name": "Partner Org", 77 | "url": [ 78 | "https://partner.org" 79 | ] 80 | }, 81 | "group": "org.partner", 82 | "name": "BOM Annotation Service", 83 | "version": "2020-Q2", 84 | "endpoints": [ 85 | "https://partner.org/api/v1/inspect", 86 | "https://partner.org/api/v1/annotate" 87 | ], 88 | "authenticated": true, 89 | "x-trust-boundary": true, 90 | "data": [ 91 | { 92 | "classification": "public", 93 | "flow": "bi-directional" 94 | } 95 | ] 96 | } 97 | }, 98 | "timestamp": "2022-01-01T00:00:00Z", 99 | "text": "This is a sample annotation made by a service" 100 | } 101 | ] 102 | } -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestXmlBOMEncoder_EncodeVersion-func1-1.0.bom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Acme Inc 6 | com.acme 7 | tomcat-catalina 8 | 9.0.14 9 | Modified version of Apache Catalina 10 | required 11 | 12 | 3942447fac867ae5cdb3229b658f4d48 13 | e6b1000b94e835ffd37f4c6dcbdad43f4b48a02a 14 | f498a8ff2dd007e29c2074f5e4b01a9a01775c3ff3aeaf6906ea503bc5791b7b 15 | e8f33e424f3f4ed6db76a482fde1a5298970e442c531729119e37991884bdffab4f9426b7ee11fccd074eeda0634d71697d6f88a460dce0ac8d627a29f7d1282 16 | 17 | 18 | 19 | Apache-2.0 20 | 21 | 22 | pkg:maven/com.acme/tomcat-catalina@9.0.14?packaging=jar 23 | false 24 | 25 | 26 | org.example 27 | mylibrary 28 | 1.0.0 29 | required 30 | 31 | 2342c2eaf1feb9a80195dbaddf2ebaa3 32 | 68b78babe00a053f9e35ec6a2d9080f5b90122b0 33 | 708f1f53b41f11f02d12a11b1a38d2905d47b099afc71a0f1124ef8582ec7313 34 | 387b7ae16b9cae45f830671541539bf544202faae5aac544a93b7b0a04f5f846fa2f4e81ef3f1677e13aed7496408a441f5657ab6d54423e56bf6f38da124aef 35 | 36 | Copyright Example Inc. All rights reserved. 37 | cpe:/a:example:myapplication:1.0.0 38 | pkg:maven/com.example/myapplication@1.0.0?packaging=war 39 | false 40 | 41 | 42 | com.example 43 | myframework 44 | 1.0.0 45 | Example Inc, enterprise framework 46 | required 47 | 48 | cfcb0b64aacd2f81c1cd546543de965a 49 | 7fbeef2346c45d565c3341f037bce4e088af8a52 50 | 0384db3cec55d86a6898c489fdb75a8e75fe66b26639634983d2f3c3558493d1 51 | 854909cdb9e3ca183056837144aab6d8069b377bd66445087cc7157bf0c3f620418705dd0b83bdc2f73a508c2bdb316ca1809d75ee6972d02023a3e7dd655c79 52 | 53 | 54 | 55 | Some random license 56 | 57 | 58 | pkg:maven/com.example/myframework@1.0.0?packaging=war 59 | false 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /decode_test.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "strings" 22 | "testing" 23 | 24 | "github.com/stretchr/testify/assert" 25 | "github.com/stretchr/testify/require" 26 | ) 27 | 28 | func TestNewBOMDecoder(t *testing.T) { 29 | assert.IsType(t, &jsonBOMDecoder{}, NewBOMDecoder(nil, BOMFileFormatJSON)) 30 | assert.IsType(t, &xmlBOMDecoder{}, NewBOMDecoder(nil, BOMFileFormatXML)) 31 | } 32 | 33 | func TestXmlBOMDecoder_Decode_InvalidXML(t *testing.T) { 34 | var bom BOM 35 | err := NewBOMDecoder(strings.NewReader("invalid"), BOMFileFormatXML).Decode(&bom) 36 | require.Error(t, err) 37 | } 38 | 39 | func TestJsonBOMDecoder_Decode_InvalidJson(t *testing.T) { 40 | var bom BOM 41 | err := NewBOMDecoder(strings.NewReader("{}invalid"), BOMFileFormatJSON).Decode(&bom) 42 | require.Error(t, err) 43 | } 44 | 45 | func TestXmlBOMDecoder_Decode(t *testing.T) { 46 | t.Run("ShouldSetSpecVersion", func(t *testing.T) { 47 | testCases := []struct { 48 | bomContent string 49 | specVersion SpecVersion 50 | }{ 51 | { 52 | bomContent: ``, 53 | specVersion: SpecVersion1_0, 54 | }, 55 | { 56 | bomContent: ``, 57 | specVersion: SpecVersion1_1, 58 | }, 59 | { 60 | bomContent: ``, 61 | specVersion: SpecVersion1_2, 62 | }, 63 | { 64 | bomContent: ``, 65 | specVersion: SpecVersion1_3, 66 | }, 67 | { 68 | bomContent: ``, 69 | specVersion: SpecVersion1_4, 70 | }, 71 | { 72 | bomContent: ``, 73 | specVersion: SpecVersion(0), 74 | }, 75 | } 76 | 77 | for _, tc := range testCases { 78 | t.Run(tc.specVersion.String(), func(t *testing.T) { 79 | var bom BOM 80 | err := NewBOMDecoder(strings.NewReader(tc.bomContent), BOMFileFormatXML).Decode(&bom) 81 | require.NoError(t, err) 82 | require.Equal(t, tc.specVersion, bom.SpecVersion) 83 | }) 84 | } 85 | }) 86 | } 87 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-annotation.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "bom-ref": "component-a", 9 | "type": "library", 10 | "name": "Component A", 11 | "version": "1.0.0" 12 | } 13 | ], 14 | "annotations": [ 15 | { 16 | "bom-ref": "annotation-1", 17 | "subjects": [ 18 | "component-a" 19 | ], 20 | "annotator": { 21 | "organization": { 22 | "name": "Acme, Inc.", 23 | "url": [ 24 | "https://example.com" 25 | ], 26 | "contact": [ 27 | { 28 | "name": "Acme Professional Services", 29 | "email": "professional.services@example.com" 30 | } 31 | ] 32 | } 33 | }, 34 | "timestamp": "2022-01-01T00:00:00Z", 35 | "text": "This is a sample annotation made by an organization" 36 | }, 37 | { 38 | "bom-ref": "annotation-2", 39 | "subjects": [ 40 | "component-a" 41 | ], 42 | "annotator": { 43 | "individual": { 44 | "name": "Samantha Wright", 45 | "email": "samantha.wright@example.com", 46 | "phone": "800-555-1212" 47 | } 48 | }, 49 | "timestamp": "2022-01-01T00:00:00Z", 50 | "text": "This is a sample annotation made by a person" 51 | }, 52 | { 53 | "bom-ref": "annotation-3", 54 | "subjects": [ 55 | "component-a" 56 | ], 57 | "annotator": { 58 | "component": { 59 | "type": "application", 60 | "name": "Awesome Tool", 61 | "version": "9.1.2" 62 | } 63 | }, 64 | "timestamp": "2022-01-01T00:00:00Z", 65 | "text": "This is a sample annotation made by a component" 66 | }, 67 | { 68 | "bom-ref": "annotation-4", 69 | "subjects": [ 70 | "component-a" 71 | ], 72 | "annotator": { 73 | "service": { 74 | "bom-ref": "b2a46a4b-8367-4bae-9820-95557cfe03a8", 75 | "provider": { 76 | "name": "Partner Org", 77 | "url": [ 78 | "https://partner.org" 79 | ] 80 | }, 81 | "group": "org.partner", 82 | "name": "BOM Annotation Service", 83 | "version": "2020-Q2", 84 | "endpoints": [ 85 | "https://partner.org/api/v1/inspect", 86 | "https://partner.org/api/v1/annotate" 87 | ], 88 | "authenticated": true, 89 | "x-trust-boundary": true, 90 | "data": [ 91 | { 92 | "flow": "bi-directional", 93 | "classification": "public" 94 | } 95 | ] 96 | } 97 | }, 98 | "timestamp": "2022-01-01T00:00:00Z", 99 | "text": "This is a sample annotation made by a service" 100 | } 101 | ] 102 | } 103 | 104 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Component A 6 | 1.0.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Acme, Inc. 17 | https://example.com 18 | 19 | Acme Professional Services 20 | professional.services@example.com 21 | 22 | 23 | 24 | 2020-04-07T07:01:00Z 25 | This is a sample annotation made by an organization 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Samantha Wright 34 | samantha.wright@example.com 35 | 800-555-1212 36 | 37 | 38 | 2020-04-07T07:01:00Z 39 | This is a sample annotation made by an person 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Awesome Tool 48 | 9.1.2 49 | 50 | 51 | 2020-04-07T07:01:00Z 52 | This is a sample annotation made by a component 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Partner Org 62 | https://partner.org 63 | 64 | Support 65 | support@partner 66 | 800-555-1212 67 | 68 | 69 | org.partner 70 | BOM Annotation Service 71 | 2020-Q2 72 | 73 | https://partner.org/api/v1/inspect 74 | https://partner.org/api/v1/annotate 75 | 76 | true 77 | true 78 | 79 | pubic 80 | 81 | 82 | 83 | 2020-04-07T07:01:00Z 84 | This is a sample annotation made by a service 85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /testdata/valid-patch.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.acme 6 | sample-library 7 | 1.0.0 8 | 9 | 10 | 11 | org.example 12 | sample-library 13 | 1.0.0 14 | 15 | 16 | 17 | 18 | 19 | blah 20 | uri/to/changes.diff 21 | 22 | 23 | 24 | JIRA-17240 25 | Great new feature that does something 26 | 27 | Acme Org 28 | https://issues.acme.org/17240 29 | 30 | 31 | 32 | 33 | 34 | 35 | blah 36 | uri/to/changes.diff 37 | 38 | 39 | 40 | CVE-2019-9997 41 | CVE-2019-9997 42 | blah blah 43 | 44 | NVD 45 | https://nvd.nist.gov/vuln/detail/CVE-2019-9997 46 | 47 | 48 | http://some/other/site-1 49 | http://some/other/site-2 50 | 51 | 52 | 53 | JIRA-874319 54 | Enable to do something 55 | 56 | Example Org 57 | https://issues.example.org/874319 58 | 59 | 60 | http://some/other/site-1 61 | http://some/other/site-2 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # cyclonedx-go 2 | 3 | [![Build Status](https://github.com/CycloneDX/cyclonedx-go/actions/workflows/ci.yml/badge.svg)](https://github.com/CycloneDX/cyclonedx-go/actions/workflows/ci.yml) 4 | [![Go Report Card](https://goreportcard.com/badge/github.com/CycloneDX/cyclonedx-go)](https://goreportcard.com/report/github.com/CycloneDX/cyclonedx-go) 5 | [![Go Reference](https://pkg.go.dev/badge/github.com/nscuro/cyclonedx-go.svg)](https://pkg.go.dev/github.com/CycloneDX/cyclonedx-go) 6 | [![License](https://img.shields.io/badge/license-Apache%202.0-brightgreen.svg)](LICENSE) 7 | [![Website](https://img.shields.io/badge/https://-cyclonedx.org-blue.svg)](https://cyclonedx.org/) 8 | [![Slack Invite](https://img.shields.io/badge/Slack-Join-blue?logo=slack&labelColor=393939)](https://cyclonedx.org/slack/invite) 9 | [![Group Discussion](https://img.shields.io/badge/discussion-groups.io-blue.svg)](https://groups.io/g/CycloneDX) 10 | [![Twitter](https://img.shields.io/twitter/url/http/shields.io.svg?style=social&label=Follow)](https://twitter.com/CycloneDX_Spec) 11 | 12 | *cyclonedx-go is a Go library to consume and produce CycloneDX Software Bill of Materials (SBOM)* 13 | 14 | > If you just want to create BOMs for your Go projects, see [*cyclonedx-gomod*](https://github.com/CycloneDX/cyclonedx-gomod) 15 | 16 | ## Installation 17 | 18 | ``` 19 | go get github.com/CycloneDX/cyclonedx-go 20 | ``` 21 | 22 | ## Usage 23 | 24 | Please refer to the module's [documentation](https://pkg.go.dev/github.com/CycloneDX/cyclonedx-go#section-documentation). 25 | Also, checkout the [`examples`](./example_test.go) to get an idea of how this library may be used. 26 | 27 | ## Compatibility 28 | 29 | | cyclonedx-go versions | Supported Go versions | Supported CycloneDX spec | 30 | |:---------------------:|:---------------------:|:------------------------:| 31 | | < v0.4.0 | 1.14+ | 1.2 | 32 | | == v0.4.0 | 1.14+ | 1.3 | 33 | | >= v0.5.0, < v0.7.0 | 1.15+ | 1.4 | 34 | | >= v0.7.0, < v0.8.0 | 1.17+ | 1.0-1.4 | 35 | | == v0.8.0 | 1.18+ | 1.0-1.5 | 36 | | >= v0.9.0 | 1.20+ | 1.0-1.6 | 37 | 38 | We're aiming to support all [officially supported](https://golang.org/doc/devel/release.html#policy) Go versions, plus 39 | an additional older version. 40 | 41 | Prior to v0.7.0, this library only supported the latest version of the CycloneDX specification. While it is generally 42 | possible to *read* BOMs of an older spec, *writing* would exclusively produce BOMs conforming to the latest supported spec. 43 | 44 | Starting with v0.7.0, writing BOMs conforming to all previous version of the spec is also possible. 45 | 46 | ## Copyright & License 47 | 48 | CycloneDX Go is Copyright (c) OWASP Foundation. All Rights Reserved. 49 | 50 | Permission to modify and redistribute is granted under the terms of the Apache 2.0 license. 51 | See the [LICENSE](./LICENSE) file for the full license. 52 | 53 | ## Contributing 54 | 55 | [![Open in Gitpod](https://gitpod.io/button/open-in-gitpod.svg)](https://gitpod.io/#https://github.com/CycloneDX/cyclonedx-go) 56 | 57 | Pull requests are welcome. But please read the 58 | [CycloneDX contributing guidelines](https://github.com/CycloneDX/.github/blob/master/CONTRIBUTING.md) first. 59 | 60 | It is generally expected that pull requests will include relevant tests. Tests are automatically run against all 61 | supported Go versions (see [Compatibility](#compatibility)) for every pull request. 62 | -------------------------------------------------------------------------------- /testdata/valid-evidence.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "group": "com.google.code.findbugs", 10 | "name": "findbugs-project", 11 | "version": "3.0.0", 12 | "licenses": [ 13 | { 14 | "license": { 15 | "id": "LGPL-3.0-or-later", 16 | "url": "https://www.gnu.org/licenses/lgpl-3.0-standalone.html" 17 | } 18 | } 19 | ], 20 | "purl": "pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0", 21 | "evidence": { 22 | "identity": [ 23 | { 24 | "field": "purl", 25 | "confidence": 1, 26 | "methods": [ 27 | { 28 | "technique": "filename", 29 | "confidence": 0.1, 30 | "value": "findbugs-project-3.0.0.jar" 31 | }, 32 | { 33 | "technique": "ast-fingerprint", 34 | "confidence": 0.9, 35 | "value": "61e4bc08251761c3a73b606b9110a65899cb7d44f3b14c81ebc1e67c98e1d9ab" 36 | }, 37 | { 38 | "technique": "hash-comparison", 39 | "confidence": 0.7, 40 | "value": "7c547a9d67cc7bc315c93b6e2ff8e4b6b41ae5be454ac249655ecb5ca2a85abf" 41 | } 42 | ], 43 | "tools": [ 44 | "bom-ref-of-tool-that-performed-analysis" 45 | ] 46 | } 47 | ], 48 | "occurrences": [ 49 | { 50 | "bom-ref": "d6bf237e-4e11-4713-9f62-56d18d5e2079", 51 | "location": "/path/to/component" 52 | }, 53 | { 54 | "bom-ref": "b574d5d1-e3cf-4dcd-9ba5-f3507eb1b175", 55 | "location": "/another/path/to/component" 56 | } 57 | ], 58 | "callstack": { 59 | "frames": [ 60 | { 61 | 62 | "package": "com.apache.logging.log4j.core", 63 | "module": "Logger.class", 64 | "function": "logMessage", 65 | "parameters": [ 66 | "com.acme.HelloWorld", "Level.INFO", "null", "Hello World" 67 | ], 68 | "line": 150, 69 | "column": 17, 70 | "fullFilename": "/path/to/log4j-core-2.14.0.jar!/org/apache/logging/log4j/core/Logger.class" 71 | }, 72 | { 73 | "module": "HelloWorld.class", 74 | "function": "main", 75 | "line": 20, 76 | "column": 12, 77 | "fullFilename": "/path/to/HelloWorld.class" 78 | } 79 | ] 80 | }, 81 | "licenses": [ 82 | { 83 | "license": { 84 | "id": "Apache-2.0", 85 | "url": "http://www.apache.org/licenses/LICENSE-2.0" 86 | } 87 | }, 88 | { 89 | "license": { 90 | "id": "LGPL-2.1-only", 91 | "url": "https://opensource.org/licenses/LGPL-2.1" 92 | } 93 | } 94 | ], 95 | "copyright": [ 96 | { 97 | "text": "Copyright 2012 Google Inc. All Rights Reserved." 98 | }, 99 | { 100 | "text": "Copyright (C) 2004,2005 Dave Brosius " 101 | }, 102 | { 103 | "text": "Copyright (C) 2005 William Pugh" 104 | }, 105 | { 106 | "text": "Copyright (C) 2004,2005 University of Maryland" 107 | } 108 | ] 109 | } 110 | } 111 | ] 112 | } 113 | -------------------------------------------------------------------------------- /testdata/valid-annotation.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Component A 6 | 1.0.0 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Acme, Inc. 17 | https://example.com 18 | 19 | Acme Professional Services 20 | professional.services@example.com 21 | 22 | 23 | 24 | 2020-04-07T07:01:00Z 25 | This is a sample annotation made by an organization 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | Samantha Wright 34 | samantha.wright@example.com 35 | 800-555-1212 36 | 37 | 38 | 2020-04-07T07:01:00Z 39 | This is a sample annotation made by an person 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | Awesome Tool 48 | 9.1.2 49 | 50 | 51 | 2020-04-07T07:01:00Z 52 | This is a sample annotation made by a component 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | Partner Org 62 | https://partner.org 63 | 64 | Support 65 | support@partner 66 | 800-555-1212 67 | 68 | 69 | org.partner 70 | BOM Annotation Service 71 | 2020-Q2 72 | 73 | https://partner.org/api/v1/inspect 74 | https://partner.org/api/v1/annotate 75 | 76 | true 77 | true 78 | 79 | pubic 80 | 81 | 82 | 83 | 2020-04-07T07:01:00Z 84 | This is a sample annotation made by a service 85 | 86 | 87 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripJSON-func1-valid-evidence.json: -------------------------------------------------------------------------------- 1 | { 2 | "bomFormat": "CycloneDX", 3 | "specVersion": "1.6", 4 | "serialNumber": "urn:uuid:3e671687-395b-41f5-a30f-a58921a69b79", 5 | "version": 1, 6 | "components": [ 7 | { 8 | "type": "application", 9 | "group": "com.google.code.findbugs", 10 | "name": "findbugs-project", 11 | "version": "3.0.0", 12 | "licenses": [ 13 | { 14 | "license": { 15 | "id": "LGPL-3.0-or-later", 16 | "url": "https://www.gnu.org/licenses/lgpl-3.0-standalone.html" 17 | } 18 | } 19 | ], 20 | "purl": "pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0", 21 | "evidence": { 22 | "identity": [ 23 | { 24 | "field": "purl", 25 | "confidence": 1, 26 | "methods": [ 27 | { 28 | "technique": "filename", 29 | "confidence": 0.1, 30 | "value": "findbugs-project-3.0.0.jar" 31 | }, 32 | { 33 | "technique": "ast-fingerprint", 34 | "confidence": 0.9, 35 | "value": "61e4bc08251761c3a73b606b9110a65899cb7d44f3b14c81ebc1e67c98e1d9ab" 36 | }, 37 | { 38 | "technique": "hash-comparison", 39 | "confidence": 0.7, 40 | "value": "7c547a9d67cc7bc315c93b6e2ff8e4b6b41ae5be454ac249655ecb5ca2a85abf" 41 | } 42 | ], 43 | "tools": [ 44 | "bom-ref-of-tool-that-performed-analysis" 45 | ] 46 | } 47 | ], 48 | "occurrences": [ 49 | { 50 | "bom-ref": "d6bf237e-4e11-4713-9f62-56d18d5e2079", 51 | "location": "/path/to/component" 52 | }, 53 | { 54 | "bom-ref": "b574d5d1-e3cf-4dcd-9ba5-f3507eb1b175", 55 | "location": "/another/path/to/component" 56 | } 57 | ], 58 | "callstack": { 59 | "frames": [ 60 | { 61 | "package": "com.apache.logging.log4j.core", 62 | "module": "Logger.class", 63 | "function": "logMessage", 64 | "parameters": [ 65 | "com.acme.HelloWorld", 66 | "Level.INFO", 67 | "null", 68 | "Hello World" 69 | ], 70 | "line": 150, 71 | "column": 17, 72 | "fullFilename": "/path/to/log4j-core-2.14.0.jar!/org/apache/logging/log4j/core/Logger.class" 73 | }, 74 | { 75 | "module": "HelloWorld.class", 76 | "function": "main", 77 | "line": 20, 78 | "column": 12, 79 | "fullFilename": "/path/to/HelloWorld.class" 80 | } 81 | ] 82 | }, 83 | "licenses": [ 84 | { 85 | "license": { 86 | "id": "Apache-2.0", 87 | "url": "http://www.apache.org/licenses/LICENSE-2.0" 88 | } 89 | }, 90 | { 91 | "license": { 92 | "id": "LGPL-2.1-only", 93 | "url": "https://opensource.org/licenses/LGPL-2.1" 94 | } 95 | } 96 | ], 97 | "copyright": [ 98 | { 99 | "text": "Copyright 2012 Google Inc. All Rights Reserved." 100 | }, 101 | { 102 | "text": "Copyright (C) 2004,2005 Dave Brosius \u003cdbrosius@users.sourceforge.net\u003e" 103 | }, 104 | { 105 | "text": "Copyright (C) 2005 William Pugh" 106 | }, 107 | { 108 | "text": "Copyright (C) 2004,2005 University of Maryland" 109 | } 110 | ] 111 | } 112 | } 113 | ] 114 | } 115 | 116 | -------------------------------------------------------------------------------- /testdata/snapshots/cyclonedx-go-TestRoundTripXML-func1-valid-evidence.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | com.google.code.findbugs 6 | findbugs-project 7 | 3.0.0 8 | 9 | 10 | LGPL-3.0-or-later 11 | https://www.gnu.org/licenses/lgpl-3.0-standalone.html 12 | 13 | 14 | pkg:maven/com.google.code.findbugs/findbugs-project@3.0.0 15 | 16 | 17 | purl 18 | 1 19 | 20 | 21 | filename 22 | 0.1 23 | findbugs-project-3.0.0.jar 24 | 25 | 26 | ast-fingerprint 27 | 0.9 28 | 61e4bc08251761c3a73b606b9110a65899cb7d44f3b14c81ebc1e67c98e1d9ab 29 | 30 | 31 | hash-comparison 32 | 0.7 33 | 7c547a9d67cc7bc315c93b6e2ff8e4b6b41ae5be454ac249655ecb5ca2a85abf 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | /path/to/component 43 | 44 | 45 | /another/path/to/component 46 | 47 | 48 | 49 | 50 | 51 | com.apache.logging.log4j.core 52 | Logger.class 53 | logMessage 54 | 55 | com.acme.HelloWorld 56 | Level.INFO 57 | null 58 | Hello World 59 | 60 | 150 61 | 17 62 | /path/to/log4j-core-2.14.0.jar!/org/apache/logging/log4j/core/Logger.class 63 | 64 | 65 | HelloWorld.class 66 | main 67 | 20 68 | 12 69 | /path/to/HelloWorld.class 70 | 71 | 72 | 73 | 74 | 75 | Apache-2.0 76 | http://www.apache.org/licenses/LICENSE-2.0 77 | 78 | 79 | LGPL-2.1-only 80 | https://opensource.org/licenses/LGPL-2.1 81 | 82 | 83 | 84 | Copyright 2012 Google Inc. All Rights Reserved. 85 | Copyright (C) 2004,2005 Dave Brosius <dbrosius@users.sourceforge.net> 86 | Copyright (C) 2005 William Pugh 87 | Copyright (C) 2004,2005 University of Maryland 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /encode.go: -------------------------------------------------------------------------------- 1 | // This file is part of CycloneDX Go 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the “License”); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an “AS IS” BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | // 15 | // SPDX-License-Identifier: Apache-2.0 16 | // Copyright (c) OWASP Foundation. All Rights Reserved. 17 | 18 | package cyclonedx 19 | 20 | import ( 21 | "encoding/json" 22 | "encoding/xml" 23 | "fmt" 24 | "io" 25 | ) 26 | 27 | type BOMEncoder interface { 28 | // Encode encodes a given BOM. 29 | Encode(bom *BOM) error 30 | 31 | // EncodeVersion encodes a given BOM in a specific version of the specification. 32 | // Choosing a lower spec version than what the BOM was constructed for will result 33 | // in loss of information. The original BOM struct is guaranteed to not be modified. 34 | EncodeVersion(bom *BOM, version SpecVersion) error 35 | 36 | // SetPretty toggles prettified output. 37 | SetPretty(pretty bool) BOMEncoder 38 | 39 | // SetEscapeHTML toggles escaped HTML output. 40 | SetEscapeHTML(escapeHTML bool) BOMEncoder 41 | } 42 | 43 | func NewBOMEncoder(writer io.Writer, format BOMFileFormat) BOMEncoder { 44 | if format == BOMFileFormatJSON { 45 | return &jsonBOMEncoder{writer: writer, escapeHTML: true} 46 | } 47 | return &xmlBOMEncoder{writer: writer} 48 | } 49 | 50 | type jsonBOMEncoder struct { 51 | writer io.Writer 52 | pretty bool 53 | escapeHTML bool 54 | } 55 | 56 | // Encode implements the BOMEncoder interface. 57 | func (j jsonBOMEncoder) Encode(bom *BOM) error { 58 | if bom.SpecVersion < SpecVersion1_2 { 59 | return fmt.Errorf("json format is not supported for specification versions lower than %s", SpecVersion1_2) 60 | } 61 | 62 | encoder := json.NewEncoder(j.writer) 63 | encoder.SetEscapeHTML(j.escapeHTML) 64 | if j.pretty { 65 | encoder.SetIndent("", " ") 66 | } 67 | 68 | return encoder.Encode(bom) 69 | } 70 | 71 | // EncodeVersion implements the BOMEncoder interface. 72 | func (j jsonBOMEncoder) EncodeVersion(bom *BOM, specVersion SpecVersion) (err error) { 73 | bom, err = bom.copyAndConvert(specVersion) 74 | if err != nil { 75 | return 76 | } 77 | 78 | return j.Encode(bom) 79 | } 80 | 81 | // SetPretty implements the BOMEncoder interface. 82 | func (j *jsonBOMEncoder) SetPretty(pretty bool) BOMEncoder { 83 | j.pretty = pretty 84 | return j 85 | } 86 | 87 | // SetEscapeHTML implements the BOMEncoder interface. 88 | func (j *jsonBOMEncoder) SetEscapeHTML(escapeHTML bool) BOMEncoder { 89 | j.escapeHTML = escapeHTML 90 | return j 91 | } 92 | 93 | type xmlBOMEncoder struct { 94 | writer io.Writer 95 | pretty bool 96 | } 97 | 98 | // Encode implements the BOMEncoder interface. 99 | func (x xmlBOMEncoder) Encode(bom *BOM) error { 100 | if _, err := fmt.Fprintf(x.writer, xml.Header); err != nil { 101 | return err 102 | } 103 | 104 | encoder := xml.NewEncoder(x.writer) 105 | if x.pretty { 106 | encoder.Indent("", " ") 107 | } 108 | 109 | return encoder.Encode(bom) 110 | } 111 | 112 | // EncodeVersion implements the BOMEncoder interface. 113 | func (x xmlBOMEncoder) EncodeVersion(bom *BOM, specVersion SpecVersion) (err error) { 114 | bom, err = bom.copyAndConvert(specVersion) 115 | if err != nil { 116 | return 117 | } 118 | 119 | return x.Encode(bom) 120 | } 121 | 122 | // SetPretty implements the BOMEncoder interface. 123 | func (x *xmlBOMEncoder) SetPretty(pretty bool) BOMEncoder { 124 | x.pretty = pretty 125 | return x 126 | } 127 | 128 | // SetEscapeHTML implements the BOMEncoder interface. 129 | func (j *xmlBOMEncoder) SetEscapeHTML(escapeHTML bool) BOMEncoder { 130 | // NOOP -- XML always needs to escape HTML 131 | return j 132 | } 133 | --------------------------------------------------------------------------------