yenop 0.0.0 → 0.1.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 (103) hide show
  1. package/LICENSE.md +105 -0
  2. package/README.md +243 -3
  3. package/dist/adapters/claude-code/hook.d.ts +43 -0
  4. package/dist/adapters/claude-code/hook.js +101 -0
  5. package/dist/adapters/claude-code/hook.js.map +1 -0
  6. package/dist/adapters/claude-code/install.d.ts +23 -0
  7. package/dist/adapters/claude-code/install.js +86 -0
  8. package/dist/adapters/claude-code/install.js.map +1 -0
  9. package/dist/adapters/codex/hook.d.ts +7 -0
  10. package/dist/adapters/codex/hook.js +134 -0
  11. package/dist/adapters/codex/hook.js.map +1 -0
  12. package/dist/adapters/codex/install.d.ts +18 -0
  13. package/dist/adapters/codex/install.js +66 -0
  14. package/dist/adapters/codex/install.js.map +1 -0
  15. package/dist/adapters/cursor/hook.d.ts +25 -0
  16. package/dist/adapters/cursor/hook.js +228 -0
  17. package/dist/adapters/cursor/hook.js.map +1 -0
  18. package/dist/adapters/cursor/install.d.ts +10 -0
  19. package/dist/adapters/cursor/install.js +57 -0
  20. package/dist/adapters/cursor/install.js.map +1 -0
  21. package/dist/adapters/gemini/hook.d.ts +20 -0
  22. package/dist/adapters/gemini/hook.js +232 -0
  23. package/dist/adapters/gemini/hook.js.map +1 -0
  24. package/dist/adapters/gemini/install.d.ts +21 -0
  25. package/dist/adapters/gemini/install.js +101 -0
  26. package/dist/adapters/gemini/install.js.map +1 -0
  27. package/dist/adapters/hooks/pipeline.d.ts +69 -0
  28. package/dist/adapters/hooks/pipeline.js +131 -0
  29. package/dist/adapters/hooks/pipeline.js.map +1 -0
  30. package/dist/adapters/hooks/registry.d.ts +8 -0
  31. package/dist/adapters/hooks/registry.js +14 -0
  32. package/dist/adapters/hooks/registry.js.map +1 -0
  33. package/dist/adapters/mcp/gateway.d.ts +64 -0
  34. package/dist/adapters/mcp/gateway.js +205 -0
  35. package/dist/adapters/mcp/gateway.js.map +1 -0
  36. package/dist/adapters/mcp/run.d.ts +12 -0
  37. package/dist/adapters/mcp/run.js +86 -0
  38. package/dist/adapters/mcp/run.js.map +1 -0
  39. package/dist/adapters/openai-agents/index.d.ts +74 -0
  40. package/dist/adapters/openai-agents/index.js +139 -0
  41. package/dist/adapters/openai-agents/index.js.map +1 -0
  42. package/dist/cli/demo.d.ts +5 -0
  43. package/dist/cli/demo.js +130 -0
  44. package/dist/cli/demo.js.map +1 -0
  45. package/dist/cli/main.d.ts +2 -0
  46. package/dist/cli/main.js +746 -0
  47. package/dist/cli/main.js.map +1 -0
  48. package/dist/core/config.d.ts +50 -0
  49. package/dist/core/config.js +93 -0
  50. package/dist/core/config.js.map +1 -0
  51. package/dist/core/engine.d.ts +31 -0
  52. package/dist/core/engine.js +301 -0
  53. package/dist/core/engine.js.map +1 -0
  54. package/dist/core/ids.d.ts +5 -0
  55. package/dist/core/ids.js +36 -0
  56. package/dist/core/ids.js.map +1 -0
  57. package/dist/core/index.d.ts +40 -0
  58. package/dist/core/index.js +73 -0
  59. package/dist/core/index.js.map +1 -0
  60. package/dist/core/policy.d.ts +41 -0
  61. package/dist/core/policy.js +205 -0
  62. package/dist/core/policy.js.map +1 -0
  63. package/dist/core/receipts.d.ts +47 -0
  64. package/dist/core/receipts.js +137 -0
  65. package/dist/core/receipts.js.map +1 -0
  66. package/dist/core/report.d.ts +51 -0
  67. package/dist/core/report.js +125 -0
  68. package/dist/core/report.js.map +1 -0
  69. package/dist/core/shell.d.ts +105 -0
  70. package/dist/core/shell.js +921 -0
  71. package/dist/core/shell.js.map +1 -0
  72. package/dist/core/state.d.ts +52 -0
  73. package/dist/core/state.js +269 -0
  74. package/dist/core/state.js.map +1 -0
  75. package/dist/core/telemetry.d.ts +52 -0
  76. package/dist/core/telemetry.js +150 -0
  77. package/dist/core/telemetry.js.map +1 -0
  78. package/dist/core/tools.d.ts +5 -0
  79. package/dist/core/tools.js +59 -0
  80. package/dist/core/tools.js.map +1 -0
  81. package/dist/core/types.d.ts +213 -0
  82. package/dist/core/types.js +3 -0
  83. package/dist/core/types.js.map +1 -0
  84. package/dist/daemon/client.d.ts +34 -0
  85. package/dist/daemon/client.js +138 -0
  86. package/dist/daemon/client.js.map +1 -0
  87. package/dist/daemon/fast.d.ts +9 -0
  88. package/dist/daemon/fast.js +43 -0
  89. package/dist/daemon/fast.js.map +1 -0
  90. package/dist/daemon/server.d.ts +38 -0
  91. package/dist/daemon/server.js +321 -0
  92. package/dist/daemon/server.js.map +1 -0
  93. package/dist/daemon/service.d.ts +26 -0
  94. package/dist/daemon/service.js +171 -0
  95. package/dist/daemon/service.js.map +1 -0
  96. package/dist/viewer/server.d.ts +52 -0
  97. package/dist/viewer/server.js +184 -0
  98. package/dist/viewer/server.js.map +1 -0
  99. package/package.json +59 -7
  100. package/policies/README.md +58 -0
  101. package/policies/approve/default.cedar +72 -0
  102. package/policies/permit/default.cedar +48 -0
  103. package/policies/schema.cedarschema +104 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ids.js","sourceRoot":"","sources":["../../src/core/ids.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE1C;;;;GAIG;AACH,IAAI,MAAM,GAAG,CAAC,CAAC;AACf,IAAI,GAAG,GAAG,CAAC,CAAC;AAEZ,MAAM,UAAU,MAAM,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;IAC7C,IAAI,GAAG,KAAK,MAAM,EAAE,CAAC;QACnB,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,CAAC;QACb,GAAG,GAAG,WAAW,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,mDAAmD;IACnG,CAAC;IACD,MAAM,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC,CAAC,WAAW,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,WAAW,CAAC,EAAE,CAAC,CAAC;IAC5B,GAAG,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACf,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,oEAAoE;IAC9F,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,GAAG,IAAI,CAAC;IAClB,CAAC,CAAC,CAAC,CAAC,GAAG,CAAE,CAAC,CAAC,CAAC,CAAY,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,mBAAmB;IAC5D,MAAM,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC5B,OAAO,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;AACnG,CAAC;AAED,0HAA0H;AAC1H,MAAM,UAAU,WAAW,CAAC,MAAc,IAAI,CAAC,GAAG,EAAE;IAClD,MAAM,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;IAC1C,OAAO,KAAK,GAAG,MAAM,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,gDAAgD;AAChD,MAAM,UAAU,UAAU,CAAC,EAAU;IACnC,OAAO,QAAQ,CAAC,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,40 @@
