mirror of https://github.com/portainer/portainer
refactor(containers): migrate caps tab to react [EE-5215] (#10366)
parent
9dde610da3
commit
57e04c3544
|
@ -23,6 +23,8 @@ parserOptions:
|
|||
modules: true
|
||||
|
||||
rules:
|
||||
no-console: error
|
||||
no-alert: error
|
||||
no-control-regex: 'off'
|
||||
no-empty: warn
|
||||
no-empty-function: warn
|
||||
|
@ -86,8 +88,8 @@ overrides:
|
|||
no-plusplus: off
|
||||
func-style: [error, 'declaration']
|
||||
import/prefer-default-export: off
|
||||
no-use-before-define: "off"
|
||||
'@typescript-eslint/no-use-before-define': ['error', { functions: false, "allowNamedExports": true }]
|
||||
no-use-before-define: 'off'
|
||||
'@typescript-eslint/no-use-before-define': ['error', { functions: false, 'allowNamedExports': true }]
|
||||
no-shadow: 'off'
|
||||
'@typescript-eslint/no-shadow': off
|
||||
jsx-a11y/no-autofocus: warn
|
||||
|
|
|
@ -1,23 +0,0 @@
|
|||
export default class ContainerCapabilitiesController {
|
||||
/* @ngInject */
|
||||
constructor($scope) {
|
||||
this.$scope = $scope;
|
||||
|
||||
this.oldCapabilities = [];
|
||||
}
|
||||
|
||||
createOnChangeHandler(capability) {
|
||||
return (checked) => {
|
||||
this.$scope.$evalAsync(() => {
|
||||
capability.allowed = checked;
|
||||
});
|
||||
};
|
||||
}
|
||||
|
||||
$doCheck() {
|
||||
if (this.oldCapabilities.length !== this.capabilities.length) {
|
||||
this.oldCapabilities = this.capabilities;
|
||||
this.capabilitiesOnChange = Object.fromEntries(this.capabilities.map((cap) => [cap.capability, this.createOnChangeHandler(cap)]));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
import controller from './container-capabilities.controller';
|
||||
|
||||
angular.module('portainer.docker').component('containerCapabilities', {
|
||||
templateUrl: './containerCapabilities.html',
|
||||
bindings: {
|
||||
capabilities: '=',
|
||||
},
|
||||
controller,
|
||||
});
|
|
@ -1,15 +0,0 @@
|
|||
<form class="form-horizontal" style="margin-top: 15px">
|
||||
<div class="col-sm-12 form-section-title"> Container capabilities </div>
|
||||
<div class="form-group flex flex-wrap gap-y-2 px-5">
|
||||
<div ng-repeat="cap in $ctrl.capabilities" class="w-1/3 text-center">
|
||||
<por-switch-field
|
||||
label-class="'col-sm-6'"
|
||||
tooltip="cap.description"
|
||||
checked="cap.allowed"
|
||||
label="cap.capability"
|
||||
name="'capability'"
|
||||
on-change="($ctrl.capabilitiesOnChange[cap.capability])"
|
||||
></por-switch-field>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
|
@ -1,90 +0,0 @@
|
|||
var capDesc = {
|
||||
SETPCAP: 'Modify process capabilities.',
|
||||
MKNOD: 'Create special files using mknod(2).',
|
||||
AUDIT_WRITE: 'Write records to kernel auditing log.',
|
||||
CHOWN: 'Make arbitrary changes to file UIDs and GIDs (see chown(2)).',
|
||||
NET_RAW: 'Use RAW and PACKET sockets.',
|
||||
DAC_OVERRIDE: 'Bypass file read, write, and execute permission checks.',
|
||||
FOWNER: 'Bypass permission checks on operations that normally require the file system UID of the process to match the UID of the file.',
|
||||
FSETID: 'Don’t clear set-user-ID and set-group-ID permission bits when a file is modified.',
|
||||
KILL: 'Bypass permission checks for sending signals.',
|
||||
SETGID: 'Make arbitrary manipulations of process GIDs and supplementary GID list.',
|
||||
SETUID: 'Make arbitrary manipulations of process UIDs.',
|
||||
NET_BIND_SERVICE: 'Bind a socket to internet domain privileged ports (port numbers less than 1024).',
|
||||
SYS_CHROOT: 'Use chroot(2), change root directory.',
|
||||
SETFCAP: 'Set file capabilities.',
|
||||
SYS_MODULE: 'Load and unload kernel modules.',
|
||||
SYS_RAWIO: 'Perform I/O port operations (iopl(2) and ioperm(2)).',
|
||||
SYS_PACCT: 'Use acct(2), switch process accounting on or off.',
|
||||
SYS_ADMIN: 'Perform a range of system administration operations.',
|
||||
SYS_NICE: 'Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes.',
|
||||
SYS_RESOURCE: 'Override resource Limits.',
|
||||
SYS_TIME: 'Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock.',
|
||||
SYS_TTY_CONFIG: 'Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals.',
|
||||
AUDIT_CONTROL: 'Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.',
|
||||
MAC_ADMIN: 'Allow MAC configuration or state changes. Implemented for the Smack LSM.',
|
||||
MAC_OVERRIDE: 'Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM).',
|
||||
NET_ADMIN: 'Perform various network-related operations.',
|
||||
SYSLOG: 'Perform privileged syslog(2) operations.',
|
||||
DAC_READ_SEARCH: 'Bypass file read permission checks and directory read and execute permission checks.',
|
||||
LINUX_IMMUTABLE: 'Set the FS_APPEND_FL and FS_IMMUTABLE_FL i-node flags.',
|
||||
NET_BROADCAST: 'Make socket broadcasts, and listen to multicasts.',
|
||||
IPC_LOCK: 'Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).',
|
||||
IPC_OWNER: 'Bypass permission checks for operations on System V IPC objects.',
|
||||
SYS_PTRACE: 'Trace arbitrary processes using ptrace(2).',
|
||||
SYS_BOOT: 'Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution.',
|
||||
LEASE: 'Establish leases on arbitrary files (see fcntl(2)).',
|
||||
WAKE_ALARM: 'Trigger something that will wake up the system.',
|
||||
BLOCK_SUSPEND: 'Employ features that can block system suspend.',
|
||||
};
|
||||
|
||||
export function ContainerCapabilities() {
|
||||
// all capabilities can be found at https://docs.docker.com/engine/reference/run/#runtime-privilege-and-linux-capabilities
|
||||
return [
|
||||
new ContainerCapability('SETPCAP', true),
|
||||
new ContainerCapability('MKNOD', true),
|
||||
new ContainerCapability('AUDIT_WRITE', true),
|
||||
new ContainerCapability('CHOWN', true),
|
||||
new ContainerCapability('NET_RAW', true),
|
||||
new ContainerCapability('DAC_OVERRIDE', true),
|
||||
new ContainerCapability('FOWNER', true),
|
||||
new ContainerCapability('FSETID', true),
|
||||
new ContainerCapability('KILL', true),
|
||||
new ContainerCapability('SETGID', true),
|
||||
new ContainerCapability('SETUID', true),
|
||||
new ContainerCapability('NET_BIND_SERVICE', true),
|
||||
new ContainerCapability('SYS_CHROOT', true),
|
||||
new ContainerCapability('SETFCAP', true),
|
||||
new ContainerCapability('SYS_MODULE', false),
|
||||
new ContainerCapability('SYS_RAWIO', false),
|
||||
new ContainerCapability('SYS_PACCT', false),
|
||||
new ContainerCapability('SYS_ADMIN', false),
|
||||
new ContainerCapability('SYS_NICE', false),
|
||||
new ContainerCapability('SYS_RESOURCE', false),
|
||||
new ContainerCapability('SYS_TIME', false),
|
||||
new ContainerCapability('SYS_TTY_CONFIG', false),
|
||||
new ContainerCapability('AUDIT_CONTROL', false),
|
||||
new ContainerCapability('MAC_ADMIN', false),
|
||||
new ContainerCapability('MAC_OVERRIDE', false),
|
||||
new ContainerCapability('NET_ADMIN', false),
|
||||
new ContainerCapability('SYSLOG', false),
|
||||
new ContainerCapability('DAC_READ_SEARCH', false),
|
||||
new ContainerCapability('LINUX_IMMUTABLE', false),
|
||||
new ContainerCapability('NET_BROADCAST', false),
|
||||
new ContainerCapability('IPC_LOCK', false),
|
||||
new ContainerCapability('IPC_OWNER', false),
|
||||
new ContainerCapability('SYS_PTRACE', false),
|
||||
new ContainerCapability('SYS_BOOT', false),
|
||||
new ContainerCapability('LEASE', false),
|
||||
new ContainerCapability('WAKE_ALARM', false),
|
||||
new ContainerCapability('BLOCK_SUSPEND', false),
|
||||
].sort(function (a, b) {
|
||||
return a.capability < b.capability ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
export function ContainerCapability(cap, allowed) {
|
||||
this.capability = cap;
|
||||
this.allowed = allowed;
|
||||
this.description = capDesc[cap];
|
||||
}
|
|
@ -30,6 +30,10 @@ import {
|
|||
resourcesTabUtils,
|
||||
type ResourcesTabValues,
|
||||
} from '@/react/docker/containers/CreateView/ResourcesTab';
|
||||
import {
|
||||
CapabilitiesTab,
|
||||
capabilitiesTabUtils,
|
||||
} from '@/react/docker/containers/CreateView/CapabilitiesTab';
|
||||
|
||||
const ngModule = angular
|
||||
.module('portainer.docker.react.components.containers', [])
|
||||
|
@ -91,3 +95,11 @@ withFormValidation<ComponentProps<typeof ResourcesTab>, ResourcesTabValues>(
|
|||
],
|
||||
resourcesTabUtils.validation
|
||||
);
|
||||
|
||||
withFormValidation(
|
||||
ngModule,
|
||||
CapabilitiesTab,
|
||||
'dockerCreateContainerCapabilitiesTab',
|
||||
[],
|
||||
capabilitiesTabUtils.validation
|
||||
);
|
||||
|
|
|
@ -9,7 +9,7 @@ import { buildConfirmButton } from '@@/modals/utils';
|
|||
import { commandsTabUtils } from '@/react/docker/containers/CreateView/CommandsTab';
|
||||
import { volumesTabUtils } from '@/react/docker/containers/CreateView/VolumesTab';
|
||||
import { networkTabUtils } from '@/react/docker/containers/CreateView/NetworkTab';
|
||||
import { ContainerCapabilities, ContainerCapability } from '@/docker/models/containerCapabilities';
|
||||
import { capabilitiesTabUtils } from '@/react/docker/containers/CreateView/CapabilitiesTab';
|
||||
import { AccessControlFormData } from '@/portainer/components/accessControlForm/porAccessControlFormModel';
|
||||
import { ContainerDetailsViewModel } from '@/docker/models/container';
|
||||
|
||||
|
@ -85,13 +85,13 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
DnsSecondary: '',
|
||||
AccessControlData: new AccessControlFormData(),
|
||||
NodeName: null,
|
||||
capabilities: [],
|
||||
RegistryModel: new PorImageRegistryModel(),
|
||||
commands: commandsTabUtils.getDefaultViewModel(),
|
||||
envVars: envVarsTabUtils.getDefaultViewModel(),
|
||||
volumes: volumesTabUtils.getDefaultViewModel(),
|
||||
network: networkTabUtils.getDefaultViewModel(),
|
||||
resources: resourcesTabUtils.getDefaultViewModel(),
|
||||
capabilities: capabilitiesTabUtils.getDefaultViewModel(),
|
||||
};
|
||||
|
||||
$scope.state = {
|
||||
|
@ -140,6 +140,12 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
});
|
||||
};
|
||||
|
||||
$scope.onCapabilitiesChange = function (capabilities) {
|
||||
return $scope.$evalAsync(() => {
|
||||
$scope.formValues.capabilities = capabilities;
|
||||
});
|
||||
};
|
||||
|
||||
function onAlwaysPullChange(checked) {
|
||||
return $scope.$evalAsync(() => {
|
||||
$scope.formValues.alwaysPull = checked;
|
||||
|
@ -301,21 +307,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
config.Labels = labels;
|
||||
}
|
||||
|
||||
function prepareCapabilities(config) {
|
||||
var allowed = $scope.formValues.capabilities.filter(function (item) {
|
||||
return item.allowed === true;
|
||||
});
|
||||
var notAllowed = $scope.formValues.capabilities.filter(function (item) {
|
||||
return item.allowed === false;
|
||||
});
|
||||
|
||||
var getCapName = function (item) {
|
||||
return item.capability;
|
||||
};
|
||||
config.HostConfig.CapAdd = allowed.map(getCapName);
|
||||
config.HostConfig.CapDrop = notAllowed.map(getCapName);
|
||||
}
|
||||
|
||||
function prepareConfiguration() {
|
||||
var config = angular.copy($scope.config);
|
||||
config = commandsTabUtils.toRequest(config, $scope.formValues.commands);
|
||||
|
@ -323,11 +314,11 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
config = volumesTabUtils.toRequest(config, $scope.formValues.volumes);
|
||||
config = networkTabUtils.toRequest(config, $scope.formValues.network, $scope.fromContainer.Id);
|
||||
config = resourcesTabUtils.toRequest(config, $scope.formValues.resources);
|
||||
config = capabilitiesTabUtils.toRequest(config, $scope.formValues.capabilities);
|
||||
|
||||
prepareImageConfig(config);
|
||||
preparePortBindings(config);
|
||||
prepareLabels(config);
|
||||
prepareCapabilities(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
|
@ -354,35 +345,6 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
});
|
||||
}
|
||||
|
||||
function loadFromContainerCapabilities(d) {
|
||||
if (d.HostConfig.CapAdd) {
|
||||
d.HostConfig.CapAdd.forEach(function (cap) {
|
||||
$scope.formValues.capabilities.push(new ContainerCapability(cap, true));
|
||||
});
|
||||
}
|
||||
if (d.HostConfig.CapDrop) {
|
||||
d.HostConfig.CapDrop.forEach(function (cap) {
|
||||
$scope.formValues.capabilities.push(new ContainerCapability(cap, false));
|
||||
});
|
||||
}
|
||||
|
||||
function hasCapability(item) {
|
||||
return item.capability === cap.capability;
|
||||
}
|
||||
|
||||
var capabilities = new ContainerCapabilities();
|
||||
for (var i = 0; i < capabilities.length; i++) {
|
||||
var cap = capabilities[i];
|
||||
if (!_.find($scope.formValues.capabilities, hasCapability)) {
|
||||
$scope.formValues.capabilities.push(cap);
|
||||
}
|
||||
}
|
||||
|
||||
$scope.formValues.capabilities.sort(function (a, b) {
|
||||
return a.capability < b.capability ? -1 : 1;
|
||||
});
|
||||
}
|
||||
|
||||
function loadFromContainerSpec() {
|
||||
// Get container
|
||||
Container.get({ id: $transition$.params().from })
|
||||
|
@ -408,12 +370,11 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
$scope.formValues.volumes = volumesTabUtils.toViewModel(d);
|
||||
$scope.formValues.network = networkTabUtils.toViewModel(d, $scope.availableNetworks, $scope.runningContainers);
|
||||
$scope.formValues.resources = resourcesTabUtils.toViewModel(d);
|
||||
$scope.formValues.capabilities = capabilitiesTabUtils.toViewModel(d);
|
||||
|
||||
loadFromContainerPortBindings(d);
|
||||
loadFromContainerLabels(d);
|
||||
loadFromContainerImageConfig(d);
|
||||
|
||||
loadFromContainerCapabilities(d);
|
||||
})
|
||||
.then(() => {
|
||||
$scope.state.containerIsLoaded = true;
|
||||
|
@ -456,7 +417,9 @@ angular.module('portainer.docker').controller('CreateContainerController', [
|
|||
} else {
|
||||
$scope.state.containerIsLoaded = true;
|
||||
$scope.fromContainer = {};
|
||||
$scope.formValues.capabilities = $scope.areContainerCapabilitiesEnabled ? new ContainerCapabilities() : [];
|
||||
if ($scope.areContainerCapabilitiesEnabled) {
|
||||
$scope.formValues.capabilities = capabilitiesTabUtils.getDefaultViewModel();
|
||||
}
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
|
|
|
@ -302,7 +302,7 @@
|
|||
<!-- !tab-runtime-resources -->
|
||||
<!-- tab-container-capabilities -->
|
||||
<div class="tab-pane" id="container-capabilities">
|
||||
<container-capabilities capabilities="formValues.capabilities"></container-capabilities>
|
||||
<docker-create-container-capabilities-tab values="formValues.capabilities" on-change="(onCapabilitiesChange)"></docker-create-container-capabilities-tab>
|
||||
</div>
|
||||
<!-- !tab-container-capabilities -->
|
||||
</div>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import { FormSection } from '@@/form-components/FormSection';
|
||||
import { SwitchField } from '@@/form-components/SwitchField';
|
||||
|
||||
import { capabilities } from './types';
|
||||
|
||||
export type Values = string[];
|
||||
|
||||
export function CapabilitiesTab({
|
||||
values,
|
||||
onChange,
|
||||
}: {
|
||||
values: Values;
|
||||
onChange: (values: Values) => void;
|
||||
}) {
|
||||
return (
|
||||
<FormSection title="Container capabilities">
|
||||
<div className="form-group flex flex-wrap gap-y-2 px-5">
|
||||
{capabilities.map((cap) => (
|
||||
<div key={cap.key} className="w-1/3 text-center">
|
||||
<SwitchField
|
||||
labelClass="col-sm-6"
|
||||
tooltip={cap.description}
|
||||
checked={values.includes(cap.key)}
|
||||
label={cap.key}
|
||||
name={`${cap.key}-capability`}
|
||||
onChange={(value) => {
|
||||
if (value) {
|
||||
onChange([...values, cap.key]);
|
||||
} else {
|
||||
onChange(values.filter((v) => v !== cap.key));
|
||||
}
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</FormSection>
|
||||
);
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
import { validation } from './validation';
|
||||
import { toViewModel, getDefaultViewModel } from './toViewModel';
|
||||
import { toRequest } from './toRequest';
|
||||
|
||||
export {
|
||||
CapabilitiesTab,
|
||||
type Values as CapabilitiesTabValues,
|
||||
} from './CapabilitiesTab';
|
||||
|
||||
export const capabilitiesTabUtils = {
|
||||
toRequest,
|
||||
toViewModel,
|
||||
validation,
|
||||
getDefaultViewModel,
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
import { CreateContainerRequest } from '@/react/docker/containers/CreateView/types';
|
||||
|
||||
import { capabilities } from './types';
|
||||
import { Values } from './CapabilitiesTab';
|
||||
|
||||
export function toRequest(
|
||||
oldConfig: CreateContainerRequest,
|
||||
values: Values
|
||||
): CreateContainerRequest {
|
||||
return {
|
||||
...oldConfig,
|
||||
HostConfig: {
|
||||
...oldConfig.HostConfig,
|
||||
CapAdd: values,
|
||||
CapDrop: capabilities
|
||||
.filter((cap) => !values.includes(cap.key))
|
||||
.map((cap) => cap.key),
|
||||
},
|
||||
};
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
import { ContainerJSON } from '@/react/docker/containers/queries/container';
|
||||
|
||||
import { capabilities } from './types';
|
||||
import { Values } from './CapabilitiesTab';
|
||||
|
||||
export function toViewModel(config: ContainerJSON): Values {
|
||||
const { CapAdd, CapDrop } = getDefaults(config);
|
||||
|
||||
const missingCaps = capabilities
|
||||
.filter(
|
||||
(cap) =>
|
||||
cap.default && !CapAdd.includes(cap.key) && !CapDrop.includes(cap.key)
|
||||
)
|
||||
.map((cap) => cap.key);
|
||||
|
||||
return [...CapAdd, ...missingCaps];
|
||||
|
||||
function getDefaults(config: ContainerJSON) {
|
||||
return {
|
||||
CapAdd: config.HostConfig?.CapAdd || [],
|
||||
CapDrop: config.HostConfig?.CapDrop || [],
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function getDefaultViewModel(): Values {
|
||||
return capabilities.filter((cap) => cap.default).map((cap) => cap.key);
|
||||
}
|
|
@ -0,0 +1,185 @@
|
|||
export interface Capability {
|
||||
key: string;
|
||||
description: string;
|
||||
default?: boolean;
|
||||
}
|
||||
|
||||
const capDesc: Array<Capability> = [
|
||||
{
|
||||
key: 'SETPCAP',
|
||||
description: 'Modify process capabilities.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'MKNOD',
|
||||
description: 'Create special files using mknod(2).',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'AUDIT_WRITE',
|
||||
description: 'Write records to kernel auditing log.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'CHOWN',
|
||||
description: 'Make arbitrary changes to file UIDs and GIDs (see chown(2)).',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'NET_RAW',
|
||||
description: 'Use RAW and PACKET sockets.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'DAC_OVERRIDE',
|
||||
description: 'Bypass file read, write, and execute permission checks.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'FOWNER',
|
||||
description:
|
||||
'Bypass permission checks on operations that normally require the file system UID of the process to match the UID of the file.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'FSETID',
|
||||
description:
|
||||
'Don’t clear set-user-ID and set-group-ID permission bits when a file is modified.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'KILL',
|
||||
description: 'Bypass permission checks for sending signals.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'SETGID',
|
||||
description:
|
||||
'Make arbitrary manipulations of process GIDs and supplementary GID list.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'SETUID',
|
||||
description: 'Make arbitrary manipulations of process UIDs.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'NET_BIND_SERVICE',
|
||||
description:
|
||||
'Bind a socket to internet domain privileged ports (port numbers less than 1024).',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'SYS_CHROOT',
|
||||
description: 'Use chroot(2), change root directory.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'SETFCAP',
|
||||
description: 'Set file capabilities.',
|
||||
default: true,
|
||||
},
|
||||
{
|
||||
key: 'SYS_MODULE',
|
||||
description: 'Load and unload kernel modules.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_RAWIO',
|
||||
description: 'Perform I/O port operations (iopl(2) and ioperm(2)).',
|
||||
},
|
||||
{
|
||||
key: 'SYS_PACCT',
|
||||
description: 'Use acct(2), switch process accounting on or off.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_ADMIN',
|
||||
description: 'Perform a range of system administration operations.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_NICE',
|
||||
description:
|
||||
'Raise process nice value (nice(2), setpriority(2)) and change the nice value for arbitrary processes.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_RESOURCE',
|
||||
description: 'Override resource Limits.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_TIME',
|
||||
description:
|
||||
'Set system clock (settimeofday(2), stime(2), adjtimex(2)); set real-time (hardware) clock.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_TTY_CONFIG',
|
||||
description:
|
||||
'Use vhangup(2); employ various privileged ioctl(2) operations on virtual terminals.',
|
||||
},
|
||||
{
|
||||
key: 'AUDIT_CONTROL',
|
||||
description:
|
||||
'Enable and disable kernel auditing; change auditing filter rules; retrieve auditing status and filtering rules.',
|
||||
},
|
||||
{
|
||||
key: 'MAC_ADMIN',
|
||||
description:
|
||||
'Allow MAC configuration or state changes. Implemented for the Smack LSM.',
|
||||
},
|
||||
{
|
||||
key: 'MAC_OVERRIDE',
|
||||
description:
|
||||
'Override Mandatory Access Control (MAC). Implemented for the Smack Linux Security Module (LSM).',
|
||||
},
|
||||
{
|
||||
key: 'NET_ADMIN',
|
||||
description: 'Perform various network-related operations.',
|
||||
},
|
||||
{
|
||||
key: 'SYSLOG',
|
||||
description: 'Perform privileged syslog(2) operations.',
|
||||
},
|
||||
{
|
||||
key: 'DAC_READ_SEARCH',
|
||||
description:
|
||||
'Bypass file read permission checks and directory read and execute permission checks.',
|
||||
},
|
||||
{
|
||||
key: 'LINUX_IMMUTABLE',
|
||||
description: 'Set the FS_APPEND_FL and FS_IMMUTABLE_FL i-node flags.',
|
||||
},
|
||||
{
|
||||
key: 'NET_BROADCAST',
|
||||
description: 'Make socket broadcasts, and listen to multicasts.',
|
||||
},
|
||||
{
|
||||
key: 'IPC_LOCK',
|
||||
description: 'Lock memory (mlock(2), mlockall(2), mmap(2), shmctl(2)).',
|
||||
},
|
||||
{
|
||||
key: 'IPC_OWNER',
|
||||
description:
|
||||
'Bypass permission checks for operations on System V IPC objects.',
|
||||
},
|
||||
{
|
||||
key: 'SYS_PTRACE',
|
||||
description: 'Trace arbitrary processes using ptrace(2).',
|
||||
},
|
||||
{
|
||||
key: 'SYS_BOOT',
|
||||
description:
|
||||
'Use reboot(2) and kexec_load(2), reboot and load a new kernel for later execution.',
|
||||
},
|
||||
{
|
||||
key: 'LEASE',
|
||||
description: 'Establish leases on arbitrary files (see fcntl(2)).',
|
||||
},
|
||||
{
|
||||
key: 'WAKE_ALARM',
|
||||
description: 'Trigger something that will wake up the system.',
|
||||
},
|
||||
{
|
||||
key: 'BLOCK_SUSPEND',
|
||||
description: 'Employ features that can block system suspend.',
|
||||
},
|
||||
];
|
||||
|
||||
export const capabilities = capDesc.sort((a, b) => (a.key < b.key ? -1 : 1));
|
|
@ -0,0 +1,7 @@
|
|||
import { array, SchemaOf, string } from 'yup';
|
||||
|
||||
import { Values } from './CapabilitiesTab';
|
||||
|
||||
export function validation(): SchemaOf<Values> {
|
||||
return array(string().default('')).default([]);
|
||||
}
|
Loading…
Reference in New Issue