Skip to content

fix: keep scan reports private and accessible to the runner - #87

Open
ANAMASGARD wants to merge 2 commits into
kubescape:mainfrom
ANAMASGARD:fix/report-ownership-and-finalization
Open

ANAMASGARD wants to merge 2 commits into
kubescape:mainfrom
ANAMASGARD:fix/report-ownership-and-finalization

Conversation

@ANAMASGARD

@ANAMASGARD ANAMASGARD commented Oct 23, 2026 •

Copy link
Copy Markdown
Member

Summary

Fixes #85.

Ensure downstream GitHub Actions steps can read generated scan reports while preserving the Kubescape CLI’s intentional owner-only permissions.

Problem

The action runs its scan container as root, while subsequent upload steps run as the non-root GitHub Actions runner. With CLI v4.0.16, reports written with mode 0600 can therefore fail to upload with EACCES.

Additionally, scanner threshold failures exit the entrypoint before SARIF normalization. Successful normalization can instead replace a private report with a temporary file whose permissions depend on the umask.

Changes

  • Run the container using the invoking runner’s UID/GID.
  • Provide a writable, ephemeral container HOME.
  • Normalize available SARIF reports even when scanning returns a nonzero status, then preserve the original scanner exit code.
  • Use unique, owner-only temporary files and clean them up on failure.
  • Fail otherwise successful scans when SARIF is missing, malformed, or empty, or requested JSON is missing.
  • Preserve autofix behavior and propagate autofix errors.
  • Exercise the checked-out action in configuration/image scan workflows rather than upstream @main.
  • Add report-finalization and container-access regressions to test CI.

No recursive workspace permission changes or world-readable report workaround is introduced.

Validation

  • 75 script assertions passed: 19 entrypoint, 23 command-construction, and 33 report-finalization assertions.
  • Six local container-boundary cases passed using rootless Podman.
  • Real CLI v4.0.16 checks covered threshold failures, nested output paths, restrictive umasks, arbitrary numeric UIDs, writable cache, actual manifest autofix, and SARIF/JSON outputs.
  • New regressions fail against the unchanged upstream baseline.
  • Bash syntax, changed production/new-test ShellCheck, and whitespace checks passed.

Hosted workflows executing this branch’s action both passed, including SARIF uploads:

Threshold-triggered scanner failures remain failures; the workflows’ existing continue-on-error permits subsequent upload steps.

Scope and remaining validation

This PR addresses report ownership and finalization only. The CodeQL uploader-version update remains separate, and the SARIF path correction from #84 is preserved.

Hosted JSON artifact-upload validation remains outstanding.

Summary by CodeRabbit

  • Bug Fixes
    • Reports are now finalized before the scanner’s exit status is returned. Missing or invalid requested reports, and report-processing failures, now result in a failure instead of being silently ignored.
    • Generated reports are restricted to the invoking user, and SARIF artifacts retain workspace-relative paths.
    • Automatic fixes run only after scanning and report finalization succeed.
  • Updates
    • Example workflows now run the action from the checked-out repository rather than the published version.

Run the container as the invoking UID/GID with a writable temporary home. Finalize SARIF even after scanner failure, preserve the scanner exit status, and use private temporary files with explicit finalization errors. Add report and container-boundary regressions and exercise the local action in scan workflows.

Signed-off-by: Gaurav Chaudhary <chaudharygaurav2004@gmail.com>
@coderabbitai

coderabbitai Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Warning

Review limit reached

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

Next included review available in 44 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: 638d15e5-7e13-4f45-8b6c-6469ca2e1cef
📥 Commits

Reviewing files that changed from the base of the PR and between b04f11b and 83e2342.

📒 Files selected for processing: 3
  • .github/workflows/example-fix-pr-review.yaml
  • tests/action_test.sh
  • tests/report-container_test.sh

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: defaults
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: d6629223-9eb6-4104-8423-9d6ae7aba49a
📥 Commits

Reviewing files that changed from the base of the PR and between 6a52718 and b04f11b.

📒 Files selected for processing: 8
  • .github/workflows/example-scan-image.yaml
  • .github/workflows/example-scan.yaml
  • .github/workflows/test.yaml
  • action.yml
  • entrypoint.sh
  • tests/action_test.sh
  • tests/report-container_test.sh
  • tests/report_test.sh

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

📝 Walkthrough

The action now runs its scan container with the runner’s UID and GID. The entrypoint finalizes SARIF and requested JSON reports while preserving the scanner’s exit status. New tests cover report permissions, finalization failures, and autofix. Repository scan examples use the checked-out action.

Changes: Report access and finalization

Layer / File(s) Summary
Container identity and report access
action.yml, tests/action_test.sh, tests/report-container_test.sh, .github/workflows/example-scan*.yaml
The container runs as the runner’s UID:GID with HOME=/tmp. Container tests check report ownership and mode, output validity, thresholds, and autofix behavior. The example workflows use the checked-out action.
Report finalization and regression coverage
entrypoint.sh, tests/report_test.sh, .github/workflows/test.yaml
The entrypoint finalizes SARIF and requested JSON, returns the scanner’s nonzero status before any finalization status, and runs kubescape fix only after successful checks. Tests cover report errors, path handling, permissions, and autofix. The test workflow runs the new report tests.

Priority: ➖ Normal

Estimated code review effort: 3 (Moderate) | ~25 minutes

Change: Bug fix · Severity of issue fixed: Medium

Possibly related PRs

Suggested reviewers: matthyx

Merge Risk: ⚪ Minimal · up to b04f1

Report handling appears ready to merge after normal checks. Hosted JSON artifact-upload validation remains outstanding.

