Unverified Commit 5d24c99f authored by bugclerk's avatar bugclerk Committed by GitHub
Browse files

NAS-127086 / 24.04-RC.1 / Missing permission checks in Apps (by undsoft) (#9565)


* Empty commit to create PR on github.

You should reset it

* NAS-127086: Missing permission checks in Apps

---------
Co-authored-by: default avatarEvgeny Stepanovych <undsoft@gmail.com>
Showing with 69 additions and 24 deletions
+69 -24
......@@ -7,11 +7,6 @@
pointer-events: none;
}
.mat-mdc-button,
.mdc-button {
margin-right: 8px;
}
.mdc-label {
text-decoration: line-through;
}
......
......@@ -11,15 +11,17 @@
<div class="app-image-holder">
<ix-app-card-logo [url]="app?.icon_url"></ix-app-card-logo>
</div>
<button
*ngIf="!(kubernetesStore.selectedPool$ | async)"
mat-button
color="primary"
ixTest="setup-pool"
(click)="showChoosePoolModal()"
>
{{ 'Setup Pool To Install' | translate }}
</button>
<ng-container *ngIf="!(kubernetesStore.selectedPool$ | async)">
<button
*ixRequiresRoles="setupPoolRequiredRoles"
mat-button
color="primary"
ixTest="setup-pool"
(click)="showChoosePoolModal()"
>
{{ 'Setup Pool To Install' | translate }}
</button>
</ng-container>
<button
*ngIf="!!(kubernetesStore.selectedPool$ | async)"
mat-button
......
......@@ -8,6 +8,7 @@ import { TranslateService } from '@ngx-translate/core';
import {
filter, map, Observable, of, switchMap, take,
} from 'rxjs';
import { Role } from 'app/enums/role.enum';
import { AvailableApp } from 'app/interfaces/available-app.interface';
import { SelectPoolDialogComponent } from 'app/pages/apps/components/select-pool-dialog/select-pool-dialog.component';
import { InstalledAppsStore } from 'app/pages/apps/store/installed-apps-store.service';
......@@ -27,6 +28,8 @@ export class AppDetailsHeaderComponent {
@Input() app: AvailableApp;
@Input() isLoading$: Observable<boolean>;
protected readonly setupPoolRequiredRoles = [Role.KubernetesWrite];
constructor(
public kubernetesStore: KubernetesStore,
private router: Router,
......
......@@ -42,6 +42,7 @@
<ix-form-actions>
<button
*ixRequiresRoles="requiredRoles"
mat-button
type="submit"
color="primary"
......
......@@ -5,6 +5,7 @@ import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonHarness } from '@angular/material/button/testing';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { mockJob, mockWebsocket } from 'app/core/testing/utils/mock-websocket.utils';
import { EntityJobComponent } from 'app/modules/entity/entity-job/entity-job.component';
import { IxSlideInRef } from 'app/modules/ix-forms/components/ix-slide-in/ix-slide-in-ref';
......@@ -47,6 +48,7 @@ describe('CatalogAddFormComponent', () => {
mockProvider(MatDialog, {
open: jest.fn(() => mockDialogRef),
}),
mockAuth(),
],
});
......
......@@ -3,6 +3,7 @@ import { FormBuilder, Validators } from '@angular/forms';
import { MatDialog } from '@angular/material/dialog';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { Role } from 'app/enums/role.enum';
import { helptextApps } from 'app/helptext/apps/apps';
import { CatalogCreate } from 'app/interfaces/catalog.interface';
import { EntityJobComponent } from 'app/modules/entity/entity-job/entity-job.component';
......@@ -35,6 +36,8 @@ export class CatalogAddFormComponent {
branch: helptextApps.catalogForm.branch.tooltip,
};
protected readonly requiredRoles = [Role.CatalogWrite];
constructor(
private slideInRef: IxSlideInRef<CatalogAddFormComponent>,
private errorHandler: FormErrorHandlerService,
......
......@@ -25,6 +25,7 @@
<ix-form-actions>
<button
*ixRequiresRoles="requiredRoles"
mat-button
type="submit"
color="primary"
......
......@@ -3,6 +3,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonHarness } from '@angular/material/button/testing';
import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { mockCall, mockWebsocket } from 'app/core/testing/utils/mock-websocket.utils';
import { Catalog, CatalogTrain } from 'app/interfaces/catalog.interface';
import { IxSlideInRef } from 'app/modules/ix-forms/components/ix-slide-in/ix-slide-in-ref';
......@@ -30,6 +31,7 @@ describe('CatalogEditFormComponent', () => {
]),
mockProvider(IxSlideInRef),
mockProvider(FormErrorHandlerService),
mockAuth(),
],
});
......
......@@ -4,6 +4,7 @@ import {
import { FormBuilder, Validators } from '@angular/forms';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { of } from 'rxjs';
import { Role } from 'app/enums/role.enum';
import { helptextApps } from 'app/helptext/apps/apps';
import { Catalog, CatalogUpdate } from 'app/interfaces/catalog.interface';
import { Option } from 'app/interfaces/option.interface';
......@@ -32,6 +33,8 @@ export class CatalogEditFormComponent implements OnInit {
preferred_trains: helptextApps.catalogForm.preferredTrains.tooltip,
};
protected readonly requiredRoles = [Role.CatalogWrite];
constructor(
private ws: WebSocketService,
private slideInRef: IxSlideInRef<CatalogEditFormComponent>,
......
......@@ -2,7 +2,12 @@
<ix-page-title-header>
<ix-search-input (search)="onListFiltered($event)"></ix-search-input>
<button mat-button ixTest="refresh-all" (click)="onRefreshAll()">
<button
*ixRequiresRoles="requiredRoles"
mat-button
ixTest="refresh-all"
(click)="onRefreshAll()"
>
{{ 'Refresh All' | translate }}
</button>
......@@ -36,6 +41,7 @@
(click)="showSummary(catalog)"
>{{ 'Summary' | translate }}</button>
<button
*ixRequiresRoles="requiredRoles"
mat-button
[ixTest]="[catalog.label, 'refresh']"
(click)="refreshRow(catalog)"
......@@ -45,12 +51,15 @@
[ixTest]="[catalog.label, 'edit']"
(click)="doEdit(catalog)"
>{{ 'Edit' | translate }}</button>
<button
*ngIf="!catalog.builtin"
mat-button
[ixTest]="[catalog.label, 'delete']"
(click)="doDelete(catalog)"
>{{ 'Delete' | translate }}</button>
<ng-container *ngIf="!catalog.builtin">
<button
*ixRequiresRoles="requiredRoles"
mat-button
[ixTest]="[catalog.label, 'delete']"
(click)="doDelete(catalog)"
>{{ 'Delete' | translate }}
</button>
</ng-container>
</div>
</ng-template>
</tbody>
......
......@@ -6,6 +6,7 @@ import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { filter, tap } from 'rxjs/operators';
import { JobState } from 'app/enums/job-state.enum';
import { Role } from 'app/enums/role.enum';
import { helptextApps } from 'app/helptext/apps/apps';
import { Catalog } from 'app/interfaces/catalog.interface';
import { EntityJobComponent } from 'app/modules/entity/entity-job/entity-job.component';
......@@ -63,6 +64,8 @@ export class CatalogsComponent implements OnInit {
rowTestId: (row) => 'catalog-' + row.label,
});
protected readonly requiredRoles = [Role.CatalogWrite];
constructor(
private matDialog: MatDialog,
private dialogService: DialogService,
......
......@@ -26,6 +26,7 @@
<div class="actions">
<button
*ixRequiresRoles="requiredRoles"
mat-button
type="submit"
color="primary"
......
......@@ -7,6 +7,7 @@ import { ActivatedRoute, Router } from '@angular/router';
import { Spectator } from '@ngneat/spectator';
import { mockProvider, createComponentFactory } from '@ngneat/spectator/jest';
import { of } from 'rxjs';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { mockEntityJobComponentRef } from 'app/core/testing/utils/mock-entity-job-component-ref.utils';
import { mockCall, mockJob, mockWebsocket } from 'app/core/testing/utils/mock-websocket.utils';
import { CatalogApp, CatalogAppVersion } from 'app/interfaces/catalog.interface';
......@@ -384,6 +385,7 @@ describe('ChartWizardComponent', () => {
}),
mockProvider(IxSlideInRef),
mockProvider(Router),
mockAuth(),
{ provide: SLIDE_IN_DATA, useValue: undefined },
],
});
......
......@@ -21,6 +21,7 @@ import {
} from 'rxjs/operators';
import { ixChartApp } from 'app/constants/catalog.constants';
import { DynamicFormSchemaType } from 'app/enums/dynamic-form-schema-type.enum';
import { Role } from 'app/enums/role.enum';
import { helptextApps } from 'app/helptext/apps/apps';
import { AppDetailsRouteParams } from 'app/interfaces/app-details-route-params.interface';
import { CatalogApp } from 'app/interfaces/catalog.interface';
......@@ -96,6 +97,8 @@ export class ChartWizardComponent implements OnInit, OnDestroy {
}),
);
protected readonly requiredRoles = [Role.AppsWrite];
get titlePrefix(): string {
return this.isNew ? this.translate.instant('Install') : this.translate.instant('Edit');
}
......
......@@ -13,6 +13,7 @@
<div class="actions">
<button
*ixRequiresRoles="requiredRoles"
mat-button
ixTest="update-selected"
[disabled]="!selectionHasUpdates"
......@@ -21,7 +22,12 @@
<ix-icon name="update"></ix-icon>
{{ 'Update' | translate }}
</button>
<button mat-button ixTest="delete-selected" (click)="doDelete(checkboxColumn?.selection.selected)">
<button
*ixRequiresRoles="requiredRoles"
mat-button
ixTest="delete-selected"
(click)="doDelete(checkboxColumn?.selection.selected)"
>
<ix-icon name="delete"></ix-icon>
{{ 'Delete' | translate }}
</button>
......@@ -101,6 +107,7 @@
</button>
<mat-menu #actionsMenu="matMenu">
<button
*ixRequiresRoles="requiredRoles"
mat-menu-item
[ixTest]="['update', image.repo_tags.join(', ')]"
[disabled]="!image.update_available"
......@@ -109,7 +116,7 @@
{{ image.update_available ? ('Update available' | translate) : ('Up to date' | translate) }}
</button>
<button
*ixRequiresRoles="[Role.FullAdmin]"
*ixRequiresRoles="requiredRoles"
mat-menu-item
[ixTest]="['delete', image.repo_tags.join(', ')]"
(click)="doDelete([image])"
......
......@@ -31,7 +31,6 @@ import { IxSlideInService } from 'app/services/ix-slide-in.service';
export class DockerImagesListComponent implements OnInit, AfterViewInit {
dataSource = new MatTableDataSource<ContainerImage>([]);
Role = Role;
displayedColumns = ['select', 'id', 'repo_tags', 'size', 'update', 'actions'];
@ViewChild(MatSort, { static: false }) sort: MatSort;
......@@ -63,6 +62,8 @@ export class DockerImagesListComponent implements OnInit, AfterViewInit {
}),
);
protected readonly requiredRoles = [Role.AppsWrite];
get selectionHasUpdates(): boolean {
return this.checkboxColumn.selection.selected.some((image) => image.update_available);
}
......
......@@ -40,6 +40,7 @@
<ix-form-actions>
<button
*ixRequiresRoles="requiredRoles"
mat-button
type="submit"
color="primary"
......
......@@ -3,6 +3,7 @@ import { TestbedHarnessEnvironment } from '@angular/cdk/testing/testbed';
import { ReactiveFormsModule } from '@angular/forms';
import { MatButtonHarness } from '@angular/material/button/testing';
import { createComponentFactory, mockProvider, Spectator } from '@ngneat/spectator/jest';
import { mockAuth } from 'app/core/testing/utils/mock-auth.utils';
import { mockJob, mockWebsocket } from 'app/core/testing/utils/mock-websocket.utils';
import { EntityModule } from 'app/modules/entity/entity.module';
import { IxSlideInRef } from 'app/modules/ix-forms/components/ix-slide-in/ix-slide-in-ref';
......@@ -35,6 +36,7 @@ describe('PullImageFormComponent', () => {
{ provide: SLIDE_IN_DATA, useValue: undefined },
mockProvider(FormErrorHandlerService),
mockProvider(DialogService),
mockAuth(),
],
});
......
......@@ -4,6 +4,7 @@ import { MatDialog } from '@angular/material/dialog';
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy';
import { TranslateService } from '@ngx-translate/core';
import { latestVersion } from 'app/constants/catalog.constants';
import { Role } from 'app/enums/role.enum';
import { helptextApps } from 'app/helptext/apps/apps';
import { PullContainerImageParams } from 'app/interfaces/container-image.interface';
import { EntityJobComponent } from 'app/modules/entity/entity-job/entity-job.component';
......@@ -34,6 +35,8 @@ export class PullImageFormComponent {
password: helptextApps.pullImageForm.password.tooltip,
};
protected readonly requiredRoles = [Role.AppsWrite];
constructor(
private slideInRef: IxSlideInRef<PullImageFormComponent>,
private cdr: ChangeDetectorRef,
......
......@@ -89,6 +89,7 @@
<div class="form-actions">
<button
*ixRequiresRoles="requiredRoles"
mat-button
type="submit"
color="primary"
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment