approval-md 0.3.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (226) hide show
  1. package/README.md +83 -914
  2. package/SPEC.md +98 -13
  3. package/cli.js +66 -7
  4. package/dist/src/adapters/smtp.d.ts +18 -0
  5. package/dist/src/adapters/smtp.js +24 -3
  6. package/dist/src/adapters/smtp.js.map +1 -1
  7. package/dist/src/channels/contract.d.ts +19 -0
  8. package/dist/src/channels/contract.js +105 -1
  9. package/dist/src/channels/contract.js.map +1 -1
  10. package/dist/src/channels/relay-server.d.ts +90 -0
  11. package/dist/src/channels/relay-server.js +295 -0
  12. package/dist/src/channels/relay-server.js.map +1 -0
  13. package/dist/src/channels/relay.d.ts +273 -0
  14. package/dist/src/channels/relay.js +564 -0
  15. package/dist/src/channels/relay.js.map +1 -0
  16. package/dist/src/channels/tagging.js +6 -1
  17. package/dist/src/channels/tagging.js.map +1 -1
  18. package/dist/src/channels/telegram-webhook.d.ts +273 -0
  19. package/dist/src/channels/telegram-webhook.js +536 -0
  20. package/dist/src/channels/telegram-webhook.js.map +1 -0
  21. package/dist/src/channels/telegram.d.ts +271 -1
  22. package/dist/src/channels/telegram.js +403 -45
  23. package/dist/src/channels/telegram.js.map +1 -1
  24. package/dist/src/cli/amend.js +350 -4
  25. package/dist/src/cli/amend.js.map +1 -1
  26. package/dist/src/cli/attest.js +43 -6
  27. package/dist/src/cli/attest.js.map +1 -1
  28. package/dist/src/cli/channel-relay.d.ts +108 -0
  29. package/dist/src/cli/channel-relay.js +334 -0
  30. package/dist/src/cli/channel-relay.js.map +1 -0
  31. package/dist/src/cli/channel-telegram-webhook.d.ts +273 -0
  32. package/dist/src/cli/channel-telegram-webhook.js +709 -0
  33. package/dist/src/cli/channel-telegram-webhook.js.map +1 -0
  34. package/dist/src/cli/channel-telegram.d.ts +272 -26
  35. package/dist/src/cli/channel-telegram.js +478 -41
  36. package/dist/src/cli/channel-telegram.js.map +1 -1
  37. package/dist/src/cli/channel.d.ts +1 -1
  38. package/dist/src/cli/channel.js +5 -1
  39. package/dist/src/cli/channel.js.map +1 -1
  40. package/dist/src/cli/daemon.js +37 -5
  41. package/dist/src/cli/daemon.js.map +1 -1
  42. package/dist/src/cli/doctor.d.ts +63 -0
  43. package/dist/src/cli/doctor.js +856 -111
  44. package/dist/src/cli/doctor.js.map +1 -1
  45. package/dist/src/cli/execute.d.ts +17 -1
  46. package/dist/src/cli/execute.js +341 -20
  47. package/dist/src/cli/execute.js.map +1 -1
  48. package/dist/src/cli/exit-codes.d.ts +12 -0
  49. package/dist/src/cli/exit-codes.js +13 -0
  50. package/dist/src/cli/exit-codes.js.map +1 -1
  51. package/dist/src/cli/gate.d.ts +2 -0
  52. package/dist/src/cli/gate.js +233 -2
  53. package/dist/src/cli/gate.js.map +1 -1
  54. package/dist/src/cli/help.d.ts +9 -1
  55. package/dist/src/cli/help.js +246 -38
  56. package/dist/src/cli/help.js.map +1 -1
  57. package/dist/src/cli/hook.d.ts +371 -3
  58. package/dist/src/cli/hook.js +1926 -44
  59. package/dist/src/cli/hook.js.map +1 -1
  60. package/dist/src/cli/init.js +16 -7
  61. package/dist/src/cli/init.js.map +1 -1
  62. package/dist/src/cli/instructions.js +24 -3
  63. package/dist/src/cli/instructions.js.map +1 -1
  64. package/dist/src/cli/log-anchor.d.ts +55 -0
  65. package/dist/src/cli/log-anchor.js +199 -60
  66. package/dist/src/cli/log-anchor.js.map +1 -1
  67. package/dist/src/cli/main.d.ts +0 -12
  68. package/dist/src/cli/main.js +51 -0
  69. package/dist/src/cli/main.js.map +1 -1
  70. package/dist/src/cli/muse.d.ts +2 -0
  71. package/dist/src/cli/muse.js +62 -0
  72. package/dist/src/cli/muse.js.map +1 -0
  73. package/dist/src/cli/payload.js +79 -1
  74. package/dist/src/cli/payload.js.map +1 -1
  75. package/dist/src/cli/scaffold.js +6 -0
  76. package/dist/src/cli/scaffold.js.map +1 -1
  77. package/dist/src/cli/serve.d.ts +53 -0
  78. package/dist/src/cli/serve.js +270 -0
  79. package/dist/src/cli/serve.js.map +1 -0
  80. package/dist/src/cli/up.js +21 -2
  81. package/dist/src/cli/up.js.map +1 -1
  82. package/dist/src/cli/verb-registry.d.ts +2 -0
  83. package/dist/src/cli/verb-registry.js +337 -39
  84. package/dist/src/cli/verb-registry.js.map +1 -1
  85. package/dist/src/cli/wordmark.d.ts +2 -2
  86. package/dist/src/cli/wordmark.js +2 -2
  87. package/dist/src/core/attest-bootstrap.d.ts +95 -0
  88. package/dist/src/core/attest-bootstrap.js +135 -0
  89. package/dist/src/core/attest-bootstrap.js.map +1 -0
  90. package/dist/src/core/attest.d.ts +20 -3
  91. package/dist/src/core/attest.js +25 -0
  92. package/dist/src/core/attest.js.map +1 -1
  93. package/dist/src/core/audit.d.ts +55 -3
  94. package/dist/src/core/audit.js +52 -5
  95. package/dist/src/core/audit.js.map +1 -1
  96. package/dist/src/core/channel-lease.d.ts +322 -0
  97. package/dist/src/core/channel-lease.js +663 -0
  98. package/dist/src/core/channel-lease.js.map +1 -0
  99. package/dist/src/core/command-class.d.ts +51 -0
  100. package/dist/src/core/command-class.js +760 -8
  101. package/dist/src/core/command-class.js.map +1 -1
  102. package/dist/src/core/daemon-host.d.ts +178 -0
  103. package/dist/src/core/daemon-host.js +228 -0
  104. package/dist/src/core/daemon-host.js.map +1 -0
  105. package/dist/src/core/daemon-identity.d.ts +238 -0
  106. package/dist/src/core/daemon-identity.js +252 -0
  107. package/dist/src/core/daemon-identity.js.map +1 -0
  108. package/dist/src/core/gate.d.ts +306 -5
  109. package/dist/src/core/gate.js +772 -24
  110. package/dist/src/core/gate.js.map +1 -1
  111. package/dist/src/core/harness-version.d.ts +128 -4
  112. package/dist/src/core/harness-version.js +179 -12
  113. package/dist/src/core/harness-version.js.map +1 -1
  114. package/dist/src/core/harness-wait.d.ts +82 -3
  115. package/dist/src/core/harness-wait.js +89 -3
  116. package/dist/src/core/harness-wait.js.map +1 -1
  117. package/dist/src/core/log-subscribe.d.ts +21 -0
  118. package/dist/src/core/log-subscribe.js +16 -6
  119. package/dist/src/core/log-subscribe.js.map +1 -1
  120. package/dist/src/core/log-write-layer.d.ts +55 -0
  121. package/dist/src/core/log-write-layer.js +91 -0
  122. package/dist/src/core/log-write-layer.js.map +1 -0
  123. package/dist/src/core/log.d.ts +50 -21
  124. package/dist/src/core/log.js +197 -19
  125. package/dist/src/core/log.js.map +1 -1
  126. package/dist/src/core/payload-census.d.ts +51 -0
  127. package/dist/src/core/payload-census.js +125 -2
  128. package/dist/src/core/payload-census.js.map +1 -1
  129. package/dist/src/core/payload-store.d.ts +31 -0
  130. package/dist/src/core/payload-store.js +113 -8
  131. package/dist/src/core/payload-store.js.map +1 -1
  132. package/dist/src/core/payload.d.ts +18 -3
  133. package/dist/src/core/payload.js +20 -4
  134. package/dist/src/core/payload.js.map +1 -1
  135. package/dist/src/core/policy-diff.d.ts +10 -0
  136. package/dist/src/core/policy-diff.js +10 -2
  137. package/dist/src/core/policy-diff.js.map +1 -1
  138. package/dist/src/core/policy-explain.d.ts +7 -1
  139. package/dist/src/core/policy-explain.js +16 -1
  140. package/dist/src/core/policy-explain.js.map +1 -1
  141. package/dist/src/core/policy-load.d.ts +24 -0
  142. package/dist/src/core/policy-load.js.map +1 -1
  143. package/dist/src/core/policy-match.d.ts +38 -0
  144. package/dist/src/core/policy-match.js +35 -0
  145. package/dist/src/core/policy-match.js.map +1 -1
  146. package/dist/src/core/policy-proposal.d.ts +23 -0
  147. package/dist/src/core/policy-proposal.js +8 -2
  148. package/dist/src/core/policy-proposal.js.map +1 -1
  149. package/dist/src/core/read-scope.d.ts +10 -0
  150. package/dist/src/core/read-scope.js +4 -0
  151. package/dist/src/core/read-scope.js.map +1 -1
  152. package/dist/src/core/run-payload.d.ts +160 -0
  153. package/dist/src/core/run-payload.js +304 -0
  154. package/dist/src/core/run-payload.js.map +1 -0
  155. package/dist/src/core/sender-identity.d.ts +35 -10
  156. package/dist/src/core/sender-identity.js +48 -11
  157. package/dist/src/core/sender-identity.js.map +1 -1
  158. package/dist/src/core/state.d.ts +52 -1
  159. package/dist/src/core/state.js +52 -6
  160. package/dist/src/core/state.js.map +1 -1
  161. package/dist/src/core/telegram-config.d.ts +79 -0
  162. package/dist/src/core/telegram-config.js +108 -0
  163. package/dist/src/core/telegram-config.js.map +1 -1
  164. package/dist/src/core/verify.d.ts +23 -1
  165. package/dist/src/core/verify.js +20 -2
  166. package/dist/src/core/verify.js.map +1 -1
  167. package/dist/src/daemon/audit.d.ts +80 -5
  168. package/dist/src/daemon/audit.js +126 -6
  169. package/dist/src/daemon/audit.js.map +1 -1
  170. package/dist/src/daemon/daemon.d.ts +174 -2
  171. package/dist/src/daemon/daemon.js +298 -7
  172. package/dist/src/daemon/daemon.js.map +1 -1
  173. package/dist/src/daemon/git-evidence.d.ts +2 -2
  174. package/dist/src/daemon/git-evidence.js +1 -1
  175. package/dist/src/daemon/projection.d.ts +13 -2
  176. package/dist/src/daemon/projection.js +39 -6
  177. package/dist/src/daemon/projection.js.map +1 -1
  178. package/dist/src/mcp/server.d.ts +39 -3
  179. package/dist/src/mcp/server.js +22 -3
  180. package/dist/src/mcp/server.js.map +1 -1
  181. package/dist/src/muse/server.d.ts +16 -0
  182. package/dist/src/muse/server.js +238 -0
  183. package/dist/src/muse/server.js.map +1 -0
  184. package/dist/src/serve/archive.d.ts +158 -0
  185. package/dist/src/serve/archive.js +354 -0
  186. package/dist/src/serve/archive.js.map +1 -0
  187. package/dist/src/serve/arguments.d.ts +93 -0
  188. package/dist/src/serve/arguments.js +228 -0
  189. package/dist/src/serve/arguments.js.map +1 -0
  190. package/dist/src/serve/credentials.d.ts +91 -0
  191. package/dist/src/serve/credentials.js +143 -0
  192. package/dist/src/serve/credentials.js.map +1 -0
  193. package/dist/src/serve/follow.d.ts +86 -0
  194. package/dist/src/serve/follow.js +101 -0
  195. package/dist/src/serve/follow.js.map +1 -0
  196. package/dist/src/serve/hook-thread.d.ts +134 -0
  197. package/dist/src/serve/hook-thread.js +333 -0
  198. package/dist/src/serve/hook-thread.js.map +1 -0
  199. package/dist/src/serve/hook-worker.d.ts +134 -0
  200. package/dist/src/serve/hook-worker.js +173 -0
  201. package/dist/src/serve/hook-worker.js.map +1 -0
  202. package/dist/src/serve/server.d.ts +412 -0
  203. package/dist/src/serve/server.js +1251 -0
  204. package/dist/src/serve/server.js.map +1 -0
  205. package/docs/README-extended.md +766 -0
  206. package/docs/cli-reference.md +1633 -43
  207. package/package.json +4 -2
  208. package/schema/event.schema.json +59 -2
  209. package/schema/fixtures/event/invalid/daemon-id-malformed.json +15 -0
  210. package/schema/fixtures/event/invalid/execution-started-truncated-policy-sha256.json +18 -0
  211. package/schema/fixtures/event/invalid/harness-cap-at-margin.json +16 -0
  212. package/schema/fixtures/event/invalid/harness-cap-fractional.json +16 -0
  213. package/schema/fixtures/event/invalid/harness-cap-negative.json +16 -0
  214. package/schema/fixtures/event/invalid/harness-cap-string.json +16 -0
  215. package/schema/fixtures/event/invalid/harness-cap-without-harness-execution.json +16 -0
  216. package/schema/fixtures/event/invalid/harness-cap-zero.json +16 -0
  217. package/schema/fixtures/event/valid/approval-requested-harness-cap.json +18 -0
  218. package/schema/fixtures/event/valid/daemon-identity-declared.json +17 -0
  219. package/schema/fixtures/event/valid/daemon-identity.json +15 -0
  220. package/schema/fixtures/event/valid/execution-started-policy-sha256.json +18 -0
  221. package/schema/fixtures/event/valid/harness-kind-hermes.json +23 -0
  222. package/schema/fixtures/policy/invalid/daemons-malformed-id.json +10 -0
  223. package/schema/fixtures/policy/valid/daemons-allowlist.json +19 -0
  224. package/schema/fixtures/policy-md/invalid/schema-invalid-agent-may-request.md +21 -0
  225. package/schema/fixtures/policy-md/valid/agent-may-request.md +24 -0
  226. package/schema/policy.schema.json +50 -6
