Skip to content

feat(ci): module signing on PR approval and manual workflow_dispatch#503

Merged
djm81 merged 2 commits intodevfrom
feature/ci-module-sign-on-approval
Apr 14, 2026
Merged

feat(ci): module signing on PR approval and manual workflow_dispatch#503
djm81 merged 2 commits intodevfrom
feature/ci-module-sign-on-approval

Conversation

@djm81
Copy link
Copy Markdown
Collaborator

@djm81 djm81 commented Apr 14, 2026

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 targeting dev or main, runs sign-modules.py --changed-only with repo secrets and pushes updated module-package.yaml files to the PR head branch.
  • sign-modules.yml: workflow_dispatch inputs (base_branch, version_bump) and a sign-and-push job; skips strict main verify and reproducibility only for manual runs so main can be recovered.
  • Docs / tests / CHANGELOG: module-security.md, workflow policy tests, changelog entry.

Notes

  • Fork PRs are not auto-signed (no push permission to the fork).
  • Repository secrets SPECFACT_MODULE_PRIVATE_SIGN_KEY (and passphrase if needed) must be configured for signing jobs to succeed.

Made with Cursor

- 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
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 14, 2026

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

CI Module Signing Automation on PR Approval and Manual Dispatch

User-visible behavior and CLI surface

  • No new public CLI commands or runtime options introduced in the core package. Existing signing script interface (scripts/sign-modules.py / scripts/sign-module.sh) remains unchanged and continues to support:
    • --changed-only
    • --base-ref
    • --bump-version patch|minor|major
    • --payload-from-filesystem
    • key material via SPECFACT_MODULE_PRIVATE_SIGN_KEY (or --key-file) and optional passphrase flags
  • New GitHub Actions UI inputs for manual dispatch (sign-modules.yml):
    • base_branch (choice: dev, main; default: dev)
    • version_bump (choice: patch, minor, major; default: patch)
    • resign_all_manifests (boolean; default: false)
  • Manual workflow_dispatch runs a new sign-and-push job that signs changed manifests (or all manifests when resign_all_manifests=true) and pushes commits back to the triggering branch.

CI automation / behavior changes

  • New approval-time signing workflow: .github/workflows/sign-modules-on-approval.yml
    • Triggers on pull_request_review submitted when state == approved
    • Runs only for same-repo PRs targeting dev or main (skips fork PRs)
    • Requires SPECFACT_MODULE_PRIVATE_SIGN_KEY secret; fetches base branch, runs scripts/sign-modules.py --changed-only --base-ref origin/ --bump-version patch --payload-from-filesystem, and commits+pushes updated module-package.yaml files to the PR head ref when diffs exist
  • sign-modules.yml changes:
    • Adds workflow_dispatch inputs and a sign-and-push job gated to workflow_dispatch (permissions.contents: write)
    • verify job builds VERIFY_ARGS starting with --enforce-version-bump --payload-from-filesystem and only prepends --require-signature when running on main pushes (workflow_dispatch skips strict signature requirement to allow recovery)
    • reproducibility (re-sign + assert no diff) is gated to push events only (no longer runs on pull_request)
  • pr-orchestrator verify job adjusted: on pull_request events it omits --require-signature (checksum + version enforcement only); --require-signature is enforced for main pushes (branch-aware verification policy)

Contract / API impact

  • No changes to public Python APIs, exported functions, Pydantic models, or module package boundaries. All functional changes are CI/workflow, docs, and test artifacts.
  • scripts/sign-modules.py and verify-modules-signature.py are invoked with adjusted CI flags but their CLI contracts remain compatible.

Testing and quality gates

  • New and updated unit tests validate workflow structure and CI wiring:
    • tests/unit/workflows/test_sign_modules_on_approval.py: verifies trigger, guard conditions, permissions, and raw invocation flags (--changed-only, --bump-version patch, --payload-from-filesystem), and commit/push behavior.
    • tests/unit/specfact_cli/registry/test_signing_artifacts.py: extended to assert sign-modules.yml workflow_dispatch inputs, sign-and-push job wiring (if: github.event_name == 'workflow_dispatch', needs: verify, permissions.contents == write), and gating of reproducibility to push events.
  • Contract/quality tooling remains unchanged; hatch-run contract tests are not modified here. New workflow policy tests are added to the unit test suite and increase CI coverage for workflow artifacts.

Documentation and changelog

  • docs/reference/module-security.md: documents approval-time signing, manual workflow_dispatch options, branch-aware verification policy, and the requirement to configure CI secrets. Clarifies that PR verification is checksum-only while main pushes are strict.
  • CHANGELOG.md: entry added (0.46.1) summarizing approval-time signing, manual dispatch signing, and verification gating changes.

