Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Gitea secrets storage and management #14483

Closed
wants to merge 61 commits into from
Closed
Show file tree
Hide file tree
Changes from 55 commits
Commits
Show all changes
61 commits
Select commit Hold shift + click to select a range
6b24ada
Add simple master key provider for secret encryption
lafriks Jan 5, 2021
47c472a
Add AES GCM encryption provider
lafriks Jan 7, 2021
64a91b4
add models and services
lunny Oct 7, 2022
9f2d204
improve UI
lunny Oct 9, 2022
368c97e
Merge main branch
lunny Oct 9, 2022
d39f7c4
finish adding and deleting secret for repository settting
lunny Oct 9, 2022
9465c13
org secrets
lunny Oct 10, 2022
eb2b139
fix show add secret panel
wxiaoguang Oct 13, 2022
f4df973
org secrets
lunny Oct 13, 2022
abde871
Fix duplicated alert
lunny Oct 14, 2022
b1e8915
delete modal
wxiaoguang Oct 14, 2022
a077ee2
Almost finished
lunny Oct 14, 2022
5b1044a
merge main branch
lunny Oct 14, 2022
834c7c1
Fix lint
lunny Oct 14, 2022
8e1291d
Some improvements
lunny Oct 15, 2022
1788de5
Merge branch 'main' into lafriks-fork-feat/secrets
lunny Oct 15, 2022
0a3be05
Fix bug
lunny Oct 15, 2022
a0ebf78
Merge branch 'main' into lafriks-fork-feat/secrets
lunny Oct 15, 2022
319da15
Fix bug
lunny Oct 16, 2022
b08114b
Merge branch 'main' into lafriks-fork-feat/secrets
lunny Oct 16, 2022
073656c
merge main branch
lunny Oct 17, 2022
f89bd80
merge main branch
lunny Oct 20, 2022
850d936
encrypt master key
lunny Oct 20, 2022
41310a7
merge main branch
lunny Oct 21, 2022
e54785a
merge main branch
lunny Oct 22, 2022
ccb57c8
merge main branch
lunny Oct 24, 2022
e30f532
merge main branch
lunny Nov 7, 2022
29e4f6b
merge main branch
lunny Nov 21, 2022
b01b2a9
merge main branch
lunny Nov 26, 2022
a1aee64
Merge branch 'main' into lafriks-fork-feat/secrets
lunny Nov 26, 2022
4c8f590
Merge branch 'main' into feature/secrets
wolfogre Dec 7, 2022
bc999bd
chore: add SPDX-License-Identifier
wolfogre Dec 7, 2022
41e9be0
fix: use .locale.Tr
wolfogre Dec 7, 2022
2c7ae0c
Merge branch 'main' into feature/secrets
wolfogre Dec 8, 2022
dd84d07
fix: use LONGTEXT
wolfogre Dec 9, 2022
f5effc1
fix: update nameRE
wolfogre Dec 9, 2022
c08fc15
fix: ErrSecretInvalidValue
wolfogre Dec 9, 2022
44ca6bf
fix: secret_deletion_failed
wolfogre Dec 9, 2022
6fcb7bf
fix: in_error
wolfogre Dec 9, 2022
b79b156
fix: remove PullRequest field
wolfogre Dec 9, 2022
acc0c12
fix: FindUserSecrets
wolfogre Dec 9, 2022
c754525
Merge pull request #4 from wolfogre/feature/secrets
lafriks Dec 9, 2022
eb5bcec
Merge branch 'main' into feat/secrets
wolfogre Dec 13, 2022
3183368
Update templates/org/settings/navbar.tmpl
wolfogre Dec 13, 2022
e86e30f
Update options/locale/locale_en-US.ini
wolfogre Dec 13, 2022
e6cee41
Update options/locale/locale_en-US.ini
wolfogre Dec 13, 2022
641d37a
fix: use web.Bind
wolfogre Dec 13, 2022
7c82f7a
fix: remove PullRequestRead
wolfogre Dec 13, 2022
f9d58d4
fix: rename to secret_name
wolfogre Dec 13, 2022
aa10928
Update templates/org/settings/secrets.tmpl
wolfogre Dec 13, 2022
f738069
Update routers/web/org/setting.go
wolfogre Dec 13, 2022
5103f1d
Update routers/web/org/setting.go
wolfogre Dec 13, 2022
a23241f
Update services/secrets/encryption_aes.go
wolfogre Dec 13, 2022
9f8fdaa
Update templates/install.tmpl
wolfogre Dec 13, 2022
b32bb7a
Update templates/repo/settings/secrets.tmpl
wolfogre Dec 13, 2022
23dd7a7
Merge branch 'main' into feat/secrets
wolfogre Dec 14, 2022
a8c192d
fix: rename to owner
wolfogre Dec 14, 2022
f1ef5ae
fix: remove FindObjects
wolfogre Dec 14, 2022
4a2676e
fix: add unique index
wolfogre Dec 14, 2022
5aa55fe
fix: delete secrets
wolfogre Dec 14, 2022
d1a729b
fix: generate master key with 64 chars
wolfogre Dec 14, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions cmd/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,14 @@
package cmd

