Skip to content

Fix cp settle: reject on V1Status only, not on stderr#374

Draft
jeanschmidt wants to merge 1 commit into
actions:mainfrom
jeanschmidt:jeanschmidt/upstream-pr03-cp-status-only-reject
Draft

Fix cp settle: reject on V1Status only, not on stderr#374
jeanschmidt wants to merge 1 commit into
actions:mainfrom
jeanschmidt:jeanschmidt/upstream-pr03-cp-status-only-reject

Conversation

@jeanschmidt

@jeanschmidt jeanschmidt commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Fix cp settle: reject on V1Status only, not on stderr

Impact: every job that uses execCpToPod / execCpFromPod (workspace setup, result extraction)
Risk: low

What

Routes the settle decision for execCpToPod and execCpFromPod through V1Status.status === 'Success' (the authoritative signal from the Kubernetes exec channel) instead of treating any non-empty stderr as failure. Stderr is still surfaced via core.debug.

Why

tar writes tar: Removing leading '/' from member names to stderr on essentially every cp call. The previous "reject if errStream.size()" check interpreted that benign warning as a failure, which tripped the surrounding 30-attempt retry loop on every single cp. Every job paid the cost across workspace setup and step-result extraction, even though the underlying exec succeeded the first time.

How

V1Status from the kc exec status callback is the authoritative success/failure signal — that is what the rejection now keys on. Benign stderr is forwarded to debug logs so operators can still inspect it but no longer drives control flow. Existing failure paths (real exec errors, Failure status) still reject with stderr included in the message.

A couple of small incidental fixes are folded in to keep the two functions symmetric and the failure path clean:

  • Added the missing return after reject(...) (the old code fell through to resolve(status) on the failure path — a double-settle that was hidden by promise semantics but is wrong on the face of it).
  • execCpFromPod's error message now includes status: ${status.status} to match execCpToPod.
  • Defensive handling for V1Status.status === undefined (the type is string | undefined) — treated as failure.

- execCpToPod/execCpFromPod now settle on V1Status.status === 'Success'
  instead of treating any non-empty stderr as failure
- Forward stderr to core.debug on Success so operators can still inspect
  it without promoting tar warnings to errors
- Align execCpFromPod error message to include `status:` like execCpToPod,
  and handle `{status: undefined}` defensively
- Add exec-cp-settle-policy-test.ts covering Success-with-stderr,
  Failure, and undefined-status paths for both directions

Notes:
Upstream rejects whenever errStream is non-empty after a `kc exec` cp,
but tar writes `tar: Removing leading '/' from member names` to stderr
on every copy. That triggered the 30-attempt retry loop on every job,
costing wall-clock time and masking real failures behind a noisy
"details:" dump. The Kubernetes exec channel already reports outcome
via V1Status; that's the authoritative signal, so settle on it alone.

Incidentally fixes a pre-existing double-settle in the upstream code
path where reject() fell through to resolve() in the same callback,
by adding an explicit `return` after reject.
Copilot AI review requested due to automatic review settings June 11, 2026 15:23

Copilot AI left a comment

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.

Pull request overview

Note

Copilot was unable to run its full agentic suite in this review.

Adds retry/settle behavior fixes for Kubernetes exec-based tar copy operations so that benign stderr on Success no longer causes retries, and introduces Jest tests to lock this behavior in.

Changes:

  • Update execCpToPod / execCpFromPod to reject only on non-Success V1Status, while still logging stderr on success.
  • Improve error formatting to avoid interpolating false when stderr is empty.
  • Add Jest tests covering success-with-stderr, failure-with-stderr, and undefined-status scenarios.

Reviewed changes

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

File Description
packages/k8s/src/k8s/index.ts Changes settle policy to key off status.status and debug-log benign stderr on success.
packages/k8s/tests/exec-cp-settle-policy-test.ts Adds tests validating the new settle/retry behavior for both directions of cp.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +100 to +106
await expect(
execCpToPod('my-pod', '/tmp/src', '/workspace')
).resolves.toBeUndefined()

// The whole point of the fix: benign stderr on Success must NOT
// trigger a retry. Exactly one tar-cp exec call.
expect(mockExec).toHaveBeenCalledTimes(1)
reject(
new Error(
`Error from cpFromPod - details: \n ${errStream.getContentsAsString()}`
`Error from cpFromPod - status: ${status.status}, details: \n ${errDetail}`
Comment on lines +79 to +84
describe('execCpToPod settle policy', () => {
beforeEach(() => {
jest.clearAllMocks()
mockDebug.mockReset()
process.env['ACTIONS_RUNNER_KUBERNETES_NAMESPACE'] = 'test-namespace'
})
@jeanschmidt jeanschmidt marked this pull request as draft June 11, 2026 15:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants