sentinelayer-cli 0.32.0 → 0.32.2
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/README.md +17 -3
- package/package.json +1 -1
- package/src/commands/config.js +63 -10
package/README.md
CHANGED
|
@@ -929,6 +929,18 @@ Ledger contract:
|
|
|
929
929
|
- network access to Sentinelayer API/web
|
|
930
930
|
- optional: GitHub CLI (`gh`) authenticated for secret injection
|
|
931
931
|
|
|
932
|
+
## Operator and architecture references
|
|
933
|
+
|
|
934
|
+
- First-run engineering onboarding: `docs/ENGINEERING_ONBOARDING.md`
|
|
935
|
+
- Senti session operations, coordination, kill, and rollback conventions: `docs/sessions.md`
|
|
936
|
+
- Release workflow map and rollback drill ownership: `docs/workflow-matrix.md`
|
|
937
|
+
- Release rollback execution: `.github/workflows/rollback.yml` and `.github/scripts/release-rollback-readiness.sh`
|
|
938
|
+
- Architecture and decision records for major surfaces:
|
|
939
|
+
- Hosted MCP connector boundary: `docs/mcp-hosted-connector.md`
|
|
940
|
+
- MCP local/runtime entry points: `docs/mcp.md`
|
|
941
|
+
- Investor-DD architecture: `docs/INVESTOR_DD_ARCHITECTURE.md`
|
|
942
|
+
- CI/CD acknowledged release risks: `.github/policies/cicd-acknowledged-risks.md`
|
|
943
|
+
|
|
932
944
|
## Release to npm
|
|
933
945
|
|
|
934
946
|
This repo includes `.github/workflows/release.yml`.
|
|
@@ -949,14 +961,15 @@ Release flow:
|
|
|
949
961
|
|
|
950
962
|
1. Merge to `main` and let `Release Please` open/update the release PR.
|
|
951
963
|
2. Merge the release PR after Omar, Quality Gates, and Attestation are green.
|
|
952
|
-
3.
|
|
964
|
+
3. Wait for the main-branch `Release Please` workflow run on that merge commit to complete successfully.
|
|
965
|
+
4. From a clean checkout of the release commit, run the guarded release command:
|
|
953
966
|
```bash
|
|
954
967
|
git fetch origin main --tags
|
|
955
968
|
git checkout main && git pull --ff-only
|
|
956
969
|
npm run release:publish -- --tag v0.1.1 --notes-file release-notes.md
|
|
957
970
|
```
|
|
958
|
-
|
|
959
|
-
|
|
971
|
+
5. The guarded command confirms the exact release commit has one successful main `Release Please` run, creates the tag with `git tag -s`, verifies it with `git tag -v`, pushes it, confirms the remote GitHub tag object is annotated and cryptographically verified by an allowlisted signer, then creates the GitHub release with `gh release create --verify-tag`.
|
|
972
|
+
6. The tag push triggers `Release`, which re-verifies upstream checks, release artifact attestations, rollback readiness, protected `package-release` approval, and npm trusted publishing OIDC before publishing.
|
|
960
973
|
|
|
961
974
|
Do not run `gh release create v0.1.1` before pushing the signed tag. GitHub release creation creates a lightweight tag when the tag does not already exist, and the Release workflow intentionally fails closed for lightweight tags. If a remote tag already exists as a lightweight tag, `npm run release:publish` refuses to create the GitHub release.
|
|
962
975
|
|
|
@@ -964,6 +977,7 @@ Release publish now enforces tarball checksum-manifest validation and attestatio
|
|
|
964
977
|
|
|
965
978
|
Release guardrails now require successful upstream checks on the target commit:
|
|
966
979
|
|
|
980
|
+
- `Release Please`
|
|
967
981
|
- `Quality Summary`
|
|
968
982
|
- `Omar Gate`
|
|
969
983
|
- `Attestation Summary`
|
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
|