import (
"encoding/base64"
"fmt"
"os"

"code.gitea.io/gitea/modules/generate"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
"code.gitea.io/gitea/services/secrets"

"github.com/mattn/go-isatty"
"github.com/urfave/cli"
Expand All @@ -31,6 +35,7 @@ var (
microcmdGenerateInternalToken,
microcmdGenerateLfsJwtSecret,
microcmdGenerateSecretKey,
microcmdGenerateMasterKey,
},
}

Expand All @@ -52,6 +57,12 @@ var (
Usage: "Generate a new SECRET_KEY",
Action: runGenerateSecretKey,
}

microcmdGenerateMasterKey = cli.Command{
Name: "MASTER_KEY",
Usage: "Generate a new MASTER_KEY",
Action: runGenerateMasterKey,
}
)

func runGenerateInternalToken(c *cli.Context) error {
Expand Down Expand Up @@ -98,3 +109,46 @@ func runGenerateSecretKey(c *cli.Context) error {

return nil
}

func runGenerateMasterKey(c *cli.Context) error {
// Silence the console logger
log.DelNamedLogger("console")
log.DelNamedLogger(log.DEFAULT)

// Read configuration file
setting.LoadFromExisting()

providerType := secrets.MasterKeyProviderType(setting.MasterKeyProvider)
if providerType == secrets.MasterKeyProviderTypeNone {
return fmt.Errorf("configured master key provider does not support key generation")
}

if err := secrets.Init(); err != nil {
return err
}

scrts, err := secrets.GenerateMasterKey()
if err != nil {
return err
}

if len(scrts) > 1 {
fmt.Println("Unseal secrets:")
for i, secret := range scrts {
if i > 0 {
fmt.Printf("\n")
}
fmt.Printf("%s\n", base64.StdEncoding.EncodeToString(secret))
}
}

if providerType == secrets.MasterKeyProviderTypePlain && len(scrts) == 1 {
fmt.Printf("%s", base64.StdEncoding.EncodeToString(scrts[0]))

if isatty.IsTerminal(os.Stdout.Fd()) {
fmt.Printf("\n")
}
}

return nil
}
62 changes: 62 additions & 0 deletions models/auth/secret.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package auth

import (
"fmt"
"regexp"

"code.gitea.io/gitea/models/db"
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
)

type ErrSecretInvalidValue struct {
Name *string
Data *string
}

func (err ErrSecretInvalidValue) Error() string {
if err.Name != nil {
return fmt.Sprintf("secret name %q is invalid", *err.Name)
}
if err.Data != nil {
return fmt.Sprintf("secret data %q is invalid", *err.Data)
}
return util.ErrInvalidArgument.Error()
}

func (err ErrSecretInvalidValue) Unwrap() error {
return util.ErrInvalidArgument
}

var nameRE = regexp.MustCompile("^[a-zA-Z_][a-zA-Z0-9-_.]*$")

// Secret represents a secret
type Secret struct {
ID int64
lunny marked this conversation as resolved.
Show resolved Hide resolved
UserID int64 `xorm:"index NOTNULL"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OwnerID?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved.

RepoID int64 `xorm:"index NOTNULL"`
Name string `xorm:"NOTNULL"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I just noticed: If we change our preconditions slightly, we can also do something more advanced:
If we always set the user ID even on org secrets, then an org secret is simply a secret with repoID == 0.
This has the benefit that we can then enforce a combined uniqueness constraint over the userID, repoID, and the name.
This would have the advantage that you cannot have more than one secret for the same user-repo combi, so no global or repo specific secret could have a duplicate name.
I think that's a check we cannot omit, as the current implementation allows for inconsistent states when multiple secrets have the same name.


Let's test that there are no drawbacks on both possible values: Assume we have a secret name in org 1.

  • the org secret would be 1, 0, name
  • the repo secret for a specific repo, i.e. 2, would be 1, 2, name, so it doesn't violate the constraint.

the only thing to keep in mind when collecting the secrets is that we need to query the org secrets first so that the repo secrets will override the org secrets.


One other thing I noticed: We should also delete repo secrets when a repo is deleted and org secrets when an org is deleted.
Should hopefully be a two-liner.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could it be that the suggestions in this file were missed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

enforce a combined uniqueness constraint over the userID, repoID, and the name.

I agree, but I think your example is incorrect. The repo secret for a specific repo, i.e. 2, would be 0, 2, name, not 1, 2, name. Anyway, the conclusion is the same.

delete repo secrets when a repo is deleted and org secrets when an org is deleted.

Agree.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved.

Copy link
Member

@delvh delvh Dec 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you are right, but I'm not completely sure.
I forgot that the repoID also tells us implicitly which owner a repo belongs to, so we don't even need to set the owner ID.
So, we don't need to change our preconditions anymore and they are fine as they are.
(I'm speaking of

I just noticed: If we change our preconditions slightly, we can also do something more advanced:
If we always set the user ID even on org secrets, then an org secret is simply a secret with repoID == 0.
This has the benefit that we can then enforce a combined uniqueness constraint over the userID, repoID, and the name.

)

Data string `xorm:"LONGTEXT"` // encrypted data, or plaintext data if there's no master key
CreatedUnix timeutil.TimeStamp `xorm:"created NOTNULL"`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also store UpdatedUnix?
Or should we perhaps only store UpdatedUnix?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, we can only add or remove a secret, so there's no "updated time".

}

func init() {
db.RegisterModel(new(Secret))
}

// Validate validates the required fields and formats.
func (s *Secret) Validate() error {
switch {
case len(s.Name) == 0:
return ErrSecretInvalidValue{Name: &s.Name}
case len(s.Data) == 0:
return ErrSecretInvalidValue{Data: &s.Data}
case nameRE.MatchString(s.Name):
return ErrSecretInvalidValue{Name: &s.Name}
default:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

and given my suggestion above, the case case s.UserID == 0 should also return an error.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why? If it's a repo secret, the OwnerID(aka UserID) should be 0. So the secret has nothing to do with the repo's owner, and works well with repo transferring.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yep, since we don't need to change our assumptions anymore, that's not needed.

return nil
}
}
18 changes: 18 additions & 0 deletions models/db/search.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,12 @@

package db

import (
"context"

"xorm.io/builder"
)

// SearchOrderBy is used to sort the result
type SearchOrderBy string

Expand All @@ -27,3 +33,15 @@ const (
SearchOrderByForks SearchOrderBy = "num_forks ASC"
SearchOrderByForksReverse SearchOrderBy = "num_forks DESC"
)

// FindObjects represents a common function to find Objects from database according cond and ListOptions
func FindObjects[Object any](ctx context.Context, cond builder.Cond, opts *ListOptions, objects *[]*Object) error {
lunny marked this conversation as resolved.
Show resolved Hide resolved
sess := GetEngine(ctx).Where(cond)
if opts != nil && opts.PageSize > 0 {
if opts.Page < 1 {
opts.Page = 1
}
sess.Limit(opts.PageSize, opts.PageSize*(opts.Page-1))
}
return sess.Find(objects)
}
2 changes: 2 additions & 0 deletions models/migrations/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,8 @@ var migrations = []Migration{
NewMigration("Add package cleanup rule table", v1_19.CreatePackageCleanupRuleTable),
// v235 -> v236
NewMigration("Add index for access_token", v1_19.AddIndexForAccessToken),
// v236 -> v237
NewMigration("Create secrets table", v1_19.CreateSecretsTable),
}

// GetCurrentDBVersion returns the current db version
Expand Down
23 changes: 23 additions & 0 deletions models/migrations/v1_19/v236.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright 2022 The Gitea Authors. All rights reserved.
// SPDX-License-Identifier: MIT

package v1_19 //nolint

import (
"code.gitea.io/gitea/modules/timeutil"

"xorm.io/xorm"
)

func CreateSecretsTable(x *xorm.Engine) error {
type Secret struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should also be updated when you update the data model as requested above.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved.

ID int64
UserID int64 `xorm:"index NOTNULL"`
RepoID int64 `xorm:"index NOTNULL"`
Name string `xorm:"NOTNULL"`
Data string `xorm:"LONGTEXT"`
CreatedUnix timeutil.TimeStamp `xorm:"created NOTNULL"`
}

return x.Sync(new(Secret))
}
5 changes: 5 additions & 0 deletions modules/generate/generate.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,3 +66,8 @@ func NewSecretKey() (string, error) {

return secretKey, nil
}

// NewMasterKey generate a new value intended to be used by MASTER_KEY.
func NewMasterKey() ([]byte, error) {
return util.CryptoRandomBytes(32)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why so short when the SecretKey already has 64 runes?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved. Actually, I don't know why it was 32, but I think you're right and it makes sense to have the same length as SecretKey.

}
17 changes: 17 additions & 0 deletions modules/setting/setting.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
package setting

import (
"crypto/sha1"
"encoding/base64"
"fmt"
"math"
Expand All @@ -27,6 +28,7 @@ import (
"code.gitea.io/gitea/modules/user"
"code.gitea.io/gitea/modules/util"

"golang.org/x/crypto/pbkdf2"
gossh "golang.org/x/crypto/ssh"
ini "gopkg.in/ini.v1"
)
Expand Down Expand Up @@ -214,6 +216,8 @@ var (
HMACKey string `ini:"HMAC_KEY"`
Allways bool
}{}
MasterKeyProvider string
MasterKey []byte
Comment on lines +219 to +220
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Those two config options are currently missing from config-cheat-sheet.
Or are they supposed to be undocumented?


// UI settings
UI = struct {
Expand Down Expand Up @@ -966,6 +970,19 @@ func loadFromConf(allowEmpty bool, extraConfig string) {
PasswordCheckPwn = sec.Key("PASSWORD_CHECK_PWN").MustBool(false)
SuccessfulTokensCacheSize = sec.Key("SUCCESSFUL_TOKENS_CACHE_SIZE").MustInt(20)

// Master key provider configuration
MasterKeyProvider = sec.Key("MASTER_KEY_PROVIDER").MustString("plain")
switch MasterKeyProvider {
case "plain":
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why plain?

tempSalt := []byte{'g', 'i', 't', 'e', 'a'}
MasterKey = []byte(sec.Key("MASTER_KEY").MustString(SecretKey))
MasterKey = pbkdf2.Key(MasterKey, tempSalt, 4096, 32, sha1.New)
case "none":
default:
log.Fatal("invalid master key provider type: %v", MasterKeyProvider)
return
}

InternalToken = loadSecret(sec, "INTERNAL_TOKEN_URI", "INTERNAL_TOKEN")
if InstallLock && InternalToken == "" {
// if Gitea has been installed but the InternalToken hasn't been generated (upgrade from an old release), we should generate
Expand Down
8 changes: 8 additions & 0 deletions modules/templates/helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
"code.gitea.io/gitea/modules/timeutil"
"code.gitea.io/gitea/modules/util"
"code.gitea.io/gitea/services/gitdiff"
secret_service "code.gitea.io/gitea/services/secrets"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Admit it: You wanted to name it that way :)


"github.com/editorconfig/editorconfig-core-go/v2"
)
Expand Down Expand Up @@ -459,6 +460,13 @@ func NewFuncMap() []template.FuncMap {
return items
},
"HasPrefix": strings.HasPrefix,
"Shadow": func(s string) string {
return "******"
},
"DecryptSecret": func(s string) string {
v, _ := secret_service.DecryptString(s)
return v
},
"CompareLink": func(baseRepo, repo *repo_model.Repository, branchName string) string {
var curBranch string
if repo.ID != baseRepo.ID {
Expand Down
7 changes: 7 additions & 0 deletions modules/web/middleware/binding.go
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,11 @@ func GetInclude(field reflect.StructField) string {
return getRuleBody(field, "Include(")
}

// GetIn get allowed values in form tag
func GetIn(field reflect.StructField) string {
return getRuleBody(field, "In(")
}

// Validate validate TODO:
func Validate(errs binding.Errors, data map[string]interface{}, f Form, l translation.Locale) binding.Errors {
if errs.Len() == 0 {
Expand Down Expand Up @@ -130,6 +135,8 @@ func Validate(errs binding.Errors, data map[string]interface{}, f Form, l transl
data["ErrorMsg"] = trName + l.Tr("form.url_error", errs[0].Message)
case binding.ERR_INCLUDE:
data["ErrorMsg"] = trName + l.Tr("form.include_error", GetInclude(field))
case binding.ERR_IN:
data["ErrorMsg"] = trName + l.Tr("form.in_error", strings.Join(strings.Split(GetIn(field), ","), ", "))
case validation.ErrGlobPattern:
data["ErrorMsg"] = trName + l.Tr("form.glob_pattern_error", errs[0].Message)
case validation.ErrRegexPattern:
Expand Down
21 changes: 21 additions & 0 deletions options/locale/locale_en-US.ini
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ app_url_helper = Base address for HTTP(S) clone URLs and email notifications.
log_root_path = Log Path
log_root_path_helper = Log files will be written to this directory.

security_title = Security Settings
master_key_provider = Master Key Provider
master_key_provider_none = None
master_key_provider_plain = Plain
master_key_provider_helper = Master Key Provider to use to store secret key that will be used for other secret encryption. Use "None" to not encrypt secrets. Use "Plain" to store automatically generated secret in configuration file.

optional_title = Optional Settings
email_title = Email Settings
smtp_addr = SMTP Host
Expand Down Expand Up @@ -243,6 +249,7 @@ no_reply_address = Hidden Email Domain
no_reply_address_helper = Domain name for users with a hidden email address. For example, the username 'joe' will be logged in Git as 'joe@noreply.example.org' if the hidden email domain is set to 'noreply.example.org'.
password_algorithm = Password Hash Algorithm
password_algorithm_helper = Set the password hashing algorithm. Algorithms have differing requirements and strength. `argon2` whilst having good characteristics uses a lot of memory and may be inappropriate for small systems.
master_key_failed = Failed to generate master key: %v
enable_update_checker = Enable Update Checker
enable_update_checker_helper = Checks for new version releases periodically by connecting to gitea.io.

Expand Down Expand Up @@ -466,6 +473,7 @@ max_size_error = ` must contain at most %s characters.`
email_error = ` is not a valid email address.`
url_error = `'%s' is not a valid URL.`
include_error = ` must contain substring '%s'.`
in_error = ` can only contain specific values: %s.`
glob_pattern_error = ` glob pattern is invalid: %s.`
regex_pattern_error = ` regex pattern is invalid: %s.`
username_error = ` can only contain alphanumeric chars ('0-9','a-z','A-Z'), dash ('-'), underscore ('_') and dot ('.'). It cannot begin or end with non-alphanumeric chars, and consecutive non-alphanumeric chars are also forbidden.`
Expand Down Expand Up @@ -2059,6 +2067,18 @@ settings.deploy_key_desc = Deploy keys have read-only pull access to the reposit
settings.is_writable = Enable Write Access
settings.is_writable_info = Allow this deploy key to <strong>push</strong> to the repository.
settings.no_deploy_keys = There are no deploy keys yet.
settings.secrets = Secrets
settings.add_secret = Add Secret
settings.add_secret_success = The secret '%s' has been added.
settings.secret_value_content_placeholder = Input any content
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't that placeholder redundant?
It doesn't serve any purpose.
It would only have a purpose if it clarified for example how surounding whitespace is handled.

Speaking of which: Do we strip surrounding whitespace already? I hope so as that is in general much more user-friendly…

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assuming my suggestion above is implemented:

Suggested change
settings.secret_value_content_placeholder = Input any content
settings.secret_value_content_placeholder = Input any content. Whitespace at the start and end will be omitted.

Then suddenly this placeholder isn't redundant anymore.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Solved in the new PR.

settings.secret_desc = Secrets will be passed to certain actions and cannot be read otherwise.
settings.secret_content = Value
settings.secret_name = Name
settings.no_secret = There are no secrets yet.
settings.secret_deletion = Remove secret
settings.secret_deletion_desc = Removing a secret will revoke its access to this repository. Continue?
settings.secret_deletion_success = The secret has been removed.
settings.secret_deletion_failed = Failed to remove secret.
settings.title = Title
settings.deploy_key_content = Content
settings.key_been_used = A deploy key with identical content is already in use.
Expand Down Expand Up @@ -2377,6 +2397,7 @@ settings.update_setting_success = Organization settings have been updated.
settings.change_orgname_prompt = Note: changing the organization name also changes the organization's URL.
settings.change_orgname_redirect_prompt = The old name will redirect until it is claimed.
settings.update_avatar_success = The organization's avatar has been updated.
settings.secrets = Secrets
lunny marked this conversation as resolved.
Show resolved Hide resolved
settings.delete = Delete Organization
settings.delete_account = Delete This Organization
settings.delete_prompt = The organization will be permanently removed. This <strong>CANNOT</strong> be undone!
Expand Down
3 changes: 3 additions & 0 deletions routers/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ import (
pull_service "code.gitea.io/gitea/services/pull"
repo_service "code.gitea.io/gitea/services/repository"
"code.gitea.io/gitea/services/repository/archiver"
secret_service "code.gitea.io/gitea/services/secrets"
"code.gitea.io/gitea/services/task"
"code.gitea.io/gitea/services/webhook"
)
Expand Down Expand Up @@ -149,6 +150,8 @@ func GlobalInitInstalled(ctx context.Context) {
mustInit(models.Init)
mustInit(repo_service.Init)

mustInit(secret_service.Init)

// Booting long running goroutines.
issue_indexer.InitIssueIndexer(false)
code_indexer.Init()
Expand Down
Loading