Skip to content

Redact delegated command output in workspace test and workspace setup reports #2425

Description

@codeforester

Goal

Route delegated-command output captured by basectl workspace test and basectl workspace setup through Base's existing subprocess redaction before it reaches stdout, stderr, or the stable JSON report.

Background

Release review on 2026-10-01 against Base 951b16d60597e4c6bf67a9701c55739f962ccaaa.

Base already owns a redaction helper for captured child output, base_setup.process.redact_command_output, which masks NAME=<secret> assignments and scheme://user:password@host URL credentials. #2396 hardened that path so redaction survives read boundaries.

The workspace fan-out commands bypass it. workspace_test.execute_workspace_test_target captures the delegated basectl test run with subprocess.run(capture_output=True) and stores the raw text on WorkspaceTestResult. print_workspace_test_result echoes it verbatim, and workspace_test_project_to_json copies it verbatim into the stdout/stderr keys of the schema_version: 1 report. workspace_setup relays captured setup output the same way.

Reproduced locally with a two-file throwaway workspace whose project test command prints secret-shaped lines:

# demo/run-tests.sh
echo "GITHUB_TOKEN=ghp_LEAKEDSECRET0123456789"
echo "cloning https://alice:ghp_URLSECRET9876@github.com/acme/private.git"
exit 1

basectl workspace test --workspace <ws> --manifest <ws>/workspace.yaml --format json emitted:

"stdout": "GITHUB_TOKEN=ghp_LEAKEDSECRET0123456789\ncloning https://alice:ghp_URLSECRET9876@github.com/acme/private.git\n",

The same two lines passed through redact_command_output return:

GITHUB_TOKEN=[REDACTED]
cloning https://[REDACTED]@github.com/acme/private.git

This matters because the delegated command is project-owned and arbitrary: a failing test, a build script, or a tool that echoes its environment can place a credential in Base's own machine-readable output. That report is explicitly designed for CI consumption, so the value typically lands in a CI log, an artifact, or a pasted issue comment. workspace update and workspace clone have a narrower version of the same shape: git_pull_detail and clone_detail fold raw Git stdout/stderr into the stable detail field.

No secret was exposed outside the local throwaway workspace while reproducing this.

Scope

  • Apply the existing subprocess redaction to child output captured by workspace test and workspace setup before printing it and before serializing it into JSON.
  • Use the same helper rather than a second redaction implementation, so base_setup and base_projects cannot drift.
  • Audit the remaining workspace fan-out paths that fold child output into stable fields (workspace_update.git_pull_detail, workspace_update.format_git_pull_debug_output, workspace_clone_command.clone_detail) and apply redaction where child output reaches user or machine-readable output.
  • Keep the redacted text readable: redaction should mask values, not drop lines or reorder output.

Acceptance Criteria

  • basectl workspace test --format json masks NAME=<secret> assignments and URL credentials in the stdout and stderr keys.
  • basectl workspace test text output masks the same values on stdout and stderr.
  • basectl workspace setup masks the same values in relayed setup output.
  • workspace update and workspace clone detail fields carry redacted child output.
  • Non-secret child output is unchanged, including exit codes, ordering, and trailing newlines.
  • Regression tests assert the redacted form for a fixture child command that prints a secret-shaped assignment and a credentialed URL, and fail before the fix.

Validation

Build the throwaway workspace above, run basectl workspace test --format json and the text form, and assert the token does not appear. Then run:

BASE_CLI_SOURCE_DIR=../base-cli/lib/python \
PYTHONPATH=../base-cli/lib/python:lib/python:cli/python \
python -m pytest cli/python/base_projects/tests cli/python/base_setup/tests/test_artifacts.py
bats cli/bash/commands/basectl/tests/workspace.bats
basectl test base

Non-Goals

Do not add a new redaction engine, do not suppress or truncate child output, and do not change the workspace test or workspace update JSON schema shape beyond the value of already-defined string fields.

Project Fields

  • Status: Ready
  • Priority: P1
  • Area: Workspace
  • Initiative: Contract Hardening
  • Size: M
  • Milestone: v1.10.0
  • Category: security

Agent Assignment

Assignee: codeforester. Implementation-ready; use an issue-backed worktree and reuse base_setup.process.redact_command_output rather than adding a parallel implementation.

Related: #2432 publishes the workspace test JSON schema and should land after this redaction fix so the schema documents redacted values.

Activity

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

Metadata

Metadata

Assignees

Labels

securitySecurity hardening or vulnerability work

Type

No type

Projects

  • Status
    In Progress

Relationships

None yet

Development

No branches or pull requests

Issue actions