Skip to content
Merged
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
7 changes: 3 additions & 4 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ jobs:
cache: true

- name: Run golangci-lint
uses: golangci/golangci-lint-action@v6
uses: golangci/golangci-lint-action@v7
with:
version: latest
version: v2.8.0
args: --timeout=5m

build:
Expand Down Expand Up @@ -79,8 +79,7 @@ jobs:

- name: Install vacuum
run: |
curl -fsSL https://quobix.com/scripts/install_vacuum.sh | sh
sudo mv vacuum /usr/local/bin/
curl -fsSL https://quobix.com/scripts/install_vacuum.sh | sudo sh
- name: Validate OpenAPI specification
run: |
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
!Makefile
!oapi-codegen-config.yml
!.golangci.yml
!vacuum-ruleset.yaml
!make-containers-dev*.sh
!Dockerfile*
!.dockerignore
Expand Down
27 changes: 14 additions & 13 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,24 @@ linters:
- revive
- unused
- unparam
exclusions:
rules:
# Exclude generated api.go file from all linters
- path: "^api/api\\.go$"
linters:
- errcheck
- govet
- ineffassign
- staticcheck
- gocyclo
- gosec
- misspell
- unconvert

formatters:
enable:
- goimports

issues:
max-issues-per-linter: 0
max-same-issues: 0
exclude-rules:
# Exclude generated api.go file from all linters
- path: "^api/api\\.go$"
linters:
- errcheck
- govet
- ineffassign
- staticcheck
- gocyclo
- gosec
- misspell
- unconvert
max-same-issues: 0
2 changes: 1 addition & 1 deletion .version
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"major": 0,
"minor": 266,
"patch": 8
"patch": 11
}
2 changes: 1 addition & 1 deletion api/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ var (
// Minor version number
VersionMinor = "266"
// Patch version number
VersionPatch = "8"
VersionPatch = "11"
// GitCommit is the git commit hash from build
GitCommit = "development"
// BuildDate is the build timestamp
Expand Down
4 changes: 2 additions & 2 deletions test/testdb/testdb.go
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ func (t *TestDB) Config() *config.Config {

// DialectName returns the name of the database dialect
func (t *TestDB) DialectName() string {
return t.db.Dialector.Name()
return t.db.Dialector.Name() //nolint:staticcheck // QF1008: Dialector is not embedded, this is the correct GORM API
}

// Close closes the database connection
Expand Down Expand Up @@ -287,7 +287,7 @@ func (t *TestDB) CleanupByPrefix(prefix string) error {
// Truncate removes all data from specified tables
// WARNING: Use with caution - this deletes all data
func (t *TestDB) Truncate(tables ...string) error {
dialect := t.db.Dialector.Name()
dialect := t.db.Dialector.Name() //nolint:staticcheck // QF1008: Dialector is not embedded, this is the correct GORM API
for _, table := range tables {
// Validate table name against whitelist to prevent SQL injection
if err := api.ValidateTableName(table); err != nil {
Expand Down
148 changes: 148 additions & 0 deletions vacuum-ruleset.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
# Vacuum ruleset for TMI OpenAPI validation
# Extends recommended OAS rules + full OWASP ruleset
#
# Usage: vacuum lint docs/reference/apis/tmi-openapi.json -r vacuum-ruleset.yaml
#
# Requirements:
# - OpenAPI 3 specific (no OpenAPI 2 rules)
# - No camelCase enforcement (TMI uses snake_case per API Design Guidelines)
# - Missing examples as informational only
# - OWASP security rules enabled
#
# Rule Suppression Decisions (documented 2026-01-17):
# See below for rationale on each suppressed rule.

extends: [[vacuum:oas, recommended], [vacuum:owasp, all]]

rules:
# Disable OpenAPI 2 specific rules (OAS3 only)
owasp-security-hosts-https-oas2: off

# Disable camelCase enforcement - TMI uses snake_case per API Design Guidelines
camel-case-properties: off

# Downgrade missing examples to info severity
oas3-missing-example: info
oas3-valid-schema-example: info

# ============================================================================
# OWASP Rule Suppressions with Rationale
# ============================================================================

# owasp-integer-format: Suppress (1,618 errors)
# Rationale: TMI only builds on 64-bit platforms with Go. When no format is
# specified in OpenAPI, oapi-codegen generates Go's `int` type, which is
# 64-bit on all supported platforms. Requiring explicit int32/int64 on every
# integer field adds documentation overhead without practical value for this
# project's deployment targets.
owasp-integer-format: off

# owasp-integer-limit: Suppress (1,606 errors)
# Rationale: Requiring min/max on every integer is impractical for most APIs.
# Critical fields (pagination limits, token expiry) have limits added manually.
# Fields like counts, IDs, and timestamps don't benefit from arbitrary limits.
owasp-integer-limit: off

# description-duplication: Suppress (2,028 info)
# Rationale: Duplicate descriptions are intentional reuse - rate limit headers,
# error responses, and common fields are deliberately consistent across endpoints.
# The spec has been standardized to use consistent wording for these duplicates.
description-duplication: off

# owasp-string-restricted: Suppress (100 of 132 errors)
# Rationale: Many string fields are legitimately free-form (error messages,
# descriptions, names, payloads). Parameters and OAuth/OIDC fields have been
# fixed with appropriate patterns/enums. Remaining fields are suppressed:
# - Error response messages (43) - free-form by nature
# - Admin schema names/descriptions (22) - user-provided content
# - Addon schema fields (12) - flexible addon metadata
# - Client credential names/descriptions (6) - user-provided
# - Miscellaneous labels/metadata (17) - flexible content
# Note: This rule cannot be partially suppressed, so we suppress it entirely
# after fixing the 32 critical fields (7 parameters + 25 OAuth/OIDC).
owasp-string-restricted: off

# owasp-protection-global-unsafe: Suppress (5 errors)
# Rationale: OAuth2/SAML endpoints intentionally use security: [] because they
# handle authentication differently (via client credentials in body, SAML assertions,
# etc.). These are marked with x-public-endpoint: true. The flagged endpoints are:
# - /oauth2/token - Token exchange (client credentials in body)
# - /oauth2/introspect - Token introspection (client auth in body)
# - /oauth2/refresh - Refresh token exchange
# - /saml/acs - SAML assertion consumer service (SAML assertions)
# - /saml/slo - SAML single logout
owasp-protection-global-unsafe: off

# owasp-string-limit: Suppress (162 errors)
# Rationale: The remaining string fields without maxLength are either:
# - Already constrained by format (uuid, email, date-time)
# - Part of suppressed owasp-string-restricted categories (error messages,
# descriptions, payloads)
# - OAuth/OIDC standard fields with well-defined specifications
# Adding arbitrary maxLength to these would not add meaningful security value.
owasp-string-limit: off

# ============================================================================
# Schema Rule Adjustments
# ============================================================================

# oas-schema-check: Suppress (3 warnings)
# Rationale: The discriminator warnings are for polymorphic schemas (Diagram,
# DfdDiagram.cells.items, DfdDiagramInput.cells.items) where the discriminator
# property is defined in the referenced schemas (Node.shape, Edge.shape) rather
# than at the parent oneOf level. Vacuum requires the property at the parent
# level, but adding it there causes oapi-codegen to generate duplicate types
# that break compilation. The schemas work correctly at runtime - the discriminator
# maps to the correct schema based on the shape value. This is a known
# incompatibility between Vacuum's strict validation and oapi-codegen's code
# generation requirements.
oas-schema-check: off

# ============================================================================
# Path and Schema Design Suppressions (documented 2026-01-17)
# ============================================================================

# paths-kebab-case: Suppress (43 warnings)
# Rationale: TMI uses snake_case for API paths (/threat_models, /threat_model_id)
# per established project convention. Changing to kebab-case would be a breaking
# API change. The snake_case convention is consistent throughout the API and
# aligns with the JSON property naming convention (also snake_case).
paths-kebab-case: off

# owasp-constrained-additionalProperties: Suppress (10 warnings)
# owasp-no-additionalProperties: Suppress (10 warnings)
# Rationale: These 10 schema locations require flexible additionalProperties:
# - JointJS diagram schemas (5): Cell.data, DfdDiagram...ports.groups,
# DfdDiagram...connector.args, DfdDiagram...router.args, MarkupElement.attrs
# JointJS library requires arbitrary properties for diagram rendering.
# - Metadata fields (3): MinimalDiagramModel.metadata, MinimalCell[0].metadata,
# MinimalCell[1].metadata - user-defined metadata must be extensible.
# - Extensibility (2): InvokeAddonRequest.payload (addon payloads vary by addon),
# Error.details.context (error context varies by error type).
# Adding maxProperties constraints would break legitimate use cases.
owasp-constrained-additionalProperties: off
owasp-no-additionalProperties: off

# owasp-define-error-responses-401: Suppress (14 warnings)
# Rationale: These are public endpoints that don't require authentication and
# never return 401 by design:
# - OAuth discovery: /.well-known/openid-configuration, /.well-known/jwks.json,
# /.well-known/oauth-authorization-server, /.well-known/oauth-protected-resource
# - OAuth flow: /oauth2/providers, /oauth2/authorize, /oauth2/token, /oauth2/introspect
# - SAML flow: /saml/slo, /saml/providers, /saml/{provider}/login, /saml/{provider}/metadata
# - Health check: /
# These endpoints are marked with x-public-endpoint: true vendor extension.
owasp-define-error-responses-401: off

# circular-references: Suppress (1 warning)
# Rationale: MarkupElement references itself intentionally for recursive SVG
# structure (nested SVG elements like <g> containing more <g> elements). This
# is valid JSON Schema and required for JointJS markup definitions.
circular-references: off

# no-unnecessary-combinator: Suppress (1 warning)
# Rationale: Diagram.oneOf currently contains only DfdDiagram, but additional
# diagram types (sequence diagrams, architecture diagrams, etc.) will be added
# in future versions. The oneOf structure is intentional to support polymorphic
# diagram types.
no-unnecessary-combinator: off
Loading