From 241d48c2fb72371d2b20c43b3a7ee121f1b01ece Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 12:55:08 +0300 Subject: [PATCH 01/16] kor server first commit: new go server in net/http, including TLS, Token, Swagger --- backend/kor/.gitignore | 2 + backend/kor/docs/docs.go | 134 ++++++++++++++++++++++++++++++++ backend/kor/docs/swagger.json | 108 +++++++++++++++++++++++++ backend/kor/docs/swagger.yaml | 69 ++++++++++++++++ backend/kor/go.mod | 25 ++++++ backend/kor/go.sum | 71 +++++++++++++++++ backend/kor/main.go | 117 ++++++++++++++++++++++++++++ backend/tools/generate_token.go | 41 ++++++++++ backend/tools/pre-setup.sh | 3 + 9 files changed, 570 insertions(+) create mode 100644 backend/kor/.gitignore create mode 100644 backend/kor/docs/docs.go create mode 100644 backend/kor/docs/swagger.json create mode 100644 backend/kor/docs/swagger.yaml create mode 100644 backend/kor/go.mod create mode 100644 backend/kor/go.sum create mode 100644 backend/kor/main.go create mode 100644 backend/tools/generate_token.go create mode 100644 backend/tools/pre-setup.sh diff --git a/backend/kor/.gitignore b/backend/kor/.gitignore new file mode 100644 index 00000000..a902256f --- /dev/null +++ b/backend/kor/.gitignore @@ -0,0 +1,2 @@ +server.crt +server.key \ No newline at end of file diff --git a/backend/kor/docs/docs.go b/backend/kor/docs/docs.go new file mode 100644 index 00000000..97f262e3 --- /dev/null +++ b/backend/kor/docs/docs.go @@ -0,0 +1,134 @@ +// Package docs Code generated by swaggo/swag. DO NOT EDIT +package docs + +import "github.com/swaggo/swag" + +const docTemplate = `{ + "schemes": {{ marshal .Schemes }}, + "swagger": "2.0", + "info": { + "description": "{{escape .Description}}", + "title": "{{.Title}}", + "contact": {}, + "version": "{{.Version}}" + }, + "host": "{{.Host}}", + "basePath": "{{.BasePath}}", + "paths": { + "/api/v1/example-get": { + "get": { + "description": "An example GET API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Example GET endpoint", + "parameters": [ + { + "type": "string", + "description": "Authorization token", + "name": "Authorization", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + }, + "/api/v1/example-post": { + "post": { + "description": "An example POST API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Example POST endpoint", + "parameters": [ + { + "description": "Post Request Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.postRequest" + } + }, + { + "type": "string", + "description": "Authorization token", + "name": "Authorization", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + }, + "/healthcheck": { + "get": { + "description": "Returns the status of the server", + "summary": "Health Check", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + } + }, + "definitions": { + "main.postRequest": { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + }, + "main.response": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } +}` + +// SwaggerInfo holds exported Swagger Info so clients can modify it +var SwaggerInfo = &swag.Spec{ + Version: "1.0", + Host: "", + BasePath: "", + Schemes: []string{}, + Title: "KOR API Swagger", + Description: "KOR API Swagger", + InfoInstanceName: "swagger", + SwaggerTemplate: docTemplate, + LeftDelim: "{{", + RightDelim: "}}", +} + +func init() { + swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo) +} diff --git a/backend/kor/docs/swagger.json b/backend/kor/docs/swagger.json new file mode 100644 index 00000000..39e24c8c --- /dev/null +++ b/backend/kor/docs/swagger.json @@ -0,0 +1,108 @@ +{ + "swagger": "2.0", + "info": { + "description": "KOR API Swagger", + "title": "KOR API Swagger", + "contact": {}, + "version": "1.0" + }, + "paths": { + "/api/v1/example-get": { + "get": { + "description": "An example GET API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Example GET endpoint", + "parameters": [ + { + "type": "string", + "description": "Authorization token", + "name": "Authorization", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + }, + "/api/v1/example-post": { + "post": { + "description": "An example POST API", + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "summary": "Example POST endpoint", + "parameters": [ + { + "description": "Post Request Data", + "name": "request", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/main.postRequest" + } + }, + { + "type": "string", + "description": "Authorization token", + "name": "Authorization", + "in": "header" + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + }, + "/healthcheck": { + "get": { + "description": "Returns the status of the server", + "summary": "Health Check", + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/main.response" + } + } + } + } + } + }, + "definitions": { + "main.postRequest": { + "type": "object", + "properties": { + "data": { + "type": "string" + } + } + }, + "main.response": { + "type": "object", + "properties": { + "message": { + "type": "string" + } + } + } + } +} \ No newline at end of file diff --git a/backend/kor/docs/swagger.yaml b/backend/kor/docs/swagger.yaml new file mode 100644 index 00000000..0fbe4e80 --- /dev/null +++ b/backend/kor/docs/swagger.yaml @@ -0,0 +1,69 @@ +definitions: + main.postRequest: + properties: + data: + type: string + type: object + main.response: + properties: + message: + type: string + type: object +info: + contact: {} + description: KOR API Swagger + title: KOR API Swagger + version: "1.0" +paths: + /api/v1/example-get: + get: + consumes: + - application/json + description: An example GET API + parameters: + - description: Authorization token + in: header + name: Authorization + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/main.response' + summary: Example GET endpoint + /api/v1/example-post: + post: + consumes: + - application/json + description: An example POST API + parameters: + - description: Post Request Data + in: body + name: request + required: true + schema: + $ref: '#/definitions/main.postRequest' + - description: Authorization token + in: header + name: Authorization + type: string + produces: + - application/json + responses: + "200": + description: OK + schema: + $ref: '#/definitions/main.response' + summary: Example POST endpoint + /healthcheck: + get: + description: Returns the status of the server + responses: + "200": + description: OK + schema: + $ref: '#/definitions/main.response' + summary: Health Check +swagger: "2.0" diff --git a/backend/kor/go.mod b/backend/kor/go.mod new file mode 100644 index 00000000..3896420e --- /dev/null +++ b/backend/kor/go.mod @@ -0,0 +1,25 @@ +module main + +go 1.22.2 + +require ( + github.com/golang-jwt/jwt/v5 v5.2.1 + github.com/gorilla/mux v1.8.1 + github.com/swaggo/http-swagger v1.3.4 + github.com/swaggo/swag v1.16.3 +) + +require ( + github.com/KyleBanks/depth v1.2.1 // indirect + github.com/go-openapi/jsonpointer v0.19.5 // indirect + github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/go-openapi/spec v0.20.6 // indirect + github.com/go-openapi/swag v0.19.15 // indirect + github.com/josharian/intern v1.0.0 // indirect + github.com/mailru/easyjson v0.7.6 // indirect + github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect + golang.org/x/net v0.17.0 // indirect + golang.org/x/sys v0.13.0 // indirect + golang.org/x/tools v0.7.0 // indirect + gopkg.in/yaml.v2 v2.4.0 // indirect +) diff --git a/backend/kor/go.sum b/backend/kor/go.sum new file mode 100644 index 00000000..10bda6ca --- /dev/null +++ b/backend/kor/go.sum @@ -0,0 +1,71 @@ +github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= +github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= +github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= +github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +github.com/go-openapi/spec v0.20.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= +github.com/go-openapi/spec v0.20.6/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 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= +github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= +github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= +github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= +github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= +github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= +github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= +github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= +github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= +github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= +github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= +golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= +golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= +golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= +golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= +golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= +gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/backend/kor/main.go b/backend/kor/main.go new file mode 100644 index 00000000..1457f6d6 --- /dev/null +++ b/backend/kor/main.go @@ -0,0 +1,117 @@ +package main + +import ( + "crypto/tls" + "encoding/json" + "github.com/golang-jwt/jwt/v5" + "github.com/gorilla/mux" + "github.com/swaggo/http-swagger" + "log" + _ "main/docs" + "net/http" + "os" +) + +var jwtSecret = []byte(os.Getenv("KOR_API_SECRET")) + +type response struct { + Message string `json:"message"` +} + +type postRequest struct { + Data string `json:"data"` +} + +// Auth middleware that verifies the JWT token using golang-jwt/jwt +func authMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if !(os.Getenv("NO_AUTH") == "true") { + tokenHeader := r.Header.Get("Authorization") + if tokenHeader == "" { + w.WriteHeader(http.StatusUnauthorized) + json.NewEncoder(w).Encode(response{Message: "Missing token"}) + return + } + + tokenString := tokenHeader[len("Bearer "):] + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return jwtSecret, nil + }) + + if err != nil || !token.Valid { + w.WriteHeader(http.StatusUnauthorized) + json.NewEncoder(w).Encode(response{Message: "Invalid token"}) + return + } + + next.ServeHTTP(w, r) + } else { + next.ServeHTTP(w, r) + } + }) +} + +// @Summary Health Check +// @Description Returns the status of the server +// @Success 200 {object} response +// @Router /healthcheck [get] +func healthCheckHandler(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(response{Message: "OK"}) +} + +// @Summary Example GET endpoint +// @Description An example GET API +// @Accept json +// @Produce json +// @Success 200 {object} response +// @Router /api/v1/example-get [get] +// @Param Authorization header string false "Authorization token" +func exampleGetHandler(w http.ResponseWriter, r *http.Request) { + json.NewEncoder(w).Encode(response{Message: "This is a GET response"}) +} + +// @Summary Example POST endpoint +// @Description An example POST API +// @Accept json +// @Produce json +// @Param request body postRequest true "Post Request Data" +// @Success 200 {object} response +// @Router /api/v1/example-post [post] +// @Param Authorization header string false "Authorization token" +func examplePostHandler(w http.ResponseWriter, r *http.Request) { + var req postRequest + err := json.NewDecoder(r.Body).Decode(&req) + if err != nil { + w.WriteHeader(http.StatusBadRequest) + json.NewEncoder(w).Encode(response{Message: "Invalid request"}) + return + } + json.NewEncoder(w).Encode(response{Message: "Received: " + req.Data}) +} + +// @title KOR API Swagger +// @version 1.0 +// @description KOR API Swagger +func main() { + router := mux.NewRouter() + + // Base path for the API is /api/v1 + router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") + api := router.PathPrefix("/api/v1").Subrouter() + api.Handle("/example-get", authMiddleware(http.HandlerFunc(exampleGetHandler))).Methods("GET") + api.Handle("/example-post", authMiddleware(http.HandlerFunc(examplePostHandler))).Methods("POST") + // Swagger documentation route + router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) + + // Start HTTPS server + srv := &http.Server{ + Addr: "localhost:8080", + Handler: router, + TLSConfig: &tls.Config{ + MinVersion: tls.VersionTLS12, + }, + } + + log.Println("Server running on https://localhost:8080") + log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key")) +} diff --git a/backend/tools/generate_token.go b/backend/tools/generate_token.go new file mode 100644 index 00000000..23e4d9aa --- /dev/null +++ b/backend/tools/generate_token.go @@ -0,0 +1,41 @@ +package main + +import ( + "fmt" + "github.com/golang-jwt/jwt/v5" +) + +var jwtSecret = []byte("XXXX") // Replace with your actual secret key + +// GenerateJWT generates a JWT token that doesn't expire +func GenerateJWT() (string, error) { + // Create a new token object with claims (additional data) + claims := jwt.MapClaims{ + "authorized": true, + "user": "exampleUser", // Replace with actual user info + // No "exp" field means the token will not expire + } + + // Create the token with signing method and claims + token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) + + // Sign the token with the secret key + tokenString, err := token.SignedString(jwtSecret) + if err != nil { + return "", err + } + + return tokenString, nil +} + +func main() { + // Generate the JWT token + token, err := GenerateJWT() + if err != nil { + fmt.Println("Error generating token:", err) + return + } + + // Print the generated token (Bearer token) + fmt.Println("Bearer token:", token) +} diff --git a/backend/tools/pre-setup.sh b/backend/tools/pre-setup.sh new file mode 100644 index 00000000..d5ac1b99 --- /dev/null +++ b/backend/tools/pre-setup.sh @@ -0,0 +1,3 @@ +#TODO: place static files in dockerfile +openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes +go run server.go \ No newline at end of file From ef91e7302f29297edc66de23d6fd762d1b0a6b2e Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 16:42:51 +0300 Subject: [PATCH 02/16] add configmaps endpoint --- backend/kor/go.mod | 62 ++++++++++++-- backend/kor/go.sum | 203 +++++++++++++++++++++++++++++++++++++++----- backend/kor/main.go | 62 +++++++++++--- 3 files changed, 289 insertions(+), 38 deletions(-) diff --git a/backend/kor/go.mod b/backend/kor/go.mod index 3896420e..fd7b092c 100644 --- a/backend/kor/go.mod +++ b/backend/kor/go.mod @@ -7,19 +7,67 @@ require ( github.com/gorilla/mux v1.8.1 github.com/swaggo/http-swagger v1.3.4 github.com/swaggo/swag v1.16.3 + github.com/yonahd/kor v0.5.5 ) require ( github.com/KyleBanks/depth v1.2.1 // indirect - github.com/go-openapi/jsonpointer v0.19.5 // indirect - github.com/go-openapi/jsonreference v0.20.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect + github.com/emicklei/go-restful/v3 v3.11.0 // indirect + github.com/fatih/color v1.17.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect + github.com/go-logr/logr v1.4.2 // indirect + github.com/go-openapi/jsonpointer v0.20.0 // indirect + github.com/go-openapi/jsonreference v0.20.2 // indirect github.com/go-openapi/spec v0.20.6 // indirect - github.com/go-openapi/swag v0.19.15 // indirect + github.com/go-openapi/swag v0.22.4 // indirect + github.com/gogo/protobuf v1.3.2 // indirect + github.com/golang/protobuf v1.5.4 // indirect + github.com/google/gnostic-models v0.6.8 // indirect + github.com/google/go-cmp v0.6.0 // indirect + github.com/google/gofuzz v1.2.0 // indirect + github.com/google/uuid v1.6.0 // indirect + github.com/imdario/mergo v0.3.16 // indirect github.com/josharian/intern v1.0.0 // indirect - github.com/mailru/easyjson v0.7.6 // indirect + github.com/json-iterator/go v1.1.12 // indirect + github.com/klauspost/compress v1.17.9 // indirect + github.com/mailru/easyjson v0.7.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.14 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.2 // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect + github.com/olekukonko/tablewriter v0.0.5 // indirect + github.com/prometheus/client_golang v1.20.0 // indirect + github.com/prometheus/client_model v0.6.1 // indirect + github.com/prometheus/common v0.55.0 // indirect + github.com/prometheus/procfs v0.15.1 // indirect + github.com/rivo/uniseg v0.4.4 // indirect + github.com/spf13/pflag v1.0.5 // indirect github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe // indirect - golang.org/x/net v0.17.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/tools v0.7.0 // indirect + github.com/x448/float16 v0.8.4 // indirect + golang.org/x/net v0.26.0 // indirect + golang.org/x/oauth2 v0.21.0 // indirect + golang.org/x/sys v0.22.0 // indirect + golang.org/x/term v0.21.0 // indirect + golang.org/x/text v0.16.0 // indirect + golang.org/x/time v0.3.0 // indirect + golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect + google.golang.org/protobuf v1.34.2 // indirect + gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/yaml.v2 v2.4.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect + k8s.io/api v0.31.0 // indirect + k8s.io/apiextensions-apiserver v0.31.0 // indirect + k8s.io/apimachinery v0.31.0 // indirect + k8s.io/client-go v0.31.0 // indirect + k8s.io/klog/v2 v2.130.1 // indirect + k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 // indirect + k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 // indirect + sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd // indirect + sigs.k8s.io/structured-merge-diff/v4 v4.4.1 // indirect + sigs.k8s.io/yaml v1.4.0 // indirect ) diff --git a/backend/kor/go.sum b/backend/kor/go.sum index 10bda6ca..fa160574 100644 --- a/backend/kor/go.sum +++ b/backend/kor/go.sum @@ -1,71 +1,234 @@ github.com/KyleBanks/depth v1.2.1 h1:5h8fQADFrWtarTdtDudMmGsC7GPbOAu6RVB3ffsVFHc= github.com/KyleBanks/depth v1.2.1/go.mod h1:jzSb9d0L43HxTQfT+oSA1EEp2q+ne2uh6XgeJcm8brE= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/emicklei/go-restful/v3 v3.11.0 h1:rAQeMHw1c7zTmncogyy8VvRZwtkmkZ4FxERmMY4rD+g= +github.com/emicklei/go-restful/v3 v3.11.0/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc= +github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= +github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= +github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonpointer v0.19.5 h1:gZr+CIYByUqjcgeLXnQu2gHYQC9o73G2XUeOFYEICuY= github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg= -github.com/go-openapi/jsonreference v0.20.0 h1:MYlu0sBgChmCfJxxUKZ8g1cPWFOB37YSZqewK7OKeyA= +github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs= +github.com/go-openapi/jsonpointer v0.20.0 h1:ESKJdU9ASRfaPNOPRx12IUyA1vn3R9GiE3KYD14BXdQ= +github.com/go-openapi/jsonpointer v0.20.0/go.mod h1:6PGzBjjIIumbLYysB73Klnms1mwnU4G3YHOECG3CedA= github.com/go-openapi/jsonreference v0.20.0/go.mod h1:Ag74Ico3lPc+zR+qjn4XBUmXymS4zJbYVCZmcgkasdo= +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.6 h1:ich1RQ3WDbfoeTqTAb+5EIxNmpKVJZWBNah9RAT0jIQ= github.com/go-openapi/spec v0.20.6/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 h1:D2NRCBzS9/pEY3gP9Nl8aDqGUcPFrwG2p+CNFrLyrCM= github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ= +github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU= +github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= +github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= +github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I= +github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af h1:kmjWCqn2qkEml422C2Rrd27c3VGxi6a/6HNq8QmHRKM= +github.com/google/pprof v0.0.0-20240525223248-4bfdf5a9a2af/go.mod h1:K1liHPHnj73Fdn/EKuT8nrFqBihUSKXoLYU0BuatOYo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4= +github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= +github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= +github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= +github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.17.9 h1:6KIumPrER1LHsvBVuDa0r5xaG0Es51mhhB9BQB2qeMA= +github.com/klauspost/compress v1.17.9/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= 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= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc= -github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA= github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= +github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= +github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= +github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= +github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= +github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= +github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= +github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.20.0 h1:jBzTZ7B099Rg24tny+qngoynol8LtVYlA2bqx3vEloI= +github.com/prometheus/client_golang v1.20.0/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= +github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E= +github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY= +github.com/prometheus/common v0.55.0 h1:KEi6DK7lXW/m7Ig5i47x0vRzuBsHuvJdi5ee6Y3G1dc= +github.com/prometheus/common v0.55.0/go.mod h1:2SECS4xJG1kd8XF9IcM1gMX6510RAEL65zxzNImwdc8= +github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc= +github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rivo/uniseg v0.4.4 h1:8TfxU8dW6PdqD27gjM8MVNuicgxIjxpm4K7x4jp8sis= +github.com/rivo/uniseg v0.4.4/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= 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/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 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -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.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe h1:K8pHPVoTgxFJt1lXuIzzOX7zZhZFldJQK/CgKx9BFIc= github.com/swaggo/files v0.0.0-20220610200504-28940afbdbfe/go.mod h1:lKJPbtWzJ9JhsTN1k1gZgleJWY/cqq0psdoMmaThG3w= github.com/swaggo/http-swagger v1.3.4 h1:q7t/XLx0n15H1Q9/tk3Y9L4n210XzJF5WtnDX64a5ww= github.com/swaggo/http-swagger v1.3.4/go.mod h1:9dAh0unqMBAlbp1uE2Uc2mQTxNMU/ha4UbucIg1MFkQ= github.com/swaggo/swag v1.16.3 h1:PnCYjPCah8FK4I26l2F/KQ4yz3sILcVUN3cTlBFA9Pg= github.com/swaggo/swag v1.16.3/go.mod h1:DImHIuOFXKpMFAQjcC7FG4m3Dg4+QuUgUzJmKjI/gRk= -golang.org/x/mod v0.9.0 h1:KENHtAZL2y3NLMYZeHY9DW8HW8V+kQyJsY/V9JlKvCs= -golang.org/x/mod v0.9.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= +github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= +github.com/yonahd/kor v0.5.5 h1:ZJ2CIV+SQGU/b7paG5DKyUtBLzfkwXNJFu9Jjqo1QL0= +github.com/yonahd/kor v0.5.5/go.mod h1:yqFBDN17GeIGDbRqXT6HK9H3arRR2KXxs3IK/5LYWuU= +github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= +golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM= -golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= +golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= +golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= +golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI= +golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA= +golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= +golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= +golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.7.0 h1:W4OVu8VVOaIO0yzWMNdepAulS7YfoS3Zabrm8DOXXU4= -golang.org/x/tools v0.7.0/go.mod h1:4pg6aUX35JBAogB10C9AtvVL+qowtN4pT3CGSQex14s= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg= +golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= +google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU= gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= +gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4= +gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M= +gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= +gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA= -gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +k8s.io/api v0.31.0 h1:b9LiSjR2ym/SzTOlfMHm1tr7/21aD7fSkqgD/CVJBCo= +k8s.io/api v0.31.0/go.mod h1:0YiFF+JfFxMM6+1hQei8FY8M7s1Mth+z/q7eF1aJkTE= +k8s.io/apiextensions-apiserver v0.31.0 h1:fZgCVhGwsclj3qCw1buVXCV6khjRzKC5eCFt24kyLSk= +k8s.io/apiextensions-apiserver v0.31.0/go.mod h1:b9aMDEYaEe5sdK+1T0KU78ApR/5ZVp4i56VacZYEHxk= +k8s.io/apimachinery v0.31.0 h1:m9jOiSr3FoSSL5WO9bjm1n6B9KROYYgNZOb4tyZ1lBc= +k8s.io/apimachinery v0.31.0/go.mod h1:rsPdaZJfTfLsNJSQzNHQvYoTmxhoOEofxtOsF3rtsMo= +k8s.io/client-go v0.31.0 h1:QqEJzNjbN2Yv1H79SsS+SWnXkBgVu4Pj3CJQgbx0gI8= +k8s.io/client-go v0.31.0/go.mod h1:Y9wvC76g4fLjmU0BA+rV+h2cncoadjvjjkkIGoTLcGU= +k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk= +k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340 h1:BZqlfIlq5YbRMFko6/PM7FjZpUb45WallggurYhKGag= +k8s.io/kube-openapi v0.0.0-20240228011516-70dd3763d340/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8 h1:pUdcCO1Lk/tbT5ztQWOBi5HBgbBP1J8+AsQnQCKsi8A= +k8s.io/utils v0.0.0-20240711033017-18e509b52bc8/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= +sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= +sigs.k8s.io/structured-merge-diff/v4 v4.4.1/go.mod h1:N8hJocpFajUSSeSJ9bOZ77VzejKZaXsTtZo4/u7Io08= +sigs.k8s.io/yaml v1.4.0 h1:Mk1wCc2gy/F0THH0TAp1QYyJNzRm2KCLy3o5ASXVI5E= +sigs.k8s.io/yaml v1.4.0/go.mod h1:Ejl7/uTz7PSA4eKMyQCUTnhZYNmLIl+5c2lQPGR2BPY= diff --git a/backend/kor/main.go b/backend/kor/main.go index 1457f6d6..2495d39f 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -3,9 +3,14 @@ package main import ( "crypto/tls" "encoding/json" + "fmt" "github.com/golang-jwt/jwt/v5" "github.com/gorilla/mux" "github.com/swaggo/http-swagger" + "github.com/yonahd/kor/pkg/common" + "github.com/yonahd/kor/pkg/filters" + "github.com/yonahd/kor/pkg/kor" + "k8s.io/client-go/kubernetes" "log" _ "main/docs" "net/http" @@ -14,7 +19,7 @@ import ( var jwtSecret = []byte(os.Getenv("KOR_API_SECRET")) -type response struct { +type SimpleResponse struct { Message string `json:"message"` } @@ -22,6 +27,8 @@ type postRequest struct { Data string `json:"data"` } +var clientset *kubernetes.Clientset + // Auth middleware that verifies the JWT token using golang-jwt/jwt func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -29,7 +36,7 @@ func authMiddleware(next http.Handler) http.Handler { tokenHeader := r.Header.Get("Authorization") if tokenHeader == "" { w.WriteHeader(http.StatusUnauthorized) - json.NewEncoder(w).Encode(response{Message: "Missing token"}) + json.NewEncoder(w).Encode(SimpleResponse{Message: "Missing token"}) return } @@ -40,7 +47,7 @@ func authMiddleware(next http.Handler) http.Handler { if err != nil || !token.Valid { w.WriteHeader(http.StatusUnauthorized) - json.NewEncoder(w).Encode(response{Message: "Invalid token"}) + json.NewEncoder(w).Encode(SimpleResponse{Message: "Invalid token"}) return } @@ -56,7 +63,7 @@ func authMiddleware(next http.Handler) http.Handler { // @Success 200 {object} response // @Router /healthcheck [get] func healthCheckHandler(w http.ResponseWriter, r *http.Request) { - json.NewEncoder(w).Encode(response{Message: "OK"}) + json.NewEncoder(w).Encode(SimpleResponse{Message: "OK"}) } // @Summary Example GET endpoint @@ -64,10 +71,42 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { // @Accept json // @Produce json // @Success 200 {object} response -// @Router /api/v1/example-get [get] +// @Router /api/v1/configmaps [get] // @Param Authorization header string false "Authorization token" -func exampleGetHandler(w http.ResponseWriter, r *http.Request) { - json.NewEncoder(w).Encode(response{Message: "This is a GET response"}) +func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { + // Defer function to recover from any panic + defer func() { + if err := recover(); err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("A fatal error occurred: %v", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + log.Printf("Recovered from panic: %v", err) // Optionally log the error + } + }() + + // Your normal business logic + outputFormat := "json" + opts := common.Opts{ + WebhookURL: "", + Channel: "", + Token: "", + DeleteFlag: false, + NoInteractive: true, + GroupBy: "namespace", + } + + // Try to get unused configmaps + response, err := kor.GetUnusedConfigmaps(&filters.Options{}, clientset, outputFormat, opts) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failed to get configmaps: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + return + } + + // If successful, encode the response + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(response) } // @Summary Example POST endpoint @@ -83,10 +122,10 @@ func examplePostHandler(w http.ResponseWriter, r *http.Request) { err := json.NewDecoder(r.Body).Decode(&req) if err != nil { w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(response{Message: "Invalid request"}) + json.NewEncoder(w).Encode(SimpleResponse{Message: "Invalid request"}) return } - json.NewEncoder(w).Encode(response{Message: "Received: " + req.Data}) + json.NewEncoder(w).Encode("") } // @title KOR API Swagger @@ -94,11 +133,12 @@ func examplePostHandler(w http.ResponseWriter, r *http.Request) { // @description KOR API Swagger func main() { router := mux.NewRouter() + clientset = kor.GetKubeClient("") - // Base path for the API is /api/v1 router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") + // Base path for the API is /api/v1 api := router.PathPrefix("/api/v1").Subrouter() - api.Handle("/example-get", authMiddleware(http.HandlerFunc(exampleGetHandler))).Methods("GET") + api.Handle("/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmaps))).Methods("GET") api.Handle("/example-post", authMiddleware(http.HandlerFunc(examplePostHandler))).Methods("POST") // Swagger documentation route router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) From 8e84eef8460d066e666611a7fecdbda7dcb3f7a8 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:24:44 +0300 Subject: [PATCH 03/16] align healthcheck --- backend/kor/main.go | 110 +++++++++++++++++++++++++++----------------- 1 file changed, 69 insertions(+), 41 deletions(-) diff --git a/backend/kor/main.go b/backend/kor/main.go index 2495d39f..9d84440d 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -23,10 +23,6 @@ type SimpleResponse struct { Message string `json:"message"` } -type postRequest struct { - Data string `json:"data"` -} - var clientset *kubernetes.Clientset // Auth middleware that verifies the JWT token using golang-jwt/jwt @@ -58,34 +54,41 @@ func authMiddleware(next http.Handler) http.Handler { }) } +func recoveryMiddleware(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + defer func() { + if err := recover(); err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Internal Server Error: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + } + }() + next.ServeHTTP(w, r) + }) +} + // @Summary Health Check // @Description Returns the status of the server // @Success 200 {object} response // @Router /healthcheck [get] func healthCheckHandler(w http.ResponseWriter, r *http.Request) { + _, err := clientset.Discovery().ServerVersion() + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failure: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + } json.NewEncoder(w).Encode(SimpleResponse{Message: "OK"}) } -// @Summary Example GET endpoint -// @Description An example GET API +// @Summary Get Unused configmaps from all namespaces // @Accept json // @Produce json // @Success 200 {object} response // @Router /api/v1/configmaps [get] // @Param Authorization header string false "Authorization token" func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { - // Defer function to recover from any panic - defer func() { - if err := recover(); err != nil { - w.WriteHeader(http.StatusInternalServerError) - errorMsg := fmt.Sprintf("A fatal error occurred: %v", err) - json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) - log.Printf("Recovered from panic: %v", err) // Optionally log the error - } - }() - // Your normal business logic - outputFormat := "json" opts := common.Opts{ WebhookURL: "", Channel: "", @@ -95,8 +98,37 @@ func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { GroupBy: "namespace", } - // Try to get unused configmaps - response, err := kor.GetUnusedConfigmaps(&filters.Options{}, clientset, outputFormat, opts) + getUnusedConfigMapWithFilters(w, opts, &filters.Options{}) +} + +// @Summary Get Unused configmaps from a specific namespace +// @Accept json +// @Produce json +// @Success 200 {object} response +// @Router /api/v1/namespaces/{namespace}/configmaps [get] +// @Param Authorization header string false "Authorization token" +func getUnusedConfigmapsForNamespace(w http.ResponseWriter, r *http.Request) { + // Extract the "namespace" parameter from the path + namespaceArr := []string{mux.Vars(r)["namespace"]} + + opts := common.Opts{ + WebhookURL: "", + Channel: "", + Token: "", + DeleteFlag: false, + NoInteractive: true, + GroupBy: "namespace", + } + + getUnusedConfigMapWithFilters(w, opts, &filters.Options{ + IncludeNamespaces: namespaceArr, + }) +} + +func getUnusedConfigMapWithFilters(w http.ResponseWriter, opts common.Opts, filterOpts *filters.Options) { + outputFormat := "json" + // Call the function that returns a JSON string + response, err := kor.GetUnusedConfigmaps(filterOpts, clientset, outputFormat, opts) if err != nil { w.WriteHeader(http.StatusInternalServerError) errorMsg := fmt.Sprintf("Failed to get configmaps: %v\n", err) @@ -104,28 +136,20 @@ func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { return } - // If successful, encode the response - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(response) -} + // Declare a variable to hold the parsed JSON structure + var parsedResponse map[string]interface{} -// @Summary Example POST endpoint -// @Description An example POST API -// @Accept json -// @Produce json -// @Param request body postRequest true "Post Request Data" -// @Success 200 {object} response -// @Router /api/v1/example-post [post] -// @Param Authorization header string false "Authorization token" -func examplePostHandler(w http.ResponseWriter, r *http.Request) { - var req postRequest - err := json.NewDecoder(r.Body).Decode(&req) - if err != nil { - w.WriteHeader(http.StatusBadRequest) - json.NewEncoder(w).Encode(SimpleResponse{Message: "Invalid request"}) + // Parse the JSON string into a map + if err := json.Unmarshal([]byte(response), &parsedResponse); err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failed to parse configmaps response: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) return } - json.NewEncoder(w).Encode("") + + // Send the parsed JSON as the response + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(parsedResponse) } // @title KOR API Swagger @@ -139,19 +163,23 @@ func main() { // Base path for the API is /api/v1 api := router.PathPrefix("/api/v1").Subrouter() api.Handle("/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmaps))).Methods("GET") + api.Handle("/namespaces/{namespace}/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmapsForNamespace))).Methods("GET") api.Handle("/example-post", authMiddleware(http.HandlerFunc(examplePostHandler))).Methods("POST") + // Swagger documentation route router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) + recoveredRouter := recoveryMiddleware(router) // Start HTTPS server srv := &http.Server{ Addr: "localhost:8080", - Handler: router, + Handler: recoveredRouter, TLSConfig: &tls.Config{ MinVersion: tls.VersionTLS12, }, } - log.Println("Server running on https://localhost:8080") - log.Fatal(srv.ListenAndServeTLS("server.crt", "server.key")) + if err := srv.ListenAndServeTLS("server.crt", "server.key"); err != nil && err != http.ErrServerClosed { + log.Printf("Error starting server: %v", err) + } } From dbef318bda2c4828528ddf5aff976ce553e7edff Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:24:55 +0300 Subject: [PATCH 04/16] align healthcheck --- backend/tools/generate_token.go | 7 +++++-- backend/tools/pre-setup.sh | 15 ++++++++++++++- 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/backend/tools/generate_token.go b/backend/tools/generate_token.go index 23e4d9aa..f4c5db61 100644 --- a/backend/tools/generate_token.go +++ b/backend/tools/generate_token.go @@ -1,11 +1,14 @@ package main +//How to use: +//export USER_SECRET=abcd12; go run generate_token.go import ( "fmt" "github.com/golang-jwt/jwt/v5" + "os" ) -var jwtSecret = []byte("XXXX") // Replace with your actual secret key +var jwtSecret = []byte(os.Getenv("KOR_API_SECRET")) // Replace with your actual secret key // GenerateJWT generates a JWT token that doesn't expire func GenerateJWT() (string, error) { @@ -37,5 +40,5 @@ func main() { } // Print the generated token (Bearer token) - fmt.Println("Bearer token:", token) + fmt.Println(token) } diff --git a/backend/tools/pre-setup.sh b/backend/tools/pre-setup.sh index d5ac1b99..fda8f175 100644 --- a/backend/tools/pre-setup.sh +++ b/backend/tools/pre-setup.sh @@ -1,3 +1,16 @@ +#Generate token +cd kor/backend/tools +export KOR_API_SECRET=abcd12; export KOR_API_TOKEN=$(go run generate_token.go) +#In case no auth needed +export NO_AUTH=true #TODO: place static files in dockerfile openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -go run server.go \ No newline at end of file +go run main.go + +### SWAGGER #### +# Install swag cli +go install github.com/swaggo/swag/cmd/swag@latest +# Regenerate swagger +swag init +#Swagger ui +https://localhost:8080/swagger/index.html From acdb1bb9cbcc592a8f1a7e77b573bc4d7350848e Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:25:42 +0300 Subject: [PATCH 05/16] align healthcheck --- backend/tools/pre-setup.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/tools/pre-setup.sh b/backend/tools/pre-setup.sh index fda8f175..0447b500 100644 --- a/backend/tools/pre-setup.sh +++ b/backend/tools/pre-setup.sh @@ -12,5 +12,4 @@ go run main.go go install github.com/swaggo/swag/cmd/swag@latest # Regenerate swagger swag init -#Swagger ui -https://localhost:8080/swagger/index.html + From c98da687b67cbac7f23c7d9e2e3e8cc812621ad0 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:27:09 +0300 Subject: [PATCH 06/16] align healthcheck --- backend/kor/main.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/kor/main.go b/backend/kor/main.go index 9d84440d..5a6bfe90 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -159,12 +159,12 @@ func main() { router := mux.NewRouter() clientset = kor.GetKubeClient("") - router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") // Base path for the API is /api/v1 api := router.PathPrefix("/api/v1").Subrouter() + + router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") api.Handle("/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmaps))).Methods("GET") api.Handle("/namespaces/{namespace}/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmapsForNamespace))).Methods("GET") - api.Handle("/example-post", authMiddleware(http.HandlerFunc(examplePostHandler))).Methods("POST") // Swagger documentation route router.PathPrefix("/swagger/").Handler(httpSwagger.WrapHandler) From ee9e6e6c7dc90c1b22d1090af1bc2d99cd4c3ae1 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:29:19 +0300 Subject: [PATCH 07/16] align healthcheck --- backend/kor/main.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/kor/main.go b/backend/kor/main.go index 5a6bfe90..edae8624 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -77,6 +77,7 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) errorMsg := fmt.Sprintf("Failure: %v\n", err) json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + return } json.NewEncoder(w).Encode(SimpleResponse{Message: "OK"}) } @@ -161,7 +162,7 @@ func main() { // Base path for the API is /api/v1 api := router.PathPrefix("/api/v1").Subrouter() - + router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") api.Handle("/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmaps))).Methods("GET") api.Handle("/namespaces/{namespace}/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmapsForNamespace))).Methods("GET") From 852c89ca3b7d62d41bbdd657e58b723c50f29b09 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:32:49 +0300 Subject: [PATCH 08/16] align swagger docs --- backend/kor/docs/docs.go | 67 +++++------------------------------ backend/kor/docs/swagger.json | 67 +++++------------------------------ backend/kor/docs/swagger.yaml | 48 +++++-------------------- backend/kor/main.go | 4 +-- 4 files changed, 28 insertions(+), 158 deletions(-) diff --git a/backend/kor/docs/docs.go b/backend/kor/docs/docs.go index 97f262e3..3e94977f 100644 --- a/backend/kor/docs/docs.go +++ b/backend/kor/docs/docs.go @@ -15,16 +15,15 @@ const docTemplate = `{ "host": "{{.Host}}", "basePath": "{{.BasePath}}", "paths": { - "/api/v1/example-get": { + "/api/v1/configmaps": { "get": { - "description": "An example GET API", "consumes": [ "application/json" ], "produces": [ "application/json" ], - "summary": "Example GET endpoint", + "summary": "Get Unused configmaps from all namespaces", "parameters": [ { "type": "string", @@ -33,36 +32,20 @@ const docTemplate = `{ "in": "header" } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } + "responses": {} } }, - "/api/v1/example-post": { - "post": { - "description": "An example POST API", + "/api/v1/namespaces/{namespace}/configmaps": { + "get": { + "description": "asd", "consumes": [ "application/json" ], "produces": [ "application/json" ], - "summary": "Example POST endpoint", + "summary": "Get Unused configmaps from a specific namespace", "parameters": [ - { - "description": "Post Request Data", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/main.postRequest" - } - }, { "type": "string", "description": "Authorization token", @@ -70,46 +53,14 @@ const docTemplate = `{ "in": "header" } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } + "responses": {} } }, "/healthcheck": { "get": { "description": "Returns the status of the server", "summary": "Health Check", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } - } - } - }, - "definitions": { - "main.postRequest": { - "type": "object", - "properties": { - "data": { - "type": "string" - } - } - }, - "main.response": { - "type": "object", - "properties": { - "message": { - "type": "string" - } + "responses": {} } } } diff --git a/backend/kor/docs/swagger.json b/backend/kor/docs/swagger.json index 39e24c8c..3f66bae6 100644 --- a/backend/kor/docs/swagger.json +++ b/backend/kor/docs/swagger.json @@ -7,16 +7,15 @@ "version": "1.0" }, "paths": { - "/api/v1/example-get": { + "/api/v1/configmaps": { "get": { - "description": "An example GET API", "consumes": [ "application/json" ], "produces": [ "application/json" ], - "summary": "Example GET endpoint", + "summary": "Get Unused configmaps from all namespaces", "parameters": [ { "type": "string", @@ -25,36 +24,20 @@ "in": "header" } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } + "responses": {} } }, - "/api/v1/example-post": { - "post": { - "description": "An example POST API", + "/api/v1/namespaces/{namespace}/configmaps": { + "get": { + "description": "asd", "consumes": [ "application/json" ], "produces": [ "application/json" ], - "summary": "Example POST endpoint", + "summary": "Get Unused configmaps from a specific namespace", "parameters": [ - { - "description": "Post Request Data", - "name": "request", - "in": "body", - "required": true, - "schema": { - "$ref": "#/definitions/main.postRequest" - } - }, { "type": "string", "description": "Authorization token", @@ -62,46 +45,14 @@ "in": "header" } ], - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } + "responses": {} } }, "/healthcheck": { "get": { "description": "Returns the status of the server", "summary": "Health Check", - "responses": { - "200": { - "description": "OK", - "schema": { - "$ref": "#/definitions/main.response" - } - } - } - } - } - }, - "definitions": { - "main.postRequest": { - "type": "object", - "properties": { - "data": { - "type": "string" - } - } - }, - "main.response": { - "type": "object", - "properties": { - "message": { - "type": "string" - } + "responses": {} } } } diff --git a/backend/kor/docs/swagger.yaml b/backend/kor/docs/swagger.yaml index 0fbe4e80..9898aa25 100644 --- a/backend/kor/docs/swagger.yaml +++ b/backend/kor/docs/swagger.yaml @@ -1,25 +1,13 @@ -definitions: - main.postRequest: - properties: - data: - type: string - type: object - main.response: - properties: - message: - type: string - type: object info: contact: {} description: KOR API Swagger title: KOR API Swagger version: "1.0" paths: - /api/v1/example-get: + /api/v1/configmaps: get: consumes: - application/json - description: An example GET API parameters: - description: Authorization token in: header @@ -27,43 +15,25 @@ paths: type: string produces: - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.response' - summary: Example GET endpoint - /api/v1/example-post: - post: + responses: {} + summary: Get Unused configmaps from all namespaces + /api/v1/namespaces/{namespace}/configmaps: + get: consumes: - application/json - description: An example POST API + description: asd parameters: - - description: Post Request Data - in: body - name: request - required: true - schema: - $ref: '#/definitions/main.postRequest' - description: Authorization token in: header name: Authorization type: string produces: - application/json - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.response' - summary: Example POST endpoint + responses: {} + summary: Get Unused configmaps from a specific namespace /healthcheck: get: description: Returns the status of the server - responses: - "200": - description: OK - schema: - $ref: '#/definitions/main.response' + responses: {} summary: Health Check swagger: "2.0" diff --git a/backend/kor/main.go b/backend/kor/main.go index edae8624..2dc391f3 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -69,7 +69,6 @@ func recoveryMiddleware(next http.Handler) http.Handler { // @Summary Health Check // @Description Returns the status of the server -// @Success 200 {object} response // @Router /healthcheck [get] func healthCheckHandler(w http.ResponseWriter, r *http.Request) { _, err := clientset.Discovery().ServerVersion() @@ -85,7 +84,6 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { // @Summary Get Unused configmaps from all namespaces // @Accept json // @Produce json -// @Success 200 {object} response // @Router /api/v1/configmaps [get] // @Param Authorization header string false "Authorization token" func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { @@ -103,9 +101,9 @@ func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { } // @Summary Get Unused configmaps from a specific namespace +// @Description asd // @Accept json // @Produce json -// @Success 200 {object} response // @Router /api/v1/namespaces/{namespace}/configmaps [get] // @Param Authorization header string false "Authorization token" func getUnusedConfigmapsForNamespace(w http.ResponseWriter, r *http.Request) { From e3e345a9560a4808b25c8756b8fbb2f7834ee0fd Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 5 Sep 2024 20:42:18 +0300 Subject: [PATCH 09/16] add go modules to backend/tools --- backend/tools/go.mod | 5 +++++ backend/tools/go.sum | 2 ++ 2 files changed, 7 insertions(+) create mode 100644 backend/tools/go.mod create mode 100644 backend/tools/go.sum diff --git a/backend/tools/go.mod b/backend/tools/go.mod new file mode 100644 index 00000000..94bb48c5 --- /dev/null +++ b/backend/tools/go.mod @@ -0,0 +1,5 @@ +module main + +go 1.22.2 + +require github.com/golang-jwt/jwt/v5 v5.2.1 diff --git a/backend/tools/go.sum b/backend/tools/go.sum new file mode 100644 index 00000000..f56d3e63 --- /dev/null +++ b/backend/tools/go.sum @@ -0,0 +1,2 @@ +github.com/golang-jwt/jwt/v5 v5.2.1 h1:OuVbFODueb089Lh128TAcimifWaLhJwVflnrgM17wHk= +github.com/golang-jwt/jwt/v5 v5.2.1/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= From ef855711cd6c1064264e61e165708d49ee0d4d85 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Sat, 7 Sep 2024 22:10:46 +0300 Subject: [PATCH 10/16] add Dockerfile, regenerated docs --- backend/kor/Dockerfile | 33 +++++++++++++++++++++++++++++++++ backend/kor/docs/docs.go | 7 +++++++ backend/kor/docs/swagger.json | 7 +++++++ backend/kor/docs/swagger.yaml | 5 +++++ backend/kor/main.go | 1 + backend/tools/.gitignore | 2 ++ backend/tools/pre-setup.sh | 15 --------------- 7 files changed, 55 insertions(+), 15 deletions(-) create mode 100644 backend/kor/Dockerfile create mode 100644 backend/tools/.gitignore delete mode 100644 backend/tools/pre-setup.sh diff --git a/backend/kor/Dockerfile b/backend/kor/Dockerfile new file mode 100644 index 00000000..97d4fd93 --- /dev/null +++ b/backend/kor/Dockerfile @@ -0,0 +1,33 @@ +# Use an official Golang image as the build environment +FROM golang:1.22.2-alpine AS builder + +# Set the working directory inside the container +WORKDIR /app + +# Copy the Go module files to install dependencies +COPY go.mod go.sum ./ + +# Download the Go dependencies +RUN go mod download + +# Copy the rest of the source code +COPY . . + +# Build the Go application +RUN go build -o /go-service + +# Use a smaller base image for the final container +FROM alpine:latest + +# Set the working directory for the final container +WORKDIR /root/ + +# Copy the compiled Go binary from the builder stage +COPY --from=builder /go-service . +COPY server.crt . +COPY server.key . +# Expose the application's port (optional) +EXPOSE 8080 + +# Command to run the Go service +CMD ["./go-service"] \ No newline at end of file diff --git a/backend/kor/docs/docs.go b/backend/kor/docs/docs.go index 3e94977f..1d8e312b 100644 --- a/backend/kor/docs/docs.go +++ b/backend/kor/docs/docs.go @@ -51,6 +51,13 @@ const docTemplate = `{ "description": "Authorization token", "name": "Authorization", "in": "header" + }, + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "path", + "required": true } ], "responses": {} diff --git a/backend/kor/docs/swagger.json b/backend/kor/docs/swagger.json index 3f66bae6..360dbdbb 100644 --- a/backend/kor/docs/swagger.json +++ b/backend/kor/docs/swagger.json @@ -43,6 +43,13 @@ "description": "Authorization token", "name": "Authorization", "in": "header" + }, + { + "type": "string", + "description": "namespace", + "name": "namespace", + "in": "path", + "required": true } ], "responses": {} diff --git a/backend/kor/docs/swagger.yaml b/backend/kor/docs/swagger.yaml index 9898aa25..f45db4b0 100644 --- a/backend/kor/docs/swagger.yaml +++ b/backend/kor/docs/swagger.yaml @@ -27,6 +27,11 @@ paths: in: header name: Authorization type: string + - description: namespace + in: path + name: namespace + required: true + type: string produces: - application/json responses: {} diff --git a/backend/kor/main.go b/backend/kor/main.go index 2dc391f3..5ed14158 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -106,6 +106,7 @@ func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { // @Produce json // @Router /api/v1/namespaces/{namespace}/configmaps [get] // @Param Authorization header string false "Authorization token" +// @Param namespace path string true "namespace" func getUnusedConfigmapsForNamespace(w http.ResponseWriter, r *http.Request) { // Extract the "namespace" parameter from the path namespaceArr := []string{mux.Vars(r)["namespace"]} diff --git a/backend/tools/.gitignore b/backend/tools/.gitignore new file mode 100644 index 00000000..a902256f --- /dev/null +++ b/backend/tools/.gitignore @@ -0,0 +1,2 @@ +server.crt +server.key \ No newline at end of file diff --git a/backend/tools/pre-setup.sh b/backend/tools/pre-setup.sh deleted file mode 100644 index 0447b500..00000000 --- a/backend/tools/pre-setup.sh +++ /dev/null @@ -1,15 +0,0 @@ -#Generate token -cd kor/backend/tools -export KOR_API_SECRET=abcd12; export KOR_API_TOKEN=$(go run generate_token.go) -#In case no auth needed -export NO_AUTH=true -#TODO: place static files in dockerfile -openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 365 -nodes -go run main.go - -### SWAGGER #### -# Install swag cli -go install github.com/swaggo/swag/cmd/swag@latest -# Regenerate swagger -swag init - From 8b2e48d3031d3e0baf790a3602dd7e884d903746 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Sat, 7 Sep 2024 22:10:59 +0300 Subject: [PATCH 11/16] .gitignore --- backend/tools/.gitignore | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/tools/.gitignore b/backend/tools/.gitignore index a902256f..3041adec 100644 --- a/backend/tools/.gitignore +++ b/backend/tools/.gitignore @@ -1,2 +1 @@ -server.crt -server.key \ No newline at end of file +notes \ No newline at end of file From 2a851751fe01fd673705fef179e9689797a17533 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Mon, 16 Sep 2024 22:05:20 +0300 Subject: [PATCH 12/16] backend kor --- backend/README.md | 0 backend/kor/main.go | 20 +++++++++++--------- 2 files changed, 11 insertions(+), 9 deletions(-) create mode 100644 backend/README.md diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 00000000..e69de29b diff --git a/backend/kor/main.go b/backend/kor/main.go index 5ed14158..67508985 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -16,6 +16,9 @@ import ( "net/http" "os" ) +// move configmap functions to a separate configmap.go file +// emptyOpts is a common value - separate file +// jwtSecret is a common value - separate file var jwtSecret = []byte(os.Getenv("KOR_API_SECRET")) @@ -25,6 +28,14 @@ type SimpleResponse struct { var clientset *kubernetes.Clientset +emptyOpts := common.Opts{ +WebhookURL: "", +Channel: "", +Token: "", +DeleteFlag: false, +NoInteractive: true, +GroupBy: "namespace", +} // Auth middleware that verifies the JWT token using golang-jwt/jwt func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { @@ -111,15 +122,6 @@ func getUnusedConfigmapsForNamespace(w http.ResponseWriter, r *http.Request) { // Extract the "namespace" parameter from the path namespaceArr := []string{mux.Vars(r)["namespace"]} - opts := common.Opts{ - WebhookURL: "", - Channel: "", - Token: "", - DeleteFlag: false, - NoInteractive: true, - GroupBy: "namespace", - } - getUnusedConfigMapWithFilters(w, opts, &filters.Options{ IncludeNamespaces: namespaceArr, }) From 5c23a15d2c84aa64c57b97e4e9533bf8dcafe718 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Mon, 16 Sep 2024 22:07:32 +0300 Subject: [PATCH 13/16] backend --- backend/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/backend/README.md b/backend/README.md index e69de29b..ad0117ec 100644 --- a/backend/README.md +++ b/backend/README.md @@ -0,0 +1,24 @@ +## Start without a token + + +## Swagger +```swag init``` + + +## Docker +#### Generate SSL certs +```bash +openssl req -x509 -newkey rsa:4096 -keyout server.key -out server.crt -days 36500 -nodes -subj "/C=US/ST=California/L=San Francisco/O=MyCompany/OU=IT/CN=localhost" +``` + +```bash +docker buildx build -t kor-backend:latest . +``` + +## Development +```bash +export NO_AUTH=true +``` +```bash +go run main.go +``` \ No newline at end of file From 82d53b714d473b4d6f6157fb3bd1e81c42d89aed Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 19 Sep 2024 01:25:08 +0300 Subject: [PATCH 14/16] configmaps functionallity moved to configmaps.go, list namespaces validation has been added, token validation moved to a separate file --- backend/kor/configmaps.go | 38 +++++++++++++++ backend/kor/main.go | 97 +++++++++++---------------------------- backend/kor/namespaces.go | 13 ++++++ backend/kor/token.go | 27 +++++++++++ 4 files changed, 105 insertions(+), 70 deletions(-) create mode 100644 backend/kor/configmaps.go create mode 100644 backend/kor/namespaces.go create mode 100644 backend/kor/token.go diff --git a/backend/kor/configmaps.go b/backend/kor/configmaps.go new file mode 100644 index 00000000..531273c8 --- /dev/null +++ b/backend/kor/configmaps.go @@ -0,0 +1,38 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/yonahd/kor/pkg/common" + "github.com/yonahd/kor/pkg/filters" + "github.com/yonahd/kor/pkg/kor" + "k8s.io/client-go/kubernetes" + "net/http" +) + +func getUnusedConfigMapWithFilters(w http.ResponseWriter, opts common.Opts, filterOpts *filters.Options, clientset kubernetes.Interface) { + outputFormat := "json" + // Call the function that returns a JSON string + response, err := kor.GetUnusedConfigmaps(filterOpts, clientset, outputFormat, opts) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failed to get configmaps: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + return + } + + // Declare a variable to hold the parsed JSON structure + var parsedResponse map[string]interface{} + + // Parse the JSON string into a map + if err := json.Unmarshal([]byte(response), &parsedResponse); err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failed to parse configmaps response: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) + return + } + + // Send the parsed JSON as the response + w.WriteHeader(http.StatusOK) + json.NewEncoder(w).Encode(parsedResponse) +} diff --git a/backend/kor/main.go b/backend/kor/main.go index 67508985..d697692e 100644 --- a/backend/kor/main.go +++ b/backend/kor/main.go @@ -4,7 +4,6 @@ import ( "crypto/tls" "encoding/json" "fmt" - "github.com/golang-jwt/jwt/v5" "github.com/gorilla/mux" "github.com/swaggo/http-swagger" "github.com/yonahd/kor/pkg/common" @@ -16,9 +15,6 @@ import ( "net/http" "os" ) -// move configmap functions to a separate configmap.go file -// emptyOpts is a common value - separate file -// jwtSecret is a common value - separate file var jwtSecret = []byte(os.Getenv("KOR_API_SECRET")) @@ -28,43 +24,41 @@ type SimpleResponse struct { var clientset *kubernetes.Clientset -emptyOpts := common.Opts{ -WebhookURL: "", -Channel: "", -Token: "", -DeleteFlag: false, -NoInteractive: true, -GroupBy: "namespace", +var emptyOpts = common.Opts{ + WebhookURL: "", + Channel: "", + Token: "", + DeleteFlag: false, + NoInteractive: true, + GroupBy: "namespace", } + // Auth middleware that verifies the JWT token using golang-jwt/jwt func authMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if !(os.Getenv("NO_AUTH") == "true") { - tokenHeader := r.Header.Get("Authorization") - if tokenHeader == "" { - w.WriteHeader(http.StatusUnauthorized) - json.NewEncoder(w).Encode(SimpleResponse{Message: "Missing token"}) - return - } - - tokenString := tokenHeader[len("Bearer "):] - token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { - return jwtSecret, nil - }) - - if err != nil || !token.Valid { - w.WriteHeader(http.StatusUnauthorized) - json.NewEncoder(w).Encode(SimpleResponse{Message: "Invalid token"}) - return - } - + validateTokenAndCallNextHttpCall(w, r, next) + } else { next.ServeHTTP(w, r) + } + }) +} + +// Validate list namespaces +func validateListNamespaces(next http.Handler) http.Handler { + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + err := getListNamespacesErrorIfExists(clientset, w) + if err != nil { + w.WriteHeader(http.StatusInternalServerError) + errorMsg := fmt.Sprintf("Failed to retreive namespaces: %v\n", err) + json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) } else { next.ServeHTTP(w, r) } }) } +// Recovery middleware that recovers from panics and returns a 500 error func recoveryMiddleware(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { defer func() { @@ -98,17 +92,7 @@ func healthCheckHandler(w http.ResponseWriter, r *http.Request) { // @Router /api/v1/configmaps [get] // @Param Authorization header string false "Authorization token" func getUnusedConfigmaps(w http.ResponseWriter, r *http.Request) { - - opts := common.Opts{ - WebhookURL: "", - Channel: "", - Token: "", - DeleteFlag: false, - NoInteractive: true, - GroupBy: "namespace", - } - - getUnusedConfigMapWithFilters(w, opts, &filters.Options{}) + getUnusedConfigMapWithFilters(w, emptyOpts, &filters.Options{}, clientset) } // @Summary Get Unused configmaps from a specific namespace @@ -122,36 +106,9 @@ func getUnusedConfigmapsForNamespace(w http.ResponseWriter, r *http.Request) { // Extract the "namespace" parameter from the path namespaceArr := []string{mux.Vars(r)["namespace"]} - getUnusedConfigMapWithFilters(w, opts, &filters.Options{ + getUnusedConfigMapWithFilters(w, emptyOpts, &filters.Options{ IncludeNamespaces: namespaceArr, - }) -} - -func getUnusedConfigMapWithFilters(w http.ResponseWriter, opts common.Opts, filterOpts *filters.Options) { - outputFormat := "json" - // Call the function that returns a JSON string - response, err := kor.GetUnusedConfigmaps(filterOpts, clientset, outputFormat, opts) - if err != nil { - w.WriteHeader(http.StatusInternalServerError) - errorMsg := fmt.Sprintf("Failed to get configmaps: %v\n", err) - json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) - return - } - - // Declare a variable to hold the parsed JSON structure - var parsedResponse map[string]interface{} - - // Parse the JSON string into a map - if err := json.Unmarshal([]byte(response), &parsedResponse); err != nil { - w.WriteHeader(http.StatusInternalServerError) - errorMsg := fmt.Sprintf("Failed to parse configmaps response: %v\n", err) - json.NewEncoder(w).Encode(SimpleResponse{Message: errorMsg}) - return - } - - // Send the parsed JSON as the response - w.WriteHeader(http.StatusOK) - json.NewEncoder(w).Encode(parsedResponse) + }, clientset) } // @title KOR API Swagger @@ -165,7 +122,7 @@ func main() { api := router.PathPrefix("/api/v1").Subrouter() router.HandleFunc("/healthcheck", healthCheckHandler).Methods("GET") - api.Handle("/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmaps))).Methods("GET") + api.Handle("/configmaps", authMiddleware(validateListNamespaces(http.HandlerFunc(getUnusedConfigmaps)))).Methods("GET") api.Handle("/namespaces/{namespace}/configmaps", authMiddleware(http.HandlerFunc(getUnusedConfigmapsForNamespace))).Methods("GET") // Swagger documentation route diff --git a/backend/kor/namespaces.go b/backend/kor/namespaces.go new file mode 100644 index 00000000..7102f4cf --- /dev/null +++ b/backend/kor/namespaces.go @@ -0,0 +1,13 @@ +package main + +import ( + "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/client-go/kubernetes" + "net/http" +) + +func getListNamespacesErrorIfExists(clientset kubernetes.Interface, w http.ResponseWriter) error { + _, err := clientset.CoreV1().Namespaces().List(context.TODO(), metav1.ListOptions{}) + return err +} diff --git a/backend/kor/token.go b/backend/kor/token.go new file mode 100644 index 00000000..b11a89a1 --- /dev/null +++ b/backend/kor/token.go @@ -0,0 +1,27 @@ +package main + +import ( + "encoding/json" + "github.com/golang-jwt/jwt/v5" + "net/http" +) + +func validateTokenAndCallNextHttpCall(w http.ResponseWriter, r *http.Request, next http.Handler) { + tokenHeader := r.Header.Get("Authorization") + if tokenHeader == "" { + w.WriteHeader(http.StatusUnauthorized) + json.NewEncoder(w).Encode(SimpleResponse{Message: "Missing token"}) + return + } + + tokenString := tokenHeader[len("Bearer "):] + token, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) { + return jwtSecret, nil + }) + + if err != nil || !token.Valid { + w.WriteHeader(http.StatusUnauthorized) + json.NewEncoder(w).Encode(SimpleResponse{Message: "Invalid token"}) + } + next.ServeHTTP(w, r) +} From 9b320ab760769bf5ac62385b65d2f27103f1fa76 Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 19 Sep 2024 10:48:19 +0300 Subject: [PATCH 15/16] fix readme --- backend/README.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/backend/README.md b/backend/README.md index ad0117ec..cf0dd6b6 100644 --- a/backend/README.md +++ b/backend/README.md @@ -18,7 +18,5 @@ docker buildx build -t kor-backend:latest . ## Development ```bash export NO_AUTH=true -``` -```bash -go run main.go +go run . ``` \ No newline at end of file From 89d915cf75ee0f70cfd8e9e1f0a88d1db9d59aca Mon Sep 17 00:00:00 2001 From: Hagai Hillel Date: Thu, 19 Sep 2024 10:51:21 +0300 Subject: [PATCH 16/16] fix readme --- backend/README.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/backend/README.md b/backend/README.md index cf0dd6b6..909d7609 100644 --- a/backend/README.md +++ b/backend/README.md @@ -1,5 +1,12 @@ -## Start without a token +# KOR Backend +Kor Backend is an API wrapper designed to expose Kor. + +A tool that identifies unused resources in Kubernetes clusters - over HTTPS. + +This backend allows users to access Kor's functionality via RESTful API calls, + +making it easier to integrate into web services, dashboards, and automation pipelines. ## Swagger ```swag init```