@sanoma-ai/workflows 0.2.0 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -85
- package/dist/approvals.d.ts +11 -6
- package/dist/approvals.js +38 -10
- package/dist/approvals.js.map +1 -1
- package/dist/call-workflow.d.ts +16 -0
- package/dist/call-workflow.js +35 -0
- package/dist/call-workflow.js.map +1 -0
- package/dist/call.d.ts +33 -4
- package/dist/call.js +107 -42
- package/dist/call.js.map +1 -1
- package/dist/cedar.d.ts +87 -0
- package/dist/cedar.js +365 -0
- package/dist/cedar.js.map +1 -0
- package/dist/client.d.ts +85 -7
- package/dist/client.js +289 -25
- package/dist/client.js.map +1 -1
- package/dist/collection.d.ts +107 -0
- package/dist/collection.js +306 -0
- package/dist/collection.js.map +1 -0
- package/dist/config.d.ts +42 -14
- package/dist/config.js +82 -18
- package/dist/config.js.map +1 -1
- package/dist/constructors.d.ts +2 -0
- package/dist/constructors.js +5 -0
- package/dist/constructors.js.map +1 -0
- package/dist/data.d.ts +2 -0
- package/dist/data.js +3 -0
- package/dist/data.js.map +1 -0
- package/dist/datafile.d.ts +28 -2
- package/dist/datafile.js +118 -19
- package/dist/datafile.js.map +1 -1
- package/dist/db.d.ts +5 -3
- package/dist/db.js +88 -21
- package/dist/db.js.map +1 -1
- package/dist/define.d.ts +14 -5
- package/dist/define.js +1 -5
- package/dist/define.js.map +1 -1
- package/dist/describe.d.ts +45 -5
- package/dist/describe.js +72 -7
- package/dist/describe.js.map +1 -1
- package/dist/direct.d.ts +9 -0
- package/dist/direct.js +11 -0
- package/dist/direct.js.map +1 -0
- package/dist/errors.d.ts +16 -1
- package/dist/errors.js +30 -1
- package/dist/errors.js.map +1 -1
- package/dist/expectations.d.ts +3 -3
- package/dist/expectations.js +16 -7
- package/dist/expectations.js.map +1 -1
- package/dist/fill.d.ts +4 -0
- package/dist/fill.js +13 -0
- package/dist/fill.js.map +1 -1
- package/dist/index.d.ts +8 -4
- package/dist/index.js +10 -4
- package/dist/index.js.map +1 -1
- package/dist/ledger.d.ts +12 -1
- package/dist/ledger.js +18 -11
- package/dist/ledger.js.map +1 -1
- package/dist/lint.d.ts +5 -4
- package/dist/lint.js +24 -7
- package/dist/lint.js.map +1 -1
- package/dist/op.d.ts +6 -0
- package/dist/op.js.map +1 -1
- package/dist/outline.d.ts +2 -0
- package/dist/outline.js +1 -1
- package/dist/outline.js.map +1 -1
- package/dist/paths.d.ts +4 -0
- package/dist/paths.js +17 -3
- package/dist/paths.js.map +1 -1
- package/dist/person.d.ts +61 -0
- package/dist/person.js +69 -0
- package/dist/person.js.map +1 -0
- package/dist/plugin.d.ts +28 -0
- package/dist/plugin.js +52 -1
- package/dist/plugin.js.map +1 -1
- package/dist/policy.d.ts +51 -55
- package/dist/policy.js +14 -36
- package/dist/policy.js.map +1 -1
- package/dist/resource.d.ts +21 -5
- package/dist/resource.js +12 -3
- package/dist/resource.js.map +1 -1
- package/dist/resources.d.ts +58 -6
- package/dist/resources.js +119 -26
- package/dist/resources.js.map +1 -1
- package/dist/run.d.ts +17 -1
- package/dist/run.js.map +1 -1
- package/dist/scenario.d.ts +16 -9
- package/dist/scenario.js +149 -44
- package/dist/scenario.js.map +1 -1
- package/dist/scenarios.d.ts +10 -6
- package/dist/scenarios.js +8 -4
- package/dist/scenarios.js.map +1 -1
- package/dist/schema.d.ts +32 -0
- package/dist/schema.js +225 -0
- package/dist/schema.js.map +1 -0
- package/dist/sdk.d.ts +34 -0
- package/dist/sdk.js +168 -0
- package/dist/sdk.js.map +1 -0
- package/dist/shared.d.ts +181 -5
- package/dist/shared.js +160 -7
- package/dist/shared.js.map +1 -1
- package/dist/sites.d.ts +52 -0
- package/dist/sites.js +174 -0
- package/dist/sites.js.map +1 -0
- package/dist/version.d.ts +3 -2
- package/dist/version.js +3 -2
- package/dist/version.js.map +1 -1
- package/dist/worker.d.ts +3 -2
- package/dist/worker.js +24 -4
- package/dist/worker.js.map +1 -1
- package/oxlint.json +7 -20
- package/package.json +8 -3
- package/src/approvals.ts +49 -13
- package/src/call-workflow.ts +44 -0
- package/src/call.ts +157 -45
- package/src/cedar.ts +493 -0
- package/src/client.ts +368 -37
- package/src/collection.ts +431 -0
- package/src/config.ts +131 -34
- package/src/constructors.ts +4 -0
- package/src/data.ts +10 -0
- package/src/datafile.ts +141 -21
- package/src/db.ts +90 -22
- package/src/define.ts +15 -10
- package/src/describe.ts +113 -10
- package/src/direct.ts +15 -0
- package/src/errors.ts +36 -1
- package/src/expectations.ts +17 -8
- package/src/fill.ts +15 -0
- package/src/index.ts +33 -2
- package/src/ledger.ts +35 -17
- package/src/lint.ts +29 -12
- package/src/op.ts +6 -0
- package/src/outline.ts +1 -1
- package/src/paths.ts +18 -3
- package/src/person.ts +75 -0
- package/src/plugin.ts +74 -5
- package/src/policy.ts +59 -63
- package/src/resource.ts +35 -8
- package/src/resources.ts +165 -24
- package/src/run.ts +18 -1
- package/src/scenario.ts +186 -57
- package/src/scenarios.ts +15 -8
- package/src/schema.ts +261 -0
- package/src/sdk.ts +211 -0
- package/src/shared.ts +271 -8
- package/src/sites.ts +220 -0
- package/src/version.ts +3 -2
- package/src/worker.ts +29 -6
package/dist/cedar.d.ts
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { ResolvedConfig } from "./config.ts";
|
|
2
|
+
import { type Policy } from "./policy.ts";
|
|
3
|
+
import { type PeopleResource } from "./shared.ts";
|
|
4
|
+
/** Where a company's policies are, under its root. */
|
|
5
|
+
export declare const POLICIES_DIR = "policies";
|
|
6
|
+
/** One policy, as loaded: its id, its text and where it is written, and the annotations Sanoma reads. */
|
|
7
|
+
export interface CedarPolicySource {
|
|
8
|
+
/** Its `@id`, else `<file>#<n>`, counting from 1 in the order written. */
|
|
9
|
+
id: string;
|
|
10
|
+
text: string;
|
|
11
|
+
/** Relative to the root, such as `policies/money.cedar`. */
|
|
12
|
+
file: string;
|
|
13
|
+
/** The line and column its text starts at in `file`, from 1. */
|
|
14
|
+
line: number;
|
|
15
|
+
column: number;
|
|
16
|
+
effect: "permit" | "forbid";
|
|
17
|
+
/** `@hold(...)`: a declared group, a declared person's id, or `on-behalf-of`. */
|
|
18
|
+
hold?: string;
|
|
19
|
+
/** `@title(...)`: the Inbox title of its hold. */
|
|
20
|
+
title?: string;
|
|
21
|
+
/** `@reason(...)`: the message of its deny. */
|
|
22
|
+
reason?: string;
|
|
23
|
+
}
|
|
24
|
+
/** What is wrong in the policies, at a file, line and column when Cedar says where. */
|
|
25
|
+
export interface PolicyProblem {
|
|
26
|
+
file?: string;
|
|
27
|
+
line?: number;
|
|
28
|
+
column?: number;
|
|
29
|
+
/** The policy's id, when the problem is in one. */
|
|
30
|
+
policy?: string;
|
|
31
|
+
message: string;
|
|
32
|
+
}
|
|
33
|
+
/** `<root>/policies/**\/*.cedar`, sorted by path, each relative to the root with `/` between its parts. */
|
|
34
|
+
export declare function readPolicyFiles(root: string): {
|
|
35
|
+
file: string;
|
|
36
|
+
text: string;
|
|
37
|
+
}[];
|
|
38
|
+
/**
|
|
39
|
+
* Each file's policies, in the order written (`policySetTextToParts`, which sorts them, then
|
|
40
|
+
* their places in the text), each with its id and annotations (`policyToJson`): built once, the
|
|
41
|
+
* map from a policy's id to what decides its answer. A file that does not parse, a template and
|
|
42
|
+
* two policies with one id are problems.
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadPolicies(files: readonly {
|
|
45
|
+
file: string;
|
|
46
|
+
text: string;
|
|
47
|
+
}[]): {
|
|
48
|
+
policies: CedarPolicySource[];
|
|
49
|
+
problems: PolicyProblem[];
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* The policies checked against the schema of the resolved config (`validate`, strict), and what
|
|
53
|
+
* Cedar cannot check: a `permit` (the runtime's is the only one), and a `@hold` naming neither a
|
|
54
|
+
* declared group, nor a declared person, nor `on-behalf-of`. In the order written, each at its
|
|
55
|
+
* file, line and column, once per place: a policy scoped to every action fails the same way for each.
|
|
56
|
+
*/
|
|
57
|
+
export declare function validatePolicies(resolved: Pick<ResolvedConfig, "ops" | "workflows" | "collections">, policies: readonly CedarPolicySource[], people: readonly PeopleResource[]): PolicyProblem[];
|
|
58
|
+
/**
|
|
59
|
+
* The policy a repo's Cedar files make, the runtime's `permit` added; its `version` a hash of the
|
|
60
|
+
* policies' ids and text. It decides each call with `statefulIsAuthorized`
|
|
61
|
+
* over the policy set and the schema of `resolved` (`schemaOf`), each parsed once:
|
|
62
|
+
*
|
|
63
|
+
* - allow: `allow`, with the policies that allowed as `reasons`;
|
|
64
|
+
* - deny, a determining `forbid` without `@hold`: `deny` with its `@reason`, or "Refused by <id>";
|
|
65
|
+
* - deny by `@hold` forbids only: each lifted once an approval addressed to its approver and
|
|
66
|
+
* covering the operation is approved (`approvedFor`); allowed when all are, else `approve` for
|
|
67
|
+
* the first, in the order written, with its `@title` and its id as `reasons`.
|
|
68
|
+
*
|
|
69
|
+
* An approver is a declared group (`{ group }`), a declared person's id, or the principal's
|
|
70
|
+
* `onBehalfOf`; a principal acting for no one makes `on-behalf-of` a deny, "cannot resolve
|
|
71
|
+
* approver". A policy that fails to evaluate is a deny naming it (Cedar would skip it), as is one
|
|
72
|
+
* reading a field a `before` lacks: a record saved under fields since changed is asked about
|
|
73
|
+
* without the schema, so it can still be fixed or deleted.
|
|
74
|
+
* `preview` asks the same ahead of a call, its context unknown; `start`, about a run's start.
|
|
75
|
+
*/
|
|
76
|
+
export declare function cedarPolicy(resolved: Pick<ResolvedConfig, "ops" | "workflows" | "collections">, policies: readonly CedarPolicySource[], people: readonly PeopleResource[]): Policy;
|
|
77
|
+
/**
|
|
78
|
+
* The policy of the repo at `root`: its `policies/**\/*.cedar` over `resolved` and the people its
|
|
79
|
+
* data files declare (`readPeople`, `cedarPolicy`), or `allowAll` when it has none. With problems
|
|
80
|
+
* (`loadPolicies`, `validatePolicies`), each a printable line (`file:line:col: <policy id>:
|
|
81
|
+
* <message>`), a policy that refuses every call, start and preview naming the first: a repo never
|
|
82
|
+
* runs on part of its rules.
|
|
83
|
+
*/
|
|
84
|
+
export declare function policyAt(root: string | undefined, resolved: Pick<ResolvedConfig, "ops" | "workflows" | "collections">): {
|
|
85
|
+
policy: Policy;
|
|
86
|
+
problems: string[];
|
|
87
|
+
};
|
package/dist/cedar.js
ADDED
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { readFileSync } from "node:fs";
|
|
3
|
+
import { join, relative, sep } from "node:path";
|
|
4
|
+
import { locator } from "./ast.js";
|
|
5
|
+
import { filesUnder } from "./paths.js";
|
|
6
|
+
import { allow, allowAll, approve, approvedFor, deny, denyAll, } from "./policy.js";
|
|
7
|
+
import { readPeople } from "./resources.js";
|
|
8
|
+
import { cedarValue, cedarWasm, contextTypeOf, messageOf, NAMESPACE, schemaOf } from "./schema.js";
|
|
9
|
+
import { approverLabel, approverOf, DATA_VENDOR, groupNamesOf, principalIdsOf, principalOf, problemLine, WORKFLOW_ACTION, } from "./shared.js";
|
|
10
|
+
// A company's policies in Cedar (`policies/**/*.cedar`), decided with `@cedar-policy/cedar-wasm`
|
|
11
|
+
// against the schema of its resolved config (`schemaOf`). Allow is the default: the runtime adds
|
|
12
|
+
// the one `permit`, so a company's policies are `forbid`s, each a hold when it carries
|
|
13
|
+
// `@hold(...)` and a deny otherwise.
|
|
14
|
+
/** Where a company's policies are, under its root. */
|
|
15
|
+
export const POLICIES_DIR = "policies";
|
|
16
|
+
/** The runtime's own policy: allow whatever no `forbid` refuses. */
|
|
17
|
+
const ALLOW_ID = "allow-by-default";
|
|
18
|
+
const ALLOW = "permit (principal, action, resource);";
|
|
19
|
+
/** The `@hold` that addresses the principal's `onBehalfOf`. */
|
|
20
|
+
const ON_BEHALF_OF = "on-behalf-of";
|
|
21
|
+
/** `<root>/policies/**\/*.cedar`, sorted by path, each relative to the root with `/` between its parts. */
|
|
22
|
+
export function readPolicyFiles(root) {
|
|
23
|
+
return filesUnder(join(root, POLICIES_DIR), (name) => name.endsWith(".cedar")).map((path) => ({
|
|
24
|
+
file: relative(root, path).split(sep).join("/"),
|
|
25
|
+
text: readFileSync(path, "utf8"),
|
|
26
|
+
}));
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Each file's policies, in the order written (`policySetTextToParts`, which sorts them, then
|
|
30
|
+
* their places in the text), each with its id and annotations (`policyToJson`): built once, the
|
|
31
|
+
* map from a policy's id to what decides its answer. A file that does not parse, a template and
|
|
32
|
+
* two policies with one id are problems.
|
|
33
|
+
*/
|
|
34
|
+
export function loadPolicies(files) {
|
|
35
|
+
const cedar = cedarWasm();
|
|
36
|
+
const policies = [];
|
|
37
|
+
const problems = [];
|
|
38
|
+
const ids = new Set([ALLOW_ID]);
|
|
39
|
+
for (const { file, text } of files) {
|
|
40
|
+
const locate = locator(text);
|
|
41
|
+
const parts = cedar.policySetTextToParts(text);
|
|
42
|
+
if (parts.type === "failure") {
|
|
43
|
+
problems.push(...parts.errors.map((e) => problemOf(e, file, text)));
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
for (const template of parts.policy_templates) {
|
|
47
|
+
problems.push({
|
|
48
|
+
file,
|
|
49
|
+
...locate(text.indexOf(template)),
|
|
50
|
+
message: "a template (`?principal`, `?resource`) is not a policy: name the principal or resource",
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const placed = new Set();
|
|
54
|
+
const inOrder = parts.policies
|
|
55
|
+
.map((part) => {
|
|
56
|
+
let offset = text.indexOf(part);
|
|
57
|
+
while (offset >= 0 && placed.has(offset))
|
|
58
|
+
offset = text.indexOf(part, offset + 1);
|
|
59
|
+
placed.add(offset);
|
|
60
|
+
// A part that is not a slice of the text (none is, as Cedar 4.14 cuts them) keeps Cedar's order, last.
|
|
61
|
+
return { part, offset: offset < 0 ? Infinity : offset };
|
|
62
|
+
})
|
|
63
|
+
.toSorted((a, b) => a.offset - b.offset);
|
|
64
|
+
inOrder.forEach(({ part, offset }, n) => {
|
|
65
|
+
const start = locate(Number.isFinite(offset) ? offset : 0);
|
|
66
|
+
const answer = cedar.policyToJson(part);
|
|
67
|
+
if (answer.type === "failure") {
|
|
68
|
+
problems.push(...answer.errors.map((e) => problemOf(e, file, part, start)));
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
const { effect, annotations = {} } = answer.json;
|
|
72
|
+
const id = annotations.id ?? `${file}#${n + 1}`;
|
|
73
|
+
if (ids.has(id)) {
|
|
74
|
+
const whose = id === ALLOW_ID ? "the runtime's own policy's" : "another policy's";
|
|
75
|
+
problems.push({ file, line: start.line, message: `the id "${id}" is ${whose}: give this one another @id` });
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
ids.add(id);
|
|
79
|
+
policies.push({
|
|
80
|
+
id,
|
|
81
|
+
text: part,
|
|
82
|
+
file,
|
|
83
|
+
...start,
|
|
84
|
+
effect,
|
|
85
|
+
...(annotations.hold !== undefined && { hold: annotations.hold }),
|
|
86
|
+
...(annotations.title !== undefined && { title: annotations.title }),
|
|
87
|
+
...(annotations.reason !== undefined && { reason: annotations.reason }),
|
|
88
|
+
});
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
return { policies, problems };
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* The policies checked against the schema of the resolved config (`validate`, strict), and what
|
|
95
|
+
* Cedar cannot check: a `permit` (the runtime's is the only one), and a `@hold` naming neither a
|
|
96
|
+
* declared group, nor a declared person, nor `on-behalf-of`. In the order written, each at its
|
|
97
|
+
* file, line and column, once per place: a policy scoped to every action fails the same way for each.
|
|
98
|
+
*/
|
|
99
|
+
export function validatePolicies(resolved, policies, people) {
|
|
100
|
+
const answer = cedarWasm().validate({
|
|
101
|
+
schema: schemaOf(resolved, people),
|
|
102
|
+
policies: { staticPolicies: Object.fromEntries(policies.map((p) => [p.id, p.text])) },
|
|
103
|
+
validationSettings: { mode: "strict" },
|
|
104
|
+
});
|
|
105
|
+
if (answer.type === "failure")
|
|
106
|
+
return answer.errors.map((e) => ({ message: messageOf(e) }));
|
|
107
|
+
return policies.flatMap((p) => {
|
|
108
|
+
const place = { file: p.file, line: p.line, policy: p.id };
|
|
109
|
+
const places = new Set();
|
|
110
|
+
const cedar = answer.validationErrors
|
|
111
|
+
.filter(({ policyId }) => policyId === p.id)
|
|
112
|
+
.map(({ error }) => ({ ...problemOf(error, p.file, p.text, p), policy: p.id }))
|
|
113
|
+
.filter(({ line, column }) => {
|
|
114
|
+
// Cedar's errors without a place are each their own.
|
|
115
|
+
if (column === undefined)
|
|
116
|
+
return true;
|
|
117
|
+
const at = `${line}:${column}`;
|
|
118
|
+
return !places.has(at) && Boolean(places.add(at));
|
|
119
|
+
})
|
|
120
|
+
.toSorted((a, b) => a.line - b.line || (a.column ?? 0) - (b.column ?? 0));
|
|
121
|
+
const ours = [];
|
|
122
|
+
if (p.effect === "permit") {
|
|
123
|
+
ours.push({ ...place, message: "a permit changes nothing: every call no forbid refuses is allowed already" });
|
|
124
|
+
}
|
|
125
|
+
else if (p.hold !== undefined && p.hold !== ON_BEHALF_OF && approverOf(p.hold, people) === undefined) {
|
|
126
|
+
ours.push({ ...place, message: `@hold("${p.hold}") names no declared group or person, nor "${ON_BEHALF_OF}"` });
|
|
127
|
+
}
|
|
128
|
+
return [...cedar, ...ours];
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* The policy a repo's Cedar files make, the runtime's `permit` added; its `version` a hash of the
|
|
133
|
+
* policies' ids and text. It decides each call with `statefulIsAuthorized`
|
|
134
|
+
* over the policy set and the schema of `resolved` (`schemaOf`), each parsed once:
|
|
135
|
+
*
|
|
136
|
+
* - allow: `allow`, with the policies that allowed as `reasons`;
|
|
137
|
+
* - deny, a determining `forbid` without `@hold`: `deny` with its `@reason`, or "Refused by <id>";
|
|
138
|
+
* - deny by `@hold` forbids only: each lifted once an approval addressed to its approver and
|
|
139
|
+
* covering the operation is approved (`approvedFor`); allowed when all are, else `approve` for
|
|
140
|
+
* the first, in the order written, with its `@title` and its id as `reasons`.
|
|
141
|
+
*
|
|
142
|
+
* An approver is a declared group (`{ group }`), a declared person's id, or the principal's
|
|
143
|
+
* `onBehalfOf`; a principal acting for no one makes `on-behalf-of` a deny, "cannot resolve
|
|
144
|
+
* approver". A policy that fails to evaluate is a deny naming it (Cedar would skip it), as is one
|
|
145
|
+
* reading a field a `before` lacks: a record saved under fields since changed is asked about
|
|
146
|
+
* without the schema, so it can still be fixed or deleted.
|
|
147
|
+
* `preview` asks the same ahead of a call, its context unknown; `start`, about a run's start.
|
|
148
|
+
*/
|
|
149
|
+
export function cedarPolicy(resolved, policies, people) {
|
|
150
|
+
const cedar = cedarWasm();
|
|
151
|
+
const schema = schemaOf(resolved, people);
|
|
152
|
+
const staticPolicies = { ...Object.fromEntries(policies.map((p) => [p.id, p.text])), [ALLOW_ID]: ALLOW };
|
|
153
|
+
const version = hash(staticPolicies);
|
|
154
|
+
// Cedar caches both per thread, by name: one for these policies over this schema.
|
|
155
|
+
const set = `sanoma-${hash({ staticPolicies, schema })}`;
|
|
156
|
+
for (const answer of [cedar.preparsePolicySet(set, { staticPolicies }), cedar.preparseSchema(set, schema)]) {
|
|
157
|
+
if (answer.type === "failure") {
|
|
158
|
+
throw new Error(`The Cedar policies do not parse: ${answer.errors.map(messageOf).join("; ")}`);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
const directory = directoryOf(people);
|
|
162
|
+
/**
|
|
163
|
+
* The determining `forbid`s, in the order written, each with whom it holds for: the first that
|
|
164
|
+
* refuses (no `@hold`, else a hold for no one), or the holds.
|
|
165
|
+
*/
|
|
166
|
+
const forbidsOf = (ids, principal) => {
|
|
167
|
+
const holds = policies
|
|
168
|
+
.filter((p) => p.effect === "forbid" && ids.includes(p.id))
|
|
169
|
+
.map((p) => ({ p, approver: p.hold === undefined ? undefined : holdOf(p.hold, principal, people) }));
|
|
170
|
+
const refusing = holds.find(({ p }) => p.hold === undefined) ?? holds.find(({ approver }) => !approver);
|
|
171
|
+
return { refusing: refusing?.p, holds };
|
|
172
|
+
};
|
|
173
|
+
/** What `request` is about: a workflow start on its `Workflow`, an operation on its target, in its collection for `data`. */
|
|
174
|
+
const requestOf = (principal, action, target, context) => {
|
|
175
|
+
const entities = directory.entities(principal);
|
|
176
|
+
let resource;
|
|
177
|
+
if (action.startsWith(WORKFLOW_ACTION)) {
|
|
178
|
+
resource = uid("Workflow", action.slice(WORKFLOW_ACTION.length));
|
|
179
|
+
}
|
|
180
|
+
else {
|
|
181
|
+
resource = uid("Target", target ?? action);
|
|
182
|
+
const op = resolved.ops.get(action);
|
|
183
|
+
const parents = op?.vendor === DATA_VENDOR ? [uid("Collection", op.resource)] : [];
|
|
184
|
+
entities.push({ uid: resource, attrs: {}, parents });
|
|
185
|
+
}
|
|
186
|
+
const type = contextTypeOf(schema, action);
|
|
187
|
+
return {
|
|
188
|
+
principal: uid("Principal", principal.id),
|
|
189
|
+
action: uid("Action", action),
|
|
190
|
+
resource,
|
|
191
|
+
context: (type ? cedarValue(context(Object.keys(type.attributes)), type) : {}),
|
|
192
|
+
entities,
|
|
193
|
+
};
|
|
194
|
+
};
|
|
195
|
+
/** May `actor` take `action` on `target` with `context`, given the run's `approvals` so far. */
|
|
196
|
+
const authorize = (actor, action, target, context, approvals) => {
|
|
197
|
+
const principal = directory.principal(actor);
|
|
198
|
+
const check = (asked) => cedar.statefulIsAuthorized({
|
|
199
|
+
...requestOf(principal, action, target, () => asked),
|
|
200
|
+
preparsedSchemaName: set,
|
|
201
|
+
validateRequest: true,
|
|
202
|
+
preparsedPolicySetId: set,
|
|
203
|
+
});
|
|
204
|
+
let answer = check(context);
|
|
205
|
+
// A record saved under fields since changed does not fit the schema as `before`. When the rest
|
|
206
|
+
// of the call does, it is asked again without the schema (the context is plain values), the
|
|
207
|
+
// action's groups given as entities: a policy reading a field the record lacks fails, so denies.
|
|
208
|
+
const { before, ...rest } = context;
|
|
209
|
+
if (answer.type === "failure" && before !== undefined && check(rest).type === "success") {
|
|
210
|
+
const request = requestOf(principal, action, target, () => context);
|
|
211
|
+
const groups = schema[NAMESPACE]?.actions[action]?.memberOf ?? [];
|
|
212
|
+
request.entities.push({ uid: request.action, attrs: {}, parents: groups.map((g) => uid("Action", g.id)) });
|
|
213
|
+
answer = cedar.statefulIsAuthorized({ ...request, preparsedPolicySetId: set });
|
|
214
|
+
}
|
|
215
|
+
// A request the schema refuses (an input Cedar cannot hold) is denied, not an error of the call.
|
|
216
|
+
if (answer.type === "failure")
|
|
217
|
+
return deny(`The call does not fit the Cedar schema: ${answer.errors.map(messageOf).join("; ")}`);
|
|
218
|
+
const { decision, diagnostics } = answer.response;
|
|
219
|
+
const failed = diagnostics.errors[0];
|
|
220
|
+
if (failed)
|
|
221
|
+
return deny(`${failed.policyId} failed: ${messageOf(failed.error)}`, [failed.policyId]);
|
|
222
|
+
const reasons = diagnostics.reason;
|
|
223
|
+
if (decision === "allow")
|
|
224
|
+
return allow(reasons);
|
|
225
|
+
const { refusing, holds } = forbidsOf(reasons, principal);
|
|
226
|
+
if (refusing) {
|
|
227
|
+
return deny(refusing.hold === undefined ? (refusing.reason ?? `Refused by ${refusing.id}`) : "cannot resolve approver", reasons);
|
|
228
|
+
}
|
|
229
|
+
const waiting = holds.find(({ approver }) => !approvedFor(approvals, action, approver));
|
|
230
|
+
if (!waiting)
|
|
231
|
+
return allow(reasons);
|
|
232
|
+
const approver = waiting.approver;
|
|
233
|
+
const title = waiting.p.title ?? `${action} needs ${approverLabel(approver)}`;
|
|
234
|
+
return approve(approver, { title, reasons: [waiting.p.id] });
|
|
235
|
+
};
|
|
236
|
+
const decide = (call) => authorize(call.actor, call.op.id, call.target, { input: call.input, ...(call.before !== undefined && { before: call.before }) }, call.run.approvals);
|
|
237
|
+
const start = (actor, workflow, input, approvals = []) => authorize(actor, `${WORKFLOW_ACTION}${workflow}`, undefined, { input }, approvals);
|
|
238
|
+
const preview = (requests) => requests.map(({ principal: actor, action, resource }) => {
|
|
239
|
+
const principal = directory.principal(actor);
|
|
240
|
+
const answer = cedar.isAuthorizedPartial({
|
|
241
|
+
...requestOf(principal, action.id, resource, unknown),
|
|
242
|
+
schema,
|
|
243
|
+
validateRequest: false,
|
|
244
|
+
policies: { staticPolicies },
|
|
245
|
+
});
|
|
246
|
+
if (answer.type === "failure")
|
|
247
|
+
throw new Error(answer.errors.map(messageOf).join("; "));
|
|
248
|
+
const { decision, mustBeDetermining, nontrivialResiduals, residuals } = answer.response;
|
|
249
|
+
if (decision === "allow")
|
|
250
|
+
return { answer: "allow" };
|
|
251
|
+
if (decision === "deny") {
|
|
252
|
+
const { refusing, holds } = forbidsOf(mustBeDetermining, principal);
|
|
253
|
+
const first = holds[0];
|
|
254
|
+
if (refusing || !first)
|
|
255
|
+
return { answer: "deny", ...(refusing && { rule: ruleOf(refusing) }) };
|
|
256
|
+
return { answer: "hold", rule: ruleOf(first.p), approver: first.approver };
|
|
257
|
+
}
|
|
258
|
+
// Undecided: a residual forbid whose conditions fold to false cannot apply.
|
|
259
|
+
const open = policies.find((p) => nontrivialResiduals.includes(p.id) && mayApply(residuals[p.id]));
|
|
260
|
+
return open ? { answer: "depends", rule: ruleOf(open) } : { answer: "allow" };
|
|
261
|
+
});
|
|
262
|
+
return Object.freeze(Object.assign(decide, { version, preview, start }));
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* The policy of the repo at `root`: its `policies/**\/*.cedar` over `resolved` and the people its
|
|
266
|
+
* data files declare (`readPeople`, `cedarPolicy`), or `allowAll` when it has none. With problems
|
|
267
|
+
* (`loadPolicies`, `validatePolicies`), each a printable line (`file:line:col: <policy id>:
|
|
268
|
+
* <message>`), a policy that refuses every call, start and preview naming the first: a repo never
|
|
269
|
+
* runs on part of its rules.
|
|
270
|
+
*/
|
|
271
|
+
export function policyAt(root, resolved) {
|
|
272
|
+
const files = root === undefined ? [] : readPolicyFiles(root);
|
|
273
|
+
if (!files.length)
|
|
274
|
+
return { policy: allowAll, problems: [] };
|
|
275
|
+
const { people } = readPeople(root);
|
|
276
|
+
const { policies, problems } = loadPolicies(files);
|
|
277
|
+
problems.push(...validatePolicies(resolved, policies, people));
|
|
278
|
+
if (!problems.length)
|
|
279
|
+
return { policy: cedarPolicy(resolved, policies, people), problems: [] };
|
|
280
|
+
const lines = problems.map(({ policy, ...p }) => problemLine({ ...p, message: policy ? `${policy}: ${p.message}` : p.message }));
|
|
281
|
+
return { policy: denyAll(`The policies do not hold: ${lines[0]}`), problems: lines };
|
|
282
|
+
}
|
|
283
|
+
/** A policy as a preview names it. */
|
|
284
|
+
const ruleOf = (p) => ({
|
|
285
|
+
id: p.id,
|
|
286
|
+
file: p.file,
|
|
287
|
+
...(p.title !== undefined && { title: p.title }),
|
|
288
|
+
...(p.reason !== undefined && { reason: p.reason }),
|
|
289
|
+
});
|
|
290
|
+
/** The first 12 hex digits of a SHA-256 of `value` as JSON. */
|
|
291
|
+
const hash = (value) => createHash("sha256").update(JSON.stringify(value)).digest("hex").slice(0, 12);
|
|
292
|
+
const uid = (type, id) => ({ type: `${NAMESPACE}::${type}`, id });
|
|
293
|
+
/** Every field of a context unknown: partial evaluation leaves what depends on it. */
|
|
294
|
+
const unknown = (names) => Object.fromEntries(names.map((name) => [name, { __extn: { fn: "unknown", arg: name } }]));
|
|
295
|
+
/** Whom `@hold(hold)` holds the call for, resolved for `principal`: undefined when it names no one. */
|
|
296
|
+
const holdOf = (hold, principal, people) => hold === ON_BEHALF_OF ? principal.onBehalfOf : approverOf(hold, people);
|
|
297
|
+
/** The people as Cedar entities, made once: each a `Principal` in its groups, with `onBehalfOf` when it acts for someone. */
|
|
298
|
+
function directoryOf(people) {
|
|
299
|
+
const groups = new Set(groupNamesOf(people));
|
|
300
|
+
const principal = (actor) => {
|
|
301
|
+
// An admitted principal (`admit`) carries its groups as the files say now: those are taken as
|
|
302
|
+
// they are. One without groups is given those declared when the policy was made.
|
|
303
|
+
const declared = actor.groups === undefined ? principalOf(actor.id, people) : undefined;
|
|
304
|
+
const onBehalfOf = actor.onBehalfOf ?? declared?.onBehalfOf;
|
|
305
|
+
return {
|
|
306
|
+
...actor,
|
|
307
|
+
groups: [...new Set([...(actor.groups ?? []), ...(declared?.groups ?? [])])],
|
|
308
|
+
...(onBehalfOf !== undefined && { onBehalfOf }),
|
|
309
|
+
};
|
|
310
|
+
};
|
|
311
|
+
const entityOf = (p) => ({
|
|
312
|
+
uid: uid("Principal", p.id),
|
|
313
|
+
attrs: p.onBehalfOf === undefined ? {} : { onBehalfOf: { __entity: uid("Principal", p.onBehalfOf) } },
|
|
314
|
+
// Only the groups the schema enumerates: Cedar refuses any other.
|
|
315
|
+
parents: (p.groups ?? []).filter((g) => groups.has(g)).map((g) => uid("Group", g)),
|
|
316
|
+
});
|
|
317
|
+
const declared = new Map(principalIdsOf(people).map((id) => [id, entityOf(principal({ id }))]));
|
|
318
|
+
return {
|
|
319
|
+
principal,
|
|
320
|
+
entities: (actor) => {
|
|
321
|
+
const actingFor = actor.onBehalfOf === undefined || actor.onBehalfOf === actor.id ? undefined : declared.get(actor.onBehalfOf);
|
|
322
|
+
return [entityOf(actor), ...(actingFor ? [actingFor] : [])];
|
|
323
|
+
},
|
|
324
|
+
};
|
|
325
|
+
}
|
|
326
|
+
/** False when one of a residual policy's conditions is already decided against it. */
|
|
327
|
+
const mayApply = ({ conditions }) => !conditions.some((c) => folded(c.body) === (c.kind === "unless"));
|
|
328
|
+
/** A residual's value when its constants decide it, else undefined: partial evaluation leaves `unknown && false` as it is. */
|
|
329
|
+
function folded(expr) {
|
|
330
|
+
const e = expr;
|
|
331
|
+
if ("Value" in e)
|
|
332
|
+
return typeof e.Value === "boolean" ? e.Value : undefined;
|
|
333
|
+
if (e["!"]) {
|
|
334
|
+
const arg = folded(e["!"].arg);
|
|
335
|
+
return arg === undefined ? undefined : !arg;
|
|
336
|
+
}
|
|
337
|
+
const pair = e["&&"] ?? e["||"];
|
|
338
|
+
if (pair) {
|
|
339
|
+
const and = e["&&"] !== undefined;
|
|
340
|
+
const [l, r] = [folded(pair.left), folded(pair.right)];
|
|
341
|
+
// `and`: false decides it, true twice makes it; `or`: the other way round.
|
|
342
|
+
if (l === !and || r === !and)
|
|
343
|
+
return !and;
|
|
344
|
+
return l === and && r === and ? and : undefined;
|
|
345
|
+
}
|
|
346
|
+
if (e["if-then-else"]) {
|
|
347
|
+
const { if: test, then, else: otherwise } = e["if-then-else"];
|
|
348
|
+
const t = folded(test);
|
|
349
|
+
return t === undefined ? undefined : folded(t ? then : otherwise);
|
|
350
|
+
}
|
|
351
|
+
return undefined;
|
|
352
|
+
}
|
|
353
|
+
/** A Cedar error in `text`, which starts at `start` in `file` (the file's start when it is the file), as a problem at its place. */
|
|
354
|
+
function problemOf(error, file, text, start = { line: 1, column: 1 }) {
|
|
355
|
+
const byte = error.sourceLocations?.[0]?.start;
|
|
356
|
+
if (byte === undefined)
|
|
357
|
+
return { file, line: start.line, message: messageOf(error) };
|
|
358
|
+
// Cedar counts bytes; a line and column count characters.
|
|
359
|
+
const at = locator(text)(Buffer.from(text).subarray(0, byte).toString().length);
|
|
360
|
+
const place = at.line === 1
|
|
361
|
+
? { line: start.line, column: start.column + at.column - 1 }
|
|
362
|
+
: { line: start.line + at.line - 1, column: at.column };
|
|
363
|
+
return { file, ...place, message: messageOf(error) };
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=cedar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cedar.js","sourceRoot":"","sources":["../src/cedar.ts"],"names":[],"mappings":"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"}
|
package/dist/client.d.ts
CHANGED
|
@@ -33,7 +33,7 @@ export interface RunSummary {
|
|
|
33
33
|
runId: string;
|
|
34
34
|
workflow: string;
|
|
35
35
|
status: RunStatus;
|
|
36
|
-
/** Who started the run, as
|
|
36
|
+
/** Who started the run, as `start` admitted them. */
|
|
37
37
|
startedBy?: Principal;
|
|
38
38
|
createdAt: number;
|
|
39
39
|
updatedAt?: number;
|
|
@@ -43,12 +43,17 @@ export interface RunSummary {
|
|
|
43
43
|
sandbox?: string;
|
|
44
44
|
}
|
|
45
45
|
export interface StartOptions {
|
|
46
|
-
/**
|
|
47
|
-
|
|
46
|
+
/**
|
|
47
|
+
* Who starts it, by id (`"ada"`, or `{ id: "ada" }`): recorded as the run's actor in the ledger
|
|
48
|
+
* and passed to the policy. When the data files declare people, the run is started as the
|
|
49
|
+
* declared principal (`principalOf`: their groups, not any given here), and an id nobody
|
|
50
|
+
* declares is refused with `not_admitted`.
|
|
51
|
+
*/
|
|
52
|
+
startedBy: Principal | string;
|
|
48
53
|
/**
|
|
49
54
|
* Use this run id instead of a new one, so a retried start makes one run. Starting an id
|
|
50
55
|
* that exists returns it, without starting another, when the workflow, the input (compared
|
|
51
|
-
* as JSON), `startedBy` and `sandbox` are the same, and throws `invalid_input` naming what differs
|
|
56
|
+
* as JSON), `startedBy`'s id and `sandbox` are the same, and throws `invalid_input` naming what differs
|
|
52
57
|
* when they are not. Of two starts racing with one new id, the first's run stands.
|
|
53
58
|
*/
|
|
54
59
|
runId?: string;
|
|
@@ -59,6 +64,19 @@ export interface StartOptions {
|
|
|
59
64
|
*/
|
|
60
65
|
sandbox?: string;
|
|
61
66
|
}
|
|
67
|
+
/** What `SanomaClient.call` takes besides the operation's id and its input. */
|
|
68
|
+
export interface CallOptions {
|
|
69
|
+
/**
|
|
70
|
+
* Who calls, by id, admitted as `startedBy` is: the policy decides as them, a write's record
|
|
71
|
+
* names them, and a save's `updatedBy` is their id.
|
|
72
|
+
*/
|
|
73
|
+
actor: Principal | string;
|
|
74
|
+
/**
|
|
75
|
+
* The call's id, so a retried write is made once: the same id with the same input returns what
|
|
76
|
+
* the first call returned, with another input is refused (`invalid_input`). A new one by default.
|
|
77
|
+
*/
|
|
78
|
+
id?: string;
|
|
79
|
+
}
|
|
62
80
|
/** Talks to the runtime from another process (the app, a script), through the shared Postgres. */
|
|
63
81
|
export declare class SanomaClient {
|
|
64
82
|
private readonly dbos;
|
|
@@ -68,6 +86,8 @@ export declare class SanomaClient {
|
|
|
68
86
|
private readonly audit;
|
|
69
87
|
/** On the config's database, for the credentials table: opened on first use. */
|
|
70
88
|
private readonly credentialsPool;
|
|
89
|
+
/** What a direct call's driver reads secrets from, as a worker's live driver does. */
|
|
90
|
+
private readonly storedSecrets;
|
|
71
91
|
private constructor();
|
|
72
92
|
/**
|
|
73
93
|
* Connects to the runtime's Postgres for the config's app. Checks the config first and throws
|
|
@@ -82,6 +102,54 @@ export declare class SanomaClient {
|
|
|
82
102
|
* `workflow` is a definition, or the name of one in the config's `workflows`.
|
|
83
103
|
*/
|
|
84
104
|
start<S extends z.ZodType>(workflow: WorkflowDefinition<any, S> | string, input: z.input<S>, options: StartOptions): Promise<string>;
|
|
105
|
+
/**
|
|
106
|
+
* The policy's answer to starting a run of `workflow` as `startedBy` (`decideStart`), for a
|
|
107
|
+
* workflow of the config's own: a deny throws `policy_denied`; a hold is what the run waits on
|
|
108
|
+
* before its body. A run `runId` names already is returned as it is, whatever the policy says now.
|
|
109
|
+
*/
|
|
110
|
+
private startHold;
|
|
111
|
+
/**
|
|
112
|
+
* Calls an operation directly, outside a run, as `actor`: one that may be (`isDirect`), a
|
|
113
|
+
* collection's or a vendor's read, never a vendor's write, the runtime's own or a resource
|
|
114
|
+
* type's (`invalid_input`, as is an unknown id or input its schema refuses). The policy decides
|
|
115
|
+
* it as the person, in a run `direct:<actor>:<id>` of the workflow `call` with no approvals. A
|
|
116
|
+
* deny throws `policy_denied` and writes nothing. An allowed call runs the driver once, without
|
|
117
|
+
* DBOS and without a retry (a driver's failure is `driver_failed`). A read returns its output
|
|
118
|
+
* and records nothing. A write is recorded as one `op.called` (seq 0) in that run, and with the
|
|
119
|
+
* default ledger in one transaction with the record it saves, so both are written or neither;
|
|
120
|
+
* a write with the same id and input returns the output recorded. When the policy asks for an
|
|
121
|
+
* approval, the call becomes run `call:<actor>:<id>` of the built-in `call` workflow, started
|
|
122
|
+
* as the person, which makes it once approved, and this throws `approval_pending` with its id.
|
|
123
|
+
*/
|
|
124
|
+
call(opId: string, input: unknown, options: CallOptions): Promise<unknown>;
|
|
125
|
+
/**
|
|
126
|
+
* A direct write, made once and recorded once: with the default ledger, a collection's write
|
|
127
|
+
* and its record in one transaction on the database both are in, so both are kept or neither;
|
|
128
|
+
* otherwise the driver's call, then the record in the config's ledger. The first record of the
|
|
129
|
+
* call's id stands: a write that finds one already there (two calls with one id at once) is
|
|
130
|
+
* undone, and answers as `recordedCall` does.
|
|
131
|
+
*/
|
|
132
|
+
private directWrite;
|
|
133
|
+
/**
|
|
134
|
+
* What the direct write recorded as `runId` returned, when one did: refused (`invalid_input`)
|
|
135
|
+
* when it was of another operation or input, and its failure again (`driver_failed`) when it failed.
|
|
136
|
+
*/
|
|
137
|
+
private recordedCall;
|
|
138
|
+
/**
|
|
139
|
+
* What the held call's run `heldId` returned once it ended (its error, when it failed);
|
|
140
|
+
* `approval_pending` while it has not; undefined when there is no such run. Refused
|
|
141
|
+
* (`invalid_input`) when the run was started with another input or by someone else.
|
|
142
|
+
*/
|
|
143
|
+
private heldCall;
|
|
144
|
+
/**
|
|
145
|
+
* The newest finished run of the workflow, with its output and when it finished; null when it
|
|
146
|
+
* has none. One query, whatever the app's runs.
|
|
147
|
+
*/
|
|
148
|
+
latest(workflow: string): Promise<{
|
|
149
|
+
runId: string;
|
|
150
|
+
output: unknown;
|
|
151
|
+
at: number;
|
|
152
|
+
} | null>;
|
|
85
153
|
/** The run's audit record, in order, from the ledger store. */
|
|
86
154
|
ledger(runId: string): Promise<LedgerRecord[]>;
|
|
87
155
|
/**
|
|
@@ -142,7 +210,8 @@ export declare class SanomaClient {
|
|
|
142
210
|
* loads it into its environment, unless its environment sets the variable itself. Refuses
|
|
143
211
|
* (`invalid_input`) a name no driver declares, and a value the variable's schema refuses, with
|
|
144
212
|
* the schema's reason and never the value; an empty value too (`clearCredential` unsets one).
|
|
145
|
-
* Nothing records the value but its row, which records `by` and when.
|
|
213
|
+
* Nothing records the value but its row, which records `by` and when. `by` is admitted as
|
|
214
|
+
* `start`'s `startedBy` is (`not_admitted`).
|
|
146
215
|
*/
|
|
147
216
|
setCredential(name: string, value: string, options: {
|
|
148
217
|
by: string;
|
|
@@ -150,7 +219,7 @@ export declare class SanomaClient {
|
|
|
150
219
|
/**
|
|
151
220
|
* Deletes the stored value of a declared variable, and tells the workers, which unset it unless
|
|
152
221
|
* their environment sets it. `by` is who asks; nothing records it once the row is gone.
|
|
153
|
-
* Refuses (`invalid_input`) a name no driver declares.
|
|
222
|
+
* Refuses (`invalid_input`) a name no driver declares, and `by` as `setCredential` does.
|
|
154
223
|
*/
|
|
155
224
|
clearCredential(name: string, options: {
|
|
156
225
|
by: string;
|
|
@@ -185,9 +254,18 @@ export declare class SanomaClient {
|
|
|
185
254
|
private declared;
|
|
186
255
|
/** The pool the credentials are read and written with, on the database once it is prepared. */
|
|
187
256
|
private credentialsDb;
|
|
257
|
+
/**
|
|
258
|
+
* The principal as the data files declare it (`admit`): its id alone is taken, never the groups
|
|
259
|
+
* a caller gives, and an id nobody declares is `not_admitted`.
|
|
260
|
+
*/
|
|
261
|
+
private admitted;
|
|
262
|
+
/** `options.by`, who sets or clears a credential, admitted (`admitted`): their id. */
|
|
263
|
+
private admittedBy;
|
|
188
264
|
/** Refuses a run id whose run, as stored, was started with another input, by someone else, or in another sandbox. */
|
|
189
265
|
private mustMatch;
|
|
190
|
-
/** The run's status row, read without its input (and its output, unless asked),
|
|
266
|
+
/** The run's status row, read without its input (and its output, unless asked), if there is one. */
|
|
267
|
+
private row;
|
|
268
|
+
/** The run's status row, as `row` reads it, or `run_not_found`. */
|
|
191
269
|
private mustExist;
|
|
192
270
|
/** The run's output once it ends, or its error, polled every 100 ms; `run_running` after `timeoutMs`. */
|
|
193
271
|
private awaitResult;
|