Repository navigation
Scan reports are unreadable by downstream GitHub Actions steps #85
Description
Description
Scan reports generated by the action can be unreadable by subsequent GitHub Actions steps, causing SARIF uploads and JSON artifact uploads to fail with EACCES.
We encountered this while investigating failed configuration-scan, image-scan, and autofix workflows. The scanner produced reports, but downstream uploaders could not open them.
This was reproduced with Kubescape CLI v4.0.16 and action revision 6a527186fc87c668469fe8b9333b251ffc4eaed8, which already includes the separate SARIF path fix from #84.
Environment
- Linux runner with rootful Docker.
- Non-root host runner executing subsequent workflow steps.
- Kubescape CLI v4.0.16.
- SARIF and JSON output formats.
Steps to reproduce locally
Prerequisites: Git, Docker, jq, and internet access. Run these commands as a non-root user with access to a rootful Docker daemon.
- Check out the affected action and build its container:
git clone https://github.com/kubescape/github-action.git github-action-report-repro
cd github-action-report-repro
git checkout 6a527186fc87c668469fe8b9333b251ffc4eaed8
docker build \
--build-arg KUBESCAPE_VERSION=v4.0.16 \
-t kubescape-action-report-repro .- Create a manifest fixture. This is scanned only; do not deploy it:
repro_dir=$(mktemp -d)
mkdir -p "$repro_dir/k"
cat > "$repro_dir/k/pod.yaml" <<'YAML'
apiVersion: v1
kind: Pod
metadata:
name: privileged-report-repro
spec:
containers:
- name: app
image: nginx:alpine
securityContext:
privileged: true
YAML- Run a scan that produces reports and fails the High severity threshold:
scan_status=0
docker run --rm \
-v "$repro_dir:/github/workspace" \
-w /github/workspace \
-e GITHUB_ACTIONS=true \
-e GITHUB_WORKSPACE=/github/workspace \
-e INPUT_CONTROLS=C-0057 \
-e INPUT_FILES=. \
-e INPUT_FORMAT=sarif,json \
-e INPUT_OUTPUTFILE=results \
-e INPUT_SEVERITYTHRESHOLD=high \
-e INPUT_FIXFILES=false \
kubescape-action-report-repro || scan_status=$?
printf 'Scanner exit status: %s\n' "$scan_status"- Inspect the reports and try reading them as the same non-root host user:
stat -c '%a %u:%g %n' \
"$repro_dir/results.sarif" \
"$repro_dir/results.json"
jq -e . "$repro_dir/results.sarif"
jq -e . "$repro_dir/results.json"Observed: the reports are owned by container root with mode 0600, and the non-root reader receives permission errors.
Rootless Docker/Podman uses different UID mappings, so it requires an appropriately mapped producer/consumer test rather than assuming identical host ownership.
Expected behavior
- The runner can read the requested reports without making them world-readable.
- Newly created nested output directories remain accessible to that runner.
- A threshold failure still returns the scanner's original nonzero exit status.
- Valid SARIF produced before a threshold failure is still normalized.
- Finalization errors fail an otherwise successful action.
Actual behavior and root cause
The composite action starts Docker without --user, so the container runs as root. CLI v4.0.16 intentionally writes reports with owner-only permissions because reports may contain sensitive data.
Two entrypoint behaviors compound the problem:
set -eexits immediately after a scanner threshold failure, skipping SARIF finalization.- After successful scans, the predictable SARIF temporary-file replacement can change
0600to0644under umask0022. JSON remains0600. Nested root-owned0750directories can also prevent traversal.
Typical downstream failures include:
EACCES: permission denied, open 'results.sarif'
EACCES: permission denied, open 'results.json'
These errors indicate unreadable files, not necessarily malformed SARIF.
Real-world impact
Scans can detect findings successfully while their reports cannot be uploaded to GitHub Code Scanning, archived as artifacts, or consumed by later review tooling.
Making reports world-readable would undermine the CLI's intentional confidentiality protection.
Proposed resolution
- Run the container using the invoking runner's UID/GID.
- Provide a writable, ephemeral container HOME/cache location.
- Preserve owner-only report permissions and accessible nested directories.
- Finalize available SARIF after scanner failure, then return the original scanner status.
- Use unique, private temporary files with cleanup on failure.
- Detect missing, malformed, or empty SARIF and propagate finalization errors.
- Preserve autofix behavior and avoid recursive workspace ownership/permission changes.
Verification
The candidate correction has passing local regression and real-CLI coverage, including threshold failures, restrictive umasks, nested paths, arbitrary numeric UIDs, and actual manifest autofix.
Hosted configuration and image scans using the candidate action both completed successful SARIF uploads:
Hosted JSON artifact-upload validation remains outstanding.
This issue is independent of #83/#84 and the separate CodeQL uploader-version update.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsAccepted
Activity