@voxgig/sdkgen 4.6.0 → 4.7.0

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.
Files changed (115) hide show
  1. package/bin/voxgig-sdkgen +1 -1
  2. package/dist/cmp/Feature.js +5 -0
  3. package/dist/cmp/Feature.js.map +1 -1
  4. package/dist/cmp/TestControl.d.ts +4 -0
  5. package/dist/cmp/TestControl.js +51 -0
  6. package/dist/cmp/TestControl.js.map +1 -0
  7. package/dist/helpers/featureSource.d.ts +3 -1
  8. package/dist/helpers/featureSource.js +105 -0
  9. package/dist/helpers/featureSource.js.map +1 -1
  10. package/dist/sdkgen.d.ts +3 -2
  11. package/dist/sdkgen.js +9 -4
  12. package/dist/sdkgen.js.map +1 -1
  13. package/dist/tsconfig.tsbuildinfo +1 -1
  14. package/dist/utility.d.ts +2 -1
  15. package/dist/utility.js +52 -0
  16. package/dist/utility.js.map +1 -1
  17. package/model/sdkgen.aon +58 -0
  18. package/package.json +1 -1
  19. package/project/.sdk/model/feature/secrets.aon +82 -0
  20. package/project/.sdk/src/cmp/cpp/Main_cpp.ts +2 -1
  21. package/project/.sdk/src/cmp/cpp/Test_cpp.ts +5 -1
  22. package/project/.sdk/src/cmp/csharp/Main_csharp.ts +2 -1
  23. package/project/.sdk/src/cmp/csharp/TestDirect_csharp.ts +30 -6
  24. package/project/.sdk/src/cmp/csharp/TestEntity_csharp.ts +29 -5
  25. package/project/.sdk/src/cmp/csharp/Test_csharp.ts +5 -1
  26. package/project/.sdk/src/cmp/dart/Main_dart.ts +2 -1
  27. package/project/.sdk/src/cmp/dart/TestDirect_dart.ts +23 -6
  28. package/project/.sdk/src/cmp/dart/TestEntity_dart.ts +28 -7
  29. package/project/.sdk/src/cmp/dart/Test_dart.ts +5 -1
  30. package/project/.sdk/src/cmp/go/Main_go.ts +2 -1
  31. package/project/.sdk/src/cmp/go/Test_go.ts +5 -1
  32. package/project/.sdk/src/cmp/java/Main_java.ts +2 -1
  33. package/project/.sdk/src/cmp/java/Test_java.ts +5 -1
  34. package/project/.sdk/src/cmp/js/Main_js.ts +2 -1
  35. package/project/.sdk/src/cmp/js/TestDirect_js.ts +30 -5
  36. package/project/.sdk/src/cmp/js/TestEntity_js.ts +35 -5
  37. package/project/.sdk/src/cmp/js/Test_js.ts +5 -1
  38. package/project/.sdk/src/cmp/js/fragment/Direct.test.fragment.js +7 -1
  39. package/project/.sdk/src/cmp/js/fragment/Entity.test.fragment.js +7 -1
  40. package/project/.sdk/src/cmp/kotlin/Main_kotlin.ts +2 -1
  41. package/project/.sdk/src/cmp/kotlin/Test_kotlin.ts +5 -1
  42. package/project/.sdk/src/cmp/lua/Main_lua.ts +2 -1
  43. package/project/.sdk/src/cmp/lua/TestDirect_lua.ts +28 -4
  44. package/project/.sdk/src/cmp/lua/TestEntity_lua.ts +24 -4
  45. package/project/.sdk/src/cmp/lua/Test_lua.ts +5 -1
  46. package/project/.sdk/src/cmp/ocaml/Gitignore_ocaml.ts +1 -0
  47. package/project/.sdk/src/cmp/perl/Main_perl.ts +2 -1
  48. package/project/.sdk/src/cmp/perl/TestDirect_perl.ts +25 -4
  49. package/project/.sdk/src/cmp/perl/TestEntity_perl.ts +24 -4
  50. package/project/.sdk/src/cmp/perl/Test_perl.ts +5 -1
  51. package/project/.sdk/src/cmp/perl/utility_perl.ts +10 -0
  52. package/project/.sdk/src/cmp/php/Main_php.ts +2 -1
  53. package/project/.sdk/src/cmp/php/TestDirect_php.ts +24 -5
  54. package/project/.sdk/src/cmp/php/TestEntity_php.ts +28 -4
  55. package/project/.sdk/src/cmp/php/Test_php.ts +5 -1
  56. package/project/.sdk/src/cmp/py/Main_py.ts +2 -1
  57. package/project/.sdk/src/cmp/py/Test_py.ts +5 -1
  58. package/project/.sdk/src/cmp/rb/Main_rb.ts +2 -1
  59. package/project/.sdk/src/cmp/rb/TestDirect_rb.ts +24 -5
  60. package/project/.sdk/src/cmp/rb/TestEntity_rb.ts +24 -4
  61. package/project/.sdk/src/cmp/rb/Test_rb.ts +5 -1
  62. package/project/.sdk/src/cmp/rb/utility_rb.ts +3 -1
  63. package/project/.sdk/src/cmp/rust/Main_rust.ts +2 -1
  64. package/project/.sdk/src/cmp/rust/TestDirect_rust.ts +31 -4
  65. package/project/.sdk/src/cmp/rust/TestEntity_rust.ts +37 -4
  66. package/project/.sdk/src/cmp/rust/Test_rust.ts +5 -1
  67. package/project/.sdk/src/cmp/scala/Main_scala.ts +2 -1
  68. package/project/.sdk/src/cmp/scala/Test_scala.ts +5 -1
  69. package/project/.sdk/src/cmp/ts/Config_ts.ts +50 -8
  70. package/project/.sdk/src/cmp/ts/Main_ts.ts +10 -2
  71. package/project/.sdk/src/cmp/ts/TestDirect_ts.ts +10 -3
  72. package/project/.sdk/src/cmp/ts/TestEntity_ts.ts +11 -3
  73. package/project/.sdk/src/cmp/ts/Test_ts.ts +5 -1
  74. package/project/.sdk/tm/csharp/test/Runner.cs +45 -0
  75. package/project/.sdk/tm/dart/test/utility.dart +39 -0
  76. package/project/.sdk/tm/js/test/sdk-test-control.json +19 -0
  77. package/project/.sdk/tm/js/test/utility.js +91 -1
  78. package/project/.sdk/tm/lua/test/runner.lua +40 -0
  79. package/project/.sdk/tm/ocaml/test/harness.ml +14 -4
  80. package/project/.sdk/tm/perl/t/runner.pm +30 -0
  81. package/project/.sdk/tm/php/test/Runner.php +36 -0
  82. package/project/.sdk/tm/rb/test/runner.rb +25 -0
  83. package/project/.sdk/tm/rust/tests/common/mod.rs +32 -0
  84. package/project/.sdk/tm/rust/utility/make_options.rs +1 -1
  85. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sekreto.ts +8 -2
  86. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Sigv4.ts +29 -5
  87. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/index.ts +30 -21
  88. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/Registry.ts +90 -0
  89. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/addr.ts +48 -0
  90. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/aws.ts +219 -0
  91. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/azuresecrets.ts +144 -0
  92. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/boru.ts +113 -0
  93. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/doppler.ts +77 -0
  94. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/dotenv.ts +51 -0
  95. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/env.ts +31 -0
  96. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/file.ts +54 -0
  97. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/gcpsecrets.ts +118 -0
  98. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/hashicorp.ts +159 -0
  99. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/http.ts +66 -0
  100. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/infisical.ts +107 -0
  101. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/memory.ts +33 -0
  102. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/onepassword.ts +120 -0
  103. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/provider/support.ts +176 -0
  104. package/project/.sdk/tm/ts/test/vendor/omni/Runner.ts +15 -13
  105. package/project/.sdk/tm/ts/test/vendor/omni/Util.ts +25 -19
  106. package/project/.sdk/tm/ts/test/vendor/omni/compat.ts +1 -1
  107. package/project/.sdk/tm/ts/test/vendor/omni/index.ts +1 -1
  108. package/project/.sdk/tm/zig/core/utility.zig +1 -1
  109. package/project/sdkgen-package.json +1 -1
  110. package/src/cmp/Feature.ts +5 -0
  111. package/src/cmp/TestControl.ts +64 -0
  112. package/src/helpers/featureSource.ts +130 -0
  113. package/src/sdkgen.ts +7 -0
  114. package/src/utility.ts +61 -0
  115. package/project/.sdk/tm/ts/src/feature/secrets/sekreto/Providers.ts +0 -1221
