@clef-sh/ui 0.1.20 → 0.1.21
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/dist/client/assets/index-DPWHjBbB.js +34 -0
- package/dist/client/assets/index-qsLTYpc9.css +2 -0
- package/dist/client/clef.svg +2 -0
- package/dist/client/index.html +3 -31
- package/dist/client-lib/components/Button.d.ts +1 -1
- package/dist/client-lib/components/Button.d.ts.map +1 -1
- package/dist/client-lib/components/CopyButton.d.ts.map +1 -1
- package/dist/client-lib/components/EnvBadge.d.ts.map +1 -1
- package/dist/client-lib/components/MatrixGrid.d.ts.map +1 -1
- package/dist/client-lib/components/Sidebar.d.ts +1 -1
- package/dist/client-lib/components/Sidebar.d.ts.map +1 -1
- package/dist/client-lib/components/StatusDot.d.ts.map +1 -1
- package/dist/client-lib/components/SyncPanel.d.ts.map +1 -1
- package/dist/client-lib/components/TopBar.d.ts +6 -0
- package/dist/client-lib/components/TopBar.d.ts.map +1 -1
- package/dist/client-lib/primitives/Badge.d.ts +11 -0
- package/dist/client-lib/primitives/Badge.d.ts.map +1 -0
- package/dist/client-lib/primitives/Card.d.ts +28 -0
- package/dist/client-lib/primitives/Card.d.ts.map +1 -0
- package/dist/client-lib/primitives/Dialog.d.ts +30 -0
- package/dist/client-lib/primitives/Dialog.d.ts.map +1 -0
- package/dist/client-lib/primitives/EmptyState.d.ts +10 -0
- package/dist/client-lib/primitives/EmptyState.d.ts.map +1 -0
- package/dist/client-lib/primitives/Field.d.ts +36 -0
- package/dist/client-lib/primitives/Field.d.ts.map +1 -0
- package/dist/client-lib/primitives/Input.d.ts +6 -0
- package/dist/client-lib/primitives/Input.d.ts.map +1 -0
- package/dist/client-lib/primitives/Stat.d.ts +11 -0
- package/dist/client-lib/primitives/Stat.d.ts.map +1 -0
- package/dist/client-lib/primitives/Table.d.ts +37 -0
- package/dist/client-lib/primitives/Table.d.ts.map +1 -0
- package/dist/client-lib/primitives/Tabs.d.ts +29 -0
- package/dist/client-lib/primitives/Tabs.d.ts.map +1 -0
- package/dist/client-lib/primitives/Toast.d.ts +16 -0
- package/dist/client-lib/primitives/Toast.d.ts.map +1 -0
- package/dist/client-lib/primitives/Toolbar.d.ts +29 -0
- package/dist/client-lib/primitives/Toolbar.d.ts.map +1 -0
- package/dist/client-lib/primitives/index.d.ts +23 -0
- package/dist/client-lib/primitives/index.d.ts.map +1 -0
- package/dist/client-lib/theme.d.ts +18 -41
- package/dist/client-lib/theme.d.ts.map +1 -1
- package/dist/server/api.d.ts.map +1 -1
- package/dist/server/api.js +215 -0
- package/dist/server/api.js.map +1 -1
- package/dist/server/envelope.d.ts +15 -0
- package/dist/server/envelope.d.ts.map +1 -0
- package/dist/server/envelope.js +310 -0
- package/dist/server/envelope.js.map +1 -0
- package/package.json +7 -2
- package/src/client/App.tsx +16 -41
- package/src/client/components/Button.tsx +13 -22
- package/src/client/components/CopyButton.tsx +5 -12
- package/src/client/components/EnvBadge.tsx +30 -15
- package/src/client/components/MatrixGrid.tsx +108 -252
- package/src/client/components/Sidebar.tsx +123 -199
- package/src/client/components/StatusDot.tsx +10 -15
- package/src/client/components/SyncPanel.tsx +14 -62
- package/src/client/components/TopBar.tsx +11 -36
- package/src/client/index.html +1 -30
- package/src/client/main.tsx +1 -0
- package/src/client/primitives/Badge.test.tsx +47 -0
- package/src/client/primitives/Badge.tsx +64 -0
- package/src/client/primitives/Card.test.tsx +50 -0
- package/src/client/primitives/Card.tsx +85 -0
- package/src/client/primitives/Dialog.test.tsx +55 -0
- package/src/client/primitives/Dialog.tsx +96 -0
- package/src/client/primitives/EmptyState.test.tsx +25 -0
- package/src/client/primitives/EmptyState.tsx +38 -0
- package/src/client/primitives/Field.test.tsx +46 -0
- package/src/client/primitives/Field.tsx +95 -0
- package/src/client/primitives/Input.tsx +26 -0
- package/src/client/primitives/Stat.test.tsx +32 -0
- package/src/client/primitives/Stat.tsx +52 -0
- package/src/client/primitives/Table.test.tsx +58 -0
- package/src/client/primitives/Table.tsx +113 -0
- package/src/client/primitives/Tabs.test.tsx +44 -0
- package/src/client/primitives/Tabs.tsx +100 -0
- package/src/client/primitives/Toast.test.tsx +77 -0
- package/src/client/primitives/Toast.tsx +89 -0
- package/src/client/primitives/Toolbar.test.tsx +50 -0
- package/src/client/primitives/Toolbar.tsx +86 -0
- package/src/client/primitives/index.ts +43 -0
- package/src/client/public/clef.svg +2 -0
- package/src/client/screens/BackendScreen.tsx +104 -363
- package/src/client/screens/DiffView.tsx +187 -378
- package/src/client/screens/EnvelopeScreen.test.tsx +542 -0
- package/src/client/screens/EnvelopeScreen.tsx +948 -0
- package/src/client/screens/GitLogView.tsx +48 -106
- package/src/client/screens/ImportScreen.tsx +105 -308
- package/src/client/screens/LintView.tsx +184 -379
- package/src/client/screens/ManifestScreen.tsx +283 -445
- package/src/client/screens/MatrixView.tsx +75 -91
- package/src/client/screens/NamespaceEditor.tsx +234 -609
- package/src/client/screens/PolicyView.tsx +183 -453
- package/src/client/screens/RecipientsScreen.tsx +71 -350
- package/src/client/screens/ResetScreen.tsx +67 -237
- package/src/client/screens/ScanScreen.tsx +85 -249
- package/src/client/screens/SchemaEditor.test.tsx +237 -0
- package/src/client/screens/SchemaEditor.tsx +435 -0
- package/src/client/screens/ServiceIdentitiesScreen.tsx +251 -788
- package/src/client/styles.css +77 -0
- package/src/client/theme.ts +27 -48
- package/dist/client/assets/index-Db6WgHgY.js +0 -38
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.registerEnvelopeRoutes = registerEnvelopeRoutes;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const core_1 = require("@clef-sh/core");
|
|
39
|
+
const runtime_1 = require("@clef-sh/runtime");
|
|
40
|
+
// Source label for all UI-initiated artifact inspections — makes it obvious
|
|
41
|
+
// in logs that the artifact came from a pasted input, not a file or URL.
|
|
42
|
+
const UI_SOURCE = "paste";
|
|
43
|
+
function setNoCacheHeaders(res) {
|
|
44
|
+
res.set({
|
|
45
|
+
"Cache-Control": "no-store, no-cache, must-revalidate",
|
|
46
|
+
Pragma: "no-cache",
|
|
47
|
+
Expires: "0",
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
// Precedence for the envelope debugger:
|
|
51
|
+
// 1. $CLEF_AGE_KEY (explicit env override — inline)
|
|
52
|
+
// 2. $CLEF_AGE_KEY_FILE (explicit env override — file path)
|
|
53
|
+
// 3. deps.ageKey (from CLI's resolveAgeCredential — may be keychain)
|
|
54
|
+
// 4. deps.ageKeyFile (from CLI's resolveAgeCredential — may be .clef/config.yaml)
|
|
55
|
+
//
|
|
56
|
+
// Env vars deliberately win over deps. The CLI's credential resolver
|
|
57
|
+
// prefers the OS keychain when configured, so without this override an
|
|
58
|
+
// operator who sets `CLEF_AGE_KEY_FILE=svc.key clef ui` to debug a
|
|
59
|
+
// service-identity-packed envelope would see their keychain key used
|
|
60
|
+
// instead — silently. Making env vars authoritative for the debugger
|
|
61
|
+
// lets operators target a specific identity without affecting the rest
|
|
62
|
+
// of `clef ui`.
|
|
63
|
+
function resolveAgeIdentity(deps) {
|
|
64
|
+
const envInline = process.env.CLEF_AGE_KEY;
|
|
65
|
+
if (envInline) {
|
|
66
|
+
return { configured: true, source: "CLEF_AGE_KEY", path: null };
|
|
67
|
+
}
|
|
68
|
+
const envFile = process.env.CLEF_AGE_KEY_FILE;
|
|
69
|
+
if (envFile) {
|
|
70
|
+
return { configured: true, source: "CLEF_AGE_KEY_FILE", path: envFile };
|
|
71
|
+
}
|
|
72
|
+
if (deps.ageKey) {
|
|
73
|
+
return { configured: true, source: "CLEF_AGE_KEY", path: null };
|
|
74
|
+
}
|
|
75
|
+
if (deps.ageKeyFile) {
|
|
76
|
+
return { configured: true, source: "CLEF_AGE_KEY_FILE", path: deps.ageKeyFile };
|
|
77
|
+
}
|
|
78
|
+
return { configured: false, source: null, path: null };
|
|
79
|
+
}
|
|
80
|
+
function loadAgePrivateKey(deps) {
|
|
81
|
+
const ageDecryptor = new runtime_1.AgeDecryptor();
|
|
82
|
+
// Same precedence as resolveAgeIdentity — env vars win over deps.
|
|
83
|
+
if (process.env.CLEF_AGE_KEY) {
|
|
84
|
+
return ageDecryptor.resolveKey(process.env.CLEF_AGE_KEY);
|
|
85
|
+
}
|
|
86
|
+
if (process.env.CLEF_AGE_KEY_FILE) {
|
|
87
|
+
return ageDecryptor.resolveKey(undefined, process.env.CLEF_AGE_KEY_FILE);
|
|
88
|
+
}
|
|
89
|
+
if (deps.ageKey)
|
|
90
|
+
return ageDecryptor.resolveKey(deps.ageKey);
|
|
91
|
+
if (deps.ageKeyFile)
|
|
92
|
+
return ageDecryptor.resolveKey(undefined, deps.ageKeyFile);
|
|
93
|
+
throw new Error("No age identity configured on the server. " +
|
|
94
|
+
"Set CLEF_AGE_KEY_FILE or CLEF_AGE_KEY before launching `clef ui`.");
|
|
95
|
+
}
|
|
96
|
+
function registerEnvelopeRoutes(router, deps) {
|
|
97
|
+
// POST /api/envelope/inspect
|
|
98
|
+
router.post("/envelope/inspect", (req, res) => {
|
|
99
|
+
setNoCacheHeaders(res);
|
|
100
|
+
const raw = (req.body ?? {}).raw;
|
|
101
|
+
const verifyHash = (req.body ?? {}).verifyHash;
|
|
102
|
+
if (typeof raw !== "string") {
|
|
103
|
+
res.status(400).json({ error: "raw is required", code: "BAD_REQUEST" });
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
let parsed;
|
|
107
|
+
try {
|
|
108
|
+
parsed = JSON.parse(raw);
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
res.json((0, core_1.buildInspectError)(UI_SOURCE, "parse_failed", err.message));
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
114
|
+
try {
|
|
115
|
+
(0, core_1.assertPackedArtifact)(parsed);
|
|
116
|
+
}
|
|
117
|
+
catch (err) {
|
|
118
|
+
const message = err instanceof core_1.InvalidArtifactError ? err.message : err.message;
|
|
119
|
+
res.json((0, core_1.buildInspectError)(UI_SOURCE, "invalid_artifact", message));
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const artifact = parsed;
|
|
123
|
+
const hashOk = verifyHash === false
|
|
124
|
+
? true
|
|
125
|
+
: (0, core_1.computeCiphertextHash)(artifact.ciphertext) === artifact.ciphertextHash;
|
|
126
|
+
res.json((0, core_1.buildInspectResult)(UI_SOURCE, artifact, hashOk));
|
|
127
|
+
});
|
|
128
|
+
// POST /api/envelope/verify
|
|
129
|
+
router.post("/envelope/verify", (req, res) => {
|
|
130
|
+
setNoCacheHeaders(res);
|
|
131
|
+
const raw = (req.body ?? {}).raw;
|
|
132
|
+
const signerKey = (req.body ?? {}).signerKey;
|
|
133
|
+
if (typeof raw !== "string") {
|
|
134
|
+
res.status(400).json({ error: "raw is required", code: "BAD_REQUEST" });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if (signerKey !== undefined && typeof signerKey !== "string") {
|
|
138
|
+
res.status(400).json({ error: "signerKey must be a string", code: "BAD_REQUEST" });
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
let parsed;
|
|
142
|
+
try {
|
|
143
|
+
parsed = JSON.parse(raw);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
res.json((0, core_1.buildVerifyError)(UI_SOURCE, "parse_failed", err.message));
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
try {
|
|
150
|
+
(0, core_1.assertPackedArtifact)(parsed);
|
|
151
|
+
}
|
|
152
|
+
catch (err) {
|
|
153
|
+
const message = err instanceof core_1.InvalidArtifactError ? err.message : err.message;
|
|
154
|
+
res.json((0, core_1.buildVerifyError)(UI_SOURCE, "invalid_artifact", message));
|
|
155
|
+
return;
|
|
156
|
+
}
|
|
157
|
+
const artifact = parsed;
|
|
158
|
+
const hashStatus = (0, core_1.computeCiphertextHash)(artifact.ciphertext) === artifact.ciphertextHash ? "ok" : "mismatch";
|
|
159
|
+
const signature = {
|
|
160
|
+
status: "absent",
|
|
161
|
+
algorithm: artifact.signatureAlgorithm ?? null,
|
|
162
|
+
};
|
|
163
|
+
if (typeof artifact.signature === "string") {
|
|
164
|
+
if (signerKey) {
|
|
165
|
+
let signerKeyBase64;
|
|
166
|
+
try {
|
|
167
|
+
// UI is paste-only: no file paths accepted (D4).
|
|
168
|
+
signerKeyBase64 = (0, core_1.parseSignerKey)(signerKey);
|
|
169
|
+
}
|
|
170
|
+
catch (err) {
|
|
171
|
+
res.json((0, core_1.buildVerifyError)(UI_SOURCE, "signer_key_invalid", err.message));
|
|
172
|
+
return;
|
|
173
|
+
}
|
|
174
|
+
const payload = (0, core_1.buildSigningPayload)(artifact);
|
|
175
|
+
try {
|
|
176
|
+
signature.status = (0, core_1.verifySignature)(payload, artifact.signature, signerKeyBase64)
|
|
177
|
+
? "valid"
|
|
178
|
+
: "invalid";
|
|
179
|
+
}
|
|
180
|
+
catch (err) {
|
|
181
|
+
signature.status = "invalid";
|
|
182
|
+
signature.algorithm = `error: ${err.message}`;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
signature.status = "not_verified";
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
const now = Date.now();
|
|
190
|
+
let expiry;
|
|
191
|
+
if (artifact.expiresAt) {
|
|
192
|
+
const expired = new Date(artifact.expiresAt).getTime() < now;
|
|
193
|
+
expiry = { status: expired ? "expired" : "ok", expiresAt: artifact.expiresAt };
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
expiry = { status: "absent", expiresAt: null };
|
|
197
|
+
}
|
|
198
|
+
const revocation = artifact.revokedAt
|
|
199
|
+
? { status: "revoked", revokedAt: artifact.revokedAt }
|
|
200
|
+
: { status: "absent", revokedAt: null };
|
|
201
|
+
const inputs = { hash: hashStatus, signature, expiry, revocation };
|
|
202
|
+
res.json((0, core_1.buildVerifyResult)(UI_SOURCE, inputs));
|
|
203
|
+
});
|
|
204
|
+
// POST /api/envelope/decrypt
|
|
205
|
+
router.post("/envelope/decrypt", async (req, res) => {
|
|
206
|
+
setNoCacheHeaders(res);
|
|
207
|
+
const raw = (req.body ?? {}).raw;
|
|
208
|
+
const reveal = (req.body ?? {}).reveal === true;
|
|
209
|
+
const key = (req.body ?? {}).key;
|
|
210
|
+
if (typeof raw !== "string") {
|
|
211
|
+
res.status(400).json({ error: "raw is required", code: "BAD_REQUEST" });
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
if (key !== undefined && typeof key !== "string") {
|
|
215
|
+
res.status(400).json({ error: "key must be a string", code: "BAD_REQUEST" });
|
|
216
|
+
return;
|
|
217
|
+
}
|
|
218
|
+
if (reveal && key) {
|
|
219
|
+
res.status(400).json({
|
|
220
|
+
error: "reveal and key are mutually exclusive; pick one",
|
|
221
|
+
code: "BAD_REQUEST",
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
let parsed;
|
|
226
|
+
try {
|
|
227
|
+
parsed = JSON.parse(raw);
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "parse_failed", err.message));
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
try {
|
|
234
|
+
(0, core_1.assertPackedArtifact)(parsed);
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
const message = err instanceof core_1.InvalidArtifactError ? err.message : err.message;
|
|
238
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "invalid_artifact", message));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const artifact = parsed;
|
|
242
|
+
if ((0, core_1.computeCiphertextHash)(artifact.ciphertext) !== artifact.ciphertextHash) {
|
|
243
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "hash_mismatch", "ciphertext hash does not match declared value"));
|
|
244
|
+
return;
|
|
245
|
+
}
|
|
246
|
+
if (artifact.expiresAt && new Date(artifact.expiresAt).getTime() < Date.now()) {
|
|
247
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "expired", `artifact expired at ${artifact.expiresAt}`));
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
if (artifact.revokedAt) {
|
|
251
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "revoked", `artifact was revoked at ${artifact.revokedAt}`));
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
// Age identity is resolved from server environment only. Clients never
|
|
255
|
+
// send keys. For KMS-enveloped artifacts the private key is not used —
|
|
256
|
+
// ArtifactDecryptor reads ambient AWS credentials internally.
|
|
257
|
+
let privateKey;
|
|
258
|
+
if (!artifact.envelope) {
|
|
259
|
+
try {
|
|
260
|
+
privateKey = loadAgePrivateKey(deps);
|
|
261
|
+
}
|
|
262
|
+
catch (err) {
|
|
263
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "key_resolution_failed", err.message));
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
let values;
|
|
268
|
+
try {
|
|
269
|
+
const decryptor = new runtime_1.ArtifactDecryptor({ privateKey });
|
|
270
|
+
({ values } = await decryptor.decrypt(artifact));
|
|
271
|
+
}
|
|
272
|
+
catch (err) {
|
|
273
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "decrypt_failed", err.message));
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const keys = Object.keys(values);
|
|
277
|
+
if (key) {
|
|
278
|
+
if (!(key in values)) {
|
|
279
|
+
res.json((0, core_1.buildDecryptError)(UI_SOURCE, "unknown_key", `key "${key}" not present in decrypted payload`));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
res.json((0, core_1.buildDecryptResult)(UI_SOURCE, { keys, singleKey: { name: key, value: values[key] } }));
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
if (reveal) {
|
|
286
|
+
res.json((0, core_1.buildDecryptResult)(UI_SOURCE, { keys, allValues: values }));
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
res.json((0, core_1.buildDecryptResult)(UI_SOURCE, { keys }));
|
|
290
|
+
});
|
|
291
|
+
// GET /api/envelope/config — tells the client which server-side identity
|
|
292
|
+
// will be used for decrypt, so operators can diagnose key_resolution_failed.
|
|
293
|
+
// Does NOT return key material, only metadata (env var name + optional path).
|
|
294
|
+
router.get("/envelope/config", (_req, res) => {
|
|
295
|
+
setNoCacheHeaders(res);
|
|
296
|
+
const ageIdentity = resolveAgeIdentity(deps);
|
|
297
|
+
const awsProfile = process.env.AWS_PROFILE ?? null;
|
|
298
|
+
const hasCredentials = !!process.env.AWS_PROFILE ||
|
|
299
|
+
!!process.env.AWS_ACCESS_KEY_ID ||
|
|
300
|
+
!!process.env.AWS_ROLE_ARN ||
|
|
301
|
+
!!process.env.AWS_WEB_IDENTITY_TOKEN_FILE ||
|
|
302
|
+
// Well-known shared credentials file — if present assume AWS SDK will find creds.
|
|
303
|
+
(!!process.env.HOME && fs.existsSync(`${process.env.HOME}/.aws/credentials`));
|
|
304
|
+
res.json({
|
|
305
|
+
ageIdentity,
|
|
306
|
+
aws: { hasCredentials, profile: awsProfile },
|
|
307
|
+
});
|
|
308
|
+
});
|
|
309
|
+
}
|
|
310
|
+
//# sourceMappingURL=envelope.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envelope.js","sourceRoot":"","sources":["../../src/server/envelope.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@clef-sh/ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.21",
|
|
4
4
|
"description": "Local web UI for Clef — git-native secrets management",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -34,12 +34,16 @@
|
|
|
34
34
|
"test:coverage": "jest --coverage"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@clef-sh/core": "0.1.
|
|
37
|
+
"@clef-sh/core": "0.1.21",
|
|
38
|
+
"@clef-sh/design": "0.1.1",
|
|
39
|
+
"@clef-sh/runtime": "0.1.24",
|
|
38
40
|
"express": "^5.1.0",
|
|
39
41
|
"express-rate-limit": "^8.3.2",
|
|
42
|
+
"lucide-react": "^0.468.0",
|
|
40
43
|
"yaml": "^2.8.3"
|
|
41
44
|
},
|
|
42
45
|
"devDependencies": {
|
|
46
|
+
"@tailwindcss/vite": "^4.1.0",
|
|
43
47
|
"@testing-library/jest-dom": "^6.4.0",
|
|
44
48
|
"@testing-library/react": "^14.2.0",
|
|
45
49
|
"@testing-library/user-event": "^14.5.0",
|
|
@@ -55,6 +59,7 @@
|
|
|
55
59
|
"react": "^18.2.0",
|
|
56
60
|
"react-dom": "^18.2.0",
|
|
57
61
|
"supertest": "^7.2.2",
|
|
62
|
+
"tailwindcss": "^4.1.0",
|
|
58
63
|
"ts-jest": "^29.4.9",
|
|
59
64
|
"typescript": "^5.9.3",
|
|
60
65
|
"vite": "^8.0.9"
|
package/src/client/App.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useState, useEffect, useCallback } from "react";
|
|
2
|
-
import { theme } from "./theme";
|
|
3
2
|
import { apiFetch } from "./api";
|
|
4
3
|
import { Sidebar, ViewName } from "./components/Sidebar";
|
|
5
4
|
import { MatrixView } from "./screens/MatrixView";
|
|
6
5
|
import { NamespaceEditor } from "./screens/NamespaceEditor";
|
|
6
|
+
import { SchemaEditor } from "./screens/SchemaEditor";
|
|
7
7
|
import { DiffView } from "./screens/DiffView";
|
|
8
8
|
import { LintView } from "./screens/LintView";
|
|
9
9
|
import { ScanScreen } from "./screens/ScanScreen";
|
|
@@ -15,6 +15,7 @@ import { ServiceIdentitiesScreen } from "./screens/ServiceIdentitiesScreen";
|
|
|
15
15
|
import { BackendScreen } from "./screens/BackendScreen";
|
|
16
16
|
import { ResetScreen } from "./screens/ResetScreen";
|
|
17
17
|
import { GitLogView } from "./screens/GitLogView";
|
|
18
|
+
import { EnvelopeScreen } from "./screens/EnvelopeScreen";
|
|
18
19
|
import type { ClefManifest, MatrixStatus, GitStatus, LintResult } from "@clef-sh/core";
|
|
19
20
|
|
|
20
21
|
export default function App() {
|
|
@@ -124,44 +125,23 @@ export default function App() {
|
|
|
124
125
|
|
|
125
126
|
if (loading) {
|
|
126
127
|
return (
|
|
127
|
-
<div
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
>
|
|
138
|
-
<div style={{ textAlign: "center" }}>
|
|
139
|
-
<div
|
|
140
|
-
style={{
|
|
141
|
-
fontSize: 24,
|
|
142
|
-
color: theme.accent,
|
|
143
|
-
marginBottom: 12,
|
|
144
|
-
}}
|
|
145
|
-
>
|
|
146
|
-
{"\u266A"}
|
|
147
|
-
</div>
|
|
148
|
-
<div style={{ fontSize: 13 }}>Loading...</div>
|
|
128
|
+
<div className="flex h-screen items-center justify-center bg-ink-950 font-sans text-ash">
|
|
129
|
+
<div className="text-center">
|
|
130
|
+
<img
|
|
131
|
+
src="/clef.svg"
|
|
132
|
+
alt=""
|
|
133
|
+
width="20"
|
|
134
|
+
height="44"
|
|
135
|
+
className="mx-auto mb-3 [filter:drop-shadow(0_0_10px_rgba(240,165,0,0.35))]"
|
|
136
|
+
/>
|
|
137
|
+
<div className="text-[13px]">Loading...</div>
|
|
149
138
|
</div>
|
|
150
139
|
</div>
|
|
151
140
|
);
|
|
152
141
|
}
|
|
153
142
|
|
|
154
143
|
return (
|
|
155
|
-
<div
|
|
156
|
-
style={{
|
|
157
|
-
display: "flex",
|
|
158
|
-
height: "100vh",
|
|
159
|
-
background: theme.bg,
|
|
160
|
-
color: theme.text,
|
|
161
|
-
fontFamily: theme.sans,
|
|
162
|
-
overflow: "hidden",
|
|
163
|
-
}}
|
|
164
|
-
>
|
|
144
|
+
<div className="flex h-screen overflow-hidden bg-ink-950 font-sans text-bone">
|
|
165
145
|
<Sidebar
|
|
166
146
|
activeView={view}
|
|
167
147
|
setView={setView}
|
|
@@ -175,14 +155,7 @@ export default function App() {
|
|
|
175
155
|
policyOverdueCount={policyOverdueCount}
|
|
176
156
|
/>
|
|
177
157
|
|
|
178
|
-
<div
|
|
179
|
-
style={{
|
|
180
|
-
flex: 1,
|
|
181
|
-
display: "flex",
|
|
182
|
-
flexDirection: "column",
|
|
183
|
-
overflow: "hidden",
|
|
184
|
-
}}
|
|
185
|
-
>
|
|
158
|
+
<div className="flex flex-1 flex-col overflow-hidden">
|
|
186
159
|
{view === "matrix" && (
|
|
187
160
|
<MatrixView
|
|
188
161
|
setView={setView}
|
|
@@ -196,6 +169,7 @@ export default function App() {
|
|
|
196
169
|
{view === "editor" && (
|
|
197
170
|
<NamespaceEditor ns={activeNs} initialEnv={activeEnv} manifest={manifest} />
|
|
198
171
|
)}
|
|
172
|
+
{view === "schema" && <SchemaEditor ns={activeNs} manifest={manifest} />}
|
|
199
173
|
{view === "diff" && <DiffView manifest={manifest} />}
|
|
200
174
|
{view === "lint" && <LintView setView={setView} setNs={setActiveNs} />}
|
|
201
175
|
{view === "scan" && <ScanScreen />}
|
|
@@ -213,6 +187,7 @@ export default function App() {
|
|
|
213
187
|
{view === "manifest" && (
|
|
214
188
|
<ManifestScreen manifest={manifest} reloadManifest={loadManifest} />
|
|
215
189
|
)}
|
|
190
|
+
{view === "envelope" && <EnvelopeScreen />}
|
|
216
191
|
</div>
|
|
217
192
|
</div>
|
|
218
193
|
);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { theme } from "../theme";
|
|
3
2
|
|
|
4
3
|
interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, "type"> {
|
|
5
4
|
children: React.ReactNode;
|
|
@@ -8,10 +7,10 @@ interface ButtonProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>
|
|
|
8
7
|
type?: "button" | "submit";
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
const
|
|
12
|
-
primary:
|
|
13
|
-
ghost:
|
|
14
|
-
danger:
|
|
10
|
+
const VARIANT_CLASSES: Record<NonNullable<ButtonProps["variant"]>, string> = {
|
|
11
|
+
primary: "bg-gold-500 text-ink-950 border border-transparent hover:bg-gold-400",
|
|
12
|
+
ghost: "bg-transparent text-bone border border-edge-strong hover:bg-ink-800",
|
|
13
|
+
danger: "bg-stop-500/15 text-stop-500 border border-stop-500/40 hover:bg-stop-500/25",
|
|
15
14
|
};
|
|
16
15
|
|
|
17
16
|
export function Button({
|
|
@@ -20,32 +19,24 @@ export function Button({
|
|
|
20
19
|
onClick,
|
|
21
20
|
icon,
|
|
22
21
|
type = "button",
|
|
22
|
+
className,
|
|
23
23
|
style: _styleProp,
|
|
24
24
|
...rest
|
|
25
25
|
}: ButtonProps) {
|
|
26
|
-
const s = VARIANT_STYLES[variant];
|
|
27
26
|
return (
|
|
28
27
|
<button
|
|
29
28
|
type={type}
|
|
30
29
|
onClick={onClick}
|
|
31
30
|
{...rest}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
fontFamily: theme.sans,
|
|
40
|
-
fontSize: 12,
|
|
41
|
-
fontWeight: 600,
|
|
42
|
-
background: s.bg,
|
|
43
|
-
color: s.color,
|
|
44
|
-
border: s.border,
|
|
45
|
-
transition: "all 0.12s",
|
|
46
|
-
}}
|
|
31
|
+
className={[
|
|
32
|
+
"inline-flex items-center gap-1.5 rounded-md px-3 py-1 font-sans text-[12px] font-semibold cursor-pointer transition-colors disabled:cursor-not-allowed disabled:opacity-60",
|
|
33
|
+
VARIANT_CLASSES[variant],
|
|
34
|
+
className ?? "",
|
|
35
|
+
]
|
|
36
|
+
.join(" ")
|
|
37
|
+
.trim()}
|
|
47
38
|
>
|
|
48
|
-
{icon && <span
|
|
39
|
+
{icon && <span className="flex">{icon}</span>}
|
|
49
40
|
{children}
|
|
50
41
|
</button>
|
|
51
42
|
);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import React, { useState, useCallback } from "react";
|
|
2
|
-
import { theme } from "../theme";
|
|
3
2
|
|
|
4
3
|
interface CopyButtonProps {
|
|
5
4
|
text: string;
|
|
@@ -18,17 +17,11 @@ export function CopyButton({ text }: CopyButtonProps) {
|
|
|
18
17
|
<button
|
|
19
18
|
data-testid="copy-button"
|
|
20
19
|
onClick={handleCopy}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
color: copied ? theme.green : theme.textDim,
|
|
27
|
-
fontFamily: theme.mono,
|
|
28
|
-
fontSize: 10,
|
|
29
|
-
padding: "2px 8px",
|
|
30
|
-
transition: "all 0.15s",
|
|
31
|
-
}}
|
|
20
|
+
className={`cursor-pointer rounded-sm border px-2 py-0.5 font-mono text-[10px] transition-colors ${
|
|
21
|
+
copied
|
|
22
|
+
? "border-go-500/40 bg-go-500/10 text-go-500"
|
|
23
|
+
: "border-edge-strong bg-transparent text-ash-dim hover:bg-ink-800"
|
|
24
|
+
}`}
|
|
32
25
|
>
|
|
33
26
|
{copied ? "copied!" : "copy"}
|
|
34
27
|
</button>
|
|
@@ -1,30 +1,45 @@
|
|
|
1
1
|
import React from "react";
|
|
2
|
-
import { theme, ENV_COLORS } from "../theme";
|
|
3
2
|
|
|
4
3
|
interface EnvBadgeProps {
|
|
5
4
|
env: string;
|
|
6
5
|
small?: boolean;
|
|
7
6
|
}
|
|
8
7
|
|
|
8
|
+
// Per-env color set. Mirrors `ENV_COLORS` from the design tokens but expressed
|
|
9
|
+
// as Tailwind class strings so we don't pay the inline-style cost. The unknown
|
|
10
|
+
// fallback ("ash") is also handled here.
|
|
11
|
+
const ENV_CLASSES: Record<string, { text: string; bg: string; border: string; label: string }> = {
|
|
12
|
+
dev: {
|
|
13
|
+
text: "text-go-500",
|
|
14
|
+
bg: "bg-go-500/10",
|
|
15
|
+
border: "border-go-500/20",
|
|
16
|
+
label: "DEV",
|
|
17
|
+
},
|
|
18
|
+
staging: {
|
|
19
|
+
text: "text-warn-500",
|
|
20
|
+
bg: "bg-warn-500/10",
|
|
21
|
+
border: "border-warn-500/20",
|
|
22
|
+
label: "STG",
|
|
23
|
+
},
|
|
24
|
+
production: {
|
|
25
|
+
text: "text-stop-500",
|
|
26
|
+
bg: "bg-stop-500/10",
|
|
27
|
+
border: "border-stop-500/20",
|
|
28
|
+
label: "PRD",
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
|
|
9
32
|
export function EnvBadge({ env, small }: EnvBadgeProps) {
|
|
10
|
-
const c =
|
|
11
|
-
|
|
12
|
-
bg: "transparent",
|
|
33
|
+
const c = ENV_CLASSES[env] ?? {
|
|
34
|
+
text: "text-ash",
|
|
35
|
+
bg: "bg-transparent",
|
|
36
|
+
border: "border-ash/20",
|
|
13
37
|
label: env.toUpperCase().slice(0, 3),
|
|
14
38
|
};
|
|
39
|
+
const sizeClasses = small ? "text-[9px] px-1.5 py-px" : "text-[10px] px-2 py-0.5";
|
|
15
40
|
return (
|
|
16
41
|
<span
|
|
17
|
-
|
|
18
|
-
fontFamily: theme.mono,
|
|
19
|
-
fontSize: small ? "9px" : "10px",
|
|
20
|
-
fontWeight: 700,
|
|
21
|
-
color: c.color,
|
|
22
|
-
background: c.bg,
|
|
23
|
-
border: `1px solid ${c.color}33`,
|
|
24
|
-
borderRadius: "3px",
|
|
25
|
-
padding: small ? "1px 5px" : "2px 7px",
|
|
26
|
-
letterSpacing: "0.08em",
|
|
27
|
-
}}
|
|
42
|
+
className={`inline-block rounded-sm border font-mono font-bold tracking-[0.08em] ${c.text} ${c.bg} ${c.border} ${sizeClasses}`}
|
|
28
43
|
>
|
|
29
44
|
{c.label}
|
|
30
45
|
</span>
|