Merge branch 'master' into fix_issues_for_jobservice

This commit is contained in:
Steven Zou 2019-04-22 19:26:51 +08:00
commit 3937c8b0dc
19 changed files with 317 additions and 213 deletions

View File

@ -101,7 +101,7 @@ PREPARE_VERSION_NAME=versions
REGISTRYVERSION=v2.7.1-patch-2819
NGINXVERSION=$(VERSIONTAG)
NOTARYVERSION=v0.6.1
CLAIRVERSION=v2.0.7
CLAIRVERSION=v2.0.8
CLAIRDBVERSION=$(VERSIONTAG)
MIGRATORVERSION=$(VERSIONTAG)
REDISVERSION=$(VERSIONTAG)

View File

@ -940,6 +940,44 @@ paths:
description: User ID does not exist.
'500':
description: Unexpected internal errors.
'/users/{user_id}/gen_cli_secret':
post:
summary: Generate new CLI secret for a user.
description: |
This endpoint let user generate a new CLI secret for himself. This API only works when auth mode is set to 'OIDC'.
Once this API returns with successful status, the old secret will be invalid, as there will be only one CLI secret
for a user. The new secret will be returned in the response.
parameters:
- name: user_id
in: path
type: integer
format: int
required: true
description: User ID
tags:
- Products
responses:
'200':
description: The secret is successfully generated.
schema:
type: object
properties:
secret:
type: string
description: The new secret
'400':
description: Invalid user ID. Or user is not onboarded via OIDC authentication.
'401':
description: User need to log in first.
'403':
description: Non-admin user can only generate the cli secret of himself.
'404':
description: User ID does not exist.
'412':
description: The auth mode of the system is not "oidc_auth", or the user is not onboarded via OIDC AuthN.
'500':
description: Unexpected internal errors.
/repositories:
get:
summary: Get repositories accompany with relevant project and repo name.
@ -1884,14 +1922,14 @@ paths:
description: |
Delete the replication policy specified by ID.
parameters:
- name: id
in: path
type: integer
format: int64
required: true
description: Replication policy ID
- name: id
in: path
type: integer
format: int64
required: true
description: Replication policy ID
tags:
- Products
- Products
responses:
'200':
$ref: '#/responses/OK'
@ -2297,18 +2335,18 @@ paths:
description: |
This endpoint let user list namespaces of registry according to query.
parameters:
- name: id
in: path
type: integer
required: true
description: The registry ID.
- name: name
in: query
type: string
required: false
description: The name of namespace.
- name: id
in: path
type: integer
required: true
description: The registry ID.
- name: name
in: query
type: string
required: false
description: The name of namespace.
tags:
- Products
- Products
responses:
'200':
description: Success
@ -2661,7 +2699,7 @@ paths:
'200':
description: Get gc results successfully.
schema:
$ref: '#/definitions/GCResult'
$ref: '#/definitions/GCResult'
'401':
description: User need to log in first.
'403':
@ -2706,7 +2744,7 @@ paths:
'200':
description: Get gc's schedule.
schema:
$ref: '#/definitions/AdminJobSchedule'
$ref: '#/definitions/AdminJobSchedule'
'401':
description: User need to log in first.
'403':
@ -2768,12 +2806,12 @@ paths:
summary: Get scan_all's schedule.
description: This endpoint is for getting a schedule for the scan all job, which scans all of images in Harbor.
tags:
- Products
- Products
responses:
'200':
description: Get a schedule for the scan all job, which scans all of images in Harbor.
schema:
$ref: '#/definitions/AdminJobSchedule'
$ref: '#/definitions/AdminJobSchedule'
'401':
description: User need to log in first.
'403':
@ -2785,14 +2823,14 @@ paths:
description: |
This endpoint is for updating the schedule of scan all job, which scans all of images in Harbor.
parameters:
- name: schedule
in: body
required: true
schema:
$ref: '#/definitions/AdminJobSchedule'
description: Updates the schedule of scan all job, which scans all of images in Harbor.
- name: schedule
in: body
required: true
schema:
$ref: '#/definitions/AdminJobSchedule'
description: Updates the schedule of scan all job, which scans all of images in Harbor.
tags:
- Products
- Products
responses:
'200':
description: Updated scan_all's schedule successfully.
@ -2809,14 +2847,14 @@ paths:
description: |
This endpoint is for creating a schedule or a manual trigger for the scan all job, which scans all of images in Harbor.
parameters:
- name: schedule
in: body
required: true
schema:
$ref: '#/definitions/AdminJobSchedule'
description: Create a schedule or a manual trigger for the scan all job.
- name: schedule
in: body
required: true
schema:
$ref: '#/definitions/AdminJobSchedule'
description: Create a schedule or a manual trigger for the scan all job.
tags:
- Products
- Products
responses:
'200':
description: Updated scan_all's schedule successfully.
@ -3289,15 +3327,15 @@ paths:
summary: Get all robot accounts of specified project
description: Get all robot accounts of specified project
parameters:
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
tags:
- Products
- Robot Account
- Products
- Robot Account
responses:
'200':
description: Get project robot accounts successfully.
@ -3319,21 +3357,21 @@ paths:
summary: Create a robot account for project
description: Create a robot account for project
tags:
- Products
- Robot Account
- Products
- Robot Account
parameters:
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot
in: body
description: Request body of creating a robot account.
required: true
schema:
$ref: '#/definitions/RobotAccountCreate'
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot
in: body
description: Request body of creating a robot account.
required: true
schema:
$ref: '#/definitions/RobotAccountCreate'
responses:
'201':
description: Project member created successfully.
@ -3354,21 +3392,21 @@ paths:
summary: Return the infor of the specified robot account.
description: Return the infor of the specified robot account.
tags:
- Products
- Robot Account
- Products
- Robot Account
parameters:
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
responses:
'200':
description: Robot account information.
@ -3386,27 +3424,27 @@ paths:
summary: Update status of robot account.
description: Used to disable/enable a specified robot account.
tags:
- Products
- Robot Account
- Products
- Robot Account
parameters:
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
- name: robot
in: body
description: Request body of enable/disable a robot account.
required: true
schema:
$ref: '#/definitions/RobotAccountUpdate'
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
- name: robot
in: body
description: Request body of enable/disable a robot account.
required: true
schema:
$ref: '#/definitions/RobotAccountUpdate'
responses:
'200':
description: Robot account has been modified success.
@ -3416,21 +3454,21 @@ paths:
summary: Delete the specified robot account
description: Delete the specified robot account
tags:
- Products
- Robot Account
- Products
- Robot Account
parameters:
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
- name: project_id
in: path
type: integer
format: int64
required: true
description: Relevant project ID.
- name: robot_id
in: path
type: integer
format: int64
required: true
description: The ID of robot account.
responses:
'200':
description: The specified robot account is successfully deleted.

