@pleri/olam-cli 0.1.127 → 0.1.131
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/bootstrap.d.ts +8 -0
- package/dist/commands/bootstrap.d.ts.map +1 -1
- package/dist/commands/bootstrap.js +14 -0
- package/dist/commands/bootstrap.js.map +1 -1
- package/dist/commands/kg-build.d.ts.map +1 -1
- package/dist/commands/kg-build.js +10 -0
- package/dist/commands/kg-build.js.map +1 -1
- package/dist/commands/kg-classify.d.ts +10 -0
- package/dist/commands/kg-classify.d.ts.map +1 -0
- package/dist/commands/kg-classify.js +51 -0
- package/dist/commands/kg-classify.js.map +1 -0
- package/dist/commands/kg-doctor.d.ts +15 -0
- package/dist/commands/kg-doctor.d.ts.map +1 -0
- package/dist/commands/kg-doctor.js +182 -0
- package/dist/commands/kg-doctor.js.map +1 -0
- package/dist/commands/kg-install-hook.d.ts +14 -0
- package/dist/commands/kg-install-hook.d.ts.map +1 -0
- package/dist/commands/kg-install-hook.js +92 -0
- package/dist/commands/kg-install-hook.js.map +1 -0
- package/dist/commands/kg-service-container.d.ts +68 -0
- package/dist/commands/kg-service-container.d.ts.map +1 -0
- package/dist/commands/kg-service-container.js +181 -0
- package/dist/commands/kg-service-container.js.map +1 -0
- package/dist/commands/kg-uninstall-hook.d.ts +12 -0
- package/dist/commands/kg-uninstall-hook.d.ts.map +1 -0
- package/dist/commands/kg-uninstall-hook.js +121 -0
- package/dist/commands/kg-uninstall-hook.js.map +1 -0
- package/dist/commands/memory/index.d.ts.map +1 -1
- package/dist/commands/memory/index.js +2 -0
- package/dist/commands/memory/index.js.map +1 -1
- package/dist/commands/memory/mode.d.ts +47 -0
- package/dist/commands/memory/mode.d.ts.map +1 -0
- package/dist/commands/memory/mode.js +181 -0
- package/dist/commands/memory/mode.js.map +1 -0
- package/dist/commands/memory/start.d.ts.map +1 -1
- package/dist/commands/memory/start.js +50 -5
- package/dist/commands/memory/start.js.map +1 -1
- package/dist/commands/rekey.d.ts +84 -0
- package/dist/commands/rekey.d.ts.map +1 -0
- package/dist/commands/rekey.js +209 -0
- package/dist/commands/rekey.js.map +1 -0
- package/dist/commands/services.d.ts +5 -5
- package/dist/commands/services.d.ts.map +1 -1
- package/dist/commands/services.js +70 -6
- package/dist/commands/services.js.map +1 -1
- package/dist/image-digests.json +3 -3
- package/dist/index.js +2116 -672
- package/dist/index.js.map +1 -1
- package/dist/lib/memory-secret.d.ts +22 -0
- package/dist/lib/memory-secret.d.ts.map +1 -1
- package/dist/lib/memory-secret.js +38 -0
- package/dist/lib/memory-secret.js.map +1 -1
- package/dist/mcp-server.js +18499 -17383
- package/package.json +1 -1
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* olam memory mode <local|cloud> — flip the workspace's agent-memory
|
|
3
|
+
* source between the host-process (Phase A) and a remote agentmemory
|
|
4
|
+
* deployment (Phase C).
|
|
5
|
+
*
|
|
6
|
+
* Reads + rewrites `.olam/config.yaml`'s `memory:` block via the schema
|
|
7
|
+
* defined in C1. Idempotent: re-running the same mode is a noop.
|
|
8
|
+
*
|
|
9
|
+
* mode local → memory.mode = "local"; ensures host-process running
|
|
10
|
+
* mode cloud [--url ...] → prompts for URL + bearer secret, writes both to
|
|
11
|
+
* config + ~/.olam/cloud-memory-secret, stops the
|
|
12
|
+
* local host-process. Operator must re-create
|
|
13
|
+
* active worlds for the new env to take effect.
|
|
14
|
+
*
|
|
15
|
+
* Plan reference: docs/plans/olam-agent-memory-distributed/phase-c-tasks.md C3
|
|
16
|
+
*/
|
|
17
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
18
|
+
import { join } from 'node:path';
|
|
19
|
+
import * as readline from 'node:readline/promises';
|
|
20
|
+
import { parse as parseYaml, stringify as stringifyYaml } from 'yaml';
|
|
21
|
+
import { MemorySchema } from '@olam/core/src/config/schema.js';
|
|
22
|
+
import { printError, printSuccess, printInfo, printHeader, printWarning } from '../../output.js';
|
|
23
|
+
import { writeCloudMemorySecret, CLOUD_MEMORY_SECRET_PATH } from '../../lib/memory-secret.js';
|
|
24
|
+
import { runMemoryStart } from './start.js';
|
|
25
|
+
import { runMemoryStop } from './stop.js';
|
|
26
|
+
const CONFIG_REL = '.olam/config.yaml';
|
|
27
|
+
function locateConfig(cwd) {
|
|
28
|
+
const absPath = join(cwd, CONFIG_REL);
|
|
29
|
+
if (!existsSync(absPath)) {
|
|
30
|
+
throw new Error(`No ${CONFIG_REL} at ${cwd}. Run \`olam init\` in your workspace root first.`);
|
|
31
|
+
}
|
|
32
|
+
return { absPath };
|
|
33
|
+
}
|
|
34
|
+
function readConfigYaml(absPath) {
|
|
35
|
+
const raw = readFileSync(absPath, 'utf-8');
|
|
36
|
+
const parsed = (parseYaml(raw) ?? {});
|
|
37
|
+
if (typeof parsed !== 'object' || parsed === null) {
|
|
38
|
+
throw new Error(`${absPath} is not a YAML object`);
|
|
39
|
+
}
|
|
40
|
+
return { raw, parsed };
|
|
41
|
+
}
|
|
42
|
+
function writeConfigYaml(absPath, parsed) {
|
|
43
|
+
// `yaml`'s default stringify is reasonable for round-trip; we don't
|
|
44
|
+
// preserve every comment edge case but the major shape + keys survive.
|
|
45
|
+
const out = stringifyYaml(parsed, { aliasDuplicateObjects: false });
|
|
46
|
+
writeFileSync(absPath, out, 'utf-8');
|
|
47
|
+
}
|
|
48
|
+
async function defaultPromptText(question) {
|
|
49
|
+
const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
50
|
+
try {
|
|
51
|
+
return (await rl.question(question)).trim();
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
rl.close();
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Same shape as defaultPromptText for now — terminals don't natively mask
|
|
59
|
+
* input via readline. Operators wanting a masked prompt can pipe via stdin
|
|
60
|
+
* or pass `--secret` (NOT recommended; argv leaks via ps). The choice is
|
|
61
|
+
* deferred to OQ4: "no Keychain integration in v1; document the limitation"
|
|
62
|
+
* (design rubric S5).
|
|
63
|
+
*/
|
|
64
|
+
async function defaultPromptSecret(question) {
|
|
65
|
+
return defaultPromptText(`${question} (will appear on-screen; use stdin to pipe) `);
|
|
66
|
+
}
|
|
67
|
+
export async function runMemoryModeLocal(deps = {}) {
|
|
68
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
69
|
+
const cfg = locateConfig(cwd);
|
|
70
|
+
const { parsed } = readConfigYaml(cfg.absPath);
|
|
71
|
+
const currentMode = parsed.memory?.mode ?? 'local';
|
|
72
|
+
if (currentMode === 'local') {
|
|
73
|
+
printInfo('memory.mode', 'already local — ensuring host-process is up');
|
|
74
|
+
const rc = (deps.runStart ?? runMemoryStart)();
|
|
75
|
+
await rc;
|
|
76
|
+
return { outcome: 'noop', mode: 'local' };
|
|
77
|
+
}
|
|
78
|
+
// Flip: drop the cloud block (operator can re-cloud later via mode cloud)
|
|
79
|
+
parsed.memory = { mode: 'local' };
|
|
80
|
+
writeConfigYaml(cfg.absPath, parsed);
|
|
81
|
+
printSuccess(`flipped .olam/config.yaml memory.mode → local`);
|
|
82
|
+
printInfo('host-process', 'starting');
|
|
83
|
+
const rc = await (deps.runStart ?? runMemoryStart)();
|
|
84
|
+
if (rc !== 0) {
|
|
85
|
+
printWarning('local host-process failed to start. Config flipped but service is down — fix the underlying issue and run `olam memory start`.');
|
|
86
|
+
}
|
|
87
|
+
return { outcome: 'flipped-to-local' };
|
|
88
|
+
}
|
|
89
|
+
export async function runMemoryModeCloud(deps = {}) {
|
|
90
|
+
const cwd = deps.cwd ?? process.cwd();
|
|
91
|
+
const cfg = locateConfig(cwd);
|
|
92
|
+
const { parsed } = readConfigYaml(cfg.absPath);
|
|
93
|
+
const currentMem = (parsed.memory ?? {});
|
|
94
|
+
const currentMode = currentMem.mode ?? 'local';
|
|
95
|
+
// Resolve URL: --url flag wins, else interactive prompt.
|
|
96
|
+
let url = deps.url;
|
|
97
|
+
if (!url) {
|
|
98
|
+
const askText = deps.promptText ?? defaultPromptText;
|
|
99
|
+
url = (await askText('Cloud agentmemory URL (e.g. https://agentmemory.<you>.workers.dev): ')).trim();
|
|
100
|
+
}
|
|
101
|
+
if (!url) {
|
|
102
|
+
throw new Error('cloud URL is required');
|
|
103
|
+
}
|
|
104
|
+
// Validate via the C1 schema before writing.
|
|
105
|
+
const candidate = { mode: 'cloud', cloud: { url } };
|
|
106
|
+
const parsedMem = MemorySchema.safeParse(candidate);
|
|
107
|
+
if (!parsedMem.success) {
|
|
108
|
+
const msg = parsedMem.error.issues.map((i) => i.message).join('; ');
|
|
109
|
+
throw new Error(`invalid memory.cloud config: ${msg}`);
|
|
110
|
+
}
|
|
111
|
+
// Resolve secret: --secret flag wins, else interactive prompt. The
|
|
112
|
+
// secret is the bearer the operator already configured on the remote
|
|
113
|
+
// service (Cloudflare wrangler secret or equivalent). We persist it to
|
|
114
|
+
// ~/.olam/cloud-memory-secret 0600 so B1's env-resolver can inject it
|
|
115
|
+
// into worlds at spawn (C4 wires the read path).
|
|
116
|
+
let secret = deps.secret;
|
|
117
|
+
if (!secret) {
|
|
118
|
+
const askSecret = deps.promptSecret ?? defaultPromptSecret;
|
|
119
|
+
secret = await askSecret('Cloud agentmemory bearer secret (64-hex):');
|
|
120
|
+
}
|
|
121
|
+
if (!secret) {
|
|
122
|
+
throw new Error('cloud secret is required');
|
|
123
|
+
}
|
|
124
|
+
// Idempotency check: if already cloud-mode with the same URL, just refresh secret.
|
|
125
|
+
const sameUrl = currentMode === 'cloud' && currentMem.cloud?.url === url;
|
|
126
|
+
if (sameUrl) {
|
|
127
|
+
printInfo('memory.mode', `already cloud (url=${url}) — refreshing secret only`);
|
|
128
|
+
(deps.writeSecret ?? ((v) => writeCloudMemorySecret(v)))(secret);
|
|
129
|
+
return { outcome: 'noop', mode: 'cloud' };
|
|
130
|
+
}
|
|
131
|
+
// Stop local host-process first — fail-soft if it wasn't running.
|
|
132
|
+
printInfo('host-process', 'stopping (was running for local mode)');
|
|
133
|
+
await (deps.runStop ?? runMemoryStop)();
|
|
134
|
+
// Persist the secret BEFORE updating the config so worlds spawned
|
|
135
|
+
// between the writes see at most a transient "cloud but no secret"
|
|
136
|
+
// state rather than the inverse (config flipped, secret missing).
|
|
137
|
+
(deps.writeSecret ?? ((v) => writeCloudMemorySecret(v)))(secret);
|
|
138
|
+
printSuccess(`wrote cloud bearer secret to ${CLOUD_MEMORY_SECRET_PATH} (0600)`);
|
|
139
|
+
parsed.memory = {
|
|
140
|
+
mode: 'cloud',
|
|
141
|
+
cloud: {
|
|
142
|
+
url,
|
|
143
|
+
secret_ref: '~/.olam/cloud-memory-secret',
|
|
144
|
+
},
|
|
145
|
+
};
|
|
146
|
+
writeConfigYaml(cfg.absPath, parsed);
|
|
147
|
+
printSuccess(`flipped .olam/config.yaml memory.mode → cloud (${url})`);
|
|
148
|
+
printWarning('Worlds spawned BEFORE this flip still have the old env. Re-create them ' +
|
|
149
|
+
'(olam destroy + olam create) to pick up the new AGENTMEMORY_URL + secret.');
|
|
150
|
+
return { outcome: 'flipped-to-cloud', url };
|
|
151
|
+
}
|
|
152
|
+
export function registerMemoryMode(cmd) {
|
|
153
|
+
const mode = cmd
|
|
154
|
+
.command('mode <target>')
|
|
155
|
+
.description('Flip agent-memory source between local (host-process) and cloud (remote agentmemory deployment)')
|
|
156
|
+
.option('--url <url>', 'Cloud URL (skips the interactive prompt; mode cloud only)')
|
|
157
|
+
.option('--secret <value>', 'Cloud bearer secret (skips interactive prompt; argv-visible — prefer stdin)');
|
|
158
|
+
mode.action(async (target, opts) => {
|
|
159
|
+
printHeader(`olam memory mode ${target}`);
|
|
160
|
+
try {
|
|
161
|
+
if (target === 'local') {
|
|
162
|
+
await runMemoryModeLocal();
|
|
163
|
+
}
|
|
164
|
+
else if (target === 'cloud') {
|
|
165
|
+
await runMemoryModeCloud({
|
|
166
|
+
...(opts.url !== undefined ? { url: opts.url } : {}),
|
|
167
|
+
...(opts.secret !== undefined ? { secret: opts.secret } : {}),
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
printError(`mode must be 'local' or 'cloud' (got: ${target})`);
|
|
172
|
+
process.exitCode = 1;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
catch (err) {
|
|
176
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
177
|
+
process.exitCode = 1;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
//# sourceMappingURL=mode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mode.js","sourceRoot":"","sources":["../../../src/commands/memory/mode.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/commands/memory/start.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoHzC,wBAAsB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAgGtD;AAED,wBAAgB,mBAAmB,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAQtD"}
|
|
@@ -20,6 +20,7 @@
|
|
|
20
20
|
import { spawn } from 'node:child_process';
|
|
21
21
|
import { existsSync, mkdirSync, openSync, readFileSync, writeFileSync } from 'node:fs';
|
|
22
22
|
import { join } from 'node:path';
|
|
23
|
+
import { pathToFileURL } from 'node:url';
|
|
23
24
|
import { printError, printSuccess, printInfo, printHeader } from '../../output.js';
|
|
24
25
|
import { ensureMemorySecret } from '../../lib/memory-secret.js';
|
|
25
26
|
import { III_BINARY_PATH, MEMORY_DATA_DIR, MEMORY_LIVEZ_URL, MEMORY_LOG_PATH, MEMORY_PID_PATH, MEMORY_SERVICE_CANDIDATES, OLAM_BIN_DIR, OLAM_HOME, } from './_paths.js';
|
|
@@ -91,19 +92,63 @@ async function waitForReady(secret) {
|
|
|
91
92
|
}
|
|
92
93
|
return false;
|
|
93
94
|
}
|
|
95
|
+
/**
|
|
96
|
+
* Auto-fetch the iii binary via A1's `ensure-iii-engine.mjs` helper.
|
|
97
|
+
*
|
|
98
|
+
* Called from `runMemoryStart` when `~/.olam/bin/iii` is missing. Closes
|
|
99
|
+
* the bootstrap-time UX gap surfaced by `olam bootstrap` in CI: A5
|
|
100
|
+
* wires `olam memory start` into the bootstrap flow, but A2's start
|
|
101
|
+
* command previously failed with a "Run: node ... ensure-iii-engine.mjs"
|
|
102
|
+
* remedy that operators on fresh hosts couldn't auto-resolve. Now
|
|
103
|
+
* `olam memory start` (and therefore `olam bootstrap`) auto-fetches the
|
|
104
|
+
* SHA256-pinned binary on first use.
|
|
105
|
+
*
|
|
106
|
+
* Dynamic-imported because the helper is in `packages/memory-service/`,
|
|
107
|
+
* a sibling workspace — resolving statically would invert the package
|
|
108
|
+
* graph. Path resolution reuses `resolveMemoryServiceDir` so the bundle-
|
|
109
|
+
* vs-source layout fallbacks stay consistent.
|
|
110
|
+
*/
|
|
111
|
+
async function autoEnsureIiiBinary(serviceDir) {
|
|
112
|
+
const helperPath = join(serviceDir, 'scripts', 'ensure-iii-engine.mjs');
|
|
113
|
+
const mod = (await import(pathToFileURL(helperPath).href));
|
|
114
|
+
const result = await mod.ensureIiiEngine();
|
|
115
|
+
if (!result.ok) {
|
|
116
|
+
throw new Error(`ensureIiiEngine returned ok=false (path=${result.path})`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
94
119
|
export async function runMemoryStart() {
|
|
95
120
|
printHeader('olam memory start');
|
|
96
|
-
//
|
|
97
|
-
|
|
98
|
-
|
|
121
|
+
// 3. Locate the service first (needed for both auto-fetch and bin
|
|
122
|
+
// resolution below). Throws with a clear remedy if the packaging
|
|
123
|
+
// is broken (e.g. running outside a checkout).
|
|
124
|
+
let serviceDir;
|
|
125
|
+
try {
|
|
126
|
+
serviceDir = resolveMemoryServiceDir();
|
|
127
|
+
}
|
|
128
|
+
catch (err) {
|
|
129
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
99
130
|
return 1;
|
|
100
131
|
}
|
|
132
|
+
// 1. iii binary (A1's deliverable). Auto-fetch when missing so
|
|
133
|
+
// `olam bootstrap` succeeds on fresh hosts (CI runners, new
|
|
134
|
+
// operator machines) without a manual ensure-iii-engine step.
|
|
135
|
+
if (!existsSync(III_BINARY_PATH)) {
|
|
136
|
+
printInfo('iii binary', `missing at ${III_BINARY_PATH} — auto-fetching v0.11.2`);
|
|
137
|
+
try {
|
|
138
|
+
await autoEnsureIiiBinary(serviceDir);
|
|
139
|
+
}
|
|
140
|
+
catch (err) {
|
|
141
|
+
printError(`iii binary auto-fetch failed: ${err instanceof Error ? err.message : String(err)}. ` +
|
|
142
|
+
`Run manually: node packages/memory-service/scripts/ensure-iii-engine.mjs`);
|
|
143
|
+
return 1;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
101
146
|
printInfo('iii binary', III_BINARY_PATH);
|
|
102
147
|
// 2. Secret (A3 lib)
|
|
103
148
|
const secret = ensureMemorySecret();
|
|
104
149
|
printInfo('secret', '~/.olam/memory-secret (0600)');
|
|
105
|
-
//
|
|
106
|
-
|
|
150
|
+
// 3b. Locate the agentmemory bin (serviceDir was resolved above for
|
|
151
|
+
// the auto-fetch path).
|
|
107
152
|
const agentmemoryBin = resolveAgentMemoryBin(serviceDir);
|
|
108
153
|
printInfo('agentmemory', agentmemoryBin);
|
|
109
154
|
// 4. Idempotency: already running?
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/commands/memory/start.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"start.js","sourceRoot":"","sources":["../../../src/commands/memory/start.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `olam rekey <world-id>` — rotate the per-world postgres password.
|
|
3
|
+
*
|
|
4
|
+
* Phase A9 of `olam-hybrid-shared-postgres`. Phase A4 (commit 7b4334ff)
|
|
5
|
+
* landed `applyPostgresWorldRole` which already supports rotation via
|
|
6
|
+
* `ALTER ROLE` when the role exists. A9 exposes that rotation as a
|
|
7
|
+
* standalone operator-facing command, useful when:
|
|
8
|
+
*
|
|
9
|
+
* - The operator wants to force-rotate credentials (suspected leak).
|
|
10
|
+
* - A world container lost its env-injected password (e.g. crashed
|
|
11
|
+
* before the app read it).
|
|
12
|
+
* - A future tmpfs cred-mount flow needs a re-inject path.
|
|
13
|
+
*
|
|
14
|
+
* Flow:
|
|
15
|
+
* 1. Load context + WorldManager.getWorld(worldId).
|
|
16
|
+
* 2. Hybrid + DB gates (exit 3 if non-hybrid or no per-world DBs).
|
|
17
|
+
* 3. `applyPostgresWorldRole(id, worldDbNames)` → ALTER ROLE rotates
|
|
18
|
+
* the password atomically. The old password is gone.
|
|
19
|
+
* 4. Write new password to `~/.olam/worlds/<id>/credentials.json`
|
|
20
|
+
* (chmod 600).
|
|
21
|
+
* 5. `docker restart olam-<id>-devbox` so the container picks up the
|
|
22
|
+
* new password from env on next process start.
|
|
23
|
+
* 6. Audit-log line to `~/.olam/usage.log` (SEC-002): timestamp +
|
|
24
|
+
* world-id + "rekey" — NEVER the password.
|
|
25
|
+
*
|
|
26
|
+
* Exit codes:
|
|
27
|
+
* 0 success
|
|
28
|
+
* 1 unexpected error
|
|
29
|
+
* 2 world not found
|
|
30
|
+
* 3 precondition failed (non-hybrid, no DBs, etc.)
|
|
31
|
+
*/
|
|
32
|
+
import type { Command } from 'commander';
|
|
33
|
+
import { type PostgresWorldRoleResult } from '@olam/core/src/world/manager.js';
|
|
34
|
+
import type { WorldMetadata } from '@olam/core/src/world/types.js';
|
|
35
|
+
export interface RekeyOptions {
|
|
36
|
+
readonly print?: boolean;
|
|
37
|
+
readonly json?: boolean;
|
|
38
|
+
}
|
|
39
|
+
export interface RekeyResult {
|
|
40
|
+
readonly worldId: string;
|
|
41
|
+
readonly worldRoleName: string;
|
|
42
|
+
readonly password: string;
|
|
43
|
+
readonly credentialsPath: string;
|
|
44
|
+
readonly rotatedAt: string;
|
|
45
|
+
readonly containerRestarted: boolean;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Minimal dependency surface used by {@link doRekey}. Pure-function
|
|
49
|
+
* injection lets tests run without docker, without disk writes outside
|
|
50
|
+
* the test's tmp dir, and without mocking modules.
|
|
51
|
+
*/
|
|
52
|
+
export interface RekeyDeps {
|
|
53
|
+
readonly getWorld: (id: string) => WorldMetadata | undefined;
|
|
54
|
+
readonly applyPostgresWorldRole: (worldId: string, worldDbNames: ReadonlyArray<string>) => PostgresWorldRoleResult;
|
|
55
|
+
readonly restartContainer: (containerName: string) => {
|
|
56
|
+
ok: boolean;
|
|
57
|
+
stderr: string;
|
|
58
|
+
};
|
|
59
|
+
/** Override for tests. Default: real fs + ~/.olam. */
|
|
60
|
+
readonly olamHomeDir: () => string;
|
|
61
|
+
readonly now: () => Date;
|
|
62
|
+
/** Stream for human-readable lines (overridable for tests). */
|
|
63
|
+
readonly stdout: {
|
|
64
|
+
write(s: string): void;
|
|
65
|
+
};
|
|
66
|
+
/** Audit-log appender; default writes to `${olamHomeDir()}/usage.log`. */
|
|
67
|
+
readonly appendAuditLog: (line: string) => void;
|
|
68
|
+
}
|
|
69
|
+
/** Domain-specific error carrying the documented exit code. */
|
|
70
|
+
export declare class RekeyError extends Error {
|
|
71
|
+
readonly exitCode: number;
|
|
72
|
+
constructor(message: string, exitCode: number);
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Core rekey logic. Returns the rotation result on success, throws
|
|
76
|
+
* {@link RekeyError} with the documented exit code on failure.
|
|
77
|
+
*
|
|
78
|
+
* The password is held in this function's local binding and the
|
|
79
|
+
* returned object only; it is written to disk with mode 0o600 and
|
|
80
|
+
* NEVER logged or written to the audit trail (SEC-002).
|
|
81
|
+
*/
|
|
82
|
+
export declare function doRekey(worldId: string, deps: RekeyDeps): Promise<RekeyResult>;
|
|
83
|
+
export declare function registerRekey(program: Command): void;
|
|
84
|
+
//# sourceMappingURL=rekey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rekey.d.ts","sourceRoot":"","sources":["../../src/commands/rekey.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAMH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,EAEL,KAAK,uBAAuB,EAC7B,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,+BAA+B,CAAC;AAcnE,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;CACtC;AAED;;;;GAIG;AACH,MAAM,WAAW,SAAS;IACxB,QAAQ,CAAC,QAAQ,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,aAAa,GAAG,SAAS,CAAC;IAC7D,QAAQ,CAAC,sBAAsB,EAAE,CAC/B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,aAAa,CAAC,MAAM,CAAC,KAChC,uBAAuB,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,CAAC,aAAa,EAAE,MAAM,KAAK;QAAE,EAAE,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IACtF,sDAAsD;IACtD,QAAQ,CAAC,WAAW,EAAE,MAAM,MAAM,CAAC;IACnC,QAAQ,CAAC,GAAG,EAAE,MAAM,IAAI,CAAC;IACzB,+DAA+D;IAC/D,QAAQ,CAAC,MAAM,EAAE;QAAE,KAAK,CAAC,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CAAC;IAC5C,0EAA0E;IAC1E,QAAQ,CAAC,cAAc,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACjD;AAsCD,+DAA+D;AAC/D,qBAAa,UAAW,SAAQ,KAAK;IACnC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;gBACd,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM;CAK9C;AAED;;;;;;;GAOG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,SAAS,GACd,OAAO,CAAC,WAAW,CAAC,CA0EtB;AAuBD,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CAqCpD"}
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `olam rekey <world-id>` — rotate the per-world postgres password.
|
|
3
|
+
*
|
|
4
|
+
* Phase A9 of `olam-hybrid-shared-postgres`. Phase A4 (commit 7b4334ff)
|
|
5
|
+
* landed `applyPostgresWorldRole` which already supports rotation via
|
|
6
|
+
* `ALTER ROLE` when the role exists. A9 exposes that rotation as a
|
|
7
|
+
* standalone operator-facing command, useful when:
|
|
8
|
+
*
|
|
9
|
+
* - The operator wants to force-rotate credentials (suspected leak).
|
|
10
|
+
* - A world container lost its env-injected password (e.g. crashed
|
|
11
|
+
* before the app read it).
|
|
12
|
+
* - A future tmpfs cred-mount flow needs a re-inject path.
|
|
13
|
+
*
|
|
14
|
+
* Flow:
|
|
15
|
+
* 1. Load context + WorldManager.getWorld(worldId).
|
|
16
|
+
* 2. Hybrid + DB gates (exit 3 if non-hybrid or no per-world DBs).
|
|
17
|
+
* 3. `applyPostgresWorldRole(id, worldDbNames)` → ALTER ROLE rotates
|
|
18
|
+
* the password atomically. The old password is gone.
|
|
19
|
+
* 4. Write new password to `~/.olam/worlds/<id>/credentials.json`
|
|
20
|
+
* (chmod 600).
|
|
21
|
+
* 5. `docker restart olam-<id>-devbox` so the container picks up the
|
|
22
|
+
* new password from env on next process start.
|
|
23
|
+
* 6. Audit-log line to `~/.olam/usage.log` (SEC-002): timestamp +
|
|
24
|
+
* world-id + "rekey" — NEVER the password.
|
|
25
|
+
*
|
|
26
|
+
* Exit codes:
|
|
27
|
+
* 0 success
|
|
28
|
+
* 1 unexpected error
|
|
29
|
+
* 2 world not found
|
|
30
|
+
* 3 precondition failed (non-hybrid, no DBs, etc.)
|
|
31
|
+
*/
|
|
32
|
+
import { spawnSync as defaultSpawnSync } from 'node:child_process';
|
|
33
|
+
import * as fs from 'node:fs';
|
|
34
|
+
import * as os from 'node:os';
|
|
35
|
+
import * as path from 'node:path';
|
|
36
|
+
import { applyPostgresWorldRole as defaultApplyPostgresWorldRole, } from '@olam/core/src/world/manager.js';
|
|
37
|
+
import { loadContext } from '../context.js';
|
|
38
|
+
import { printError, printSuccess, printInfo, printHeader } from '../output.js';
|
|
39
|
+
/** Container name convention — mirrors enter.ts:286, refresh.ts:90, ps.ts:157. */
|
|
40
|
+
function devboxContainerName(worldId) {
|
|
41
|
+
return `olam-${worldId}-devbox`;
|
|
42
|
+
}
|
|
43
|
+
/** Resolve `~/.olam` honoring OLAM_HOME (mirrors host-cp.ts:55). */
|
|
44
|
+
function olamHomeDir() {
|
|
45
|
+
return process.env['OLAM_HOME'] ?? path.join(os.homedir(), '.olam');
|
|
46
|
+
}
|
|
47
|
+
function defaultRestartContainer(name, spawn = defaultSpawnSync) {
|
|
48
|
+
// 30s graceful-stop window matches refresh.ts:41 (RESTART_TIMEOUT_S).
|
|
49
|
+
const r = spawn('docker', ['restart', '--time', '30', name], {
|
|
50
|
+
encoding: 'utf-8',
|
|
51
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
52
|
+
});
|
|
53
|
+
return {
|
|
54
|
+
ok: r.status === 0 && r.error === undefined,
|
|
55
|
+
stderr: (r.stderr || '').trim() || (r.stdout || '').trim(),
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
function defaultAppendAuditLog(homeDir, line) {
|
|
59
|
+
fs.mkdirSync(homeDir, { recursive: true });
|
|
60
|
+
fs.appendFileSync(path.join(homeDir, 'usage.log'), line.endsWith('\n') ? line : line + '\n', {
|
|
61
|
+
encoding: 'utf-8',
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
function buildDefaultDeps() {
|
|
65
|
+
return {
|
|
66
|
+
// Replaced inside `registerRekey` once the context is loaded; the
|
|
67
|
+
// default here keeps the type contract self-consistent.
|
|
68
|
+
getWorld: () => undefined,
|
|
69
|
+
applyPostgresWorldRole: (id, dbs) => defaultApplyPostgresWorldRole(id, dbs),
|
|
70
|
+
restartContainer: (name) => defaultRestartContainer(name),
|
|
71
|
+
olamHomeDir,
|
|
72
|
+
now: () => new Date(),
|
|
73
|
+
stdout: { write: (s) => process.stdout.write(s) },
|
|
74
|
+
appendAuditLog: (line) => defaultAppendAuditLog(olamHomeDir(), line),
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
/** Domain-specific error carrying the documented exit code. */
|
|
78
|
+
export class RekeyError extends Error {
|
|
79
|
+
exitCode;
|
|
80
|
+
constructor(message, exitCode) {
|
|
81
|
+
super(message);
|
|
82
|
+
this.name = 'RekeyError';
|
|
83
|
+
this.exitCode = exitCode;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Core rekey logic. Returns the rotation result on success, throws
|
|
88
|
+
* {@link RekeyError} with the documented exit code on failure.
|
|
89
|
+
*
|
|
90
|
+
* The password is held in this function's local binding and the
|
|
91
|
+
* returned object only; it is written to disk with mode 0o600 and
|
|
92
|
+
* NEVER logged or written to the audit trail (SEC-002).
|
|
93
|
+
*/
|
|
94
|
+
export async function doRekey(worldId, deps) {
|
|
95
|
+
const world = deps.getWorld(worldId);
|
|
96
|
+
if (!world) {
|
|
97
|
+
throw new RekeyError(`world not found: ${worldId}`, 2);
|
|
98
|
+
}
|
|
99
|
+
if (world.worldRoleName === undefined) {
|
|
100
|
+
throw new RekeyError(`world ${worldId} is not hybrid-mode (no per-world role). ` +
|
|
101
|
+
'`olam rekey` only applies to hybrid-mode worlds; use the bridge ' +
|
|
102
|
+
"postgres's `development` user.", 3);
|
|
103
|
+
}
|
|
104
|
+
if (world.worldDbNames === undefined || world.worldDbNames.length === 0) {
|
|
105
|
+
throw new RekeyError('world has no per-world DBs to rotate role on', 3);
|
|
106
|
+
}
|
|
107
|
+
// 1. Rotate. ALTER ROLE inside applyPostgresWorldRole is idempotent —
|
|
108
|
+
// the same function handles both initial create and rotation.
|
|
109
|
+
const { worldRoleName, password } = deps.applyPostgresWorldRole(worldId, world.worldDbNames);
|
|
110
|
+
// 2. Persist credentials BEFORE restart so the container always has a
|
|
111
|
+
// valid file to consult if env-injection ever moves to file-mount.
|
|
112
|
+
const rotatedAt = deps.now().toISOString();
|
|
113
|
+
const homeDir = deps.olamHomeDir();
|
|
114
|
+
const worldDir = path.join(homeDir, 'worlds', worldId);
|
|
115
|
+
fs.mkdirSync(worldDir, { recursive: true });
|
|
116
|
+
const credentialsPath = path.join(worldDir, 'credentials.json');
|
|
117
|
+
const payload = {
|
|
118
|
+
worldRoleName,
|
|
119
|
+
password,
|
|
120
|
+
rotatedAt,
|
|
121
|
+
};
|
|
122
|
+
// chmod 600 — owner read/write only. Order matters: create empty file
|
|
123
|
+
// first, fchmod, THEN write. `writeFileSync({ mode })` only applies on
|
|
124
|
+
// initial create, so re-rotations on an existing file keep the old
|
|
125
|
+
// mode if we skip the explicit chmod.
|
|
126
|
+
fs.writeFileSync(credentialsPath, JSON.stringify(payload, null, 2) + '\n', {
|
|
127
|
+
encoding: 'utf-8',
|
|
128
|
+
mode: 0o600,
|
|
129
|
+
});
|
|
130
|
+
fs.chmodSync(credentialsPath, 0o600);
|
|
131
|
+
// 3. Restart the world devbox container so the (env-injected)
|
|
132
|
+
// password reload happens. Failure here is reported but the
|
|
133
|
+
// rotation itself is already durable in postgres.
|
|
134
|
+
const restart = deps.restartContainer(devboxContainerName(worldId));
|
|
135
|
+
// Container restart is best-effort; rotation already landed in pg.
|
|
136
|
+
// 4. Audit-log line — NO password. SEC-002 closure.
|
|
137
|
+
deps.appendAuditLog(`${rotatedAt} ${worldId} rekey`);
|
|
138
|
+
if (!restart.ok) {
|
|
139
|
+
// Surface the restart failure in stderr; caller can re-run
|
|
140
|
+
// `docker restart olam-<id>-devbox` manually. Exit code stays 0
|
|
141
|
+
// because the credential rotation succeeded.
|
|
142
|
+
process.stderr.write(`warn: docker restart ${devboxContainerName(worldId)} failed (` +
|
|
143
|
+
`${restart.stderr || 'unknown'}). Run it manually to pick up the new ` +
|
|
144
|
+
'password.\n');
|
|
145
|
+
}
|
|
146
|
+
return {
|
|
147
|
+
worldId,
|
|
148
|
+
worldRoleName,
|
|
149
|
+
password,
|
|
150
|
+
credentialsPath,
|
|
151
|
+
rotatedAt,
|
|
152
|
+
containerRestarted: restart.ok,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
function emitJson(stdout, result) {
|
|
156
|
+
stdout.write(JSON.stringify(result, null, 2) + '\n');
|
|
157
|
+
}
|
|
158
|
+
function emitHuman(result, opts) {
|
|
159
|
+
printHeader(`Rotated credentials for ${result.worldId}`);
|
|
160
|
+
printInfo('role', result.worldRoleName);
|
|
161
|
+
printInfo('credentials', result.credentialsPath);
|
|
162
|
+
printInfo('rotated', result.rotatedAt);
|
|
163
|
+
printInfo('container', result.containerRestarted ? 'restarted' : 'restart failed (see stderr)');
|
|
164
|
+
if (opts.print) {
|
|
165
|
+
// Plain stdout (no `printInfo` decorator) so the password can be
|
|
166
|
+
// piped: `olam rekey <id> --print | tail -n1`.
|
|
167
|
+
process.stdout.write(result.password + '\n');
|
|
168
|
+
}
|
|
169
|
+
printSuccess(`Run \`olam enter ${result.worldId}\` to verify the new password works`);
|
|
170
|
+
}
|
|
171
|
+
export function registerRekey(program) {
|
|
172
|
+
program
|
|
173
|
+
.command('rekey')
|
|
174
|
+
.description('Rotate the per-world postgres password for a hybrid-mode world')
|
|
175
|
+
.argument('<world-id>', 'World ID (e.g. iron-bay-3122)')
|
|
176
|
+
.option('--print', 'Also print the new password to stdout (default: write to file only)')
|
|
177
|
+
.option('--json', 'Emit the rotation result as JSON')
|
|
178
|
+
.action(async (worldId, opts) => {
|
|
179
|
+
const { ctx, error } = await loadContext();
|
|
180
|
+
if (!ctx) {
|
|
181
|
+
printError(error?.message ?? 'Olam is not configured. Run `olam init` first.');
|
|
182
|
+
process.exitCode = 1;
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
const deps = {
|
|
186
|
+
...buildDefaultDeps(),
|
|
187
|
+
getWorld: (id) => ctx.worldManager.getWorld(id),
|
|
188
|
+
};
|
|
189
|
+
try {
|
|
190
|
+
const result = await doRekey(worldId, deps);
|
|
191
|
+
if (opts.json) {
|
|
192
|
+
emitJson(deps.stdout, result);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
emitHuman(result, opts);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (err instanceof RekeyError) {
|
|
200
|
+
printError(err.message);
|
|
201
|
+
process.exitCode = err.exitCode;
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
printError(err instanceof Error ? err.message : String(err));
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
//# sourceMappingURL=rekey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rekey.js","sourceRoot":"","sources":["../../src/commands/rekey.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,9 +2,9 @@
|
|
|
2
2
|
* `olam services` — umbrella verb for managing Olam service containers.
|
|
3
3
|
*
|
|
4
4
|
* Subcommands:
|
|
5
|
-
* olam services up — start olam-auth + olam-mcp-auth (idempotent)
|
|
6
|
-
* olam services down — stop
|
|
7
|
-
* olam services status — show state of
|
|
5
|
+
* olam services up — start olam-auth + olam-mcp-auth + olam-kg-service (idempotent)
|
|
6
|
+
* olam services down — stop all service containers
|
|
7
|
+
* olam services status — show state of all service containers
|
|
8
8
|
*
|
|
9
9
|
* `olam auth up/down/status` delegates here with a deprecation warning.
|
|
10
10
|
*/
|
|
@@ -27,11 +27,11 @@ export declare class McpAuthContainerController {
|
|
|
27
27
|
export declare function servicesUp(): Promise<{
|
|
28
28
|
exitCode: number;
|
|
29
29
|
}>;
|
|
30
|
-
/** Stop
|
|
30
|
+
/** Stop all service containers. */
|
|
31
31
|
export declare function servicesDown(): {
|
|
32
32
|
exitCode: number;
|
|
33
33
|
};
|
|
34
|
-
/** Show container state for
|
|
34
|
+
/** Show container state for all services. */
|
|
35
35
|
export declare function servicesStatus(): void;
|
|
36
36
|
export declare function registerServices(program: Command): void;
|
|
37
37
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"services.d.ts","sourceRoot":"","sources":["../../src/commands/services.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgCzC,KAAK,cAAc,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAExD,UAAU,eAAe;IACvB,QAAQ,CAAC,KAAK,EAAE,cAAc,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED,qBAAa,0BAA0B;IACrC,OAAO,CAAC,QAAQ,CAA8B;IAE9C,MAAM,IAAI,eAAe;IAiBzB,OAAO,CAAC,WAAW;IAInB,KAAK,IAAI,IAAI;IAgCb,IAAI,IAAI,IAAI;IAMZ,MAAM,IAAI,IAAI;IAIR,YAAY,CAAC,SAAS,SAA6B,GAAG,OAAO,CAAC,OAAO,CAAC;CAa7E;AAgCD,wBAAsB,UAAU,IAAI,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAgGhE;AAED,mCAAmC;AACnC,wBAAgB,YAAY,IAAI;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CA+BnD;AAED,6CAA6C;AAC7C,wBAAgB,cAAc,IAAI,IAAI,CAiCrC;AAID,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI,CA2BvD"}
|