Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 40 additions & 27 deletions src/sandboxes/setupOpenClaw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,30 @@ import { logger } from "@trigger.dev/sdk/v3";
import { onboardOpenClaw } from "./onboardOpenClaw";
import { OPENCLAW_DEFAULT_MODEL } from "../consts";

// Constant script body. No interpolation of caller-supplied values — all
// secrets are read at runtime from process.env inside the sandbox, so a
// value containing quotes, backslashes, or newlines cannot break out of
// the shell or the JS string. See: shell-injection fix for accountId.
const INJECT_ENV_SCRIPT = `
const fs = require('fs');
const os = require('os');
const path = os.homedir() + '/.openclaw/openclaw.json';
const c = JSON.parse(fs.readFileSync(path, 'utf8'));
c.env = c.env || {};
c.env.RECOUP_API_KEY = process.env.RECOUP_API_KEY;
c.env.RECOUP_ACCOUNT_ID = process.env.RECOUP_ACCOUNT_ID;
if (process.env.GITHUB_TOKEN) {
c.env.GITHUB_TOKEN = process.env.GITHUB_TOKEN;
}
Comment on lines +18 to +20
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear GITHUB_TOKEN when it is absent.

openclaw.json is persisted, so skipping this branch leaves any previous c.env.GITHUB_TOKEN in place. A later run without GITHUB_TOKEN will keep using the old credential.

Suggested fix
   c.env.RECOUP_API_KEY = process.env.RECOUP_API_KEY;
   c.env.RECOUP_ACCOUNT_ID = process.env.RECOUP_ACCOUNT_ID;
   if (process.env.GITHUB_TOKEN) {
     c.env.GITHUB_TOKEN = process.env.GITHUB_TOKEN;
+  } else {
+    delete c.env.GITHUB_TOKEN;
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (process.env.GITHUB_TOKEN) {
c.env.GITHUB_TOKEN = process.env.GITHUB_TOKEN;
}
if (process.env.GITHUB_TOKEN) {
c.env.GITHUB_TOKEN = process.env.GITHUB_TOKEN;
} else {
delete c.env.GITHUB_TOKEN;
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sandboxes/setupOpenClaw.ts` around lines 18 - 20, When populating c.env
in setupOpenClaw (the c variable in src/sandboxes/setupOpenClaw.ts), ensure you
explicitly clear c.env.GITHUB_TOKEN when process.env.GITHUB_TOKEN is not set;
currently only the presence branch sets the token so old values persist in the
persisted openclaw.json—add logic to set c.env.GITHUB_TOKEN = undefined (or
delete c.env.GITHUB_TOKEN) in the else path to remove any previously saved
credential.

