code.gitea.io/gitea@v1.22.3/models/secret/secret.go (about) 1 // Copyright 2022 The Gitea Authors. All rights reserved. 2 // SPDX-License-Identifier: MIT 3 4 package secret 5 6 import ( 7 "context" 8 "errors" 9 "fmt" 10 "strings" 11 12 actions_model "code.gitea.io/gitea/models/actions" 13 "code.gitea.io/gitea/models/db" 14 actions_module "code.gitea.io/gitea/modules/actions" 15 "code.gitea.io/gitea/modules/log" 16 secret_module "code.gitea.io/gitea/modules/secret" 17 "code.gitea.io/gitea/modules/setting" 18 "code.gitea.io/gitea/modules/timeutil" 19 "code.gitea.io/gitea/modules/util" 20 21 "xorm.io/builder" 22 ) 23 24 // Secret represents a secret 25 type Secret struct { 26 ID int64 27 OwnerID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL"` 28 RepoID int64 `xorm:"INDEX UNIQUE(owner_repo_name) NOT NULL DEFAULT 0"` 29 Name string `xorm:"UNIQUE(owner_repo_name) NOT NULL"` 30 Data string `xorm:"LONGTEXT"` // encrypted data 31 CreatedUnix timeutil.TimeStamp `xorm:"created NOT NULL"` 32 } 33 34 // ErrSecretNotFound represents a "secret not found" error. 35 type ErrSecretNotFound struct { 36 Name string 37 } 38 39 func (err ErrSecretNotFound) Error() string { 40 return fmt.Sprintf("secret was not found [name: %s]", err.Name) 41 } 42 43 func (err ErrSecretNotFound) Unwrap() error { 44 return util.ErrNotExist 45 } 46 47 // InsertEncryptedSecret Creates, encrypts, and validates a new secret with yet unencrypted data and insert into database 48 func InsertEncryptedSecret(ctx context.Context, ownerID, repoID int64, name, data string) (*Secret, error) { 49 encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data) 50 if err != nil { 51 return nil, err 52 } 53 secret := &Secret{ 54 OwnerID: ownerID, 55 RepoID: repoID, 56 Name: strings.ToUpper(name), 57 Data: encrypted, 58 } 59 if err := secret.Validate(); err != nil { 60 return secret, err 61 } 62 return secret, db.Insert(ctx, secret) 63 } 64 65 func init() { 66 db.RegisterModel(new(Secret)) 67 } 68 69 func (s *Secret) Validate() error { 70 if s.OwnerID == 0 && s.RepoID == 0 { 71 return errors.New("the secret is not bound to any scope") 72 } 73 return nil 74 } 75 76 type FindSecretsOptions struct { 77 db.ListOptions 78 OwnerID int64 79 RepoID int64 80 SecretID int64 81 Name string 82 } 83 84 func (opts FindSecretsOptions) ToConds() builder.Cond { 85 cond := builder.NewCond() 86 if opts.OwnerID > 0 { 87 cond = cond.And(builder.Eq{"owner_id": opts.OwnerID}) 88 } 89 if opts.RepoID > 0 { 90 cond = cond.And(builder.Eq{"repo_id": opts.RepoID}) 91 } 92 if opts.SecretID != 0 { 93 cond = cond.And(builder.Eq{"id": opts.SecretID}) 94 } 95 if opts.Name != "" { 96 cond = cond.And(builder.Eq{"name": strings.ToUpper(opts.Name)}) 97 } 98 99 return cond 100 } 101 102 // UpdateSecret changes org or user reop secret. 103 func UpdateSecret(ctx context.Context, secretID int64, data string) error { 104 encrypted, err := secret_module.EncryptSecret(setting.SecretKey, data) 105 if err != nil { 106 return err 107 } 108 109 s := &Secret{ 110 Data: encrypted, 111 } 112 affected, err := db.GetEngine(ctx).ID(secretID).Cols("data").Update(s) 113 if affected != 1 { 114 return ErrSecretNotFound{} 115 } 116 return err 117 } 118 119 func GetSecretsOfTask(ctx context.Context, task *actions_model.ActionTask) (map[string]string, error) { 120 secrets := map[string]string{} 121 122 secrets["GITHUB_TOKEN"] = task.Token 123 secrets["GITEA_TOKEN"] = task.Token 124 125 if task.Job.Run.IsForkPullRequest && task.Job.Run.TriggerEvent != actions_module.GithubEventPullRequestTarget { 126 // ignore secrets for fork pull request, except GITHUB_TOKEN and GITEA_TOKEN which are automatically generated. 127 // for the tasks triggered by pull_request_target event, they could access the secrets because they will run in the context of the base branch 128 // see the documentation: https://docs.github.com/en/actions/using-workflows/events-that-trigger-workflows#pull_request_target 129 return secrets, nil 130 } 131 132 ownerSecrets, err := db.Find[Secret](ctx, FindSecretsOptions{OwnerID: task.Job.Run.Repo.OwnerID}) 133 if err != nil { 134 log.Error("find secrets of owner %v: %v", task.Job.Run.Repo.OwnerID, err) 135 return nil, err 136 } 137 repoSecrets, err := db.Find[Secret](ctx, FindSecretsOptions{RepoID: task.Job.Run.RepoID}) 138 if err != nil { 139 log.Error("find secrets of repo %v: %v", task.Job.Run.RepoID, err) 140 return nil, err 141 } 142 143 for _, secret := range append(ownerSecrets, repoSecrets...) { 144 v, err := secret_module.DecryptSecret(setting.SecretKey, secret.Data) 145 if err != nil { 146 log.Error("decrypt secret %v %q: %v", secret.ID, secret.Name, err) 147 return nil, err 148 } 149 secrets[secret.Name] = v 150 } 151 152 return secrets, nil 153 }