diff --git a/api/v2.0/swagger.yaml b/api/v2.0/swagger.yaml index 71805a430..c995f705e 100644 --- a/api/v2.0/swagger.yaml +++ b/api/v2.0/swagger.yaml @@ -7846,6 +7846,9 @@ definitions: type: array items: $ref: '#/definitions/RobotPermission' + creator: + type: string + description: The creator of the robot creation_time: type: string format: date-time diff --git a/make/migrations/postgresql/0150_2.12.0_schema.up.sql b/make/migrations/postgresql/0150_2.12.0_schema.up.sql new file mode 100644 index 000000000..82f106172 --- /dev/null +++ b/make/migrations/postgresql/0150_2.12.0_schema.up.sql @@ -0,0 +1,5 @@ +/* +Add new column creator for robot table to add a new column to record the creator of the robot +*/ +ALTER TABLE robot ADD COLUMN IF NOT EXISTS creator varchar(255); +UPDATE robot SET creator = 'unknown' WHERE creator IS NULL; diff --git a/src/controller/robot/controller.go b/src/controller/robot/controller.go index f0073810f..79ae3576c 100644 --- a/src/controller/robot/controller.go +++ b/src/controller/robot/controller.go @@ -123,6 +123,7 @@ func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error if r.Level == LEVELPROJECT { name = fmt.Sprintf("%s+%s", r.ProjectName, r.Name) } + rCreate := &model.Robot{ Name: name, Description: r.Description, @@ -132,6 +133,7 @@ func (d *controller) Create(ctx context.Context, r *Robot) (int64, string, error Duration: r.Duration, Salt: salt, Visible: r.Visible, + Creator: r.Creator, } robotID, err := d.robotMgr.Create(ctx, rCreate) if err != nil { diff --git a/src/controller/robot/controller_test.go b/src/controller/robot/controller_test.go index 4bb1b4cfc..1475d39e3 100644 --- a/src/controller/robot/controller_test.go +++ b/src/controller/robot/controller_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/suite" "github.com/goharbor/harbor/src/common" + "github.com/goharbor/harbor/src/common/security" "github.com/goharbor/harbor/src/common/utils/test" "github.com/goharbor/harbor/src/lib/config" "github.com/goharbor/harbor/src/lib/q" @@ -18,6 +19,7 @@ import ( rbac_model "github.com/goharbor/harbor/src/pkg/rbac/model" "github.com/goharbor/harbor/src/pkg/robot/model" htesting "github.com/goharbor/harbor/src/testing" + testsec "github.com/goharbor/harbor/src/testing/common/security" "github.com/goharbor/harbor/src/testing/mock" "github.com/goharbor/harbor/src/testing/pkg/project" "github.com/goharbor/harbor/src/testing/pkg/rbac" @@ -102,7 +104,9 @@ func (suite *ControllerTestSuite) TestCreate() { robotMgr := &robot.Manager{} c := controller{robotMgr: robotMgr, rbacMgr: rbacMgr, proMgr: projectMgr} - ctx := context.TODO() + secCtx := &testsec.Context{} + secCtx.On("GetUsername").Return("security-context-user") + ctx := security.NewContext(context.Background(), secCtx) projectMgr.On("Get", mock.Anything, mock.Anything).Return(&proModels.Project{ProjectID: 1, Name: "library"}, nil) robotMgr.On("Create", mock.Anything, mock.Anything).Return(int64(1), nil) rbacMgr.On("CreateRbacPolicy", mock.Anything, mock.Anything, mock.Anything).Return(int64(1), nil) diff --git a/src/controller/scan/base_controller.go b/src/controller/scan/base_controller.go index f6a0427b4..fe4a15faf 100644 --- a/src/controller/scan/base_controller.go +++ b/src/controller/scan/base_controller.go @@ -864,6 +864,7 @@ func (bc *basicController) makeRobotAccount(ctx context.Context, projectID int64 Description: "for scan", ProjectID: projectID, Duration: -1, + Creator: "harbor-core-for-scan-all", }, Level: robot.LEVELPROJECT, Permissions: []*robot.Permission{ diff --git a/src/controller/scan/base_controller_test.go b/src/controller/scan/base_controller_test.go index ca12196d7..028c860d7 100644 --- a/src/controller/scan/base_controller_test.go +++ b/src/controller/scan/base_controller_test.go @@ -235,6 +235,7 @@ func (suite *ControllerTestSuite) SetupSuite() { Description: "for scan", ProjectID: suite.artifact.ProjectID, Duration: -1, + Creator: "harbor-core-for-scan-all", }, Level: robot.LEVELPROJECT, Permissions: []*robot.Permission{ @@ -266,6 +267,7 @@ func (suite *ControllerTestSuite) SetupSuite() { Description: "for scan", ProjectID: suite.artifact.ProjectID, Duration: -1, + Creator: "harbor-core-for-scan-all", }, Level: "project", }, nil) diff --git a/src/pkg/robot/dao/dao_test.go b/src/pkg/robot/dao/dao_test.go index 4723b6401..972c75514 100644 --- a/src/pkg/robot/dao/dao_test.go +++ b/src/pkg/robot/dao/dao_test.go @@ -52,6 +52,7 @@ func (suite *DaoTestSuite) robots() { Description: "test3 description", ProjectID: 1, Secret: suite.RandString(10), + Creator: "tester", }) suite.Nil(err) @@ -120,6 +121,7 @@ func (suite *DaoTestSuite) TestGet() { r, err := suite.dao.Get(orm.Context(), suite.robotID3) suite.Nil(err) suite.Equal("test3", r.Name) + suite.Equal("tester", r.Creator) } func (suite *DaoTestSuite) TestCount() { diff --git a/src/pkg/robot/model/model.go b/src/pkg/robot/model/model.go index f35e309c6..a31cb0eed 100644 --- a/src/pkg/robot/model/model.go +++ b/src/pkg/robot/model/model.go @@ -39,6 +39,7 @@ type Robot struct { ExpiresAt int64 `orm:"column(expiresat)" json:"expires_at"` Disabled bool `orm:"column(disabled)" json:"disabled"` Visible bool `orm:"column(visible)" json:"-"` + Creator string `orm:"column(creator)" json:"creator"` CreationTime time.Time `orm:"column(creation_time);auto_now_add" json:"creation_time"` UpdateTime time.Time `orm:"column(update_time);auto_now" json:"update_time"` } diff --git a/src/server/v2.0/handler/model/robot.go b/src/server/v2.0/handler/model/robot.go index e1a97d273..d107bfc0b 100644 --- a/src/server/v2.0/handler/model/robot.go +++ b/src/server/v2.0/handler/model/robot.go @@ -48,6 +48,7 @@ func (r *Robot) ToSwagger() *models.Robot { Level: r.Level, Disable: r.Disabled, Editable: r.Editable, + Creator: r.Creator, CreationTime: strfmt.DateTime(r.CreationTime), UpdateTime: strfmt.DateTime(r.UpdateTime), Permissions: perms, diff --git a/src/server/v2.0/handler/robot.go b/src/server/v2.0/handler/robot.go index fff5f2aac..316db7cd5 100644 --- a/src/server/v2.0/handler/robot.go +++ b/src/server/v2.0/handler/robot.go @@ -62,12 +62,18 @@ func (rAPI *robotAPI) CreateRobot(ctx context.Context, params operation.CreateRo return rAPI.SendError(ctx, err) } + sc, err := rAPI.GetSecurityContext(ctx) + if err != nil { + return rAPI.SendError(ctx, err) + } + r := &robot.Robot{ Robot: pkg.Robot{ Name: params.Robot.Name, Description: params.Robot.Description, Duration: params.Robot.Duration, Visible: true, + Creator: sc.GetUsername(), }, Level: params.Robot.Level, }