@multiplier-labs/stepflow 0.3.3 → 0.3.6

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 (84) hide show
  1. package/README.md +9 -0
  2. package/dist/{chunk-GYPNJBDP.js → chunk-D5HW7VEG.js} +269 -48
  3. package/dist/chunk-D5HW7VEG.js.map +1 -0
  4. package/dist/{chunk-KHTUWLVZ.js → chunk-FMPJBK2N.js} +55 -10
  5. package/dist/chunk-FMPJBK2N.js.map +1 -0
  6. package/dist/{chunk-ML35PIHX.js → chunk-JPXPB7U5.js} +52 -2
  7. package/dist/chunk-JPXPB7U5.js.map +1 -0
  8. package/dist/{chunk-4VOKMGP6.js → chunk-JUPZEBR3.js} +519 -522
  9. package/dist/chunk-JUPZEBR3.js.map +1 -0
  10. package/dist/events/index.d.ts +58 -3
  11. package/dist/events/index.js +1 -1
  12. package/dist/{index-Dzr437iW.d.ts → index-Cd0IZ40L.d.ts} +50 -11
  13. package/dist/index.d.ts +2 -12
  14. package/dist/index.js +764 -485
  15. package/dist/index.js.map +1 -1
  16. package/dist/scheduler/index.d.ts +1 -1
  17. package/dist/scheduler/index.js +2 -2
  18. package/dist/storage/index.d.ts +313 -47
  19. package/dist/storage/index.js +4 -2
  20. package/package.json +27 -13
  21. package/.codekin/reports/comments/2026-04-04_comment-assessment.md +0 -179
  22. package/.codekin/reports/complexity/2026-04-03_complexity-report.md +0 -152
  23. package/.codekin/reports/dependencies/2026-04-04_dependency-health.md +0 -94
  24. package/.codekin/reports/docs-audit/2026-04-04_docs-audit.md +0 -10
  25. package/.codekin/reports/security/2026-04-03_security-audit.md +0 -208
  26. package/.github/CODEOWNERS +0 -15
  27. package/.github/dependabot.yml +0 -23
  28. package/.github/workflows/ci.yml +0 -38
  29. package/.github/workflows/publish.yml +0 -36
  30. package/.github/workflows/security.yml +0 -29
  31. package/CHANGELOG.md +0 -34
  32. package/SECURITY.md +0 -40
  33. package/dist/chunk-4VOKMGP6.js.map +0 -1
  34. package/dist/chunk-GYPNJBDP.js.map +0 -1
  35. package/dist/chunk-KHTUWLVZ.js.map +0 -1
  36. package/dist/chunk-ML35PIHX.js.map +0 -1
  37. package/docs/github-packages-setup.md +0 -97
  38. package/docs/stepflow-api-reference.md +0 -1661
  39. package/src/core/engine.test.ts +0 -1365
  40. package/src/core/engine.ts +0 -692
  41. package/src/core/index.ts +0 -7
  42. package/src/core/orchestrator.ts +0 -571
  43. package/src/core/types.ts +0 -220
  44. package/src/events/index.ts +0 -8
  45. package/src/events/memory.test.ts +0 -107
  46. package/src/events/memory.ts +0 -92
  47. package/src/events/socketio.test.ts +0 -378
  48. package/src/events/socketio.ts +0 -262
  49. package/src/events/types.ts +0 -118
  50. package/src/events/webhook.test.ts +0 -657
  51. package/src/events/webhook.ts +0 -564
  52. package/src/index.ts +0 -270
  53. package/src/planning/index.ts +0 -55
  54. package/src/planning/planner.ts +0 -576
  55. package/src/planning/planning.test.ts +0 -727
  56. package/src/planning/registry.test.ts +0 -398
  57. package/src/planning/registry.ts +0 -365
  58. package/src/planning/types.ts +0 -566
  59. package/src/scheduler/cron.test.ts +0 -471
  60. package/src/scheduler/cron.ts +0 -414
  61. package/src/scheduler/index.ts +0 -8
  62. package/src/scheduler/postgres-persistence.ts +0 -518
  63. package/src/scheduler/sqlite-persistence.test.ts +0 -235
  64. package/src/scheduler/sqlite-persistence.ts +0 -261
  65. package/src/scheduler/types.ts +0 -73
  66. package/src/storage/index.ts +0 -27
  67. package/src/storage/memory.test.ts +0 -349
  68. package/src/storage/memory.ts +0 -227
  69. package/src/storage/postgres.ts +0 -1354
  70. package/src/storage/sqlite.test.ts +0 -466
  71. package/src/storage/sqlite.ts +0 -627
  72. package/src/storage/types.ts +0 -343
  73. package/src/utils/errors.test.ts +0 -150
  74. package/src/utils/errors.ts +0 -161
  75. package/src/utils/id.ts +0 -21
  76. package/src/utils/index.ts +0 -8
  77. package/src/utils/logger.test.ts +0 -121
  78. package/src/utils/logger.ts +0 -96
  79. package/src/utils/postgres-deps.ts +0 -63
  80. package/src/utils/retry.test.ts +0 -177
  81. package/src/utils/retry.ts +0 -121
  82. package/tsconfig.json +0 -21
  83. package/tsup.config.ts +0 -14
  84. package/vitest.config.ts +0 -9
