Skip to content

Commit 3794e37

Browse files
authored
Merge branch 'main' into patch-1
2 parents 219d4d4 + 8b5c081 commit 3794e37

File tree

121 files changed

+1986
-1452
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

121 files changed

+1986
-1452
lines changed

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ docker run --entrypoint="" --rm -it gitea/act_runner:latest act_runner generate-
8181
When you are using the docker image, you can specify the configuration file by using the `CONFIG_FILE` environment variable. Make sure that the file is mounted into the container as a volume:
8282

8383
```bash
84-
docker run -v $(pwd)/config.yaml:/config.yaml -e CONFIG_FILE=/config.yaml ...
84+
docker run -v $PWD/config.yaml:/config.yaml -e CONFIG_FILE=/config.yaml ...
8585
```
8686

8787
You may notice the commands above are both incomplete, because it is not the time to run the act runner yet.
@@ -157,8 +157,8 @@ If you are using the docker image, behaviour will be slightly different. Registr
157157

158158
```bash
159159
docker run \
160-
-v $(pwd)/config.yaml:/config.yaml \
161-
-v $(pwd)/data:/data \
160+
-v $PWD/config.yaml:/config.yaml \
161+
-v $PWD/data:/data \
162162
-v /var/run/docker.sock:/var/run/docker.sock \
163163
-e CONFIG_FILE=/config.yaml \
164164
-e GITEA_INSTANCE_URL=<instance_url> \
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
---
2+
date: "2023-08-22T14:21:00+08:00"
3+
title: "Usage: Multi-factor Authentication (MFA)"
4+
slug: "multi-factor-authentication"
5+
weight: 15
6+
toc: false
7+
draft: false
8+
menu:
9+
sidebar:
10+
parent: "usage"
11+
name: "Multi-factor Authentication (MFA)"
12+
weight: 15
13+
identifier: "multi-factor-authentication"
14+
---
15+
16+
# Multi-factor Authentication (MFA)
17+
18+
Multi-factor Authentication (also referred to as MFA or 2FA) enhances security by requiring a time-sensitive set of credentials in addition to a password.
19+
If a password were later to be compromised, logging into Gitea will not be possible without the additional credentials and the account would remain secure.
20+
Gitea supports both TOTP (Time-based One-Time Password) tokens and FIDO-based hardware keys using the Webauthn API.
21+
22+
MFA can be configured within the "Security" tab of the user settings page.
23+
24+
## MFA Considerations
25+
26+
Enabling MFA on a user does affect how the Git HTTP protocol can be used with the Git CLI.
27+
This interface does not support MFA, and trying to use a password normally will no longer be possible whilst MFA is enabled.
28+
If SSH is not an option for Git operations, an access token can be generated within the "Applications" tab of the user settings page.
29+
This access token can be used as if it were a password in order to allow the Git CLI to function over HTTP.
30+
31+
> **Warning** - By its very nature, an access token sidesteps the security benefits of MFA.
32+
> It must be kept secure and should only be used as a last resort.
33+
34+
The Gitea API supports providing the relevant TOTP password in the `X-Gitea-OTP` header, as described in [API Usage](development/api-usage.md).
35+
This should be used instead of an access token where possible.

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ require (
9090
github.com/prometheus/client_golang v1.16.0
9191
github.com/quasoft/websspi v1.1.2
9292
github.com/redis/go-redis/v9 v9.0.5
93+
github.com/robfig/cron/v3 v3.0.1
9394
github.com/santhosh-tekuri/jsonschema/v5 v5.3.1
9495
github.com/sassoftware/go-rpmutils v0.2.0
9596
github.com/sergi/go-diff v1.3.1
@@ -254,7 +255,6 @@ require (
254255
github.com/rhysd/actionlint v1.6.25 // indirect
255256
github.com/rivo/uniseg v0.4.4 // indirect
256257
github.com/robfig/cron v1.2.0 // indirect
257-
github.com/robfig/cron/v3 v3.0.1 // indirect
258258
github.com/rogpeppe/go-internal v1.11.0 // indirect
259259
github.com/rs/xid v1.5.0 // indirect
260260
github.com/russross/blackfriday/v2 v2.1.0 // indirect

models/actions/schedule.go

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package actions
5+
6+
import (
7+
"context"
8+
"time"
9+
10+
"code.gitea.io/gitea/models/db"
11+
repo_model "code.gitea.io/gitea/models/repo"
12+
user_model "code.gitea.io/gitea/models/user"
13+
"code.gitea.io/gitea/modules/timeutil"
14+
webhook_module "code.gitea.io/gitea/modules/webhook"
15+
16+
"github.com/robfig/cron/v3"
17+
)
18+
19+
// ActionSchedule represents a schedule of a workflow file
20+
type ActionSchedule struct {
21+
ID int64
22+
Title string
23+
Specs []string
24+
RepoID int64 `xorm:"index"`
25+
Repo *repo_model.Repository `xorm:"-"`
26+
OwnerID int64 `xorm:"index"`
27+
WorkflowID string
28+
TriggerUserID int64
29+
TriggerUser *user_model.User `xorm:"-"`
30+
Ref string
31+
CommitSHA string
32+
Event webhook_module.HookEventType
33+
EventPayload string `xorm:"LONGTEXT"`
34+
Content []byte
35+
Created timeutil.TimeStamp `xorm:"created"`
36+
Updated timeutil.TimeStamp `xorm:"updated"`
37+
}
38+
39+
func init() {
40+
db.RegisterModel(new(ActionSchedule))
41+
}
42+
43+
// GetSchedulesMapByIDs returns the schedules by given id slice.
44+
func GetSchedulesMapByIDs(ids []int64) (map[int64]*ActionSchedule, error) {
45+
schedules := make(map[int64]*ActionSchedule, len(ids))
46+
return schedules, db.GetEngine(db.DefaultContext).In("id", ids).Find(&schedules)
47+
}
48+
49+
// GetReposMapByIDs returns the repos by given id slice.
50+
func GetReposMapByIDs(ids []int64) (map[int64]*repo_model.Repository, error) {
51+
repos := make(map[int64]*repo_model.Repository, len(ids))
52+
return repos, db.GetEngine(db.DefaultContext).In("id", ids).Find(&repos)
53+
}
54+
55+
var cronParser = cron.NewParser(cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor)
56+
57+
// CreateScheduleTask creates new schedule task.
58+
func CreateScheduleTask(ctx context.Context, rows []*ActionSchedule) error {
59+
// Return early if there are no rows to insert
60+
if len(rows) == 0 {
61+
return nil
62+
}
63+
64+
// Begin transaction
65+
ctx, committer, err := db.TxContext(ctx)
66+
if err != nil {
67+
return err
68+
}
69+
defer committer.Close()
70+
71+
// Loop through each schedule row
72+
for _, row := range rows {
73+
// Create new schedule row
74+
if err = db.Insert(ctx, row); err != nil {
75+
return err
76+
}
77+
78+
// Loop through each schedule spec and create a new spec row
79+
now := time.Now()
80+
81+
for _, spec := range row.Specs {
82+
// Parse the spec and check for errors
83+
schedule, err := cronParser.Parse(spec)
84+
if err != nil {
85+
continue // skip to the next spec if there's an error
86+
}
87+
88+
// Insert the new schedule spec row
89+
if err = db.Insert(ctx, &ActionScheduleSpec{
90+
RepoID: row.RepoID,
91+
ScheduleID: row.ID,
92+
Spec: spec,
93+
Next: timeutil.TimeStamp(schedule.Next(now).Unix()),
94+
}); err != nil {
95+
return err
96+
}
97+
}
98+
}
99+
100+
// Commit transaction
101+
return committer.Commit()
102+
}
103+
104+
func DeleteScheduleTaskByRepo(ctx context.Context, id int64) error {
105+
ctx, committer, err := db.TxContext(ctx)
106+
if err != nil {
107+
return err
108+
}
109+
defer committer.Close()
110+
111+
if _, err := db.GetEngine(ctx).Delete(&ActionSchedule{RepoID: id}); err != nil {
112+
return err
113+
}
114+
115+
if _, err := db.GetEngine(ctx).Delete(&ActionScheduleSpec{RepoID: id}); err != nil {
116+
return err
117+
}
118+
119+
return committer.Commit()
120+
}

models/actions/schedule_list.go

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package actions
5+
6+
import (
7+
"context"
8+
9+
"code.gitea.io/gitea/models/db"
10+
repo_model "code.gitea.io/gitea/models/repo"
11+
user_model "code.gitea.io/gitea/models/user"
12+
"code.gitea.io/gitea/modules/container"
13+
14+
"xorm.io/builder"
15+
)
16+
17+
type ScheduleList []*ActionSchedule
18+
19+
// GetUserIDs returns a slice of user's id
20+
func (schedules ScheduleList) GetUserIDs() []int64 {
21+
ids := make(container.Set[int64], len(schedules))
22+
for _, schedule := range schedules {
23+
ids.Add(schedule.TriggerUserID)
24+
}
25+
return ids.Values()
26+
}
27+
28+
func (schedules ScheduleList) GetRepoIDs() []int64 {
29+
ids := make(container.Set[int64], len(schedules))
30+
for _, schedule := range schedules {
31+
ids.Add(schedule.RepoID)
32+
}
33+
return ids.Values()
34+
}
35+
36+
func (schedules ScheduleList) LoadTriggerUser(ctx context.Context) error {
37+
userIDs := schedules.GetUserIDs()
38+
users := make(map[int64]*user_model.User, len(userIDs))
39+
if err := db.GetEngine(ctx).In("id", userIDs).Find(&users); err != nil {
40+
return err
41+
}
42+
for _, schedule := range schedules {
43+
if schedule.TriggerUserID == user_model.ActionsUserID {
44+
schedule.TriggerUser = user_model.NewActionsUser()
45+
} else {
46+
schedule.TriggerUser = users[schedule.TriggerUserID]
47+
}
48+
}
49+
return nil
50+
}
51+
52+
func (schedules ScheduleList) LoadRepos() error {
53+
repoIDs := schedules.GetRepoIDs()
54+
repos, err := repo_model.GetRepositoriesMapByIDs(repoIDs)
55+
if err != nil {
56+
return err
57+
}
58+
for _, schedule := range schedules {
59+
schedule.Repo = repos[schedule.RepoID]
60+
}
61+
return nil
62+
}
63+
64+
type FindScheduleOptions struct {
65+
db.ListOptions
66+
RepoID int64
67+
OwnerID int64
68+
}
69+
70+
func (opts FindScheduleOptions) toConds() builder.Cond {
71+
cond := builder.NewCond()
72+
if opts.RepoID > 0 {
73+
cond = cond.And(builder.Eq{"repo_id": opts.RepoID})
74+
}
75+
if opts.OwnerID > 0 {
76+
cond = cond.And(builder.Eq{"owner_id": opts.OwnerID})
77+
}
78+
79+
return cond
80+
}
81+
82+
func FindSchedules(ctx context.Context, opts FindScheduleOptions) (ScheduleList, int64, error) {
83+
e := db.GetEngine(ctx).Where(opts.toConds())
84+
if !opts.ListAll && opts.PageSize > 0 && opts.Page >= 1 {
85+
e.Limit(opts.PageSize, (opts.Page-1)*opts.PageSize)
86+
}
87+
var schedules ScheduleList
88+
total, err := e.Desc("id").FindAndCount(&schedules)
89+
return schedules, total, err
90+
}
91+
92+
func CountSchedules(ctx context.Context, opts FindScheduleOptions) (int64, error) {
93+
return db.GetEngine(ctx).Where(opts.toConds()).Count(new(ActionSchedule))
94+
}

models/actions/schedule_spec.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
// Copyright 2023 The Gitea Authors. All rights reserved.
2+
// SPDX-License-Identifier: MIT
3+
4+
package actions
5+
6+
import (
7+
"context"
8+
9+
"code.gitea.io/gitea/models/db"
10+
repo_model "code.gitea.io/gitea/models/repo"
11+
"code.gitea.io/gitea/modules/timeutil"
12+
13+
"github.com/robfig/cron/v3"
14+
)
15+
16+
// ActionScheduleSpec represents a schedule spec of a workflow file
17+
type ActionScheduleSpec struct {
18+
ID int64
19+
RepoID int64 `xorm:"index"`
20+
Repo *repo_model.Repository `xorm:"-"`
21+
ScheduleID int64 `xorm:"index"`
22+
Schedule *ActionSchedule `xorm:"-"`
23+
24+
// Next time the job will run, or the zero time if Cron has not been
25+
// started or this entry's schedule is unsatisfiable
26+
Next timeutil.TimeStamp `xorm:"index"`
27+
// Prev is the last time this job was run, or the zero time if never.
28+
Prev timeutil.TimeStamp
29+
Spec string
30+
31+
Created timeutil.TimeStamp `xorm:"created"`
32+
Updated timeutil.TimeStamp `xorm:"updated"`
33+
}
34+
35+
func (s *ActionScheduleSpec) Parse() (cron.Schedule, error) {
36+
return cronParser.Parse(s.Spec)
37+
}
38+
39+
func init() {
40+
db.RegisterModel(new(ActionScheduleSpec))
41+
}
42+
43+
func UpdateScheduleSpec(ctx context.Context, spec *ActionScheduleSpec, cols ...string) error {
44+
sess := db.GetEngine(ctx).ID(spec.ID)
45+
if len(cols) > 0 {
46+
sess.Cols(cols...)
47+
}
48+
_, err := sess.Update(spec)
49+
return err
50+
}

0 commit comments

Comments
 (0)