@smthrs/kernel 0.0.0-stage → 1.0.0-rc.4
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/CHANGELOG.md +206 -0
- package/LICENSE +21 -0
- package/README.md +154 -2
- package/dist/cjs/CapabilitySet.d.ts +6 -0
- package/dist/cjs/CapabilitySet.d.ts.map +1 -0
- package/dist/cjs/CapabilitySet.js +19 -0
- package/dist/cjs/CapabilitySet.js.map +7 -0
- package/dist/cjs/ChildProcessEnvironment.d.ts +60 -0
- package/dist/cjs/ChildProcessEnvironment.d.ts.map +1 -0
- package/dist/cjs/ChildProcessEnvironment.js +61 -0
- package/dist/cjs/ChildProcessEnvironment.js.map +7 -0
- package/dist/cjs/ChildProcessSpawner.d.ts +100 -0
- package/dist/cjs/ChildProcessSpawner.d.ts.map +1 -0
- package/dist/cjs/ChildProcessSpawner.js +291 -0
- package/dist/cjs/ChildProcessSpawner.js.map +7 -0
- package/dist/cjs/CommandLine.d.ts +173 -0
- package/dist/cjs/CommandLine.d.ts.map +1 -0
- package/dist/cjs/CommandLine.js +54 -0
- package/dist/cjs/CommandLine.js.map +7 -0
- package/dist/cjs/ContainedSpawner.d.ts +135 -0
- package/dist/cjs/ContainedSpawner.d.ts.map +1 -0
- package/dist/cjs/ContainedSpawner.js +141 -0
- package/dist/cjs/ContainedSpawner.js.map +7 -0
- package/dist/cjs/FileSystem.d.ts +452 -0
- package/dist/cjs/FileSystem.d.ts.map +1 -0
- package/dist/cjs/FileSystem.js +890 -0
- package/dist/cjs/FileSystem.js.map +7 -0
- package/dist/cjs/FileSystemBatch.d.ts +94 -0
- package/dist/cjs/FileSystemBatch.d.ts.map +1 -0
- package/dist/cjs/FileSystemBatch.js +31 -0
- package/dist/cjs/FileSystemBatch.js.map +7 -0
- package/dist/cjs/GrantEvent.d.ts +240 -0
- package/dist/cjs/GrantEvent.d.ts.map +1 -0
- package/dist/cjs/GrantEvent.js +115 -0
- package/dist/cjs/GrantEvent.js.map +7 -0
- package/dist/cjs/GrantStore.d.ts +270 -0
- package/dist/cjs/GrantStore.d.ts.map +1 -0
- package/dist/cjs/GrantStore.js +857 -0
- package/dist/cjs/GrantStore.js.map +7 -0
- package/dist/cjs/HostError.d.ts +36 -0
- package/dist/cjs/HostError.d.ts.map +1 -0
- package/dist/cjs/HostError.js +17 -0
- package/dist/cjs/HostError.js.map +7 -0
- package/dist/cjs/HostServices.d.ts +101 -0
- package/dist/cjs/HostServices.d.ts.map +1 -0
- package/dist/cjs/HostServices.js +66 -0
- package/dist/cjs/HostServices.js.map +7 -0
- package/dist/cjs/HttpClient.d.ts +177 -0
- package/dist/cjs/HttpClient.d.ts.map +1 -0
- package/dist/cjs/HttpClient.js +217 -0
- package/dist/cjs/HttpClient.js.map +7 -0
- package/dist/cjs/Jj.d.ts +67 -0
- package/dist/cjs/Jj.d.ts.map +1 -0
- package/dist/cjs/Jj.js +118 -0
- package/dist/cjs/Jj.js.map +7 -0
- package/dist/cjs/JournalGrantStore.d.ts +65 -0
- package/dist/cjs/JournalGrantStore.d.ts.map +1 -0
- package/dist/cjs/JournalGrantStore.js +354 -0
- package/dist/cjs/JournalGrantStore.js.map +7 -0
- package/dist/cjs/Path.d.ts +37 -0
- package/dist/cjs/Path.d.ts.map +1 -0
- package/dist/cjs/Path.js +46 -0
- package/dist/cjs/Path.js.map +7 -0
- package/dist/cjs/ProcessConfinement.d.ts +55 -0
- package/dist/cjs/ProcessConfinement.d.ts.map +1 -0
- package/dist/cjs/ProcessConfinement.js +94 -0
- package/dist/cjs/ProcessConfinement.js.map +7 -0
- package/dist/cjs/ProcessLedger.d.ts +260 -0
- package/dist/cjs/ProcessLedger.d.ts.map +1 -0
- package/dist/cjs/ProcessLedger.js +190 -0
- package/dist/cjs/ProcessLedger.js.map +7 -0
- package/dist/cjs/Rooted.d.ts +53 -0
- package/dist/cjs/Rooted.d.ts.map +1 -0
- package/dist/cjs/Rooted.js +101 -0
- package/dist/cjs/Rooted.js.map +7 -0
- package/dist/cjs/Unreachable.d.ts +27 -0
- package/dist/cjs/Unreachable.d.ts.map +1 -0
- package/dist/cjs/Unreachable.js +43 -0
- package/dist/cjs/Unreachable.js.map +7 -0
- package/dist/cjs/Workspace.d.ts +62 -0
- package/dist/cjs/Workspace.d.ts.map +1 -0
- package/dist/cjs/Workspace.js +35 -0
- package/dist/cjs/Workspace.js.map +7 -0
- package/dist/cjs/index.d.ts +161 -0
- package/dist/cjs/index.d.ts.map +1 -0
- package/dist/cjs/index.js +73 -0
- package/dist/cjs/index.js.map +7 -0
- package/dist/cjs/internal/Containment.d.ts +24 -0
- package/dist/cjs/internal/Containment.d.ts.map +1 -0
- package/dist/cjs/internal/Containment.js +30 -0
- package/dist/cjs/internal/Containment.js.map +7 -0
- package/dist/cjs/internal/Pipeline.d.ts +18 -0
- package/dist/cjs/internal/Pipeline.d.ts.map +1 -0
- package/dist/cjs/internal/Pipeline.js +90 -0
- package/dist/cjs/internal/Pipeline.js.map +7 -0
- package/dist/cjs/internal/makeCapability.d.ts +16 -0
- package/dist/cjs/internal/makeCapability.d.ts.map +1 -0
- package/dist/cjs/internal/makeCapability.js +44 -0
- package/dist/cjs/internal/makeCapability.js.map +7 -0
- package/dist/cjs/package.json +1 -0
- package/dist/cjs/test/FileSystemBatchContract.d.ts +15 -0
- package/dist/cjs/test/FileSystemBatchContract.d.ts.map +1 -0
- package/dist/cjs/test/FileSystemBatchContract.js +76 -0
- package/dist/cjs/test/FileSystemBatchContract.js.map +7 -0
- package/dist/cjs/test/HostContract.d.ts +225 -0
- package/dist/cjs/test/HostContract.d.ts.map +1 -0
- package/dist/cjs/test/HostContract.js +489 -0
- package/dist/cjs/test/HostContract.js.map +7 -0
- package/dist/cjs/test/TestGrantStore.d.ts +31 -0
- package/dist/cjs/test/TestGrantStore.d.ts.map +1 -0
- package/dist/cjs/test/TestGrantStore.js +65 -0
- package/dist/cjs/test/TestGrantStore.js.map +7 -0
- package/dist/esm/CapabilitySet.d.ts +6 -0
- package/dist/esm/CapabilitySet.d.ts.map +1 -0
- package/dist/esm/CapabilitySet.js +6 -0
- package/dist/esm/CapabilitySet.js.map +1 -0
- package/dist/esm/ChildProcessEnvironment.d.ts +60 -0
- package/dist/esm/ChildProcessEnvironment.d.ts.map +1 -0
- package/dist/esm/ChildProcessEnvironment.js +91 -0
- package/dist/esm/ChildProcessEnvironment.js.map +1 -0
- package/dist/esm/ChildProcessSpawner.d.ts +100 -0
- package/dist/esm/ChildProcessSpawner.d.ts.map +1 -0
- package/dist/esm/ChildProcessSpawner.js +342 -0
- package/dist/esm/ChildProcessSpawner.js.map +1 -0
- package/dist/esm/CommandLine.d.ts +173 -0
- package/dist/esm/CommandLine.d.ts.map +1 -0
- package/dist/esm/CommandLine.js +195 -0
- package/dist/esm/CommandLine.js.map +1 -0
- package/dist/esm/ContainedSpawner.d.ts +135 -0
- package/dist/esm/ContainedSpawner.d.ts.map +1 -0
- package/dist/esm/ContainedSpawner.js +180 -0
- package/dist/esm/ContainedSpawner.js.map +1 -0
- package/dist/esm/FileSystem.d.ts +452 -0
- package/dist/esm/FileSystem.d.ts.map +1 -0
- package/dist/esm/FileSystem.js +989 -0
- package/dist/esm/FileSystem.js.map +1 -0
- package/dist/esm/FileSystemBatch.d.ts +94 -0
- package/dist/esm/FileSystemBatch.d.ts.map +1 -0
- package/dist/esm/FileSystemBatch.js +26 -0
- package/dist/esm/FileSystemBatch.js.map +1 -0
- package/dist/esm/GrantEvent.d.ts +240 -0
- package/dist/esm/GrantEvent.d.ts.map +1 -0
- package/dist/esm/GrantEvent.js +155 -0
- package/dist/esm/GrantEvent.js.map +1 -0
- package/dist/esm/GrantStore.d.ts +270 -0
- package/dist/esm/GrantStore.d.ts.map +1 -0
- package/dist/esm/GrantStore.js +951 -0
- package/dist/esm/GrantStore.js.map +1 -0
- package/dist/esm/HostError.d.ts +36 -0
- package/dist/esm/HostError.d.ts.map +1 -0
- package/dist/esm/HostError.js +20 -0
- package/dist/esm/HostError.js.map +1 -0
- package/dist/esm/HostServices.d.ts +101 -0
- package/dist/esm/HostServices.d.ts.map +1 -0
- package/dist/esm/HostServices.js +76 -0
- package/dist/esm/HostServices.js.map +1 -0
- package/dist/esm/HttpClient.d.ts +177 -0
- package/dist/esm/HttpClient.d.ts.map +1 -0
- package/dist/esm/HttpClient.js +299 -0
- package/dist/esm/HttpClient.js.map +1 -0
- package/dist/esm/Jj.d.ts +67 -0
- package/dist/esm/Jj.d.ts.map +1 -0
- package/dist/esm/Jj.js +111 -0
- package/dist/esm/Jj.js.map +1 -0
- package/dist/esm/JournalGrantStore.d.ts +65 -0
- package/dist/esm/JournalGrantStore.d.ts.map +1 -0
- package/dist/esm/JournalGrantStore.js +350 -0
- package/dist/esm/JournalGrantStore.js.map +1 -0
- package/dist/esm/Path.d.ts +37 -0
- package/dist/esm/Path.d.ts.map +1 -0
- package/dist/esm/Path.js +34 -0
- package/dist/esm/Path.js.map +1 -0
- package/dist/esm/ProcessConfinement.d.ts +55 -0
- package/dist/esm/ProcessConfinement.d.ts.map +1 -0
- package/dist/esm/ProcessConfinement.js +106 -0
- package/dist/esm/ProcessConfinement.js.map +1 -0
- package/dist/esm/ProcessLedger.d.ts +260 -0
- package/dist/esm/ProcessLedger.d.ts.map +1 -0
- package/dist/esm/ProcessLedger.js +283 -0
- package/dist/esm/ProcessLedger.js.map +1 -0
- package/dist/esm/Rooted.d.ts +53 -0
- package/dist/esm/Rooted.d.ts.map +1 -0
- package/dist/esm/Rooted.js +104 -0
- package/dist/esm/Rooted.js.map +1 -0
- package/dist/esm/Unreachable.d.ts +27 -0
- package/dist/esm/Unreachable.d.ts.map +1 -0
- package/dist/esm/Unreachable.js +26 -0
- package/dist/esm/Unreachable.js.map +1 -0
- package/dist/esm/Workspace.d.ts +62 -0
- package/dist/esm/Workspace.d.ts.map +1 -0
- package/dist/esm/Workspace.js +51 -0
- package/dist/esm/Workspace.js.map +1 -0
- package/dist/esm/index.d.ts +161 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +151 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/internal/Containment.d.ts +24 -0
- package/dist/esm/internal/Containment.d.ts.map +1 -0
- package/dist/esm/internal/Containment.js +27 -0
- package/dist/esm/internal/Containment.js.map +1 -0
- package/dist/esm/internal/Pipeline.d.ts +18 -0
- package/dist/esm/internal/Pipeline.d.ts.map +1 -0
- package/dist/esm/internal/Pipeline.js +68 -0
- package/dist/esm/internal/Pipeline.js.map +1 -0
- package/dist/esm/internal/makeCapability.d.ts +16 -0
- package/dist/esm/internal/makeCapability.d.ts.map +1 -0
- package/dist/esm/internal/makeCapability.js +22 -0
- package/dist/esm/internal/makeCapability.js.map +1 -0
- package/dist/esm/test/FileSystemBatchContract.d.ts +15 -0
- package/dist/esm/test/FileSystemBatchContract.d.ts.map +1 -0
- package/dist/esm/test/FileSystemBatchContract.js +57 -0
- package/dist/esm/test/FileSystemBatchContract.js.map +1 -0
- package/dist/esm/test/HostContract.d.ts +225 -0
- package/dist/esm/test/HostContract.d.ts.map +1 -0
- package/dist/esm/test/HostContract.js +460 -0
- package/dist/esm/test/HostContract.js.map +1 -0
- package/dist/esm/test/TestGrantStore.d.ts +31 -0
- package/dist/esm/test/TestGrantStore.d.ts.map +1 -0
- package/dist/esm/test/TestGrantStore.js +57 -0
- package/dist/esm/test/TestGrantStore.js.map +1 -0
- package/docs/README.md +162 -0
- package/docs/api.md +1532 -0
- package/docs/concepts/decoration-in-place.md +117 -0
- package/docs/concepts/filesystem-batches.md +58 -0
- package/docs/concepts/filesystem-confinement.md +168 -0
- package/docs/concepts/grant-decisions.md +181 -0
- package/docs/concepts/process-containment.md +155 -0
- package/docs/contract.md +14 -0
- package/docs/guides/adapt-a-new-host-platform.md +148 -0
- package/docs/guides/answer-permission-requests.md +151 -0
- package/docs/guides/authorize-network-and-model-calls.md +118 -0
- package/docs/guides/contain-spawned-processes.md +118 -0
- package/docs/guides/guard-a-host-bundle.md +109 -0
- package/docs/guides/persist-grants-across-restarts.md +135 -0
- package/docs/guides/write-a-capability-policy.md +159 -0
- package/docs/installation.md +115 -0
- package/docs/quickstart.md +182 -0
- package/docs/testing.md +108 -0
- package/docs/troubleshooting.md +281 -0
- package/package.json +344 -3
- package/src/CapabilitySet.ts +6 -0
- package/src/ChildProcessEnvironment.ts +98 -0
- package/src/ChildProcessSpawner.ts +414 -0
- package/src/CommandLine.ts +250 -0
- package/src/ContainedSpawner.ts +284 -0
- package/src/FileSystem.ts +1655 -0
- package/src/FileSystemBatch.ts +90 -0
- package/src/GrantEvent.ts +174 -0
- package/src/GrantStore.ts +1345 -0
- package/src/HostError.ts +37 -0
- package/src/HostServices.ts +133 -0
- package/src/HttpClient.ts +406 -0
- package/src/Jj.ts +159 -0
- package/src/JournalGrantStore.ts +461 -0
- package/src/Path.ts +47 -0
- package/src/ProcessConfinement.ts +156 -0
- package/src/ProcessLedger.ts +423 -0
- package/src/Rooted.ts +128 -0
- package/src/Unreachable.ts +30 -0
- package/src/Workspace.ts +65 -0
- package/src/index.ts +181 -0
- package/src/internal/Containment.ts +37 -0
- package/src/internal/Pipeline.ts +85 -0
- package/src/internal/makeCapability.ts +26 -0
- package/src/test/FileSystemBatchContract.ts +59 -0
- package/src/test/HostContract.ts +785 -0
- package/src/test/TestGrantStore.ts +73 -0
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var JournalGrantStore_exports = {};
|
|
30
|
+
__export(JournalGrantStore_exports, {
|
|
31
|
+
layer: () => layer,
|
|
32
|
+
make: () => make
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(JournalGrantStore_exports);
|
|
35
|
+
var Capability = __toESM(require("@smthrs/capability/Capability"), 1);
|
|
36
|
+
var import_Permission = require("@smthrs/capability/Permission");
|
|
37
|
+
var JournalModule = __toESM(require("@smthrs/journal/Journal"), 1);
|
|
38
|
+
var JournalEvent = __toESM(require("@smthrs/journal/JournalEvent"), 1);
|
|
39
|
+
var Effect = __toESM(require("effect/Effect"), 1);
|
|
40
|
+
var Layer = __toESM(require("effect/Layer"), 1);
|
|
41
|
+
var Schema = __toESM(require("effect/Schema"), 1);
|
|
42
|
+
var Semaphore = __toESM(require("effect/Semaphore"), 1);
|
|
43
|
+
var import_GrantEvent = require("./GrantEvent.js");
|
|
44
|
+
var GrantStore = __toESM(require("./GrantStore.js"), 1);
|
|
45
|
+
var import_Workspace = require("./Workspace.js");
|
|
46
|
+
const journalFailed = (message, cause) => new import_Permission.GrantStoreError({
|
|
47
|
+
code: "journal_failed",
|
|
48
|
+
message,
|
|
49
|
+
cause
|
|
50
|
+
});
|
|
51
|
+
const knownEventTypes = /* @__PURE__ */ new Set([
|
|
52
|
+
"flows.kernel.grant.once.v1",
|
|
53
|
+
"flows.kernel.grant.run.v1",
|
|
54
|
+
"flows.kernel.grant.run.v2",
|
|
55
|
+
"flows.kernel.grant.remembered.v1",
|
|
56
|
+
"flows.kernel.grant.denied.v1",
|
|
57
|
+
"flows.kernel.grant.envelope.v1"
|
|
58
|
+
]);
|
|
59
|
+
const invalidReplay = (message) => new import_Permission.GrantStoreError({ code: "invalid_resolution", message });
|
|
60
|
+
const appendReplayedRule = (rules, seen, pattern) => {
|
|
61
|
+
const rule = new import_Permission.Rule({ effect: "allow", pattern });
|
|
62
|
+
const key = Capability.format(rule.pattern);
|
|
63
|
+
if (seen.has(key)) return;
|
|
64
|
+
seen.add(key);
|
|
65
|
+
rules.push(rule);
|
|
66
|
+
};
|
|
67
|
+
const validId = (value) => {
|
|
68
|
+
if (typeof value !== "string" || value.length === 0 || value.length > GrantStore.maximumIdentityLength) return false;
|
|
69
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
70
|
+
const unit = value.charCodeAt(index);
|
|
71
|
+
if (unit === 0) return false;
|
|
72
|
+
if (unit >= 55296 && unit <= 56319) {
|
|
73
|
+
const next = value.charCodeAt(index + 1);
|
|
74
|
+
if (!(next >= 56320 && next <= 57343)) return false;
|
|
75
|
+
index += 1;
|
|
76
|
+
} else if (unit >= 56320 && unit <= 57343) {
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return true;
|
|
81
|
+
};
|
|
82
|
+
const encodeGrantEvent = Schema.encodeSync(import_GrantEvent.GrantEventSchema);
|
|
83
|
+
const decodeTrustedEntry = (entry, sourceId, runId) => {
|
|
84
|
+
if (entry.sourceId !== sourceId || !knownEventTypes.has(entry.eventType)) {
|
|
85
|
+
return Effect.succeed(void 0);
|
|
86
|
+
}
|
|
87
|
+
if (entry.eventType === "flows.kernel.grant.run.v1") {
|
|
88
|
+
return Effect.fail(
|
|
89
|
+
invalidReplay(`legacy run grant has no captured ceiling in run ${runId} at journal sequence ${entry.seq}`)
|
|
90
|
+
);
|
|
91
|
+
}
|
|
92
|
+
const event = (0, import_GrantEvent.decode)(entry.payload);
|
|
93
|
+
if (event._tag === "Failure") {
|
|
94
|
+
return Effect.fail(invalidReplay(`invalid grant payload in run ${runId} at journal sequence ${entry.seq}`));
|
|
95
|
+
}
|
|
96
|
+
if (event.success.eventType !== entry.eventType) {
|
|
97
|
+
return Effect.fail(
|
|
98
|
+
invalidReplay(`grant envelope/payload type mismatch in run ${runId} at journal sequence ${entry.seq}`)
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return Effect.succeed(event.success);
|
|
102
|
+
};
|
|
103
|
+
const constructionLocks = /* @__PURE__ */ new WeakMap();
|
|
104
|
+
const constructionLock = (journal) => {
|
|
105
|
+
const existing = constructionLocks.get(journal);
|
|
106
|
+
if (existing !== void 0) {
|
|
107
|
+
return existing;
|
|
108
|
+
}
|
|
109
|
+
const created = Semaphore.makeUnsafe(1);
|
|
110
|
+
constructionLocks.set(journal, created);
|
|
111
|
+
return created;
|
|
112
|
+
};
|
|
113
|
+
const replayRememberedRules = (policyRunId, sourceId, workspaceRoot) => Effect.gen(function* () {
|
|
114
|
+
const journal = yield* JournalModule.Journal;
|
|
115
|
+
const rules = [];
|
|
116
|
+
const seenRules = /* @__PURE__ */ new Set();
|
|
117
|
+
const envelopeSignatures = /* @__PURE__ */ new Set();
|
|
118
|
+
let after;
|
|
119
|
+
do {
|
|
120
|
+
const page = yield* journal.entries({
|
|
121
|
+
runId: policyRunId,
|
|
122
|
+
...after === void 0 ? {} : { after },
|
|
123
|
+
limit: 256
|
|
124
|
+
});
|
|
125
|
+
const last = page.entries.at(-1);
|
|
126
|
+
if (last !== void 0 && after !== void 0 && last.seq <= after) {
|
|
127
|
+
return yield* Effect.fail(
|
|
128
|
+
invalidReplay(`non-advancing journal page in run ${policyRunId} at sequence ${last.seq}`)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
for (const entry of page.entries) {
|
|
132
|
+
const event = yield* decodeTrustedEntry(entry, sourceId, policyRunId);
|
|
133
|
+
if (event === void 0) {
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (event.eventType === "flows.kernel.grant.remembered.v1") {
|
|
137
|
+
if (!GrantStore.isValidGrantPattern(event.pattern, event.capability, event.tier, workspaceRoot)) {
|
|
138
|
+
return yield* Effect.fail(
|
|
139
|
+
invalidReplay(`unsafe remembered grant event in run ${policyRunId} at sequence ${entry.seq}`)
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
appendReplayedRule(rules, seenRules, event.pattern);
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
if (event.eventType === "flows.kernel.grant.envelope.v1" && event.scope === "remembered") {
|
|
146
|
+
if (event.patterns.some((pattern) => !GrantStore.isValidEnvelopePattern(pattern, workspaceRoot))) {
|
|
147
|
+
return yield* Effect.fail(
|
|
148
|
+
invalidReplay(`unsafe remembered envelope event in run ${policyRunId} at sequence ${entry.seq}`)
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
for (const pattern of event.patterns) appendReplayedRule(rules, seenRules, pattern);
|
|
152
|
+
envelopeSignatures.add(GrantStore.envelopeSignature(event.planDigest, event.scope, event.patterns));
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
return yield* Effect.fail(
|
|
156
|
+
invalidReplay(`run-scoped event found in policy journal run ${policyRunId} at sequence ${entry.seq}`)
|
|
157
|
+
);
|
|
158
|
+
}
|
|
159
|
+
after = last?.seq;
|
|
160
|
+
if (!page.hasMore) {
|
|
161
|
+
return { rules, envelopeSignatures };
|
|
162
|
+
}
|
|
163
|
+
} while (after !== void 0);
|
|
164
|
+
return { rules, envelopeSignatures };
|
|
165
|
+
});
|
|
166
|
+
const replayRunRules = (runId, sourceId, planDigest, workspaceRoot) => Effect.gen(function* () {
|
|
167
|
+
const journal = yield* JournalModule.Journal;
|
|
168
|
+
const rules = [];
|
|
169
|
+
const seenRules = /* @__PURE__ */ new Set();
|
|
170
|
+
const envelopeSignatures = /* @__PURE__ */ new Set();
|
|
171
|
+
let after;
|
|
172
|
+
do {
|
|
173
|
+
const page = yield* journal.entries({
|
|
174
|
+
runId,
|
|
175
|
+
...after === void 0 ? {} : { after },
|
|
176
|
+
limit: 256
|
|
177
|
+
});
|
|
178
|
+
const last = page.entries.at(-1);
|
|
179
|
+
if (last !== void 0 && after !== void 0 && last.seq <= after) {
|
|
180
|
+
return yield* Effect.fail(invalidReplay(`non-advancing journal page in run ${runId} at sequence ${last.seq}`));
|
|
181
|
+
}
|
|
182
|
+
for (const entry of page.entries) {
|
|
183
|
+
const event = yield* decodeTrustedEntry(entry, sourceId, runId);
|
|
184
|
+
if (event === void 0) {
|
|
185
|
+
continue;
|
|
186
|
+
}
|
|
187
|
+
if (event.runId !== runId) {
|
|
188
|
+
return yield* Effect.fail(
|
|
189
|
+
invalidReplay(`grant payload run mismatch in run ${runId} at journal sequence ${entry.seq}`)
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
if (event.eventType === "flows.kernel.grant.once.v1" || event.eventType === "flows.kernel.grant.denied.v1") {
|
|
193
|
+
continue;
|
|
194
|
+
}
|
|
195
|
+
if (event.eventType === "flows.kernel.grant.run.v2") {
|
|
196
|
+
if (event.planDigest !== planDigest) {
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
if (!GrantStore.isValidGrantPattern(event.pattern, event.capability, event.tier, workspaceRoot)) {
|
|
200
|
+
return yield* Effect.fail(invalidReplay(`unsafe run grant event in run ${runId} at sequence ${entry.seq}`));
|
|
201
|
+
}
|
|
202
|
+
const key = `run:${JSON.stringify([event.pattern, event.ceiling])}`;
|
|
203
|
+
if (!seenRules.has(key)) {
|
|
204
|
+
seenRules.add(key);
|
|
205
|
+
rules.push({ rule: new import_Permission.Rule({ effect: "allow", pattern: event.pattern }), ceiling: event.ceiling });
|
|
206
|
+
}
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
209
|
+
if (event.eventType === "flows.kernel.grant.envelope.v1" && event.scope === "run") {
|
|
210
|
+
if (event.planDigest !== planDigest) {
|
|
211
|
+
continue;
|
|
212
|
+
}
|
|
213
|
+
if (event.patterns.some((pattern) => !GrantStore.isValidEnvelopePattern(pattern, workspaceRoot))) {
|
|
214
|
+
return yield* Effect.fail(
|
|
215
|
+
invalidReplay(`unsafe run envelope event in run ${runId} at sequence ${entry.seq}`)
|
|
216
|
+
);
|
|
217
|
+
}
|
|
218
|
+
for (const pattern of event.patterns) appendReplayedRule(rules, seenRules, pattern);
|
|
219
|
+
envelopeSignatures.add(GrantStore.envelopeSignature(event.planDigest, event.scope, event.patterns));
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
return yield* Effect.fail(
|
|
223
|
+
invalidReplay(`remembered event found in run journal ${runId} at sequence ${entry.seq}`)
|
|
224
|
+
);
|
|
225
|
+
}
|
|
226
|
+
after = last?.seq;
|
|
227
|
+
if (!page.hasMore) {
|
|
228
|
+
return { rules, envelopeSignatures };
|
|
229
|
+
}
|
|
230
|
+
} while (after !== void 0);
|
|
231
|
+
return { rules, envelopeSignatures };
|
|
232
|
+
});
|
|
233
|
+
const make = (options) => Effect.gen(function* () {
|
|
234
|
+
const runId = options.runId;
|
|
235
|
+
const policyRunId = options.policyRunId;
|
|
236
|
+
const sourceId = options.sourceId;
|
|
237
|
+
const planDigest = options.planDigest;
|
|
238
|
+
if (!validId(runId)) return yield* Effect.fail(invalidReplay("runId must be non-empty, bounded, well-formed text"));
|
|
239
|
+
if (!validId(policyRunId)) {
|
|
240
|
+
return yield* Effect.fail(invalidReplay("policyRunId must be non-empty, bounded, well-formed text"));
|
|
241
|
+
}
|
|
242
|
+
if (!validId(sourceId)) {
|
|
243
|
+
return yield* Effect.fail(invalidReplay("sourceId must be non-empty, bounded, well-formed text"));
|
|
244
|
+
}
|
|
245
|
+
if (!validId(planDigest)) {
|
|
246
|
+
return yield* Effect.fail(invalidReplay("planDigest must be non-empty, bounded, well-formed text"));
|
|
247
|
+
}
|
|
248
|
+
if (runId === policyRunId) {
|
|
249
|
+
return yield* Effect.fail(invalidReplay("runId and policyRunId must be distinct"));
|
|
250
|
+
}
|
|
251
|
+
const journal = yield* JournalModule.Journal;
|
|
252
|
+
const workspace = yield* import_Workspace.Workspace;
|
|
253
|
+
const replayPolicy = replayRememberedRules(
|
|
254
|
+
policyRunId,
|
|
255
|
+
sourceId,
|
|
256
|
+
workspace.root
|
|
257
|
+
).pipe(
|
|
258
|
+
Effect.mapError(
|
|
259
|
+
(cause) => cause instanceof import_Permission.GrantStoreError ? cause : journalFailed("could not replay remembered grants", cause)
|
|
260
|
+
)
|
|
261
|
+
);
|
|
262
|
+
const replayRun = replayRunRules(
|
|
263
|
+
runId,
|
|
264
|
+
sourceId,
|
|
265
|
+
planDigest,
|
|
266
|
+
workspace.root
|
|
267
|
+
).pipe(
|
|
268
|
+
Effect.mapError(
|
|
269
|
+
(cause) => cause instanceof import_Permission.GrantStoreError ? cause : journalFailed("could not replay run grants", cause)
|
|
270
|
+
)
|
|
271
|
+
);
|
|
272
|
+
let replayedPolicy = yield* replayPolicy;
|
|
273
|
+
let replayedRun = yield* replayRun;
|
|
274
|
+
const persist = (event) => {
|
|
275
|
+
const payload = encodeGrantEvent(event);
|
|
276
|
+
return Effect.gen(function* () {
|
|
277
|
+
yield* journal.emitDurableUnfenced(
|
|
278
|
+
new JournalEvent.Input({
|
|
279
|
+
runId: event.eventType === "flows.kernel.grant.remembered.v1" || event.eventType === "flows.kernel.grant.envelope.v1" && event.scope === "remembered" ? policyRunId : runId,
|
|
280
|
+
sourceId,
|
|
281
|
+
eventType: event.eventType,
|
|
282
|
+
payload
|
|
283
|
+
})
|
|
284
|
+
);
|
|
285
|
+
}).pipe(
|
|
286
|
+
Effect.mapError((cause) => journalFailed("could not persist grant event", cause)),
|
|
287
|
+
Effect.asVoid
|
|
288
|
+
);
|
|
289
|
+
};
|
|
290
|
+
const envelope = options.envelope;
|
|
291
|
+
const build = () => {
|
|
292
|
+
const configuredCount = options.rules?.reduce((count, rules) => count + rules.length, 0) ?? 0;
|
|
293
|
+
const rememberedCount = replayedPolicy.rules.length;
|
|
294
|
+
const runCount = replayedRun.rules.length;
|
|
295
|
+
const total = configuredCount + rememberedCount + runCount;
|
|
296
|
+
if (total > GrantStore.maximumRules) {
|
|
297
|
+
return Effect.fail(
|
|
298
|
+
invalidReplay(
|
|
299
|
+
`policy run ${policyRunId} replayed ${rememberedCount} remembered rules; configured rules (${configuredCount}) and replayed run rules (${runCount}) bring the total to ${total}, which exceeds the ${GrantStore.maximumRules}-rule ceiling; remove configured rules or start a new policyRunId and grant again`
|
|
300
|
+
)
|
|
301
|
+
);
|
|
302
|
+
}
|
|
303
|
+
const policySignatureCount = replayedPolicy.envelopeSignatures.size;
|
|
304
|
+
const runSignatureCount = replayedRun.envelopeSignatures.size;
|
|
305
|
+
const signatureTotal = policySignatureCount + runSignatureCount;
|
|
306
|
+
if (signatureTotal > GrantStore.maximumRules) {
|
|
307
|
+
return Effect.fail(
|
|
308
|
+
invalidReplay(
|
|
309
|
+
`policy run ${policyRunId} replayed ${policySignatureCount} remembered envelope signatures; replayed run envelope signatures (${runSignatureCount}) bring the total to ${signatureTotal}, which exceeds the ${GrantStore.maximumRules}-envelope-signature ceiling; start a new policyRunId and grant again`
|
|
310
|
+
)
|
|
311
|
+
);
|
|
312
|
+
}
|
|
313
|
+
return GrantStore.make({
|
|
314
|
+
runId,
|
|
315
|
+
planDigest,
|
|
316
|
+
...options.attended === void 0 ? {} : { attended: options.attended },
|
|
317
|
+
rules: options.rules === void 0 || options.rules.length === 0 ? [[], replayedPolicy.rules] : [...options.rules, replayedPolicy.rules],
|
|
318
|
+
runRules: replayedRun.rules,
|
|
319
|
+
envelopeSignatures: [
|
|
320
|
+
...replayedPolicy.envelopeSignatures,
|
|
321
|
+
...replayedRun.envelopeSignatures
|
|
322
|
+
],
|
|
323
|
+
...envelope === void 0 ? {} : {
|
|
324
|
+
envelope: {
|
|
325
|
+
planDigest,
|
|
326
|
+
patterns: envelope.patterns,
|
|
327
|
+
...envelope.scope === void 0 ? {} : { scope: envelope.scope }
|
|
328
|
+
}
|
|
329
|
+
},
|
|
330
|
+
persist
|
|
331
|
+
});
|
|
332
|
+
};
|
|
333
|
+
if (envelope === void 0 || envelope.patterns.length === 0) {
|
|
334
|
+
return yield* build();
|
|
335
|
+
}
|
|
336
|
+
const scope = envelope.scope ?? "run";
|
|
337
|
+
const signature = GrantStore.envelopeSignature(planDigest, scope, envelope.patterns);
|
|
338
|
+
const replayedSignatures = scope === "remembered" ? replayedPolicy.envelopeSignatures : replayedRun.envelopeSignatures;
|
|
339
|
+
if (replayedSignatures.has(signature)) {
|
|
340
|
+
return yield* build();
|
|
341
|
+
}
|
|
342
|
+
return yield* constructionLock(journal).withPermit(
|
|
343
|
+
Effect.gen(function* () {
|
|
344
|
+
if (scope === "remembered") {
|
|
345
|
+
replayedPolicy = yield* replayPolicy;
|
|
346
|
+
} else {
|
|
347
|
+
replayedRun = yield* replayRun;
|
|
348
|
+
}
|
|
349
|
+
return yield* build();
|
|
350
|
+
})
|
|
351
|
+
);
|
|
352
|
+
});
|
|
353
|
+
const layer = (options) => Layer.effect(GrantStore.GrantStore)(make(options));
|
|
354
|
+
//# sourceMappingURL=JournalGrantStore.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/JournalGrantStore.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Journal-backed persistence and replay for capability decisions.\n *\n * Governing design:\n * `docs/specs/Concepts/Permission Kernel.md` and\n * `docs/specs/Concepts/Journal Queue.md`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport * as Capability from \"@smthrs/capability/Capability\"\nimport { GrantStoreError, Rule } from \"@smthrs/capability/Permission\"\nimport * as JournalModule from \"@smthrs/journal/Journal\"\nimport * as JournalEvent from \"@smthrs/journal/JournalEvent\"\nimport * as Effect from \"effect/Effect\"\nimport * as Layer from \"effect/Layer\"\nimport * as Schema from \"effect/Schema\"\nimport * as Semaphore from \"effect/Semaphore\"\nimport { decode, type GrantEvent, GrantEventSchema } from \"./GrantEvent.ts\"\nimport * as GrantStore from \"./GrantStore.ts\"\nimport { Workspace } from \"./Workspace.ts\"\n\n/**\n * Configuration for a journal-backed grant store.\n *\n * `policyRunId` is a deliberately dedicated run containing remembered-policy\n * events. The journal has no global grant projection, so callers that want\n * remembered grants to span operational runs must keep this id stable.\n * `planDigest` binds run grants and envelopes to the exact active plan.\n * `sourceId` is also checked during replay; events from other producers cannot\n * activate kernel authority.\n *\n * The journal is authoritative permission storage: SqlJournal must use the\n * `reject` overflow policy. Drop-capable overflow policies are unsupported,\n * because a dropped grant decision cannot safely be treated as persisted.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport interface JournalGrantStoreOptions {\n readonly runId: string\n readonly policyRunId: string\n readonly sourceId: string\n readonly planDigest: string\n readonly attended?: boolean\n readonly rules?: ReadonlyArray<ReadonlyArray<Rule>>\n readonly envelope?: {\n readonly patterns: ReadonlyArray<Capability.CapabilityPattern>\n readonly scope?: \"run\" | \"remembered\" | undefined\n }\n}\n\nconst journalFailed = (message: string, cause: unknown): GrantStoreError =>\n new GrantStoreError({\n code: \"journal_failed\",\n message,\n cause\n })\n\nconst knownEventTypes: ReadonlySet<string> = new Set([\n \"flows.kernel.grant.once.v1\",\n \"flows.kernel.grant.run.v1\",\n \"flows.kernel.grant.run.v2\",\n \"flows.kernel.grant.remembered.v1\",\n \"flows.kernel.grant.denied.v1\",\n \"flows.kernel.grant.envelope.v1\"\n])\n\nconst invalidReplay = (message: string): GrantStoreError => new GrantStoreError({ code: \"invalid_resolution\", message })\n\nconst appendReplayedRule = (\n rules: Array<NonNullable<GrantStore.MakeOptions[\"runRules\"]>[number]>,\n seen: Set<string>,\n pattern: Capability.CapabilityPattern\n): void => {\n const rule = new Rule({ effect: \"allow\", pattern })\n const key = Capability.format(rule.pattern)\n if (seen.has(key)) return\n seen.add(key)\n rules.push(rule)\n}\n\nconst validId = (value: unknown): value is string => {\n if (typeof value !== \"string\" || value.length === 0 || value.length > GrantStore.maximumIdentityLength) return false\n for (let index = 0; index < value.length; index += 1) {\n const unit = value.charCodeAt(index)\n if (unit === 0) return false\n if (unit >= 0xd800 && unit <= 0xdbff) {\n const next = value.charCodeAt(index + 1)\n if (!(next >= 0xdc00 && next <= 0xdfff)) return false\n index += 1\n } else if (unit >= 0xdc00 && unit <= 0xdfff) {\n return false\n }\n }\n return true\n}\n\nconst encodeGrantEvent = Schema.encodeSync(GrantEventSchema)\n\n// Replay reads two runs (`policyRunId` and `runId`) and journal sequences are\n// per run, so every refusal names the run it was replaying: the operator then\n// knows which journal run to inspect. Replay always reads a run from its start\n// and never consults a checkpoint, so compacting a run it replays makes every\n// later construction fail `compacted`.\nconst decodeTrustedEntry = (\n entry: JournalEvent.Entry,\n sourceId: string,\n runId: string\n): Effect.Effect<GrantEvent | undefined, GrantStoreError> => {\n if (entry.sourceId !== sourceId || !knownEventTypes.has(entry.eventType)) {\n return Effect.succeed(undefined)\n }\n if (entry.eventType === \"flows.kernel.grant.run.v1\") {\n return Effect.fail(\n invalidReplay(`legacy run grant has no captured ceiling in run ${runId} at journal sequence ${entry.seq}`)\n )\n }\n const event = decode(entry.payload)\n if (event._tag === \"Failure\") {\n return Effect.fail(invalidReplay(`invalid grant payload in run ${runId} at journal sequence ${entry.seq}`))\n }\n if (event.success.eventType !== entry.eventType) {\n return Effect.fail(\n invalidReplay(`grant envelope/payload type mismatch in run ${runId} at journal sequence ${entry.seq}`)\n )\n }\n return Effect.succeed(event.success)\n}\n\n// One construction-envelope critical section per Journal service instance.\n// Two concurrent constructors sharing one service object can both replay the\n// envelope's absence before either persists it; the lock serializes the\n// re-check-then-append so exactly one construction envelope lands.\n//\n// The guarantee stops at the service object. The lock is a WeakMap keyed by\n// the in-memory `Journal.Service`, and the persisted Input carries no\n// `sourceSeq` or `dedupe` key, so two service objects over one backing journal\n// (two processes, or two connections in one process) each hold their own\n// permit and can both append the envelope. Replay tolerates the duplicate:\n// the signature set collapses it and the rules are identical.\nconst constructionLocks = new WeakMap<JournalModule.Service, Semaphore.Semaphore>()\n\nconst constructionLock = (journal: JournalModule.Service): Semaphore.Semaphore => {\n const existing = constructionLocks.get(journal)\n if (existing !== undefined) {\n return existing\n }\n const created = Semaphore.makeUnsafe(1)\n constructionLocks.set(journal, created)\n return created\n}\n\nconst replayRememberedRules = (\n policyRunId: string,\n sourceId: string,\n workspaceRoot: string\n) =>\n Effect.gen(function*() {\n const journal = yield* JournalModule.Journal\n const rules: Array<Rule> = []\n const seenRules = new Set<string>()\n const envelopeSignatures = new Set<string>()\n let after: JournalEvent.Seq | undefined\n\n do {\n const page = yield* journal.entries({\n runId: policyRunId as JournalEvent.RunId,\n ...(after === undefined ? {} : { after }),\n limit: 256\n })\n const last = page.entries.at(-1)\n if (last !== undefined && after !== undefined && last.seq <= after) {\n // A page that does not advance past the cursor it was asked for is\n // corrupt journal output. Following it would replay the same events\n // forever; accepting it would double-apply them. Refuse construction.\n return yield* Effect.fail(\n invalidReplay(`non-advancing journal page in run ${policyRunId} at sequence ${last.seq}`)\n )\n }\n for (const entry of page.entries) {\n const event = yield* decodeTrustedEntry(entry, sourceId, policyRunId)\n if (event === undefined) {\n continue\n }\n if (event.eventType === \"flows.kernel.grant.remembered.v1\") {\n if (!GrantStore.isValidGrantPattern(event.pattern, event.capability, event.tier, workspaceRoot)) {\n return yield* Effect.fail(\n invalidReplay(`unsafe remembered grant event in run ${policyRunId} at sequence ${entry.seq}`)\n )\n }\n appendReplayedRule(rules, seenRules, event.pattern)\n continue\n }\n if (event.eventType === \"flows.kernel.grant.envelope.v1\" && event.scope === \"remembered\") {\n if (event.patterns.some((pattern) => !GrantStore.isValidEnvelopePattern(pattern, workspaceRoot))) {\n return yield* Effect.fail(\n invalidReplay(`unsafe remembered envelope event in run ${policyRunId} at sequence ${entry.seq}`)\n )\n }\n for (const pattern of event.patterns) appendReplayedRule(rules, seenRules, pattern)\n envelopeSignatures.add(GrantStore.envelopeSignature(event.planDigest, event.scope, event.patterns))\n continue\n }\n return yield* Effect.fail(\n invalidReplay(`run-scoped event found in policy journal run ${policyRunId} at sequence ${entry.seq}`)\n )\n }\n after = last?.seq\n if (!page.hasMore) {\n return { rules, envelopeSignatures }\n }\n } while (after !== undefined)\n\n return { rules, envelopeSignatures }\n })\n\nconst replayRunRules = (\n runId: string,\n sourceId: string,\n planDigest: string,\n workspaceRoot: string\n) =>\n Effect.gen(function*() {\n const journal = yield* JournalModule.Journal\n const rules: Array<NonNullable<GrantStore.MakeOptions[\"runRules\"]>[number]> = []\n const seenRules = new Set<string>()\n const envelopeSignatures = new Set<string>()\n let after: JournalEvent.Seq | undefined\n\n do {\n const page = yield* journal.entries({\n runId: runId as JournalEvent.RunId,\n ...(after === undefined ? {} : { after }),\n limit: 256\n })\n const last = page.entries.at(-1)\n if (last !== undefined && after !== undefined && last.seq <= after) {\n // See the identical guard in `replayRememberedRules`.\n return yield* Effect.fail(invalidReplay(`non-advancing journal page in run ${runId} at sequence ${last.seq}`))\n }\n for (const entry of page.entries) {\n const event = yield* decodeTrustedEntry(entry, sourceId, runId)\n if (event === undefined) {\n continue\n }\n if (event.runId !== runId) {\n return yield* Effect.fail(\n invalidReplay(`grant payload run mismatch in run ${runId} at journal sequence ${entry.seq}`)\n )\n }\n if (event.eventType === \"flows.kernel.grant.once.v1\" || event.eventType === \"flows.kernel.grant.denied.v1\") {\n continue\n }\n if (event.eventType === \"flows.kernel.grant.run.v2\") {\n if (event.planDigest !== planDigest) {\n continue\n }\n if (!GrantStore.isValidGrantPattern(event.pattern, event.capability, event.tier, workspaceRoot)) {\n return yield* Effect.fail(invalidReplay(`unsafe run grant event in run ${runId} at sequence ${entry.seq}`))\n }\n const key = `run:${JSON.stringify([event.pattern, event.ceiling])}`\n if (!seenRules.has(key)) {\n seenRules.add(key)\n rules.push({ rule: new Rule({ effect: \"allow\", pattern: event.pattern }), ceiling: event.ceiling })\n }\n continue\n }\n if (event.eventType === \"flows.kernel.grant.envelope.v1\" && event.scope === \"run\") {\n if (event.planDigest !== planDigest) {\n continue\n }\n if (event.patterns.some((pattern) => !GrantStore.isValidEnvelopePattern(pattern, workspaceRoot))) {\n return yield* Effect.fail(\n invalidReplay(`unsafe run envelope event in run ${runId} at sequence ${entry.seq}`)\n )\n }\n for (const pattern of event.patterns) appendReplayedRule(rules, seenRules, pattern)\n envelopeSignatures.add(GrantStore.envelopeSignature(event.planDigest, event.scope, event.patterns))\n continue\n }\n return yield* Effect.fail(\n invalidReplay(`remembered event found in run journal ${runId} at sequence ${entry.seq}`)\n )\n }\n after = last?.seq\n if (!page.hasMore) {\n return { rules, envelopeSignatures }\n }\n } while (after !== undefined)\n\n return { rules, envelopeSignatures }\n })\n\n/**\n * Makes a grant store that replays remembered policy from, and writes decisions\n * to, the supplied journal.\n *\n * `emitDurable` commits before `GrantStore` activates a remembered or\n * run-scoped rule (or resolves a denial). Any journal failure is mapped to\n * `journal_failed`, so permission decisions fail closed.\n *\n * @category constructors\n * @since 1.0.0-rc.0\n */\nexport const make = (options: JournalGrantStoreOptions) =>\n Effect.gen(function*() {\n const runId = options.runId\n const policyRunId = options.policyRunId\n const sourceId = options.sourceId\n const planDigest = options.planDigest\n if (!validId(runId)) return yield* Effect.fail(invalidReplay(\"runId must be non-empty, bounded, well-formed text\"))\n if (!validId(policyRunId)) {\n return yield* Effect.fail(invalidReplay(\"policyRunId must be non-empty, bounded, well-formed text\"))\n }\n if (!validId(sourceId)) {\n return yield* Effect.fail(invalidReplay(\"sourceId must be non-empty, bounded, well-formed text\"))\n }\n if (!validId(planDigest)) {\n return yield* Effect.fail(invalidReplay(\"planDigest must be non-empty, bounded, well-formed text\"))\n }\n if (runId === policyRunId) {\n return yield* Effect.fail(invalidReplay(\"runId and policyRunId must be distinct\"))\n }\n const journal = yield* JournalModule.Journal\n const workspace = yield* Workspace\n const replayPolicy = replayRememberedRules(\n policyRunId,\n sourceId,\n workspace.root\n ).pipe(\n Effect.mapError((cause) =>\n cause instanceof GrantStoreError ? cause : journalFailed(\"could not replay remembered grants\", cause)\n )\n )\n const replayRun = replayRunRules(\n runId,\n sourceId,\n planDigest,\n workspace.root\n ).pipe(\n Effect.mapError((cause) =>\n cause instanceof GrantStoreError ? cause : journalFailed(\"could not replay run grants\", cause)\n )\n )\n let replayedPolicy = yield* replayPolicy\n let replayedRun = yield* replayRun\n const persist = (event: GrantEvent): Effect.Effect<void, GrantStoreError> => {\n const payload = encodeGrantEvent(event)\n return Effect.gen(function*() {\n // Unfenced: the grant store is the kernel's own ledger, not a run's\n // lifecycle \u2014 it owns no run, and grant admissions are\n // first-writer-wins records replayed by every later process.\n yield* journal.emitDurableUnfenced(\n new JournalEvent.Input({\n runId: (\n event.eventType === \"flows.kernel.grant.remembered.v1\"\n || (event.eventType === \"flows.kernel.grant.envelope.v1\" && event.scope === \"remembered\")\n ? policyRunId\n : runId\n ) as JournalEvent.RunId,\n sourceId: sourceId as JournalEvent.SourceId,\n eventType: event.eventType,\n payload\n })\n )\n }).pipe(\n Effect.mapError((cause) => journalFailed(\"could not persist grant event\", cause)),\n Effect.asVoid\n )\n }\n const envelope = options.envelope\n const build = () => {\n const configuredCount = options.rules?.reduce((count, rules) => count + rules.length, 0) ?? 0\n const rememberedCount = replayedPolicy.rules.length\n const runCount = replayedRun.rules.length\n const total = configuredCount + rememberedCount + runCount\n if (total > GrantStore.maximumRules) {\n return Effect.fail(\n invalidReplay(\n `policy run ${policyRunId} replayed ${rememberedCount} remembered rules; configured rules (${configuredCount}) and replayed run rules (${runCount}) bring the total to ${total}, which exceeds the ${GrantStore.maximumRules}-rule ceiling; remove configured rules or start a new policyRunId and grant again`\n )\n )\n }\n // Envelope signatures accumulate in the policy journal exactly the way\n // remembered rules do, and `GrantStore.make` refuses more than\n // `maximumRules` of them with a message that names neither the journal\n // nor the counts. Diagnose it here instead, so an operator reading the\n // failure knows which policy run filled rather than which field overflowed.\n const policySignatureCount = replayedPolicy.envelopeSignatures.size\n const runSignatureCount = replayedRun.envelopeSignatures.size\n const signatureTotal = policySignatureCount + runSignatureCount\n if (signatureTotal > GrantStore.maximumRules) {\n return Effect.fail(\n invalidReplay(\n `policy run ${policyRunId} replayed ${policySignatureCount} remembered envelope signatures; replayed run envelope signatures (${runSignatureCount}) bring the total to ${signatureTotal}, which exceeds the ${GrantStore.maximumRules}-envelope-signature ceiling; start a new policyRunId and grant again`\n )\n )\n }\n // GrantStore's shared envelope admission adds only patterns not already\n // replayed for a seeded envelope, and checks the combined rule and\n // signature counts before any construction event is persisted.\n return GrantStore.make({\n runId,\n planDigest,\n ...(options.attended === undefined ? {} : { attended: options.attended }),\n rules: options.rules === undefined || options.rules.length === 0\n ? [[], replayedPolicy.rules]\n : [...options.rules, replayedPolicy.rules],\n runRules: replayedRun.rules,\n envelopeSignatures: [\n ...replayedPolicy.envelopeSignatures,\n ...replayedRun.envelopeSignatures\n ],\n ...(envelope === undefined ? {} : {\n envelope: {\n planDigest,\n patterns: envelope.patterns,\n ...(envelope.scope === undefined ? {} : { scope: envelope.scope })\n }\n }),\n persist\n })\n }\n if (envelope === undefined || envelope.patterns.length === 0) {\n return yield* build()\n }\n const scope = envelope.scope ?? \"run\"\n const signature = GrantStore.envelopeSignature(planDigest, scope, envelope.patterns)\n const replayedSignatures = scope === \"remembered\"\n ? replayedPolicy.envelopeSignatures\n : replayedRun.envelopeSignatures\n if (replayedSignatures.has(signature)) {\n // Already durable: the seeded signature makes the construction envelope\n // activate without persisting again.\n return yield* build()\n }\n // The envelope was absent when this constructor replayed, but a concurrent\n // constructor sharing this Journal service may persist it before we do.\n // Re-replay the target run inside the per-service critical section, so\n // exactly one such constructor appends the envelope and every other one\n // replays it instead.\n return yield* constructionLock(journal).withPermit(\n Effect.gen(function*() {\n if (scope === \"remembered\") {\n replayedPolicy = yield* replayPolicy\n } else {\n replayedRun = yield* replayRun\n }\n return yield* build()\n })\n )\n })\n\n/**\n * Provides a journal-backed `GrantStore`.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer = (options: JournalGrantStoreOptions) => Layer.effect(GrantStore.GrantStore)(make(options))\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Explicit kernel decision for the Effect path service.
|
|
3
|
+
*
|
|
4
|
+
* Governing design:
|
|
5
|
+
* `docs/specs/Concepts/Permission Kernel.md` and
|
|
6
|
+
* `docs/specs/Concepts/Host Adapters.md`.
|
|
7
|
+
*
|
|
8
|
+
* @since 1.0.0-rc.0
|
|
9
|
+
*/
|
|
10
|
+
import { Layer, Path as EffectPath } from "effect";
|
|
11
|
+
import { Workspace } from "./Workspace.ts";
|
|
12
|
+
/**
|
|
13
|
+
* Effect's lexical path-service shape.
|
|
14
|
+
*
|
|
15
|
+
* @category models
|
|
16
|
+
* @since 1.0.0-rc.0
|
|
17
|
+
*/
|
|
18
|
+
export type Path = EffectPath.Path;
|
|
19
|
+
/**
|
|
20
|
+
* The unchanged underlying path-service tag.
|
|
21
|
+
*
|
|
22
|
+
* @category services
|
|
23
|
+
* @since 1.0.0-rc.0
|
|
24
|
+
*/
|
|
25
|
+
export declare const Path: import("effect/Context").Service<EffectPath.Path, EffectPath.Path>;
|
|
26
|
+
/**
|
|
27
|
+
* Re-provides Effect's path service with relative paths resolved against
|
|
28
|
+
* `Workspace.root`, the same root the kernel spawner runs commands in. Path
|
|
29
|
+
* manipulation is pure and lexical, so it requires no capability check. This
|
|
30
|
+
* explicit layer proves that every member of the Host services closed list has
|
|
31
|
+
* a kernel decision.
|
|
32
|
+
*
|
|
33
|
+
* @category layers
|
|
34
|
+
* @since 1.0.0-rc.0
|
|
35
|
+
*/
|
|
36
|
+
export declare const layer: Layer.Layer<Path, never, Path | Workspace>;
|
|
37
|
+
//# sourceMappingURL=Path.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Path.d.ts","sourceRoot":"","sources":["../../src/Path.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAU,KAAK,EAAE,IAAI,IAAI,UAAU,EAAE,MAAM,QAAQ,CAAA;AAE1D,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAE1C;;;;;GAKG;AACH,MAAM,MAAM,IAAI,GAAG,UAAU,CAAC,IAAI,CAAA;AAElC;;;;;GAKG;AACH,eAAO,MAAM,IAAI,oEAAkB,CAAA;AAEnC;;;;;;;;;GASG;AACH,eAAO,MAAM,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,SAAS,CAM5D,CAAA"}
|
package/dist/cjs/Path.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
var Path_exports = {};
|
|
30
|
+
__export(Path_exports, {
|
|
31
|
+
Path: () => Path,
|
|
32
|
+
layer: () => layer
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(Path_exports);
|
|
35
|
+
var import_effect = require("effect");
|
|
36
|
+
var Rooted = __toESM(require("./Rooted.js"), 1);
|
|
37
|
+
var import_Workspace = require("./Workspace.js");
|
|
38
|
+
const Path = import_effect.Path.Path;
|
|
39
|
+
const layer = import_effect.Layer.effect(
|
|
40
|
+
Path,
|
|
41
|
+
import_effect.Effect.gen(function* () {
|
|
42
|
+
const path = yield* Path;
|
|
43
|
+
return Rooted.path(path, path.resolve((yield* import_Workspace.Workspace).root));
|
|
44
|
+
})
|
|
45
|
+
);
|
|
46
|
+
//# sourceMappingURL=Path.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/Path.ts"],
|
|
4
|
+
"sourcesContent": ["/**\n * Explicit kernel decision for the Effect path service.\n *\n * Governing design:\n * `docs/specs/Concepts/Permission Kernel.md` and\n * `docs/specs/Concepts/Host Adapters.md`.\n *\n * @since 1.0.0-rc.0\n */\n\nimport { Effect, Layer, Path as EffectPath } from \"effect\"\nimport * as Rooted from \"./Rooted.ts\"\nimport { Workspace } from \"./Workspace.ts\"\n\n/**\n * Effect's lexical path-service shape.\n *\n * @category models\n * @since 1.0.0-rc.0\n */\nexport type Path = EffectPath.Path\n\n/**\n * The unchanged underlying path-service tag.\n *\n * @category services\n * @since 1.0.0-rc.0\n */\nexport const Path = EffectPath.Path\n\n/**\n * Re-provides Effect's path service with relative paths resolved against\n * `Workspace.root`, the same root the kernel spawner runs commands in. Path\n * manipulation is pure and lexical, so it requires no capability check. This\n * explicit layer proves that every member of the Host services closed list has\n * a kernel decision.\n *\n * @category layers\n * @since 1.0.0-rc.0\n */\nexport const layer: Layer.Layer<Path, never, Path | Workspace> = Layer.effect(\n Path,\n Effect.gen(function*() {\n const path = yield* Path\n return Rooted.path(path, path.resolve((yield* Workspace).root))\n })\n)\n"],
|
|
5
|
+
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAUA,oBAAkD;AAClD,aAAwB;AACxB,uBAA0B;AAgBnB,MAAM,OAAO,cAAAA,KAAW;AAYxB,MAAM,QAAoD,oBAAM;AAAA,EACrE;AAAA,EACA,qBAAO,IAAI,aAAY;AACrB,UAAM,OAAO,OAAO;AACpB,WAAO,OAAO,KAAK,MAAM,KAAK,SAAS,OAAO,4BAAW,IAAI,CAAC;AAAA,EAChE,CAAC;AACH;",
|
|
6
|
+
"names": ["EffectPath"]
|
|
7
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/** Operating-system confinement derived conservatively from effective grants.
|
|
2
|
+
* @since 1.0.0-rc.1
|
|
3
|
+
*/
|
|
4
|
+
import type { GrantStoreError } from "@smthrs/capability/Permission";
|
|
5
|
+
import { Context, Effect, Layer, type Path, type Scope } from "effect";
|
|
6
|
+
import type { PlatformError } from "effect/PlatformError";
|
|
7
|
+
import type * as ChildProcess from "effect/unstable/process/ChildProcess";
|
|
8
|
+
import type { Service as GrantService } from "./GrantStore.ts";
|
|
9
|
+
/** Workspace-relative trees; `.` names the workspace. No path opens its parent.
|
|
10
|
+
* @category models
|
|
11
|
+
* @since 1.0.0-rc.1
|
|
12
|
+
*/
|
|
13
|
+
export interface Profile {
|
|
14
|
+
readonly workspaceRoot: string;
|
|
15
|
+
readonly reads: ReadonlyArray<string>;
|
|
16
|
+
readonly writes: ReadonlyArray<string>;
|
|
17
|
+
readonly readOnly: ReadonlyArray<string>;
|
|
18
|
+
readonly network: "none" | "open";
|
|
19
|
+
}
|
|
20
|
+
/** Host wrapper for one process stage. Failure must occur before spawning.
|
|
21
|
+
* @category models
|
|
22
|
+
* @since 1.0.0-rc.1
|
|
23
|
+
*/
|
|
24
|
+
export interface Service {
|
|
25
|
+
readonly confine: (command: ChildProcess.StandardCommand, profile: Profile) => Effect.Effect<ChildProcess.StandardCommand, PlatformError, Scope.Scope>;
|
|
26
|
+
}
|
|
27
|
+
declare const ProcessConfinement_base: Context.ServiceClass<ProcessConfinement, "@smthrs/kernel/ProcessConfinement", Service>;
|
|
28
|
+
/** Host confinement seam; missing service refuses spawning.
|
|
29
|
+
* @category services
|
|
30
|
+
* @since 1.0.0-rc.1
|
|
31
|
+
*/
|
|
32
|
+
export declare class ProcessConfinement extends ProcessConfinement_base {
|
|
33
|
+
}
|
|
34
|
+
/** Explicit unconfined composition.
|
|
35
|
+
* @category constructors
|
|
36
|
+
* @since 1.0.0-rc.1
|
|
37
|
+
*/
|
|
38
|
+
export declare const makeNoop: Service;
|
|
39
|
+
/** Explicit unconfined layer.
|
|
40
|
+
* @category layers
|
|
41
|
+
* @since 1.0.0-rc.1
|
|
42
|
+
*/
|
|
43
|
+
export declare const layerNoop: Layer.Layer<ProcessConfinement>;
|
|
44
|
+
/** Derives a subset of authority, never a widening. Literal filesystem grants,
|
|
45
|
+
* complex globs and unrepresentable restrictions conservatively open nothing.
|
|
46
|
+
* Writable trees also require read authority and write authority over their
|
|
47
|
+
* exact directory root: native mounts permit reads and directory metadata
|
|
48
|
+
* changes. Only whole-tree grants prove filesystem trees; unrestricted
|
|
49
|
+
* authority for each of get/post/private is required to open network access.
|
|
50
|
+
* @category resolution
|
|
51
|
+
* @since 1.0.0-rc.1
|
|
52
|
+
*/
|
|
53
|
+
export declare const profile: (grants: GrantService, workspaceRoot: string, path: Path.Path) => Effect.Effect<Profile, GrantStoreError>;
|
|
54
|
+
export {};
|
|
55
|
+
//# sourceMappingURL=ProcessConfinement.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ProcessConfinement.d.ts","sourceRoot":"","sources":["../../src/ProcessConfinement.ts"],"names":[],"mappings":"AAAA;;GAEG;AAWH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAA;AACpE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,IAAI,EAAE,KAAK,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAA;AACzD,OAAO,KAAK,KAAK,YAAY,MAAM,sCAAsC,CAAA;AACzE,OAAO,KAAK,EAAsB,OAAO,IAAI,YAAY,EAAE,MAAM,iBAAiB,CAAA;AAElF;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,KAAK,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACrC,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACtC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAC,MAAM,CAAC,CAAA;IACxC,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAAA;CAClC;AACD;;;GAGG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,OAAO,EAAE,CAChB,OAAO,EAAE,YAAY,CAAC,eAAe,EACrC,OAAO,EAAE,OAAO,KACb,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,eAAe,EAAE,aAAa,EAAE,KAAK,CAAC,KAAK,CAAC,CAAA;CAC7E;;AACD;;;GAGG;AACH,qBAAa,kBACX,SAAQ,uBAAmF;CAC3F;AACF;;;GAGG;AACH,eAAO,MAAM,QAAQ,EAAE,OAAkF,CAAA;AACzG;;;GAGG;AACH,eAAO,MAAM,SAAS,EAAE,KAAK,CAAC,KAAK,CAAC,kBAAkB,CAA+C,CAAA;AAqCrG;;;;;;;;GAQG;AACH,eAAO,MAAM,OAAO,GAClB,QAAQ,YAAY,EACpB,eAAe,MAAM,EACrB,MAAM,IAAI,CAAC,IAAI,KACd,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,eAAe,CAiDrC,CAAA"}
|