Add UI for viewing and changing trust setting in repo
This commit is contained in:
parent
dec14647a8
commit
14054a237a
7 changed files with 161 additions and 23 deletions
16
static/css/directives/ui/repository-signing-config.css
Normal file
16
static/css/directives/ui/repository-signing-config.css
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
.repository-signing-config-element td {
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repository-signing-config-element .status-icon {
|
||||||
|
font-size: 48px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repository-signing-config-element .status-icon.ci-shield-check-outline {
|
||||||
|
color: #2FC98E;
|
||||||
|
}
|
||||||
|
|
||||||
|
.repository-signing-config-element .status-icon.ci-shield-none {
|
||||||
|
color: #9B9B9B;
|
||||||
|
}
|
|
@ -18,6 +18,11 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Signing and Trust -->
|
||||||
|
<div ng-if="repository.kind == 'image'">
|
||||||
|
<repository-signing-config repository="repository"></repository-signing-config>
|
||||||
|
</div>
|
||||||
|
|
||||||
<!-- Events and Notifications -->
|
<!-- Events and Notifications -->
|
||||||
<div ng-if="repository.kind == 'image'">
|
<div ng-if="repository.kind == 'image'">
|
||||||
<div class="repository-events-table" repository="repository"
|
<div class="repository-events-table" repository="repository"
|
||||||
|
|
|
@ -0,0 +1,65 @@
|
||||||
|
<div class="repository-signing-config-element" quay-require="['SIGNING']">
|
||||||
|
<div class="repository-events-table-element">
|
||||||
|
<div class="co-panel">
|
||||||
|
<div class="co-panel-heading">
|
||||||
|
<i class="fa ci-shield-check-full"></i> Trust and Signing
|
||||||
|
</div>
|
||||||
|
<div class="panel-body">
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<i class="fa status-icon"
|
||||||
|
ng-class="{'ci-shield-check-outline': $ctrl.repository.trust_enabled, 'ci-shield-none': !$ctrl.repository.trust_enabled}"></i>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<div ng-if="$ctrl.repository.trust_enabled">
|
||||||
|
<h4>Content Trust Enabled</h4>
|
||||||
|
<p>
|
||||||
|
Content Trust and Signing is enabled on this repository and all tag operations must be signed via Docker Content Trust.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Note that due to this feature being enabled, all UI-based tag operations and all build support is <strong>disabled on this repository</strong>.
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-danger" ng-click="$ctrl.askChangeTrust(false)">Disable Content Trust</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div ng-if="!$ctrl.repository.trust_enabled">
|
||||||
|
<h4>Content Trust Disabled</h4>
|
||||||
|
<p>
|
||||||
|
Content Trust and Signing is disabled on this repository.
|
||||||
|
</p>
|
||||||
|
<button class="btn btn-default" ng-click="$ctrl.askChangeTrust(true)">Enable Content Trust</button>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Change trust dialogs -->
|
||||||
|
<div class="cor-confirm-dialog"
|
||||||
|
dialog-context="$ctrl.enableTrustInfo"
|
||||||
|
dialog-action="$ctrl.changeTrust(true, callback)"
|
||||||
|
dialog-title="Enable Content Trust"
|
||||||
|
dialog-action-title="Enable Trust">
|
||||||
|
<p>Click "Enable Trust" to enable content trust on this repository.</p>
|
||||||
|
<p>Please note that at this time, having content trust will <strong>disable</strong> the following
|
||||||
|
features under the repository:
|
||||||
|
<ul>
|
||||||
|
<li>Any tag operations in the UI (Add Tag, Delete Tag, Restore Tag)
|
||||||
|
<li>All build triggers and ability to invoke builds
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="cor-confirm-dialog"
|
||||||
|
dialog-context="$ctrl.disableTrustInfo"
|
||||||
|
dialog-action="$ctrl.changeTrust(false, callback)"
|
||||||
|
dialog-title="Disable Content Trust"
|
||||||
|
dialog-action-title="Disable Trust and Delete Data">
|
||||||
|
<div class="co-alert co-alert-warning">
|
||||||
|
<strong>Warning:</strong> Disabling content trust will prevent users from pushing signed
|
||||||
|
manifests to this repository and will <strong>delete all existing signing and trust data</strong>.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { Input, Component, Inject } from 'ng-metadata/core';
|
||||||
|
import { Repository } from '../../../types/common.types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A component that displays the configuration and options for repository signing.
|
||||||
|
*/
|
||||||
|
@Component({
|
||||||
|
selector: 'repository-signing-config',
|
||||||
|
templateUrl: '/static/js/directives/ui/repository-signing-config/repository-signing-config.component.html',
|
||||||
|
})
|
||||||
|
export class RepositorySigningConfigComponent {
|
||||||
|
@Input('<') public repository: Repository;
|
||||||
|
|
||||||
|
private enableTrustInfo: {[key: string]: string} = null;
|
||||||
|
private disableTrustInfo: {[key: string]: string} = null;
|
||||||
|
|
||||||
|
constructor (@Inject("ApiService") private ApiService: any) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private askChangeTrust(newState: boolean) {
|
||||||
|
if (newState) {
|
||||||
|
this.enableTrustInfo = {};
|
||||||
|
} else {
|
||||||
|
this.disableTrustInfo = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private changeTrust(newState: boolean, callback: (success: boolean) => void) {
|
||||||
|
var params = {
|
||||||
|
'repository': this.repository.namespace + '/' + this.repository.name,
|
||||||
|
};
|
||||||
|
|
||||||
|
var data = {
|
||||||
|
'trust_enabled': newState,
|
||||||
|
};
|
||||||
|
|
||||||
|
var errorDisplay = this.ApiService.errorDisplay('Could not just change trust', callback);
|
||||||
|
this.ApiService.changeRepoTrust(data, params).then((resp) => {
|
||||||
|
this.repository.trust_enabled = newState;
|
||||||
|
callback(true);
|
||||||
|
}, errorDisplay);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,25 +1,7 @@
|
||||||
import { Input, Component, Inject } from 'ng-metadata/core';
|
import { Input, Component, Inject } from 'ng-metadata/core';
|
||||||
|
import { ApostilleSignatureDocument, ApostilleTagDocument } from '../../../types/common.types';
|
||||||
import * as moment from "moment";
|
import * as moment from "moment";
|
||||||
|
|
||||||
interface ApostilleSignatureDocument {
|
|
||||||
// When the signed document expires.
|
|
||||||
expiration: string
|
|
||||||
|
|
||||||
// Object of information for each tag.
|
|
||||||
tags: {string: ApostilleTagDocument}
|
|
||||||
|
|
||||||
// If true, an error occurred while trying to load this document.
|
|
||||||
error: boolean
|
|
||||||
}
|
|
||||||
|
|
||||||
interface ApostilleTagDocument {
|
|
||||||
// The length of the document.
|
|
||||||
length: number
|
|
||||||
|
|
||||||
// The hashes for the tag.
|
|
||||||
hashes: {string: string}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A component that displays the signing status of a tag in the repository view.
|
* A component that displays the signing status of a tag in the repository view.
|
||||||
*/
|
*/
|
||||||
|
@ -29,14 +11,12 @@ interface ApostilleTagDocument {
|
||||||
})
|
})
|
||||||
export class TagSigningDisplayComponent {
|
export class TagSigningDisplayComponent {
|
||||||
@Input('<') public tag: any;
|
@Input('<') public tag: any;
|
||||||
@Input('=') public signatures: ApostilleSignatureDocument;
|
@Input('<') public signatures: ApostilleSignatureDocument;
|
||||||
|
|
||||||
private signedDigest: string;
|
private signedDigest: string;
|
||||||
private pushedDigest: string;
|
private pushedDigest: string;
|
||||||
|
|
||||||
constructor (@Inject("$sanitize") private $sanitize: ng.sanitize.ISanitizeService) {
|
constructor(@Inject("$sanitize") private $sanitize: ng.sanitize.ISanitizeService) {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private base64ToHex(base64String: string): string {
|
private base64ToHex(base64String: string): string {
|
||||||
// Based on: http://stackoverflow.com/questions/39460182/decode-base64-to-hexadecimal-string-with-javascript
|
// Based on: http://stackoverflow.com/questions/39460182/decode-base64-to-hexadecimal-string-with-javascript
|
||||||
|
|
|
@ -15,6 +15,7 @@ import { CorTableComponent } from './directives/ui/cor-table/cor-table.component
|
||||||
import { CorTableColumn } from './directives/ui/cor-table/cor-table-col.component';
|
import { CorTableColumn } from './directives/ui/cor-table/cor-table-col.component';
|
||||||
import { ChannelIconComponent } from './directives/ui/channel-icon/channel-icon.component';
|
import { ChannelIconComponent } from './directives/ui/channel-icon/channel-icon.component';
|
||||||
import { TagSigningDisplayComponent } from './directives/ui/tag-signing-display/tag-signing-display.component';
|
import { TagSigningDisplayComponent } from './directives/ui/tag-signing-display/tag-signing-display.component';
|
||||||
|
import { RepositorySigningConfigComponent } from './directives/ui/repository-signing-config/repository-signing-config.component';
|
||||||
import { BuildServiceImpl } from './services/build/build.service.impl';
|
import { BuildServiceImpl } from './services/build/build.service.impl';
|
||||||
import { AvatarServiceImpl } from './services/avatar/avatar.service.impl';
|
import { AvatarServiceImpl } from './services/avatar/avatar.service.impl';
|
||||||
import { DockerfileServiceImpl } from './services/dockerfile/dockerfile.service.impl';
|
import { DockerfileServiceImpl } from './services/dockerfile/dockerfile.service.impl';
|
||||||
|
@ -46,6 +47,7 @@ import { QuayRequireDirective } from './directives/structural/quay-require/quay-
|
||||||
ChannelIconComponent,
|
ChannelIconComponent,
|
||||||
QuayRequireDirective,
|
QuayRequireDirective,
|
||||||
TagSigningDisplayComponent,
|
TagSigningDisplayComponent,
|
||||||
|
RepositorySigningConfigComponent,
|
||||||
],
|
],
|
||||||
providers: [
|
providers: [
|
||||||
ViewArrayImpl,
|
ViewArrayImpl,
|
||||||
|
|
|
@ -79,6 +79,7 @@ export type Repository = {
|
||||||
private: boolean;
|
private: boolean;
|
||||||
url: string;
|
url: string;
|
||||||
namespace?: string;
|
namespace?: string;
|
||||||
|
trust_enabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -101,4 +102,29 @@ export type Namespace = {
|
||||||
export type Trigger = {
|
export type Trigger = {
|
||||||
id: number;
|
id: number;
|
||||||
service: any;
|
service: any;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents an apostille signature document, with extra expiration information.
|
||||||
|
*/
|
||||||
|
export type ApostilleSignatureDocument = {
|
||||||
|
// When the signed document expires.
|
||||||
|
expiration: string
|
||||||
|
|
||||||
|
// Object of information for each tag.
|
||||||
|
tags: {string: ApostilleTagDocument}
|
||||||
|
|
||||||
|
// If true, an error occurred while trying to load this document.
|
||||||
|
error: boolean
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An apostille document containing signatures for a tag.
|
||||||
|
*/
|
||||||
|
export type ApostilleTagDocument = {
|
||||||
|
// The length of the document.
|
||||||
|
length: number
|
||||||
|
|
||||||
|
// The hashes for the tag.
|
||||||
|
hashes: {string: string}
|
||||||
};
|
};
|
Reference in a new issue