Skip to content

fix: preserve paperclip runtime env in exec tool defaults#59485

Open
bboyyan wants to merge 3 commits intoopenclaw:mainfrom
bboyyan:fix/pi-tools-paperclip-runtime-env-pr
Open

fix: preserve paperclip runtime env in exec tool defaults#59485
bboyyan wants to merge 3 commits intoopenclaw:mainfrom
bboyyan:fix/pi-tools-paperclip-runtime-env-pr

Conversation

@bboyyan
Copy link
Copy Markdown
Contributor

@bboyyan bboyyan commented Apr 2, 2026

Summary

  • preserve paperclipRuntimeEnv when wiring exec tool defaults in createOpenClawCodingTools
  • add a regression test that verifies PAPERCLIP_AUTH_HEADER and PAPERCLIP_API_KEY reach the exec tool

Root cause

createOpenClawCodingTools was building the exec tool with:

  • paperclipRuntimeEnv: options?.paperclipRuntimeEnv

But the runtime auth env was being attached under:

  • options.exec.paperclipRuntimeEnv

That mismatch meant Paperclip runtime auth could be present upstream, but get dropped at the pi-tools.ts -> createExecTool() callsite before reaching exec defaults.

Why this change

This is a small env-plumbing bugfix, not a new integration surface:

  • the Paperclip runtime auth/env path already exists in the codebase
  • this patch preserves the existing runtime env through the final exec-tool wiring step
  • non-Paperclip flows are unchanged

Validation

  • added regression test: src/agents/pi-tools.paperclip-runtime-env.test.ts
  • local test passed:
    • pnpm vitest run src/agents/pi-tools.paperclip-runtime-env.test.ts
  • local build passed:
    • npm run build

Notes

During local validation, the failure manifested as issue-bound runs receiving runtime auth upstream but losing PAPERCLIP_* env before exec. This change fixes that last-hop drop.