View File

@ -3,15 +3,19 @@
#The IP address or hostname to access admin UI and registry service.
#DO NOT use localhost or 127.0.0.1, because Harbor needs to be accessed by external clients.
hostname: reg.mydomain.com
# core, harbor
# http related comfig
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 80
# https:
# port: 443
# #The path of cert and key files for nginx
# certificate: /your/certificate/path
# private_key: /your/private/key/path
# https related comfig
https:
# https port for harbor, default is 443
port: 443
#The path of cert and key files for nginx
certificate: /data/cert/server.crt
private_key: /data/cert/server.key
# Uncomment extearnal_url if you want to enable external proxy
# And when it enabled the hostname will no longger used

View File

@ -38,7 +38,7 @@ CREATE TABLE oidc_user (
UNIQUE (subiss)
);
CREATE TRIGGER odic_user_update_time_at_modtime BEFORE UPDATE ON oidc_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
CREATE TRIGGER oidc_user_update_time_at_modtime BEFORE UPDATE ON oidc_user FOR EACH ROW EXECUTE PROCEDURE update_update_time_at_column();
/*add master role*/
INSERT INTO role (role_code, name) VALUES ('DRWS', 'master');

View File

@ -6,7 +6,7 @@ name = "pypi"
[packages]
pyyaml = "==4.2b1"
click = "*"
"jinja2" = "*"
"jinja2" = ">=2.10.1"
[dev-packages]
pylint = "*"

View File

