101 Commits

Author SHA1 Message Date
jmiller 657b122736 fix(ci): harden branch-cleanup.yml against Actions injection (sync from Template-Generic) 2026-07-15 03:24:46 +00:00
jmiller bacb977fac fix(ci): harden issue-branch.yml against Actions injection (sync from Template-Generic) 2026-07-15 03:24:45 +00:00
jmiller fec05ff9ac Merge pull request 'chore(rebrand): brand caps MokoGit -> MokoGIT' (#27) from fix/brand-mokogit-caps into main 2026-07-14 21:15:36 +00:00
jmiller ff156d3df8 chore(rebrand): brand caps MokoGit -> MokoGIT
Branding: the MokoGIT wordmark is caps-GIT. Corrects the display token from
MokoGit to MokoGIT (case-sensitive; lowercase path form .mokogit untouched).

Claude-Session: https://claude.ai/code/session_01DQEMmJPe61ya7HDfA6BHP8
2026-07-14 16:14:52 -05:00
jmiller bc80d64de0 Merge pull request 'chore(rebrand): gitea -> git (MokoGitea -> MokoGit, .mokogitea -> .mokogit)' (#26) from chore/rebrand-gitea-to-git into main 2026-07-14 20:56:55 +00:00
jmiller ee2590e1e9 chore(rebrand): gitea -> git (MokoGitea -> MokoGit, .mokogitea -> .mokogit)
Universal: Auto-Assign / Assign unassigned issues and PRs (pull_request_target) Successful in 1s
Case-preserving gitea->git across brand text + functional identifiers
(MOKOGITEA_TOKEN->MOKOGIT_TOKEN, GITEA_URL/ORG/REPO, gitea-actions[bot],
ntfy gitea-*). Protected: literal `.gitea` and git.mokoconsulting.tech.

WARNING: CI-breaking until the MokoGit server side is reconfigured.

Claude-Session: https://claude.ai/code/session_01DQEMmJPe61ya7HDfA6BHP8
2026-07-14 15:54:19 -05:00
jmiller 6e5322bd27 Merge pull request 'fix(sync): correct own case label Template-MCP -> Template-NPM' (#25) from fix/npm-sync-trigger-label into main
Universal: Changelog Validation / Validate CHANGELOG.md (push) Failing after 3s
Publish to npm / publish (push) Has been skipped
Generic: Standards Compliance / Secret Scanning (push) Successful in 3s
Generic: Standards Compliance / License Header Validation (push) Successful in 3s
Generic: Standards Compliance / Repository Structure Validation (push) Failing after 4s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 3s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 4s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 4s
Generic: Standards Compliance / README Completeness Check (push) Failing after 3s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 3s
Generic: Standards Compliance / Line Length Check (push) Successful in 4s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 5s
Generic: Standards Compliance / File Naming Standards (push) Successful in 3s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 3s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 39s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 4s
Generic: Standards Compliance / File Size Limits (push) Successful in 3s
Generic: Standards Compliance / Binary File Detection (push) Successful in 3s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 3s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 38s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 39s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 3s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 4s
Generic: Standards Compliance / Accessibility Check (push) Successful in 3s
Generic: Standards Compliance / Performance Metrics (push) Successful in 3s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 42s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 40s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 7s
Generic: Standards Compliance / Enterprise Readiness Check (push) Successful in 40s
Generic: Standards Compliance / Repository Health Check (push) Successful in 36s
Universal: Sync Version on Merge / Propagate README version (push) Failing after 42s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-14 20:17:42 +00:00
jmiller 7a7d855d1e fix(sync): correct own case label Template-MCP -> Template-NPM
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 9s
Branch Policy Check / Verify merge target (pull_request) Failing after 2s
Universal: PR Check / Branch Policy (pull_request) Failing after 1s
Universal: Changelog Validation / Validate CHANGELOG.md (pull_request) Failing after 5s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: PR Check / Secret Scan (pull_request) Successful in 5s
Universal: PR Check / Validate PR (pull_request) Successful in 6s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Standards Compliance / Secret Scanning (pull_request) Successful in 4s
Generic: Standards Compliance / License Header Validation (pull_request) Successful in 3s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 10s
Generic: Standards Compliance / Repository Structure Validation (pull_request) Failing after 4s
Generic: Standards Compliance / Coding Standards Check (pull_request) Successful in 4s
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Failing after 4s
Generic: Standards Compliance / Documentation Quality Check (pull_request) Successful in 3s
Generic: Standards Compliance / README Completeness Check (pull_request) Failing after 4s
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Successful in 3s
Generic: Standards Compliance / Line Length Check (pull_request) Successful in 4s
Generic: Standards Compliance / Script Integrity Validation (pull_request) Successful in 6s
Generic: Standards Compliance / File Naming Standards (pull_request) Successful in 3s
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Successful in 3s
Generic: Standards Compliance / Version Consistency Check (pull_request) Successful in 47s
Generic: Standards Compliance / Dead Code Detection (pull_request) Successful in 5s
Generic: Standards Compliance / File Size Limits (pull_request) Successful in 4s
Generic: Standards Compliance / Binary File Detection (pull_request) Successful in 3s
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Successful in 42s
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Successful in 3s
Generic: Standards Compliance / Code Duplication Detection (pull_request) Successful in 43s
Generic: Standards Compliance / Broken Link Detection (pull_request) Successful in 4s
Generic: Standards Compliance / API Documentation Coverage (pull_request) Successful in 3s
Generic: Standards Compliance / Accessibility Check (pull_request) Successful in 4s
Generic: Standards Compliance / Performance Metrics (pull_request) Successful in 3s
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Successful in 41s
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Successful in 43s
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Successful in 8s
Universal: Auto-Assign / Assign unassigned issues and PRs (pull_request_target) Successful in 1s
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Successful in 37s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 11s
Generic: Standards Compliance / Repository Health Check (pull_request) Successful in 42s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
PR #24 fixed this but concurrent workflow-sync-trigger relocation churn
reverted the custom/ copy to the old label. Since the trigger lives in
custom/ (never cascaded by the sync tool), it can't self-heal — fix directly
so $REPO=Template-NPM matches and Phase 2 runs with --platform-filter npm.

Claude-Session: https://claude.ai/code/session_01DQEMmJPe61ya7HDfA6BHP8
2026-07-14 15:17:19 -05:00
jmiller 6a3e066b4b Merge pull request 'chore(rename): Template-MCP -> Template-NPM (identity + drop stale mcp-*.yml)' (#24) from chore/rename-mcp-to-npm into main
Universal: Changelog Validation / Validate CHANGELOG.md (push) Failing after 3s
Publish to npm / publish (push) Has been skipped
Generic: Standards Compliance / Secret Scanning (push) Successful in 3s
Generic: Standards Compliance / License Header Validation (push) Successful in 3s
Generic: Standards Compliance / Repository Structure Validation (push) Failing after 4s
Generic: Standards Compliance / Coding Standards Check (push) Successful in 3s
Generic: Standards Compliance / Workflow Configuration Check (push) Failing after 4s
Generic: Standards Compliance / Documentation Quality Check (push) Successful in 3s
Generic: Standards Compliance / README Completeness Check (push) Failing after 2s
Generic: Standards Compliance / Git Repository Hygiene (push) Successful in 3s
Generic: Standards Compliance / Script Integrity Validation (push) Successful in 5s
Generic: Standards Compliance / Line Length Check (push) Successful in 4s
Generic: Standards Compliance / File Naming Standards (push) Successful in 3s
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 4s
Generic: Standards Compliance / Version Consistency Check (push) Successful in 44s
Generic: Standards Compliance / Code Complexity Analysis (push) Successful in 37s
Generic: Standards Compliance / Dead Code Detection (push) Successful in 4s
Generic: Standards Compliance / File Size Limits (push) Successful in 3s
Generic: Standards Compliance / Code Duplication Detection (push) Successful in 38s
Generic: Standards Compliance / Binary File Detection (push) Successful in 4s
Generic: Standards Compliance / TODO/FIXME Tracking (push) Successful in 4s
Generic: Standards Compliance / Broken Link Detection (push) Successful in 3s
Generic: Standards Compliance / API Documentation Coverage (push) Successful in 4s
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 43s
Generic: Standards Compliance / Accessibility Check (push) Successful in 3s
Generic: Standards Compliance / Unused Dependencies Check (push) Successful in 42s
Generic: Standards Compliance / Performance Metrics (push) Successful in 4s
Generic: Standards Compliance / Terraform Configuration Validation (push) Successful in 7s
Generic: Standards Compliance / Repository Health Check (push) Successful in 40s
Generic: Standards Compliance / Enterprise Readiness Check (push) Successful in 41s
Universal: Sync Version on Merge / Propagate README version (push) Failing after 42s
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-14 15:26:50 +00:00
jmiller 5d4ca460fb chore(rename): Template-MCP -> Template-NPM (identity + drop stale mcp-*.yml)
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 9s
Branch Policy Check / Verify merge target (pull_request) Successful in 1s
Universal: PR Check / Branch Policy (pull_request) Successful in 2s
Universal: Changelog Validation / Validate CHANGELOG.md (pull_request) Failing after 5s
Universal: PR Check / Secret Scan (pull_request) Successful in 5s
Universal: PR Check / Validate PR (pull_request) Successful in 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Standards Compliance / Secret Scanning (pull_request) Successful in 3s
Generic: Standards Compliance / License Header Validation (pull_request) Successful in 5s
Generic: Project CI / Lint & Validate (pull_request) Successful in 16s
Generic: Standards Compliance / Repository Structure Validation (pull_request) Failing after 3s
Generic: Standards Compliance / Coding Standards Check (pull_request) Successful in 4s
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Failing after 4s
Generic: Standards Compliance / Documentation Quality Check (pull_request) Successful in 3s
Generic: Standards Compliance / README Completeness Check (pull_request) Failing after 3s
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Successful in 3s
Generic: Standards Compliance / Script Integrity Validation (pull_request) Successful in 6s
Generic: Standards Compliance / Line Length Check (pull_request) Successful in 5s
Generic: Standards Compliance / File Naming Standards (pull_request) Successful in 3s
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Successful in 3s
Generic: Standards Compliance / Version Consistency Check (pull_request) Successful in 42s
Generic: Standards Compliance / Dead Code Detection (pull_request) Successful in 5s
Generic: Standards Compliance / File Size Limits (pull_request) Successful in 3s
Generic: Standards Compliance / Binary File Detection (pull_request) Successful in 3s
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Successful in 3s
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Successful in 40s
Generic: Standards Compliance / Code Duplication Detection (pull_request) Successful in 46s
Generic: Standards Compliance / Broken Link Detection (pull_request) Successful in 4s
Generic: Standards Compliance / API Documentation Coverage (pull_request) Successful in 3s
Generic: Standards Compliance / Accessibility Check (pull_request) Successful in 4s
Generic: Standards Compliance / Performance Metrics (pull_request) Successful in 2s
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Successful in 42s
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Successful in 43s
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Successful in 7s
Universal: Auto-Assign / Assign unassigned issues and PRs (pull_request_target) Successful in 1s
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Successful in 44s
Generic: Standards Compliance / Repository Health Check (pull_request) Successful in 45s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 2m24s
Repo renamed on MokoGitea to match the consolidated `npm` platform enum.
Updates repo identity references (README, CLAUDE, CONTRIBUTING,
CODE_OF_CONDUCT, issue template, sync-trigger case label) from
Template-MCP to Template-NPM, and removes the 4 stale mcp-*.yml workflows
that were superseded by npm-*.yml (which use src/ + Template-* guard).
MCP protocol references (Model Context Protocol / MCP server) are retained.

Claude-Session: https://claude.ai/code/session_01DQEMmJPe61ya7HDfA6BHP8
2026-07-14 10:07:02 -05:00
jmiller e2d82f294e Merge pull request 'chore(ci): enable --delete-orphans in workflow sync' (#23) from chore/enable-orphan-pruning into main
Universal: Changelog Validation / Validate CHANGELOG.md (push) Has been cancelled
Publish to npm / publish (push) Has been cancelled
Generic: Standards Compliance / Secret Scanning (push) Has been cancelled
Generic: Standards Compliance / License Header Validation (push) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (push) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (push) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (push) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (push) Has been cancelled
Generic: Standards Compliance / README Completeness Check (push) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (push) Has been cancelled
Generic: Standards Compliance / Line Length Check (push) Has been cancelled
Generic: Standards Compliance / File Naming Standards (push) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (push) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (push) Has been cancelled
Generic: Standards Compliance / File Size Limits (push) Has been cancelled
Generic: Standards Compliance / Binary File Detection (push) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (push) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (push) Has been cancelled
Generic: Standards Compliance / Accessibility Check (push) Has been cancelled
Generic: Standards Compliance / Performance Metrics (push) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Generic: Standards Compliance / Repository Health Check (push) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Universal: Sync Version on Merge / Propagate README version (push) Has been cancelled
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-14 04:30:51 +00:00
jmiller 9a1c1cd37d chore(ci): enable --delete-orphans in workflow sync
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 4s
Universal: Changelog Validation / Validate CHANGELOG.md (pull_request) Has been cancelled
Generic: Project CI / Lint & Validate (pull_request) Has been cancelled
Branch Policy Check / Verify merge target (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Has been cancelled
Universal: PR Check / Secret Scan (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Has been cancelled
Generic: Repo Health / Access control (pull_request) Has been cancelled
Generic: Repo Health / Site Health (pull_request) Has been cancelled
Generic: Standards Compliance / Secret Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / License Header Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (pull_request) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (pull_request) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (pull_request) Has been cancelled
Generic: Standards Compliance / README Completeness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Line Length Check (pull_request) Has been cancelled
Generic: Standards Compliance / File Naming Standards (pull_request) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (pull_request) Has been cancelled
Generic: Standards Compliance / File Size Limits (pull_request) Has been cancelled
Generic: Standards Compliance / Binary File Detection (pull_request) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (pull_request) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (pull_request) Has been cancelled
Generic: Standards Compliance / Accessibility Check (pull_request) Has been cancelled
Generic: Standards Compliance / Performance Metrics (pull_request) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Health Check (pull_request) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Has been cancelled
Universal: Auto-Assign / Assign unassigned issues and PRs (pull_request_target) Has been cancelled
Branch Cleanup / Delete merged branch (pull_request) Has been cancelled
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
Now that getRepoPlatform reads /metadata (correct platform routing) and platform templates are complete supersets, turn on orphan pruning so repos converge exactly to their template set (custom/ and custom-* preserved).
2026-07-14 04:30:47 +00:00
jmiller d316fe89b5 Merge pull request 'chore(ci): add standards-compliance + MCP-standard CI workflows' (#22) from chore/add-mcp-standard-ci into main
Universal: Changelog Validation / Validate CHANGELOG.md (push) Has been cancelled
Publish to npm / publish (push) Has been cancelled
Generic: Standards Compliance / Secret Scanning (push) Has been cancelled
Generic: Standards Compliance / License Header Validation (push) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (push) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (push) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (push) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (push) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (push) Has been cancelled
Generic: Standards Compliance / README Completeness Check (push) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (push) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (push) Has been cancelled
Generic: Standards Compliance / Line Length Check (push) Has been cancelled
Generic: Standards Compliance / File Naming Standards (push) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (push) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (push) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (push) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (push) Has been cancelled
Generic: Standards Compliance / File Size Limits (push) Has been cancelled
Generic: Standards Compliance / Binary File Detection (push) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (push) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (push) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (push) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (push) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (push) Has been cancelled
Generic: Standards Compliance / Accessibility Check (push) Has been cancelled
Generic: Standards Compliance / Performance Metrics (push) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (push) Has been cancelled
Generic: Standards Compliance / Repository Health Check (push) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (push) Has been cancelled
Universal: Sync Version on Merge / Propagate README version (push) Has been cancelled
Generic: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-14 03:28:41 +00:00
jmiller 42f6730a4c chore(ci): add standards-compliance + MCP-standard CI workflows
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 4s
Universal: Changelog Validation / Validate CHANGELOG.md (pull_request) Has been cancelled
Generic: Project CI / Lint & Validate (pull_request) Has been cancelled
Branch Policy Check / Verify merge target (pull_request) Has been cancelled
Universal: PR Check / Branch Policy (pull_request) Has been cancelled
Universal: PR Check / Secret Scan (pull_request) Has been cancelled
Universal: PR Check / Validate PR (pull_request) Has been cancelled
Generic: Repo Health / Access control (pull_request) Has been cancelled
Generic: Repo Health / Site Health (pull_request) Has been cancelled
Generic: Standards Compliance / Secret Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / License Header Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Structure Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Coding Standards Check (pull_request) Has been cancelled
Generic: Standards Compliance / Version Consistency Check (pull_request) Has been cancelled
Generic: Standards Compliance / Workflow Configuration Check (pull_request) Has been cancelled
Generic: Standards Compliance / Documentation Quality Check (pull_request) Has been cancelled
Generic: Standards Compliance / README Completeness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Git Repository Hygiene (pull_request) Has been cancelled
Generic: Standards Compliance / Script Integrity Validation (pull_request) Has been cancelled
Generic: Standards Compliance / Line Length Check (pull_request) Has been cancelled
Generic: Standards Compliance / File Naming Standards (pull_request) Has been cancelled
Generic: Standards Compliance / Insecure Code Pattern Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Code Complexity Analysis (pull_request) Has been cancelled
Generic: Standards Compliance / Code Duplication Detection (pull_request) Has been cancelled
Generic: Standards Compliance / Dead Code Detection (pull_request) Has been cancelled
Generic: Standards Compliance / File Size Limits (pull_request) Has been cancelled
Generic: Standards Compliance / Binary File Detection (pull_request) Has been cancelled
Generic: Standards Compliance / TODO/FIXME Tracking (pull_request) Has been cancelled
Generic: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Has been cancelled
Generic: Standards Compliance / Unused Dependencies Check (pull_request) Has been cancelled
Generic: Standards Compliance / Broken Link Detection (pull_request) Has been cancelled
Generic: Standards Compliance / API Documentation Coverage (pull_request) Has been cancelled
Generic: Standards Compliance / Accessibility Check (pull_request) Has been cancelled
Generic: Standards Compliance / Performance Metrics (pull_request) Has been cancelled
Generic: Standards Compliance / Enterprise Readiness Check (pull_request) Has been cancelled
Generic: Standards Compliance / Repository Health Check (pull_request) Has been cancelled
Generic: Standards Compliance / Terraform Configuration Validation (pull_request) Has been cancelled
Branch Cleanup / Delete merged branch (pull_request) Has been cancelled
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been cancelled
RC Revert / Rename rc/ back to dev/ (pull_request) Has been cancelled
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Generic: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
2026-07-14 03:28:37 +00:00
jmiller 03f41cc0d0 Merge pull request 'ci: migrate pr-check to /metadata + auto-release rc-move to git-push' (#21) from chore/metadata-rc-migration into main
Publish to npm / publish (push) Has been skipped
2026-07-13 16:43:53 +00:00
jmiller 587c0fc5b7 ci: migrate platform detection to /metadata API + rc-move to git push
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 3s
Universal: PR Check / Secret Scan (pull_request) Successful in 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 12s
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 8s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
pr-check.yml: 'Detect platform' now reads the public MokoGitea /metadata
endpoint (retires the manifest.xml / /manifest-field lookup).
auto-release.yml: 'Rename branch to rc' now points rc via git push instead
of branch_rename.php's PATCH /git/refs (which 405s on protected branches).
Surgical step swaps only; branch-policy and platform-specific logic untouched.
2026-07-13 16:43:51 +00:00
jmiller c4c008feff Merge pull request 'chore(platform): consolidate mcp -> npm (rename workflows + sync-trigger)' (#20) from chore/consolidate-npm-platform into main
Publish to npm / publish (push) Has been skipped
2026-07-13 16:31:52 +00:00
jmiller bcb4698213 chore(platform): consolidate mcp -> npm (rename mcp-*.yml workflows, sync-trigger)
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Failing after 4s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 8s
Generic: Project CI / Lint & Validate (pull_request) Successful in 12s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Secret Scan (pull_request) Successful in 3s
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 7s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
- Rename mcp-{auto-release,build-test,sdk-check,tool-inventory}.yml -> npm-*.yml
- sync-trigger: Template-MCP -> PLATFORM=npm
- docs platform example -> npm

Authored-by: Moko Consulting
2026-07-13 11:31:45 -05:00
jmiller a5c7dc4040 Merge pull request 'chore(sync): relocate workflow-sync-trigger.yml to workflows/custom/' (#19) from chore/sync-workflow-to-custom into main
Publish to npm / publish (push) Has been skipped
2026-07-13 16:20:53 +00:00
jmiller 7b4a1533f7 chore(sync): relocate workflow-sync-trigger.yml to workflows/custom/
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 8s
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 4s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 13s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 9s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Keeps the template-only sync workflow out of the root dir that
workflow_sync.php distributes, so it never propagates to child repos.
Still runs here (Gitea Actions executes custom/).
2026-07-13 16:18:25 +00:00
jmiller 98d2303ebd Merge pull request 'Rebrand: MokoGitea + MokoCLI/mokocli, metadata via API, AI-client files' (#18) from gitea-land/mokocli-mokogitea into main
Publish to npm / publish (push) Has been skipped
2026-07-13 15:42:51 +00:00
jmiller c4fc5fd0b9 chore: MokoGitea + MokoCLI/mokocli rebrand, metadata via API, AI-client files
Universal: PR Check / Branch Policy (pull_request) Successful in 1s
Universal: PR Check / Secret Scan (pull_request) Successful in 4s
Universal: PR Check / Validate PR (pull_request) Successful in 5s
Generic: Repo Health / Site Health (pull_request) Has been skipped
Generic: Repo Health / Access control (pull_request) Successful in 1s
Generic: Project CI / Lint & Validate (pull_request) Successful in 14s
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Failing after 9s
Branch Cleanup / Delete merged branch (pull_request) Successful in 1s
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Successful in 8s
Applied on canonical Gitea main. MokoStandards retired; MokoCLI branding
(lowercase mokocli URLs); Gitea->MokoGitea; metadata via MokoGitea Metadata
field (API); .mokogitea/GEMINI.md + MOKOAI.md; gitignore AI entries.

Authored-by: Moko Consulting
2026-07-13 10:23:03 -05:00
jmiller 92b76c4a22 Merge fix/rebrand-mokogitea: Gitea -> MokoGitea branding (Template-Generic#68)
Publish to npm / publish (push) Has been skipped
2026-07-05 21:14:27 +00:00
jmiller 31718da51a chore(branding): Gitea -> MokoGitea in workflow/doc branding (detached fork)
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
DEFGROUP Gitea.* -> MokoGitea.*, committer gitea-actions[bot] -> mokogitea-actions[bot],
platform prose (Gitea wiki/release/Pages/API -> MokoGitea). Preserves functional tokens:
secrets.GITEA_TOKEN/GITHUB_TOKEN, GITEA_ACTIONS_* runner env, vars.GITEA_URL/GITEA_ORG,
and the git.mokoconsulting.tech domain. Refs Template-Generic#68.
2026-07-05 21:14:25 +00:00
jmiller b51b8698d9 Merge fix/move-sync-trigger: relocate workflow-sync-trigger to .mokogitea/workflows/
Publish to npm / publish (push) Has been skipped
2026-07-05 21:00:06 +00:00
jmiller f983d3771b ci(sync): move workflow-sync-trigger.yml out of custom/ to top-level (shared workflow; keeps Template-* gate)
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 9s
2026-07-05 21:00:05 +00:00
jmiller 9ed5e2a6ed Merge fix/gate-sync-trigger: gate workflow-sync-trigger to Template-* only
Publish to npm / publish (push) Has been skipped
2026-07-05 20:58:28 +00:00
jmiller 0f72a807be ci(sync): smart-gate custom/workflow-sync-trigger to run only on Template-* repos
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 14s
2026-07-05 20:58:27 +00:00
jmiller f117c0de0f Merge fix/strip-github-workflows: remove GitHub-only workflows
Publish to npm / publish (push) Has been skipped
2026-07-05 20:51:40 +00:00
jmiller 27fc4dddcf chore: strip GitHub-only workflows (DEFGROUP GitHub.Workflow) not functional on MokoGitea
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 15s
2026-07-05 20:51:40 +00:00
jmiller 5cea5c5b6b Merge fix/remove-github-cruft: drop GitHub-only workflows from Template-MCP
Universal: Changelog Validation / Validate CHANGELOG.md (push) Has been skipped
Publish to npm / publish (push) Has been skipped
MCP: Standards Compliance / Secret Scanning (push) Successful in 4s
MCP: Standards Compliance / License Header Validation (push) Successful in 4s
MCP: Standards Compliance / Repository Structure Validation (push) Failing after 4s
MCP: Standards Compliance / Coding Standards Check (push) Failing after 4s
MCP: Standards Compliance / Workflow Configuration Check (push) Failing after 4s
MCP: Standards Compliance / Documentation Quality Check (push) Successful in 5s
MCP: Standards Compliance / README Completeness Check (push) Failing after 5s
MCP: Standards Compliance / Git Repository Hygiene (push) Successful in 5s
MCP: Standards Compliance / Script Integrity Validation (push) Successful in 7s
MCP: Standards Compliance / Line Length Check (push) Failing after 5s
MCP: Standards Compliance / File Naming Standards (push) Successful in 5s
MCP: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 6s
MCP: Standards Compliance / Version Consistency Check (push) Successful in 1m9s
MCP: Standards Compliance / Dead Code Detection (push) Successful in 11s
MCP: Standards Compliance / File Size Limits (push) Successful in 5s
MCP: Standards Compliance / Binary File Detection (push) Successful in 6s
MCP: Standards Compliance / TODO/FIXME Tracking (push) Successful in 5s
MCP: Standards Compliance / Code Complexity Analysis (push) Successful in 1m19s
MCP: Standards Compliance / Code Duplication Detection (push) Successful in 1m18s
MCP: Standards Compliance / Broken Link Detection (push) Successful in 6s
MCP: Standards Compliance / API Documentation Coverage (push) Successful in 6s
MCP: Standards Compliance / Accessibility Check (push) Successful in 5s
MCP: Standards Compliance / Performance Metrics (push) Successful in 5s
MCP: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 1m13s
MCP: Standards Compliance / Unused Dependencies Check (push) Successful in 1m7s
Universal: Sync Version on Merge / Propagate README version (push) Has been skipped
MCP: Standards Compliance / Terraform Configuration Validation (push) Successful in 14s
MCP: Standards Compliance / Enterprise Readiness Check (push) Successful in 1m7s
MCP: Standards Compliance / Repository Health Check (push) Successful in 1m8s
MCP: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-05 20:49:31 +00:00
jmiller 97183ea293 chore(mcp): remove GitHub-only workflows not functional on Gitea
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 16s
codeql-analysis (github/codeql-action), copilot-agent + enterprise-firewall-setup
(github/copilot-swe-agent), auto-assign, and repository-cleanup (gh api against
github.com; duplicated Gitea cleanup.yml) were imported from the GitHub
MokoStandards repo and do not run on MokoGitea Actions.
2026-07-05 20:49:29 +00:00
jmiller 78cbb2704a Merge pull request #17 from fix/gate-and-normalize (gate MCP workflows + normalize refs)
Universal: Changelog Validation / Validate CHANGELOG.md (push) Has been skipped
Publish to npm / publish (push) Has been skipped
Universal: CodeQL Analysis / Analyze (actions) (push) Failing after 1m0s
MCP: Standards Compliance / Secret Scanning (push) Successful in 6s
Universal: CodeQL Analysis / Analyze (javascript) (push) Failing after 1m2s
MCP: Standards Compliance / License Header Validation (push) Successful in 4s
MCP: Standards Compliance / Repository Structure Validation (push) Failing after 4s
MCP: Standards Compliance / Coding Standards Check (push) Failing after 5s
MCP: Standards Compliance / Workflow Configuration Check (push) Failing after 6s
MCP: Standards Compliance / Documentation Quality Check (push) Successful in 6s
MCP: Standards Compliance / README Completeness Check (push) Failing after 5s
MCP: Standards Compliance / Git Repository Hygiene (push) Successful in 7s
MCP: Standards Compliance / Script Integrity Validation (push) Successful in 9s
MCP: Standards Compliance / Line Length Check (push) Failing after 7s
MCP: Standards Compliance / File Naming Standards (push) Successful in 6s
MCP: Standards Compliance / Insecure Code Pattern Detection (push) Successful in 5s
MCP: Standards Compliance / Version Consistency Check (push) Successful in 1m11s
MCP: Standards Compliance / Dead Code Detection (push) Successful in 8s
MCP: Standards Compliance / File Size Limits (push) Successful in 5s
MCP: Standards Compliance / Binary File Detection (push) Successful in 6s
MCP: Standards Compliance / TODO/FIXME Tracking (push) Successful in 5s
MCP: Standards Compliance / Code Complexity Analysis (push) Successful in 1m14s
MCP: Standards Compliance / Code Duplication Detection (push) Successful in 1m12s
MCP: Standards Compliance / Broken Link Detection (push) Successful in 4s
MCP: Standards Compliance / API Documentation Coverage (push) Successful in 4s
MCP: Standards Compliance / Accessibility Check (push) Successful in 4s
MCP: Standards Compliance / Performance Metrics (push) Successful in 4s
MCP: Standards Compliance / Dependency Vulnerability Scanning (push) Successful in 1m9s
MCP: Standards Compliance / Unused Dependencies Check (push) Successful in 1m4s
MCP: Standards Compliance / Terraform Configuration Validation (push) Successful in 14s
Universal: Sync Version on Merge / Propagate README version (push) Has been skipped
MCP: Standards Compliance / Enterprise Readiness Check (push) Successful in 1m6s
MCP: Standards Compliance / Repository Health Check (push) Successful in 1m6s
Universal: CodeQL Analysis / Security Scan Summary (push) Has been cancelled
MCP: Standards Compliance / Compliance Summary (push) Has been cancelled
2026-07-05 20:45:08 +00:00
jmiller 5505a305cc ci(templates): AND Template- guard into remaining platform release/publish/sync workflows
Universal: Auto Version Bump / Version Bump (push) Successful in 21s
Universal: Build & Release / Promote to RC (pull_request) Has been skipped
Universal: Build & Release / Build & Release Pipeline (pull_request) Has been skipped
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 21s
Universal: Auto-Assign / Assign unassigned issues and PRs (pull_request_target) Successful in 3s
Universal: Changelog Validation / Validate CHANGELOG.md (pull_request) Has been skipped
Generic: Project CI / Lint & Validate (pull_request) Successful in 28s
MCP: Copilot Agent / Run Copilot Coding Agent (pull_request) Failing after 5s
Universal: PR Check / Branch Policy (pull_request) Successful in 3s
Universal: PR Check / Secret Scan (pull_request) Successful in 8s
Universal: PR Check / Validate PR (pull_request) Failing after 6s
Generic: Repo Health / Access control (pull_request) Successful in 2s
Generic: Repo Health / Site Health (pull_request) Has been skipped
MCP: Standards Compliance / Secret Scanning (pull_request) Successful in 6s
Universal: CodeQL Analysis / Analyze (actions) (pull_request) Failing after 1m7s
MCP: Standards Compliance / License Header Validation (pull_request) Successful in 6s
Universal: CodeQL Analysis / Analyze (javascript) (pull_request) Failing after 1m8s
MCP: Standards Compliance / Repository Structure Validation (pull_request) Failing after 6s
MCP: Standards Compliance / Coding Standards Check (pull_request) Failing after 7s
MCP: Standards Compliance / Workflow Configuration Check (pull_request) Failing after 6s
MCP: Standards Compliance / Documentation Quality Check (pull_request) Successful in 6s
MCP: Standards Compliance / README Completeness Check (pull_request) Failing after 5s
MCP: Standards Compliance / Git Repository Hygiene (pull_request) Successful in 7s
MCP: Standards Compliance / Line Length Check (pull_request) Failing after 7s
MCP: Standards Compliance / Script Integrity Validation (pull_request) Successful in 9s
MCP: Standards Compliance / File Naming Standards (pull_request) Successful in 6s
MCP: Standards Compliance / Insecure Code Pattern Detection (pull_request) Successful in 6s
MCP: Standards Compliance / Version Consistency Check (pull_request) Successful in 1m22s
MCP: Standards Compliance / Dead Code Detection (pull_request) Successful in 8s
MCP: Standards Compliance / File Size Limits (pull_request) Successful in 6s
MCP: Standards Compliance / Binary File Detection (pull_request) Successful in 7s
MCP: Standards Compliance / TODO/FIXME Tracking (pull_request) Successful in 5s
MCP: Standards Compliance / Code Complexity Analysis (pull_request) Successful in 1m25s
MCP: Standards Compliance / Code Duplication Detection (pull_request) Successful in 1m30s
MCP: Standards Compliance / Broken Link Detection (pull_request) Successful in 7s
MCP: Standards Compliance / API Documentation Coverage (pull_request) Successful in 6s
MCP: Standards Compliance / Accessibility Check (pull_request) Successful in 6s
MCP: Standards Compliance / Performance Metrics (pull_request) Successful in 6s
MCP: Standards Compliance / Unused Dependencies Check (pull_request) Successful in 1m22s
MCP: Standards Compliance / Dependency Vulnerability Scanning (pull_request) Successful in 1m26s
MCP: Standards Compliance / Terraform Configuration Validation (pull_request) Successful in 17s
MCP: Standards Compliance / Enterprise Readiness Check (pull_request) Successful in 1m13s
MCP: Standards Compliance / Repository Health Check (pull_request) Successful in 1m15s
Branch Cleanup / Delete merged branch (pull_request) Has been skipped
Universal: Workflow Sync Trigger / Sync workflows to live repos (pull_request) Has been skipped
RC Revert / Rename rc/ back to dev/ (pull_request) Has been skipped
Generic: Project CI / Tests (pull_request) Has been cancelled
Universal: CodeQL Analysis / Security Scan Summary (pull_request) Has been cancelled
Universal: PR Check / Build RC Package (pull_request) Has been cancelled
Universal: PR Check / Report Issues (pull_request) Has been cancelled
Generic: Repo Health / Scripts governance (pull_request) Has been cancelled
Generic: Repo Health / Repository health (pull_request) Has been cancelled
Generic: Repo Health / Report: Scripts Governance (pull_request) Has been cancelled
Generic: Repo Health / Report: Repository Health (pull_request) Has been cancelled
MCP: Standards Compliance / Compliance Summary (pull_request) Has been cancelled
2026-07-05 20:40:06 +00:00
jmiller ab9112c234 ci(templates): gate build/CI/release/version workflows off template repos + normalize mokocli refs
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 26s
- Add 'skip on Template-*' guards to build/CI/release/version workflows so they
  don't run on the template repo itself (only on repos created from it).
- Smart-gate sync workflows to run ONLY on Template-* sources (so platform
  templates still propagate, but regular repos don't trigger sync-out).
- Normalize mokocli->MokoCLI repo/clone URLs, drop stale mokoconsulting-tech
  org slug on the git host, and mokoplatform/moko-platform->mokocli.
  (/opt/mokocli + /tmp/mokocli server paths left intact.)
2026-07-05 20:37:37 +00:00
jmiller 5fe246908c Merge pull request 'fix: move workflow-sync-trigger to custom/' (#15) from fix/move-workflow-sync-trigger into main
fix: move workflow-sync-trigger to custom/ [skip ci]
2026-06-30 18:06:50 +00:00
jmiller 1503cca367 chore: remove old workflow-sync-trigger from top-level [skip ci] 2026-06-30 18:03:50 +00:00
jmiller c5e5ca3261 chore: move workflow-sync-trigger to custom/ [skip ci] 2026-06-30 18:03:48 +00:00
jmiller f8a105ec7a Merge pull request 'chore(workflows): sync shared workflows from Template-Generic (main)' (#13) from fix/sync-from-generic into main 2026-06-27 19:28:50 +00:00
jmiller d70de91d3d chore(workflows): sync shared workflows from Template-Generic (main)
Authored-by: Moko Consulting
2026-06-27 14:27:39 -05:00
jmiller 6fa062a61a refactor: use ci-issue-reporter reusable workflow in repo-health [skip ci] 2026-06-25 17:27:16 +00:00
jmiller 36ce9234eb refactor: use ci-issue-reporter reusable workflow in pr-check [skip ci] 2026-06-25 17:26:47 +00:00
jmiller 444d9fc732 feat: add ci-issue-reporter reusable workflow [skip ci] 2026-06-25 17:26:02 +00:00
Moko Consulting [bot] d4e3aa57d0 fix: standardize token/URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:56:15 +00:00
Moko Consulting [bot] 026e7266b6 fix: standardize token/URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:56:09 +00:00
Moko Consulting [bot] eff49e0260 fix: standardize token/URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:55:37 +00:00
Moko Consulting [bot] a2ad009425 fix: standardize token/URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:55:31 +00:00
Moko Consulting [bot] ba05fec731 fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:27 +00:00
Moko Consulting [bot] bdd843c8d3 fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:24 +00:00
Moko Consulting [bot] 256e45f092 fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:21 +00:00
Moko Consulting [bot] 77ca6c37d4 fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:18 +00:00
Moko Consulting [bot] d5714805f8 fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:14 +00:00
Moko Consulting [bot] 780bb86b1f fix: standardize token and URL env vars to MOKOGITEA naming [skip ci] 2026-06-25 16:46:11 +00:00
jmiller f323e69fe0 chore: add version-set workflow [skip ci] 2026-06-23 22:00:28 +00:00
jmiller 43670c9e22 chore: remove security-audit.yml -- handled by MokoGitea 2026-06-23 18:05:54 +00:00
jmiller 0c60846ff6 chore: remove composer-publish.yml -- no longer needed 2026-06-23 18:00:40 +00:00
jmiller 0ce5dc1789 Merge pull request 'chore: remove automation directory' (#11) from fix/remove-automation into main 2026-06-21 23:10:31 +00:00
Jonathan Miller 698b8e9b18 chore: remove automation directory 2026-06-21 18:03:19 -05:00
jmiller 8af663df17 chore: sync auto-release.yml with semver tag support (#304) [skip ci] 2026-06-21 16:53:34 +00:00
jmiller 3e7f57c258 chore: sync auto-release.yml with semver tag support (#304) [skip ci] 2026-06-21 16:40:42 +00:00
jmiller e3e0a68a1c feat: add npm-publish workflow to MCP template 2026-06-21 05:49:31 +00:00
jmiller f216bd0f7c feat: add Composer publish workflow for Gitea registry + Packagist 2026-06-21 05:46:34 +00:00
jmiller 4c23fc5ae5 chore: delete manifest.xml (no longer used) 2026-06-21 00:19:40 +00:00
jmiller 6aee534334 refactor: merge PR workflows, reduce CI noise 2026-06-20 23:12:21 +00:00
jmiller 8ecee813dd refactor: merge PR workflows, reduce CI noise 2026-06-20 23:12:21 +00:00
jmiller d88e725cd3 refactor: merge PR workflows, reduce CI noise 2026-06-20 23:12:20 +00:00
jmiller af60e0af7e fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:17 +00:00
jmiller 1806f4f457 fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:16 +00:00
jmiller 06a23f53cc fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:16 +00:00
jmiller e8aea5bf6d fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:15 +00:00
jmiller ab5dca295e fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:14 +00:00
jmiller cf35adb1db fix: rename moko-platform to mokocli + changelog promotion in workflows 2026-06-20 17:16:13 +00:00
jmiller a5d777c62f fix(ci): restore full pre-release.yml content [skip ci] 2026-06-19 02:03:15 +00:00
jmiller 5154d97bff fix(ci): detect rebuild by branch name not version suffix [skip ci] 2026-06-19 02:01:49 +00:00
jmiller 591bfa76c3 ci: patch bump on same-branch rebuilds, minor only on elevation [skip ci] 2026-06-19 01:09:12 +00:00
jmiller dd13aff38c fix: update boilerplate references to correct repo name 2026-06-18 20:01:01 +00:00
jmiller 2aaa79c0d2 fix: update boilerplate references to correct repo name 2026-06-18 20:01:00 +00:00
jmiller 9b15d342b1 fix(ci): run repo-health on PR to main only, not on push 2026-06-18 16:39:43 +00:00
jmiller 521e4e4ba1 ci: add changelog extraction to promote-rc job [skip ci] 2026-06-18 16:37:30 +00:00
jmiller edc3316ac8 fix(ci): run CI on PR only, not on push 2026-06-18 16:13:52 +00:00
jmiller b9e4777d4a ci: deploy full pre-release workflow from mokoplatform [skip ci] 2026-06-18 13:47:53 +00:00
jmiller 1e301e7401 ci: disable auto-bump on push to dev [skip ci] 2026-06-16 20:46:33 +00:00
jmiller a9a01c322b fix(ci): rename secret refs to MOKOGITEA_TOKEN 2026-06-10 00:06:05 +00:00
jmiller 79b6aedf76 chore: sync security-audit.yml from Template-Generic [skip ci] 2026-06-07 17:51:19 +00:00
jmiller a91c05730e chore: sync pre-release.yml from Template-Generic [skip ci] 2026-06-07 17:51:19 +00:00
jmiller 1c1b23c640 chore: sync notify.yml from Template-Generic [skip ci] 2026-06-07 17:51:18 +00:00
jmiller 6f50658213 chore: sync ci-generic.yml from Template-Generic [skip ci] 2026-06-07 17:51:17 +00:00
jmiller 6a923039f8 chore: sync auto-release.yml from Template-Generic [skip ci] 2026-06-07 17:51:17 +00:00
Jonathan Miller ee15d17974 Merge remote-tracking branch 'origin/dev'
# Conflicts:
#	.mokogitea/workflows/pre-release.yml
2026-06-06 11:46:12 -05:00
jmiller e558156b11 Merge pull request 'chore: remove retired scripts directory' (#8) from dev into main
chore: remove retired scripts directory (#8)
2026-06-06 12:24:06 +00:00
jmiller 2a5aac40df chore: remove update-server workflow [skip ci] 2026-06-05 00:07:27 +00:00
jmiller a254b02b86 Merge pull request 'chore(ci): sync CI workflow updates from dev' (#7) from dev into main
chore(ci): sync CI workflow updates
2026-06-04 17:03:57 +00:00
gitea-actions[bot] 5e20194dd0 fix: ensure all pre-releases marked prerelease=true [skip ci] 2026-06-04 16:10:51 +00:00
jmiller 5fdce27fe2 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:58:17 +00:00
jmiller 0de85a595f chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:40:43 +00:00
jmiller 89c21dee45 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:32:06 +00:00
jmiller f2e3d2caa5 chore: sync .mokogitea/workflows/pr-check.yml from moko-platform [skip ci] 2026-06-04 15:18:55 +00:00
gitea-actions[bot] 419504ee4b chore: sync pre-release workflow — auto RC on PR to main [skip ci] 2026-06-04 14:45:47 +00:00
jmiller 436fa138e8 chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-06-04 14:23:20 +00:00
jmiller c606c3c453 chore: sync .mokogitea/workflows/repo-health.yml from moko-platform [skip ci] 2026-06-04 13:47:07 +00:00
jmiller aad56fc91a Merge pull request 'chore: gitignore config.json' (#5) from dev into main
fix(ci): add conflict-marker guard and remove RS_FTP_PATH_SUFFIX requirement
2026-06-03 03:50:56 +00:00
61 changed files with 2971 additions and 3227 deletions
+1 -1
View File
@@ -41,7 +41,7 @@
# CI and automation
.github/ export-ignore
.github/workflows/ export-ignore
.gitea/ export-ignore
.mokogit/ export-ignore
.gitlab/ export-ignore
# Development and tooling
+8
View File
@@ -205,6 +205,14 @@ hypothesis/
profile.ps1
.mcp.json
# ============================================================
# AI client working directories and instruction files
# ============================================================
.gemini/
.mokoai/
/GEMINI.md
/MOKOAI.md
# ============================================================
# Local wiki clone (not version controlled)
# ============================================================
+51
View File
@@ -0,0 +1,51 @@
# {{REPO_NAME}}
{{REPO_DESCRIPTION}}
> AI-client instructions for **Gemini**. Mirrors `.mokogit/CLAUDE.md` — keep CLAUDE.md, GEMINI.md, and MOKOAI.md in sync.
## First-Run Setup
> Before starting any work, complete these steps:
>
> 1. Replace all `{{REPO_NAME}}` placeholders with the actual repository name
> 2. Replace `{{REPO_DESCRIPTION}}` with a one-line project description
> 3. Replace `{{PLATFORM_TYPE}}` with the project type (e.g. `generic`, `npm`, `joomla`)
> 4. Replace `{{PRIMARY_LANGUAGE}}` with the dominant language
> 5. Set repository metadata via the MokoGIT **Metadata** field — repository **Settings → Metadata**, or the REST API `PUT /api/v1/repos/{owner}/{repo}/manifest` (identity, platform, language, package-type, entry-point). There is no metadata file in the repo.
> 6. Update the **Architecture** section for your project
> 7. Update the Commands section with actual build commands
> 8. Delete this setup block after completing all steps
> 9. Commit: `chore: initialize {{REPO_NAME}}`
## Quick Reference
| Field | Value |
|---|---|
| **Platform** | {{PLATFORM_TYPE}} |
| **Language** | {{PRIMARY_LANGUAGE}} |
| **Branch** | develop on `dev`, merge to `main` (protected) |
| **Wiki** | [Wiki](https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/wiki) |
## Commands
```bash
make build # Build the project
make lint # Run linters
make validate # Validate structure
make release # Full release pipeline
make clean # Clean build artifacts
```
## Architecture
<!-- Update this section for your project -->
## Rules
- **Never commit** `.gemini/`, `.mcp.json`, `TODO.md`, `*.min.css`/`*.min.js`
- **Attribution**: `Authored-by: Moko Consulting`
- **Workflow directory**: `.mokogit/` (not `.gitea/` or `.github/`)
- **Metadata**: set via the MokoGIT **Metadata** field (API / Settings → Metadata), never a committed manifest file
- **Wiki**: documentation lives in the MokoGIT wiki, not `docs/` files
- **Standards**: [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)
@@ -7,11 +7,11 @@ contact_links:
- name: 💬 Ask a Question
url: https://mokoconsulting.tech/
about: Get help or ask questions through our website
- name: 📚 MokoStandards Documentation
url: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
- name: 📚 MokoCLI Documentation
url: https://git.mokoconsulting.tech/MokoConsulting/mokocli
about: View our coding standards and best practices
- name: 🔒 Report a Security Vulnerability
url: https://git.mokoconsulting.tech/mokoconsulting-tech/.github-private/security/advisories/new
url: https://git.mokoconsulting.tech/MokoConsulting/.github-private/security/advisories/new
about: Report security vulnerabilities privately (for critical issues)
- name: 💡 Community Discussions
url: https://github.com/orgs/mokoconsulting-tech/discussions
@@ -42,7 +42,7 @@ Suggested text here
<!-- Add any other context, screenshots, or references -->
## Standards Alignment
- [ ] Follows MokoStandards documentation guidelines
- [ ] Follows MokoCLI documentation guidelines
- [ ] Uses en_US/en_GB localization
- [ ] Includes proper SPDX headers where applicable
@@ -37,7 +37,7 @@ If you have ideas about how this could be implemented, share them here:
Add any other context, mockups, or screenshots about the feature request here.
## Relevant Standards
Does this relate to any standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)?
Does this relate to any standards in [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli)?
- [ ] Accessibility (WCAG 2.1 AA)
- [ ] Localization (en_US/en_GB)
- [ ] Security best practices
@@ -45,4 +45,4 @@ Are there other ways to accomplish this today? If so, why is an MCP integration
- [ ] API documentation is available and accessible
- [ ] API supports the required authentication method
- [ ] I have tested the API endpoints manually
- [ ] The integration follows the Template-MCP architecture pattern
- [ ] The integration follows the Template-NPM architecture pattern
@@ -35,7 +35,7 @@ Use this template only for:
<!-- Describe how this could be addressed -->
## Standards Reference
Does this relate to security standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)?
Does this relate to security standards in [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli)?
- [ ] SPDX license identifiers
- [ ] Secret management
- [ ] Dependency security
+51
View File
@@ -0,0 +1,51 @@
# {{REPO_NAME}}
{{REPO_DESCRIPTION}}
> AI-client instructions for **MokoAI**. Mirrors `.mokogit/CLAUDE.md` — keep CLAUDE.md, GEMINI.md, and MOKOAI.md in sync.
## First-Run Setup
> Before starting any work, complete these steps:
>
> 1. Replace all `{{REPO_NAME}}` placeholders with the actual repository name
> 2. Replace `{{REPO_DESCRIPTION}}` with a one-line project description
> 3. Replace `{{PLATFORM_TYPE}}` with the project type (e.g. `generic`, `npm`, `joomla`)
> 4. Replace `{{PRIMARY_LANGUAGE}}` with the dominant language
> 5. Set repository metadata via the MokoGIT **Metadata** field — repository **Settings → Metadata**, or the REST API `PUT /api/v1/repos/{owner}/{repo}/manifest` (identity, platform, language, package-type, entry-point). There is no metadata file in the repo.
> 6. Update the **Architecture** section for your project
> 7. Update the Commands section with actual build commands
> 8. Delete this setup block after completing all steps
> 9. Commit: `chore: initialize {{REPO_NAME}}`
## Quick Reference
| Field | Value |
|---|---|
| **Platform** | {{PLATFORM_TYPE}} |
| **Language** | {{PRIMARY_LANGUAGE}} |
| **Branch** | develop on `dev`, merge to `main` (protected) |
| **Wiki** | [Wiki](https://git.mokoconsulting.tech/MokoConsulting/{{REPO_NAME}}/wiki) |
## Commands
```bash
make build # Build the project
make lint # Run linters
make validate # Validate structure
make release # Full release pipeline
make clean # Clean build artifacts
```
## Architecture
<!-- Update this section for your project -->
## Rules
- **Never commit** `.mokoai/`, `.mcp.json`, `TODO.md`, `*.min.css`/`*.min.js`
- **Attribution**: `Authored-by: Moko Consulting`
- **Workflow directory**: `.mokogit/` (not `.gitea/` or `.github/`)
- **Metadata**: set via the MokoGIT **Metadata** field (API / Settings → Metadata), never a committed manifest file
- **Wiki**: documentation lives in the MokoGIT wiki, not `docs/` files
- **Standards**: [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)
@@ -1,10 +1,10 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.gitea/workflows/branch-protection.yml
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories
#
# +========================================================================+
@@ -42,8 +42,8 @@ on:
default: ''
env:
GITEA_URL: https://git.mokoconsulting.tech
GITEA_ORG: MokoConsulting
GIT_URL: https://git.mokoconsulting.tech
GIT_ORG: MokoConsulting
permissions:
contents: read
@@ -59,11 +59,11 @@ jobs:
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: |
API="${GITEA_URL}/api/v1"
API="${GIT_URL}/api/v1"
# Platform/standards/infra repos to exclude
EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards moko-platform MokoTesting"
EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate"
EXCLUDE="git-org-config org-profile git-private .mokogit-private mokocli MokoTesting"
EXCLUDE="$EXCLUDE Template-Client Template-Dolibarr Template-Generic Template-Joomla MokoDoliProjTemplate"
if [ -n "${{ inputs.repos }}" ]; then
# User-specified repos
@@ -75,7 +75,7 @@ jobs:
while true; do
BATCH=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \
"${API}/orgs/${GIT_ORG}/repos?page=${PAGE}&limit=50" \
| jq -r '.[].name // empty')
[ -z "$BATCH" ] && break
REPOS="$REPOS $BATCH"
@@ -108,7 +108,7 @@ jobs:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: |
API="${GITEA_URL}/api/v1"
API="${GIT_URL}/api/v1"
REPOS="${{ steps.repos.outputs.repos }}"
SUCCESS=0
@@ -215,7 +215,7 @@ jobs:
curl -sS -o /dev/null -w "" \
-X DELETE \
-H "Authorization: token ${GA_TOKEN}" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true
"${API}/repos/${GIT_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true
# Create rule
RESPONSE=$(curl -sS -w "\n%{http_code}" \
@@ -223,7 +223,7 @@ jobs:
-H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \
-d "$RULE" \
"${API}/repos/${GITEA_ORG}/${REPO}/branch_protections")
"${API}/repos/${GIT_ORG}/${REPO}/branch_protections")
HTTP=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d')
@@ -5,7 +5,7 @@
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Workflows.Shared
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.mokogitea/workflows/auto-assign.yml
# PATH: /.mokogit/workflows/auto-assign.yml
# VERSION: 04.06.00
# BRIEF: Auto-assign jmiller to unassigned issues and PRs every 15 minutes
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/auto-bump.yml
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/auto-bump.yml
# VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
@@ -22,7 +22,7 @@ on:
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions:
contents: write
@@ -40,27 +40,27 @@ jobs:
- name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
token: ${{ secrets.MOKOGIT_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
- name: Setup MokoCLI tools
run: |
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
if [ -d "/opt/moko-platform/cli" ]; then
echo "MOKO_CLI=/opt/moko-platform/cli" >> "$GITHUB_ENV"
if [ -d "/opt/mokocli/cli" ]; then
echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV"
else
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/moko-platform-api/cli" >> "$GITHUB_ENV"
"https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \
/tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV"
fi
- name: Bump version
run: |
php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
--token "${{ secrets.MOKOGIT_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template
# VERSION: 04.06.00
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
# NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/auto-dev-issue.yml in all governed repos.
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/auto-dev-issue.yml in all governed repos.
name: "Universal: Dev/RC Branch Issue"
+492
View File
@@ -0,0 +1,492 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml
#
# +=======================================================================+
# | UNIVERSAL BUILD & RELEASE PIPELINE |
# +=======================================================================+
# | |
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
# | |
# | Platform-specific: |
# | joomla: XML manifest, type-prefixed packages |
# | dolibarr: mod*.class.php, update.txt, dev version reset |
# | generic: README-only, no update stream |
# | |
# +=======================================================================+
name: "Universal: Build & Release"
on:
pull_request:
types: [opened, synchronize, closed]
branches:
- main
paths-ignore:
- '.mokogit/workflows/**'
- '*.md'
- 'wiki/**'
- '.editorconfig'
- '.gitignore'
- '.gitattributes'
- '.gitmessage'
- 'LICENSE'
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: false
type: choice
default: release
options:
- release
- promote-rc
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GIT_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GIT_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
permissions:
contents: write
jobs:
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────────
promote-rc:
name: Promote to RC
runs-on: release
if: >-
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
(github.event.action == 'synchronize' && github.event.pull_request.merged != true) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGIT_TOKEN }}
fetch-depth: 1
- name: Setup MokoCLI tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
else
echo Falling back to fresh clone
if ! command -v composer > /dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
fi
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: Rename branch to rc
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
AUTH="Authorization: token ${{ secrets.MOKOGIT_TOKEN }}"
FROM="${{ github.event.pull_request.head.ref || 'dev' }}"
PR="${{ github.event.pull_request.number }}"
# Resolve the source branch HEAD commit.
SRC_JSON=$(curl -sf -H "$AUTH" "${API_BASE}/branches/${FROM}") \
|| { echo "::error::Source branch ${FROM} not found"; exit 1; }
SRC_SHA=$(printf '%s' "$SRC_JSON" | python3 -c "import sys, json; print(json.load(sys.stdin)['commit']['id'])" 2>/dev/null || true)
[ -n "$SRC_SHA" ] || { echo "::error::Could not resolve HEAD of ${FROM}"; exit 1; }
# Point rc at the source commit via git push. Git's git/refs PATCH API
# returns HTTP 405 on ANY protected branch (force or not, even for a user in
# the force-push allowlist), so it cannot move a protected rc. git push honors
# the push + force-push allowlists and creates rc if it is absent.
PUSH_URL="https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@${MOKOGIT_URL#https://}/${GIT_ORG}/${GIT_REPO}.git"
git config --global user.name "mokogit-actions[bot]"
git config --global user.email "actions@mokoconsulting.tech"
git fetch --no-tags "$PUSH_URL" "${FROM}"
git push --force "$PUSH_URL" "FETCH_HEAD:refs/heads/rc" \
|| { echo "::error::Failed to point rc at ${FROM} (${SRC_SHA}) via git push"; exit 1; }
echo "rc set to ${FROM} (${SRC_SHA})"
# Repoint the PR at rc, then delete the old source branch (non-fatal).
if [ -n "$PR" ]; then
curl -s -X PATCH -H "$AUTH" -H "Content-Type: application/json" \
"${API_BASE}/pulls/${PR}" -d '{"head":"rc"}' >/dev/null || true
fi
curl -s -X DELETE -H "$AUTH" "${API_BASE}/branches/${FROM}" >/dev/null || true
echo "Renamed ${FROM} -> rc"
- name: Checkout rc and configure git
run: |
git fetch origin rc
git checkout rc
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Publish RC release
run: |
php ${MOKO_CLI}/release_publish.php \
--path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGIT_TOKEN }}"
- name: Update RC release notes from CHANGELOG.md
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
# Extract [Unreleased] section from changelog
NOTES=""
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
fi
[ -z "$NOTES" ] && NOTES="Release candidate"
# Find the RC release and update its body
RELEASE_ID=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/release-candidate" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
python3 -c "
import json, urllib.request
body = open('/dev/stdin').read()
payload = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${TOKEN}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
" <<< "$NOTES"
echo "RC release notes updated from CHANGELOG.md"
fi
- name: Summary
if: always()
run: |
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
echo "Branch renamed to rc, minor bump, RC release built" >> $GITHUB_STEP_SUMMARY
# ── Merged PR → Build & Release (or promote RC to stable) ─────────────────────────
release:
name: Build & Release Pipeline
runs-on: release
if: >-
github.event.pull_request.merged == true ||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGIT_TOKEN }}
fetch-depth: 0
- name: Configure git for bot pushes
run: |
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Check for merge conflict markers
run: |
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
if [ -n "$CONFLICTS" ]; then
echo "::error::Merge conflict markers found — aborting release"
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "No conflict markers found"
- name: Setup MokoCLI tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
else
echo Falling back to fresh clone
if ! command -v composer > /dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
fi
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli
composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: "Detect platform"
id: platform
run: |
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
php ${MOKO_CLI}/manifest_read.php --path . --github-output 2>/dev/null || true
- name: "Determine version bump level"
id: bump
run: |
# Fix/patch branches: version was already bumped by pre-release, just strip suffix
# Feature/dev branches: bump minor for the new stable release
HEAD_REF="${{ github.event.pull_request.head.ref || 'dev' }}"
case "$HEAD_REF" in
fix/*|patch/*|hotfix/*|bugfix/*) BUMP="none" ;;
*) BUMP="minor" ;;
esac
echo "level=${BUMP}" >> "$GITHUB_OUTPUT"
echo "Bump level: ${BUMP} (from branch: ${HEAD_REF})"
- name: "Publish stable release"
run: |
BUMP_FLAG=""
if [ "${{ steps.bump.outputs.level }}" != "none" ]; then
BUMP_FLAG="--bump ${{ steps.bump.outputs.level }}"
fi
php ${MOKO_CLI}/release_publish.php \
--path . --stability stable ${BUMP_FLAG} --branch main \
--token "${{ secrets.MOKOGIT_TOKEN }}"
- name: "Read published version"
id: version
run: |
VERSION=$(php ${MOKO_CLI}/version_read.php --path . 2>/dev/null || echo "")
VERSION=$(echo "$VERSION" | sed 's/-\(dev\|alpha\|beta\|rc\)$//')
[ -z "$VERSION" ] && VERSION="00.00.00" && echo "skip=true" >> "$GITHUB_OUTPUT"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [[ "$PLATFORM" == joomla* ]]; then
echo "tag=stable" >> "$GITHUB_OUTPUT"
echo "release_tag=stable" >> "$GITHUB_OUTPUT"
else
echo "tag=v${VERSION}" >> "$GITHUB_OUTPUT"
echo "release_tag=v${VERSION}" >> "$GITHUB_OUTPUT"
fi
echo "branch=main" >> "$GITHUB_OUTPUT"
echo "Published version: ${VERSION}"
- name: "Create semver tag for non-Joomla repos"
id: semver
if: |
steps.version.outputs.skip != 'true' &&
!startsWith(steps.platform.outputs.platform, 'joomla')
run: |
VERSION="${{ steps.version.outputs.version }}"
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
SEMVER_TAG="v${VERSION}"
echo "Creating semver tag: ${SEMVER_TAG}"
# Create the git tag via API
HTTP_CODE=$(curl -sf -o /dev/null -w "%{http_code}" \
-X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/tags" \
-d "{\"tag_name\":\"${SEMVER_TAG}\",\"target\":\"main\",\"message\":\"Release ${VERSION}\"}" 2>/dev/null || echo "000")
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
echo "Created semver tag: ${SEMVER_TAG}"
elif [ "$HTTP_CODE" = "409" ]; then
echo "Semver tag ${SEMVER_TAG} already exists (skipped)"
else
echo "::warning::Failed to create semver tag ${SEMVER_TAG} (HTTP ${HTTP_CODE})"
fi
echo "semver_tag=${SEMVER_TAG}" >> "$GITHUB_OUTPUT"
- name: Update release notes and promote changelog
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
# Get the stable release info (version and ID)
RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/releases/tags/stable" 2>/dev/null || echo '{}')
RELEASE_ID=$(python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" <<< "$RELEASE_JSON" 2>/dev/null || true)
# Extract version from release name (e.g. "06.17.00" or "v06.17.00")
VERSION=$(python3 -c "
import json, sys, re
r = json.load(sys.stdin)
name = r.get('name', '')
m = re.search(r'(\d+\.\d+\.\d+)', name)
print(m.group(1) if m else '')
" <<< "$RELEASE_JSON" 2>/dev/null || true)
# Extract [Unreleased] section from changelog
NOTES=""
if [ -f "CHANGELOG.md" ]; then
NOTES=$(awk '/^## \[Unreleased\]/{found=1; next} /^## \[/{if(found) exit} found{print}' CHANGELOG.md)
fi
[ -z "$NOTES" ] && NOTES="Stable release"
# Update release body via API
if [ -n "$RELEASE_ID" ]; then
python3 -c "
import json, urllib.request
body = open('/dev/stdin').read()
payload = json.dumps({'body': body}).encode()
req = urllib.request.Request(
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${TOKEN}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
" <<< "$NOTES"
echo "Release notes updated from CHANGELOG.md"
fi
# Promote [Unreleased] → [version] in CHANGELOG.md and reset
if [ -n "$VERSION" ] && [ -f "CHANGELOG.md" ]; then
DATE=$(date +%Y-%m-%d)
python3 -c "
import sys
version, date = sys.argv[1], sys.argv[2]
content = open('CHANGELOG.md').read()
old = '## [Unreleased]'
new = f'## [Unreleased]\n\n## [{version}] --- {date}'
content = content.replace(old, new, 1)
open('CHANGELOG.md', 'w').write(content)
" "$VERSION" "$DATE"
git add CHANGELOG.md
git commit -m "chore: promote changelog [Unreleased] → [${VERSION}]" || true
git push origin main || true
echo "Changelog promoted: [Unreleased] → [${VERSION}]"
fi
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
php ${MOKO_CLI}/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
--branch main 2>&1 || true
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
- name: "Step 10: Push main to GitHub mirror"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
git fetch origin main --depth=1
git push github origin/main:refs/heads/main --force 2>/dev/null \
&& echo "main branch pushed to GitHub mirror" \
|| echo "WARNING: GitHub mirror push failed"
- name: "Step 11: Delete rc branch and recreate dev from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
# Delete rc branch (ephemeral — created by promote-rc)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/rc" 2>/dev/null \
&& echo "Deleted rc branch" || echo "rc branch not found"
# Delete dev branch
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
# Recreate dev from main (now includes version bump + changelog promotion)
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/branches" \
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
- name: "Step 12: Create version branch from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
BRANCH_NAME="version/${VERSION}"
MAIN_SHA=$(git rev-parse HEAD)
# Delete old version branch if it exists (same version re-release)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
# Create version/XX.YY.ZZ from main
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
# -- Dolibarr post-release: Reset dev version -----------------------------
- name: "Post-release: Reset dev version"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
php ${MOKO_CLI}/version_reset_dev.php \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true
# -- Summary --------------------------------------------------------------
- name: Pipeline Summary
if: always()
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Release | [View](${MOKOGIT_URL}/${GIT_ORG}/${GIT_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi
+60
View File
@@ -0,0 +1,60 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.mokogit/workflows/branch-cleanup.yml
# VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge
name: "Branch Cleanup"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
cleanup:
name: Delete merged branch
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == true &&
github.event.pull_request.head.ref != 'dev' &&
github.event.pull_request.head.ref != 'main'
steps:
- name: Delete source branch
# SECURITY: the PR head ref is attacker-controllable. Pass it (and the
# repo/token) through env so the Actions engine cannot splice it into the
# shell source, and validate it to a safe charset before use.
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
REPO: ${{ github.repository }}
API_BASE: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
BRANCH: ${{ github.event.pull_request.head.ref }}
run: |
set -euo pipefail
if ! printf '%s' "${BRANCH}" | grep -Eq '^[A-Za-z0-9._/-]+$'; then
echo "::error::unsafe branch name; refusing to proceed"; exit 1
fi
API="${API_BASE}/api/v1/repos/${REPO}/branches"
# URL-encode the branch name's slashes (no PHP dependency on the runner)
ENCODED=$(printf '%s' "${BRANCH}" | sed 's|/|%2F|g')
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${MOKOGIT_TOKEN}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
elif [ "$STATUS" = "404" ]; then
echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})"
fi
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/changelog-validation.yml.template
# VERSION: 04.06.00
# BRIEF: Validates CHANGELOG.md format and version consistency
# NOTE: Deployed to .mokogitea/workflows/changelog-validation.yml in governed repos.
# NOTE: Deployed to .mokogit/workflows/changelog-validation.yml in governed repos.
name: "Universal: Changelog Validation"
+197
View File
@@ -0,0 +1,197 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.mokogit/workflows/ci-generic.yml
# VERSION: 01.00.00
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)
name: "Generic: Project CI"
on:
pull_request:
branches:
- main
- dev
- dev/**
- rc/**
workflow_dispatch:
permissions:
contents: read
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
# ── Lint & Validate ───────────────────────────────────────────────────
lint:
name: Lint & Validate
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect toolchain
id: detect
run: |
HAS_PHP=false
HAS_NODE=false
[ -f "composer.json" ] && HAS_PHP=true
[ -f "package.json" ] && HAS_NODE=true
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
echo "Toolchain: PHP=$HAS_PHP Node=$HAS_NODE"
- name: Setup PHP
if: steps.detect.outputs.has_php == 'true'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
php -v
- name: Setup Node.js
if: steps.detect.outputs.has_node == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install PHP dependencies
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "composer.json" ]; then
composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
fi
- name: Install Node.js dependencies
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "package.json" ]; then
npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true
fi
- name: PHP syntax check
if: steps.detect.outputs.has_php == 'true'
run: |
ERRORS=0
while IFS= read -r -d '' file; do
if ! php -l "$file" 2>&1 | grep -q "No syntax errors"; then
echo "::error file=${file}::PHP syntax error"
ERRORS=$((ERRORS + 1))
fi
done < <(find . -name "*.php" -not -path "./.git/*" -not -path "./vendor/*" -not -path "./node_modules/*" -print0)
echo "## PHP Lint" >> $GITHUB_STEP_SUMMARY
if [ "$ERRORS" -eq 0 ]; then
echo "All PHP files passed syntax check." >> $GITHUB_STEP_SUMMARY
else
echo "${ERRORS} file(s) with syntax errors." >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: TypeScript/JavaScript lint
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "node_modules/.bin/eslint" ]; then
npx eslint src/ --quiet 2>&1 || { echo "::error::ESLint errors found"; exit 1; }
echo "## ESLint" >> $GITHUB_STEP_SUMMARY
echo "All files passed ESLint." >> $GITHUB_STEP_SUMMARY
elif [ -f ".eslintrc.json" ] || [ -f ".eslintrc.js" ] || [ -f "eslint.config.js" ]; then
echo "::warning::ESLint config found but eslint not installed"
else
echo "No ESLint configured — skipping"
fi
- name: TypeScript compile check
if: steps.detect.outputs.has_node == 'true'
run: |
if [ -f "tsconfig.json" ] && [ -f "node_modules/.bin/tsc" ]; then
npx tsc --noEmit 2>&1 || { echo "::error::TypeScript compilation errors"; exit 1; }
echo "## TypeScript" >> $GITHUB_STEP_SUMMARY
echo "TypeScript compilation passed." >> $GITHUB_STEP_SUMMARY
fi
- name: PHPStan static analysis
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "phpstan.neon" ] && [ -f "vendor/bin/phpstan" ]; then
vendor/bin/phpstan analyse --no-progress 2>&1 || { echo "::warning::PHPStan found issues"; }
fi
# ── Tests ─────────────────────────────────────────────────────────────
test:
name: Tests
runs-on: ubuntu-latest
needs: lint
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Detect toolchain
id: detect
run: |
HAS_PHP=false
HAS_NODE=false
[ -f "composer.json" ] && HAS_PHP=true
[ -f "package.json" ] && HAS_NODE=true
echo "has_php=$HAS_PHP" >> "$GITHUB_OUTPUT"
echo "has_node=$HAS_NODE" >> "$GITHUB_OUTPUT"
- name: Setup PHP
if: steps.detect.outputs.has_php == 'true'
run: |
if ! command -v php &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli php-mbstring php-xml >/dev/null 2>&1
fi
- name: Setup Node.js
if: steps.detect.outputs.has_node == 'true'
uses: actions/setup-node@v4
with:
node-version: '20'
- name: Install dependencies
run: |
[ -f "composer.json" ] && composer install --no-interaction --prefer-dist --quiet 2>/dev/null || true
[ -f "package.json" ] && { npm ci --quiet 2>/dev/null || npm install --quiet 2>/dev/null || true; }
- name: Run PHP tests
if: steps.detect.outputs.has_php == 'true'
run: |
if [ -f "vendor/bin/phpunit" ]; then
vendor/bin/phpunit --testdox 2>&1
echo "## PHPUnit" >> $GITHUB_STEP_SUMMARY
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
elif [ -f "phpunit.xml" ] || [ -f "phpunit.xml.dist" ]; then
echo "::warning::PHPUnit config found but phpunit not installed"
else
echo "No PHPUnit configured — skipping"
fi
- name: Run Node.js tests
if: steps.detect.outputs.has_node == 'true'
run: |
if jq -e '.scripts.test' package.json > /dev/null 2>&1; then
npm test 2>&1
echo "## Node.js Tests" >> $GITHUB_STEP_SUMMARY
echo "Tests passed." >> $GITHUB_STEP_SUMMARY
else
echo "No test script in package.json — skipping"
fi
- name: Build check
run: |
if [ -f "Makefile" ]; then
make build 2>&1 || echo "::warning::Build failed or not configured"
elif [ -f "package.json" ] && jq -e '.scripts.build' package.json > /dev/null 2>&1; then
npm run build 2>&1 || echo "::warning::Build failed"
fi
+68
View File
@@ -0,0 +1,68 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/ci-issue-reporter.yml
# VERSION: 01.00.00
# BRIEF: Reusable workflow — creates/updates a MokoGIT issue when a CI gate fails.
# Clones MokoCLI and runs cli/ci_issue_reporter.sh.
name: "Universal: CI Issue Reporter"
on:
workflow_call:
inputs:
gate:
description: "CI gate name (e.g. PR Validation, Repository Health)"
required: true
type: string
details:
description: "Human-readable failure description"
required: true
type: string
severity:
description: "error or warning"
required: false
type: string
default: "error"
workflow:
description: "Workflow name for the issue title"
required: false
type: string
default: ""
secrets:
MOKOGIT_TOKEN:
required: true
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
report:
name: "Report: ${{ inputs.gate }}"
runs-on: ubuntu-latest
steps:
- name: Clone MokoCLI
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
MOKOGIT_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
git clone --depth 1 --filter=blob:none --sparse "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli
cd /tmp/mokocli && git sparse-checkout set cli/ci_issue_reporter.sh
- name: Report CI failure
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x /tmp/mokocli/cli/ci_issue_reporter.sh
/tmp/mokocli/cli/ci_issue_reporter.sh \
--gate "${{ inputs.gate }}" \
--details "${{ inputs.details }}" \
--severity "${{ inputs.severity }}" \
--workflow "${{ inputs.workflow }}"
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.gitea/workflows/cleanup.yml
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/cleanup.yml
# VERSION: 01.00.00
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
@@ -21,7 +21,7 @@ permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs:
cleanup:
@@ -33,17 +33,17 @@ jobs:
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.GA_TOKEN }}
token: ${{ secrets.MOKOGIT_TOKEN }}
- name: Delete merged branches
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
echo "=== Merged Branch Cleanup ==="
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
# List branches via API
BRANCHES=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
BRANCHES=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \
"${API}/branches?limit=50" | jq -r '.[].name')
DELETED=0
@@ -56,7 +56,7 @@ jobs:
# Check if branch is merged into main
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
echo " Deleting merged branch: ${BRANCH}"
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \
"${API}/branches/${BRANCH}" 2>/dev/null || true
DELETED=$((DELETED + 1))
fi
@@ -66,20 +66,20 @@ jobs:
- name: Clean old workflow runs
env:
GA_TOKEN: ${{ secrets.GA_TOKEN }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
echo "=== Workflow Run Cleanup ==="
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}"
CUTOFF=$(date -d "30 days ago" +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -v-30d +%Y-%m-%dT%H:%M:%SZ)
# Get old completed runs
RUNS=$(curl -sS -H "Authorization: token ${GA_TOKEN}" \
RUNS=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \
"${API}/actions/runs?status=completed&limit=50" | \
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
DELETED=0
for RUN_ID in $RUNS; do
curl -sS -X DELETE -H "Authorization: token ${GA_TOKEN}" \
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
DELETED=$((DELETED + 1))
done
@@ -0,0 +1,83 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/workflow-sync-trigger.yml
# VERSION: 01.01.00
# BRIEF: Trigger workflow sync to live repos when a PR is merged to main
name: "Universal: Workflow Sync Trigger"
on:
workflow_dispatch:
pull_request:
types: [closed]
branches:
- main
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
sync:
name: Sync workflows to live repos
runs-on: ubuntu-latest
if: >-
startsWith(github.event.repository.name, 'Template-') &&
(github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true &&
!contains(github.event.pull_request.title, '[skip sync]')))
steps:
- name: Determine platform from repo name
id: platform
run: |
REPO="${{ github.event.repository.name }}"
case "$REPO" in
Template-Joomla) PLATFORM="joomla" ;;
Template-Dolibarr) PLATFORM="dolibarr" ;;
Template-Go) PLATFORM="go" ;;
Template-NPM) PLATFORM="npm" ;;
Template-Generic) PLATFORM="" ;;
*) PLATFORM="" ;;
esac
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
echo "Platform: ${PLATFORM:-all}"
- name: Clone MokoCLI
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
MOKOGIT_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
git clone --depth 1 "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli
- name: Install PHP
run: |
if ! command -v php &> /dev/null; then
apt-get update -qq && apt-get install -y -qq php-cli php-json php-curl > /dev/null 2>&1
fi
- name: Install dependencies
run: |
cd /tmp/mokocli
composer install --no-dev --no-interaction --quiet 2>/dev/null || true
- name: Run workflow sync
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
ARGS="--token ${MOKOGIT_TOKEN}"
ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}"
ARGS="${ARGS} --phase repos"
ARGS="${ARGS} --delete-orphans"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ -n "$PLATFORM" ]; then
ARGS="${ARGS} --platform-filter ${PLATFORM}"
fi
php /tmp/mokocli/cli/workflow_sync.php ${ARGS}
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/gitleaks.yml.template
# VERSION: 01.00.00
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
@@ -25,10 +25,6 @@
name: "Universal: Secret Scanning"
on:
pull_request:
branches:
- main
- 'dev/**'
schedule:
- cron: '0 5 * * 1' # Weekly Monday 05:00 UTC
workflow_dispatch:
@@ -38,7 +34,7 @@ permissions:
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'git-security' }}
jobs:
gitleaks:
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Automation
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Automation
# VERSION: 01.00.00
# BRIEF: Auto-create feature branch when an issue is opened
@@ -19,7 +19,7 @@ permissions:
issues: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs:
create-branch:
@@ -27,14 +27,22 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Create branch and comment
# SECURITY: never interpolate github.event.* into a run: script — the
# Actions engine splices the raw value into the shell source (command
# injection via a crafted issue title). Pass everything through env so
# the values arrive as ordinary shell variables that are not re-parsed.
env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
REPO: ${{ github.repository }}
ISSUE_NUM: ${{ github.event.issue.number }}
ISSUE_TITLE: ${{ github.event.issue.title }}
run: |
TOKEN="${{ secrets.GA_TOKEN }}"
API="${GITEA_URL}/api/v1/repos/${{ github.repository }}"
ISSUE_NUM="${{ github.event.issue.number }}"
ISSUE_TITLE="${{ github.event.issue.title }}"
TOKEN="${MOKOGIT_TOKEN}"
API="${MOKOGIT_URL}/api/v1/repos/${REPO}"
# Build slug from title: lowercase, replace non-alnum with dash, trim
SLUG=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
# Build slug from title: lowercase, replace non-alnum with dash, trim.
# printf (not echo) so a title beginning with "-" is not read as flags.
SLUG=$(printf '%s' "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
BRANCH="feature/${ISSUE_NUM}-${SLUG}"
# Check dev branch exists
@@ -58,7 +66,7 @@ jobs:
echo "Created branch: ${BRANCH}"
# Comment on issue with branch link
REPO_URL="${GITEA_URL}/${{ github.repository }}"
REPO_URL="${MOKOGIT_URL}/${REPO}"
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
curl -sf -X POST \
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.mokogitea/workflows/notify.yml
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/notify.yml
# VERSION: 01.00.00
# BRIEF: Push notifications via ntfy on release success or workflow failure
@@ -18,7 +18,6 @@ on:
- "Joomla Build & Release"
- "Joomla Extension CI"
- "Deploy"
- "Cascade Main → Dev"
types:
- completed
@@ -27,7 +26,7 @@ permissions:
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-releases' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'git-releases' }}
jobs:
notify:
@@ -32,7 +32,8 @@ jobs:
runs-on: ubuntu-latest
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
github.actor != 'github-actions[bot]'
github.actor != 'github-actions[bot]' &&
!startsWith(github.event.repository.name, 'Template-')
steps:
- name: Checkout repository
@@ -87,13 +88,13 @@ jobs:
done
# ── Version ──────────────────────────────────────────────────────
- name: Setup moko-platform tools
- name: Setup MokoCLI tools
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: |
git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/MokoConsulting/moko-platform.git" \
"https://x-access-token:${GH_TOKEN}@github.com/MokoConsulting/mokocli.git" \
/tmp/mokostandards
cd /tmp/mokostandards
composer install --no-dev --no-interaction --quiet
@@ -22,6 +22,7 @@ permissions:
jobs:
build:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
strategy:
matrix:
node-version: [20, 22]
+114
View File
@@ -0,0 +1,114 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
name: "Publish to npm"
on:
push:
branches:
- main
workflow_dispatch:
env:
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GIT_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GIT_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs:
publish:
runs-on: ubuntu-latest
if: >-
!contains(github.event.head_commit.message, '[skip ci]') &&
!contains(github.event.head_commit.message, '[skip publish]') &&
!startsWith(github.event.repository.name, 'Template-')
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
run: npm install
- name: Build
run: npm run build
- name: Auto-bump patch version
run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
PKG_NAME=$(node -p "require('./package.json').name")
CURRENT=$(node -p "require('./package.json').version")
PUBLISHED=$(npm view "${PKG_NAME}@latest" version 2>/dev/null || echo "0.0.0")
if [ "$CURRENT" != "$PUBLISHED" ]; then
echo "Version ${CURRENT} not yet published, using as-is."
exit 0
fi
# Bump locally to get the new version
npm version patch --no-git-tag-version
NEW_VER=$(node -p "require('./package.json').version")
echo "Bumping ${CURRENT} -> ${NEW_VER}"
# Push via MokoGIT API: branch + PR + merge
BRANCH="chore/npm-version-bump"
FILEPATH="package.json"
CONTENT=$(base64 -w 0 < package.json)
COMMIT_MSG="chore: bump to ${NEW_VER} [skip ci]"
# Get current file SHA on main
FILE_SHA=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/contents/${FILEPATH}?ref=main" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true)
# Create chore branch from main
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/branches" \
-d "{\"new_branch_name\":\"${BRANCH}\",\"old_branch_name\":\"main\"}" 2>/dev/null || true
# Get file SHA on chore branch (may differ if branch already existed)
BRANCH_SHA=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/contents/${FILEPATH}?ref=${BRANCH}" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('sha',''))" 2>/dev/null || true)
[ -n "$BRANCH_SHA" ] && FILE_SHA="$BRANCH_SHA"
# Push package.json to chore branch
PAYLOAD="{\"content\":\"${CONTENT}\",\"message\":\"${COMMIT_MSG}\",\"branch\":\"${BRANCH}\",\"sha\":\"${FILE_SHA}\"}"
HTTP=$(curl -sf -o /dev/null -w "%{http_code}" -X PUT \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "$PAYLOAD" \
"${API_BASE}/contents/${FILEPATH}" 2>/dev/null || echo "ERR")
echo "File push: HTTP ${HTTP}"
# Create PR
PR_NUM=$(curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/pulls" \
-d "{\"title\":\"${COMMIT_MSG}\",\"head\":\"${BRANCH}\",\"base\":\"main\"}" \
| python3 -c "import json,sys; print(json.load(sys.stdin).get('number',''))" 2>/dev/null || true)
if [ -n "$PR_NUM" ]; then
# Merge PR
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/pulls/${PR_NUM}/merge" \
-d "{\"Do\":\"merge\",\"merge_message_field\":\"${COMMIT_MSG}\"}" 2>/dev/null
echo "Version bumped via PR #${PR_NUM} (merged)"
else
echo "::warning::Could not create PR for version bump — publishing with current version"
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Publish
run: npm publish --access public
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
@@ -19,6 +19,7 @@ permissions:
jobs:
check-sdk:
runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
steps:
- uses: actions/checkout@v4
+90
View File
@@ -0,0 +1,90 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Enforces branch merge policy:
# feature/* → dev only
# fix/* → dev only
# hotfix/* → dev or main (emergency)
# dev → main only
# alpha/* → dev only
# beta/* → dev only
# rc/* → main only
name: Branch Policy Check
on:
pull_request:
types: [opened, synchronize, reopened, edited]
jobs:
check-target:
name: Verify merge target
runs-on: ubuntu-latest
steps:
- name: Check branch policy
run: |
HEAD="${{ github.head_ref }}"
BASE="${{ github.base_ref }}"
echo "PR: ${HEAD} → ${BASE}"
ALLOWED=true
REASON=""
case "$HEAD" in
feature/*|feat/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Feature branches must target 'dev', not '${BASE}'"
fi
;;
fix/*|bugfix/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Fix branches must target 'dev', not '${BASE}'"
fi
;;
hotfix/*)
if [ "$BASE" != "dev" ] && [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Hotfix branches can only target 'dev' or 'main', not '${BASE}'"
fi
;;
alpha/*|beta/*)
if [ "$BASE" != "dev" ]; then
ALLOWED=false
REASON="Pre-release branches must target 'dev', not '${BASE}'"
fi
;;
rc/*)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Release candidate branches must target 'main', not '${BASE}'"
fi
;;
dev)
if [ "$BASE" != "main" ]; then
ALLOWED=false
REASON="Dev branch can only merge into 'main', not '${BASE}'"
fi
;;
esac
if [ "$ALLOWED" = false ]; then
echo "::error::${REASON}"
echo ""
echo "## Branch Policy Violation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "${REASON}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Allowed merge paths:" >> $GITHUB_STEP_SUMMARY
echo "- \`feature/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`fix/*\` → \`dev\`" >> $GITHUB_STEP_SUMMARY
echo "- \`hotfix/*\` → \`dev\` or \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`dev\` → \`main\`" >> $GITHUB_STEP_SUMMARY
echo "- \`rc/*\` → \`main\`" >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge
@@ -96,6 +96,32 @@ jobs:
echo "Branch policy: OK (${HEAD} → ${BASE})"
echo "## Branch Policy: Passed" >> $GITHUB_STEP_SUMMARY
# ── Secret Scanning ──────────────────────────────────────────────────
gitleaks:
name: Secret Scan
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install Gitleaks
run: |
GITLEAKS_VERSION="8.21.2"
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${GITLEAKS_VERSION}/gitleaks_${GITLEAKS_VERSION}_linux_x64.tar.gz" \
| tar -xz -C /usr/local/bin gitleaks
- name: Scan PR commits for secrets
run: |
if gitleaks detect --source . --verbose \
--log-opts=${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }} 2>&1; then
echo "**No secrets detected.**" >> $GITHUB_STEP_SUMMARY
else
echo "::error::Potential secrets detected in PR commits"
exit 1
fi
# ── Code Validation ────────────────────────────────────────────────────
validate:
name: Validate PR
@@ -121,11 +147,12 @@ jobs:
- name: Detect platform
id: platform
run: |
# Read platform from XML manifest (<platform> tag) or plain text fallback
PLATFORM=$(sed -n 's/.*<platform>\([^<]*\)<\/platform>.*/\1/p' .mokogitea/manifest.xml 2>/dev/null | head -1)
[ -z "$PLATFORM" ] && PLATFORM=$(cat .mokogitea/manifest.xml 2>/dev/null | tr -d '[:space:]')
# Platform comes from the MokoGIT metadata API (public GET).
API="${GITHUB_SERVER_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${GITHUB_REPOSITORY}/metadata"
PLATFORM="$(curl -sf "$API" 2>/dev/null | python3 -c "import sys, json; print(json.load(sys.stdin).get('platform') or '')" 2>/dev/null || true)"
[ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
echo "Detected platform: $PLATFORM"
- name: Setup PHP
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
@@ -256,10 +283,10 @@ jobs:
for ELEMENT in name version description; do
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
done
# Block legacy raw/branch update server URLs on MokoGitea
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogitea\|git\.mokoconsulting\.tech' || true)
# Block legacy raw/branch update server URLs on MokoGIT
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogit\|git\.mokoconsulting\.tech' || true)
if [ -n "$RAW_URLS" ]; then
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGitea. Use the Gitea Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
echo "::error::Manifest contains legacy raw/branch update server URL on MokoGIT. Use the MokoGIT Pages URL instead (e.g. /{REPO}/updates.xml not /{REPO}/raw/branch/main/updates.xml)"
echo "$RAW_URLS"
exit 1
fi
@@ -470,39 +497,26 @@ jobs:
steps:
- name: Trigger RC pre-release
env:
GA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
REPO: ${{ github.repository }}
BRANCH: ${{ github.head_ref }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
curl -s -X POST "${GITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${GITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
curl -s -X POST "${MOKOGIT_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${MOKOGIT_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
# ── Issue Reporter ──────────────────────────────────────────────────────
report-issues:
name: Report Issues
runs-on: ubuntu-latest
needs: [branch-policy, validate]
if: >-
always() &&
needs.validate.result == 'failure'
steps:
- name: Checkout
uses: actions/checkout@v4
uses: ./.mokogit/workflows/ci-issue-reporter.yml
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
- name: "File issue for PR validation failure"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
./automation/ci-issue-reporter.sh \
--gate "PR Validation" \
--workflow "PR Check" \
--severity error \
--details "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed."
gate: "PR Validation"
workflow: "PR Check"
severity: error
details: "PR validation failed (syntax, manifest, changelog, or source checks). See the CI run for the specific check that failed."
secrets: inherit
@@ -3,24 +3,27 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.01.00
# BRIEF: Manual pre-release -- builds dev/alpha/beta/rc packages from any branch
# VERSION: 05.02.00
# BRIEF: Auto pre-release on push to dev/alpha/beta/rc branches
name: "Universal: Pre-Release"
on:
pull_request:
types: [closed]
push:
branches:
- dev
pull_request_target:
types: [synchronize, opened, reopened]
branches:
- main
- 'fix/**'
- 'patch/**'
- 'hotfix/**'
- 'bugfix/**'
- 'chore/**'
- alpha
- beta
- rc
workflow_dispatch:
inputs:
stability:
@@ -37,60 +40,82 @@ permissions:
contents: write
env:
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
GIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GIT_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GIT_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs:
build:
name: "Build Pre-Release (${{ inputs.stability || 'development' }})"
name: "Build Pre-Release (${{ inputs.stability || github.ref_name }})"
runs-on: release
if: >-
github.event_name == 'workflow_dispatch' ||
(github.event_name == 'pull_request' && github.event.pull_request.merged == true && github.event.pull_request.base.ref == 'dev') ||
(github.event_name == 'pull_request_target' && github.event.pull_request.base.ref == 'main')
github.event_name == 'push'
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
token: ${{ secrets.MOKOGITEA_TOKEN }}
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || '' }}
token: ${{ secrets.MOKOGIT_TOKEN }}
ref: ${{ github.ref_name }}
submodules: recursive
- name: Setup moko-platform tools
- name: Update submodules to main
run: |
git submodule foreach --quiet 'git checkout main && git pull --quiet origin main' 2>/dev/null || true
- name: Setup MokoCLI tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
# Use pre-installed /opt/moko-platform if available (updated by cron every 6h)
if [ -f /opt/moko-platform/cli/version_bump.php ] && [ -f /opt/moko-platform/vendor/autoload.php ]; then
echo Using pre-installed /opt/moko-platform”
echo MOKO_CLI=/opt/moko-platform/cli >> $GITHUB_ENV
# Use pre-installed /opt/mokocli if available (updated by cron every 6h)
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/cli/manifest_element.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
echo Using pre-installed /opt/mokocli
echo MOKO_CLI=/opt/mokocli/cli >> $GITHUB_ENV
else
echo Falling back to fresh clone
if ! command -v composer &> /dev/null; then
echo Falling back to fresh clone
if ! command -v composer > /dev/null 2>&1; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer > /dev/null 2>&1
fi
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
“https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git” \
/tmp/moko-platform-api
cd /tmp/moko-platform-api && composer install --no-dev --no-interaction --quiet
echo “MOKO_CLI=/tmp/moko-platform-api/cli” >> “$GITHUB_ENV”
rm -rf /tmp/mokocli
CLONE_URL=https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/mokocli.git
git clone --depth 1 --branch main --quiet $CLONE_URL /tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo MOKO_CLI=/tmp/mokocli/cli >> $GITHUB_ENV
fi
- name: Detect platform
id: platform
run: |
# Auto-detect and update platform if not set in manifest
php ${MOKO_CLI}/platform_detect.php --path . --github-output 2>/dev/null || true
php ${MOKO_CLI}/manifest_read.php --path . --github-output
- name: Check platform eligibility (Joomla only)
id: eligibility
run: |
PLATFORM="${{ steps.platform.outputs.platform }}"
if [[ "$PLATFORM" == joomla* ]] || [[ "$PLATFORM" == "joomla" ]]; then
echo "proceed=true" >> "$GITHUB_OUTPUT"
else
echo "proceed=false" >> "$GITHUB_OUTPUT"
echo "::notice::Platform '$PLATFORM' — non-Joomla, skipping pre-release auto-bump"
fi
- name: Resolve metadata and bump version
id: meta
if: steps.eligibility.outputs.proceed == 'true'
run: |
# Auto-detect stability: RC for PRs targeting main, else use input or default to development
if [ "${{ github.event_name }}" = "pull_request_target" ] && [ "${{ github.event.pull_request.base.ref }}" = "main" ]; then
STABILITY="release-candidate"
# Auto-detect stability from branch name on push, or use input on dispatch
if [ "${{ github.event_name }}" = "push" ]; then
case "${{ github.ref_name }}" in
rc) STABILITY="release-candidate" ;;
alpha) STABILITY="alpha" ;;
beta) STABILITY="beta" ;;
*) STABILITY="development" ;;
esac
else
STABILITY="${{ inputs.stability || 'development' }}"
fi
@@ -118,15 +143,18 @@ jobs:
--path . --version "$VERSION" --branch "${{ github.ref_name }}" --stability "$STABILITY" 2>/dev/null || true
php ${MOKO_CLI}/version_check.php --path . --fix 2>/dev/null || true
# Ensure licensing tags (updateservers, dlid) if enabled in manifest.xml
php ${MOKO_CLI}/manifest_licensing.php --path . --fix 2>/dev/null || true
# Append suffix for output
if [ -n "$SUFFIX" ]; then
VERSION="${VERSION}${SUFFIX}"
fi
# Commit version bump
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A
git diff --cached --quiet || {
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
@@ -136,12 +164,12 @@ jobs:
# Auto-detect element via manifest_element.php
php ${MOKO_CLI}/manifest_element.php \
--path . --version "$VERSION" --stability "$STABILITY" \
--repo "${GITEA_REPO}" --github-output
--repo "${GIT_REPO}" --github-output
# Read back element outputs
EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
ZIP_NAME=$(grep '^zip_name=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
[ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GIT_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
[ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
@@ -155,20 +183,22 @@ jobs:
- name: Create release
id: release
if: steps.eligibility.outputs.proceed == 'true'
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --branch dev --prerelease
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \
--repo "${GIT_REPO}" --branch "${{ github.ref_name }}" --prerelease
- name: Update release notes from CHANGELOG.md
if: steps.eligibility.outputs.proceed == 'true'
run: |
TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
# Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading)
if [ -f "CHANGELOG.md" ]; then
@@ -179,7 +209,7 @@ jobs:
fi
# Update release body via API
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGIT_TOKEN }}" \
"${API_BASE}/releases/tags/${TAG}" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true)
if [ -n "$RELEASE_ID" ]; then
@@ -191,7 +221,7 @@ jobs:
'${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH',
headers={
'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Authorization': 'token ${{ secrets.MOKOGIT_TOKEN }}',
'Content-Type': 'application/json'
})
urllib.request.urlopen(req)
@@ -201,23 +231,25 @@ jobs:
- name: Build package and upload
id: package
if: steps.eligibility.outputs.proceed == 'true'
run: |
VERSION="${{ steps.meta.outputs.version }}"
TAG="${{ steps.meta.outputs.tag }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
php ${MOKO_CLI}/release_package.php \
--path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GITEA_REPO}" --output /tmp || true
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \
--repo "${GIT_REPO}" --output /tmp || true
# updates.xml is generated dynamically by MokoGitea license server
# updates.xml is generated dynamically by MokoGIT license server
# No need to build, commit, or sync updates.xml from workflows
- name: "Delete lesser pre-release channels (cascade)"
if: steps.eligibility.outputs.proceed == 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}"
php ${MOKO_CLI}/release_cascade.php \
--stability "${{ steps.meta.outputs.stability }}" \
+71
View File
@@ -0,0 +1,71 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/rc-revert.yml
# VERSION: 09.23.00
# BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge
name: "RC Revert"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
revert:
name: Rename rc/ back to dev/
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == false &&
startsWith(github.event.pull_request.head.ref, 'rc/')
steps:
- name: Rename branch
env:
BRANCH: ${{ github.event.pull_request.head.ref }}
REPO: ${{ github.repository }}
GIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
TOKEN: ${{ secrets.MOKOGIT_TOKEN }}
run: |
set -euo pipefail
# BRANCH is attacker-controlled (PR head ref). Strict allowlist before ANY use.
if ! printf '%s' "$BRANCH" | grep -Eq '^rc/[A-Za-z0-9._/-]+$'; then
echo "::error::Refusing unsafe branch name: $BRANCH"; exit 1
fi
SUFFIX="${BRANCH#rc/}"
DEV_BRANCH="dev/${SUFFIX}"
API="${GIT_URL}/api/v1/repos/${REPO}/branches"
# Create dev/ branch from rc/ branch
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \
-H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"new_branch_name\": \"${DEV_BRANCH}\", \"old_branch_name\": \"${BRANCH}\"}" \
"${API}" 2>/dev/null || true)
if [ "$STATUS" = "201" ]; then
echo "Created branch: ${DEV_BRANCH}" >> "$GITHUB_STEP_SUMMARY"
else
echo "::error::Failed to create ${DEV_BRANCH} from ${BRANCH} (HTTP ${STATUS})"; exit 1
fi
# Read BRANCH from the environment inside PHP (getenv, no string interpolation -> no PHP injection)
ENCODED=$(php -r 'echo rawurlencode(getenv("BRANCH"));')
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${TOKEN}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> "$GITHUB_STEP_SUMMARY"
else
echo "::warning::Failed to delete ${BRANCH} (HTTP ${STATUS})"
fi
echo "### RC Reverted" >> "$GITHUB_STEP_SUMMARY"
echo "${BRANCH} → ${DEV_BRANCH}" >> "$GITHUB_STEP_SUMMARY"
@@ -6,9 +6,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Validation
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# DEFGROUP: MokoGIT.Workflow
# INGROUP: MokoCLI.Validation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
@@ -33,7 +33,8 @@ on:
- scripts
- repo
pull_request:
push:
branches:
- main
permissions:
contents: read
@@ -44,7 +45,7 @@ env:
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
# Repo health policy
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogit/workflows/
REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
REPO_DISALLOWED_DIRS:
REPO_DISALLOWED_FILES: TODO.md,todo.md
@@ -55,7 +56,7 @@ env:
# File / directory variables
DOCS_INDEX: docs/docs-index.md
SCRIPT_DIR: scripts
WORKFLOWS_DIR: .mokogitea/workflows
WORKFLOWS_DIR: .mokogit/workflows
SHELLCHECK_PATTERN: '*.sh'
SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
@@ -76,7 +77,7 @@ jobs:
- name: Check actor permission (admin only)
id: perm
env:
TOKEN: ${{ secrets.MOKOGITEA_TOKEN || secrets.MOKOGITEA_TOKEN || github.token }}
TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }}
REPO: ${{ github.repository }}
ACTOR: ${{ github.actor }}
run: |
@@ -87,14 +88,14 @@ jobs:
# Hardcoded authorized users — always allowed
case "$ACTOR" in
jmiller|gitea-actions[bot])
jmiller|mokogit-actions[bot])
ALLOWED=true
PERMISSION=admin
METHOD="hardcoded allowlist"
;;
*)
# Detect platform and check permissions via API
API_BASE="${GITHUB_API_URL:-${GITEA_API_URL:-https://api.github.com}}"
API_BASE="${GITHUB_API_URL:-${GIT_API_URL:-https://api.github.com}}"
RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}')
PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown")
@@ -604,7 +605,7 @@ jobs:
printf '%s\n' '| Domain | Status | Notes |'
printf '%s\n' '|---|---|---|'
printf '%s\n' '| Access control | OK | Admin-only execution gate |'
printf '%s\n' '| Release policy | N/A | Releases handled by MokoGitea |'
printf '%s\n' '| Release policy | N/A | Releases handled by MokoGIT |'
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |'
printf '%s\n' '| Repo required artifacts | OK | Required, optional, disallowed enforcement |'
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
@@ -670,42 +671,30 @@ jobs:
# ═══════════════════════════════════════════════════════════════════════
# Issue Reporter — file issues for failed gates
# ═══════════════════════════════════════════════════════════════════════
report-issues:
name: "Report Issues"
runs-on: ubuntu-latest
needs: [access_check, scripts_governance, repo_health]
report-scripts:
name: "Report: Scripts Governance"
needs: [access_check, scripts_governance]
if: >-
always() &&
(needs.scripts_governance.result == 'failure' ||
needs.repo_health.result == 'failure')
steps:
- name: Checkout
uses: actions/checkout@v4
needs.scripts_governance.result == 'failure'
uses: ./.mokogit/workflows/ci-issue-reporter.yml
with:
sparse-checkout: automation/ci-issue-reporter.sh
sparse-checkout-cone-mode: false
gate: "Scripts Governance"
workflow: "Repo Health"
severity: error
details: "Scripts directory policy violations detected. Review required and allowed directories."
secrets: inherit
- name: "File issues for failed gates"
env:
GITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: |
chmod +x automation/ci-issue-reporter.sh
REPORTER="./automation/ci-issue-reporter.sh"
WF="Repo Health"
report_gate() {
local gate="$1" result="$2" details="$3"
if [ "$result" = "failure" ]; then
"$REPORTER" --gate "$gate" --details "$details" --workflow "$WF" --severity error
fi
}
report_gate "Scripts Governance" \
"${{ needs.scripts_governance.result }}" \
"Scripts directory policy violations detected. Review required and allowed directories."
report_gate "Repository Health" \
"${{ needs.repo_health.result }}" \
"Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
report-health:
name: "Report: Repository Health"
needs: [access_check, repo_health]
if: >-
always() &&
needs.repo_health.result == 'failure'
uses: ./.mokogit/workflows/ci-issue-reporter.yml
with:
gate: "Repository Health"
workflow: "Repo Health"
severity: error
details: "Repository health checks failed — missing required artifacts, disallowed files, or content warnings. Check the CI run summary."
secrets: inherit
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/repository-cleanup.yml.template
# VERSION: 04.06.00
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
# NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/repository-cleanup.yml in all governed repos.
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/repository-cleanup.yml in all governed repos.
# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
name: "Universal: Repository Cleanup"
@@ -2,14 +2,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Compliance
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.mokogitea/workflows/standards-compliance.yml
# INGROUP: MokoCLI.Compliance
# REPO: https://github.com/mokoconsulting-tech/mokocli
# PATH: /.mokogit/workflows/standards-compliance.yml
# VERSION: 04.06.00
# BRIEF: MokoStandards compliance validation workflow
# BRIEF: MokoCLI compliance validation workflow
# NOTE: Validates repository structure, documentation, and coding standards
name: "MCP: Standards Compliance"
name: "Generic: Standards Compliance"
# ╔════════════════════════════════════════════════════════════════════════╗
# ║ MOKOSTANDARDS COMPLIANCE WORKFLOW ║
@@ -42,7 +42,7 @@ env:
WORKFLOW_VERSION: "04.04.01"
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
# MokoStandards Policy Compliance:
# MokoCLI Policy Compliance:
# - File formatting: Enforces organizational coding standards
# - Reference: docs/policy/file-formatting.md
@@ -252,7 +252,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: LICENSE File Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** LICENSE file is required for all MokoStandards-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Error:** LICENSE file is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Add LICENSE file with appropriate open-source license (GPL-3.0-or-later recommended)" >> $GITHUB_STEP_SUMMARY
echo ""
echo "❌ ERROR: LICENSE file not found - This is a critical requirement"
@@ -291,7 +291,7 @@ jobs:
MISSING=0
PRESENT=0
TOTAL=2
TOTAL=1
echo "### Required Directories" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
@@ -299,7 +299,7 @@ jobs:
echo "|-----------|--------|-------|------|-------|" >> $GITHUB_STEP_SUMMARY
# Check required directories
for dir in docs .github; do
for dir in .mokogit; do
if [ -d "$dir" ]; then
FILE_COUNT=$(find "$dir" -type f 2>/dev/null | wc -l)
DIR_SIZE=$(du -sh "$dir" 2>/dev/null | cut -f1)
@@ -320,14 +320,13 @@ jobs:
echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Remediation Steps:**" >> $GITHUB_STEP_SUMMARY
[ ! -d "docs" ] && echo "- Create docs directory: \`mkdir docs && echo '# Documentation' > docs/README.md\`" >> $GITHUB_STEP_SUMMARY
[ ! -d ".github" ] && echo "- Create .github directory: \`mkdir -p .github/workflows\`" >> $GITHUB_STEP_SUMMARY
[ ! -d ".mokogit" ] && echo "- Create .mokogit directory: \`mkdir -p .mokogit/workflows\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📚 Reference: [MokoStandards Repository Structure](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/core-structure.md)" >> $GITHUB_STEP_SUMMARY
echo "📚 Reference: [MokoCLI Repository Structure](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/core-structure.md)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Required Directories Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository structure does not meet MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository structure does not meet MokoCLI requirements" >> $GITHUB_STEP_SUMMARY
echo "**Missing:** $MISSING required director(y|ies)" >> $GITHUB_STEP_SUMMARY
echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL directories present)" >> $GITHUB_STEP_SUMMARY
echo ""
@@ -384,17 +383,17 @@ jobs:
echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Remediation Steps:**" >> $GITHUB_STEP_SUMMARY
[ ! -f "README.md" ] && echo "- Create README.md: Use [template](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/templates/docs/required/README.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f "README.md" ] && echo "- Create README.md: Use [template](https://github.com/mokoconsulting-tech/mokocli/tree/main/templates/docs/required/README.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f "LICENSE" ] && echo "- Add LICENSE file: Choose from [OSI-approved licenses](https://opensource.org/licenses)" >> $GITHUB_STEP_SUMMARY
[ ! -f "CONTRIBUTING.md" ] && echo "- Create CONTRIBUTING.md: Use [template](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/templates/docs/required/CONTRIBUTING.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f "SECURITY.md" ] && echo "- Create SECURITY.md: Use [template](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/templates/docs/required/SECURITY.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f ".editorconfig" ] && echo "- Add .editorconfig: Use [template](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/templates/.editorconfig)" >> $GITHUB_STEP_SUMMARY
[ ! -f "CONTRIBUTING.md" ] && echo "- Create CONTRIBUTING.md: Use [template](https://github.com/mokoconsulting-tech/mokocli/tree/main/templates/docs/required/CONTRIBUTING.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f "SECURITY.md" ] && echo "- Create SECURITY.md: Use [template](https://github.com/mokoconsulting-tech/mokocli/tree/main/templates/docs/required/SECURITY.md)" >> $GITHUB_STEP_SUMMARY
[ ! -f ".editorconfig" ] && echo "- Add .editorconfig: Use [template](https://github.com/mokoconsulting-tech/mokocli/tree/main/templates/.editorconfig)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📚 Reference: [MokoStandards File Requirements](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/file-header-standards.md)" >> $GITHUB_STEP_SUMMARY
echo "📚 Reference: [MokoCLI File Requirements](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/file-header-standards.md)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Required Files Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository files do not meet MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository files do not meet MokoCLI requirements" >> $GITHUB_STEP_SUMMARY
echo "**Missing:** $MISSING required file(s)" >> $GITHUB_STEP_SUMMARY
echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL files present)" >> $GITHUB_STEP_SUMMARY
echo ""
@@ -437,7 +436,7 @@ jobs:
echo "$TABS_IN_SPACES_FILES" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "These languages require spaces (tabs will break): YAML, Python, Haskell, F#, CoffeeScript, Nim, JSON, RST" >> $GITHUB_STEP_SUMMARY
echo "All other files (including .md, .ps1, LICENSE, etc.) may use tabs per MokoStandards policy" >> $GITHUB_STEP_SUMMARY
echo "All other files (including .md, .ps1, LICENSE, etc.) may use tabs per MokoCLI policy" >> $GITHUB_STEP_SUMMARY
else
echo "✅ No tabs found in files requiring spaces" >> $GITHUB_STEP_SUMMARY
echo "Note: Tabs are allowed in most files (policy default). Only checked files requiring spaces." >> $GITHUB_STEP_SUMMARY
@@ -454,7 +453,7 @@ jobs:
! -path "./vendor/*" \
! -path "./node_modules/*" \
! -path "./.git/*" \
-exec file {} \; | grep -v "UTF-8" | grep -v "ASCII" | head -5)
-exec file {} \; | grep -v "UTF-8" | grep -v "ASCII" | head -5 || true)
if [ -n "$NON_UTF8" ]; then
echo "⚠️ Non-UTF-8 files detected:" >> $GITHUB_STEP_SUMMARY
@@ -476,14 +475,14 @@ jobs:
! -path "./vendor/*" \
! -path "./node_modules/*" \
! -path "./.git/*" \
-exec file {} \; | grep "CRLF" | head -5)
-exec file {} \; | grep "CRLF" | head -5 || true)
if [ -n "$CRLF_FILES" ]; then
echo "⚠️ Files with CRLF line endings found:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "$CRLF_FILES" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "MokoStandards requires LF line endings" >> $GITHUB_STEP_SUMMARY
echo "MokoCLI requires LF line endings" >> $GITHUB_STEP_SUMMARY
else
echo "✅ Line endings are consistent (LF)" >> $GITHUB_STEP_SUMMARY
fi
@@ -504,13 +503,13 @@ jobs:
tools: composer
coverage: none
- name: Setup MokoStandards tools
- name: Setup MokoCLI tools
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: |
git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \
/tmp/mokostandards 2>/dev/null || true
if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards
@@ -524,7 +523,7 @@ jobs:
echo "## 🔢 Version Consistency Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Use MokoStandards tools (no Composer needed on the governed repo)
# Use MokoCLI tools (no Composer needed on the governed repo)
if [ -f "/tmp/mokostandards/api/validate/check_version_consistency.php" ]; then
php /tmp/mokostandards/api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log
EXIT_CODE=${PIPESTATUS[0]}
@@ -532,7 +531,7 @@ jobs:
php api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log
EXIT_CODE=${PIPESTATUS[0]}
else
echo "⏭️ MokoStandards tools not available — skipping version check" >> $GITHUB_STEP_SUMMARY
echo "⏭️ MokoCLI tools not available — skipping version check" >> $GITHUB_STEP_SUMMARY
exit 0
fi
@@ -564,17 +563,17 @@ jobs:
set -x
echo "### GitHub Actions Workflows" >> $GITHUB_STEP_SUMMARY
WORKFLOWS_DIR=".github/workflows"
WORKFLOWS_DIR=".mokogit/workflows"
if [ ! -d "$WORKFLOWS_DIR" ]; then
echo "❌ No workflows directory found" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Workflows Directory Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** .github/workflows directory is required for CI/CD automation" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create .github/workflows directory and add GitHub Actions workflows" >> $GITHUB_STEP_SUMMARY
echo "**Error:** .mokogit/workflows directory is required for CI/CD automation" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create .mokogit/workflows directory and add GitHub Actions workflows" >> $GITHUB_STEP_SUMMARY
echo ""
echo "❌ ERROR: .github/workflows directory not found"
echo "❌ ERROR: .mokogit/workflows directory not found"
exit 1
fi
@@ -597,12 +596,12 @@ jobs:
echo "⚠️ CodeQL workflow not found" >> $GITHUB_STEP_SUMMARY
fi
# Check for MokoStandards-synced workflows
# Check for MokoCLI-synced workflows
for wf in deploy-dev.yml deploy-demo.yml deploy-rs.yml sync-version-on-merge.yml auto-release.yml standards-compliance.yml enterprise-firewall-setup.yml; do
if [ -f "$WORKFLOWS_DIR/$wf" ]; then
echo "✅ ${wf}" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ ${wf} not found (synced from MokoStandards)" >> $GITHUB_STEP_SUMMARY
echo "⚠️ ${wf} not found (synced from MokoCLI)" >> $GITHUB_STEP_SUMMARY
fi
done
@@ -613,7 +612,7 @@ jobs:
echo "### Workflow YAML Syntax" >> $GITHUB_STEP_SUMMARY
INVALID=0
for workflow in $(find .github/workflows -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" \) 2>/dev/null); do
for workflow in $(find .mokogit/workflows -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" \) 2>/dev/null); do
if [ -f "$workflow" ]; then
if python3 -c "import yaml, sys; yaml.safe_load(open(sys.argv[1]))" "$workflow" 2>/dev/null; then
echo "✅ $(basename $workflow)" >> $GITHUB_STEP_SUMMARY
@@ -630,7 +629,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** $INVALID workflow file(s) have invalid YAML syntax" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Fix YAML syntax errors in the marked workflow files" >> $GITHUB_STEP_SUMMARY
echo "**Tool:** Run \`python3 -c \"import yaml; yaml.safe_load(open('.github/workflows/FILE.yml'))\"\` locally" >> $GITHUB_STEP_SUMMARY
echo "**Tool:** Run \`python3 -c \"import yaml; yaml.safe_load(open('.mokogit/workflows/FILE.yml'))\"\` locally" >> $GITHUB_STEP_SUMMARY
echo ""
echo "❌ ERROR: $INVALID workflow file(s) with invalid YAML syntax"
exit 1
@@ -642,7 +641,7 @@ jobs:
echo "✅ SUCCESS: All workflow files passed YAML validation"
- name: Validate CodeQL Configuration
if: hashFiles('.github/workflows/codeql-analysis.yml') != ''
if: hashFiles('.mokogit/workflows/codeql-analysis.yml') != ''
run: |
set -e
echo "" >> $GITHUB_STEP_SUMMARY
@@ -650,7 +649,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
# Inline validation (rewritten from Python to bash for PHP-only architecture)
CODEQL_FILE=".github/workflows/codeql-analysis.yml"
CODEQL_FILE=".mokogit/workflows/codeql-analysis.yml"
if [ ! -f "$CODEQL_FILE" ]; then
echo "⚠️ CodeQL workflow file not found" >> $GITHUB_STEP_SUMMARY
@@ -809,7 +808,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: README.md Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** README.md is required for all MokoStandards-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Error:** README.md is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create README.md with project description, setup instructions, and usage examples" >> $GITHUB_STEP_SUMMARY
echo ""
echo "❌ ERROR: README.md not found - This is a critical requirement"
@@ -915,7 +914,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: CHANGELOG.md Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** CHANGELOG.md is required for all MokoStandards-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Error:** CHANGELOG.md is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create CHANGELOG.md following [Keep a Changelog](https://keepachangelog.com/) format" >> $GITHUB_STEP_SUMMARY
echo ""
echo "❌ ERROR: CHANGELOG.md not found - This is a critical requirement"
@@ -1183,11 +1182,11 @@ jobs:
# Install yamllint if not present
:
else
pip install yamllint >/dev/null 2>&1
pip install yamllint >/dev/null 2>&1 || true
fi
# Run yamllint and count line-length warnings
YAML_OUTPUT=$(yamllint .github/workflows/*.yml 2>&1 | grep "line too long" || true)
YAML_OUTPUT=$(yamllint .mokogit/workflows/*.yml 2>&1 | grep "line too long" || true)
if [ -n "$YAML_OUTPUT" ]; then
YAML_VIOLATIONS=$(echo "$YAML_OUTPUT" | wc -l)
echo "⚠️ Found $YAML_VIOLATIONS lines exceeding 180 characters in YAML files" >> $GITHUB_STEP_SUMMARY
@@ -1214,7 +1213,7 @@ jobs:
! -path "./.git/*" \
! -path "./build/*" \
! -path "./dist/*" \
-exec awk 'length > 120 { print FILENAME ":" NR ": " length " chars" }' {} \; 2>/dev/null | head -20)
-exec awk 'length > 120 { print FILENAME ":" NR ": " length " chars" }' {} \; 2>/dev/null | head -20 || true)
if [ -n "$LONG_LINES" ]; then
LINE_COUNT=$(echo "$LONG_LINES" | wc -l)
@@ -1976,10 +1975,10 @@ jobs:
if [ -f "composer.json" ]; then
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
else
echo "No composer.json — pulling MokoStandards tools"
echo "No composer.json — pulling MokoCLI tools"
if [ ! -d "/tmp/mokostandards" ]; then
git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \
/tmp/mokostandards 2>/dev/null || true
if [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
@@ -2048,10 +2047,10 @@ jobs:
if [ -f "composer.json" ]; then
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
else
echo "No composer.json — pulling MokoStandards tools"
echo "No composer.json — pulling MokoCLI tools"
if [ ! -d "/tmp/mokostandards" ]; then
git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \
/tmp/mokostandards 2>/dev/null || true
if [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
@@ -2131,17 +2130,17 @@ jobs:
WARNINGS=0
ERRORS=0
# 1. Check .github/config.tf location (not root override files)
# 1. Check .mokogit/config.tf location (not root override files)
echo "### Override Configuration Check" >> $GITHUB_STEP_SUMMARY
LEGACY_OVERRIDES=$(find . -maxdepth 1 -name "*override*.tf" -o -name "MokoStandards.override.tf" 2>/dev/null | wc -l || echo 0)
LEGACY_OVERRIDES=$(find . -maxdepth 1 -name "*override*.tf" -o -name "MokoCLI.override.tf" 2>/dev/null | wc -l || echo 0)
if [ "$LEGACY_OVERRIDES" -gt 0 ]; then
echo "⚠️ Found legacy override files in root directory" >> $GITHUB_STEP_SUMMARY
echo "**Expected Location**: .github/config.tf" >> $GITHUB_STEP_SUMMARY
echo "**Expected Location**: .mokogit/config.tf" >> $GITHUB_STEP_SUMMARY
echo "**Legacy files found**: $LEGACY_OVERRIDES" >> $GITHUB_STEP_SUMMARY
WARNINGS=$((WARNINGS + 1))
else
if [ -f ".github/config.tf" ]; then
echo "✅ Override configuration in correct location (.github/config.tf)" >> $GITHUB_STEP_SUMMARY
if [ -f ".mokogit/config.tf" ]; then
echo "✅ Override configuration in correct location (.mokogit/config.tf)" >> $GITHUB_STEP_SUMMARY
else
echo "️ No override configuration found" >> $GITHUB_STEP_SUMMARY
fi
@@ -2299,7 +2298,7 @@ jobs:
- name: Generate Compliance Report
run: |
set -x
echo "# 📊 MokoStandards Compliance Report" >> $GITHUB_STEP_SUMMARY
echo "# 📊 MokoCLI Compliance Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Calculate overall status
@@ -2486,7 +2485,7 @@ jobs:
else
echo "## 🎉 Excellent!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Your repository is **fully compliant** with MokoStandards!" >> $GITHUB_STEP_SUMMARY
echo "Your repository is **fully compliant** with MokoCLI!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Achievements:**" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All required directories and files present" >> $GITHUB_STEP_SUMMARY
@@ -2501,12 +2500,12 @@ jobs:
echo "---" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "📚 **Resources:**" >> $GITHUB_STEP_SUMMARY
echo "- [MokoStandards Documentation](https://github.com/mokoconsulting-tech/MokoStandards)" >> $GITHUB_STEP_SUMMARY
echo "- [Repository Structure Guide](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/core-structure.md)" >> $GITHUB_STEP_SUMMARY
echo "- [Documentation Standards](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/document-formatting.md)" >> $GITHUB_STEP_SUMMARY
echo "- [Coding Standards](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/coding-style-guide.md)" >> $GITHUB_STEP_SUMMARY
echo "- [MokoCLI Documentation](https://github.com/mokoconsulting-tech/mokocli)" >> $GITHUB_STEP_SUMMARY
echo "- [Repository Structure Guide](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/core-structure.md)" >> $GITHUB_STEP_SUMMARY
echo "- [Documentation Standards](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/document-formatting.md)" >> $GITHUB_STEP_SUMMARY
echo "- [Coding Standards](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/coding-style-guide.md)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "_Generated by MokoStandards Compliance Workflow v${WORKFLOW_VERSION}_" >> $GITHUB_STEP_SUMMARY
echo "_Generated by MokoCLI Compliance Workflow v${WORKFLOW_VERSION}_" >> $GITHUB_STEP_SUMMARY
# Create tracking issue for non-compliance if on push
if [ "$COMPLIANCE_PERCENT" -lt 100 ] && [ "${{ github.event_name }}" = "push" ]; then
@@ -2530,9 +2529,9 @@ jobs:
echo "### ✅ Full Standards Compliance Achieved" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Overall Compliance:** 100%" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository meets all MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository meets all MokoCLI requirements" >> $GITHUB_STEP_SUMMARY
echo ""
echo "✅ SUCCESS: Repository is fully MokoStandards compliant"
echo "✅ SUCCESS: Repository is fully MokoCLI compliant"
- name: Create or reopen tracking issue for standards violations
if: failure()
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
# VERSION: 04.06.00
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
# NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/sync-version-on-merge.yml in all governed repos.
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/sync-version-on-merge.yml in all governed repos.
# README.md is the single source of truth for the repository version.
name: "Universal: Sync Version on Merge"
@@ -47,22 +47,19 @@ jobs:
token: ${{ secrets.GH_TOKEN || github.token }}
fetch-depth: 0
- name: Set up PHP
uses: shivammathur/setup-php@fcafdd6392932010c2bd5094439b8e33be2a8a09 # v2.37.0
with:
php-version: '8.1'
tools: composer
- name: Setup MokoStandards tools
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: |
git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
/tmp/mokostandards
cd /tmp/mokostandards
composer install --no-dev --no-interaction --quiet
# Use pre-installed mokoplatform on runner host (symlink /opt/mokoplatform -> /opt/moko-platform)
if [ -d /opt/mokoplatform/api/cli ] && [ -f /opt/mokoplatform/vendor/autoload.php ]; then
ln -sf /opt/mokoplatform /tmp/mokostandards
echo "Using pre-installed /opt/mokoplatform"
elif [ -d /opt/moko-platform/api/cli ]; then
ln -sf /opt/moko-platform /tmp/mokostandards
echo "Using pre-installed /opt/moko-platform"
else
echo "::warning::MokoStandards tools not found on runner - skipping"
echo "MOKO_SKIP=true" >> "$GITHUB_ENV"
fi
- name: Auto-bump patch version
if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }}
+130
View File
@@ -0,0 +1,130 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow.Template
# INGROUP: MokoCLI.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
# PATH: /.mokogit/workflows/version-set.yml
# VERSION: 01.00.00
# BRIEF: Set or reset the extension version across all version-bearing files
name: "Joomla: Set Version"
on:
workflow_dispatch:
inputs:
version:
description: "Version number (e.g. 01.00.00)"
required: true
type: string
branch:
description: "Branch to update (default: current)"
required: false
type: string
permissions:
contents: write
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
set-version:
name: Set Version to ${{ inputs.version }}
runs-on: ubuntu-latest
steps:
- name: Validate version format
run: |
VERSION="${{ inputs.version }}"
if ! echo "$VERSION" | grep -qP '^\d{2}\.\d{2}\.\d{2}$'; then
echo "::error::Invalid version format '${VERSION}' — expected XX.YY.ZZ (e.g. 01.00.00)"
exit 1
fi
echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.MOKOGIT_TOKEN || github.token }}
ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1
- name: Update manifest version
run: |
MANIFEST=""
for XML_FILE in $(find . -maxdepth 3 -name "*.xml" -not -path "./.git/*" -not -path "./vendor/*"); do
if grep -q "<extension" "$XML_FILE" 2>/dev/null; then
MANIFEST="$XML_FILE"
break
fi
done
if [ -z "$MANIFEST" ]; then
echo "::warning::No Joomla extension manifest found — skipping manifest update"
else
OLD_VER=$(grep -oP '<version>\K[^<]+' "$MANIFEST" | head -1)
sed -i "s|<version>${OLD_VER}</version>|<version>${VERSION}</version>|" "$MANIFEST"
echo "Manifest: ${OLD_VER} → ${VERSION} (${MANIFEST})"
fi
- name: Update README.md version
run: |
if [ -f "README.md" ]; then
if grep -qP '^\s*VERSION:\s*\d' README.md; then
sed -i -E "s/(VERSION:\s*)[0-9]{2}\.[0-9]{2}\.[0-9]{2}/\1${VERSION}/" README.md
echo "README.md version updated to ${VERSION}"
else
echo "::warning::No VERSION line found in README.md — skipping"
fi
fi
- name: Update CHANGELOG.md
run: |
if [ -f "CHANGELOG.md" ]; then
DATE=$(date +%Y-%m-%d)
# Check if this version already has an entry
if grep -q "^\#\# \[${VERSION}\]" CHANGELOG.md; then
echo "CHANGELOG.md already has entry for ${VERSION} — skipping"
else
# Insert new version entry after [Unreleased] or at the top after header
if grep -q '^\#\# \[Unreleased\]' CHANGELOG.md; then
sed -i "/^\#\# \[Unreleased\]/a\\\\n## [${VERSION}] --- ${DATE}" CHANGELOG.md
else
sed -i "/^\# Changelog/a\\\\n## [Unreleased]\n\n## [${VERSION}] --- ${DATE}" CHANGELOG.md
fi
echo "CHANGELOG.md: added entry for ${VERSION}"
fi
else
echo "::warning::No CHANGELOG.md found — skipping"
fi
- name: Update FILE INFORMATION blocks
run: |
# Update VERSION in file header blocks (# VERSION: XX.YY.ZZ)
find . -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" -o -name "*.php" -o -name "*.md" \) \
-not -path "./.git/*" -not -path "./vendor/*" -print0 2>/dev/null | \
while IFS= read -r -d '' FILE; do
if head -20 "$FILE" | grep -qP '^\s*#?\s*VERSION:\s*\d{2}\.\d{2}\.\d{2}'; then
sed -i -E "s/(#?\s*VERSION:\s*)[0-9]{2}\.[0-9]{2}\.[0-9]{2}/\1${VERSION}/" "$FILE"
echo "Updated FILE INFORMATION VERSION in ${FILE}"
fi
done
- name: Commit and push
run: |
git config user.name "Moko Consulting [bot]"
git config user.email "hello@mokoconsulting.tech"
git add -A
if git diff --cached --quiet; then
echo "No version changes detected — nothing to commit"
else
git commit -m "chore: set version to ${VERSION} [skip bump]
Authored-by: Moko Consulting"
git push
echo "### Version Set" >> $GITHUB_STEP_SUMMARY
echo "Version updated to \`${VERSION}\` on branch \`${GITHUB_REF_NAME}\`" >> $GITHUB_STEP_SUMMARY
fi
-24
View File
@@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
MokoStandards Repository Manifest
Template: MCP Server
See: https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home
-->
<moko-platform xmlns="https://standards.mokoconsulting.tech/moko-platform/1.0" schema-version="1.0">
<identity>
<name>Template-MCP</name>
<org>MokoConsulting</org>
<description>Template repository for Model Context Protocol (MCP) servers</description>
<license spdx="GPL-3.0-or-later">GNU General Public License v3</license>
</identity>
<governance>
<platform>mcp</platform>
<standards-version>05.00.00</standards-version>
<standards-source>https://git.mokoconsulting.tech/MokoConsulting/moko-platform</standards-source>
</governance>
<build>
<language>TypeScript</language>
<package-type>mcp-server</package-type>
<entry-point>src/</entry-point>
</build>
</moko-platform>
-285
View File
@@ -1,285 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: moko-platform.Release
# REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml
#
# +========================================================================+
# | UNIVERSAL BUILD & RELEASE PIPELINE |
# +========================================================================+
# | |
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. |
# | |
# | Platform-specific: |
# | joomla: XML manifest, updates.xml, type-prefixed packages |
# | dolibarr: mod*.class.php, update.txt, dev version reset |
# | generic: README-only, no update stream |
# | |
# +========================================================================+
name: "Universal: Build & Release"
on:
pull_request:
types: [opened, closed]
branches:
- main
workflow_dispatch:
inputs:
action:
description: 'Action to perform'
required: false
type: choice
default: release
options:
- release
- promote-rc
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
permissions:
contents: write
jobs:
# ── PR Opened → Rename branch to RC and build RC release ─────────────────────
promote-rc:
name: Promote to RC
runs-on: release
if: >-
(github.event.action == 'opened' && github.event.pull_request.merged != true) ||
(github.event_name == 'workflow_dispatch' && inputs.action == 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: |
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
- name: Rename branch to rc
run: |
php /tmp/moko-platform-api/cli/branch_rename.php \
--from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--api-base "${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
--pr "${{ github.event.pull_request.number }}"
- name: Checkout rc and configure git
run: |
git fetch origin rc
git checkout rc
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Publish RC release
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
--path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--skip-update-stream
- name: Summary
if: always()
run: |
echo "## Promoted to Release Candidate" >> $GITHUB_STEP_SUMMARY
echo "Branch renamed to rc, minor bump, RC release built (updates.xml managed by Gitea Pages)" >> $GITHUB_STEP_SUMMARY
# ── Merged PR → Build & Release (or promote RC to stable) ────────────────────
release:
name: Build & Release Pipeline
runs-on: release
if: >-
github.event.pull_request.merged == true ||
(github.event_name == 'workflow_dispatch' && inputs.action != 'promote-rc')
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with:
token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0
- name: Configure git for bot pushes
run: |
git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Check for merge conflict markers
run: |
CONFLICTS=$(grep -rn '<<<<<<< \|>>>>>>> \|^=======$' --include='*.php' --include='*.xml' --include='*.css' --include='*.js' --include='*.json' --include='*.md' --include='*.yml' --include='*.yaml' --include='*.ini' --include='*.txt' . 2>/dev/null | grep -v '.git/' || true)
if [ -n "$CONFLICTS" ]; then
echo "::error::Merge conflict markers found — aborting release"
echo "## Release Blocked: Conflict Markers" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
echo "$CONFLICTS" >> $GITHUB_STEP_SUMMARY
echo '```' >> $GITHUB_STEP_SUMMARY
exit 1
fi
echo "No conflict markers found"
- name: Setup moko-platform tools
env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: |
# Ensure PHP + Composer are available
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq && sudo apt-get install -y -qq php-cli php-mbstring php-xml php-zip php-curl composer >/dev/null 2>&1
fi
# Always fetch latest CLI tools — never use stale cache from previous runs
rm -rf /tmp/moko-platform-api
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/moko-platform.git" \
/tmp/moko-platform-api
cd /tmp/moko-platform-api
composer install --no-dev --no-interaction --quiet
- name: "Publish stable release"
run: |
php /tmp/moko-platform-api/cli/release_publish.php \
--path . --stability stable --bump minor --branch main \
--token "${{ secrets.MOKOGITEA_TOKEN }}" \
--skip-update-stream
# -- STEP 9: Mirror to GitHub (stable only) --------------------------------
- name: "Step 9: Mirror release to GitHub"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
--branch main 2>&1 || true
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
# -- STEP 10: Sync main branch to GitHub mirror ----------------------------
- name: "Step 10: Push main to GitHub mirror"
if: >-
steps.version.outputs.skip != 'true' &&
secrets.GH_MIRROR_TOKEN != ''
continue-on-error: true
run: |
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
GH_ORG=$(echo "$GH_REPO" | cut -d/ -f1)
GH_NAME=$(echo "$GH_REPO" | cut -d/ -f2)
git remote add github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git" 2>/dev/null || \
git remote set-url github "https://x-access-token:${{ secrets.GH_MIRROR_TOKEN }}@github.com/${GH_ORG}/${GH_NAME}.git"
git fetch origin main --depth=1
git push github origin/main:refs/heads/main --force 2>/dev/null \
&& echo "main branch pushed to GitHub mirror" \
|| echo "WARNING: GitHub mirror push failed"
- name: "Step 11: Delete rc branch and recreate dev from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Delete rc branch (ephemeral — created by promote-rc)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/rc" 2>/dev/null \
&& echo "Deleted rc branch" || echo "rc branch not found"
# Delete dev branch
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
"${API_BASE}/branches/dev" 2>/dev/null && echo "Deleted dev branch"
# Recreate dev from main (now includes version bump + changelog promotion)
curl -sf -X POST -H "Authorization: token ${TOKEN}" \
-H "Content-Type: application/json" \
"${API_BASE}/branches" \
-d '{"new_branch_name":"dev","old_branch_name":"main"}' 2>/dev/null && echo "Recreated dev from main"
echo "Pre-release branches cleaned, dev reset from main" >> $GITHUB_STEP_SUMMARY
- name: "Step 12: Create version branch from main"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
BRANCH_NAME="version/${VERSION}"
MAIN_SHA=$(git rev-parse HEAD)
# Delete old version branch if it exists (same version re-release)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" "${API_BASE}/branches/${BRANCH_NAME}" 2>/dev/null && echo "Deleted old ${BRANCH_NAME}"
# Create version/XX.YY.ZZ from main
curl -sf -X POST -H "Authorization: token ${TOKEN}" -H "Content-Type: application/json" "${API_BASE}/branches" -d "{\"new_branch_name\":\"${BRANCH_NAME}\",\"old_branch_name\":\"main\"}" 2>/dev/null && echo "Created ${BRANCH_NAME} from main (${MAIN_SHA})" || echo "WARNING: ${BRANCH_NAME} creation failed"
echo "Version branch created: ${BRANCH_NAME} (${MAIN_SHA})" >> $GITHUB_STEP_SUMMARY
# -- Dolibarr post-release: Reset dev version -----------------------------
- name: "Post-release: Reset dev version"
if: steps.version.outputs.skip != 'true'
continue-on-error: true
run: |
API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php /tmp/moko-platform-api/cli/version_reset_dev.php \
--token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true
# -- Summary --------------------------------------------------------------
- name: Pipeline Summary
if: always()
run: |
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
PLATFORM="${{ steps.platform.outputs.platform }}"
if [ "${{ steps.version.outputs.skip }}" = "true" ]; then
echo "## Release Skipped" >> $GITHUB_STEP_SUMMARY
echo "No VERSION in README.md" >> $GITHUB_STEP_SUMMARY
elif [ "${{ steps.check.outputs.already_released }}" = "true" ]; then
echo "## Already Released — ${VERSION}" >> $GITHUB_STEP_SUMMARY
else
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Build & Release Complete (${PLATFORM})" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Step | Result |" >> $GITHUB_STEP_SUMMARY
echo "|------|--------|" >> $GITHUB_STEP_SUMMARY
echo "| Platform | \`${PLATFORM}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Release | [View](${GITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi
-48
View File
@@ -1,48 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogitea/workflows/branch-cleanup.yml
# VERSION: 01.00.00
# BRIEF: Delete feature branches after PR merge
name: "Branch Cleanup"
on:
pull_request:
types: [closed]
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
jobs:
cleanup:
name: Delete merged branch
runs-on: ubuntu-latest
if: >-
github.event.pull_request.merged == true &&
github.event.pull_request.head.ref != 'dev' &&
github.event.pull_request.head.ref != 'main'
steps:
- name: Delete source branch
run: |
BRANCH="${{ github.event.pull_request.head.ref }}"
API="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}/api/v1/repos/${{ github.repository }}/branches"
ENCODED=$(php -r "echo rawurlencode('${BRANCH}');")
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X DELETE \
-H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API}/${ENCODED}" 2>/dev/null || true)
if [ "$STATUS" = "204" ]; then
echo "Deleted branch: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
elif [ "$STATUS" = "404" ]; then
echo "Branch already deleted: ${BRANCH}" >> $GITHUB_STEP_SUMMARY
else
echo "::warning::Failed to delete branch ${BRANCH} (HTTP ${STATUS})"
fi
-115
View File
@@ -1,115 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow.Template
# INGROUP: MokoStandards.Security
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /templates/workflows/generic/codeql-analysis.yml.template
# VERSION: 04.05.00
# BRIEF: CodeQL security scanning workflow (generic — all repo types)
# NOTE: Deployed to .mokogitea/workflows/codeql-analysis.yml in governed repos.
# CodeQL does not support PHP directly; JavaScript scans JSON/YAML/shell.
# For PHP-specific security scanning see standards-compliance.yml.
name: "Universal: CodeQL Analysis"
on:
push:
branches:
- main
- dev/**
- rc/**
- version/**
pull_request:
branches:
- main
- dev/**
- rc/**
schedule:
# Weekly on Monday at 06:00 UTC
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
actions: read
contents: read
security-events: write
pull-requests: read
jobs:
analyze:
name: Analyze (${{ matrix.language }})
runs-on: ubuntu-latest
timeout-minutes: 360
strategy:
fail-fast: false
matrix:
# CodeQL does not support PHP. Use 'javascript' to scan JSON, YAML,
# and shell scripts. Add 'actions' to scan GitHub Actions workflows.
language: ['javascript', 'actions']
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
queries: security-extended,security-and-quality
- name: Autobuild
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
with:
category: "/language:${{ matrix.language }}"
upload: true
output: sarif-results
wait-for-processing: true
- name: Upload SARIF results
if: always()
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.5.0
with:
name: codeql-results-${{ matrix.language }}
path: sarif-results
retention-days: 30
- name: Step summary
if: always()
run: |
echo "### 🔍 CodeQL — ${{ matrix.language }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
URL="https://github.com/${{ github.repository }}/security/code-scanning"
echo "See the [Security tab]($URL) for findings." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Severity | SLA |" >> $GITHUB_STEP_SUMMARY
echo "|----------|-----|" >> $GITHUB_STEP_SUMMARY
echo "| Critical | 7 days |" >> $GITHUB_STEP_SUMMARY
echo "| High | 14 days |" >> $GITHUB_STEP_SUMMARY
echo "| Medium | 30 days |" >> $GITHUB_STEP_SUMMARY
echo "| Low | 60 days / next release |" >> $GITHUB_STEP_SUMMARY
summary:
name: Security Scan Summary
runs-on: ubuntu-latest
needs: analyze
if: always()
steps:
- name: Summary
run: |
echo "### 🛡️ CodeQL Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
SECURITY_URL="https://github.com/${{ github.repository }}/security"
echo "" >> $GITHUB_STEP_SUMMARY
echo "📊 [View all security alerts]($SECURITY_URL)" >> $GITHUB_STEP_SUMMARY
-44
View File
@@ -1,44 +0,0 @@
# Copyright (C) 2025 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-LICENSE-IDENTIFIER: GPL-3.0-or-later
#
# GitHub Actions workflow for Copilot coding agent
# This workflow demonstrates how to use the firewall configuration
name: "MCP: Copilot Agent"
on:
pull_request:
types: [opened, synchronize, reopened]
issue_comment:
types: [created]
permissions:
contents: write
pull-requests: write
issues: write
jobs:
copilot-agent:
name: Run Copilot Coding Agent
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Configure Copilot Firewall
run: |
echo "Configuring firewall allowlist for enterprise-ready sites..."
bash .github/copilot/setup-firewall.sh
echo "Firewall configuration completed"
- name: Run Copilot Agent
uses: github/copilot-swe-agent@v1
with:
token: ${{ secrets.GITHUB_TOKEN }}
issue_number: ${{ github.event.issue.number || github.event.pull_request.number }}
env:
# Environment variables are set by setup-firewall.sh
COPILOT_FIREWALL_ALLOWLIST: ${{ env.COPILOT_FIREWALL_ALLOWLIST }}
-126
View File
@@ -1,126 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Deploy
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-API
# PATH: /templates/workflows/joomla/deploy-manual.yml.template
# VERSION: 04.07.00
# BRIEF: Manual SFTP deploy to dev server for Joomla repos
name: "Universal: Deploy to Dev (Manual)"
on:
workflow_dispatch:
inputs:
clear_remote:
description: 'Delete all remote files before uploading'
required: false
default: 'false'
type: boolean
env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
permissions:
contents: read
jobs:
deploy:
name: SFTP Deploy to Dev
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Setup PHP
run: |
php -v && composer --version
- name: Setup MokoStandards tools
env:
GA_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
MOKO_CLONE_TOKEN: ${{ secrets.GA_TOKEN || secrets.GA_TOKEN || github.token }}
MOKO_CLONE_HOST: ${{ secrets.GA_TOKEN && 'git.mokoconsulting.tech/MokoConsulting' || 'github.com/mokoconsulting-tech' }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GA_TOKEN || github.token }}"}}'
run: |
git clone --depth 1 --branch main --quiet \
"https://x-access-token:${MOKO_CLONE_TOKEN}@${MOKO_CLONE_HOST}/MokoStandards-API.git" \
/tmp/mokostandards-api 2>/dev/null || true
if [ -d "/tmp/mokostandards-api" ] && [ -f "/tmp/mokostandards-api/composer.json" ]; then
cd /tmp/mokostandards-api && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
fi
- name: Check FTP configuration
id: check
env:
HOST: ${{ vars.DEV_FTP_HOST }}
PATH_VAR: ${{ vars.DEV_FTP_PATH }}
PORT: ${{ vars.DEV_FTP_PORT }}
run: |
if [ -z "$HOST" ] || [ -z "$PATH_VAR" ]; then
echo "DEV_FTP_HOST or DEV_FTP_PATH not configured -- cannot deploy"
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "host=$HOST" >> "$GITHUB_OUTPUT"
REMOTE="${PATH_VAR%/}"
echo "remote=$REMOTE" >> "$GITHUB_OUTPUT"
[ -z "$PORT" ] && PORT="22"
echo "port=$PORT" >> "$GITHUB_OUTPUT"
- name: Deploy via SFTP
if: steps.check.outputs.skip != 'true'
env:
SFTP_KEY: ${{ secrets.DEV_FTP_KEY }}
SFTP_PASS: ${{ secrets.DEV_FTP_PASSWORD }}
SFTP_USER: ${{ vars.DEV_FTP_USERNAME }}
run: |
SOURCE_DIR="src"
[ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs"
[ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ -- nothing to deploy"; exit 0; }
printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \
"${{ steps.check.outputs.host }}" "${{ steps.check.outputs.port }}" "$SFTP_USER" "${{ steps.check.outputs.remote }}" \
> /tmp/sftp-config.json
if [ -n "$SFTP_KEY" ]; then
echo "$SFTP_KEY" > /tmp/deploy_key
chmod 600 /tmp/deploy_key
printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json
else
printf ',"password":"%s"}' "$SFTP_PASS" >> /tmp/sftp-config.json
fi
DEPLOY_ARGS=(--path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json)
[ "${{ inputs.clear_remote }}" = "true" ] && DEPLOY_ARGS+=(--clear-remote)
PLATFORM=$(php /tmp/mokostandards-api/cli/platform_detect.php --path . 2>/dev/null || true)
if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards-api/deploy/deploy-joomla.php" ]; then
php /tmp/mokostandards-api/deploy/deploy-joomla.php "${DEPLOY_ARGS[@]}"
else
php /tmp/mokostandards-api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}"
fi
rm -f /tmp/deploy_key /tmp/sftp-config.json
- name: Summary
if: always()
run: |
if [ "${{ steps.check.outputs.skip }}" = "true" ]; then
echo "### Deploy Skipped -- FTP not configured" >> $GITHUB_STEP_SUMMARY
else
echo "### Manual Dev Deploy Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY
echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY
echo "| Host | \`${{ steps.check.outputs.host }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Remote | \`${{ steps.check.outputs.remote }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Clear | ${{ inputs.clear_remote }} |" >> $GITHUB_STEP_SUMMARY
fi
@@ -1,758 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Firewall
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /templates/workflows/shared/enterprise-firewall-setup.yml.template
# VERSION: 04.06.00
# BRIEF: Enterprise firewall configuration — generates outbound allow-rules including SFTP deployment server
# NOTE: Reads DEV_FTP_HOST / DEV_FTP_PORT variables to include SFTP egress rules alongside HTTPS rules.
name: "MCP: Enterprise Firewall"
# This workflow provides firewall configuration guidance for enterprise-ready sites
# It generates firewall rules for allowing outbound access to trusted domains
# including license providers, documentation sources, package registries,
# and the SFTP deployment server (DEV_FTP_HOST / DEV_FTP_PORT).
#
# Runs automatically when:
# - Coding agent workflows are triggered (pull requests with copilot/ prefix)
# - Manual workflow dispatch for custom configurations
on:
workflow_dispatch:
inputs:
firewall_type:
description: 'Target firewall type'
required: true
type: choice
options:
- 'iptables'
- 'ufw'
- 'firewalld'
- 'aws-security-group'
- 'azure-nsg'
- 'gcp-firewall'
- 'cloudflare'
- 'all'
default: 'all'
output_format:
description: 'Output format'
required: true
type: choice
options:
- 'shell-script'
- 'json'
- 'yaml'
- 'markdown'
- 'all'
default: 'markdown'
# Auto-run when coding agent creates or updates PRs
pull_request:
branches:
- 'copilot/**'
- 'agent/**'
types: [opened, synchronize, reopened]
# Auto-run on push to coding agent branches
push:
branches:
- 'copilot/**'
- 'agent/**'
permissions:
contents: read
actions: read
jobs:
generate-firewall-rules:
name: Generate Firewall Rules
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: '3.11'
- name: Apply Firewall Rules to Runner (Auto-run only)
if: github.event_name != 'workflow_dispatch'
env:
DEV_FTP_HOST: ${{ vars.DEV_FTP_HOST }}
DEV_FTP_PORT: ${{ vars.DEV_FTP_PORT }}
run: |
echo "🔥 Applying firewall rules for coding agent environment..."
echo ""
echo "This step ensures the GitHub Actions runner can access trusted domains"
echo "including license providers, package registries, and documentation sources."
echo ""
# Note: GitHub Actions runners are ephemeral and run in controlled environments
# This step documents what domains are being accessed during the workflow
# Actual firewall configuration is managed by GitHub
cat > /tmp/trusted-domains.txt << 'EOF'
# Trusted domains for coding agent environment
# License Providers
www.gnu.org
opensource.org
choosealicense.com
spdx.org
creativecommons.org
apache.org
fsf.org
# Documentation & Standards
semver.org
keepachangelog.com
conventionalcommits.org
# GitHub & Related
github.com
api.github.com
docs.github.com
raw.githubusercontent.com
ghcr.io
# Package Registries
npmjs.com
registry.npmjs.org
pypi.org
files.pythonhosted.org
packagist.org
repo.packagist.org
rubygems.org
# Platform-Specific
joomla.org
downloads.joomla.org
docs.joomla.org
php.net
getcomposer.org
dolibarr.org
wiki.dolibarr.org
docs.dolibarr.org
# Moko Consulting
mokoconsulting.tech
# SFTP Deployment Server (DEV_FTP_HOST)
${DEV_FTP_HOST:-<not configured>}
# Google Services
drive.google.com
docs.google.com
sheets.google.com
accounts.google.com
storage.googleapis.com
fonts.googleapis.com
fonts.gstatic.com
# GitHub Extended
upload.github.com
objects.githubusercontent.com
user-images.githubusercontent.com
codeload.github.com
pkg.github.com
# Developer Reference
developer.mozilla.org
stackoverflow.com
git-scm.com
# CDN & Infrastructure
cdn.jsdelivr.net
unpkg.com
cdnjs.cloudflare.com
img.shields.io
# Container Registries
hub.docker.com
registry-1.docker.io
# CI & Code Quality
codecov.io
sonarcloud.io
# Terraform & Infrastructure
registry.terraform.io
releases.hashicorp.com
checkpoint-api.hashicorp.com
EOF
echo "✓ Trusted domains documented for this runner"
echo "✓ GitHub Actions runners have network access to these domains"
echo ""
# Test connectivity to key domains
echo "Testing connectivity to key domains..."
for domain in "github.com" "www.gnu.org" "npmjs.com" "pypi.org"; do
if curl -s --max-time 3 -o /dev/null -w "%{http_code}" "https://$domain" | grep -q "200\|301\|302"; then
echo " ✓ $domain is accessible"
else
echo " ⚠️ $domain connectivity check failed (may be expected)"
fi
done
# Test SFTP server connectivity (TCP port check)
SFTP_HOST="${DEV_FTP_HOST:-}"
SFTP_PORT="${DEV_FTP_PORT:-22}"
if [ -n "$SFTP_HOST" ]; then
# Strip any embedded :port suffix
SFTP_HOST="${SFTP_HOST%%:*}"
echo ""
echo "Testing SFTP deployment server connectivity..."
if timeout 5 bash -c "echo >/dev/tcp/${SFTP_HOST}/${SFTP_PORT}" 2>/dev/null; then
echo " ✓ SFTP server ${SFTP_HOST}:${SFTP_PORT} is reachable"
else
echo " ⚠️ SFTP server ${SFTP_HOST}:${SFTP_PORT} is not reachable from runner (firewall rule needed)"
fi
else
echo ""
echo " ️ DEV_FTP_HOST not configured — skipping SFTP connectivity check"
fi
- name: Generate Firewall Configuration
id: generate
env:
DEV_FTP_HOST: ${{ vars.DEV_FTP_HOST }}
DEV_FTP_PORT: ${{ vars.DEV_FTP_PORT }}
run: |
cat > generate_firewall_config.py << 'PYTHON_EOF'
#!/usr/bin/env python3
"""
Enterprise Firewall Configuration Generator
Generates firewall rules for enterprise-ready deployments allowing
access to trusted domains including license providers, documentation
sources, package registries, and platform-specific sites.
"""
import json
import os
import yaml
import sys
from typing import List, Dict
# SFTP deployment server from org variables
_sftp_host_raw = os.environ.get("DEV_FTP_HOST", "").strip()
_sftp_port = os.environ.get("DEV_FTP_PORT", "").strip() or "22"
# Strip embedded :port suffix if present
_sftp_host = _sftp_host_raw.split(":")[0] if _sftp_host_raw else ""
if ":" in _sftp_host_raw and not _sftp_port:
_sftp_port = _sftp_host_raw.split(":")[1]
SFTP_HOST = _sftp_host
SFTP_PORT = int(_sftp_port) if _sftp_port.isdigit() else 22
# Trusted domains from .github/copilot.yml
TRUSTED_DOMAINS = {
"license_providers": [
"www.gnu.org",
"opensource.org",
"choosealicense.com",
"spdx.org",
"creativecommons.org",
"apache.org",
"fsf.org",
],
"documentation_standards": [
"semver.org",
"keepachangelog.com",
"conventionalcommits.org",
],
"github_related": [
"github.com",
"api.github.com",
"docs.github.com",
"raw.githubusercontent.com",
"ghcr.io",
],
"package_registries": [
"npmjs.com",
"registry.npmjs.org",
"pypi.org",
"files.pythonhosted.org",
"packagist.org",
"repo.packagist.org",
"rubygems.org",
],
"standards_organizations": [
"json-schema.org",
"w3.org",
"ietf.org",
],
"platform_specific": [
"joomla.org",
"downloads.joomla.org",
"docs.joomla.org",
"php.net",
"getcomposer.org",
"dolibarr.org",
"wiki.dolibarr.org",
"docs.dolibarr.org",
],
"moko_consulting": [
"mokoconsulting.tech",
],
"google_services": [
"drive.google.com",
"docs.google.com",
"sheets.google.com",
"accounts.google.com",
"storage.googleapis.com",
"fonts.googleapis.com",
"fonts.gstatic.com",
],
"github_extended": [
"upload.github.com",
"objects.githubusercontent.com",
"user-images.githubusercontent.com",
"codeload.github.com",
"pkg.github.com",
],
"developer_reference": [
"developer.mozilla.org",
"stackoverflow.com",
"git-scm.com",
],
"cdn_and_infrastructure": [
"cdn.jsdelivr.net",
"unpkg.com",
"cdnjs.cloudflare.com",
"img.shields.io",
],
"container_registries": [
"hub.docker.com",
"registry-1.docker.io",
],
"ci_code_quality": [
"codecov.io",
"sonarcloud.io",
],
"terraform_infrastructure": [
"registry.terraform.io",
"releases.hashicorp.com",
"checkpoint-api.hashicorp.com",
],
}
# Inject SFTP deployment server as a separate category (port 22, not 443)
if SFTP_HOST:
TRUSTED_DOMAINS["sftp_deployment_server"] = [SFTP_HOST]
print(f"️ SFTP deployment server: {SFTP_HOST}:{SFTP_PORT}")
def generate_sftp_iptables_rules(host: str, port: int) -> str:
"""Generate iptables rules specifically for SFTP egress"""
return (
f"# Allow SFTP to deployment server {host}:{port}\n"
f"iptables -A OUTPUT -p tcp -d $(dig +short {host} | head -1)"
f" --dport {port} -j ACCEPT # SFTP deploy\n"
)
def generate_sftp_ufw_rules(host: str, port: int) -> str:
"""Generate UFW rules for SFTP egress"""
return (
f"# Allow SFTP to deployment server\n"
f"ufw allow out to $(dig +short {host} | head -1)"
f" port {port} proto tcp comment 'SFTP deploy to {host}'\n"
)
def generate_sftp_firewalld_rules(host: str, port: int) -> str:
"""Generate firewalld rules for SFTP egress"""
return (
f"# Allow SFTP to deployment server\n"
f"firewall-cmd --permanent --add-rich-rule='"
f"rule family=ipv4 destination address=$(dig +short {host} | head -1)"
f" port port={port} protocol=tcp accept' # SFTP deploy\n"
)
def generate_iptables_rules(domains: List[str]) -> str:
"""Generate iptables firewall rules"""
rules = ["#!/bin/bash", "", "# Enterprise Firewall Rules - iptables", ""]
rules.append("# Allow outbound HTTPS to trusted domains")
rules.append("")
for domain in domains:
rules.append(f"# Allow {domain}")
rules.append(f"iptables -A OUTPUT -p tcp -d $(dig +short {domain} | head -1) --dport 443 -j ACCEPT")
rules.append("")
rules.append("# Allow DNS lookups")
rules.append("iptables -A OUTPUT -p udp --dport 53 -j ACCEPT")
rules.append("iptables -A OUTPUT -p tcp --dport 53 -j ACCEPT")
return "\n".join(rules)
def generate_ufw_rules(domains: List[str]) -> str:
"""Generate UFW firewall rules"""
rules = ["#!/bin/bash", "", "# Enterprise Firewall Rules - UFW", ""]
rules.append("# Allow outbound HTTPS to trusted domains")
rules.append("")
for domain in domains:
rules.append(f"# Allow {domain}")
rules.append(f"ufw allow out to $(dig +short {domain} | head -1) port 443 proto tcp comment 'Allow {domain}'")
rules.append("")
rules.append("# Allow DNS")
rules.append("ufw allow out 53/udp comment 'Allow DNS UDP'")
rules.append("ufw allow out 53/tcp comment 'Allow DNS TCP'")
return "\n".join(rules)
def generate_firewalld_rules(domains: List[str]) -> str:
"""Generate firewalld rules"""
rules = ["#!/bin/bash", "", "# Enterprise Firewall Rules - firewalld", ""]
rules.append("# Add trusted domains to firewall")
rules.append("")
for domain in domains:
rules.append(f"# Allow {domain}")
rules.append(f"firewall-cmd --permanent --add-rich-rule='rule family=ipv4 destination address=$(dig +short {domain} | head -1) port port=443 protocol=tcp accept'")
rules.append("")
rules.append("# Reload firewall")
rules.append("firewall-cmd --reload")
return "\n".join(rules)
def generate_aws_security_group(domains: List[str]) -> Dict:
"""Generate AWS Security Group rules (JSON format)"""
rules = {
"SecurityGroupRules": {
"Egress": []
}
}
for domain in domains:
rules["SecurityGroupRules"]["Egress"].append({
"Description": f"Allow HTTPS to {domain}",
"IpProtocol": "tcp",
"FromPort": 443,
"ToPort": 443,
"CidrIp": "0.0.0.0/0", # In practice, resolve to specific IPs
"Tags": [{
"Key": "Domain",
"Value": domain
}]
})
# Add DNS
rules["SecurityGroupRules"]["Egress"].append({
"Description": "Allow DNS",
"IpProtocol": "udp",
"FromPort": 53,
"ToPort": 53,
"CidrIp": "0.0.0.0/0"
})
return rules
def generate_markdown_documentation(domains_by_category: Dict[str, List[str]]) -> str:
"""Generate markdown documentation"""
md = ["# Enterprise Firewall Configuration Guide", ""]
md.append("## Overview")
md.append("")
md.append("This document provides firewall configuration guidance for enterprise-ready deployments.")
md.append("It lists trusted domains that should be whitelisted for outbound access to ensure")
md.append("proper functionality of license validation, package management, and documentation access.")
md.append("")
md.append("## Trusted Domains by Category")
md.append("")
all_domains = []
for category, domains in domains_by_category.items():
category_name = category.replace("_", " ").title()
md.append(f"### {category_name}")
md.append("")
md.append("| Domain | Purpose |")
md.append("|--------|---------|")
for domain in domains:
all_domains.append(domain)
purpose = get_domain_purpose(domain)
md.append(f"| `{domain}` | {purpose} |")
md.append("")
md.append("## Implementation Examples")
md.append("")
md.append("### iptables Example")
md.append("")
md.append("```bash")
md.append("# Allow HTTPS to trusted domain")
md.append(f"iptables -A OUTPUT -p tcp -d $(dig +short {all_domains[0]}) --dport 443 -j ACCEPT")
md.append("```")
md.append("")
md.append("### UFW Example")
md.append("")
md.append("```bash")
md.append("# Allow HTTPS to trusted domain")
md.append(f"ufw allow out to {all_domains[0]} port 443 proto tcp")
md.append("```")
md.append("")
md.append("### AWS Security Group Example")
md.append("")
md.append("```json")
md.append("{")
md.append(' "IpPermissions": [{')
md.append(' "IpProtocol": "tcp",')
md.append(' "FromPort": 443,')
md.append(' "ToPort": 443,')
md.append(' "IpRanges": [{"CidrIp": "0.0.0.0/0", "Description": "HTTPS to trusted domains"}]')
md.append(" }]")
md.append("}")
md.append("```")
md.append("")
md.append("## Ports Required")
md.append("")
md.append("| Port | Protocol | Purpose |")
md.append("|------|----------|---------|")
md.append("| 443 | TCP | HTTPS (secure web access) |")
md.append("| 80 | TCP | HTTP (redirects to HTTPS) |")
md.append("| 53 | UDP/TCP | DNS resolution |")
md.append("")
md.append("## Security Considerations")
md.append("")
md.append("1. **DNS Resolution**: Ensure DNS queries are allowed (port 53 UDP/TCP)")
md.append("2. **Certificate Validation**: HTTPS requires ability to reach certificate authorities")
md.append("3. **Dynamic IPs**: Some domains use CDNs with dynamic IPs - consider using FQDNs in rules")
md.append("4. **Regular Updates**: Review and update whitelist as services change")
md.append("5. **Logging**: Enable logging for blocked connections to identify missing rules")
md.append("")
md.append("## Compliance Notes")
md.append("")
md.append("- All listed domains provide read-only access to public information")
md.append("- License providers enable GPL compliance verification")
md.append("- Package registries support dependency security scanning")
md.append("- No authentication credentials are transmitted to these domains")
md.append("")
return "\n".join(md)
def get_domain_purpose(domain: str) -> str:
"""Get human-readable purpose for a domain"""
purposes = {
"www.gnu.org": "GNU licenses and documentation",
"opensource.org": "Open Source Initiative resources",
"choosealicense.com": "GitHub license selection tool",
"spdx.org": "Software Package Data Exchange identifiers",
"creativecommons.org": "Creative Commons licenses",
"apache.org": "Apache Software Foundation licenses",
"fsf.org": "Free Software Foundation resources",
"semver.org": "Semantic versioning specification",
"keepachangelog.com": "Changelog format standards",
"conventionalcommits.org": "Commit message conventions",
"github.com": "GitHub platform access",
"api.github.com": "GitHub API access",
"docs.github.com": "GitHub documentation",
"raw.githubusercontent.com": "GitHub raw content access",
"npmjs.com": "npm package registry",
"pypi.org": "Python Package Index",
"packagist.org": "PHP Composer package registry",
"rubygems.org": "Ruby gems registry",
"joomla.org": "Joomla CMS platform",
"php.net": "PHP documentation and downloads",
"dolibarr.org": "Dolibarr ERP/CRM platform",
}
return purposes.get(domain, "Trusted resource")
def main():
# Use inputs if provided (manual dispatch), otherwise use defaults (auto-run)
firewall_type = "${{ github.event.inputs.firewall_type }}" or "all"
output_format = "${{ github.event.inputs.output_format }}" or "markdown"
print(f"Running in {'manual' if '${{ github.event.inputs.firewall_type }}' else 'automatic'} mode")
print(f"Firewall type: {firewall_type}")
print(f"Output format: {output_format}")
print("")
# Collect all domains
all_domains = []
for domains in TRUSTED_DOMAINS.values():
all_domains.extend(domains)
# Remove duplicates and sort
all_domains = sorted(set(all_domains))
print(f"Generating firewall rules for {len(all_domains)} trusted domains...")
print("")
# Exclude SFTP server from HTTPS rule generation (different port)
https_domains = [d for d in all_domains if d != SFTP_HOST]
# Generate based on firewall type
if firewall_type in ["iptables", "all"]:
rules = generate_iptables_rules(https_domains)
if SFTP_HOST:
rules += "\n# ── SFTP Deployment Server ──────────────────────────────\n"
rules += generate_sftp_iptables_rules(SFTP_HOST, SFTP_PORT)
with open("firewall-rules-iptables.sh", "w") as f:
f.write(rules)
print("✓ Generated iptables rules: firewall-rules-iptables.sh")
if firewall_type in ["ufw", "all"]:
rules = generate_ufw_rules(https_domains)
if SFTP_HOST:
rules += "\n# ── SFTP Deployment Server ──────────────────────────────\n"
rules += generate_sftp_ufw_rules(SFTP_HOST, SFTP_PORT)
with open("firewall-rules-ufw.sh", "w") as f:
f.write(rules)
print("✓ Generated UFW rules: firewall-rules-ufw.sh")
if firewall_type in ["firewalld", "all"]:
rules = generate_firewalld_rules(https_domains)
if SFTP_HOST:
rules += "\n# ── SFTP Deployment Server ──────────────────────────────\n"
rules += generate_sftp_firewalld_rules(SFTP_HOST, SFTP_PORT)
with open("firewall-rules-firewalld.sh", "w") as f:
f.write(rules)
print("✓ Generated firewalld rules: firewall-rules-firewalld.sh")
if firewall_type in ["aws-security-group", "all"]:
rules = generate_aws_security_group(all_domains)
with open("firewall-rules-aws-sg.json", "w") as f:
json.dump(rules, f, indent=2)
print("✓ Generated AWS Security Group rules: firewall-rules-aws-sg.json")
if output_format in ["yaml", "all"]:
with open("trusted-domains.yml", "w") as f:
yaml.dump(TRUSTED_DOMAINS, f, default_flow_style=False)
print("✓ Generated YAML domain list: trusted-domains.yml")
if output_format in ["json", "all"]:
with open("trusted-domains.json", "w") as f:
json.dump(TRUSTED_DOMAINS, f, indent=2)
print("✓ Generated JSON domain list: trusted-domains.json")
if output_format in ["markdown", "all"]:
md = generate_markdown_documentation(TRUSTED_DOMAINS)
with open("FIREWALL_CONFIGURATION.md", "w") as f:
f.write(md)
print("✓ Generated documentation: FIREWALL_CONFIGURATION.md")
print("")
print("Domain Categories:")
for category, domains in TRUSTED_DOMAINS.items():
print(f" - {category}: {len(domains)} domains")
print("")
print("Total unique domains: ", len(all_domains))
if __name__ == "__main__":
main()
PYTHON_EOF
chmod +x generate_firewall_config.py
pip install PyYAML
python3 generate_firewall_config.py
- name: Upload Firewall Configuration Artifacts
uses: actions/upload-artifact@v6
with:
name: firewall-configurations
path: |
firewall-rules-*.sh
firewall-rules-*.json
trusted-domains.*
FIREWALL_CONFIGURATION.md
retention-days: 90
- name: Display Summary
run: |
echo "## Firewall Configuration" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "**Mode**: Manual Execution" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Firewall rules have been generated for enterprise-ready deployments." >> $GITHUB_STEP_SUMMARY
else
echo "**Mode**: Automatic Execution (Coding Agent Active)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "This workflow ran automatically because a coding agent (GitHub Copilot) is active." >> $GITHUB_STEP_SUMMARY
echo "Firewall configuration has been validated for the coding agent environment." >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Files Generated" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
if ls firewall-rules-* trusted-domains.* FIREWALL_CONFIGURATION.md 2>/dev/null; then
ls -lh firewall-rules-* trusted-domains.* FIREWALL_CONFIGURATION.md 2>/dev/null | awk '{print "- " $9 " (" $5 ")"}' >> $GITHUB_STEP_SUMMARY
else
echo "- Documentation generated" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "### Download Artifacts" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Download the generated firewall configurations from the workflow artifacts." >> $GITHUB_STEP_SUMMARY
else
echo "### Trusted Domains Active" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "The coding agent has access to:" >> $GITHUB_STEP_SUMMARY
echo "- License providers (GPL, OSI, SPDX, Apache, etc.)" >> $GITHUB_STEP_SUMMARY
echo "- Package registries (npm, PyPI, Packagist, RubyGems)" >> $GITHUB_STEP_SUMMARY
echo "- Documentation sources (GitHub, Joomla, Dolibarr, PHP)" >> $GITHUB_STEP_SUMMARY
echo "- Standards organizations (W3C, IETF, JSON Schema)" >> $GITHUB_STEP_SUMMARY
fi
# Usage Instructions:
#
# This workflow runs in two modes:
#
# 1. AUTOMATIC MODE (Coding Agent):
# - Triggers when coding agent branches (copilot/**, agent/**) are pushed or PR'd
# - Validates firewall configuration for the coding agent environment
# - Documents accessible domains for compliance
# - Ensures license sources and package registries are available
#
# 2. MANUAL MODE (Enterprise Configuration):
# - Manually trigger from the Actions tab
# - Select desired firewall type and output format
# - Download generated artifacts
# - Apply firewall rules to your enterprise environment
#
# Configuration:
# - Trusted domains are sourced from .github/copilot.yml
# - Modify copilot.yml to add/remove trusted domains
# - Changes automatically propagate to firewall rules
#
# Important Notes:
# - Review generated rules before applying to production
# - Some domains may use CDNs with dynamic IPs
# - Consider using FQDN-based rules where supported
# - Test thoroughly in staging environment first
# - Monitor logs for blocked connections
# - Update rules as domains/services change
-82
View File
@@ -1,82 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Gitea.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.mokogitea/workflows/security-audit.yml
# VERSION: 01.00.00
# BRIEF: Dependency vulnerability scanning for composer and npm packages
name: "Universal: Security Audit"
on:
schedule:
- cron: '0 6 * * 1' # Weekly on Monday at 06:00 UTC
pull_request:
branches:
- main
paths:
- 'composer.json'
- 'composer.lock'
- 'package.json'
- 'package-lock.json'
workflow_dispatch:
permissions:
contents: read
env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
jobs:
audit:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Composer audit
if: hashFiles('composer.lock') != ''
run: |
echo "=== Composer Security Audit ==="
if ! command -v composer &> /dev/null; then
sudo apt-get update -qq
sudo apt-get install -y -qq php-cli composer >/dev/null 2>&1
fi
composer audit --format=plain 2>&1 | tee /tmp/composer-audit.txt
RESULT=$?
if [ $RESULT -ne 0 ]; then
echo "::warning::Composer vulnerabilities found"
echo "composer_vulnerable=true" >> "$GITHUB_ENV"
else
echo "No known vulnerabilities in composer dependencies"
fi
- name: NPM audit
if: hashFiles('package-lock.json') != ''
run: |
echo "=== NPM Security Audit ==="
npm audit --production 2>&1 | tee /tmp/npm-audit.txt || true
if npm audit --production 2>&1 | grep -q "found 0 vulnerabilities"; then
echo "No known vulnerabilities in npm dependencies"
else
echo "::warning::NPM vulnerabilities found"
echo "npm_vulnerable=true" >> "$GITHUB_ENV"
fi
- name: Notify on vulnerabilities
if: env.composer_vulnerable == 'true' || env.npm_vulnerable == 'true'
run: |
REPO="${{ github.event.repository.name }}"
curl -sS \
-H "Title: ${REPO} has vulnerable dependencies" \
-H "Tags: lock,warning" \
-H "Priority: high" \
-d "Security audit found vulnerabilities. Review dependency updates." \
"${NTFY_URL}/${NTFY_TOPIC}" || true
+9 -2
View File
@@ -3,9 +3,16 @@
## [Unreleased]
### Changed
- Migrated all workflow and template paths from `.github/` to `.mokogitea/`
- Template source paths updated: `templates/gitea/` to `templates/mokogitea/`
- Branding: Git -> MokoGIT in workflow DEFGROUP tags, committer identity (git-actions[bot] -> mokogit-actions[bot]), and platform prose. Functional tokens (GIT_TOKEN/GITHUB_TOKEN, GIT_ACTIONS_*, vars.GITEA_*, git.mokoconsulting.tech) preserved.
### Removed
- CI: stripped GitHub-only workflows (DEFGROUP GitHub.Workflow), which do not run on MokoGIT Actions: auto-dev-issue.yml changelog-validation.yml standards-compliance.yml sync-version-on-merge.yml.
### Changed
- Migrated all workflow and template paths from `.github/` to `.mokogit/`
- Template source paths updated: `templates/git/` to `templates/mokogit/`
- HCL definition files removed -- Template repos are now the canonical source
### Added
- CI: gate build/CI/release/version workflows so they skip template repos; smart-gate the sync workflows to run only on Template-* repos; normalize mokocli/MokoCLI refs and drop the stale mokoconsulting-tech org slug.
- `branch-cleanup.yml`: auto-delete merged feature branches after PR merge
+6 -6
View File
@@ -4,7 +4,7 @@ This file provides guidance to Claude Code when working with this repository.
## Project Overview
**Template-MCP** -- Template repository for creating MokoStandards-compliant MCP API servers
**Template-NPM** -- Template repository for creating MokoCLI-compliant MCP API servers
| Field | Value |
|---|---|
@@ -12,8 +12,8 @@ This file provides guidance to Claude Code when working with this repository.
| **Language** | TypeScript |
| **Default branch** | main |
| **License** | GPL-3.0-or-later |
| **Wiki** | [Template-MCP Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki) |
| **Standards** | [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home) |
| **Wiki** | [Template-NPM Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki) |
| **Standards** | [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home) |
## Common Commands
@@ -42,11 +42,11 @@ This is an MCP (Model Context Protocol) server. Key files:
## Rules
- **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`)
- **Workflow directory**: `.mokogit/` (not `.gitea/` or `.github/`)
- **Never commit** `.claude/`, `.mcp.json`, `TODO.md`, or `*.min.css`/`*.min.js`
- **Attribution**: use `Authored-by: Moko Consulting` in commits
- **Branch strategy**: develop on `dev`, merge to `main` for release
- **Minification**: handled at build time (CI) and runtime (MokoMinifyHelper for Joomla templates)
- **Wiki**: documentation lives in the Gitea wiki, not in `docs/` files
- **Standards**: this repo follows [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)
- **Wiki**: documentation lives in the MokoGIT wiki, not in `docs/` files
- **Standards**: this repo follows [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)
+1 -1
View File
@@ -13,7 +13,7 @@
# FILE INFORMATION
DEFGROUP:
INGROUP: Project.Documentation
REPO: mokoconsulting-tech/MokoStandards-Template-Generic
REPO: MokoConsulting/Template-NPM
VERSION: 00.00.01
PATH: ./CODE_OF_CONDUCT.md
BRIEF: Contributor Covenant Code of Conduct version 1.3.0
+5 -5
View File
@@ -13,13 +13,13 @@
# FILE INFORMATION
DEFGROUP:
INGROUP: Project.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Generic
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-NPM
VERSION: 00.00.01
PATH: ./CONTRIBUTING.md
BRIEF: Contribution guidelines for the project
-->
# Contributing to MokoStandards-Template-Generic
# Contributing to Template-NPM
We appreciate your interest in contributing to this project! This document provides guidelines for contributing.
@@ -148,13 +148,13 @@ Every repo maintains 5 standard release channel tags:
### CI/CD
- Gitea Actions runs all CI workflows
- MokoGIT Actions runs all CI workflows
- GitHub Actions are disabled on mirrored repos
- Workflows live in both `.github/workflows/` and `.gitea/workflows/`
- Workflows live in both `.github/workflows/` and `.mokogit/workflows/`
### Update Servers (Joomla)
In manifest `<updateservers>`, Gitea must be priority 1, GitHub priority 2.
In manifest `<updateservers>`, MokoGIT must be priority 1, GitHub priority 2.
### Secrets
+3 -3
View File
@@ -11,9 +11,9 @@
You should have received a copy of the GNU General Public License (./LICENSE).
# FILE INFORMATION
DEFGROUP: MokoStandards
INGROUP: MokoStandards.Documentation
REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/
DEFGROUP: MokoCLI
INGROUP: MokoCLI.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli/
VERSION: 05.00.00
PATH: ./LICENSE
BRIEF: Project license (GPL-3.0-or-later)
+1 -1
View File
@@ -23,7 +23,7 @@ install-deps: ## Install dependencies
@$(NPM) install
@echo "$(COLOR_GREEN)✓ Dependencies installed$(COLOR_RESET)"
MOKO_PLATFORM ?= $(or $(wildcard ../moko-platform),$(wildcard $(HOME)/moko-platform),$(wildcard /opt/moko-platform))
MOKO_PLATFORM ?= $(or $(wildcard ../mokocli),$(wildcard $(HOME)/mokocli),$(wildcard /opt/mokocli))
MINIFY_SCRIPT := $(MOKO_PLATFORM)/build/minify.js
.PHONY: minify
+14 -10
View File
@@ -1,8 +1,8 @@
# Template-MCP
# Template-NPM
![Language](https://img.shields.io/badge/language-TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white) ![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green?style=flat-square) ![Platform](https://img.shields.io/badge/platform-Node.js%20%7C%20MCP-339933?style=flat-square&logo=node.js&logoColor=white) ![Wiki](https://img.shields.io/badge/wiki-Template--MCP-blue?style=flat-square)
![Language](https://img.shields.io/badge/language-TypeScript-3178C6?style=flat-square&logo=typescript&logoColor=white) ![License](https://img.shields.io/badge/license-GPL--3.0--or--later-green?style=flat-square) ![Platform](https://img.shields.io/badge/platform-Node.js%20%7C%20MCP-339933?style=flat-square&logo=node.js&logoColor=white) ![Wiki](https://img.shields.io/badge/wiki-Template--NPM-blue?style=flat-square)
Template repository for creating MokoStandards-compliant Model Context Protocol (MCP) API servers. Provides the scaffolding, configuration patterns, and architecture conventions used by all Moko Consulting MCP servers, enabling AI assistants like Claude to interact with REST APIs through a standardized tool interface.
Template repository for creating MokoCLI-compliant Model Context Protocol (MCP) API servers. Provides the scaffolding, configuration patterns, and architecture conventions used by all Moko Consulting MCP servers, enabling AI assistants like Claude to interact with REST APIs through a standardized tool interface.
## Features
@@ -11,7 +11,7 @@ Template repository for creating MokoStandards-compliant Model Context Protocol
- **REST API bridge architecture** -- standardized pattern for bridging any REST API as MCP tools, with typed request/response handling
- **TypeScript-first** -- full TypeScript setup with `tsconfig.json`, strict mode, and ES module output
- **Build tooling** -- Makefile with `build`, `dev`, `clean`, and `lint` targets; npm scripts for compilation and development
- **MokoStandards compliant** -- follows all Moko Consulting governance conventions: file headers, commit messages, `.gitattributes`, `.gitmessage`, PR/issue templates
- **MokoCLI compliant** -- follows all Moko Consulting governance conventions: file headers, commit messages, `.gitattributes`, `.gitmessage`, PR/issue templates
- **Example configuration** -- `config.example.json` demonstrates the connection configuration schema
- **Documentation templates** -- wiki pages for API reference, architecture overview, and installation pre-generated
@@ -19,7 +19,7 @@ Template repository for creating MokoStandards-compliant Model Context Protocol
1. Create a new repository from this template (or clone directly):
```bash
git clone https://git.mokoconsulting.tech/MokoConsulting/Template-MCP.git my-mcp-server
git clone https://git.mokoconsulting.tech/MokoConsulting/Template-NPM.git my-mcp-server
cd my-mcp-server
```
2. Install dependencies:
@@ -61,11 +61,11 @@ Template repository for creating MokoStandards-compliant Model Context Protocol
## Documentation
Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki), including:
Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki), including:
- [API](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki/API) -- tool reference and connection parameter documentation
- [ARCHITECTURE](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki/ARCHITECTURE) -- MCP server design and REST API bridge pattern
- [INSTALLATION](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki/INSTALLATION) -- setup prerequisites and configuration guide
- [API](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki/API) -- tool reference and connection parameter documentation
- [ARCHITECTURE](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki/ARCHITECTURE) -- MCP server design and REST API bridge pattern
- [INSTALLATION](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki/INSTALLATION) -- setup prerequisites and configuration guide
## Contributing
@@ -77,4 +77,8 @@ This project is licensed under the GNU General Public License v3.0 or later -- s
---
*[Moko Consulting](https://mokoconsulting.tech) -- [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)*
*[Moko Consulting](https://mokoconsulting.tech) -- [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)*
## Template CI Notes
Build/CI/release/version workflows are guarded to skip template repos (Template-*) and only run in repos created from them.
-237
View File
@@ -1,237 +0,0 @@
#!/usr/bin/env bash
# ============================================================================
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: Automation.CI
# INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /automation/ci-issue-reporter.sh
# VERSION: 09.23.00
# BRIEF: Creates or updates a Gitea issue when a CI gate fails.
# Deduplicates by searching open issues with the "ci-auto" label
# whose title matches the gate. If a matching issue exists, a comment
# is appended instead of opening a duplicate.
# ============================================================================
set -euo pipefail
# ── Defaults ────────────────────────────────────────────────────────────────
GITEA_URL="${GITEA_URL:-https://git.mokoconsulting.tech}"
GITEA_TOKEN="${GITEA_TOKEN:-}"
REPO="${GITHUB_REPOSITORY:-}"
RUN_URL="${GITHUB_SERVER_URL:-${GITEA_URL}}/${REPO}/actions/runs/${GITHUB_RUN_ID:-0}"
LABEL_NAME="ci-auto"
LABEL_COLOR="#e11d48"
GATE=""
DETAILS=""
SEVERITY="error"
WORKFLOW=""
# ── Parse arguments ─────────────────────────────────────────────────────────
usage() {
cat <<EOF
Usage: ci-issue-reporter.sh --gate NAME --details TEXT [OPTIONS]
Required:
--gate CI gate name (e.g. "Code Quality", "Self-Health")
--details Human-readable failure description
Optional:
--severity "error" (default) or "warning"
--workflow Workflow name for the issue title
--repo owner/repo (default: \$GITHUB_REPOSITORY)
--run-url URL to the CI run (auto-detected from env)
--token Gitea API token (default: \$GITEA_TOKEN)
--url Gitea base URL (default: \$GITEA_URL)
EOF
exit 1
}
while [[ $# -gt 0 ]]; do
case "$1" in
--gate) GATE="$2"; shift 2 ;;
--details) DETAILS="$2"; shift 2 ;;
--severity) SEVERITY="$2"; shift 2 ;;
--workflow) WORKFLOW="$2"; shift 2 ;;
--repo) REPO="$2"; shift 2 ;;
--run-url) RUN_URL="$2"; shift 2 ;;
--token) GITEA_TOKEN="$2"; shift 2 ;;
--url) GITEA_URL="$2"; shift 2 ;;
-h|--help) usage ;;
*) echo "Unknown option: $1"; usage ;;
esac
done
[[ -z "$GATE" ]] && { echo "ERROR: --gate is required"; usage; }
[[ -z "$DETAILS" ]] && { echo "ERROR: --details is required"; usage; }
[[ -z "$GITEA_TOKEN" ]] && { echo "ERROR: GITEA_TOKEN not set"; exit 1; }
[[ -z "$REPO" ]] && { echo "ERROR: GITHUB_REPOSITORY not set"; exit 1; }
API="${GITEA_URL}/api/v1/repos/${REPO}"
# ── Build title ─────────────────────────────────────────────────────────────
if [[ -n "$WORKFLOW" ]]; then
TITLE="[CI] ${WORKFLOW}: ${GATE} failed"
else
TITLE="[CI] ${GATE} failed"
fi
# ── Ensure label exists ─────────────────────────────────────────────────────
ensure_label() {
local exists
exists=$(curl -sf -o /dev/null -w '%{http_code}' \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null || echo "000")
if [[ "$exists" == "200" ]]; then
# Check if label already exists
local found
found=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -o "\"name\":\"${LABEL_NAME}\"" || true)
if [[ -z "$found" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/labels" \
-d "{\"name\":\"${LABEL_NAME}\",\"color\":\"${LABEL_COLOR}\",\"description\":\"Auto-created by CI issue reporter\"}" \
> /dev/null 2>&1 || true
fi
fi
}
# ── Search for existing open issue ──────────────────────────────────────────
find_existing_issue() {
# URL-encode the gate name for the query
local query
query=$(printf '%s' "[CI] ${GATE}" | sed 's/ /%20/g; s/\[/%5B/g; s/\]/%5D/g')
local response
response=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/issues?type=issues&state=open&labels=${LABEL_NAME}&q=${query}&limit=5" \
2>/dev/null || echo "[]")
# Extract the first matching issue number
echo "$response" \
| grep -oP '"number":\s*\K[0-9]+' \
| head -1
}
# ── Build issue body ────────────────────────────────────────────────────────
build_body() {
local severity_badge
if [[ "$SEVERITY" == "error" ]]; then
severity_badge="**Severity:** Error"
else
severity_badge="**Severity:** Warning"
fi
cat <<BODY
## CI Gate Failure: ${GATE}
${severity_badge}
**Workflow:** ${WORKFLOW:-unknown}
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
### Details
${DETAILS}
### Resolution
Fix the issue described above and push a new commit. This issue will be closed automatically when the gate passes, or can be closed manually.
---
*Auto-created by [ci-issue-reporter](${GITEA_URL}/${REPO}/src/branch/main/automation/ci-issue-reporter.sh)*
BODY
}
# ── Build comment body (for existing issues) ────────────────────────────────
build_comment() {
cat <<COMMENT
### CI failure recurrence
**Branch:** ${GITHUB_REF_NAME:-unknown}
**Commit:** \`${GITHUB_SHA:0:8}\`
**Run:** [View CI run](${RUN_URL})
${DETAILS}
COMMENT
}
# ── Main ────────────────────────────────────────────────────────────────────
ensure_label
EXISTING=$(find_existing_issue)
if [[ -n "$EXISTING" ]]; then
# Append comment to existing issue
COMMENT_BODY=$(build_comment)
COMMENT_JSON=$(printf '%s' "$COMMENT_BODY" | python3 -c "
import sys, json
print(json.dumps({'body': sys.stdin.read()}))" 2>/dev/null)
HTTP=$(curl -sf -o /dev/null -w '%{http_code}' -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${EXISTING}/comments" \
-d "${COMMENT_JSON}" 2>/dev/null || echo "000")
if [[ "$HTTP" == "201" ]]; then
echo "Commented on existing issue #${EXISTING}"
else
echo "WARNING: Failed to comment on issue #${EXISTING} (HTTP ${HTTP})"
fi
else
# Create new issue
ISSUE_BODY=$(build_body)
ISSUE_JSON=$(python3 -c "
import sys, json
body = sys.stdin.read()
print(json.dumps({
'title': sys.argv[1],
'body': body,
'labels': []
}))" "$TITLE" <<< "$ISSUE_BODY" 2>/dev/null)
# Create the issue
RESPONSE=$(curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues" \
-d "${ISSUE_JSON}" 2>/dev/null || echo "{}")
ISSUE_NUM=$(echo "$RESPONSE" | grep -oP '"number":\s*\K[0-9]+' | head -1)
if [[ -n "$ISSUE_NUM" ]]; then
# Apply label (separate call — more reliable across Gitea versions)
LABEL_ID=$(curl -sf \
-H "Authorization: token ${GITEA_TOKEN}" \
"${API}/labels" 2>/dev/null \
| grep -oP "\"id\":\s*\K[0-9]+(?=[^}]*\"name\":\s*\"${LABEL_NAME}\")" \
| head -1 || true)
if [[ -n "$LABEL_ID" ]]; then
curl -sf -X POST \
-H "Authorization: token ${GITEA_TOKEN}" \
-H "Content-Type: application/json" \
"${API}/issues/${ISSUE_NUM}/labels" \
-d "{\"labels\":[${LABEL_ID}]}" \
> /dev/null 2>&1 || true
fi
echo "Created issue #${ISSUE_NUM}: ${TITLE}"
else
echo "WARNING: Failed to create issue"
echo "Response: ${RESPONSE}"
fi
fi