From dc25b77a1cebbc7a645262cf0450f70002f0f439 Mon Sep 17 00:00:00 2001 From: Marcel Date: Sat, 13 Jun 2026 12:16:48 +0200 Subject: [PATCH] fix(sdd): add Spectral ruleset so contract-validate passes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Spectral v6 ships no implicit ruleset — the CI job exited 'no ruleset found'. Adds .spectral.yaml (extends spectral:oas, documentation-only warnings relaxed for design-time stubs), adds operation tags to the _example contract so it lints clean (0 results), and aligns the api-contract-stub note. Co-Authored-By: Claude Opus 4.8 --- .specify/features/_example/api-contract.yaml | 4 ++++ .specify/templates/api-contract-stub.md | 9 +++++---- .spectral.yaml | 15 +++++++++++++++ 3 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 .spectral.yaml diff --git a/.specify/features/_example/api-contract.yaml b/.specify/features/_example/api-contract.yaml index 19685e1d..29b50702 100644 --- a/.specify/features/_example/api-contract.yaml +++ b/.specify/features/_example/api-contract.yaml @@ -45,6 +45,7 @@ paths: /api/users/me/avatar: post: summary: Upload or replace the current user's avatar + tags: [Users] operationId: uploadMyAvatar security: - cookieAuth: [] @@ -78,6 +79,7 @@ paths: schema: { $ref: '#/components/schemas/ErrorResponse' } delete: summary: Remove the current user's avatar + tags: [Users] operationId: deleteMyAvatar security: - cookieAuth: [] @@ -95,6 +97,7 @@ paths: /api/users/{id}/avatar: get: summary: Stream a user's avatar image (authenticated proxy) + tags: [Users] operationId: getUserAvatar security: - cookieAuth: [] @@ -113,6 +116,7 @@ paths: '404': { description: User has no avatar, content: { application/json: { schema: { $ref: '#/components/schemas/ErrorResponse' } } } } delete: summary: Remove another user's avatar (admin only) + tags: [Users] operationId: deleteUserAvatar description: Requires Permission.ADMIN_USER (enforced by @RequirePermission on the controller). security: diff --git a/.specify/templates/api-contract-stub.md b/.specify/templates/api-contract-stub.md index dac59a5b..050af9f4 100644 --- a/.specify/templates/api-contract-stub.md +++ b/.specify/templates/api-contract-stub.md @@ -86,11 +86,12 @@ paths: ## Validating the contract in CI -The `sdd-gate.yml` workflow runs, on PRs that touch a `api-contract.yaml`: +The `sdd-gate.yml` `contract-validate` job lints any committed OpenAPI file changed in the PR: ```bash -npx @stoplight/spectral-cli lint .specify/features/**/api-contract.yaml +npx @stoplight/spectral-cli lint .yaml ``` -Spectral's default OpenAPI ruleset catches malformed specs, missing `operationId`s, and -undefined `$ref`s. Add a `.spectral.yaml` at the repo root to tune rules if needed. +The ruleset is `.spectral.yaml` at the repo root (extends `spectral:oas`; documentation-only +warnings relaxed for design-time stubs). Spectral auto-discovers it. It catches malformed +specs, undefined `$ref`s, and duplicate `operationId`s; tune `.spectral.yaml` to adjust. diff --git a/.spectral.yaml b/.spectral.yaml new file mode 100644 index 00000000..7c7dbf28 --- /dev/null +++ b/.spectral.yaml @@ -0,0 +1,15 @@ +# Spectral ruleset for OpenAPI contract linting (SDD api-contract files). +# Spectral v6 ships no implicit ruleset — this enables the built-in OpenAPI rules. +# Used by .gitea/workflows/sdd-gate.yml (contract-validate) and locally: +# npx @stoplight/spectral-cli lint .yaml +extends: ["spectral:oas"] + +rules: + # Design-time SDD stubs are not full published API docs — relax the documentation-completeness + # warnings that would otherwise fire on a focused contract. The structural/correctness rules + # (oas3-schema, valid $refs, duplicate operationId, etc.) stay on. + info-contact: off + info-description: off + operation-description: off + operation-tag-defined: off + oas3-unused-component: off