test: expand Crestodian first-run Docker smoke

This commit is contained in:
Peter Steinberger
2026-04-25 12:30:10 +01:00
parent 9ab51bb66e
commit 4ac6729d12
3 changed files with 97 additions and 1 deletions

View File

@@ -304,6 +304,10 @@ Fresh configless setup through Crestodian is covered by:
pnpm test:docker:crestodian-first-run
```
That lane starts with an empty state dir, routes bare `openclaw` to Crestodian,
sets the default model, creates an additional agent, configures Discord through
a token SecretRef, validates config, and checks the audit log.
## Related
- [CLI reference](/cli)

View File

@@ -63,6 +63,10 @@ When debugging real providers/models (requires real creds):
- Runs Crestodian in a configless container with a fake Claude CLI on `PATH`
and verifies the fuzzy planner fallback translates into an audited typed
config write.
- Crestodian first-run Docker smoke: `pnpm test:docker:crestodian-first-run`
- Starts from an empty OpenClaw state dir, routes bare `openclaw` to
Crestodian, applies setup/model/agent/Discord SecretRef writes, validates
config, and verifies audit entries.
- Moonshot/Kimi cost smoke: with `MOONSHOT_API_KEY` set, run
`openclaw models list --provider moonshot --json`, then run an isolated
`openclaw agent --local --session-id live-kimi-cost --message 'Reply exactly: KIMI_LIVE_OK' --thinking off --json`

View File

@@ -57,10 +57,12 @@ async function main() {
"fresh overview did not report missing config",
);
assert(
overviewOutput.includes('Next: say "setup" to create a starter config'),
overviewOutput.includes('Next: run "setup" to create a starter config'),
"fresh overview did not include setup recommendation",
);
process.env.DISCORD_BOT_TOKEN = "openclaw-crestodian-discord-e2e-token";
const setupRuntime = createRuntime();
await runCrestodian(
{
@@ -76,6 +78,66 @@ async function main() {
"Crestodian setup did not apply",
);
clearConfigCache();
const modelRuntime = createRuntime();
await runCrestodian(
{
message: "set default model openai/gpt-5.2",
yes: true,
interactive: false,
},
modelRuntime.runtime,
);
assert(
modelRuntime.lines.join("\n").includes("[crestodian] done: config.setDefaultModel"),
"Crestodian default model update did not apply",
);
clearConfigCache();
const agentRuntime = createRuntime();
await runCrestodian(
{
message: "create agent reef workspace /tmp/openclaw-reef model openai/gpt-5.2",
yes: true,
interactive: false,
},
agentRuntime.runtime,
);
assert(
agentRuntime.lines.join("\n").includes("[crestodian] done: agents.create"),
"Crestodian agent creation did not apply",
);
clearConfigCache();
const discordTokenRuntime = createRuntime();
await runCrestodian(
{
message: "config set-ref channels.discord.token env DISCORD_BOT_TOKEN",
yes: true,
interactive: false,
},
discordTokenRuntime.runtime,
);
assert(
discordTokenRuntime.lines.join("\n").includes("[crestodian] done: config.setRef"),
"Crestodian Discord token SecretRef did not apply",
);
clearConfigCache();
const discordEnabledRuntime = createRuntime();
await runCrestodian(
{
message: "config set channels.discord.enabled true",
yes: true,
interactive: false,
},
discordEnabledRuntime.runtime,
);
assert(
discordEnabledRuntime.lines.join("\n").includes("[crestodian] done: config.set"),
"Crestodian Discord enabled flag did not apply",
);
clearConfigCache();
const validateRuntime = createRuntime();
await runCrestodian({ message: "validate config", interactive: false }, validateRuntime.runtime);
@@ -96,10 +158,36 @@ async function main() {
config.agents.defaults.model.primary === "openai/gpt-5.2",
"first-run setup did not write default model",
);
const reef = config.agents?.list?.find((agent) => agent.id === "reef");
assert(reef, "Crestodian did not create reef agent");
assert(reef.workspace === "/tmp/openclaw-reef", "Crestodian did not write reef workspace");
assert(reef.model === "openai/gpt-5.2", "Crestodian did not write reef model");
assert(config.channels?.discord?.enabled === true, "Crestodian did not enable Discord");
const discordToken = config.channels?.discord?.token;
assert(
discordToken &&
typeof discordToken === "object" &&
"source" in discordToken &&
discordToken.source === "env" &&
"id" in discordToken &&
discordToken.id === "DISCORD_BOT_TOKEN",
"Crestodian did not write Discord token SecretRef",
);
assert(
!JSON.stringify(config.channels.discord).includes(process.env.DISCORD_BOT_TOKEN),
"Crestodian persisted the raw Discord token",
);
const auditPath = path.join(stateDir, "audit", "crestodian.jsonl");
const audit = (await fs.readFile(auditPath, "utf8")).trim();
assert(audit.includes('"operation":"crestodian.setup"'), "setup audit entry missing");
assert(
audit.includes('"operation":"config.setDefaultModel"'),
"default model audit entry missing",
);
assert(audit.includes('"operation":"agents.create"'), "agent creation audit entry missing");
assert(audit.includes('"operation":"config.setRef"'), "Discord SecretRef audit entry missing");
assert(audit.includes('"operation":"config.set"'), "Discord enabled audit entry missing");
console.log("Crestodian first-run Docker E2E passed");
}