chore: Make the security-scan log path safe for uncontainerised jobs #33
Labels
No labels
priority/P0
priority/P1
priority/P2
priority/P3
size/L
size/M
size/S
size/XL
size/XS
state/blocked
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#33
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
security-scanwrites to a fixed/tmp/security-scan.logand truncates it when the action starts, on the premise that a runner may reuse/tmpbetween jobs. Raised in the review of #32 as a question rather than a finding: if the runner shares a filesystem across concurrently-running jobs, twosecurityjobs would interleave into one file and each would see a mixed tail.Not reachable today, and here is the evidence rather than the assumption:
The only consumer runs the action inside a per-job container, so
/tmpis that container's. The exposure begins the moment a consumer adds asecurityjob without acontainer:.The consequence is a mixed or truncated tail on a failure — diagnostic quality, not a wrong exit code. That is why it was not a blocker for #32.
Why it was not simply fixed there
RUNNER_TEMPandrunner.tempare referenced nowhere in this repository or the consuming ones, so their behaviour on this runner is untested. Ifrunner.tempexpands to empty,outputs.log-pathbecomes/security-scan.logwhile the shell writes somewhere else — a silently wrong path, which is a worse failure than the one it prevents. Swapping a known-good constant for an unverified expression, on an approved change, to fix something no consumer can currently hit, is the wrong order to do things in.Scope
/tmpper job; if it does not, make the log path unique per job and keepoutputs.log-pathagreeing with it.Acceptance criteria
/tmpisolated per job, or shared.${{ runner.temp }}is used in a workflow on this runner, when the job runs, then it is confirmed to expand to a non-empty per-job path before anything depends on it.outputs.log-path, then it names the same file the action wrote — verified by a consuming job, not by inspection.securityjobs run concurrently without containers, when both fail, then each posts only its own output.Notes
The second criterion is the one that matters. The reason this is an issue rather than a commit is precisely that the obvious fix depends on an untested assumption, and substituting one unverified premise for another is not progress.
Plan, honouring the issue's ordering: evidence first. The WIP PR opens with a temporary probe step in validate that prints runner.temp, RUNNER_TEMP, the job's container identity (os-release, hostname) and /tmp's device — the runner's own CI run then answers criteria 1 and 2, and the findings land here as a comment before any path changes. Implementation follows the evidence: if runner.temp is confirmed non-empty and per-job, the action's log path moves to it with the output expression kept in lockstep (composite outputs evaluate runner context without a GITHUB_OUTPUT step, preserving the deliberate literal-output shape); a shell-side guard keeps /tmp as fallback so an empty expansion can never produce /security-scan.log. The probe commit is dropped before the PR leaves WIP.
Findings from the probe run (platform-actions run 2432, validate job — the probe step is in that log verbatim):
Criterion 1 — the runner's filesystem model: /tmp is isolated per job. The job executed inside its own docker container (
docker exec, container hostname25c4a0f7d05e,overlaymounted at/), and its/tmpcontained exactly one file: the marker the probe had just written. Nothing from any other job, ever. This is act_runner's label→image model: every job — with or without acontainer:of its own — runs in a per-job container. Corroborating operational evidence:ahmad/expiro'simagejob (nocontainer:) installs the docker CLI with apt from scratch every run and its/tmp/image-job.loghas never collided across the hundreds of runs this week.Criterion 2 —
${{ runner.temp }}expands non-empty: it expands to exactly/tmp(andRUNNER_TEMP=/tmpin the environment). So the "obvious fix" — substituting the expression for the constant — would be a semantic no-op on this runner: same path, same isolation, one more layer of indirection.Conclusion: the scope's conditional ("if it does not isolate, make the path unique") does not fire. The fixed
/tmp/security-scan.logis safe because isolation comes from the per-job container, not from the path — and criteria 3 and 4 hold by construction under that model. The interleaving scenario would require the runner to switch to host-mode execution, which would break far more than this log (every apt-get install in every workflow); if that ever changes, this issue's probe is the two-minute way to re-answer.Closing: the issue asked for an answer before a change, and the answer is that no change is warranted. The probe commit is discarded and the WIP PR closed without merging.