chore: Expose security-scan output so consumers can report failures #29
Labels
No labels
priority/P0
priority/P1
priority/P2
priority/P3
size/L
size/M
size/S
size/XL
size/XS
state/done
state/in-progress
state/in-review
state/needs-refinement
state/ready
type/bug
type/chore
type/feature
type/refactor
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
amtronics/platform-actions#29
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Context
Forgejo Actions serves no job logs over its REST API —
/actions/jobs/{id}/logs,/actions/runs/{n}/jobs/{i}/logsand/actions/tasks/{id}/logsall return 404. Consuming repositories work around this by having a job capture its own output withteeand post the tail as a pull request comment on failure.That workaround cannot be applied to a job whose work is a composite action. In
ahmad/expiro's PR pipeline the wholesecurityjob is:There is nothing in the consuming workflow to redirect: the action's steps run inside it, and their output is not reachable from outside. So a red
securityis a bare word, and the report-only findings the action is supposed to surface are readable only from a browser.This came up while fixing the same gap for
expiro'svalidatejob (ahmad/expiro#25), where a red check blocked a pull request through three rounds of guessing.validatecould be fixed in the consuming repository;securitycannot.Scope
security-scanwrites its own output to a path it exposes as an output (or a documented fixed path), so a consuming workflow can post the tail on failure; the action's README documents it.enforcedefault, or any consuming repository's workflow — those follow once the output exists.Acceptance criteria
if: failure()step, when the job fails, then the tail can be posted without reading the run log.tee, when a piped command fails, then the step still fails —set -o pipefailis set, because arun:step's shell isbash -ewithout it.Note
ahmad/expiro'svalidatejob is the worked pattern, and one measured detail from writing it: preferset -o pipefailwithcmd 2>&1 | tee -a logoverexec > >(tee -a log) 2>&1. Both preserve the command's exit status, but the process-substitution form'steeoutlives the shell — the log can be unflushed or absent when a later step reads it. The pipeline finishes writing before it returns.Picking this up.
expiro's pipeline has been unable to reach Docker Hub since 02:06, so this repository is where work can still finish; this issue is also the thing that unblocksexpiro#25's fourth criterion, which I left visibly unmet for exactly this reason.The approach. Each scanning step already captures its tool's exit code inline (
cmd && rc=0 || rc=$?) because the runner injects-e. Adding2>&1 | tee -a "$LOG"keeps that working: every step already setspipefail, so the pipeline's status is the tool's, nottee's. That is the trap recorded in the knowledge file and it is already avoided here — worth stating because it is the one change that could silently turn a failing scan green.On exposing the path. I am declaring
outputs.log-pathwith a literal value rather than threading it through a step'sGITHUB_OUTPUT. A step that sets it would needif: always(), or it would not run in enforce mode when a scan fails — which is precisely the case a consumer wants the log for. A constant cannot fail to be set.Two things I will be careful about, both from tonight:
expiro#26shipped a fallback that could never fire because a redirection created the file it was checking for; the same shape is available here and I will test the composed form rather than the halves.Out of scope: changing what the scanners check, the
enforcedefault, or any consuming workflow. Consumers wiring up the tail is a follow-up in each repository —expiro#25already names it.