Module signing and version bumps

  • Approval-time signing and manual dispatch both perform version bumping when required:
    • Approval-time signing uses --bump-version patch in the approval workflow (sign-modules-on-approval.yml).
    • Manual dispatch accepts explicit version_bump input to control bump semantics.
  • Reproducibility (deterministic-sign then assert no-diff) runs on push to dev/main to ensure signed manifests are stable for the trusted key; this check is skipped for pull_request so unsigned manifests can be reviewed pre-merge.

Operational notes / secrets / limitations

  • Repository secret SPECFACT_MODULE_PRIVATE_SIGN_KEY is required for approval-time and manual signing jobs to succeed. An optional SPECFACT_MODULE_PRIVATE_SIGN_KEY_PASSPHRASE secret is supported.
  • Fork-originated PRs are not auto-signed (no push permission to fork head). If secrets or workflows are unavailable, maintainers must sign locally before merging or expect post-merge verification failures on main.
🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 35.71% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Description check ❓ Inconclusive The description includes a clear summary, itemized changes, and important notes, though it deviates from the repository's detailed template structure and lacks formal sections like 'Type of Change', 'How Has This Been Tested', and quality gate checklist completion. Expand the description to include the repository's template sections: Type of Change checklist, Contract-First Testing Evidence, Test Execution confirmation, and Quality Gates Status to demonstrate adherence to project standards.
✅ Passed checks (1 passed)
Check name Status Explanation
Title check ✅ Passed The title follows Conventional Commits style with 'feat(ci):' prefix and clearly summarizes the main changes: adding module signing on PR approval and via manual workflow_dispatch.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/ci-module-sign-on-approval

Comment @coderabbitai help to get the list of available commands and usage tips.

@djm81 djm81 self-assigned this Apr 14, 2026
@djm81 djm81 added bug Something isn't working module-system Module system and registry labels Apr 14, 2026
@djm81 djm81 linked an issue Apr 14, 2026 that may be closed by this pull request
Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 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".

Comment thread .github/workflows/sign-modules.yml
Comment thread .github/workflows/sign-modules.yml Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

📥 Commits

Reviewing files that changed from the base of the PR and between c8a1116 and 7f01b7c.

📒 Files selected for processing (7)
  • .github/workflows/pr-orchestrator.yml
  • .github/workflows/sign-modules-on-approval.yml
  • .github/workflows/sign-modules.yml
  • CHANGELOG.md
  • docs/reference/module-security.md
  • tests/unit/specfact_cli/registry/test_signing_artifacts.py
  • tests/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.asyncio decorator 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.py
  • tests/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_cache and 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.py
  • tests/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 oracles

Secret redaction via LoggerSetup.redact_secrets must be covered by unit tests

Files:

  • tests/unit/specfact_cli/registry/test_signing_artifacts.py
  • tests/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.py
  • tests/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.py
  • tests/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: Run hatch run contract-test for 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 @icontract decorators and @beartype type 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.py
  • tests/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.md
  • CHANGELOG.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.md
  • CHANGELOG.md
.github/workflows/*.{yml,yaml}

📄 CodeRabbit inference engine (.cursor/rules/testing-and-build-guide.mdc)

Validate GitHub workflow files using hatch run lint-workflows before committing

.github/workflows/*.{yml,yaml}: Use actionlint for semantic validation of GitHub Actions workflows
Format GitHub Actions workflows using hatch run workflows-fmt and lint them with hatch run workflows-lint after 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.py
  • docs/reference/module-security.md
  • .github/workflows/sign-modules-on-approval.yml
  • .github/workflows/sign-modules.yml
  • CHANGELOG.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.py
  • docs/reference/module-security.md
  • .github/workflows/sign-modules-on-approval.yml
  • .github/workflows/sign-modules.yml
  • 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: 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.yml
  • 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: 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.yml
  • 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: 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.yml
  • tests/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 clarity

This 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_branch and version_bump to explicit choices keeps the dispatch path predictable and avoids free-form refs.

tests/unit/specfact_cli/registry/test_signing_artifacts.py (1)

438-443: Nice on: 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: Good on: fallback here as well.

Catching the YAML onTrue coercion keeps these policy tests loader-agnostic.

Comment thread .github/workflows/sign-modules-on-approval.yml
Comment thread .github/workflows/sign-modules-on-approval.yml
Comment thread .github/workflows/sign-modules.yml Outdated
Comment thread CHANGELOG.md
Comment thread docs/reference/module-security.md Outdated
Comment thread tests/unit/specfact_cli/registry/test_signing_artifacts.py
Comment thread tests/unit/workflows/test_sign_modules_on_approval.py
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working module-system Module system and registry

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

[Change] CI-Driven Module Signing On PR Approval

1 participant