@@ -1,208 +0,0 @@
1
- # Security Audit: stepflow
2
-
3
- **Date**: 2026-04-03T20:03:06.542Z
4
- **Repository**: /srv/repos/stepflow
5
- **Branch**: main
6
- **Workflow Run**: 54523493-771d-44b8-b39f-03f2d6caa49e
7
- **Session**: 53e402d9-8d47-49b4-9a27-03f2ae5ec912
8
-
9
- ---
10
-
11
- I now have all the information needed to produce the report. Here is the security audit:
12
-
13
- ---
14
-
15
- ## Summary
16
-
17
- **Overall Risk Rating: Low**
18
-
19
- The Stepflow project is a TypeScript workflow orchestration library with a mature security posture. No critical or high vulnerabilities were identified. The codebase demonstrates intentional, defence-in-depth practices: parameterized queries, SSRF protection with DNS-rebinding prevention, HMAC-SHA256 webhook signing, and delegated authorization. Recent commits (`48e5f0a`, `d61858c`) show that prior SSRF and SQL-injection issues were already discovered and remediated.
20
-
21
- | Severity | Count |
22
- |----------|-------|
23
- | Critical | 0 |
24
- | High | 0 |
25
- | Medium | 2 |
26
- | Low | 3 |
27
- | Informational | 4 |
28
-
29
- ---
30
-
31
- ## Critical Findings
32
-
33
- None.
34
-
35
- ---
36
-
37
- ## High Findings
38
-
39
- None.
40
-
41
- ---
42
-
43
- ## Medium Findings
44
-
45
- ### M1 — Missing Input Validation on `tableName` in `PostgresSchedulePersistence`
46
-
47
- **File:** `src/scheduler/postgres-persistence.ts:153`
48
-
49
- **Description:**
50
- `PostgresSchedulePersistence` validates `schema` with a strict regex (`^[a-zA-Z_][a-zA-Z0-9_]{0,62}$`) but applies **no equivalent validation to `tableName`**. The raw `tableName` string is concatenated into `fullTableName` (`${this.schema}.${this.tableName}`) at line 235 and then passed to Kysely's `sql.table()` and `sql.ref()` at lines 257–296. While Kysely correctly double-quotes identifiers — preventing SQL injection — there is no upfront guard to reject nonsensical or adversarially crafted values.
51
-
52
- Contrast: `SQLiteSchedulePersistence` (`src/scheduler/sqlite-persistence.ts:61`) validates its `tableName` with `^[a-zA-Z_][a-zA-Z0-9_]*$` and the Postgres *storage* adapter (`src/storage/postgres.ts:228`) validates its schema similarly. The omission in `postgres-persistence.ts` is an inconsistency in the defensive pattern.
53
-
54
- **Impact:**
55
- In the current implementation, `sql.table()` quoting prevents SQL injection. However, a consumer passing a malformed `tableName` (e.g. `"foo\x00bar"`, very long strings, or strings containing periods) will receive a confusing runtime database error rather than a clear upfront `Error`. If the Kysely dependency ever changes its quoting behaviour, this becomes a direct injection point.
56
-
57
- **Remediation:**
58
- Add the same regex guard used for `schema` immediately after line 153:
59
- ```typescript
60
- if (!/^[a-zA-Z_][a-zA-Z0-9_]{0,62}$/.test(this.tableName)) {
61
- throw new Error(`Invalid table name "${this.tableName}".`);
62
- }
63
- ```
64
-
65
- ---
66
-
67
- ### M2 — Non-Cryptographic ID Generation Used for Workflow Run Identifiers
68
-
69
- **File:** `src/utils/id.ts:17`
70
-
71
- **Description:**
72
- `generateId()` constructs identifiers using `Date.now()` and `Math.random()`:
73
-
74
- ```typescript
75
- const randomPart = Math.random().toString(36).substring(2, 10);
76
- ```
77
-
78
- `Math.random()` is not a CSPRNG. V8's implementation is seeded with a 64-bit value derived from the system clock at startup; an attacker with knowledge of the process start time can reconstruct the PRNG state and predict future IDs. These IDs are used as primary keys for workflow runs and steps (`src/core/orchestrator.ts`).
79
-
80
- **Impact:**
81
- If run IDs are used for access-control purposes by a consumer (e.g. "share a link containing the run ID" patterns), predictable IDs enable enumeration and unauthorized access. The library itself does not enforce any access control on run IDs, so impact depends entirely on the consuming application's threat model.
82
-
83
- **Remediation:**
84
- Replace `Math.random()` with `crypto.randomBytes` (Node) or `crypto.getRandomValues` (Web Crypto), both available in Node.js 18+:
85
- ```typescript
86
- import { randomBytes } from 'node:crypto';
87
- const randomPart = randomBytes(6).toString('base64url');
88
- ```
89
-
90
- ---
91
-
92
- ## Low Findings
93
-
94
- ### L1 — Blanket Block of All IPv6 Literals in SSRF Protection
95
-
96
- **File:** `src/events/webhook.ts:493–496`
97
-
98
- **Description:**
99
- The `isBlockedHost` function blocks **all** IPv6 address literals, not just private/reserved ones:
100
-
101
- ```typescript
102
- // Block all IPv6 address literals (wrapped in brackets by URL parser)
103
- if (hostname.startsWith('[')) {
104
- return true;
105
- }
106
- ```
107
-
108
- This was added to prevent SSRF via `[::1]` and similar loopback bypasses (commit `48e5f0a`). While the intent is correct, the implementation also blocks legitimate public IPv6 targets such as `[2001:db8::1]`.
109
-
110
- **Impact:**
111
- Consumers cannot register webhook endpoints using public IPv6 addresses. This is a functional limitation, not a security vulnerability. As global IPv6 adoption grows, this will become increasingly restrictive.
112
-
113
- **Remediation:**
114
- Instead of blocking all bracket-wrapped addresses, parse the IPv6 address, expand it to full form, and check only against reserved ranges (loopback `::1`, ULA `fc00::/7`, link-local `fe80::/10`, documentation prefixes, etc.) using a library or the same range-check logic applied to IPv4.
115
-
116
- ---
117
-
118
- ### L2 — `allowInsecureUrls` Flag Lacks Production-Safety Warning
119
-
120
- **File:** `src/events/webhook.ts:64–67`
121
-
122
- **Description:**
123
- The `allowInsecureUrls` option on `WebhookEventTransportConfig` relaxes the HTTPS requirement and bypasses URL scheme validation:
124
-
125
- ```typescript
126
- /**
127
- * Whether to allow non-HTTPS URLs (default: false).
128
- * Set to true only in development environments.
129
- */
130
- allowInsecureUrls?: boolean;
131
- ```
132
-
133
- The comment mentions development use, but there is no runtime enforcement or warning when this flag is enabled in a context that looks like production (e.g. `NODE_ENV=production`).
134
-
135
- **Impact:**
136
- A consumer who copies a development configuration to production silently downgrades all webhooks to plain HTTP, exposing payloads (which may contain workflow results and metadata) to network interception, and disabling part of the SSRF protection.
137
-
138
- **Remediation:**
139
- Emit a logger warning at construction time when `allowInsecureUrls: true` is set, e.g.:
140
- ```typescript
141
- if (this.allowInsecureUrls) {
142
- this.logger.warn('allowInsecureUrls is enabled. Do not use this in production.');
143
- }
144
- ```
145
-
146
- ---
147
-
148
- ### L3 — No Rate Limiting on Outbound Webhook Dispatch
149
-
150
- **File:** `src/events/webhook.ts:465–480`
151
-
152
- **Description:**
153
- The webhook transport implements concurrency limiting (default 50 concurrent requests) and a queue, but no per-endpoint rate limiting or per-second emission cap. A burst of workflow events can cause hundreds of webhook deliveries in a short window.
154
-
155
- **Impact:**
156
- Could trigger rate limiting or bans from external webhook receivers. Does not directly introduce an inbound attack surface (the library sends, not receives), but could cause unintended denial-of-service toward third-party services.
157
-
158
- **Remediation:**
159
- Add an optional `rateLimit` configuration (e.g. `maxRequestsPerSecond`) per endpoint or globally, with token-bucket or leaky-bucket logic.
160
-
161
- ---
162
-
163
- ## Secrets & Credentials Exposure
164
-
165
- **Result: None found.**
166
-
167
- - `git grep` across all `*.ts`, `*.js`, `*.json`, `*.yaml`, `*.yml` files for `password`, `secret`, `api_key`, `token`, and `private_key` returned only:
168
- - **`src/events/webhook.ts:22–23`** — `secret?: string` type definition for HMAC signing (no value)
169
- - **`src/events/webhook.ts:116`** — JSDoc comment example: `secret: process.env.WEBHOOK_SECRET` (correctly references an environment variable, not a hardcoded value)
170
- - **`src/planning/planner.ts`, `src/planning/types.ts`** — `tokensPerStep`, `tokens` — LLM token budget fields, not credentials
171
- - **`dist/` build artefacts** — mirror of source, no embedded values
172
-
173
- - No `.env` files exist in the repository at any path.
174
- - `git log --all -p -- "*.env" "*.pem" "*.key"` returned no output — no credential files were ever committed to git history.
175
-
176
- ---
177
-
178
- ## Recommendations
179
-
180
- The following are ordered by risk impact:
181
-
182
- 1. **[Medium — M1] Validate `tableName` in `PostgresSchedulePersistence`.**
183
- Add a regex guard (`^[a-zA-Z_][a-zA-Z0-9_]{0,62}$`) for `tableName` at `src/scheduler/postgres-persistence.ts:153`, matching the existing pattern in `sqlite-persistence.ts:61` and `storage/postgres.ts:228`. This closes the inconsistency and provides a clean failure mode.
184
-
185
- 2. **[Medium — M2] Replace `Math.random()` with a CSPRNG in ID generation.**
186
- Replace `Math.random()` at `src/utils/id.ts:17` with `crypto.getRandomValues` or Node's `crypto.randomBytes`. The timestamp prefix can remain. This is low-effort and eliminates predictability of workflow run IDs if consumers use them for access decisions.
187
-
188
- 3. **[Low — L2] Add a runtime warning for `allowInsecureUrls: true`.**
189
- Log a warning through the configured logger in `WebhookEventTransport`'s constructor when `allowInsecureUrls` is set. This is a single-line addition that prevents silent production misconfiguration.
190
-
191
- 4. **[Low — L1] Narrow IPv6 blocking to reserved ranges only.**
192
- Replace the blanket `hostname.startsWith('[')` block in `isBlockedHost` (`webhook.ts:493`) with targeted checks for `[::1]`, `[fc00:...]`, `[fe80:...]`, and other RFC-reserved IPv6 prefixes, allowing legitimate public IPv6 webhook endpoints.
193
-
194
- 5. **[Low — L3] Document or implement outbound webhook rate limiting.**
195
- Either add an optional `rateLimit` configuration to `WebhookEventTransport`, or explicitly document in JSDoc that consumers are responsible for choosing receivers that can handle burst traffic.
196
-
197
- 6. **[Informational] Add explicit authorization enforcement documentation.**
198
- The Socket.IO transport (`src/events/socketio.ts`) requires consumers to provide an `authorize` callback. Add JSDoc `@throws` documentation and an example showing what happens when no `authorize` callback is supplied, to prevent consumers from accidentally running with open subscriptions.
199
-
200
- 7. **[Informational] Consider documenting CORS requirements for Socket.IO consumers.**
201
- The library accepts an already-constructed `SocketIOServer` (`src/events/socketio.ts:45`) and does not configure CORS. Add a README section or JSDoc example showing the minimum recommended CORS configuration to avoid consumers defaulting to wildcard origins.
202
-
203
- 8. **[Informational] Run `npm audit` in CI.**
204
- The production dependency surface is minimal (only `cron-parser` and `re2`), but automated vulnerability scanning should be enforced in the CI pipeline to catch transitive dependency CVEs early.
205
-
206
- ---
207
-
208
- *Audit performed: 2026-04-03. Branch: `main` (HEAD `4d9838a`). No source files were modified during this audit.*
@@ -1,15 +0,0 @@
1
- # Default owners for all files
2
- * @Multiplier-Labs/engineering
3
-
4
- # CI/CD and GitHub configuration — require admin review
5
- .github/ @Multiplier-Labs/admin
6
- package.json @Multiplier-Labs/admin
7
- package-lock.json @Multiplier-Labs/admin
8
-
9
- # Security-sensitive code
10
- src/events/webhook.ts @Multiplier-Labs/admin
11
- src/utils/id.ts @Multiplier-Labs/admin
12
-
13
- # Persistence layer
14
- src/storage/ @Multiplier-Labs/engineering
15
- src/scheduler/ @Multiplier-Labs/engineering
@@ -1,23 +0,0 @@
1
- version: 2
2
- updates:
3
- - package-ecosystem: npm
4
- directory: /
5
- schedule:
6
- interval: weekly
7
- day: monday
8
- open-pull-requests-limit: 10
9
- reviewers:
10
- - Multiplier-Labs/engineering
11
- labels:
12
- - dependencies
13
-
14
- - package-ecosystem: github-actions
15
- directory: /
16
- schedule:
17
- interval: weekly
18
- day: monday
19
- open-pull-requests-limit: 5
20
- reviewers:
21
- - Multiplier-Labs/admin
22
- labels:
23
- - ci
@@ -1,38 +0,0 @@
1
- name: CI
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
-
9
- permissions:
10
- contents: read
11
-
12
- jobs:
13
- build-and-test:
14
- runs-on: ubuntu-latest
15
- strategy:
16
- matrix:
17
- node-version: [20, 22]
18
- steps:
19
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
20
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
21
- with:
22
- node-version: ${{ matrix.node-version }}
23
- cache: npm
24
-
25
- - name: Install dependencies
26
- run: npm ci
27
-
28
- - name: Audit dependencies
29
- run: npm audit --audit-level=high
30
-
31
- - name: Typecheck
32
- run: npm run typecheck
33
-
34
- - name: Build
35
- run: npm run build
36
-
37
- - name: Test
38
- run: npm test
@@ -1,36 +0,0 @@
1
- name: Publish to GitHub Packages
2
-
3
- on:
4
- release:
5
- types: [created]
6
-
7
- jobs:
8
- publish:
9
- runs-on: ubuntu-latest
10
- permissions:
11
- contents: read
12
- packages: write
13
- steps:
14
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
15
-
16
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
17
- with:
18
- node-version: '20'
19
- registry-url: 'https://registry.npmjs.org'
20
-
21
- - name: Install dependencies
22
- run: npm ci
23
-
24
- - name: Build
25
- run: npm run build
26
-
27
- - name: Typecheck
28
- run: npm run typecheck
29
-
30
- - name: Test
31
- run: npm test
32
-
33
- - name: Publish
34
- run: npm publish
35
- env:
36
- NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -1,29 +0,0 @@
1
- name: Security
2
-
3
- on:
4
- push:
5
- branches: [main]
6
- pull_request:
7
- branches: [main]
8
- schedule:
9
- - cron: '0 8 * * 1' # Weekly on Monday at 08:00 UTC
10
-
11
- permissions:
12
- contents: read
13
-
14
- jobs:
15
- audit:
16
- name: Dependency Audit
17
- runs-on: ubuntu-latest
18
- steps:
19
- - uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
20
- - uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4
21
- with:
22
- node-version: '20'
23
- cache: npm
24
-
25
- - name: Install dependencies
26
- run: npm ci
27
-
28
- - name: Run npm audit
29
- run: npm audit --audit-level=moderate
package/CHANGELOG.md DELETED
@@ -1,34 +0,0 @@
1
- # Changelog
2
-
3
- All notable changes to this project will be documented in this file.
4
-
5
- The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
- and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
-
8
- ## [Unreleased]
9
-
10
- ### Added
11
- - CI workflow for automated build, typecheck, and test on pull requests
12
- - Security scanning workflow with weekly `npm audit` checks
13
- - Dependabot configuration for automated dependency and GitHub Actions updates
14
- - `CODEOWNERS` file requiring designated reviewers for security-sensitive paths
15
- - `SECURITY.md` with vulnerability reporting instructions and disclosure policy
16
- - Branch protection documentation in README
17
-
18
- ### Changed
19
- - Pinned GitHub Actions in `publish.yml` to full commit SHAs to prevent supply-chain attacks via tag hijacking
20
-
21
- ## [0.2.6] - 2026-04-03
22
-
23
- ### Added
24
- - Initial public release
25
- - Durable workflow execution engine with step orchestration
26
- - SQLite and PostgreSQL storage backends
27
- - In-memory storage for testing
28
- - Cron-based scheduling with SQLite and PostgreSQL persistence
29
- - Workflow completion triggers
30
- - Socket.IO and webhook event transports with HMAC-SHA256 signing
31
- - SSRF protection for webhook URLs with DNS-rebinding prevention
32
- - Concurrency control with priority queues
33
- - Rule-based planning system for dynamic workflow generation
34
- - Full TypeScript support with type inference
package/SECURITY.md DELETED
@@ -1,40 +0,0 @@
1
- # Security Policy
2
-
3
- ## Supported Versions
4
-
5
- | Version | Supported |
6
- | ------- | ------------------ |
7
- | 0.2.x | Yes |
8
- | < 0.2 | No |
9
-
10
- ## Reporting a Vulnerability
11
-
12
- If you discover a security vulnerability in Stepflow, please report it responsibly.
13
-
14
- **Do not open a public GitHub issue for security vulnerabilities.**
15
-
16
- Instead, please email **security@multiplier-labs.com** with:
17
-
18
- - A description of the vulnerability
19
- - Steps to reproduce the issue
20
- - The potential impact
21
- - Any suggested remediation (optional)
22
-
23
- We will acknowledge receipt within **48 hours** and aim to provide an initial assessment within **5 business days**.
24
-
25
- ## Disclosure Policy
26
-
27
- - We follow coordinated disclosure. Please allow us reasonable time to address the issue before public disclosure.
28
- - Once a fix is released, we will publish a security advisory via GitHub Security Advisories.
29
- - Contributors who report valid vulnerabilities will be credited in the advisory (unless they prefer anonymity).
30
-
31
- ## Security Practices
32
-
33
- This project follows these security practices:
34
-
35
- - **Signed commits** are encouraged for all contributors
36
- - **Branch protection** is enforced on `main` with required reviews and status checks
37
- - **Dependency scanning** via Dependabot with automated PRs for security updates
38
- - **npm audit** runs in CI on every pull request
39
- - **Secret scanning** and **push protection** are enabled on the repository
40
- - **CODEOWNERS** requires review from designated maintainers for security-sensitive code paths