@toa.io/extensions.configuration 1.0.1 → 1.1.0-dev.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +7 -7
- package/readme.md +15 -11
- package/source/.deployment/index.js +7 -0
- package/source/.deployment/secrets.js +33 -0
- package/{src/deployment.js → source/.deployment/variables.js} +7 -4
- package/{src → source}/.manifest/.normalize/verbose.js +7 -3
- package/{test/annotations.test.js → source/annotation.test.js} +1 -1
- package/source/deployment.js +20 -0
- package/{test → source}/deployment.test.js +26 -1
- package/{test → source}/manifest.test.js +0 -3
- package/{src → source}/provider.js +19 -14
- package/source/provider.test.js +89 -0
- package/source/secrets.js +28 -0
- package/source/secrets.test.js +47 -0
- /package/{src → source}/.manifest/index.js +0 -0
- /package/{src → source}/.manifest/normalize.js +0 -0
- /package/{src → source}/.manifest/schema.yaml +0 -0
- /package/{src → source}/.manifest/validate.js +0 -0
- /package/{src → source}/.provider/form.js +0 -0
- /package/{test/annotations.fixtures.js → source/annotation.fixtures.js} +0 -0
- /package/{src → source}/annotation.js +0 -0
- /package/{test → source}/aspect.fixtures.js +0 -0
- /package/{src → source}/aspect.js +0 -0
- /package/{test → source}/aspect.test.js +0 -0
- /package/{src → source}/configuration.js +0 -0
- /package/{test → source}/deployment.fixtures.js +0 -0
- /package/{src → source}/factory.js +0 -0
- /package/{test → source}/factory.test.js +0 -0
- /package/{src → source}/index.js +0 -0
- /package/{src → source}/manifest.js +0 -0
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@toa.io/extensions.configuration",
|
|
3
|
-
"version": "1.0.1",
|
|
3
|
+
"version": "1.1.0-dev.1",
|
|
4
4
|
"description": "Toa Configuration",
|
|
5
5
|
"author": "temich <tema.gurtovoy@gmail.com>",
|
|
6
6
|
"homepage": "https://github.com/toa-io/toa#readme",
|
|
7
|
-
"main": "
|
|
7
|
+
"main": "source/index.js",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
10
10
|
"url": "git+https://github.com/toa-io/toa.git"
|
|
@@ -16,11 +16,11 @@
|
|
|
16
16
|
"access": "public"
|
|
17
17
|
},
|
|
18
18
|
"dependencies": {
|
|
19
|
-
"@toa.io/core": "1.0.1",
|
|
20
|
-
"@toa.io/generic": "0.
|
|
21
|
-
"@toa.io/schema": "0.7.
|
|
22
|
-
"@toa.io/yaml": "0.7.
|
|
19
|
+
"@toa.io/core": "1.1.0-dev.1",
|
|
20
|
+
"@toa.io/generic": "0.11.0-dev.1",
|
|
21
|
+
"@toa.io/schema": "0.7.6-dev.1",
|
|
22
|
+
"@toa.io/yaml": "0.7.6-dev.1",
|
|
23
23
|
"clone-deep": "4.0.1"
|
|
24
24
|
},
|
|
25
|
-
"gitHead": "
|
|
25
|
+
"gitHead": "ef65d2f42f13aac397c14f8c47eb026a191cda66"
|
|
26
26
|
}
|
package/readme.md
CHANGED
|
@@ -30,15 +30,15 @@ function transition (input, entity, context) {
|
|
|
30
30
|
# context.toa.yaml
|
|
31
31
|
configuration:
|
|
32
32
|
dummies.dummy:
|
|
33
|
-
foo: qux
|
|
34
|
-
foo@staging: quux #
|
|
35
|
-
baz: $BAZ_VALUE #
|
|
33
|
+
foo: qux # override default value defined by dummies.dummy
|
|
34
|
+
foo@staging: quux # deployment environment discriminator
|
|
35
|
+
baz: $BAZ_VALUE # secret
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
### Deploy secrets
|
|
39
39
|
|
|
40
40
|
```shell
|
|
41
|
-
$ toa conceal
|
|
41
|
+
$ toa conceal configuration BAZ_VALUE '$ecr3t'
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
---
|
|
@@ -107,7 +107,7 @@ extensions:
|
|
|
107
107
|
default: 'baz'
|
|
108
108
|
bar:
|
|
109
109
|
type: number
|
|
110
|
-
required: [
|
|
110
|
+
required: [foo]
|
|
111
111
|
```
|
|
112
112
|
|
|
113
113
|
### Concise Declaration
|
|
@@ -140,7 +140,7 @@ extensions:
|
|
|
140
140
|
type: number
|
|
141
141
|
default: 1
|
|
142
142
|
additionalProperties: false
|
|
143
|
-
required: [
|
|
143
|
+
required: [foo, bar]
|
|
144
144
|
```
|
|
145
145
|
|
|
146
146
|
## Context Configuration
|
|
@@ -170,11 +170,7 @@ by [`toa configure`](../../runtime/cli/readme.md#configure) command.
|
|
|
170
170
|
|
|
171
171
|
## Configuration Secrets
|
|
172
172
|
|
|
173
|
-
|
|
174
|
-
> Not implemented. [#132](https://github.com/toa-io/toa/issues/132)
|
|
175
|
-
|
|
176
|
-
Context Configuration values which are uppercase strings prefixed with `$`
|
|
177
|
-
considered as Secrets.
|
|
173
|
+
Context Configuration values which are uppercase strings prefixed with `$` considered as Secrets.
|
|
178
174
|
|
|
179
175
|
### Example
|
|
180
176
|
|
|
@@ -185,6 +181,8 @@ configuration:
|
|
|
185
181
|
api-key: $STRIPE_API_KEY
|
|
186
182
|
```
|
|
187
183
|
|
|
184
|
+
Configuration values that are assigned with a reference to the Secret must be of type `string`.
|
|
185
|
+
|
|
188
186
|
### Secrets Deployment
|
|
189
187
|
|
|
190
188
|
Secrets are not being deployed with context
|
|
@@ -192,6 +190,12 @@ deployment ([`toa deploy`](../../runtime/cli/readme.md#deploy)),
|
|
|
192
190
|
thus must be deployed separately at least once for each deployment environment
|
|
193
191
|
manually ([`toa conceal`](../../runtime/cli/readme.md#conceal)).
|
|
194
192
|
|
|
193
|
+
Deployed kubernetes secret's name is predefined as `configuration`.
|
|
194
|
+
|
|
195
|
+
```shell
|
|
196
|
+
$ toa conceal configuration STRIPE_API_KEY xxxxxxxx
|
|
197
|
+
```
|
|
198
|
+
|
|
195
199
|
## Operation Context
|
|
196
200
|
|
|
197
201
|
Configuration Value is available as a well-known operation context extension `configuration`.
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const find = require('../secrets')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {toa.norm.context.dependencies.Instance[]} components
|
|
7
|
+
* @param {object} annotations
|
|
8
|
+
* @return {toa.deployment.dependency.Variables}
|
|
9
|
+
*/
|
|
10
|
+
function secrets (components, annotations) {
|
|
11
|
+
/** @type {toa.deployment.dependency.Variables} */
|
|
12
|
+
const variables = {}
|
|
13
|
+
|
|
14
|
+
for (const [id, annotation] of Object.entries(annotations)) {
|
|
15
|
+
const component = components.find((component) => component.locator.id === id)
|
|
16
|
+
const label = component.locator.label
|
|
17
|
+
|
|
18
|
+
find.secrets(annotation, (variable, key) => {
|
|
19
|
+
if (variables[label] === undefined) variables[label] = []
|
|
20
|
+
|
|
21
|
+
variables[label].push({
|
|
22
|
+
name: variable,
|
|
23
|
+
secret: { name: SECRET_NAME, key }
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return variables
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
const SECRET_NAME = 'toa-configuration'
|
|
32
|
+
|
|
33
|
+
exports.secrets = secrets
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
const { encode } = require('@toa.io/generic')
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
* @
|
|
6
|
+
* @param {toa.norm.context.dependencies.Instance[]} components
|
|
7
|
+
* @param {object} annotations
|
|
8
|
+
* @return {toa.deployment.dependency.Variables}
|
|
7
9
|
*/
|
|
8
|
-
|
|
10
|
+
function variables (components, annotations) {
|
|
11
|
+
/** @type {toa.deployment.dependency.Variables} */
|
|
9
12
|
const variables = {}
|
|
10
13
|
|
|
11
14
|
for (const [id, annotation] of Object.entries(annotations)) {
|
|
@@ -17,7 +20,7 @@ const deployment = (components, annotations) => {
|
|
|
17
20
|
}]
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
return
|
|
23
|
+
return variables
|
|
21
24
|
}
|
|
22
25
|
|
|
23
|
-
exports.
|
|
26
|
+
exports.variables = variables
|
|
@@ -21,7 +21,8 @@ const convert = (node) => {
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
function property (node) {
|
|
24
|
-
if (node === null) throw new Error('Configuration: cannot resolve type of null, use JSONSchema declaration.')
|
|
24
|
+
// if (node === null) throw new Error('Configuration: cannot resolve type of null, use JSONSchema declaration.')
|
|
25
|
+
if (node === null) return { type: 'null', default: null }
|
|
25
26
|
|
|
26
27
|
const type = Array.isArray(node) ? 'array' : typeof node
|
|
27
28
|
|
|
@@ -36,11 +37,14 @@ const array = (array) => {
|
|
|
36
37
|
|
|
37
38
|
const type = typeof array[0]
|
|
38
39
|
|
|
39
|
-
|
|
40
|
+
const schema = {
|
|
40
41
|
type: 'array',
|
|
41
|
-
items: { type },
|
|
42
42
|
default: array
|
|
43
43
|
}
|
|
44
|
+
|
|
45
|
+
if (array.length === 1) schema.items = array[0]
|
|
46
|
+
|
|
47
|
+
return schema
|
|
44
48
|
}
|
|
45
49
|
|
|
46
50
|
const SYM = Symbol()
|
|
@@ -4,7 +4,7 @@ const clone = require('clone-deep')
|
|
|
4
4
|
const { generate } = require('randomstring')
|
|
5
5
|
const { sample } = require('@toa.io/generic')
|
|
6
6
|
|
|
7
|
-
const fixtures = require('./
|
|
7
|
+
const fixtures = require('./annotation.fixtures')
|
|
8
8
|
const { annotation } = require('../')
|
|
9
9
|
|
|
10
10
|
let input
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { merge } = require('@toa.io/generic')
|
|
4
|
+
const get = require('./.deployment')
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {toa.norm.context.dependencies.Instance[]} components
|
|
8
|
+
* @param {object} annotations
|
|
9
|
+
* @return {toa.deployment.dependency.Declaration}
|
|
10
|
+
*/
|
|
11
|
+
const deployment = (components, annotations) => {
|
|
12
|
+
const variables = get.variables(components, annotations)
|
|
13
|
+
const secrets = get.secrets(components, annotations)
|
|
14
|
+
|
|
15
|
+
merge(variables, secrets)
|
|
16
|
+
|
|
17
|
+
return { variables }
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
exports.deployment = deployment
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
|
|
3
|
-
const
|
|
3
|
+
const clone = require('clone-deep')
|
|
4
|
+
const { encode, sample } = require('@toa.io/generic')
|
|
4
5
|
|
|
5
6
|
const fixtures = require('./deployment.fixtures')
|
|
6
7
|
const { deployment } = require('../')
|
|
8
|
+
const { generate } = require('randomstring')
|
|
7
9
|
|
|
8
10
|
/** @type {toa.deployment.dependency.Declaration} */
|
|
9
11
|
let declaration
|
|
@@ -43,3 +45,26 @@ it('should map configurations', () => {
|
|
|
43
45
|
expect(env.value).toStrictEqual(encoded)
|
|
44
46
|
}
|
|
45
47
|
})
|
|
48
|
+
|
|
49
|
+
it('should declare secrets', async () => {
|
|
50
|
+
const annotations = clone(fixtures.annotations)
|
|
51
|
+
const component = sample(fixtures.components)
|
|
52
|
+
const id = component.locator.id
|
|
53
|
+
const key = generate()
|
|
54
|
+
const name = generate().substring(0, 16).toUpperCase()
|
|
55
|
+
const value = '$' + name
|
|
56
|
+
|
|
57
|
+
if (annotations[id] === undefined) annotations[id] = {}
|
|
58
|
+
|
|
59
|
+
annotations[id][key] = value
|
|
60
|
+
|
|
61
|
+
declaration = deployment(fixtures.components, annotations)
|
|
62
|
+
|
|
63
|
+
const variables = declaration.variables[component.locator.label]
|
|
64
|
+
|
|
65
|
+
expect(variables).toBeDefined()
|
|
66
|
+
|
|
67
|
+
const secret = variables.find((variable) => variable.name === 'TOA_CONFIGURATION__' + name)
|
|
68
|
+
|
|
69
|
+
expect(secret).toBeDefined()
|
|
70
|
+
})
|
|
@@ -4,6 +4,8 @@ const clone = require('clone-deep')
|
|
|
4
4
|
const { decode, encode, empty, overwrite } = require('@toa.io/generic')
|
|
5
5
|
|
|
6
6
|
const { Connector } = require('@toa.io/core')
|
|
7
|
+
|
|
8
|
+
const { secrets } = require('./secrets')
|
|
7
9
|
const { form } = require('./.provider/form')
|
|
8
10
|
|
|
9
11
|
/**
|
|
@@ -39,11 +41,7 @@ class Provider extends Connector {
|
|
|
39
41
|
}
|
|
40
42
|
|
|
41
43
|
async open () {
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
async #source () {
|
|
46
|
-
return this.#value
|
|
44
|
+
this.#retrieve()
|
|
47
45
|
}
|
|
48
46
|
|
|
49
47
|
set (key, value) {
|
|
@@ -77,7 +75,11 @@ class Provider extends Connector {
|
|
|
77
75
|
return this.object === undefined ? undefined : encode(this.object)
|
|
78
76
|
}
|
|
79
77
|
|
|
80
|
-
|
|
78
|
+
#source () {
|
|
79
|
+
return this.#value
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
#retrieve () {
|
|
81
83
|
const string = process.env[this.key]
|
|
82
84
|
const object = string === undefined ? {} : decode(string)
|
|
83
85
|
|
|
@@ -85,18 +87,12 @@ class Provider extends Connector {
|
|
|
85
87
|
}
|
|
86
88
|
|
|
87
89
|
#set (object) {
|
|
88
|
-
this.#
|
|
90
|
+
object = this.#reveal(object)
|
|
89
91
|
this.#merge(object)
|
|
90
92
|
|
|
91
93
|
this.object = empty(object) ? undefined : object
|
|
92
94
|
}
|
|
93
95
|
|
|
94
|
-
#validate (object) {
|
|
95
|
-
const error = this.#schema.match(object)
|
|
96
|
-
|
|
97
|
-
if (error !== null) throw new TypeError(error.message)
|
|
98
|
-
}
|
|
99
|
-
|
|
100
96
|
#merge (object) {
|
|
101
97
|
object = clone(object)
|
|
102
98
|
|
|
@@ -104,9 +100,18 @@ class Provider extends Connector {
|
|
|
104
100
|
const value = overwrite(form, object)
|
|
105
101
|
|
|
106
102
|
this.#schema.validate(value)
|
|
107
|
-
|
|
108
103
|
this.#value = value
|
|
109
104
|
}
|
|
105
|
+
|
|
106
|
+
#reveal (object) {
|
|
107
|
+
return secrets(object, (variable) => {
|
|
108
|
+
if (!(variable in process.env)) throw new Error(`Configuration secret value ${variable} is not set`)
|
|
109
|
+
|
|
110
|
+
const base64 = process.env[variable]
|
|
111
|
+
|
|
112
|
+
return decode(base64)
|
|
113
|
+
})
|
|
114
|
+
}
|
|
110
115
|
}
|
|
111
116
|
|
|
112
117
|
const PREFIX = 'TOA_CONFIGURATION_'
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { generate } = require('randomstring')
|
|
4
|
+
const { encode } = require('@toa.io/generic')
|
|
5
|
+
|
|
6
|
+
const { Provider } = require('./provider')
|
|
7
|
+
|
|
8
|
+
it('should be', async () => {
|
|
9
|
+
expect(Provider).toBeInstanceOf(Function)
|
|
10
|
+
})
|
|
11
|
+
|
|
12
|
+
const locator = /** @type {toa.core.Locator} */ { uppercase: generate().toUpperCase() }
|
|
13
|
+
const schema = /** @type {toa.schema.Schema} */ { validate: () => undefined }
|
|
14
|
+
|
|
15
|
+
/** @type {Provider} */
|
|
16
|
+
let provider
|
|
17
|
+
|
|
18
|
+
beforeEach(() => {
|
|
19
|
+
cleanEnv()
|
|
20
|
+
provider = new Provider(locator, schema)
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
it('should replace secret values', async () => {
|
|
24
|
+
const configuration = { foo: '$FOO_SECRET' }
|
|
25
|
+
const secrets = { FOO_SECRET: generate() }
|
|
26
|
+
|
|
27
|
+
setEnv(configuration, secrets)
|
|
28
|
+
|
|
29
|
+
await provider.open()
|
|
30
|
+
const value = provider.source()
|
|
31
|
+
|
|
32
|
+
expect(value).toStrictEqual({ foo: secrets.FOO_SECRET })
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
it('should throw if secret value is not set', async () => {
|
|
36
|
+
const configuration = { foo: '$FOO_SECRET' }
|
|
37
|
+
|
|
38
|
+
setEnv(configuration)
|
|
39
|
+
|
|
40
|
+
await expect(provider.open()).rejects.toThrow('FOO_SECRET is not set')
|
|
41
|
+
})
|
|
42
|
+
|
|
43
|
+
it('should replace nested secrets', async () => {
|
|
44
|
+
const configuration = { foo: { bar: '$BAR' } }
|
|
45
|
+
const secrets = { BAR: generate() }
|
|
46
|
+
|
|
47
|
+
setEnv(configuration, secrets)
|
|
48
|
+
|
|
49
|
+
await provider.open()
|
|
50
|
+
const value = provider.source()
|
|
51
|
+
|
|
52
|
+
expect(value).toStrictEqual({ foo: { bar: secrets.BAR } })
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
const usedVariables = []
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @param {object} configuration
|
|
59
|
+
* @param {Record<string, string>} [secrets]
|
|
60
|
+
*/
|
|
61
|
+
function setEnv (configuration, secrets) {
|
|
62
|
+
const variable = PREFIX + locator.uppercase
|
|
63
|
+
|
|
64
|
+
setVal(variable, configuration)
|
|
65
|
+
|
|
66
|
+
if (secrets !== undefined) {
|
|
67
|
+
for (const [key, value] of Object.entries(secrets)) {
|
|
68
|
+
const variable = PREFIX + '_' + key
|
|
69
|
+
|
|
70
|
+
process.env[variable] = encode(value)
|
|
71
|
+
usedVariables.push(variable)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function setVal (variable, value) {
|
|
77
|
+
process.env[variable] = encode(value)
|
|
78
|
+
usedVariables.push(variable)
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function cleanEnv () {
|
|
82
|
+
for (const variable of usedVariables) {
|
|
83
|
+
delete process.env[variable]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
usedVariables.length = 0
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const PREFIX = 'TOA_CONFIGURATION_'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { map } = require('@toa.io/generic')
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @param {object} configuration
|
|
7
|
+
* @param {(variable: string, name?: string) => void} callback
|
|
8
|
+
* @returns {object}
|
|
9
|
+
*/
|
|
10
|
+
function secrets (configuration, callback) {
|
|
11
|
+
return map(configuration, (value) => {
|
|
12
|
+
if (typeof value !== 'string') return
|
|
13
|
+
|
|
14
|
+
const match = value.match(SECRET_RX)
|
|
15
|
+
|
|
16
|
+
if (match === null) return
|
|
17
|
+
|
|
18
|
+
const name = match.groups.variable
|
|
19
|
+
const variable = PREFIX + name
|
|
20
|
+
|
|
21
|
+
return callback(variable, name)
|
|
22
|
+
})
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const PREFIX = 'TOA_CONFIGURATION__'
|
|
26
|
+
const SECRET_RX = /^\$(?<variable>[A-Z0-9_]{1,32})$/
|
|
27
|
+
|
|
28
|
+
exports.secrets = secrets
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
'use strict'
|
|
2
|
+
|
|
3
|
+
const { secrets } = require('./secrets')
|
|
4
|
+
|
|
5
|
+
it('should be', async () => {
|
|
6
|
+
expect(secrets).toBeInstanceOf(Function)
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it('should find secrets', async () => {
|
|
10
|
+
const configuration = {
|
|
11
|
+
foo: {
|
|
12
|
+
bar: '$BAR_VALUE'
|
|
13
|
+
},
|
|
14
|
+
baz: '$BAZ_VALUE'
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const variables = new Set()
|
|
18
|
+
const names = new Set()
|
|
19
|
+
|
|
20
|
+
secrets(configuration, (variable, name) => {
|
|
21
|
+
variables.add(variable)
|
|
22
|
+
names.add(name)
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
expect(variables.has('TOA_CONFIGURATION__BAR_VALUE')).toStrictEqual(true)
|
|
26
|
+
expect(variables.has('TOA_CONFIGURATION__BAZ_VALUE')).toStrictEqual(true)
|
|
27
|
+
|
|
28
|
+
expect(names.has('BAR_VALUE')).toStrictEqual(true)
|
|
29
|
+
expect(names.has('BAZ_VALUE')).toStrictEqual(true)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
it('should replace values', async () => {
|
|
33
|
+
const configuration = { foo: '$FOO' }
|
|
34
|
+
|
|
35
|
+
const output = secrets(configuration, (variable) => 'hello')
|
|
36
|
+
|
|
37
|
+
expect(output).toStrictEqual({ foo: 'hello' })
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should allow numbers in secret names', async () => {
|
|
41
|
+
const configuration = { foo: '$HOST_0' }
|
|
42
|
+
const found = new Set()
|
|
43
|
+
|
|
44
|
+
secrets(configuration, (variable) => found.add(variable))
|
|
45
|
+
|
|
46
|
+
expect(found.has('TOA_CONFIGURATION__HOST_0')).toStrictEqual(true)
|
|
47
|
+
})
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
/package/{src → source}/index.js
RENAMED
|
File without changes
|
|
File without changes
|