Skip to content

Commit

Permalink
Define schema for managed fields of "os" config.json key
Browse files Browse the repository at this point in the history
As there are also fields in "os" which are not managed by the
Supervisor, the Supervisor should not be aware of them.
Using t.exact and t.partial to define the managed fields
ensures that unmanaged fields are filtered out when decoding
with io-ts.

Signed-off-by: Christina Ying Wang <[email protected]>
  • Loading branch information
cywang117 committed Oct 19, 2024
1 parent 775e62e commit e6463cb
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 0 deletions.
20 changes: 20 additions & 0 deletions src/config/schema-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,26 @@ export const schemaTypes = {
type: t.string,
default: NullOrUndefined,
},
// Protected config.json types
// As protected object fields may contain keys that are unmanaged,
// use exact or strict types to filter out unrelated keys when decoding.
os: {
type: t.exact(
t.partial({
power: t.exact(
t.partial({
mode: t.string,
}),
),
fan: t.exact(
t.partial({
profile: t.string,
}),
),
}),
),
default: t.never,
},

// Database types
name: {
Expand Down
12 changes: 12 additions & 0 deletions src/config/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,18 @@ export const schema = {
mutable: false,
removeIfNull: false,
},
/**
* Protected fields
*
* `mutable` & `removeIfNull` do not apply to protected fields, so are
* set to false to avoid modifications or deletions which do not go through
* the protected workflow.
*/
os: {
source: 'config.json',
mutable: false,
removeIfNull: false,
},

name: {
source: 'db',
Expand Down
119 changes: 119 additions & 0 deletions test/unit/config/schema-type.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import { expect } from 'chai';
import { isRight, isLeft } from 'fp-ts/lib/Either';

import { schemaTypes } from '~/src/config/schema-type';

describe('SchemaType', () => {
describe('os.power.mode / os.fan.profile', () => {
it('should decode to right if managed configs are present', () => {
const managedOsConfig = {
power: {
mode: 'low',
},
fan: {
profile: 'quiet',
},
};
const decoded = schemaTypes.os.type.decode(managedOsConfig);

expect(isRight(decoded)).to.be.true;
expect((decoded as any).right).to.deep.equal({
power: { mode: 'low' },
fan: { profile: 'quiet' },
});
});

it('should decode to right if managed configs are partially present', () => {
const powerMode = {
power: {
mode: 'high',
},
};
const decoded = schemaTypes.os.type.decode(powerMode);

expect(isRight(decoded)).to.be.true;
expect((decoded as any).right).to.deep.equal({
power: { mode: 'high' },
});

const fanProfile = {
fan: {
profile: 'cool',
},
};
const decodedFanProfile = schemaTypes.os.type.decode(fanProfile);

expect(isRight(decodedFanProfile)).to.be.true;
expect((decodedFanProfile as any).right).to.deep.equal({
fan: { profile: 'cool' },
});
});

it('should decode to right while filtering out unrelated keys', () => {
const configWithExtras = {
power: {
mode: 'high',
someKey: 'someValue',
},
fan: {
otherKey: 'otherValue',
},
};
const decoded = schemaTypes.os.type.decode(configWithExtras);

expect(isRight(decoded)).to.be.true;
expect((decoded as any).right).to.deep.equal({
power: { mode: 'high' },
fan: {},
});
});

it('should decode to right as empty object if no managed configs are present', () => {
const decoded = schemaTypes.os.type.decode({});

expect(isRight(decoded)).to.be.true;
expect((decoded as any).right).to.deep.equal({});
});

it('should decode to left if managed configs are not the right type', () => {
const decoded = schemaTypes.os.type.decode({
power: 'high',
fan: {
profile: 123,
},
});

expect(isLeft(decoded)).to.be.true;
});

it('should filter out unmanaged fields', () => {
const withUnmanagedFields = {
power: {
mode: 'high',
someKey: 'someValue',
},
fan: {
profile: 'cool',
otherKey: 'otherValue',
},
network: {
connectivity: {
uri: 'https://api.balena-cloud.com/connectivity-check',
interval: '300',
response: 'optional value in the response',
},
wifi: {
randomMacAddressScan: false,
},
},
};
const decoded = schemaTypes.os.type.decode(withUnmanagedFields);

expect(isRight(decoded)).to.be.true;
expect((decoded as any).right).to.deep.equal({
power: { mode: 'high' },
fan: { profile: 'cool' },
});
});
});
});

0 comments on commit e6463cb

Please sign in to comment.