feat(ci): add composite actions for reqstool validate/status - #41
Conversation
Two separate composite actions for the OpenSpec dogfooding rollout (reqstool/PLAN_dog_fooding.md), each installing reqstool from either PyPI or reqstool-client@main: - validate-reqstool: runs `reqstool validate --strict` (spec completeness — every requirement has SVCs, manual SVCs have MVRs). - reqstool-status: runs `reqstool status --verbosity compact`, optionally gated on `--check-all-reqs-met` via fail-if-incomplete (left off by default for repos that intentionally have incomplete requirements, e.g. demo/fixture repos). These are composite actions, not reusable workflows (unlike common-validate-openspec.yml, #40): they run as steps within the calling job, after that job's own build step, since reqstool status/validate needs build-time artifacts (annotations.yml, test results) that a separate reusable-workflow job wouldn't have access to. First consumer: reqstool-demo#104. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
validate-reqstool and reqstool-status both duplicated the same "set up Python + pip install reqstool from pypi/main" logic. Extract it into a third composite action both now call via a nested `uses: ./.github/actions/install-reqstool`, so the install logic lives in one place. Found via self-review on #41. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
…erpolation
CodeQL flagged code-injection risk: ${{ inputs.x }} interpolated directly
into run: shell blocks substitutes literal script text before execution,
so a malicious input value could inject arbitrary shell commands. Pass
all inputs used in run: blocks via env: instead and reference them as
shell variables, which the shell expands safely without re-parsing as
script.
Affects install-reqstool, validate-reqstool, reqstool-status.
Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
|
Addressed all 7 CodeQL code-injection findings: `${{ inputs.x }}` was interpolated directly into `run:` shell blocks across all three action files, which is a script-injection risk. Fixed by passing every such input via `env:` and referencing it as a shell variable instead — the shell expands env vars safely without re-parsing them as script text. All 7 review threads auto-resolved once CodeQL re-scanned the fix commit. Confirmed no open alerts remain in any of the 3 new files (`install-reqstool`, `validate-reqstool`, `reqstool-status`); the org's other open CodeQL alerts are all in unrelated pre-existing workflows, out of scope here. Also did a self-review pass (no separate review-pr tool available in this environment) and found+fixed one duplication issue before any of this: both `validate-reqstool` and `reqstool-status` duplicated the same install logic, now extracted into a shared `install-reqstool` composite action both call. All checks pass. |
What
Two composite actions, both installing
reqstoolfrom either PyPI orreqstool-client@main:validate-reqstool— runsreqstool validate --strict(spec completeness: every requirement has SVCs, manual SVCs have MVRs).reqstool-status— runsreqstool status --verbosity compact, optionally gated on--check-all-reqs-metvia thefail-if-incompleteinput (defaultfalse, so repos that intentionally have incomplete requirements — e.g. demo/fixture repos — don't have to fail CI on it; repos aiming for 100% completeness, like reqstool-client, can opt in).Why composite actions, not a reusable workflow
common-validate-openspec.yml(#40) is a reusable workflow — it runs as its own job with a fresh checkout, which works because validating OpenSpec specs has no build dependency.reqstool status/reqstool validateneed build-time artifacts (annotations.yml, test results) that only exist within the job that already ran the repo's build step (mvn clean verify, etc. — different per language). A reusable workflow can't see those without an explicit artifact upload/download round-trip. A composite action runs as steps inside the calling job, so it can simply be inserted right after the existing build step and pick up whatever was just produced.Usage
First consumer: reqstool-demo#104.
🤖 Generated with Claude Code