feat(ci): add reusable workflow to validate OpenSpec specs - #40
Merged
Conversation
Extracts the openspec validate --specs --strict step that the OpenSpec ↔ reqstool dogfooding rollout (see reqstool/PLAN_dog_fooding.md) is adding to every participating repo's build.yml, so it lives once instead of being copy-pasted into each one. This step is fully build-system-agnostic (pure Node, no language toolchain dependency), unlike the reqstool status/validate steps which depend on per-language build artifacts and stay inline per-repo for now. First consumer: reqstool-demo#104. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
that referenced
this pull request
Jun 21, 2026
* feat(ci): add composite actions for reqstool validate/status 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> * refactor(ci): extract shared install-reqstool composite action 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> * fix(security): pass action inputs via env instead of inline shell interpolation 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> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-demo
that referenced
this pull request
Jun 21, 2026
Replaces the inline reqstool install/status/validate steps and the inline openspec install/validate step with the reusable building blocks just added to reqstool/.github for this rollout: - reqstool/.github/.github/actions/validate-reqstool (reqstool-client#412 follow-up notwithstanding, runs reqstool validate --strict; only called for the main matrix leg since that subcommand isn't on PyPI yet) - reqstool/.github/.github/actions/reqstool-status (runs reqstool status, fail-if-incomplete left false since this repo intentionally has incomplete requirements) - reqstool/.github/.github/workflows/common-validate-openspec.yml (now a separate job, since it's a reusable *workflow* rather than a composite action) Pinned to reqstool/.github@cd3b5e8 (main, 2026-06-21) per reqstool/.github#40 and #41. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
jimisola
added a commit
to reqstool/reqstool-demo
that referenced
this pull request
Jun 21, 2026
…howcase (#104) * feat(openspec): bootstrap OpenSpec spec layer for the demo's status showcase Adds an OpenSpec layer mirroring reqstool-client#407's dogfooding pattern, scoped to this repo's actual purpose: showcasing every reqstool status outcome (pass, manual-fail, not-implemented, failing-test, skipped-test, missing-test) across six small feature capabilities. - openspec/specs/{greeting,billing,reporting,validation,notifications, audit-logging}/spec.md — one capability per status outcome, in thin ID-reference form against the existing requirements.yml/SVC IDs (REQ_PASS, REQ_MANUAL_FAIL, ...). IDs are kept as-is (no capability prefix) since they're already domain-named and intentionally demonstrate non-passing states, unlike reqstool-client's renamed/100%-passing set. - openspec/openspecui.hooks.ts — reqstool-ai's openspecui enrichment hook. - .reqstool-ai.yaml — single "demo" module, domain-specific (no) prefix. - .mcp.json — project-scoped reqstool MCP server entry. Validated: openspec validate --specs --strict (6/6 pass), reqstool validate --strict (pass), reqstool status (1/6 complete, by design), mvn clean verify (build succeeds; one intentionally failing test, by design), and CLI vs MCP get_requirements_status now agree exactly across all 6 requirements (confirmed after reqstool-client#411's fix). Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * ci(build): validate OpenSpec specs, clarify reqstool-ai prefix comment - Add an openspec validate --specs --strict step to build.yml so spec/SSOT drift fails CI instead of relying on the manual run documented in #104's PR description; build-docs.yml's docs/** path filter doesn't cover openspec/**, so nothing else was catching this. - Expand the .reqstool-ai.yaml comment explaining why req_prefix is empty while svc_prefix isn't. Found by /x:full-pr-review on #104. reqstool validate --strict was intentionally not added yet — not in the currently published PyPI release. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * ci(build): matrix reqstool CI across PyPI and reqstool-client@main Adds an openspec validate --specs --strict step to build.yml so spec/SSOT drift fails CI instead of relying on the manual run documented in #104's PR description. Runs reqstool status/validate against both the latest PyPI release and reqstool-client's main branch in a matrix, since reqstool-client is deliberately holding off its next release until the org-wide OpenSpec dogfooding rollout is complete, and main already has fixes (#411) and commands (validate) not yet published. reqstool validate --strict only runs on the main leg since that subcommand isn't on PyPI yet. CI continues to run the latest PyPI release as its baseline; see reqstool-demo#105 for tracking divergence between the two legs and collapsing back to PyPI-only once reqstool-client cuts its next release. Also expands the .reqstool-ai.yaml comment explaining why req_prefix is empty while svc_prefix isn't. Found by /x:full-pr-review on #104. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * fix(ci): pin Python 3.13 for reqstool install step build (main) failed: the runner's default Python (3.12) doesn't satisfy reqstool-client@main's reqstool-python-decorators>=0.1.0 dependency, which requires Python >=3.13. Add actions/setup-python@v6 pinned to 3.13, matching reqstool-client's own CI convention (build.yml, lint.yml). Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * ci(build): use shared reqstool/openspec workflows from reqstool/.github Replaces the inline reqstool install/status/validate steps and the inline openspec install/validate step with the reusable building blocks just added to reqstool/.github for this rollout: - reqstool/.github/.github/actions/validate-reqstool (reqstool-client#412 follow-up notwithstanding, runs reqstool validate --strict; only called for the main matrix leg since that subcommand isn't on PyPI yet) - reqstool/.github/.github/actions/reqstool-status (runs reqstool status, fail-if-incomplete left false since this repo intentionally has incomplete requirements) - reqstool/.github/.github/workflows/common-validate-openspec.yml (now a separate job, since it's a reusable *workflow* rather than a composite action) Pinned to reqstool/.github@cd3b5e8 (main, 2026-06-21) per reqstool/.github#40 and #41. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * fix(ci): call install-reqstool explicitly, per reqstool/.github#48 validate-reqstool/reqstool-status no longer install reqstool themselves (reqstool/.github#48 removed their broken nested ./.github/actions/install-reqstool reference, which only resolved when called from within reqstool/.github itself, not from a consuming repo like this one). Call install-reqstool explicitly as its own step first. Pinned to reqstool/.github@11a00fc (main, 2026-06-21). Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * ci(build): re-pin reqstool/.github to 5bdf4e5 Picks up reqstool/.github#59 (drop --verbosity compact from reqstool-status, also not yet on PyPI — same situation as the validate subcommand fixed in #48), found via this PR's pypi matrix leg failing with "invalid choice: 'compact'". Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * fix(reqstool): use 0.1.0 as the first revision, per semver requirements.yml and software_verification_cases.yml used 0.0.1 for every requirement/SVC. Per semver, 0.0.x is reserved for pre-release/unstable work before any real first version — the first published revision of a thing should be 0.1.0, which also matches reqstool-ai's own .reqstool-ai.yaml.template default ("Revision string for new requirements and SVCs. Default: 0.1.0"). My earlier .reqstool-ai.yaml matched the existing (non-conventional) 0.0.1 instead of fixing it forward. manual_verification_results.yml has no revision field in its schema, so nothing to change there. Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> * fix(security): add explicit permissions block to build.yml CodeQL flagged this 3 times across commits: the workflow didn't limit GITHUB_TOKEN permissions. Add permissions: contents: read at the workflow root, matching the existing convention in this repo (build-docs.yml, check-semantic-pr.yml). Signed-off-by: Jimisola Laursen <jimisola@jimisola.com> --------- Signed-off-by: Jimisola Laursen <jimisola@jimisola.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds
common-validate-openspec.yml, a reusable workflow that runsopenspec validate --specs --strictagainst a repo'sopenspec/directory.Why
The OpenSpec ↔ reqstool dogfooding rollout (tracked in
reqstool/PLAN_dog_fooding.md) is adding the sameopenspec validate --specs --strictCI step to every participating repo'sbuild.yml(first one: reqstool-demo#104). Rather than copy-pasting the same npm-install-and-validate steps into ~10 more repos, this extracts it once, following the samecommon-*/reusable-workflow pattern already used forcommon-validate-renovate.yml,java-build-maven.yml, etc.This step is fully build-system-agnostic (pure Node, no language toolchain dependency) — unlike the accompanying
reqstool status/reqstool validatesteps in each repo, which depend on per-language build artifacts and stay inline per-repo for now (those aren't safely generalizable across Java/Python/TypeScript without more design work).Usage
🤖 Generated with Claude Code