@@ -0,0 +1,144 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/azuresecrets.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, SekretoError, flatname } from './support'
7
+ import { checkaddr } from './addr'
8
+ import { fetchjson } from './http'
9
+
10
+ export function azuresecretsprovider(options?: {
11
+ vault?: string
12
+ token?: string
13
+ tenant?: string
14
+ clientid?: string
15
+ clientsecret?: string
16
+ loginaddr?: string
17
+ imdsaddr?: string
18
+ apiversion?: string
19
+ }): Provider {
20
+ const opts = options || {}
21
+ const resource = 'https://vault.azure.net'
22
+
23
+ // A configured token is kept forever; logged-in and IMDS tokens carry
24
+ // expires_in and are renewed shortly before they run out.
25
+ let livetoken: string | undefined
26
+ let renewat = Infinity
27
+
28
+ const expiry = (expires: any): number => {
29
+ const seconds = Number(expires)
30
+ return 0 < seconds ? Date.now() + Math.max(seconds - 60, 1) * 1000 : Infinity
31
+ }
32
+
33
+ const login = async (): Promise<string> => {
34
+ if (opts.token) {
35
+ return opts.token
36
+ }
37
+
38
+ if (opts.tenant && opts.clientid && opts.clientsecret) {
39
+ const loginaddr = opts.loginaddr || 'https://login.microsoftonline.com'
40
+ checkaddr(loginaddr)
41
+
42
+ const url = loginaddr.replace(/\/$/, '') + '/' + opts.tenant + '/oauth2/v2.0/token'
43
+ const form =
44
+ 'grant_type=client_credentials&client_id=' +
45
+ encodeURIComponent(opts.clientid) +
46
+ '&client_secret=' +
47
+ encodeURIComponent(opts.clientsecret) +
48
+ '&scope=' +
49
+ encodeURIComponent(resource + '/.default')
50
+
51
+ const res = await fetchjson(
52
+ 'POST',
53
+ url,
54
+ { 'content-type': 'application/x-www-form-urlencoded' },
55
+ form,
56
+ )
57
+
58
+ const got = res.body && res.body.access_token
59
+ if (200 !== res.status || !got) {
60
+ throw new SekretoError('sekreto: azure login failed: ' + res.status)
61
+ }
62
+
63
+ renewat = expiry(res.body.expires_in)
64
+ return String(got)
65
+ }
66
+
67
+ const imds =
68
+ (opts.imdsaddr || 'http://169.254.169.254').replace(/\/$/, '') +
69
+ '/metadata/identity/oauth2/token?api-version=2018-02-01&resource=' +
70
+ encodeURIComponent(resource)
71
+
72
+ const res = await fetchjson('GET', imds, { Metadata: 'true' })
73
+
74
+ const got = res.body && res.body.access_token
75
+ if (200 !== res.status || !got) {
76
+ throw new SekretoError(
77
+ 'sekreto: azure: no token, no client credentials, and IMDS did not answer',
78
+ )
79
+ }
80
+
81
+ renewat = expiry(res.body.expires_in)
82
+ return String(got)
83
+ }
84
+
85
+ return {
86
+ lookup: async (name: string) => {
87
+ const vault = opts.vault || ''
88
+ if ('' === vault) {
89
+ throw new SekretoError('sekreto: azure: no vault')
90
+ }
91
+
92
+ // Only an explicit scheme is a URL; a vault NAMED httpvault must
93
+ // still become https://httpvault.vault.azure.net.
94
+ const vaulturl =
95
+ vault.startsWith('http://') || vault.startsWith('https://')
96
+ ? vault
97
+ : 'https://' + vault + '.vault.azure.net'
98
+ checkaddr(vaulturl)
99
+
100
+ if (undefined === livetoken || Date.now() >= renewat) {
101
+ livetoken = await login()
102
+ }
103
+
104
+ const url =
105
+ vaulturl.replace(/\/$/, '') +
106
+ '/secrets/' +
107
+ flatname(name, '-') +
108
+ '?api-version=' +
109
+ (opts.apiversion || '7.4')
110
+
111
+ const res = await fetchjson('GET', url, { authorization: 'Bearer ' + livetoken })
112
+
113
+ if (404 === res.status) {
114
+ return undefined
115
+ }
116
+
117
+ if (200 !== res.status) {
118
+ throw new SekretoError('sekreto: azure error: ' + res.status + ': ' + url.split('?')[0])
119
+ }
120
+
121
+ const value = res.body && res.body.value
122
+ return undefined === value || null === value ? undefined : String(value)
123
+ },
124
+ describe: () => 'azuresecrets:' + (opts.vault || ''),
125
+ }
126
+ }
127
+
128
+ /** 1Password, through a Connect server.
129
+ *
130
+ * The item titled `api.token` (titles keep their dots), in the named
131
+ * vault. The value is the field with purpose PASSWORD, or the field
132
+ * labelled `value`. A vault that cannot be found is an error - config
133
+ * names it, so its absence is a broken store, not a missing secret. */
134
+
135
+
136
+ // Registering at import is what makes this module's presence the only
137
+ // thing that decides whether the kind exists in a build.
138
+ import { register } from './Registry'
139
+
140
+ register({
141
+ name: 'azuresecrets',
142
+ needs: ['fetch'],
143
+ define: (spec: ProviderSpec) => azuresecretsprovider(spec),
144
+ })
@@ -0,0 +1,113 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/boru.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, SekretoError, checkname, nodemod } from './support'
7
+ import { checkaddr } from './addr'
8
+ import { fetchjson } from './http'
9
+
10
+ export function boruprovider(options?: {
11
+ command?: string
12
+ namespace?: string
13
+ home?: string
14
+ addr?: string
15
+ token?: string
16
+ mount?: string
17
+ }): Provider {
18
+ const opts = options || {}
19
+ const command = opts.command || 'boru'
20
+
21
+ if (opts.addr) {
22
+ const addr = opts.addr.replace(/\/$/, '')
23
+ const mount = opts.mount || 'secret'
24
+
25
+ return {
26
+ lookup: async (name: string) => {
27
+ checkname(name)
28
+ checkaddr(addr)
29
+
30
+ const alias = opts.namespace ? opts.namespace + '/' + name : name
31
+ const url = addr + '/v1/' + mount + '/data/' + alias
32
+
33
+ const res = await fetchjson('GET', url, { 'X-Vault-Token': opts.token || '' })
34
+
35
+ if (404 === res.status) {
36
+ return undefined
37
+ }
38
+
39
+ if (200 !== res.status) {
40
+ throw new SekretoError('sekreto: boru serve error: ' + res.status + ': ' + url)
41
+ }
42
+
43
+ const data = res.body && res.body.data && res.body.data.data
44
+ const value = data ? data['value'] : undefined
45
+ return undefined === value || null === value ? undefined : String(value)
46
+ },
47
+ describe: () => 'boru:' + addr,
48
+ }
49
+ }
50
+
51
+ return {
52
+ lookup: (name: string) => {
53
+ checkname(name)
54
+
55
+ const alias = opts.namespace ? opts.namespace + ':' + name : name
56
+ const env = opts.home ? { ...process.env, BORU_HOME: opts.home } : process.env
57
+
58
+ const { spawnSync } = nodemod<typeof import('node:child_process')>('node:child_process')
59
+ const run = spawnSync(command, ['vault', 'get', '--reveal', alias], {
60
+ encoding: 'utf8',
61
+ env,
62
+ })
63
+
64
+ if (run.error) {
65
+ throw new SekretoError('sekreto: cannot run ' + command + ': ' + run.error.message)
66
+ }
67
+
68
+ if (0 === run.status) {
69
+ // boru prints the value and one newline, and nothing else.
70
+ return run.stdout.replace(/\n$/, '')
71
+ }
72
+
73
+ const why = (run.stderr || '').trim()
74
+
75
+ // "no alias named" is boru saying it does not hold this secret, which
76
+ // is a miss: the chain carries on to the next provider. A locked vault
77
+ // or a wrong passphrase is not a miss - treating it as one would fall
78
+ // through to a weaker store without saying so.
79
+ if (borumiss(why)) {
80
+ return undefined
81
+ }
82
+
83
+ throw new SekretoError('sekreto: boru vault error: ' + (why || 'exit ' + run.status))
84
+ },
85
+ describe: () => 'boru' + (opts.namespace ? ':' + opts.namespace : ''),
86
+ }
87
+ }
88
+
89
+ /** Does this boru failure mean "no such secret" rather than "I could not
90
+ * answer"? Matched on boru's own wording for a missing alias. */
91
+ function borumiss(why: string): boolean {
92
+ return /no alias named/.test(why)
93
+ }
94
+
95
+ /** The `YYYYMMDDTHHMMSSZ` timestamp SigV4 wants, for now. */
96
+
97
+
98
+ // Registering at import is what makes this module's presence the only
99
+ // thing that decides whether the kind exists in a build.
100
+ import { register } from './Registry'
101
+
102
+ register({
103
+ name: 'boru',
104
+ needs: ['fetch'],
105
+ define: (spec: ProviderSpec) => boruprovider({
106
+ command: spec.command,
107
+ namespace: spec.namespace,
108
+ home: spec.home,
109
+ addr: spec.addr,
110
+ token: spec.token,
111
+ mount: spec.mount,
112
+ }),
113
+ })
@@ -0,0 +1,77 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/doppler.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, SekretoError, envkey } from './support'
7
+ import { checkaddr } from './addr'
8
+ import { fetchjson } from './http'
9
+
10
+ export function dopplerprovider(options?: {
11
+ token?: string
12
+ project?: string
13
+ config?: string
14
+ addr?: string
15
+ }): Provider {
16
+ const opts = options || {}
17
+
18
+ let values: Record<string, string> | undefined
19
+
20
+ const load = async (): Promise<Record<string, string>> => {
21
+ if (undefined !== values) {
22
+ return values
23
+ }
24
+
25
+ const addr = (opts.addr || 'https://api.doppler.com').replace(/\/$/, '')
26
+ checkaddr(addr)
27
+
28
+ let url = addr + '/v3/configs/config/secrets/download?format=json'
29
+ if (opts.project) {
30
+ url += '&project=' + encodeURIComponent(opts.project)
31
+ }
32
+ if (opts.config) {
33
+ url += '&config=' + encodeURIComponent(opts.config)
34
+ }
35
+
36
+ const res = await fetchjson('GET', url, {
37
+ authorization: 'Bearer ' + (opts.token || ''),
38
+ })
39
+
40
+ if (200 !== res.status || !res.body || 'object' !== typeof res.body) {
41
+ throw new SekretoError('sekreto: doppler error: ' + res.status)
42
+ }
43
+
44
+ values = {}
45
+ for (const [key, value] of Object.entries(res.body)) {
46
+ if (null !== value && undefined !== value) {
47
+ values[key] = String(value)
48
+ }
49
+ }
50
+
51
+ return values
52
+ }
53
+
54
+ return {
55
+ lookup: async (name: string) => (await load())[envkey(name)],
56
+ describe: () =>
57
+ 'doppler' + (opts.project ? ':' + opts.project + '/' + (opts.config || '') : ''),
58
+ }
59
+ }
60
+
61
+ /** Infisical.
62
+ *
63
+ * `api.token` reads the secret keyed `API_TOKEN` (Infisical's own
64
+ * convention is environment-style keys) at a secret path in one
65
+ * environment of a project. Auth is a token, or a universal-auth
66
+ * (machine identity) login with clientid/clientsecret. */
67
+
68
+
69
+ // Registering at import is what makes this module's presence the only
70
+ // thing that decides whether the kind exists in a build.
71
+ import { register } from './Registry'
72
+
73
+ register({
74
+ name: 'doppler',
75
+ needs: ['fetch'],
76
+ define: (spec: ProviderSpec) => dopplerprovider(spec),
77
+ })
@@ -0,0 +1,51 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/dotenv.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, SekretoError, envkey, nodemod, parsedotenv } from './support'
7
+
8
+ export function dotenvprovider(file: string, prefix?: string): Provider {
9
+ let values: Record<string, string> | undefined
10
+
11
+ const load = () => {
12
+ if (undefined === values) {
13
+ try {
14
+ const { readFileSync } = nodemod<typeof import('node:fs')>('node:fs')
15
+ values = parsedotenv(readFileSync(file, 'utf8'))
16
+ } catch (err: any) {
17
+ // An absent file - or an absent directory - means "no secrets
18
+ // here", exactly like fileprovider. Anything else (permission
19
+ // denied, an unreadable mount) is a store that could not answer,
20
+ // and swallowing it would fall through to a weaker store.
21
+ if ('ENOENT' === err.code || 'ENOTDIR' === err.code) {
22
+ values = {}
23
+ } else {
24
+ throw new SekretoError(
25
+ 'sekreto: dotenv provider cannot read ' + file + ': ' + err.message,
26
+ )
27
+ }
28
+ }
29
+ }
30
+ return values
31
+ }
32
+
33
+ return {
34
+ lookup: (name: string) => load()[envkey(name, prefix)],
35
+ describe: () => 'dotenv:' + file,
36
+ }
37
+ }
38
+
39
+ /** Literal values, keyed like environment variables. The spec uses this
40
+ * to test chain behaviour without touching the outside world. */
41
+
42
+
43
+ // Registering at import is what makes this module's presence the only
44
+ // thing that decides whether the kind exists in a build.
45
+ import { register } from './Registry'
46
+
47
+ register({
48
+ name: 'dotenv',
49
+ needs: ['fs'],
50
+ define: (spec: ProviderSpec) => dotenvprovider(spec.file || '.env', spec.prefix),
51
+ })
@@ -0,0 +1,31 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/env.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, envkey } from './support'
7
+
8
+ export function envprovider(prefix?: string, source?: Record<string, any>): Provider {
9
+ const env = source || process.env
10
+
11
+ return {
12
+ lookup: (name: string) => {
13
+ const value = env[envkey(name, prefix)]
14
+ return undefined === value || null === value ? undefined : String(value)
15
+ },
16
+ describe: () => 'env' + (prefix ? ':' + prefix : ''),
17
+ }
18
+ }
19
+
20
+ /** A `.env` file, read once, keyed exactly like the environment. */
21
+
22
+
23
+ // Registering at import is what makes this module's presence the only
24
+ // thing that decides whether the kind exists in a build.
25
+ import { register } from './Registry'
26
+
27
+ register({
28
+ name: 'env',
29
+ needs: [],
30
+ define: (spec: ProviderSpec) => envprovider(spec.prefix),
31
+ })
@@ -0,0 +1,54 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/file.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import {
7
+ ProviderSpec, Provider, SekretoError, envkey, flatname, nodemod,
8
+ } from './support'
9
+
10
+ export function fileprovider(dir: string, prefix?: string): Provider {
11
+ return {
12
+ lookup: (name: string) => {
13
+ const { join } = nodemod<typeof import('node:path')>('node:path')
14
+ const file = join(dir, envkey(name, prefix))
15
+
16
+ let text: string
17
+ try {
18
+ const { readFileSync } = nodemod<typeof import('node:fs')>('node:fs')
19
+ text = readFileSync(file, 'utf8')
20
+ } catch (err: any) {
21
+ // An absent file - or an absent directory - means "no secrets
22
+ // here", exactly like a missing .env. Anything else (permission
23
+ // denied, an unreadable mount) is a store that could not answer.
24
+ if ('ENOENT' === err.code || 'ENOTDIR' === err.code) {
25
+ return undefined
26
+ }
27
+ throw new SekretoError('sekreto: file provider cannot read ' + file + ': ' + err.message)
28
+ }
29
+
30
+ return text.replace(/\r?\n$/, '')
31
+ },
32
+ describe: () => 'file:' + dir,
33
+ }
34
+ }
35
+
36
+ /** Refuse to send a secret-bearing credential in the clear.
37
+ *
38
+ * A vault API is HTTPS in any real deployment; plaintext is a dev-mode
39
+ * convenience. Sending a token over http to anything but the local
40
+ * machine puts both the token and the secret it fetches on the wire for
41
+ * anyone on the path, so sekreto will not do it. Loopback stays allowed:
42
+ * that is `vault server -dev`, `boru vault serve`, and this repo's own
43
+ * test harness. */
44
+
45
+
46
+ // Registering at import is what makes this module's presence the only
47
+ // thing that decides whether the kind exists in a build.
48
+ import { register } from './Registry'
49
+
50
+ register({
51
+ name: 'file',
52
+ needs: ['fs'],
53
+ define: (spec: ProviderSpec) => fileprovider(spec.dir || '', spec.prefix),
54
+ })
@@ -0,0 +1,118 @@
1
+ // VENDORED: @voxgig/sekreto 0.1.2 (typescript/src/provider/gcpsecrets.ts)
2
+ // Source: https://github.com/voxgig/sekreto @ 65009cb5758850db767785ab666e71895f86086b
3
+ // License: MIT (c) voxgig - see repository LICENSE. Do not edit: resync from upstream.
4
+ /* Copyright (c) 2025 Voxgig Ltd, MIT License */
5
+
6
+ import { ProviderSpec, Provider, SekretoError, flatname, nodemod } from './support'
7
+ import { checkaddr } from './addr'
8
+ import { fetchjson } from './http'
9
+
10
+ export function gcpsecretsprovider(options?: {
11
+ project?: string
12
+ token?: string
13
+ addr?: string
14
+ metadataaddr?: string
15
+ }): Provider {
16
+ const opts = options || {}
17
+
18
+ // A configured token is kept forever; a metadata-server token carries
19
+ // expires_in and is renewed shortly before it runs out.
20
+ let livetoken: string | undefined
21
+ let renewat = Infinity
22
+
23
+ const metadataaddr = (): string => {
24
+ if (opts.metadataaddr) {
25
+ return opts.metadataaddr
26
+ }
27
+ const host = process.env.GCE_METADATA_HOST
28
+ return host ? 'http://' + host : 'http://metadata.google.internal'
29
+ }
30
+
31
+ const login = async (): Promise<string> => {
32
+ const configured = opts.token || process.env.GOOGLE_OAUTH_ACCESS_TOKEN
33
+ if (configured) {
34
+ return configured
35
+ }
36
+
37
+ const url =
38
+ metadataaddr().replace(/\/$/, '') +
39
+ '/computeMetadata/v1/instance/service-accounts/default/token'
40
+
41
+ const res = await fetchjson('GET', url, { 'Metadata-Flavor': 'Google' })
42
+
43
+ const got = res.body && res.body.access_token
44
+ if (200 !== res.status || !got) {
45
+ throw new SekretoError('sekreto: gcp: no token and metadata server did not answer')
46
+ }
47
+
48
+ const expires = Number(res.body.expires_in)
49
+ renewat = 0 < expires ? Date.now() + Math.max(expires - 60, 1) * 1000 : Infinity
50
+
51
+ return String(got)
52
+ }
53
+
54
+ return {
55
+ lookup: async (name: string) => {
56
+ const project = opts.project || ''
57
+ if ('' === project) {
58
+ throw new SekretoError('sekreto: gcp: no project')
59
+ }
60
+
61
+ const addr = opts.addr || 'https://secretmanager.googleapis.com'
62
+ checkaddr(addr)
63
+
64
+ if (undefined === livetoken || Date.now() >= renewat) {
65
+ livetoken = await login()
66
+ }
67
+
68
+ const url =
69
+ addr.replace(/\/$/, '') +
70
+ '/v1/projects/' +
71
+ project +
72
+ '/secrets/' +
73
+ flatname(name, '_') +
74
+ '/versions/latest:access'
75
+
76
+ const res = await fetchjson('GET', url, { authorization: 'Bearer ' + livetoken })
77
+
78
+ if (404 === res.status) {
79
+ return undefined
80
+ }
81
+
82
+ if (200 !== res.status) {
83
+ throw new SekretoError('sekreto: gcp error: ' + res.status + ': ' + url)
84
+ }
85
+
86
+ const data = res.body && res.body.payload && res.body.payload.data
87
+ if ('string' !== typeof data) {
88
+ return undefined
89
+ }
90
+
91
+ return Buffer.from(data, 'base64').toString('utf8')
92
+ },
93
+ describe: () => 'gcpsecrets:' + (opts.project || ''),
94
+ }
95
+ }
96
+
97
+ /** Azure Key Vault.
98
+ *
99
+ * `api.token` reads secret `api-token` (dots flattened to `-`; Key
100
+ * Vault names allow nothing else), current version. The token comes
101
+ * from config, then a client-credentials login when tenant/clientid/
102
+ * clientsecret are given, then the IMDS managed-identity endpoint - so
103
+ * on Azure's own platform no credential configuration is needed.
104
+ *
105
+ * As with GCP, the IMDS call is plain http to a link-local host by
106
+ * platform design and carries no credential; the login and vault
107
+ * addresses are `checkaddr`-guarded. */
108
+
109
+
110
+ // Registering at import is what makes this module's presence the only
111
+ // thing that decides whether the kind exists in a build.
112
+ import { register } from './Registry'
113
+
114
+ register({
115
+ name: 'gcpsecrets',
116
+ needs: ['fetch'],
117
+ define: (spec: ProviderSpec) => gcpsecretsprovider(spec),
118
+ })