Fix Trigger Setup Robot Permissions for Private Base (#2543)
This commit is contained in:
parent
2f757faa40
commit
581d7c67a7
5 changed files with 210 additions and 91 deletions
|
@ -356,7 +356,10 @@
|
||||||
total-count="$ctrl.local.orderedRobotAccounts.entries.length"
|
total-count="$ctrl.local.orderedRobotAccounts.entries.length"
|
||||||
current-page="$ctrl.local.robotOptions.page"
|
current-page="$ctrl.local.robotOptions.page"
|
||||||
page-size="$ctrl.robotsPerPage"></span>
|
page-size="$ctrl.robotsPerPage"></span>
|
||||||
<input class="form-control" type="text" ng-model="$ctrl.local.robotOptions.filter" placeholder="Filter robot accounts...">
|
<input class="form-control"
|
||||||
|
type="text"
|
||||||
|
ng-model="$ctrl.local.robotOptions.filter"
|
||||||
|
placeholder="Filter robot accounts...">
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -1,27 +1,30 @@
|
||||||
import { ManageTriggerGithostComponent, Local, Trigger } from './manage-trigger-githost.component';
|
import { ManageTriggerGithostComponent } from './manage-trigger-githost.component';
|
||||||
|
import { Local, Trigger, Repository } from '../../../types/common.types';
|
||||||
|
import { Mock } from 'ts-mocks';
|
||||||
|
import Spy = jasmine.Spy;
|
||||||
|
|
||||||
|
|
||||||
describe("ManageTriggerGithostComponent", () => {
|
describe("ManageTriggerGithostComponent", () => {
|
||||||
var component: ManageTriggerGithostComponent;
|
var component: ManageTriggerGithostComponent;
|
||||||
var apiServiceMock: any;
|
var apiServiceMock: Mock<any>;
|
||||||
var tableServiceMock: any;
|
var tableServiceMock: Mock<any>;
|
||||||
var triggerServiceMock: any;
|
var triggerServiceMock: Mock<any>;
|
||||||
var rolesServiceMock: any;
|
var rolesServiceMock: Mock<any>;
|
||||||
var repository: any;
|
var repository: any;
|
||||||
var trigger: Trigger;
|
var trigger: Trigger;
|
||||||
var $scope: ng.IScope;
|
var $scopeMock: Mock<ng.IScope>;
|
||||||
|
|
||||||
beforeEach(inject(($injector: ng.auto.IInjectorService) => {
|
beforeEach(inject(($injector: ng.auto.IInjectorService) => {
|
||||||
apiServiceMock = jasmine.createSpyObj('apiServiceMock', ['listTriggerBuildSourceNamespaces']);
|
apiServiceMock = new Mock<any>();
|
||||||
tableServiceMock = jasmine.createSpyObj('tableServiceMock', ['buildOrderedItems']);
|
tableServiceMock = new Mock<any>();
|
||||||
triggerServiceMock = jasmine.createSpyObj('triggerServiceMock', ['getIcon']);
|
triggerServiceMock = new Mock<any>();
|
||||||
rolesServiceMock = jasmine.createSpyObj('rolesServiceMock', ['setRepositoryRole']);
|
rolesServiceMock = new Mock<any>();
|
||||||
$scope = $injector.get('$rootScope');
|
$scopeMock = new Mock<ng.IScope>();
|
||||||
component = new ManageTriggerGithostComponent(apiServiceMock,
|
component = new ManageTriggerGithostComponent(apiServiceMock.Object,
|
||||||
tableServiceMock,
|
tableServiceMock.Object,
|
||||||
triggerServiceMock,
|
triggerServiceMock.Object,
|
||||||
rolesServiceMock,
|
rolesServiceMock.Object,
|
||||||
$scope);
|
$scopeMock.Object);
|
||||||
trigger = {service: "serviceMock", id: 1};
|
trigger = {service: "serviceMock", id: 1};
|
||||||
component.trigger = trigger;
|
component.trigger = trigger;
|
||||||
}));
|
}));
|
||||||
|
@ -36,14 +39,75 @@ describe("ManageTriggerGithostComponent", () => {
|
||||||
|
|
||||||
describe("getTriggerIcon", () => {
|
describe("getTriggerIcon", () => {
|
||||||
|
|
||||||
it("calls trigger service to get icon", () => {
|
beforeEach(() => {
|
||||||
component.getTriggerIcon();
|
triggerServiceMock.setup(mock => mock.getIcon).is((service: any) => null);
|
||||||
|
});
|
||||||
|
|
||||||
expect(triggerServiceMock.getIcon.calls.argsFor(0)[0]).toEqual(component.trigger.service);
|
it("calls trigger service to get icon", () => {
|
||||||
|
const icon: any = component.getTriggerIcon();
|
||||||
|
|
||||||
|
expect((<Spy>triggerServiceMock.Object.getIcon).calls.argsFor(0)[0]).toEqual(component.trigger.service);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("createTrigger", () => {
|
describe("createTrigger", () => {
|
||||||
// TODO
|
|
||||||
|
beforeEach(() => {
|
||||||
|
component.local.selectedRepository = new Mock<Repository>().Object;
|
||||||
|
component.local.selectedRepository.full_name = "someorg/some-repository";
|
||||||
|
component.local.dockerfilePath = "/Dockerfile";
|
||||||
|
component.local.dockerContext = "/";
|
||||||
|
component.local.triggerOptions = {};
|
||||||
|
component.local.triggerAnalysis = {};
|
||||||
|
rolesServiceMock.setup(mock => mock.setRepositoryRole).is((repo, role, entityKind, entityName, callback) => {
|
||||||
|
callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("calls roles service to grant read access to selected robot if robot is required and cannot read", (done) => {
|
||||||
|
component.local.triggerAnalysis = {status: 'requiresrobot', name: 'privatebase', namespace: 'someorg'};
|
||||||
|
component.local.robotAccount = {can_read: false, is_robot: true, kind: 'user', name: 'test-robot'};
|
||||||
|
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||||
|
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[0]).toEqual({
|
||||||
|
name: component.local.triggerAnalysis.name,
|
||||||
|
namespace: component.local.triggerAnalysis.namespace,
|
||||||
|
});
|
||||||
|
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[1]).toEqual('read');
|
||||||
|
expect((<Spy>rolesServiceMock.Object.setRepositoryRole).calls.argsFor(0)[2]).toEqual('robot');
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.createTrigger();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not call roles service if robot is required but already has read access", (done) => {
|
||||||
|
component.local.robotAccount = {can_read: true, is_robot: true, kind: 'user', name: 'test-robot'};
|
||||||
|
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||||
|
expect((<Spy>rolesServiceMock.Object.setRepositoryRole)).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.createTrigger();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("does not call roles service if robot is not required", (done) => {
|
||||||
|
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||||
|
expect((<Spy>rolesServiceMock.Object.setRepositoryRole)).not.toHaveBeenCalled();
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.createTrigger();
|
||||||
|
});
|
||||||
|
|
||||||
|
it("emits output event with config and pull robot", (done) => {
|
||||||
|
component.activateTrigger.subscribe((event: {config: any, pull_robot: any}) => {
|
||||||
|
expect(event.config.build_source).toEqual(component.local.selectedRepository.full_name);
|
||||||
|
expect(event.config.dockerfile_path).toEqual(component.local.dockerfilePath);
|
||||||
|
expect(event.config.context).toEqual(component.local.dockerContext);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
|
||||||
|
component.createTrigger();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
|
@ -1,5 +1,6 @@
|
||||||
import { Input, Output, Component, Inject, EventEmitter, OnInit } from 'ng-metadata/core';
|
import { Input, Output, Component, Inject, EventEmitter, OnInit } from 'ng-metadata/core';
|
||||||
import * as moment from 'moment';
|
import * as moment from 'moment';
|
||||||
|
import { Local, Trigger, Repository, Namespace } from '../../../types/common.types';
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,30 +13,14 @@ import * as moment from 'moment';
|
||||||
export class ManageTriggerGithostComponent implements OnInit {
|
export class ManageTriggerGithostComponent implements OnInit {
|
||||||
|
|
||||||
// FIXME: Use one-way data binding
|
// FIXME: Use one-way data binding
|
||||||
@Input('=') public repository: any;
|
@Input('=') public repository: Repository;
|
||||||
@Input('=') public trigger: Trigger;
|
@Input('=') public trigger: Trigger;
|
||||||
@Output() public activateTrigger: EventEmitter<{config: any, pull_robot?: any}> = new EventEmitter();
|
@Output() public activateTrigger: EventEmitter<{config: any, pull_robot?: any}> = new EventEmitter();
|
||||||
private config: any;
|
public config: any;
|
||||||
private local: any = {
|
public local: Local = {
|
||||||
namespaceOptions: {
|
namespaceOptions: {filter: '', predicate: 'score', reverse: false, page: 0},
|
||||||
filter: '',
|
repositoryOptions: {filter: '', predicate: 'score', reverse: false, page: 0, hideStale: true},
|
||||||
predicate: 'score',
|
robotOptions: {filter: '', predicate: 'score', reverse: false, page: 0},
|
||||||
reverse: false,
|
|
||||||
page: 0
|
|
||||||
},
|
|
||||||
repositoryOptions: {
|
|
||||||
filter: '',
|
|
||||||
predicate: 'score',
|
|
||||||
reverse: false,
|
|
||||||
page: 0,
|
|
||||||
hideStale: true
|
|
||||||
},
|
|
||||||
robotOptions: {
|
|
||||||
filter: '',
|
|
||||||
predicate: 'score',
|
|
||||||
reverse: false,
|
|
||||||
page: 0
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
private currentState: any | null;
|
private currentState: any | null;
|
||||||
private namespacesPerPage: number = 10;
|
private namespacesPerPage: number = 10;
|
||||||
|
@ -128,23 +113,21 @@ export class ManageTriggerGithostComponent implements OnInit {
|
||||||
context: this.local.dockerContext
|
context: this.local.dockerContext
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.local.triggerOptions.hasBranchTagFilter &&
|
if (this.local.triggerOptions['hasBranchTagFilter'] && this.local.triggerOptions['branchTagFilter']) {
|
||||||
this.local.triggerOptions.branchTagFilter) {
|
config['branchtag_regex'] = this.local.triggerOptions['branchTagFilter'];
|
||||||
config['branchtag_regex'] = this.local.triggerOptions.branchTagFilter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var activate = () => {
|
const activate = () => {
|
||||||
this.activateTrigger.emit({config: config, pull_robot: this.local.robotAccount});
|
this.activateTrigger.emit({config: config, pull_robot: this.local.robotAccount});
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.local.robotAccount && this.local.triggerAnalysis.status == 'requiresrobot') {
|
if (this.local.triggerAnalysis.status == 'requiresrobot' && this.local.robotAccount) {
|
||||||
if (this.local.robotAccount.can_read) {
|
if (this.local.robotAccount.can_read) {
|
||||||
activate();
|
activate();
|
||||||
} else {
|
} else {
|
||||||
// Add read permission onto the base repository for the robot and then activate the
|
// Add read permission onto the base repository for the robot and then activate the trigger.
|
||||||
// trigger.
|
const baseRepo: any = {name: this.local.triggerAnalysis.name, namespace: this.local.triggerAnalysis.namespace};
|
||||||
var robot_name = this.local.robotAccount.name;
|
this.RolesService.setRepositoryRole(baseRepo, 'read', 'robot', this.local.robotAccount.name, activate);
|
||||||
this.RolesService.setRepositoryRole(this.repository, 'read', 'robot', robot_name, activate);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
activate();
|
activate();
|
||||||
|
@ -156,7 +139,7 @@ export class ManageTriggerGithostComponent implements OnInit {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var namespaces = this.local.namespaces || [];
|
var namespaces: Namespace[] = this.local.namespaces || [];
|
||||||
this.local.orderedNamespaces = this.TableService.buildOrderedItems(namespaces,
|
this.local.orderedNamespaces = this.TableService.buildOrderedItems(namespaces,
|
||||||
this.local.namespaceOptions,
|
this.local.namespaceOptions,
|
||||||
['id'],
|
['id'],
|
||||||
|
@ -305,9 +288,9 @@ export class ManageTriggerGithostComponent implements OnInit {
|
||||||
|
|
||||||
var robots = this.local.triggerAnalysis.robots;
|
var robots = this.local.triggerAnalysis.robots;
|
||||||
this.local.orderedRobotAccounts = this.TableService.buildOrderedItems(robots,
|
this.local.orderedRobotAccounts = this.TableService.buildOrderedItems(robots,
|
||||||
this.local.robotOptions,
|
this.local.robotOptions,
|
||||||
['name'],
|
['name'],
|
||||||
[]);
|
[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkDockerfilePath(repository: any, path: string, context: string): void {
|
private checkDockerfilePath(repository: any, path: string, context: string): void {
|
||||||
|
@ -342,38 +325,3 @@ export class ManageTriggerGithostComponent implements OnInit {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A type representing local application data.
|
|
||||||
*/
|
|
||||||
export type Local = {
|
|
||||||
namespaceOptions: {
|
|
||||||
filter: string;
|
|
||||||
predicate: string;
|
|
||||||
reverse: boolean;
|
|
||||||
page: number;
|
|
||||||
};
|
|
||||||
repositoryOptions: {
|
|
||||||
filter: string;
|
|
||||||
predicate: string;
|
|
||||||
reverse: boolean;
|
|
||||||
page: number;
|
|
||||||
hideStale: boolean;
|
|
||||||
};
|
|
||||||
robotOptions: {
|
|
||||||
filter: string;
|
|
||||||
predicate: string;
|
|
||||||
reverse: boolean;
|
|
||||||
page: number;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A type representing a trigger.
|
|
||||||
*/
|
|
||||||
export type Trigger = {
|
|
||||||
id: number;
|
|
||||||
service: any;
|
|
||||||
};
|
|
104
static/js/types/common.types.ts
Normal file
104
static/js/types/common.types.ts
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
import { ViewArray } from '../services/view-array/view-array';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing local application data.
|
||||||
|
*/
|
||||||
|
export type Local = {
|
||||||
|
contexts?: string[];
|
||||||
|
dockerContext?: string;
|
||||||
|
dockerfileLocations?: any;
|
||||||
|
dockerfilePath?: string;
|
||||||
|
hasValidContextLocation?: boolean;
|
||||||
|
hasValidDockerfilePath?: boolean;
|
||||||
|
maxScore?: number;
|
||||||
|
namespaceOptions?: {
|
||||||
|
filter: string;
|
||||||
|
predicate: string;
|
||||||
|
reverse: boolean;
|
||||||
|
page: number;
|
||||||
|
};
|
||||||
|
namespaces?: Namespace[];
|
||||||
|
orderedNamespaces?: ViewArray;
|
||||||
|
orderedRepositories?: ViewArray;
|
||||||
|
orderedRobotAccounts?: ViewArray;
|
||||||
|
repositories?: Repository[];
|
||||||
|
repositoryFullRefs?: {
|
||||||
|
icon: string;
|
||||||
|
title: string;
|
||||||
|
value: string;
|
||||||
|
}[];
|
||||||
|
repositoryOptions?: {
|
||||||
|
filter: string;
|
||||||
|
predicate: string;
|
||||||
|
reverse: boolean;
|
||||||
|
page: number;
|
||||||
|
hideStale: boolean;
|
||||||
|
};
|
||||||
|
repositoryRefs?: {
|
||||||
|
kind: string;
|
||||||
|
name: string;
|
||||||
|
}[];
|
||||||
|
robotAccount?: RobotAccount;
|
||||||
|
robotOptions?: {
|
||||||
|
filter: string;
|
||||||
|
predicate: string;
|
||||||
|
reverse: boolean;
|
||||||
|
page: number;
|
||||||
|
};
|
||||||
|
selectedNamespace?: Namespace;
|
||||||
|
selectedRepository?: Repository;
|
||||||
|
triggerAnalysis?: any;
|
||||||
|
triggerOptions?: {
|
||||||
|
[key: string]: boolean;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing a robot account.
|
||||||
|
*/
|
||||||
|
export type RobotAccount = {
|
||||||
|
can_read: boolean;
|
||||||
|
is_robot: boolean;
|
||||||
|
kind: string;
|
||||||
|
name: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing a Git repository.
|
||||||
|
*/
|
||||||
|
export type Repository = {
|
||||||
|
description: string;
|
||||||
|
full_name: string;
|
||||||
|
has_admin_permissions: boolean;
|
||||||
|
last_updated: number;
|
||||||
|
last_updated_datetime: Date;
|
||||||
|
name: string;
|
||||||
|
private: boolean;
|
||||||
|
url: string;
|
||||||
|
namespace?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing a repository namespace.
|
||||||
|
*/
|
||||||
|
export type Namespace = {
|
||||||
|
avatar_url: string;
|
||||||
|
id: string;
|
||||||
|
personal: boolean;
|
||||||
|
score: number;
|
||||||
|
title: string;
|
||||||
|
url: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A type representing a trigger.
|
||||||
|
*/
|
||||||
|
export type Trigger = {
|
||||||
|
id: number;
|
||||||
|
service: any;
|
||||||
|
};
|
Binary file not shown.
Reference in a new issue