diff --git a/changes/20f4328db25794b411a68fd7cdcc3f34.yaml b/changes/20f4328db25794b411a68fd7cdcc3f34.yaml new file mode 100644 index 00000000000..f7cc1a16862 --- /dev/null +++ b/changes/20f4328db25794b411a68fd7cdcc3f34.yaml @@ -0,0 +1,7 @@ +--- +desc: 'Added ``vaults`` to the Storm package definition schema, which enables declaring + vaults and their associated schemas.' +desc:literal: false +prs: [] +type: feat +... diff --git a/synapse/data/jsonschemas/json-schema.org/draft-07/schema b/synapse/data/jsonschemas/json-schema.org/draft-07/schema new file mode 100644 index 00000000000..5165426e1d9 --- /dev/null +++ b/synapse/data/jsonschemas/json-schema.org/draft-07/schema @@ -0,0 +1,244 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://json-schema.org/draft-07/schema#", + "title": "Core schema meta-schema", + "definitions": { + "schemaArray": { + "type": "array", + "minItems": 1, + "items": { + "$ref": "#" + } + }, + "nonNegativeInteger": { + "type": "integer", + "minimum": 0 + }, + "nonNegativeIntegerDefault0": { + "allOf": [ + { + "$ref": "#/definitions/nonNegativeInteger" + }, + { + "default": 0 + } + ] + }, + "simpleTypes": { + "enum": [ + "array", + "boolean", + "integer", + "null", + "number", + "object", + "string" + ] + }, + "stringArray": { + "type": "array", + "items": { + "type": "string" + }, + "uniqueItems": true, + "default": [] + } + }, + "type": [ + "object", + "boolean" + ], + "properties": { + "$id": { + "type": "string", + "format": "uri-reference" + }, + "$schema": { + "type": "string", + "format": "uri" + }, + "$ref": { + "type": "string", + "format": "uri-reference" + }, + "$comment": { + "type": "string" + }, + "title": { + "type": "string" + }, + "description": { + "type": "string" + }, + "default": true, + "readOnly": { + "type": "boolean", + "default": false + }, + "writeOnly": { + "type": "boolean", + "default": false + }, + "examples": { + "type": "array", + "items": true + }, + "multipleOf": { + "type": "number", + "exclusiveMinimum": 0 + }, + "maximum": { + "type": "number" + }, + "exclusiveMaximum": { + "type": "number" + }, + "minimum": { + "type": "number" + }, + "exclusiveMinimum": { + "type": "number" + }, + "maxLength": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "minLength": { + "$ref": "#/definitions/nonNegativeIntegerDefault0" + }, + "pattern": { + "type": "string", + "format": "regex" + }, + "additionalItems": { + "$ref": "#" + }, + "items": { + "anyOf": [ + { + "$ref": "#" + }, + { + "$ref": "#/definitions/schemaArray" + } + ], + "default": true + }, + "maxItems": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "minItems": { + "$ref": "#/definitions/nonNegativeIntegerDefault0" + }, + "uniqueItems": { + "type": "boolean", + "default": false + }, + "contains": { + "$ref": "#" + }, + "maxProperties": { + "$ref": "#/definitions/nonNegativeInteger" + }, + "minProperties": { + "$ref": "#/definitions/nonNegativeIntegerDefault0" + }, + "required": { + "$ref": "#/definitions/stringArray" + }, + "additionalProperties": { + "$ref": "#" + }, + "definitions": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "default": {} + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "default": {} + }, + "patternProperties": { + "type": "object", + "additionalProperties": { + "$ref": "#" + }, + "propertyNames": { + "format": "regex" + } + }, + "dependencies": { + "type": "object", + "additionalProperties": { + "anyOf": [ + { + "$ref": "#" + }, + { + "$ref": "#/definitions/stringArray" + } + ] + } + }, + "propertyNames": { + "$ref": "#" + }, + "const": true, + "enum": { + "type": "array", + "items": true, + "minItems": 1, + "uniqueItems": true + }, + "type": { + "anyOf": [ + { + "$ref": "#/definitions/simpleTypes" + }, + { + "type": "array", + "items": { + "$ref": "#/definitions/simpleTypes" + }, + "minItems": 1, + "uniqueItems": true + } + ] + }, + "format": { + "type": "string" + }, + "contentMediaType": { + "type": "string" + }, + "contentEncoding": { + "type": "string" + }, + "if": { + "$ref": "#" + }, + "then": { + "$ref": "#" + }, + "else": { + "$ref": "#" + }, + "allOf": { + "$ref": "#/definitions/schemaArray" + }, + "anyOf": { + "$ref": "#/definitions/schemaArray" + }, + "oneOf": { + "$ref": "#/definitions/schemaArray" + }, + "not": { + "$ref": "#" + } + }, + "default": true +} diff --git a/synapse/lib/schemas.py b/synapse/lib/schemas.py index 67fd03ee7e0..a724a95e281 100644 --- a/synapse/lib/schemas.py +++ b/synapse/lib/schemas.py @@ -790,6 +790,26 @@ 'required': ['name', 'varname', 'desc', 'type', 'scopes'], }, }, + 'vaults': { + 'type': 'object', + 'patternProperties': { + '^.*$': { + 'type': 'object', + 'properties': { + 'schemas': { + 'type': 'object', + 'properties': { + 'configs': {'$ref': 'https://json-schema.org/draft-07/schema'}, + 'secrets': {'$ref': 'https://json-schema.org/draft-07/schema'} + }, + 'additionalProperties': False, + }, + }, + 'additionalProperties': False, + }, + }, + 'additionalProperties': False, + } }, 'additionalProperties': True, 'required': ['name', 'version'], @@ -1063,7 +1083,7 @@ }, 'additionalItems': True, 'required': ('name',), - }, + } } } reqValidPkgdef = s_config.getJsValidator(_reqValidPkgdefSchema) diff --git a/synapse/tests/files/stormpkg/badvaultskeys.yaml b/synapse/tests/files/stormpkg/badvaultskeys.yaml new file mode 100644 index 00000000000..54d3b43d85e --- /dev/null +++ b/synapse/tests/files/stormpkg/badvaultskeys.yaml @@ -0,0 +1,16 @@ +name: badvaultskeys +version: 0.0.1 + +vaults: + badvaultskeys: + schemas: + newpconfigs: + type: object + properties: + foo: + type: string + newpsecrets: + type: object + properties: + quux: + type: string diff --git a/synapse/tests/files/stormpkg/badvaultsschema.yaml b/synapse/tests/files/stormpkg/badvaultsschema.yaml new file mode 100644 index 00000000000..41269d84951 --- /dev/null +++ b/synapse/tests/files/stormpkg/badvaultsschema.yaml @@ -0,0 +1,16 @@ +name: badvaultsschema +version: 0.0.1 + +vaults: + badvaultsschema: + schemas: + configs: + type: newpobject + properties: + foo: + type: string + secrets: + type: object + properties: + quux: + type: string diff --git a/synapse/tests/files/stormpkg/testpkg.yaml b/synapse/tests/files/stormpkg/testpkg.yaml index 6baaad1da00..a68f74a4266 100644 --- a/synapse/tests/files/stormpkg/testpkg.yaml +++ b/synapse/tests/files/stormpkg/testpkg.yaml @@ -109,6 +109,35 @@ configvars: workflowconfig: true type: [inet:fqdn, [str, inet:url]] +vaults: + testpkg: + schemas: + configs: + type: object + properties: + foo: + type: string + default: hehe haha + bar: + oneOf: + - { type: boolean } + - { type: string } + baz: + type: boolean + additionalProperties: false + required: + - bar + - baz + secrets: + type: object + properties: + quux: + type: string + minLength: 2 + additionalProperties: false + required: + - quux + commands: - name: testpkgcmd descr: | diff --git a/synapse/tests/test_tools_storm_pkg_gen.py b/synapse/tests/test_tools_storm_pkg_gen.py index 5e0087b1087..25f3fc2894a 100644 --- a/synapse/tests/test_tools_storm_pkg_gen.py +++ b/synapse/tests/test_tools_storm_pkg_gen.py @@ -84,6 +84,14 @@ async def test_tools_genpkg(self): ymlpath = s_common.genpath(dirname, 'files', 'stormpkg', 'badinits.yaml') await s_genpkg.main((ymlpath,)) + with self.raises(s_exc.SchemaViolation): + ymlpath = s_common.genpath(dirname, 'files', 'stormpkg', 'badvaultskeys.yaml') + await s_genpkg.main((ymlpath,)) + + with self.raises(s_exc.SchemaViolation): + ymlpath = s_common.genpath(dirname, 'files', 'stormpkg', 'badvaultsschema.yaml') + await s_genpkg.main((ymlpath,)) + ymlpath = s_common.genpath(dirname, 'files', 'stormpkg', 'testpkg.yaml') async with self.getTestCore() as core: @@ -147,6 +155,17 @@ async def test_tools_genpkg(self): self.eq(pdef['configvars'][1]['workflowconfig'], True) self.eq(pdef['configvars'][1]['type'], ['inet:fqdn', ['str', 'inet:url']]) + pvault = pdef['vaults']['testpkg'] + self.eq(pvault['schemas']['configs']['properties']['foo']['type'], 'string') + self.eq(pvault['schemas']['configs']['properties']['foo']['default'], 'hehe haha') + self.eq(pvault['schemas']['configs']['properties']['bar']['oneOf'][0]['type'], 'boolean') + self.eq(pvault['schemas']['configs']['properties']['bar']['oneOf'][1]['type'], 'string') + self.eq(pvault['schemas']['configs']['properties']['baz']['type'], 'boolean') + self.eq(pvault['schemas']['configs']['additionalProperties'], False) + self.eq(pvault['schemas']['secrets']['properties']['quux']['type'], 'string') + self.eq(pvault['schemas']['secrets']['properties']['quux']['minLength'], 2) + self.eq(pvault['schemas']['secrets']['required'], ('quux',)) + self.eq(pdef['optic']['files']['index.html']['file'], 'aGkK') self.eq(pdef['docs'][0]['title'], 'Foo Bar') @@ -172,6 +191,22 @@ async def test_tools_genpkg(self): self.eq(build.get('synapse:version'), s_version.verstring) self.eq(build.get('synapse:commit'), s_version.commit) + ret = await core.callStorm(''' + $s = $lib.pkg.get(testpkg).vaults.testpkg.schemas.configs + return($lib.json.schema($s).validate(({"bar": true, "baz": true}))) + ''') + self.eq([True, { + 'foo': 'hehe haha', + 'bar': True, + 'baz': True, + }], ret) + + ret = await core.callStorm(''' + $s = $lib.pkg.get(testpkg).vaults.testpkg.schemas.secrets + return($lib.json.schema($s).validate(({"quux": "foo"}))) + ''') + self.eq([True, {'quux': 'foo'}], ret) + # nodocs nodocspath = s_common.genpath(core.dirn, 'testpkg_nodocs.json') argv = ('--no-docs', '--save', nodocspath, ymlpath)