@ant.sh/colony 0.1.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.
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/dist/cjs/cli.js +281 -0
- package/dist/cjs/cli.js.map +7 -0
- package/dist/cjs/index.js +383 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/parser.js +319 -0
- package/dist/cjs/parser.js.map +7 -0
- package/dist/cjs/providers/aws.js +115 -0
- package/dist/cjs/providers/aws.js.map +7 -0
- package/dist/cjs/providers/openbao.js +49 -0
- package/dist/cjs/providers/openbao.js.map +7 -0
- package/dist/cjs/providers/vault-base.js +98 -0
- package/dist/cjs/providers/vault-base.js.map +7 -0
- package/dist/cjs/providers/vault.js +49 -0
- package/dist/cjs/providers/vault.js.map +7 -0
- package/dist/cjs/resolver.js +247 -0
- package/dist/cjs/resolver.js.map +7 -0
- package/dist/cjs/secrets.js +238 -0
- package/dist/cjs/secrets.js.map +7 -0
- package/dist/cjs/strings.js +99 -0
- package/dist/cjs/strings.js.map +7 -0
- package/dist/cjs/util.js +74 -0
- package/dist/cjs/util.js.map +7 -0
- package/dist/esm/cli.js +281 -0
- package/dist/esm/cli.js.map +7 -0
- package/dist/esm/index.d.ts +342 -0
- package/dist/esm/index.js +347 -0
- package/dist/esm/index.js.map +7 -0
- package/dist/esm/package.json +3 -0
- package/dist/esm/parser.js +286 -0
- package/dist/esm/parser.js.map +7 -0
- package/dist/esm/providers/aws.js +82 -0
- package/dist/esm/providers/aws.js.map +7 -0
- package/dist/esm/providers/openbao.js +26 -0
- package/dist/esm/providers/openbao.js.map +7 -0
- package/dist/esm/providers/vault-base.js +75 -0
- package/dist/esm/providers/vault-base.js.map +7 -0
- package/dist/esm/providers/vault.js +26 -0
- package/dist/esm/providers/vault.js.map +7 -0
- package/dist/esm/resolver.js +224 -0
- package/dist/esm/resolver.js.map +7 -0
- package/dist/esm/secrets.js +209 -0
- package/dist/esm/secrets.js.map +7 -0
- package/dist/esm/strings.js +75 -0
- package/dist/esm/strings.js.map +7 -0
- package/dist/esm/util.js +47 -0
- package/dist/esm/util.js.map +7 -0
- package/package.json +66 -0
- package/src/cli.js +353 -0
- package/src/index.d.ts +342 -0
- package/src/index.js +473 -0
- package/src/parser.js +381 -0
- package/src/providers/aws.js +112 -0
- package/src/providers/openbao.js +32 -0
- package/src/providers/vault-base.js +92 -0
- package/src/providers/vault.js +31 -0
- package/src/resolver.js +286 -0
- package/src/secrets.js +313 -0
- package/src/strings.js +84 -0
- package/src/util.js +49 -0
package/src/index.d.ts
ADDED
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for colony
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export interface SandboxOptions {
|
|
6
|
+
/** Restrict @include paths to this directory */
|
|
7
|
+
basePath?: string;
|
|
8
|
+
/** Whitelist of allowed environment variables for ${ENV:*} (null = allow all) */
|
|
9
|
+
allowedEnvVars?: string[] | null;
|
|
10
|
+
/** Whitelist of allowed custom variables for ${VAR:*} (null = allow all) */
|
|
11
|
+
allowedVars?: string[] | null;
|
|
12
|
+
/** Maximum depth for nested includes (default: 50) */
|
|
13
|
+
maxIncludeDepth?: number;
|
|
14
|
+
/** Maximum file size in bytes for included files */
|
|
15
|
+
maxFileSize?: number;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Secret provider interface for custom integrations
|
|
20
|
+
*/
|
|
21
|
+
export interface SecretProvider {
|
|
22
|
+
/** Unique prefix for this provider (e.g., "AWS", "VAULT") */
|
|
23
|
+
readonly prefix: string;
|
|
24
|
+
/** Fetch a secret value by key/path */
|
|
25
|
+
fetch(key: string): Promise<string>;
|
|
26
|
+
/** Optional: validate configuration on registration */
|
|
27
|
+
validate?(): Promise<void>;
|
|
28
|
+
/** Optional: cleanup resources */
|
|
29
|
+
dispose?(): Promise<void>;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export interface SecretCacheOptions {
|
|
33
|
+
/** Enable caching (default: true) */
|
|
34
|
+
enabled?: boolean;
|
|
35
|
+
/** Cache TTL in milliseconds (default: 300000 = 5 minutes) */
|
|
36
|
+
ttl?: number;
|
|
37
|
+
/** Maximum number of cached secrets (default: 100) */
|
|
38
|
+
maxSize?: number;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export interface SecretsOptions {
|
|
42
|
+
/** Secret providers to use (e.g., AwsSecretsProvider) */
|
|
43
|
+
providers?: SecretProvider[];
|
|
44
|
+
/** Whitelist of allowed secret patterns (glob supported, null = allow all) */
|
|
45
|
+
allowedSecrets?: string[] | null;
|
|
46
|
+
/** Cache settings */
|
|
47
|
+
cache?: SecretCacheOptions;
|
|
48
|
+
/** Behavior when secret not found: 'empty' returns "", 'warn' adds warning, 'error' throws */
|
|
49
|
+
onNotFound?: "empty" | "warn" | "error";
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface LoadColonyOptions {
|
|
53
|
+
/** Entry colony file path */
|
|
54
|
+
entry: string;
|
|
55
|
+
/** Dimension names (e.g., ["env", "realm", "region"]) */
|
|
56
|
+
dims?: string[];
|
|
57
|
+
/** Context values for scope matching */
|
|
58
|
+
ctx?: Record<string, string>;
|
|
59
|
+
/** Custom variables for ${VAR:*} interpolation */
|
|
60
|
+
vars?: Record<string, string>;
|
|
61
|
+
/** Schema validation hook (supports sync and async) */
|
|
62
|
+
schema?: (cfg: ColonyConfig) => ColonyConfig | Promise<ColonyConfig>;
|
|
63
|
+
/** Security sandbox options */
|
|
64
|
+
sandbox?: SandboxOptions;
|
|
65
|
+
/** Warn when skipping already-visited includes */
|
|
66
|
+
warnOnSkippedIncludes?: boolean;
|
|
67
|
+
/** Secrets provider options */
|
|
68
|
+
secrets?: SecretsOptions;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface Warning {
|
|
72
|
+
type:
|
|
73
|
+
| "blocked_env_var"
|
|
74
|
+
| "blocked_var"
|
|
75
|
+
| "unknown_var"
|
|
76
|
+
| "unknown_ctx"
|
|
77
|
+
| "unknown_interpolation"
|
|
78
|
+
| "skipped_include"
|
|
79
|
+
| "blocked_secret"
|
|
80
|
+
| "secret_not_found"
|
|
81
|
+
| "secret_fetch_error"
|
|
82
|
+
| "unknown_provider";
|
|
83
|
+
message: string;
|
|
84
|
+
var?: string;
|
|
85
|
+
file?: string;
|
|
86
|
+
pattern?: string;
|
|
87
|
+
/** Provider name (for secret warnings) */
|
|
88
|
+
provider?: string;
|
|
89
|
+
/** Secret key (for secret warnings) */
|
|
90
|
+
key?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface TraceInfo {
|
|
94
|
+
/** Operator used (=, :=, |=, +=, -=) */
|
|
95
|
+
op: string;
|
|
96
|
+
/** Scope segments that matched */
|
|
97
|
+
scope: string[];
|
|
98
|
+
/** Specificity score (number of non-* segments) */
|
|
99
|
+
specificity: number;
|
|
100
|
+
/** File path where the rule was defined */
|
|
101
|
+
filePath: string;
|
|
102
|
+
/** Line number in the file */
|
|
103
|
+
line: number;
|
|
104
|
+
/** Column number in the file */
|
|
105
|
+
col: number;
|
|
106
|
+
/** Raw key from the rule */
|
|
107
|
+
keyRaw: string;
|
|
108
|
+
/** Source location string (filePath:line:col) */
|
|
109
|
+
source: string;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export interface DiffResult {
|
|
113
|
+
/** Keys present in other but not in this config */
|
|
114
|
+
added: string[];
|
|
115
|
+
/** Keys present in this config but not in other */
|
|
116
|
+
removed: string[];
|
|
117
|
+
/** Keys present in both but with different values */
|
|
118
|
+
changed: Array<{
|
|
119
|
+
key: string;
|
|
120
|
+
from: unknown;
|
|
121
|
+
to: unknown;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export interface ColonyConfig {
|
|
126
|
+
/** Get a value by dot-notation path */
|
|
127
|
+
get(path: string): unknown;
|
|
128
|
+
/** Get trace info for how a key was set */
|
|
129
|
+
explain(path: string): TraceInfo | null;
|
|
130
|
+
/** Serialize to plain object */
|
|
131
|
+
toJSON(): Record<string, unknown>;
|
|
132
|
+
/** List all leaf keys in dot notation */
|
|
133
|
+
keys(): string[];
|
|
134
|
+
/** Compare with another config */
|
|
135
|
+
diff(other: ColonyConfig | Record<string, unknown>): DiffResult;
|
|
136
|
+
/** Internal trace data */
|
|
137
|
+
readonly _trace: Map<string, TraceInfo>;
|
|
138
|
+
/** Warnings generated during resolution */
|
|
139
|
+
readonly _warnings: Warning[];
|
|
140
|
+
/** Allow indexing with any string key */
|
|
141
|
+
[key: string]: unknown;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export interface ValidationResult {
|
|
145
|
+
/** Whether all files are valid */
|
|
146
|
+
valid: boolean;
|
|
147
|
+
/** List of all files that were checked */
|
|
148
|
+
files: string[];
|
|
149
|
+
/** List of errors found */
|
|
150
|
+
errors: Array<{
|
|
151
|
+
file: string;
|
|
152
|
+
error: string;
|
|
153
|
+
}>;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
export interface DiffColonyOptions extends Omit<LoadColonyOptions, "ctx"> {
|
|
157
|
+
/** First context to compare */
|
|
158
|
+
ctx1: Record<string, string>;
|
|
159
|
+
/** Second context to compare */
|
|
160
|
+
ctx2: Record<string, string>;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
export interface DiffColonyResult {
|
|
164
|
+
/** Config resolved with ctx1 */
|
|
165
|
+
cfg1: ColonyConfig;
|
|
166
|
+
/** Config resolved with ctx2 */
|
|
167
|
+
cfg2: ColonyConfig;
|
|
168
|
+
/** Differences between the two configs */
|
|
169
|
+
diff: DiffResult;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Load and resolve a colony configuration file
|
|
174
|
+
*/
|
|
175
|
+
export function loadColony(options: LoadColonyOptions): Promise<ColonyConfig>;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Validate syntax of colony files without resolving
|
|
179
|
+
*/
|
|
180
|
+
export function validateColony(entry: string): Promise<ValidationResult>;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* List all files that would be included (dry run)
|
|
184
|
+
*/
|
|
185
|
+
export function dryRunIncludes(entry: string): Promise<string[]>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Compare configs loaded with different contexts
|
|
189
|
+
*/
|
|
190
|
+
export function diffColony(options: DiffColonyOptions): Promise<DiffColonyResult>;
|
|
191
|
+
|
|
192
|
+
export interface LintIssue {
|
|
193
|
+
/** Type of issue found */
|
|
194
|
+
type: "parse_error" | "shadowed_rule" | "overridden_wildcard" | "empty_include";
|
|
195
|
+
/** Severity level */
|
|
196
|
+
severity: "error" | "warning" | "info";
|
|
197
|
+
/** Human-readable message */
|
|
198
|
+
message: string;
|
|
199
|
+
/** File where the issue was found */
|
|
200
|
+
file?: string;
|
|
201
|
+
/** Line number in the file */
|
|
202
|
+
line?: number;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export interface LintColonyOptions {
|
|
206
|
+
/** Entry colony file path */
|
|
207
|
+
entry: string;
|
|
208
|
+
/** Dimension names (e.g., ["env", "realm", "region"]) */
|
|
209
|
+
dims?: string[];
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
export interface LintColonyResult {
|
|
213
|
+
/** List of issues found */
|
|
214
|
+
issues: LintIssue[];
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Lint colony files for potential issues
|
|
219
|
+
*/
|
|
220
|
+
export function lintColony(options: LintColonyOptions): Promise<LintColonyResult>;
|
|
221
|
+
|
|
222
|
+
// ============================================================================
|
|
223
|
+
// Secrets Management
|
|
224
|
+
// ============================================================================
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Register a secret provider globally (available to all loadColony calls)
|
|
228
|
+
*/
|
|
229
|
+
export function registerSecretProvider(provider: SecretProvider): void;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Unregister a secret provider by prefix
|
|
233
|
+
*/
|
|
234
|
+
export function unregisterSecretProvider(prefix: string): boolean;
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Clear all globally registered secret providers
|
|
238
|
+
*/
|
|
239
|
+
export function clearSecretProviders(): void;
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* AWS Secrets Manager provider
|
|
243
|
+
*
|
|
244
|
+
* @example
|
|
245
|
+
* ```ts
|
|
246
|
+
* import { loadColony, AwsSecretsProvider } from "@ant.sh/colony";
|
|
247
|
+
*
|
|
248
|
+
* const cfg = await loadColony({
|
|
249
|
+
* entry: "./config/app.colony",
|
|
250
|
+
* secrets: {
|
|
251
|
+
* providers: [new AwsSecretsProvider({ region: "us-east-1" })],
|
|
252
|
+
* },
|
|
253
|
+
* });
|
|
254
|
+
* ```
|
|
255
|
+
*
|
|
256
|
+
* Config usage:
|
|
257
|
+
* ```
|
|
258
|
+
* *.db.password = "${AWS:myapp/db#password}";
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
export class AwsSecretsProvider implements SecretProvider {
|
|
262
|
+
readonly prefix: "AWS";
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* @param options.region - AWS region (default: process.env.AWS_REGION or "us-east-1")
|
|
266
|
+
*/
|
|
267
|
+
constructor(options?: { region?: string });
|
|
268
|
+
|
|
269
|
+
fetch(key: string): Promise<string>;
|
|
270
|
+
validate(): Promise<void>;
|
|
271
|
+
dispose(): Promise<void>;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/**
|
|
275
|
+
* HashiCorp Vault provider
|
|
276
|
+
*
|
|
277
|
+
* @example
|
|
278
|
+
* ```ts
|
|
279
|
+
* import { loadColony, VaultProvider } from "@ant.sh/colony";
|
|
280
|
+
*
|
|
281
|
+
* const cfg = await loadColony({
|
|
282
|
+
* entry: "./config/app.colony",
|
|
283
|
+
* secrets: {
|
|
284
|
+
* providers: [new VaultProvider({ addr: "https://vault.example.com" })],
|
|
285
|
+
* },
|
|
286
|
+
* });
|
|
287
|
+
* ```
|
|
288
|
+
*
|
|
289
|
+
* Config usage:
|
|
290
|
+
* ```
|
|
291
|
+
* *.api.key = "${VAULT:secret/data/myapp#api_key}";
|
|
292
|
+
* ```
|
|
293
|
+
*/
|
|
294
|
+
export class VaultProvider implements SecretProvider {
|
|
295
|
+
readonly prefix: "VAULT";
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* @param options.addr - Vault address (default: process.env.VAULT_ADDR or "http://127.0.0.1:8200")
|
|
299
|
+
* @param options.token - Vault token (default: process.env.VAULT_TOKEN)
|
|
300
|
+
* @param options.namespace - Vault namespace (default: process.env.VAULT_NAMESPACE)
|
|
301
|
+
* @param options.timeout - Request timeout in ms (default: 30000)
|
|
302
|
+
*/
|
|
303
|
+
constructor(options?: { addr?: string; token?: string; namespace?: string; timeout?: number });
|
|
304
|
+
|
|
305
|
+
fetch(key: string): Promise<string>;
|
|
306
|
+
validate(): Promise<void>;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/**
|
|
310
|
+
* OpenBao provider (API-compatible Vault fork)
|
|
311
|
+
*
|
|
312
|
+
* @example
|
|
313
|
+
* ```ts
|
|
314
|
+
* import { loadColony, OpenBaoProvider } from "@ant.sh/colony";
|
|
315
|
+
*
|
|
316
|
+
* const cfg = await loadColony({
|
|
317
|
+
* entry: "./config/app.colony",
|
|
318
|
+
* secrets: {
|
|
319
|
+
* providers: [new OpenBaoProvider({ addr: "https://bao.example.com" })],
|
|
320
|
+
* },
|
|
321
|
+
* });
|
|
322
|
+
* ```
|
|
323
|
+
*
|
|
324
|
+
* Config usage:
|
|
325
|
+
* ```
|
|
326
|
+
* *.api.key = "${OPENBAO:secret/data/myapp#api_key}";
|
|
327
|
+
* ```
|
|
328
|
+
*/
|
|
329
|
+
export class OpenBaoProvider implements SecretProvider {
|
|
330
|
+
readonly prefix: "OPENBAO";
|
|
331
|
+
|
|
332
|
+
/**
|
|
333
|
+
* @param options.addr - OpenBao address (default: process.env.BAO_ADDR or "http://127.0.0.1:8200")
|
|
334
|
+
* @param options.token - OpenBao token (default: process.env.BAO_TOKEN)
|
|
335
|
+
* @param options.namespace - OpenBao namespace (default: process.env.BAO_NAMESPACE)
|
|
336
|
+
* @param options.timeout - Request timeout in ms (default: 30000)
|
|
337
|
+
*/
|
|
338
|
+
constructor(options?: { addr?: string; token?: string; namespace?: string; timeout?: number });
|
|
339
|
+
|
|
340
|
+
fetch(key: string): Promise<string>;
|
|
341
|
+
validate(): Promise<void>;
|
|
342
|
+
}
|