@enspirit/emb 0.15.0 → 0.17.5

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 (57) hide show
  1. package/README.md +218 -43
  2. package/bin/release +122 -0
  3. package/dist/src/cli/abstract/BaseCommand.d.ts +1 -0
  4. package/dist/src/cli/abstract/BaseCommand.js +23 -4
  5. package/dist/src/cli/abstract/FlavouredCommand.d.ts +1 -0
  6. package/dist/src/cli/abstract/KubernetesCommand.d.ts +1 -0
  7. package/dist/src/cli/commands/components/logs.d.ts +2 -1
  8. package/dist/src/cli/commands/components/logs.js +21 -24
  9. package/dist/src/cli/commands/secrets/index.d.ts +14 -0
  10. package/dist/src/cli/commands/secrets/index.js +71 -0
  11. package/dist/src/cli/commands/secrets/providers.d.ts +12 -0
  12. package/dist/src/cli/commands/secrets/providers.js +50 -0
  13. package/dist/src/cli/commands/secrets/validate.d.ts +18 -0
  14. package/dist/src/cli/commands/secrets/validate.js +145 -0
  15. package/dist/src/cli/commands/tasks/run.js +6 -1
  16. package/dist/src/cli/hooks/init.js +7 -1
  17. package/dist/src/config/index.d.ts +10 -1
  18. package/dist/src/config/index.js +28 -3
  19. package/dist/src/config/schema.d.ts +7 -4
  20. package/dist/src/config/schema.json +173 -9
  21. package/dist/src/context.d.ts +9 -0
  22. package/dist/src/context.js +19 -0
  23. package/dist/src/docker/compose/operations/ComposeLogsOperation.d.ts +21 -0
  24. package/dist/src/docker/compose/operations/ComposeLogsOperation.js +85 -0
  25. package/dist/src/docker/compose/operations/index.d.ts +1 -0
  26. package/dist/src/docker/compose/operations/index.js +1 -0
  27. package/dist/src/index.d.ts +1 -0
  28. package/dist/src/index.js +1 -0
  29. package/dist/src/monorepo/monorepo.js +13 -5
  30. package/dist/src/monorepo/operations/shell/ExecuteLocalCommandOperation.js +40 -10
  31. package/dist/src/monorepo/operations/tasks/RunTasksOperation.d.ts +1 -1
  32. package/dist/src/monorepo/operations/tasks/RunTasksOperation.js +1 -1
  33. package/dist/src/monorepo/plugins/VaultPlugin.d.ts +46 -0
  34. package/dist/src/monorepo/plugins/VaultPlugin.js +91 -0
  35. package/dist/src/monorepo/plugins/index.d.ts +1 -0
  36. package/dist/src/monorepo/plugins/index.js +3 -0
  37. package/dist/src/secrets/SecretDiscovery.d.ts +46 -0
  38. package/dist/src/secrets/SecretDiscovery.js +82 -0
  39. package/dist/src/secrets/SecretManager.d.ts +52 -0
  40. package/dist/src/secrets/SecretManager.js +75 -0
  41. package/dist/src/secrets/SecretProvider.d.ts +45 -0
  42. package/dist/src/secrets/SecretProvider.js +38 -0
  43. package/dist/src/secrets/index.d.ts +3 -0
  44. package/dist/src/secrets/index.js +3 -0
  45. package/dist/src/secrets/providers/VaultOidcHelper.d.ts +39 -0
  46. package/dist/src/secrets/providers/VaultOidcHelper.js +226 -0
  47. package/dist/src/secrets/providers/VaultProvider.d.ts +74 -0
  48. package/dist/src/secrets/providers/VaultProvider.js +266 -0
  49. package/dist/src/secrets/providers/VaultTokenCache.d.ts +60 -0
  50. package/dist/src/secrets/providers/VaultTokenCache.js +188 -0
  51. package/dist/src/secrets/providers/index.d.ts +2 -0
  52. package/dist/src/secrets/providers/index.js +2 -0
  53. package/dist/src/types.d.ts +2 -0
  54. package/dist/src/utils/TemplateExpander.d.ts +13 -1
  55. package/dist/src/utils/TemplateExpander.js +68 -15
  56. package/oclif.manifest.json +578 -173
  57. package/package.json +12 -5