1
+ import { type YenopConfig } from "./config.js";
2
+ import type { Decision, DecisionRequest, Outcome, OutcomeReceipt, ReceiptSink, RunStateStore } from "./types.js";
3
+ export * from "./types.js";
4
+ export { classifyTool } from "./tools.js";
5
+ export { loadConfig, DEFAULT_BUDGETS, type Mode, type YenopConfig, type PolicyLayer } from "./config.js";
6
+ export { loadPolicies, checkPolicies, evaluate, toCedarValue } from "./policy.js";
7
+ export { RECEIPT_VERSION } from "./types.js";
8
+ export { decide } from "./engine.js";
9
+ export { uuidv7, uuidv7Time, newTenantId } from "./ids.js";
10
+ export { analyzeShell, matchesSecretPattern, isInternalHost, isControlPlanePath, DEFAULT_SECRET_PATTERNS, type ShellFacts } from "./shell.js";
11
+ export { loadSchema, validateAgainstSchema } from "./policy.js";
12
+ export { CONFIG_VERSION, resolveTenant, localTenantId } from "./config.js";
13
+ export { STATE_VERSION, REPLAY_WINDOW_MS } from "./state.js";
14
+ export { SqliteRunState, MemoryRunState } from "./state.js";
15
+ export { buildReport, renderReport, type Report } from "./report.js";
16
+ export { readTelemetry, writeTelemetry, enableTelemetry, disableTelemetry, resetInstallId, toTelemetry, sendTelemetry, dueForDaily, hookedRuntimes, DEFAULT_TELEMETRY_ENDPOINT, type TelemetryState, type TelemetryPayload } from "./telemetry.js";
17
+ export { JsonlReceipts, NullReceipts, readReceipts, readAllReceipts, answersFor, isOutcome, summarizeCall, verifyReceipts, RECEIPT_GENESIS, type ChainCheck } from "./receipts.js";
18
+ /** Directory of the default policy pack shipped with the package. */
19
+ export declare function builtinPoliciesDir(): string;
20
+ export interface Yenop {
21
+ config: YenopConfig;
22
+ /** Set when the policies could not be loaded or do not match the vocabulary. Every decision is then a deny. */
23
+ policyError?: string;
24
+ decide(req: DecisionRequest): Decision;
25
+ /** Record what the runtime reported about a call Yenop asked about: it ran, failed, or was refused. */
26
+ recordOutcome(runId: string, callId: string, tool: string, outcome: Outcome, detail?: string): OutcomeReceipt | undefined;
27
+ /** End a run now, because the runtime said the session ended. The next call on this id starts fresh. */
28
+ endRun(runId: string): void;
29
+ close(): void;
30
+ }
31
+ /** Wire the local, single-machine configuration: SQLite state, JSONL receipts, policies from disk. */
32
+ export interface OpenOptions {
33
+ cwd?: string;
34
+ home?: string;
35
+ /** Dry run: same policies and config, but nothing is counted or recorded. */
36
+ dryRun?: boolean;
37
+ state?: RunStateStore;
38
+ receipts?: ReceiptSink;
39
+ }
40
+ export declare function openYenop(opts?: OpenOptions): Yenop;
@@ -0,0 +1,73 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { dirname, join } from "node:path";
3
+ import { loadConfig, ensureHome } from "./config.js";
4
+ import { loadPolicies } from "./policy.js";
5
+ import { SqliteRunState, MemoryRunState, RUN_IDLE_MS } from "./state.js";
6
+ import { JsonlReceipts, NullReceipts } from "./receipts.js";
7
+ import { decide, recordOutcome } from "./engine.js";
8
+ export * from "./types.js";
9
+ export { classifyTool } from "./tools.js";
10
+ export { loadConfig, DEFAULT_BUDGETS } from "./config.js";
11
+ export { loadPolicies, checkPolicies, evaluate, toCedarValue } from "./policy.js";
12
+ export { RECEIPT_VERSION } from "./types.js";
13
+ export { decide } from "./engine.js";
14
+ export { uuidv7, uuidv7Time, newTenantId } from "./ids.js";
15
+ export { analyzeShell, matchesSecretPattern, isInternalHost, isControlPlanePath, DEFAULT_SECRET_PATTERNS } from "./shell.js";
16
+ export { loadSchema, validateAgainstSchema } from "./policy.js";
17
+ export { CONFIG_VERSION, resolveTenant, localTenantId } from "./config.js";
18
+ export { STATE_VERSION, REPLAY_WINDOW_MS } from "./state.js";
19
+ export { SqliteRunState, MemoryRunState } from "./state.js";
20
+ export { buildReport, renderReport } from "./report.js";
21
+ export { readTelemetry, writeTelemetry, enableTelemetry, disableTelemetry, resetInstallId, toTelemetry, sendTelemetry, dueForDaily, hookedRuntimes, DEFAULT_TELEMETRY_ENDPOINT } from "./telemetry.js";
22
+ export { JsonlReceipts, NullReceipts, readReceipts, readAllReceipts, answersFor, isOutcome, summarizeCall, verifyReceipts, RECEIPT_GENESIS } from "./receipts.js";
23
+ /** Directory of the default policy pack shipped with the package. */
24
+ export function builtinPoliciesDir() {
25
+ // dist/core/index.js -> ../../policies ; src/core/index.ts -> ../../policies
26
+ return join(dirname(fileURLToPath(import.meta.url)), "..", "..", "policies");
27
+ }
28
+ export function openYenop(opts = {}) {
29
+ const cfgOpts = { builtinPoliciesDir: builtinPoliciesDir() };
30
+ if (opts.cwd !== undefined)
31
+ cfgOpts.cwd = opts.cwd;
32
+ if (opts.home !== undefined)
33
+ cfgOpts.home = opts.home;
34
+ const config = loadConfig(cfgOpts);
35
+ ensureHome(config.home);
36
+ // A guard that cannot read its rules must not wave everything through. Load errors become a standing deny,
37
+ // and the instance still opens so `yenop check`, `status` and `receipts` can show a person what is wrong.
38
+ let policies = { permit: {}, approve: {}, origins: {}, disabled: {}, layers: [], warnings: [] };
39
+ let policyError;
40
+ try {
41
+ policies = loadPolicies(config.policyLayers, { disabled: config.disabledPolicies });
42
+ }
43
+ catch (e) {
44
+ policyError = e.message.replace(/^yenop: /, "");
45
+ }
46
+ const idleMs = config.runIdleMs ?? RUN_IDLE_MS;
47
+ const deps = {
48
+ idleMs,
49
+ tenant: config.tenant,
50
+ mode: config.mode,
51
+ policies,
52
+ ...(policyError !== undefined ? { policyError } : {}),
53
+ secretPatterns: config.secretPatterns,
54
+ sensitivePatterns: config.sensitivePatterns,
55
+ trustedServers: config.trustedServers,
56
+ sensitiveServers: config.sensitiveServers,
57
+ budgets: config.budgets,
58
+ state: opts.state ?? (opts.dryRun ? new MemoryRunState() : new SqliteRunState(config.statePath)),
59
+ receipts: opts.receipts ?? (opts.dryRun ? new NullReceipts() : new JsonlReceipts(config.receiptsPath)),
60
+ };
61
+ return {
62
+ config,
63
+ ...(policyError !== undefined ? { policyError } : {}),
64
+ decide: (req) => decide(deps, req),
65
+ recordOutcome: (runId, callId, tool, outcome, detail) => recordOutcome(deps, runId, callId, tool, outcome, detail),
66
+ endRun: (runId) => deps.state.endRun(deps.tenant.id, runId),
67
+ close: () => {
68
+ deps.state.close();
69
+ deps.receipts.close();
70
+ },
71
+ };
72
+ }
73
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/core/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,41 @@
1
+ import * as cedar from "@cedar-policy/cedar-wasm/nodejs";
2
+ import type { DecisionRequest, FlowFacts, PolicyBundle, RunFacts } from "./types.js";
3
+ import type { PolicyLayer } from "./config.js";
4
+ import type { ShellFacts } from "./shell.js";
5
+ /** The policy vocabulary, shipped next to the baseline policies. */
6
+ export declare function loadSchema(baselineDir: string): string;
7
+ /** Validate a policy set against the vocabulary. Errors are returned as readable strings. */
8
+ export declare function validateAgainstSchema(schema: string, policies: Record<string, string>): {
9
+ errors: string[];
10
+ warnings: string[];
11
+ };
12
+ /**
13
+ * Load every layer, in order. The baseline ships with the package and is always first;
14
+ * customer layers add to it. Ids listed in `disabled` are skipped wherever they appear.
15
+ */
16
+ export declare function loadPolicies(layers: PolicyLayer[], opts?: {
17
+ disabled?: string[];
18
+ validate?: boolean;
19
+ }): PolicyBundle;
20
+ /** Cedar only accepts integers as numbers; coerce anything else to a safe JSON shape. */
21
+ export declare function toCedarValue(v: unknown, depth?: number): cedar.CedarValueJson;
22
+ export interface EvalResult {
23
+ decision: "allow" | "deny";
24
+ reasons: string[];
25
+ errors: string[];
26
+ }
27
+ export interface EvalInput {
28
+ req: DecisionRequest;
29
+ /** What the run has done before this call, with `steps` already counting this one. */
30
+ run: RunFacts;
31
+ /** What this call does. */
32
+ flow: FlowFacts;
33
+ /** Derived facts we compute so policies stay simple. */
34
+ derived: Record<string, cedar.CedarValueJson>;
35
+ /** Parsed shell facts when the tool runs a shell command. */
36
+ shell?: ShellFacts;
37
+ }
38
+ /** Evaluate one policy set. Any evaluation error is reported; the engine fails closed on errors. */
39
+ export declare function evaluate(input: EvalInput, policies: Record<string, string>): EvalResult;
40
+ /** Parse-check a bundle without evaluating. Throws with a readable message on the first problem. */
41
+ export declare function checkPolicies(bundle: PolicyBundle): void;
@@ -0,0 +1,205 @@
1
+ import { readdirSync, readFileSync, existsSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import * as cedar from "@cedar-policy/cedar-wasm/nodejs";
4
+ /** The policy vocabulary, shipped next to the baseline policies. */
5
+ export function loadSchema(baselineDir) {
6
+ return readFileSync(join(baselineDir, "schema.cedarschema"), "utf8");
7
+ }
8
+ /** Validate a policy set against the vocabulary. Errors are returned as readable strings. */
9
+ export function validateAgainstSchema(schema, policies) {
10
+ if (Object.keys(policies).length === 0)
11
+ return { errors: [], warnings: [] };
12
+ const r = cedar.validate({ schema, policies: { staticPolicies: policies }, validationSettings: { mode: "strict" } });
13
+ if (r.type === "failure")
14
+ return { errors: r.errors.map((e) => e.message), warnings: [] };
15
+ const fmt = (v) => `${v.policyId}: ${v.error.message}${v.error.help ? ` (${v.error.help})` : ""}`;
16
+ // A policy that can never apply is a mistake (usually a misspelled attribute behind a `has` guard).
17
+ const impossible = r.validationWarnings.filter((w) => /impossible/i.test(w.error.message));
18
+ const rest = r.validationWarnings.filter((w) => !/impossible/i.test(w.error.message));
19
+ return {
20
+ errors: [...r.validationErrors.map(fmt), ...impossible.map((w) => `${fmt(w)} (check the attribute names against the vocabulary)`)],
21
+ warnings: rest.map(fmt),
22
+ };
23
+ }
24
+ /** Split a .cedar file into individual policies keyed by their @id annotation (or file:index). */
25
+ function splitPolicies(text, origin) {
26
+ const parts = cedar.policySetTextToParts(text);
27
+ if (parts.type === "failure") {
28
+ const msg = parts.errors.map((e) => e.message).join("; ");
29
+ throw new Error(`yenop: cannot parse ${origin}: ${msg}`);
30
+ }
31
+ const out = {};
32
+ parts.policies.forEach((p, i) => {
33
+ let id = `${origin}#${i}`;
34
+ const json = cedar.policyToJson(p);
35
+ if (json.type === "success") {
36
+ const ann = json.json.annotations;
37
+ if (ann && typeof ann["id"] === "string" && ann["id"].length > 0)
38
+ id = ann["id"];
39
+ }
40
+ if (out[id])
41
+ throw new Error(`yenop: duplicate policy id "${id}" in ${origin}`);
42
+ out[id] = p;
43
+ });
44
+ return out;
45
+ }
46
+ /** Structural equality: formatting and comments do not count. */
47
+ function samePolicy(a, b) {
48
+ const ja = cedar.policyToJson(a);
49
+ const jb = cedar.policyToJson(b);
50
+ if (ja.type !== "success" || jb.type !== "success")
51
+ return a === b;
52
+ return JSON.stringify(ja.json) === JSON.stringify(jb.json);
53
+ }
54
+ function loadDir(layer, bundle, which, disabled) {
55
+ const sub = join(layer.dir, which);
56
+ if (!existsSync(sub))
57
+ return 0;
58
+ let count = 0;
59
+ for (const f of readdirSync(sub).filter((n) => n.endsWith(".cedar")).sort()) {
60
+ const path = join(sub, f);
61
+ const policies = splitPolicies(readFileSync(path, "utf8"), `${which}/${f}`);
62
+ for (const [id, text] of Object.entries(policies)) {
63
+ const origin = `${layer.name}:${path}`;
64
+ if (disabled.has(id)) {
65
+ bundle.disabled[id] = origin;
66
+ continue;
67
+ }
68
+ const existing = bundle[which][id];
69
+ if (existing !== undefined) {
70
+ // A copy of a policy already loaded (typically an old init that copied the baseline) is harmless.
71
+ if (samePolicy(existing, text))
72
+ continue;
73
+ throw new Error(`yenop: policy id "${id}" is defined in ${bundle.origins[id]} and again, differently, in ${origin}. ` +
74
+ `Give the new one its own @id, or switch the first one off with "disabledPolicies": ["${id}"] in config.json.`);
75
+ }
76
+ bundle[which][id] = text;
77
+ bundle.origins[id] = origin;
78
+ count++;
79
+ }
80
+ }
81
+ return count;
82
+ }
83
+ /**
84
+ * Load every layer, in order. The baseline ships with the package and is always first;
85
+ * customer layers add to it. Ids listed in `disabled` are skipped wherever they appear.
86
+ */
87
+ export function loadPolicies(layers, opts = {}) {
88
+ const disabled = new Set(opts.disabled ?? []);
89
+ const bundle = { permit: {}, approve: {}, origins: {}, disabled: {}, layers: [], warnings: [] };
90
+ for (const layer of layers) {
91
+ const permit = loadDir(layer, bundle, "permit", disabled);
92
+ const approve = loadDir(layer, bundle, "approve", disabled);
93
+ bundle.layers.push({ name: layer.name, dir: layer.dir, permit, approve });
94
+ }
95
+ if (opts.validate !== false) {
96
+ const baseline = layers.find((l) => l.name === "baseline");
97
+ if (baseline) {
98
+ const schema = loadSchema(baseline.dir);
99
+ for (const which of ["permit", "approve"]) {
100
+ const { errors, warnings } = validateAgainstSchema(schema, bundle[which]);
101
+ if (errors.length) {
102
+ const where = errors.map((e) => ` ${e} [${bundle.origins[e.split(":")[0] ?? ""] ?? which}]`).join("\n");
103
+ throw new Error(`yenop: ${which} policies do not match the policy vocabulary (policies/schema.cedarschema):\n${where}`);
104
+ }
105
+ bundle.warnings.push(...warnings);
106
+ }
107
+ }
108
+ }
109
+ return bundle;
110
+ }
111
+ /** Cedar only accepts integers as numbers; coerce anything else to a safe JSON shape. */
112
+ export function toCedarValue(v, depth = 0) {
113
+ if (depth > 8)
114
+ return "[nested]";
115
+ if (v === null || v === undefined)
116
+ return null;
117
+ if (typeof v === "string" || typeof v === "boolean")
118
+ return v;
119
+ if (typeof v === "number")
120
+ return Number.isInteger(v) ? v : String(v);
121
+ if (typeof v === "bigint")
122
+ return String(v);
123
+ if (Array.isArray(v))
124
+ return v.map((x) => toCedarValue(x, depth + 1));
125
+ if (typeof v === "object") {
126
+ const out = {};
127
+ for (const [k, x] of Object.entries(v))
128
+ out[k] = toCedarValue(x, depth + 1);
129
+ return out;
130
+ }
131
+ return String(v);
132
+ }
133
+ /** Every argument as a string tag on the Call entity, for policies on tools with untyped arguments. */
134
+ function argTags(args) {
135
+ const out = {};
136
+ for (const [k, v] of Object.entries(args)) {
137
+ if (!/^[A-Za-z_][A-Za-z0-9_-]*$/.test(k))
138
+ continue;
139
+ const s = typeof v === "string" ? v : JSON.stringify(v) ?? "";
140
+ out[k] = s.length > 4000 ? s.slice(0, 4000) : s;
141
+ }
142
+ return out;
143
+ }
144
+ function buildCall(input, policies) {
145
+ const { req } = input;
146
+ const principal = { type: "Yenop::Agent", id: `${req.principal.runtime}/${req.principal.agent}` };
147
+ const action = { type: "Yenop::Action", id: "call" };
148
+ const resource = { type: "Yenop::Tool", id: req.tool.name };
149
+ const call = { type: "Yenop::Call", id: req.callId ?? "call" };
150
+ const toolAttrs = {
151
+ name: req.tool.name,
152
+ kind: req.tool.kind,
153
+ readOnly: req.tool.readOnly,
154
+ };
155
+ if (req.tool.server)
156
+ toolAttrs["server"] = req.tool.server;
157
+ const context = {
158
+ args: toCedarValue(req.args),
159
+ call: { __entity: call },
160
+ run: { ...input.run },
161
+ flow: { ...input.flow },
162
+ cwd: req.cwd ?? "",
163
+ permissionMode: req.permissionMode ?? "",
164
+ derived: input.derived,
165
+ };
166
+ if (input.shell)
167
+ context["shell"] = { ...input.shell };
168
+ return {
169
+ principal,
170
+ action,
171
+ resource,
172
+ context,
173
+ policies: { staticPolicies: policies },
174
+ entities: [
175
+ { uid: principal, attrs: { runtime: req.principal.runtime, agent: req.principal.agent, user: req.principal.user }, parents: [] },
176
+ { uid: action, attrs: {}, parents: [] },
177
+ { uid: resource, attrs: toolAttrs, parents: [] },
178
+ { uid: call, attrs: {}, parents: [], tags: argTags(req.args) },
179
+ ],
180
+ };
181
+ }
182
+ /** Evaluate one policy set. Any evaluation error is reported; the engine fails closed on errors. */
183
+ export function evaluate(input, policies) {
184
+ if (Object.keys(policies).length === 0)
185
+ return { decision: "deny", reasons: [], errors: [] };
186
+ const answer = cedar.isAuthorized(buildCall(input, policies));
187
+ if (answer.type === "failure") {
188
+ return { decision: "deny", reasons: [], errors: answer.errors.map((e) => e.message) };
189
+ }
190
+ const { decision, diagnostics } = answer.response;
191
+ return {
192
+ decision,
193
+ reasons: diagnostics.reason,
194
+ errors: diagnostics.errors.map((e) => `${e.policyId}: ${e.error.message}`),
195
+ };
196
+ }
197
+ /** Parse-check a bundle without evaluating. Throws with a readable message on the first problem. */
198
+ export function checkPolicies(bundle) {
199
+ for (const which of ["permit", "approve"]) {
200
+ const r = cedar.checkParsePolicySet({ staticPolicies: bundle[which] });
201
+ if (r.type === "failure")
202
+ throw new Error(`yenop: ${which} policies do not parse: ${r.errors.map((e) => e.message).join("; ")}`);
203
+ }
204
+ }
205
+ //# sourceMappingURL=policy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"policy.js","sourceRoot":"","sources":["../../src/core/policy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ import type { OutcomeReceipt, Receipt, ReceiptSink } from "./types.js";
2
+ /** One short line describing a call: the command, path, URL or query. */
3
+ export declare function summarizeCall(args: unknown, max?: number): string;
4
+ /** Trim long strings so a receipt never balloons; structure is preserved. */
5
+ export declare function trimForReceipt(v: unknown, depth?: number): unknown;
6
+ /** Append-only JSON Lines file. One line per decision, written synchronously so a crash never loses it. */
7
+ /** The chain's anchor: the "hash before the first line". A fixed, public constant. */
8
+ export declare const RECEIPT_GENESIS = "yenop-receipts-v1";
9
+ /**
10
+ * Appends receipts as a hash chain: each line carries `prev`, the SHA-256 of the previous line's exact bytes.
11
+ * Editing, deleting or reordering any line makes the next line's `prev` wrong, so tampering is detectable with
12
+ * `verifyReceipts`. The hash is over the literal line, so there is no canonical-form step to get wrong. This is
13
+ * local tamper-evidence, not a signature: it catches changes to the recorded history, and truncation of the
14
+ * tail is caught by anchoring the head elsewhere (the control plane, later). Documented as such.
15
+ */
16
+ export declare class JsonlReceipts implements ReceiptSink {
17
+ private path;
18
+ private prevHash;
19
+ constructor(path: string);
20
+ append(receipt: Receipt | OutcomeReceipt): void;
21
+ close(): void;
22
+ }
23
+ export interface ChainCheck {
24
+ ok: boolean;
25
+ lines: number;
26
+ /** 1-based line number where the chain first breaks, if any. */
27
+ brokenAt?: number;
28
+ reason?: string;
29
+ }
30
+ /** Walk the receipts file and confirm every line's `prev` matches the hash of the line before it. */
31
+ export declare function verifyReceipts(path: string): ChainCheck;
32
+ /** Every line of the receipts file: decisions and outcomes, oldest first. */
33
+ export declare function readAllReceipts(path: string): (Receipt | OutcomeReceipt)[];
34
+ export declare function isOutcome(r: Receipt | OutcomeReceipt): r is OutcomeReceipt;
35
+ /** Decisions only, the last `last` of them. */
36
+ export declare function readReceipts(path: string, last?: number): Receipt[];
37
+ export type Answer = "approved, ran" | "approved, failed" | "refused by the permission system" | "not run: rejected or abandoned" | "awaiting an answer";
38
+ /**
39
+ * What became of each ask. The runtime reports when a call ran or was refused by its own permission system;
40
+ * a person clicking Deny produces no event, so an ask that is followed by later steps with no run recorded was rejected or abandoned.
41
+ */
42
+ export declare function answersFor(all: (Receipt | OutcomeReceipt)[]): Map<string, Answer>;
43
+ /** Discards receipts. Only for dry runs that must leave no trace. */
44
+ export declare class NullReceipts implements ReceiptSink {
45
+ append(): void;
46
+ close(): void;
47
+ }
@@ -0,0 +1,137 @@
1
+ import { appendFileSync, mkdirSync, existsSync, readFileSync } from "node:fs";
2
+ import { createHash } from "node:crypto";
3
+ import { dirname } from "node:path";
4
+ /** One short line describing a call: the command, path, URL or query. */
5
+ export function summarizeCall(args, max = 80) {
6
+ if (!args || typeof args !== "object")
7
+ return "";
8
+ const a = args;
9
+ const key = ["command", "file_path", "path", "notebook_path", "url", "query", "pattern"].find((k) => typeof a[k] === "string");
10
+ const v = (key ? String(a[key]) : JSON.stringify(a)).replace(/\s+/g, " ").trim();
11
+ return v.length > max ? v.slice(0, max - 3) + "..." : v;
12
+ }
13
+ const MAX_STRING = 4000;
14
+ /** Trim long strings so a receipt never balloons; structure is preserved. */
15
+ export function trimForReceipt(v, depth = 0) {
16
+ if (depth > 8)
17
+ return "[nested]";
18
+ if (typeof v === "string")
19
+ return v.length > MAX_STRING ? v.slice(0, MAX_STRING) + `…[${v.length - MAX_STRING} more]` : v;
20
+ if (Array.isArray(v))
21
+ return v.slice(0, 200).map((x) => trimForReceipt(x, depth + 1));
22
+ if (v && typeof v === "object") {
23
+ const out = {};
24
+ for (const [k, x] of Object.entries(v))
25
+ out[k] = trimForReceipt(x, depth + 1);
26
+ return out;
27
+ }
28
+ return v;
29
+ }
30
+ /** Append-only JSON Lines file. One line per decision, written synchronously so a crash never loses it. */
31
+ /** The chain's anchor: the "hash before the first line". A fixed, public constant. */
32
+ export const RECEIPT_GENESIS = "yenop-receipts-v1";
33
+ function sha256(s) {
34
+ return createHash("sha256").update(s, "utf8").digest("hex");
35
+ }
36
+ /**
37
+ * Appends receipts as a hash chain: each line carries `prev`, the SHA-256 of the previous line's exact bytes.
38
+ * Editing, deleting or reordering any line makes the next line's `prev` wrong, so tampering is detectable with
39
+ * `verifyReceipts`. The hash is over the literal line, so there is no canonical-form step to get wrong. This is
40
+ * local tamper-evidence, not a signature: it catches changes to the recorded history, and truncation of the
41
+ * tail is caught by anchoring the head elsewhere (the control plane, later). Documented as such.
42
+ */
43
+ export class JsonlReceipts {
44
+ path;
45
+ prevHash;
46
+ constructor(path) {
47
+ this.path = path;
48
+ const dir = dirname(path);
49
+ if (!existsSync(dir))
50
+ mkdirSync(dir, { recursive: true });
51
+ this.prevHash = lastLineHash(path);
52
+ }
53
+ append(receipt) {
54
+ const line = JSON.stringify({ ...receipt, prev: this.prevHash });
55
+ appendFileSync(this.path, line + "\n", "utf8");
56
+ this.prevHash = sha256(line);
57
+ }
58
+ close() { }
59
+ }
60
+ /** The chain hash to continue from: SHA-256 of the last line, or the genesis anchor for an empty/new file. */
61
+ function lastLineHash(path) {
62
+ if (!existsSync(path))
63
+ return RECEIPT_GENESIS;
64
+ const lines = readFileSync(path, "utf8").split("\n").filter((l) => l.length > 0);
65
+ const last = lines[lines.length - 1];
66
+ return last ? sha256(last) : RECEIPT_GENESIS;
67
+ }
68
+ /** Walk the receipts file and confirm every line's `prev` matches the hash of the line before it. */
69
+ export function verifyReceipts(path) {
70
+ if (!existsSync(path))
71
+ return { ok: true, lines: 0 };
72
+ const lines = readFileSync(path, "utf8").split("\n").filter((l) => l.length > 0);
73
+ let expected = RECEIPT_GENESIS;
74
+ for (let i = 0; i < lines.length; i++) {
75
+ const text = lines[i];
76
+ let parsed;
77
+ try {
78
+ parsed = JSON.parse(text);
79
+ }
80
+ catch {
81
+ return { ok: false, lines: lines.length, brokenAt: i + 1, reason: "line is not valid JSON" };
82
+ }
83
+ const prev = parsed.prev ?? RECEIPT_GENESIS; // older unchained lines read as genesis-anchored
84
+ if (prev !== expected) {
85
+ return { ok: false, lines: lines.length, brokenAt: i + 1, reason: `prev hash does not match the line before it (a line was edited, removed, or reordered)` };
86
+ }
87
+ expected = sha256(text);
88
+ }
89
+ return { ok: true, lines: lines.length };
90
+ }
91
+ /** Every line of the receipts file: decisions and outcomes, oldest first. */
92
+ export function readAllReceipts(path) {
93
+ if (!existsSync(path))
94
+ return [];
95
+ return readFileSync(path, "utf8")
96
+ .split("\n")
97
+ .filter((l) => l.length > 0)
98
+ .map((l) => JSON.parse(l));
99
+ }
100
+ export function isOutcome(r) {
101
+ return r.kind === "outcome";
102
+ }
103
+ /** Decisions only, the last `last` of them. */
104
+ export function readReceipts(path, last = 20) {
105
+ return readAllReceipts(path).filter((r) => !isOutcome(r)).slice(-last);
106
+ }
107
+ /**
108
+ * What became of each ask. The runtime reports when a call ran or was refused by its own permission system;
109
+ * a person clicking Deny produces no event, so an ask that is followed by later steps with no run recorded was rejected or abandoned.
110
+ */
111
+ export function answersFor(all) {
112
+ const outcomes = new Map();
113
+ for (const r of all)
114
+ if (isOutcome(r))
115
+ outcomes.set(r.decisionId, r);
116
+ const decisions = all.filter((r) => !isOutcome(r));
117
+ const lastStep = new Map();
118
+ for (const d of decisions)
119
+ lastStep.set(d.runId, Math.max(lastStep.get(d.runId) ?? 0, d.steps));
120
+ const out = new Map();
121
+ for (const d of decisions) {
122
+ if (d.effect !== "ask" || d.mode === "observe")
123
+ continue;
124
+ const o = outcomes.get(d.id);
125
+ if (o)
126
+ out.set(d.id, o.outcome === "ran" ? "approved, ran" : o.outcome === "failed" ? "approved, failed" : "refused by the permission system");
127
+ else
128
+ out.set(d.id, (lastStep.get(d.runId) ?? 0) > d.steps ? "not run: rejected or abandoned" : "awaiting an answer");
129
+ }
130
+ return out;
131
+ }
132
+ /** Discards receipts. Only for dry runs that must leave no trace. */
133
+ export class NullReceipts {
134
+ append() { }
135
+ close() { }
136
+ }
137
+ //# sourceMappingURL=receipts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"receipts.js","sourceRoot":"","sources":["../../src/core/receipts.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
1
+ /**
2
+ * `yenop report`: what your agents did, in aggregate, from the receipts on this machine.
3
+ *
4
+ * Two audiences. A developer reads it after a week in observe mode to see what would have been stopped, and
5
+ * whether the asks were the right asks. And, with the person's explicit consent, the same numbers with every
6
+ * piece of content removed are what Yenop's telemetry sends. The report is built once; telemetry is the
7
+ * report minus everything that could identify a project, a file, a command, or a person.
8
+ *
9
+ * The number that matters most is the ASK calibration: of the calls Yenop held for a person, how many did the
10
+ * person then allow? Near 100 % means the baseline asks too often (fatigue); near 0 % means the asks were
11
+ * real. That ratio, per rule, is how the baseline gets tuned by evidence instead of opinion.
12
+ */
13
+ import type { YenopConfig } from "./config.js";
14
+ import { type Answer } from "./receipts.js";
15
+ export interface Report {
16
+ /** ISO timestamps bounding the period, and the number of days requested. */
17
+ from: string;
18
+ to: string;
19
+ days: number;
20
+ /** Which tenant's receipts, or "all". Never sent in telemetry. */
21
+ scope: string;
22
+ runs: number;
23
+ actions: number;
24
+ allow: number;
25
+ ask: number;
26
+ deny: number;
27
+ /** What became of the asks. */
28
+ askOutcomes: Record<Answer, number>;
29
+ /** Of asks that got an answer, the share the person allowed. undefined when no ask was answered. */
30
+ askApprovalRate?: number;
31
+ /** Approval rule id -> {asked, allowed, refused}; the calibration table. */
32
+ askByRule: Record<string, {
33
+ asked: number;
34
+ allowed: number;
35
+ refused: number;
36
+ }>;
37
+ /** Deny rule id -> count. */
38
+ denyByRule: Record<string, number>;
39
+ /** Runtime -> action count (claude-code, cursor, codex, mcp, ...). */
40
+ byRuntime: Record<string, number>;
41
+ /** Tool kind -> action count (shell, write, read, mcp, web, unknown). */
42
+ byToolKind: Record<string, number>;
43
+ /** Observe-mode share of actions: how much of this was recorded without being enforced. */
44
+ observedOnly: number;
45
+ }
46
+ export declare function buildReport(config: YenopConfig, opts?: {
47
+ days?: number;
48
+ all?: boolean;
49
+ }): Report;
50
+ /** The report as a person reads it. */
51
+ export declare function renderReport(r: Report): string;