Skip to content

The action-pin check counts a directory named x.yml as a workflow it read #444

Description

@vladimirrott

#443 closes the case where assert_action_pins cannot read a workflow file: the loop now refuses and names the path. One entry of the same shape survives it. [ -r "$workflow" ] is true for a directory, grep on a directory exits 2 with Is a directory, and a process substitution's exit status is never checked, so the file count stays where it was and the run reports success over something it never opened.

Measured

On #443's head ce773581, with a probe appended to a copy of the shipped test (the probe is mine, it is not part of that pull request) and the whole script run in a container as uid 1000:

# PROBE (maintainer, not part of the PR): a *directory* named x.yaml passes -r.
mkdir -p "$pin_fixture/dirshaped"
printf '  uses: ./.github/workflows/local.yml\n' > "$pin_fixture/dirshaped/readable.yml"
mkdir "$pin_fixture/dirshaped/blocked.yaml"
if probe_out="$(assert_action_pins "$pin_fixture/dirshaped" 1 2>&1)"; then
    printf 'PROBE: pin check PASSED over a directory named blocked.yaml\n' >&2
else
    printf 'PROBE: pin check refused: %s\n' "$probe_out" >&2
fi
PROBE: pin check PASSED over a directory named blocked.yaml
Release rehearsal contract passed.
TEST rc=0

The readable file clears the floor of 1 on its own, which is the same arrangement #442 used: one entry answers for the directory and nobody notices the other one was skipped.

Severity, stated plainly

Lower than #442. A directory named docs.yml under .github/workflows is not something an ordinary checkout grows, and GitHub would ignore it as well. What makes it worth closing is the shape: this is the third way the same loop reports "asked, found nothing" for "could not ask", after the empty glob (#432) and the unreadable file (#442).

Suggested shape

Fold the file-type test into the arm that #443 added, and keep the message specific about which of the two failed:

[ -f "$workflow" ] || {
    printf 'FAIL: not a regular file: %s\n' "$workflow" >&2
    return 1
}
[ -r "$workflow" ] || {
    printf 'FAIL: cannot read %s\n' "$workflow" >&2
    return 1
}

A single combined condition is shorter and worse: the test then cannot tell the two refusals apart, and a diagnostic that covers both is one a future mutation can satisfy for the wrong reason.

Tests first

Copy the fixture #443 added at the end of tests/release/release-rehearsal.test.sh. Build a directory holding one readable .yml and one mkdir-ed blocked.yaml, call assert_action_pins with a floor of 1, require a non-zero exit and require the exact diagnostic with grep -Fxq. Write it before the fix and watch it print PROBE:-style success, as above.

No root skip is needed for this one: a directory is a directory for uid 0 too, which makes it cheaper to test than #442 was.

Difficulty

easy. Four lines of guard and one fixture, in a file whose test harness already exists. No Rust, no VM, no daemon, no credentials.

Getting started

CONTRIBUTING.md has the build and test commands. The only one you need here is bash tests/release/release-rehearsal.test.sh.

Land #443 first: this edits the four lines that pull request adds.

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingeasyDifficulty: self-contained, no deep context neededhelp wantedExtra attention is needed

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions