From 7ffc63ea54218bfabfb7c2d9c77f94003f3f49f4 Mon Sep 17 00:00:00 2001 From: allanice001 Date: Thu, 6 Nov 2025 03:30:13 +0000 Subject: [PATCH] fix: clean cache and go mod tidy for go1.25.3 --- go.mod | 5 +- go.sum | 20 ++- internal/handlers/annotations.go | 183 +++++++++++----------- internal/handlers/auth.go | 66 ++++---- internal/handlers/health.go | 17 +- internal/handlers/jobs.go | 147 +++++++++--------- internal/handlers/jwks.go | 15 +- internal/handlers/labels.go | 183 +++++++++++----------- internal/handlers/me.go | 38 ++--- internal/handlers/me_keys.go | 57 +++---- internal/handlers/orgs.go | 257 ++++++++++++++++--------------- internal/handlers/servers.go | 181 +++++++++++----------- internal/handlers/ssh_keys.go | 179 ++++++++++----------- internal/handlers/taints.go | 181 +++++++++++----------- main.go | 46 +++--- 15 files changed, 815 insertions(+), 760 deletions(-) diff --git a/go.mod b/go.mod index 6547c3d..a17cac0 100644 --- a/go.mod +++ b/go.mod @@ -30,11 +30,10 @@ require ( github.com/KyleBanks/depth v1.2.1 // indirect github.com/fsnotify/fsnotify v1.9.0 // indirect github.com/go-jose/go-jose/v4 v4.1.3 // indirect - github.com/go-openapi/jsonpointer v0.22.1 // indirect - github.com/go-openapi/jsonreference v0.21.2 // indirect + github.com/go-openapi/jsonpointer v0.19.6 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/spec v0.20.9 // indirect github.com/go-openapi/swag v0.22.3 // indirect - github.com/go-openapi/swag/jsonname v0.25.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect github.com/goccy/go-json v0.10.5 // indirect diff --git a/go.sum b/go.sum index 181a340..ebe5024 100644 --- a/go.sum +++ b/go.sum @@ -32,19 +32,17 @@ github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZR github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.22.1 h1:sHYI1He3b9NqJ4wXLoJDKmUmHkWy/L7rtEo92JUxBNk= -github.com/go-openapi/jsonpointer v0.22.1/go.mod h1:pQT9OsLkfz1yWoMgYFy4x3U5GY5nUlsOn1qSBH5MkCM= +github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= -github.com/go-openapi/jsonreference v0.21.2 h1:Wxjda4M/BBQllegefXrY/9aq1fxBA8sI5M/lFU6tSWU= -github.com/go-openapi/jsonreference v0.21.2/go.mod h1:pp3PEjIsJ9CZDGCNOyXIQxsNuroxm8FAJ/+quA0yKzQ= +github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE= +github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/spec v0.20.9 h1:xnlYNQAwKd2VQRRfwTEI0DcK+2cbuvI/0c7jx3gA8/8= github.com/go-openapi/spec v0.20.9/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6VaaBKcWA= github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-openapi/swag/jsonname v0.25.1 h1:Sgx+qbwa4ej6AomWC6pEfXrA6uP2RkaNjA9BR8a1RJU= -github.com/go-openapi/swag/jsonname v0.25.1/go.mod h1:71Tekow6UOLBD3wS7XhdT98g5J5GR13NOTQ9/6Q11Zo= github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= @@ -84,6 +82,7 @@ github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFF github.com/klauspost/cpuid/v2 v2.2.10 h1:tBs3QSyvjDyFTq3uoc/9xFpCuOsJQFNPiAhYdw2skhE= github.com/klauspost/cpuid/v2 v2.2.10/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= @@ -115,8 +114,8 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= -github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= +github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8= +github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs= github.com/rs/xid v1.6.0/go.mod h1:7XoLgs4eV+QndskICGsho+ADou8ySMSjJKDIan90Nz0= github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY= github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ= @@ -137,11 +136,16 @@ github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3A github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU= github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8= diff --git a/internal/handlers/annotations.go b/internal/handlers/annotations.go index a85d57c..c797afe 100644 --- a/internal/handlers/annotations.go +++ b/internal/handlers/annotations.go @@ -17,24 +17,25 @@ import ( ) // ListAnnotations godoc -// @ID ListAnnotations -// @Summary List annotations (org scoped) -// @Description Returns annotations for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools. -// @Tags Annotations -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param key query string false "Exact key" -// @Param value query string false "Exact value" -// @Param q query string false "key contains (case-insensitive)" -// @Success 200 {array} dto.AnnotationResponse -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "failed to list annotations" -// @Router /annotations [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID ListAnnotations +// @Summary List annotations (org scoped) +// @Description Returns annotations for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param key query string false "Exact key" +// @Param value query string false "Exact value" +// @Param q query string false "key contains (case-insensitive)" +// @Success 200 {array} dto.AnnotationResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "failed to list annotations" +// @Router /annotations [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func ListAnnotations(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -69,24 +70,25 @@ func ListAnnotations(db *gorm.DB) http.HandlerFunc { } // GetAnnotation godoc -// @ID GetAnnotation -// @Summary Get annotation by ID (org scoped) -// @Description Returns one annotation. Add `include=node_pools` to include node pools. -// @Tags Annotations -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Annotation ID (UUID)" -// @Success 200 {object} dto.AnnotationResponse -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "fetch failed" -// @Router /annotations/{id} [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID GetAnnotation +// @Summary Get annotation by ID (org scoped) +// @Description Returns one annotation. Add `include=node_pools` to include node pools. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Annotation ID (UUID)" +// @Success 200 {object} dto.AnnotationResponse +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "fetch failed" +// @Router /annotations/{id} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func GetAnnotation(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -115,23 +117,24 @@ func GetAnnotation(db *gorm.DB) http.HandlerFunc { } // CreateAnnotation godoc -// @ID CreateAnnotation -// @Summary Create annotation (org scoped) -// @Description Creates an annotation. -// @Tags Annotations -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param body body dto.CreateAnnotationRequest true "Annotation payload" -// @Success 201 {object} dto.AnnotationResponse -// @Failure 400 {string} string "invalid json / missing fields" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "create failed" -// @Router /annotations [post] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID CreateAnnotation +// @Summary Create annotation (org scoped) +// @Description Creates an annotation. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateAnnotationRequest true "Annotation payload" +// @Success 201 {object} dto.AnnotationResponse +// @Failure 400 {string} string "invalid json / missing fields" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "create failed" +// @Router /annotations [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func CreateAnnotation(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -175,25 +178,26 @@ func CreateAnnotation(db *gorm.DB) http.HandlerFunc { } // UpdateAnnotation godoc -// @ID UpdateAnnotation -// @Summary Update annotation (org scoped) -// @Description Partially update annotation fields. -// @Tags Annotations -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Annotation ID (UUID)" -// @Param body body dto.UpdateAnnotationRequest true "Fields to update" -// @Success 200 {object} dto.AnnotationResponse -// @Failure 400 {string} string "invalid id / invalid json" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "update failed" -// @Router /annotations/{id} [patch] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID UpdateAnnotation +// @Summary Update annotation (org scoped) +// @Description Partially update annotation fields. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Annotation ID (UUID)" +// @Param body body dto.UpdateAnnotationRequest true "Fields to update" +// @Success 200 {object} dto.AnnotationResponse +// @Failure 400 {string} string "invalid id / invalid json" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "update failed" +// @Router /annotations/{id} [patch] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func UpdateAnnotation(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -246,23 +250,24 @@ func UpdateAnnotation(db *gorm.DB) http.HandlerFunc { } // DeleteAnnotation godoc -// @ID DeleteAnnotation -// @Summary Delete annotation (org scoped) -// @Description Permanently deletes the annotation. -// @Tags Annotations -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Annotation ID (UUID)" -// @Success 204 {string} string "No Content" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "delete failed" -// @Router /annotations/{id} [delete] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DeleteAnnotation +// @Summary Delete annotation (org scoped) +// @Description Permanently deletes the annotation. +// @Tags Annotations +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Annotation ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /annotations/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DeleteAnnotation(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) diff --git a/internal/handlers/auth.go b/internal/handlers/auth.go index 9c4e074..fa690c4 100644 --- a/internal/handlers/auth.go +++ b/internal/handlers/auth.go @@ -51,14 +51,15 @@ func providerConfig(cfg config.Config, name string) (oauthProvider, bool) { } // AuthStart godoc -// @ID AuthStart -// @Summary Begin social login -// @Description Returns provider authorization URL for the frontend to redirect -// @Tags Auth -// @Param provider path string true "google|github" -// @Produce json -// @Success 200 {object} dto.AuthStartResponse -// @Router /auth/{provider}/start [post] +// +// @ID AuthStart +// @Summary Begin social login +// @Description Returns provider authorization URL for the frontend to redirect +// @Tags Auth +// @Param provider path string true "google|github" +// @Produce json +// @Success 200 {object} dto.AuthStartResponse +// @Router /auth/{provider}/start [post] func AuthStart(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cfg, _ := config.Load() @@ -118,13 +119,14 @@ func AuthStart(db *gorm.DB) http.HandlerFunc { } // AuthCallback godoc -// @ID AuthCallback -// @Summary Handle social login callback -// @Tags Auth -// @Param provider path string true "google|github" -// @Produce json -// @Success 200 {object} dto.TokenPair -// @Router /auth/{provider}/callback [get] +// +// @ID AuthCallback +// @Summary Handle social login callback +// @Tags Auth +// @Param provider path string true "google|github" +// @Produce json +// @Success 200 {object} dto.TokenPair +// @Router /auth/{provider}/callback [get] func AuthCallback(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cfg, _ := config.Load() @@ -306,14 +308,15 @@ func AuthCallback(db *gorm.DB) http.HandlerFunc { } // Refresh godoc -// @ID Refresh -// @Summary Rotate refresh token -// @Tags Auth -// @Accept json -// @Produce json -// @Param body body dto.RefreshRequest true "Refresh token" -// @Success 200 {object} dto.TokenPair -// @Router /auth/refresh [post] +// +// @ID Refresh +// @Summary Rotate refresh token +// @Tags Auth +// @Accept json +// @Produce json +// @Param body body dto.RefreshRequest true "Refresh token" +// @Success 200 {object} dto.TokenPair +// @Router /auth/refresh [post] func Refresh(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { cfg, _ := config.Load() @@ -363,14 +366,15 @@ func Refresh(db *gorm.DB) http.HandlerFunc { } // Logout godoc -// @ID Logout -// @Summary Revoke refresh token family (logout everywhere) -// @Tags Auth -// @Accept json -// @Produce json -// @Param body body dto.LogoutRequest true "Refresh token" -// @Success 204 "No Content" -// @Router /auth/logout [post] +// +// @ID Logout +// @Summary Revoke refresh token family (logout everywhere) +// @Tags Auth +// @Accept json +// @Produce json +// @Param body body dto.LogoutRequest true "Refresh token" +// @Success 204 "No Content" +// @Router /auth/logout [post] func Logout(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req dto.LogoutRequest diff --git a/internal/handlers/health.go b/internal/handlers/health.go index f28210d..c40d2e1 100644 --- a/internal/handlers/health.go +++ b/internal/handlers/health.go @@ -11,14 +11,15 @@ type HealthStatus struct { } // HealthCheck godoc -// @Summary Basic health check -// @Description Returns 200 OK when the service is up -// @Tags Health -// @ID HealthCheck // operationId -// @Accept json -// @Produce json -// @Success 200 {object} HealthStatus -// @Router /healthz [get] +// +// @Summary Basic health check +// @Description Returns 200 OK when the service is up +// @Tags Health +// @ID HealthCheck // operationId +// @Accept json +// @Produce json +// @Success 200 {object} HealthStatus +// @Router /healthz [get] func HealthCheck(w http.ResponseWriter, r *http.Request) { utils.WriteJSON(w, http.StatusOK, HealthStatus{Status: "ok"}) } diff --git a/internal/handlers/jobs.go b/internal/handlers/jobs.go index d4c4c9a..d64bc1e 100644 --- a/internal/handlers/jobs.go +++ b/internal/handlers/jobs.go @@ -20,23 +20,24 @@ import ( ) // AdminListArcherJobs godoc -// @ID AdminListArcherJobs -// @Summary List Archer jobs (admin) -// @Description Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). -// @Tags ArcherAdmin -// @Accept json -// @Produce json -// @Param status query string false "Filter by status" Enums(queued,running,succeeded,failed,canceled,retrying,scheduled) -// @Param queue query string false "Filter by queue name / worker name" -// @Param q query string false "Free-text search" -// @Param page query int false "Page number" default(1) -// @Param page_size query int false "Items per page" minimum(1) maximum(100) default(25) -// @Success 200 {object} dto.PageJob -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "forbidden" -// @Failure 500 {string} string "internal error" -// @Router /admin/archer/jobs [get] -// @Security BearerAuth +// +// @ID AdminListArcherJobs +// @Summary List Archer jobs (admin) +// @Description Paginated background jobs with optional filters. Search `q` may match id, type, error, payload (implementation-dependent). +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param status query string false "Filter by status" Enums(queued,running,succeeded,failed,canceled,retrying,scheduled) +// @Param queue query string false "Filter by queue name / worker name" +// @Param q query string false "Free-text search" +// @Param page query int false "Page number" default(1) +// @Param page_size query int false "Items per page" minimum(1) maximum(100) default(25) +// @Success 200 {object} dto.PageJob +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/jobs [get] +// @Security BearerAuth func AdminListArcherJobs(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { status := strings.TrimSpace(r.URL.Query().Get("status")) @@ -90,20 +91,21 @@ func AdminListArcherJobs(db *gorm.DB) http.HandlerFunc { } // AdminEnqueueArcherJob godoc -// @ID AdminEnqueueArcherJob -// @Summary Enqueue a new Archer job (admin) -// @Description Create a job immediately or schedule it for the future via `run_at`. -// @Tags ArcherAdmin -// @Accept json -// @Produce json -// @Param body body dto.EnqueueRequest true "Job parameters" -// @Success 200 {object} dto.Job -// @Failure 400 {string} string "invalid json or missing fields" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "forbidden" -// @Failure 500 {string} string "internal error" -// @Router /admin/archer/jobs [post] -// @Security BearerAuth +// +// @ID AdminEnqueueArcherJob +// @Summary Enqueue a new Archer job (admin) +// @Description Create a job immediately or schedule it for the future via `run_at`. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param body body dto.EnqueueRequest true "Job parameters" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid json or missing fields" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/jobs [post] +// @Security BearerAuth func AdminEnqueueArcherJob(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var in dto.EnqueueRequest @@ -168,20 +170,21 @@ func AdminEnqueueArcherJob(db *gorm.DB, jobs *bg.Jobs) http.HandlerFunc { } // AdminRetryArcherJob godoc -// @ID AdminRetryArcherJob -// @Summary Retry a failed/canceled Archer job (admin) -// @Description Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. -// @Tags ArcherAdmin -// @Accept json -// @Produce json -// @Param id path string true "Job ID" -// @Success 200 {object} dto.Job -// @Failure 400 {string} string "invalid job or not eligible" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "forbidden" -// @Failure 404 {string} string "not found" -// @Router /admin/archer/jobs/{id}/retry [post] -// @Security BearerAuth +// +// @ID AdminRetryArcherJob +// @Summary Retry a failed/canceled Archer job (admin) +// @Description Marks the job retriable (DB flip). Swap this for an Archer admin call if you expose one. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid job or not eligible" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 404 {string} string "not found" +// @Router /admin/archer/jobs/{id}/retry [post] +// @Security BearerAuth func AdminRetryArcherJob(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") @@ -222,20 +225,21 @@ func AdminRetryArcherJob(db *gorm.DB) http.HandlerFunc { } // AdminCancelArcherJob godoc -// @ID AdminCancelArcherJob -// @Summary Cancel an Archer job (admin) -// @Description Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. -// @Tags ArcherAdmin -// @Accept json -// @Produce json -// @Param id path string true "Job ID" -// @Success 200 {object} dto.Job -// @Failure 400 {string} string "invalid job or not cancellable" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "forbidden" -// @Failure 404 {string} string "not found" -// @Router /admin/archer/jobs/{id}/cancel [post] -// @Security BearerAuth +// +// @ID AdminCancelArcherJob +// @Summary Cancel an Archer job (admin) +// @Description Set job status to canceled if cancellable. For running jobs, this only affects future picks; wire to Archer if you need active kill. +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Param id path string true "Job ID" +// @Success 200 {object} dto.Job +// @Failure 400 {string} string "invalid job or not cancellable" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 404 {string} string "not found" +// @Router /admin/archer/jobs/{id}/cancel [post] +// @Security BearerAuth func AdminCancelArcherJob(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { id := chi.URLParam(r, "id") @@ -274,18 +278,19 @@ func AdminCancelArcherJob(db *gorm.DB) http.HandlerFunc { } // AdminListArcherQueues godoc -// @ID AdminListArcherQueues -// @Summary List Archer queues (admin) -// @Description Summary metrics per queue (pending, running, failed, scheduled). -// @Tags ArcherAdmin -// @Accept json -// @Produce json -// @Success 200 {array} dto.QueueInfo -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "forbidden" -// @Failure 500 {string} string "internal error" -// @Router /admin/archer/queues [get] -// @Security BearerAuth +// +// @ID AdminListArcherQueues +// @Summary List Archer queues (admin) +// @Description Summary metrics per queue (pending, running, failed, scheduled). +// @Tags ArcherAdmin +// @Accept json +// @Produce json +// @Success 200 {array} dto.QueueInfo +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "forbidden" +// @Failure 500 {string} string "internal error" +// @Router /admin/archer/queues [get] +// @Security BearerAuth func AdminListArcherQueues(db *gorm.DB) http.HandlerFunc { type row struct { QueueName string diff --git a/internal/handlers/jwks.go b/internal/handlers/jwks.go index 308b574..9066064 100644 --- a/internal/handlers/jwks.go +++ b/internal/handlers/jwks.go @@ -23,13 +23,14 @@ type jwks struct { } // JWKSHandler godoc -// @ID getJWKS -// @Summary Get JWKS -// @Description Returns the JSON Web Key Set for token verification -// @Tags Auth -// @Produce json -// @Success 200 {object} dto.JWKS -// @Router /.well-known/jwks.json [get] +// +// @ID getJWKS +// @Summary Get JWKS +// @Description Returns the JSON Web Key Set for token verification +// @Tags Auth +// @Produce json +// @Success 200 {object} dto.JWKS +// @Router /.well-known/jwks.json [get] func JWKSHandler(w http.ResponseWriter, _ *http.Request) { out := dto.JWKS{Keys: make([]dto.JWK, 0)} diff --git a/internal/handlers/labels.go b/internal/handlers/labels.go index 5d74360..dad73cf 100644 --- a/internal/handlers/labels.go +++ b/internal/handlers/labels.go @@ -17,24 +17,25 @@ import ( ) // ListLabels godoc -// @ID ListLabels -// @Summary List node labels (org scoped) -// @Description Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups. -// @Tags Labels -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param key query string false "Exact key" -// @Param value query string false "Exact value" -// @Param q query string false "Key contains (case-insensitive)" -// @Success 200 {array} dto.LabelResponse -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "failed to list node taints" -// @Router /labels [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID ListLabels +// @Summary List node labels (org scoped) +// @Description Returns node labels for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node groups. +// @Tags Labels +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param key query string false "Exact key" +// @Param value query string false "Exact value" +// @Param q query string false "Key contains (case-insensitive)" +// @Success 200 {array} dto.LabelResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "failed to list node taints" +// @Router /labels [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func ListLabels(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -68,24 +69,25 @@ func ListLabels(db *gorm.DB) http.HandlerFunc { } // GetLabel godoc -// @ID GetLabel -// @Summary Get label by ID (org scoped) -// @Description Returns one label. -// @Tags Labels -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Label ID (UUID)" -// @Success 200 {object} dto.LabelResponse -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "fetch failed" -// @Router /labels/{id} [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID GetLabel +// @Summary Get label by ID (org scoped) +// @Description Returns one label. +// @Tags Labels +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Label ID (UUID)" +// @Success 200 {object} dto.LabelResponse +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "fetch failed" +// @Router /labels/{id} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func GetLabel(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -113,23 +115,24 @@ func GetLabel(db *gorm.DB) http.HandlerFunc { } // CreateLabel godoc -// @ID CreateLabel -// @Summary Create label (org scoped) -// @Description Creates a label. -// @Tags Labels -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param body body dto.CreateLabelRequest true "Label payload" -// @Success 201 {object} dto.LabelResponse -// @Failure 400 {string} string "invalid json / missing fields / invalid node_pool_ids" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "create failed" -// @Router /labels [post] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID CreateLabel +// @Summary Create label (org scoped) +// @Description Creates a label. +// @Tags Labels +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateLabelRequest true "Label payload" +// @Success 201 {object} dto.LabelResponse +// @Failure 400 {string} string "invalid json / missing fields / invalid node_pool_ids" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "create failed" +// @Router /labels [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func CreateLabel(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -173,25 +176,26 @@ func CreateLabel(db *gorm.DB) http.HandlerFunc { // UpdateLabel godoc // UpdateLabel godoc -// @ID UpdateLabel -// @Summary Update label (org scoped) -// @Description Partially update label fields. -// @Tags Labels -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Label ID (UUID)" -// @Param body body dto.UpdateLabelRequest true "Fields to update" -// @Success 200 {object} dto.LabelResponse -// @Failure 400 {string} string "invalid id / invalid json" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "update failed" -// @Router /labels/{id} [patch] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID UpdateLabel +// @Summary Update label (org scoped) +// @Description Partially update label fields. +// @Tags Labels +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Label ID (UUID)" +// @Param body body dto.UpdateLabelRequest true "Fields to update" +// @Success 200 {object} dto.LabelResponse +// @Failure 400 {string} string "invalid id / invalid json" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "update failed" +// @Router /labels/{id} [patch] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func UpdateLabel(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -244,23 +248,24 @@ func UpdateLabel(db *gorm.DB) http.HandlerFunc { } // DeleteLabel godoc -// @ID DeleteLabel -// @Summary Delete label (org scoped) -// @Description Permanently deletes the label. -// @Tags Labels -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Label ID (UUID)" -// @Success 204 {string} string "No Content" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "delete failed" -// @Router /labels/{id} [delete] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DeleteLabel +// @Summary Delete label (org scoped) +// @Description Permanently deletes the label. +// @Tags Labels +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Label ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /labels/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DeleteLabel(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) diff --git a/internal/handlers/me.go b/internal/handlers/me.go index 16a6a3b..f5c59dc 100644 --- a/internal/handlers/me.go +++ b/internal/handlers/me.go @@ -17,14 +17,15 @@ type meResponse struct { } // GetMe godoc -// @ID GetMe -// @Summary Get current user profile -// @Tags Me -// @Produce json -// @Success 200 {object} meResponse -// @Router /me [get] -// @Security BearerAuth -// @Security ApiKeyAuth +// +// @ID GetMe +// @Summary Get current user profile +// @Tags Me +// @Produce json +// @Success 200 {object} meResponse +// @Router /me [get] +// @Security BearerAuth +// @Security ApiKeyAuth func GetMe(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := httpmiddleware.UserFrom(r.Context()) @@ -69,16 +70,17 @@ type updateMeRequest struct { } // UpdateMe godoc -// @ID UpdateMe -// @Summary Update current user profile -// @Tags Me -// @Accept json -// @Produce json -// @Param body body updateMeRequest true "Patch profile" -// @Success 200 {object} models.User -// @Router /me [patch] -// @Security BearerAuth -// @Security ApiKeyAuth +// +// @ID UpdateMe +// @Summary Update current user profile +// @Tags Me +// @Accept json +// @Produce json +// @Param body body updateMeRequest true "Patch profile" +// @Success 200 {object} models.User +// @Router /me [patch] +// @Security BearerAuth +// @Security ApiKeyAuth func UpdateMe(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := httpmiddleware.UserFrom(r.Context()) diff --git a/internal/handlers/me_keys.go b/internal/handlers/me_keys.go index 6a869e3..d7a11a3 100644 --- a/internal/handlers/me_keys.go +++ b/internal/handlers/me_keys.go @@ -27,14 +27,15 @@ type userAPIKeyOut struct { } // ListUserAPIKeys godoc -// @ID ListUserAPIKeys -// @Summary List my API keys -// @Tags MeAPIKeys -// @Produce json -// @Success 200 {array} userAPIKeyOut -// @Router /me/api-keys [get] -// @Security BearerAuth -// @Security ApiKeyAuth +// +// @ID ListUserAPIKeys +// @Summary List my API keys +// @Tags MeAPIKeys +// @Produce json +// @Success 200 {array} userAPIKeyOut +// @Router /me/api-keys [get] +// @Security BearerAuth +// @Security ApiKeyAuth func ListUserAPIKeys(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := httpmiddleware.UserFrom(r.Context()) @@ -64,17 +65,18 @@ type createUserKeyRequest struct { } // CreateUserAPIKey godoc -// @ID CreateUserAPIKey -// @Summary Create a new user API key -// @Description Returns the plaintext key once. Store it securely on the client side. -// @Tags MeAPIKeys -// @Accept json -// @Produce json -// @Param body body createUserKeyRequest true "Key options" -// @Success 201 {object} userAPIKeyOut -// @Router /me/api-keys [post] -// @Security BearerAuth -// @Security ApiKeyAuth +// +// @ID CreateUserAPIKey +// @Summary Create a new user API key +// @Description Returns the plaintext key once. Store it securely on the client side. +// @Tags MeAPIKeys +// @Accept json +// @Produce json +// @Param body body createUserKeyRequest true "Key options" +// @Success 201 {object} userAPIKeyOut +// @Router /me/api-keys [post] +// @Security BearerAuth +// @Security ApiKeyAuth func CreateUserAPIKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := httpmiddleware.UserFrom(r.Context()) @@ -118,14 +120,15 @@ func CreateUserAPIKey(db *gorm.DB) http.HandlerFunc { } // DeleteUserAPIKey godoc -// @ID DeleteUserAPIKey -// @Summary Delete a user API key -// @Tags MeAPIKeys -// @Produce json -// @Param id path string true "Key ID (UUID)" -// @Success 204 "No Content" -// @Router /me/api-keys/{id} [delete] -// @Security BearerAuth +// +// @ID DeleteUserAPIKey +// @Summary Delete a user API key +// @Tags MeAPIKeys +// @Produce json +// @Param id path string true "Key ID (UUID)" +// @Success 204 "No Content" +// @Router /me/api-keys/{id} [delete] +// @Security BearerAuth func DeleteUserAPIKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := httpmiddleware.UserFrom(r.Context()) diff --git a/internal/handlers/orgs.go b/internal/handlers/orgs.go index d8f0ace..0f94848 100644 --- a/internal/handlers/orgs.go +++ b/internal/handlers/orgs.go @@ -59,19 +59,20 @@ type orgCreateReq struct { } // CreateOrg godoc -// @ID CreateOrg -// @Summary Create organization -// @Tags Orgs -// @Accept json -// @Produce json -// @Param body body orgCreateReq true "Org payload" -// @Success 201 {object} models.Organization -// @Failure 400 {object} utils.ErrorResponse -// @Failure 401 {object} utils.ErrorResponse -// @Failure 409 {object} utils.ErrorResponse -// @Router /orgs [post] -// @ID createOrg -// @Security BearerAuth +// +// @ID CreateOrg +// @Summary Create organization +// @Tags Orgs +// @Accept json +// @Produce json +// @Param body body orgCreateReq true "Org payload" +// @Success 201 {object} models.Organization +// @Failure 400 {object} utils.ErrorResponse +// @Failure 401 {object} utils.ErrorResponse +// @Failure 409 {object} utils.ErrorResponse +// @Router /orgs [post] +// @ID createOrg +// @Security BearerAuth func CreateOrg(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -111,15 +112,16 @@ func CreateOrg(db *gorm.DB) http.HandlerFunc { } // ListMyOrgs godoc -// @ID ListMyOrgs -// @Summary List organizations I belong to -// @Tags Orgs -// @Produce json -// @Success 200 {array} models.Organization -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs [get] -// @ID listMyOrgs -// @Security BearerAuth +// +// @ID ListMyOrgs +// @Summary List organizations I belong to +// @Tags Orgs +// @Produce json +// @Success 200 {array} models.Organization +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs [get] +// @ID listMyOrgs +// @Security BearerAuth func ListMyOrgs(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -142,17 +144,18 @@ func ListMyOrgs(db *gorm.DB) http.HandlerFunc { } // GetOrg godoc -// @ID GetOrg -// @Summary Get organization -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Success 200 {object} models.Organization -// @Failure 401 {object} utils.ErrorResponse -// @Failure 404 {object} utils.ErrorResponse -// @Router /orgs/{id} [get] -// @ID getOrg -// @Security BearerAuth +// +// @ID GetOrg +// @Summary Get organization +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Success 200 {object} models.Organization +// @Failure 401 {object} utils.ErrorResponse +// @Failure 404 {object} utils.ErrorResponse +// @Router /orgs/{id} [get] +// @ID getOrg +// @Security BearerAuth func GetOrg(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -184,19 +187,20 @@ type orgUpdateReq struct { } // UpdateOrg godoc -// @ID UpdateOrg -// @Summary Update organization (owner/admin) -// @Tags Orgs -// @Accept json -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Param body body orgUpdateReq true "Update payload" -// @Success 200 {object} models.Organization -// @Failure 401 {object} utils.ErrorResponse -// @Failure 404 {object} utils.ErrorResponse -// @Router /orgs/{id} [patch] -// @ID updateOrg -// @Security BearerAuth +// +// @ID UpdateOrg +// @Summary Update organization (owner/admin) +// @Tags Orgs +// @Accept json +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Param body body orgUpdateReq true "Update payload" +// @Success 200 {object} models.Organization +// @Failure 401 {object} utils.ErrorResponse +// @Failure 404 {object} utils.ErrorResponse +// @Router /orgs/{id} [patch] +// @ID updateOrg +// @Security BearerAuth func UpdateOrg(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -242,17 +246,18 @@ func UpdateOrg(db *gorm.DB) http.HandlerFunc { } // DeleteOrg godoc -// @ID DeleteOrg -// @Summary Delete organization (owner) -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Success 204 "Deleted" -// @Failure 401 {object} utils.ErrorResponse -// @Failure 404 {object} utils.ErrorResponse -// @Router /orgs/{id} [delete] -// @ID deleteOrg -// @Security BearerAuth +// +// @ID DeleteOrg +// @Summary Delete organization (owner) +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Success 204 "Deleted" +// @Failure 401 {object} utils.ErrorResponse +// @Failure 404 {object} utils.ErrorResponse +// @Router /orgs/{id} [delete] +// @ID deleteOrg +// @Security BearerAuth func DeleteOrg(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -297,16 +302,17 @@ type memberUpsertReq struct { } // ListMembers godoc -// @ID ListMembers -// @Summary List members in org -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Success 200 {array} memberOut -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/members [get] -// @ID listMembers -// @Security BearerAuth +// +// @ID ListMembers +// @Summary List members in org +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Success 200 {array} memberOut +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/members [get] +// @ID listMembers +// @Security BearerAuth func ListMembers(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -352,18 +358,19 @@ func ListMembers(db *gorm.DB) http.HandlerFunc { } // AddOrUpdateMember godoc -// @ID AddOrUpdateMember -// @Summary Add or update a member (owner/admin) -// @Tags Orgs -// @Accept json -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Param body body memberUpsertReq true "User & role" -// @Success 200 {object} memberOut -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/members [post] -// @ID addOrUpdateMember -// @Security BearerAuth +// +// @ID AddOrUpdateMember +// @Summary Add or update a member (owner/admin) +// @Tags Orgs +// @Accept json +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Param body body memberUpsertReq true "User & role" +// @Success 200 {object} memberOut +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/members [post] +// @ID addOrUpdateMember +// @Security BearerAuth func AddOrUpdateMember(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -419,17 +426,18 @@ func AddOrUpdateMember(db *gorm.DB) http.HandlerFunc { } // RemoveMember godoc -// @ID RemoveMember -// @Summary Remove a member (owner/admin) -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Param user_id path string true "User ID (UUID)" -// @Success 204 "Removed" -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/members/{user_id} [delete] -// @ID removeMember -// @Security BearerAuth +// +// @ID RemoveMember +// @Summary Remove a member (owner/admin) +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Param user_id path string true "User ID (UUID)" +// @Success 204 "Removed" +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/members/{user_id} [delete] +// @ID removeMember +// @Security BearerAuth func RemoveMember(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -478,16 +486,17 @@ type orgKeyCreateResp struct { } // ListOrgKeys godoc -// @ID ListOrgKeys -// @Summary List org-scoped API keys (no secrets) -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Success 200 {array} models.APIKey -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/api-keys [get] -// @ID listOrgKeys -// @Security BearerAuth +// +// @ID ListOrgKeys +// @Summary List org-scoped API keys (no secrets) +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Success 200 {array} models.APIKey +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/api-keys [get] +// @ID listOrgKeys +// @Security BearerAuth func ListOrgKeys(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -513,18 +522,19 @@ func ListOrgKeys(db *gorm.DB) http.HandlerFunc { } // CreateOrgKey godoc -// @ID CreateOrgKey -// @Summary Create org key/secret pair (owner/admin) -// @Tags Orgs -// @Accept json -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Param body body orgKeyCreateReq true "Key name + optional expiry" -// @Success 201 {object} orgKeyCreateResp -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/api-keys [post] -// @ID createOrgKey -// @Security BearerAuth +// +// @ID CreateOrgKey +// @Summary Create org key/secret pair (owner/admin) +// @Tags Orgs +// @Accept json +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Param body body orgKeyCreateReq true "Key name + optional expiry" +// @Success 201 {object} orgKeyCreateResp +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/api-keys [post] +// @ID createOrgKey +// @Security BearerAuth func CreateOrgKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) @@ -601,17 +611,18 @@ func CreateOrgKey(db *gorm.DB) http.HandlerFunc { } // DeleteOrgKey godoc -// @ID DeleteOrgKey -// @Summary Delete org key (owner/admin) -// @Tags Orgs -// @Produce json -// @Param id path string true "Org ID (UUID)" -// @Param key_id path string true "Key ID (UUID)" -// @Success 204 "Deleted" -// @Failure 401 {object} utils.ErrorResponse -// @Router /orgs/{id}/api-keys/{key_id} [delete] -// @ID deleteOrgKey -// @Security BearerAuth +// +// @ID DeleteOrgKey +// @Summary Delete org key (owner/admin) +// @Tags Orgs +// @Produce json +// @Param id path string true "Org ID (UUID)" +// @Param key_id path string true "Key ID (UUID)" +// @Success 204 "Deleted" +// @Failure 401 {object} utils.ErrorResponse +// @Router /orgs/{id}/api-keys/{key_id} [delete] +// @ID deleteOrgKey +// @Security BearerAuth func DeleteOrgKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { u, ok := mustUser(r) diff --git a/internal/handlers/servers.go b/internal/handlers/servers.go index 97e5fc9..a951996 100644 --- a/internal/handlers/servers.go +++ b/internal/handlers/servers.go @@ -17,23 +17,24 @@ import ( ) // ListServers godoc -// @ID ListServers -// @Summary List servers (org scoped) -// @Description Returns servers for the organization in X-Org-ID. Optional filters: status, role. -// @Tags Servers -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param status query string false "Filter by status (pending|provisioning|ready|failed)" -// @Param role query string false "Filter by role" -// @Success 200 {array} dto.ServerResponse -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "failed to list servers" -// @Router /servers [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID ListServers +// @Summary List servers (org scoped) +// @Description Returns servers for the organization in X-Org-ID. Optional filters: status, role. +// @Tags Servers +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param status query string false "Filter by status (pending|provisioning|ready|failed)" +// @Param role query string false "Filter by role" +// @Success 200 {array} dto.ServerResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "failed to list servers" +// @Router /servers [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func ListServers(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -83,24 +84,25 @@ func ListServers(db *gorm.DB) http.HandlerFunc { } // GetServer godoc -// @ID GetServer -// @Summary Get server by ID (org scoped) -// @Description Returns one server in the given organization. -// @Tags Servers -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Server ID (UUID)" -// @Success 200 {object} dto.ServerResponse -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "fetch failed" -// @Router /servers/{id} [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID GetServer +// @Summary Get server by ID (org scoped) +// @Description Returns one server in the given organization. +// @Tags Servers +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Server ID (UUID)" +// @Success 200 {object} dto.ServerResponse +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "fetch failed" +// @Router /servers/{id} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func GetServer(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -130,23 +132,24 @@ func GetServer(db *gorm.DB) http.HandlerFunc { } // CreateServer godoc -// @ID CreateServer -// @Summary Create server (org scoped) -// @Description Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org. -// @Tags Servers -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param body body dto.CreateServerRequest true "Server payload" -// @Success 201 {object} dto.ServerResponse -// @Failure 400 {string} string "invalid json / missing fields / invalid status / invalid ssh_key_id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "create failed" -// @Router /servers [post] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID CreateServer +// @Summary Create server (org scoped) +// @Description Creates a server bound to the org in X-Org-ID. Validates that ssh_key_id belongs to the org. +// @Tags Servers +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateServerRequest true "Server payload" +// @Success 201 {object} dto.ServerResponse +// @Failure 400 {string} string "invalid json / missing fields / invalid status / invalid ssh_key_id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "create failed" +// @Router /servers [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func CreateServer(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -218,25 +221,26 @@ func CreateServer(db *gorm.DB) http.HandlerFunc { } // UpdateServer godoc -// @ID UpdateServer -// @Summary Update server (org scoped) -// @Description Partially update fields; changing ssh_key_id validates ownership. -// @Tags Servers -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Server ID (UUID)" -// @Param body body dto.UpdateServerRequest true "Fields to update" -// @Success 200 {object} dto.ServerResponse -// @Failure 400 {string} string "invalid id / invalid json / invalid status / invalid ssh_key_id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "update failed" -// @Router /servers/{id} [patch] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID UpdateServer +// @Summary Update server (org scoped) +// @Description Partially update fields; changing ssh_key_id validates ownership. +// @Tags Servers +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Server ID (UUID)" +// @Param body body dto.UpdateServerRequest true "Fields to update" +// @Success 200 {object} dto.ServerResponse +// @Failure 400 {string} string "invalid id / invalid json / invalid status / invalid ssh_key_id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "update failed" +// @Router /servers/{id} [patch] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func UpdateServer(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -320,23 +324,24 @@ func UpdateServer(db *gorm.DB) http.HandlerFunc { } // DeleteServer godoc -// @ID DeleteServer -// @Summary Delete server (org scoped) -// @Description Permanently deletes the server. -// @Tags Servers -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Server ID (UUID)" -// @Success 204 {string} string "No Content" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "delete failed" -// @Router /servers/{id} [delete] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DeleteServer +// @Summary Delete server (org scoped) +// @Description Permanently deletes the server. +// @Tags Servers +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Server ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /servers/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DeleteServer(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) diff --git a/internal/handlers/ssh_keys.go b/internal/handlers/ssh_keys.go index 3095d2f..cbe3b7e 100644 --- a/internal/handlers/ssh_keys.go +++ b/internal/handlers/ssh_keys.go @@ -26,21 +26,22 @@ import ( ) // ListPublicSshKeys godoc -// @ID ListPublicSshKeys -// @Summary List ssh keys (org scoped) -// @Description Returns ssh keys for the organization in X-Org-ID. -// @Tags Ssh -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Success 200 {array} dto.SshResponse -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "failed to list keys" -// @Router /ssh [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID ListPublicSshKeys +// @Summary List ssh keys (org scoped) +// @Description Returns ssh keys for the organization in X-Org-ID. +// @Tags Ssh +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Success 200 {array} dto.SshResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "failed to list keys" +// @Router /ssh [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func ListPublicSshKeys(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -66,23 +67,24 @@ func ListPublicSshKeys(db *gorm.DB) http.HandlerFunc { } // CreateSSHKey -// @ID CreateSSHKey -// @Summary Create ssh keypair (org scoped) -// @Description Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits. -// @Tags Ssh -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param body body dto.CreateSSHRequest true "Key generation options" -// @Success 201 {object} dto.SshResponse -// @Failure 400 {string} string "invalid json / invalid bits" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "generation/create failed" -// @Router /ssh [post] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID CreateSSHKey +// @Summary Create ssh keypair (org scoped) +// @Description Generates an RSA or ED25519 keypair, saves it, and returns metadata. For RSA you may set bits (2048/3072/4096). Default is 4096. ED25519 ignores bits. +// @Tags Ssh +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateSSHRequest true "Key generation options" +// @Success 201 {object} dto.SshResponse +// @Failure 400 {string} string "invalid json / invalid bits" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "generation/create failed" +// @Router /ssh [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func CreateSSHKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -179,26 +181,27 @@ func CreateSSHKey(db *gorm.DB) http.HandlerFunc { } // GetSSHKey godoc -// @ID GetSSHKey -// @Summary Get ssh key by ID (org scoped) -// @Description Returns public key fields. Append `?reveal=true` to include the private key PEM. -// @Tags Ssh -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "SSH Key ID (UUID)" -// @Param reveal query bool false "Reveal private key PEM" -// @Success 200 {object} dto.SshResponse -// @Success 200 {object} dto.SshRevealResponse "When reveal=true" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "fetch failed" -// @Router /ssh/{id} [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID GetSSHKey +// @Summary Get ssh key by ID (org scoped) +// @Description Returns public key fields. Append `?reveal=true` to include the private key PEM. +// @Tags Ssh +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "SSH Key ID (UUID)" +// @Param reveal query bool false "Reveal private key PEM" +// @Success 200 {object} dto.SshResponse +// @Success 200 {object} dto.SshRevealResponse "When reveal=true" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "fetch failed" +// @Router /ssh/{id} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func GetSSHKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -272,23 +275,24 @@ func GetSSHKey(db *gorm.DB) http.HandlerFunc { } // DeleteSSHKey godoc -// @ID DeleteSSHKey -// @Summary Delete ssh keypair (org scoped) -// @Description Permanently deletes a keypair. -// @Tags Ssh -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "SSH Key ID (UUID)" -// @Success 204 {string} string "No Content" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "delete failed" -// @Router /ssh/{id} [delete] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DeleteSSHKey +// @Summary Delete ssh keypair (org scoped) +// @Description Permanently deletes a keypair. +// @Tags Ssh +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "SSH Key ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /ssh/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DeleteSSHKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -318,24 +322,25 @@ func DeleteSSHKey(db *gorm.DB) http.HandlerFunc { } // DownloadSSHKey godoc -// @ID DownloadSSHKey -// @Summary Download ssh key files by ID (org scoped) -// @Description Download `part=public|private|both` of the keypair. `both` returns a zip file. -// @Tags Ssh -// @Produce json -// @Param X-Org-ID header string true "Organization UUID" -// @Param id path string true "SSH Key ID (UUID)" -// @Param part query string true "Which part to download" Enums(public,private,both) -// @Success 200 {string} string "file content" -// @Failure 400 {string} string "invalid id / invalid part" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "download failed" -// @Router /ssh/{id}/download [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DownloadSSHKey +// @Summary Download ssh key files by ID (org scoped) +// @Description Download `part=public|private|both` of the keypair. `both` returns a zip file. +// @Tags Ssh +// @Produce json +// @Param X-Org-ID header string true "Organization UUID" +// @Param id path string true "SSH Key ID (UUID)" +// @Param part query string true "Which part to download" Enums(public,private,both) +// @Success 200 {string} string "file content" +// @Failure 400 {string} string "invalid id / invalid part" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "download failed" +// @Router /ssh/{id}/download [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DownloadSSHKey(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) diff --git a/internal/handlers/taints.go b/internal/handlers/taints.go index 41ebf36..acb99f2 100644 --- a/internal/handlers/taints.go +++ b/internal/handlers/taints.go @@ -17,24 +17,25 @@ import ( ) // ListTaints godoc -// @ID ListTaints -// @Summary List node pool taints (org scoped) -// @Description Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools. -// @Tags Taints -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param key query string false "Exact key" -// @Param value query string false "Exact value" -// @Param q query string false "key contains (case-insensitive)" -// @Success 200 {array} dto.TaintResponse -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "failed to list node taints" -// @Router /taints [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID ListTaints +// @Summary List node pool taints (org scoped) +// @Description Returns node taints for the organization in X-Org-ID. Filters: `key`, `value`, and `q` (key contains). Add `include=node_pools` to include linked node pools. +// @Tags Taints +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param key query string false "Exact key" +// @Param value query string false "Exact value" +// @Param q query string false "key contains (case-insensitive)" +// @Success 200 {array} dto.TaintResponse +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "failed to list node taints" +// @Router /taints [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func ListTaints(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -65,23 +66,24 @@ func ListTaints(db *gorm.DB) http.HandlerFunc { } // GetTaint godoc -// @ID GetTaint -// @Summary Get node taint by ID (org scoped) -// @Tags Taints -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Node Taint ID (UUID)" -// @Success 200 {object} dto.TaintResponse -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "fetch failed" -// @Router /taints/{id} [get] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID GetTaint +// @Summary Get node taint by ID (org scoped) +// @Tags Taints +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Node Taint ID (UUID)" +// @Success 200 {object} dto.TaintResponse +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "fetch failed" +// @Router /taints/{id} [get] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func GetTaint(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -111,23 +113,24 @@ func GetTaint(db *gorm.DB) http.HandlerFunc { } // CreateTaint godoc -// @ID CreateTaint -// @Summary Create node taint (org scoped) -// @Description Creates a taint. -// @Tags Taints -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param body body dto.CreateTaintRequest true "Taint payload" -// @Success 201 {object} dto.TaintResponse -// @Failure 400 {string} string "invalid json / missing fields / invalid node_pool_ids" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "create failed" -// @Router /taints [post] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID CreateTaint +// @Summary Create node taint (org scoped) +// @Description Creates a taint. +// @Tags Taints +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param body body dto.CreateTaintRequest true "Taint payload" +// @Success 201 {object} dto.TaintResponse +// @Failure 400 {string} string "invalid json / missing fields / invalid node_pool_ids" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "create failed" +// @Router /taints [post] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func CreateTaint(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -181,25 +184,26 @@ func CreateTaint(db *gorm.DB) http.HandlerFunc { } // UpdateTaint godoc -// @ID UpdateTaint -// @Summary Update node taint (org scoped) -// @Description Partially update taint fields. -// @Tags Taints -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Node Taint ID (UUID)" -// @Param body body dto.UpdateTaintRequest true "Fields to update" -// @Success 200 {object} dto.TaintResponse -// @Failure 400 {string} string "invalid id / invalid json" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 404 {string} string "not found" -// @Failure 500 {string} string "update failed" -// @Router /taints/{id} [patch] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID UpdateTaint +// @Summary Update node taint (org scoped) +// @Description Partially update taint fields. +// @Tags Taints +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Node Taint ID (UUID)" +// @Param body body dto.UpdateTaintRequest true "Fields to update" +// @Success 200 {object} dto.TaintResponse +// @Failure 400 {string} string "invalid id / invalid json" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 404 {string} string "not found" +// @Failure 500 {string} string "update failed" +// @Router /taints/{id} [patch] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func UpdateTaint(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) @@ -270,23 +274,24 @@ func UpdateTaint(db *gorm.DB) http.HandlerFunc { } // DeleteTaint godoc -// @ID DeleteTaint -// @Summary Delete taint (org scoped) -// @Description Permanently deletes the taint. -// @Tags Taints -// @Accept json -// @Produce json -// @Param X-Org-ID header string false "Organization UUID" -// @Param id path string true "Node Taint ID (UUID)" -// @Success 204 {string} string "No Content" -// @Failure 400 {string} string "invalid id" -// @Failure 401 {string} string "Unauthorized" -// @Failure 403 {string} string "organization required" -// @Failure 500 {string} string "delete failed" -// @Router /taints/{id} [delete] -// @Security BearerAuth -// @Security OrgKeyAuth -// @Security OrgSecretAuth +// +// @ID DeleteTaint +// @Summary Delete taint (org scoped) +// @Description Permanently deletes the taint. +// @Tags Taints +// @Accept json +// @Produce json +// @Param X-Org-ID header string false "Organization UUID" +// @Param id path string true "Node Taint ID (UUID)" +// @Success 204 {string} string "No Content" +// @Failure 400 {string} string "invalid id" +// @Failure 401 {string} string "Unauthorized" +// @Failure 403 {string} string "organization required" +// @Failure 500 {string} string "delete failed" +// @Router /taints/{id} [delete] +// @Security BearerAuth +// @Security OrgKeyAuth +// @Security OrgSecretAuth func DeleteTaint(db *gorm.DB) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { orgID, ok := httpmiddleware.OrgIDFrom(r.Context()) diff --git a/main.go b/main.go index f3f17e5..195599d 100644 --- a/main.go +++ b/main.go @@ -2,35 +2,35 @@ package main import "github.com/glueops/autoglue/cmd" -// @title AutoGlue API -// @version 1.0 -// @description API for managing K3s clusters across cloud providers +// @title AutoGlue API +// @version 1.0 +// @description API for managing K3s clusters across cloud providers -// @contact.name GlueOps +// @contact.name GlueOps -// @BasePath /api/v1 -// @schemes http https -// @host localhost:8080 +// @BasePath /api/v1 +// @schemes http https +// @host localhost:8080 -// @securityDefinitions.apikey BearerAuth -// @in header -// @name Authorization -// @description Bearer token authentication +// @securityDefinitions.apikey BearerAuth +// @in header +// @name Authorization +// @description Bearer token authentication -// @securityDefinitions.apikey ApiKeyAuth -// @in header -// @name X-API-KEY -// @description User API key +// @securityDefinitions.apikey ApiKeyAuth +// @in header +// @name X-API-KEY +// @description User API key -// @securityDefinitions.apikey OrgKeyAuth -// @in header -// @name X-ORG-KEY -// @description Org-level key/secret authentication +// @securityDefinitions.apikey OrgKeyAuth +// @in header +// @name X-ORG-KEY +// @description Org-level key/secret authentication -// @securityDefinitions.apikey OrgSecretAuth -// @in header -// @name X-ORG-SECRET -// @description Org-level secret +// @securityDefinitions.apikey OrgSecretAuth +// @in header +// @name X-ORG-SECRET +// @description Org-level secret func main() { cmd.Execute()