patchwork-os 1.2.0-beta.2.canary.679 → 1.2.0-beta.2.canary.680
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/claudeOrchestrator.js +6 -2
- package/dist/claudeOrchestrator.js.map +1 -1
- package/dist/privacy/boundaryReceiptLog.d.ts +3 -0
- package/dist/privacy/boundaryReceiptLog.js.map +1 -1
- package/dist/privacy/shadowLog.d.ts +2 -0
- package/dist/privacy/shadowLog.js.map +1 -1
- package/dist/recipeOrchestration.js +8 -1
- package/dist/recipeOrchestration.js.map +1 -1
- package/dist/recipes/yamlRunner.js +23 -0
- package/dist/recipes/yamlRunner.js.map +1 -1
- package/dist/workerGateDecisionLog.d.ts +9 -0
- package/dist/workerGateDecisionLog.js.map +1 -1
- package/dist/workspaceId.d.ts +21 -0
- package/dist/workspaceId.js +97 -0
- package/dist/workspaceId.js.map +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A short, stable identifier for the workspace an evidence record belongs to.
|
|
3
|
+
*
|
|
4
|
+
* ## Why evidence needs this and scoping does not
|
|
5
|
+
*
|
|
6
|
+
* Isolation, policy and blast radius are workspace-scoped already: one bridge,
|
|
7
|
+
* one workspace, one policy. Evidence is different, and deliberately so — it
|
|
8
|
+
* must OUTLIVE the workspace it describes. Deleting a workspace must not delete
|
|
9
|
+
* the record of what was done in it; that is the property an auditor is paying
|
|
10
|
+
* for. So evidence is not scoped by workspace, it is TAGGED with one.
|
|
11
|
+
*
|
|
12
|
+
* Concretely, today: no run row, gate decision, boundary receipt or trust
|
|
13
|
+
* checkpoint carries a workspace, so a decision cannot be attributed to the
|
|
14
|
+
* context it was made in. That is invisible while there is exactly one
|
|
15
|
+
* workspace and is the first thing to break when there are two — at which point
|
|
16
|
+
* two workspaces sharing a recipe name also share one trust ledger.
|
|
17
|
+
*
|
|
18
|
+
* ## Why a hash rather than the path
|
|
19
|
+
*
|
|
20
|
+
* Two reasons, both concrete.
|
|
21
|
+
*
|
|
22
|
+
* **Bytes.** `runs.jsonl` is capped at 1 MB and that cap is already what starves
|
|
23
|
+
* the trust ledger (#1337) — a full path is 40-60 bytes on a ~758-byte row,
|
|
24
|
+
* roughly 7%. Twelve hex characters is not.
|
|
25
|
+
*
|
|
26
|
+
* **Disclosure.** An evidence record is the artefact most likely to leave the
|
|
27
|
+
* machine — exported, attached to a compliance question, pasted into a ticket.
|
|
28
|
+
* A filesystem path names directories, and often a person: `/Users/<name>/...`.
|
|
29
|
+
* The id identifies the workspace to anyone holding the mapping and discloses
|
|
30
|
+
* nothing to anyone who is not.
|
|
31
|
+
*
|
|
32
|
+
* ## What it is not
|
|
33
|
+
*
|
|
34
|
+
* Not a secret, and not an authentication token — it is derived from a path
|
|
35
|
+
* anyone with the machine already knows, so it resists disclosure, not
|
|
36
|
+
* guessing.
|
|
37
|
+
*
|
|
38
|
+
* **Deliberately NOT a cryptographic hash, and please do not "fix" that.** The
|
|
39
|
+
* fingerprint below is FNV-1a: fast, stable, and obviously an identifier rather
|
|
40
|
+
* than a security primitive. An earlier revision used `createHash("sha256")`,
|
|
41
|
+
* which bought nothing — the value is not a secret and brute-forcing it means
|
|
42
|
+
* guessing a path, which a cryptographic digest does not prevent either — and
|
|
43
|
+
* cost something real: CodeQL correctly identifies a filesystem string reaching
|
|
44
|
+
* a password-hashing sink as `js/insufficient-password-hash`, because the sink
|
|
45
|
+
* is the sink regardless of intent. Restructuring beats suppressing; a
|
|
46
|
+
* suppression comment would rot and the next reader would not know why it was
|
|
47
|
+
* there. Not stable across a workspace being MOVED: the path is the
|
|
48
|
+
* identity, so relocating a workspace starts a new id. That is the honest
|
|
49
|
+
* behaviour — a moved directory genuinely may not be the same operating
|
|
50
|
+
* context — and the alternative (a stored id file) invents an identity that can
|
|
51
|
+
* be copied, which is worse for an audit record.
|
|
52
|
+
*/
|
|
53
|
+
import path from "node:path";
|
|
54
|
+
/** Hex characters kept. 48 bits — ample against accidental collision between
|
|
55
|
+
* the handful of workspaces one installation ever sees, and short enough to
|
|
56
|
+
* add to a byte-capped log without argument. */
|
|
57
|
+
const ID_LENGTH = 12;
|
|
58
|
+
/**
|
|
59
|
+
* Derive the id for a workspace path.
|
|
60
|
+
*
|
|
61
|
+
* Normalised first so that `/a/b`, `/a/b/` and `/a/./b` are one workspace
|
|
62
|
+
* rather than three — otherwise a trailing slash in a config file silently
|
|
63
|
+
* splits an audit trail in half.
|
|
64
|
+
*
|
|
65
|
+
* Returns `undefined` for absent or empty input. A caller must be able to tell
|
|
66
|
+
* "no workspace was recorded" from "the workspace is «»", and the record
|
|
67
|
+
* omitting the field is how that is expressed.
|
|
68
|
+
*/
|
|
69
|
+
export function workspaceIdFor(workspacePath) {
|
|
70
|
+
if (!workspacePath || !workspacePath.trim())
|
|
71
|
+
return "";
|
|
72
|
+
const normalised = path.resolve(workspacePath.trim());
|
|
73
|
+
// FNV-1a, 64-bit, over UTF-8 bytes. BigInt rather than `>>>` arithmetic
|
|
74
|
+
// because 32 bits collides at a few tens of thousands of inputs by the
|
|
75
|
+
// birthday bound, and an id that can silently merge two workspaces' evidence
|
|
76
|
+
// is worse than no id at all.
|
|
77
|
+
let hash = 0xcbf29ce484222325n;
|
|
78
|
+
const bytes = Buffer.from(normalised, "utf8");
|
|
79
|
+
for (const byte of bytes) {
|
|
80
|
+
hash ^= BigInt(byte);
|
|
81
|
+
hash = (hash * 0x100000001b3n) & 0xffffffffffffffffn;
|
|
82
|
+
}
|
|
83
|
+
return hash.toString(16).padStart(16, "0").slice(0, ID_LENGTH);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* The id for this process's workspace, or `undefined` when it has none.
|
|
87
|
+
*
|
|
88
|
+
* `undefined` is deliberately not a sentinel string. An evidence row that omits
|
|
89
|
+
* the field says nothing; a row carrying `"unknown"` asserts that somebody
|
|
90
|
+
* looked and could not tell. Those differ, and the second is a claim this
|
|
91
|
+
* module has no grounds to make.
|
|
92
|
+
*/
|
|
93
|
+
export function currentWorkspaceId(workspacePath) {
|
|
94
|
+
const id = workspaceIdFor(workspacePath);
|
|
95
|
+
return id === "" ? undefined : id;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=workspaceId.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspaceId.js","sourceRoot":"","sources":["../src/workspaceId.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B;;iDAEiD;AACjD,MAAM,SAAS,GAAG,EAAE,CAAC;AAErB;;;;;;;;;;GAUG;AACH,MAAM,UAAU,cAAc,CAAC,aAAiC;IAC9D,IAAI,CAAC,aAAa,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;QAAE,OAAO,EAAE,CAAC;IACvD,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,IAAI,EAAE,CAAC,CAAC;IACtD,wEAAwE;IACxE,uEAAuE;IACvE,6EAA6E;IAC7E,8BAA8B;IAC9B,IAAI,IAAI,GAAG,mBAAmB,CAAC;IAC/B,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,MAAM,CAAC,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC;QACrB,IAAI,GAAG,CAAC,IAAI,GAAG,cAAc,CAAC,GAAG,mBAAmB,CAAC;IACvD,CAAC;IACD,OAAO,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,EAAE,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC,CAAC;AACjE,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,kBAAkB,CAChC,aAAiC;IAEjC,MAAM,EAAE,GAAG,cAAc,CAAC,aAAa,CAAC,CAAC;IACzC,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC;AACpC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "patchwork-os",
|
|
3
|
-
"version": "1.2.0-beta.2.canary.
|
|
3
|
+
"version": "1.2.0-beta.2.canary.680",
|
|
4
4
|
"description": "Your personal AI runtime, local-first. Patchwork OS gives any AI model a consistent set of tools, YAML recipes, a delegation policy with approval queue, and a durable trace memory — all on your machine, all under your policy.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|