From b53a3a7cb1eae46ba4ca578c96d7563024632551 Mon Sep 17 00:00:00 2001 From: myarmolinsky Date: Tue, 3 Dec 2024 06:55:21 -0500 Subject: [PATCH] `application.generateProvisioningKey`: Require `keyExpiryDate` parameter and require it before the optional description Change-type: major --- DOCUMENTATION.md | 16 +-- src/models/application.ts | 120 ++++++++++--------- src/models/device.ts | 1 + tests/integration/models/api-key.spec.ts | 1 + tests/integration/models/application.spec.ts | 13 +- tests/integration/setup.ts | 1 + 6 files changed, 84 insertions(+), 68 deletions(-) diff --git a/DOCUMENTATION.md b/DOCUMENTATION.md index 1a817cda6..c3a19a111 100644 --- a/DOCUMENTATION.md +++ b/DOCUMENTATION.md @@ -213,7 +213,7 @@ const sdk = fromSharedOptions(); * [.remove(slugOrUuidOrIdOrIds)](#balena.models.application.remove) ⇒ Promise * [.rename(slugOrUuidOrId, newName)](#balena.models.application.rename) ⇒ Promise * [.restart(slugOrUuidOrId)](#balena.models.application.restart) ⇒ Promise - * [.generateProvisioningKey(slugOrUuidOrId, [keyName], [keyDescription], [keyExpiryDate])](#balena.models.application.generateProvisioningKey) ⇒ Promise + * [.generateProvisioningKey(slugOrUuidOrId, keyExpiryDate, [keyName], [keyDescription])](#balena.models.application.generateProvisioningKey) ⇒ Promise * [.purge(appId)](#balena.models.application.purge) ⇒ Promise * [.shutdown(appId, [options])](#balena.models.application.shutdown) ⇒ Promise * [.reboot(appId, [options])](#balena.models.application.reboot) ⇒ Promise @@ -616,7 +616,7 @@ balena.models.device.get(123).catch(function (error) { * [.remove(slugOrUuidOrIdOrIds)](#balena.models.application.remove) ⇒ Promise * [.rename(slugOrUuidOrId, newName)](#balena.models.application.rename) ⇒ Promise * [.restart(slugOrUuidOrId)](#balena.models.application.restart) ⇒ Promise - * [.generateProvisioningKey(slugOrUuidOrId, [keyName], [keyDescription], [keyExpiryDate])](#balena.models.application.generateProvisioningKey) ⇒ Promise + * [.generateProvisioningKey(slugOrUuidOrId, keyExpiryDate, [keyName], [keyDescription])](#balena.models.application.generateProvisioningKey) ⇒ Promise * [.purge(appId)](#balena.models.application.purge) ⇒ Promise * [.shutdown(appId, [options])](#balena.models.application.shutdown) ⇒ Promise * [.reboot(appId, [options])](#balena.models.application.reboot) ⇒ Promise @@ -867,7 +867,7 @@ balena.models.device.get(123).catch(function (error) { * [.remove(slugOrUuidOrIdOrIds)](#balena.models.application.remove) ⇒ Promise * [.rename(slugOrUuidOrId, newName)](#balena.models.application.rename) ⇒ Promise * [.restart(slugOrUuidOrId)](#balena.models.application.restart) ⇒ Promise - * [.generateProvisioningKey(slugOrUuidOrId, [keyName], [keyDescription], [keyExpiryDate])](#balena.models.application.generateProvisioningKey) ⇒ Promise + * [.generateProvisioningKey(slugOrUuidOrId, keyExpiryDate, [keyName], [keyDescription])](#balena.models.application.generateProvisioningKey) ⇒ Promise * [.purge(appId)](#balena.models.application.purge) ⇒ Promise * [.shutdown(appId, [options])](#balena.models.application.shutdown) ⇒ Promise * [.reboot(appId, [options])](#balena.models.application.reboot) ⇒ Promise @@ -1878,7 +1878,7 @@ balena.models.application.restart(123); ``` -##### application.generateProvisioningKey(slugOrUuidOrId, [keyName], [keyDescription], [keyExpiryDate]) ⇒ Promise +##### application.generateProvisioningKey(slugOrUuidOrId, keyExpiryDate, [keyName], [keyDescription]) ⇒ Promise **Kind**: static method of [application](#balena.models.application) **Summary**: Generate a device provisioning key for a specific application **Access**: public @@ -1887,25 +1887,25 @@ balena.models.application.restart(123); | Param | Type | Description | | --- | --- | --- | | slugOrUuidOrId | String \| Number | application slug (string), uuid (string) or id (number) | +| keyExpiryDate | String | Expiry Date for provisioning key | | [keyName] | String | Provisioning key name | | [keyDescription] | String | Description for provisioning key | -| [keyExpiryDate] | String | Expiry Date for provisioning key | **Example** ```js -balena.models.application.generateProvisioningKey('myorganization/myapp').then(function(key) { +balena.models.application.generateProvisioningKey('myorganization/myapp', '2030-10-12').then(function(key) { console.log(key); }); ``` **Example** ```js -balena.models.application.generateProvisioningKey(123).then(function(key) { +balena.models.application.generateProvisioningKey(123, '2030-10-12').then(function(key) { console.log(key); }); ``` **Example** ```js -balena.models.application.generateProvisioningKey(123, 'api key name', 'api key long description', '2030-01-01T00:00:00Z').then(function(key) { +balena.models.application.generateProvisioningKey(123, '2030-10-12', 'api key name', 'api key long description', '2030-01-01T00:00:00Z').then(function(key) { console.log(key); }); ``` diff --git a/src/models/application.ts b/src/models/application.ts index 8b28ab269..154ebdec1 100644 --- a/src/models/application.ts +++ b/src/models/application.ts @@ -37,11 +37,7 @@ import * as url from 'url'; import once from 'lodash/once'; import * as errors from 'balena-errors'; -import { - isId, - mergePineOptions, - withSupervisorLockedError, -} from '../util'; +import { isId, mergePineOptions, withSupervisorLockedError } from '../util'; import { getCurrentServiceDetailsPineExpand, @@ -729,11 +725,13 @@ const getApplicationModel = function ( slugOrUuidOrIdOrIds: string | number | number[], ): Promise => { if (typeof slugOrUuidOrIdOrIds === 'string') { - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrIdOrIds)).id; - await pine.delete({ - resource: 'application', - id: applicationId, - }); + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrIdOrIds) + ).id; + await pine.delete({ + resource: 'application', + id: applicationId, + }); return; } await batchApplicationOperation()({ @@ -773,14 +771,16 @@ const getApplicationModel = function ( slugOrUuidOrId: string | number, newAppName: string, ): Promise => { - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrId)).id; - await pine.patch({ - resource: 'application', - id: applicationId, - body: { - app_name: newAppName, - }, - }); + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrId) + ).id; + await pine.patch({ + resource: 'application', + id: applicationId, + body: { + app_name: newAppName, + }, + }); }, /** @@ -801,13 +801,15 @@ const getApplicationModel = function ( */ restart: (slugOrUuidOrId: string | number): Promise => withSupervisorLockedError(async () => { - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrId)).id; + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrId) + ).id; - await request.send({ - method: 'POST', - url: `/application/${applicationId}/restart`, - baseUrl: apiUrl, - }); + await request.send({ + method: 'POST', + url: `/application/${applicationId}/restart`, + baseUrl: apiUrl, + }); }), /** @@ -818,48 +820,50 @@ const getApplicationModel = function ( * @memberof balena.models.application * * @param {String|Number} slugOrUuidOrId - application slug (string), uuid (string) or id (number) + * @param {String} keyExpiryDate - Expiry Date for provisioning key * @param {String} [keyName] - Provisioning key name * @param {String} [keyDescription] - Description for provisioning key - * @param {String} [keyExpiryDate] - Expiry Date for provisioning key * @fulfil {String} - device provisioning key * @returns {Promise} * * @example - * balena.models.application.generateProvisioningKey('myorganization/myapp').then(function(key) { + * balena.models.application.generateProvisioningKey('myorganization/myapp', '2030-10-12').then(function(key) { * console.log(key); * }); * * @example - * balena.models.application.generateProvisioningKey(123).then(function(key) { + * balena.models.application.generateProvisioningKey(123, '2030-10-12').then(function(key) { * console.log(key); * }); * * @example - * balena.models.application.generateProvisioningKey(123, 'api key name', 'api key long description', '2030-01-01T00:00:00Z').then(function(key) { + * balena.models.application.generateProvisioningKey(123, '2030-10-12', 'api key name', 'api key long description', '2030-01-01T00:00:00Z').then(function(key) { * console.log(key); * }); */ generateProvisioningKey: async ( slugOrUuidOrId: string | number, + keyExpiryDate: string | null, keyName?: string, keyDescription?: string, - keyExpiryDate?: string, ): Promise => { - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrId)).id; - const { body } = await request.send({ - method: 'POST', - url: '/api-key/v1/', - baseUrl: apiUrl, - body: { - actorType: 'application', - actorTypeId: applicationId, - roles: ['provisioning-api-key'], - name: keyName, - description: keyDescription, - expiryDate: keyExpiryDate, - }, - }); - return body; + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrId) + ).id; + const { body } = await request.send({ + method: 'POST', + url: '/api-key/v1/', + baseUrl: apiUrl, + body: { + actorType: 'application', + actorTypeId: applicationId, + roles: ['provisioning-api-key'], + name: keyName, + description: keyDescription, + expiryDate: keyExpiryDate, + }, + }); + return body; }, /** @@ -1287,12 +1291,14 @@ const getApplicationModel = function ( ); } - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrId)).id; - await pine.patch({ - resource: 'application', - id: applicationId, - body: { is_accessible_by_support_until__date: expiryTimestamp }, - }); + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrId) + ).id; + await pine.patch({ + resource: 'application', + id: applicationId, + body: { is_accessible_by_support_until__date: expiryTimestamp }, + }); }, /** @@ -1314,12 +1320,14 @@ const getApplicationModel = function ( revokeSupportAccess: async ( slugOrUuidOrId: string | number, ): Promise => { - const applicationId = (await sdkInstance.models.application.get(slugOrUuidOrId)).id; - await pine.patch({ - resource: 'application', - id: applicationId, - body: { is_accessible_by_support_until__date: null }, - }); + const applicationId = ( + await sdkInstance.models.application.get(slugOrUuidOrId) + ).id; + await pine.patch({ + resource: 'application', + id: applicationId, + body: { is_accessible_by_support_until__date: null }, + }); }, /** diff --git a/src/models/device.ts b/src/models/device.ts index a599f6c75..420afe5f5 100644 --- a/src/models/device.ts +++ b/src/models/device.ts @@ -1373,6 +1373,7 @@ const getDeviceModel = function ( sdkInstance.auth.getUserInfo(), sdkInstance.models.application.generateProvisioningKey( applicationSlugOrUuidOrId, + new Date(Date.now() + 1000 * 60 * 10).toISOString(), ), sdkInstance.models.application.get( applicationSlugOrUuidOrId, diff --git a/tests/integration/models/api-key.spec.ts b/tests/integration/models/api-key.spec.ts index 9fe4e3295..28f2e0c35 100644 --- a/tests/integration/models/api-key.spec.ts +++ b/tests/integration/models/api-key.spec.ts @@ -177,6 +177,7 @@ describe('API Key model', function () { await balena.models.application.generateProvisioningKey( this.application.id, + null, ); await balena.models.device.generateDeviceKey(this.device.id); diff --git a/tests/integration/models/application.spec.ts b/tests/integration/models/application.spec.ts index 47cbe5f8a..7dda8de9e 100644 --- a/tests/integration/models/application.spec.ts +++ b/tests/integration/models/application.spec.ts @@ -609,7 +609,7 @@ describe('Application Model', function () { applicationRetrievalFields.forEach((prop) => { it(`should be able to generate a provisioning key by ${prop}`, function () { return balena.models.application - .generateProvisioningKey(this.application[prop]) + .generateProvisioningKey(this.application[prop], null) .then(function (key) { expect(_.isString(key)).to.be.true; return expect(key).to.have.length(32); @@ -625,6 +625,7 @@ describe('Application Model', function () { const key = await balena.models.application.generateProvisioningKey( this.application[prop], + null, `key_${prop}`, ); @@ -654,6 +655,7 @@ describe('Application Model', function () { const key = await balena.models.application.generateProvisioningKey( this.application[prop], + null, `key_${prop}`, `Provisioning key generated with name key_${prop}`, ); @@ -684,9 +686,9 @@ describe('Application Model', function () { const key = await balena.models.application.generateProvisioningKey( this.application[prop], + '2030-01-01', `key_${prop}`, `Provisioning key generated with name key_${prop}`, - '2030-01-01', ); expect(key).to.be.a('string'); @@ -712,6 +714,7 @@ describe('Application Model', function () { it('should be rejected if the application slug does not exist', function () { const promise = balena.models.application.generateProvisioningKey( `${this.initialOrg.handle}/helloworldapp`, + null, ); return expect(promise).to.be.rejectedWith( `Application not found: ${this.initialOrg.handle}/helloworldapp`, @@ -719,8 +722,10 @@ describe('Application Model', function () { }); it('should be rejected if the application id does not exist', function () { - const promise = - balena.models.application.generateProvisioningKey(999999); + const promise = balena.models.application.generateProvisioningKey( + 999999, + null, + ); return expect(promise).to.be.rejectedWith( 'Application not found: 999999', ); diff --git a/tests/integration/setup.ts b/tests/integration/setup.ts index 3adf07d87..184464f60 100644 --- a/tests/integration/setup.ts +++ b/tests/integration/setup.ts @@ -363,6 +363,7 @@ export function givenLoggedInWithAnApplicationApiKey( beforeFn(async function () { const key = await balena.models.application.generateProvisioningKey( this.application.slug, + null, ); await balena.auth.logout(); await balena.auth.loginWithToken(key);