c.tools = c.tools || {};
c.tools.profile = 'coding';
c.agents = c.agents || {};
c.agents.defaults = c.agents.defaults || {};
c.agents.defaults.model = c.agents.defaults.model || {};
c.agents.defaults.model.primary = process.env.OPENCLAW_DEFAULT_MODEL;
fs.writeFileSync(path, JSON.stringify(c, null, 2));
`;

/**
* Ensures OpenClaw is onboarded, seeds env vars into the config,
* and starts the gateway process in the background.
Expand All @@ -17,42 +41,31 @@ export async function setupOpenClaw(
): Promise<void> {
await onboardOpenClaw(sandbox);

// Inject RECOUP env vars into openclaw.json's env block so they're
// available to the agent and all tools/subprocesses it spawns.
if (!process.env.RECOUP_API_KEY) {
const recoupApiKey = process.env.RECOUP_API_KEY;
if (!recoupApiKey) {
throw new Error("Missing RECOUP_API_KEY environment variable");
}

const githubToken = process.env.GITHUB_TOKEN;

logger.log("Injecting env vars into openclaw.json", {
RECOUP_API_KEY: `${process.env.RECOUP_API_KEY.slice(0, 4)}...`,
RECOUP_API_KEY: `${recoupApiKey.slice(0, 4)}...`,
RECOUP_ACCOUNT_ID: accountId,
GITHUB_TOKEN: githubToken ? "present" : "missing",
});
Comment on lines 51 to 55
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Stop logging secret fragments and raw account IDs.

This security fix still emits a stable prefix of RECOUP_API_KEY and the raw tenant identifier into logs. Prefer presence-only fields here.

Suggested fix
   logger.log("Injecting env vars into openclaw.json", {
-    RECOUP_API_KEY: `${recoupApiKey.slice(0, 4)}...`,
-    RECOUP_ACCOUNT_ID: accountId,
+    RECOUP_API_KEY: "present",
+    RECOUP_ACCOUNT_ID: "present",
     GITHUB_TOKEN: githubToken ? "present" : "missing",
   });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
logger.log("Injecting env vars into openclaw.json", {
RECOUP_API_KEY: `${process.env.RECOUP_API_KEY.slice(0, 4)}...`,
RECOUP_API_KEY: `${recoupApiKey.slice(0, 4)}...`,
RECOUP_ACCOUNT_ID: accountId,
GITHUB_TOKEN: githubToken ? "present" : "missing",
});
logger.log("Injecting env vars into openclaw.json", {
RECOUP_API_KEY: "present",
RECOUP_ACCOUNT_ID: "present",
GITHUB_TOKEN: githubToken ? "present" : "missing",
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/sandboxes/setupOpenClaw.ts` around lines 51 - 55, The current logger.log
call in setupOpenClaw.ts leaks sensitive fragments and raw account identifiers
(logger.log(... { RECOUP_API_KEY: `${recoupApiKey.slice(0, 4)}...`,
RECOUP_ACCOUNT_ID: accountId, ... })); change it to emit only presence booleans
or redacted flags: replace RECOUP_API_KEY with something like hasRecoupApiKey:
Boolean(recoupApiKey) (no fragments), replace RECOUP_ACCOUNT_ID with
hasRecoupAccountId: Boolean(accountId) (do not log the raw ID), and keep
GITHUB_TOKEN as the existing presence check; update the logger.log invocation
and any related callers to use these presence-only fields.


const injectEnv = await sandbox.runCommand({
cmd: "sh",
args: [
"-c",
`node -e "
const fs = require('fs');
const p = require('os').homedir() + '/.openclaw/openclaw.json';
const c = JSON.parse(fs.readFileSync(p, 'utf8'));
c.env = c.env || {};
c.env.RECOUP_API_KEY = '${process.env.RECOUP_API_KEY}';
c.env.RECOUP_ACCOUNT_ID = '${accountId}';
${githubToken ? `c.env.GITHUB_TOKEN = '${githubToken}';` : ""}
c.tools = c.tools || {};
c.tools.profile = 'coding';
c.agents = c.agents || {};
c.agents.defaults = c.agents.defaults || {};
c.agents.defaults.model = c.agents.defaults.model || {};
c.agents.defaults.model.primary = '${OPENCLAW_DEFAULT_MODEL}';
fs.writeFileSync(p, JSON.stringify(c, null, 2));
"`,
],
});
const injectEnvOpts: Record<string, unknown> = {
cmd: "node",
args: ["-e", INJECT_ENV_SCRIPT],
env: {
RECOUP_API_KEY: recoupApiKey,
RECOUP_ACCOUNT_ID: accountId,
OPENCLAW_DEFAULT_MODEL,
...(githubToken ? { GITHUB_TOKEN: githubToken } : {}),
},
};

const injectEnv = await sandbox.runCommand(injectEnvOpts as any);

if (injectEnv.exitCode !== 0) {
const stderr = (await injectEnv.stderr()) || "";
Expand Down Expand Up @@ -82,4 +95,4 @@ export async function setupOpenClaw(
}

logger.log("OpenClaw gateway started");
}
}