fix: Separate stacked securityDefinitions into distinct comment groups

swag v2.0.0-rc5's parseSecAttributesV3 resolves a security scheme's map key
via getSecurityDefinitionKey(lines), which scans from the start of whatever
comment-line slice it was handed and returns the first @securitydefinitions
match — ignoring the current parse position entirely. Three
@securityDefinitions.apikey blocks stacked in one Go comment group (the
three were separated only by bare '//' lines, which do not split an
ast.CommentGroup) therefore all resolved to the first block's name
(cookieAuth), with the last block's in/name/description winning: the
generated document had exactly one securityScheme, keyed cookieAuth, body
esoAuth.

Separating the three blocks with real blank source lines splits them into
three distinct ast.CommentGroups, so swag's file-level comment scan (which
requires no other tokens between them, same rule Go uses for doc comments)
hands each block its own line slice and each resolves its own key.
Regenerated openapi.json now carries all three schemes with correct
bodies, referenced with no dangling security requirements.
This commit is contained in:
2026-08-13 07:54:56 +00:00
parent 4c88d6e768
commit 9df4a29210
2 changed files with 34 additions and 15 deletions
+23 -15
View File
@@ -29,24 +29,32 @@ import (
"github.com/gin-gonic/gin"
)
// @title Vantage API
// @version 1.0
// @description The Vantage control plane REST API. Authenticate with a browser session cookie, or with an API token created under Settings → API tokens.
// @BasePath /api
//
// @title Vantage API
// @version 1.0
// @description The Vantage control plane REST API. Authenticate with a browser session cookie, or with an API token created under Settings → API tokens.
// @BasePath /api
// Each @securityDefinitions.apikey block below is deliberately its own
// comment group, separated by a real blank line rather than a bare "//": Go's
// parser only splits ast.CommentGroups on an actual blank line, and
// swag v2.0.0-rc5's parseSecAttributesV3 resolves a scheme's map key by
// scanning from the start of whatever comment group it was handed — so three
// stacked blocks sharing one group all collapse onto the first block's name.
// Three groups means three independent scans, each finding its own name.
// @securityDefinitions.apikey cookieAuth
// @in cookie
// @name km_session
//
// @in cookie
// @name km_session
// @securityDefinitions.apikey bearerAuth
// @in header
// @name Authorization
// @description An API token, sent as "Bearer vt_…". Scoped and optionally expiring.
//
// @in header
// @name Authorization
// @description An API token, sent as "Bearer vt_…". Scoped and optionally expiring.
// @securityDefinitions.apikey esoAuth
// @in header
// @name Authorization
// @description The External Secrets read token, rotated under Settings. It reaches /api/secrets/{group}/values and nothing else. It is a different credential from an API token, and the two must never be substituted for one another.
// @in header
// @name Authorization
// @description The External Secrets read token, rotated under Settings. It reaches /api/secrets/{group}/values and nothing else. It is a different credential from an API token, and the two must never be substituted for one another.
func main() {
mongoURI := getEnv("MONGO_URI", "mongodb://localhost:27017")
+11
View File
@@ -2002,7 +2002,18 @@
}
},
"securitySchemes": {
"bearerAuth": {
"description": "An API token, sent as \"Bearer vt_…\". Scoped and optionally expiring.",
"in": "header",
"name": "Authorization",
"type": "apiKey"
},
"cookieAuth": {
"in": "cookie",
"name": "km_session",
"type": "apiKey"
},
"esoAuth": {
"description": "The External Secrets read token, rotated under Settings. It reaches /api/secrets/{group}/values and nothing else. It is a different credential from an API token, and the two must never be substituted for one another.",
"in": "header",
"name": "Authorization",