Skip to content

Fix/reject multi line inputs unset va files under - #5

Merged
donkan168 merged 2 commits into
mainfrom
fix/reject-multi-line-inputs-unset-VA_FILES-under
Oct 18, 2026
Merged

donkan168 merged 2 commits into
mainfrom
fix/reject-multi-line-inputs-unset-VA_FILES-under

Conversation

@donkan168

Copy link
Copy Markdown
Collaborator

No description provided.

Line coverage of scripts/ (kcov, merged over the unit tests):
  before: 21.05% (92/437; only test/checksum-test.sh, which needs the network:
          install.sh 70%, lib.sh 58%, verify-checksum.sh 87%, check.sh and
          resolve.sh 0%)
  after:  97.48% (426/437): check.sh 96.3%, install.sh 98.4%, lib.sh,
          resolve.sh and verify-checksum.sh 100%
kcov reports lines only for bash. Branches were checked by hand: every
if/elif/else and case arm is exercised except install.sh's pwsh
Expand-Archive fallback (a Windows runner without unzip). The other lines
kcov leaves unmarked close multi-line commands or are empty case arms.

New tests, in the style of test/checksum-test.sh (ok/FAIL lines, exit 1 on a
failure), sharing test/harness.sh (clean env -i per case, assertions,
expected failures for known bugs):
- lib-test.sh: workflow-command escaping, masking, set_output refusing
  multi-line values, Windows path helpers (cygpath stand-in), sha256_of with
  each tool and with none, make_temp_dir
- resolve-test.sh: pinned version, v prefix, pre-releases, latest and
  malformed versions rejected (exit 2), every supported OS/arch and asset,
  unsupported runners, uname fallback, cache location
- verify-checksum-test.sh: accepted formats (cargo-dist, sha256sum, bare,
  upper case, CRLF), tampered digest and archive, another asset's checksum,
  malformed, blank, empty and missing files, usage
- install-test.sh: fresh download, checksum gate, cache reuse and poisoned
  cache, missing checksum/archive downloads (network failure), archive
  without the binary, wrong version, unknown archive type, .zip assets, and
  the advisory attestation (verified, failed, no token, no gh). Downloads come
  from file:// through a curl stand-in: no network.
- check-test.sh: input validation (exit 2, the CLI never runs), credentials
  (exit 3, masking, job-level key, OIDC), CLI arguments, files/directories/
  globs (*, ?, [...], **, hidden directories, spaces, duplicates, hostile
  patterns, no match), results and outputs per format, CLI exit codes 0-4 and
  others, annotations, the job summary, SARIF path rewriting in a
  subdirectory, no jq, and changed-files bases (pull_request, push,
  merge_group, default branch, since, shallow clones) in temporary git repos.
  It runs a stand-in CLI, test/fixtures/fake-cli/vericto.

CI: a "unit" job runs them on ubuntu-latest and macos-latest; shellcheck now
covers the new scripts. README "Tests" and a CHANGELOG Unreleased entry.

Findings, left unchanged and recorded as xfail cases:
- The input validators (cli-version in resolve.sh; dialect, timeout,
  api-url, workspace and since in check.sh) use grep, which matches line by
  line, so a multi-line value passes when its first line is valid. In
  check.sh it reaches the CLI as one argument with a newline in it (no shell
  injection: it stays one quoted argument); in resolve.sh set_output stops it
  with exit 1 instead of the input error (exit 2).
- check.sh reads "${VA_FILES//[[:space:]]/}" under set -u, so with VA_FILES
  unset bash 4+ aborts with "unbound variable" (exit 1). action.yml always
  sets VA_FILES, so the action is not affected; only a direct run of the
  script is.

No change to action.yml or scripts/.
The input validators matched with grep, which works line by line, so a
cli-version, dialect, timeout, api-url, workspace or since containing a
line break passed as long as one of its lines was valid. check.sh then
passed the CLI one argument with a newline in it (no shell injection,
but validation was defeated), and resolve.sh stopped with exit 1 at
set_output instead of the input error (exit 2).

scripts/lib.sh now holds the one shared validator, matches ERE VALUE:
it rejects any value with a line feed or carriage return first, then
matches the whole value with bash's =~ (bash 3.2 and 5.x). resolve.sh,
check.sh (every input and the internal commit/count checks) and
verify-checksum.sh use it; is_single_line also serves the baseline and
file-name checks and set_output. A multi-line input is an input error
(exit 2) with that input's usual message.

check.sh read "${VA_FILES//[[:space:]]/}" under set -u, which aborts on
bash 4+ when VA_FILES is unset (direct runs; action.yml always sets
it). It now reads ${VA_FILES:-}. The other optional variables were
audited: all are read through ${VAR:-} or only after a non-empty check.

Tests: the xfail cases are plain assertions now, with LF, CRLF, a
trailing LF and a trailing CR on every affected input, unit tests for
the helpers, and runs with every optional input unset.

Release 1.0.2: CHANGELOG. The action has no version file or lockfile;
the release is the v1.0.2 tag, and v1 moves to it.
@donkan168
donkan168 requested a review from vericto as a code owner October 18, 2026 15:30
@donkan168
donkan168 merged commit 22ab7fe into main Oct 18, 2026
11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants