@orygn/opa-mcp 0.1.2 → 0.1.3
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 +37 -1
- package/README.md +62 -23
- package/dist/config.d.ts +1 -1
- package/dist/config.js +2 -2
- package/dist/constants.d.ts +8 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +8 -0
- package/dist/constants.js.map +1 -0
- package/dist/lib/errors.d.ts +1 -1
- package/dist/lib/logger.js +2 -2
- package/dist/lib/logger.js.map +1 -1
- package/dist/lib/opa-cli.d.ts +3 -3
- package/dist/lib/opa-cli.js +4 -4
- package/dist/lib/opa-client.d.ts +1 -1
- package/dist/lib/regal-cli.d.ts +4 -4
- package/dist/lib/regal-cli.js +5 -5
- package/dist/lib/subprocess.d.ts +1 -1
- package/dist/lib/subprocess.js +2 -2
- package/dist/lib/tool-helpers.d.ts +1 -1
- package/dist/prompts/index.js +6 -6
- package/dist/prompts/index.js.map +1 -1
- package/dist/resources/index.d.ts +4 -4
- package/dist/resources/patterns.d.ts +1 -1
- package/dist/resources/patterns.d.ts.map +1 -1
- package/dist/resources/patterns.js +7 -7
- package/dist/resources/style-guide.d.ts +1 -1
- package/dist/resources/style-guide.d.ts.map +1 -1
- package/dist/resources/style-guide.js +3 -3
- package/dist/server.d.ts +2 -2
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +4 -4
- package/dist/server.js.map +1 -1
- package/dist/tools/authoring/capabilities.js +1 -1
- package/dist/tools/authoring/check.js +3 -3
- package/dist/tools/authoring/check.js.map +1 -1
- package/dist/tools/authoring/deps.js +2 -2
- package/dist/tools/authoring/deps.js.map +1 -1
- package/dist/tools/authoring/format.js +1 -1
- package/dist/tools/authoring/index.d.ts +1 -1
- package/dist/tools/authoring/inspect.js +2 -2
- package/dist/tools/authoring/inspect.js.map +1 -1
- package/dist/tools/authoring/lint.js +1 -1
- package/dist/tools/authoring/parse.js +1 -1
- package/dist/tools/bundles/build.js +1 -1
- package/dist/tools/bundles/index.d.ts +1 -1
- package/dist/tools/bundles/sign.js +1 -1
- package/dist/tools/evaluation/_shared.d.ts +1 -1
- package/dist/tools/evaluation/_shared.js +1 -1
- package/dist/tools/evaluation/bench.js +1 -1
- package/dist/tools/evaluation/compile.d.ts +2 -2
- package/dist/tools/evaluation/compile.js +1 -1
- package/dist/tools/evaluation/compile.js.map +1 -1
- package/dist/tools/evaluation/eval.d.ts +2 -2
- package/dist/tools/evaluation/eval.js +1 -1
- package/dist/tools/evaluation/eval.js.map +1 -1
- package/dist/tools/evaluation/index.d.ts +1 -1
- package/dist/tools/evaluation/test.js +1 -1
- package/dist/tools/helpers/coverage-gaps.d.ts +29 -0
- package/dist/tools/helpers/coverage-gaps.d.ts.map +1 -0
- package/dist/tools/helpers/coverage-gaps.js +125 -0
- package/dist/tools/helpers/coverage-gaps.js.map +1 -0
- package/dist/tools/helpers/describe-policy.js +1 -1
- package/dist/tools/helpers/explain-decision.d.ts +1 -1
- package/dist/tools/helpers/explain-decision.js +1 -1
- package/dist/tools/helpers/explain-decision.js.map +1 -1
- package/dist/tools/helpers/generate-test-skeleton.js +3 -3
- package/dist/tools/helpers/generate-test-skeleton.js.map +1 -1
- package/dist/tools/helpers/index.d.ts +1 -1
- package/dist/tools/helpers/index.d.ts.map +1 -1
- package/dist/tools/helpers/index.js +4 -0
- package/dist/tools/helpers/index.js.map +1 -1
- package/dist/tools/helpers/security-audit.d.ts +21 -0
- package/dist/tools/helpers/security-audit.d.ts.map +1 -0
- package/dist/tools/helpers/security-audit.js +111 -0
- package/dist/tools/helpers/security-audit.js.map +1 -0
- package/dist/tools/helpers/suggest-fix.js +6 -6
- package/dist/tools/helpers/suggest-fix.js.map +1 -1
- package/dist/tools/index.d.ts +9 -6
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/meta/index.d.ts +10 -0
- package/dist/tools/meta/index.d.ts.map +1 -0
- package/dist/tools/meta/index.js +5 -0
- package/dist/tools/meta/index.js.map +1 -0
- package/dist/tools/meta/server-info.d.ts +17 -0
- package/dist/tools/meta/server-info.d.ts.map +1 -0
- package/dist/tools/meta/server-info.js +30 -0
- package/dist/tools/meta/server-info.js.map +1 -0
- package/dist/tools/server-management/data.js +1 -1
- package/dist/tools/server-management/data.js.map +1 -1
- package/dist/tools/server-management/decisions.js +1 -1
- package/dist/tools/server-management/decisions.js.map +1 -1
- package/dist/tools/server-management/index.d.ts +1 -1
- package/dist/tools/server-management/policies.js +1 -1
- package/dist/tools/server-management/policies.js.map +1 -1
- package/dist/tools/server-management/status.js +2 -2
- package/dist/tools/server-management/status.js.map +1 -1
- package/package.json +1 -1
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
export const PATTERNS = `# Rego pattern library
|
|
9
9
|
|
|
10
10
|
Common Rego patterns with working examples, tests, and pitfalls. Each
|
|
11
|
-
pattern is self-contained
|
|
11
|
+
pattern is self-contained -- copy, adapt, and ship.
|
|
12
12
|
|
|
13
13
|
---
|
|
14
14
|
|
|
@@ -25,7 +25,7 @@ import rego.v1
|
|
|
25
25
|
|
|
26
26
|
default allow := false
|
|
27
27
|
|
|
28
|
-
# Permissions table
|
|
28
|
+
# Permissions table -- extend as roles evolve.
|
|
29
29
|
permissions := {
|
|
30
30
|
"admin": {"read", "write", "delete", "manage_users"},
|
|
31
31
|
"editor": {"read", "write"},
|
|
@@ -37,7 +37,7 @@ allow if {
|
|
|
37
37
|
input.action in permissions[role]
|
|
38
38
|
}
|
|
39
39
|
|
|
40
|
-
# Why was it denied?
|
|
40
|
+
# Why was it denied? -- useful for audit logs.
|
|
41
41
|
deny_reasons contains reason if {
|
|
42
42
|
not allow
|
|
43
43
|
input.user
|
|
@@ -91,7 +91,7 @@ test_anonymous_denied if {
|
|
|
91
91
|
|
|
92
92
|
## 2. Attribute-based access control (ABAC)
|
|
93
93
|
|
|
94
|
-
**When to use:** when "who" alone isn't enough
|
|
94
|
+
**When to use:** when "who" alone isn't enough -- decisions also depend
|
|
95
95
|
on resource attributes (ownership, tenant, sensitivity) and context
|
|
96
96
|
(time of day, source IP).
|
|
97
97
|
|
|
@@ -250,7 +250,7 @@ deny contains msg if {
|
|
|
250
250
|
**Pitfalls:**
|
|
251
251
|
- Terraform plan JSON is verbose and version-specific. Pin the
|
|
252
252
|
\`terraform plan -json\` schema you target.
|
|
253
|
-
- \`resource_changes[_].change.after\` may be \`null\` for destroys
|
|
253
|
+
- \`resource_changes[_].change.after\` may be \`null\` for destroys --
|
|
254
254
|
guard against it.
|
|
255
255
|
- For wide-radius changes, use \`opa exec --decision\` against a plan
|
|
256
256
|
file in CI, not the live API.
|
|
@@ -270,7 +270,7 @@ import rego.v1
|
|
|
270
270
|
|
|
271
271
|
default allow := false
|
|
272
272
|
|
|
273
|
-
# Public endpoints
|
|
273
|
+
# Public endpoints -- no auth required.
|
|
274
274
|
public_endpoints := {
|
|
275
275
|
{"method": "GET", "path": ["health"]},
|
|
276
276
|
{"method": "GET", "path": ["version"]},
|
|
@@ -353,7 +353,7 @@ deny_reason := sprintf(
|
|
|
353
353
|
**Pitfalls:**
|
|
354
354
|
- \`data.requests\` grows unbounded unless the writer prunes outside the
|
|
355
355
|
window. Schedule prune on every write.
|
|
356
|
-
- This pattern is *advisory*
|
|
356
|
+
- This pattern is *advisory* -- under load, two concurrent decisions
|
|
357
357
|
can both see \`count == limit - 1\` and both allow. For strict
|
|
358
358
|
limits, use a Lua/Redis token bucket at the gateway and have OPA
|
|
359
359
|
validate the token, not count requests.
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Curated Rego style guide. Adapted from the Styra reference plus the
|
|
3
3
|
* OPA team's own conventions, condensed for LLM consumption.
|
|
4
4
|
*/
|
|
5
|
-
export declare const STYLE_GUIDE = "# Rego style guide\n\nA condensed reference for writing idiomatic, maintainable Rego. Adapted\nfrom the Styra style guide and the OPA project's conventions.\n\n## Always import `rego.v1`\n\nEvery `.rego` file should start with the v1 import. It enables the\nmodern syntax (`if`, `contains`, `every`) and disables the older\nimplicit-membership operator that's a frequent source of bugs.\n\n```rego\npackage authz\n\nimport rego.v1\n```\n\nOPA 1.0 (released January 2025) treats this as the default, but\nincluding it explicitly makes intent clear and keeps the file portable\nto older OPA installations.\n\n## Package layout mirrors directory layout\n\nMatch `package foo.bar` with the file path `foo/bar/main.rego` (or\n`foo/bar/<anything>.rego`). Regal flags mismatches as\n`directory-package-mismatch`.\n\nFor a multi-file package, group by responsibility:\n\n```\nauthz/\n main.rego # principal decision (allow / deny)\n rbac.rego # role-based access checks\n abac.rego # attribute-based access checks\n helpers.rego # shared helpers, no decisions\n main_test.rego # tests for principal decisions\n rbac_test.rego # tests for rbac\n```\n\nTests live in `*_test.rego` siblings of the source they test, in the\nsame package or a `<package>_test` package.\n\n## Naming\n\n- Rule names: `snake_case`.\n- Boolean rules: read like predicates
|
|
5
|
+
export declare const STYLE_GUIDE = "# Rego style guide\n\nA condensed reference for writing idiomatic, maintainable Rego. Adapted\nfrom the Styra style guide and the OPA project's conventions.\n\n## Always import `rego.v1`\n\nEvery `.rego` file should start with the v1 import. It enables the\nmodern syntax (`if`, `contains`, `every`) and disables the older\nimplicit-membership operator that's a frequent source of bugs.\n\n```rego\npackage authz\n\nimport rego.v1\n```\n\nOPA 1.0 (released January 2025) treats this as the default, but\nincluding it explicitly makes intent clear and keeps the file portable\nto older OPA installations.\n\n## Package layout mirrors directory layout\n\nMatch `package foo.bar` with the file path `foo/bar/main.rego` (or\n`foo/bar/<anything>.rego`). Regal flags mismatches as\n`directory-package-mismatch`.\n\nFor a multi-file package, group by responsibility:\n\n```\nauthz/\n main.rego # principal decision (allow / deny)\n rbac.rego # role-based access checks\n abac.rego # attribute-based access checks\n helpers.rego # shared helpers, no decisions\n main_test.rego # tests for principal decisions\n rbac_test.rego # tests for rbac\n```\n\nTests live in `*_test.rego` siblings of the source they test, in the\nsame package or a `<package>_test` package.\n\n## Naming\n\n- Rule names: `snake_case`.\n- Boolean rules: read like predicates -- `allow`, `is_admin`,\n `should_log`. Avoid `is_not_blocked` (double negative).\n- Set/object rules: read like nouns -- `grants`, `roles`, `reasons`.\n- Helper rules: `_` prefix is *not* a convention; just give them names\n that explain what they return.\n\nNames that conflict with reserved words (`type`, `time`, `input`) won't\nparse. Names matching builtins (`http`, `json`) shadow them.\n\n## Default deny\n\nEvery principal decision should have a default fallback so the policy\nreturns a value even when no rule matches.\n\n```rego\ndefault allow := false\n\nallow if {\n input.user.role == \"admin\"\n}\n```\n\nThe same applies to set-valued reasons:\n\n```rego\ndeny contains reason if {\n not allow\n reason := \"not authorized\"\n}\n```\n\n## Comprehensions vs `every`\n\nWhen you need a value derived from a collection, use a comprehension:\n\n```rego\nadmin_users := {u | some u in input.users; u.role == \"admin\"}\n```\n\nWhen you need to assert that a property holds for every element, use\n`every` (introduced in OPA 0.41):\n\n```rego\nallow if {\n every claim in input.token.claims {\n claim.verified == true\n }\n}\n```\n\n`every` is clearer than the older `not <comprehension>` idiom and\nshort-circuits on the first failure.\n\n## Annotations\n\nPublic rules deserve a metadata block so consumers know what they do.\n\n```rego\n# METADATA\n# title: Authorization decision for HTTP requests\n# description: |\n# Returns true when the requesting principal has a role with a\n# permission entry for the requested action on the requested\n# resource. Anonymous requests always deny.\n# entrypoint: true\nallow if {\n some role in input.principal.roles\n permission_grants[role][input.action]\n}\n```\n\nAnnotations show up in `opa inspect`, the registry, and editor\nhovers. They are also extracted by `rego_describe_policy`.\n\n## Schema annotations\n\nFor policies that are sensitive to input shape, attach a JSON Schema:\n\n```rego\n# METADATA\n# schemas:\n# - input: schema.input\nallow if {\n input.user.id != \"\"\n}\n```\n\nCombined with `opa check --schema`, this turns input-shape mismatches\ninto compile errors instead of runtime undefineds.\n\n## Anti-patterns\n\n- **`http.send` in the decision path.** Each call adds round-trip\n latency. If you must, scope it to a small, cacheable read.\n- **Deep `with` chains.** `x with input as ... with data as ...` more\n than two layers deep is a smell -- the test is doing too much. Split.\n- **`print` and `trace`.** Useful in development; remove before\n shipping. Regal flags both as `print-or-trace-call`.\n- **Mixing `if` and the legacy implicit form in the same file.** Pick\n one. With `rego.v1` imported you cannot use the implicit form.\n\n## Tests\n\n`opa test` runs every rule whose name starts with `test_`. A test\neither evaluates to true (pass) or fails to evaluate (fail). The\ncommon shape:\n\n```rego\npackage authz_test\n\nimport rego.v1\nimport data.authz\n\ntest_admin_can_delete if {\n authz.allow with input as {\n \"user\": {\"role\": \"admin\"},\n \"action\": \"delete\",\n }\n}\n\ntest_viewer_cannot_delete if {\n not authz.allow with input as {\n \"user\": {\"role\": \"viewer\"},\n \"action\": \"delete\",\n }\n}\n```\n\nRun with `opa test -v ./...` for verbose output. Add `--coverage` to\nverify which lines were exercised.\n\n## References\n\n- Official Rego style guide: https://docs.styra.com/regal/rego-style-guide\n- OPA documentation: https://www.openpolicyagent.org/docs/latest/\n- Regal linter rules: https://docs.styra.com/regal/rules\n";
|
|
6
6
|
//# sourceMappingURL=style-guide.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"style-guide.d.ts","sourceRoot":"","sources":["../../src/resources/style-guide.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW
|
|
1
|
+
{"version":3,"file":"style-guide.d.ts","sourceRoot":"","sources":["../../src/resources/style-guide.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,eAAO,MAAM,WAAW,m6JAqLvB,CAAC"}
|
|
@@ -47,9 +47,9 @@ same package or a \`<package>_test\` package.
|
|
|
47
47
|
## Naming
|
|
48
48
|
|
|
49
49
|
- Rule names: \`snake_case\`.
|
|
50
|
-
- Boolean rules: read like predicates
|
|
50
|
+
- Boolean rules: read like predicates -- \`allow\`, \`is_admin\`,
|
|
51
51
|
\`should_log\`. Avoid \`is_not_blocked\` (double negative).
|
|
52
|
-
- Set/object rules: read like nouns
|
|
52
|
+
- Set/object rules: read like nouns -- \`grants\`, \`roles\`, \`reasons\`.
|
|
53
53
|
- Helper rules: \`_\` prefix is *not* a convention; just give them names
|
|
54
54
|
that explain what they return.
|
|
55
55
|
|
|
@@ -142,7 +142,7 @@ into compile errors instead of runtime undefineds.
|
|
|
142
142
|
- **\`http.send\` in the decision path.** Each call adds round-trip
|
|
143
143
|
latency. If you must, scope it to a small, cacheable read.
|
|
144
144
|
- **Deep \`with\` chains.** \`x with input as ... with data as ...\` more
|
|
145
|
-
than two layers deep is a smell
|
|
145
|
+
than two layers deep is a smell -- the test is doing too much. Split.
|
|
146
146
|
- **\`print\` and \`trace\`.** Useful in development; remove before
|
|
147
147
|
shipping. Regal flags both as \`print-or-trace-call\`.
|
|
148
148
|
- **Mixing \`if\` and the legacy implicit form in the same file.** Pick
|
package/dist/server.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
3
3
|
import type { Transport } from '@modelcontextprotocol/sdk/shared/transport.js';
|
|
4
4
|
import { type Config } from './config.js';
|
|
5
|
-
|
|
6
|
-
export
|
|
5
|
+
import { SERVER_NAME, SERVER_VERSION } from './constants.js';
|
|
6
|
+
export { SERVER_NAME, SERVER_VERSION };
|
|
7
7
|
/**
|
|
8
8
|
* Construct an `McpServer`, register every tool / prompt / resource
|
|
9
9
|
* onto it, and return it. Exported for tests so they can drive a
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AAYA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,+CAA+C,CAAC;AAE/E,OAAO,EAAc,KAAK,MAAM,EAAE,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAQ7D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,CAAC;AAEvC;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAoBrD;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA4BvE;AAED;;;;;;;GAOG;AACH,wBAAsB,IAAI,CAAC,SAAS,CAAC,EAAE,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,CAepE"}
|
package/dist/server.js
CHANGED
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
/**
|
|
3
|
-
* @orygn/opa-mcp
|
|
3
|
+
* @orygn/opa-mcp -- entry point.
|
|
4
4
|
*
|
|
5
5
|
* Initializes the MCP server, registers tools/prompts/resources,
|
|
6
6
|
* and connects the stdio transport.
|
|
7
7
|
*
|
|
8
|
-
* IMPORTANT: never write to stdout from anywhere in this process
|
|
8
|
+
* IMPORTANT: never write to stdout from anywhere in this process --
|
|
9
9
|
* stdout is the MCP protocol channel. Use `logger` (file) or stderr.
|
|
10
10
|
*/
|
|
11
11
|
import { pathToFileURL } from 'node:url';
|
|
12
12
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
13
13
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
14
14
|
import { loadConfig } from './config.js';
|
|
15
|
+
import { SERVER_NAME, SERVER_VERSION } from './constants.js';
|
|
15
16
|
import { initLogger, logger } from './lib/logger.js';
|
|
16
17
|
import { OpaCli } from './lib/opa-cli.js';
|
|
17
18
|
import { RegalCli } from './lib/regal-cli.js';
|
|
18
19
|
import { registerPrompts } from './prompts/index.js';
|
|
19
20
|
import { registerResources } from './resources/index.js';
|
|
20
21
|
import { registerTools } from './tools/index.js';
|
|
21
|
-
export
|
|
22
|
-
export const SERVER_VERSION = '0.1.2';
|
|
22
|
+
export { SERVER_NAME, SERVER_VERSION };
|
|
23
23
|
/**
|
|
24
24
|
* Construct an `McpServer`, register every tool / prompt / resource
|
|
25
25
|
* onto it, and return it. Exported for tests so they can drive a
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,oBAAoB,EAAE,MAAM,2CAA2C,CAAC;AAGjF,OAAO,EAAE,UAAU,EAAe,MAAM,aAAa,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,kBAAkB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACzD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEjD,
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rego_capabilities`
|
|
2
|
+
* `rego_capabilities` -- list OPA's built-in functions and feature flags.
|
|
3
3
|
*
|
|
4
4
|
* Useful as a reference when authoring policies, especially for
|
|
5
5
|
* answering "is `crypto.x509.parse_certificates` available?" without
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rego_check`
|
|
2
|
+
* `rego_check` -- type-check Rego using `opa check`.
|
|
3
3
|
*
|
|
4
4
|
* Returns `{ valid: true }` when the policy passes. On failure,
|
|
5
5
|
* returns the structured error report `opa check --format=json` writes
|
|
@@ -18,7 +18,7 @@ const RegoCheckInput = {
|
|
|
18
18
|
strict: z
|
|
19
19
|
.boolean()
|
|
20
20
|
.optional()
|
|
21
|
-
.describe('Enable strict mode
|
|
21
|
+
.describe('Enable strict mode -- fail on unused vars, deprecated builtins, etc.'),
|
|
22
22
|
capabilities: z
|
|
23
23
|
.string()
|
|
24
24
|
.optional()
|
|
@@ -37,7 +37,7 @@ export function registerRegoCheck(server, config) {
|
|
|
37
37
|
return err('INVALID_INPUT', 'rego_check requires either `source` or at least one entry in `paths`.');
|
|
38
38
|
}
|
|
39
39
|
if (source && paths?.length) {
|
|
40
|
-
return err('INVALID_INPUT', 'rego_check does not accept both `source` and `paths`
|
|
40
|
+
return err('INVALID_INPUT', 'rego_check does not accept both `source` and `paths` -- pass one or the other.');
|
|
41
41
|
}
|
|
42
42
|
let resolvedPaths;
|
|
43
43
|
if (paths?.length) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/tools/authoring/check.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;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,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,cAAc,GAAG;IACrB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;IAC9F,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,8FAA8F,CAC/F;IACH,MAAM,EAAE,CAAC;SACN,OAAO,EAAE;SACT,QAAQ,EAAE;SACV,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../../src/tools/authoring/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rego_deps`
|
|
2
|
+
* `rego_deps` -- static dependency analysis for a Rego ref.
|
|
3
3
|
*
|
|
4
4
|
* Wraps `opa deps`. Given a target like `data.example.allow`, returns
|
|
5
5
|
* the base (input/data) and virtual (rule) document references the
|
|
@@ -36,7 +36,7 @@ export function registerRegoDeps(server, config) {
|
|
|
36
36
|
if (subprocessFailure)
|
|
37
37
|
return subprocessFailure;
|
|
38
38
|
if (result.exitCode !== 0) {
|
|
39
|
-
return err('INVALID_REGO', 'opa deps exited non-zero
|
|
39
|
+
return err('INVALID_REGO', 'opa deps exited non-zero -- the policy did not compile or the ref is invalid.', { details: { stderr: result.stderr.trim(), ref } });
|
|
40
40
|
}
|
|
41
41
|
const parsed = tryParseJson(result.stdout);
|
|
42
42
|
if (parsed === undefined) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../src/tools/authoring/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;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,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,yHAAyH,CAC1H;IACH,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,mEAAmE,CAAC;CACjF,CAAC;AAOF,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAc;IAChE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,8NAA8N;QAChO,WAAW,EAAE,aAAa;KAC3B,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE;QACvB,OAAO,gBAAgB,CAAiB,MAAM,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YACnE,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,CACR,cAAc,EACd,
|
|
1
|
+
{"version":3,"file":"deps.js","sourceRoot":"","sources":["../../../src/tools/authoring/deps.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;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,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,aAAa,GAAG;IACpB,KAAK,EAAE,CAAC;SACL,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CACP,yHAAyH,CAC1H;IACH,GAAG,EAAE,CAAC;SACH,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,mEAAmE,CAAC;CACjF,CAAC;AAOF,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAc;IAChE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,8NAA8N;QAChO,WAAW,EAAE,aAAa;KAC3B,EACD,KAAK,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,EAAE,EAAE;QACvB,OAAO,gBAAgB,CAAiB,MAAM,EAAE,KAAK,IAAI,EAAE;YACzD,MAAM,UAAU,GAAG,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACrE,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAE5C,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC;YACnE,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,CACR,cAAc,EACd,+EAA+E,EAC/E,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE,CACnD,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAiB,MAAM,CAAC,MAAM,CAAC,CAAC;YAC3D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,GAAG,CAAC,eAAe,EAAE,6CAA6C,EAAE;oBACzE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBAC1C,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAiB,MAAM,CAAC,CAAC;QACpC,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rego_inspect`
|
|
2
|
+
* `rego_inspect` -- inspect a bundle, directory, or single Rego file
|
|
3
3
|
* via `opa inspect`. Returns the manifest (if present), namespaces,
|
|
4
4
|
* and rule annotations as JSON.
|
|
5
5
|
*/
|
|
@@ -30,7 +30,7 @@ export function registerRegoInspect(server, config) {
|
|
|
30
30
|
if (subprocessFailure)
|
|
31
31
|
return subprocessFailure;
|
|
32
32
|
if (result.exitCode !== 0) {
|
|
33
|
-
return err('INVALID_BUNDLE', 'opa inspect rejected the target
|
|
33
|
+
return err('INVALID_BUNDLE', 'opa inspect rejected the target -- it is not a valid bundle, directory, or Rego file.', {
|
|
34
34
|
details: { stderr: result.stderr.trim(), stdout: result.stdout.trim() },
|
|
35
35
|
});
|
|
36
36
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../src/tools/authoring/inspect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,gBAAgB,GAAG;IACvB,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;AASF,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAc;IACnE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,2KAA2K;QAC7K,WAAW,EAAE,gBAAgB;KAC9B,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,OAAO,gBAAgB,CAAoB,MAAM,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAC5C,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC;YAEvC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAS,EAAE,CAAC,CAAC;YAExD,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,CACR,gBAAgB,EAChB,
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../../../src/tools/authoring/inspect.ts"],"names":[],"mappings":"AAAA;;;;GAIG;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,EACL,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,gBAAgB,GAAG;IACvB,MAAM,EAAE,CAAC;SACN,MAAM,EAAE;SACR,GAAG,CAAC,CAAC,CAAC;SACN,QAAQ,CAAC,wEAAwE,CAAC;CACtF,CAAC;AASF,MAAM,UAAU,mBAAmB,CAAC,MAAiB,EAAE,MAAc;IACnE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,cAAc,EACd;QACE,KAAK,EAAE,0BAA0B;QACjC,WAAW,EACT,2KAA2K;QAC7K,WAAW,EAAE,gBAAgB;KAC9B,EACD,KAAK,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE;QACnB,OAAO,gBAAgB,CAAoB,MAAM,EAAE,KAAK,IAAI,EAAE;YAC5D,MAAM,UAAU,GAAG,aAAa,CAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YACxE,IAAI,CAAC,UAAU,CAAC,EAAE;gBAAE,OAAO,UAAU,CAAC,KAAK,CAAC;YAC5C,MAAM,CAAC,QAAQ,CAAC,GAAG,UAAU,CAAC,QAAQ,CAAC;YAEvC,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,OAAO,CAAC,EAAE,MAAM,EAAE,QAAS,EAAE,CAAC,CAAC;YAExD,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,CACR,gBAAgB,EAChB,uFAAuF,EACvF;oBACE,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBACxE,CACF,CAAC;YACJ,CAAC;YAED,MAAM,MAAM,GAAG,YAAY,CAAoB,MAAM,CAAC,MAAM,CAAC,CAAC;YAC9D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,OAAO,GAAG,CAAC,eAAe,EAAE,gDAAgD,EAAE;oBAC5E,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE;iBAC1C,CAAC,CAAC;YACL,CAAC;YACD,OAAO,EAAE,CAAoB,MAAM,CAAC,CAAC;QACvC,CAAC,CAAC,CAAC;IACL,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared helpers for the evaluation tool category.
|
|
3
3
|
*
|
|
4
4
|
* `rego_eval` and its three trace/profile/coverage variants all share
|
|
5
|
-
* the same input/output shape and error handling
|
|
5
|
+
* the same input/output shape and error handling -- only the OPA flags
|
|
6
6
|
* differ. The shared `runEval` helper takes the resolved EvalInput and
|
|
7
7
|
* returns an envelope; each tool's handler is a thin adapter that
|
|
8
8
|
* preps inputs and forwards.
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Shared helpers for the evaluation tool category.
|
|
3
3
|
*
|
|
4
4
|
* `rego_eval` and its three trace/profile/coverage variants all share
|
|
5
|
-
* the same input/output shape and error handling
|
|
5
|
+
* the same input/output shape and error handling -- only the OPA flags
|
|
6
6
|
* differ. The shared `runEval` helper takes the resolved EvalInput and
|
|
7
7
|
* returns an envelope; each tool's handler is a thin adapter that
|
|
8
8
|
* preps inputs and forwards.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* `rego_compile_query`
|
|
2
|
+
* `rego_compile_query` -- partially evaluate a query.
|
|
3
3
|
*
|
|
4
4
|
* Wraps `opa eval --partial` with a defaulted `unknowns` set. The
|
|
5
|
-
* result is a residual query
|
|
5
|
+
* result is a residual query -- what remains after substituting in
|
|
6
6
|
* everything that's known. Useful for offline policy slicing.
|
|
7
7
|
*/
|
|
8
8
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
@@ -6,7 +6,7 @@ export function registerRegoCompileQuery(server, config) {
|
|
|
6
6
|
const opa = new OpaCli(config);
|
|
7
7
|
server.registerTool('rego_compile_query', {
|
|
8
8
|
title: 'Partially evaluate a Rego query',
|
|
9
|
-
description: 'Run partial evaluation on a query
|
|
9
|
+
description: 'Run partial evaluation on a query -- substitute known values and return the residual policy. Defaults `unknowns` to `["input"]` (treat input as unknown), so the residual encodes "given input X, this is what would have to be true." Use this for offline policy slicing or pre-computing decision sets.',
|
|
10
10
|
inputSchema: RegoCompileQueryInput,
|
|
11
11
|
}, async (args) => {
|
|
12
12
|
return withToolEnvelope(config, () => runEval(opa, config, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/tools/evaluation/compile.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAC;AAE7E,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAE9C,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,MAAc;IACxE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"compile.js","sourceRoot":"","sources":["../../../src/tools/evaluation/compile.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAC;AAE7E,MAAM,qBAAqB,GAAG,eAAe,CAAC;AAE9C,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,MAAc;IACxE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,oBAAoB,EACpB;QACE,KAAK,EAAE,iCAAiC;QACxC,WAAW,EACT,4SAA4S;QAC9S,WAAW,EAAE,qBAAqB;KACnC,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CACnD,OAAO,CACL,GAAG,EACH,MAAM,EACN;YACE,GAAG,IAAI;YACP,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC;SAC5D,EACD,EAAE,CACH,CACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* `rego_eval` and the three flag-extended variants.
|
|
3
3
|
*
|
|
4
|
-
* Each variant is a thin adapter
|
|
5
|
-
* flags
|
|
4
|
+
* Each variant is a thin adapter -- same input shape, different OPA
|
|
5
|
+
* flags -- built on the shared `runEval` helper.
|
|
6
6
|
*/
|
|
7
7
|
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
8
8
|
import type { Config } from '../../config.js';
|
|
@@ -12,7 +12,7 @@ export function registerRegoEval(server, config) {
|
|
|
12
12
|
});
|
|
13
13
|
server.registerTool('rego_eval_with_explain', {
|
|
14
14
|
title: 'Evaluate Rego with execution trace',
|
|
15
|
-
description: "Evaluate with `--explain=full` and return a structured trace alongside the result. Use this when an agent needs to see why a rule fired (or didn't)
|
|
15
|
+
description: "Evaluate with `--explain=full` and return a structured trace alongside the result. Use this when an agent needs to see why a rule fired (or didn't) -- the trace is the basis for `rego_explain_decision`.",
|
|
16
16
|
inputSchema: SharedEvalInput,
|
|
17
17
|
}, async (args) => {
|
|
18
18
|
return withToolEnvelope(config, () => runEval(opa, config, args, { explain: 'full' }));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../../src/tools/evaluation/eval.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAC;AAE7E,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAc;IAChE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,mKAAmK;QACrK,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACxF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB;QACE,KAAK,EAAE,oCAAoC;QAC3C,WAAW,EACT,
|
|
1
|
+
{"version":3,"file":"eval.js","sourceRoot":"","sources":["../../../src/tools/evaluation/eval.ts"],"names":[],"mappings":"AASA,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAC9C,OAAO,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAC7D,OAAO,EAAE,OAAO,EAAE,eAAe,EAAuB,MAAM,cAAc,CAAC;AAE7E,MAAM,UAAU,gBAAgB,CAAC,MAAiB,EAAE,MAAc;IAChE,MAAM,GAAG,GAAG,IAAI,MAAM,CAAC,MAAM,CAAC,CAAC;IAE/B,MAAM,CAAC,YAAY,CACjB,WAAW,EACX;QACE,KAAK,EAAE,qBAAqB;QAC5B,WAAW,EACT,mKAAmK;QACrK,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC;IACxF,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB;QACE,KAAK,EAAE,oCAAoC;QAC3C,WAAW,EACT,4MAA4M;QAC9M,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAChD,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,wBAAwB,EACxB;QACE,KAAK,EAAE,8BAA8B;QACrC,WAAW,EACT,0HAA0H;QAC5H,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAC7D,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,MAAM,CAAC,YAAY,CACjB,yBAAyB,EACzB;QACE,KAAK,EAAE,6BAA6B;QACpC,WAAW,EACT,6IAA6I;QAC/I,WAAW,EAAE,eAAe;KAC7B,EACD,KAAK,EAAE,IAAI,EAAE,EAAE;QACb,OAAO,gBAAgB,CAAiB,MAAM,EAAE,GAAG,EAAE,CACnD,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAC/C,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
2
|
+
import type { Config } from '../../config.js';
|
|
3
|
+
interface CoverageRange {
|
|
4
|
+
start: {
|
|
5
|
+
row: number;
|
|
6
|
+
col?: number;
|
|
7
|
+
};
|
|
8
|
+
end: {
|
|
9
|
+
row: number;
|
|
10
|
+
col?: number;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export interface FileCoverageGap {
|
|
14
|
+
file: string;
|
|
15
|
+
coveragePercent: number;
|
|
16
|
+
uncoveredRanges: CoverageRange[];
|
|
17
|
+
uncoveredLineCount: number;
|
|
18
|
+
}
|
|
19
|
+
export interface RegoCoverageGapsOutput {
|
|
20
|
+
overallCoverage: number;
|
|
21
|
+
totalFiles: number;
|
|
22
|
+
filesWithGaps: FileCoverageGap[];
|
|
23
|
+
testsPassed: number;
|
|
24
|
+
testsFailed: number;
|
|
25
|
+
testsSkipped: number;
|
|
26
|
+
}
|
|
27
|
+
export declare function registerRegoCoverageGaps(server: McpServer, config: Config): void;
|
|
28
|
+
export {};
|
|
29
|
+
//# sourceMappingURL=coverage-gaps.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"coverage-gaps.d.ts","sourceRoot":"","sources":["../../../src/tools/helpers/coverage-gaps.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AA4B9C,UAAU,aAAa;IACrB,KAAK,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACrC,GAAG,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CACpC;AAmBD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAED,MAAM,WAAW,sBAAsB;IACrC,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,aAAa,EAAE,eAAe,EAAE,CAAC;IACjC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;CACtB;AA0CD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAiFhF"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `rego_coverage_gaps` -- run opa test --coverage and surface the
|
|
3
|
+
* uncovered line ranges per file as a structured gap report.
|
|
4
|
+
*
|
|
5
|
+
* OPA emits two JSON documents on stdout when --coverage is set: a
|
|
6
|
+
* test-results array followed by a coverage report object. Both are
|
|
7
|
+
* parsed here; files with uncovered ranges are returned sorted by
|
|
8
|
+
* coverage ascending so the worst-covered files appear first.
|
|
9
|
+
*/
|
|
10
|
+
import { z } from 'zod';
|
|
11
|
+
import { OpaCli } from '../../lib/opa-cli.js';
|
|
12
|
+
import { err, ok } from '../../lib/errors.js';
|
|
13
|
+
import { mapSubprocessFailure, tryParseJson, validatePaths, withToolEnvelope, } from '../../lib/tool-helpers.js';
|
|
14
|
+
const RegoCoverageGapsInput = {
|
|
15
|
+
paths: z
|
|
16
|
+
.array(z.string())
|
|
17
|
+
.min(1)
|
|
18
|
+
.describe('Test directories or files. opa test looks for *_test.rego siblings of source files.'),
|
|
19
|
+
threshold: z
|
|
20
|
+
.number()
|
|
21
|
+
.min(0)
|
|
22
|
+
.max(100)
|
|
23
|
+
.optional()
|
|
24
|
+
.describe('Report only files below this coverage percentage (0-100). When omitted, all files with uncovered ranges are reported.'),
|
|
25
|
+
runPattern: z.string().optional().describe('Run only tests whose names match this regex.'),
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* Parse the combined stdout of `opa test --coverage --format=json`.
|
|
29
|
+
*
|
|
30
|
+
* OPA emits a JSON test-results array followed by a JSON coverage
|
|
31
|
+
* report object. They may appear on separate lines or concatenated.
|
|
32
|
+
* We scan lines and classify each by shape: arrays are test records,
|
|
33
|
+
* objects with a `files` key are coverage reports.
|
|
34
|
+
*/
|
|
35
|
+
function parseTestAndCoverage(stdout) {
|
|
36
|
+
const testRecords = [];
|
|
37
|
+
let coverageReport;
|
|
38
|
+
// Fast path: entire stdout is already a coverage-only object.
|
|
39
|
+
const full = tryParseJson(stdout);
|
|
40
|
+
if (full && typeof full === 'object' && !Array.isArray(full) && 'files' in full) {
|
|
41
|
+
return { testRecords, coverageReport: full };
|
|
42
|
+
}
|
|
43
|
+
// Scan line-by-line for the two documents.
|
|
44
|
+
for (const line of stdout.split(/\r?\n/)) {
|
|
45
|
+
const trimmed = line.trim();
|
|
46
|
+
if (!trimmed)
|
|
47
|
+
continue;
|
|
48
|
+
const parsed = tryParseJson(trimmed);
|
|
49
|
+
if (!parsed)
|
|
50
|
+
continue;
|
|
51
|
+
if (Array.isArray(parsed)) {
|
|
52
|
+
testRecords.push(...parsed);
|
|
53
|
+
}
|
|
54
|
+
else if (typeof parsed === 'object' && parsed !== null && 'files' in parsed) {
|
|
55
|
+
coverageReport = parsed;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
return { testRecords, coverageReport };
|
|
59
|
+
}
|
|
60
|
+
function countUncoveredLines(ranges) {
|
|
61
|
+
return ranges.reduce((sum, r) => sum + (r.end.row - r.start.row + 1), 0);
|
|
62
|
+
}
|
|
63
|
+
export function registerRegoCoverageGaps(server, config) {
|
|
64
|
+
const opa = new OpaCli(config);
|
|
65
|
+
server.registerTool('rego_coverage_gaps', {
|
|
66
|
+
title: 'Rego test coverage gaps',
|
|
67
|
+
description: 'Run opa test --coverage and return a per-file breakdown of uncovered line ranges. Identifies which rules or branches are not yet exercised by tests. Files are sorted by coverage ascending so the worst-covered files appear first. Use threshold to limit the report to files below a target coverage percentage.',
|
|
68
|
+
inputSchema: RegoCoverageGapsInput,
|
|
69
|
+
}, async ({ paths, threshold, runPattern }) => {
|
|
70
|
+
return withToolEnvelope(config, async () => {
|
|
71
|
+
const validation = validatePaths(paths, config, { mustExist: true });
|
|
72
|
+
if (!validation.ok)
|
|
73
|
+
return validation.error;
|
|
74
|
+
const result = await opa.test({
|
|
75
|
+
paths: validation.resolved,
|
|
76
|
+
coverage: true,
|
|
77
|
+
runPattern,
|
|
78
|
+
});
|
|
79
|
+
const subprocessFailure = mapSubprocessFailure(result, 'opa');
|
|
80
|
+
if (subprocessFailure)
|
|
81
|
+
return subprocessFailure;
|
|
82
|
+
const { testRecords, coverageReport } = parseTestAndCoverage(result.stdout);
|
|
83
|
+
if (!coverageReport) {
|
|
84
|
+
if (result.exitCode !== 0) {
|
|
85
|
+
return err('EVAL_ERROR', 'opa test reported failures or a compile error; coverage is only emitted when all tests pass. Fix the failing tests or policy errors first.', { details: { stderr: result.stderr.trim() } });
|
|
86
|
+
}
|
|
87
|
+
return err('NO_TESTS_FOUND', 'opa test ran but produced no coverage report. Ensure the paths contain *_test.rego files with test_ rules.', {
|
|
88
|
+
hint: 'Test rules must begin with test_ and live in *_test.rego files alongside the policy.',
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
const testsPassed = testRecords.filter((r) => r.pass).length;
|
|
92
|
+
const testsFailed = testRecords.filter((r) => r.fail).length;
|
|
93
|
+
const testsSkipped = testRecords.filter((r) => r.skip).length;
|
|
94
|
+
const overallCoverage = coverageReport.coverage ?? 0;
|
|
95
|
+
const filesWithGaps = [];
|
|
96
|
+
for (const [file, report] of Object.entries(coverageReport.files ?? {})) {
|
|
97
|
+
const coveragePercent = report.coverage ?? 0;
|
|
98
|
+
const notCovered = report.not_covered ?? [];
|
|
99
|
+
// Apply threshold filter: skip files already above the target.
|
|
100
|
+
if (threshold !== undefined && coveragePercent >= threshold)
|
|
101
|
+
continue;
|
|
102
|
+
// Skip files with no uncovered ranges at all.
|
|
103
|
+
if (notCovered.length === 0)
|
|
104
|
+
continue;
|
|
105
|
+
filesWithGaps.push({
|
|
106
|
+
file,
|
|
107
|
+
coveragePercent,
|
|
108
|
+
uncoveredRanges: notCovered,
|
|
109
|
+
uncoveredLineCount: countUncoveredLines(notCovered),
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
// Sort worst-covered first so the agent sees the biggest gaps immediately.
|
|
113
|
+
filesWithGaps.sort((a, b) => a.coveragePercent - b.coveragePercent);
|
|
114
|
+
return ok({
|
|
115
|
+
overallCoverage,
|
|
116
|
+
totalFiles: Object.keys(coverageReport.files ?? {}).length,
|
|
117
|
+
filesWithGaps,
|
|
118
|
+
testsPassed,
|
|
119
|
+
testsFailed,
|
|
120
|
+
testsSkipped,
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=coverage-gaps.js.map
|