sentinelayer-cli 0.32.0 → 0.32.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/commands/config.js +63 -10
package/package.json
CHANGED
package/src/commands/config.js
CHANGED
|
@@ -13,6 +13,14 @@ import {
|
|
|
13
13
|
} from "../config/service.js";
|
|
14
14
|
|
|
15
15
|
const SCOPES = "global|project|env|resolved";
|
|
16
|
+
const REDACTION_MARKER = "[REDACTED]";
|
|
17
|
+
const SENSITIVE_TOP_LEVEL_KEYS = new Set([
|
|
18
|
+
"sentinelayerToken",
|
|
19
|
+
"openaiApiKey",
|
|
20
|
+
"anthropicApiKey",
|
|
21
|
+
"googleApiKey",
|
|
22
|
+
]);
|
|
23
|
+
const SENSITIVE_KEY_RE = /(authorization|cookie|set-cookie|x-api-key|api[_-]?key|secret|password|credential|token|webhook[_-]?url)/i;
|
|
16
24
|
|
|
17
25
|
function shouldEmitJson(options, command) {
|
|
18
26
|
const local = Boolean(options && options.json);
|
|
@@ -21,14 +29,59 @@ function shouldEmitJson(options, command) {
|
|
|
21
29
|
return local || globalFromCommand;
|
|
22
30
|
}
|
|
23
31
|
|
|
24
|
-
function
|
|
32
|
+
function isPlainObject(value) {
|
|
33
|
+
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
function isSensitiveConfigPath(pathParts = []) {
|
|
37
|
+
const lastKey = String(pathParts[pathParts.length - 1] || "");
|
|
38
|
+
if (!lastKey) return false;
|
|
39
|
+
if (pathParts.length === 1 && SENSITIVE_TOP_LEVEL_KEYS.has(lastKey)) return true;
|
|
40
|
+
if (SENSITIVE_KEY_RE.test(lastKey)) return true;
|
|
41
|
+
if (pathParts.includes("alerts") && lastKey.replace(/[_-]/g, "").toLowerCase() === "url") {
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function redactConfigValue(value, pathParts = [], depth = 0) {
|
|
48
|
+
if (value === undefined) return undefined;
|
|
49
|
+
if (isSensitiveConfigPath(pathParts)) return REDACTION_MARKER;
|
|
50
|
+
if (depth > 8) return REDACTION_MARKER;
|
|
51
|
+
if (Array.isArray(value)) {
|
|
52
|
+
return value.map((entry) => redactConfigValue(entry, pathParts, depth + 1));
|
|
53
|
+
}
|
|
54
|
+
if (isPlainObject(value)) {
|
|
55
|
+
return Object.fromEntries(
|
|
56
|
+
Object.entries(value).map(([key, inner]) => [
|
|
57
|
+
key,
|
|
58
|
+
redactConfigValue(inner, [...pathParts, key], depth + 1),
|
|
59
|
+
])
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function redactConfigLayer(layer = {}) {
|
|
66
|
+
return redactConfigValue(layer, []);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function redactConfigResult(result = {}) {
|
|
70
|
+
return {
|
|
71
|
+
...result,
|
|
72
|
+
value: redactConfigValue(result.value, [result.key]),
|
|
73
|
+
};
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
function displayValue(key, value) {
|
|
77
|
+
const safeValue = redactConfigValue(value, [key]);
|
|
25
78
|
if (value === undefined) {
|
|
26
79
|
return "";
|
|
27
80
|
}
|
|
28
|
-
if (typeof
|
|
29
|
-
return
|
|
81
|
+
if (typeof safeValue === "string") {
|
|
82
|
+
return safeValue;
|
|
30
83
|
}
|
|
31
|
-
return JSON.stringify(
|
|
84
|
+
return JSON.stringify(safeValue);
|
|
32
85
|
}
|
|
33
86
|
|
|
34
87
|
function assertKnownKey(key) {
|
|
@@ -61,7 +114,7 @@ export function registerConfigCommand(program) {
|
|
|
61
114
|
JSON.stringify(
|
|
62
115
|
{
|
|
63
116
|
scope,
|
|
64
|
-
config: layer,
|
|
117
|
+
config: redactConfigLayer(layer),
|
|
65
118
|
paths: payload.paths,
|
|
66
119
|
},
|
|
67
120
|
null,
|
|
@@ -78,7 +131,7 @@ export function registerConfigCommand(program) {
|
|
|
78
131
|
return;
|
|
79
132
|
}
|
|
80
133
|
for (const [key, value] of entries) {
|
|
81
|
-
console.log(`${key}: ${displayValue(value)}`);
|
|
134
|
+
console.log(`${key}: ${displayValue(key, value)}`);
|
|
82
135
|
}
|
|
83
136
|
});
|
|
84
137
|
|
|
@@ -103,7 +156,7 @@ export function registerConfigCommand(program) {
|
|
|
103
156
|
{
|
|
104
157
|
key: normalizedKey,
|
|
105
158
|
scope,
|
|
106
|
-
value,
|
|
159
|
+
value: redactConfigValue(value, [normalizedKey]),
|
|
107
160
|
source,
|
|
108
161
|
},
|
|
109
162
|
null,
|
|
@@ -119,7 +172,7 @@ export function registerConfigCommand(program) {
|
|
|
119
172
|
return;
|
|
120
173
|
}
|
|
121
174
|
|
|
122
|
-
console.log(displayValue(value));
|
|
175
|
+
console.log(displayValue(normalizedKey, value));
|
|
123
176
|
});
|
|
124
177
|
|
|
125
178
|
config
|
|
@@ -137,13 +190,13 @@ export function registerConfigCommand(program) {
|
|
|
137
190
|
});
|
|
138
191
|
|
|
139
192
|
if (shouldEmitJson(options, command)) {
|
|
140
|
-
console.log(JSON.stringify(result, null, 2));
|
|
193
|
+
console.log(JSON.stringify(redactConfigResult(result), null, 2));
|
|
141
194
|
return;
|
|
142
195
|
}
|
|
143
196
|
|
|
144
197
|
console.log(pc.green(`Updated ${result.key} in ${result.scope} config.`));
|
|
145
198
|
console.log(pc.gray(`Path: ${result.path}`));
|
|
146
|
-
console.log(`${result.key}: ${displayValue(result.value)}`);
|
|
199
|
+
console.log(`${result.key}: ${displayValue(result.key, result.value)}`);
|
|
147
200
|
});
|
|
148
201
|
|
|
149
202
|
config
|