@xeplr/workflow-engine 0.0.0-stage → 1.0.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/LICENSE +21 -0
- package/README.md +182 -2
- package/db/xcfgSetup.js +8 -0
- package/index.js +290 -0
- package/lib/actionCatalog.js +197 -0
- package/lib/actions/jobChainSteps.js +79 -0
- package/lib/actions/jobRun.js +171 -0
- package/lib/actions/screenShow.js +71 -0
- package/lib/auth.js +19 -0
- package/lib/db.js +82 -0
- package/lib/envExposed.js +87 -0
- package/lib/flows.js +916 -0
- package/lib/jobChains.js +426 -0
- package/lib/workflowRunner.js +652 -0
- package/migrations/0003_workflows.sql +35 -0
- package/migrations/0004_workflow_steps.sql +79 -0
- package/migrations/0005_workflow_runs.sql +49 -0
- package/migrations/0006_workflow_step_runs.sql +42 -0
- package/migrations/0007_workflow_resume_keys.sql +42 -0
- package/migrations/0008_workflow_run_edges.sql +43 -0
- package/migrations/0009_workflow_steps_layout.sql +11 -0
- package/migrations/0010_workflow_steps_sample_output.sql +17 -0
- package/migrations/0011_workflow_steps_params.sql +27 -0
- package/migrations/0012_workflows_kind.sql +27 -0
- package/migrations/0013_workflows_key.sql +48 -0
- package/migrations/0014_workflows_trigger.sql +30 -0
- package/migrations-tenants/0001_companies.sql +23 -0
- package/migrations-tenants/0002_workspaces.sql +22 -0
- package/models/Company.js +82 -0
- package/models/Workflow.js +67 -0
- package/models/WorkflowResumeKey.js +32 -0
- package/models/WorkflowRun.js +64 -0
- package/models/WorkflowRunEdge.js +49 -0
- package/models/WorkflowStep.js +66 -0
- package/models/WorkflowStepRun.js +49 -0
- package/models/Workspace.js +75 -0
- package/models/index.js +25 -0
- package/package.json +47 -4
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// WHICH ENV VARS A WORKFLOW STEP MAY REFERENCE, as `{env.NAME}`.
|
|
2
|
+
//
|
|
3
|
+
// Nothing, unless named:
|
|
4
|
+
//
|
|
5
|
+
// WORKFLOW_ENV_EXPOSED=PUBLIC_BASE_URL,DEPLOY_TAG
|
|
6
|
+
//
|
|
7
|
+
// AN ALLOWLIST, NOT A DENYLIST, and that is the whole design. A denylist works
|
|
8
|
+
// on the day it is written and fails silently afterwards: the day somebody
|
|
9
|
+
// adds STRIPE_SECRET_KEY to the environment it is readable until a second
|
|
10
|
+
// person remembers to go and hide it. This way a new variable is invisible
|
|
11
|
+
// until it is deliberately published, so the failure mode of forgetting is
|
|
12
|
+
// "the template renders empty" rather than "the key leaked".
|
|
13
|
+
//
|
|
14
|
+
// WHY THIS MATTERS MORE THAN IT LOOKS. A resolved step input is not private:
|
|
15
|
+
//
|
|
16
|
+
// - POST /workflows/:id/steps/try ECHOES the interpolated input straight
|
|
17
|
+
// back to the browser, by design, so the builder can show what it sent
|
|
18
|
+
// (see lib/router.js). The step does not even have to be saved — `values`
|
|
19
|
+
// comes off the request body.
|
|
20
|
+
// - workflowRunner writes the resolved values into WorkflowStepRun.input,
|
|
21
|
+
// where they stay for the life of the run history.
|
|
22
|
+
//
|
|
23
|
+
// So without a list, "can author a workflow step" would silently mean "can
|
|
24
|
+
// read ENCRYPTION_KEY and AUTH_JWT_SECRET" — the two that decrypt every
|
|
25
|
+
// stored connection string and mint a token for any user. Both halves of that
|
|
26
|
+
// escalation look ordinary in an access-control table, which is exactly why
|
|
27
|
+
// it has to be shut off here rather than noticed later.
|
|
28
|
+
//
|
|
29
|
+
// KEEP SECRETS OFF THIS LIST. It is for values that are awkward to hardcode
|
|
30
|
+
// per environment and harmless to read: a public base URL, an environment
|
|
31
|
+
// tag, a bucket name. A credential belongs on the path where the ACTION reads
|
|
32
|
+
// it server-side at execution time and it never enters the template context
|
|
33
|
+
// at all — that is what `useCustomConnection: false` on the email actions
|
|
34
|
+
// does with SMTP_*, and it is strictly safer than any list.
|
|
35
|
+
|
|
36
|
+
// Exact names only. No prefixes and no globs: `PUBLIC_*` reads as a small
|
|
37
|
+
// convenience right up until somebody names a secret PUBLIC_something, and
|
|
38
|
+
// then the list no longer says what it exposes. A literal '*' matches a
|
|
39
|
+
// variable actually called '*', which does not exist — so the tempting
|
|
40
|
+
// shortcut fails closed rather than exposing everything.
|
|
41
|
+
function exposedNames() {
|
|
42
|
+
var raw = process.env.WORKFLOW_ENV_EXPOSED;
|
|
43
|
+
if (!raw) return [];
|
|
44
|
+
return String(raw).split(',')
|
|
45
|
+
.map(function(n) { return n.trim(); })
|
|
46
|
+
.filter(function(n) { return n.length > 0; });
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* The `env` branch of a step's interpolation context.
|
|
51
|
+
*
|
|
52
|
+
* Read per call rather than memoized at load: this module is required before
|
|
53
|
+
* the host has finished loading its .env in at least one boot order, and a
|
|
54
|
+
* snapshot taken then would be permanently empty with nothing to explain it.
|
|
55
|
+
* The cost is splitting a short string once per step.
|
|
56
|
+
*
|
|
57
|
+
* A name on the list that is not set is OMITTED rather than included as
|
|
58
|
+
* undefined — either way `{env.NAME}` renders as empty string, since that is
|
|
59
|
+
* what interpolate() does with any unknown path (see @xeplr/schema-handler's
|
|
60
|
+
* templating.js). Worth knowing when debugging: a misspelled name and an
|
|
61
|
+
* unexposed one look identical in the output.
|
|
62
|
+
*/
|
|
63
|
+
function exposedEnv() {
|
|
64
|
+
var out = {};
|
|
65
|
+
exposedNames().forEach(function(name) {
|
|
66
|
+
if (process.env[name] !== undefined) out[name] = process.env[name];
|
|
67
|
+
});
|
|
68
|
+
return out;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Say at boot what is readable, so it is a fact in the log rather than a
|
|
73
|
+
* thing you would have to go and derive from an .env file. A list that
|
|
74
|
+
* accidentally names a secret is only catchable if somebody can see it.
|
|
75
|
+
*/
|
|
76
|
+
function logExposure() {
|
|
77
|
+
var names = exposedNames();
|
|
78
|
+
if (!names.length) return;
|
|
79
|
+
var missing = names.filter(function(n) { return process.env[n] === undefined; });
|
|
80
|
+
console.log('[workflow] {env.*} exposes ' + names.length + ' var(s) to step templates: ' + names.join(', '));
|
|
81
|
+
if (missing.length) {
|
|
82
|
+
console.warn('[workflow] WORKFLOW_ENV_EXPOSED names ' + missing.length +
|
|
83
|
+
' var(s) that are not set (they resolve to empty string): ' + missing.join(', '));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
module.exports = { exposedNames: exposedNames, exposedEnv: exposedEnv, logExposure: logExposure };
|