Pre-merge checks: Passed 4 · Failed 1

Failed Failed checks: 1 warning

Check name Status Explanation Resolution
Docstring Coverage Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 4 files. (4 skipped: 4… Write docstrings for the functions missing them to satisfy the coverage threshold.
Passed Passed checks: 4 passed
Check name Status Explanation
Description Check Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check Passed The title "fix: keep scan reports private and accessible to the runner" matches the main change. The PR runs the scan container as the runner's UID/GID with HOME=/tmp, so reports stay owner-only yet r…
Linked Issues check Passed The PR addresses the active coding requirements in #85. action.yml runs the container with the runner UID/GID and sets HOME=/tmp. entrypoint.sh preserves the scanner status, normalizes available…
Out of Scope Changes check Passed The changes stay within #85. Workflow changes execute the checked-out action and add regression tests for report finalization and container access. These changes directly validate the report-access fi…
Full details: Title check

Explanation

The title "fix: keep scan reports private and accessible to the runner" matches the main change. The PR runs the scan container as the runner's UID/GID with HOME=/tmp, so reports stay owner-only yet readable by the runner. It also finalizes SARIF after scanner failure and preserves the scanner's exit status, which the title does not mention. The title is specific, concise, and free of noise.

Full details: Linked Issues check

Explanation

The PR addresses the active coding requirements in #85. action.yml runs the container with the runner UID/GID and sets HOME=/tmp. entrypoint.sh preserves the scanner status, normalizes available SARIF after scanner failure, checks requested SARIF and JSON outputs, uses a private temporary file with cleanup, preserves autofix behavior, and propagates autofix errors. The added tests cover threshold failures, nested paths, restrictive umasks, malformed and empty reports, missing outputs, and autofix. The reported hosted SARIF checks passed. Outstanding hosted JSON validation is explicitly noted and is not required for the coding verdict.

Full details: Out of Scope Changes check

Explanation

The changes stay within #85. Workflow changes execute the checked-out action and add regression tests for report finalization and container access. These changes directly validate the report-access fix. No recursive workspace permission change, world-readable report workaround, or separate CodeQL uploader update is introduced.

Full details: Docstring Coverage

Explanation

Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff. Analyzed 4 functions across 4 files. (4 skipped: 4 unsupported.)

Resolution

Write docstrings for the functions missing them to satisfy the coverage threshold.

✨ Finishing Touches: 💡 1
🛠️ Fix failing CI checks: 💡
  • Commit to this branch
  • Create a new PR
🧪 Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Run the unprivileged autofix scan against the checked-out action so its JSON reports use the runner identity. Resolve the container test runtime before shadowing Docker on PATH to avoid recursive shim execution. Add workflow-selection and bounded default-Docker dispatch regressions.

Signed-off-by: Gaurav Chaudhary <chaudharygaurav2004@gmail.com>

@matthyx matthyx 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.

Request changes: the ownership/finalization fix is needed, but one introduced format-compatibility regression remains.

P2 — Match the JSON format as a complete token (entrypoint.sh:183). contains "${output_formats}" "json" also matches supported image formats cyclonedx-json and spdx-json. With image: nginx, either format and the default outputFile: results, a successful scanner writes results.cdx.json or results.spdx.json. This new guard instead requires results or results.json and returns failure (JSON file results not found.). The CLI v4.0.16 format/output contract confirms those formats and extensions. A credential-free, network-isolated boundary reproduction with successful scanner fixtures returned baseline=0, PR=1 for both formats. Use exact comma-delimited membership for the standalone json format and add both regressions. The existing substring-based autofix behavior predates this PR; this finding concerns the newly unconditional report check.

Reviewed head 83e2342c8ba2d5985875de989a534bd887259e0d against main at 6a527186fc87c668469fe8b9333b251ffc4eaed8. Immediately before submission the PR remained open, non-draft and mergeable, with both commits unchanged and no human reviews or inline threads to duplicate.

Necessity: #85 documents root-owned 0600 reports; the target still runs Docker without --user. Matching the runner identity fixes the producer/consumer boundary without weakening confidentiality. Capturing scanner status, private temporary files, cleanup, and preserving failed scan status are sound. No other material blocker found across the nine changed files; independent architecture review identifies the format guard as a blocker.

History: merged #84 fixes SARIF paths and is preserved; open #88 updates the uploader and is complementary. Merged #3 explicitly approved non-root execution. #61, #71 and #50 concern missing/empty reports or Helm attribution, not this ownership fix. Closed #7 was explicitly replaced by #9; #44 has no recorded rejection of this approach. #20 reverted an executable-bit regression, not non-root execution. No duplicate/superseding ownership fix found. Search covered all 65 PRs and 23 issues plus repository search for SARIF, permissions and entrypoint symbols; this does not cover private/unindexed discussions or all forks.

Validation: inspected scripts before executing in Bubblewrap with cleared environment, network isolation, read-only source and ephemeral writable storage. bash tests/entrypoint_test.sh: 19/19; bash tests/action_test.sh: 27/27; bash tests/report_test.sh: 33/33. The report suite against main's entrypoint fails 10/33 assertions. Shell syntax and git diff --check pass. ShellCheck unavailable; real CLI/container tests not rerun locally. Latest test CI confirms all six container cases pass. Hosted configuration and image logs confirm completed SARIF uploads after threshold failures. Autofix CI successfully uploads both results.sarif and results.json, closing the description's stated hosted JSON-upload gap. Those checks do not cover SBOM-only formats.

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

Labels

None yet

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

Scan reports are unreadable by downstream GitHub Actions steps

2 participants