aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--models/actions/variable.go31
-rw-r--r--models/migrations/migrations.go1
-rw-r--r--models/migrations/v1_24/v316.go20
-rw-r--r--models/secret/secret.go37
-rw-r--r--modules/structs/secret.go7
-rw-r--r--modules/structs/variable.go12
-rw-r--r--options/locale/locale_en-US.ini2
-rw-r--r--routers/api/v1/org/action.go28
-rw-r--r--routers/api/v1/repo/action.go27
-rw-r--r--routers/api/v1/user/action.go23
-rw-r--r--routers/web/shared/actions/variables.go6
-rw-r--r--routers/web/shared/secrets/secrets.go4
-rw-r--r--services/actions/variables.go6
-rw-r--r--services/forms/user_form.go10
-rw-r--r--services/secrets/secrets.go6
-rw-r--r--templates/shared/secrets/add_list.tmpl14
-rw-r--r--templates/shared/variables/variable_list.tmpl16
-rw-r--r--templates/swagger/v1_json.tmpl25
-rw-r--r--tests/integration/actions_variables_test.go8
-rw-r--r--tests/integration/api_repo_secrets_test.go27
20 files changed, 247 insertions, 63 deletions
diff --git a/models/actions/variable.go b/models/actions/variable.go
index 1929cffbd8..7154843c17 100644
--- a/models/actions/variable.go
+++ b/models/actions/variable.go
@@ -6,10 +6,12 @@ package actions
import (
"context"
"strings"
+ "unicode/utf8"
"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/timeutil"
+ "code.gitea.io/gitea/modules/util"
"xorm.io/builder"
)
@@ -32,26 +34,39 @@ type ActionVariable struct {
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name)"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT NOT NULL"`
+ Description string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
UpdatedUnix timeutil.TimeStamp `xorm:"updated"`
}
+const (
+ VariableDataMaxLength = 65536
+ VariableDescriptionMaxLength = 4096
+)
+
func init() {
db.RegisterModel(new(ActionVariable))
}
-func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*ActionVariable, error) {
+func InsertVariable(ctx context.Context, ownerID, repoID int64, name, data, description string) (*ActionVariable, error) {
if ownerID != 0 && repoID != 0 {
// It's trying to create a variable that belongs to a repository, but OwnerID has been set accidentally.
// Remove OwnerID to avoid confusion; it's not worth returning an error here.
ownerID = 0
}
+ if utf8.RuneCountInString(data) > VariableDataMaxLength {
+ return nil, util.NewInvalidArgumentErrorf("data too long")
+ }
+
+ description = util.TruncateRunes(description, VariableDescriptionMaxLength)
+
variable := &ActionVariable{
- OwnerID: ownerID,
- RepoID: repoID,
- Name: strings.ToUpper(name),
- Data: data,
+ OwnerID: ownerID,
+ RepoID: repoID,
+ Name: strings.ToUpper(name),
+ Data: data,
+ Description: description,
}
return variable, db.Insert(ctx, variable)
}
@@ -96,6 +111,12 @@ func FindVariables(ctx context.Context, opts FindVariablesOpts) ([]*ActionVariab
}
func UpdateVariableCols(ctx context.Context, variable *ActionVariable, cols ...string) (bool, error) {
+ if utf8.RuneCountInString(variable.Data) > VariableDataMaxLength {
+ return false, util.NewInvalidArgumentErrorf("data too long")
+ }
+
+ variable.Description = util.TruncateRunes(variable.Description, VariableDescriptionMaxLength)
+
variable.Name = strings.ToUpper(variable.Name)
count, err := db.GetEngine(ctx).
ID(variable.ID).
diff --git a/models/migrations/migrations.go b/models/migrations/migrations.go
index f9ab993abf..297c50a267 100644
--- a/models/migrations/migrations.go
+++ b/models/migrations/migrations.go
@@ -376,6 +376,7 @@ func prepareMigrationTasks() []*migration {
newMigration(313, "Move PinOrder from issue table to a new table issue_pin", v1_24.MovePinOrderToTableIssuePin),
newMigration(314, "Update OwnerID as zero for repository level action tables", v1_24.UpdateOwnerIDOfRepoLevelActionsTables),
newMigration(315, "Add Ephemeral to ActionRunner", v1_24.AddEphemeralToActionRunner),
+ newMigration(316, "Add description for secrets and variables", v1_24.AddDescriptionForSecretsAndVariables),
}
return preparedMigrations
}
diff --git a/models/migrations/v1_24/v316.go b/models/migrations/v1_24/v316.go
new file mode 100644
index 0000000000..0378133e53
--- /dev/null
+++ b/models/migrations/v1_24/v316.go
@@ -0,0 +1,20 @@
+// Copyright 2025 The Gitea Authors. All rights reserved.
+// SPDX-License-Identifier: MIT
+
+package v1_24 //nolint
+
+import (
+ "xorm.io/xorm"
+)
+
+func AddDescriptionForSecretsAndVariables(x *xorm.Engine) error {
+ type Secret struct {
+ Description string `xorm:"TEXT"`
+ }
+
+ type ActionVariable struct {
+ Description string `xorm:"TEXT"`
+ }
+
+ return x.Sync(new(Secret), new(ActionVariable))
+}
diff --git a/models/secret/secret.go b/models/secret/secret.go
index eab9cf0712..10a0287dfd 100644
--- a/models/secret/secret.go
+++ b/models/secret/secret.go
@@ -40,9 +40,15 @@ type Secret struct {
RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"`
Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"`
Data string `xorm:"LONGTEXT"` // encrypted data
+ Description string `xorm:"TEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"`
}
+const (
+ SecretDataMaxLength = 65536
+ SecretDescriptionMaxLength = 4096
+)
+
// ErrSecretNotFound represents a "secret not found" error.
type ErrSecretNotFound struct {
Name string
@@ -57,7 +63,7 @@ func (err ErrSecretNotFound) Unwrap() error {
}
// InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database
-func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) {
+func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data, description string) (*Secret, error) {
if ownerID != 0 && repoID != 0 {
// It's trying to create a secret that belongs to a repository, but OwnerID has been set accidentally.
// Remove OwnerID to avoid confusion; it's not worth returning an error here.
@@ -67,15 +73,23 @@ func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, dat
return nil, fmt.Errorf("%w: ownerID and repoID cannot be both zero, global secrets are not supported", util.ErrInvalidArgument)
}
+ if len(data) > SecretDataMaxLength {
+ return nil, util.NewInvalidArgumentErrorf("data too long")
+ }
+
+ description = util.TruncateRunes(description, SecretDescriptionMaxLength)
+
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
if err != nil {
return nil, err
}
+
secret := &Secret{
- OwnerID: ownerID,
- RepoID: repoID,
- Name: strings.ToUpper(name),
- Data: encrypted,
+ OwnerID: ownerID,
+ RepoID: repoID,
+ Name: strings.ToUpper(name),
+ Data: encrypted,
+ Description: description,
}
return secret, db.Insert(ctx, secret)
}
@@ -114,16 +128,23 @@ func (opts FindSecretsOptions) ToConds() builder.Cond {
}
// UpdateSecret changes org or user reop secret.
-func UpdateSecret(ctx context.Context, secretID int64, data string) error {
+func UpdateSecret(ctx context.Context, secretID int64, data, description string) error {
+ if len(data) > SecretDataMaxLength {
+ return util.NewInvalidArgumentErrorf("data too long")
+ }
+
+ description = util.TruncateRunes(description, SecretDescriptionMaxLength)
+
encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data)
if err != nil {
return err
}
s := &Secret{
- Data: encrypted,
+ Data: encrypted,
+ Description: description,
}
- affected, err := db.GetEngine(ctx).ID(secretID).Cols("data").Update(s)
+ affected, err := db.GetEngine(ctx).ID(secretID).Cols("data", "description").Update(s)
if affected != 1 {
return ErrSecretNotFound{}
}
diff --git a/modules/structs/secret.go b/modules/structs/secret.go
index a0673ca08c..2afb41ec43 100644
--- a/modules/structs/secret.go
+++ b/modules/structs/secret.go
@@ -10,6 +10,8 @@ import "time"
type Secret struct {
// the secret's name
Name string `json:"name"`
+ // the secret's description
+ Description string `json:"description"`
// swagger:strfmt date-time
Created time.Time `json:"created_at"`
}
@@ -21,4 +23,9 @@ type CreateOrUpdateSecretOption struct {
//
// required: true
Data string `json:"data" binding:"Required"`
+
+ // Description of the secret to update
+ //
+ // required: false
+ Description string `json:"description"`
}
diff --git a/modules/structs/variable.go b/modules/structs/variable.go
index cc846cf0ec..5198937303 100644
--- a/modules/structs/variable.go
+++ b/modules/structs/variable.go
@@ -10,6 +10,11 @@ type CreateVariableOption struct {
//
// required: true
Value string `json:"value" binding:"Required"`
+
+ // Description of the variable to create
+ //
+ // required: false
+ Description string `json:"description"`
}
// UpdateVariableOption the option when updating variable
@@ -21,6 +26,11 @@ type UpdateVariableOption struct {
//
// required: true
Value string `json:"value" binding:"Required"`
+
+ // Description of the variable to update
+ //
+ // required: false
+ Description string `json:"description"`
}
// ActionVariable return value of the query API
@@ -34,4 +44,6 @@ type ActionVariable struct {
Name string `json:"name"`
// the value of the variable
Data string `json:"data"`
+ // the description of the variable
+ Description string `json:"description"`
}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index 3ee7c8818c..876e135b22 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -3712,8 +3712,10 @@ secrets = Secrets
description = Secrets will be passed to certain actions and cannot be read otherwise.
none = There are no secrets yet.
creation = Add Secret
+creation.description = Description
creation.name_placeholder = case-insensitive, alphanumeric characters or underscores only, cannot start with GITEA_ or GITHUB_
creation.value_placeholder = Input any content. Whitespace at the start and end will be omitted.
+creation.description_placeholder = Enter short description (optional).
creation.success = The secret "%s" has been added.
creation.failed = Failed to add secret.
deletion = Remove secret
diff --git a/routers/api/v1/org/action.go b/routers/api/v1/org/action.go
index d9bdb3ab48..b1cd2f0c3c 100644
--- a/routers/api/v1/org/action.go
+++ b/routers/api/v1/org/action.go
@@ -61,8 +61,9 @@ func (Action) ListActionsSecrets(ctx *context.APIContext) {
apiSecrets := make([]*api.Secret, len(secrets))
for k, v := range secrets {
apiSecrets[k] = &api.Secret{
- Name: v.Name,
- Created: v.CreatedUnix.AsTime(),
+ Name: v.Name,
+ Description: v.Description,
+ Created: v.CreatedUnix.AsTime(),
}
}
@@ -106,7 +107,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
- _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"), opt.Data)
+ _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Org.Organization.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
@@ -230,10 +231,11 @@ func (Action) ListVariables(ctx *context.APIContext) {
variables := make([]*api.ActionVariable, len(vars))
for i, v := range vars {
variables[i] = &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
- Data: v.Data,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
}
@@ -281,10 +283,11 @@ func (Action) GetVariable(ctx *context.APIContext) {
}
variable := &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
- Data: v.Data,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
ctx.JSON(http.StatusOK, variable)
@@ -386,7 +389,7 @@ func (Action) CreateVariable(ctx *context.APIContext) {
return
}
- if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value); err != nil {
+ if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value, opt.Description); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
} else {
@@ -453,6 +456,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) {
v.Name = opt.Name
v.Data = opt.Value
+ v.Description = opt.Description
if _, err := actions_service.UpdateVariableNameData(ctx, v); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
diff --git a/routers/api/v1/repo/action.go b/routers/api/v1/repo/action.go
index 6b4ce37fcf..2ace9fa295 100644
--- a/routers/api/v1/repo/action.go
+++ b/routers/api/v1/repo/action.go
@@ -84,8 +84,9 @@ func (Action) ListActionsSecrets(ctx *context.APIContext) {
apiSecrets := make([]*api.Secret, len(secrets))
for k, v := range secrets {
apiSecrets[k] = &api.Secret{
- Name: v.Name,
- Created: v.CreatedUnix.AsTime(),
+ Name: v.Name,
+ Description: v.Description,
+ Created: v.CreatedUnix.AsTime(),
}
}
@@ -136,7 +137,7 @@ func (Action) CreateOrUpdateSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
- _, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.PathParam("secretname"), opt.Data)
+ _, created, err := secret_service.CreateOrUpdateSecret(ctx, 0, repo.ID, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
@@ -249,10 +250,11 @@ func (Action) GetVariable(ctx *context.APIContext) {
}
variable := &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
- Data: v.Data,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
ctx.JSON(http.StatusOK, variable)
@@ -362,7 +364,7 @@ func (Action) CreateVariable(ctx *context.APIContext) {
return
}
- if _, err := actions_service.CreateVariable(ctx, 0, repoID, variableName, opt.Value); err != nil {
+ if _, err := actions_service.CreateVariable(ctx, 0, repoID, variableName, opt.Value, opt.Description); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
} else {
@@ -432,6 +434,7 @@ func (Action) UpdateVariable(ctx *context.APIContext) {
v.Name = opt.Name
v.Data = opt.Value
+ v.Description = opt.Description
if _, err := actions_service.UpdateVariableNameData(ctx, v); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
@@ -491,9 +494,11 @@ func (Action) ListVariables(ctx *context.APIContext) {
variables := make([]*api.ActionVariable, len(vars))
for i, v := range vars {
variables[i] = &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
}
diff --git a/routers/api/v1/user/action.go b/routers/api/v1/user/action.go
index 1c8e3b6e71..04097fcc95 100644
--- a/routers/api/v1/user/action.go
+++ b/routers/api/v1/user/action.go
@@ -49,7 +49,7 @@ func CreateOrUpdateSecret(ctx *context.APIContext) {
opt := web.GetForm(ctx).(*api.CreateOrUpdateSecretOption)
- _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"), opt.Data)
+ _, created, err := secret_service.CreateOrUpdateSecret(ctx, ctx.Doer.ID, 0, ctx.PathParam("secretname"), opt.Data, opt.Description)
if err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
@@ -153,7 +153,7 @@ func CreateVariable(ctx *context.APIContext) {
return
}
- if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value); err != nil {
+ if _, err := actions_service.CreateVariable(ctx, ownerID, 0, variableName, opt.Value, opt.Description); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
ctx.APIError(http.StatusBadRequest, err)
} else {
@@ -215,6 +215,7 @@ func UpdateVariable(ctx *context.APIContext) {
v.Name = opt.Name
v.Data = opt.Value
+ v.Description = opt.Description
if _, err := actions_service.UpdateVariableNameData(ctx, v); err != nil {
if errors.Is(err, util.ErrInvalidArgument) {
@@ -300,10 +301,11 @@ func GetVariable(ctx *context.APIContext) {
}
variable := &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
- Data: v.Data,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
ctx.JSON(http.StatusOK, variable)
@@ -345,10 +347,11 @@ func ListVariables(ctx *context.APIContext) {
variables := make([]*api.ActionVariable, len(vars))
for i, v := range vars {
variables[i] = &api.ActionVariable{
- OwnerID: v.OwnerID,
- RepoID: v.RepoID,
- Name: v.Name,
- Data: v.Data,
+ OwnerID: v.OwnerID,
+ RepoID: v.RepoID,
+ Name: v.Name,
+ Data: v.Data,
+ Description: v.Description,
}
}
diff --git a/routers/web/shared/actions/variables.go b/routers/web/shared/actions/variables.go
index 7e8100b948..9cc1676d7b 100644
--- a/routers/web/shared/actions/variables.go
+++ b/routers/web/shared/actions/variables.go
@@ -106,7 +106,8 @@ func Variables(ctx *context.Context) {
return
}
ctx.Data["Variables"] = variables
-
+ ctx.Data["DataMaxLength"] = actions_model.VariableDataMaxLength
+ ctx.Data["DescriptionMaxLength"] = actions_model.VariableDescriptionMaxLength
ctx.HTML(http.StatusOK, vCtx.VariablesTemplate)
}
@@ -124,7 +125,7 @@ func VariableCreate(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.EditVariableForm)
- v, err := actions_service.CreateVariable(ctx, vCtx.OwnerID, vCtx.RepoID, form.Name, form.Data)
+ v, err := actions_service.CreateVariable(ctx, vCtx.OwnerID, vCtx.RepoID, form.Name, form.Data, form.Description)
if err != nil {
log.Error("CreateVariable: %v", err)
ctx.JSONError(ctx.Tr("actions.variables.creation.failed"))
@@ -157,6 +158,7 @@ func VariableUpdate(ctx *context.Context) {
form := web.GetForm(ctx).(*forms.EditVariableForm)
variable.Name = form.Name
variable.Data = form.Data
+ variable.Description = form.Description
if ok, err := actions_service.UpdateVariableNameData(ctx, variable); err != nil || !ok {
log.Error("UpdateVariable: %v", err)
diff --git a/routers/web/shared/secrets/secrets.go b/routers/web/shared/secrets/secrets.go
index 3bd421f86a..c8b80ebb26 100644
--- a/routers/web/shared/secrets/secrets.go
+++ b/routers/web/shared/secrets/secrets.go
@@ -22,12 +22,14 @@ func SetSecretsContext(ctx *context.Context, ownerID, repoID int64) {
}
ctx.Data["Secrets"] = secrets
+ ctx.Data["DataMaxLength"] = secret_model.SecretDataMaxLength
+ ctx.Data["DescriptionMaxLength"] = secret_model.SecretDescriptionMaxLength
}
func PerformSecretsPost(ctx *context.Context, ownerID, repoID int64, redirectURL string) {
form := web.GetForm(ctx).(*forms.AddSecretForm)
- s, _, err := secret_service.CreateOrUpdateSecret(ctx, ownerID, repoID, form.Name, util.ReserveLineBreakForTextarea(form.Data))
+ s, _, err := secret_service.CreateOrUpdateSecret(ctx, ownerID, repoID, form.Name, util.ReserveLineBreakForTextarea(form.Data), form.Description)
if err != nil {
log.Error("CreateOrUpdateSecret failed: %v", err)
ctx.JSONError(ctx.Tr("secrets.creation.failed"))
diff --git a/services/actions/variables.go b/services/actions/variables.go
index 95f088dbd3..2603f1d461 100644
--- a/services/actions/variables.go
+++ b/services/actions/variables.go
@@ -13,7 +13,7 @@ import (
secret_service "code.gitea.io/gitea/services/secrets"
)
-func CreateVariable(ctx context.Context, ownerID, repoID int64, name, data string) (*actions_model.ActionVariable, error) {
+func CreateVariable(ctx context.Context, ownerID, repoID int64, name, data, description string) (*actions_model.ActionVariable, error) {
if err := secret_service.ValidateName(name); err != nil {
return nil, err
}
@@ -22,7 +22,7 @@ func CreateVariable(ctx context.Context, ownerID, repoID int64, name, data strin
return nil, err
}
- v, err := actions_model.InsertVariable(ctx, ownerID, repoID, name, util.ReserveLineBreakForTextarea(data))
+ v, err := actions_model.InsertVariable(ctx, ownerID, repoID, name, util.ReserveLineBreakForTextarea(data), description)
if err != nil {
return nil, err
}
@@ -41,7 +41,7 @@ func UpdateVariableNameData(ctx context.Context, variable *actions_model.ActionV
variable.Data = util.ReserveLineBreakForTextarea(variable.Data)
- return actions_model.UpdateVariableCols(ctx, variable, "name", "data")
+ return actions_model.UpdateVariableCols(ctx, variable, "name", "data", "description")
}
func DeleteVariableByID(ctx context.Context, variableID int64) error {
diff --git a/services/forms/user_form.go b/services/forms/user_form.go
index c9ce71e886..ddf2bd09b0 100644
--- a/services/forms/user_form.go
+++ b/services/forms/user_form.go
@@ -323,8 +323,9 @@ func (f *AddKeyForm) Validate(req *http.Request, errs binding.Errors) binding.Er
// AddSecretForm for adding secrets
type AddSecretForm struct {
- Name string `binding:"Required;MaxSize(255)"`
- Data string `binding:"Required;MaxSize(65535)"`
+ Name string `binding:"Required;MaxSize(255)"`
+ Data string `binding:"Required;MaxSize(65535)"`
+ Description string `binding:"MaxSize(65535)"`
}
// Validate validates the fields
@@ -334,8 +335,9 @@ func (f *AddSecretForm) Validate(req *http.Request, errs binding.Errors) binding
}
type EditVariableForm struct {
- Name string `binding:"Required;MaxSize(255)"`
- Data string `binding:"Required;MaxSize(65535)"`
+ Name string `binding:"Required;MaxSize(255)"`
+ Data string `binding:"Required;MaxSize(65535)"`
+ Description string `binding:"MaxSize(65535)"`
}
func (f *EditVariableForm) Validate(req *http.Request, errs binding.Errors) binding.Errors {
diff --git a/services/secrets/secrets.go b/services/secrets/secrets.go
index 031c474dd7..ec6a3cb062 100644
--- a/services/secrets/secrets.go
+++ b/services/secrets/secrets.go
@@ -10,7 +10,7 @@ import (
secret_model "code.gitea.io/gitea/models/secret"
)
-func CreateOrUpdateSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*secret_model.Secret, bool, error) {
+func CreateOrUpdateSecret(ctx context.Context, ownerID, repoID int64, name, data, description string) (*secret_model.Secret, bool, error) {
if err := ValidateName(name); err != nil {
return nil, false, err
}
@@ -25,14 +25,14 @@ func CreateOrUpdateSecret(ctx context.Context, ownerID, repoID int64, name, data
}
if len(s) == 0 {
- s, err := secret_model.InsertEncryptedSecret(ctx, ownerID, repoID, name, data)
+ s, err := secret_model.InsertEncryptedSecret(ctx, ownerID, repoID, name, data, description)
if err != nil {
return nil, false, err
}
return s, true, nil
}
- if err := secret_model.UpdateSecret(ctx, s[0].ID, data); err != nil {
+ if err := secret_model.UpdateSecret(ctx, s[0].ID, data, description); err != nil {
return nil, false, err
}
diff --git a/templates/shared/secrets/add_list.tmpl b/templates/shared/secrets/add_list.tmpl
index 59596d1013..977f308b71 100644
--- a/templates/shared/secrets/add_list.tmpl
+++ b/templates/shared/secrets/add_list.tmpl
@@ -23,6 +23,9 @@
{{.Name}}
</div>
<div class="flex-item-body">
+ {{if .Description}}{{.Description}}{{else}}-{{end}}
+ </div>
+ <div class="flex-item-body">
******
</div>
</div>
@@ -72,9 +75,20 @@
<textarea required
id="secret-data"
name="data"
+ maxlength="{{.DataMaxLength}}"
placeholder="{{ctx.Locale.Tr "secrets.creation.value_placeholder"}}"
></textarea>
</div>
+ <div class="field">
+ <label for="secret-description">{{ctx.Locale.Tr "secrets.creation.description"}}</label>
+ <textarea
+ id="secret-description"
+ name="description"
+ rows="2"
+ maxlength="{{.DescriptionMaxLength}}"
+ placeholder="{{ctx.Locale.Tr "secrets.creation.description_placeholder"}}"
+ ></textarea>
+ </div>
</div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
diff --git a/templates/shared/variables/variable_list.tmpl b/templates/shared/variables/variable_list.tmpl
index 7a0ab48cef..2edca431c1 100644
--- a/templates/shared/variables/variable_list.tmpl
+++ b/templates/shared/variables/variable_list.tmpl
@@ -7,6 +7,7 @@
data-modal-header="{{ctx.Locale.Tr "actions.variables.creation"}}"
data-modal-dialog-variable-name=""
data-modal-dialog-variable-data=""
+ data-modal-dialog-variable-description=""
>
{{ctx.Locale.Tr "actions.variables.creation"}}
</button>
@@ -25,6 +26,9 @@
{{.Name}}
</div>
<div class="flex-item-body">
+ {{if .Description}}{{.Description}}{{else}}-{{end}}
+ </div>
+ <div class="flex-item-body">
{{.Data}}
</div>
</div>
@@ -39,6 +43,7 @@
data-modal-header="{{ctx.Locale.Tr "actions.variables.edit"}}"
data-modal-dialog-variable-name="{{.Name}}"
data-modal-dialog-variable-data="{{.Data}}"
+ data-modal-dialog-variable-description="{{.Description}}"
>
{{svg "octicon-pencil"}}
</button>
@@ -82,9 +87,20 @@
<textarea required
name="data"
id="dialog-variable-data"
+ maxlength="{{.DataMaxLength}}"
placeholder="{{ctx.Locale.Tr "secrets.creation.value_placeholder"}}"
></textarea>
</div>
+ <div class="field">
+ <label for="dialog-variable-description">{{ctx.Locale.Tr "secrets.creation.description"}}</label>
+ <textarea
+ name="description"
+ id="dialog-variable-description"
+ rows="2"
+ maxlength="{{.DescriptionMaxLength}}"
+ placeholder="{{ctx.Locale.Tr "secrets.creation.description_placeholder"}}"
+ ></textarea>
+ </div>
</div>
{{template "base/modal_actions_confirm" (dict "ModalButtonTypes" "confirm")}}
</form>
diff --git a/templates/swagger/v1_json.tmpl b/templates/swagger/v1_json.tmpl
index 48ed958ca2..1efaf1a875 100644
--- a/templates/swagger/v1_json.tmpl
+++ b/templates/swagger/v1_json.tmpl
@@ -19325,6 +19325,11 @@
"type": "string",
"x-go-name": "Data"
},
+ "description": {
+ "description": "the description of the variable",
+ "type": "string",
+ "x-go-name": "Description"
+ },
"name": {
"description": "the name of the variable",
"type": "string",
@@ -20988,6 +20993,11 @@
"description": "Data of the secret to update",
"type": "string",
"x-go-name": "Data"
+ },
+ "description": {
+ "description": "Description of the secret to update",
+ "type": "string",
+ "x-go-name": "Description"
}
},
"x-go-package": "code.gitea.io/gitea/modules/structs"
@@ -21498,6 +21508,11 @@
"value"
],
"properties": {
+ "description": {
+ "description": "Description of the variable to create",
+ "type": "string",
+ "x-go-name": "Description"
+ },
"value": {
"description": "Value of the variable to create",
"type": "string",
@@ -25459,6 +25474,11 @@
"format": "date-time",
"x-go-name": "Created"
},
+ "description": {
+ "description": "the secret's description",
+ "type": "string",
+ "x-go-name": "Description"
+ },
"name": {
"description": "the secret's name",
"type": "string",
@@ -26034,6 +26054,11 @@
"value"
],
"properties": {
+ "description": {
+ "description": "Description of the variable to update",
+ "type": "string",
+ "x-go-name": "Description"
+ },
"name": {
"description": "New name for the variable. If the field is empty, the variable name won't be updated.",
"type": "string",
diff --git a/tests/integration/actions_variables_test.go b/tests/integration/actions_variables_test.go
index 1fd3294109..c0d0bd371b 100644
--- a/tests/integration/actions_variables_test.go
+++ b/tests/integration/actions_variables_test.go
@@ -27,21 +27,21 @@ func TestActionsVariables(t *testing.T) {
require.NoError(t, db.DeleteAllRecords("action_variable"))
user2 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 2})
- _, _ = actions_model.InsertVariable(ctx, user2.ID, 0, "VAR", "user2-var")
+ _, _ = actions_model.InsertVariable(ctx, user2.ID, 0, "VAR", "user2-var", "user2-var-description")
user2Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{OwnerID: user2.ID, Name: "VAR"})
userWebURL := "/user/settings/actions/variables"
org3 := unittest.AssertExistsAndLoadBean(t, &user_model.User{ID: 3, Type: user_model.UserTypeOrganization})
- _, _ = actions_model.InsertVariable(ctx, org3.ID, 0, "VAR", "org3-var")
+ _, _ = actions_model.InsertVariable(ctx, org3.ID, 0, "VAR", "org3-var", "org3-var-description")
org3Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{OwnerID: org3.ID, Name: "VAR"})
orgWebURL := "/org/org3/settings/actions/variables"
repo1 := unittest.AssertExistsAndLoadBean(t, &repo_model.Repository{ID: 1})
- _, _ = actions_model.InsertVariable(ctx, 0, repo1.ID, "VAR", "repo1-var")
+ _, _ = actions_model.InsertVariable(ctx, 0, repo1.ID, "VAR", "repo1-var", "repo1-var-description")
repo1Var := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{RepoID: repo1.ID, Name: "VAR"})
repoWebURL := "/user2/repo1/settings/actions/variables"
- _, _ = actions_model.InsertVariable(ctx, 0, 0, "VAR", "global-var")
+ _, _ = actions_model.InsertVariable(ctx, 0, 0, "VAR", "global-var", "global-var-description")
globalVar := unittest.AssertExistsAndLoadBean(t, &actions_model.ActionVariable{Name: "VAR", Data: "global-var"})
adminWebURL := "/-/admin/actions/variables"
diff --git a/tests/integration/api_repo_secrets_test.go b/tests/integration/api_repo_secrets_test.go
index c3074d9ece..2059aff484 100644
--- a/tests/integration/api_repo_secrets_test.go
+++ b/tests/integration/api_repo_secrets_test.go
@@ -73,6 +73,33 @@ func TestAPIRepoSecrets(t *testing.T) {
}
})
+ t.Run("CreateWithDescription", func(t *testing.T) {
+ cases := []struct {
+ Name string
+ Description string
+ ExpectedStatus int
+ }{
+ {
+ Name: "no_description",
+ Description: "",
+ ExpectedStatus: http.StatusCreated,
+ },
+ {
+ Name: "description",
+ Description: "some description",
+ ExpectedStatus: http.StatusCreated,
+ },
+ }
+
+ for _, c := range cases {
+ req := NewRequestWithJSON(t, "PUT", fmt.Sprintf("/api/v1/repos/%s/actions/secrets/%s", repo.FullName(), c.Name), api.CreateOrUpdateSecretOption{
+ Data: "data",
+ Description: c.Description,
+ }).AddTokenAuth(token)
+ MakeRequest(t, req, c.ExpectedStatus)
+ }
+ })
+
t.Run("Update", func(t *testing.T) {
name := "update_secret"
url := fmt.Sprintf("/api/v1/repos/%s/actions/secrets/%s", repo.FullName(), name)