@ -1,7 +1,7 @@
{
"_meta": {
"hash": {
"sha256": "0fd59e52429cbbc5e345259707a98d7c071a0a59ca709882d8b106321fb2191e"
"sha256": "a3c7e13ece64f4447d0bd3648257ca4117192e5d52ff7cdd4b4c2d3109ae6500"
},
"pipfile-spec": 6,
"requires": {
@ -26,11 +26,11 @@
},
"jinja2": {
"hashes": [
"sha256:74c935a1b8bb9a3947c50a54766a969d4846290e1e788ea44c1392163723c3bd",
"sha256:f84be1bb0040caca4cea721fcbbbbd61f9be9464ca236387158b0feea01914a4"
"sha256:065c4f02ebe7f7cf559e49ee5a95fb800a9e4528727aec6f24402a5374c65013",
"sha256:14dd6caf1527abb21f08f86c784eac40853ba93edb79552aa1e4b8aef1b61c7b"
],
"index": "pypi",
"version": "==2.10"
"version": "==2.10.1"
},
"markupsafe": {
"hashes": [
@ -83,10 +83,10 @@
},
"isort": {
"hashes": [
"sha256:18c796c2cd35eb1a1d3f012a214a542790a1aed95e29768bdcb9f2197eccbd0b",
"sha256:96151fca2c6e736503981896495d344781b60d18bfda78dc11b290c6125ebdb6"
"sha256:01cb7e1ca5e6c5b3f235f0385057f70558b70d2f00320208825fa62887292f43",
"sha256:268067462aed7eb2a1e237fcb287852f22077de3fb07964e87e00f829eea2d1a"
],
"version": "==4.3.15"
"version": "==4.3.17"
},
"lazy-object-proxy": {
"hashes": [
@ -146,28 +146,29 @@
},
"typed-ast": {
"hashes": [
"sha256:035a54ede6ce1380599b2ce57844c6554666522e376bd111eb940fbc7c3dad23",
"sha256:037c35f2741ce3a9ac0d55abfcd119133cbd821fffa4461397718287092d9d15",
"sha256:049feae7e9f180b64efacbdc36b3af64a00393a47be22fa9cb6794e68d4e73d3",
"sha256:19228f7940beafc1ba21a6e8e070e0b0bfd1457902a3a81709762b8b9039b88d",
"sha256:2ea681e91e3550a30c2265d2916f40a5f5d89b59469a20f3bad7d07adee0f7a6",
"sha256:3a6b0a78af298d82323660df5497bcea0f0a4a25a0b003afd0ce5af049bd1f60",
"sha256:5385da8f3b801014504df0852bf83524599df890387a3c2b17b7caa3d78b1773",
"sha256:606d8afa07eef77280c2bf84335e24390055b478392e1975f96286d99d0cb424",
"sha256:69245b5b23bbf7fb242c9f8f08493e9ecd7711f063259aefffaeb90595d62287",
"sha256:6f6d839ab09830d59b7fa8fb6917023d8cb5498ee1f1dbd82d37db78eb76bc99",
"sha256:730888475f5ac0e37c1de4bd05eeb799fdb742697867f524dc8a4cd74bcecc23",
"sha256:9819b5162ffc121b9e334923c685b0d0826154e41dfe70b2ede2ce29034c71d8",
"sha256:9e60ef9426efab601dd9aa120e4ff560f4461cf8442e9c0a2b92548d52800699",
"sha256:af5fbdde0690c7da68e841d7fc2632345d570768ea7406a9434446d7b33b0ee1",
"sha256:b64efdbdf3bbb1377562c179f167f3bf301251411eb5ac77dec6b7d32bcda463",
"sha256:bac5f444c118aeb456fac1b0b5d14c6a71ea2a42069b09c176f75e9bd4c186f6",
"sha256:bda9068aafb73859491e13b99b682bd299c1b5fd50644d697533775828a28ee0",
"sha256:d659517ca116e6750101a1326107d3479028c5191f0ecee3c7203c50f5b915b0",
"sha256:eddd3fb1f3e0f82e5915a899285a39ee34ce18fd25d89582bc89fc9fb16cd2c6"
"sha256:04894d268ba6eab7e093d43107869ad49e7b5ef40d1a94243ea49b352061b200",
"sha256:16616ece19daddc586e499a3d2f560302c11f122b9c692bc216e821ae32aa0d0",
"sha256:252fdae740964b2d3cdfb3f84dcb4d6247a48a6abe2579e8029ab3be3cdc026c",
"sha256:2af80a373af123d0b9f44941a46df67ef0ff7a60f95872412a145f4500a7fc99",
"sha256:2c88d0a913229a06282b285f42a31e063c3bf9071ff65c5ea4c12acb6977c6a7",
"sha256:2ea99c029ebd4b5a308d915cc7fb95b8e1201d60b065450d5d26deb65d3f2bc1",
"sha256:3d2e3ab175fc097d2a51c7a0d3fda442f35ebcc93bb1d7bd9b95ad893e44c04d",
"sha256:4766dd695548a15ee766927bf883fb90c6ac8321be5a60c141f18628fb7f8da8",
"sha256:56b6978798502ef66625a2e0f80cf923da64e328da8bbe16c1ff928c70c873de",
"sha256:5cddb6f8bce14325b2863f9d5ac5c51e07b71b462361fd815d1d7706d3a9d682",
"sha256:644ee788222d81555af543b70a1098f2025db38eaa99226f3a75a6854924d4db",
"sha256:64cf762049fc4775efe6b27161467e76d0ba145862802a65eefc8879086fc6f8",
"sha256:68c362848d9fb71d3c3e5f43c09974a0ae319144634e7a47db62f0f2a54a7fa7",
"sha256:6c1f3c6f6635e611d58e467bf4371883568f0de9ccc4606f17048142dec14a1f",
"sha256:b213d4a02eec4ddf622f4d2fbc539f062af3788d1f332f028a2e19c42da53f15",
"sha256:bb27d4e7805a7de0e35bd0cb1411bc85f807968b2b0539597a49a23b00a622ae",
"sha256:c9d414512eaa417aadae7758bc118868cd2396b0e6138c1dd4fda96679c079d3",
"sha256:f0937165d1e25477b01081c4763d2d9cdc3b18af69cb259dd4f640c9b900fe5e",
"sha256:fb96a6e2c11059ecf84e6741a319f93f683e440e341d4489c9b161eca251cf2a",
"sha256:fc71d2d6ae56a091a8d94f33ec9d0f2001d1cb1db423d8b4355debfe9ce689b7"
],
"markers": "implementation_name == 'cpython'",
"version": "==1.3.1"
"version": "==1.3.4"
},
"wrapt": {
"hashes": [

View File

@ -92,10 +92,17 @@ func GetOIDCUserByUserID(userID int) (*models.OIDCUser, error) {
return &oidcUsers[0], nil
}
// UpdateOIDCUser ...
// UpdateOIDCUser updates the OIDCUser based on the input parm, only the column "secret" and "token" can be updated
func UpdateOIDCUser(oidcUser *models.OIDCUser) error {
oidcUser.UpdateTime = time.Now()
_, err := GetOrmer().Update(oidcUser)
cols := []string{"secret", "token"}
_, err := GetOrmer().Update(oidcUser, cols...)
return err
}
// UpdateOIDCUserSecret updates the secret of the OIDC User. The secret in the input parm should be encrypted before
// calling this func
func UpdateOIDCUserSecret(oidcUser *models.OIDCUser) error {
_, err := GetOrmer().Update(oidcUser, "secret")
return err
}

View File

@ -80,15 +80,13 @@ func TestOIDCUserMetaDaoMethods(t *testing.T) {
ID: ou111.ID,
UserID: ou111.UserID,
SubIss: "newSub",
Secret: "newSecret",
}
require.Nil(t, UpdateOIDCUser(meta3))
oidcUser1Update, err := GetOIDCUserByID(ou111.ID)
require.Nil(t, err)
assert.Equal(t, "newSub", oidcUser1Update.SubIss)
user, err := GetUserBySubIss("new", "Sub")
require.Nil(t, err)
assert.Equal(t, "user111", user.Username)
assert.Equal(t, "QWE123123RT1", oidcUser1Update.SubIss)
assert.Equal(t, "newSecret", oidcUser1Update.Secret)
// clear data
defer func() {

View File

@ -38,6 +38,7 @@ type UserAPI struct {
SelfRegistration bool
IsAdmin bool
AuthMode string
secretKey string
}
type passwordReq struct {
@ -50,6 +51,10 @@ type userSearch struct {
Username string `json:"username"`
}
type secretResp struct {
Secret string `json:"secret"`
}
// Prepare validates the URL and parms
func (ua *UserAPI) Prepare() {
ua.BaseController.Prepare()
@ -61,6 +66,15 @@ func (ua *UserAPI) Prepare() {
}
ua.AuthMode = mode
if mode == common.OIDCAuth {
key, err := config.SecretKey()
if err != nil {
log.Errorf("failed to get secret key: %v", err)
ua.SendInternalServerError(fmt.Errorf("failed to get secret key: %v", err))
return
}
ua.secretKey = key
}
self, err := config.SelfRegistration()
if err != nil {
@ -475,17 +489,53 @@ func (ua *UserAPI) ListUserPermissions() {
return
}
func (ua *UserAPI) getOIDCUserInfo() (*models.OIDCUser, error) {
key, err := config.SecretKey()
if err != nil {
return nil, err
// GenCLISecret generates a new CLI secret and replace the old one
func (ua *UserAPI) GenCLISecret() {
if ua.AuthMode != common.OIDCAuth {
ua.SendPreconditionFailedError(errors.New("the auth mode has to be oidc auth"))
return
}
if ua.userID != ua.currentUserID && !ua.IsAdmin {
ua.SendForbiddenError(errors.New(""))
return
}
oidcData, err := dao.GetOIDCUserByUserID(ua.userID)
if err != nil {
log.Errorf("Failed to get OIDC User meta for user, id: %d, error: %v", ua.userID, err)
ua.SendInternalServerError(errors.New("failed to get OIDC meta data for user"))
return
}
if oidcData == nil {
log.Errorf("User is not onboarded via OIDC AuthN, user id: %d", ua.userID)
ua.SendPreconditionFailedError(errors.New("user is not onboarded via OIDC AuthN"))
return
}
sec := utils.GenerateRandomString()
encSec, err := utils.ReversibleEncrypt(sec, ua.secretKey)
if err != nil {
log.Errorf("Failed to encrypt secret, error: %v", err)
ua.SendInternalServerError(errors.New("failed to encrypt secret"))
return
}
oidcData.Secret = encSec
err = dao.UpdateOIDCUserSecret(oidcData)
if err != nil {
log.Errorf("Failed to update secret in DB, error: %v", err)
ua.SendInternalServerError(errors.New("failed to update secret in DB"))
return
}
ua.Data["json"] = secretResp{sec}
ua.ServeJSON()
}
func (ua *UserAPI) getOIDCUserInfo() (*models.OIDCUser, error) {
o, err := dao.GetOIDCUserByUserID(ua.userID)
if err != nil || o == nil {
return nil, err
}
if len(o.Secret) > 0 {
p, err := utils.ReversibleDecrypt(o.Secret, key)
p, err := utils.ReversibleDecrypt(o.Secret, ua.secretKey)
if err != nil {
return nil, err
}

View File

@ -53,6 +53,7 @@ func initRouters() {
beego.Router("/api/users/:id([0-9]+)/password", &api.UserAPI{}, "put:ChangePassword")
beego.Router("/api/users/:id/permissions", &api.UserAPI{}, "get:ListUserPermissions")
beego.Router("/api/users/:id/sysadmin", &api.UserAPI{}, "put:ToggleUserAdminRole")
beego.Router("/api/users/:id/gen_cli_secret", &api.UserAPI{}, "post:GenCLISecret")
beego.Router("/api/usergroups/?:ugid([0-9]+)", &api.UserGroupAPI{})
beego.Router("/api/ldap/ping", &api.LdapAPI{}, "post:Ping")
beego.Router("/api/ldap/users/search", &api.LdapAPI{}, "get:Search")

View File

@ -15,8 +15,8 @@
<div class="form-group">
<label class="form-group-label-override required">{{'DESTINATION.PROVIDER' | translate}}</label>
<div class="form-select">
<div class="select providerSelect pull-left">
<select name="adapter" id="adapter" [(ngModel)]="target.type" [disabled]="testOngoing || controlEnabled">
<div class="select inputWidth pull-left">
<select name="adapter" id="adapter" (change)="adapterChange($event)" [(ngModel)]="target.type" [disabled]="testOngoing || editDisabled">
<option *ngFor="let adapter of adapterList" value="{{adapter}}">{{adapter}}</option>
</select>
</div>
@ -29,7 +29,7 @@
<label class="col-md-8" for="destination_name" aria-haspopup="true" role="tooltip" [class.invalid]="targetName.errors && (targetName.dirty || targetName.touched)"
[class.valid]="targetName.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_name" [disabled]="testOngoing" [readonly]="!editable" [(ngModel)]="target.name"
name="targetName" size="20" #targetName="ngModel" required>
name="targetName" size="25" #targetName="ngModel" required>
<span class="tooltip-content" *ngIf="targetName.errors && targetName.errors.required && (targetName.dirty || targetName.touched)">
{{ 'DESTINATION.NAME_IS_REQUIRED' | translate }}
</span>
@ -46,8 +46,8 @@
translate }}</label>
<label class="col-md-8" for="destination_url" aria-haspopup="true" role="tooltip" [class.invalid]="targetEndpoint.errors && (targetEndpoint.dirty || targetEndpoint.touched)"
[class.valid]="targetEndpoint.valid" class="tooltip tooltip-validation tooltip-sm tooltip-bottom-left">
<input type="text" id="destination_url" [disabled]="testOngoing || controlEnabled" [readonly]="!editable" [(ngModel)]="target.url"
size="20" name="endpointUrl" #targetEndpoint="ngModel" required placeholder="http(s)://192.168.1.1">
<input type="text" id="destination_url" [disabled]="testOngoing || editDisabled || controlEnabled" [readonly]="!editable" [(ngModel)]="target.url"
size="25" name="endpointUrl" #targetEndpoint="ngModel" required placeholder="http(s)://192.168.1.1">
<span class="tooltip-content" *ngIf="targetEndpoint.errors && targetEndpoint.errors.required && (targetEndpoint.dirty || targetEndpoint.touched)">
{{ 'DESTINATION.URL_IS_REQUIRED' | translate }}
</span>
@ -58,14 +58,14 @@
<label for="destination_access_key" class="col-md-4 form-group-label-override">{{ 'DESTINATION.ACCESS_ID' |
translate }}</label>
<input type="text" placeholder="Access ID" class="col-md-8" id="destination_access_key" [disabled]="testOngoing" [readonly]="!editable"
[(ngModel)]="target.credential.access_key" size="23" name="access_key" #access_key="ngModel">
[(ngModel)]="target.credential.access_key" size="28" name="access_key" #access_key="ngModel">
</div>
<!-- access_secret -->
<div class="form-group">
<label for="destination_password" class="col-md-4 form-group-label-override">{{ 'DESTINATION.ACCESS_SECRET' |
translate }}</label>
<input type="password" placeholder="Access Secret" class="col-md-8" id="destination_password" [disabled]="testOngoing" [readonly]="!editable"
[(ngModel)]="target.credential.access_secret" size="23" name="access_secret" #access_secret="ngModel">
[(ngModel)]="target.credential.access_secret" size="28" name="access_secret" #access_secret="ngModel">
</div>
<!-- Verify Remote Cert -->
<div class="form-group">

View File

@ -12,10 +12,6 @@
height: 30px;
}
.providerSelect {
width: 180px;
}
.inputWidth {
width: 182px;
width: 216px;
}

View File

@ -32,7 +32,7 @@ import { Endpoint } from "../service/interface";
import { clone, compareValue, isEmptyObject } from "../utils";
const FAKE_PASSWORD = "rjGcfuRu";
const DOCKERHUB_URL = "https://registry-1.docker.io";
@Component({
selector: "hbr-create-edit-endpoint",
templateUrl: "./create-edit-endpoint.component.html",
@ -41,6 +41,7 @@ const FAKE_PASSWORD = "rjGcfuRu";
export class CreateEditEndpointComponent
implements AfterViewChecked, OnDestroy, OnInit {
modalTitle: string;
editDisabled: boolean = false;
controlEnabled: boolean = false;
createEditDestinationOpened: boolean;
staticBackdrop: boolean = true;
@ -178,7 +179,7 @@ export class CreateEditEndpointComponent
// Open the modal now
this.open();
this.controlEnabled = true;
this.editDisabled = true;
this.forceRefreshView(2000);
},
error => this.errorHandler.error(error)
@ -190,6 +191,17 @@ export class CreateEditEndpointComponent
.subscribe(res => (this.modalTitle = res));
// Directly open the modal
this.open();
this.editDisabled = false;
}
}
adapterChange($event): void {
let selectValue = this.targetForm.controls.adapter.value;
if (selectValue === 'dockerHub') {
this.targetForm.controls.endpointUrl.setValue(DOCKERHUB_URL);
this.controlEnabled = true;
} else {
this.targetForm.controls.endpointUrl.setValue("");
this.controlEnabled = false;
}
}

View File

@ -474,9 +474,7 @@ export class ReplicationComponent implements OnInit, OnDestroy {
if (!j) {
return;
}
if (j.status === "Failed") {
return "-";
}
let start_time = new Date(j.start_time).getTime();
let end_time = new Date(j.end_time).getTime();
let timesDiff = end_time - start_time;

View File

@ -3,7 +3,3 @@ IP=`ip addr s eth0 |grep "inet "|awk '{print $2}' |awk -F "/" '{print $1}'`
#echo $IP
sudo sed "s/reg.mydomain.com/$IP/" -i make/harbor.yml
echo "https:" >> make/harbor.yml
echo " certificate: /data/cert/server.crt" >> make/harbor.yml
echo " private_key: /data/cert/server.key" >> make/harbor.yml

View File

@ -18,22 +18,18 @@ Resource ../../resources/Util.robot
*** Keywords ***
View Repo Scan Details
Click Element xpath=${first_repo_xpath}
Sleep 2
Retry Element Click xpath=${first_repo_xpath}
Capture Page Screenshot viewcve1.png
Wait Until Page Contains unknown
Wait Until Page Contains high
Wait Until Page Contains medium
Page Should Contain CVE
Sleep 2
Click Element xpath=${build_history_btn}
Sleep 1
Page Should Contain Element xpath=${build_history_data}
Retry Wait Until Page Contains unknown
Retry Wait Until Page Contains high
Retry Wait Until Page Contains medium
Retry Wait Until Page Contains CVE
Retry Element Click xpath=${build_history_btn}
Retry Wait Until Page Contains Element xpath=${build_history_data}
View Scan Error Log
Page Should Contain View Log
Click Element xpath=${view_log_xpath}
Sleep 1
Retry Wait Until Page Contains View Log
Retry Element Click xpath=${view_log_xpath}
Capture Page Screenshot viewlog.png

View File

@ -21,11 +21,11 @@ ${HARBOR_VERSION} v1.1.1
*** Keywords ***
Check New Rule UI Without Endpoint
Click Element ${new_replication-rule_button}
Page Should Contain Please add an endpoint first
Mouse Down ${link_to_registries}
Mouse Up ${link_to_registries}
Page Should Contain Endpoint Name
Retry Element Click ${new_replication-rule_button}
Page Should Contain Please add an endpoint first
Retry Element Click ${link_to_registries}
Retry Wait Until Page Contains Endpoint URL
Retry Wait Element ${new_endpoint_button}
Create A New Endpoint
[Arguments] ${name} ${url} ${username} ${pwd} ${save}=Y

View File

@ -31,7 +31,7 @@ ${destination_insecure_xpath} //label[@id='destination_insecure_checkbox']
${new_replication-rule_button} //button[contains(.,'New Replication Rule')]
${link_to_registries} //clr-modal//span[contains(.,'Endpoint')]
${new_endpoint_button} //hbr-endpoint//button[contains(.,'New')]
${new_endpoint_button} //hbr-endpoint//button[contains(.,'New Endpoint')]
${rule_name} //input[@id='ruleName']
${source_project} //input[@value='name']
${source_image_filter_add} //hbr-create-edit-rule/clr-modal//clr-icon[@id='add-label-list']

View File

@ -34,3 +34,10 @@ ${REMOTE_SERVER_API_ENDPOINT} ${REMOTE_SERVER_URL}/api
Test Case - Get Harbor Version
#Just get harbor version and log it
Get Harbor Version
Test Case - Pro Replication Rules Add
Init Chrome Driver
Sign In Harbor ${HARBOR_URL} ${HARBOR_ADMIN} ${HARBOR_PASSWORD}
Switch To Replication Manage
Check New Rule UI Without Endpoint
Close Browser