@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
|
@@ -0,0 +1,383 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
20
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
21
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
22
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
23
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
24
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
25
|
+
mod
|
|
26
|
+
));
|
|
27
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
28
|
+
var index_exports = {};
|
|
29
|
+
__export(index_exports, {
|
|
30
|
+
AwsSecretsProvider: () => import_aws.AwsSecretsProvider,
|
|
31
|
+
OpenBaoProvider: () => import_openbao.OpenBaoProvider,
|
|
32
|
+
VaultProvider: () => import_vault.VaultProvider,
|
|
33
|
+
clearSecretProviders: () => import_secrets.clearSecretProviders,
|
|
34
|
+
diffColony: () => diffColony,
|
|
35
|
+
dryRunIncludes: () => dryRunIncludes,
|
|
36
|
+
lintColony: () => lintColony,
|
|
37
|
+
loadColony: () => loadColony,
|
|
38
|
+
registerSecretProvider: () => import_secrets.registerSecretProvider,
|
|
39
|
+
unregisterSecretProvider: () => import_secrets.unregisterSecretProvider,
|
|
40
|
+
validateColony: () => validateColony
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(index_exports);
|
|
43
|
+
var import_promises = __toESM(require("node:fs/promises"), 1);
|
|
44
|
+
var import_node_path = __toESM(require("node:path"), 1);
|
|
45
|
+
var import_fast_glob = __toESM(require("fast-glob"), 1);
|
|
46
|
+
var import_parser = require("./parser.js");
|
|
47
|
+
var import_resolver = require("./resolver.js");
|
|
48
|
+
var import_secrets = require("./secrets.js");
|
|
49
|
+
var import_aws = require("./providers/aws.js");
|
|
50
|
+
var import_vault = require("./providers/vault.js");
|
|
51
|
+
var import_openbao = require("./providers/openbao.js");
|
|
52
|
+
async function loadColony(opts) {
|
|
53
|
+
const entry = opts?.entry;
|
|
54
|
+
if (!entry) throw new Error("loadColony: opts.entry is required");
|
|
55
|
+
const sandbox = opts.sandbox ?? {};
|
|
56
|
+
const basePath = sandbox.basePath ? import_node_path.default.resolve(sandbox.basePath) : null;
|
|
57
|
+
const maxIncludeDepth = sandbox.maxIncludeDepth ?? 50;
|
|
58
|
+
const maxFileSize = sandbox.maxFileSize ?? null;
|
|
59
|
+
const warnOnSkippedIncludes = opts.warnOnSkippedIncludes ?? false;
|
|
60
|
+
const visited = /* @__PURE__ */ new Set();
|
|
61
|
+
const warnings = [];
|
|
62
|
+
const files = await expandIncludes(entry, visited, {
|
|
63
|
+
basePath,
|
|
64
|
+
maxIncludeDepth,
|
|
65
|
+
maxFileSize,
|
|
66
|
+
warnOnSkippedIncludes,
|
|
67
|
+
warnings
|
|
68
|
+
});
|
|
69
|
+
const parsed = [];
|
|
70
|
+
for (const file of files) {
|
|
71
|
+
const text = await import_promises.default.readFile(file, "utf8");
|
|
72
|
+
parsed.push((0, import_parser.parseColony)(text, { filePath: file }));
|
|
73
|
+
}
|
|
74
|
+
const dims = (Array.isArray(opts.dims) && opts.dims.length ? opts.dims : null) ?? parsed.find((p) => p.dims?.length)?.dims ?? ["env"];
|
|
75
|
+
const envDefaults = mergeEnvDefaults(parsed.map((p) => p.envDefaults ?? {}));
|
|
76
|
+
const ctx = {
|
|
77
|
+
...envDefaults,
|
|
78
|
+
env: process.env.NODE_ENV ?? "dev",
|
|
79
|
+
...opts.ctx
|
|
80
|
+
};
|
|
81
|
+
const vars = { ROOT: process.cwd(), ...opts.vars ?? {} };
|
|
82
|
+
const requires = parsed.flatMap((p) => p.requires ?? []);
|
|
83
|
+
const allRules = parsed.flatMap((p) => p.rules);
|
|
84
|
+
const allowedEnvVars = sandbox.allowedEnvVars ?? null;
|
|
85
|
+
const allowedVars = sandbox.allowedVars ?? null;
|
|
86
|
+
let cfg = (0, import_resolver.resolveRules)({ rules: allRules, dims, ctx, vars, allowedEnvVars, allowedVars, warnings });
|
|
87
|
+
const secretsOpts = opts.secrets ?? {};
|
|
88
|
+
if (secretsOpts.providers?.length || (0, import_secrets.hasGlobalProviders)()) {
|
|
89
|
+
const cacheOpts = secretsOpts.cache ?? {};
|
|
90
|
+
const cache = cacheOpts.enabled !== false ? new import_secrets.SecretCache(cacheOpts.maxSize ?? 100) : null;
|
|
91
|
+
const secretified = await (0, import_secrets.applySecretsDeep)(cfg, {
|
|
92
|
+
providers: secretsOpts.providers ?? [],
|
|
93
|
+
allowedSecrets: secretsOpts.allowedSecrets ?? null,
|
|
94
|
+
cache,
|
|
95
|
+
cacheTtl: cacheOpts.ttl ?? 3e5,
|
|
96
|
+
onNotFound: secretsOpts.onNotFound ?? "warn",
|
|
97
|
+
warnings
|
|
98
|
+
});
|
|
99
|
+
copyConfigMethods(secretified, cfg, warnings);
|
|
100
|
+
cfg = secretified;
|
|
101
|
+
}
|
|
102
|
+
const missing = [];
|
|
103
|
+
for (const reqKey of requires) {
|
|
104
|
+
if (cfg.get(reqKey) === void 0) missing.push(reqKey);
|
|
105
|
+
}
|
|
106
|
+
if (missing.length) {
|
|
107
|
+
throw new Error(
|
|
108
|
+
`COLONY @require failed (missing keys):
|
|
109
|
+
` + missing.map((k) => ` - ${k}`).join("\n")
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
Object.defineProperty(cfg, "_warnings", { enumerable: false, value: warnings });
|
|
113
|
+
if (typeof opts.schema === "function") {
|
|
114
|
+
const result = opts.schema(cfg);
|
|
115
|
+
if (result && typeof result.then === "function") {
|
|
116
|
+
const validated = await result;
|
|
117
|
+
if (validated && validated !== cfg) {
|
|
118
|
+
copyConfigMethods(validated, cfg, warnings);
|
|
119
|
+
return validated;
|
|
120
|
+
}
|
|
121
|
+
} else if (result && result !== cfg) {
|
|
122
|
+
copyConfigMethods(result, cfg, warnings);
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return cfg;
|
|
127
|
+
}
|
|
128
|
+
function copyConfigMethods(target, source, warnings) {
|
|
129
|
+
Object.defineProperties(target, {
|
|
130
|
+
get: { enumerable: false, value: source.get },
|
|
131
|
+
explain: { enumerable: false, value: source.explain },
|
|
132
|
+
toJSON: { enumerable: false, value: source.toJSON },
|
|
133
|
+
keys: { enumerable: false, value: source.keys },
|
|
134
|
+
diff: { enumerable: false, value: source.diff },
|
|
135
|
+
_trace: { enumerable: false, value: source._trace },
|
|
136
|
+
_warnings: { enumerable: false, value: warnings }
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
function mergeEnvDefaults(list) {
|
|
140
|
+
const out = {};
|
|
141
|
+
for (const m of list) {
|
|
142
|
+
for (const [k, v] of Object.entries(m)) out[k] = v;
|
|
143
|
+
}
|
|
144
|
+
return out;
|
|
145
|
+
}
|
|
146
|
+
async function expandIncludes(entry, visited, { basePath, maxIncludeDepth, maxFileSize, warnOnSkippedIncludes, warnings }) {
|
|
147
|
+
const absEntry = import_node_path.default.resolve(entry);
|
|
148
|
+
const out = [];
|
|
149
|
+
await dfs(absEntry, 0);
|
|
150
|
+
return out;
|
|
151
|
+
async function dfs(file, depth) {
|
|
152
|
+
if (depth > maxIncludeDepth) {
|
|
153
|
+
throw new Error(`COLONY: Max include depth (${maxIncludeDepth}) exceeded at: ${file}`);
|
|
154
|
+
}
|
|
155
|
+
const abs = import_node_path.default.resolve(file);
|
|
156
|
+
if (visited.has(abs)) {
|
|
157
|
+
if (warnOnSkippedIncludes) {
|
|
158
|
+
warnings.push({ type: "skipped_include", file: abs, message: `Skipping already-visited include: ${abs}` });
|
|
159
|
+
}
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
visited.add(abs);
|
|
163
|
+
if (maxFileSize !== null) {
|
|
164
|
+
const stat = await import_promises.default.stat(abs);
|
|
165
|
+
if (stat.size > maxFileSize) {
|
|
166
|
+
throw new Error(`COLONY: File size (${stat.size} bytes) exceeds maxFileSize (${maxFileSize} bytes): ${abs}`);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
const text = await import_promises.default.readFile(abs, "utf8");
|
|
170
|
+
const { includes } = (0, import_parser.parseColony)(text, { filePath: abs, parseOnlyDirectives: true });
|
|
171
|
+
for (const inc of includes) {
|
|
172
|
+
const incAbs = import_node_path.default.resolve(import_node_path.default.dirname(abs), inc);
|
|
173
|
+
if (basePath !== null) {
|
|
174
|
+
const normalizedInc = import_node_path.default.normalize(incAbs);
|
|
175
|
+
if (!normalizedInc.startsWith(basePath + import_node_path.default.sep) && normalizedInc !== basePath) {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`COLONY: Path traversal blocked. Include "${inc}" resolves to "${normalizedInc}" which is outside basePath "${basePath}"`
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const matches = await (0, import_fast_glob.default)(incAbs.replace(/\\/g, "/"), { dot: true });
|
|
182
|
+
for (const m of matches.sort((a, b) => a.localeCompare(b))) {
|
|
183
|
+
if (basePath !== null) {
|
|
184
|
+
const normalizedMatch = import_node_path.default.normalize(m);
|
|
185
|
+
if (!normalizedMatch.startsWith(basePath + import_node_path.default.sep) && normalizedMatch !== basePath) {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`COLONY: Path traversal blocked. Glob match "${m}" is outside basePath "${basePath}"`
|
|
188
|
+
);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
await dfs(m, depth + 1);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
out.push(abs);
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
async function validateColony(entry) {
|
|
198
|
+
const visited = /* @__PURE__ */ new Set();
|
|
199
|
+
const files = [];
|
|
200
|
+
const errors = [];
|
|
201
|
+
await validateDfs(import_node_path.default.resolve(entry));
|
|
202
|
+
return {
|
|
203
|
+
valid: errors.length === 0,
|
|
204
|
+
files,
|
|
205
|
+
errors
|
|
206
|
+
};
|
|
207
|
+
async function validateDfs(file) {
|
|
208
|
+
const abs = import_node_path.default.resolve(file);
|
|
209
|
+
if (visited.has(abs)) return;
|
|
210
|
+
visited.add(abs);
|
|
211
|
+
try {
|
|
212
|
+
const text = await import_promises.default.readFile(abs, "utf8");
|
|
213
|
+
const { includes } = (0, import_parser.parseColony)(text, { filePath: abs });
|
|
214
|
+
files.push(abs);
|
|
215
|
+
for (const inc of includes) {
|
|
216
|
+
const incAbs = import_node_path.default.resolve(import_node_path.default.dirname(abs), inc);
|
|
217
|
+
const matches = await (0, import_fast_glob.default)(incAbs.replace(/\\/g, "/"), { dot: true });
|
|
218
|
+
for (const m of matches.sort((a, b) => a.localeCompare(b))) {
|
|
219
|
+
await validateDfs(m);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
} catch (e) {
|
|
223
|
+
errors.push({ file: abs, error: e.message });
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
async function dryRunIncludes(entry) {
|
|
228
|
+
const visited = /* @__PURE__ */ new Set();
|
|
229
|
+
const files = [];
|
|
230
|
+
await dryRunDfs(import_node_path.default.resolve(entry));
|
|
231
|
+
return files;
|
|
232
|
+
async function dryRunDfs(file) {
|
|
233
|
+
const abs = import_node_path.default.resolve(file);
|
|
234
|
+
if (visited.has(abs)) return;
|
|
235
|
+
visited.add(abs);
|
|
236
|
+
const text = await import_promises.default.readFile(abs, "utf8");
|
|
237
|
+
const { includes } = (0, import_parser.parseColony)(text, { filePath: abs, parseOnlyDirectives: true });
|
|
238
|
+
for (const inc of includes) {
|
|
239
|
+
const incAbs = import_node_path.default.resolve(import_node_path.default.dirname(abs), inc);
|
|
240
|
+
const matches = await (0, import_fast_glob.default)(incAbs.replace(/\\/g, "/"), { dot: true });
|
|
241
|
+
for (const m of matches.sort((a, b) => a.localeCompare(b))) {
|
|
242
|
+
await dryRunDfs(m);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
files.push(abs);
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async function diffColony(opts) {
|
|
249
|
+
const { ctx1, ctx2, ...baseOpts } = opts;
|
|
250
|
+
if (!ctx1 || !ctx2) {
|
|
251
|
+
throw new Error("diffColony: both ctx1 and ctx2 are required");
|
|
252
|
+
}
|
|
253
|
+
const cfg1 = await loadColony({ ...baseOpts, ctx: ctx1 });
|
|
254
|
+
const cfg2 = await loadColony({ ...baseOpts, ctx: ctx2 });
|
|
255
|
+
return {
|
|
256
|
+
cfg1,
|
|
257
|
+
cfg2,
|
|
258
|
+
diff: cfg1.diff(cfg2)
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
async function lintColony(opts) {
|
|
262
|
+
const entry = opts?.entry;
|
|
263
|
+
if (!entry) throw new Error("lintColony: opts.entry is required");
|
|
264
|
+
const issues = [];
|
|
265
|
+
const visited = /* @__PURE__ */ new Set();
|
|
266
|
+
const allRules = [];
|
|
267
|
+
const allFiles = [];
|
|
268
|
+
let foundDims = null;
|
|
269
|
+
await collectRules(import_node_path.default.resolve(entry));
|
|
270
|
+
async function collectRules(file) {
|
|
271
|
+
const abs = import_node_path.default.resolve(file);
|
|
272
|
+
if (visited.has(abs)) return;
|
|
273
|
+
visited.add(abs);
|
|
274
|
+
try {
|
|
275
|
+
const text = await import_promises.default.readFile(abs, "utf8");
|
|
276
|
+
const parsed = (0, import_parser.parseColony)(text, { filePath: abs });
|
|
277
|
+
allFiles.push(abs);
|
|
278
|
+
if (!foundDims && parsed.dims?.length) {
|
|
279
|
+
foundDims = parsed.dims;
|
|
280
|
+
}
|
|
281
|
+
for (const rule of parsed.rules) {
|
|
282
|
+
allRules.push({ ...rule, filePath: abs });
|
|
283
|
+
}
|
|
284
|
+
for (const inc of parsed.includes) {
|
|
285
|
+
const incAbs = import_node_path.default.resolve(import_node_path.default.dirname(abs), inc);
|
|
286
|
+
const matches = await (0, import_fast_glob.default)(incAbs.replace(/\\/g, "/"), { dot: true });
|
|
287
|
+
for (const m of matches.sort((a, b) => a.localeCompare(b))) {
|
|
288
|
+
await collectRules(m);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
} catch (e) {
|
|
292
|
+
issues.push({
|
|
293
|
+
type: "parse_error",
|
|
294
|
+
severity: "error",
|
|
295
|
+
message: e.message,
|
|
296
|
+
file: abs
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
const dims = opts.dims ?? foundDims ?? ["env"];
|
|
301
|
+
const rulesByKey = /* @__PURE__ */ new Map();
|
|
302
|
+
for (const rule of allRules) {
|
|
303
|
+
const scope = rule.keySegments.slice(0, dims.length).join(".");
|
|
304
|
+
const keyPath = rule.keySegments.slice(dims.length).join(".");
|
|
305
|
+
const key = `${scope}|${keyPath}`;
|
|
306
|
+
if (!rulesByKey.has(key)) {
|
|
307
|
+
rulesByKey.set(key, []);
|
|
308
|
+
}
|
|
309
|
+
rulesByKey.get(key).push(rule);
|
|
310
|
+
}
|
|
311
|
+
for (const [key, rules] of rulesByKey.entries()) {
|
|
312
|
+
if (rules.length > 1) {
|
|
313
|
+
const locations = rules.map((r) => `${r.filePath}:${r.line}`);
|
|
314
|
+
const uniqueLocations = new Set(locations);
|
|
315
|
+
if (uniqueLocations.size > 1) {
|
|
316
|
+
const [scope, keyPath] = key.split("|");
|
|
317
|
+
issues.push({
|
|
318
|
+
type: "shadowed_rule",
|
|
319
|
+
severity: "warning",
|
|
320
|
+
message: `Rule "${scope}.${keyPath}" is defined ${rules.length} times. Later rule wins.`,
|
|
321
|
+
file: rules[rules.length - 1].filePath,
|
|
322
|
+
line: rules[rules.length - 1].line
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
for (const rule of allRules) {
|
|
328
|
+
const scope = rule.keySegments.slice(0, dims.length);
|
|
329
|
+
const keyPath = rule.keySegments.slice(dims.length).join(".");
|
|
330
|
+
if (scope.every((s) => s === "*")) {
|
|
331
|
+
const moreSpecific = allRules.filter((r) => {
|
|
332
|
+
const rKeyPath = r.keySegments.slice(dims.length).join(".");
|
|
333
|
+
if (rKeyPath !== keyPath) return false;
|
|
334
|
+
const rScope = r.keySegments.slice(0, dims.length);
|
|
335
|
+
return rScope.some((s) => s !== "*") && r !== rule;
|
|
336
|
+
});
|
|
337
|
+
if (moreSpecific.length > 0) {
|
|
338
|
+
issues.push({
|
|
339
|
+
type: "overridden_wildcard",
|
|
340
|
+
severity: "info",
|
|
341
|
+
message: `Wildcard rule for "${keyPath}" is overridden by ${moreSpecific.length} more specific rule(s)`,
|
|
342
|
+
file: rule.filePath,
|
|
343
|
+
line: rule.line
|
|
344
|
+
});
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
for (const file of allFiles) {
|
|
349
|
+
try {
|
|
350
|
+
const text = await import_promises.default.readFile(file, "utf8");
|
|
351
|
+
const parsed = (0, import_parser.parseColony)(text, { filePath: file });
|
|
352
|
+
for (const inc of parsed.includes) {
|
|
353
|
+
const incAbs = import_node_path.default.resolve(import_node_path.default.dirname(file), inc);
|
|
354
|
+
const matches = await (0, import_fast_glob.default)(incAbs.replace(/\\/g, "/"), { dot: true });
|
|
355
|
+
if (matches.length === 0) {
|
|
356
|
+
issues.push({
|
|
357
|
+
type: "empty_include",
|
|
358
|
+
severity: "warning",
|
|
359
|
+
message: `Include pattern "${inc}" matches no files`,
|
|
360
|
+
file
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
} catch {
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
return { issues };
|
|
368
|
+
}
|
|
369
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
370
|
+
0 && (module.exports = {
|
|
371
|
+
AwsSecretsProvider,
|
|
372
|
+
OpenBaoProvider,
|
|
373
|
+
VaultProvider,
|
|
374
|
+
clearSecretProviders,
|
|
375
|
+
diffColony,
|
|
376
|
+
dryRunIncludes,
|
|
377
|
+
lintColony,
|
|
378
|
+
loadColony,
|
|
379
|
+
registerSecretProvider,
|
|
380
|
+
unregisterSecretProvider,
|
|
381
|
+
validateColony
|
|
382
|
+
});
|
|
383
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/index.js"],
|
|
4
|
+
"sourcesContent": ["import fs from \"node:fs/promises\";\nimport path from \"node:path\";\nimport fg from \"fast-glob\";\nimport { parseColony } from \"./parser.js\";\nimport { resolveRules } from \"./resolver.js\";\nimport {\n applySecretsDeep,\n SecretCache,\n hasGlobalProviders,\n registerSecretProvider,\n unregisterSecretProvider,\n clearSecretProviders,\n} from \"./secrets.js\";\n\n// Re-export secrets functions\nexport { registerSecretProvider, unregisterSecretProvider, clearSecretProviders };\n\n// Re-export providers\nexport { AwsSecretsProvider } from \"./providers/aws.js\";\nexport { VaultProvider } from \"./providers/vault.js\";\nexport { OpenBaoProvider } from \"./providers/openbao.js\";\n\n/**\n * @param {object} opts\n * @param {string} opts.entry\n * @param {string[]=} opts.dims\n * @param {Record<string,string>=} opts.ctx\n * @param {Record<string,string>=} opts.vars\n * @param {(cfg: any) => any=} opts.schema // optional validation hook (e.g. zod.parse)\n * @param {object=} opts.sandbox // security options\n * @param {string=} opts.sandbox.basePath // restrict includes to this directory\n * @param {string[]=} opts.sandbox.allowedEnvVars // whitelist of allowed env vars (null = allow all)\n * @param {number=} opts.sandbox.maxIncludeDepth // max depth for includes (default 50)\n * @param {boolean=} opts.warnOnSkippedIncludes // warn when skipping already-visited includes\n * @param {object=} opts.secrets // secrets provider options\n * @param {Array=} opts.secrets.providers // secret providers (e.g. AwsSecretsProvider)\n * @param {string[]=} opts.secrets.allowedSecrets // whitelist of allowed secret patterns\n * @param {object=} opts.secrets.cache // cache options\n * @param {string=} opts.secrets.onNotFound // 'empty' | 'warn' | 'error' (default: 'warn')\n * @returns {Promise<object>}\n */\nexport async function loadColony(opts) {\n const entry = opts?.entry;\n if (!entry) throw new Error(\"loadColony: opts.entry is required\");\n\n const sandbox = opts.sandbox ?? {};\n const basePath = sandbox.basePath ? path.resolve(sandbox.basePath) : null;\n const maxIncludeDepth = sandbox.maxIncludeDepth ?? 50;\n const maxFileSize = sandbox.maxFileSize ?? null;\n const warnOnSkippedIncludes = opts.warnOnSkippedIncludes ?? false;\n\n const visited = new Set();\n const warnings = [];\n const files = await expandIncludes(entry, visited, {\n basePath,\n maxIncludeDepth,\n maxFileSize,\n warnOnSkippedIncludes,\n warnings,\n });\n\n const parsed = [];\n for (const file of files) {\n const text = await fs.readFile(file, \"utf8\");\n parsed.push(parseColony(text, { filePath: file }));\n }\n\n const dims =\n (Array.isArray(opts.dims) && opts.dims.length ? opts.dims : null) ??\n parsed.find((p) => p.dims?.length)?.dims ??\n [\"env\"];\n\n // ctx precedence: opts.ctx overrides, else @envDefaults, else sensible defaults\n const envDefaults = mergeEnvDefaults(parsed.map((p) => p.envDefaults ?? {}));\n const ctx = {\n ...envDefaults,\n env: process.env.NODE_ENV ?? \"dev\",\n ...opts.ctx,\n };\n\n const vars = { ROOT: process.cwd(), ...(opts.vars ?? {}) };\n\n // Collect requires from all parsed files\n const requires = parsed.flatMap((p) => p.requires ?? []);\n\n const allRules = parsed.flatMap((p) => p.rules);\n\n const allowedEnvVars = sandbox.allowedEnvVars ?? null;\n const allowedVars = sandbox.allowedVars ?? null;\n let cfg = resolveRules({ rules: allRules, dims, ctx, vars, allowedEnvVars, allowedVars, warnings });\n\n // Apply secrets if providers are configured\n const secretsOpts = opts.secrets ?? {};\n if (secretsOpts.providers?.length || hasGlobalProviders()) {\n const cacheOpts = secretsOpts.cache ?? {};\n const cache = cacheOpts.enabled !== false\n ? new SecretCache(cacheOpts.maxSize ?? 100)\n : null;\n\n const secretified = await applySecretsDeep(cfg, {\n providers: secretsOpts.providers ?? [],\n allowedSecrets: secretsOpts.allowedSecrets ?? null,\n cache,\n cacheTtl: cacheOpts.ttl ?? 300000,\n onNotFound: secretsOpts.onNotFound ?? \"warn\",\n warnings,\n });\n\n // Copy config methods to new object\n copyConfigMethods(secretified, cfg, warnings);\n cfg = secretified;\n }\n\n // Enforce @require after resolution\n const missing = [];\n for (const reqKey of requires) {\n if (cfg.get(reqKey) === undefined) missing.push(reqKey);\n }\n if (missing.length) {\n throw new Error(\n `COLONY @require failed (missing keys):\\n` +\n missing.map((k) => ` - ${k}`).join(\"\\n\")\n );\n }\n\n // Attach warnings as non-enumerable\n Object.defineProperty(cfg, \"_warnings\", { enumerable: false, value: warnings });\n\n // Optional schema validation hook (supports both sync and async)\n if (typeof opts.schema === \"function\") {\n const result = opts.schema(cfg);\n\n // Handle async schema validators (e.g., async Zod, Joi)\n if (result && typeof result.then === \"function\") {\n const validated = await result;\n if (validated && validated !== cfg) {\n copyConfigMethods(validated, cfg, warnings);\n return validated;\n }\n } else if (result && result !== cfg) {\n copyConfigMethods(result, cfg, warnings);\n return result;\n }\n }\n\n return cfg;\n}\n\n/**\n * Copy non-enumerable config methods to validated object\n */\nfunction copyConfigMethods(target, source, warnings) {\n Object.defineProperties(target, {\n get: { enumerable: false, value: source.get },\n explain: { enumerable: false, value: source.explain },\n toJSON: { enumerable: false, value: source.toJSON },\n keys: { enumerable: false, value: source.keys },\n diff: { enumerable: false, value: source.diff },\n _trace: { enumerable: false, value: source._trace },\n _warnings: { enumerable: false, value: warnings },\n });\n}\n\nfunction mergeEnvDefaults(list) {\n const out = {};\n for (const m of list) {\n for (const [k, v] of Object.entries(m)) out[k] = v;\n }\n return out;\n}\n\nasync function expandIncludes(entry, visited, { basePath, maxIncludeDepth, maxFileSize, warnOnSkippedIncludes, warnings }) {\n const absEntry = path.resolve(entry);\n const out = [];\n await dfs(absEntry, 0);\n return out;\n\n async function dfs(file, depth) {\n if (depth > maxIncludeDepth) {\n throw new Error(`COLONY: Max include depth (${maxIncludeDepth}) exceeded at: ${file}`);\n }\n\n const abs = path.resolve(file);\n\n if (visited.has(abs)) {\n if (warnOnSkippedIncludes) {\n warnings.push({ type: \"skipped_include\", file: abs, message: `Skipping already-visited include: ${abs}` });\n }\n return;\n }\n visited.add(abs);\n\n // Check file size if limit is set\n if (maxFileSize !== null) {\n const stat = await fs.stat(abs);\n if (stat.size > maxFileSize) {\n throw new Error(`COLONY: File size (${stat.size} bytes) exceeds maxFileSize (${maxFileSize} bytes): ${abs}`);\n }\n }\n\n const text = await fs.readFile(abs, \"utf8\");\n const { includes } = parseColony(text, { filePath: abs, parseOnlyDirectives: true });\n\n for (const inc of includes) {\n const incAbs = path.resolve(path.dirname(abs), inc);\n\n // Security: validate path is within basePath if set\n if (basePath !== null) {\n const normalizedInc = path.normalize(incAbs);\n if (!normalizedInc.startsWith(basePath + path.sep) && normalizedInc !== basePath) {\n throw new Error(\n `COLONY: Path traversal blocked. Include \"${inc}\" resolves to \"${normalizedInc}\" which is outside basePath \"${basePath}\"`\n );\n }\n }\n\n const matches = await fg(incAbs.replace(/\\\\/g, \"/\"), { dot: true });\n // Sort alphabetically for deterministic ordering across platforms/filesystems\n for (const m of matches.sort((a, b) => a.localeCompare(b))) {\n // Also validate glob matches against basePath\n if (basePath !== null) {\n const normalizedMatch = path.normalize(m);\n if (!normalizedMatch.startsWith(basePath + path.sep) && normalizedMatch !== basePath) {\n throw new Error(\n `COLONY: Path traversal blocked. Glob match \"${m}\" is outside basePath \"${basePath}\"`\n );\n }\n }\n await dfs(m, depth + 1);\n }\n }\n\n out.push(abs);\n }\n}\n\n/**\n * Validate syntax of colony files without resolving\n * @param {string} entry - Entry file path\n * @returns {Promise<{valid: boolean, files: string[], errors: Array<{file: string, error: string}>}>}\n */\nexport async function validateColony(entry) {\n const visited = new Set();\n const files = [];\n const errors = [];\n\n await validateDfs(path.resolve(entry));\n\n return {\n valid: errors.length === 0,\n files,\n errors,\n };\n\n async function validateDfs(file) {\n const abs = path.resolve(file);\n if (visited.has(abs)) return;\n visited.add(abs);\n\n try {\n const text = await fs.readFile(abs, \"utf8\");\n const { includes } = parseColony(text, { filePath: abs });\n files.push(abs);\n\n for (const inc of includes) {\n const incAbs = path.resolve(path.dirname(abs), inc);\n const matches = await fg(incAbs.replace(/\\\\/g, \"/\"), { dot: true });\n for (const m of matches.sort((a, b) => a.localeCompare(b))) {\n await validateDfs(m);\n }\n }\n } catch (e) {\n errors.push({ file: abs, error: e.message });\n }\n }\n}\n\n/**\n * Dry-run: list all files that would be included\n * @param {string} entry - Entry file path\n * @returns {Promise<string[]>}\n */\nexport async function dryRunIncludes(entry) {\n const visited = new Set();\n const files = [];\n await dryRunDfs(path.resolve(entry));\n return files;\n\n async function dryRunDfs(file) {\n const abs = path.resolve(file);\n if (visited.has(abs)) return;\n visited.add(abs);\n\n const text = await fs.readFile(abs, \"utf8\");\n const { includes } = parseColony(text, { filePath: abs, parseOnlyDirectives: true });\n\n for (const inc of includes) {\n const incAbs = path.resolve(path.dirname(abs), inc);\n const matches = await fg(incAbs.replace(/\\\\/g, \"/\"), { dot: true });\n for (const m of matches.sort((a, b) => a.localeCompare(b))) {\n await dryRunDfs(m);\n }\n }\n\n files.push(abs);\n }\n}\n\n/**\n * Compare two configs loaded with different contexts\n * @param {object} opts - Same options as loadColony, but with ctx1 and ctx2\n * @param {Record<string,string>} opts.ctx1 - First context\n * @param {Record<string,string>} opts.ctx2 - Second context\n * @returns {Promise<{cfg1: object, cfg2: object, diff: object}>}\n */\nexport async function diffColony(opts) {\n const { ctx1, ctx2, ...baseOpts } = opts;\n\n if (!ctx1 || !ctx2) {\n throw new Error(\"diffColony: both ctx1 and ctx2 are required\");\n }\n\n const cfg1 = await loadColony({ ...baseOpts, ctx: ctx1 });\n const cfg2 = await loadColony({ ...baseOpts, ctx: ctx2 });\n\n return {\n cfg1,\n cfg2,\n diff: cfg1.diff(cfg2),\n };\n}\n\n/**\n * Lint colony files for potential issues\n * @param {object} opts\n * @param {string} opts.entry - Entry file path\n * @param {string[]=} opts.dims - Dimension names\n * @returns {Promise<{issues: Array<{type: string, severity: string, message: string, file?: string, line?: number}>}>}\n */\nexport async function lintColony(opts) {\n const entry = opts?.entry;\n if (!entry) throw new Error(\"lintColony: opts.entry is required\");\n\n const issues = [];\n const visited = new Set();\n const allRules = [];\n const allFiles = [];\n let foundDims = null;\n\n // Collect all rules from all files\n await collectRules(path.resolve(entry));\n\n async function collectRules(file) {\n const abs = path.resolve(file);\n if (visited.has(abs)) return;\n visited.add(abs);\n\n try {\n const text = await fs.readFile(abs, \"utf8\");\n const parsed = parseColony(text, { filePath: abs });\n allFiles.push(abs);\n\n // Capture dims from first file that has them\n if (!foundDims && parsed.dims?.length) {\n foundDims = parsed.dims;\n }\n\n for (const rule of parsed.rules) {\n allRules.push({ ...rule, filePath: abs });\n }\n\n for (const inc of parsed.includes) {\n const incAbs = path.resolve(path.dirname(abs), inc);\n const matches = await fg(incAbs.replace(/\\\\/g, \"/\"), { dot: true });\n for (const m of matches.sort((a, b) => a.localeCompare(b))) {\n await collectRules(m);\n }\n }\n } catch (e) {\n issues.push({\n type: \"parse_error\",\n severity: \"error\",\n message: e.message,\n file: abs,\n });\n }\n }\n\n // Get dims from options, or from parsed files, or default\n const dims = opts.dims ?? foundDims ?? [\"env\"];\n\n // Check for shadowed rules (same key, same scope, different values)\n const rulesByKey = new Map();\n for (const rule of allRules) {\n const scope = rule.keySegments.slice(0, dims.length).join(\".\");\n const keyPath = rule.keySegments.slice(dims.length).join(\".\");\n const key = `${scope}|${keyPath}`;\n\n if (!rulesByKey.has(key)) {\n rulesByKey.set(key, []);\n }\n rulesByKey.get(key).push(rule);\n }\n\n for (const [key, rules] of rulesByKey.entries()) {\n if (rules.length > 1) {\n // Check if they're in different files or same file\n const locations = rules.map((r) => `${r.filePath}:${r.line}`);\n const uniqueLocations = new Set(locations);\n\n if (uniqueLocations.size > 1) {\n const [scope, keyPath] = key.split(\"|\");\n issues.push({\n type: \"shadowed_rule\",\n severity: \"warning\",\n message: `Rule \"${scope}.${keyPath}\" is defined ${rules.length} times. Later rule wins.`,\n file: rules[rules.length - 1].filePath,\n line: rules[rules.length - 1].line,\n });\n }\n }\n }\n\n // Check for potentially unused wildcard rules\n // (rules with all wildcards that might be overridden by more specific rules)\n for (const rule of allRules) {\n const scope = rule.keySegments.slice(0, dims.length);\n const keyPath = rule.keySegments.slice(dims.length).join(\".\");\n\n if (scope.every((s) => s === \"*\")) {\n // Check if there are more specific rules for the same key\n const moreSpecific = allRules.filter((r) => {\n const rKeyPath = r.keySegments.slice(dims.length).join(\".\");\n if (rKeyPath !== keyPath) return false;\n const rScope = r.keySegments.slice(0, dims.length);\n return rScope.some((s) => s !== \"*\") && r !== rule;\n });\n\n if (moreSpecific.length > 0) {\n issues.push({\n type: \"overridden_wildcard\",\n severity: \"info\",\n message: `Wildcard rule for \"${keyPath}\" is overridden by ${moreSpecific.length} more specific rule(s)`,\n file: rule.filePath,\n line: rule.line,\n });\n }\n }\n }\n\n // Check for empty includes\n for (const file of allFiles) {\n try {\n const text = await fs.readFile(file, \"utf8\");\n const parsed = parseColony(text, { filePath: file });\n\n for (const inc of parsed.includes) {\n const incAbs = path.resolve(path.dirname(file), inc);\n const matches = await fg(incAbs.replace(/\\\\/g, \"/\"), { dot: true });\n if (matches.length === 0) {\n issues.push({\n type: \"empty_include\",\n severity: \"warning\",\n message: `Include pattern \"${inc}\" matches no files`,\n file,\n });\n }\n }\n } catch {}\n }\n\n return { issues };\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": ["path", "fs", "fg"]
|
|
7
|
+
}
|