@stratusagent/plugins 0.11.1 → 0.11.3
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/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/loader.d.ts +69 -0
- package/dist/loader.d.ts.map +1 -1
- package/dist/loader.js +115 -13
- package/dist/loader.js.map +1 -1
- package/dist/provenance.d.ts +144 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +316 -0
- package/dist/provenance.js.map +1 -0
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -11,5 +11,6 @@
|
|
|
11
11
|
export { declaredRiskFor, parsePluginManifest, parseToolRiskOverrides, resolvePluginAgentConfig, validateAgainstSchema, validatePluginConfig, HOST_CONFIG_KEYS, PLUGIN_MANIFEST_VERSION, PluginConfigError, PluginManifestError, type PluginContributions, type PluginManifest, type PluginNamespaceDeclaration, type PluginSkillDeclaration, type PluginToolDeclaration, } from './manifest.ts';
|
|
12
12
|
export { createManifestBoundCredentialResolver } from './credentials.ts';
|
|
13
13
|
export { ManifestBoundToolRegistry, riskFloorFor, type PluginToolRecord, } from './registry.ts';
|
|
14
|
-
export { isFirstPartyPackage, loadOptionalModule, loadPlugins, type CreatePlugin, type LoadedPlugin, type LoadPluginsOptions, type LoadPluginsResult, type OptionalModuleHost, type PluginLoadFailure, type PluginSkillRecord, } from './loader.ts';
|
|
14
|
+
export { isFirstPartyPackage, loadOptionalModule, loadPlugins, pluginConfigWithHostDefaults, preflightPlugin, installedPackageVersion, readPluginManifest, type CreatePlugin, type LoadedPlugin, type LoadPluginsOptions, type LoadPluginsResult, type OptionalModuleHost, type PluginLoadFailure, type PluginSkillRecord, } from './loader.ts';
|
|
15
|
+
export { createFileLedger, createProcessLocalLedger, isLedgerPath, LEDGER_FILENAME, ledgerContentTrust, ledgerGuard, ledgerTrustOfContent, nameIdentifiesHandle, type FileIdentity, type LedgerGuard, type TaintedWriteLedger, } from './provenance.ts';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,qCAAqC,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,EACnB,KAAK,mBAAmB,EACxB,KAAK,cAAc,EACnB,KAAK,0BAA0B,EAC/B,KAAK,sBAAsB,EAC3B,KAAK,qBAAqB,GAC3B,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,qCAAqC,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EACL,yBAAyB,EACzB,YAAY,EACZ,KAAK,gBAAgB,GACtB,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,4BAA4B,EAC5B,eAAe,EACf,uBAAuB,EACvB,kBAAkB,EAClB,KAAK,YAAY,EACjB,KAAK,YAAY,EACjB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,kBAAkB,EACvB,KAAK,iBAAiB,EACtB,KAAK,iBAAiB,GACvB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,oBAAoB,EACpB,KAAK,YAAY,EACjB,KAAK,WAAW,EAChB,KAAK,kBAAkB,GACxB,MAAM,iBAAiB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -11,5 +11,6 @@
|
|
|
11
11
|
export { declaredRiskFor, parsePluginManifest, parseToolRiskOverrides, resolvePluginAgentConfig, validateAgainstSchema, validatePluginConfig, HOST_CONFIG_KEYS, PLUGIN_MANIFEST_VERSION, PluginConfigError, PluginManifestError, } from "./manifest.js";
|
|
12
12
|
export { createManifestBoundCredentialResolver } from "./credentials.js";
|
|
13
13
|
export { ManifestBoundToolRegistry, riskFloorFor, } from "./registry.js";
|
|
14
|
-
export { isFirstPartyPackage, loadOptionalModule, loadPlugins, } from "./loader.js";
|
|
14
|
+
export { isFirstPartyPackage, loadOptionalModule, loadPlugins, pluginConfigWithHostDefaults, preflightPlugin, installedPackageVersion, readPluginManifest, } from "./loader.js";
|
|
15
|
+
export { createFileLedger, createProcessLocalLedger, isLedgerPath, LEDGER_FILENAME, ledgerContentTrust, ledgerGuard, ledgerTrustOfContent, nameIdentifiesHandle, } from "./provenance.js";
|
|
15
16
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,GAMpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,qCAAqC,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EACL,yBAAyB,EACzB,YAAY,GAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EACL,eAAe,EACf,mBAAmB,EACnB,sBAAsB,EACtB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACpB,gBAAgB,EAChB,uBAAuB,EACvB,iBAAiB,EACjB,mBAAmB,GAMpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,qCAAqC,EAAE,MAAM,kBAAkB,CAAC;AAEzE,OAAO,EACL,yBAAyB,EACzB,YAAY,GAEb,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,4BAA4B,EAC5B,eAAe,EACf,uBAAuB,EACvB,kBAAkB,GAQnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,gBAAgB,EAChB,wBAAwB,EACxB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,WAAW,EACX,oBAAoB,EACpB,oBAAoB,GAIrB,MAAM,iBAAiB,CAAC"}
|
package/dist/loader.d.ts
CHANGED
|
@@ -33,6 +33,37 @@ export interface OptionalModuleHost {
|
|
|
33
33
|
export declare const loadOptionalModule: <T = unknown>(specifier: string, host: OptionalModuleHost) => Promise<T | undefined>;
|
|
34
34
|
/** The ABI every loadable plugin exports. See `plugins.md`. */
|
|
35
35
|
export type CreatePlugin = (config: JsonObject) => Plugin | Promise<Plugin>;
|
|
36
|
+
/**
|
|
37
|
+
* The version an installed package declares, or undefined when it is not
|
|
38
|
+
* installed or names no version.
|
|
39
|
+
*
|
|
40
|
+
* Through `packageJsonFor`, so there is one answer to where a package's
|
|
41
|
+
* package.json is rather than a second walk that drifts from it — and one
|
|
42
|
+
* that is bounded the same way, so a package without its own manifest
|
|
43
|
+
* reports nothing instead of some parent directory's version.
|
|
44
|
+
*
|
|
45
|
+
* Nothing is imported: `stratus update` asks this of every companion
|
|
46
|
+
* package before it decides what to upgrade, and importing a channel
|
|
47
|
+
* adapter to read its version would open the sockets it exists to open.
|
|
48
|
+
*/
|
|
49
|
+
export declare const installedPackageVersion: (specifier: string, host: Pick<OptionalModuleHost, "resolve">) => Promise<string | undefined>;
|
|
50
|
+
/**
|
|
51
|
+
* A package's manifest, and the directory it was found in.
|
|
52
|
+
*
|
|
53
|
+
* Nothing here imports the package — the property `parsePluginManifest`
|
|
54
|
+
* exists for, and the reason this is worth having on its own. `stratus
|
|
55
|
+
* plugins` has to answer "what would this contribute, and at what risk"
|
|
56
|
+
* for a daemon that is not running, and running somebody's `setup` to find
|
|
57
|
+
* out would spawn the MCP subprocesses and open the sockets that a listing
|
|
58
|
+
* command has no business starting.
|
|
59
|
+
*
|
|
60
|
+
* `loadPlugins` goes through here too, so there is one answer to where a
|
|
61
|
+
* package's manifest is rather than a second walk that drifts from it.
|
|
62
|
+
*/
|
|
63
|
+
export declare const readPluginManifest: (specifier: string, host: Pick<OptionalModuleHost, "resolve">) => Promise<{
|
|
64
|
+
manifest: PluginManifest;
|
|
65
|
+
directory: string;
|
|
66
|
+
}>;
|
|
36
67
|
/**
|
|
37
68
|
* Whether a package's code is trusted — which is to say whether its
|
|
38
69
|
* manifest may declare a tool `safe`.
|
|
@@ -132,6 +163,44 @@ export interface LoadPluginsResult {
|
|
|
132
163
|
loaded: LoadedPlugin[];
|
|
133
164
|
failures: PluginLoadFailure[];
|
|
134
165
|
}
|
|
166
|
+
/**
|
|
167
|
+
* The configuration a plugin will actually be handed: its own block, minus
|
|
168
|
+
* the keys the host owns, plus the host defaults its manifest declares.
|
|
169
|
+
*
|
|
170
|
+
* Exported because validating a block against a manifest is only right on
|
|
171
|
+
* *this* object — `validatePluginConfig` on the raw block would refuse a
|
|
172
|
+
* manifest that declares `workspaceRoot` required for missing the very
|
|
173
|
+
* setting the host supplies. `stratus plugins` has to answer whether a
|
|
174
|
+
* daemon would accept a plugin's settings, and answering it from a
|
|
175
|
+
* different object than the loader uses is how a diagnostic ends up
|
|
176
|
+
* disagreeing with the thing it diagnoses.
|
|
177
|
+
*/
|
|
178
|
+
export declare const pluginConfigWithHostDefaults: (block: JsonObject, manifest: PluginManifest, workspaceRoot: string | undefined) => JsonObject;
|
|
179
|
+
/**
|
|
180
|
+
* Everything `loadPlugins` checks before it imports a package: that the
|
|
181
|
+
* settings match the manifest's own schema, that any `toolRisks` overrides
|
|
182
|
+
* name tools the manifest declares and risks it permits, and that every
|
|
183
|
+
* skill file the manifest names is present, inside the package, and
|
|
184
|
+
* readable.
|
|
185
|
+
*
|
|
186
|
+
* One function because any of them failing rejects the *whole* plugin — it
|
|
187
|
+
* registers no tools and no skills — so a caller that ran a subset would
|
|
188
|
+
* report a plugin ready that the daemon refuses. `stratus plugins` is that
|
|
189
|
+
* caller, and it got exactly half of this right the first time; the
|
|
190
|
+
* `toolRisks` parse was the third check, missing here while the doc below
|
|
191
|
+
* said it should not be, until setup started asking this question too.
|
|
192
|
+
*
|
|
193
|
+
* Nothing here imports the package, which is what lets a diagnostic ask the
|
|
194
|
+
* question without starting anything.
|
|
195
|
+
*
|
|
196
|
+
* `loadPlugins` calls the same three checks rather than this composition of
|
|
197
|
+
* them, because it needs what the staging and the parse *return* and stages
|
|
198
|
+
* only when it has a registry to put skills in. The checks themselves are
|
|
199
|
+
* shared, so there is no second reading of a schema, an override or a skill
|
|
200
|
+
* path here — only a second caller of each. Anything added to the loader's
|
|
201
|
+
* preflight belongs in both.
|
|
202
|
+
*/
|
|
203
|
+
export declare const preflightPlugin: (manifest: PluginManifest, directory: string, block: JsonObject, workspaceRoot: string | undefined) => Promise<void>;
|
|
135
204
|
/**
|
|
136
205
|
* Turn a `plugins` config block into running capability.
|
|
137
206
|
*
|
package/dist/loader.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,kBAAkB,EAClB,QAAQ,EACR,UAAU,EACV,MAAM,EAEN,aAAa,EACb,YAAY,EACb,MAAM,oBAAoB,CAAC;AAG5B,OAAO,EAKL,KAAK,cAAc,EACpB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAA6B,KAAK,gBAAgB,EAAE,MAAM,eAAe,CAAC;AAEjF;;;;;;;;;;GAUG;AACH,MAAM,WAAW,kBAAkB;IACjC,OAAO,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAAC;IACnC,MAAM,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,kBAAkB,GAAU,CAAC,GAAG,OAAO,EAClD,WAAW,MAAM,EACjB,MAAM,kBAAkB,KACvB,OAAO,CAAC,CAAC,GAAG,SAAS,CASvB,CAAC;AAEF,+DAA+D;AAC/D,MAAM,MAAM,YAAY,GAAG,CAAC,MAAM,EAAE,UAAU,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AA8B5E;;;;;;;;GAQG;AACH,eAAO,MAAM,mBAAmB,GAAI,aAAa,MAAM,KAAG,OACmB,CAAC;AAE9E;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,iFAAiF;IACjF,EAAE,EAAE,MAAM,CAAC;IACX;;;;;OAKG;IACH,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,YAAY;IAC3B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,cAAc,CAAC;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB;;;;;OAKG;IACH,KAAK,EAAE,gBAAgB,EAAE,CAAC;IAC1B,MAAM,EAAE,iBAAiB,EAAE,CAAC;IAC5B;;;;OAIG;IACH,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,iEAAiE;AACjE,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,oEAAoE;IACpE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,GAAG,SAAS,CAAC;IAC/C,IAAI,EAAE,kBAAkB,CAAC;IACzB,4EAA4E;IAC5E,KAAK,EAAE,YAAY,CAAC;IACpB;;;;OAIG;IACH,MAAM,CAAC,EAAE,aAAa,CAAC;IACvB,GAAG,EAAE,QAAQ,CAAC;IACd;;;;OAIG;IACH,WAAW,CAAC,EAAE,kBAAkB,CAAC;IACjC;;;;;;OAMG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,4DAA4D;IAC5D,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;IAC3C,yEAAyE;IACzE,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAChC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CAClC;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,YAAY,EAAE,CAAC;IACvB,QAAQ,EAAE,iBAAiB,EAAE,CAAC;CAC/B;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
package/dist/loader.js
CHANGED
|
@@ -55,6 +55,53 @@ const packageJsonFor = async (resolvedUrl, specifier) => {
|
|
|
55
55
|
}
|
|
56
56
|
throw new PluginManifestError(`Could not find a package.json for ${specifier}.`);
|
|
57
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* The version an installed package declares, or undefined when it is not
|
|
60
|
+
* installed or names no version.
|
|
61
|
+
*
|
|
62
|
+
* Through `packageJsonFor`, so there is one answer to where a package's
|
|
63
|
+
* package.json is rather than a second walk that drifts from it — and one
|
|
64
|
+
* that is bounded the same way, so a package without its own manifest
|
|
65
|
+
* reports nothing instead of some parent directory's version.
|
|
66
|
+
*
|
|
67
|
+
* Nothing is imported: `stratus update` asks this of every companion
|
|
68
|
+
* package before it decides what to upgrade, and importing a channel
|
|
69
|
+
* adapter to read its version would open the sockets it exists to open.
|
|
70
|
+
*/
|
|
71
|
+
export const installedPackageVersion = async (specifier, host) => {
|
|
72
|
+
let resolved;
|
|
73
|
+
try {
|
|
74
|
+
resolved = host.resolve(specifier);
|
|
75
|
+
}
|
|
76
|
+
catch {
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
try {
|
|
80
|
+
const { packageJson } = await packageJsonFor(resolved, specifier);
|
|
81
|
+
const version = packageJson.version;
|
|
82
|
+
return typeof version === 'string' && version.length > 0 ? version : undefined;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* A package's manifest, and the directory it was found in.
|
|
90
|
+
*
|
|
91
|
+
* Nothing here imports the package — the property `parsePluginManifest`
|
|
92
|
+
* exists for, and the reason this is worth having on its own. `stratus
|
|
93
|
+
* plugins` has to answer "what would this contribute, and at what risk"
|
|
94
|
+
* for a daemon that is not running, and running somebody's `setup` to find
|
|
95
|
+
* out would spawn the MCP subprocesses and open the sockets that a listing
|
|
96
|
+
* command has no business starting.
|
|
97
|
+
*
|
|
98
|
+
* `loadPlugins` goes through here too, so there is one answer to where a
|
|
99
|
+
* package's manifest is rather than a second walk that drifts from it.
|
|
100
|
+
*/
|
|
101
|
+
export const readPluginManifest = async (specifier, host) => {
|
|
102
|
+
const { packageJson, directory } = await packageJsonFor(host.resolve(specifier), specifier);
|
|
103
|
+
return { manifest: parsePluginManifest(packageJson, specifier), directory };
|
|
104
|
+
};
|
|
58
105
|
/**
|
|
59
106
|
* Whether a package's code is trusted — which is to say whether its
|
|
60
107
|
* manifest may declare a tool `safe`.
|
|
@@ -66,20 +113,45 @@ const packageJsonFor = async (resolvedUrl, specifier) => {
|
|
|
66
113
|
*/
|
|
67
114
|
export const isFirstPartyPackage = (packageName) => packageName === '@stratusagent' || packageName.startsWith('@stratusagent/');
|
|
68
115
|
const WORKSPACE_ROOT_KEY = 'workspaceRoot';
|
|
69
|
-
|
|
116
|
+
/**
|
|
117
|
+
* Where the filesystem provenance ledger lives — always the host's
|
|
118
|
+
* workspace root, whatever a plugin's own `workspaceRoot` says. Two plugins
|
|
119
|
+
* write into the ledger (`tool-fs`, `plugin-mcp`), and an operator who
|
|
120
|
+
* points one of them at a different workspace must not thereby give it a
|
|
121
|
+
* different ledger: `fs.read` consults one, so a file recorded in another
|
|
122
|
+
* reads back unlabelled. Overwritten rather than defaulted, for that reason.
|
|
123
|
+
*/
|
|
124
|
+
const LEDGER_ROOT_KEY = 'ledgerRoot';
|
|
125
|
+
const declares = (manifest, key) => Boolean(manifest.config
|
|
126
|
+
&& typeof manifest.config.properties === 'object'
|
|
127
|
+
&& manifest.config.properties !== null
|
|
128
|
+
&& !Array.isArray(manifest.config.properties)
|
|
129
|
+
&& key in manifest.config.properties);
|
|
130
|
+
/**
|
|
131
|
+
* The configuration a plugin will actually be handed: its own block, minus
|
|
132
|
+
* the keys the host owns, plus the host defaults its manifest declares.
|
|
133
|
+
*
|
|
134
|
+
* Exported because validating a block against a manifest is only right on
|
|
135
|
+
* *this* object — `validatePluginConfig` on the raw block would refuse a
|
|
136
|
+
* manifest that declares `workspaceRoot` required for missing the very
|
|
137
|
+
* setting the host supplies. `stratus plugins` has to answer whether a
|
|
138
|
+
* daemon would accept a plugin's settings, and answering it from a
|
|
139
|
+
* different object than the loader uses is how a diagnostic ends up
|
|
140
|
+
* disagreeing with the thing it diagnoses.
|
|
141
|
+
*/
|
|
142
|
+
export const pluginConfigWithHostDefaults = (block, manifest, workspaceRoot) => {
|
|
70
143
|
// `toolRisks` is the host's key, applied by the view at registration —
|
|
71
144
|
// stripped here so the plugin's code never sees, and so can never
|
|
72
145
|
// second-guess, the operator's risk word.
|
|
73
146
|
const { enabled: _enabled, toolRisks: _toolRisks, ...rest } = block;
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
return { ...rest, [WORKSPACE_ROOT_KEY]: workspaceRoot };
|
|
147
|
+
let config = rest;
|
|
148
|
+
if (declares(manifest, WORKSPACE_ROOT_KEY) && workspaceRoot !== undefined && config[WORKSPACE_ROOT_KEY] === undefined) {
|
|
149
|
+
config = { ...config, [WORKSPACE_ROOT_KEY]: workspaceRoot };
|
|
150
|
+
}
|
|
151
|
+
if (declares(manifest, LEDGER_ROOT_KEY) && workspaceRoot !== undefined) {
|
|
152
|
+
config = { ...config, [LEDGER_ROOT_KEY]: workspaceRoot };
|
|
81
153
|
}
|
|
82
|
-
return
|
|
154
|
+
return config;
|
|
83
155
|
};
|
|
84
156
|
/**
|
|
85
157
|
* Read and validate every skill a manifest declares — staged, not
|
|
@@ -131,6 +203,38 @@ const stageManifestSkills = async (manifest, packageDirectory) => {
|
|
|
131
203
|
}
|
|
132
204
|
return staged;
|
|
133
205
|
};
|
|
206
|
+
/**
|
|
207
|
+
* Everything `loadPlugins` checks before it imports a package: that the
|
|
208
|
+
* settings match the manifest's own schema, that any `toolRisks` overrides
|
|
209
|
+
* name tools the manifest declares and risks it permits, and that every
|
|
210
|
+
* skill file the manifest names is present, inside the package, and
|
|
211
|
+
* readable.
|
|
212
|
+
*
|
|
213
|
+
* One function because any of them failing rejects the *whole* plugin — it
|
|
214
|
+
* registers no tools and no skills — so a caller that ran a subset would
|
|
215
|
+
* report a plugin ready that the daemon refuses. `stratus plugins` is that
|
|
216
|
+
* caller, and it got exactly half of this right the first time; the
|
|
217
|
+
* `toolRisks` parse was the third check, missing here while the doc below
|
|
218
|
+
* said it should not be, until setup started asking this question too.
|
|
219
|
+
*
|
|
220
|
+
* Nothing here imports the package, which is what lets a diagnostic ask the
|
|
221
|
+
* question without starting anything.
|
|
222
|
+
*
|
|
223
|
+
* `loadPlugins` calls the same three checks rather than this composition of
|
|
224
|
+
* them, because it needs what the staging and the parse *return* and stages
|
|
225
|
+
* only when it has a registry to put skills in. The checks themselves are
|
|
226
|
+
* shared, so there is no second reading of a schema, an override or a skill
|
|
227
|
+
* path here — only a second caller of each. Anything added to the loader's
|
|
228
|
+
* preflight belongs in both.
|
|
229
|
+
*/
|
|
230
|
+
export const preflightPlugin = async (manifest, directory, block, workspaceRoot) => {
|
|
231
|
+
// The loader's order, kept: a block whose settings are wrong should say
|
|
232
|
+
// so before its overrides are read, since the overrides are the narrower
|
|
233
|
+
// mistake and the schema error is the one more likely to explain it.
|
|
234
|
+
validatePluginConfig(manifest, pluginConfigWithHostDefaults(block, manifest, workspaceRoot));
|
|
235
|
+
parseToolRiskOverrides(manifest, block);
|
|
236
|
+
await stageManifestSkills(manifest, directory);
|
|
237
|
+
};
|
|
134
238
|
/**
|
|
135
239
|
* Turn a `plugins` config block into running capability.
|
|
136
240
|
*
|
|
@@ -166,15 +270,13 @@ export const loadPlugins = async (options) => {
|
|
|
166
270
|
// held for the life of a daemon that goes on running without it.
|
|
167
271
|
let instance;
|
|
168
272
|
try {
|
|
169
|
-
const
|
|
170
|
-
const { packageJson, directory } = await packageJsonFor(resolved, specifier);
|
|
171
|
-
const manifest = parsePluginManifest(packageJson, specifier);
|
|
273
|
+
const { manifest, directory } = await readPluginManifest(specifier, options.host);
|
|
172
274
|
const isTrusted = trusted(manifest.packageName);
|
|
173
275
|
// Validated *after* the host's defaults are folded in, because that
|
|
174
276
|
// is the configuration the plugin will actually be handed: a manifest
|
|
175
277
|
// that declares `workspaceRoot` required would otherwise be refused
|
|
176
278
|
// for missing the very setting the host supplies.
|
|
177
|
-
const config =
|
|
279
|
+
const config = pluginConfigWithHostDefaults(block, manifest, options.workspaceRoot);
|
|
178
280
|
validatePluginConfig(manifest, config);
|
|
179
281
|
const riskOverrides = parseToolRiskOverrides(manifest, block);
|
|
180
282
|
// Skills are read and validated before the module is imported —
|
package/dist/loader.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAWzC,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAE3E,OAAO,EACL,mBAAmB,EACnB,sBAAsB,EACtB,oBAAoB,EACpB,mBAAmB,GAEpB,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,qCAAqC,EAAE,MAAM,kBAAkB,CAAC;AACzE,OAAO,EAAE,yBAAyB,EAAyB,MAAM,eAAe,CAAC;AAkBjF;;;;;;;;;;;;;GAaG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,KAAK,EACrC,SAAiB,EACjB,IAAwB,EACA,EAAE;IAC1B,IAAI,CAAC;QACH,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IAC1B,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,yEAAyE;IACzE,yBAAyB;IACzB,OAAO,CAAC,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAM,CAAC;AAC7C,CAAC,CAAC;AAKF;;;;GAIG;AACH,MAAM,cAAc,GAAG,KAAK,EAC1B,WAAmB,EACnB,SAAiB,EACqC,EAAE;IACxD,IAAI,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,WAAW,CAAC,CAAC,CAAC;IACzD,uEAAuE;IACvE,qEAAqE;IACrE,qCAAqC;IACrC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1C,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,MAAM,CAAC,CAAC;YACzE,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,CAAY,EAAE,SAAS,EAAE,CAAC;QAChE,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;YACvC,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;gBACzB,MAAM;YACR,CAAC;YACD,SAAS,GAAG,MAAM,CAAC;QACrB,CAAC;IACH,CAAC;IACD,MAAM,IAAI,mBAAmB,CAAC,qCAAqC,SAAS,GAAG,CAAC,CAAC;AACnF,CAAC,CAAC;AAEF
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../src/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
import type { FileHandle } from 'node:fs/promises';
|
|
2
|
+
import { type TrustLevel } from '@stratusagent/core';
|
|
3
|
+
/**
|
|
4
|
+
* The tainted-write ledger: which paths an agent wrote while its session
|
|
5
|
+
* was at `external` or `unknown`, and at which label.
|
|
6
|
+
*
|
|
7
|
+
* The filesystem is a laundering channel by construction — a durable store
|
|
8
|
+
* the agent controls. An agent that `fs.write`s fetched text into its
|
|
9
|
+
* workspace and `fs.read`s it back next week gets a file with no
|
|
10
|
+
* provenance, arriving as its own notes. This closes the sequence an agent
|
|
11
|
+
* can perform by itself: a write from a tainted session records the path,
|
|
12
|
+
* and a later read of that path taints the reading session at the recorded
|
|
13
|
+
* label.
|
|
14
|
+
*
|
|
15
|
+
* What it does not cover, said plainly: a copy under another name, a file a
|
|
16
|
+
* different process wrote, content pasted through some path the ledger
|
|
17
|
+
* never saw. Full filesystem provenance means carrying labels on bytes
|
|
18
|
+
* across a surface the agent does not exclusively own, which is a different
|
|
19
|
+
* project.
|
|
20
|
+
*
|
|
21
|
+
* One file per agent, under the agent's own workspace — next to the roots
|
|
22
|
+
* `tool-fs` already resolves per call, and keyed the same way, because two
|
|
23
|
+
* agents with different roots is the whole point of the per-agent block.
|
|
24
|
+
* It lives in the plugin host rather than in `tool-fs` because `tool-fs`
|
|
25
|
+
* is not the only plugin that puts a server's bytes on disk: `plugin-mcp`
|
|
26
|
+
* writes a bridged tool's image and audio blocks into the same workspace,
|
|
27
|
+
* and a file that bypassed `fs.write` would otherwise read back unlabelled.
|
|
28
|
+
* Without a workspace root (a host that loaded the plugin outside the
|
|
29
|
+
* loader) the ledger is process-local and says so in its name: the
|
|
30
|
+
* read-back-next-week case then survives only as long as the daemon does.
|
|
31
|
+
*/
|
|
32
|
+
export interface TaintedWriteLedger {
|
|
33
|
+
/** The label a read of this path carries, or undefined for a path the ledger never saw. */
|
|
34
|
+
lookup(agentId: string, absolutePath: string): Promise<TrustLevel | undefined>;
|
|
35
|
+
/**
|
|
36
|
+
* Every recorded path and its label, for a result that names many files
|
|
37
|
+
* at once — a listing, a search's matches and skips — read once rather
|
|
38
|
+
* than once per file.
|
|
39
|
+
*/
|
|
40
|
+
snapshot(agentId: string): Promise<Record<string, TrustLevel>>;
|
|
41
|
+
/**
|
|
42
|
+
* Record a write at the writing session's label. A record only ever goes
|
|
43
|
+
* down and never clears — not even when a clean session later rewrites
|
|
44
|
+
* the file whole — because the path was the tainted session's choice as
|
|
45
|
+
* much as the bytes were, and because a clearing is the one record that
|
|
46
|
+
* could race a tainted write from another process into leaving tainted
|
|
47
|
+
* bytes unlabelled. Over-marking is the safe direction; an operator who
|
|
48
|
+
* wants a path back removes its lines from the ledger by hand. A clean
|
|
49
|
+
* session's write records nothing.
|
|
50
|
+
*/
|
|
51
|
+
recordWrite(agentId: string, absolutePath: string, trust: TrustLevel): Promise<void>;
|
|
52
|
+
}
|
|
53
|
+
/** The ledger's filename inside an agent's workspace. Exported so `fs.write` can refuse to write it. */
|
|
54
|
+
export declare const LEDGER_FILENAME = "fs-provenance.jsonl";
|
|
55
|
+
/** In-process only. See `TaintedWriteLedger` for when this is what a host gets. */
|
|
56
|
+
export declare const createProcessLocalLedger: () => TaintedWriteLedger;
|
|
57
|
+
/**
|
|
58
|
+
* The label the ledger's own contents carry: the lowest label recorded in
|
|
59
|
+
* it. Every path in it was chosen by a session at `unknown` or `external`,
|
|
60
|
+
* and the ledger's own path has no record, so an agent whose roots cover
|
|
61
|
+
* its workspace could otherwise `fs.read` the ledger and get a list of
|
|
62
|
+
* attacker-chosen filenames back at `agent`. Undefined for no file or an
|
|
63
|
+
* empty one; `unknown` for a file that holds lines nothing here can read
|
|
64
|
+
* — nobody vouches for those.
|
|
65
|
+
*/
|
|
66
|
+
export declare const ledgerContentTrust: (ledgerFilePath: string,
|
|
67
|
+
/**
|
|
68
|
+
* The inode the caller read the ledger at. Given, the bytes judged are
|
|
69
|
+
* read from that inode or not at all: a name swapped for an empty file
|
|
70
|
+
* after the caller's read would otherwise be read here as "no label",
|
|
71
|
+
* while the result still shows the ledger's contents. A swap reads
|
|
72
|
+
* `unknown` — nobody can vouch for bytes they can no longer see.
|
|
73
|
+
*/
|
|
74
|
+
identity?: FileIdentity) => Promise<TrustLevel | undefined>;
|
|
75
|
+
/**
|
|
76
|
+
* The label a ledger's bytes carry: the lowest recorded label, `unknown`
|
|
77
|
+
* for lines nothing here can read, nothing for an empty file. Pure over the
|
|
78
|
+
* bytes, so a caller that already holds what it showed the model — an
|
|
79
|
+
* `fs.read` result, a search's file contents — judges exactly that, and a
|
|
80
|
+
* peer rewriting the ledger in place after the read (same inode, new
|
|
81
|
+
* bytes) cannot make the shown lines read as unlabelled.
|
|
82
|
+
*/
|
|
83
|
+
export declare const ledgerTrustOfContent: (raw: string) => TrustLevel | undefined;
|
|
84
|
+
/**
|
|
85
|
+
* The durable ledger, one append-only JSONL file per agent at
|
|
86
|
+
* `<workspaceRoot>/<agentId>/fs-provenance.jsonl`, owner-only. Each record
|
|
87
|
+
* is one `O_APPEND` write, so processes that share an agent — the daemon and
|
|
88
|
+
* a `stratus run` — interleave records rather than overwrite each other.
|
|
89
|
+
*/
|
|
90
|
+
export declare const createFileLedger: (workspaceRoot: string) => TaintedWriteLedger;
|
|
91
|
+
/**
|
|
92
|
+
* Whether `absolutePath` is an agent's ledger — exactly
|
|
93
|
+
* `<workspaceRoot>/<agentId>/fs-provenance.json`, any agent's — which is the
|
|
94
|
+
* one path `fs.write` refuses. Exactly that depth, not any descendant with
|
|
95
|
+
* the name: a project an agent keeps under its workspace may legitimately
|
|
96
|
+
* have a file called `fs-provenance.json` of its own.
|
|
97
|
+
*
|
|
98
|
+
* `workspaceRoots` are every spelling of the workspace root worth checking
|
|
99
|
+
* — the configured path and its canonical form — because the path being
|
|
100
|
+
* judged arrives canonical from the root resolver, and a workspace an
|
|
101
|
+
* operator moved behind a symlink would otherwise compare as outside.
|
|
102
|
+
*/
|
|
103
|
+
export declare const isLedgerPath: (workspaceRoots: readonly string[], absolutePath: string) => boolean;
|
|
104
|
+
/**
|
|
105
|
+
* The predicate `fs.write` refuses on and `fs.read` labels by, built once
|
|
106
|
+
* per tool call from what the workspace holds right now. A path is an
|
|
107
|
+
* agent's ledger two ways: lexically —
|
|
108
|
+
* `<workspaceRoot>/<agent>/fs-provenance.jsonl` under the configured or the
|
|
109
|
+
* canonical root — or through a link at the agent directory. An operator
|
|
110
|
+
* who relocated one agent's workspace with `<workspaceRoot>/ava -> /data/ava`
|
|
111
|
+
* has the ledger at `/data/ava/fs-provenance.jsonl`, which is how the root
|
|
112
|
+
* resolver spells every path under it and which no spelling of the root
|
|
113
|
+
* reaches, so every entry of the workspace is canonicalized and its ledger
|
|
114
|
+
* path listed — the ledger file's own canonical path too, for a link at
|
|
115
|
+
* the file rather than the directory, and its device and inode, for a hard
|
|
116
|
+
* link to it from inside a root. Built per call and never cached: a
|
|
117
|
+
* link repointed under a running daemon is judged where it points now, and
|
|
118
|
+
* one `readdir` plus two `realpath`s per agent is nothing next to the write.
|
|
119
|
+
*/
|
|
120
|
+
export interface FileIdentity {
|
|
121
|
+
dev: number;
|
|
122
|
+
ino: number;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Whether a path is an agent's ledger. `identity` is the inode the caller
|
|
126
|
+
* already holds for it — captured by the root resolver and verified by the
|
|
127
|
+
* open, so it is the file whose bytes were read or are about to be
|
|
128
|
+
* written. Given, it is what is judged; without it the path is stat'd,
|
|
129
|
+
* which names whatever is there *now*, and a peer can swap the name
|
|
130
|
+
* between a read and this check.
|
|
131
|
+
*/
|
|
132
|
+
export type LedgerGuard = (absolutePath: string, identity?: FileIdentity) => Promise<boolean>;
|
|
133
|
+
export declare const ledgerGuard: (workspaceRoot: string | undefined) => Promise<LedgerGuard>;
|
|
134
|
+
/**
|
|
135
|
+
* Whether `absolutePath`, spelled exactly so and through no link, names the
|
|
136
|
+
* file `handle` holds open — right now. Both halves matter: the canonical
|
|
137
|
+
* spelling must be the name itself, or a directory on the way is a link and
|
|
138
|
+
* the file lives somewhere else; and the inode at that name must be the
|
|
139
|
+
* handle's, or the name has since been given to a decoy while the handle
|
|
140
|
+
* still refers to wherever the link sent the create. A pathname comparison
|
|
141
|
+
* alone passes the second case.
|
|
142
|
+
*/
|
|
143
|
+
export declare const nameIdentifiesHandle: (absolutePath: string, handle: FileHandle) => Promise<boolean>;
|
|
144
|
+
//# sourceMappingURL=provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.d.ts","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAA8B,KAAK,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,MAAM,WAAW,kBAAkB;IACjC,2FAA2F;IAC3F,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,GAAG,SAAS,CAAC,CAAC;IAC/E;;;;OAIG;IACH,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;IAC/D;;;;;;;;;OASG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACtF;AAED,wGAAwG;AACxG,eAAO,MAAM,eAAe,wBAAwB,CAAC;AAiCrD,mFAAmF;AACnF,eAAO,MAAM,wBAAwB,QAAO,kBAa3C,CAAC;AAiCF;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,GAC7B,gBAAgB,MAAM;AACtB;;;;;;GAMG;AACH,WAAW,YAAY,KACtB,OAAO,CAAC,UAAU,GAAG,SAAS,CA0BhC,CAAC;AAEF;;;;;;;GAOG;AACH,eAAO,MAAM,oBAAoB,GAAI,KAAK,MAAM,KAAG,UAAU,GAAG,SAW/D,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,GAAI,eAAe,MAAM,KAAG,kBAmExD,CAAC;AAEF;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,YAAY,GAAI,gBAAgB,SAAS,MAAM,EAAE,EAAE,cAAc,MAAM,KAAG,OAQnF,CAAC;AAEL;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,YAAY;IAC3B,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,YAAY,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAI9F,eAAO,MAAM,WAAW,GAAU,eAAe,MAAM,GAAG,SAAS,KAAG,OAAO,CAAC,WAAW,CAgExF,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,oBAAoB,GAC/B,cAAc,MAAM,EACpB,QAAQ,UAAU,KACjB,OAAO,CAAC,OAAO,CAUjB,CAAC"}
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { lstat, mkdir, open, readdir, readFile, realpath, stat } from 'node:fs/promises';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { isTrustLevel, leastTrusted } from '@stratusagent/core';
|
|
5
|
+
/** The ledger's filename inside an agent's workspace. Exported so `fs.write` can refuse to write it. */
|
|
6
|
+
export const LEDGER_FILENAME = 'fs-provenance.jsonl';
|
|
7
|
+
const tainted = (trust) => trust === 'external' || trust === 'unknown';
|
|
8
|
+
/** The ledger after a write at `trust`: the same object when nothing changed. */
|
|
9
|
+
const nextPaths = (paths, absolutePath, trust) => {
|
|
10
|
+
if (!tainted(trust)) {
|
|
11
|
+
return paths;
|
|
12
|
+
}
|
|
13
|
+
const recorded = paths[absolutePath];
|
|
14
|
+
const combined = recorded !== undefined ? leastTrusted(recorded, trust) : trust;
|
|
15
|
+
return combined === recorded ? paths : { ...paths, [absolutePath]: combined };
|
|
16
|
+
};
|
|
17
|
+
/** In-process only. See `TaintedWriteLedger` for when this is what a host gets. */
|
|
18
|
+
export const createProcessLocalLedger = () => {
|
|
19
|
+
const byAgent = new Map();
|
|
20
|
+
return {
|
|
21
|
+
async lookup(agentId, absolutePath) {
|
|
22
|
+
return byAgent.get(agentId)?.[absolutePath];
|
|
23
|
+
},
|
|
24
|
+
async snapshot(agentId) {
|
|
25
|
+
return { ...(byAgent.get(agentId) ?? {}) };
|
|
26
|
+
},
|
|
27
|
+
async recordWrite(agentId, absolutePath, trust) {
|
|
28
|
+
byAgent.set(agentId, nextPaths(byAgent.get(agentId) ?? {}, absolutePath, trust));
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
const parseLedger = (raw, filePath) => {
|
|
33
|
+
const paths = {};
|
|
34
|
+
for (const line of raw.split('\n')) {
|
|
35
|
+
if (line.trim().length === 0) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
let parsed;
|
|
39
|
+
try {
|
|
40
|
+
parsed = JSON.parse(line);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
throw new Error(`The filesystem provenance ledger has an invalid line: ${filePath}. Delete it to start over; the cost is that files written by earlier tainted sessions read as the agent's own.`);
|
|
44
|
+
}
|
|
45
|
+
if (typeof parsed !== 'object' || parsed === null || typeof parsed.path !== 'string') {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const record = parsed;
|
|
49
|
+
// Order-independent on purpose: labels only ever go down, so the lowest
|
|
50
|
+
// record for a path stands whichever process appended first. A path is
|
|
51
|
+
// in the ledger because a tainted write put it there, so a record whose
|
|
52
|
+
// label is missing or one nobody recognises — a hand edit, a label from
|
|
53
|
+
// a newer build — still marks the path: at `unknown`, never dropped,
|
|
54
|
+
// which would read the file back as the agent's own.
|
|
55
|
+
const label = isTrustLevel(record.trust) ? record.trust : 'unknown';
|
|
56
|
+
if (tainted(label)) {
|
|
57
|
+
const recorded = paths[record.path];
|
|
58
|
+
paths[record.path] = recorded !== undefined ? leastTrusted(recorded, label) : label;
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return paths;
|
|
62
|
+
};
|
|
63
|
+
/**
|
|
64
|
+
* The label the ledger's own contents carry: the lowest label recorded in
|
|
65
|
+
* it. Every path in it was chosen by a session at `unknown` or `external`,
|
|
66
|
+
* and the ledger's own path has no record, so an agent whose roots cover
|
|
67
|
+
* its workspace could otherwise `fs.read` the ledger and get a list of
|
|
68
|
+
* attacker-chosen filenames back at `agent`. Undefined for no file or an
|
|
69
|
+
* empty one; `unknown` for a file that holds lines nothing here can read
|
|
70
|
+
* — nobody vouches for those.
|
|
71
|
+
*/
|
|
72
|
+
export const ledgerContentTrust = async (ledgerFilePath,
|
|
73
|
+
/**
|
|
74
|
+
* The inode the caller read the ledger at. Given, the bytes judged are
|
|
75
|
+
* read from that inode or not at all: a name swapped for an empty file
|
|
76
|
+
* after the caller's read would otherwise be read here as "no label",
|
|
77
|
+
* while the result still shows the ledger's contents. A swap reads
|
|
78
|
+
* `unknown` — nobody can vouch for bytes they can no longer see.
|
|
79
|
+
*/
|
|
80
|
+
identity) => {
|
|
81
|
+
let raw;
|
|
82
|
+
try {
|
|
83
|
+
if (identity !== undefined) {
|
|
84
|
+
const handle = await open(ledgerFilePath, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
85
|
+
try {
|
|
86
|
+
const info = await handle.stat();
|
|
87
|
+
if (info.dev !== identity.dev || info.ino !== identity.ino) {
|
|
88
|
+
return 'unknown';
|
|
89
|
+
}
|
|
90
|
+
raw = (await handle.readFile()).toString('utf8');
|
|
91
|
+
}
|
|
92
|
+
finally {
|
|
93
|
+
await handle.close();
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
raw = await readFile(ledgerFilePath, 'utf8');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
const code = error.code;
|
|
102
|
+
if (code === 'ENOENT' || code === 'ENOTDIR' || code === 'EISDIR' || code === 'ELOOP') {
|
|
103
|
+
// With an inode in hand, a name that no longer opens is a swap too.
|
|
104
|
+
return identity !== undefined ? 'unknown' : undefined;
|
|
105
|
+
}
|
|
106
|
+
throw error;
|
|
107
|
+
}
|
|
108
|
+
return ledgerTrustOfContent(raw);
|
|
109
|
+
};
|
|
110
|
+
/**
|
|
111
|
+
* The label a ledger's bytes carry: the lowest recorded label, `unknown`
|
|
112
|
+
* for lines nothing here can read, nothing for an empty file. Pure over the
|
|
113
|
+
* bytes, so a caller that already holds what it showed the model — an
|
|
114
|
+
* `fs.read` result, a search's file contents — judges exactly that, and a
|
|
115
|
+
* peer rewriting the ledger in place after the read (same inode, new
|
|
116
|
+
* bytes) cannot make the shown lines read as unlabelled.
|
|
117
|
+
*/
|
|
118
|
+
export const ledgerTrustOfContent = (raw) => {
|
|
119
|
+
if (raw.trim().length === 0) {
|
|
120
|
+
return undefined;
|
|
121
|
+
}
|
|
122
|
+
let labels;
|
|
123
|
+
try {
|
|
124
|
+
labels = Object.values(parseLedger(raw, 'the ledger as read'));
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return 'unknown';
|
|
128
|
+
}
|
|
129
|
+
return labels.length > 0 ? leastTrusted(...labels) : 'unknown';
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* The durable ledger, one append-only JSONL file per agent at
|
|
133
|
+
* `<workspaceRoot>/<agentId>/fs-provenance.jsonl`, owner-only. Each record
|
|
134
|
+
* is one `O_APPEND` write, so processes that share an agent — the daemon and
|
|
135
|
+
* a `stratus run` — interleave records rather than overwrite each other.
|
|
136
|
+
*/
|
|
137
|
+
export const createFileLedger = (workspaceRoot) => {
|
|
138
|
+
const ledgerPath = (agentId) => path.join(workspaceRoot, agentId, LEDGER_FILENAME);
|
|
139
|
+
const read = async (agentId) => {
|
|
140
|
+
const filePath = ledgerPath(agentId);
|
|
141
|
+
try {
|
|
142
|
+
return parseLedger(await readFile(filePath, 'utf8'), filePath);
|
|
143
|
+
}
|
|
144
|
+
catch (error) {
|
|
145
|
+
// No ledger yet, or a workspace root that is not a directory: either
|
|
146
|
+
// way nothing has been recorded. A tainted write still fails when it
|
|
147
|
+
// tries to record, which is the failure direction that leaves no
|
|
148
|
+
// unlabelled file behind.
|
|
149
|
+
const code = error.code;
|
|
150
|
+
if (code === 'ENOENT' || code === 'ENOTDIR') {
|
|
151
|
+
return {};
|
|
152
|
+
}
|
|
153
|
+
throw error;
|
|
154
|
+
}
|
|
155
|
+
};
|
|
156
|
+
// Serialized per process: two writes in one turn are rare, but a
|
|
157
|
+
// read-modify-write with no lock would let the second drop the first.
|
|
158
|
+
let chain = Promise.resolve();
|
|
159
|
+
return {
|
|
160
|
+
lookup: (agentId, absolutePath) => read(agentId).then((paths) => paths[absolutePath]),
|
|
161
|
+
snapshot: (agentId) => read(agentId),
|
|
162
|
+
recordWrite(agentId, absolutePath, trust) {
|
|
163
|
+
const work = chain.then(async () => {
|
|
164
|
+
if (!tainted(trust)) {
|
|
165
|
+
// A clean write records nothing — see `TaintedWriteLedger`.
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
const filePath = ledgerPath(agentId);
|
|
169
|
+
await mkdir(path.dirname(filePath), { recursive: true, mode: 0o700 });
|
|
170
|
+
// Read and appended through ONE descriptor. A ledger reached through
|
|
171
|
+
// a link (a relocated workspace, a relocated file — both supported)
|
|
172
|
+
// is resolved once, at this open; a second open for the append
|
|
173
|
+
// would resolve the name afresh, and a link repointed in between
|
|
174
|
+
// would put the record in some other file while the bytes it
|
|
175
|
+
// describes land where the resolver already decided. O_APPEND keeps
|
|
176
|
+
// the write itself atomic against a peer's.
|
|
177
|
+
const handle = await open(filePath, constants.O_RDWR | constants.O_CREAT | constants.O_APPEND, 0o600);
|
|
178
|
+
try {
|
|
179
|
+
// Tightened before the append, like the memory file: the mode on
|
|
180
|
+
// open applies only when it creates the file.
|
|
181
|
+
await handle.chmod(0o600);
|
|
182
|
+
const before = parseLedger((await handle.readFile()).toString('utf8'), filePath);
|
|
183
|
+
const paths = nextPaths(before, absolutePath, trust);
|
|
184
|
+
// A path already at this label or lower needs no second line.
|
|
185
|
+
if (paths === before) {
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const record = {
|
|
189
|
+
path: absolutePath,
|
|
190
|
+
trust: paths[absolutePath],
|
|
191
|
+
at: new Date().toISOString(),
|
|
192
|
+
};
|
|
193
|
+
await handle.appendFile(`${JSON.stringify(record)}\n`);
|
|
194
|
+
}
|
|
195
|
+
finally {
|
|
196
|
+
await handle.close();
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
chain = work.then(() => undefined, () => undefined);
|
|
200
|
+
return work;
|
|
201
|
+
},
|
|
202
|
+
};
|
|
203
|
+
};
|
|
204
|
+
/**
|
|
205
|
+
* Whether `absolutePath` is an agent's ledger — exactly
|
|
206
|
+
* `<workspaceRoot>/<agentId>/fs-provenance.json`, any agent's — which is the
|
|
207
|
+
* one path `fs.write` refuses. Exactly that depth, not any descendant with
|
|
208
|
+
* the name: a project an agent keeps under its workspace may legitimately
|
|
209
|
+
* have a file called `fs-provenance.json` of its own.
|
|
210
|
+
*
|
|
211
|
+
* `workspaceRoots` are every spelling of the workspace root worth checking
|
|
212
|
+
* — the configured path and its canonical form — because the path being
|
|
213
|
+
* judged arrives canonical from the root resolver, and a workspace an
|
|
214
|
+
* operator moved behind a symlink would otherwise compare as outside.
|
|
215
|
+
*/
|
|
216
|
+
export const isLedgerPath = (workspaceRoots, absolutePath) => workspaceRoots.some((workspaceRoot) => {
|
|
217
|
+
const relative = path.relative(workspaceRoot, absolutePath);
|
|
218
|
+
if (relative.length === 0 || relative.startsWith('..') || path.isAbsolute(relative)) {
|
|
219
|
+
return false;
|
|
220
|
+
}
|
|
221
|
+
const segments = relative.split(path.sep);
|
|
222
|
+
return segments.length === 2 && segments[1] === LEDGER_FILENAME;
|
|
223
|
+
});
|
|
224
|
+
const identityKey = (identity) => `${identity.dev}:${identity.ino}`;
|
|
225
|
+
export const ledgerGuard = async (workspaceRoot) => {
|
|
226
|
+
if (workspaceRoot === undefined) {
|
|
227
|
+
return async () => false;
|
|
228
|
+
}
|
|
229
|
+
const roots = [workspaceRoot];
|
|
230
|
+
try {
|
|
231
|
+
const canonical = await realpath(workspaceRoot);
|
|
232
|
+
if (canonical !== workspaceRoot) {
|
|
233
|
+
roots.push(canonical);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
catch {
|
|
237
|
+
// Not there yet: only the configured spelling, and no agents to list.
|
|
238
|
+
}
|
|
239
|
+
const ledgers = new Set();
|
|
240
|
+
// And the files themselves, by identity: a hard link to a ledger from
|
|
241
|
+
// inside a root has a path no spelling reaches and `realpath` leaves
|
|
242
|
+
// alone, and is the same bytes. Plain numbers, like the resolver's
|
|
243
|
+
// `identity`, so the two sides of a comparison round the same way.
|
|
244
|
+
const identities = new Set();
|
|
245
|
+
let entries = [];
|
|
246
|
+
try {
|
|
247
|
+
entries = await readdir(workspaceRoot, { withFileTypes: true });
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
entries = [];
|
|
251
|
+
}
|
|
252
|
+
for (const entry of entries) {
|
|
253
|
+
if (!entry.isDirectory() && !entry.isSymbolicLink()) {
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
const lexical = path.join(workspaceRoot, entry.name, LEDGER_FILENAME);
|
|
257
|
+
// Two canonical spellings, because either component can be a link: the
|
|
258
|
+
// agent directory (`ava -> /data/ava`, judged even before the ledger
|
|
259
|
+
// exists there) and the ledger file itself (`fs-provenance.jsonl ->
|
|
260
|
+
// /data/ava-ledger.jsonl`, whose target is what the resolver returns
|
|
261
|
+
// and what a truncating write would empty).
|
|
262
|
+
try {
|
|
263
|
+
ledgers.add(path.join(await realpath(path.dirname(lexical)), LEDGER_FILENAME));
|
|
264
|
+
}
|
|
265
|
+
catch {
|
|
266
|
+
// A dangling link holds no ledger.
|
|
267
|
+
}
|
|
268
|
+
try {
|
|
269
|
+
ledgers.add(await realpath(lexical));
|
|
270
|
+
identities.add(identityKey(await stat(lexical)));
|
|
271
|
+
}
|
|
272
|
+
catch {
|
|
273
|
+
// No ledger there yet, or a dangling link: nothing to protect.
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
return async (absolutePath, identity) => {
|
|
277
|
+
if (isLedgerPath(roots, absolutePath) || ledgers.has(absolutePath)) {
|
|
278
|
+
return true;
|
|
279
|
+
}
|
|
280
|
+
if (identities.size === 0) {
|
|
281
|
+
return false;
|
|
282
|
+
}
|
|
283
|
+
if (identity !== undefined) {
|
|
284
|
+
return identities.has(identityKey(identity));
|
|
285
|
+
}
|
|
286
|
+
try {
|
|
287
|
+
return identities.has(identityKey(await stat(absolutePath)));
|
|
288
|
+
}
|
|
289
|
+
catch {
|
|
290
|
+
// Nothing there: a write about to create a file is not the ledger.
|
|
291
|
+
return false;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
};
|
|
295
|
+
/**
|
|
296
|
+
* Whether `absolutePath`, spelled exactly so and through no link, names the
|
|
297
|
+
* file `handle` holds open — right now. Both halves matter: the canonical
|
|
298
|
+
* spelling must be the name itself, or a directory on the way is a link and
|
|
299
|
+
* the file lives somewhere else; and the inode at that name must be the
|
|
300
|
+
* handle's, or the name has since been given to a decoy while the handle
|
|
301
|
+
* still refers to wherever the link sent the create. A pathname comparison
|
|
302
|
+
* alone passes the second case.
|
|
303
|
+
*/
|
|
304
|
+
export const nameIdentifiesHandle = async (absolutePath, handle) => {
|
|
305
|
+
try {
|
|
306
|
+
if ((await realpath(absolutePath)) !== absolutePath) {
|
|
307
|
+
return false;
|
|
308
|
+
}
|
|
309
|
+
const [atName, held] = await Promise.all([lstat(absolutePath), handle.stat()]);
|
|
310
|
+
return atName.dev === held.dev && atName.ino === held.ino;
|
|
311
|
+
}
|
|
312
|
+
catch {
|
|
313
|
+
return false;
|
|
314
|
+
}
|
|
315
|
+
};
|
|
316
|
+
//# sourceMappingURL=provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provenance.js","sourceRoot":"","sources":["../src/provenance.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stratusagent/plugins",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
"node": ">=22.13 <23 || >=23.4"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@stratusagent/agents": "0.11.
|
|
22
|
-
"@stratusagent/core": "0.11.
|
|
21
|
+
"@stratusagent/agents": "0.11.3",
|
|
22
|
+
"@stratusagent/core": "0.11.3"
|
|
23
23
|
},
|
|
24
24
|
"devDependencies": {
|
|
25
25
|
"@types/node": "^24.6.0",
|