@@ -1,10 +1,35 @@
1
1
  import { findUp } from 'find-up';
2
- import { dirname } from 'node:path';
2
+ import { existsSync } from 'node:fs';
3
+ import { dirname, join, resolve } from 'node:path';
3
4
  import { validateUserConfig } from './validation.js';
4
5
  export * from './types.js';
5
6
  export * from './validation.js';
6
- export const loadConfig = async () => {
7
- const path = await findUp('.emb.yml');
7
+ export const loadConfig = async (options = {}) => {
8
+ let path;
9
+ // Priority 1: Explicit root option (from --root/-C flag)
10
+ // Priority 2: EMB_ROOT environment variable
11
+ // Priority 3: Walk up to find .emb.yml (original behavior)
12
+ const explicitRoot = options.root || process.env.EMB_ROOT;
13
+ if (explicitRoot) {
14
+ const resolved = resolve(explicitRoot);
15
+ // Check if it's a direct path to a config file
16
+ if (resolved.endsWith('.emb.yml') && existsSync(resolved)) {
17
+ path = resolved;
18
+ }
19
+ else {
20
+ // Assume it's a directory, look for .emb.yml inside
21
+ const configPath = join(resolved, '.emb.yml');
22
+ if (existsSync(configPath)) {
23
+ path = configPath;
24
+ }
25
+ else {
26
+ throw new Error(`Could not find .emb.yml in specified root: ${explicitRoot}`);
27
+ }
28
+ }
29
+ }
30
+ else {
31
+ path = await findUp('.emb.yml');
32
+ }
8
33
  if (!path) {
9
34
  throw new Error('Could not find EMB config anywhere');
10
35
  }
@@ -3,6 +3,12 @@
3
3
  * DO NOT MODIFY IT BY HAND. Instead, modify the source JSONSchema file,
4
4
  * and run json-schema-to-typescript to regenerate this file.
5
5
  */
6
+ export type PluginConfigItem = {
7
+ [k: string]: unknown;
8
+ } & {
9
+ name: Identifier;
10
+ config?: unknown;
11
+ };
6
12
  export type Identifier = string;
7
13
  export type TaskConfig = TaskConfig1 & {
8
14
  description?: string;
@@ -55,10 +61,7 @@ export interface EMBConfig {
55
61
  */
56
62
  rootDir?: string;
57
63
  };
58
- plugins?: {
59
- name: Identifier;
60
- config?: unknown;
61
- }[];
64
+ plugins?: PluginConfigItem[];
62
65
  /**
63
66
  * Variables to install on the environment
64
67
  */
@@ -24,15 +24,7 @@
24
24
  "plugins": {
25
25
  "type": "array",
26
26
  "items": {
27
- "type": "object",
28
- "required": ["name"],
29
- "properties": {
30
- "name": {
31
- "$ref": "#/definitions/Identifier"
32
- },
33
- "config": {}
34
- },
35
- "additionalProperties": false
27
+ "$ref": "#/definitions/PluginConfigItem"
36
28
  }
37
29
  },
38
30
  "env": {
@@ -376,6 +368,178 @@
376
368
  { "$ref": "#/definitions/JsonPatchMoveOperation" },
377
369
  { "$ref": "#/definitions/JsonPatchCopyOperation" }
378
370
  ]
371
+ },
372
+ "VaultTokenAuth": {
373
+ "type": "object",
374
+ "required": ["method", "token"],
375
+ "properties": {
376
+ "method": { "const": "token" },
377
+ "token": { "type": "string", "description": "Vault token for authentication" }
378
+ },
379
+ "additionalProperties": false
380
+ },
381
+ "VaultAppRoleAuth": {
382
+ "type": "object",
383
+ "required": ["method", "roleId", "secretId"],
384
+ "properties": {
385
+ "method": { "const": "approle" },
386
+ "roleId": { "type": "string", "description": "AppRole role ID" },
387
+ "secretId": { "type": "string", "description": "AppRole secret ID" }
388
+ },
389
+ "additionalProperties": false
390
+ },
391
+ "VaultKubernetesAuth": {
392
+ "type": "object",
393
+ "required": ["method", "role"],
394
+ "properties": {
395
+ "method": { "const": "kubernetes" },
396
+ "role": { "type": "string", "description": "Kubernetes auth role name" }
397
+ },
398
+ "additionalProperties": false
399
+ },
400
+ "VaultJwtAuth": {
401
+ "type": "object",
402
+ "required": ["method", "role", "jwt"],
403
+ "properties": {
404
+ "method": { "const": "jwt" },
405
+ "role": { "type": "string", "description": "JWT auth role name" },
406
+ "jwt": { "type": "string", "description": "JWT token for authentication" }
407
+ },
408
+ "additionalProperties": false
409
+ },
410
+ "VaultOidcAuth": {
411
+ "type": "object",
412
+ "required": ["method"],
413
+ "properties": {
414
+ "method": { "const": "oidc" },
415
+ "role": { "type": "string", "description": "OIDC auth role name" },
416
+ "port": { "type": "integer", "description": "Local port for OIDC callback" }
417
+ },
418
+ "additionalProperties": false
419
+ },
420
+ "VaultAuthConfig": {
421
+ "description": "Authentication configuration for HashiCorp Vault",
422
+ "oneOf": [
423
+ { "$ref": "#/definitions/VaultTokenAuth" },
424
+ { "$ref": "#/definitions/VaultAppRoleAuth" },
425
+ { "$ref": "#/definitions/VaultKubernetesAuth" },
426
+ { "$ref": "#/definitions/VaultJwtAuth" },
427
+ { "$ref": "#/definitions/VaultOidcAuth" }
428
+ ]
429
+ },
430
+ "VaultPluginConfig": {
431
+ "type": "object",
432
+ "description": "Configuration for the HashiCorp Vault plugin",
433
+ "properties": {
434
+ "address": {
435
+ "type": "string",
436
+ "description": "Vault server address. Defaults to VAULT_ADDR env var."
437
+ },
438
+ "namespace": {
439
+ "type": "string",
440
+ "description": "Vault namespace. Defaults to VAULT_NAMESPACE env var."
441
+ },
442
+ "auth": {
443
+ "$ref": "#/definitions/VaultAuthConfig"
444
+ }
445
+ },
446
+ "additionalProperties": false
447
+ },
448
+ "AutoDockerPluginConfig": {
449
+ "type": "object",
450
+ "description": "Configuration for the AutoDocker plugin",
451
+ "properties": {
452
+ "glob": {
453
+ "type": "string",
454
+ "description": "Glob pattern to find Dockerfiles. Defaults to '*/Dockerfile'."
455
+ },
456
+ "ignore": {
457
+ "oneOf": [
458
+ { "type": "string" },
459
+ { "type": "array", "items": { "type": "string" } }
460
+ ],
461
+ "description": "Patterns to ignore when searching for Dockerfiles."
462
+ }
463
+ },
464
+ "additionalProperties": false
465
+ },
466
+ "DotEnvPluginConfig": {
467
+ "type": "array",
468
+ "description": "Array of .env file paths to load",
469
+ "items": {
470
+ "type": "string"
471
+ }
472
+ },
473
+ "EmbfilesPluginConfig": {
474
+ "type": "object",
475
+ "description": "Configuration for the Embfiles loader plugin",
476
+ "properties": {
477
+ "glob": {
478
+ "oneOf": [
479
+ { "type": "string" },
480
+ { "type": "array", "items": { "type": "string" } }
481
+ ],
482
+ "description": "Glob pattern(s) to find Embfiles. Defaults to '*/Embfile.{yaml,yml}'."
483
+ }
484
+ },
485
+ "additionalProperties": false
486
+ },
487
+ "PluginConfigItem": {
488
+ "type": "object",
489
+ "required": ["name"],
490
+ "properties": {
491
+ "name": {
492
+ "$ref": "#/definitions/Identifier"
493
+ },
494
+ "config": {}
495
+ },
496
+ "additionalProperties": false,
497
+ "allOf": [
498
+ {
499
+ "if": {
500
+ "properties": { "name": { "const": "vault" } },
501
+ "required": ["name"]
502
+ },
503
+ "then": {
504
+ "properties": {
505
+ "config": { "$ref": "#/definitions/VaultPluginConfig" }
506
+ }
507
+ }
508
+ },
509
+ {
510
+ "if": {
511
+ "properties": { "name": { "const": "autodocker" } },
512
+ "required": ["name"]
513
+ },
514
+ "then": {
515
+ "properties": {
516
+ "config": { "$ref": "#/definitions/AutoDockerPluginConfig" }
517
+ }
518
+ }
519
+ },
520
+ {
521
+ "if": {
522
+ "properties": { "name": { "const": "dotenv" } },
523
+ "required": ["name"]
524
+ },
525
+ "then": {
526
+ "properties": {
527
+ "config": { "$ref": "#/definitions/DotEnvPluginConfig" }
528
+ }
529
+ }
530
+ },
531
+ {
532
+ "if": {
533
+ "properties": { "name": { "const": "embfiles" } },
534
+ "required": ["name"]
535
+ },
536
+ "then": {
537
+ "properties": {
538
+ "config": { "$ref": "#/definitions/EmbfilesPluginConfig" }
539
+ }
540
+ }
541
+ }
542
+ ]
379
543
  }
380
544
  }
381
545
  }
