feat(ci): module signing on PR approval and manual workflow_dispatch#503
feat(ci): module signing on PR approval and manual workflow_dispatch#503
Conversation
- Add sign-modules-on-approval workflow (approved reviews, dev/main base) - Extend sign-modules.yml with workflow_dispatch inputs and sign-and-push job - Document flows in module-security.md; update CHANGELOG and tests Made-with: Cursor
|
Caution Review failedPull request was closed or merged during review 📝 WalkthroughCI Module Signing Automation on PR Approval and Manual DispatchUser-visible behavior and CLI surface
CI automation / behavior changes
Contract / API impact
Testing and quality gates
Documentation and changelog
Module signing and version bumps
Operational notes / secrets / limitations
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7f01b7c14f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
There was a problem hiding this comment.
Actionable comments posted: 7
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In @.github/workflows/sign-modules-on-approval.yml:
- Around line 14-23: The "sign" job (name "CI sign changed modules") is
currently skipped until a PR is approved which prevents its status check from
existing as a required branch-protection check; remove the top-level job-level
if that checks github.event.review.state and github.event.pull_request.base.ref
so the sign job always runs on PR workflow runs, and instead move the approval
gating inside the job (e.g., as the first step that exits/continues based on
github.event.review.state or by checking PR reviews) so the job produces a
stable status check name while still only performing signing after approval.
- Around line 40-63: The workflow currently sets BASE_REF to the moving branch
tip and passes it to scripts/sign-modules.py with --changed-only; instead
compute the merge base between the PR head and the remote base branch (e.g., run
git merge-base HEAD origin/${{ github.event.pull_request.base.ref }} and store
that SHA in BASE_REF) and pass that SHA to the python scripts/sign-modules.py
invocation (keep the same flags like --changed-only, --bump-version,
--payload-from-filesystem) so the signer compares against the deterministic
merge-base rather than the moving tip.
In @.github/workflows/sign-modules.yml:
- Around line 150-174: The workflow currently sets BASE_REF to "origin/${{
github.event.inputs.base_branch }}" and passes it to scripts/sign-modules.py
with --changed-only; change this to resolve a stable comparison point by
computing the merge-base (git merge-base HEAD origin/${{
github.event.inputs.base_branch }}) and assign that SHA to BASE_REF before
invoking sign-modules.py so --changed-only receives the merge-base commit
instead of the branch ref, ensuring stable changed-module detection consistent
with specfact-cli-modules.
In `@CHANGELOG.md`:
- Around line 36-40: The changelog wording is inconsistent about when
`--require-signature` is applied; update the entry that mentions
`pr-orchestrator` and `sign-modules` so it clearly states that pull request
verification does not pass `--require-signature` by default (it only runs
checksum + `--enforce-version-bump`), except when the PR target/base branch is
`main` where strict `--require-signature` verification is enforced on pushes to
`main`; also ensure the note about `sign-modules` passing
`--payload-from-filesystem` remains and that the guidance to sign bundled
manifests before merging release PRs or post-merge CI failure is unambiguous.
In `@docs/reference/module-security.md`:
- Around line 56-68: Wrap the long lines in the module-security.md paragraph
describing "Approval-time signing" and "Manual signing" so no line exceeds 120
characters (preserve inline code and identifiers like
`sign-modules-on-approval.yml`, `sign-modules.yml`, `--changed-only`,
`--require-signature`, `SPECFACT_MODULE_PRIVATE_SIGN_KEY`, and
`module-package.yaml`), breaking sentences or clauses at logical boundaries to
keep markdown semantics intact and avoid altering any code snippets or flags.
In `@tests/unit/specfact_cli/registry/test_signing_artifacts.py`:
- Around line 466-483: The tests currently validate workflow_dispatch inputs but
don't lock the compare-point contract (whether --base-ref uses the moving branch
tip vs a merge-base-derived SHA). Update the assertions in
_assert_sign_modules_dispatch_raw_content (used by
test_sign_modules_workflow_dispatch_signs_changed_modules_and_pushes and reading
SIGN_WORKFLOW) to explicitly require the merge-base usage and forbid the
branch-tip usage: assert the raw workflow contains the token "merge-base" (or
the exact merge-base CLI snippet your template emits) and assert it does NOT
contain a direct branch-tip substitution like "github.event.inputs.base_branch"
or an un-merged HEAD reference; this ensures the workflow's --base-ref behavior
is locked to the intended compare-point.
In `@tests/unit/workflows/test_sign_modules_on_approval.py`:
- Around line 56-67: The test
test_sign_modules_on_approval_runs_signer_with_changed_only_mode currently
asserts the compare ref is the moving branch tip ("origin/${{
github.event.pull_request.base.ref }}") but must instead assert the workflow
computes and uses a merge-base-derived SHA; update the test (reading WORKFLOW)
to look for the merge-base computation step or variable (e.g., a step that runs
git merge-base or defines MERGE_BASE_SHA/BASE_SHA) and assert the signer is
invoked with that merge-base variable (for example check for usage of '${{
env.MERGE_BASE_SHA }}' or '${MERGE_BASE_SHA}') instead of the hardcoded
origin/${{ github.event.pull_request.base.ref }} to lock the contract that
approval-time signing uses the merge-base-derived SHA.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: ASSERTIVE
Plan: Pro
Run ID: ded23b5b-ff4b-4b12-9454-b7699458f7e8
📒 Files selected for processing (7)
.github/workflows/pr-orchestrator.yml.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.ymlCHANGELOG.mddocs/reference/module-security.mdtests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
💤 Files with no reviewable changes (1)
- .github/workflows/pr-orchestrator.yml
📜 Review details
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
- GitHub Check: Tests (Python 3.12)
- GitHub Check: Compatibility (Python 3.11)
- GitHub Check: Linting (ruff, pylint, safe-write guard)
🧰 Additional context used
📓 Path-based instructions (12)
**/test_*.py
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
**/test_*.py: Write tests first in test-driven development (TDD) using the Red-Green-Refactor cycle
Ensure each test is independent and repeatable with no shared state between tests
Organize Python imports in tests using unittest.mock for Mock and patch
Use setup_method() for test initialization and Arrange-Act-Assert pattern in test files
Use@pytest.mark.asynciodecorator for async test functions in Python
Organize test files in structure: tests/unit/, tests/integration/, tests/e2e/ by module
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
**/*.py
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
**/*.py: Maintain minimum 80% test coverage, with 100% coverage for critical paths in Python code
Use clear naming and self-documenting code, preferring clear names over comments
Ensure each function/class has a single clear purpose (Single Responsibility Principle)
Extract common patterns to avoid code duplication (DRY principle)
Apply SOLID object-oriented design principles in Python code
Use type hints everywhere in Python code and enable basedpyright strict mode
Use Pydantic models for data validation and serialization in Python
Use async/await for I/O operations in Python code
Use context managers for resource management in Python
Use dataclasses for simple data containers in Python
Enforce maximum line length of 120 characters in Python code
Use 4 spaces for indentation in Python code (no tabs)
Use 2 blank lines between classes and 1 blank line between methods in Python
Organize imports in order: Standard library → Third party → Local in Python files
Use snake_case for variables and functions in Python
Use PascalCase for class names in Python
Use UPPER_SNAKE_CASE for constants in Python
Use leading underscore (_) for private methods in Python classes
Use snake_case for Python file names
Enable basedpyright strict mode with strict type checking configuration in Python
Use Google-style docstrings for functions and classes in Python
Include comprehensive exception handling with specific exception types in Python code
Use logging with structured context (extra parameters) instead of print statements
Use retry logic with tenacity decorators (@retry) for operations that might fail
Use Pydantic BaseSettings for environment-based configuration in Python
Validate user input using Pydantic validators in Python models
Use@lru_cacheand Redis-based caching for expensive calculations in Python
Run code formatting with Black (120 character line length) and isort in Python
Run type checking with basedpyright on all Python files
Run linting with ruff and pylint on all Pyth...
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
tests/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Tests must be meaningful and test actual functionality, cover both success and failure cases, be independent and repeatable, and have clear, descriptive names. NO EXCEPTIONS - no placeholder or empty tests.
tests/**/*.py: Trim low-value unit tests when a contract covers the same assertion (type/shape/raises on negative checks)
Delete tests that only assert input validation, datatype/shape enforcement, or raises on negative conditions now guarded by contracts and runtime typing
Convert repeated edge-case permutations into one Hypothesis property with contracts acting as oraclesSecret redaction via
LoggerSetup.redact_secretsmust be covered by unit tests
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
⚙️ CodeRabbit configuration file
tests/**/*.py: Contract-first testing: meaningful scenarios, not redundant assertions already covered by
contracts. Flag flakiness, environment coupling, and missing coverage for changed behavior.
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
@(src|tests)/**/*.py
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Linting must pass with no errors using: pylint src tests
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
**/*.{py,pyi}
📄 CodeRabbit inference engine (.cursorrules)
**/*.{py,pyi}: After any code changes, follow these steps in order: (1) Apply linting and formatting to ensure code quality:hatch run format, (2) Type checking:hatch run type-check(basedpyright), (3) Contract-first approach: Runhatch run contract-testfor contract validation, (4) Run full test suite:hatch test --cover -v, (5) Verify all tests pass and contracts are satisfied, (6) Fix any issues and repeat steps until all tests pass
All public APIs must have@icontractdecorators and@beartypetype checking
Use Pydantic models for all data structures with data validation
Only write high-value comments if at all. Avoid talking to the user through comments
Files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pytests/unit/workflows/test_sign_modules_on_approval.py
**/*.{md,mdc}
📄 CodeRabbit inference engine (.cursor/rules/markdown-rules.mdc)
**/*.{md,mdc}: Do not use more than one consecutive blank line anywhere in the document (MD012: No Multiple Consecutive Blank Lines)
Fenced code blocks should be surrounded by blank lines (MD031: Fenced Code Blocks)
Lists should be surrounded by blank lines (MD032: Lists)
Files must end with a single empty line (MD047: Files Must End With Single Newline)
Lines should not have trailing spaces (MD009: No Trailing Spaces)
Use asterisks (**) for strong emphasis, not underscores (__) (MD050: Strong Style)
Fenced code blocks must have a language specified (MD040: Fenced Code Language)
Headers should increment by one level at a time (MD001: Header Increment)
Headers should be surrounded by blank lines (MD022: Headers Should Be Surrounded By Blank Lines)
Only one top-level header (H1) is allowed per document (MD025: Single H1 Header)
Use consistent list markers, preferring dashes (-) for unordered lists (MD004: List Style)
Nested unordered list items should be indented consistently, typically by 2 spaces (MD007: Unordered List Indentation)
Use exactly one space after the list marker (e.g., -, *, +, 1.) (MD030: Spaces After List Markers)
Use incrementing numbers for ordered lists (MD029: Ordered List Item Prefix)
Enclose bare URLs in angle brackets or format them as links (MD034: Bare URLs)
Don't use spaces immediately inside code spans (MD038: Spaces Inside Code Spans)
Use consistent indentation (usually 2 or 4 spaces) throughout markdown files
Keep line length under 120 characters in markdown files
Use reference-style links for better readability in markdown files
Use a trailing slash for directory paths in markdown files
Ensure proper escaping of special characters in markdown files
Files:
docs/reference/module-security.mdCHANGELOG.md
docs/**/*.md
📄 CodeRabbit inference engine (.cursor/rules/spec-fact-cli-rules.mdc)
Update architecture documentation in docs/ for architecture changes, state machine documentation for FSM modifications, interface documentation for API changes, and configuration guides for configuration changes. DO NOT create internal docs in specfact-cli repo folder that should not be visible to end users; use the respective internal repository instead.
Files:
docs/reference/module-security.md
⚙️ CodeRabbit configuration file
docs/**/*.md: User-facing accuracy: CLI examples match current behavior; preserve Jekyll front matter;
call out when README/docs index need sync.
Files:
docs/reference/module-security.md
**/*.md
📄 CodeRabbit inference engine (.cursorrules)
Avoid markdown linting errors (refer to markdown-rules)
Files:
docs/reference/module-security.mdCHANGELOG.md
.github/workflows/*.{yml,yaml}
📄 CodeRabbit inference engine (.cursor/rules/testing-and-build-guide.mdc)
Validate GitHub workflow files using
hatch run lint-workflowsbefore committing
.github/workflows/*.{yml,yaml}: Use actionlint for semantic validation of GitHub Actions workflows
Format GitHub Actions workflows usinghatch run workflows-fmtand lint them withhatch run workflows-lintafter editing
Files:
.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.yml
.github/workflows/!(tests).{yml,yaml}
📄 CodeRabbit inference engine (.cursor/rules/testing-and-build-guide.mdc)
Do not re-run the full test suite in other CI workflows; tests are enforced only in the dedicated Tests workflow (.github/workflows/tests.yml)
Files:
.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.yml
.github/workflows/**
⚙️ CodeRabbit configuration file
.github/workflows/**: CI safety: secrets usage, workflow dependencies, alignment with hatch test / contract-test
gates, and action versions.
Files:
.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.yml
CHANGELOG.md
📄 CodeRabbit inference engine (.cursor/rules/python-github-rules.mdc)
Include new version entries at the top of CHANGELOG.md when updating versions
Update CHANGELOG.md with all code changes as part of version control requirements.
Update CHANGELOG.md to document all significant changes under Added, Fixed, Changed, or Removed sections when making a version change
Files:
CHANGELOG.md
🧠 Learnings (16)
📓 Common learnings
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursorrules:0-0
Timestamp: 2026-04-10T22:41:19.077Z
Learning: Applies to openspec/changes/**/*.md : For `/opsx:archive` (Archive change): Include module signing and cleanup in final tasks. Agents MUST run `openspec archive <change-id>` from repo root (no manual `mv` under `openspec/changes/archive/`)
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-10T22:42:21.849Z
Learning: Enforce module signatures and version bumps when signed module assets or manifests are affected
📚 Learning: 2026-04-10T22:41:19.077Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursorrules:0-0
Timestamp: 2026-04-10T22:41:19.077Z
Learning: Applies to openspec/changes/**/*.md : For `/opsx:archive` (Archive change): Include module signing and cleanup in final tasks. Agents MUST run `openspec archive <change-id>` from repo root (no manual `mv` under `openspec/changes/archive/`)
Applied to files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pydocs/reference/module-security.md.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.ymlCHANGELOG.md
📚 Learning: 2026-04-10T22:42:21.849Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: AGENTS.md:0-0
Timestamp: 2026-04-10T22:42:21.849Z
Learning: Enforce module signatures and version bumps when signed module assets or manifests are affected
Applied to files:
tests/unit/specfact_cli/registry/test_signing_artifacts.pydocs/reference/module-security.md.github/workflows/sign-modules-on-approval.yml.github/workflows/sign-modules.ymlCHANGELOG.md
📚 Learning: 2026-04-10T22:41:19.077Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursorrules:0-0
Timestamp: 2026-04-10T22:41:19.077Z
Learning: For `/opsx:ff` (Fast-Forward Change Creation): OPSX provides change scaffolding and artifact templates. AGENTS.md requires explicitly adding: Worktree creation task as Step 1 in tasks.md (not just 'create branch'), TDD_EVIDENCE.md tracking task in section 2 (Tests), Documentation research task per `openspec/config.yaml`, Module signing quality gate if applicable, Worktree cleanup steps in final section
Applied to files:
tests/unit/specfact_cli/registry/test_signing_artifacts.py.github/workflows/sign-modules.ymlCHANGELOG.md
📚 Learning: 2026-04-10T22:41:19.077Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursorrules:0-0
Timestamp: 2026-04-10T22:41:19.077Z
Learning: Before executing ANY workflow command (`/opsx:ff`, `/opsx:apply`, `/opsx:continue`, etc.), perform the Pre-Execution Checklist: (1) Git Worktree - create if task creates branches/modifies code, (2) TDD Evidence - create `TDD_EVIDENCE.md` if behavior changes, (3) Documentation - include documentation research if changes affect user-facing behavior, (4) Module Signing - include signature verification if changes modify bundled modules, (5) Confirmation - state clearly that pre-execution checklist is complete and AGENTS.md compliance is confirmed
Applied to files:
docs/reference/module-security.md.github/workflows/sign-modules.ymlCHANGELOG.md
📚 Learning: 2026-04-10T22:41:54.419Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/automatic-openspec-workflow.mdc:0-0
Timestamp: 2026-04-10T22:41:54.419Z
Learning: For changes created from plan documents, use `/specfact-cli/wf-create-change-from-plan <plan-path>` workflow to create OpenSpec proposals; the workflow includes plan selection, alignment review, integrity re-check, proposal creation, improvement, optional GitHub issue creation, and completion steps
Applied to files:
.github/workflows/sign-modules.yml
📚 Learning: 2026-03-25T21:33:15.296Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/testing-and-build-guide.mdc:0-0
Timestamp: 2026-03-25T21:33:15.296Z
Learning: Applies to .github/workflows/!(tests).{yml,yaml} : Do not re-run the full test suite in other CI workflows; tests are enforced only in the dedicated Tests workflow (.github/workflows/tests.yml)
Applied to files:
.github/workflows/sign-modules.ymltests/unit/workflows/test_sign_modules_on_approval.py
📚 Learning: 2026-03-25T21:33:15.296Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/testing-and-build-guide.mdc:0-0
Timestamp: 2026-03-25T21:33:15.296Z
Learning: Applies to .github/workflows/*.{yml,yaml} : Validate GitHub workflow files using `hatch run lint-workflows` before committing
Applied to files:
.github/workflows/sign-modules.yml
📚 Learning: 2026-03-25T21:33:22.650Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/yaml-and-workflows.md:0-0
Timestamp: 2026-03-25T21:33:22.650Z
Learning: Run `hatch run yaml-check-all` in CI and before pull requests to validate all YAML and workflow files
Applied to files:
.github/workflows/sign-modules.yml
📚 Learning: 2026-03-25T21:32:57.944Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/spec-fact-cli-rules.mdc:0-0
Timestamp: 2026-03-25T21:32:57.944Z
Learning: Applies to src/**/*.py : Test Coverage Validation: Run hatch run smart-test-unit for modified files, hatch run smart-test-folder for modified directories, and hatch run smart-test-full before committing. ALL TESTS MUST PASS.
Applied to files:
tests/unit/workflows/test_sign_modules_on_approval.py
📚 Learning: 2026-03-25T21:32:57.944Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/spec-fact-cli-rules.mdc:0-0
Timestamp: 2026-03-25T21:32:57.944Z
Learning: Applies to docs/**/*.md : Update architecture documentation in docs/ for architecture changes, state machine documentation for FSM modifications, interface documentation for API changes, and configuration guides for configuration changes. DO NOT create internal docs in specfact-cli repo folder that should not be visible to end users; use the respective internal repository instead.
Applied to files:
CHANGELOG.md
📚 Learning: 2026-03-25T21:33:15.296Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/testing-and-build-guide.mdc:0-0
Timestamp: 2026-03-25T21:33:15.296Z
Learning: Applies to CHANGELOG.md : Update CHANGELOG.md to document all significant changes under Added, Fixed, Changed, or Removed sections when making a version change
Applied to files:
CHANGELOG.md
📚 Learning: 2026-03-25T21:32:57.944Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/spec-fact-cli-rules.mdc:0-0
Timestamp: 2026-03-25T21:32:57.944Z
Learning: Applies to CHANGELOG.md : Update CHANGELOG.md with all code changes as part of version control requirements.
Applied to files:
CHANGELOG.md
📚 Learning: 2026-03-25T21:33:22.650Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/yaml-and-workflows.md:0-0
Timestamp: 2026-03-25T21:33:22.650Z
Learning: Applies to .github/workflows/*.{yml,yaml} : Format GitHub Actions workflows using `hatch run workflows-fmt` and lint them with `hatch run workflows-lint` after editing
Applied to files:
CHANGELOG.md
📚 Learning: 2026-04-10T22:41:19.077Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursorrules:0-0
Timestamp: 2026-04-10T22:41:19.077Z
Learning: All development work MUST use git worktrees per AGENTS.md Git Worktree Policy. Never create branches with `git checkout -b` in the primary checkout. Create worktree from origin/dev: `git worktree add ../specfact-cli-worktrees/<type>/<slug> -b <branch-name> origin/dev` where allowed types are: `feature/`, `bugfix/`, `hotfix/`, `chore/`. Forbidden in worktrees: `dev`, `main`. After creating worktree: `cd ../specfact-cli-worktrees/<type>/<slug>`. Bootstrap Hatch in worktree: `hatch env create`. Run pre-flight checks: `hatch run smart-test-status` and `hatch run contract-test-status`. Do all implementation work from the worktree, never from primary checkout. After PR merge: cleanup with `git worktree remove`, `git branch -d`, `git worktree prune`
Applied to files:
CHANGELOG.md
📚 Learning: 2026-04-10T22:41:54.419Z
Learnt from: CR
Repo: nold-ai/specfact-cli PR: 0
File: .cursor/rules/automatic-openspec-workflow.mdc:0-0
Timestamp: 2026-04-10T22:41:54.419Z
Learning: Applies to openspec/**/{proposal.md,tasks.md,design.md,spec.md} : After implementation, validate the change with `openspec validate <change-id> --strict`; fix validation errors in proposal, specs, design, or tasks and re-validate until passing before considering the change complete
Applied to files:
CHANGELOG.md
🔀 Multi-repo context nold-ai/specfact-cli-modules
nold-ai/specfact-cli-modules
-
New approval-triggered signing workflow added:
- .github/workflows/sign-modules-on-approval.yml — signs changed manifests on approved same-repo PRs to dev/main, requires SPECFACT_MODULE_PRIVATE_SIGN_KEY and SPECFACT_MODULE_PRIVATE_SIGN_KEY_PASSPHRASE, uses git merge-base and runs scripts/sign-modules.py --changed-only --base-ref "$MERGE_BASE" --bump-version patch --payload-from-filesystem; commits/pushes signed manifests back to PR head. [::nold-ai/specfact-cli-modules::.github/workflows/sign-modules-on-approval.yml]
-
PR orchestrator verify behavior:
- .github/workflows/pr-orchestrator.yml builds VERIFY_CMD=(python scripts/verify-modules-signature.py --payload-from-filesystem --enforce-version-bump) and only appends --require-signature when TARGET_BRANCH = main (push or PR target main). This matches the PR summary change (omit --require-signature for non-main PRs). [::nold-ai/specfact-cli-modules::.github/workflows/pr-orchestrator.yml]
-
Signing & verification scripts (consumers/implementations):
- scripts/sign-modules.py — reads SPECFACT_MODULE_PRIVATE_SIGN_KEY / SPECFACT_MODULE_PRIVATE_SIGN_KEY_FILE and SPECFACT_MODULE_PRIVATE_SIGN_KEY_PASSPHRASE; exposes --changed-only and --base-ref options used by workflows. [::nold-ai/specfact-cli-modules::scripts/sign-modules.py]
- scripts/verify-modules-signature.py — defines --require-signature flag and is invoked by workflows; pre-commit wrapper (scripts/pre-commit-verify-modules-signature.sh) sets --require-signature on branch main. [::nold-ai/specfact-cli-modules::scripts/verify-modules-signature.py] [::nold-ai/specfact-cli-modules::scripts/pre-commit-verify-modules-signature.sh]
-
Tests validating workflow behavior:
- tests/unit/workflows/test_sign_modules_on_approval.py — asserts the new workflow exists and includes secrets checks, invocation of scripts/sign-modules.py with --changed-only and expected commit/push behavior. [::nold-ai/specfact-cli-modules::tests/unit/workflows/test_sign_modules_on_approval.py]
- tests/unit/workflows/test_pr_orchestrator_signing.py — asserts pr-orchestrator contains verify-modules-signature invocation and presence/placement of --require-signature. [::nold-ai/specfact-cli-modules::tests/unit/workflows/test_pr_orchestrator_signing.py]
- Other unit tests reference scripts/verify-modules-signature.py (tests/unit/test_verify_modules_signature_script.py). [::nold-ai/specfact-cli-modules::tests/unit/test_verify_modules_signature_script.py]
-
Documentation and policy references (consumers of the behavior):
- docs/reference/module-security.md, docs/authoring/module-signing.md, docs/guides/ci-cd-pipeline.md, docs/authoring/publishing-modules.md, README.md — multiple places document the branch-aware --require-signature policy, CI signing via SPECFACT_MODULE_PRIVATE_SIGN_KEY, and guidance for running sign-modules/verify-modules-signature. These will need to stay consistent with workflow changes. [::nold-ai/specfact-cli-modules::docs/reference/module-security.md] [::nold-ai/specfact-cli-modules::docs/authoring/module-signing.md]
Implications for review
- The repo itself is the primary consumer/owner of the changed workflows and scripts; signatures and verification flags are heavily referenced in tests and docs. Ensure tests and docs align with the conditional removal of --require-signature on PR base != main (they appear to already). [::nold-ai/specfact-cli-modules::tests/unit/workflows/test_pr_orchestrator_signing.py] [::nold-ai/specfact-cli-modules::docs/reference/module-security.md]
Conclusion: Found multiple relevant cross-references (workflows, scripts, tests, docs) that confirm the PR’s changes affect verification/signing behavior and that consumers within this repository expect the branch-aware --require-signature policy.
🔇 Additional comments (5)
docs/reference/module-security.md (1)
53-68: Strong branch-aware policy documentation and CI contract clarityThis section clearly documents the trust boundary: checksum-only on PRs, strict signature gating on
main, plus approval/manual recovery flows. That matches the workflow contract and improves long-term maintainability for bundled module delivery paths.CHANGELOG.md (1)
17-23: Good release-note detail for the new signing paths.This is clear, actionable, and maps directly to the new CI behavior (approval signing + manual repair path).
.github/workflows/sign-modules.yml (1)
6-22: Good manual repair surface.Constraining
base_branchandversion_bumpto explicit choices keeps the dispatch path predictable and avoids free-form refs.tests/unit/specfact_cli/registry/test_signing_artifacts.py (1)
438-443: Niceon:parsing fallback.Handling PyYAML's boolean-key quirk here makes the workflow assertions much less brittle.
tests/unit/workflows/test_sign_modules_on_approval.py (1)
21-26: Goodon:fallback here as well.Catching the YAML
on→Truecoercion keeps these policy tests loader-agnostic.
Summary
Adds CI automation so bundled module manifests can be signed without a local key, plus a manual repair path from the Actions UI.
Changes
sign-modules-on-approval.yml: On approved reviews for same-repo PRs targetingdevormain, runssign-modules.py --changed-onlywith repo secrets and pushes updatedmodule-package.yamlfiles to the PR head branch.sign-modules.yml:workflow_dispatchinputs (base_branch,version_bump) and a sign-and-push job; skips strictmainverify and reproducibility only for manual runs somaincan be recovered.module-security.md, workflow policy tests, changelog entry.Notes
SPECFACT_MODULE_PRIVATE_SIGN_KEY(and passphrase if needed) must be configured for signing jobs to succeed.Made with Cursor