dodo-mcp 1.2.1 → 1.3.1

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 (151) hide show
  1. package/README.md +37 -6
  2. package/dist/cli/dataRecovery.js +38 -0
  3. package/dist/cli/dataRecovery.js.map +1 -0
  4. package/dist/cli/deployment.js +61 -0
  5. package/dist/cli/deployment.js.map +1 -0
  6. package/dist/cli/main.js +36 -1
  7. package/dist/cli/main.js.map +1 -1
  8. package/dist/config/globalConfig.js +3 -5
  9. package/dist/config/globalConfig.js.map +1 -1
  10. package/dist/errors.js +1 -1
  11. package/dist/errors.js.map +1 -1
  12. package/dist/ipc/server.js +2 -0
  13. package/dist/ipc/server.js.map +1 -1
  14. package/dist/ipc/timeouts.js +5 -0
  15. package/dist/ipc/timeouts.js.map +1 -0
  16. package/dist/platform/privateFs.js +32 -3
  17. package/dist/platform/privateFs.js.map +1 -1
  18. package/dist/platform/windowsPrivateAcl.js +90 -0
  19. package/dist/platform/windowsPrivateAcl.js.map +1 -0
  20. package/dist/security/outboundAddress.js +20 -0
  21. package/dist/security/outboundAddress.js.map +1 -0
  22. package/dist/server/aiAdmin.js +21 -24
  23. package/dist/server/aiAdmin.js.map +1 -1
  24. package/dist/server/appServer.js +3 -6
  25. package/dist/server/appServer.js.map +1 -1
  26. package/dist/server/bootstrap.js +14 -0
  27. package/dist/server/bootstrap.js.map +1 -1
  28. package/dist/server/configSession.js +21 -0
  29. package/dist/server/configSession.js.map +1 -0
  30. package/dist/server/configUi/index.html +3 -0
  31. package/dist/server/configUi/ui/dataRecovery.js +90 -0
  32. package/dist/server/configUi/ui/deployment.js +111 -0
  33. package/dist/server/configUi/ui/recovery.js +167 -0
  34. package/dist/server/configUi/workbench.js +23 -7
  35. package/dist/server/installationRuntime.js +3 -1
  36. package/dist/server/installationRuntime.js.map +1 -1
  37. package/dist/server/instructions.js.map +1 -1
  38. package/dist/server/ipcDispatch.js +219 -0
  39. package/dist/server/ipcDispatch.js.map +1 -1
  40. package/dist/server/localConfig.js +34 -11
  41. package/dist/server/localConfig.js.map +1 -1
  42. package/dist/server/remoteConfig.js +23 -13
  43. package/dist/server/remoteConfig.js.map +1 -1
  44. package/dist/server/stdioServer.js +2 -5
  45. package/dist/server/stdioServer.js.map +1 -1
  46. package/dist/services/ai/network.js +1 -18
  47. package/dist/services/ai/network.js.map +1 -1
  48. package/dist/services/ai/subagents.js +5 -2
  49. package/dist/services/ai/subagents.js.map +1 -1
  50. package/dist/services/assistance/verification.js +43 -10
  51. package/dist/services/assistance/verification.js.map +1 -1
  52. package/dist/services/changes/applier.js +472 -297
  53. package/dist/services/changes/applier.js.map +1 -1
  54. package/dist/services/git/gitService.js +150 -34
  55. package/dist/services/git/gitService.js.map +1 -1
  56. package/dist/services/jobs/jobManager.js +59 -2
  57. package/dist/services/jobs/jobManager.js.map +1 -1
  58. package/dist/services/jobs/spool.js +9 -3
  59. package/dist/services/jobs/spool.js.map +1 -1
  60. package/dist/services/multimodal/mediaService.js +6 -6
  61. package/dist/services/multimodal/mediaService.js.map +1 -1
  62. package/dist/services/recovery/configKeys.js +115 -0
  63. package/dist/services/recovery/configKeys.js.map +1 -0
  64. package/dist/services/recovery/configVault.js +361 -0
  65. package/dist/services/recovery/configVault.js.map +1 -0
  66. package/dist/services/recovery/contracts.js +24 -0
  67. package/dist/services/recovery/contracts.js.map +1 -0
  68. package/dist/services/recovery/databaseAwareness.js +179 -0
  69. package/dist/services/recovery/databaseAwareness.js.map +1 -0
  70. package/dist/services/recovery/deploymentArchive.js +129 -0
  71. package/dist/services/recovery/deploymentArchive.js.map +1 -0
  72. package/dist/services/recovery/deploymentContracts.js +70 -0
  73. package/dist/services/recovery/deploymentContracts.js.map +1 -0
  74. package/dist/services/recovery/deploymentHealth.js +143 -0
  75. package/dist/services/recovery/deploymentHealth.js.map +1 -0
  76. package/dist/services/recovery/deploymentMaintenance.js +197 -0
  77. package/dist/services/recovery/deploymentMaintenance.js.map +1 -0
  78. package/dist/services/recovery/deploymentService.js +429 -0
  79. package/dist/services/recovery/deploymentService.js.map +1 -0
  80. package/dist/services/recovery/deploymentSource.js +36 -0
  81. package/dist/services/recovery/deploymentSource.js.map +1 -0
  82. package/dist/services/recovery/dockerDeployment.js +172 -0
  83. package/dist/services/recovery/dockerDeployment.js.map +1 -0
  84. package/dist/services/recovery/drift.js +178 -0
  85. package/dist/services/recovery/drift.js.map +1 -0
  86. package/dist/services/recovery/evidence.js +127 -0
  87. package/dist/services/recovery/evidence.js.map +1 -0
  88. package/dist/services/recovery/gitCopies.js +219 -0
  89. package/dist/services/recovery/gitCopies.js.map +1 -0
  90. package/dist/services/recovery/history.js +423 -0
  91. package/dist/services/recovery/history.js.map +1 -0
  92. package/dist/services/recovery/recoveryService.js +521 -0
  93. package/dist/services/recovery/recoveryService.js.map +1 -0
  94. package/dist/services/recovery/storage.js +344 -0
  95. package/dist/services/recovery/storage.js.map +1 -0
  96. package/dist/services/schedules/scheduleService.js +9 -10
  97. package/dist/services/schedules/scheduleService.js.map +1 -1
  98. package/dist/store/db.js +71 -0
  99. package/dist/store/db.js.map +1 -1
  100. package/dist/tools/catalog.js +4 -0
  101. package/dist/tools/catalog.js.map +1 -1
  102. package/dist/tools/changeTools.js +1 -1
  103. package/dist/tools/changeTools.js.map +1 -1
  104. package/dist/tools/context.js +23 -3
  105. package/dist/tools/context.js.map +1 -1
  106. package/dist/tools/deploymentTools.js +58 -0
  107. package/dist/tools/deploymentTools.js.map +1 -0
  108. package/dist/tools/directTools.js +9 -5
  109. package/dist/tools/directTools.js.map +1 -1
  110. package/dist/tools/gitTools.js +7 -2
  111. package/dist/tools/gitTools.js.map +1 -1
  112. package/dist/tools/jobTools.js +4 -4
  113. package/dist/tools/jobTools.js.map +1 -1
  114. package/dist/tools/projectTools.js +1 -0
  115. package/dist/tools/projectTools.js.map +1 -1
  116. package/dist/tools/recoveryTools.js +79 -0
  117. package/dist/tools/recoveryTools.js.map +1 -0
  118. package/dist/tools/runtimeTools.js +1 -1
  119. package/dist/tools/runtimeTools.js.map +1 -1
  120. package/dist/tools/surface.js +6 -1
  121. package/dist/tools/surface.js.map +1 -1
  122. package/dist/tunnel/credentials.js +1 -1
  123. package/dist/tunnel/credentials.js.map +1 -1
  124. package/docs/ARCHITECTURE.md +92 -2
  125. package/docs/CI.md +118 -0
  126. package/docs/COMPATIBILITY.md +7 -6
  127. package/docs/EVALUATION.md +17 -12
  128. package/docs/MANUAL_ACCEPTANCE.md +72 -2
  129. package/docs/MCP_CONNECTIONS.md +238 -0
  130. package/docs/RECOVERY.md +448 -0
  131. package/docs/RELEASE_1.3.0.md +64 -0
  132. package/docs/RELEASE_1.3.1.md +49 -0
  133. package/docs/RELEASE_NOTES.md +31 -0
  134. package/docs/SECURITY.md +123 -0
  135. package/docs/TEST_REPORT.md +312 -5
  136. package/docs/TUNNEL.md +6 -0
  137. package/docs/WEB_CLIENTS.md +3 -0
  138. package/docs/adr/047-temporary-remote-config.md +11 -0
  139. package/docs/adr/051-source-recovery-foundation.md +45 -0
  140. package/docs/adr/052-reviewed-source-restore.md +50 -0
  141. package/docs/adr/053-content-drift-and-private-git-recovery.md +29 -0
  142. package/docs/adr/054-verified-source-checkpoints.md +58 -0
  143. package/docs/adr/055-reviewed-docker-deployments.md +42 -0
  144. package/docs/adr/056-owner-data-recovery.md +47 -0
  145. package/docs/adr/README.md +7 -0
  146. package/native/private-state-windows.cs +105 -0
  147. package/package.json +8 -1
  148. package/schemas/global-config.schema.json +34 -0
  149. package/schemas/tools.compact.json +175 -15
  150. package/schemas/tools.hybrid.json +350 -16
  151. package/schemas/tools.json +4883 -816
