Skip to content

Commit b3c5cb5

Browse files
committed
Merge remote-tracking branch 'giteaofficial/main'
* giteaofficial/main: Filter inactive auth sources (go-gitea#27870) refactor postgres connection string building (go-gitea#27723) doc: actions/act-runner: document running as a systemd service (go-gitea#27844) Support storage base path as prefix (go-gitea#27827)
2 parents 6d8bdf9 + e378545 commit b3c5cb5

File tree

7 files changed

+149
-34
lines changed

7 files changed

+149
-34
lines changed

docs/content/administration/config-cheat-sheet.en-us.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ The following configuration set `Content-Type: application/vnd.android.package-a
424424
## Database (`database`)
425425

426426
- `DB_TYPE`: **mysql**: The database type in use \[mysql, postgres, mssql, sqlite3\].
427-
- `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres\] (ex: /var/run/mysqld/mysqld.sock).
427+
- `HOST`: **127.0.0.1:3306**: Database host address and port or absolute path for unix socket \[mysql, postgres[^1]\] (ex: /var/run/mysqld/mysqld.sock).
428428
- `NAME`: **gitea**: Database name.
429429
- `USER`: **root**: Database username.
430430
- `PASSWD`: **_empty_**: Database user password. Use \`your password\` or """your password""" for quoting if you use special characters in the password.
@@ -455,6 +455,8 @@ The following configuration set `Content-Type: application/vnd.android.package-a
455455
- `CONN_MAX_LIFETIME` **0 or 3s**: Sets the maximum amount of time a DB connection may be reused - default is 0, meaning there is no limit (except on MySQL where it is 3s - see #6804 & #7071).
456456
- `AUTO_MIGRATION` **true**: Whether execute database models migrations automatically.
457457

458+
[^1]: It may be necessary to specify a hostport even when listening on a unix socket, as the port is part of the socket name. see [#24552](https://github.com/go-gitea/gitea/issues/24552#issuecomment-1681649367) for additional details.
459+
458460
Please see #8540 & #8273 for further discussion of the appropriate values for `MAX_OPEN_CONNS`, `MAX_IDLE_CONNS` & `CONN_MAX_LIFETIME` and their
459461
relation to port exhaustion.
460462

docs/content/usage/actions/act-runner.en-us.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,40 @@ The runner will fetch jobs from the Gitea instance and run them automatically.
268268

269269
Since act runner is still in development, it is recommended to check the latest version and upgrade it regularly.
270270

271+
## Systemd service
272+
273+
It is also possible to run act-runner as a [systemd](https://en.wikipedia.org/wiki/Systemd) service. Create an unprivileged `act_runner` user on your system, and the following file in `/etc/systemd/system/act_runner.service`. The paths in `ExecStart` and `WorkingDirectory` may need to be adjusted depending on where you installed the `act_runner` binary, its configuration file, and the home directory of the `act_runner` user.
274+
275+
```ini
276+
[Unit]
277+
Description=Gitea Actions runner
278+
Documentation=https://gitea.com/gitea/act_runner
279+
After=docker.service
280+
281+
[Service]
282+
ExecStart=/usr/local/bin/act_runner daemon --config /etc/act_runner/config.yaml
283+
ExecReload=/bin/kill -s HUP $MAINPID
284+
WorkingDirectory=/var/lib/act_runner
285+
TimeoutSec=0
286+
RestartSec=10
287+
Restart=always
288+
User=act_runner
289+
290+
[Install]
291+
WantedBy=multi-user.target
292+
```
293+
294+
Then:
295+
296+
```bash
297+
# load the new systemd unit file
298+
sudo systemctl daemon-reload
299+
# start the service and enable it at boot
300+
sudo systemctl enable act_runner --now
301+
```
302+
303+
If using Docker, the `act_runner` user should also be added to the `docker` group before starting the service. Keep in mind that this effectively gives `act_runner` root access to the system [[1]](https://docs.docker.com/engine/security/#docker-daemon-attack-surface).
304+
271305
## Configuration variable
272306

273307
You can create configuration variables on the user, organization and repository level.

modules/setting/database.go

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ package setting
66
import (
77
"errors"
88
"fmt"
9+
"net"
910
"net/url"
1011
"os"
1112
"path"
@@ -135,15 +136,18 @@ func DBConnStr() (string, error) {
135136
// parsePostgreSQLHostPort parses given input in various forms defined in
136137
// https://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING
137138
// and returns proper host and port number.
138-
func parsePostgreSQLHostPort(info string) (string, string) {
139-
host, port := "127.0.0.1", "5432"
140-
if strings.Contains(info, ":") && !strings.HasSuffix(info, "]") {
141-
idx := strings.LastIndex(info, ":")
142-
host = info[:idx]
143-
port = info[idx+1:]
144-
} else if len(info) > 0 {
139+
func parsePostgreSQLHostPort(info string) (host, port string) {
140+
if h, p, err := net.SplitHostPort(info); err == nil {
141+
host, port = h, p
142+
} else {
143+
// treat the "info" as "host", if it's an IPv6 address, remove the wrapper
145144
host = info
145+
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
146+
host = host[1 : len(host)-1]
147+
}
146148
}
149+
150+
// set fallback values
147151
if host == "" {
148152
host = "127.0.0.1"
149153
}
@@ -155,14 +159,22 @@ func parsePostgreSQLHostPort(info string) (string, string) {
155159

156160
func getPostgreSQLConnectionString(dbHost, dbUser, dbPasswd, dbName, dbParam, dbsslMode string) (connStr string) {
157161
host, port := parsePostgreSQLHostPort(dbHost)
158-
if host[0] == '/' { // looks like a unix socket
159-
connStr = fmt.Sprintf("postgres://%s:%s@:%s/%s%ssslmode=%s&host=%s",
160-
url.PathEscape(dbUser), url.PathEscape(dbPasswd), port, dbName, dbParam, dbsslMode, host)
161-
} else {
162-
connStr = fmt.Sprintf("postgres://%s:%s@%s:%s/%s%ssslmode=%s",
163-
url.PathEscape(dbUser), url.PathEscape(dbPasswd), host, port, dbName, dbParam, dbsslMode)
162+
connURL := url.URL{
163+
Scheme: "postgres",
164+
User: url.UserPassword(dbUser, dbPasswd),
165+
Host: net.JoinHostPort(host, port),
166+
Path: dbName,
167+
OmitHost: false,
168+
RawQuery: dbParam,
169+
}
170+
query := connURL.Query()
171+
if dbHost[0] == '/' { // looks like a unix socket
172+
query.Add("host", dbHost)
173+
connURL.Host = ":" + port
164174
}
165-
return connStr
175+
query.Set("sslmode", dbsslMode)
176+
connURL.RawQuery = query.Encode()
177+
return connURL.String()
166178
}
167179

168180
// ParseMSSQLHostPort splits the host into host and port

modules/setting/database_test.go

Lines changed: 18 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,46 +10,49 @@ import (
1010
)
1111

1212
func Test_parsePostgreSQLHostPort(t *testing.T) {
13-
tests := []struct {
13+
tests := map[string]struct {
1414
HostPort string
1515
Host string
1616
Port string
1717
}{
18-
{
18+
"host-port": {
1919
HostPort: "127.0.0.1:1234",
2020
Host: "127.0.0.1",
2121
Port: "1234",
2222
},
23-
{
23+
"no-port": {
2424
HostPort: "127.0.0.1",
2525
Host: "127.0.0.1",
2626
Port: "5432",
2727
},
28-
{
28+
"ipv6-port": {
2929
HostPort: "[::1]:1234",
30-
Host: "[::1]",
30+
Host: "::1",
3131
Port: "1234",
3232
},
33-
{
33+
"ipv6-no-port": {
3434
HostPort: "[::1]",
35-
Host: "[::1]",
35+
Host: "::1",
3636
Port: "5432",
3737
},
38-
{
38+
"unix-socket": {
3939
HostPort: "/tmp/pg.sock:1234",
4040
Host: "/tmp/pg.sock",
4141
Port: "1234",
4242
},
43-
{
43+
"unix-socket-no-port": {
4444
HostPort: "/tmp/pg.sock",
4545
Host: "/tmp/pg.sock",
4646
Port: "5432",
4747
},
4848
}
49-
for _, test := range tests {
50-
host, port := parsePostgreSQLHostPort(test.HostPort)
51-
assert.Equal(t, test.Host, host)
52-
assert.Equal(t, test.Port, port)
49+
for k, test := range tests {
50+
t.Run(k, func(t *testing.T) {
51+
t.Log(test.HostPort)
52+
host, port := parsePostgreSQLHostPort(test.HostPort)
53+
assert.Equal(t, test.Host, host)
54+
assert.Equal(t, test.Port, port)
55+
})
5356
}
5457
}
5558

@@ -72,7 +75,7 @@ func Test_getPostgreSQLConnectionString(t *testing.T) {
7275
Name: "gitea",
7376
Param: "",
7477
SSLMode: "false",
75-
Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/giteasslmode=false&host=/tmp/pg.sock",
78+
Output: "postgres://testuser:space%20space%20%21%23$%25%5E%5E%25%5E%60%60%60-=%3F=@:5432/gitea?host=%2Ftmp%2Fpg.sock&sslmode=false",
7679
},
7780
{
7881
Host: "localhost",
@@ -82,7 +85,7 @@ func Test_getPostgreSQLConnectionString(t *testing.T) {
8285
Name: "gitea",
8386
Param: "",
8487
SSLMode: "true",
85-
Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/giteasslmode=true",
88+
Output: "postgres://pgsqlusername:I%20love%20Gitea%21@localhost:5432/gitea?sslmode=true",
8689
},
8790
}
8891

modules/setting/storage.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"errors"
88
"fmt"
99
"path/filepath"
10+
"strings"
1011
)
1112

1213
// StorageType is a type of Storage
@@ -249,14 +250,24 @@ func getStorageForMinio(targetSec, overrideSec ConfigSection, tp targetSecType,
249250
return nil, fmt.Errorf("map minio config failed: %v", err)
250251
}
251252

252-
if storage.MinioConfig.BasePath == "" {
253-
storage.MinioConfig.BasePath = name + "/"
253+
var defaultPath string
254+
if storage.MinioConfig.BasePath != "" {
255+
if tp == targetSecIsStorage || tp == targetSecIsDefault {
256+
defaultPath = strings.TrimSuffix(storage.MinioConfig.BasePath, "/") + "/" + name + "/"
257+
} else {
258+
defaultPath = storage.MinioConfig.BasePath
259+
}
260+
}
261+
if defaultPath == "" {
262+
defaultPath = name + "/"
254263
}
255264

256265
if overrideSec != nil {
257266
storage.MinioConfig.ServeDirect = ConfigSectionKeyBool(overrideSec, "SERVE_DIRECT", storage.MinioConfig.ServeDirect)
258-
storage.MinioConfig.BasePath = ConfigSectionKeyString(overrideSec, "MINIO_BASE_PATH", storage.MinioConfig.BasePath)
267+
storage.MinioConfig.BasePath = ConfigSectionKeyString(overrideSec, "MINIO_BASE_PATH", defaultPath)
259268
storage.MinioConfig.Bucket = ConfigSectionKeyString(overrideSec, "MINIO_BUCKET", storage.MinioConfig.Bucket)
269+
} else {
270+
storage.MinioConfig.BasePath = defaultPath
260271
}
261272
return &storage, nil
262273
}

modules/setting/storage_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -412,3 +412,56 @@ MINIO_USE_SSL = true
412412
assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL)
413413
assert.EqualValues(t, "repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
414414
}
415+
416+
func Test_getStorageConfiguration28(t *testing.T) {
417+
cfg, err := NewConfigProviderFromData(`
418+
[storage]
419+
STORAGE_TYPE = minio
420+
MINIO_ACCESS_KEY_ID = my_access_key
421+
MINIO_SECRET_ACCESS_KEY = my_secret_key
422+
MINIO_USE_SSL = true
423+
MINIO_BASE_PATH = /prefix
424+
`)
425+
assert.NoError(t, err)
426+
assert.NoError(t, loadRepoArchiveFrom(cfg))
427+
assert.EqualValues(t, "my_access_key", RepoArchive.Storage.MinioConfig.AccessKeyID)
428+
assert.EqualValues(t, "my_secret_key", RepoArchive.Storage.MinioConfig.SecretAccessKey)
429+
assert.EqualValues(t, true, RepoArchive.Storage.MinioConfig.UseSSL)
430+
assert.EqualValues(t, "/prefix/repo-archive/", RepoArchive.Storage.MinioConfig.BasePath)
431+
432+
cfg, err = NewConfigProviderFromData(`
433+
[storage]
434+
STORAGE_TYPE = minio
435+
MINIO_ACCESS_KEY_ID = my_access_key
436+
MINIO_SECRET_ACCESS_KEY = my_secret_key
437+
MINIO_USE_SSL = true
438+
MINIO_BASE_PATH = /prefix
439+
440+
[lfs]
441+
MINIO_BASE_PATH = /lfs
442+
`)
443+
assert.NoError(t, err)
444+
assert.NoError(t, loadLFSFrom(cfg))
445+
assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID)
446+
assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey)
447+
assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL)
448+
assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath)
449+
450+
cfg, err = NewConfigProviderFromData(`
451+
[storage]
452+
STORAGE_TYPE = minio
453+
MINIO_ACCESS_KEY_ID = my_access_key
454+
MINIO_SECRET_ACCESS_KEY = my_secret_key
455+
MINIO_USE_SSL = true
456+
MINIO_BASE_PATH = /prefix
457+
458+
[storage.lfs]
459+
MINIO_BASE_PATH = /lfs
460+
`)
461+
assert.NoError(t, err)
462+
assert.NoError(t, loadLFSFrom(cfg))
463+
assert.EqualValues(t, "my_access_key", LFS.Storage.MinioConfig.AccessKeyID)
464+
assert.EqualValues(t, "my_secret_key", LFS.Storage.MinioConfig.SecretAccessKey)
465+
assert.EqualValues(t, true, LFS.Storage.MinioConfig.UseSSL)
466+
assert.EqualValues(t, "/lfs", LFS.Storage.MinioConfig.BasePath)
467+
}

routers/web/user/setting/security/security.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ func loadSecurityData(ctx *context.Context) {
8282
// map the provider display name with the AuthSource
8383
sources := make(map[*auth_model.Source]string)
8484
for _, externalAccount := range accountLinks {
85-
if authSource, err := auth_model.GetSourceByID(ctx, externalAccount.LoginSourceID); err == nil {
85+
if authSource, err := auth_model.GetSourceByID(ctx, externalAccount.LoginSourceID); err == nil && authSource.IsActive {
8686
var providerDisplayName string
8787

8888
type DisplayNamed interface {

0 commit comments

Comments
 (0)