mirror of
https://github.com/balena-io/balena-cli.git
synced 2025-01-19 19:29:02 +00:00
Merge pull request #2619 from balena-io/alexgg/sb
os configure, config generate: Add '--secureBoot' option to opt-in secure boot
This commit is contained in:
commit
9a8b0b4a0d
2
.github/workflows/flowzone.yml
vendored
2
.github/workflows/flowzone.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
)
|
||||
secrets: inherit
|
||||
with:
|
||||
custom_runs_on: '[["self-hosted","Linux","distro:focal","X64"],["self-hosted","Linux","distro:focal","ARM64"],["macos-11"],["windows-2019"]]'
|
||||
custom_runs_on: '[["self-hosted","Linux","distro:focal","X64"],["self-hosted","Linux","distro:focal","ARM64"],["macos-12"],["windows-2019"]]'
|
||||
repo_config: true
|
||||
repo_description: "The official balena CLI tool."
|
||||
github_prerelease: true
|
||||
|
@ -2160,6 +2160,9 @@ confuse the balenaOS "development mode" with a device's "local mode", the latter
|
||||
being a supervisor feature that allows the "balena push" command to push a user's
|
||||
application directly to a device in the local network.
|
||||
|
||||
The '--secureBoot' option is used to configure a balenaOS installer image to opt-in
|
||||
secure boot and disk encryption.
|
||||
|
||||
The --system-connection (-c) option is used to inject NetworkManager connection
|
||||
profiles for additional network interfaces, such as cellular/GSM or additional
|
||||
WiFi or ethernet connections. This option may be passed multiple times in case there
|
||||
@ -2230,6 +2233,10 @@ WiFi SSID (network name) (non-interactive configuration)
|
||||
|
||||
Configure balenaOS to operate in development mode
|
||||
|
||||
#### --secureBoot
|
||||
|
||||
Configure balenaOS installer to opt-in secure boot and disk encryption
|
||||
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device UUID
|
||||
@ -2314,6 +2321,9 @@ confuse the balenaOS "development mode" with a device's "local mode", the latter
|
||||
being a supervisor feature that allows the "balena push" command to push a user's
|
||||
application directly to a device in the local network.
|
||||
|
||||
The '--secureBoot' option is used to configure a balenaOS installer image to opt-in
|
||||
secure boot and disk encryption.
|
||||
|
||||
To configure an image for a fleet of mixed device types, use the --fleet option
|
||||
alongside the --deviceType option to specify the target device type.
|
||||
|
||||
@ -2337,6 +2347,7 @@ Examples:
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --deviceApiKey <existingDeviceKey>
|
||||
$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json
|
||||
$ balena config generate --fleet myorg/fleet --version 2.12.7 --dev
|
||||
$ balena config generate --fleet myorg/fleet --version 2.12.7 --secureBoot
|
||||
$ balena config generate --fleet myorg/fleet --version 2.12.7 --deviceType fincm3
|
||||
$ balena config generate --fleet myorg/fleet --version 2.12.7 --output config.json
|
||||
$ balena config generate --fleet myorg/fleet --version 2.12.7 --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 15
|
||||
@ -2355,6 +2366,10 @@ fleet name or slug (preferred)
|
||||
|
||||
Configure balenaOS to operate in development mode
|
||||
|
||||
#### --secureBoot
|
||||
|
||||
Configure balenaOS installer to opt-in secure boot and disk encryption
|
||||
|
||||
#### -d, --device DEVICE
|
||||
|
||||
device UUID
|
||||
|
@ -19,13 +19,18 @@ import { flags } from '@oclif/command';
|
||||
import Command from '../../command';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, getCliForm, stripIndent } from '../../utils/lazy';
|
||||
import { applicationIdInfo, devModeInfo } from '../../utils/messages';
|
||||
import {
|
||||
applicationIdInfo,
|
||||
devModeInfo,
|
||||
secureBootInfo,
|
||||
} from '../../utils/messages';
|
||||
import type { PineDeferred } from 'balena-sdk';
|
||||
|
||||
interface FlagsDef {
|
||||
version: string; // OS version
|
||||
fleet?: string;
|
||||
dev?: boolean; // balenaOS development variant
|
||||
secureBoot?: boolean;
|
||||
device?: string;
|
||||
deviceApiKey?: string;
|
||||
deviceType?: string;
|
||||
@ -51,6 +56,8 @@ export default class ConfigGenerateCmd extends Command {
|
||||
|
||||
${devModeInfo.split('\n').join('\n\t\t')}
|
||||
|
||||
${secureBootInfo.split('\n').join('\n\t\t')}
|
||||
|
||||
To configure an image for a fleet of mixed device types, use the --fleet option
|
||||
alongside the --deviceType option to specify the target device type.
|
||||
|
||||
@ -66,6 +73,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
'$ balena config generate --device 7cf02a6 --version 2.12.7 --deviceApiKey <existingDeviceKey>',
|
||||
'$ balena config generate --device 7cf02a6 --version 2.12.7 --output config.json',
|
||||
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --dev',
|
||||
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --secureBoot',
|
||||
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --deviceType fincm3',
|
||||
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --output config.json',
|
||||
'$ balena config generate --fleet myorg/fleet --version 2.12.7 --network wifi --wifiSsid mySsid --wifiKey abcdefgh --appUpdatePollInterval 15',
|
||||
@ -80,6 +88,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
}),
|
||||
fleet: { ...cf.fleet, exclusive: ['device'] },
|
||||
dev: cf.dev,
|
||||
secureBoot: cf.secureBoot,
|
||||
device: {
|
||||
...cf.device,
|
||||
exclusive: [
|
||||
@ -195,6 +204,15 @@ export default class ConfigGenerateCmd extends Command {
|
||||
deviceType,
|
||||
);
|
||||
|
||||
const { validateSecureBootOptionAndWarn } = await import(
|
||||
'../../utils/config'
|
||||
);
|
||||
await validateSecureBootOptionAndWarn(
|
||||
options.secureBoot,
|
||||
deviceType,
|
||||
options.version,
|
||||
);
|
||||
|
||||
// Prompt for values
|
||||
// Pass params as an override: if there is any param with exactly the same name as a
|
||||
// required option, that value is used (and the corresponding question is not asked)
|
||||
@ -203,6 +221,7 @@ export default class ConfigGenerateCmd extends Command {
|
||||
});
|
||||
answers.version = options.version;
|
||||
answers.developmentMode = options.dev;
|
||||
answers.secureBoot = options.secureBoot;
|
||||
answers.provisioningKeyName = options['provisioning-key-name'];
|
||||
answers.provisioningKeyExpiryDate = options['provisioning-key-expiry-date'];
|
||||
|
||||
|
@ -23,7 +23,11 @@ import Command from '../../command';
|
||||
import { ExpectedError } from '../../errors';
|
||||
import * as cf from '../../utils/common-flags';
|
||||
import { getBalenaSdk, stripIndent, getCliForm } from '../../utils/lazy';
|
||||
import { applicationIdInfo, devModeInfo } from '../../utils/messages';
|
||||
import {
|
||||
applicationIdInfo,
|
||||
devModeInfo,
|
||||
secureBootInfo,
|
||||
} from '../../utils/messages';
|
||||
|
||||
const CONNECTIONS_FOLDER = '/system-connections';
|
||||
|
||||
@ -36,6 +40,7 @@ interface FlagsDef {
|
||||
'config-wifi-key'?: string;
|
||||
'config-wifi-ssid'?: string;
|
||||
dev?: boolean; // balenaOS development variant
|
||||
secureBoot?: boolean;
|
||||
device?: string; // device UUID
|
||||
'device-type'?: string;
|
||||
help?: void;
|
||||
@ -53,6 +58,7 @@ interface ArgsDef {
|
||||
interface Answers {
|
||||
appUpdatePollInterval: number; // in minutes
|
||||
developmentMode?: boolean; // balenaOS development variant
|
||||
secureBoot?: boolean;
|
||||
deviceType: string; // e.g. "raspberrypi3"
|
||||
network: 'ethernet' | 'wifi';
|
||||
version: string; // e.g. "2.32.0+rev1"
|
||||
@ -80,6 +86,8 @@ export default class OsConfigureCmd extends Command {
|
||||
|
||||
${devModeInfo.split('\n').join('\n\t\t')}
|
||||
|
||||
${secureBootInfo.split('\n').join('\n\t\t')}
|
||||
|
||||
The --system-connection (-c) option is used to inject NetworkManager connection
|
||||
profiles for additional network interfaces, such as cellular/GSM or additional
|
||||
WiFi or ethernet connections. This option may be passed multiple times in case there
|
||||
@ -140,6 +148,7 @@ export default class OsConfigureCmd extends Command {
|
||||
description: 'WiFi SSID (network name) (non-interactive configuration)',
|
||||
}),
|
||||
dev: cf.dev,
|
||||
secureBoot: cf.secureBoot,
|
||||
device: {
|
||||
...cf.device,
|
||||
exclusive: [
|
||||
@ -238,6 +247,15 @@ export default class OsConfigureCmd extends Command {
|
||||
const { validateDevOptionAndWarn } = await import('../../utils/config');
|
||||
await validateDevOptionAndWarn(options.dev, osVersion);
|
||||
|
||||
const { validateSecureBootOptionAndWarn } = await import(
|
||||
'../../utils/config'
|
||||
);
|
||||
await validateSecureBootOptionAndWarn(
|
||||
options.secureBoot,
|
||||
deviceTypeSlug,
|
||||
osVersion,
|
||||
);
|
||||
|
||||
const answers: Answers = await askQuestionsForDeviceType(
|
||||
deviceTypeManifest,
|
||||
options,
|
||||
@ -248,6 +266,7 @@ export default class OsConfigureCmd extends Command {
|
||||
}
|
||||
answers.version = osVersion;
|
||||
answers.developmentMode = options.dev;
|
||||
answers.secureBoot = options.secureBoot;
|
||||
answers.provisioningKeyName = options['provisioning-key-name'];
|
||||
answers.provisioningKeyExpiryDate = options['provisioning-key-expiry-date'];
|
||||
|
||||
|
@ -74,6 +74,12 @@ export const dev: IBooleanFlag<boolean> = flags.boolean({
|
||||
default: false,
|
||||
});
|
||||
|
||||
export const secureBoot: IBooleanFlag<boolean> = flags.boolean({
|
||||
description:
|
||||
'Configure balenaOS installer to opt-in secure boot and disk encryption',
|
||||
default: false,
|
||||
});
|
||||
|
||||
export const drive = flags.string({
|
||||
char: 'd',
|
||||
description: stripIndent`
|
||||
|
@ -52,6 +52,10 @@ export interface ImgConfig {
|
||||
os?: {
|
||||
sshKeys?: string[];
|
||||
};
|
||||
|
||||
installer?: {
|
||||
secureboot?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export async function generateApplicationConfig(
|
||||
@ -63,6 +67,7 @@ export async function generateApplicationConfig(
|
||||
os?: {
|
||||
sshKeys?: string[];
|
||||
};
|
||||
secureBoot?: boolean;
|
||||
},
|
||||
): Promise<ImgConfig> {
|
||||
options = {
|
||||
@ -84,6 +89,12 @@ export async function generateApplicationConfig(
|
||||
: options.os.sshKeys;
|
||||
}
|
||||
|
||||
// configure installer secure boot opt-in if specified
|
||||
if (options.secureBoot) {
|
||||
config.installer ??= {};
|
||||
config.installer.secureboot = options.secureBoot;
|
||||
}
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
@ -165,3 +176,62 @@ export async function validateDevOptionAndWarn(
|
||||
and exposes network ports such as 2375 that allows unencrypted access to balenaEngine.
|
||||
Therefore, development mode should only be used in private, trusted local networks.`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Chech whether the `--secureBoot` option of commands related to OS configuration
|
||||
* such as `os configure` and `config generate` is compatible with a given
|
||||
* OS release, and print a warning regarding the consequences of using that
|
||||
* option.
|
||||
*/
|
||||
export async function validateSecureBootOptionAndWarn(
|
||||
secureBoot?: boolean,
|
||||
slug?: string,
|
||||
version?: string,
|
||||
logger?: import('./logger'),
|
||||
) {
|
||||
if (!secureBoot) {
|
||||
return;
|
||||
}
|
||||
const { ExpectedError } = await import('../errors');
|
||||
if (!version) {
|
||||
throw new ExpectedError(`Error: No version provided`);
|
||||
}
|
||||
if (!slug) {
|
||||
throw new ExpectedError(`Error: No device type provided`);
|
||||
}
|
||||
const sdk = getBalenaSdk();
|
||||
const releasePineOpts = {
|
||||
$select: 'contract',
|
||||
$filter: { raw_version: `${version.replace(/^v/, '')}` },
|
||||
} satisfies BalenaSdk.PineOptions<BalenaSdk.Release>;
|
||||
// TODO: Remove the added type casting when the SDK returns the fully typed result
|
||||
const [osRelease] = (await sdk.models.os.getAllOsVersions(
|
||||
slug,
|
||||
releasePineOpts,
|
||||
)) as Array<
|
||||
BalenaSdk.OsVersion &
|
||||
BalenaSdk.PineTypedResult<BalenaSdk.Release, typeof releasePineOpts>
|
||||
>;
|
||||
if (!osRelease) {
|
||||
throw new ExpectedError(`Error: No ${version} release for ${slug}`);
|
||||
}
|
||||
|
||||
const contract = osRelease.contract ? JSON.parse(osRelease.contract) : null;
|
||||
if (
|
||||
contract?.provides.some((entry: Dictionary<string>) => {
|
||||
return entry.type === 'sw.feature' && entry.slug === 'secureboot';
|
||||
})
|
||||
) {
|
||||
if (!logger) {
|
||||
const Logger = await import('./logger');
|
||||
logger = Logger.getLogger();
|
||||
}
|
||||
logger.logInfo(stripIndent`
|
||||
The '--secureBoot' option is being used to configure a balenaOS installer image
|
||||
into secure boot and full disk encryption.`);
|
||||
} else {
|
||||
throw new ExpectedError(
|
||||
`Error: The '--secureBoot' option is not supported for ${slug} in ${version}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -169,6 +169,10 @@ confuse the balenaOS "development mode" with a device's "local mode", the latter
|
||||
being a supervisor feature that allows the "balena push" command to push a user's
|
||||
application directly to a device in the local network.`;
|
||||
|
||||
export const secureBootInfo = `\
|
||||
The '--secureBoot' option is used to configure a balenaOS installer image to opt-in
|
||||
secure boot and disk encryption.`;
|
||||
|
||||
export const jsonInfo = `\
|
||||
The --json option is recommended when scripting the output of this command,
|
||||
because field names are less likely to change in JSON format and because it
|
||||
|
42
npm-shrinkwrap.json
generated
42
npm-shrinkwrap.json
generated
@ -24,7 +24,7 @@
|
||||
"balena-image-fs": "^7.0.6",
|
||||
"balena-image-manager": "^8.0.0",
|
||||
"balena-preload": "^13.0.0",
|
||||
"balena-sdk": "^16.40.0",
|
||||
"balena-sdk": "^16.44.2",
|
||||
"balena-semver": "^2.3.0",
|
||||
"balena-settings-client": "^4.0.7",
|
||||
"balena-settings-storage": "^7.0.0",
|
||||
@ -3048,9 +3048,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "16.18.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.30.tgz",
|
||||
"integrity": "sha512-Kmp/wBZk19Dn7uRiol8kF8agnf8m0+TU9qIwyfPmXglVxMlmiIz0VQSMw5oFgwhmD2aKTlfBIO5FtsVj3y7hKQ=="
|
||||
"version": "16.18.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.31.tgz",
|
||||
"integrity": "sha512-KPXltf4z4g517OlVJO9XQ2357CYw7fvuJ3ZuBynjXC5Jos9i+K7LvFb7bUIwtJXSZj0vTp9Q6NJBSQpkwwO8Zw=="
|
||||
},
|
||||
"node_modules/@types/node-cleanup": {
|
||||
"version": "2.1.2",
|
||||
@ -4148,9 +4148,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/balena-sdk": {
|
||||
"version": "16.40.0",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-16.40.0.tgz",
|
||||
"integrity": "sha512-w7oP/oESZnymWtngieQrR3YJAR+CLSnys5RllPZBtZ5vYZsSHdrdRRMamlemy5ydCQN4q66Uw95U20bBXigT5g==",
|
||||
"version": "16.45.1",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-16.45.1.tgz",
|
||||
"integrity": "sha512-pY3anTkmEcOp8GEgjkeJl8aj7SZBWifh4DSp8sUnryE0U7IGA3UcKggsfMjYsP1ZKvPlAvweNHQuUujfBOHbXg==",
|
||||
"dependencies": {
|
||||
"@balena/es-version": "^1.0.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
@ -4527,6 +4527,7 @@
|
||||
"node_modules/bonjour": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "git+ssh://git@github.com/balena-io-modules/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
||||
"integrity": "sha512-JCw9ygNWGhAngIABMPiBlBlyPYVDFwllFa0Xuory9yatGday0pmSBRJhYMXqIJ4vmqDkPVqTD5JV+YM8ypLRKg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"array-flatten": "^2.1.0",
|
||||
@ -13488,6 +13489,7 @@
|
||||
"node_modules/multicast-dns": {
|
||||
"version": "6.1.1",
|
||||
"resolved": "git+ssh://git@github.com/resin-io-modules/multicast-dns.git#db98d68b79bbefc936b6799de9de1038ba49f85d",
|
||||
"integrity": "sha512-AYHxmNN71KOfxHElYREhx8LqjIpfc3WFhq+Oht9IOEk82jXXF9qRavowyUvc9JLkPjUzLZmjy14/a1NtBduQoQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"dns-packet": "^1.0.1",
|
||||
@ -19435,9 +19437,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
|
||||
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA=="
|
||||
},
|
||||
"node_modules/tslint": {
|
||||
"version": "6.1.3",
|
||||
@ -24890,9 +24892,9 @@
|
||||
}
|
||||
},
|
||||
"@types/node": {
|
||||
"version": "16.18.30",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.30.tgz",
|
||||
"integrity": "sha512-Kmp/wBZk19Dn7uRiol8kF8agnf8m0+TU9qIwyfPmXglVxMlmiIz0VQSMw5oFgwhmD2aKTlfBIO5FtsVj3y7hKQ=="
|
||||
"version": "16.18.31",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.31.tgz",
|
||||
"integrity": "sha512-KPXltf4z4g517OlVJO9XQ2357CYw7fvuJ3ZuBynjXC5Jos9i+K7LvFb7bUIwtJXSZj0vTp9Q6NJBSQpkwwO8Zw=="
|
||||
},
|
||||
"@types/node-cleanup": {
|
||||
"version": "2.1.2",
|
||||
@ -25814,9 +25816,9 @@
|
||||
}
|
||||
},
|
||||
"balena-sdk": {
|
||||
"version": "16.40.0",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-16.40.0.tgz",
|
||||
"integrity": "sha512-w7oP/oESZnymWtngieQrR3YJAR+CLSnys5RllPZBtZ5vYZsSHdrdRRMamlemy5ydCQN4q66Uw95U20bBXigT5g==",
|
||||
"version": "16.45.1",
|
||||
"resolved": "https://registry.npmjs.org/balena-sdk/-/balena-sdk-16.45.1.tgz",
|
||||
"integrity": "sha512-pY3anTkmEcOp8GEgjkeJl8aj7SZBWifh4DSp8sUnryE0U7IGA3UcKggsfMjYsP1ZKvPlAvweNHQuUujfBOHbXg==",
|
||||
"requires": {
|
||||
"@balena/es-version": "^1.0.0",
|
||||
"@types/json-schema": "^7.0.9",
|
||||
@ -26149,6 +26151,7 @@
|
||||
},
|
||||
"bonjour": {
|
||||
"version": "git+ssh://git@github.com/balena-io-modules/bonjour.git#e018851dc823b4b3f670f658f71d0c1c7f3e637c",
|
||||
"integrity": "sha512-JCw9ygNWGhAngIABMPiBlBlyPYVDFwllFa0Xuory9yatGday0pmSBRJhYMXqIJ4vmqDkPVqTD5JV+YM8ypLRKg==",
|
||||
"from": "bonjour@git+https://github.com/balena-io-modules/bonjour.git#fixed-mdns",
|
||||
"requires": {
|
||||
"array-flatten": "^2.1.0",
|
||||
@ -33190,6 +33193,7 @@
|
||||
},
|
||||
"multicast-dns": {
|
||||
"version": "git+ssh://git@github.com/resin-io-modules/multicast-dns.git#db98d68b79bbefc936b6799de9de1038ba49f85d",
|
||||
"integrity": "sha512-AYHxmNN71KOfxHElYREhx8LqjIpfc3WFhq+Oht9IOEk82jXXF9qRavowyUvc9JLkPjUzLZmjy14/a1NtBduQoQ==",
|
||||
"from": "multicast-dns@git+https://github.com/resin-io-modules/multicast-dns#listen-on-all-interfaces",
|
||||
"requires": {
|
||||
"dns-packet": "^1.0.1",
|
||||
@ -37863,9 +37867,9 @@
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.5.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.0.tgz",
|
||||
"integrity": "sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg=="
|
||||
"version": "2.5.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.5.2.tgz",
|
||||
"integrity": "sha512-5svOrSA2w3iGFDs1HibEVBGbDrAY82bFQ3HZ3ixB+88nsbsWQoKqDRb5UBYAUPEzbBn6dAp5gRNXglySbx1MlA=="
|
||||
},
|
||||
"tslint": {
|
||||
"version": "6.1.3",
|
||||
|
@ -207,7 +207,7 @@
|
||||
"balena-image-fs": "^7.0.6",
|
||||
"balena-image-manager": "^8.0.0",
|
||||
"balena-preload": "^13.0.0",
|
||||
"balena-sdk": "^16.40.0",
|
||||
"balena-sdk": "^16.44.2",
|
||||
"balena-semver": "^2.3.0",
|
||||
"balena-settings-client": "^4.0.7",
|
||||
"balena-settings-storage": "^7.0.0",
|
||||
|
Loading…
Reference in New Issue
Block a user