@@ -1,3 +1,12 @@
1
1
  import { EmbContext } from './types.js';
2
2
  export declare const getContext: () => EmbContext;
3
3
  export declare const setContext: (ctx: EmbContext) => EmbContext;
4
+ /**
5
+ * Check if the context's EMB_ROOT matches the current environment.
6
+ * Used to detect when tests switch between different example monorepos.
7
+ */
8
+ export declare const isContextStale: () => boolean;
9
+ /**
10
+ * Reset the context. Used in testing to ensure a fresh context for each test suite.
11
+ */
12
+ export declare const resetContext: () => void;
@@ -1,8 +1,27 @@
1
1
  let context;
2
+ let contextEmbRoot;
2
3
  export const getContext = () => {
3
4
  return context;
4
5
  };
5
6
  export const setContext = (ctx) => {
6
7
  context = ctx;
8
+ contextEmbRoot = process.env.EMB_ROOT;
7
9
  return ctx;
8
10
  };
11
+ /**
12
+ * Check if the context's EMB_ROOT matches the current environment.
13
+ * Used to detect when tests switch between different example monorepos.
14
+ */
15
+ export const isContextStale = () => {
16
+ if (!context) {
17
+ return false;
18
+ }
19
+ return contextEmbRoot !== process.env.EMB_ROOT;
20
+ };
21
+ /**
22
+ * Reset the context. Used in testing to ensure a fresh context for each test suite.
23
+ */
24
+ export const resetContext = () => {
25
+ context = undefined;
26
+ contextEmbRoot = undefined;
27
+ };
@@ -0,0 +1,21 @@
1
+ import { Writable } from 'node:stream';
2
+ import * as z from 'zod';
3
+ import { AbstractOperation } from '../../../operations/index.js';
4
+ /**
5
+ * https://docs.docker.com/reference/cli/docker/compose/logs/
6
+ */
7
+ export declare const ComposeLogsOperationInputSchema: z.ZodOptional<z.ZodObject<{
8
+ services: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ follow: z.ZodOptional<z.ZodBoolean>;
10
+ timestamps: z.ZodOptional<z.ZodBoolean>;
11
+ tail: z.ZodOptional<z.ZodNumber>;
12
+ }, z.core.$strip>>;
13
+ export declare class ComposeLogsOperation extends AbstractOperation<typeof ComposeLogsOperationInputSchema, void> {
14
+ protected out?: Writable | undefined;
15
+ /**
16
+ * @param out Optional writable stream to capture output. If not provided,
17
+ * output is streamed directly to the terminal (stdio: 'inherit').
18
+ */
19
+ constructor(out?: Writable | undefined);
20
+ protected _run(input: z.input<typeof ComposeLogsOperationInputSchema>): Promise<void>;
21
+ }
@@ -0,0 +1,85 @@
1
+ import { spawn } from 'node:child_process';
2
+ import * as z from 'zod';
3
+ import { AbstractOperation } from '../../../operations/index.js';
4
+ /**
5
+ * https://docs.docker.com/reference/cli/docker/compose/logs/
6
+ */
7
+ export const ComposeLogsOperationInputSchema = z
8
+ .object({
9
+ services: z
10
+ .array(z.string())
11
+ .optional()
12
+ .describe('The list of services to show logs for (all if omitted)'),
13
+ follow: z.boolean().optional().describe('Follow log output'),
14
+ timestamps: z.boolean().optional().describe('Show timestamps'),
15
+ tail: z
16
+ .number()
17
+ .optional()
18
+ .describe('Number of lines to show from the end'),
19
+ })
20
+ .optional();
21
+ export class ComposeLogsOperation extends AbstractOperation {
22
+ out;
23
+ /**
24
+ * @param out Optional writable stream to capture output. If not provided,
25
+ * output is streamed directly to the terminal (stdio: 'inherit').
26
+ */
27
+ constructor(out) {
28
+ super(ComposeLogsOperationInputSchema);
29
+ this.out = out;
30
+ }
31
+ async _run(input) {
32
+ const { monorepo } = this.context;
33
+ const cmd = 'docker';
34
+ const args = ['compose', 'logs'];
35
+ const follow = input?.follow ?? true;
36
+ if (follow) {
37
+ args.push('-f');
38
+ }
39
+ if (input?.timestamps) {
40
+ args.push('-t');
41
+ }
42
+ if (input?.tail !== undefined) {
43
+ args.push('--tail', String(input.tail));
44
+ }
45
+ if (input?.services && input.services.length > 0) {
46
+ args.push(...input.services);
47
+ }
48
+ const child = spawn(cmd, args, {
49
+ stdio: this.out ? 'pipe' : 'inherit',
50
+ cwd: monorepo.rootDir,
51
+ });
52
+ if (this.out && child.stdout && child.stderr) {
53
+ child.stdout.pipe(this.out, { end: false });
54
+ child.stderr.pipe(this.out, { end: false });
55
+ }
56
+ const forward = (sig) => {
57
+ try {
58
+ child.kill(sig);
59
+ }
60
+ catch { }
61
+ };
62
+ const signals = [
63
+ 'SIGINT',
64
+ 'SIGTERM',
65
+ 'SIGHUP',
66
+ 'SIGQUIT',
67
+ ];
68
+ signals.forEach((sig) => {
69
+ process.on(sig, () => forward(sig));
70
+ });
71
+ return new Promise((resolve, reject) => {
72
+ child.on('error', (err) => {
73
+ reject(new Error(`Failed to execute docker compose logs: ${err.message}`));
74
+ });
75
+ child.on('exit', (code) => {
76
+ if (code !== null && code !== 0) {
77
+ reject(new Error(`docker compose logs exited with code ${code}`));
78
+ }
79
+ else {
80
+ resolve();
81
+ }
82
+ });
83
+ });
84
+ }
85
+ }
@@ -1,6 +1,7 @@
1
1
  export * from './ComposeDownOperation.js';
