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 });