@sanoma-ai/workflows 0.0.0-stage → 0.2.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.
- package/LICENSE +105 -0
- package/README.md +544 -2
- package/dist/apply-steps.d.ts +6 -0
- package/dist/apply-steps.js +93 -0
- package/dist/apply-steps.js.map +1 -0
- package/dist/apply.d.ts +197 -0
- package/dist/apply.js +470 -0
- package/dist/apply.js.map +1 -0
- package/dist/approvals.d.ts +46 -0
- package/dist/approvals.js +111 -0
- package/dist/approvals.js.map +1 -0
- package/dist/ast.d.ts +57 -0
- package/dist/ast.js +81 -0
- package/dist/ast.js.map +1 -0
- package/dist/call.d.ts +37 -0
- package/dist/call.js +417 -0
- package/dist/call.js.map +1 -0
- package/dist/client.d.ts +203 -0
- package/dist/client.js +457 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +126 -0
- package/dist/config.js +264 -0
- package/dist/config.js.map +1 -0
- package/dist/credentials.d.ts +55 -0
- package/dist/credentials.js +261 -0
- package/dist/credentials.js.map +1 -0
- package/dist/cucumber.d.ts +64 -0
- package/dist/cucumber.js +158 -0
- package/dist/cucumber.js.map +1 -0
- package/dist/datafile.d.ts +71 -0
- package/dist/datafile.js +380 -0
- package/dist/datafile.js.map +1 -0
- package/dist/db.d.ts +58 -0
- package/dist/db.js +179 -0
- package/dist/db.js.map +1 -0
- package/dist/define.d.ts +205 -0
- package/dist/define.js +103 -0
- package/dist/define.js.map +1 -0
- package/dist/describe.d.ts +141 -0
- package/dist/describe.js +135 -0
- package/dist/describe.js.map +1 -0
- package/dist/drift.d.ts +127 -0
- package/dist/drift.js +167 -0
- package/dist/drift.js.map +1 -0
- package/dist/env.d.ts +49 -0
- package/dist/env.js +83 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +88 -0
- package/dist/errors.js +148 -0
- package/dist/errors.js.map +1 -0
- package/dist/expectations.d.ts +26 -0
- package/dist/expectations.js +162 -0
- package/dist/expectations.js.map +1 -0
- package/dist/fake.d.ts +55 -0
- package/dist/fake.js +87 -0
- package/dist/fake.js.map +1 -0
- package/dist/fill.d.ts +9 -0
- package/dist/fill.js +17 -0
- package/dist/fill.js.map +1 -0
- package/dist/host.d.ts +56 -0
- package/dist/host.js +45 -0
- package/dist/host.js.map +1 -0
- package/dist/index.d.ts +23 -0
- package/dist/index.js +29 -0
- package/dist/index.js.map +1 -0
- package/dist/ledger.d.ts +217 -0
- package/dist/ledger.js +251 -0
- package/dist/ledger.js.map +1 -0
- package/dist/lint.d.ts +32 -0
- package/dist/lint.js +168 -0
- package/dist/lint.js.map +1 -0
- package/dist/lockfile.d.ts +36 -0
- package/dist/lockfile.js +69 -0
- package/dist/lockfile.js.map +1 -0
- package/dist/log.d.ts +24 -0
- package/dist/log.js +83 -0
- package/dist/log.js.map +1 -0
- package/dist/op.d.ts +260 -0
- package/dist/op.js +188 -0
- package/dist/op.js.map +1 -0
- package/dist/outline.d.ts +179 -0
- package/dist/outline.js +506 -0
- package/dist/outline.js.map +1 -0
- package/dist/paths.d.ts +11 -0
- package/dist/paths.js +30 -0
- package/dist/paths.js.map +1 -0
- package/dist/plugin.d.ts +28 -0
- package/dist/plugin.js +25 -0
- package/dist/plugin.js.map +1 -0
- package/dist/policy.d.ts +114 -0
- package/dist/policy.js +60 -0
- package/dist/policy.js.map +1 -0
- package/dist/resource.d.ts +378 -0
- package/dist/resource.js +430 -0
- package/dist/resource.js.map +1 -0
- package/dist/resources.d.ts +77 -0
- package/dist/resources.js +244 -0
- package/dist/resources.js.map +1 -0
- package/dist/run.d.ts +101 -0
- package/dist/run.js +7 -0
- package/dist/run.js.map +1 -0
- package/dist/sandbox.d.ts +33 -0
- package/dist/sandbox.js +127 -0
- package/dist/sandbox.js.map +1 -0
- package/dist/scenario.d.ts +221 -0
- package/dist/scenario.js +1104 -0
- package/dist/scenario.js.map +1 -0
- package/dist/scenarios.d.ts +55 -0
- package/dist/scenarios.js +71 -0
- package/dist/scenarios.js.map +1 -0
- package/dist/secret.d.ts +42 -0
- package/dist/secret.js +58 -0
- package/dist/secret.js.map +1 -0
- package/dist/shared.d.ts +69 -0
- package/dist/shared.js +84 -0
- package/dist/shared.js.map +1 -0
- package/dist/source.d.ts +58 -0
- package/dist/source.js +54 -0
- package/dist/source.js.map +1 -0
- package/dist/steps.d.ts +76 -0
- package/dist/steps.js +23 -0
- package/dist/steps.js.map +1 -0
- package/dist/version.d.ts +29 -0
- package/dist/version.js +76 -0
- package/dist/version.js.map +1 -0
- package/dist/worker.d.ts +37 -0
- package/dist/worker.js +228 -0
- package/dist/worker.js.map +1 -0
- package/dist/writer.d.ts +35 -0
- package/dist/writer.js +201 -0
- package/dist/writer.js.map +1 -0
- package/oxlint.json +128 -0
- package/package.json +96 -3
- package/src/apply-steps.ts +110 -0
- package/src/apply.ts +626 -0
- package/src/approvals.ts +157 -0
- package/src/ast.ts +115 -0
- package/src/call.ts +483 -0
- package/src/client.ts +604 -0
- package/src/config.ts +404 -0
- package/src/credentials.ts +296 -0
- package/src/cucumber.ts +230 -0
- package/src/datafile.ts +481 -0
- package/src/db.ts +197 -0
- package/src/define.ts +285 -0
- package/src/describe.ts +282 -0
- package/src/drift.ts +259 -0
- package/src/env.ts +122 -0
- package/src/errors.ts +202 -0
- package/src/expectations.ts +191 -0
- package/src/fake.ts +156 -0
- package/src/fill.ts +24 -0
- package/src/host.ts +96 -0
- package/src/index.ts +143 -0
- package/src/ledger.ts +419 -0
- package/src/lint.ts +208 -0
- package/src/lockfile.ts +95 -0
- package/src/log.ts +82 -0
- package/src/op.ts +402 -0
- package/src/outline.ts +620 -0
- package/src/paths.ts +32 -0
- package/src/plugin.ts +37 -0
- package/src/policy.ts +139 -0
- package/src/resource.ts +670 -0
- package/src/resources.ts +311 -0
- package/src/run.ts +106 -0
- package/src/sandbox.ts +161 -0
- package/src/scenario.ts +1365 -0
- package/src/scenarios.ts +111 -0
- package/src/secret.ts +92 -0
- package/src/shared.ts +126 -0
- package/src/source.ts +82 -0
- package/src/steps.ts +90 -0
- package/src/version.ts +86 -0
- package/src/worker.ts +264 -0
- package/src/writer.ts +225 -0
package/dist/config.js
ADDED
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
import { existsSync, readFileSync, statSync } from "node:fs";
|
|
2
|
+
import { dirname, join, resolve } from "node:path";
|
|
3
|
+
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { DBOS } from "@dbos-inc/dbos-sdk";
|
|
5
|
+
import { applyWorkflow } from "./apply.js";
|
|
6
|
+
import { applySteps } from "./apply-steps.js";
|
|
7
|
+
import { callerFile } from "./define.js";
|
|
8
|
+
import { DRIFT_WORKFLOW, driftWorkflow } from "./drift.js";
|
|
9
|
+
import { statusesOf, unconfigured } from "./env.js";
|
|
10
|
+
import { DriverError, isOp, checkConnector, setupOf, VENDOR, } from "./op.js";
|
|
11
|
+
import { isChangeOp, resourceTypesOf, withoutWriteOnly } from "./resource.js";
|
|
12
|
+
import { APPLY_WORKFLOW, BUILT_IN_WORKFLOWS } from "./shared.js";
|
|
13
|
+
import { sourceDriver, sourceOps } from "./source.js";
|
|
14
|
+
import { computeVersion } from "./version.js";
|
|
15
|
+
export const DEFAULT_DATABASE_URL = "postgresql://postgres:dbos@localhost:5433/sanoma";
|
|
16
|
+
/** Returns the config, with the file it is called from as its `file`: its directory is the config's `root`. */
|
|
17
|
+
export function defineConfig(config) {
|
|
18
|
+
return { ...config, file: config.file ?? callerFile() };
|
|
19
|
+
}
|
|
20
|
+
export function resolveDatabaseUrl(config, env = process.env) {
|
|
21
|
+
return config.databaseUrl ?? env.SANOMA_DATABASE_URL ?? DEFAULT_DATABASE_URL;
|
|
22
|
+
}
|
|
23
|
+
const isStore = (x) => typeof x?.append === "function" && typeof x.read === "function";
|
|
24
|
+
/** The config's `ledger`, checked, when it gives one. */
|
|
25
|
+
function ledgerOf(config) {
|
|
26
|
+
if (config.ledger !== undefined && !isStore(config.ledger)) {
|
|
27
|
+
throw new Error("The config's `ledger` must be a ledger store: leave it out for `postgresLedger` on the config's database, " +
|
|
28
|
+
"or use `jsonlLedger(dir)` to keep records in files, or `memoryLedger()` to keep them in memory, for tests");
|
|
29
|
+
}
|
|
30
|
+
return config.ledger;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The config's directory, absolute: its `root`, else its `file`'s directory; undefined when it
|
|
34
|
+
* has neither. No fallback to the working directory: a config found nowhere has no data files,
|
|
35
|
+
* and says so. What a read that needs only the root calls, rather than `resolveConfig`.
|
|
36
|
+
*/
|
|
37
|
+
export function rootOf(config) {
|
|
38
|
+
return config.root !== undefined
|
|
39
|
+
? resolve(config.root)
|
|
40
|
+
: config.file !== undefined
|
|
41
|
+
? dirname(config.file)
|
|
42
|
+
: undefined;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Checks a config and derives what the runtime needs from it: the drivers and fakes from the
|
|
46
|
+
* connectors' setups (`withSetup`), and from `root`, the app's name (`package.json`) and the
|
|
47
|
+
* scenarios (`scenarios/`). Throws what `startWorker` would refuse, with the same message, so
|
|
48
|
+
* `describeConfig`, `SanomaClient.connect` and the app fail the same way the worker does. It
|
|
49
|
+
* opens nothing and reads no file outside `root`. Each entry
|
|
50
|
+
* point resolves once: the worker and the client when they start, the app at `startApp`, the
|
|
51
|
+
* `sanoma` bin when it loads the config.
|
|
52
|
+
*/
|
|
53
|
+
export function resolveConfig(config) {
|
|
54
|
+
if (!Array.isArray(config.connectors)) {
|
|
55
|
+
throw new Error("The config needs `connectors`: the connectors its workflows call, as their packages export them");
|
|
56
|
+
}
|
|
57
|
+
for (const connector of config.connectors)
|
|
58
|
+
checkConnector(connector);
|
|
59
|
+
if (!Array.isArray(config.workflows)) {
|
|
60
|
+
throw new Error("The config needs `workflows`: an array of defineWorkflow definitions");
|
|
61
|
+
}
|
|
62
|
+
if (typeof config.policy !== "function") {
|
|
63
|
+
throw new Error("The config needs a `policy`; use `allowAll` to allow every operation call");
|
|
64
|
+
}
|
|
65
|
+
// An untyped config naming fake drivers would otherwise run live. Delete once sanoma-ops has migrated.
|
|
66
|
+
if (config.drivers !== undefined || config.fakes !== undefined)
|
|
67
|
+
throw new Error("The config's `drivers` and `fakes` are gone: each connector carries its driver and its fake; leave them out");
|
|
68
|
+
const ledger = ledgerOf(config);
|
|
69
|
+
const root = rootOf(config);
|
|
70
|
+
const appName = appNameAt(root);
|
|
71
|
+
const scenarios = scenariosAt(root);
|
|
72
|
+
const types = resourceTypesOf(config.connectors);
|
|
73
|
+
// Built-in: `sanoma.source.resolve`, which apply and drift call for a host's revision.
|
|
74
|
+
const hosts = [...types.values()].some((type) => type.host);
|
|
75
|
+
const ops = indexConnectors([...config.connectors, ...(hosts ? [sourceOps] : [])]);
|
|
76
|
+
const driversByVendor = new Map([...makersOf(config.connectors, "driver")].map(([vendor, make]) => [vendor, make()]));
|
|
77
|
+
const drivers = indexDrivers([...driversByVendor.values(), ...(hosts ? [sourceDriver] : [])], ops);
|
|
78
|
+
const fakes = makersOf(config.connectors, "fake");
|
|
79
|
+
const names = new Map();
|
|
80
|
+
for (const wf of config.workflows) {
|
|
81
|
+
if (BUILT_IN_WORKFLOWS.has(wf.name)) {
|
|
82
|
+
throw new Error(`A workflow is named "${wf.name}", the name of a built-in workflow; name it otherwise`);
|
|
83
|
+
}
|
|
84
|
+
checkUses(wf, ops, drivers, types);
|
|
85
|
+
const other = names.get(wf.name);
|
|
86
|
+
if (other && other !== wf) {
|
|
87
|
+
throw new Error(`Two different workflow definitions are named "${wf.name}"; a name can be registered once per process`);
|
|
88
|
+
}
|
|
89
|
+
names.set(wf.name, wf);
|
|
90
|
+
}
|
|
91
|
+
// Built-in: checking the resources the data files declare against their vendors, and applying them.
|
|
92
|
+
if (types.size) {
|
|
93
|
+
const read = () => readDeclared(root, config.connectors, types);
|
|
94
|
+
names.set(DRIFT_WORKFLOW, driftWorkflow(types, ops, drivers, () => DBOS.runStep(read, { name: "drift:data-files" })));
|
|
95
|
+
names.set(APPLY_WORKFLOW, applyWorkflow(types, ops, drivers, applySteps(appName, root, read)));
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
appName,
|
|
99
|
+
databaseUrl: resolveDatabaseUrl(config),
|
|
100
|
+
// The built-in's code and operations are part of the app's version, like the config's own.
|
|
101
|
+
version: computeVersion({ appName, workflows: [...names.values()] }),
|
|
102
|
+
queueName: `sanoma:${appName}`,
|
|
103
|
+
ops,
|
|
104
|
+
drivers,
|
|
105
|
+
driversByVendor,
|
|
106
|
+
fakes,
|
|
107
|
+
...(scenarios && { scenarios }),
|
|
108
|
+
types,
|
|
109
|
+
steps: [...new Set([...config.connectors.flatMap((c) => setupOf(c).steps ?? []), ...(config.steps ?? [])])],
|
|
110
|
+
workflows: names,
|
|
111
|
+
policy: config.policy,
|
|
112
|
+
...(ledger !== undefined && { ledger }),
|
|
113
|
+
...(root !== undefined && { root }),
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* What the connectors' setups attach under `key` (`withSetup`), by vendor id in `connectors`
|
|
118
|
+
* order. One vendor's connectors may name one maker, as copies of one connector do, never two.
|
|
119
|
+
*/
|
|
120
|
+
function makersOf(connectors, key) {
|
|
121
|
+
const makers = new Map();
|
|
122
|
+
for (const connector of connectors) {
|
|
123
|
+
const make = setupOf(connector)[key];
|
|
124
|
+
if (make === undefined)
|
|
125
|
+
continue;
|
|
126
|
+
const vendor = connector[VENDOR].id;
|
|
127
|
+
const seen = makers.get(vendor);
|
|
128
|
+
if (seen && seen !== make) {
|
|
129
|
+
throw new Error(`Two connectors in \`connectors\` attach a ${key} for "${vendor}"; keep one per vendor`);
|
|
130
|
+
}
|
|
131
|
+
makers.set(vendor, make);
|
|
132
|
+
}
|
|
133
|
+
return makers;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* The `name` of `<root>/package.json`, kept whole (`@acme/ops`), when that file exists and names
|
|
137
|
+
* one; else "sanoma", as for a config with no `root`. Never a `package.json` above the root: a
|
|
138
|
+
* parent project's name must not become the app's. A file that is not JSON is refused, naming it.
|
|
139
|
+
*/
|
|
140
|
+
function appNameAt(root) {
|
|
141
|
+
const file = root === undefined ? undefined : join(root, "package.json");
|
|
142
|
+
if (file === undefined || !existsSync(file))
|
|
143
|
+
return "sanoma";
|
|
144
|
+
let manifest;
|
|
145
|
+
try {
|
|
146
|
+
manifest = JSON.parse(readFileSync(file, "utf8"));
|
|
147
|
+
}
|
|
148
|
+
catch (err) {
|
|
149
|
+
throw new Error(`${file} is not JSON, so it names no app: ${err.message}`, { cause: err });
|
|
150
|
+
}
|
|
151
|
+
const named = manifest?.name;
|
|
152
|
+
return typeof named === "string" && named.trim() ? named.trim() : "sanoma";
|
|
153
|
+
}
|
|
154
|
+
/** `<root>/scenarios/`, as a `file:` URL to the directory (with its trailing slash), when it is a directory. */
|
|
155
|
+
function scenariosAt(root) {
|
|
156
|
+
const dir = root === undefined ? undefined : join(root, "scenarios");
|
|
157
|
+
if (dir === undefined || !statSync(dir, { throwIfNoEntry: false })?.isDirectory())
|
|
158
|
+
return undefined;
|
|
159
|
+
return pathToFileURL(`${dir}/`);
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* The data files under `root` and the lockfile beside them, in one read, as a drift or apply run
|
|
163
|
+
* records them: each resource with its binding, without its write-only values (a secret marker
|
|
164
|
+
* names one, and stays), which a run never compares and never records, the bindings, the orphans
|
|
165
|
+
* and the problems.
|
|
166
|
+
*/
|
|
167
|
+
async function readDeclared(root, connectors, types) {
|
|
168
|
+
// Loaded when a run reads the files, not with the worker: the reader parses with oxc-parser.
|
|
169
|
+
const { readDataFiles } = await import("./resources.js");
|
|
170
|
+
const { resources, bindings, orphans, problems } = readDataFiles(root, connectors, types);
|
|
171
|
+
return {
|
|
172
|
+
resources: resources.map(({ id, vendor, type, name, identity, binding, desired, refs }) => ({
|
|
173
|
+
id,
|
|
174
|
+
vendor,
|
|
175
|
+
type,
|
|
176
|
+
name,
|
|
177
|
+
...(identity !== undefined && { identity }),
|
|
178
|
+
...(binding !== undefined && { binding }),
|
|
179
|
+
desired: withoutWriteOnly(types.get(`${vendor}.${type}`).fields, desired),
|
|
180
|
+
refs,
|
|
181
|
+
})),
|
|
182
|
+
bindings,
|
|
183
|
+
orphans,
|
|
184
|
+
problems,
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
function indexConnectors(list) {
|
|
188
|
+
const map = new Map();
|
|
189
|
+
for (const connector of list) {
|
|
190
|
+
for (const resource of Object.values(connector)) {
|
|
191
|
+
for (const op of Object.values(resource)) {
|
|
192
|
+
if (!isOp(op))
|
|
193
|
+
continue;
|
|
194
|
+
const seen = map.get(op.id);
|
|
195
|
+
if (seen && seen !== op)
|
|
196
|
+
throw new Error(`Two connectors in \`connectors\` declare ${op.id}`);
|
|
197
|
+
map.set(op.id, op);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return map;
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* The drivers' functions by operation id, refusing one no connector declares. A driver that
|
|
205
|
+
* declares an `env` has each function guarded by it (`guarded`); a fake declares none, so a
|
|
206
|
+
* sandbox run's calls are not.
|
|
207
|
+
*/
|
|
208
|
+
export function indexDrivers(list, ops) {
|
|
209
|
+
const map = new Map();
|
|
210
|
+
for (const d of list) {
|
|
211
|
+
for (const [key, fn] of Object.entries(d.ops)) {
|
|
212
|
+
const id = `${d.vendor}.${key}`;
|
|
213
|
+
if (!ops.has(id)) {
|
|
214
|
+
throw new Error(`Driver "${d.vendor}" implements ${id}, which no connector in \`connectors\` declares`);
|
|
215
|
+
}
|
|
216
|
+
map.set(id, d.env ? guarded(d.vendor, d.env, fn) : fn);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
return map;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* `fn`, refused while the environment leaves a variable `env` declares missing or invalid. The
|
|
223
|
+
* worker started without it (`startWorker` only warns), and stored credentials load into the
|
|
224
|
+
* environment as they are set, so the check is made when the function is called, inside the
|
|
225
|
+
* driver step, and nowhere earlier: not at start, and not before the policy's decision or an
|
|
226
|
+
* approval hold, so a credential set on the connector page while a call waits for approval is
|
|
227
|
+
* used when the approver approves. The refusal is the call's own failure, final: recorded as
|
|
228
|
+
* the call's, and never retried.
|
|
229
|
+
*/
|
|
230
|
+
function guarded(vendor, env, fn) {
|
|
231
|
+
return async (input, call) => {
|
|
232
|
+
const why = unconfigured(vendor, statusesOf(env, (name) => process.env[name]));
|
|
233
|
+
if (why)
|
|
234
|
+
throw new DriverError(why, { retryable: false });
|
|
235
|
+
return fn(input, call);
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* Every operation a workflow uses must be one the config's connectors declare, with a driver.
|
|
240
|
+
* The workflow normally imports the same connector object; a copy is accepted only if it
|
|
241
|
+
* declares the same effect and retry setting, and the worker's declaration is used either way.
|
|
242
|
+
* None may change a declared resource (`isChangeOp`): only the built-in apply workflow does.
|
|
243
|
+
*/
|
|
244
|
+
function checkUses(wf, ops, impls, types) {
|
|
245
|
+
const problems = [];
|
|
246
|
+
for (const op of wf.uses.filter(isOp)) {
|
|
247
|
+
const known = ops.get(op.id);
|
|
248
|
+
if (!known)
|
|
249
|
+
problems.push(`${op.id} is not declared by any connector in \`connectors\``);
|
|
250
|
+
else if (isChangeOp(known, types)) {
|
|
251
|
+
problems.push(`${op.id} changes a declared resource, which only ${APPLY_WORKFLOW} does: change the data file instead`);
|
|
252
|
+
}
|
|
253
|
+
else if (known !== op && (known.effect !== op.effect || known.idempotent !== op.idempotent)) {
|
|
254
|
+
problems.push(`${op.id} is declared with effect "${op.effect}"${op.idempotent ? " (idempotent)" : ""}, ` +
|
|
255
|
+
`but its connector says "${known.effect}"${known.idempotent ? " (idempotent)" : ""}`);
|
|
256
|
+
}
|
|
257
|
+
else if (!impls.has(op.id)) {
|
|
258
|
+
problems.push(`\`${op.id}\` has no driver: the connector package must attach one`);
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if (problems.length)
|
|
262
|
+
throw new Error(`Workflow "${wf.name}": ${problems.join("; ")}`);
|
|
263
|
+
}
|
|
264
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { type Db } from "./db.ts";
|
|
2
|
+
import type { Driver } from "./op.ts";
|
|
3
|
+
import type { Secrets } from "./secret.ts";
|
|
4
|
+
/** The variable holding the key the stored values are encrypted with: 32 bytes, base64. */
|
|
5
|
+
export declare const SECRETS_KEY = "SANOMA_SECRETS_KEY";
|
|
6
|
+
/**
|
|
7
|
+
* `name`'s value encrypted for the table: `v1:<iv, base64>:<ciphertext and tag, base64>`,
|
|
8
|
+
* AES-256-GCM, with the name as associated data, so a value moved to another row does not decrypt.
|
|
9
|
+
*/
|
|
10
|
+
export declare function encrypt(name: string, value: string): string;
|
|
11
|
+
/** The value `name`'s row holds: decrypted, or a plaintext one as it is (it is encrypted on its next write). */
|
|
12
|
+
export declare function decrypt(name: string, stored: string): string;
|
|
13
|
+
/** The stored rows of these names, values included: for loading into an environment or checking, never for showing. */
|
|
14
|
+
export declare function storedCredentials(db: Db, names: readonly string[]): Promise<Map<string, {
|
|
15
|
+
value: string;
|
|
16
|
+
setBy: string;
|
|
17
|
+
setAt: string;
|
|
18
|
+
}>>;
|
|
19
|
+
/** Upserts the value and announces it, in one statement, so a worker never hears of a change it cannot read. */
|
|
20
|
+
export declare function storeCredential(db: Db, { name, value, setBy }: {
|
|
21
|
+
name: string;
|
|
22
|
+
value: string;
|
|
23
|
+
setBy: string;
|
|
24
|
+
}): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* The stored value of `name`; when there is none, `make()`'s, stored first and announced. Of two
|
|
27
|
+
* at once, the first stored wins, and both return it.
|
|
28
|
+
*/
|
|
29
|
+
export declare function ensureCredential(db: Db, { name, make, setBy }: {
|
|
30
|
+
name: string;
|
|
31
|
+
make: () => string;
|
|
32
|
+
setBy: string;
|
|
33
|
+
}): Promise<string>;
|
|
34
|
+
/**
|
|
35
|
+
* The secrets store a live driver is given (`CallContext.secrets`): a variable the environment
|
|
36
|
+
* sets wins, as it does for a driver's `env`; else the stored value. `ensure` stores what it
|
|
37
|
+
* makes as `setBy`.
|
|
38
|
+
*/
|
|
39
|
+
export declare function storedSecrets(db: () => Promise<Db>, setBy: string): Secrets;
|
|
40
|
+
/** Deletes the row, announcing it when there was one. */
|
|
41
|
+
export declare function deleteCredential(db: Db, name: string): Promise<void>;
|
|
42
|
+
/** Stops a worker's credentials listener. */
|
|
43
|
+
export interface CredentialsWatch {
|
|
44
|
+
close(): Promise<void>;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Loads the stored values of the declared variables the environment does not set into
|
|
48
|
+
* `process.env`, then keeps them current: on each change announced, and on reconnecting, it
|
|
49
|
+
* loads them again, so a value set replaces the one before and a value cleared is deleted. A
|
|
50
|
+
* name the environment set when this started is never touched, and the names it did set are
|
|
51
|
+
* deleted on `close`. Logs, per vendor, how many variables each load changed, never a value, and
|
|
52
|
+
* warns of a reloaded value its schema refuses. A listener that drops reconnects, waiting longer
|
|
53
|
+
* after each failure, up to 30 s, until it is closed. With no such variable, it connects to nothing.
|
|
54
|
+
*/
|
|
55
|
+
export declare function watchCredentials(databaseUrl: string, drivers: ReadonlyMap<string, Driver>): Promise<CredentialsWatch>;
|
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
import { createCipheriv, createDecipheriv, randomBytes } from "node:crypto";
|
|
2
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
3
|
+
import { Client } from "pg";
|
|
4
|
+
import { credentialsOf } from "./env.js";
|
|
5
|
+
import { CREDENTIALS_TABLE as TABLE, prepareDatabase } from "./db.js";
|
|
6
|
+
import { info, warn } from "./log.js";
|
|
7
|
+
import { errorMessage } from "./shared.js";
|
|
8
|
+
// Where the credentials set from the app live: one table in the config's database, beside DBOS's
|
|
9
|
+
// own (made by `prepareDatabase` in db.ts). A value is read here only, by the worker to load it
|
|
10
|
+
// into its environment or hand it to a driver (`storedSecrets`) and by the client to check it,
|
|
11
|
+
// and leaves none of them. The write (`storeCredential`, `ensureCredential`) and the read
|
|
12
|
+
// (`storedCredentials`) are the only places that touch `value`, which holds it encrypted
|
|
13
|
+
// (`encrypt`) under `SANOMA_SECRETS_KEY`.
|
|
14
|
+
/** Where a change is announced, with the variable's name as the payload. */
|
|
15
|
+
const CHANNEL = "sanoma_credentials";
|
|
16
|
+
/** The variable holding the key the stored values are encrypted with: 32 bytes, base64. */
|
|
17
|
+
export const SECRETS_KEY = "SANOMA_SECRETS_KEY";
|
|
18
|
+
/** What starts an encrypted value; a value without it is a plaintext one stored before encryption, read as it is. */
|
|
19
|
+
const V1 = "v1:";
|
|
20
|
+
const CIPHER = "aes-256-gcm";
|
|
21
|
+
const TAG_BYTES = 16;
|
|
22
|
+
/** The key from the environment, or an error naming the variable. */
|
|
23
|
+
function secretsKey() {
|
|
24
|
+
const text = process.env[SECRETS_KEY];
|
|
25
|
+
if (!text) {
|
|
26
|
+
throw new Error(`${SECRETS_KEY} is not set: it encrypts the stored credentials; set it to 32 random bytes, base64 (\`openssl rand -base64 32\`)`);
|
|
27
|
+
}
|
|
28
|
+
const key = Buffer.from(text, "base64");
|
|
29
|
+
if (key.length !== 32)
|
|
30
|
+
throw new Error(`${SECRETS_KEY} must be 32 bytes, base64; it is ${key.length} bytes`);
|
|
31
|
+
return key;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* `name`'s value encrypted for the table: `v1:<iv, base64>:<ciphertext and tag, base64>`,
|
|
35
|
+
* AES-256-GCM, with the name as associated data, so a value moved to another row does not decrypt.
|
|
36
|
+
*/
|
|
37
|
+
export function encrypt(name, value) {
|
|
38
|
+
const iv = randomBytes(12);
|
|
39
|
+
const cipher = createCipheriv(CIPHER, secretsKey(), iv).setAAD(Buffer.from(name));
|
|
40
|
+
const sealed = Buffer.concat([cipher.update(value, "utf8"), cipher.final(), cipher.getAuthTag()]);
|
|
41
|
+
return `${V1}${iv.toString("base64")}:${sealed.toString("base64")}`;
|
|
42
|
+
}
|
|
43
|
+
/** The value `name`'s row holds: decrypted, or a plaintext one as it is (it is encrypted on its next write). */
|
|
44
|
+
export function decrypt(name, stored) {
|
|
45
|
+
if (!stored.startsWith(V1))
|
|
46
|
+
return stored;
|
|
47
|
+
const key = secretsKey();
|
|
48
|
+
const [iv = "", body = ""] = stored.slice(V1.length).split(":");
|
|
49
|
+
const sealed = Buffer.from(body, "base64");
|
|
50
|
+
try {
|
|
51
|
+
const decipher = createDecipheriv(CIPHER, key, Buffer.from(iv, "base64")).setAAD(Buffer.from(name));
|
|
52
|
+
decipher.setAuthTag(sealed.subarray(-TAG_BYTES));
|
|
53
|
+
return Buffer.concat([decipher.update(sealed.subarray(0, -TAG_BYTES)), decipher.final()]).toString("utf8");
|
|
54
|
+
}
|
|
55
|
+
catch (err) {
|
|
56
|
+
throw new Error(`the stored ${name} cannot be decrypted: ${SECRETS_KEY} is not the key it was stored with, or the row was not stored as ${name}`, { cause: err });
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/** The stored rows of these names, values included: for loading into an environment or checking, never for showing. */
|
|
60
|
+
export async function storedCredentials(db, names) {
|
|
61
|
+
const { rows } = await db.query(`SELECT name, value, set_by, set_at FROM ${TABLE} WHERE name = ANY($1)`, [names]);
|
|
62
|
+
return new Map(rows.map((r) => [r.name, { value: decrypt(r.name, r.value), setBy: r.set_by, setAt: r.set_at.toISOString() }]));
|
|
63
|
+
}
|
|
64
|
+
/** Upserts the value and announces it, in one statement, so a worker never hears of a change it cannot read. */
|
|
65
|
+
export async function storeCredential(db, { name, value, setBy }) {
|
|
66
|
+
await db.query(`WITH stored AS (INSERT INTO ${TABLE} (name, value, set_by) VALUES ($1, $2, $3) ` +
|
|
67
|
+
"ON CONFLICT (name) DO UPDATE SET value = EXCLUDED.value, set_by = EXCLUDED.set_by, set_at = now() " +
|
|
68
|
+
`RETURNING name) SELECT pg_notify('${CHANNEL}', name) FROM stored`, [name, encrypt(name, value), setBy]);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* The stored value of `name`; when there is none, `make()`'s, stored first and announced. Of two
|
|
72
|
+
* at once, the first stored wins, and both return it.
|
|
73
|
+
*/
|
|
74
|
+
export async function ensureCredential(db, { name, make, setBy }) {
|
|
75
|
+
const stored = (await storedCredentials(db, [name])).get(name);
|
|
76
|
+
if (stored)
|
|
77
|
+
return stored.value;
|
|
78
|
+
await db.query(`WITH stored AS (INSERT INTO ${TABLE} (name, value, set_by) VALUES ($1, $2, $3) ON CONFLICT (name) DO NOTHING ` +
|
|
79
|
+
`RETURNING name) SELECT pg_notify('${CHANNEL}', name) FROM stored`, [name, encrypt(name, make()), setBy]);
|
|
80
|
+
return (await storedCredentials(db, [name])).get(name).value;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The secrets store a live driver is given (`CallContext.secrets`): a variable the environment
|
|
84
|
+
* sets wins, as it does for a driver's `env`; else the stored value. `ensure` stores what it
|
|
85
|
+
* makes as `setBy`.
|
|
86
|
+
*/
|
|
87
|
+
export function storedSecrets(db, setBy) {
|
|
88
|
+
return {
|
|
89
|
+
get: async (name) => process.env[name] || (await storedCredentials(await db(), [name])).get(name)?.value,
|
|
90
|
+
ensure: async (name, make) => process.env[name] || ensureCredential(await db(), { name, make, setBy }),
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Deletes the row, announcing it when there was one. */
|
|
94
|
+
export async function deleteCredential(db, name) {
|
|
95
|
+
await db.query(`WITH gone AS (DELETE FROM ${TABLE} WHERE name = $1 RETURNING name) SELECT pg_notify('${CHANNEL}', name) FROM gone`, [name]);
|
|
96
|
+
}
|
|
97
|
+
/** The longest wait between two attempts to reconnect the listener, and between two warnings that one failed. */
|
|
98
|
+
const RETRY_MAX_MS = 30_000;
|
|
99
|
+
/**
|
|
100
|
+
* Loads the stored values of the declared variables the environment does not set into
|
|
101
|
+
* `process.env`, then keeps them current: on each change announced, and on reconnecting, it
|
|
102
|
+
* loads them again, so a value set replaces the one before and a value cleared is deleted. A
|
|
103
|
+
* name the environment set when this started is never touched, and the names it did set are
|
|
104
|
+
* deleted on `close`. Logs, per vendor, how many variables each load changed, never a value, and
|
|
105
|
+
* warns of a reloaded value its schema refuses. A listener that drops reconnects, waiting longer
|
|
106
|
+
* after each failure, up to 30 s, until it is closed. With no such variable, it connects to nothing.
|
|
107
|
+
*/
|
|
108
|
+
export async function watchCredentials(databaseUrl, drivers) {
|
|
109
|
+
const vendors = new Map();
|
|
110
|
+
for (const [vendor, list] of credentialsOf(drivers, () => undefined)) {
|
|
111
|
+
for (const { name } of list)
|
|
112
|
+
if (!process.env[name] && !vendors.has(name))
|
|
113
|
+
vendors.set(name, vendor);
|
|
114
|
+
}
|
|
115
|
+
const names = [...vendors.keys()];
|
|
116
|
+
if (!names.length)
|
|
117
|
+
return { close: async () => undefined };
|
|
118
|
+
/** The listener's connection, from when it connects until it drops or closes. */
|
|
119
|
+
let db;
|
|
120
|
+
let closed = false;
|
|
121
|
+
let reconnecting = false;
|
|
122
|
+
// One load at a time, so close() can wait for it; the changes announced during one make one more.
|
|
123
|
+
let loading;
|
|
124
|
+
let stale = false;
|
|
125
|
+
async function load(first) {
|
|
126
|
+
const conn = db;
|
|
127
|
+
if (closed || !conn)
|
|
128
|
+
return;
|
|
129
|
+
const rows = await storedCredentials(conn, names);
|
|
130
|
+
// Nothing touches the environment once closed: a worker or an app started after may own it.
|
|
131
|
+
if (closed)
|
|
132
|
+
return;
|
|
133
|
+
const changed = names.filter((name) => rows.get(name)?.value !== process.env[name]);
|
|
134
|
+
const counts = new Map();
|
|
135
|
+
for (const name of changed) {
|
|
136
|
+
const value = rows.get(name)?.value;
|
|
137
|
+
if (value === undefined)
|
|
138
|
+
delete process.env[name];
|
|
139
|
+
else
|
|
140
|
+
process.env[name] = value;
|
|
141
|
+
const vendor = vendors.get(name);
|
|
142
|
+
counts.set(vendor, (counts.get(vendor) ?? 0) + 1);
|
|
143
|
+
}
|
|
144
|
+
const verb = first ? "loaded" : "reloaded";
|
|
145
|
+
for (const [vendor, n] of counts)
|
|
146
|
+
info(`credentials ${verb} for ${vendor} (${n} variable${n === 1 ? "" : "s"})`);
|
|
147
|
+
// At start, startWorker warns of an invalid one, naming it.
|
|
148
|
+
if (first)
|
|
149
|
+
return;
|
|
150
|
+
for (const list of credentialsOf(drivers, (name) => changed.includes(name) ? process.env[name] : undefined).values()) {
|
|
151
|
+
for (const c of list) {
|
|
152
|
+
if (c.status === "invalid")
|
|
153
|
+
warn(`the stored ${c.name} is invalid (${c.problem}): calls that read it will fail`);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
function reload(first = false) {
|
|
158
|
+
if (loading) {
|
|
159
|
+
stale = true;
|
|
160
|
+
return loading;
|
|
161
|
+
}
|
|
162
|
+
loading = (async () => {
|
|
163
|
+
try {
|
|
164
|
+
do {
|
|
165
|
+
stale = false;
|
|
166
|
+
await load(first);
|
|
167
|
+
first = false;
|
|
168
|
+
} while (stale);
|
|
169
|
+
}
|
|
170
|
+
finally {
|
|
171
|
+
loading = undefined;
|
|
172
|
+
}
|
|
173
|
+
})();
|
|
174
|
+
return loading;
|
|
175
|
+
}
|
|
176
|
+
async function open(first) {
|
|
177
|
+
const conn = new Client({ connectionString: databaseUrl, keepAlive: true, connectionTimeoutMillis: 10_000 });
|
|
178
|
+
// Before anything can fail: an error nobody listens for ends the process.
|
|
179
|
+
conn.on("error", (err) => lost(conn, err));
|
|
180
|
+
// Before LISTEN, so no change announced from then on is missed.
|
|
181
|
+
conn.on("notification", () => {
|
|
182
|
+
if (!closed && conn === db) {
|
|
183
|
+
reload().catch((err) => warn(`could not reload the credentials: ${errorMessage(err)}`));
|
|
184
|
+
}
|
|
185
|
+
});
|
|
186
|
+
try {
|
|
187
|
+
if (first)
|
|
188
|
+
await prepareDatabase(databaseUrl);
|
|
189
|
+
await conn.connect();
|
|
190
|
+
if (closed) {
|
|
191
|
+
await conn.end();
|
|
192
|
+
return;
|
|
193
|
+
}
|
|
194
|
+
db = conn;
|
|
195
|
+
await conn.query(`LISTEN ${CHANNEL}`);
|
|
196
|
+
await reload(first);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (db === conn)
|
|
200
|
+
db = undefined;
|
|
201
|
+
await conn.end().catch(() => undefined);
|
|
202
|
+
throw err;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
/** A connection that dropped: the one listening is replaced; one still connecting fails its own open. */
|
|
206
|
+
function lost(conn, err) {
|
|
207
|
+
if (closed || conn !== db)
|
|
208
|
+
return;
|
|
209
|
+
db = undefined;
|
|
210
|
+
void conn.end().catch(() => undefined);
|
|
211
|
+
warn(`the credentials listener failed (${errorMessage(err)}); reconnecting`);
|
|
212
|
+
void reconnect();
|
|
213
|
+
}
|
|
214
|
+
async function reconnect() {
|
|
215
|
+
if (reconnecting)
|
|
216
|
+
return;
|
|
217
|
+
reconnecting = true;
|
|
218
|
+
let wait = 1_000;
|
|
219
|
+
let warnedAt = 0;
|
|
220
|
+
try {
|
|
221
|
+
for (;;) {
|
|
222
|
+
await sleep(wait, undefined, { ref: false });
|
|
223
|
+
if (closed)
|
|
224
|
+
return;
|
|
225
|
+
try {
|
|
226
|
+
await open(false);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
catch (err) {
|
|
230
|
+
if (Date.now() - warnedAt >= RETRY_MAX_MS) {
|
|
231
|
+
warnedAt = Date.now();
|
|
232
|
+
warn(`could not reconnect the credentials listener (${errorMessage(err)}); trying again`);
|
|
233
|
+
}
|
|
234
|
+
wait = Math.min(wait * 2, RETRY_MAX_MS);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
finally {
|
|
239
|
+
reconnecting = false;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
await open(true);
|
|
244
|
+
}
|
|
245
|
+
catch (err) {
|
|
246
|
+
closed = true;
|
|
247
|
+
throw err;
|
|
248
|
+
}
|
|
249
|
+
return {
|
|
250
|
+
async close() {
|
|
251
|
+
closed = true;
|
|
252
|
+
await loading?.catch(() => undefined);
|
|
253
|
+
for (const name of names)
|
|
254
|
+
delete process.env[name];
|
|
255
|
+
const conn = db;
|
|
256
|
+
db = undefined;
|
|
257
|
+
await conn?.end();
|
|
258
|
+
},
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=credentials.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"credentials.js","sourceRoot":"","sources":["../src/credentials.ts"],"names":[],"mappings":"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"}
|