Copilot AI review requested due to automatic review settings April 2, 2026 06:19
@bboyyan bboyyan requested a review from a team as a code owner April 2, 2026 06:19
@openclaw-barnacle openclaw-barnacle Bot added channel: msteams Channel integration: msteams channel: voice-call Channel integration: voice-call agents Agent runtime and tooling size: XL labels Apr 2, 2026
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 6bda3f4e6b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/agents/pi-embedded-runner/run.ts Outdated
Comment on lines +156 to +157
if (!params.paperclipRuntimeAuth) {
return fn();
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Serialize all runs while PAPERCLIP env is globally overridden

runEmbeddedPiAgent now writes Paperclip credentials into process.env for the duration of a run, but withPaperclipRuntimeEnvLock skips locking when paperclipRuntimeAuth is absent. That allows a concurrent run on another command lane (for example subagent or cron) to execute while PAPERCLIP_* is still set by a different run, so unrelated exec calls can inherit and leak the wrong Paperclip auth header/API key. Because the env mutation is process-global, non-Paperclip runs must also be blocked (or the env must be passed per-invocation) to avoid cross-run credential contamination.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR aims to fix Paperclip runtime auth/env propagation so that Paperclip credentials (e.g., PAPERCLIP_AUTH_HEADER, PAPERCLIP_API_KEY) survive the final wiring step into exec-tool execution, and adds regression tests around this behavior.

Changes:

  • Update createOpenClawCodingTools to prefer options.exec.paperclipRuntimeEnv (with fallback to options.paperclipRuntimeEnv) when constructing exec tool defaults.
  • Add Paperclip runtime-auth env application/restoration (with a lock to avoid cross-run contamination) plus tests validating env behavior.
  • Adjust several tests’ fetch mocks to be typed as typeof fetch.

Reviewed changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
test/pi-embedded-runner.paperclip-auth.test.ts Adds a unit test for applying/restoring Paperclip env vars.
src/infra/clawhub.test.ts Tweaks fetch mock typing/casting in ClawHub helper tests.
src/agents/pi-tools.ts Attempts to plumb paperclipRuntimeEnv into exec tool defaults.
src/agents/pi-tools.paperclip-runtime-env.test.ts Adds regression coverage intended to verify Paperclip env reaches exec.
src/agents/pi-embedded-runner/run.ts Adds Paperclip env application/restoration + a lock around embedded runs.
src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts Adjusts fetch mock typing via a helper cast.
extensions/voice-call/src/providers/twilio/api.test.ts Adjusts fetch mock typing via a helper cast.
extensions/msteams/src/graph.test.ts Adjusts fetch mock typing via a helper cast.
extensions/microsoft/speech-provider.test.ts Adjusts fetch mock typing via a helper cast.

Comment thread src/agents/pi-tools.ts
Comment on lines 433 to +437
messageProvider: options?.messageProvider,
currentChannelId: options?.currentChannelId,
currentThreadTs: options?.currentThreadTs,
accountId: options?.agentAccountId,
paperclipRuntimeEnv: options?.exec?.paperclipRuntimeEnv ?? options?.paperclipRuntimeEnv,
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

createExecTool() currently does not define or consume a paperclipRuntimeEnv default (and ExecToolDefaults doesn’t include this field). As written, this value is effectively ignored, so Paperclip env won’t actually be injected into the exec subprocess. Consider either (a) adding paperclipRuntimeEnv support to ExecToolDefaults + createExecTool and merging it into the effective env, or (b) wiring it here by merging into args.env before delegating to the exec tool.

Copilot uses AI. Check for mistakes.
Comment on lines +6 to +13
const tools = createOpenClawCodingTools({
workspaceDir: process.cwd(),
exec: {
host: "gateway",
security: "full",
ask: "off",
paperclipRuntimeEnv: {
PAPERCLIP_AUTH_HEADER: "Bearer test-header",
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

This test passes paperclipRuntimeEnv under exec, but createOpenClawCodingTools types exec as ExecToolDefaults & ProcessToolDefaults, and ExecToolDefaults currently doesn’t include paperclipRuntimeEnv. This will fail TypeScript excess-property checking, and even at runtime the exec tool won’t see these values unless the exec tool defaults explicitly merge them into env.

Copilot uses AI. Check for mistakes.
Comment thread src/agents/pi-embedded-runner/run.ts Outdated
Comment on lines +144 to +153
"PAPERCLIP_AUTH_HEADER",
] as const;

let paperclipRuntimeEnvLock: Promise<void> = Promise.resolve();

async function withPaperclipRuntimeEnvLock<T>(
params: Pick<
RunEmbeddedPiAgentParams,
"paperclipRuntimeAuth" | "runId" | "sessionId" | "sessionKey"
>,
Copy link

Copilot AI Apr 2, 2026

Choose a reason for hiding this comment

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

RunEmbeddedPiAgentParams (src/agents/pi-embedded-runner/run/params.ts) does not currently define a paperclipRuntimeAuth field, so this Pick<..."paperclipRuntimeAuth"...> and subsequent params.paperclipRuntimeAuth usage will not typecheck. Add paperclipRuntimeAuth (and its shape) to RunEmbeddedPiAgentParams (or change these helpers to accept an explicit Paperclip auth type) to keep the runner buildable.

Suggested change
"PAPERCLIP_AUTH_HEADER",
] as const;
let paperclipRuntimeEnvLock: Promise<void> = Promise.resolve();
async function withPaperclipRuntimeEnvLock<T>(
params: Pick<
RunEmbeddedPiAgentParams,
"paperclipRuntimeAuth" | "runId" | "sessionId" | "sessionKey"
>,
"PAPERCLIP_AUTH_HEADER",
] as const;
let paperclipRuntimeEnvLock: Promise<void> = Promise.resolve();
type PaperclipRuntimeEnvLockParams = {
paperclipRuntimeAuth?: unknown;
runId: string;
sessionId: string;
sessionKey: string;
};
async function withPaperclipRuntimeEnvLock<T>(
params: PaperclipRuntimeEnvLockParams,

Copilot uses AI. Check for mistakes.
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Apr 2, 2026

Greptile Summary

This PR fixes a one-line env-plumbing bug in createOpenClawCodingTools (pi-tools.ts) where paperclipRuntimeEnv passed through options.exec was being silently discarded because the explicit assignment paperclipRuntimeEnv: options?.paperclipRuntimeEnv overrode the ...execDefaults spread. The fix (options?.exec?.paperclipRuntimeEnv ?? options?.paperclipRuntimeEnv) is correct and minimal. Alongside the core fix, the PR introduces a per-run applyPaperclipRuntimeAuthEnv mechanism in pi-embedded-runner/run.ts that snapshots, applies, and restores PAPERCLIP_* env vars around each run, guarded by a promise-chain mutex (withPaperclipRuntimeEnvLock). Several test files are also updated to use a new asFetch cast helper in place of the previous direct-cast pattern.

Key concerns:

  • The withPaperclipRuntimeEnvLock mutex is only acquired for runs that have paperclipRuntimeAuth set; runs without it bypass the lock but still execute the snapshot/restore logic. If enqueueCommandInLane global-lane concurrency is ever raised above 1 (currently defaults to 1), a no-auth run that overlaps with an auth run could restore stale env values mid-flight of the auth run.
  • __paperclipAuthEnvTestUtils is exported directly from the production run.ts module, coupling test infrastructure to the production module interface.
  • The identical asFetch helper is copy-pasted into four separate test files rather than being extracted to a shared test utility.
  • The new regression test covers options.exec.paperclipRuntimeEnv but does not have a companion case for the top-level options.paperclipRuntimeEnv fallback.

Confidence Score: 3/5

  • The core one-line fix is correct and safe to merge; the new env-lock mechanism works correctly under the current serial-queue default, but has a latent race condition if lane concurrency is ever increased.
  • The primary bugfix in pi-tools.ts is straightforward and well-tested. The larger addition in pi-embedded-runner/run.ts introduces a mutex that is correctly implemented for the auth path, but bypasses locking for no-auth runs while still performing a snapshot/restore. With maxConcurrent=1 this is safe today, but the design is fragile under any future concurrency increase. The test-utility export from a production module and the duplicated asFetch helper are minor code quality issues that don't affect correctness now.
  • src/agents/pi-embedded-runner/run.ts — the withPaperclipRuntimeEnvLock / applyPaperclipRuntimeAuthEnv interaction for no-auth runs deserves a second look before any change to lane concurrency.

Comments Outside Diff (2)

  1. src/agents/pi-embedded-runner/run.ts, line 257-288 (link)

    P1 Lock not acquired for no-auth runs may cause env-state corruption if lane concurrency is raised

    withPaperclipRuntimeEnvLock only acquires the mutex when params.paperclipRuntimeAuth is truthy. Runs without auth skip the lock entirely and call fn() directly. However, applyPaperclipRuntimeAuthEnv is called unconditionally for every run (auth or not), and its returned restore function will overwrite all PAPERCLIP_* vars back to the snapshot taken at the start of that no-auth run.

    If enqueueCommandInLane for the global lane is ever configured with maxConcurrent > 1 (via setCommandLaneConcurrency), the following race becomes possible:

    1. Auth run A acquires the lock and sets PAPERCLIP_AUTH_HEADER / PAPERCLIP_API_KEY.
    2. No-auth run B starts concurrently (no lock), snapshots the env — which now includes A's auth values.
    3. Auth run A finishes and restores the env to its pre-run state.
    4. No-auth run B finishes and calls its restore, which re-writes A's stale auth values back — corrupting any subsequent run that started after A's restore.

    Since the current default is maxConcurrent: 1, this is not a live bug today, but the lock was clearly added in anticipation of potential concurrency, and the no-auth path bypasses it entirely.

    Consider either:

    • always acquiring the lock (not just for auth runs), or
    • skipping the snapshot/restore entirely when !auth (the no-op path does not modify env, so there is nothing to restore)
    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: src/agents/pi-embedded-runner/run.ts
    Line: 257-288
    
    Comment:
    **Lock not acquired for no-auth runs may cause env-state corruption if lane concurrency is raised**
    
    `withPaperclipRuntimeEnvLock` only acquires the mutex when `params.paperclipRuntimeAuth` is truthy. Runs _without_ auth skip the lock entirely and call `fn()` directly. However, `applyPaperclipRuntimeAuthEnv` is called unconditionally for every run (auth or not), and its returned restore function will overwrite all `PAPERCLIP_*` vars back to the snapshot taken at the start of that no-auth run.
    
    If `enqueueCommandInLane` for the global lane is ever configured with `maxConcurrent > 1` (via `setCommandLaneConcurrency`), the following race becomes possible:
    
    1. Auth run A acquires the lock and sets `PAPERCLIP_AUTH_HEADER` / `PAPERCLIP_API_KEY`.
    2. No-auth run B starts concurrently (no lock), snapshots the env — which now includes A's auth values.
    3. Auth run A finishes and restores the env to its pre-run state.
    4. No-auth run B finishes and calls its restore, which _re-writes_ A's stale auth values back — corrupting any subsequent run that started after A's restore.
    
    Since the current default is `maxConcurrent: 1`, this is not a live bug today, but the lock was clearly added in anticipation of potential concurrency, and the no-auth path bypasses it entirely.
    
    Consider either:
    - always acquiring the lock (not just for auth runs), or
    - skipping the snapshot/restore entirely when `!auth` (the no-op path does not modify env, so there is nothing to restore)
    
    How can I resolve this? If you propose a fix, please make it concise.
  2. extensions/microsoft/speech-provider.test.ts, line 9 (link)

    P2 asFetch helper copy-pasted across four test files

    The identical helper:

    const asFetch = <T extends typeof fetch>(fn: T): typeof fetch => fn as unknown as typeof fetch;

    is duplicated in extensions/microsoft/speech-provider.test.ts, extensions/msteams/src/graph.test.ts, extensions/voice-call/src/providers/twilio/api.test.ts, and src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts.

    Extracting it to a shared test utility (e.g. test/helpers/fetch.ts) would keep all four files in sync and make future type-signature changes a single edit.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: extensions/microsoft/speech-provider.test.ts
    Line: 9
    
    Comment:
    **`asFetch` helper copy-pasted across four test files**
    
    The identical helper:
    ```ts
    const asFetch = <T extends typeof fetch>(fn: T): typeof fetch => fn as unknown as typeof fetch;
    ```
    is duplicated in `extensions/microsoft/speech-provider.test.ts`, `extensions/msteams/src/graph.test.ts`, `extensions/voice-call/src/providers/twilio/api.test.ts`, and `src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts`.
    
    Extracting it to a shared test utility (e.g. `test/helpers/fetch.ts`) would keep all four files in sync and make future type-signature changes a single edit.
    
    How can I resolve this? If you propose a fix, please make it concise.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix All With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run.ts
Line: 257-288

Comment:
**Lock not acquired for no-auth runs may cause env-state corruption if lane concurrency is raised**

`withPaperclipRuntimeEnvLock` only acquires the mutex when `params.paperclipRuntimeAuth` is truthy. Runs _without_ auth skip the lock entirely and call `fn()` directly. However, `applyPaperclipRuntimeAuthEnv` is called unconditionally for every run (auth or not), and its returned restore function will overwrite all `PAPERCLIP_*` vars back to the snapshot taken at the start of that no-auth run.

If `enqueueCommandInLane` for the global lane is ever configured with `maxConcurrent > 1` (via `setCommandLaneConcurrency`), the following race becomes possible:

1. Auth run A acquires the lock and sets `PAPERCLIP_AUTH_HEADER` / `PAPERCLIP_API_KEY`.
2. No-auth run B starts concurrently (no lock), snapshots the env — which now includes A's auth values.
3. Auth run A finishes and restores the env to its pre-run state.
4. No-auth run B finishes and calls its restore, which _re-writes_ A's stale auth values back — corrupting any subsequent run that started after A's restore.

Since the current default is `maxConcurrent: 1`, this is not a live bug today, but the lock was clearly added in anticipation of potential concurrency, and the no-auth path bypasses it entirely.

Consider either:
- always acquiring the lock (not just for auth runs), or
- skipping the snapshot/restore entirely when `!auth` (the no-op path does not modify env, so there is nothing to restore)

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run.ts
Line: 359-362

Comment:
**Test utilities exported from production module**

`__paperclipAuthEnvTestUtils` exports internal implementation details (`applyPaperclipRuntimeAuthEnv` and `PAPERCLIP_RUNTIME_ENV_KEYS`) directly from the production `run.ts` file. This couples the test surface to the implementation and leaks internals into the public module interface.

Consider moving these to a dedicated test-helper file (e.g. `run.test-utils.ts`) or using Vitest's module-mocking approach so that the production module has no test-only exports.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: extensions/microsoft/speech-provider.test.ts
Line: 9

Comment:
**`asFetch` helper copy-pasted across four test files**

The identical helper:
```ts
const asFetch = <T extends typeof fetch>(fn: T): typeof fetch => fn as unknown as typeof fetch;
```
is duplicated in `extensions/microsoft/speech-provider.test.ts`, `extensions/msteams/src/graph.test.ts`, `extensions/voice-call/src/providers/twilio/api.test.ts`, and `src/agents/pi-embedded-runner.run-embedded-pi-agent.auth-profile-rotation.e2e.test.ts`.

Extracting it to a shared test utility (e.g. `test/helpers/fetch.ts`) would keep all four files in sync and make future type-signature changes a single edit.

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: src/agents/pi-tools.paperclip-runtime-env.test.ts
Line: 5-39

Comment:
**Top-level `paperclipRuntimeEnv` fallback path is not tested**

The regression test passes the env through `options.exec.paperclipRuntimeEnv`, which correctly exercises the primary path in the fix (`options?.exec?.paperclipRuntimeEnv ?? …`).

The complementary fallback — providing `options.paperclipRuntimeEnv` at the top level _without_ an `options.exec.paperclipRuntimeEnv` — is not covered by any test. A second test case mirroring the existing one but placing the `paperclipRuntimeEnv` map at the top level of options (rather than under `exec`) would close this gap and guard against the `??` being accidentally reversed in a future refactor.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: preserve paperclip runtime env in e..." | Re-trigger Greptile

Comment thread src/agents/pi-embedded-runner/run.ts Outdated
Comment on lines +359 to +362
const redactedSessionId = redactRunIdentifier(params.sessionId);
const redactedSessionKey = redactRunIdentifier(params.sessionKey);
const redactedWorkspace = redactRunIdentifier(resolvedWorkspace);
if (workspaceResolution.usedFallback) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Test utilities exported from production module

__paperclipAuthEnvTestUtils exports internal implementation details (applyPaperclipRuntimeAuthEnv and PAPERCLIP_RUNTIME_ENV_KEYS) directly from the production run.ts file. This couples the test surface to the implementation and leaks internals into the public module interface.

Consider moving these to a dedicated test-helper file (e.g. run.test-utils.ts) or using Vitest's module-mocking approach so that the production module has no test-only exports.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-embedded-runner/run.ts
Line: 359-362

Comment:
**Test utilities exported from production module**

`__paperclipAuthEnvTestUtils` exports internal implementation details (`applyPaperclipRuntimeAuthEnv` and `PAPERCLIP_RUNTIME_ENV_KEYS`) directly from the production `run.ts` file. This couples the test surface to the implementation and leaks internals into the public module interface.

Consider moving these to a dedicated test-helper file (e.g. `run.test-utils.ts`) or using Vitest's module-mocking approach so that the production module has no test-only exports.

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +5 to +39
it("passes exec.paperclipRuntimeEnv through to the exec tool defaults", async () => {
const tools = createOpenClawCodingTools({
workspaceDir: process.cwd(),
exec: {
host: "gateway",
security: "full",
ask: "off",
paperclipRuntimeEnv: {
PAPERCLIP_AUTH_HEADER: "Bearer test-header",
PAPERCLIP_API_KEY: "pcp_test_key",
},
},
sessionKey: "agent:test:paperclip",
});

const execTool = tools.find((tool) => tool.name === "exec");
expect(execTool).toBeTruthy();

const result = await execTool!.execute(
"toolcall-test",
{
command:
'node -e "console.log(JSON.stringify({auth:process.env.PAPERCLIP_AUTH_HEADER||null,key:process.env.PAPERCLIP_API_KEY||null}))"',
host: "gateway",
security: "full",
ask: "off",
},
new AbortController().signal,
async () => {},
);

const text = JSON.stringify(result);
expect(text).toContain("Bearer test-header");
expect(text).toContain("pcp_test_key");
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

P2 Top-level paperclipRuntimeEnv fallback path is not tested

The regression test passes the env through options.exec.paperclipRuntimeEnv, which correctly exercises the primary path in the fix (options?.exec?.paperclipRuntimeEnv ?? …).

The complementary fallback — providing options.paperclipRuntimeEnv at the top level without an options.exec.paperclipRuntimeEnv — is not covered by any test. A second test case mirroring the existing one but placing the paperclipRuntimeEnv map at the top level of options (rather than under exec) would close this gap and guard against the ?? being accidentally reversed in a future refactor.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/agents/pi-tools.paperclip-runtime-env.test.ts
Line: 5-39

Comment:
**Top-level `paperclipRuntimeEnv` fallback path is not tested**

The regression test passes the env through `options.exec.paperclipRuntimeEnv`, which correctly exercises the primary path in the fix (`options?.exec?.paperclipRuntimeEnv ?? …`).

The complementary fallback — providing `options.paperclipRuntimeEnv` at the top level _without_ an `options.exec.paperclipRuntimeEnv` — is not covered by any test. A second test case mirroring the existing one but placing the `paperclipRuntimeEnv` map at the top level of options (rather than under `exec`) would close this gap and guard against the `??` being accidentally reversed in a future refactor.

How can I resolve this? If you propose a fix, please make it concise.

- avoid mutating process.env for no-auth embedded runs
- add top-level paperclipRuntimeEnv fallback coverage
- move paperclip auth env test helpers out of production module exports
- dedupe asFetch into shared test helper
@bboyyan
Copy link
Copy Markdown
Contributor Author

bboyyan commented Apr 2, 2026

Fixed both comments.

  • moved the Paperclip auth env test helpers out of the production module surface into a dedicated helper module
  • added regression coverage for the top-level paperclipRuntimeEnv fallback path
  • also made the no-auth runtime env path a true no-op so it no longer touches process.env when runtime auth is absent
  • deduped repeated asFetch helpers into a shared test helper while touching the related tests

Validation:

  • test/pi-embedded-runner.paperclip-auth.test.ts
  • src/agents/pi-tools.paperclip-runtime-env.test.ts
  • extensions/microsoft/speech-provider.test.ts
  • extensions/voice-call/src/providers/twilio/api.test.ts
  • extensions/msteams/src/graph.test.ts

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9a58ff0276

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +951 to +952
paperclipRuntimeEnv: params.paperclipRuntimeEnv,
paperclipRuntimeAuth: params.paperclipRuntimeAuth,
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Forward Paperclip runtime env into attempt tool wiring

Passing paperclipRuntimeEnv/paperclipRuntimeAuth into runEmbeddedAttempt here does not actually deliver those values to the exec tool, because run/attempt.ts builds createOpenClawCodingTools(...) without forwarding either field (see src/agents/pi-embedded-runner/run/attempt.ts:1779-1834). In the real embedded-run path, exec still runs without PAPERCLIP_* variables, so Paperclip-authenticated commands continue to fail even though this commit adds plumbing and a regression test.

Useful? React with 👍 / 👎.

@clawsweeper
Copy link
Copy Markdown
Contributor

clawsweeper Bot commented May 1, 2026

Codex review: found issues before merge.

Summary
The PR adds Paperclip runtime auth env helpers and tests, attempts to pass Paperclip env values from embedded runner into exec tool defaults, and refactors several fetch test casts into a shared helper.

Reproducibility: yes. Static inspection is enough to reproduce the PR defects: the branch uses fields missing from current main types, createExecTool never consumes the proposed default, and the embedded attempt path still omits the env when creating tools.

Next step before merge
Maintainer review is needed because the remaining decision is whether to support Paperclip-specific exec credential env injection or treat it as superseded by provider runtime auth.

Security
Cleared: No concrete supply-chain regression or secret-value logging was found in the diff; the credential propagation design still needs maintainer/security review before implementation.

Review findings

  • [P1] Forward the Paperclip env into attempt tool creation — src/agents/pi-embedded-runner/run.ts:948-949
  • [P1] Make exec consume the runtime env default — src/agents/pi-tools.ts:434
  • [P2] Declare the Paperclip auth params before using them — src/agents/pi-embedded-runner/run.paperclip-auth-test-utils.ts:36-38
Review details

Best possible solution:

Decide the product boundary first; if Paperclip exec env is obsolete, close this PR as superseded by provider runtime auth, otherwise rebuild it as a typed end-to-end exec env contract with attempt forwarding, exec merging, sanitizer review, docs, and regression tests.

Do we have a high-confidence way to reproduce the issue?

Yes. Static inspection is enough to reproduce the PR defects: the branch uses fields missing from current main types, createExecTool never consumes the proposed default, and the embedded attempt path still omits the env when creating tools.

Is this the best way to solve the issue?

No. The PR is not the best current fix because it adds Paperclip-specific core plumbing only partway through the pipeline; the safer path is either the existing generic provider runtime-auth mechanism or a fully typed and reviewed generic exec-env contract.

Full review comments:

  • [P1] Forward the Paperclip env into attempt tool creation — src/agents/pi-embedded-runner/run.ts:948-949
    Passing paperclipRuntimeEnv and paperclipRuntimeAuth into runEmbeddedAttempt here does not deliver those values to the exec tool, because run/attempt.ts builds createOpenClawCodingTools(...) without forwarding either field. Real embedded runs would still construct the exec tool without the PAPERCLIP_* values.
    Confidence: 0.9
  • [P1] Make exec consume the runtime env default — src/agents/pi-tools.ts:434
    This adds paperclipRuntimeEnv to the defaults passed into createLazyExecTool, but ExecToolDefaults and createExecTool do not define or merge that field into the child process env. The values are ignored, so the new regression test is asserting behavior the implementation does not provide.
    Confidence: 0.91
  • [P2] Declare the Paperclip auth params before using them — src/agents/pi-embedded-runner/run.paperclip-auth-test-utils.ts:36-38
    buildPaperclipRuntimeEnv narrows RunEmbeddedPiAgentParams to paperclipRuntimeAuth, and run.ts also reads and assigns Paperclip fields, but those fields are not declared in the current params type. This leaves the branch unbuildable before the env plumbing can be exercised.
    Confidence: 0.86

Overall correctness: patch is incorrect
Overall confidence: 0.9

Acceptance criteria:

  • pnpm test src/agents/pi-tools.paperclip-runtime-env.test.ts test/pi-embedded-runner.paperclip-auth.test.ts
  • pnpm test src/agents/pi-embedded-runner/run/auth-controller.test.ts
  • pnpm check:changed

What I checked:

  • Current main has no Paperclip runtime env surface on tool options: createOpenClawCodingTools currently accepts exec?: ExecToolDefaults & ProcessToolDefaults and has no top-level paperclipRuntimeEnv, so the PR adds a new core option surface rather than preserving an existing typed field. (src/agents/pi-tools.ts:267, f523620abe7f)
  • Exec defaults do not define the proposed field: ExecToolDefaults has host/security/path/session defaults but no paperclipRuntimeEnv, so options.exec.paperclipRuntimeEnv is outside the current typed exec defaults contract. (src/agents/bash-tools.exec-types.ts:7, f523620abe7f)
  • Exec env construction ignores defaults-side env maps: createExecTool builds host env from sanitized process.env plus per-call params.env; there is no merge point for a defaults.paperclipRuntimeEnv value. (src/agents/bash-tools.exec.ts:1613, f523620abe7f)
  • Embedded attempt tool creation does not forward Paperclip fields: Current runEmbeddedAttempt calls createOpenClawCodingTools with execOverrides, sandbox, run context, and channel metadata, but no Paperclip runtime env/auth values. (src/agents/pi-embedded-runner/run/attempt.ts:867, f523620abe7f)
  • Run params do not declare the proposed auth fields: RunEmbeddedPiAgentParams has no paperclipRuntimeAuth or paperclipRuntimeEnv, so the PR's helper and run.ts assignments are not buildable against the current type surface. (src/agents/pi-embedded-runner/run/params.ts:26, f523620abe7f)
  • Current runtime auth contract is provider-generic: Current main stores prepared runtime credentials in authStorage after prepareProviderRuntimeAuth, and ProviderPreparedRuntimeAuth exposes generic apiKey/baseUrl/request/expiresAt fields rather than Paperclip env variables. (src/agents/pi-embedded-runner/run/auth-controller.ts:421, f523620abe7f)

Likely related people:

  • steipete: GitHub path history shows repeated recent maintenance across pi-tools.ts, bash-tools.exec.ts, and embedded runner attempt/tool prep code, including lazy loader, exec, and agent tool-prep changes. (role: recent maintainer and adjacent owner; confidence: high; commits: 59fb9e5ca7fe, cd398a543d9f, 738f5f7508ae; files: src/agents/pi-tools.ts, src/agents/bash-tools.exec.ts, src/agents/pi-embedded-runner/run/attempt.ts)
  • shakkernerd: Recent commits touched runtime auth scope, run auth-store reuse, and tool-prep tracing in the embedded runner areas most relevant to this PR's auth/runtime boundary. (role: runtime auth and embedded runner maintainer; confidence: medium; commits: 2fe3e779ffb1, 186b8e44dce2, a36a3ab0de15; files: src/agents/pi-embedded-runner/run/auth-controller.ts, src/agents/pi-embedded-runner/run/types.ts, src/agents/pi-tools.ts)
  • jalehman: Authored the provider runtime-auth exposure work that is the current generic alternative to Paperclip-specific env plumbing. (role: provider runtime-auth contract introducer; confidence: medium; commits: b8f12d99b254; files: src/plugins/runtime/runtime-model-auth.runtime.ts, src/plugins/types.ts, src/plugin-sdk/provider-auth-runtime.ts)
  • pashpashpash: Recent exec and diagnostics work touched bash-tools.exec.ts and exec approval boundaries, which are security-adjacent to any credential-bearing child-process env change. (role: adjacent exec approval/tooling maintainer; confidence: low; commits: 6ce1058296cc; files: src/agents/bash-tools.exec.ts)

Remaining risk / open question:

  • Maintainers still need to decide whether Paperclip-specific exec env injection is supported or superseded by the provider runtime-auth design.
  • If exec env injection is still required, it needs an explicit security boundary because it would expose runtime credentials to child processes for the run.

Codex review notes: model gpt-5.5, reasoning high; reviewed against f523620abe7f.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling channel: msteams Channel integration: msteams channel: voice-call Channel integration: voice-call size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants