# SPDX-License-Identifier: CC-BY-NC-SA-4.0 # # SCIM 2.0, as a Spectral ruleset. # # GENERATED by scripts/build-ruleset.py from the measured profile. # # THIS RULESET DOES NOT CHECK CONFORMANCE TO RFC 7644, and the distinction matters. SCIM is # ratified: the RFC is the conformance authority and says what a SCIM server must do. What # it cannot tell you is what the industry actually built. These rules encode the MEASURED # core — the operations declared by a majority of the 77 providers publishing a # SCIM path, out of 368 that mention SCIM — so a document that passes is # interoperable with the SCIM that exists, which is not the same as conformant. # # The severities say which is which: a missing measured-core operation is an error because # real clients will break on it; a missing discovery endpoint is a WARNING, because the RFC # does not compel it and a third of the cohort omits it. # # WHAT THIS DOES NOT CHECK # - RFC conformance. Filter syntax, PATCH semantics, sorting, pagination bounds, # attribute mutability and returned-ness are all normative and none is visible here. # - Runtime behaviour. Every SCIM operation is authenticated, so no probe is possible. # - Schema extensions. The enterprise User extension and vendor schemas are out of scope. # # Built-in functions only, so it runs unchanged in the browser validator. formats: [oas3] rules: scim-core-get-users: description: >- `GET /Users` is measured core: 53 of 77 providers that publish a SCIM path declare it (68.8%). RFC 7644 Section 3.4.1. message: "`GET /Users` is not described. 68.8% of the measured cohort declares it." severity: error documentationUrl: https://apicommons.org/standards/identity/#core given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "\\/Users$" scim-core-post-users: description: >- `POST /Users` is measured core: 52 of 77 providers that publish a SCIM path declare it (67.5%). RFC 7644 Section 3.3. message: "`POST /Users` is not described. 67.5% of the measured cohort declares it." severity: error documentationUrl: https://apicommons.org/standards/identity/#core given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "\\/Users$" scim-core-get-users-id: description: >- `GET /Users/{id}` is measured core: 51 of 77 providers that publish a SCIM path declare it (66.2%). RFC 7644 Section 3.4.1. message: "`GET /Users/{id}` is not described. 66.2% of the measured cohort declares it." severity: error documentationUrl: https://apicommons.org/standards/identity/#core given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "\\/Users\\/\\{[^}]+\\}$" scim-core-put-users-id: description: >- `PUT /Users/{id}` is measured core: 46 of 77 providers that publish a SCIM path declare it (59.7%). RFC 7644 Section 3.5.1. message: "`PUT /Users/{id}` is not described. 59.7% of the measured cohort declares it." severity: error documentationUrl: https://apicommons.org/standards/identity/#core given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "\\/Users\\/\\{[^}]+\\}$" scim-core-delete-users-id: description: >- `DELETE /Users/{id}` is measured core: 42 of 77 providers that publish a SCIM path declare it (54.5%). RFC 7644 Section 3.6. message: "`DELETE /Users/{id}` is not described. 54.5% of the measured cohort declares it." severity: error documentationUrl: https://apicommons.org/standards/identity/#core given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "\\/Users\\/\\{[^}]+\\}$" scim-discovery-endpoints: description: >- SCIM's three discovery endpoints — /ServiceProviderConfig, /ResourceTypes and /Schemas — are the only mechanism a client has for adapting to a server's capabilities. RFC 7644 Section 4 does NOT compel a server to implement them: it says they "MAY be retrieved using HTTP GET", and uses SHALL only for the shape of the response if one comes. About a third of the measured cohort declares them. This is a warning rather than an error for exactly that reason — but a server without them leaves every client guessing. message: "No SCIM discovery endpoint described. Clients cannot learn what this server supports." severity: warn documentationUrl: https://apicommons.org/standards/identity/#discovery given: "$" then: field: paths function: schema functionOptions: schema: type: object minProperties: 1 not: propertyNames: not: pattern: "(ServiceProviderConfig|ResourceTypes|Schemas)$" scim-media-type: description: >- RFC 7644 Section 3.1: "To identify this content, SCIM uses a media type of 'application/scim+json'". A document that answers only application/json is describing something adjacent to SCIM, and a strict client checking the response type will reject it. message: "This response declares no `application/scim+json` content type." severity: warn documentationUrl: https://www.rfc-editor.org/rfc/rfc7644#section-3.1 given: "$.paths[*][*].responses[?(@property == '200')].content" then: function: schema functionOptions: schema: type: object not: allOf: - required: ["application/json"] - maxProperties: 1 scim-error-status-is-a-string: description: >- RFC 7644 Section 3.12 carries the HTTP status code INSIDE the error body as a JSON string — `"status": "404"`, not `"status": 404`. Describing it as an integer is a small error that produces a real one: a generated client deserialises the field, gets a type mismatch on every error response, and fails while handling a failure. message: "SCIM error `status` is a string carrying the HTTP status code, not an integer." severity: error documentationUrl: https://www.rfc-editor.org/rfc/rfc7644#section-3.12 given: "$..properties.status[?(@property === 'type')]" then: function: pattern functionOptions: notMatch: "^(integer|number)$"