@@ -0,0 +1,172 @@
1
+ import path from 'node:path';
2
+ import { z } from 'zod';
3
+ import { DodoError } from '../../errors.js';
4
+ import { newId } from '../../util/hash.js';
5
+ import { DEPLOYMENT_ARCHIVE_BYTES, verifySourceArchive } from './deploymentArchive.js';
6
+ const ImageDigest = z.string().regex(/^sha256:[a-f0-9]{64}$/);
7
+ const ContainerId = z.string().regex(/^[a-f0-9]{64}$/);
8
+ /** Typed commands only. Never reads repo Compose configuration or falls back outside the owner's sandbox. */
9
+ export class DockerDeploymentAdapter {
10
+ s;
11
+ actor;
12
+ target;
13
+ revalidate;
14
+ recordJob;
15
+ beforeEffect;
16
+ saveProbe;
17
+ constructor(s, actor, target, revalidate, recordJob, beforeEffect, saveProbe) {
18
+ this.s = s;
19
+ this.actor = actor;
20
+ this.target = target;
21
+ this.revalidate = revalidate;
22
+ this.recordJob = recordJob;
23
+ this.beforeEffect = beforeEffect;
24
+ this.saveProbe = saveProbe;
25
+ }
26
+ async command(stage, args, inputBytes, maxBytes = 1024 * 1024) {
27
+ this.revalidate();
28
+ const job = await this.s.jobs.startProtected({ workspaceId: this.s.workspaceId, epoch: this.s.epoch, principal: this.actor,
29
+ kind: 'exec', program: 'docker', args: ['--context', this.target.dockerContext, ...args], cwdRel: '.',
30
+ timeoutMs: this.target.commandTimeoutMs, privateOutput: true, ...(inputBytes ? { inputBytes } : { stdin: false }) }, async () => {
31
+ if (['build', 'compose-up', 'source-probe-create'].includes(stage))
32
+ await this.beforeEffect();
33
+ this.revalidate();
34
+ });
35
+ // State transitions happen in the caller BEFORE the command; an unrecorded delivery is uncertain, never replayed.
36
+ this.recordJob(job.jobId, stage);
37
+ if (!await this.s.jobs.waitForExit(job.jobId, this.target.commandTimeoutMs + 5000))
38
+ throw new DodoError('CONFLICT', 'deployment command outcome is uncertain; inspect before any new action', { detail: { jobId: job.jobId } });
39
+ this.revalidate();
40
+ try {
41
+ return this.s.jobs.binaryOutput(job.jobId, this.s.workspaceId, this.actor, maxBytes);
42
+ }
43
+ catch {
44
+ throw new DodoError('CONFLICT', 'deployment command failed or output is incomplete; private output hidden, not retried', { detail: { jobId: job.jobId } });
45
+ }
46
+ }
47
+ async build(deploymentId, archive) {
48
+ if (!/^deploy_[a-z0-9]{10}$/.test(deploymentId))
49
+ throw new DodoError('INVALID_INPUT', 'invalid deployment ID');
50
+ const tag = `dodo-recovery:${deploymentId}`;
51
+ await this.command('build', ['build', '--quiet', '--network=' + this.target.buildNetwork, '--tag', tag, '--file', this.target.dockerfile, '-'], archive);
52
+ const output = await this.command('image-inspect', ['image', 'inspect', '--format', '{{.Id}}', tag]);
53
+ return ImageDigest.parse(output.toString('utf8').trim());
54
+ }
55
+ async containers() {
56
+ const output = await this.command('service-inspect', ['container', 'ls', '--all', '--no-trunc', '--filter', `label=com.docker.compose.project=${this.target.composeProject}`,
57
+ '--filter', `label=com.docker.compose.service=${this.target.service}`, '--format', '{{.ID}}']);
58
+ const ids = output.toString('utf8').split(/\r?\n/).filter(Boolean);
59
+ if (ids.length > 1)
60
+ throw new DodoError('CONFLICT', 'this adapter requires exactly one container per registered service');
61
+ const result = [];
62
+ for (const id of ids)
63
+ result.push(await this.inspectContainer(ContainerId.parse(id)));
64
+ return result;
65
+ }
66
+ async inspectContainer(id) {
67
+ ContainerId.parse(id);
68
+ const output = await this.command('container-inspect', ['container', 'inspect', '--format', '{{json .}}', id]);
69
+ const data = z.object({ Id: ContainerId, Image: ImageDigest, State: z.object({ Running: z.boolean() }),
70
+ Mounts: z.array(z.object({ Type: z.string().max(64), Destination: z.string().max(4096) })).max(100) }).parse(JSON.parse(output.toString('utf8')));
71
+ if (data.Id !== id)
72
+ throw new DodoError('CONFLICT', 'container identity differs from inspected ID');
73
+ return { id: data.Id, image: data.Image, running: data.State.Running, mounts: data.Mounts.map(m => ({ type: m.Type, destination: m.Destination })) };
74
+ }
75
+ compose(imageDigest) {
76
+ ImageDigest.parse(imageDigest);
77
+ const d = this.target;
78
+ return Buffer.from(JSON.stringify({ services: { [d.service]: { image: imageDigest, pull_policy: 'never',
79
+ ports: d.ports.map(p => ({ host_ip: p.host, published: String(p.published), target: p.target, protocol: 'tcp' })),
80
+ volumes: d.volumes.map(v => ({ type: 'volume', source: v.name, target: v.target, volume: { nocopy: true } })) } },
81
+ volumes: Object.fromEntries(d.volumes.map(v => [v.name, { external: true, name: v.name }])) }));
82
+ }
83
+ async deploy(imageDigest) {
84
+ await this.command('compose-up', ['compose', '--project-name', this.target.composeProject, '--file', '-', 'up', '--detach', '--no-build', '--no-deps', '--pull', 'never', this.target.service], this.compose(imageDigest));
85
+ }
86
+ async sourceFromContainer(id, imageDigest, expected, assertPath) {
87
+ if (!this.target.sourceMapping)
88
+ throw new DodoError('NOT_SUPPORTED', 'this target has no declared source mapping; image labels do not prove source availability');
89
+ const before = await this.inspectContainer(id), root = this.target.sourceMapping.containerRoot;
90
+ if (before.image !== ImageDigest.parse(imageDigest))
91
+ throw new DodoError('CONFLICT', 'source container image differs from recorded image');
92
+ if (before.mounts.some(m => m.destination === root || m.destination === '/' || root.startsWith(m.destination + '/') || m.destination.startsWith(root + '/')))
93
+ throw new DodoError('PATH_DENIED', 'container source mapping overlaps mounted data; no copy was attempted');
94
+ // No -L, docker exec, export of /, pause, stop or restart.
95
+ const archive = await this.command('container-source-read', ['container', 'cp', `${id}:${root}`, '-'], undefined, Math.min(this.s.limits.jobLogBytesPerJob, DEPLOYMENT_ARCHIVE_BYTES));
96
+ const result = await verifySourceArchive(archive, expected, assertPath, path.posix.basename(root));
97
+ const after = await this.inspectContainer(id);
98
+ if (JSON.stringify(before) !== JSON.stringify(after))
99
+ throw new DodoError('CONFLICT', 'container identity or mount state changed while inspecting source');
100
+ return result;
101
+ }
102
+ /** Stopped disposable probe only; refuse declared volumes so image inspection cannot create data volumes. */
103
+ async verifyImageSource(imageDigest, expected, assertPath) {
104
+ ImageDigest.parse(imageDigest);
105
+ const volumeOutput = await this.command('image-volumes', ['image', 'inspect', '--format', '{{json .Config.Volumes}}', imageDigest]);
106
+ const volumes = JSON.parse(volumeOutput.toString('utf8'));
107
+ if (volumes !== null && (typeof volumes !== 'object' || Array.isArray(volumes) || Object.keys(volumes).length > 0))
108
+ throw new DodoError('NOT_SUPPORTED', 'image declares data volumes; verify the approved running service mapping instead');
109
+ const probe = { name: newId('dodo-source-probe'), claim: newId('probeclaim'), image: imageDigest, removed: false };
110
+ this.saveProbe(probe); // Durable intended identity BEFORE daemon delivery.
111
+ const id = ContainerId.parse((await this.command('source-probe-create', ['container', 'create', '--network', 'none', '--name', probe.name,
112
+ '--label', `dodo.recovery.probe=${probe.claim}`, '--entrypoint', '/dodo-never-executed', imageDigest])).toString('utf8').trim());
113
+ probe.id = id;
114
+ this.saveProbe(probe);
115
+ try {
116
+ return await this.sourceFromContainer(id, imageDigest, expected, assertPath);
117
+ }
118
+ finally {
119
+ await this.removeProbe(probe);
120
+ }
121
+ }
122
+ async probeObservation(probe) {
123
+ if (!/^dodo-source-probe_[a-z0-9]{10}$/.test(probe.name) || !/^probeclaim_[a-z0-9]{10}$/.test(probe.claim))
124
+ throw new DodoError('RECOVERY_REQUIRED', 'invalid recorded probe identity');
125
+ const output = await this.command('probe-find', ['container', 'ls', '--all', '--no-trunc', '--filter', `name=^/${probe.name}$`, '--format', '{{.ID}}']);
126
+ const ids = output.toString('utf8').split(/\r?\n/).filter(Boolean);
127
+ if (!ids.length)
128
+ return { present: false };
129
+ if (ids.length !== 1 || (probe.id && ids[0] !== probe.id))
130
+ throw new DodoError('CONFLICT', 'recorded source probe was replaced');
131
+ const id = ContainerId.parse(ids[0]);
132
+ const result = await this.command('probe-identity', ['container', 'inspect', '--format', '{{json .}}', id]);
133
+ const data = z.object({ Name: z.string(), Config: z.object({ Labels: z.record(z.string(), z.string()) }) }).parse(JSON.parse(result.toString('utf8')));
134
+ const container = await this.inspectContainer(id);
135
+ if (data.Name !== '/' + probe.name || data.Config.Labels['dodo.recovery.probe'] !== probe.claim || container.image !== probe.image || container.running || container.mounts.length)
136
+ throw new DodoError('CONFLICT', 'probe identity, image, mounts or stopped state changed; no cleanup');
137
+ return { present: true, id, image: container.image };
138
+ }
139
+ async removeProbe(probe) {
140
+ const observed = await this.probeObservation(probe);
141
+ if (observed.present)
142
+ await this.command('source-probe-remove', ['container', 'rm', observed.id]);
143
+ this.saveProbe({ ...probe, removed: true });
144
+ }
145
+ async imageInventory(image) {
146
+ ImageDigest.parse(image);
147
+ const output = await this.command('image-inventory', ['image', 'ls', '--no-trunc', '--quiet']);
148
+ const all = output.toString('utf8').split(/\r?\n/).filter(Boolean);
149
+ if (all.length > 10000)
150
+ throw new DodoError('RESOURCE_LIMIT', 'Docker image inventory exceeds the bounded inspection limit');
151
+ if (!all.includes(image))
152
+ return { present: false, tags: [], used: false };
153
+ const raw = await this.command('image-tags', ['image', 'inspect', '--format', '{{json .RepoTags}}', image]);
154
+ const tags = z.array(z.string().max(512)).max(1000).nullable().parse(JSON.parse(raw.toString('utf8'))) ?? [];
155
+ const usage = await this.command('image-users', ['container', 'ls', '--all', '--no-trunc', '--filter', `ancestor=${image}`, '--format', '{{.ID}}']);
156
+ return { present: true, tags: tags.sort(), used: usage.toString('utf8').trim().length > 0 };
157
+ }
158
+ async removeImage(image, expectedTags) {
159
+ const live = await this.imageInventory(image);
160
+ if (!live.present)
161
+ throw new DodoError('CONFLICT', 'image disappeared after review; inspect again');
162
+ if (live.used || JSON.stringify(live.tags) !== JSON.stringify([...expectedTags].sort()))
163
+ throw new DodoError('CONFLICT', 'image references changed; no removal');
164
+ // Only exact private managed tags (or an untagged ID), never force/prune.
165
+ if (expectedTags.some(t => !/^dodo-recovery:deploy_[a-z0-9]{10}$/.test(t)))
166
+ throw new DodoError('PATH_DENIED', 'refusing non-DODO image tags');
167
+ await this.command('image-remove', ['image', 'rm', ...(expectedTags.length ? expectedTags : [ImageDigest.parse(image)])]);
168
+ if ((await this.imageInventory(image)).present)
169
+ throw new DodoError('CONFLICT', 'image remains after tag removal; inspect outcome, do not repeat');
170
+ }
171
+ }
172
+ //# sourceMappingURL=dockerDeployment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dockerDeployment.js","sourceRoot":"","sources":["../../../src/services/recovery/dockerDeployment.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,178 @@
1
+ import fs from 'node:fs';
2
+ import { DodoError } from '../../errors.js';
3
+ import { digestOf } from '../../util/hash.js';
4
+ import { rootIdentity } from './storage.js';
5
+ const absent = (path) => ({ path, kind: 'absent', hash: null, mode: null, bytes: 0 });
6
+ const comparable = (e) => [e.kind, e.hash, e.mode, e.identity ?? null];
7
+ /** Expected bytes advance only from a committed journal or explicit owner review.
8
+ * Capturing an emergency/owner snapshot never silently adopts external changes. */
9
+ export class RecoveryDrift {
10
+ s;
11
+ recovery;
12
+ observation;
13
+ lastError = null;
14
+ constructor(s, recovery) {
15
+ this.s = s;
16
+ this.recovery = recovery;
17
+ }
18
+ load() {
19
+ const row = this.s.store.db.prepare('SELECT payload FROM recovery_drift WHERE workspace_id=?').get(this.s.workspaceId);
20
+ if (!row)
21
+ return undefined;
22
+ const state = JSON.parse(row.payload);
23
+ if (state.rootIdentity !== rootIdentity(this.s.wfs.root))
24
+ throw new DodoError('PATH_DENIED', 'expected source belongs to a different root identity');
25
+ return state;
26
+ }
27
+ initialize(m) {
28
+ if (this.load())
29
+ return;
30
+ this.save({ rootIdentity: m.rootIdentity, entries: m.entries, revision: 0 }, m.id);
31
+ }
32
+ save(state, baseline) {
33
+ if (baseline)
34
+ this.s.store.db.prepare('INSERT INTO recovery_drift VALUES (?,?,?) ON CONFLICT(workspace_id) DO UPDATE SET payload=excluded.payload,baseline_id=excluded.baseline_id').run(this.s.workspaceId, JSON.stringify(state), baseline);
35
+ else
36
+ this.s.store.db.prepare('UPDATE recovery_drift SET payload=? WHERE workspace_id=?').run(JSON.stringify(state), this.s.workspaceId);
37
+ }
38
+ trackedPaths() { return this.load()?.entries.filter(e => e.kind !== 'absent').map(e => e.path) ?? []; }
39
+ status(limit = 50, cursor = 0) {
40
+ return { state: this.lastError ? 'unavailable' : !this.load() ? 'pending' : !this.observation ? 'not_scanned' : this.observation.changes.length ? 'external_changes' : 'unchanged',
41
+ attribution: 'unknown', checkedAt: this.observation?.checkedAt ?? null, digest: this.observation?.digest ?? null,
42
+ changedCount: this.observation?.changes.length ?? 0, critical: this.observation?.critical ?? false, emergencyCheckpointId: this.observation?.snapshotId ?? null,
43
+ changes: (this.observation?.changes ?? []).filter(c => { try {
44
+ this.recovery.assertSourcePath(c.path);
45
+ return true;
46
+ }
47
+ catch {
48
+ return false;
49
+ } }).slice(cursor, cursor + limit),
50
+ nextCursor: cursor + limit < (this.observation?.changes.length ?? 0) ? cursor + limit : null, truncated: cursor + limit < (this.observation?.changes.length ?? 0), errorCode: this.lastError };
51
+ }
52
+ compare(expected, current) {
53
+ const before = new Map(expected.map(e => [e.path, e])), after = new Map(current.map(e => [e.path, e]));
54
+ const changes = [];
55
+ for (const path of [...new Set([...before.keys(), ...after.keys()])].sort()) {
56
+ // A newly excluded credential/data path must not leak through old metadata.
57
+ try {
58
+ this.recovery.assertSourcePath(path);
59
+ }
60
+ catch {
61
+ continue;
62
+ }
63
+ const a = before.get(path) ?? absent(path), b = after.get(path) ?? absent(path);
64
+ if (digestOf(comparable(a)) !== digestOf(comparable(b)))
65
+ changes.push({ path, change: b.kind === 'absent' ? 'deleted' : a.kind === 'absent' ? 'added' : 'modified', beforeHash: a.hash, observedHash: b.hash });
66
+ }
67
+ return changes;
68
+ }
69
+ async guard(targets) {
70
+ if (!this.load())
71
+ return;
72
+ if (!targets) {
73
+ const status = await this.scan();
74
+ if (status.critical)
75
+ throw new DodoError('CONFLICT', 'significant external source drift requires owner review before commands', { detail: { changedCount: status.changedCount, observationDigest: status.digest }, recovery: 'compare and acknowledge the exact observation in Recovery, or preview a restore' });
76
+ return;
77
+ }
78
+ const expected = this.load();
79
+ const current = await this.recovery.currentEntries(targets);
80
+ const relevant = expected.entries.filter(e => targets.some(t => e.path === t || e.path.startsWith(t + '/')));
81
+ // Ordinary ignore rules may omit the first before-image; named targets are
82
+ // still captured. Once journaled, they stay tracked regardless of ignores.
83
+ const known = new Set(expected.entries.map(e => e.path));
84
+ const compared = current.filter(e => known.has(e.path) || !this.s.wfs.ignores.isOrdinarilyIgnored(e.path, e.kind === 'directory'));
85
+ const changes = this.compare(relevant, compared);
86
+ if (changes.length) {
87
+ await this.scan();
88
+ throw new DodoError('FILE_CHANGED', 'mutation target differs from recorded source; owner review is required', { detail: { paths: changes.slice(0, 20).map(c => c.path) }, recovery: 'compare external changes in Recovery; acknowledge only the reviewed state or preview a restore' });
89
+ }
90
+ }
91
+ async scan() {
92
+ this.recovery.assertProject();
93
+ const expected = this.load();
94
+ if (!expected)
95
+ return this.status();
96
+ try {
97
+ const current = await this.recovery.currentEntries(undefined, this.trackedPaths());
98
+ const changes = this.compare(expected.entries, current), policy = this.recovery.policy();
99
+ const fileChanges = changes.filter(c => c.beforeHash !== null || c.observedHash !== null);
100
+ const denominator = Math.max(1, expected.entries.filter(e => e.kind === 'file').length);
101
+ const critical = (fileChanges.length >= policy.massFiles && 100 * fileChanges.length / denominator > policy.massPercent) || fileChanges.filter(c => c.change === 'deleted').length >= policy.deletedFiles;
102
+ const digest = digestOf({ revision: expected.revision, current });
103
+ let snapshotId = null;
104
+ if (changes.length) {
105
+ if (this.observation?.digest === digest && this.observation.snapshotId)
106
+ snapshotId = this.observation.snapshotId;
107
+ else {
108
+ snapshotId = await this.recovery.captureObserved();
109
+ const m = await this.recovery.storage.readVerified(snapshotId, this.s.workspaceId);
110
+ // The emergency capture can contain additional ordinarily ignored tracked
111
+ // targets. Use the same source+tracked inventory for both observations.
112
+ const after = await this.recovery.currentEntries(undefined, this.trackedPaths());
113
+ if (digestOf(after) !== digestOf(current))
114
+ throw new DodoError('FILE_CHANGED', 'source changed while recording external drift');
115
+ if (m.rootIdentity !== expected.rootIdentity)
116
+ throw new DodoError('PATH_DENIED', 'source root changed');
117
+ }
118
+ }
119
+ this.observation = { digest, checkedAt: Date.now(), changes, critical, snapshotId };
120
+ this.lastError = null;
121
+ return this.status();
122
+ }
123
+ catch (e) {
124
+ this.lastError = e instanceof DodoError ? e.code : 'BACKUP_IO_ERROR';
125
+ throw e;
126
+ }
127
+ }
128
+ async acknowledge(digest, revalidate) {
129
+ const observed = await this.scan();
130
+ if (observed.digest !== digest)
131
+ throw new DodoError('FILE_CHANGED', 'source changed since review; scan and compare again');
132
+ revalidate();
133
+ const id = await this.recovery.captureObserved();
134
+ const m = await this.recovery.storage.readVerified(id, this.s.workspaceId);
135
+ const current = await this.recovery.currentEntries(undefined, this.trackedPaths()), state = this.load();
136
+ if (digestOf({ revision: state.revision, current }) !== digest)
137
+ throw new DodoError('FILE_CHANGED', 'source changed during acknowledgement');
138
+ revalidate();
139
+ this.s.store.db.transaction(() => {
140
+ this.save({ rootIdentity: state.rootIdentity, entries: current, revision: state.revision + 1 }, m.id);
141
+ this.s.store.audit({ principal: 'local-config-owner', workspaceId: this.s.workspaceId, tool: 'recovery.drift.acknowledge', inputDigest: digest, result: 'acknowledged_observed_not_verified' });
142
+ })();
143
+ this.observation = undefined;
144
+ return this.scan();
145
+ }
146
+ /** Called inside the SAME transaction as journal commit, after byte verification.
147
+ * No asynchronous reread can accidentally adopt another writer's contents. */
148
+ committed(files) {
149
+ const state = this.load();
150
+ if (!state)
151
+ return;
152
+ const entries = new Map(state.entries.map(e => [e.path, e]));
153
+ const set = (p, kind, hash, bytes) => {
154
+ const st = kind === 'absent' ? undefined : fs.lstatSync(this.s.wfs.resolve(p).abs);
155
+ entries.set(p, { path: p, kind, hash: hash?.replace(/^sha256:/, '') ?? null, bytes, mode: st ? st.mode & 0o777 : null, ...(kind === 'directory' ? { identity: rootIdentity(this.s.wfs.resolve(p).abs) } : {}) });
156
+ };
157
+ for (const f of files) {
158
+ for (const p of f.createParents ?? [])
159
+ if (!entries.has(p))
160
+ set(p, 'directory', null, 0);
161
+ if (f.action === 'move') {
162
+ set(f.path, 'absent', null, 0);
163
+ set(f.destPath, 'file', f.afterHash, f.bytesAfter);
164
+ }
165
+ else if (f.action === 'delete' || f.action === 'rmdir')
166
+ set(f.path, 'absent', null, 0);
167
+ else if (f.action === 'mkdir')
168
+ set(f.path, 'directory', null, 0);
169
+ else
170
+ set(f.path, 'file', f.afterHash, f.bytesAfter);
171
+ }
172
+ state.entries = [...entries.values()].sort((a, b) => a.path.localeCompare(b.path));
173
+ state.revision++;
174
+ this.save(state);
175
+ this.observation = undefined;
176
+ }
177
+ }
178
+ //# sourceMappingURL=drift.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift.js","sourceRoot":"","sources":["../../../src/services/recovery/drift.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,127 @@
1
+ import { z } from 'zod';
2
+ import { readVerificationEvidence } from '../assistance/verification.js';
3
+ import { DodoError } from '../../errors.js';
4
+ import { digestOf } from '../../util/hash.js';
5
+ export const PointerName = z.string().trim().min(1).max(64).regex(/^[\p{L}\p{N}][\p{L}\p{N}\p{M} ._-]*$/u)
6
+ .refine(n => !/^production(?:[ _.-]|$)|^last[ _.-]verified$/i.test(n), 'reserved recovery name');
7
+ // Directory inode is not source content; modes and every included file hash ARE.
8
+ const sourceDigest = (entries) => digestOf(entries.map(({ path, kind, hash, bytes, mode }) => ({ path, kind, hash, bytes, mode })));
9
+ /** Evidence and owner labels never grant execution or restore authority. */
10
+ export class RecoveryEvidence {
11
+ s;
12
+ r;
13
+ constructor(s, r) {
14
+ this.s = s;
15
+ this.r = r;
16
+ }
17
+ get db() { return this.s.store.db; }
18
+ async bind(id, actor, snapshotId) {
19
+ const m = await this.r.history.manifest(snapshotId, { id: actor });
20
+ if (m.scope !== 'source' || sourceDigest(m.entries) !== sourceDigest(await this.r.currentEntries()))
21
+ throw new DodoError('FILE_CHANGED', 'source changed before verification launch');
22
+ this.db.prepare('INSERT INTO recovery_verifications (id,workspace_id,actor,snapshot_id,manifest_digest,created_at) VALUES (?,?,?,?,?,?)')
23
+ .run(id, this.s.workspaceId, actor, m.id, digestOf(m), Date.now());
24
+ }
25
+ binding(id, a) {
26
+ this.r.assertProject();
27
+ const b = this.db.prepare('SELECT * FROM recovery_verifications WHERE id=? AND workspace_id=?').get(id, this.s.workspaceId);
28
+ if (!b || (!a.owner && b.actor !== a.id))
29
+ throw new DodoError('NOT_FOUND', 'verification unavailable for this caller/project');
30
+ return b;
31
+ }
32
+ async inspect(id, a) {
33
+ const b = this.binding(id, a);
34
+ let state = 'INCONCLUSIVE', reason = 'evidence_unavailable';
35
+ let evidence = null;
36
+ let sourceMatches = false;
37
+ try {
38
+ evidence = readVerificationEvidence(this.s, id, b.actor);
39
+ const m = await this.r.history.manifest(b.snapshot_id, a);
40
+ sourceMatches = digestOf(m) === b.manifest_digest && m.policyDigest === digestOf(this.r.policy()) && sourceDigest(m.entries) === sourceDigest(await this.r.currentEntries());
41
+ // Re-read live jobs/recipe/source AFTER the asynchronous manifest check.
42
+ evidence = readVerificationEvidence(this.s, id, b.actor);
43
+ if (evidence.status === 'failed') {
44
+ state = 'FAILED';
45
+ reason = 'required_check_failed';
46
+ }
47
+ else if (b.stale || !sourceMatches || evidence.status === 'stale') {
48
+ state = 'STALE';
49
+ reason = 'source_recipe_or_runtime_changed';
50
+ }
51
+ else if (evidence.status === 'passed') {
52
+ state = 'VERIFIED';
53
+ reason = 'selected_required_checks_passed';
54
+ }
55
+ else
56
+ reason = evidence.status === 'running' ? 'jobs_running' : 'missing_or_incomplete_evidence';
57
+ }
58
+ catch (e) {
59
+ reason = e instanceof DodoError ? e.code : 'evidence_unavailable';
60
+ }
61
+ if (state === 'VERIFIED' && this.binding(id, a).stale) {
62
+ state = 'STALE';
63
+ reason = 'previously_observed_drift';
64
+ }
65
+ const result = { verificationId: b.id, checkpointId: b.snapshot_id, manifestHash: b.manifest_digest, state, reason, sourceMatches,
66
+ checkedAt: Date.now(), createdAt: b.created_at, evidence, scope: 'included_source_and_selected_checks', production: this.r.deployments.summary().state, database: this.r.databases.summary().state };
67
+ // Sanitized evidence only: no stdout/stderr, arbitrary messages or environment values.
68
+ this.db.prepare('UPDATE recovery_verifications SET result_json=?,stale=MAX(stale,?),verified_at=COALESCE(verified_at,?) WHERE id=? AND workspace_id=?').run(JSON.stringify(result), Number(state === 'STALE'), state === 'VERIFIED' ? result.checkedAt : null, id, this.s.workspaceId);
69
+ return result;
70
+ }
71
+ list(a, cursor = 0, limit = 10) {
72
+ this.r.assertProject();
73
+ const rows = this.db.prepare(`SELECT * FROM recovery_verifications WHERE workspace_id=? ${a.owner ? '' : 'AND actor=?'} ORDER BY created_at DESC,id LIMIT ? OFFSET ?`)
74
+ .all(this.s.workspaceId, ...(a.owner ? [] : [a.id]), limit + 1, cursor);
75
+ return { items: rows.slice(0, limit).map(b => ({ verificationId: b.id, checkpointId: b.snapshot_id, createdAt: b.created_at,
76
+ lastObservation: b.result_json ? JSON.parse(b.result_json) : null, freshness: 'refresh_required' })), nextCursor: rows.length > limit ? cursor + limit : null };
77
+ }
78
+ summary() {
79
+ const row = this.db.prepare('SELECT MAX(verified_at) AS lastVerifiedAt FROM recovery_verifications WHERE workspace_id=?').get(this.s.workspaceId);
80
+ // Public overview discloses no cross-caller IDs, titles, paths or test details.
81
+ return { lastVerifiedAt: row.lastVerifiedAt, freshness: 'historical_observation_only', production: this.r.deployments.summary().state, database: this.r.databases.summary().state };
82
+ }
83
+ pointerEvents(cursor = 0, limit = 20) {
84
+ this.r.assertProject();
85
+ const rows = this.db.prepare('SELECT seq,name,previous_id AS previousId,snapshot_id AS snapshotId,revision,created_at AS createdAt FROM recovery_pointer_events WHERE workspace_id=? ORDER BY seq DESC LIMIT ? OFFSET ?').all(this.s.workspaceId, limit + 1, cursor);
86
+ return { items: rows.slice(0, limit), nextCursor: rows.length > limit ? cursor + limit : null };
87
+ }
88
+ pointers() {
89
+ this.r.assertProject();
90
+ return this.db.prepare('SELECT name,snapshot_id AS snapshotId,revision,updated_at AS updatedAt FROM recovery_pointers WHERE workspace_id=? ORDER BY name').all(this.s.workspaceId);
91
+ }
92
+ async mark(name, snapshotId, expectedRevision, revalidate) {
93
+ name = PointerName.parse(name);
94
+ return this.s.mutations.run(async () => {
95
+ this.r.assertProject();
96
+ if (snapshotId)
97
+ await this.r.history.manifest(snapshotId, { id: 'local-config-owner', owner: true });
98
+ revalidate();
99
+ return this.db.transaction(() => {
100
+ const old = this.pointers().find(p => p.name === name);
101
+ if ((old?.revision ?? 0) !== expectedRevision)
102
+ throw new DodoError('CONFLICT', 'checkpoint name changed since review; refresh before saving');
103
+ if (!old && this.pointers().length >= 100)
104
+ throw new DodoError('RESOURCE_LIMIT', 'named checkpoint limit reached');
105
+ const revision = expectedRevision + 1, now = Date.now();
106
+ this.db.prepare('INSERT INTO recovery_pointers VALUES (?,?,?,?,?) ON CONFLICT(workspace_id,name) DO UPDATE SET snapshot_id=excluded.snapshot_id,revision=excluded.revision,updated_at=excluded.updated_at').run(this.s.workspaceId, name, snapshotId, revision, now);
107
+ this.db.prepare('INSERT INTO recovery_pointer_events (workspace_id,name,previous_id,snapshot_id,revision,created_at) VALUES (?,?,?,?,?,?)').run(this.s.workspaceId, name, old?.snapshotId ?? null, snapshotId, revision, now);
108
+ this.s.store.audit({ principal: 'local-config-owner', workspaceId: this.s.workspaceId, tool: 'recovery.mark', refId: snapshotId ?? 'cleared', inputDigest: digestOf({ name, previous: old?.snapshotId ?? null, snapshotId, revision }), result: 'owner_marked' });
109
+ return { name, snapshotId, revision, updatedAt: now, label: snapshotId ? 'OWNER_MARKED_STABLE' : 'cleared', tested: false };
110
+ }).immediate();
111
+ });
112
+ }
113
+ async pin(snapshotId, pinned, expectedPinned, revalidate) {
114
+ return this.s.mutations.run(async () => {
115
+ await this.r.history.manifest(snapshotId, { id: 'local-config-owner', owner: true });
116
+ revalidate();
117
+ return this.db.transaction(() => {
118
+ const changed = this.db.prepare('UPDATE recovery_snapshots SET pinned=? WHERE id=? AND workspace_id=? AND pinned=?').run(Number(pinned), snapshotId, this.s.workspaceId, Number(expectedPinned));
119
+ if (changed.changes !== 1)
120
+ throw new DodoError('CONFLICT', 'pin changed since review; refresh first');
121
+ this.s.store.audit({ principal: 'local-config-owner', workspaceId: this.s.workspaceId, tool: 'recovery.pin', refId: snapshotId, result: pinned ? 'pinned' : 'unpinned' });
122
+ return { checkpointId: snapshotId, pinned };
123
+ }).immediate();
124
+ });
125
+ }
126
+ }
127
+ //# sourceMappingURL=evidence.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"evidence.js","sourceRoot":"","sources":["../../../src/services/recovery/evidence.ts"],"names":[],"mappings":"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"}