From 23addde28ebd69ef2c1cec6a63123c87ec8bffe9 Mon Sep 17 00:00:00 2001 From: Bo-Yi Wu Date: Tue, 22 Aug 2023 11:20:34 +0800 Subject: [PATCH] feat: implement organization secret creation API (#26566) - Add a new `CreateSecretOption` struct for creating secrets - Implement a `CreateOrgSecret` function to create a secret in an organization - Add a new route in `api.go` to handle the creation of organization secrets - Update the Swagger template to include the new `CreateOrgSecret` API endpoint --------- Signed-off-by: appleboy --- modules/structs/secret.go | 14 +++++- routers/api/v1/api.go | 1 + routers/api/v1/org/action.go | 51 +++++++++++++++++++-- routers/api/v1/swagger/action.go | 7 +++ routers/api/v1/swagger/options.go | 3 ++ services/convert/secret.go | 18 ++++++++ templates/swagger/v1_json.tmpl | 74 ++++++++++++++++++++++++++++++- 7 files changed, 161 insertions(+), 7 deletions(-) create mode 100644 services/convert/secret.go diff --git a/modules/structs/secret.go b/modules/structs/secret.go index 6a41db4cd2..c707eb2278 100644 --- a/modules/structs/secret.go +++ b/modules/structs/secret.go @@ -5,7 +5,7 @@ package structs import "time" -// User represents a secret +// Secret represents a secret // swagger:model type Secret struct { // the secret's name @@ -13,3 +13,15 @@ type Secret struct { // swagger:strfmt date-time Created time.Time `json:"created_at"` } + +// CreateSecretOption options when creating secret +// swagger:model +type CreateSecretOption struct { + // Name of the secret to create + // + // required: true + // unique: true + Name string `json:"name" binding:"Required;AlphaDashDot;MaxSize(100)"` + // Data of the secret to create + Data string `json:"data" binding:"Required"` +} diff --git a/routers/api/v1/api.go b/routers/api/v1/api.go index ccae83a940..9613bd610d 100644 --- a/routers/api/v1/api.go +++ b/routers/api/v1/api.go @@ -1300,6 +1300,7 @@ func Routes() *web.Route { }) m.Group("/actions/secrets", func() { m.Get("", reqToken(), reqOrgOwnership(), org.ListActionsSecrets) + m.Post("", reqToken(), reqOrgOwnership(), bind(api.CreateSecretOption{}), org.CreateOrgSecret) }) m.Group("/public_members", func() { m.Get("", org.ListPublicMembers) diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/action.go index 9deda2209c..7659191946 100644 --- a/routers/api/v1/org/action.go +++ b/routers/api/v1/org/action.go @@ -6,10 +6,13 @@ package org import ( "net/http" - "code.gitea.io/gitea/models/secret" + secret_model "code.gitea.io/gitea/models/secret" "code.gitea.io/gitea/modules/context" api "code.gitea.io/gitea/modules/structs" + "code.gitea.io/gitea/modules/web" "code.gitea.io/gitea/routers/api/v1/utils" + "code.gitea.io/gitea/routers/web/shared/actions" + "code.gitea.io/gitea/services/convert" ) // ListActionsSecrets list an organization's actions secrets @@ -42,18 +45,18 @@ func ListActionsSecrets(ctx *context.APIContext) { // listActionsSecrets list an organization's actions secrets func listActionsSecrets(ctx *context.APIContext) { - opts := &secret.FindSecretsOptions{ + opts := &secret_model.FindSecretsOptions{ OwnerID: ctx.Org.Organization.ID, ListOptions: utils.GetListOptions(ctx), } - count, err := secret.CountSecrets(ctx, opts) + count, err := secret_model.CountSecrets(ctx, opts) if err != nil { ctx.InternalServerError(err) return } - secrets, err := secret.FindSecrets(ctx, *opts) + secrets, err := secret_model.FindSecrets(ctx, *opts) if err != nil { ctx.InternalServerError(err) return @@ -70,3 +73,43 @@ func listActionsSecrets(ctx *context.APIContext) { ctx.SetTotalCountHeader(count) ctx.JSON(http.StatusOK, apiSecrets) } + +// CreateOrgSecret create one secret of the organization +func CreateOrgSecret(ctx *context.APIContext) { + // swagger:operation POST /orgs/{org}/actions/secrets organization createOrgSecret + // --- + // summary: Create a secret in an organization + // consumes: + // - application/json + // produces: + // - application/json + // parameters: + // - name: org + // in: path + // description: name of organization + // type: string + // required: true + // - name: body + // in: body + // schema: + // "$ref": "#/definitions/CreateSecretOption" + // responses: + // "201": + // "$ref": "#/responses/Secret" + // "400": + // "$ref": "#/responses/error" + // "404": + // "$ref": "#/responses/notFound" + // "403": + // "$ref": "#/responses/forbidden" + opt := web.GetForm(ctx).(*api.CreateSecretOption) + s, err := secret_model.InsertEncryptedSecret( + ctx, ctx.Org.Organization.ID, 0, opt.Name, actions.ReserveLineBreakForTextarea(opt.Data), + ) + if err != nil { + ctx.Error(http.StatusInternalServerError, "InsertEncryptedSecret", err) + return + } + + ctx.JSON(http.StatusCreated, convert.ToSecret(s)) +} diff --git a/routers/api/v1/swagger/action.go b/routers/api/v1/swagger/action.go index 493b167f72..3771780718 100644 --- a/routers/api/v1/swagger/action.go +++ b/routers/api/v1/swagger/action.go @@ -11,3 +11,10 @@ type swaggerResponseSecretList struct { // in:body Body []api.Secret `json:"body"` } + +// Secret +// swagger:response Secret +type swaggerResponseSecret struct { + // in:body + Body api.Secret `json:"body"` +} diff --git a/routers/api/v1/swagger/options.go b/routers/api/v1/swagger/options.go index 073d9a19f7..8e7e6ec3df 100644 --- a/routers/api/v1/swagger/options.go +++ b/routers/api/v1/swagger/options.go @@ -187,4 +187,7 @@ type swaggerParameterBodies struct { // in:body UpdateRepoAvatarOptions api.UpdateRepoAvatarOption + + // in:body + CreateSecretOption api.CreateSecretOption } diff --git a/services/convert/secret.go b/services/convert/secret.go new file mode 100644 index 0000000000..dd7b9f0a6a --- /dev/null +++ b/services/convert/secret.go @@ -0,0 +1,18 @@ +// Copyright 2023 The Gitea Authors. All rights reserved. +// SPDX-License-Identifier: MIT + +package convert + +import ( + secret_model "code.gitea.io/gitea/models/secret" + api "code.gitea.io/gitea/modules/structs" +) + +// ToSecret converts Secret to API format +func ToSecret(secret *secret_model.Secret) *api.Secret { + result := &api.Secret{ + Name: secret.Name, + } + + return result +} diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl index 734a73bc0c..5e75f6f8b4 100644 --- a/templates/swagger/v1_json.tmpl +++ b/templates/swagger/v1_json.tmpl @@ -1586,6 +1586,49 @@ "$ref": "#/responses/SecretList" } } + }, + "post": { + "consumes": [ + "application/json" + ], + "produces": [ + "application/json" + ], + "tags": [ + "organization" + ], + "summary": "Create a secret in an organization", + "operationId": "createOrgSecret", + "parameters": [ + { + "type": "string", + "description": "name of organization", + "name": "org", + "in": "path", + "required": true + }, + { + "name": "body", + "in": "body", + "schema": { + "$ref": "#/definitions/CreateSecretOption" + } + } + ], + "responses": { + "201": { + "$ref": "#/responses/Secret" + }, + "400": { + "$ref": "#/responses/error" + }, + "403": { + "$ref": "#/responses/forbidden" + }, + "404": { + "$ref": "#/responses/notFound" + } + } } }, "/orgs/{org}/activities/feeds": { @@ -17443,6 +17486,27 @@ }, "x-go-package": "code.gitea.io/gitea/modules/structs" }, + "CreateSecretOption": { + "description": "CreateSecretOption options when creating secret", + "type": "object", + "required": [ + "name" + ], + "properties": { + "data": { + "description": "Data of the secret to create", + "type": "string", + "x-go-name": "Data" + }, + "name": { + "description": "Name of the secret to create", + "type": "string", + "uniqueItems": true, + "x-go-name": "Name" + } + }, + "x-go-package": "code.gitea.io/gitea/modules/structs" + }, "CreateStatusOption": { "description": "CreateStatusOption holds the information needed to create a new CommitStatus for a Commit", "type": "object", @@ -21334,7 +21398,7 @@ "x-go-package": "code.gitea.io/gitea/modules/structs" }, "Secret": { - "description": "User represents a secret", + "description": "Secret represents a secret", "type": "object", "properties": { "created_at": { @@ -22921,6 +22985,12 @@ "$ref": "#/definitions/SearchResults" } }, + "Secret": { + "description": "Secret", + "schema": { + "$ref": "#/definitions/Secret" + } + }, "SecretList": { "description": "SecretList", "schema": { @@ -23137,7 +23207,7 @@ "parameterBodies": { "description": "parameterBodies", "schema": { - "$ref": "#/definitions/UpdateRepoAvatarOption" + "$ref": "#/definitions/CreateSecretOption" } }, "redirect": {