Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -545,5 +545,6 @@ jobs:
dshanley/vacuum:latest lint \
--functions /work/specs/functions \
--ruleset /work/specs/.vacuum.yaml \
--ignore-file /work/specs/.vacuum-ignore.yaml \
--fail-severity error \
/work/specs/burst-api.yaml
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ cargo test
cargo deny check advisories

# 5. Lint OpenAPI spec (MUST pass — CI gate)
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml --ignore-file specs/.vacuum-ignore.yaml
```

The vacuum lint step is a **hard gate** in CI. Any errors will fail the pipeline.

To debug vacuum errors, use details mode and filter for error markers:

```bash
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml --no-banner -d -q 2>&1 | grep "✗"
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml --ignore-file specs/.vacuum-ignore.yaml --no-banner -d -q 2>&1 | grep "✗"
```

## OpenAPI Spec
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,7 @@ specs/functions/.barbacane-fetched:
@touch $@

lint-spec: specs/functions/.barbacane-fetched ## Lint OpenAPI spec with vacuum
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml
vacuum lint -f specs/functions specs/burst-api.yaml -r specs/.vacuum.yaml --ignore-file specs/.vacuum-ignore.yaml

# ── Quality ────────────────────────────────────────────────────────────────────
check: ## Run fmt, clippy, and tests
Expand Down
78 changes: 78 additions & 0 deletions specs/.vacuum-ignore.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# Findings that do not apply to this spec, each with the reason.
# Passed to vacuum with --ignore-file by `make lint-spec` and CI.

# The WebSocket upgrade succeeds with 101, not a 2xx or 3xx.
# The /api catch-all answers 404 by design: no API operation matches it.
operation-success-response:
- $.paths['/ws'].get.responses
- $.paths['/api/{path+}'].get.responses

# These operations take no parameters and no body, so they cannot fail validation.
owasp-define-error-validation:
- $.paths['/api/users/me'].get.responses
- $.paths['/api/users/me/status'].delete.responses
- $.paths['/api/users/me/do-not-disturb'].get.responses
- $.paths['/api/emojis'].get.responses
- $.paths['/api/admin/exports'].get.responses
- $.paths['/api/admin/emojis'].get.responses
- $.paths['/api/admin/bots'].get.responses
- $.paths['/'].get.responses
- $.paths['/api/{path+}'].get.responses
- $.paths['/{path+}'].get.responses

# The SPA routes run no middleware (x-barbacane-middlewares: []): they are public,
# not rate limited, and answered by the gateway's mock and s3 dispatchers.
owasp-protection-global-safe:
- $.paths['/'].get
- $.paths['/api/{path+}'].get
- $.paths['/{path+}'].get
owasp-define-error-responses-429:
- $.paths['/'].get.responses
- $.paths['/api/{path+}'].get.responses
- $.paths['/{path+}'].get.responses
owasp-define-error-responses-500:
- $.paths['/'].get.responses
- $.paths['/api/{path+}'].get.responses
- $.paths['/{path+}'].get.responses
owasp-rate-limit:
- $.paths['/api/{path+}'].get.responses['404']
- $.paths['/{path+}'].get.responses['200']
- $.paths['/{path+}'].get.responses['404']

# Free text, arbitrary paths, and cursors the server never sets: no format,
# pattern or enum describes them.
owasp-string-restricted:
- $.paths['/api/search/messages'].get.parameters[0].schema
- $.paths['/api/admin/audit-log'].get.parameters[2].schema
- $.paths['/api/{path+}'].get.parameters[0].schema
- $.paths['/{path+}'].get.parameters[0].schema
- $.paths['/api/emojis'].get.responses['200'].content['application/json'].schema.properties['cursor']
- $.paths['/api/admin/emojis'].get.responses['200'].content['application/json'].schema.properties['cursor']
- $.components.schemas['ChannelMemberList'].properties['cursor']
- $.components.schemas['ExportList'].properties['cursor']
- $.components.schemas['User'].properties['statusEmoji']
- $.components.schemas['UpdateProfileRequest'].properties['statusText']
- $.components.schemas['SetStatusRequest'].properties['text']
- $.components.schemas['SetStatusRequest'].properties['emoji']
- $.components.schemas['Export'].properties['error']
- $.components.schemas['ReactionCount'].properties['emoji']
- $.components.schemas['SearchResult'].properties['matchedFile']
- $.components.schemas['SearchResult'].properties['headline']
- $.components.schemas['Attachment'].properties['fileName']
- $.components.schemas['Attachment'].properties['contentType']
- $.components.schemas['AdminUser'].properties['username']
- $.components.schemas['AdminUser'].properties['displayName']
- $.components.schemas['Webhook'].properties['name']
- $.components.schemas['CreateWebhookRequest'].properties['name']
- $.components.schemas['UpdateWebhookRequest'].properties['name']
- $.components.schemas['IncomingWebhookPayload'].properties['content']
- $.components.schemas['CreateBotRequest'].properties['displayName']
- $.components.schemas['UpdateBotRequest'].properties['displayName']

# Attachment and audit metadata are free-form JSON objects by design.
owasp-no-additionalProperties:
- $.components.schemas['Attachment'].properties['metadata']
- $.components.schemas['AuditLogEntry'].properties['metadata']
owasp-constrained-additionalProperties:
- $.components.schemas['Attachment'].properties['metadata']
- $.components.schemas['AuditLogEntry'].properties['metadata']
Loading
Loading