2
2
  export * from './ComposeExecOperation.js';
3
3
  export * from './ComposeExecShellOperation.js';
4
+ export * from './ComposeLogsOperation.js';
4
5
  export * from './ComposePsOperation.js';
5
6
  export * from './ComposeRestartOperation.js';
6
7
  export * from './ComposeStartOperation.js';
@@ -1,6 +1,7 @@
1
1
  export * from './ComposeDownOperation.js';
2
2
  export * from './ComposeExecOperation.js';
3
3
  export * from './ComposeExecShellOperation.js';
4
+ export * from './ComposeLogsOperation.js';
4
5
  export * from './ComposePsOperation.js';
5
6
  export * from './ComposeRestartOperation.js';
6
7
  export * from './ComposeStartOperation.js';
@@ -2,5 +2,6 @@ export * from './context.js';
2
2
  export * from './docker/index.js';
3
3
  export * from './errors.js';
4
4
  export * from './monorepo/index.js';
5
+ export * from './secrets/index.js';
5
6
  export * from './types.js';
6
7
  export { run } from '@oclif/core';
package/dist/src/index.js CHANGED
@@ -2,5 +2,6 @@ export * from './context.js';
2
2
  export * from './docker/index.js';
3
3
  export * from './errors.js';
4
4
  export * from './monorepo/index.js';
