mirror of
https://github.com/balena-os/balena-supervisor.git
synced 2025-01-20 11:38:51 +00:00
Merge pull request #2090 from balena-os/colon-config-vars
Allow using colon character in config vars
This commit is contained in:
commit
afc1372655
@ -87,25 +87,22 @@ export type NumericIdentifier = t.TypeOf<typeof NumericIdentifier>;
|
||||
*/
|
||||
const VAR_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
|
||||
|
||||
export const VariableName = new t.Type<string, string>(
|
||||
'VariableName',
|
||||
(s: unknown): s is string => ShortString.is(s) && VAR_NAME_REGEX.test(s),
|
||||
(i, c) =>
|
||||
pipe(
|
||||
ShortString.validate(i, c),
|
||||
chain((s) =>
|
||||
VAR_NAME_REGEX.test(s)
|
||||
? t.success(s)
|
||||
: t.failure(
|
||||
s,
|
||||
c,
|
||||
"needs to start with a letter and may only contain alphanumeric characters plus '_'",
|
||||
),
|
||||
/**
|
||||
* Config vars also allow a colon in the name
|
||||
*/
|
||||
const CONFIG_VAR_NAME_REGEX = /^[a-zA-Z_][a-zA-Z0-9_:]*$/;
|
||||
|
||||
const shortStringWithRegex = (name: string, regex: RegExp, message: string) =>
|
||||
new t.Type<string, string>(
|
||||
name,
|
||||
(s: unknown): s is string => ShortString.is(s) && VAR_NAME_REGEX.test(s),
|
||||
(i, c) =>
|
||||
pipe(
|
||||
ShortString.validate(i, c),
|
||||
chain((s) => (regex.test(s) ? t.success(s) : t.failure(s, c, message))),
|
||||
),
|
||||
),
|
||||
t.identity,
|
||||
);
|
||||
export type VariableName = t.TypeOf<typeof VariableName>;
|
||||
t.identity,
|
||||
);
|
||||
|
||||
/**
|
||||
* Valid label names are between 0 and 255 characters
|
||||
@ -115,30 +112,37 @@ export type VariableName = t.TypeOf<typeof VariableName>;
|
||||
*/
|
||||
const LABEL_NAME_REGEX = /^[!#-&(-_a-~]+$/;
|
||||
|
||||
export const LabelName = new t.Type<string, string>(
|
||||
export const LabelName = shortStringWithRegex(
|
||||
'LabelName',
|
||||
(s: unknown): s is string => ShortString.is(s) && LABEL_NAME_REGEX.test(s),
|
||||
(i, c) =>
|
||||
pipe(
|
||||
ShortString.validate(i, c),
|
||||
chain((s) =>
|
||||
LABEL_NAME_REGEX.test(s)
|
||||
? t.success(s)
|
||||
: t.failure(
|
||||
s,
|
||||
c,
|
||||
'may contain printable ASCII characters except space, single/double quotes and backtick',
|
||||
),
|
||||
),
|
||||
),
|
||||
t.identity,
|
||||
LABEL_NAME_REGEX,
|
||||
'may contain printable ASCII characters except space, single/double quotes and backtick',
|
||||
);
|
||||
export type LabelName = t.TypeOf<typeof LabelName>;
|
||||
|
||||
/**
|
||||
* An env var object is a dictionary with valid variables as keys
|
||||
*/
|
||||
export const EnvVarObject = t.record(VariableName, t.string);
|
||||
export const ConfigVarObject = t.record(
|
||||
shortStringWithRegex(
|
||||
'ConfigVarName',
|
||||
CONFIG_VAR_NAME_REGEX,
|
||||
"needs to start with a letter and may only contain alphanumeric characters plus '_' or ':'",
|
||||
),
|
||||
t.string,
|
||||
);
|
||||
export type ConfigVarObject = t.TypeOf<typeof ConfigVarObject>;
|
||||
|
||||
/**
|
||||
* An env var object is a dictionary with valid variables as keys
|
||||
*/
|
||||
export const EnvVarObject = t.record(
|
||||
shortStringWithRegex(
|
||||
'EnvVarName',
|
||||
VAR_NAME_REGEX,
|
||||
"needs to start with a letter and may only contain alphanumeric characters plus '_'",
|
||||
),
|
||||
t.string,
|
||||
);
|
||||
export type EnvVarObject = t.TypeOf<typeof EnvVarObject>;
|
||||
|
||||
/**
|
||||
@ -151,19 +155,10 @@ export type LabelObject = t.TypeOf<typeof LabelObject>;
|
||||
// https://github.com/moby/moby/blob/04c6f09fbdf60c7765cc4cb78883faaa9d971fa5/daemon/daemon.go#L56
|
||||
// [a-zA-Z0-9][a-zA-Z0-9_.-]
|
||||
const DOCKER_NAME_REGEX = /^[a-zA-Z0-9][a-zA-Z0-9_\.\-]*$/;
|
||||
export const DockerName = new t.Type<string, string>(
|
||||
'DockerName',
|
||||
(s: unknown): s is string => ShortString.is(s) && DOCKER_NAME_REGEX.test(s),
|
||||
(i, c) =>
|
||||
pipe(
|
||||
ShortString.validate(i, c),
|
||||
chain((s) =>
|
||||
DOCKER_NAME_REGEX.test(s)
|
||||
? t.success(s)
|
||||
: t.failure(s, c, 'only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed'),
|
||||
),
|
||||
),
|
||||
t.identity,
|
||||
export const DockerName = shortStringWithRegex(
|
||||
'LabelName',
|
||||
DOCKER_NAME_REGEX,
|
||||
'only "[a-zA-Z0-9][a-zA-Z0-9_.-]" are allowed',
|
||||
);
|
||||
export type DockerName = t.TypeOf<typeof DockerName>;
|
||||
|
||||
|
@ -7,6 +7,7 @@ import { ComposeVolumeConfig } from '../compose/volume';
|
||||
import {
|
||||
DockerName,
|
||||
EnvVarObject,
|
||||
ConfigVarObject,
|
||||
LabelObject,
|
||||
NumericIdentifier,
|
||||
ShortString,
|
||||
@ -274,7 +275,7 @@ export type TargetApps = t.TypeOf<typeof TargetApps>;
|
||||
const TargetDevice = t.intersection([
|
||||
t.type({
|
||||
name: DeviceName,
|
||||
config: EnvVarObject,
|
||||
config: ConfigVarObject,
|
||||
apps: TargetApps,
|
||||
}),
|
||||
t.partial({
|
||||
@ -350,7 +351,7 @@ const TargetAppWithRelease = t.intersection([
|
||||
|
||||
export const AppsJsonFormat = t.intersection([
|
||||
t.type({
|
||||
config: withDefault(EnvVarObject, {}),
|
||||
config: withDefault(ConfigVarObject, {}),
|
||||
apps: withDefault(t.record(UUID, TargetAppWithRelease), {}),
|
||||
}),
|
||||
t.partial({ pinDevice: t.boolean }),
|
||||
|
@ -8,6 +8,7 @@ import {
|
||||
DeviceName,
|
||||
NumericIdentifier,
|
||||
TargetApps,
|
||||
TargetState,
|
||||
} from '~/src/types';
|
||||
|
||||
import * as validation from '~/lib/validation';
|
||||
@ -493,4 +494,47 @@ describe('validation', () => {
|
||||
).to.be.false;
|
||||
});
|
||||
});
|
||||
|
||||
describe('target state', () => {
|
||||
it('accepts target state with config vars and apps', () => {
|
||||
expect(
|
||||
isRight(
|
||||
TargetState.decode({
|
||||
one: {
|
||||
name: 'angry-einstein',
|
||||
config: {
|
||||
BALENA_HOST_CONFIG_hdmi_force_hotplug: '0',
|
||||
'BALENA_HOST_CONFIG_hdmi_force_hotplug:1': '1',
|
||||
BALENA_HOST_CONFIG_dtoverlay: 'balena-fin',
|
||||
},
|
||||
apps: {},
|
||||
},
|
||||
}),
|
||||
),
|
||||
).to.be.true;
|
||||
});
|
||||
|
||||
it('rejects target state with an invalid config vars', () => {
|
||||
expect(
|
||||
isRight(
|
||||
TargetState.decode({
|
||||
one: {
|
||||
name: 'angry-einstein',
|
||||
config: {
|
||||
'BALENA_CONFIG_ INVALID VAR': '123',
|
||||
},
|
||||
apps: {
|
||||
abcd: {
|
||||
id: 1234,
|
||||
name: 'something',
|
||||
class: 'fleet',
|
||||
releases: {},
|
||||
},
|
||||
},
|
||||
},
|
||||
}),
|
||||
),
|
||||
).to.be.false;
|
||||
});
|
||||
});
|
||||
});
|
||||
|
Loading…
Reference in New Issue
Block a user