@f5-sales-demo/xcsh 22.15.0 → 23.0.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/CHANGELOG.md CHANGED
@@ -4,6 +4,12 @@
4
4
 
5
5
  ## Unreleased
6
6
 
7
+ ### Breaking changes
8
+
9
+ - `request secrets encrypt` now emits bare base64; its policy retrieval requires `--name` and defaults to namespace `default`. Public documents default to camelCase YAML. The article consumer adds exactly one `string:///`. Canonical `blindfold` keeps snake_case JSON and location defaults.
10
+ - Both paths accept known camelCase/snake_case aliases and explicit encryption encoding; compatibility `--outfile` writes raw envelopes securely, `--outfmt` selects public document format, and public-key retrieval supports exact unsigned key versions. No legacy authentication or runtime vesctl dependency is introduced.
11
+
12
+
7
13
  ### Added
8
14
 
9
15
  - Added shared host-aware software setup with live management probes, reviewed package-manager routes, checksum-verified per-user archives, and asynchronous CLI/TUI setup preparation ([#4598](https://github.com/f5-sales-demo/xcsh/issues/4598)).
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5-sales-demo/xcsh",
4
- "version": "22.15.0",
4
+ "version": "23.0.1",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5-sales-demo/xcsh",
7
7
  "author": "Can Boluk",
@@ -68,13 +68,13 @@
68
68
  },
69
69
  "dependencies": {
70
70
  "@agentclientprotocol/sdk": "1.4.0",
71
- "@f5-sales-demo/pi-agent-core": "22.15.0",
72
- "@f5-sales-demo/pi-ai": "22.15.0",
73
- "@f5-sales-demo/pi-natives": "22.15.0",
74
- "@f5-sales-demo/pi-resource-management": "22.15.0",
75
- "@f5-sales-demo/pi-tui": "22.15.0",
76
- "@f5-sales-demo/pi-utils": "22.15.0",
77
- "@f5-sales-demo/xcsh-stats": "22.15.0",
71
+ "@f5-sales-demo/pi-agent-core": "23.0.1",
72
+ "@f5-sales-demo/pi-ai": "23.0.1",
73
+ "@f5-sales-demo/pi-natives": "23.0.1",
74
+ "@f5-sales-demo/pi-resource-management": "23.0.1",
75
+ "@f5-sales-demo/pi-tui": "23.0.1",
76
+ "@f5-sales-demo/pi-utils": "23.0.1",
77
+ "@f5-sales-demo/xcsh-stats": "23.0.1",
78
78
  "@mozilla/readability": "^0.6",
79
79
  "@resvg/resvg-wasm": "2.6.2",
80
80
  "@sinclair/typebox": "0.34.52",
@@ -14,6 +14,10 @@ export const blindfoldFlags = {
14
14
  policy: Flags.string({ description: "Secret policy namespace/name (default shared/ves-io-allow-volterra)" }),
15
15
  "passphrase-env": Flags.string({ description: "Passphrase environment variable name" }),
16
16
  "context-name": Flags.string({ description: "Assert selected native context (online only)" }),
17
+ encoding: Flags.string({ description: "Encryption text encoding", options: ["base64", "location"] }),
18
+ outfile: Flags.string({ description: "New raw binary envelope file (0600; compatibility only)" }),
19
+ outfmt: Flags.string({ description: "Compatibility public document format", options: ["json", "yaml"] }),
20
+ "key-version": Flags.string({ description: "Unsigned 32-bit public key version; zero selects server default" }),
17
21
  output: Flags.string({ description: "Public material format", options: ["json", "yaml"] }),
18
22
  "output-file": Flags.string({ description: "New artifact file (0600)" }),
19
23
  "result-file": Flags.string({ description: "New public JSON report file (0600)" }),
@@ -23,14 +27,22 @@ export const blindfoldFlags = {
23
27
  const aliases = { "get-public-key": "public-key", "get-policy-document": "policy", encrypt: "encrypt" } as const;
24
28
  const supported = ["public-key", "policy", "encrypt", "certificate", "create", "replace"];
25
29
  const common = ["context-name", "output-file", "result-file", "json"];
26
- export function flagsForBlindfold(operation: string) {
30
+ export function flagsForBlindfold(operation: string, compatibility = false) {
27
31
  const names =
28
32
  operation === "public-key"
29
- ? [...common, "output"]
33
+ ? [...common, "output", "key-version", ...(compatibility ? ["outfmt"] : [])]
30
34
  : operation === "policy"
31
- ? [...common, "output", "policy", "namespace", "name"]
35
+ ? [...common, "output", "namespace", "name", ...(compatibility ? ["outfmt"] : ["policy"])]
32
36
  : operation === "encrypt"
33
- ? [...common, "input", "policy", "public-key", "policy-document"]
37
+ ? [
38
+ ...common,
39
+ "input",
40
+ "policy",
41
+ "public-key",
42
+ "policy-document",
43
+ "encoding",
44
+ ...(compatibility ? ["outfile", "outfmt"] : []),
45
+ ]
34
46
  : [...common, "cert", "key", "bundle", "name", "namespace", "policy", "passphrase-env", "dry-run"];
35
47
  return Object.fromEntries(names.map(name => [name, blindfoldFlags[name as keyof typeof blindfoldFlags]]));
36
48
  }
@@ -49,7 +61,7 @@ export function parseBlindfoldCli(
49
61
  throw new CliUsageError("Legacy authentication is unsupported; configure xcsh context with xcsh context");
50
62
  }
51
63
  const parsed = parseCommandArgv(parts, {
52
- flags: flagsForBlindfold(operation),
64
+ flags: flagsForBlindfold(operation, compatibility),
53
65
  args: operation === "encrypt" ? { file: Args.string() } : {},
54
66
  });
55
67
  if (parsed.argv.length > (operation === "encrypt" ? 1 : 0)) throw new CliUsageError("Surplus positional arguments");
@@ -58,6 +70,9 @@ export function parseBlindfoldCli(
58
70
  throw new CliUsageError("Select one secret input source");
59
71
  const args: BlindfoldArgs & { json?: boolean } = {
60
72
  operation: operation as BlindfoldOperation,
73
+ compatibility,
74
+ encoding: f.encoding as "base64" | "location" | undefined,
75
+ outfile: f.outfile as string | undefined,
61
76
  input: (f.input ?? parsed.args.file) as string | undefined,
62
77
  publicKey: f["public-key"] as string | undefined,
63
78
  policyDocument: f["policy-document"] as string | undefined,
@@ -69,12 +84,28 @@ export function parseBlindfoldCli(
69
84
  policy: f.policy as string | undefined,
70
85
  passphraseEnv: f["passphrase-env"] as string | undefined,
71
86
  contextName: f["context-name"] as string | undefined,
72
- output: f.output as "json" | "yaml" | undefined,
87
+ output: (f.output ?? (operation !== "encrypt" ? f.outfmt : undefined)) as "json" | "yaml" | undefined,
73
88
  outputFile: f["output-file"] as string | undefined,
74
89
  resultFile: f["result-file"] as string | undefined,
75
90
  dryRun: f["dry-run"] as "client" | undefined,
76
91
  json: f.json as boolean | undefined,
77
92
  };
93
+ if (f.output !== undefined && f.outfmt !== undefined)
94
+ throw new CliUsageError("Conflicting public material format selectors");
95
+ if (f["key-version"] !== undefined) {
96
+ const version = String(f["key-version"]);
97
+ if (!/^[0-9]+$/.test(version) || !Number.isSafeInteger(Number(version)) || Number(version) > 0xffffffff)
98
+ throw new CliUsageError("Key version must be an unsigned 32-bit integer");
99
+ args.keyVersion = Number(version);
100
+ }
101
+ if (compatibility && operation === "policy") {
102
+ if (!args.name) throw new CliUsageError("Compatibility policy retrieval requires --name");
103
+ args.namespace ??= "default";
104
+ }
105
+ if (args.outfile && (args.outputFile || args.json || args.encoding))
106
+ throw new CliUsageError("Binary --outfile conflicts with textual encoding, --output-file or --json");
107
+ if (args.outfile && args.resultFile && resolve(args.outfile) === resolve(args.resultFile))
108
+ throw new CliUsageError("Artifact and report destinations must differ");
78
109
  if (Boolean(args.publicKey) !== Boolean(args.policyDocument))
79
110
  throw new CliUsageError("--public-key and --policy-document must be supplied together");
80
111
  if (args.publicKey && args.contextName)
@@ -88,7 +119,11 @@ export function parseBlindfoldCli(
88
119
  throw new CliUsageError("Policy must be namespace/name");
89
120
  if ([args.name, args.namespace].some(v => v !== undefined && !label.test(v)))
90
121
  throw new CliUsageError("Invalid resource namespace or name");
91
- if ([args.input, args.publicKey, args.policyDocument, args.outputFile, args.resultFile].some(v => v === ""))
122
+ if (
123
+ [args.input, args.publicKey, args.policyDocument, args.outputFile, args.outfile, args.resultFile].some(
124
+ v => v === "",
125
+ )
126
+ )
92
127
  throw new CliUsageError("File paths must be nonempty");
93
128
  if (["certificate", "create", "replace"].includes(operation)) {
94
129
  if (!args.name || (args.bundle ? args.cert || args.key : !args.cert || !args.key))
@@ -36,7 +36,7 @@ export function showBlindfoldHelp(argv: string[], bin: string): void {
36
36
  : operation === "policy"
37
37
  ? "Retrieve a secret policy document; namespace/name select the policy"
38
38
  : "Native Blindfold operation";
39
- static flags = flagsForBlindfold(operation!);
39
+ static flags = flagsForBlindfold(operation!, compatibility);
40
40
  static args: Record<string, ArgDescriptor> =
41
41
  operation === "encrypt"
42
42
  ? { file: Args.string({ description: "Filename or -; omit for redirected stdin" }) }