5
+ export * from './secrets/index.js';
5
6
  export * from './types.js';
6
7
  export { run } from '@oclif/core';
@@ -1,4 +1,4 @@
1
- import { TaskManagerFactory } from '../index.js';
1
+ import { getContext, TaskManagerFactory } from '../index.js';
2
2
  import jsonpatch from 'fast-json-patch';
3
3
  import { join } from 'node:path';
4
4
  import { TemplateExpander } from '../utils/index.js';
@@ -106,12 +106,20 @@ export class Monorepo {
106
106
  }
107
107
  // Helper to expand a record of strings
108
108
  async expand(toExpand, vars, expander = new TemplateExpander()) {
109
+ const secrets = getContext()?.secrets;
110
+ const sources = {
111
+ env: process.env,
112
+ vars: vars || this.vars,
113
+ };
114
+ // Add all registered secret providers as sources
115
+ if (secrets) {
116
+ for (const providerName of secrets.getProviderNames()) {
117
+ sources[providerName] = secrets.createSource(providerName);
118
+ }
119
+ }
109
120
  const options = {
110
121
  default: 'vars',
111
- sources: {
112
- env: process.env,
113
- vars: vars || this.vars,
114
- },
122
+ sources,
115
123
  };
116
124
  return expander.expandRecord(toExpand, options);
117
125
  }
