@orygn/opa-mcp 0.3.0 → 0.5.0

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.
Files changed (157) hide show
  1. package/CHANGELOG.md +396 -3
  2. package/README.md +132 -98
  3. package/dist/cli.d.ts.map +1 -1
  4. package/dist/cli.js +8 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/config.d.ts +15 -3
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +74 -14
  9. package/dist/config.js.map +1 -1
  10. package/dist/constants.d.ts +1 -1
  11. package/dist/constants.js +1 -1
  12. package/dist/lib/bundle-signatures.d.ts +23 -0
  13. package/dist/lib/bundle-signatures.d.ts.map +1 -0
  14. package/dist/lib/bundle-signatures.js +152 -0
  15. package/dist/lib/bundle-signatures.js.map +1 -0
  16. package/dist/lib/child-env.d.ts +41 -0
  17. package/dist/lib/child-env.d.ts.map +1 -0
  18. package/dist/lib/child-env.js +176 -0
  19. package/dist/lib/child-env.js.map +1 -0
  20. package/dist/lib/conftest-cli.d.ts +25 -10
  21. package/dist/lib/conftest-cli.d.ts.map +1 -1
  22. package/dist/lib/conftest-cli.js +153 -33
  23. package/dist/lib/conftest-cli.js.map +1 -1
  24. package/dist/lib/install-id.d.ts.map +1 -1
  25. package/dist/lib/install-id.js +18 -3
  26. package/dist/lib/install-id.js.map +1 -1
  27. package/dist/lib/json-stream.d.ts +26 -0
  28. package/dist/lib/json-stream.d.ts.map +1 -0
  29. package/dist/lib/json-stream.js +69 -0
  30. package/dist/lib/json-stream.js.map +1 -0
  31. package/dist/lib/opa-cli.d.ts +64 -16
  32. package/dist/lib/opa-cli.d.ts.map +1 -1
  33. package/dist/lib/opa-cli.js +99 -28
  34. package/dist/lib/opa-cli.js.map +1 -1
  35. package/dist/lib/opa-paths.d.ts +24 -0
  36. package/dist/lib/opa-paths.d.ts.map +1 -0
  37. package/dist/lib/opa-paths.js +97 -0
  38. package/dist/lib/opa-paths.js.map +1 -0
  39. package/dist/lib/regal-cli.d.ts +16 -1
  40. package/dist/lib/regal-cli.d.ts.map +1 -1
  41. package/dist/lib/regal-cli.js +41 -6
  42. package/dist/lib/regal-cli.js.map +1 -1
  43. package/dist/lib/rego-ast-walker.d.ts.map +1 -1
  44. package/dist/lib/rego-ast-walker.js +141 -17
  45. package/dist/lib/rego-ast-walker.js.map +1 -1
  46. package/dist/lib/rego-counterexample.d.ts +1 -1
  47. package/dist/lib/rego-counterexample.d.ts.map +1 -1
  48. package/dist/lib/rego-counterexample.js +23 -5
  49. package/dist/lib/rego-counterexample.js.map +1 -1
  50. package/dist/lib/rego-ir.d.ts +32 -2
  51. package/dist/lib/rego-ir.d.ts.map +1 -1
  52. package/dist/lib/rego-smt-encoder.d.ts +53 -5
  53. package/dist/lib/rego-smt-encoder.d.ts.map +1 -1
  54. package/dist/lib/rego-smt-encoder.js +192 -26
  55. package/dist/lib/rego-smt-encoder.js.map +1 -1
  56. package/dist/lib/rego-type-inferencer.d.ts +1 -1
  57. package/dist/lib/rego-type-inferencer.d.ts.map +1 -1
  58. package/dist/lib/rego-type-inferencer.js +3 -3
  59. package/dist/lib/rego-type-inferencer.js.map +1 -1
  60. package/dist/lib/rego-verify-engine.d.ts.map +1 -1
  61. package/dist/lib/rego-verify-engine.js +109 -77
  62. package/dist/lib/rego-verify-engine.js.map +1 -1
  63. package/dist/lib/rego-z3.d.ts +10 -0
  64. package/dist/lib/rego-z3.d.ts.map +1 -1
  65. package/dist/lib/rego-z3.js +38 -0
  66. package/dist/lib/rego-z3.js.map +1 -1
  67. package/dist/lib/security.d.ts +8 -0
  68. package/dist/lib/security.d.ts.map +1 -1
  69. package/dist/lib/security.js +130 -54
  70. package/dist/lib/security.js.map +1 -1
  71. package/dist/lib/subprocess.d.ts +36 -3
  72. package/dist/lib/subprocess.d.ts.map +1 -1
  73. package/dist/lib/subprocess.js +121 -20
  74. package/dist/lib/subprocess.js.map +1 -1
  75. package/dist/lib/tool-helpers.d.ts.map +1 -1
  76. package/dist/lib/tool-helpers.js +10 -0
  77. package/dist/lib/tool-helpers.js.map +1 -1
  78. package/dist/resources/patterns.d.ts +1 -1
  79. package/dist/resources/patterns.d.ts.map +1 -1
  80. package/dist/resources/patterns.js +40 -12
  81. package/dist/resources/patterns.js.map +1 -1
  82. package/dist/server.d.ts.map +1 -1
  83. package/dist/server.js +10 -2
  84. package/dist/server.js.map +1 -1
  85. package/dist/tools/authoring/check-schema.js +1 -1
  86. package/dist/tools/authoring/check-schema.js.map +1 -1
  87. package/dist/tools/bundles/build.d.ts.map +1 -1
  88. package/dist/tools/bundles/build.js +12 -4
  89. package/dist/tools/bundles/build.js.map +1 -1
  90. package/dist/tools/bundles/sign.d.ts +9 -2
  91. package/dist/tools/bundles/sign.d.ts.map +1 -1
  92. package/dist/tools/bundles/sign.js +145 -19
  93. package/dist/tools/bundles/sign.js.map +1 -1
  94. package/dist/tools/bundles/verify.d.ts +1 -1
  95. package/dist/tools/bundles/verify.d.ts.map +1 -1
  96. package/dist/tools/bundles/verify.js +58 -19
  97. package/dist/tools/bundles/verify.js.map +1 -1
  98. package/dist/tools/conftest/pull.d.ts.map +1 -1
  99. package/dist/tools/conftest/pull.js +24 -10
  100. package/dist/tools/conftest/pull.js.map +1 -1
  101. package/dist/tools/conftest/push.d.ts.map +1 -1
  102. package/dist/tools/conftest/push.js +17 -7
  103. package/dist/tools/conftest/push.js.map +1 -1
  104. package/dist/tools/conftest/test.d.ts +10 -6
  105. package/dist/tools/conftest/test.d.ts.map +1 -1
  106. package/dist/tools/conftest/test.js +47 -24
  107. package/dist/tools/conftest/test.js.map +1 -1
  108. package/dist/tools/conftest/verify.d.ts +10 -6
  109. package/dist/tools/conftest/verify.d.ts.map +1 -1
  110. package/dist/tools/conftest/verify.js +30 -18
  111. package/dist/tools/conftest/verify.js.map +1 -1
  112. package/dist/tools/evaluation/bench.d.ts +16 -0
  113. package/dist/tools/evaluation/bench.d.ts.map +1 -1
  114. package/dist/tools/evaluation/bench.js +30 -5
  115. package/dist/tools/evaluation/bench.js.map +1 -1
  116. package/dist/tools/evaluation/exec.d.ts +16 -0
  117. package/dist/tools/evaluation/exec.d.ts.map +1 -1
  118. package/dist/tools/evaluation/exec.js +35 -2
  119. package/dist/tools/evaluation/exec.js.map +1 -1
  120. package/dist/tools/evaluation/test-multiroot.d.ts +4 -0
  121. package/dist/tools/evaluation/test-multiroot.d.ts.map +1 -1
  122. package/dist/tools/evaluation/test-multiroot.js +21 -14
  123. package/dist/tools/evaluation/test-multiroot.js.map +1 -1
  124. package/dist/tools/evaluation/test.d.ts +45 -0
  125. package/dist/tools/evaluation/test.d.ts.map +1 -1
  126. package/dist/tools/evaluation/test.js +146 -27
  127. package/dist/tools/evaluation/test.js.map +1 -1
  128. package/dist/tools/helpers/coverage-gaps.d.ts +11 -3
  129. package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -1
  130. package/dist/tools/helpers/coverage-gaps.js +4 -3
  131. package/dist/tools/helpers/coverage-gaps.js.map +1 -1
  132. package/dist/tools/helpers/explain-undefined.d.ts +9 -3
  133. package/dist/tools/helpers/explain-undefined.d.ts.map +1 -1
  134. package/dist/tools/helpers/explain-undefined.js +83 -51
  135. package/dist/tools/helpers/explain-undefined.js.map +1 -1
  136. package/dist/tools/helpers/verify.d.ts.map +1 -1
  137. package/dist/tools/helpers/verify.js +5 -1
  138. package/dist/tools/helpers/verify.js.map +1 -1
  139. package/dist/tools/server-management/_shared.d.ts +15 -4
  140. package/dist/tools/server-management/_shared.d.ts.map +1 -1
  141. package/dist/tools/server-management/_shared.js +73 -12
  142. package/dist/tools/server-management/_shared.js.map +1 -1
  143. package/dist/tools/server-management/data.d.ts.map +1 -1
  144. package/dist/tools/server-management/data.js +88 -23
  145. package/dist/tools/server-management/data.js.map +1 -1
  146. package/dist/tools/server-management/decisions.d.ts.map +1 -1
  147. package/dist/tools/server-management/decisions.js +16 -3
  148. package/dist/tools/server-management/decisions.js.map +1 -1
  149. package/dist/tools/server-management/policies.d.ts.map +1 -1
  150. package/dist/tools/server-management/policies.js +44 -7
  151. package/dist/tools/server-management/policies.js.map +1 -1
  152. package/dist/tools/server-management/status.d.ts.map +1 -1
  153. package/dist/tools/server-management/status.js +80 -13
  154. package/dist/tools/server-management/status.js.map +1 -1
  155. package/dist/types.d.ts +10 -1
  156. package/dist/types.d.ts.map +1 -1
  157. package/package.json +2 -1
@@ -28,14 +28,17 @@ const OpaBundleBuildInput = {
28
28
  .array(z.string())
29
29
  .optional()
30
30
  .describe('Entrypoint refs (required when `target=wasm` or `optimize > 0`).'),
31
- signingKey: z.string().optional().describe('Path to a signing key for inline signing.'),
31
+ signingKey: z
32
+ .string()
33
+ .optional()
34
+ .describe('Path to a PEM private key for signing the built bundle (`--signing-key`). Implies `bundle: true`, which OPA requires for signing.'),
32
35
  signingAlg: z.string().optional().describe('Signing algorithm (e.g. RS256).'),
33
36
  claimsFile: z.string().optional().describe('Path to a claims file for inline signing.'),
34
37
  capabilities: z.string().optional().describe('Path to a capabilities JSON file.'),
35
38
  bundle: z
36
39
  .boolean()
37
40
  .optional()
38
- .describe('Load `paths` as bundle files or root directories (`--bundle`). Required when rebuilding or re-signing an existing bundle.'),
41
+ .describe('Load `paths` as bundle files or root directories (`--bundle`). Implied by `signingKey` and `verificationKey`; set it explicitly to rebuild an existing bundle without signing.'),
39
42
  pruneUnused: z
40
43
  .boolean()
41
44
  .optional()
@@ -51,7 +54,7 @@ const OpaBundleBuildInput = {
51
54
  verificationKey: z
52
55
  .string()
53
56
  .optional()
54
- .describe('Path to a PEM public key (or HMAC secret file) used to re-verify an existing signed bundle during the build (`--verification-key`). Pair with `bundle: true`.'),
57
+ .describe('Path to a PEM public key (or HMAC secret file) used to re-verify an existing signed bundle during the build (`--verification-key`). Implies `bundle: true`, which OPA requires for verification.'),
55
58
  verificationKeyId: z
56
59
  .string()
57
60
  .optional()
@@ -117,7 +120,12 @@ export function registerOpaBundleBuild(server, config) {
117
120
  signingAlg: input.signingAlg,
118
121
  claimsFile: resolvedClaimsFile,
119
122
  capabilities: resolvedCapabilities,
120
- bundle: input.bundle,
123
+ // opa build refuses --signing-key and --verification-key outside
124
+ // bundle mode ("enable bundle mode (ie. --bundle) to verify or sign
125
+ // bundle files or directories"), so either option implies it.
126
+ bundle: input.bundle === true ||
127
+ input.signingKey !== undefined ||
128
+ input.verificationKey !== undefined,
121
129
  pruneUnused: input.pruneUnused,
122
130
  ignore: input.ignore,
123
131
  v1Compatible: input.v1Compatible,
@@ -1 +1 @@
1
- {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/tools/bundles/build.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/tools/bundles/build.ts"],"names":[],"mappings":"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"}
@@ -1,8 +1,15 @@
1
1
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { Config } from '../../config.js';
3
3
  export interface OpaBundleSignOutput {
4
- signed: boolean;
5
- signaturesPath?: string;
4
+ signed: true;
5
+ /** Absolute path of the `.signatures.json` that was written. */
6
+ signaturesPath: string;
7
+ /** JWT algorithm recorded in the signature header. */
8
+ algorithm: string;
9
+ /** Number of files the signature covers. */
10
+ filesSigned: number;
11
+ keyId?: string;
12
+ scope?: string;
6
13
  }
7
14
  export declare function registerOpaBundleSign(server: McpServer, config: Config): void;
8
15
  //# sourceMappingURL=sign.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../../src/tools/bundles/sign.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAe9C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAgD7E"}
1
+ {"version":3,"file":"sign.d.ts","sourceRoot":"","sources":["../../../src/tools/bundles/sign.ts"],"names":[],"mappings":"AAgBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA+C9C,MAAM,WAAW,mBAAmB;IAClC,MAAM,EAAE,IAAI,CAAC;IACb,gEAAgE;IAChE,cAAc,EAAE,MAAM,CAAC;IACvB,sDAAsD;IACtD,SAAS,EAAE,MAAM,CAAC;IAClB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAWD,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA+J7E"}
@@ -1,25 +1,58 @@
1
- /**
2
- * `opa_bundle_sign` -- sign an existing bundle directory or archive
3
- * via `opa sign`.
4
- */
1
+ import { lstat, readlink, realpath, stat } from 'node:fs/promises';
2
+ import { basename, dirname, join } from 'node:path';
5
3
  import { z } from 'zod';
6
- import { OpaCli } from '../../lib/opa-cli.js';
4
+ import { isKeyOrAlgorithmError, readSignaturesSummary } from '../../lib/bundle-signatures.js';
7
5
  import { err, ok } from '../../lib/errors.js';
6
+ import { OpaCli } from '../../lib/opa-cli.js';
8
7
  import { mapSubprocessFailure, validatePaths, withToolEnvelope } from '../../lib/tool-helpers.js';
8
+ const SIGNATURES_FILE = '.signatures.json';
9
+ /**
10
+ * How far before the call a pre-existing `.signatures.json` may have been
11
+ * modified and still count as written by this call. Filesystems with coarse
12
+ * timestamps (FAT: 2s, HFS+: 1s) can report an unchanged mtime for a rewrite
13
+ * inside the same tick, and a clock only ever compares against itself here.
14
+ */
15
+ const MTIME_SLACK_MS = 2000;
9
16
  const OpaBundleSignInput = {
10
17
  bundle: z
11
18
  .string()
12
19
  .min(1)
13
- .describe('Path to a bundle directory or archive. Must be in an allowed root.'),
14
- signingKey: z.string().min(1).describe('Path to the signing key.'),
15
- signingAlg: z.string().optional().describe('Signing algorithm (e.g. RS256). Default: RS256.'),
16
- claimsFile: z.string().optional().describe('Path to extra claims to include in the signature.'),
20
+ .describe('Path to a bundle directory or `.tar.gz` archive. Must be inside an allowed root.'),
21
+ signingKey: z
22
+ .string()
23
+ .min(1)
24
+ .describe('Path to the PEM private key (RSA or ECDSA), or for HMAC algorithms a file holding the secret. Must be inside an allowed root.'),
25
+ signingAlg: z
26
+ .string()
27
+ .optional()
28
+ .describe('Signing algorithm: RS256 (default), RS384, RS512, PS256, PS384, PS512, ES256, ES384, ES512, HS256, HS384, HS512.'),
29
+ claimsFile: z
30
+ .string()
31
+ .optional()
32
+ .describe('Path to a JSON file of extra claims to sign, such as {"keyid": "...", "scope": "..."}. Must be inside an allowed root.'),
33
+ outputDir: z
34
+ .string()
35
+ .optional()
36
+ .describe("For an archive, the directory that receives `.signatures.json`; defaults to the archive's own directory. Must exist and be inside an allowed root. Not accepted for a directory bundle, which is signed in place."),
17
37
  };
38
+ /** lstat, so a symlink is reported as itself rather than as its target. */
39
+ async function lstatOrUndefined(path) {
40
+ try {
41
+ return await lstat(path);
42
+ }
43
+ catch {
44
+ return undefined;
45
+ }
46
+ }
18
47
  export function registerOpaBundleSign(server, config) {
19
48
  const opa = new OpaCli(config);
20
49
  server.registerTool('opa_bundle_sign', {
21
50
  title: 'Sign OPA bundle',
22
- description: 'Sign an OPA bundle with a private key using `opa sign`. Writes a `.signatures.json` next to the bundle directory, or updates the archive in place.',
51
+ description: 'Sign a bundle directory or `.tar.gz` archive with `opa sign`. ' +
52
+ 'A directory is signed in place: `.signatures.json` is written into it and files are recorded as `<directory name>/<file>`, so the signed directory verifies wherever it is placed as long as its name is unchanged, with `opa_bundle_verify` or with `opa build` or `opa run --bundle <name>` from its parent. ' +
53
+ "For an archive the signature is written beside it, into `outputDir` or the archive's own directory, and the archive is not modified; a signed archive comes from `opa_bundle_build` with `signingKey`. " +
54
+ 'The key is a PEM private key (RSA or ECDSA); for HMAC algorithms pass a file holding the secret. Extra claims such as `keyid` and `scope` come from `claimsFile`. ' +
55
+ 'Returns the path written, the algorithm, and the number of files covered.',
23
56
  inputSchema: OpaBundleSignInput,
24
57
  annotations: {
25
58
  readOnlyHint: false,
@@ -32,21 +65,114 @@ export function registerOpaBundleSign(server, config) {
32
65
  const validation = validatePaths([input.bundle, input.signingKey, ...(input.claimsFile ? [input.claimsFile] : [])], config, { mustExist: true });
33
66
  if (!validation.ok)
34
67
  return validation.error;
35
- const result = await opa.sign({
36
- bundle: validation.resolved[0],
37
- signingKey: validation.resolved[1],
38
- signingAlg: input.signingAlg,
39
- claimsFile: input.claimsFile ? validation.resolved[2] : undefined,
40
- }, signal);
68
+ const [resolvedBundle, resolvedKey, resolvedClaims] = validation.resolved;
69
+ // validatePath returns the path as given once its real target is
70
+ // inside an allowed root. OPA's directory walk does not descend a
71
+ // symlink or junction root, so a linked bundle would sign as an empty
72
+ // file list; the real path is what gets signed.
73
+ const realBundle = await realpath(resolvedBundle);
74
+ const isDirectory = (await stat(realBundle)).isDirectory();
75
+ let outputDir;
76
+ if (isDirectory) {
77
+ if (input.outputDir !== undefined) {
78
+ return err('INVALID_INPUT', `outputDir applies to archives only. A directory bundle is signed in place, since OPA reads ${SIGNATURES_FILE} from inside the bundle and cannot use a detached one.`, { details: { bundle: input.bundle } });
79
+ }
80
+ outputDir = realBundle;
81
+ }
82
+ else {
83
+ // The archive's own directory is derived from the path as given,
84
+ // not from the real path: an allowed root that is itself a symlink
85
+ // or a Windows short name (a macOS /var, an 8.3 temp directory)
86
+ // would otherwise fail the syntactic containment check against its
87
+ // own canonical form. Validation resolves the symlink itself.
88
+ const requested = input.outputDir ?? dirname(resolvedBundle);
89
+ const outputValidation = validatePaths([requested], config, { mustExist: true });
90
+ if (!outputValidation.ok)
91
+ return outputValidation.error;
92
+ outputDir = outputValidation.resolved[0];
93
+ if (!(await stat(outputDir)).isDirectory()) {
94
+ return err('INVALID_INPUT', 'outputDir must be an existing directory.', {
95
+ details: { outputDir },
96
+ });
97
+ }
98
+ }
99
+ const signaturesPath = join(outputDir, SIGNATURES_FILE);
100
+ // The directory is inside an allowed root, but the file inside it need
101
+ // not be: a pre-existing `.signatures.json` that is a symlink would
102
+ // have opa write through it to wherever it points.
103
+ const before = await lstatOrUndefined(signaturesPath);
104
+ if (before?.isSymbolicLink()) {
105
+ return err('PATH_NOT_ALLOWED', `${SIGNATURES_FILE} at the output location is a symbolic link; refusing to write through it.`, { details: { signaturesPath } });
106
+ }
107
+ const startedAt = Date.now();
108
+ const signInput = {
109
+ bundle: isDirectory ? basename(realBundle) : realBundle,
110
+ signingKey: resolvedKey,
111
+ outputDir,
112
+ };
113
+ if (isDirectory)
114
+ signInput.cwd = dirname(realBundle);
115
+ if (input.signingAlg !== undefined)
116
+ signInput.signingAlg = input.signingAlg;
117
+ if (resolvedClaims !== undefined)
118
+ signInput.claimsFile = resolvedClaims;
119
+ const result = await opa.sign(signInput, signal);
41
120
  const subprocessFailure = mapSubprocessFailure(result, 'opa');
42
121
  if (subprocessFailure)
43
122
  return subprocessFailure;
123
+ // opa prints its own errors on stdout, so both streams are kept.
124
+ const streams = { stderr: result.stderr.trim(), stdout: result.stdout.trim() };
44
125
  if (result.exitCode !== 0) {
45
- return err('INVALID_BUNDLE', 'opa sign failed.', {
46
- details: { stderr: result.stderr.trim() },
126
+ if (isKeyOrAlgorithmError(`${result.stdout}\n${result.stderr}`)) {
127
+ return err('INVALID_INPUT', 'The signing key or algorithm could not be used.', {
128
+ hint: 'signingKey must be a PEM private key, or for HS256, HS384 and HS512 a file holding the secret, and signingAlg one OPA supports.',
129
+ details: streams,
130
+ });
131
+ }
132
+ return err('INVALID_BUNDLE', 'opa sign failed.', { details: streams });
133
+ }
134
+ // Exit 0 is not the claim; the file is. A signature that was not
135
+ // written, or a stale one from an earlier run, must not be reported
136
+ // as this call's work.
137
+ const after = await lstatOrUndefined(signaturesPath);
138
+ if (after?.isSymbolicLink()) {
139
+ // A link planted between the check above and opa's write has
140
+ // already been followed. Say so, and do not report success.
141
+ const target = await readlink(signaturesPath).catch(() => undefined);
142
+ return err('PATH_NOT_ALLOWED', `${SIGNATURES_FILE} at the output location became a symbolic link while opa ran; the signature may have been written to its target. Not reporting success.`, { details: { signaturesPath, target } });
143
+ }
144
+ const written = after !== undefined &&
145
+ (before === undefined || after.mtimeMs >= startedAt - MTIME_SLACK_MS);
146
+ if (!written) {
147
+ return err('UNKNOWN_ERROR', `opa sign exited 0 but did not write ${SIGNATURES_FILE}.`, {
148
+ details: { signaturesPath, ...streams },
149
+ });
150
+ }
151
+ let summary;
152
+ try {
153
+ summary = await readSignaturesSummary(signaturesPath);
154
+ }
155
+ catch (e) {
156
+ return err('UNKNOWN_ERROR', `opa sign wrote a ${SIGNATURES_FILE} this tool could not read.`, { details: { signaturesPath, error: e instanceof Error ? e.message : String(e) } });
157
+ }
158
+ // A signature over nothing is what an empty directory produces. It
159
+ // verifies nothing and is not worth reporting as success.
160
+ if (summary.filesSigned === 0) {
161
+ return err('INVALID_BUNDLE', 'opa sign covered no files: the bundle is empty.', {
162
+ details: { signaturesPath },
47
163
  });
48
164
  }
49
- return ok({ signed: true });
165
+ const output = {
166
+ signed: true,
167
+ signaturesPath,
168
+ algorithm: summary.algorithm,
169
+ filesSigned: summary.filesSigned,
170
+ };
171
+ if (summary.keyId !== undefined)
172
+ output.keyId = summary.keyId;
173
+ if (summary.scope !== undefined)
174
+ output.scope = summary.scope;
175
+ return ok(output);
50
176
  });
51
177
  });
52
178
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sign.js","sourceRoot":"","sources":["../../../src/tools/bundles/sign.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElG,MAAM,kBAAkB,GAAG;IACzB,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,oEAAoE,CAAC;IACjF,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,0BAA0B,CAAC;IAClE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;IAC7F,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC;CAChG,CAAC;AAOF,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc;IACrE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,oJAAoJ;QACtJ,WAAW,EAAE,kBAAkB;QAC/B,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1B,OAAO,gBAAgB,CAAsB,MAAM,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,UAAU,GAAG,aAAa,CAC9B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACjF,MAAM,EACN,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAC3B;gBACE,MAAM,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAE;gBAC/B,UAAU,EAAE,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAE;gBACnC,UAAU,EAAE,KAAK,CAAC,UAAU;gBAC5B,UAAU,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS;aAClE,EACD,MAAM,CACP,CAAC;YAEF,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,iBAAiB;gBAAE,OAAO,iBAAiB,CAAC;YAEhD,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC1B,OAAO,GAAG,CAAC,gBAAgB,EAAE,kBAAkB,EAAE;oBAC/C,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBAC1C,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAsB,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"sign.js","sourceRoot":"","sources":["../../../src/tools/bundles/sign.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AACnE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB,OAAO,EAAE,qBAAqB,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAC9F,OAAO,EAAE,GAAG,EAAE,EAAE,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,MAAM,EAAkB,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAElG,MAAM,eAAe,GAAG,kBAAkB,CAAC;AAE3C;;;;;GAKG;AACH,MAAM,cAAc,GAAG,IAAI,CAAC;AAE5B,MAAM,kBAAkB,GAAG;IACzB,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,kFAAkF,CAAC;IAC/F,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,+HAA+H,CAChI;IACH,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,kHAAkH,CACnH;IACH,UAAU,EAAE,CAAC;SACV,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,wHAAwH,CACzH;IACH,SAAS,EAAE,CAAC;SACT,MAAM,EAAE;SACR,QAAQ,EAAE;SACV,QAAQ,CACP,mNAAmN,CACpN;CACJ,CAAC;AAcF,2EAA2E;AAC3E,KAAK,UAAU,gBAAgB,CAAC,IAAY;IAC1C,IAAI,CAAC;QACH,OAAO,MAAM,KAAK,CAAC,IAAI,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,MAAiB,EAAE,MAAc;IACrE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,iBAAiB,EACjB;QACE,KAAK,EAAE,iBAAiB;QACxB,WAAW,EACT,gEAAgE;YAChE,iTAAiT;YACjT,yMAAyM;YACzM,oKAAoK;YACpK,2EAA2E;QAC7E,WAAW,EAAE,kBAAkB;QAC/B,WAAW,EAAE;YACX,YAAY,EAAE,KAAK;YACnB,eAAe,EAAE,IAAI;YACrB,cAAc,EAAE,IAAI;YACpB,aAAa,EAAE,KAAK;SACrB;KACF,EACD,KAAK,EAAE,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QAC1B,OAAO,gBAAgB,CAAsB,MAAM,EAAE,KAAK,IAAI,EAAE;YAC9D,MAAM,UAAU,GAAG,aAAa,CAC9B,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,UAAU,EAAE,GAAG,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EACjF,MAAM,EACN,EAAE,SAAS,EAAE,IAAI,EAAE,CACpB,CAAC;YACF,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAC5C,MAAM,CAAC,cAAc,EAAE,WAAW,EAAE,cAAc,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC;YAE1E,iEAAiE;YACjE,kEAAkE;YAClE,sEAAsE;YACtE,gDAAgD;YAChD,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,cAAe,CAAC,CAAC;YACnD,MAAM,WAAW,GAAG,CAAC,MAAM,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;YAE3D,IAAI,SAAiB,CAAC;YACtB,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,KAAK,CAAC,SAAS,KAAK,SAAS,EAAE,CAAC;oBAClC,OAAO,GAAG,CACR,eAAe,EACf,8FAA8F,eAAe,wDAAwD,EACrK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,KAAK,CAAC,MAAM,EAAE,EAAE,CACtC,CAAC;gBACJ,CAAC;gBACD,SAAS,GAAG,UAAU,CAAC;YACzB,CAAC;iBAAM,CAAC;gBACN,iEAAiE;gBACjE,mEAAmE;gBACnE,gEAAgE;gBAChE,mEAAmE;gBACnE,8DAA8D;gBAC9D,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,IAAI,OAAO,CAAC,cAAe,CAAC,CAAC;gBAC9D,MAAM,gBAAgB,GAAG,aAAa,CAAC,CAAC,SAAS,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;gBACjF,IAAI,CAAC,gBAAgB,CAAC,EAAE;oBAAE,OAAO,gBAAgB,CAAC,KAAK,CAAC;gBACxD,SAAS,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC;gBAC1C,IAAI,CAAC,CAAC,MAAM,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;oBAC3C,OAAO,GAAG,CAAC,eAAe,EAAE,0CAA0C,EAAE;wBACtE,OAAO,EAAE,EAAE,SAAS,EAAE;qBACvB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;YAED,MAAM,cAAc,GAAG,IAAI,CAAC,SAAS,EAAE,eAAe,CAAC,CAAC;YAExD,uEAAuE;YACvE,oEAAoE;YACpE,mDAAmD;YACnD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,cAAc,CAAC,CAAC;YACtD,IAAI,MAAM,EAAE,cAAc,EAAE,EAAE,CAAC;gBAC7B,OAAO,GAAG,CACR,kBAAkB,EAClB,GAAG,eAAe,2EAA2E,EAC7F,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,EAAE,CAChC,CAAC;YACJ,CAAC;YACD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAE7B,MAAM,SAAS,GAAc;gBAC3B,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,UAAU;gBACvD,UAAU,EAAE,WAAY;gBACxB,SAAS;aACV,CAAC;YACF,IAAI,WAAW;gBAAE,SAAS,CAAC,GAAG,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YACrD,IAAI,KAAK,CAAC,UAAU,KAAK,SAAS;gBAAE,SAAS,CAAC,UAAU,GAAG,KAAK,CAAC,UAAU,CAAC;YAC5E,IAAI,cAAc,KAAK,SAAS;gBAAE,SAAS,CAAC,UAAU,GAAG,cAAc,CAAC;YACxE,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;YAEjD,MAAM,iBAAiB,GAAG,oBAAoB,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YAC9D,IAAI,iBAAiB;gBAAE,OAAO,iBAAiB,CAAC;YAEhD,iEAAiE;YACjE,MAAM,OAAO,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;YAC/E,IAAI,MAAM,CAAC,QAAQ,KAAK,CAAC,EAAE,CAAC;gBAC1B,IAAI,qBAAqB,CAAC,GAAG,MAAM,CAAC,MAAM,KAAK,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;oBAChE,OAAO,GAAG,CAAC,eAAe,EAAE,iDAAiD,EAAE;wBAC7E,IAAI,EAAE,iIAAiI;wBACvI,OAAO,EAAE,OAAO;qBACjB,CAAC,CAAC;gBACL,CAAC;gBACD,OAAO,GAAG,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;YACzE,CAAC;YAED,iEAAiE;YACjE,oEAAoE;YACpE,uBAAuB;YACvB,MAAM,KAAK,GAAG,MAAM,gBAAgB,CAAC,cAAc,CAAC,CAAC;YACrD,IAAI,KAAK,EAAE,cAAc,EAAE,EAAE,CAAC;gBAC5B,6DAA6D;gBAC7D,4DAA4D;gBAC5D,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,cAAc,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,SAAS,CAAC,CAAC;gBACrE,OAAO,GAAG,CACR,kBAAkB,EAClB,GAAG,eAAe,yIAAyI,EAC3J,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,MAAM,EAAE,EAAE,CACxC,CAAC;YACJ,CAAC;YACD,MAAM,OAAO,GACX,KAAK,KAAK,SAAS;gBACnB,CAAC,MAAM,KAAK,SAAS,IAAI,KAAK,CAAC,OAAO,IAAI,SAAS,GAAG,cAAc,CAAC,CAAC;YACxE,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,OAAO,GAAG,CAAC,eAAe,EAAE,uCAAuC,eAAe,GAAG,EAAE;oBACrF,OAAO,EAAE,EAAE,cAAc,EAAE,GAAG,OAAO,EAAE;iBACxC,CAAC,CAAC;YACL,CAAC;YAED,IAAI,OAAO,CAAC;YACZ,IAAI,CAAC;gBACH,OAAO,GAAG,MAAM,qBAAqB,CAAC,cAAc,CAAC,CAAC;YACxD,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,OAAO,GAAG,CACR,eAAe,EACf,oBAAoB,eAAe,4BAA4B,EAC/D,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,KAAK,EAAE,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACnF,CAAC;YACJ,CAAC;YAED,mEAAmE;YACnE,0DAA0D;YAC1D,IAAI,OAAO,CAAC,WAAW,KAAK,CAAC,EAAE,CAAC;gBAC9B,OAAO,GAAG,CAAC,gBAAgB,EAAE,iDAAiD,EAAE;oBAC9E,OAAO,EAAE,EAAE,cAAc,EAAE;iBAC5B,CAAC,CAAC;YACL,CAAC;YAED,MAAM,MAAM,GAAwB;gBAClC,MAAM,EAAE,IAAI;gBACZ,cAAc;gBACd,SAAS,EAAE,OAAO,CAAC,SAAS;gBAC5B,WAAW,EAAE,OAAO,CAAC,WAAW;aACjC,CAAC;YACF,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YAC9D,IAAI,OAAO,CAAC,KAAK,KAAK,SAAS;gBAAE,MAAM,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;YAC9D,OAAO,EAAE,CAAsB,MAAM,CAAC,CAAC;QACzC,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -2,7 +2,7 @@ import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
2
2
  import type { Config } from '../../config.js';
3
3
  export interface OpaBundleVerifyOutput {
4
4
  bundle: string;
5
- verified: boolean;
5
+ verified: true;
6
6
  }
7
7
  export declare function registerOpaBundleVerify(server: McpServer, config: Config): void;
8
8
  //# sourceMappingURL=verify.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/tools/bundles/verify.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAsC9C,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAqD/E"}
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../../src/tools/bundles/verify.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA6C9C,MAAM,WAAW,qBAAqB;IACpC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,IAAI,CAAC;CAChB;AAED,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAiF/E"}
@@ -1,10 +1,19 @@
1
1
  /**
2
- * `opa_bundle_verify` -- verify the cryptographic signature of a signed
3
- * OPA bundle via `opa eval --bundle --verification-key`.
2
+ * `opa_bundle_verify` -- verify the signature of a signed OPA bundle.
3
+ *
4
+ * OPA has no standalone verify command. The check runs as
5
+ * `opa build --verification-key` into a temp file that is discarded; see
6
+ * `OpaCli.bundleVerify`. A directory is verified by name from its parent, the
7
+ * same way `opa_bundle_sign` signs it. OPA reports the first failure it hits,
8
+ * and the reason is classified into `details.reason` so a caller can tell a
9
+ * wrong key from a tampered file.
4
10
  */
11
+ import { realpath, stat } from 'node:fs/promises';
12
+ import { basename, dirname } from 'node:path';
5
13
  import { z } from 'zod';
6
- import { OpaCli } from '../../lib/opa-cli.js';
14
+ import { classifyVerificationFailure } from '../../lib/bundle-signatures.js';
7
15
  import { err, ok } from '../../lib/errors.js';
16
+ import { OpaCli } from '../../lib/opa-cli.js';
8
17
  import { mapSubprocessFailure, validatePaths, withToolEnvelope } from '../../lib/tool-helpers.js';
9
18
  const OpaBundleVerifyInput = {
10
19
  bundle: z
@@ -14,11 +23,11 @@ const OpaBundleVerifyInput = {
14
23
  verificationKey: z
15
24
  .string()
16
25
  .min(1)
17
- .describe('Path to the PEM file containing the RSA or ECDSA public key, or the path to the HMAC secret file. Must be inside an allowed root.'),
26
+ .describe('Path to the PEM file containing the RSA or ECDSA public key, or for HMAC algorithms a file holding the secret. Must be inside an allowed root.'),
18
27
  verificationKeyId: z
19
28
  .string()
20
29
  .optional()
21
- .describe('Key ID that must match the `keyid` field in the bundle signature. Required when the bundle was signed with `--public-key-id`.'),
30
+ .describe('Name the key is registered under for OPA (`--verification-key-id`, default `default`). With a single key OPA verifies against it regardless of the signature keyid claim, so this rarely needs setting.'),
22
31
  signingAlg: z
23
32
  .string()
24
33
  .optional()
@@ -26,13 +35,24 @@ const OpaBundleVerifyInput = {
26
35
  scope: z
27
36
  .string()
28
37
  .optional()
29
- .describe('Expected `scope` value in the bundle signature. Required when the bundle was signed with `--scope`.'),
38
+ .describe('Expected `scope` claim in the signature. Pass exactly the value the bundle was signed with, and nothing if it was signed without one; the failure reason is scope_mismatch otherwise.'),
39
+ v0Compatible: z
40
+ .boolean()
41
+ .optional()
42
+ .describe('Load the bundle as Rego v0 (`--v0-compatible`). A policy written before Rego v1 otherwise fails to load, after the signature and digests have already been checked.'),
30
43
  };
31
44
  export function registerOpaBundleVerify(server, config) {
32
45
  const opa = new OpaCli(config);
33
46
  server.registerTool('opa_bundle_verify', {
34
47
  title: 'Verify OPA bundle signature',
35
- description: 'Verify the cryptographic signature of a signed OPA bundle using `opa eval --bundle --verification-key`. The bundle must have been signed with `opa sign` (or `opa_bundle_sign`). OPA checks the `.signatures.json` manifest inside the bundle against the provided public key before loading any policy -- a tampered or unsigned bundle will fail with `INVALID_BUNDLE`. Returns `{ bundle, verified: true }` on success.',
48
+ description: 'Verify the signature of a signed bundle directory or `.tar.gz` archive with the public key. ' +
49
+ 'OPA has no standalone verify command, so this runs `opa build --verification-key` into a private temp file that is discarded. ' +
50
+ 'A directory is verified by name from its parent, matching how `opa_bundle_sign` signs it. ' +
51
+ 'OPA reads the key, checks the JWT in `.signatures.json`, compares the scope claim, then checks every file: Rego files by digest before parsing, data files and `.manifest` by parsed value, so an unparseable data file fails before its digest is compared. ' +
52
+ 'Failures return `INVALID_BUNDLE` with `details.reason` set to one of signature_invalid, scope_mismatch, file_modified, file_added, file_missing, file_unparseable, unsigned, signatures_malformed, not_a_bundle, bundle_load_error, or unknown when the message is not recognised; the raw output is in `details`. ' +
53
+ 'A key or algorithm OPA cannot use returns `INVALID_INPUT`. ' +
54
+ 'Pass `scope` exactly as the bundle was signed with. With a single key OPA does not check `verificationKeyId` against the signature keyid claim. ' +
55
+ '`verified: true` is returned only when OPA loaded the bundle with its signature intact.',
36
56
  inputSchema: OpaBundleVerifyInput,
37
57
  annotations: {
38
58
  readOnlyHint: true,
@@ -48,23 +68,42 @@ export function registerOpaBundleVerify(server, config) {
48
68
  if (!validation.ok)
49
69
  return validation.error;
50
70
  const [resolvedBundle, resolvedKey] = validation.resolved;
51
- const result = await opa.bundleVerify({
52
- bundle: resolvedBundle,
71
+ // Same resolution as the sign tool: OPA does not descend a symlink or
72
+ // junction root, and a directory's signature names files under the
73
+ // directory name, so a directory is loaded by name from its parent.
74
+ const realBundle = await realpath(resolvedBundle);
75
+ const isDirectory = (await stat(realBundle)).isDirectory();
76
+ const verifyInput = {
77
+ bundle: isDirectory ? basename(realBundle) : realBundle,
53
78
  verificationKey: resolvedKey,
54
- verificationKeyId: input.verificationKeyId,
55
- signingAlg: input.signingAlg,
56
- scope: input.scope,
57
- }, signal);
79
+ };
80
+ if (isDirectory)
81
+ verifyInput.cwd = dirname(realBundle);
82
+ if (input.verificationKeyId !== undefined) {
83
+ verifyInput.verificationKeyId = input.verificationKeyId;
84
+ }
85
+ if (input.signingAlg !== undefined)
86
+ verifyInput.signingAlg = input.signingAlg;
87
+ if (input.scope !== undefined)
88
+ verifyInput.scope = input.scope;
89
+ if (input.v0Compatible)
90
+ verifyInput.v0Compatible = true;
91
+ const result = await opa.bundleVerify(verifyInput, signal);
58
92
  const subprocessFailure = mapSubprocessFailure(result, 'opa');
59
93
  if (subprocessFailure)
60
94
  return subprocessFailure;
61
95
  if (result.exitCode !== 0) {
62
- return err('INVALID_BUNDLE', 'Bundle signature verification failed.', {
63
- details: {
64
- stderr: result.stderr.trim(),
65
- stdout: result.stdout.trim(),
66
- },
67
- });
96
+ // opa build prints the reason on stdout, not stderr.
97
+ const failure = classifyVerificationFailure(`${result.stdout}\n${result.stderr}`);
98
+ const details = {
99
+ reason: failure.reason,
100
+ stdout: result.stdout.trim(),
101
+ stderr: result.stderr.trim(),
102
+ };
103
+ if (failure.reason === 'key_invalid') {
104
+ return err('INVALID_INPUT', `The verification key or algorithm could not be used: ${failure.summary}.`, { hint: failure.hint, details });
105
+ }
106
+ return err('INVALID_BUNDLE', `Bundle signature verification failed: ${failure.summary}.`, { hint: failure.hint, details });
68
107
  }
69
108
  return ok({ bundle: input.bundle, verified: true });
70
109
  });
@@ -1 +1 @@
1
- {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/tools/bundles/verify.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../../src/tools/bundles/verify.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/tools/conftest/pull.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA0B9C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CA0D5E"}
1
+ {"version":3,"file":"pull.d.ts","sourceRoot":"","sources":["../../../src/tools/conftest/pull.ts"],"names":[],"mappings":"AAwBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA4B9C,MAAM,WAAW,kBAAkB;IACjC,+BAA+B;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAuE5E"}
@@ -17,6 +17,8 @@
17
17
  * 0 -- pull succeeded
18
18
  * non-0 -- network / auth error
19
19
  */
20
+ import { mkdir } from 'node:fs/promises';
21
+ import { dirname, resolve } from 'node:path';
20
22
  import { z } from 'zod';
21
23
  import { ConftestCli } from '../../lib/conftest-cli.js';
22
24
  import { err, ok } from '../../lib/errors.js';
@@ -35,8 +37,12 @@ const ConftestPullInput = {
35
37
  .optional()
36
38
  .describe('Local directory where the pulled policies will be written. ' +
37
39
  'Must be inside an allowed root (OPA_MCP_ALLOWED_PATHS). ' +
38
- "Defaults to `./policy` (conftest's convention)."),
40
+ 'Omitted, it falls back to `policy` in the working directory of the server process, the conftest convention, which must itself sit inside an allowed root. ' +
41
+ 'The directory is emptied before the pull, so do not point it at one holding anything ' +
42
+ 'you want to keep.'),
39
43
  };
44
+ /** Where conftest looks when `--policy` is not given, as an absolute path. */
45
+ const DEFAULT_POLICY_DIR = resolve('policy');
40
46
  export function registerConftestPull(server, config) {
41
47
  const conftest = new ConftestCli(config);
42
48
  server.registerTool('conftest_pull', {
@@ -59,24 +65,32 @@ export function registerConftestPull(server, config) {
59
65
  }, async (input, { signal }) => {
60
66
  return withToolEnvelope(config, async () => {
61
67
  // ── Path validation ──────────────────────────────────────────────
62
- // The policy directory does not have to exist yet -- conftest will
63
- // create it. Validate only that the parent is within allowed roots
64
- // by validating the path itself (without mustExist).
65
- if (input.policy !== undefined) {
66
- const v = validatePaths([input.policy], config);
67
- if (!v.ok)
68
+ // The directory does not have to exist yet; conftest creates it. An
69
+ // omitted path means conftest's own default, which it resolves against
70
+ // the working directory. This tool writes files, so that default is
71
+ // checked against the allow-list too rather than escaping it by being
72
+ // implicit.
73
+ const v = validatePaths([input.policy ?? DEFAULT_POLICY_DIR], config);
74
+ if (!v.ok) {
75
+ if (input.policy !== undefined)
68
76
  return v.error;
69
- input = { ...input, policy: v.resolved[0] };
77
+ return err('PATH_NOT_ALLOWED', 'The conftest default policy directory is outside the allowed roots.', {
78
+ hint: 'Pass `policy` with a directory inside OPA_MCP_ALLOWED_PATHS.',
79
+ details: { defaultPolicyDir: DEFAULT_POLICY_DIR },
80
+ });
70
81
  }
82
+ const policyDir = v.resolved[0];
83
+ // conftest runs from the parent, so the parent has to exist.
84
+ await mkdir(dirname(policyDir), { recursive: true });
71
85
  // ── Run conftest pull ────────────────────────────────────────────
72
- const result = await conftest.pull({ url: input.url, policy: input.policy }, signal);
86
+ const result = await conftest.pull({ url: input.url, policy: policyDir }, signal);
73
87
  const subprocessFailure = mapSubprocessFailure(result, 'conftest');
74
88
  if (subprocessFailure)
75
89
  return subprocessFailure;
76
90
  if (result.exitCode === 0) {
77
91
  return ok({
78
92
  url: input.url,
79
- policyDir: input.policy ?? 'policy',
93
+ policyDir,
80
94
  });
81
95
  }
82
96
  const detail = result.stderr.trim() || result.stdout.trim();
@@ -1 +1 @@
1
- {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/tools/conftest/pull.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pull.js","sourceRoot":"","sources":["../../../src/tools/conftest/pull.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/tools/conftest/push.ts"],"names":[],"mappings":"AAiBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAyB9C,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAuD5E"}
1
+ {"version":3,"file":"push.d.ts","sourceRoot":"","sources":["../../../src/tools/conftest/push.ts"],"names":[],"mappings":"AAmBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAyB9C,MAAM,WAAW,kBAAkB;IACjC,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,+DAA+D;IAC/D,SAAS,EAAE,MAAM,CAAC;CACnB;AAKD,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAkE5E"}
@@ -14,6 +14,7 @@
14
14
  * non-0 -- push error (auth failure, network error, etc.)
15
15
  */
16
16
  import { z } from 'zod';
17
+ import { resolve } from 'node:path';
17
18
  import { ConftestCli } from '../../lib/conftest-cli.js';
18
19
  import { err, ok } from '../../lib/errors.js';
19
20
  import { mapSubprocessFailure, validatePaths, withToolEnvelope } from '../../lib/tool-helpers.js';
@@ -30,8 +31,10 @@ const ConftestPushInput = {
30
31
  .optional()
31
32
  .describe('Path to the local directory containing Rego policies to push. ' +
32
33
  'Must be inside an allowed root (OPA_MCP_ALLOWED_PATHS) and must exist. ' +
33
- "Defaults to `./policy` (conftest's convention)."),
34
+ 'Omitted, it falls back to `policy` in the working directory of the server process, the conftest convention, which must itself sit inside an allowed root.'),
34
35
  };
36
+ /** Where conftest looks when `--policy` is not given, as an absolute path. */
37
+ const DEFAULT_POLICY_DIR = resolve('policy');
35
38
  export function registerConftestPush(server, config) {
36
39
  const conftest = new ConftestCli(config);
37
40
  server.registerTool('conftest_push', {
@@ -51,21 +54,28 @@ export function registerConftestPush(server, config) {
51
54
  }, async (input, { signal }) => {
52
55
  return withToolEnvelope(config, async () => {
53
56
  // ── Path validation ──────────────────────────────────────────────
54
- if (input.policy !== undefined) {
55
- const v = validatePaths([input.policy], config, { mustExist: true });
56
- if (!v.ok)
57
+ // An omitted path means the conftest default, resolved against the
58
+ // working directory. This publishes whatever it finds there, so the
59
+ // default is checked against the allow-list like an explicit one.
60
+ const v = validatePaths([input.policy ?? DEFAULT_POLICY_DIR], config, { mustExist: true });
61
+ if (!v.ok) {
62
+ if (input.policy !== undefined)
57
63
  return v.error;
58
- input = { ...input, policy: v.resolved[0] };
64
+ return err('PATH_NOT_ALLOWED', 'The conftest default policy directory is outside the allowed roots.', {
65
+ hint: 'Pass `policy` with a directory inside OPA_MCP_ALLOWED_PATHS.',
66
+ details: { defaultPolicyDir: DEFAULT_POLICY_DIR },
67
+ });
59
68
  }
69
+ const policyDir = v.resolved[0];
60
70
  // ── Run conftest push ────────────────────────────────────────────
61
- const result = await conftest.push({ repository: input.repository, policy: input.policy }, signal);
71
+ const result = await conftest.push({ repository: input.repository, policy: policyDir }, signal);
62
72
  const subprocessFailure = mapSubprocessFailure(result, 'conftest');
63
73
  if (subprocessFailure)
64
74
  return subprocessFailure;
65
75
  if (result.exitCode === 0) {
66
76
  return ok({
67
77
  repository: input.repository,
68
- policyDir: input.policy ?? 'policy',
78
+ policyDir,
69
79
  });
70
80
  }
71
81
  const detail = result.stderr.trim() || result.stdout.trim();