@foldrun/core 1.1.2 → 1.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 +29 -192
- package/README.md +14 -17
- package/dist/index.js +3 -3
- package/dist/src/deploy.d.ts +16 -0
- package/dist/src/deploy.js +35 -1
- package/dist/src/platform.d.ts +4 -4
- package/dist/src/run-container.d.ts +1 -1
- package/dist/src/run-container.js +1 -1
- package/dist/src/scan.d.ts +168 -0
- package/dist/src/scan.js +744 -0
- package/dist/src/starter.js +9 -0
- package/dist/src/tool-loop.js +4 -0
- package/index.ts +3 -3
- package/package.json +4 -6
- package/src/deploy.ts +40 -2
- package/src/platform.ts +4 -4
- package/src/run-container.ts +1 -1
- package/src/scan.ts +849 -0
- package/src/starter.ts +9 -0
- package/src/tool-loop.ts +4 -0
package/LICENSE
CHANGED
|
@@ -1,202 +1,39 @@
|
|
|
1
|
+
foldrun proprietary licence
|
|
1
2
|
|
|
2
|
-
|
|
3
|
-
Version 2.0, January 2004
|
|
4
|
-
http://www.apache.org/licenses/
|
|
3
|
+
Copyright (c) 2026 foldrun. All rights reserved.
|
|
5
4
|
|
|
6
|
-
|
|
5
|
+
This software, its source code and its documentation are the property of
|
|
6
|
+
foldrun. They are licensed, not sold.
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
You may install and run the foldrun packages published to npm (`foldrun`
|
|
9
|
+
and `@foldrun/core`) to write, check, run and deploy your own agents,
|
|
10
|
+
flows and workspaces, on your own machines and with the foldrun platform.
|
|
11
|
+
That includes the copies installing and running need, for your own use:
|
|
12
|
+
package caches and mirrors, CI and build machines, container images and
|
|
13
|
+
backups.
|
|
9
14
|
|
|
10
|
-
|
|
11
|
-
|
|
15
|
+
You may not, except where the law allows it despite this restriction:
|
|
16
|
+
copy, modify, merge, publish, distribute, sublicense, rent or sell the
|
|
17
|
+
software or any part of it; reverse engineer, decompile or disassemble it;
|
|
18
|
+
or use it to build a product or service that competes with foldrun.
|
|
12
19
|
|
|
13
|
-
|
|
14
|
-
|
|
20
|
+
What you write with the software (your agents, flows, knowledge and other
|
|
21
|
+
files) is yours.
|
|
15
22
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
control with that entity. For the purposes of this definition,
|
|
19
|
-
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
-
direction or management of such entity, whether by contract or
|
|
21
|
-
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
-
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
Third-party components the software includes or installs (its npm
|
|
24
|
+
dependencies) remain under their own licences.
|
|
23
25
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
+
This licence ends automatically if you break its terms, and you must then
|
|
27
|
+
stop using the software.
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
source, and configuration files.
|
|
29
|
+
Versions published before 17 October 2026 under the Apache License 2.0
|
|
30
|
+
remain available under that licence for those versions only.
|
|
30
31
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
32
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
33
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
34
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. TO THE EXTENT THE
|
|
35
|
+
LAW ALLOWS, IN NO EVENT SHALL FOLDRUN BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
36
|
+
OTHER LIABILITY ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
|
|
37
|
+
ITS USE.
|
|
35
38
|
|
|
36
|
-
|
|
37
|
-
Object form, made available under the License, as indicated by a
|
|
38
|
-
copyright notice that is included in or attached to the work
|
|
39
|
-
(an example is provided in the Appendix below).
|
|
40
|
-
|
|
41
|
-
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
-
form, that is based on (or derived from) the Work and for which the
|
|
43
|
-
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
-
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
-
of this License, Derivative Works shall not include works that remain
|
|
46
|
-
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
-
the Work and Derivative Works thereof.
|
|
48
|
-
|
|
49
|
-
"Contribution" shall mean any work of authorship, including
|
|
50
|
-
the original version of the Work and any modifications or additions
|
|
51
|
-
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
-
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
-
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
-
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
-
means any form of electronic, verbal, or written communication sent
|
|
56
|
-
to the Licensor or its representatives, including but not limited to
|
|
57
|
-
communication on electronic mailing lists, source code control systems,
|
|
58
|
-
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
-
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
-
excluding communication that is conspicuously marked or otherwise
|
|
61
|
-
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
-
|
|
63
|
-
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
-
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
-
subsequently incorporated within the Work.
|
|
66
|
-
|
|
67
|
-
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
-
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
-
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
-
Work and such Derivative Works in Source or Object form.
|
|
73
|
-
|
|
74
|
-
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
-
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
-
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
-
(except as stated in this section) patent license to make, have made,
|
|
78
|
-
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
-
where such license applies only to those patent claims licensable
|
|
80
|
-
by such Contributor that are necessarily infringed by their
|
|
81
|
-
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
-
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
-
institute patent litigation against any entity (including a
|
|
84
|
-
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
-
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
-
or contributory patent infringement, then any patent licenses
|
|
87
|
-
granted to You under this License for that Work shall terminate
|
|
88
|
-
as of the date such litigation is filed.
|
|
89
|
-
|
|
90
|
-
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
-
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
-
modifications, and in Source or Object form, provided that You
|
|
93
|
-
meet the following conditions:
|
|
94
|
-
|
|
95
|
-
(a) You must give any other recipients of the Work or
|
|
96
|
-
Derivative Works a copy of this License; and
|
|
97
|
-
|
|
98
|
-
(b) You must cause any modified files to carry prominent notices
|
|
99
|
-
stating that You changed the files; and
|
|
100
|
-
|
|
101
|
-
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
-
that You distribute, all copyright, patent, trademark, and
|
|
103
|
-
attribution notices from the Source form of the Work,
|
|
104
|
-
excluding those notices that do not pertain to any part of
|
|
105
|
-
the Derivative Works; and
|
|
106
|
-
|
|
107
|
-
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
-
distribution, then any Derivative Works that You distribute must
|
|
109
|
-
include a readable copy of the attribution notices contained
|
|
110
|
-
within such NOTICE file, excluding those notices that do not
|
|
111
|
-
pertain to any part of the Derivative Works, in at least one
|
|
112
|
-
of the following places: within a NOTICE text file distributed
|
|
113
|
-
as part of the Derivative Works; within the Source form or
|
|
114
|
-
documentation, if provided along with the Derivative Works; or,
|
|
115
|
-
within a display generated by the Derivative Works, if and
|
|
116
|
-
wherever such third-party notices normally appear. The contents
|
|
117
|
-
of the NOTICE file are for informational purposes only and
|
|
118
|
-
do not modify the License. You may add Your own attribution
|
|
119
|
-
notices within Derivative Works that You distribute, alongside
|
|
120
|
-
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
-
that such additional attribution notices cannot be construed
|
|
122
|
-
as modifying the License.
|
|
123
|
-
|
|
124
|
-
You may add Your own copyright statement to Your modifications and
|
|
125
|
-
may provide additional or different license terms and conditions
|
|
126
|
-
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
-
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
-
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
-
the conditions stated in this License.
|
|
130
|
-
|
|
131
|
-
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
-
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
-
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
-
this License, without any additional terms or conditions.
|
|
135
|
-
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
-
the terms of any separate license agreement you may have executed
|
|
137
|
-
with Licensor regarding such Contributions.
|
|
138
|
-
|
|
139
|
-
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
-
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
-
except as required for reasonable and customary use in describing the
|
|
142
|
-
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
-
|
|
144
|
-
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
-
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
-
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
-
implied, including, without limitation, any warranties or conditions
|
|
149
|
-
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
-
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
-
appropriateness of using or redistributing the Work and assume any
|
|
152
|
-
risks associated with Your exercise of permissions under this License.
|
|
153
|
-
|
|
154
|
-
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
-
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
-
unless required by applicable law (such as deliberate and grossly
|
|
157
|
-
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
-
liable to You for damages, including any direct, indirect, special,
|
|
159
|
-
incidental, or consequential damages of any character arising as a
|
|
160
|
-
result of this License or out of the use or inability to use the
|
|
161
|
-
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
-
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
-
other commercial damages or losses), even if such Contributor
|
|
164
|
-
has been advised of the possibility of such damages.
|
|
165
|
-
|
|
166
|
-
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
-
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
-
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
-
or other liability obligations and/or rights consistent with this
|
|
170
|
-
License. However, in accepting such obligations, You may act only
|
|
171
|
-
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
-
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
-
defend, and hold each Contributor harmless for any liability
|
|
174
|
-
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
-
of your accepting any such warranty or additional liability.
|
|
176
|
-
|
|
177
|
-
END OF TERMS AND CONDITIONS
|
|
178
|
-
|
|
179
|
-
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
-
|
|
181
|
-
To apply the Apache License to your work, attach the following
|
|
182
|
-
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
-
replaced with your own identifying information. (Don't include
|
|
184
|
-
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
-
comment syntax for the file format. We also recommend that a
|
|
186
|
-
file or class name and description of purpose be included on the
|
|
187
|
-
same "printed page" as the copyright notice for easier
|
|
188
|
-
identification within third-party archives.
|
|
189
|
-
|
|
190
|
-
Copyright 2026 foldrun contributors
|
|
191
|
-
|
|
192
|
-
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
-
you may not use this file except in compliance with the License.
|
|
194
|
-
You may obtain a copy of the License at
|
|
195
|
-
|
|
196
|
-
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
-
|
|
198
|
-
Unless required by applicable law or agreed to in writing, software
|
|
199
|
-
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
-
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
-
See the License for the specific language governing permissions and
|
|
202
|
-
limitations under the License.
|
|
39
|
+
Questions: hello@foldrun.io
|
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# foldrun
|
|
2
2
|
|
|
3
|
-
[](https://github.com/foldrun-io/foldrun-core/actions/workflows/ci.yml)
|
|
4
3
|
[](https://www.npmjs.com/package/@foldrun/core)
|
|
5
|
-
[](LICENSE)
|
|
6
4
|
|
|
7
5
|
**Agents are just folders. Write them, check them, run them.**
|
|
8
6
|
|
|
@@ -126,14 +124,14 @@ truth.
|
|
|
126
124
|
webhook triggers, durable runs with full history, a secret store, team access,
|
|
127
125
|
and containers you never touch. Push the folder, it runs.
|
|
128
126
|
|
|
129
|
-
The
|
|
130
|
-
|
|
127
|
+
The CLI and the runtime are free to install from npm, and the hosted
|
|
128
|
+
platform imports the same core rather than a fork. Writing and checking
|
|
131
129
|
an agent locally costs nothing and needs no account — that is the on-ramp to
|
|
132
130
|
the host, not a competitor to it.
|
|
133
131
|
|
|
134
132
|
Where the two differ is operations, not capability. Locally a run happens in
|
|
135
133
|
your terminal; hosted, it survives a restart, retries a failed step, waits days
|
|
136
|
-
for an approval and tells you what it cost. Nothing is held back from the
|
|
134
|
+
for an approval and tells you what it cost. Nothing is held back from the local
|
|
137
135
|
version to make the hosted one worth buying.
|
|
138
136
|
|
|
139
137
|
## This repo, and the others
|
|
@@ -150,11 +148,11 @@ Most people want the CLI, not this package — `npm install -g foldrun`.
|
|
|
150
148
|
| `okf/WHITE-PAPER.md` | hosting OKF: what the spec leaves to hosts |
|
|
151
149
|
| `tests/` | the runtime's tests (`npm test`) |
|
|
152
150
|
|
|
153
|
-
The command-line tool is its own
|
|
154
|
-
[`foldrun
|
|
151
|
+
The command-line tool is its own package,
|
|
152
|
+
[`foldrun`](https://www.npmjs.com/package/foldrun), and depends on
|
|
155
153
|
this package. The reference documentation is at
|
|
156
|
-
[docs.foldrun.io](https://docs.foldrun.io).
|
|
157
|
-
|
|
154
|
+
[docs.foldrun.io](https://docs.foldrun.io). Every foldrun repository is
|
|
155
|
+
private; see "Hosting it" below.
|
|
158
156
|
|
|
159
157
|
### Templates and workspaces
|
|
160
158
|
|
|
@@ -191,13 +189,9 @@ This package is the framework: everything needed to read a workspace and
|
|
|
191
189
|
run it on the machine you are on. The platform — the dashboard, a queue and
|
|
192
190
|
its worker, one sandbox per step, a vault, metering, a team — is built on
|
|
193
191
|
it, in a separate package that plugs in through `src/platform.ts`. Nothing
|
|
194
|
-
in this repository imports it
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
[self-hosting/](self-hosting/). Sign up at `localhost:3900`, and
|
|
198
|
-
`foldrun deploy` moves a workspace from your machine to it unchanged. The
|
|
199
|
-
images are the same builds that run foldrun's own installation, published
|
|
200
|
-
under the same versions.
|
|
192
|
+
in this repository imports it. The platform is hosted by foldrun and is not
|
|
193
|
+
distributed; `foldrun deploy` moves a workspace from your machine to it
|
|
194
|
+
unchanged.
|
|
201
195
|
|
|
202
196
|
## Requirements
|
|
203
197
|
|
|
@@ -273,4 +267,7 @@ Known gaps: one platform replica per data directory (the web/worker role
|
|
|
273
267
|
split needs RWX storage), and the dashboard's run lists re-read run files
|
|
274
268
|
per request (fine to thousands of runs).
|
|
275
269
|
|
|
276
|
-
|
|
270
|
+
## Licence
|
|
271
|
+
|
|
272
|
+
Proprietary; see [LICENSE](LICENSE). Versions published before 17 October
|
|
273
|
+
2026 were Apache-2.0 and stay so.
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
// @foldrun/core — the
|
|
1
|
+
// @foldrun/core — the runtime.
|
|
2
2
|
//
|
|
3
3
|
// Everything needed to read a workspace of markdown files and run the agents
|
|
4
4
|
// in it. No server, no database, no account: point it at a folder.
|
|
5
5
|
//
|
|
6
6
|
// The hosted platform imports these same modules. That is deliberate — if the
|
|
7
|
-
//
|
|
8
|
-
//
|
|
7
|
+
// local version were a reduced copy it would rot, and running on a laptop
|
|
8
|
+
// would behave differently from running hosted. What the platform adds — a queue and
|
|
9
9
|
// its worker, metering and billing, pods on a cluster, per-account keys in a
|
|
10
10
|
// database, previews, share links, tenancy — lives in its own private package
|
|
11
11
|
// and plugs in through platform.ts. Nothing here imports it.
|
package/dist/src/deploy.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type DeployFile } from "./store.ts";
|
|
2
|
+
import { type ScanFinding, type ScanOptions } from "./scan.ts";
|
|
2
3
|
/**
|
|
3
4
|
* Is this path, relative to a workspace root, one `readTree` would carry?
|
|
4
5
|
*
|
|
@@ -69,7 +70,22 @@ export declare function readTree(dir: string): DeployFile[];
|
|
|
69
70
|
* Returns the problem, or null.
|
|
70
71
|
*/
|
|
71
72
|
export declare function unopenedFrontmatter(raw: string): string | null;
|
|
73
|
+
/**
|
|
74
|
+
* What a deploy says but does not refuse: the structural warnings below, and
|
|
75
|
+
* the scanner's findings about what should not be in the files at all — a
|
|
76
|
+
* credential written in, text a reviewer cannot see. The scanner's design
|
|
77
|
+
* advice (an agent that could leak, an unpinned package) is for `foldrun
|
|
78
|
+
* check` and the Checks page, not for every deploy's output.
|
|
79
|
+
*/
|
|
72
80
|
export declare function deployWarnings(files: DeployFile[]): DeployIssue[];
|
|
81
|
+
/**
|
|
82
|
+
* Everything the platform can say about a workspace's files, as findings
|
|
83
|
+
* with rule ids: what a deploy refuses (errors), what it warns about, and the
|
|
84
|
+
* whole scanner. The Checks page and `GET …/check` answer with this; `foldrun
|
|
85
|
+
* check` asks more (it resolves every library and the platform's), so treat
|
|
86
|
+
* this as the server's view of the same rules, not a second set.
|
|
87
|
+
*/
|
|
88
|
+
export declare function checkFiles(files: DeployFile[], options?: ScanOptions): ScanFinding[];
|
|
73
89
|
export declare function deployIssues(files: DeployFile[]): DeployIssue[];
|
|
74
90
|
/**
|
|
75
91
|
* Runs that make this a bad moment to swap the files under them.
|
package/dist/src/deploy.js
CHANGED
|
@@ -34,6 +34,7 @@ import { languageProblem } from "./language.js";
|
|
|
34
34
|
import { localeProblems } from "./locale.js";
|
|
35
35
|
import { repoDir } from "./gitrepo.js";
|
|
36
36
|
import { entriesNoFollow } from "./paths.js";
|
|
37
|
+
import { filterIgnored, findingFingerprint, ruleForWhere, scanFiles } from "./scan.js";
|
|
37
38
|
/** Directories a deploy never reads out of a source tree. */
|
|
38
39
|
const NOT_SOURCE = new Set([".git", "node_modules", "runs", "outputs", ".foldrun", ".results"]);
|
|
39
40
|
/** Files that are never part of a workspace, whatever directory they sit in. */
|
|
@@ -186,7 +187,40 @@ export function unopenedFrontmatter(raw) {
|
|
|
186
187
|
return null;
|
|
187
188
|
return "the frontmatter has no opening `---`, so none of it is read: the agent runs with no tools and the default model. Add `---` as the first line.";
|
|
188
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* What a deploy says but does not refuse: the structural warnings below, and
|
|
192
|
+
* the scanner's findings about what should not be in the files at all — a
|
|
193
|
+
* credential written in, text a reviewer cannot see. The scanner's design
|
|
194
|
+
* advice (an agent that could leak, an unpinned package) is for `foldrun
|
|
195
|
+
* check` and the Checks page, not for every deploy's output.
|
|
196
|
+
*/
|
|
189
197
|
export function deployWarnings(files) {
|
|
198
|
+
const scanned = scanFiles(files, { only: ["secret", "content"] })
|
|
199
|
+
.filter((f) => f.level !== "info")
|
|
200
|
+
.map((f) => ({ where: `${f.file}${f.line ? `:${f.line}` : ""}`, message: `${f.message} [${f.rule}]` }));
|
|
201
|
+
return [...structuralWarnings(files), ...scanned];
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Everything the platform can say about a workspace's files, as findings
|
|
205
|
+
* with rule ids: what a deploy refuses (errors), what it warns about, and the
|
|
206
|
+
* whole scanner. The Checks page and `GET …/check` answer with this; `foldrun
|
|
207
|
+
* check` asks more (it resolves every library and the platform's), so treat
|
|
208
|
+
* this as the server's view of the same rules, not a second set.
|
|
209
|
+
*/
|
|
210
|
+
export function checkFiles(files, options = {}) {
|
|
211
|
+
const finding = (i, level, kind) => {
|
|
212
|
+
const m = /^(.*?)(?::(\d+))?(?: .*)?$/.exec(i.where);
|
|
213
|
+
const file = m?.[1] || i.where;
|
|
214
|
+
const rule = ruleForWhere(i.where, kind);
|
|
215
|
+
return { rule, level, file, ...(m?.[2] ? { line: Number(m[2]) } : {}), message: i.message, fingerprint: findingFingerprint(rule, file, i.message) };
|
|
216
|
+
};
|
|
217
|
+
const own = [
|
|
218
|
+
...deployIssues(files).map((i) => finding(i, "error")),
|
|
219
|
+
...structuralWarnings(files).map((i) => finding(i, "warn", i.kind)),
|
|
220
|
+
];
|
|
221
|
+
return [...filterIgnored(own, files), ...scanFiles(files, options)].sort((a, b) => a.file.localeCompare(b.file) || (a.line ?? 0) - (b.line ?? 0) || a.rule.localeCompare(b.rule));
|
|
222
|
+
}
|
|
223
|
+
function structuralWarnings(files) {
|
|
190
224
|
const front = (content) => {
|
|
191
225
|
try {
|
|
192
226
|
return matter(content).data;
|
|
@@ -244,7 +278,7 @@ export function deployWarnings(files) {
|
|
|
244
278
|
}
|
|
245
279
|
for (const w of lintFlow(flow, { agents: agentNames, outwardAgents })) {
|
|
246
280
|
if (w.kind === "outward")
|
|
247
|
-
out.push({ where: `${f.path}${w.line ? `:${w.line}` : ""}`, message: w.message });
|
|
281
|
+
out.push({ where: `${f.path}${w.line ? `:${w.line}` : ""}`, message: w.message, kind: "outward" });
|
|
248
282
|
}
|
|
249
283
|
}
|
|
250
284
|
return out;
|
package/dist/src/platform.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { EgressHooks } from "./egress.ts";
|
|
|
4
4
|
export type IsolatedStepRunner = (args: RunInContainerArgs) => Promise<ContainerStepOutcome>;
|
|
5
5
|
/** Who this install is for. `hosted` means someone is paying the operator
|
|
6
6
|
* for it — a wallet, a plan, a bill. `self-hosted` is everything else: a
|
|
7
|
-
* laptop, a
|
|
7
|
+
* laptop, a dev install, a box nobody bills on. */
|
|
8
8
|
export type Edition = "self-hosted" | "hosted";
|
|
9
9
|
/** What a trigger gate decided. `admit: false` is never an error: the
|
|
10
10
|
* trigger was received and understood, and the flow's own file says this
|
|
@@ -23,9 +23,9 @@ export interface PlatformHooks {
|
|
|
23
23
|
* the wallet, top-ups, plan limits, whatever is added next that assumes
|
|
24
24
|
* a customer — asks before it renders or answers. Default: self-hosted,
|
|
25
25
|
* which is what a process that never registered a platform is, and what
|
|
26
|
-
*
|
|
27
|
-
*
|
|
28
|
-
*
|
|
26
|
+
* any install is unless its operator configures billing. One predicate,
|
|
27
|
+
* one place, so "does an unbilled install show X" is a test and not an
|
|
28
|
+
* audit. */
|
|
29
29
|
edition(): Edition;
|
|
30
30
|
/** Put a flow run where a worker will pick it up. Default: start it here, now. */
|
|
31
31
|
enqueueFlowRun(tenant: string, workspace: string, steps: FlowStep[], flowName: string, modelOverride?: string | null, tags?: string[],
|
|
@@ -239,7 +239,7 @@ export declare const SHARED_RUNTIMES = "/opt/foldrun-runtimes/shared/.runtimes";
|
|
|
239
239
|
* as a trusted local file, which is precisely the path gVisor, the capability
|
|
240
240
|
* drop and the egress policy all exist to close. Disk is the cheaper thing to
|
|
241
241
|
* spend. One volume per tenant keeps that boundary; each carries a
|
|
242
|
-
* `foldrun.io/tenant` label so it can be found and pruned
|
|
242
|
+
* `foldrun.io/tenant` label so it can be found and pruned.
|
|
243
243
|
*
|
|
244
244
|
* The venvs inside carry the runner's own absolute paths, distinct from the
|
|
245
245
|
* host's `<tenant>/.runtimes` cache — two roots, so a hit is always a real hit.
|
|
@@ -345,7 +345,7 @@ const DOCKER_VOLUME_NAME = /^[a-zA-Z0-9][a-zA-Z0-9_.-]*$/;
|
|
|
345
345
|
* as a trusted local file, which is precisely the path gVisor, the capability
|
|
346
346
|
* drop and the egress policy all exist to close. Disk is the cheaper thing to
|
|
347
347
|
* spend. One volume per tenant keeps that boundary; each carries a
|
|
348
|
-
* `foldrun.io/tenant` label so it can be found and pruned
|
|
348
|
+
* `foldrun.io/tenant` label so it can be found and pruned.
|
|
349
349
|
*
|
|
350
350
|
* The venvs inside carry the runner's own absolute paths, distinct from the
|
|
351
351
|
* host's `<tenant>/.runtimes` cache — two roots, so a hit is always a real hit.
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
export type ScanLevel = "error" | "warn" | "info";
|
|
2
|
+
export type ScanCategory = "secret" | "security" | "content" | "supply-chain" | "config";
|
|
3
|
+
export interface ScanRule {
|
|
4
|
+
id: string;
|
|
5
|
+
category: ScanCategory;
|
|
6
|
+
level: ScanLevel;
|
|
7
|
+
/** One line, for a rule list. */
|
|
8
|
+
title: string;
|
|
9
|
+
/** Why it matters and what to do instead — the rule's docs, in short. */
|
|
10
|
+
help: string;
|
|
11
|
+
/** OWASP Top 10 for Agentic Applications (2026) ids it guards against. */
|
|
12
|
+
owasp?: string[];
|
|
13
|
+
}
|
|
14
|
+
export interface ScanFile {
|
|
15
|
+
/** Relative to the workspace root (`agents/x/agent.md`), or `library/…`. */
|
|
16
|
+
path: string;
|
|
17
|
+
content: string;
|
|
18
|
+
}
|
|
19
|
+
export interface ScanFinding {
|
|
20
|
+
rule: string;
|
|
21
|
+
level: ScanLevel;
|
|
22
|
+
file: string;
|
|
23
|
+
/** 1-indexed; absent for a finding about the whole file. */
|
|
24
|
+
line?: number;
|
|
25
|
+
message: string;
|
|
26
|
+
/** Stable across edits elsewhere in the file: rule + file + line text. */
|
|
27
|
+
fingerprint: string;
|
|
28
|
+
}
|
|
29
|
+
export interface ScanOptions {
|
|
30
|
+
/** Tool names whose definition says `outward: true` — the CLI and the
|
|
31
|
+
* deploy resolve these across the library; the scanner also finds the
|
|
32
|
+
* workspace's own among the files it is given. */
|
|
33
|
+
outwardTools?: Iterable<string>;
|
|
34
|
+
/** Only these rule ids (or categories, `secret`, `security`, …). */
|
|
35
|
+
only?: string[];
|
|
36
|
+
}
|
|
37
|
+
export declare const OWASP_URL = "https://genai.owasp.org/resource/owasp-top-10-for-agentic-applications-for-2026";
|
|
38
|
+
export declare const SCAN_RULES: readonly ScanRule[];
|
|
39
|
+
/**
|
|
40
|
+
* The rules `foldrun check` and the deploy have always had — "will this
|
|
41
|
+
* run?" — given ids so a finding from them can be filtered, ignored,
|
|
42
|
+
* baselined and carried in SARIF like the scanner's. Coarse on purpose, one
|
|
43
|
+
* per kind of file; the message says exactly what is wrong. Their level is
|
|
44
|
+
* each problem's own, so it is not fixed here.
|
|
45
|
+
*/
|
|
46
|
+
export declare const CHECK_RULES: readonly (Omit<ScanRule, "level"> & {
|
|
47
|
+
level?: ScanLevel;
|
|
48
|
+
})[];
|
|
49
|
+
/** The rule id of a check or deploy problem, from where it was found and
|
|
50
|
+
* the flow lint's tag when it has one. */
|
|
51
|
+
export declare function ruleForWhere(where: string, kind?: string): string;
|
|
52
|
+
/** The rule behind an id — the scanner's or check's own — or undefined. */
|
|
53
|
+
export declare function scanRule(id: string): (Omit<ScanRule, "level"> & {
|
|
54
|
+
level?: ScanLevel;
|
|
55
|
+
}) | undefined;
|
|
56
|
+
/** Where a rule's docs live — one page, an anchor per rule. */
|
|
57
|
+
export declare function ruleDocsUrl(id: string): string;
|
|
58
|
+
/** rule + file + the text that was flagged, normalised. Not the line number:
|
|
59
|
+
* a baseline must survive a paragraph added above the finding. */
|
|
60
|
+
export declare function findingFingerprint(rule: string, file: string, text: string): string;
|
|
61
|
+
/** What a finding may show of a secret: enough to find it, not to use it. */
|
|
62
|
+
export declare function redactSecret(secret: string): string;
|
|
63
|
+
/** The known field a key was probably meant to be, or null. */
|
|
64
|
+
export declare function nearestField(key: string, known: readonly string[]): string | null;
|
|
65
|
+
/**
|
|
66
|
+
* Every finding in these files, ignores applied. Findings are sorted by file
|
|
67
|
+
* then line, and one rule says one thing once per line.
|
|
68
|
+
*/
|
|
69
|
+
export declare function scanFiles(files: ScanFile[], options?: ScanOptions): ScanFinding[];
|
|
70
|
+
/**
|
|
71
|
+
* Drop the findings a `foldrun-ignore` comment (with a reason) covers — for
|
|
72
|
+
* findings that did not come from scanFiles, such as check's own rules, so
|
|
73
|
+
* one comment syntax works for every rule. Ignores without a reason are
|
|
74
|
+
* reported by scanFiles itself, once.
|
|
75
|
+
*/
|
|
76
|
+
export declare function filterIgnored<T extends {
|
|
77
|
+
rule: string;
|
|
78
|
+
file: string;
|
|
79
|
+
line?: number;
|
|
80
|
+
}>(findings: T[], files: ScanFile[]): T[];
|
|
81
|
+
export interface ScanBaseline {
|
|
82
|
+
version: 1;
|
|
83
|
+
/** When it was written — for a person reading the file, not for matching. */
|
|
84
|
+
created?: string;
|
|
85
|
+
findings: {
|
|
86
|
+
rule: string;
|
|
87
|
+
file: string;
|
|
88
|
+
fingerprint: string;
|
|
89
|
+
}[];
|
|
90
|
+
}
|
|
91
|
+
/** A baseline that accepts every finding here as known. */
|
|
92
|
+
export declare function makeBaseline(findings: Pick<ScanFinding, "rule" | "file" | "fingerprint">[], created?: string): ScanBaseline;
|
|
93
|
+
/** Findings not in the baseline, and how many it hid. A baseline that does
|
|
94
|
+
* not parse hides nothing — failing open would hide every new finding. */
|
|
95
|
+
export declare function applyBaseline<T extends Pick<ScanFinding, "rule" | "file" | "fingerprint">>(findings: T[], baseline: unknown): {
|
|
96
|
+
kept: T[];
|
|
97
|
+
baselined: number;
|
|
98
|
+
};
|
|
99
|
+
export interface SarifFinding {
|
|
100
|
+
rule: string;
|
|
101
|
+
level: ScanLevel;
|
|
102
|
+
file: string;
|
|
103
|
+
line?: number;
|
|
104
|
+
message: string;
|
|
105
|
+
fingerprint: string;
|
|
106
|
+
}
|
|
107
|
+
export declare function toSarif(findings: SarifFinding[], opts?: {
|
|
108
|
+
version?: string;
|
|
109
|
+
rules?: {
|
|
110
|
+
id: string;
|
|
111
|
+
title: string;
|
|
112
|
+
help?: string;
|
|
113
|
+
}[];
|
|
114
|
+
root?: string;
|
|
115
|
+
}): {
|
|
116
|
+
$schema: string;
|
|
117
|
+
version: string;
|
|
118
|
+
runs: {
|
|
119
|
+
tool: {
|
|
120
|
+
driver: {
|
|
121
|
+
name: string;
|
|
122
|
+
informationUri: string;
|
|
123
|
+
version?: string | undefined;
|
|
124
|
+
rules: {
|
|
125
|
+
id: string;
|
|
126
|
+
name: string;
|
|
127
|
+
shortDescription: {
|
|
128
|
+
text: string;
|
|
129
|
+
};
|
|
130
|
+
help?: {
|
|
131
|
+
text: string;
|
|
132
|
+
} | undefined;
|
|
133
|
+
helpUri: string;
|
|
134
|
+
properties: {
|
|
135
|
+
tags: string[];
|
|
136
|
+
};
|
|
137
|
+
}[];
|
|
138
|
+
};
|
|
139
|
+
};
|
|
140
|
+
originalUriBaseIds?: {
|
|
141
|
+
SRCROOT: {
|
|
142
|
+
uri: string;
|
|
143
|
+
};
|
|
144
|
+
} | undefined;
|
|
145
|
+
results: {
|
|
146
|
+
ruleId: string;
|
|
147
|
+
ruleIndex: number;
|
|
148
|
+
level: string;
|
|
149
|
+
message: {
|
|
150
|
+
text: string;
|
|
151
|
+
};
|
|
152
|
+
locations: {
|
|
153
|
+
physicalLocation: {
|
|
154
|
+
artifactLocation: {
|
|
155
|
+
uri: string;
|
|
156
|
+
uriBaseId?: string | undefined;
|
|
157
|
+
};
|
|
158
|
+
region?: {
|
|
159
|
+
startLine: number;
|
|
160
|
+
} | undefined;
|
|
161
|
+
};
|
|
162
|
+
}[];
|
|
163
|
+
partialFingerprints: {
|
|
164
|
+
"foldrun/v1": string;
|
|
165
|
+
};
|
|
166
|
+
}[];
|
|
167
|
+
}[];
|
|
168
|
+
};
|