diff --git a/lib/models/os.ts b/lib/models/os.ts index dd5c27231..b22db27ec 100644 --- a/lib/models/os.ts +++ b/lib/models/os.ts @@ -30,7 +30,7 @@ import type { import { InjectedDependenciesParam, InjectedOptionsParam } from '..'; import { getAuthDependentMemoize } from '../util/cache'; -const BALENAOS_VERSION_REGEX = /v?\d+\.\d+\.\d+(\.rev\d+)?((\-|\+).+)?/; +const BALENAOS_VERSION_REGEX = /^\d+\.\d+\.\d+(\+rev\d+)?(\.(dev|prod))?$/; const getOsModel = function ( deps: InjectedDependenciesParam, @@ -159,7 +159,7 @@ const getOsModel = function ( } const vNormalized = v[0] === 'v' ? v.substring(1) : v; if (!BALENAOS_VERSION_REGEX.test(vNormalized)) { - throw new Error(`Invalid semver version: ${v}`); + throw new Error(`Invalid balenaOS version format: ${v}`); } return vNormalized; }; diff --git a/tests/integration/models/os.spec.ts b/tests/integration/models/os.spec.ts index dea0cb7dc..0de987794 100644 --- a/tests/integration/models/os.spec.ts +++ b/tests/integration/models/os.spec.ts @@ -450,6 +450,49 @@ describe('OS model', function () { const promise = balena.models.os.download('foo-bar-baz'); return expect(promise).to.be.rejectedWith('No such device type'); })); + + describe('given well formed and malformed balenaOS versions', () => { + it('should reject malformed versions with an error', async () => { + const versions = [ + '2.60.1+foo', + '2.60.1-foo', + '2.60.1.foo', + '2.60.1+rev', + '2.60.1+rev1+foo', + '2.60.1+rev1-foo', + '2.60.1+rev1.foo', + '2.60.1+rev1.dev.foo', + '2.60.1+rev1.prod.foo', + ]; + for (const version of [...versions]) { + versions.push(`v${version}`); + } + for (const version of versions) { + await expect( + balena.models.os.download('raspberry-pi', version), + ).to.be.rejectedWith(`Invalid balenaOS version format: ${version}`); + } + }); + + it('should accept well formed versions', async () => { + const versions = [ + '0.0.1', + '0.0.1.dev', + '0.0.1.prod', + '0.0.1+rev1', + '0.0.1+rev1.dev', + '0.0.1+rev1.prod', + ]; + for (const version of [...versions]) { + versions.push(`v${version}`); + } + for (const version of versions) { + await expect( + balena.models.os.download('raspberry-pi', version), + ).to.be.rejectedWith(`No such version for the device type`); + } + }); + }); }); describe('balena.models.os.isSupportedOsUpdate()', function () {