@@ -0,0 +1,238 @@
1
+ /** Local synthetic Muse consumer facade. No native Muse protocol is claimed. */
2
+ import { createHash, timingSafeEqual } from "node:crypto";
3
+ import { createServer } from "node:http";
4
+ import { buildPendingQueue } from "../channels/tagging.js";
5
+ import { readGateRecords, register, registeredAction, request } from "../core/gate.js";
6
+ import { payloadHash } from "../core/payload.js";
7
+ import { loadPolicy } from "../core/policy-load.js";
8
+ import { requestState } from "../core/state.js";
9
+ import { canonicalRender } from "../core/wysiwys.js";
10
+ export const MUSE_TOKEN_MIN_LENGTH = 24;
11
+ const MAX_BODY = 64 * 1024;
12
+ const KEY = /^[A-Za-z0-9][A-Za-z0-9_.:/-]{0,159}$/u;
13
+ /** Facade-local refusals. Core gate/tagger codes pass through separately. */
14
+ export const MUSE_LOCAL_REFUSAL_CODES = [
15
+ "unauthorized", "scope-forbidden", "unsupported-query", "not-found",
16
+ "invalid-registration", "invalid-request", "invalid-lookup", "invalid-payload",
17
+ "payload-mismatch", "not-awaiting", "policy-unavailable", "sensitive-payload",
18
+ "body-too-large", "malformed-body", "internal-error",
19
+ ];
20
+ class MuseBodyError extends Error {
21
+ code;
22
+ constructor(code) {
23
+ super(code);
24
+ this.code = code;
25
+ }
26
+ }
27
+ export function validMuseOptions(o) {
28
+ return KEY.test(o.tenant) && /^agent:[A-Za-z0-9][A-Za-z0-9_.:/-]{0,159}$/u.test(o.actor)
29
+ && o.readToken.length >= MUSE_TOKEN_MIN_LENGTH && o.proposeToken.length >= MUSE_TOKEN_MIN_LENGTH
30
+ && o.readToken !== o.proposeToken && Number.isInteger(o.port) && o.port >= 0 && o.port <= 65535;
31
+ }
32
+ function equalToken(a, b) {
33
+ const left = createHash("sha256").update(a).digest();
34
+ const right = createHash("sha256").update(b).digest();
35
+ return timingSafeEqual(left, right);
36
+ }
37
+ function respond(res, status, value) {
38
+ const bytes = JSON.stringify(value);
39
+ res.writeHead(status, {
40
+ "content-type": "application/json; charset=utf-8",
41
+ "cache-control": "no-store",
42
+ "content-security-policy": "default-src 'none'",
43
+ "x-content-type-options": "nosniff",
44
+ });
45
+ res.end(bytes);
46
+ }
47
+ function fail(res, status, code) {
48
+ respond(res, status, { ok: false, error: { code } });
49
+ }
50
+ function object(value) {
51
+ return typeof value === "object" && value !== null && !Array.isArray(value);
52
+ }
53
+ function exact(value, fields) {
54
+ return Object.keys(value).every((name) => fields.includes(name));
55
+ }
56
+ async function body(req) {
57
+ const parts = [];
58
+ let size = 0;
59
+ for await (const part of req) {
60
+ const chunk = Buffer.isBuffer(part) ? part : Buffer.from(part);
61
+ size += chunk.length;
62
+ if (size > MAX_BODY)
63
+ throw new MuseBodyError("body-too-large");
64
+ parts.push(chunk);
65
+ }
66
+ try {
67
+ return JSON.parse(Buffer.concat(parts).toString("utf8"));
68
+ }
69
+ catch {
70
+ throw new MuseBodyError("malformed-body");
71
+ }
72
+ }
73
+ /** No caller-supplied object may smuggle bearer values into a durable payload. */
74
+ function secretLike(value) {
75
+ if (typeof value === "string")
76
+ return /(?:\bbearer\s+[A-Za-z0-9._~+/-]{12,}|\b(?:sk|ghp|xox[baprs])-\S{12,}|-----BEGIN [A-Z ]*PRIVATE KEY-----)/iu.test(value);
77
+ if (Array.isArray(value))
78
+ return value.some(secretLike);
79
+ if (object(value))
80
+ return Object.entries(value).some(([key, item]) => /(?:secret|password|credential|api[_-]?key|access[_-]?token|refresh[_-]?token|private[_-]?key)/iu.test(key) || secretLike(item));
81
+ return false;
82
+ }
83
+ function sensitive(value, o) {
84
+ if (secretLike(value))
85
+ return true;
86
+ if (typeof value === "string")
87
+ return value.includes(o.readToken) || value.includes(o.proposeToken);
88
+ if (Array.isArray(value))
89
+ return value.some((item) => sensitive(item, o));
90
+ if (object(value))
91
+ return Object.entries(value).some(([key, item]) => key.includes(o.readToken) || key.includes(o.proposeToken) || sensitive(item, o));
92
+ return false;
93
+ }
94
+ function safeRequest(item, detail) {
95
+ const canonical = item.fullPayload.value === null ? null : canonicalRender(item.fullPayload.value.value, item.class.value);
96
+ const result = {
97
+ task: item.task.value,
98
+ action_key: item.action_key.value,
99
+ class: item.class.value,
100
+ autonomy: item.autonomy.value,
101
+ state: item.state.value,
102
+ payload_hash: item.payload_hash.value,
103
+ display_hash: canonical?.display_hash ?? null,
104
+ requested_ts: item.requested_ts.value,
105
+ ttl_remaining_ms: item.ttl_remaining_ms.value,
106
+ chain_seq: item.chain.value.seq,
107
+ decision_channel: "telegram",
108
+ telegram_delivery_observed: false,
109
+ native_human_confirmation: false,
110
+ };
111
+ if (detail) {
112
+ // A canonical block is returned only on the read scope, and only when the
113
+ // verified payload store produced it. Never return claimed summaries or
114
+ // free-form gate errors, which may echo caller-supplied sensitive text.
115
+ result["canonical_rendering"] = canonical?.text ?? null;
116
+ }
117
+ return result;
118
+ }
119
+ function identity(req, o) {
120
+ let authorizationCount = 0;
121
+ for (let i = 0; i < req.rawHeaders.length; i += 2) {
122
+ if (req.rawHeaders[i]?.toLowerCase() === "authorization")
123
+ authorizationCount += 1;
124
+ }
125
+ if (authorizationCount !== 1)
126
+ return null;
127
+ const header = req.headers.authorization;
128
+ if (typeof header !== "string" || !header.startsWith("Bearer "))
129
+ return null;
130
+ const token = header.slice(7);
131
+ if (equalToken(token, o.readToken))
132
+ return "read";
133
+ if (equalToken(token, o.proposeToken))
134
+ return "propose";
135
+ return null;
136
+ }
137
+ export function createMuseServer(o) {
138
+ if (!validMuseOptions(o))
139
+ throw new Error("invalid Muse launch configuration");
140
+ return createServer((req, res) => {
141
+ void (async () => {
142
+ const role = identity(req, o);
143
+ if (role === null)
144
+ return fail(res, 401, "unauthorized");
145
+ const url = new URL(req.url ?? "/", "http://localhost");
146
+ if (url.search !== "" || url.hash !== "")
147
+ return fail(res, 400, "unsupported-query");
148
+ if (req.method === "GET" && url.pathname === "/v1/pending") {
149
+ if (role !== "read")
150
+ return fail(res, 403, "scope-forbidden");
151
+ const queue = buildPendingQueue(o.log, { policy: { dir: o.root } }, new Date().toISOString());
152
+ if (!queue.ok)
153
+ return fail(res, 409, queue.code);
154
+ const visible = queue.requests.filter((item) => !sensitive(item.fullPayload.value?.value, o));
155
+ return respond(res, 200, { ok: true, tenant: o.tenant, requests: visible.map((item) => safeRequest(item, false)), skipped: [...queue.skipped.map((item) => ({ action_key: item.action_key, code: item.code })), ...queue.requests.filter((item) => sensitive(item.fullPayload.value?.value, o)).map((item) => ({ action_key: item.action_key.value, code: "sensitive-payload" }))] });
156
+ }
157
+ if (req.method === "POST" && url.pathname === "/v1/registrations") {
158
+ if (role !== "propose")
159
+ return fail(res, 403, "scope-forbidden");
160
+ const input = await body(req);
161
+ if (!object(input) || !exact(input, ["task", "envelope"]) || typeof input["task"] !== "string" || !KEY.test(input["task"]) || !object(input["envelope"]) || sensitive(input, o))
162
+ return fail(res, 400, "invalid-registration");
163
+ const result = register(o.log, { task: input["task"], envelope: input["envelope"] }, o.actor);
164
+ if (!result.ok)
165
+ return fail(res, 409, result.code);
166
+ return respond(res, 201, { ok: true, tenant: o.tenant, task: result.task, seq: result.record.seq });
167
+ }
168
+ if (req.method === "POST" && url.pathname === "/v1/requests") {
169
+ if (role !== "propose")
170
+ return fail(res, 403, "scope-forbidden");
171
+ const input = await body(req);
172
+ if (!object(input) || !exact(input, ["task", "action_key", "payload"]) || typeof input["task"] !== "string" || !KEY.test(input["task"]) || typeof input["action_key"] !== "string" || !KEY.test(input["action_key"]) || !("payload" in input) || sensitive(input["payload"], o))
173
+ return fail(res, 400, "invalid-request");
174
+ let hash;
175
+ try {
176
+ hash = payloadHash(input["payload"]);
177
+ }
178
+ catch {
179
+ return fail(res, 400, "invalid-payload");
180
+ }
181
+ const read = readGateRecords(o.log);
182
+ if (!read.ok)
183
+ return fail(res, 409, read.code);
184
+ const declared = registeredAction(read.records, input["task"], input["action_key"]);
185
+ if (!declared.ok)
186
+ return fail(res, 409, declared.code);
187
+ if (declared.action.payload_hash !== hash)
188
+ return fail(res, 409, "payload-mismatch");
189
+ const result = request(o.log, {
190
+ task: input["task"], actionKey: input["action_key"], cls: declared.action.class,
191
+ ...(declared.action.est_cost_usd === undefined ? {} : { est_cost_usd: declared.action.est_cost_usd }),
192
+ ...(declared.action.reversible === undefined ? {} : { reversible: declared.action.reversible }),
193
+ ...(declared.action.summary === undefined ? {} : { summary: declared.action.summary }),
194
+ payload: { value: input["payload"] },
195
+ }, o.actor, { policy: { dir: o.root } });
196
+ if (!result.ok)
197
+ return fail(res, 409, result.code);
198
+ return respond(res, 200, { ok: true, tenant: o.tenant, task: input["task"], action_key: input["action_key"], payload_hash: hash, autonomy: result.autonomy, requested: result.record !== null, seq: result.record?.seq ?? null, decision_channel: "telegram", telegram_delivery_observed: false, native_human_confirmation: false });
199
+ }
200
+ if (req.method === "POST" && (url.pathname === "/v1/status" || url.pathname === "/v1/request-detail")) {
201
+ if (role !== "read")
202
+ return fail(res, 403, "scope-forbidden");
203
+ const input = await body(req);
204
+ if (!object(input) || !exact(input, ["task", "action_key"]) || typeof input["task"] !== "string" || !KEY.test(input["task"]) || typeof input["action_key"] !== "string" || !KEY.test(input["action_key"]))
205
+ return fail(res, 400, "invalid-lookup");
206
+ const read = readGateRecords(o.log);
207
+ if (!read.ok)
208
+ return fail(res, 409, read.code);
209
+ const declared = registeredAction(read.records, input["task"], input["action_key"]);
210
+ if (!declared.ok)
211
+ return fail(res, 404, "not-found");
212
+ const load = loadPolicy({ dir: o.root });
213
+ if (!load.ok)
214
+ return fail(res, 409, "policy-unavailable");
215
+ const state = requestState(read.records, input["action_key"], new Date().toISOString(), load.ok ? load.durations.approvalTtlMs : null);
216
+ if (url.pathname === "/v1/status")
217
+ return respond(res, 200, { ok: true, tenant: o.tenant, task: input["task"], action_key: input["action_key"], payload_hash: declared.action.payload_hash ?? null, state: state.state, decision_channel: "telegram", telegram_delivery_observed: false });
218
+ const queue = buildPendingQueue(o.log, { policy: { dir: o.root } }, new Date().toISOString());
219
+ if (!queue.ok)
220
+ return fail(res, 409, queue.code);
221
+ const item = queue.requests.find((entry) => entry.task.value === input["task"] && entry.action_key.value === input["action_key"]);
222
+ if (item === undefined)
223
+ return fail(res, 409, "not-awaiting");
224
+ if (sensitive(item.fullPayload.value?.value, o))
225
+ return fail(res, 409, "sensitive-payload");
226
+ return respond(res, 200, { ok: true, tenant: o.tenant, request: safeRequest(item, true) });
227
+ }
228
+ return fail(res, 404, "not-found");
229
+ })().catch((cause) => {
230
+ if (res.headersSent)
231
+ return;
232
+ if (cause instanceof MuseBodyError)
233
+ return fail(res, cause.code === "body-too-large" ? 413 : 400, cause.code);
234
+ return fail(res, 500, "internal-error");
235
+ });
236
+ });
237
+ }
238
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/muse/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,158 @@
1
+ /**
2
+ * The store as an archive (APRV-421): a POSIX ustar tar, gzipped, written here
3
+ * rather than by a library.
4
+ *
5
+ * ## Why a writer and not a dependency
6
+ *
7
+ * The repository rule is minimal dependencies, justified per addition, and the
8
+ * justification for a tar library would have to survive one question: what does
9
+ * it do that ninety lines here do not? A ustar header is a fixed 512-byte
10
+ * record with octal fields and a checksum, `node:zlib` already ships the
11
+ * compression, and the archive this verb produces contains a handful of files
12
+ * whose paths are short and known. A dependency would add a supply-chain
13
+ * surface to a process that hands a tenant their own evidence, in exchange for
14
+ * code this file can state completely.
15
+ *
16
+ * ## The contents are a POSITIVE allowlist
17
+ *
18
+ * {@link EXPORTED_PATHS} names what goes in. Everything else is out by not
19
+ * being named, which is the fail-closed direction SPEC.md §11 asks for
20
+ * everywhere else: `.approval/keys`, `.approval/env`, `.approval/daemon` and
21
+ * any `vault.enc` are excluded because nothing admits them, not because a
22
+ * denylist remembered them. A file added to the store next month is absent
23
+ * from this archive until somebody decides it belongs, and that decision is a
24
+ * diff here.
25
+ *
26
+ * `.approval/payloads/` IS on the list, and it is the entry the reasoning
27
+ * turns on. The log records a `payload_hash` for every action a human was
28
+ * shown, and the bytes those hashes name live in that directory. An archive
29
+ * carrying the hashes without the bytes would hand a tenant a chain of
30
+ * references to evidence they no longer hold: a receipt for an exit rather
31
+ * than an exit. Payload bytes are the tenant's own and are not credential
32
+ * material — the vault, the keys and the environment source map are, and
33
+ * those are the things excluded below.
34
+ *
35
+ * ## What the reader is for
36
+ *
37
+ * {@link readTarEntries} exists so that a test, and a conformance reader after
38
+ * it, can assert what an archive CONTAINS rather than trusting the writer that
39
+ * produced it. A test that checked the writer against itself would pass on the
40
+ * day the writer put the vault in.
41
+ */
42
+ /**
43
+ * What an export carries, relative to the store root, in archive order.
44
+ *
45
+ * A trailing `/` means "this directory, recursively". Everything else is one
46
+ * file, included when it exists and silently absent when it does not: a store
47
+ * whose index has never been built is an ordinary store, not a broken one.
48
+ */
49
+ export declare const EXPORTED_PATHS: readonly string[];
50
+ /**
51
+ * Paths an export MUST NOT carry, checked as well as excluded.
52
+ *
53
+ * The allowlist above is what decides; this list is what a test asserts
54
+ * against, so the property "no credential material left the store" is written
55
+ * down as a property and not merely implied by the absence of an entry.
56
+ */
57
+ export declare const EXCLUDED_PREFIXES: readonly string[];
58
+ /** Any file with this name is credential material, wherever it sits. */
59
+ export declare const EXCLUDED_BASENAMES: readonly string[];
60
+ export interface TarEntry {
61
+ /** POSIX path inside the archive, relative to the store root. */
62
+ path: string;
63
+ /** File contents. */
64
+ data: Buffer;
65
+ /** Modification time, seconds since the epoch. */
66
+ mtime: number;
67
+ }
68
+ type NameSplit = {
69
+ name: string;
70
+ prefix: string;
71
+ };
72
+ /**
73
+ * Split a path into ustar's `prefix` and `name` fields.
74
+ *
75
+ * Refused rather than truncated when it does not fit: a truncated path in an
76
+ * archive is a file restored to the wrong place, which is worse than an export
77
+ * that says plainly it cannot represent this store.
78
+ */
79
+ export declare function splitTarName(path: string): NameSplit;
80
+ /** Write `entries` as an uncompressed ustar archive. */
81
+ export declare function writeTar(entries: readonly TarEntry[]): Buffer;
82
+ /**
83
+ * Read an uncompressed ustar archive back.
84
+ *
85
+ * Deliberately strict about the checksum: the point of this function is to be
86
+ * an independent reader of what {@link writeTar} produced, and a reader that
87
+ * ignored the field the writer computes would not be independent of it.
88
+ */
89
+ export declare function readTarEntries(archive: Buffer): TarEntry[];
90
+ /**
91
+ * Is this store-relative path one an export may never carry?
92
+ *
93
+ * `excludedLock` is the ONE lockfile this server itself creates, passed in as
94
+ * an exact path rather than matched as a class. An earlier pass excluded
95
+ * `*.lock` by suffix, which quietly deleted a tenant's own
96
+ * `.approval/payloads/x.lock` from their archive: the tenant's bytes are the
97
+ * tenant's, and a name this runtime happens to use for its own bookkeeping is
98
+ * not a reason to drop somebody else's file. Only the path derived from the
99
+ * log is dropped, and only because the export holds that lock while it walks,
100
+ * so the file exists for exactly the span of the copy and means nothing but
101
+ * "somebody was reading when this was made".
102
+ */
103
+ export declare function isExcludedPath(path: string, excludedLock?: string | null): boolean;
104
+ /**
105
+ * A symlink the export walk reached.
106
+ *
107
+ * Thrown rather than returned because it must abort the WHOLE archive from
108
+ * wherever it is found, and an error is the one control flow that cannot be
109
+ * accidentally ignored by a caller that forgot to check a return value.
110
+ */
111
+ export declare class ExportSymlinkError extends Error {
112
+ /** The store-relative path of the link itself, never its target. */
113
+ readonly path: string;
114
+ constructor(path: string);
115
+ }
116
+ /**
117
+ * A HARD link, which a name-based exclusion cannot see at all (APRV-421,
118
+ * second review pass).
119
+ *
120
+ * `ln .approval/keys/sender.key .approval/log/note.jsonl` produces a second
121
+ * name for the same inode. There is no link to refuse to follow and no target
122
+ * to notice: the excluded path and the admitted path ARE one file, and the
123
+ * admitted name is a perfectly ordinary regular file by every test a walker
124
+ * can apply to it except one — its link count.
125
+ *
126
+ * So `nlink > 1` on a regular file under the store is refused, fail-closed and
127
+ * whole, exactly as a symlink is. The false positive is a tenant who
128
+ * deliberately hard-linked something into their own store, which is rare, is
129
+ * visible in the refusal, and is repaired by copying the file.
130
+ */
131
+ export declare class ExportHardLinkError extends Error {
132
+ /** The store-relative path of the link, which is also the file. */
133
+ readonly path: string;
134
+ /** How many names this inode has. */
135
+ readonly links: number;
136
+ constructor(path: string, links: number);
137
+ }
138
+ export interface StoreArchive {
139
+ /** The gzipped ustar bytes. */
140
+ bytes: Buffer;
141
+ /** The paths it carries, in archive order. Reported, and asserted by tests. */
142
+ paths: string[];
143
+ }
144
+ /**
145
+ * Build the export archive for the store rooted at `root`.
146
+ *
147
+ * Reads only; writes nothing anywhere, appends no record, and touches no
148
+ * credential. A path outside the allowlist cannot be reached from here, because
149
+ * the walk starts at the allowlist and nowhere else, and no path is followed
150
+ * through a link.
151
+ *
152
+ * Throws {@link ExportSymlinkError} when the walk meets a symbolic link. The
153
+ * caller turns that into a refusal naming the link's own relative path.
154
+ */
155
+ export declare function buildStoreArchive(root: string, logPath: string): StoreArchive;
156
+ /** `relative()` in POSIX spelling, for callers that hold absolute paths. */
157
+ export declare function storeRelative(root: string, path: string): string;
158
+ export {};