mirror of
https://github.com/windmill-labs/windmill.git
synced 2026-08-19 16:02:14 +00:00
fix(cli): redact encryption_key diff in stdout by default (#9347)
* fix(cli): redact encryption_key diff in stdout by default Sync diff output previously printed the full encryption_key contents on stdout whenever the workspace key changed locally or on the remote, which made it easy to leak the key via shell history, CI logs, etc. Now the diff is replaced with a redacted notice for any encryption_key change in both prettyChanges and showConflict. Pass --show-encryption-key-diff (also configurable via wmill.yaml's showEncryptionKeyDiff) to opt back into the full diff. Fixes WIN-1992 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * refactor(cli): redact encryption_key diff with fixed-length mask Drop the --show-encryption-key-diff opt-in and always redact: the diff now keeps the first 5 chars of the key so rotations are still visible (different prefixes), then replaces every remaining char with `*` so the length of the key is preserved without leaking it. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -22,6 +22,7 @@ import {
|
||||
showConflict,
|
||||
showDiff,
|
||||
extractNativeTriggerInfo,
|
||||
redactEncryptionKey,
|
||||
} from "../../types.ts";
|
||||
import { downloadZip } from "./pull.ts";
|
||||
import { runLint, printReport, checkMissingLocks } from "../lint/lint.ts";
|
||||
@@ -3095,16 +3096,22 @@ function prettyChanges(
|
||||
),
|
||||
);
|
||||
} else if (change.name === "edited") {
|
||||
const changeType = getTypeStrFromPath(change.path);
|
||||
log.info(
|
||||
colors.yellow(
|
||||
`~ ${getTypeStrFromPath(change.path)} ` +
|
||||
`~ ${changeType} ` +
|
||||
displayPath +
|
||||
colors.gray(wsNote) +
|
||||
(change.codebase ? ` (codebase changed)` : ""),
|
||||
),
|
||||
);
|
||||
if (change.before != change.after) {
|
||||
if (change.path.endsWith(".yaml")) {
|
||||
if (changeType === "encryption_key") {
|
||||
showDiff(
|
||||
redactEncryptionKey(change.before),
|
||||
redactEncryptionKey(change.after),
|
||||
);
|
||||
} else if (change.path.endsWith(".yaml")) {
|
||||
try {
|
||||
showDiff(
|
||||
yamlStringify(
|
||||
|
||||
+36
-1
@@ -129,11 +129,46 @@ export function showDiff(local: string, remote: string) {
|
||||
|
||||
export function showConflict(path: string, local: string, remote: string) {
|
||||
log.info(colors.yellow(`- ${path}`));
|
||||
showDiff(local, remote);
|
||||
let isEncryptionKey = false;
|
||||
try {
|
||||
isEncryptionKey = getTypeStrFromPath(path) === "encryption_key";
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
if (isEncryptionKey) {
|
||||
showDiff(redactEncryptionKey(local), redactEncryptionKey(remote));
|
||||
} else {
|
||||
showDiff(local, remote);
|
||||
}
|
||||
log.info("\x1b[31mlocal\x1b[31m - \x1b[32mremote\x1b[32m");
|
||||
log.info("\n");
|
||||
}
|
||||
|
||||
// Reveal only the first 5 chars of the key so a rotation is still visible in
|
||||
// the diff (different prefixes), without leaking the whole secret to stdout.
|
||||
// The remaining chars are replaced with `*`, preserving length so the diff
|
||||
// keeps showing whether the key length changed.
|
||||
export function redactEncryptionKey(content: string): string {
|
||||
if (!content) return content;
|
||||
// The encryption_key payload is JSON-encoded (a quoted string). Parse it so
|
||||
// we redact the key value itself, then re-serialize to JSON to preserve the
|
||||
// file's shape; fall back to raw redaction if parsing fails.
|
||||
try {
|
||||
const parsed = JSON.parse(content);
|
||||
if (typeof parsed === "string") {
|
||||
return JSON.stringify(redactString(parsed));
|
||||
}
|
||||
} catch {
|
||||
// not JSON — treat content as the raw key
|
||||
}
|
||||
return redactString(content);
|
||||
}
|
||||
|
||||
function redactString(s: string): string {
|
||||
if (s.length <= 5) return s;
|
||||
return s.slice(0, 5) + "*".repeat(s.length - 5);
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an object to the workspace server based on its type
|
||||
* @param workspace - The workspace ID to push to
|
||||
|
||||
Reference in New Issue
Block a user