diff --git a/.spectral.yml b/.spectral.yml index dea8377..a728a67 100644 --- a/.spectral.yml +++ b/.spectral.yml @@ -10,6 +10,7 @@ functions: - conditionallyDefined - requireExampleOrRef - requireRequestBodyDescription + - xEnturPermissions rules: # ============================================================================= @@ -164,53 +165,11 @@ rules: # ------------------------------------------------------------------------- entur-permissions: - message: "x-entur-permissions must match the schema" documentationUrl: "https://github.com/entur/api-guidelines/blob/main/guidelines.md#233-documenting-permissions-for-partner-endpoints" severity: error given: $.paths.*[get,post,put,patch,delete,options,head,trace].x-entur-permissions then: - function: schema - functionOptions: - schema: - type: object - required: - - value - properties: - description: - type: string - value: - $ref: "#/$defs/permission-node" - $defs: - permission-node: - oneOf: - - $ref: "#/$defs/permission-leaf" - - $ref: "#/$defs/permission-all" - - $ref: "#/$defs/permission-any" - - permission-leaf: - type: string - pattern: "^[0-9a-zA-ZæøåØÆÅ][0-9a-zA-ZæøåØÆÅ.\\-]{0,99}:(les|opprett|endre|slett)$" - - permission-all: - type: object - required: - - all - properties: - all: - type: array - items: - - $ref: "#/$defs/permission-node" - - permission-any: - type: object - required: - - any - properties: - any: - type: array - items: - - $ref: "#/$defs/permission-node" - + function: xEnturPermissions # ------------------------------------------------------------------------- # 2.4 Entur Metadata diff --git a/functions/xEnturPermissions.js b/functions/xEnturPermissions.js new file mode 100644 index 0000000..9e9a396 --- /dev/null +++ b/functions/xEnturPermissions.js @@ -0,0 +1,47 @@ +module.exports = (targetVal, options, context) => { + if (typeof targetVal !== "object") { + return [{message: "\"x-entur-permissions\" must be an object."}] + } + + const messages = [] + for (const prop of Object.getOwnPropertyNames(targetVal)) { + if (!["value", "description"].includes(prop)) { + messages.push({ message: `Unrecognized property \"${prop}\"`, path: [...context.path, prop] }) + } + } + if (targetVal.description != null && typeof targetVal.description !== "string") { + messages.push({ message: "\"description\" property must be a string", path: [...context.path, "description"] }) + } + + messages.push(...xEnturPermissionsValue(targetVal.value, [...context.path, "value"])) + + return messages +} + +function xEnturPermissionsValue(targetVal, path = []) { + if (typeof targetVal === "string") { + const match = targetVal.toLocaleLowerCase().match(/^[0-9a-zæøå][0-9a-zæøå.\\-]{0,99}:(les|opprett|endre|slett)$/) + if (!match) { + return [{ message: "Must match format \"permission:(les/opprett/endre/slett)\"", path}] + } else { + return [] + } + } else if (typeof targetVal === "object") { + const props = Object.getOwnPropertyNames(targetVal); + + if (props.length != 1 || !["any", "all"].includes(props[0])) { + return [{ message: "Must be an object with either \"any\" or \"all\"", path}] + } + + const val = targetVal[props[0]]; + if (!Array.isArray(val)) { + return [{ message: "Must be an array", path: [...path, props[0]] }] + } + + return val.flatMap((x, index) => xEnturPermissionsValue(x, [...path, props[0], index])); + } else { + return [{ message: "Must be either an object or a string", path }] + + } + +} \ No newline at end of file diff --git a/specs/reference-spec-with-errors.json b/specs/reference-spec-with-errors.json index f7bd399..03762d2 100644 --- a/specs/reference-spec-with-errors.json +++ b/specs/reference-spec-with-errors.json @@ -160,7 +160,8 @@ } }, "x-entur-permissions": { - "value": "items:les" + "description": 10, + "value": {"and": ["items:les"]} } }, "post": { @@ -195,14 +196,15 @@ } }, "x-entur-permissions": { + "bar": "something", "description": "You need access to read organisations, and create items.", "value": { "all": [ - "organisations:les", + "organisations:le", { "any": [ - "items:opprett", - "items-global:opprett" + "items:oppret", + "items-global:oprett" ] } ] diff --git a/specs/reference-spec.json b/specs/reference-spec.json index 5601d68..5854234 100644 --- a/specs/reference-spec.json +++ b/specs/reference-spec.json @@ -161,7 +161,7 @@ } }, "x-entur-permissions": { - "value": "items:les" + "value": "items:LES" } }, "post": {