@coffre/vault 0.14.5 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -4
- package/dist/cloudflare.d.ts +341 -4
- package/dist/cloudflare.js +802 -6
- package/dist/index.js +1 -1
- package/dist/log-entry-BYWqj3O5.d.ts +364 -0
- package/dist/node.d.ts +181 -6
- package/dist/node.js +358 -16
- package/dist/{src-Bg0ZeMJW.js → src-DheG92EM.js} +1 -1
- package/dist/vault-kmtojYnW.js +14623 -0
- package/package.json +4 -5
- package/src/bulk.ts +89 -0
- package/src/changes.ts +478 -0
- package/src/checkpointer-node.ts +342 -0
- package/src/checkpointer-workers.ts +514 -0
- package/src/checkpointer.ts +1165 -0
- package/src/cloudflare.ts +207 -13
- package/src/config.ts +3 -2
- package/src/credentials.postgres.ts +78 -0
- package/src/credentials.sqlite.ts +240 -0
- package/src/credentials.ts +630 -0
- package/src/cutover.ts +275 -0
- package/src/decide.ts +437 -2
- package/src/inputs.ts +499 -0
- package/src/local.ts +20 -4
- package/src/log-checkpointer.ts +116 -0
- package/src/log-entry.ts +113 -0
- package/src/log-replay.ts +188 -0
- package/src/log-store.ts +695 -0
- package/src/node.ts +73 -9
- package/src/objects.ts +141 -0
- package/src/reads.ts +502 -0
- package/src/retention.ts +229 -0
- package/src/snapshot.postgres.ts +39 -9
- package/src/snapshot.sqlite.ts +28 -3
- package/src/snapshot.ts +64 -10
- package/src/store.ts +832 -36
- package/src/use.postgres.ts +111 -0
- package/src/use.sqlite.ts +542 -0
- package/src/use.ts +1060 -0
- package/src/vault.ts +1366 -220
- package/src/verifier.ts +136 -0
- package/src/witness-workers.ts +163 -0
- package/dist/vault-Cbi45kLB.js +0 -5197
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, r as awsKms, s as derivedSigningKey, t as KekBadClaimError } from "./src-
|
|
1
|
+
import { a as verifyCheckpoint, i as checkpointMessage, n as KekUnavailableError, r as awsKms, s as derivedSigningKey, t as KekBadClaimError } from "./src-DheG92EM.js";
|
|
2
2
|
export { KekBadClaimError, KekUnavailableError, awsKms, checkpointMessage, derivedSigningKey, verifyCheckpoint };
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import { Sealing } from "@coffre/core/vault";
|
|
2
|
+
import { Hash, LogEntry, LogReader, Pair, PairNotes, PairProofs, PairSigners, PairVerifiers, StoredPair, Tile, TreeName, WitnessAnswer } from "@coffre/core/merkle";
|
|
3
|
+
//#region src/checkpointer.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* 0.15's checkpointer (docs/design/audit-tree.md): every tick it seals what
|
|
6
|
+
* has committed into the two trees, signs both heads as one pair, remembers
|
|
7
|
+
* the pair outside the database, writes it, and hands it to the witnesses.
|
|
8
|
+
* The rest of the vault sees one seam: `tick()` (the window in, a signed pair
|
|
9
|
+
* out), `sealThrough(number)` for a change that waits for its seal (R51), and
|
|
10
|
+
* `prove(number)`. The trees' shape stays behind it.
|
|
11
|
+
*
|
|
12
|
+
* What it stands on, each a protection formal/Seal.tla shows necessary:
|
|
13
|
+
* - the barrier (`close`): every number at or below the `upto` it returns has
|
|
14
|
+
* ended, committed or not, so a window is final once read;
|
|
15
|
+
* - the signer's memory (`Memory`, core, R54): the last pair it signed, kept
|
|
16
|
+
* where a database writer cannot reach, written before the database
|
|
17
|
+
* (RememberFirst) and checked at every open, so neither a tail cut nor a
|
|
18
|
+
* rollback gets a second history signed;
|
|
19
|
+
* - each tick compares the database's newest row with the pair it holds
|
|
20
|
+
* (RowChecked), so a deleted row shows within a tick, traffic or not;
|
|
21
|
+
* - nothing is sealed over an entry that fails its MAC (`authentic`), is out
|
|
22
|
+
* of its window, or is much older than the pair it holds (a replay).
|
|
23
|
+
*
|
|
24
|
+
* And nothing it awaits is unbounded (T169): a tick that runs past
|
|
25
|
+
* `TICK_BOUND_MS` stalls the checkpointer, closed for good behind its
|
|
26
|
+
* `Fence`, so that its host opens another while the database still holds
|
|
27
|
+
* the old one's statement (Seal.tla's Fenced); a change waits at most
|
|
28
|
+
* `SEAL_WAIT_MS` for its seal, then answers `Unsealed`.
|
|
29
|
+
*/
|
|
30
|
+
/** What the checkpointer needs of the database. Postgres and SQLite implement it; so do the tests. */
|
|
31
|
+
type CheckpointStore = LogReader & {
|
|
32
|
+
/**
|
|
33
|
+
* The barrier, then the window: `upto`, such that every number at or below
|
|
34
|
+
* it has ended; the entries in (after, upto], by number; and the newest
|
|
35
|
+
* pair, as `newest()` reads it. The window is read after the barrier's lock
|
|
36
|
+
* is let go, in a snapshot of its own (`close_one`, then one read): a
|
|
37
|
+
* snapshot from before the lock would miss what committed while it waited.
|
|
38
|
+
*
|
|
39
|
+
* The barrier also raises the floor of `at` (`close_one`): `floor.found` is
|
|
40
|
+
* the floor it found, null if none, and `floor.set` the one it left. The
|
|
41
|
+
* window's uses are read from `from`, the floor the signer holds, as the
|
|
42
|
+
* last barrier set it. `floor.ceiling` is the database's clock less the
|
|
43
|
+
* use deadline, read once the barrier has run: the highest floor any
|
|
44
|
+
* barrier before it can have left (HotPathOne.tla's BarrierAcceptsLate).
|
|
45
|
+
*
|
|
46
|
+
* With `limit` (T169), the window's first `limit` entries by number, and
|
|
47
|
+
* `more` when there were more: `more.above`, the lowest `at` of the uses
|
|
48
|
+
* the window holds above the last of them, from `from` on (null: none).
|
|
49
|
+
* `barrier`, told the barrier's `upto` before the window is read.
|
|
50
|
+
*/
|
|
51
|
+
close(after: bigint, from: number, limit?: number, barrier?: (upto: bigint) => void): Promise<{
|
|
52
|
+
upto: bigint;
|
|
53
|
+
newest: StoredPair | null;
|
|
54
|
+
entries: LogEntry[];
|
|
55
|
+
floor: {
|
|
56
|
+
found: number | null;
|
|
57
|
+
set: number;
|
|
58
|
+
ceiling: number;
|
|
59
|
+
};
|
|
60
|
+
more?: {
|
|
61
|
+
above: number | null;
|
|
62
|
+
} | null;
|
|
63
|
+
}>;
|
|
64
|
+
/**
|
|
65
|
+
* The newest pair: each tree's own newest note, `upto` the larger of theirs
|
|
66
|
+
* (Seal.tla's PairChecked). Stored as one row a pair, that is the newest
|
|
67
|
+
* row; stored as a row a tree, never one tree's newest row for both, since
|
|
68
|
+
* deleting the other tree's newest row would then pass unseen. Notes of two
|
|
69
|
+
* places then fail every check that wants one pair.
|
|
70
|
+
*/
|
|
71
|
+
newest(): Promise<StoredPair | null>;
|
|
72
|
+
/**
|
|
73
|
+
* One statement: both trees' tiles and both notes (PairWrittenTogether). No
|
|
74
|
+
* state holds one head without the other.
|
|
75
|
+
*/
|
|
76
|
+
write(row: StoredPair, tiles: Record<TreeName, Tile[]>): Promise<void>;
|
|
77
|
+
/**
|
|
78
|
+
* Entry `number` and its leaf index in its tree, if it is in the log; a
|
|
79
|
+
* use found at `at` when the caller knows its time, which spares a scan
|
|
80
|
+
* of its window's time. With `tree`, an entry in the other is refused
|
|
81
|
+
* (`misplaced`) before its index is sought.
|
|
82
|
+
*/
|
|
83
|
+
locate(number: bigint, options?: Locating): Promise<{
|
|
84
|
+
entry: LogEntry;
|
|
85
|
+
index: number;
|
|
86
|
+
} | null>;
|
|
87
|
+
};
|
|
88
|
+
/**
|
|
89
|
+
* The signer's memory: the one record holding the last pair it signed. A
|
|
90
|
+
* Durable Object's storage on Workers, a synced file beside a Node vault.
|
|
91
|
+
*/
|
|
92
|
+
type Memory = {
|
|
93
|
+
last(): Promise<string | null>;
|
|
94
|
+
remember(record: string): Promise<void>;
|
|
95
|
+
};
|
|
96
|
+
/** What a proof asks of `locate`: the use's time, if known, and the tree the entry must be in. */
|
|
97
|
+
type Locating = {
|
|
98
|
+
at?: number;
|
|
99
|
+
tree?: TreeName;
|
|
100
|
+
};
|
|
101
|
+
/** Somewhere each signed pair goes that a database writer cannot reach: a witness, an archive (R40's plugin). */
|
|
102
|
+
type Witness = {
|
|
103
|
+
name: string;
|
|
104
|
+
/**
|
|
105
|
+
* Publishes the pair; `proofs(from)` gives each tree's consistency proof
|
|
106
|
+
* from the sizes the witness holds. A try that outlives its bound (2 s) is
|
|
107
|
+
* a failure to the pump, and `signal` aborts: an implementation that makes
|
|
108
|
+
* a request passes it on, so abandoned tries do not pile up.
|
|
109
|
+
*/
|
|
110
|
+
publish(notes: PairNotes, proofs: (from: Record<TreeName, number>) => Promise<PairProofs>, signal: AbortSignal): Promise<WitnessAnswer>;
|
|
111
|
+
};
|
|
112
|
+
/**
|
|
113
|
+
* What a checkpointer given up on may still do (T169; Seal.tla's Fenced):
|
|
114
|
+
* nothing it starts once its fence is closed. Every call it makes to its
|
|
115
|
+
* store, and every write to its memory, is checked against the fence
|
|
116
|
+
* first. What it sent before may still land: a database write is refused
|
|
117
|
+
* where a row holds its place (`write_checkpoint`, one statement), and a
|
|
118
|
+
* barrier raises the floor no higher than the next one does
|
|
119
|
+
* (HotPathOne.tla's LateBarrier); the memory writes in flight, `close`
|
|
120
|
+
* waits for, so that the next checkpointer reads them.
|
|
121
|
+
*/
|
|
122
|
+
declare class Fence {
|
|
123
|
+
#private;
|
|
124
|
+
/** Why it was closed; null while it is open. */
|
|
125
|
+
get closed(): string | null;
|
|
126
|
+
/** Closed for good; resolves once the memory writes already sent have landed. */
|
|
127
|
+
close(why: string): Promise<void>;
|
|
128
|
+
/** The store, each of its calls refused once the fence is closed, and each answer that comes after. */
|
|
129
|
+
store<T extends object>(store: T): T;
|
|
130
|
+
/** The memory, its writes refused once the fence is closed, and those in flight kept for `close`. */
|
|
131
|
+
memory(memory: Memory): Memory;
|
|
132
|
+
}
|
|
133
|
+
type Tick = {
|
|
134
|
+
/**
|
|
135
|
+
* Whether a pair landed in the database this tick: a new one, or a pending
|
|
136
|
+
* one finished. A tick can finish a pending pair and then refuse its own
|
|
137
|
+
* window: `failures` says so.
|
|
138
|
+
*/
|
|
139
|
+
signed: boolean;
|
|
140
|
+
upto: bigint;
|
|
141
|
+
sizes: Record<TreeName, number>;
|
|
142
|
+
entries: number;
|
|
143
|
+
/** Why nothing was signed, when something is wrong: each is an alarm for an operator. */
|
|
144
|
+
failures: string[];
|
|
145
|
+
/** Database time: the barrier and window, then the write. */
|
|
146
|
+
closeMs: number;
|
|
147
|
+
writeMs: number;
|
|
148
|
+
/** Whether the window held more than this tick sealed (`WINDOW_MAX`): its host ticks again at once. */
|
|
149
|
+
more: boolean;
|
|
150
|
+
};
|
|
151
|
+
type Sealed = {
|
|
152
|
+
pair: Pair;
|
|
153
|
+
notes: PairNotes;
|
|
154
|
+
/** null when no witness is set up, so nothing reads "witnessed" there. */
|
|
155
|
+
witnessed: boolean | null;
|
|
156
|
+
failures: string[];
|
|
157
|
+
/**
|
|
158
|
+
* Each witness's cosignature of the newest pair it took in time: a pair
|
|
159
|
+
* covering the change, which may be later than `pair` if a tick landed
|
|
160
|
+
* meanwhile. Each note says its own place. An archive cosigns nothing and
|
|
161
|
+
* adds none: whether the change was witnessed is `witnessed`, never the
|
|
162
|
+
* length of this.
|
|
163
|
+
*/
|
|
164
|
+
cosigned: PairNotes[];
|
|
165
|
+
/** The change's entry, proved in the pair: what the admin's client checks and can keep. */
|
|
166
|
+
proof: InclusionProof;
|
|
167
|
+
};
|
|
168
|
+
/**
|
|
169
|
+
* The change path's seam (plan PR 4): a change, once committed, asks for its
|
|
170
|
+
* seal and answers with what this gives it (R51). The Node checkpointer's
|
|
171
|
+
* `sealThrough` is one; on Workers, `durableSealThrough` asks the
|
|
172
|
+
* checkpointer's Durable Object.
|
|
173
|
+
*/
|
|
174
|
+
type SealThrough = (number: bigint, deadline?: number) => Promise<Sealed>;
|
|
175
|
+
/** An alarm the checkpointer raised, as its host keeps it for whoever watches (R40's plugin, PR 8's surfaces). */
|
|
176
|
+
type Alarm = {
|
|
177
|
+
at: number;
|
|
178
|
+
message: string;
|
|
179
|
+
};
|
|
180
|
+
type InclusionProof = {
|
|
181
|
+
number: bigint;
|
|
182
|
+
tree: TreeName;
|
|
183
|
+
index: number;
|
|
184
|
+
size: number;
|
|
185
|
+
/** The leaf's data: the whole entry. */
|
|
186
|
+
leaf: Buffer;
|
|
187
|
+
proof: Hash[];
|
|
188
|
+
/** The pair it is proved against. */
|
|
189
|
+
notes: PairNotes;
|
|
190
|
+
};
|
|
191
|
+
type Options = {
|
|
192
|
+
memory: Memory;
|
|
193
|
+
witnesses?: readonly Witness[];
|
|
194
|
+
/**
|
|
195
|
+
* Whether an entry's MAC holds: the vault checks it with its key before
|
|
196
|
+
* anything is sealed. The MAC must cover the entry's tree (Seal.tla's
|
|
197
|
+
* KindInMac): otherwise a change moved into the uses partition before its
|
|
198
|
+
* tick would be sealed into the uses tree, and pruned with the uses.
|
|
199
|
+
*/
|
|
200
|
+
authentic: (entry: LogEntry) => boolean;
|
|
201
|
+
/** Where alarms go: refused ticks, unwitnessed changes, memory and database out of step. */
|
|
202
|
+
alert?: (message: string) => void;
|
|
203
|
+
freshMs?: number;
|
|
204
|
+
now?: () => number;
|
|
205
|
+
/**
|
|
206
|
+
* What closes this checkpointer for good (T169): a host bounding the open
|
|
207
|
+
* passes its own, to close it if the open stalls. One is made otherwise.
|
|
208
|
+
*/
|
|
209
|
+
fence?: Fence;
|
|
210
|
+
/** `TICK_BOUND_MS`, `SEAL_WAIT_MS` and `WINDOW_MAX`, for the tests. */
|
|
211
|
+
tickBoundMs?: number;
|
|
212
|
+
sealWaitMs?: number;
|
|
213
|
+
windowMax?: number;
|
|
214
|
+
};
|
|
215
|
+
declare class Checkpointer {
|
|
216
|
+
private store;
|
|
217
|
+
private signers;
|
|
218
|
+
private options;
|
|
219
|
+
private fence;
|
|
220
|
+
private edges;
|
|
221
|
+
private head;
|
|
222
|
+
private running;
|
|
223
|
+
private pumps;
|
|
224
|
+
/**
|
|
225
|
+
* A pair signed, perhaps remembered, not known to be written: the memory
|
|
226
|
+
* may hold it, or the database may (a write that committed, then threw).
|
|
227
|
+
* It is finished before anything else is signed, never replaced by another
|
|
228
|
+
* pair for its place.
|
|
229
|
+
*/
|
|
230
|
+
private pending;
|
|
231
|
+
/** The last pairs it wrote, newest last, each with what proves a change it sealed (T171). */
|
|
232
|
+
private signed;
|
|
233
|
+
/** The tick running now (T171): a change committed before its barrier is sealed by it, and waits for no other. */
|
|
234
|
+
private flight;
|
|
235
|
+
/**
|
|
236
|
+
* The floor of `at` signed into the newest pair: windows are read from it.
|
|
237
|
+
* It moves only when a pair carrying a new floor is written.
|
|
238
|
+
*/
|
|
239
|
+
private floor;
|
|
240
|
+
/**
|
|
241
|
+
* The floor this process's last barrier set, which the next barrier must
|
|
242
|
+
* find exactly; null until its first barrier (a restart cannot know what
|
|
243
|
+
* barriers whose pairs went unsigned raised it to).
|
|
244
|
+
*/
|
|
245
|
+
private barrier;
|
|
246
|
+
/** Set once a barrier finds the floor elsewhere: every tick refuses until the checkpointer is reopened. */
|
|
247
|
+
private floorAlarm;
|
|
248
|
+
/** The failures the last refused tick alerted: a refusal that stands is alerted once, not every tick. */
|
|
249
|
+
private refused;
|
|
250
|
+
/** The log's public keys, which open its pairs. */
|
|
251
|
+
readonly verifiers: PairVerifiers;
|
|
252
|
+
private constructor();
|
|
253
|
+
/**
|
|
254
|
+
* What stands against it sealing, whichever tick met it, an alarm's or a change's: why it stalled, or the refusal of
|
|
255
|
+
* its last tick; null when its last tick held. Readiness reads it beside its host's own view (T169, review r5).
|
|
256
|
+
*/
|
|
257
|
+
get standing(): string | null;
|
|
258
|
+
/** Why its last tick threw, whichever tick it was, a change's or its host's; null once one ends well (review r6). */
|
|
259
|
+
private thrown;
|
|
260
|
+
/** The newest pair the signer signed and the database holds. */
|
|
261
|
+
get pair(): {
|
|
262
|
+
pair: Pair;
|
|
263
|
+
notes: PairNotes;
|
|
264
|
+
};
|
|
265
|
+
/** How much older than its pair an entry the signer seals may be (`FRESH_MS`): retention drops a day two of these past its cut. */
|
|
266
|
+
get freshMs(): number;
|
|
267
|
+
/**
|
|
268
|
+
* From the newest checkpoint row, checked against what the signer
|
|
269
|
+
* remembers, which comes first: nothing is signed or remembered before the
|
|
270
|
+
* two are compared. The signer remembers a pair before the database has it
|
|
271
|
+
* (RememberFirst), so the memory may be ahead of the database: after a crash
|
|
272
|
+
* between the two, or because a writer deleted the newest rows. Either way,
|
|
273
|
+
* if the entries the database holds give the remembered pair, its row is
|
|
274
|
+
* written again and nothing was lost; if they do not, the database lost
|
|
275
|
+
* entries the signer sealed, and it refuses. A database beside the memory,
|
|
276
|
+
* another pair at the same place, is refused too.
|
|
277
|
+
*/
|
|
278
|
+
static open(store: CheckpointStore, signers: PairSigners, options: Options): Promise<Checkpointer>;
|
|
279
|
+
/**
|
|
280
|
+
* One checkpoint: seal what has committed, sign it, remember it, store it,
|
|
281
|
+
* publish it. Ticks run one at a time, the regular ones and those a change
|
|
282
|
+
* asks for.
|
|
283
|
+
*/
|
|
284
|
+
/**
|
|
285
|
+
* Stops this checkpointer for good: every tick after, and every change
|
|
286
|
+
* that would tick, is refused, and its fence refuses whatever its tick in
|
|
287
|
+
* flight still does. Resolves once that tick has ended or stalled
|
|
288
|
+
* (`TICK_BOUND_MS`), and its memory writes in flight have landed. A host
|
|
289
|
+
* that opens another over the same memory closes this one first, so that
|
|
290
|
+
* two signers never act at once.
|
|
291
|
+
*/
|
|
292
|
+
close(): Promise<void>;
|
|
293
|
+
private closed;
|
|
294
|
+
/** Why it stalled (T169): a tick past its bound. */
|
|
295
|
+
private stalled;
|
|
296
|
+
/** When the tick in flight stalls: `TICK_BOUND_MS` after it started, and more for a long window. */
|
|
297
|
+
private until;
|
|
298
|
+
/** What the tick in flight awaits, which a stall says, so that an operator sees what stalled. */
|
|
299
|
+
private phase;
|
|
300
|
+
/**
|
|
301
|
+
* A tick: the one queued behind the running one, if there is one yet,
|
|
302
|
+
* else a new one. Its barrier comes after every commit made before it
|
|
303
|
+
* starts, so whoever asks before it starts is sealed by it as well as by
|
|
304
|
+
* one of their own: many changes waiting at once share ticks, rather than
|
|
305
|
+
* each waiting for a tick per change before it (0.15-plan.md, "As built:
|
|
306
|
+
* PR 4b", measured).
|
|
307
|
+
*/
|
|
308
|
+
tick(): Promise<Tick>;
|
|
309
|
+
private queued;
|
|
310
|
+
private tickNow;
|
|
311
|
+
/**
|
|
312
|
+
* Finishes a pending pair: remembered again (the first try may have failed,
|
|
313
|
+
* or not), then held by the database, which may hold it already; else it is
|
|
314
|
+
* written now over the pair the signer holds. A database at neither pair
|
|
315
|
+
* is refused until the checkpointer is reopened, whose rules then apply.
|
|
316
|
+
*/
|
|
317
|
+
private finish;
|
|
318
|
+
private commit;
|
|
319
|
+
/**
|
|
320
|
+
* A change answers once its entry is sealed and, where witnesses are set
|
|
321
|
+
* up, witnessed (R51): seal now unless a pair already covers it, then wait
|
|
322
|
+
* for every witness to hold a pair that covers it, whichever tick sealed it,
|
|
323
|
+
* for at most `deadline`. A witness silent that long lets the change answer
|
|
324
|
+
* unwitnessed, alerted: the change is in force either way, and its entry is
|
|
325
|
+
* sealed in the database and in the signer's memory. A tick that cannot seal
|
|
326
|
+
* (an entry failing its MAC) fails the wait rather than spinning.
|
|
327
|
+
*
|
|
328
|
+
* A pair covering the number is not enough: the entry must be in it. An
|
|
329
|
+
* entry deleted before its tick leaves its number a gap the pair calls
|
|
330
|
+
* final, and nothing could ever show the change again; so the change is
|
|
331
|
+
* proved in the pair, and refused, alerted, if it is not there.
|
|
332
|
+
*/
|
|
333
|
+
sealThrough(number: bigint, deadline?: number): Promise<Sealed>;
|
|
334
|
+
/**
|
|
335
|
+
* Change `number`'s inclusion proof in a pair this checkpointer signed and wrote, from the tiles its tick wrote, and
|
|
336
|
+
* checked against that pair's root; null if it kept none holding it (T171).
|
|
337
|
+
*/
|
|
338
|
+
private proveKept;
|
|
339
|
+
/**
|
|
340
|
+
* Entry `number`'s inclusion proof against the newest pair, checked before
|
|
341
|
+
* it is handed out; null if not sealed. A use's `at`, if known, finds it
|
|
342
|
+
* in one probe; with `tree`, an entry in the other is refused.
|
|
343
|
+
*/
|
|
344
|
+
prove(number: bigint, options?: Locating): Promise<InclusionProof | null>;
|
|
345
|
+
private proveAt;
|
|
346
|
+
/** Each witness's pump: one publication in flight at a time, always of the newest pair (a witness needs only that). */
|
|
347
|
+
private pump;
|
|
348
|
+
private publish;
|
|
349
|
+
/** Hands a witness the newest pair: sent now if its pump is idle, else next. A checkpointer closed hands none. */
|
|
350
|
+
private kick;
|
|
351
|
+
private drain;
|
|
352
|
+
private publishAll;
|
|
353
|
+
/** The witnesses that do not hold a pair sealing `upto` within the deadline, each with its last failure. */
|
|
354
|
+
private witnessed;
|
|
355
|
+
}
|
|
356
|
+
//#endregion
|
|
357
|
+
//#region src/log-entry.d.ts
|
|
358
|
+
/** The key that MACs log entries, and its tag: both from the vault's signing seed, each under a label of its own. */
|
|
359
|
+
type LogMacKey = {
|
|
360
|
+
tag: Buffer;
|
|
361
|
+
key: Buffer;
|
|
362
|
+
};
|
|
363
|
+
//#endregion
|
|
364
|
+
export { SealThrough as a, Memory as i, Alarm as n, Tick as o, Checkpointer as r, Witness as s, LogMacKey as t };
|
package/dist/node.d.ts
CHANGED
|
@@ -1,11 +1,46 @@
|
|
|
1
|
+
import { a as SealThrough, i as Memory, n as Alarm, r as Checkpointer, s as Witness } from "./log-entry-BYWqj3O5.js";
|
|
1
2
|
import { a as KekUnavailableError, c as awsKms, d as Kek, f as VaultConfig, i as KekProvider, l as checkpointMessage, n as AwsKmsOptions, o as SecretContext, p as derivedSigningKey, r as KekBadClaimError, s as WrappedDek, t as AwsCredentials, u as verifyCheckpoint } from "./index-DQ-FKVF3.js";
|
|
2
|
-
import { Vault, Vault as Vault$1 } from "@coffre/core/vault";
|
|
3
|
-
import {
|
|
3
|
+
import { NamedUseInput, Sealing, UseCode, Vault, Vault as Vault$1 } from "@coffre/core/vault";
|
|
4
|
+
import { KekRegistry } from "@coffre/core/kek";
|
|
5
|
+
import { Database, Queryable } from "@coffre/db";
|
|
6
|
+
import { PairNotes, PairVerifiers } from "@coffre/core/merkle";
|
|
4
7
|
import "@coffre/core/access";
|
|
5
|
-
import "@coffre/core/audit";
|
|
6
|
-
import "@coffre/db/grants";
|
|
7
8
|
import "@coffre/db/log";
|
|
9
|
+
import "@coffre/db/grants";
|
|
10
|
+
import "drizzle-orm";
|
|
11
|
+
import "@coffre/core/audit";
|
|
8
12
|
export * from "@coffre/core/vault";
|
|
13
|
+
//#region src/log-replay.d.ts
|
|
14
|
+
/**
|
|
15
|
+
* The log as stored, read whole and replayed with the seal keys of
|
|
16
|
+
* `signingKeys` (the vault's): each use's decision by its entry number,
|
|
17
|
+
* and what does not hold, an entry that names no object or no purpose
|
|
18
|
+
* among `replay`'s faults. The verifier of plan PR 8 walks the log a
|
|
19
|
+
* stretch at a time; this reads all of it, for the suites that hold every
|
|
20
|
+
* live answer to it (R53).
|
|
21
|
+
*/
|
|
22
|
+
export declare function replayStored(db: Queryable, signingKeys: readonly Uint8Array[]): Promise<{
|
|
23
|
+
decided: Map<string, UseCode | null>;
|
|
24
|
+
faults: string[];
|
|
25
|
+
}>;
|
|
26
|
+
//#endregion
|
|
27
|
+
//#region src/use.d.ts
|
|
28
|
+
/**
|
|
29
|
+
* The settings of an isolate's uses: how many calls in flight at once, how long a cover holds, and how many requests'
|
|
30
|
+
* names it maps to ids (`UseCache.names`; 0 maps none, each request then reads its ids: the bench's worst case).
|
|
31
|
+
*/
|
|
32
|
+
type UseLimits = {
|
|
33
|
+
inFlight: number;
|
|
34
|
+
coverMs: number;
|
|
35
|
+
names: number;
|
|
36
|
+
/**
|
|
37
|
+
* The most keys a statement of a batch makes uses of (`useMany`): each statement holds the fence for its keys' uses,
|
|
38
|
+
* about 0.4 ms a key, and a change or the checkpointer's barrier waits behind it, every use queued behind that (R44).
|
|
39
|
+
* A batch of more is made in statements of this many, in turn (review r2 of #433): 100 hold the fence about 40 ms.
|
|
40
|
+
*/
|
|
41
|
+
batch: number;
|
|
42
|
+
};
|
|
43
|
+
//#endregion
|
|
9
44
|
//#region src/vault.d.ts
|
|
10
45
|
type VaultOptions = {
|
|
11
46
|
/**
|
|
@@ -17,6 +52,50 @@ type VaultOptions = {
|
|
|
17
52
|
clockOffset?: () => number;
|
|
18
53
|
/** How far one call walks the log (`WALKS`); tests shorten them. */
|
|
19
54
|
walks?: Partial<Walks>;
|
|
55
|
+
/**
|
|
56
|
+
* Which log the vault keeps (0.15's plan, "Behind one switch"): 0.15's,
|
|
57
|
+
* the default since its flip (plan PR 10), where each decision that
|
|
58
|
+
* changes an input also logs it as a change of 0.15's log (`changes.ts`),
|
|
59
|
+
* or 0.14's alone, for the suites until 0.16 removes it. Not a
|
|
60
|
+
* deployment's to set: once cut over, the database refuses 0.14's writes.
|
|
61
|
+
*/
|
|
62
|
+
log?: '0.14' | '0.15';
|
|
63
|
+
/**
|
|
64
|
+
* Under 0.15's log, what a change waits for before it answers: its entry
|
|
65
|
+
* sealed in a signed checkpoint, and witnessed or past the witnesses'
|
|
66
|
+
* bound (R51): the checkpointer's `sealThrough` (checkpointer.ts). A
|
|
67
|
+
* change whose entry it does not seal fails, though committed. Required
|
|
68
|
+
* under 0.15's log.
|
|
69
|
+
*/
|
|
70
|
+
sealThrough?: SealThrough;
|
|
71
|
+
/**
|
|
72
|
+
* Under 0.15's log, the pairs held where no database writer reaches: the
|
|
73
|
+
* signer's memory (`durableHeldOutside` on Workers, the Node runner's
|
|
74
|
+
* `heldOutside`), later a witness's. The verifier holds every walk to
|
|
75
|
+
* them; without, a database rolled back whole to an earlier pair would
|
|
76
|
+
* verify until the signer's next tick refuses it (verifier.ts). Required
|
|
77
|
+
* under 0.15's log, as `sealThrough` is (T151).
|
|
78
|
+
*/
|
|
79
|
+
heldOutside?: () => Promise<readonly PairNotes[]>;
|
|
80
|
+
/**
|
|
81
|
+
* Under 0.15's log, whether the checkpointer seals (T169), bounded: what
|
|
82
|
+
* `sealing()` answers, and `/readyz` asks. The Node runner's `sealing`;
|
|
83
|
+
* on Workers the entrypoint asks the object itself. Without, it seals.
|
|
84
|
+
*/
|
|
85
|
+
sealing?: () => Promise<Sealing> | Sealing;
|
|
86
|
+
/**
|
|
87
|
+
* 0.15's uses, per isolate (use.ts): how many calls in flight at once, by
|
|
88
|
+
* default the hot path's pool, `connections`, and how long a cover holds.
|
|
89
|
+
*/
|
|
90
|
+
uses?: Partial<UseLimits> & {
|
|
91
|
+
connections?: number;
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Whether a call's I/O ends with its request, as on Workers, where a call whose request has ended may never settle:
|
|
95
|
+
* then a use's place in admission lapses past its deadline, settled or not (use.ts, `HELD_PAST_DEADLINE_MS`), its
|
|
96
|
+
* connection closed by then (cloudflare.ts). Not a deployment's to set.
|
|
97
|
+
*/
|
|
98
|
+
callsEndWithRequest?: boolean;
|
|
20
99
|
};
|
|
21
100
|
/** How far one call walks the log, in entries: a checkpoint's walk from the last, its rehash of the past, and a verification's own walk. */
|
|
22
101
|
type Walks = {
|
|
@@ -27,9 +106,84 @@ type Walks = {
|
|
|
27
106
|
//#endregion
|
|
28
107
|
//#region src/local.d.ts
|
|
29
108
|
type LocalVault = Vault$1 & {
|
|
109
|
+
use: NonNullable<Vault$1['use']>;
|
|
30
110
|
close(): Promise<void>;
|
|
31
111
|
};
|
|
32
112
|
//#endregion
|
|
113
|
+
//#region src/checkpointer-node.d.ts
|
|
114
|
+
/**
|
|
115
|
+
* The 0.15 checkpointer on Node (docs/design/audit-tree.md): one process
|
|
116
|
+
* seals the log every 500 ms, its memory a file beside the vault, synced
|
|
117
|
+
* before the database has the pair it holds (RememberFirst). The vault's
|
|
118
|
+
* process runs it (`keepCheckpointer`, node.ts). Nothing it awaits is
|
|
119
|
+
* unbounded (T169): a tick past its bound stalls the checkpointer, and the
|
|
120
|
+
* vault's process opens another.
|
|
121
|
+
*/
|
|
122
|
+
/** The signer's memory in a file: written whole, synced, renamed over the last, and the directory synced, so a power loss keeps it. */
|
|
123
|
+
export declare function fileMemory(path: string): Memory;
|
|
124
|
+
type RunningCheckpointer = {
|
|
125
|
+
checkpointer: Checkpointer;
|
|
126
|
+
/** For the change path (plan PR 4): seal now, then wait for the witnesses (R51). */
|
|
127
|
+
sealThrough: SealThrough;
|
|
128
|
+
/** The alarms raised since `since` (ms), oldest first, from the file beside the memory. */
|
|
129
|
+
alarms(since?: number): Promise<Alarm[]>;
|
|
130
|
+
/** The pair the signer remembers, from its file: what the vault's verifier holds its walks to (`VaultOptions.heldOutside`). */
|
|
131
|
+
heldOutside(): Promise<PairNotes[]>;
|
|
132
|
+
/** The reads' projection run until it stands at the newest pair (T166): for tests and tools, never on a request's path. */
|
|
133
|
+
projected(): Promise<void>;
|
|
134
|
+
/** Whether it seals (`Vault.sealing`): ticking, its last tick ended well, lately. */
|
|
135
|
+
sealing(): Sealing;
|
|
136
|
+
stop(): Promise<void>;
|
|
137
|
+
};
|
|
138
|
+
/** A connection of the checkpointer's own (T169), which its runner cuts once it stalls: `openDatabase(url, { max })`. */
|
|
139
|
+
type Session = {
|
|
140
|
+
db: Database;
|
|
141
|
+
cut(): Promise<void>;
|
|
142
|
+
};
|
|
143
|
+
/**
|
|
144
|
+
* Opens the checkpointer over `database` (the vault's login) and ticks it
|
|
145
|
+
* every `intervalMs`, a tick after the last one ends, each followed by the
|
|
146
|
+
* log's upkeep (days made ahead, retention past `retainDays`, the bulk
|
|
147
|
+
* cap's rows pruned). Each alarm is appended to `<memory>.alarms`, one JSON
|
|
148
|
+
* line each. Given `connect` instead, over a session of its own, cut once
|
|
149
|
+
* it stalls or stops, so that what it still awaits holds no connection of
|
|
150
|
+
* the vault's (review r1).
|
|
151
|
+
*/
|
|
152
|
+
export declare function runCheckpointer(options: {
|
|
153
|
+
/** The vault's database, or `connect`, a session of its own. */
|
|
154
|
+
database?: Database;
|
|
155
|
+
connect?: () => Promise<Session>;
|
|
156
|
+
seed: Uint8Array;
|
|
157
|
+
/** The memory's file. */
|
|
158
|
+
memory: string;
|
|
159
|
+
witnesses?: readonly Witness[];
|
|
160
|
+
intervalMs?: number;
|
|
161
|
+
tileRange?: number;
|
|
162
|
+
/** Full days of uses kept before today's; null keeps every day (retention.ts). */
|
|
163
|
+
retainDays?: number | null;
|
|
164
|
+
/** Told once its checkpointer stalls (T169), which ticks no more: `keepCheckpointer` opens another. */
|
|
165
|
+
stalled?: (why: string) => void;
|
|
166
|
+
/** `TICK_BOUND_MS`, which bounds the open and the next days too: for the tests. */
|
|
167
|
+
tickBoundMs?: number;
|
|
168
|
+
/** The memory over its file, `fileMemory` unless a test holds its writes. */
|
|
169
|
+
memoryOf?: (path: string) => Memory;
|
|
170
|
+
/** `UPKEEP_BOUND_MS`, for the tests. */
|
|
171
|
+
upkeepBoundMs?: number;
|
|
172
|
+
}): Promise<RunningCheckpointer>;
|
|
173
|
+
type KeptCheckpointer = Pick<RunningCheckpointer, 'sealThrough' | 'heldOutside' | 'alarms' | 'sealing' | 'stop'>;
|
|
174
|
+
/**
|
|
175
|
+
* The checkpointer as the vault's process keeps it: `runCheckpointer`, tried
|
|
176
|
+
* again every `retryMs` while it cannot open (a log it refuses, as after a
|
|
177
|
+
* restore, docs/restore.md; the database out of reach), each try making the
|
|
178
|
+
* next days of uses first, so that uses go on; its failure an alarm, kept
|
|
179
|
+
* once while it stands. Meanwhile a change's seal fails with why, as on
|
|
180
|
+
* Workers, and the pair held outside is read from the file as ever. One
|
|
181
|
+
* that stalls (T169) is stopped, fenced, and another opened a tick later.
|
|
182
|
+
*/
|
|
183
|
+
export declare function keepCheckpointer(options: Parameters<typeof runCheckpointer>[0] & {
|
|
184
|
+
retryMs?: number;
|
|
185
|
+
}): Promise<KeptCheckpointer>;
|
|
186
|
+
//#endregion
|
|
33
187
|
//#region src/node.d.ts
|
|
34
188
|
export type NodeVaultConfig = VaultConfig & {
|
|
35
189
|
/**
|
|
@@ -38,8 +192,29 @@ export type NodeVaultConfig = VaultConfig & {
|
|
|
38
192
|
* development. Or one already open, which the vault leaves open.
|
|
39
193
|
*/
|
|
40
194
|
database: string | Database;
|
|
195
|
+
/**
|
|
196
|
+
* 0.15's uses (docs/design/0.15-plan.md, PR 5): the same database as
|
|
197
|
+
* `coffre_vault_hot`, whose lock and statement timeouts bound a use, or
|
|
198
|
+
* one already open; on SQLite, the same `file:` URL. Required.
|
|
199
|
+
*/
|
|
200
|
+
hotDatabase?: string | Database;
|
|
201
|
+
/**
|
|
202
|
+
* 0.15's checkpointer, which this process runs: `memory`, the file it
|
|
203
|
+
* keeps the newest pair it signed in, where no database writer reaches,
|
|
204
|
+
* such as `/var/lib/coffre/checkpointer-memory`, writable by the vault's
|
|
205
|
+
* user alone (its alarms go beside it, in `<memory>.alarms`). Required,
|
|
206
|
+
* unless the caller seals through a checkpointer of its own
|
|
207
|
+
* (`VaultOptions.sealThrough` and `heldOutside`).
|
|
208
|
+
*/
|
|
209
|
+
checkpointer?: {
|
|
210
|
+
memory: string;
|
|
211
|
+
};
|
|
41
212
|
};
|
|
42
|
-
/**
|
|
213
|
+
/**
|
|
214
|
+
* The vault in this process, and under 0.15's log, the default, its
|
|
215
|
+
* checkpointer, opened before the vault serves, so that no call meets a log
|
|
216
|
+
* with no checkpoint yet. A configuration without what 0.15 needs is refused.
|
|
217
|
+
*/
|
|
43
218
|
export declare function localVault(config: NodeVaultConfig, options?: VaultOptions): Promise<LocalVault>;
|
|
44
219
|
export type VaultServer = {
|
|
45
220
|
socket: string;
|
|
@@ -56,4 +231,4 @@ export declare function serveVault(config: NodeVaultConfig & {
|
|
|
56
231
|
/** The vault that `serveVault` runs, from the server's side of its socket. */
|
|
57
232
|
export declare function connectVault(socket: string): Vault;
|
|
58
233
|
//#endregion
|
|
59
|
-
export { type AwsCredentials, type AwsKmsOptions, type Kek, KekBadClaimError, type KekProvider, KekUnavailableError, type LocalVault, type SecretContext, type Vault, type VaultConfig, type VaultOptions, type WrappedDek, awsKms, checkpointMessage, derivedSigningKey, verifyCheckpoint };
|
|
234
|
+
export { type AwsCredentials, type AwsKmsOptions, type Kek, KekBadClaimError, type KekProvider, KekUnavailableError, type KeptCheckpointer, type LocalVault, type RunningCheckpointer, type SecretContext, type Vault, type VaultConfig, type VaultOptions, type WrappedDek, awsKms, checkpointMessage, derivedSigningKey, verifyCheckpoint };
|