github.com/anth0d/nomad@v0.0.0-20221214183521-ae3a0a2cad06/ui/tests/unit/abilities/job-test.js (about)

     1  /* eslint-disable ember/avoid-leaking-state-in-ember-objects */
     2  import { module, test } from 'qunit';
     3  import { setupTest } from 'ember-qunit';
     4  import Service from '@ember/service';
     5  import setupAbility from 'nomad-ui/tests/helpers/setup-ability';
     6  
     7  module('Unit | Ability | job', function (hooks) {
     8    setupTest(hooks);
     9    setupAbility('job')(hooks);
    10  
    11    test('it permits job run when ACLs are disabled', function (assert) {
    12      const mockToken = Service.extend({
    13        aclEnabled: false,
    14      });
    15  
    16      this.owner.register('service:token', mockToken);
    17  
    18      assert.ok(this.ability.canRun);
    19    });
    20  
    21    test('it permits job run for management tokens', function (assert) {
    22      const mockToken = Service.extend({
    23        aclEnabled: true,
    24        selfToken: { type: 'management' },
    25      });
    26  
    27      this.owner.register('service:token', mockToken);
    28  
    29      assert.ok(this.ability.canRun);
    30    });
    31  
    32    test('it permits job run for client tokens with a policy that has namespace submit-job', function (assert) {
    33      const mockSystem = Service.extend({
    34        aclEnabled: true,
    35      });
    36  
    37      const mockToken = Service.extend({
    38        aclEnabled: true,
    39        selfToken: { type: 'client' },
    40        selfTokenPolicies: [
    41          {
    42            rulesJSON: {
    43              Namespaces: [
    44                {
    45                  Name: 'aNamespace',
    46                  Capabilities: ['submit-job'],
    47                },
    48              ],
    49            },
    50          },
    51        ],
    52      });
    53  
    54      this.owner.register('service:system', mockSystem);
    55      this.owner.register('service:token', mockToken);
    56  
    57      assert.ok(this.can.can('run job', null, { namespace: 'aNamespace' }));
    58    });
    59  
    60    test('it permits job run for client tokens with a policy that has default namespace submit-job and no capabilities for active namespace', function (assert) {
    61      const mockSystem = Service.extend({
    62        aclEnabled: true,
    63      });
    64  
    65      const mockToken = Service.extend({
    66        aclEnabled: true,
    67        selfToken: { type: 'client' },
    68        selfTokenPolicies: [
    69          {
    70            rulesJSON: {
    71              Namespaces: [
    72                {
    73                  Name: 'aNamespace',
    74                  Capabilities: [],
    75                },
    76                {
    77                  Name: 'default',
    78                  Capabilities: ['submit-job'],
    79                },
    80              ],
    81            },
    82          },
    83        ],
    84      });
    85  
    86      this.owner.register('service:system', mockSystem);
    87      this.owner.register('service:token', mockToken);
    88  
    89      assert.ok(this.can.can('run job', null, { namespace: 'anotherNamespace' }));
    90    });
    91  
    92    test('it blocks job run for client tokens with a policy that has no submit-job capability', function (assert) {
    93      const mockSystem = Service.extend({
    94        aclEnabled: true,
    95      });
    96  
    97      const mockToken = Service.extend({
    98        aclEnabled: true,
    99        selfToken: { type: 'client' },
   100        selfTokenPolicies: [
   101          {
   102            rulesJSON: {
   103              Namespaces: [
   104                {
   105                  Name: 'aNamespace',
   106                  Capabilities: ['list-jobs'],
   107                },
   108              ],
   109            },
   110          },
   111        ],
   112      });
   113  
   114      this.owner.register('service:system', mockSystem);
   115      this.owner.register('service:token', mockToken);
   116  
   117      assert.ok(this.can.cannot('run job', null, { namespace: 'aNamespace' }));
   118    });
   119  
   120    test('job scale requires a client token with the submit-job or scale-job capability', function (assert) {
   121      const makePolicies = (namespace, ...capabilities) => [
   122        {
   123          rulesJSON: {
   124            Namespaces: [
   125              {
   126                Name: namespace,
   127                Capabilities: capabilities,
   128              },
   129            ],
   130          },
   131        },
   132      ];
   133  
   134      const mockSystem = Service.extend({
   135        aclEnabled: true,
   136      });
   137  
   138      const mockToken = Service.extend({
   139        aclEnabled: true,
   140        selfToken: { type: 'client' },
   141        selfTokenPolicies: makePolicies('aNamespace'),
   142      });
   143  
   144      this.owner.register('service:system', mockSystem);
   145      this.owner.register('service:token', mockToken);
   146      const tokenService = this.owner.lookup('service:token');
   147  
   148      assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' }));
   149  
   150      tokenService.set(
   151        'selfTokenPolicies',
   152        makePolicies('aNamespace', 'scale-job')
   153      );
   154      assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' }));
   155  
   156      tokenService.set(
   157        'selfTokenPolicies',
   158        makePolicies('aNamespace', 'submit-job')
   159      );
   160      assert.ok(this.can.can('scale job', null, { namespace: 'aNamespace' }));
   161  
   162      tokenService.set(
   163        'selfTokenPolicies',
   164        makePolicies('bNamespace', 'scale-job')
   165      );
   166      assert.ok(this.can.cannot('scale job', null, { namespace: 'aNamespace' }));
   167    });
   168  
   169    test('job dispatch requires a client token with the dispatch-job capability', function (assert) {
   170      const makePolicies = (namespace, ...capabilities) => [
   171        {
   172          rulesJSON: {
   173            Namespaces: [
   174              {
   175                Name: namespace,
   176                Capabilities: capabilities,
   177              },
   178            ],
   179          },
   180        },
   181      ];
   182  
   183      const mockSystem = Service.extend({
   184        aclEnabled: true,
   185      });
   186  
   187      const mockToken = Service.extend({
   188        aclEnabled: true,
   189        selfToken: { type: 'client' },
   190        selfTokenPolicies: makePolicies('aNamespace'),
   191      });
   192  
   193      this.owner.register('service:system', mockSystem);
   194      this.owner.register('service:token', mockToken);
   195      const tokenService = this.owner.lookup('service:token');
   196  
   197      assert.ok(
   198        this.can.cannot('dispatch job', null, { namespace: 'aNamespace' })
   199      );
   200  
   201      tokenService.set(
   202        'selfTokenPolicies',
   203        makePolicies('aNamespace', 'dispatch-job')
   204      );
   205      assert.ok(this.can.can('dispatch job', null, { namespace: 'aNamespace' }));
   206    });
   207  
   208    test('it handles globs in namespace names', function (assert) {
   209      const mockSystem = Service.extend({
   210        aclEnabled: true,
   211      });
   212  
   213      const mockToken = Service.extend({
   214        aclEnabled: true,
   215        selfToken: { type: 'client' },
   216        selfTokenPolicies: [
   217          {
   218            rulesJSON: {
   219              Namespaces: [
   220                {
   221                  Name: 'production-*',
   222                  Capabilities: ['submit-job'],
   223                },
   224                {
   225                  Name: 'production-api',
   226                  Capabilities: ['submit-job'],
   227                },
   228                {
   229                  Name: 'production-web',
   230                  Capabilities: [],
   231                },
   232                {
   233                  Name: '*-suffixed',
   234                  Capabilities: ['submit-job'],
   235                },
   236                {
   237                  Name: '*-more-suffixed',
   238                  Capabilities: [],
   239                },
   240                {
   241                  Name: '*-abc-*',
   242                  Capabilities: ['submit-job'],
   243                },
   244              ],
   245            },
   246          },
   247        ],
   248      });
   249  
   250      this.owner.register('service:system', mockSystem);
   251      this.owner.register('service:token', mockToken);
   252  
   253      assert.ok(
   254        this.can.can(
   255          'run job',
   256          null,
   257          { namespace: 'production-web' },
   258          'The existence of a single namespace where a job can be run means that can run is enabled'
   259        )
   260      );
   261      assert.ok(this.can.can('run job', null, { namespace: 'production-api' }));
   262      assert.ok(this.can.can('run job', null, { namespace: 'production-other' }));
   263      assert.ok(
   264        this.can.can('run job', null, { namespace: 'something-suffixed' })
   265      );
   266      assert.ok(
   267        this.can.can('run job', null, { namespace: '000-abc-999' }),
   268        'expected to be able to match against more than one wildcard'
   269      );
   270    });
   271  });