@@ -1,6 +1,12 @@
1
+ import { CommandExecError } from '../../../index.js';
1
2
  import { execa } from 'execa';
3
+ import { Readable } from 'node:stream';
2
4
  import * as z from 'zod';
3
5
  import { AbstractOperation } from '../../../operations/index.js';
6
+ // Type guard for execa error objects
7
+ function isExecaError(error) {
8
+ return error instanceof Error && 'exitCode' in error;
9
+ }
4
10
  /**
5
11
  * https://docs.docker.com/reference/api/engine/version/v1.37/#tag/Exec/operation/ContainerExec
6
12
  */
@@ -27,20 +33,44 @@ export class ExecuteLocalCommandOperation extends AbstractOperation {
27
33
  this.out = out;
28
34
  }
29
35
  async _run(input) {
30
- const proc = input.interactive
31
- ? execa(input.script, {
32
- cwd: input.workingDir,
33
- shell: true,
34
- env: input.env,
35
- stdin: 'inherit',
36
- })
37
- : execa(input.script, {
36
+ try {
37
+ if (input.interactive) {
38
+ // For interactive mode, inherit all stdio streams so the child process
39
+ // has direct access to the terminal TTY. This allows interactive CLI tools
40
+ // (like ionic, npm, etc.) to detect TTY and show prompts.
41
+ await execa(input.script, {
42
+ cwd: input.workingDir,
43
+ shell: true,
44
+ env: input.env,
45
+ stdio: 'inherit',
46
+ });
47
+ // Return an empty stream for type compatibility - the caller won't use it
48
+ // since interactive mode outputs directly to the terminal
49
+ return new Readable({
50
+ read() {
51
+ this.push(null);
52
+ },
53
+ });
54
+ }
55
+ // Non-interactive mode: capture output
56
+ const proc = execa(input.script, {
38
57
  all: true,
39
58
  cwd: input.workingDir,
40
59
  shell: true,
41
60
  env: input.env,
42
61
  });
43
- proc.all?.pipe(this.out || process.stdout);
44
- return proc.all || proc.stdout;
62
+ // With all: true, proc.all is always defined
63
+ proc.all.pipe(this.out || process.stdout);
64
+ await proc;
65
+ return proc.all;
66
+ }
67
+ catch (error) {
68
+ if (isExecaError(error)) {
69
+ const stderr = error.stderr?.trim();
70
+ const message = stderr || error.shortMessage || error.message;
71
+ throw new CommandExecError(message, error.exitCode ?? 1, error.signal);
72
+ }
73
+ throw error;
74
+ }
45
75
  }
46
76
  }
@@ -21,7 +21,7 @@ export type TaskWithScriptAndComponent = TaskInfo & {
21
21
  export declare class RunTasksOperation implements IOperation<RunTasksOperationParams, Array<TaskInfo>> {
22
22
  run(params: RunTasksOperationParams): Promise<Array<TaskInfo>>;
23
23
  protected runDocker(task: TaskWithScriptAndComponent, out?: Writable): Promise<void>;
24
- protected runLocal(task: TaskWithScript, out: Writable): Promise<import("stream").Readable>;
24
+ protected runLocal(task: TaskWithScript, _out: Writable): Promise<import("stream").Readable>;
25
25
  private defaultExecutorFor;
26
26
  private ensureExecutorValid;
27
27
  private availableExecutorsFor;
@@ -82,7 +82,7 @@ export class RunTasksOperation {
82
82
  env: await monorepo.expand(task.vars || {}),
83
83
  });
84
84
  }
85
- async runLocal(task, out) {
85
+ async runLocal(task, _out) {
86
86
  const { monorepo } = getContext();
87
87
  const cwd = task.component
88
88
  ? monorepo.join(monorepo.component(task.component).rootDir)
@@ -0,0 +1,46 @@
1
+ import { VaultAuthConfig } from '../../secrets/providers/VaultProvider.js';
2
+ import { AbstractPlugin } from './plugin.js';
3
+ /**
4
+ * Configuration for the Vault plugin in .emb.yml
5
+ */
6
+ export interface VaultPluginConfig {
7
+ /** Vault server address. Defaults to VAULT_ADDR env var. */
8
+ address?: string;
9
+ /** Authentication configuration */
10
+ auth?: VaultAuthConfig;
11
+ /** Vault namespace. Defaults to VAULT_NAMESPACE env var. */
12
+ namespace?: string;
13
+ }
14
+ /**
15
+ * Plugin that integrates HashiCorp Vault with EMB.
16
+ *
17
+ * Usage in .emb.yml:
18
+ * ```yaml
19
+ * plugins:
20
+ * - name: vault
21
+ * config:
22
+ * address: ${env:VAULT_ADDR:-http://localhost:8200}
23
+ * auth:
24
+ * method: token
25
+ * token: ${env:VAULT_TOKEN}
26
+ * ```
27
+ *
28
+ * Then use secrets in templates:
29
+ * ```yaml
30
+ * env:
31
+ * DB_PASSWORD: ${vault:secret/myapp/db#password}
32
+ * ```
33
+ */
34
+ export declare class VaultPlugin extends AbstractPlugin<VaultPluginConfig> {
35
+ static name: string;
36
+ private provider;
37
+ init(): Promise<void>;
38
+ /**
39
+ * Resolve the plugin configuration, filling in defaults from env vars.
40
+ */
41
+ private resolveConfig;
42
+ /**
43
+ * Resolve authentication configuration.
44
+ */
45
+ private resolveAuth;
46
+ }