10 Commits

Author SHA1 Message Date
jmiller 65f57f466e ci: read platform from MokoGitea metadata API in pr-check (retire manifest.xml)
Universal: Auto Version Bump / Version Bump (push) Successful in 6s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 7s
Matches Template-Generic's dev block. Platform detection now GETs
/api/v1/repos/{owner}/{repo}/metadata instead of reading .mokogitea/manifest.xml;
falls back to 'generic' if unavailable.
2026-07-12 18:07:39 -05:00
jmiller 95b542bff2 chore: retire .mokogitea/manifest.xml doc/comment references
Universal: Auto Version Bump / Version Bump (push) Successful in 7s
Universal: Pre-Release / Build Pre-Release (${{ inputs.stability || github.ref_name }}) (push) Successful in 7s
Platform detection already reads the MokoGitea metadata API on dev; this removes
leftover manifest.xml references from docs and comments (CLAUDE.md, auto-release
comments, pr-check comment tail, CONTRIBUTING). Joomla EXTENSION manifest refs
left intact.
2026-07-12 18:05:14 -05:00
jmiller 749e5ec149 Merge pull request 'chore(workflows): sync shared workflows from Template-Generic (dev)' (#14) from fix/sync-from-generic-dev into dev 2026-06-27 19:28:54 +00:00
jmiller ac2d35439c chore(workflows): sync shared workflows from Template-Generic (dev)
Authored-by: Moko Consulting
2026-06-27 14:27:43 -05:00
jmiller 5c28793132 chore: remove deploy-manual.yml -- no longer needed 2026-06-23 18:00:41 +00:00
jmiller 3428e59893 fix(ci): run repo-health on PR to main only, not on push 2026-06-18 16:47:43 +00:00
jmiller 6b55296699 fix(ci): run repo-health on PR to main only, not on push 2026-06-18 16:45:19 +00:00
jmiller 23493fb182 revert: re-enable auto-bump on dev push [skip ci] 2026-06-18 13:18:40 +00:00
jmiller 447dd488ac chore: sync .mokogitea/workflows/auto-release.yml from moko-platform [skip ci] 2026-06-06 19:50:51 +00:00
jmiller b0beef55ed chore: sync .mokogitea/workflows/pre-release.yml from moko-platform [skip ci] 2026-06-06 19:48:19 +00:00
58 changed files with 1524 additions and 718 deletions
+1 -1
View File
@@ -41,7 +41,7 @@
# CI and automation # CI and automation
.github/ export-ignore .github/ export-ignore
.github/workflows/ export-ignore .github/workflows/ export-ignore
.mokogit/ export-ignore .gitea/ export-ignore
.gitlab/ export-ignore .gitlab/ export-ignore
# Development and tooling # Development and tooling
-8
View File
@@ -205,14 +205,6 @@ hypothesis/
profile.ps1 profile.ps1
.mcp.json .mcp.json
# ============================================================
# AI client working directories and instruction files
# ============================================================
.gemini/
.mokoai/
/GEMINI.md
/MOKOAI.md
# ============================================================ # ============================================================
# Local wiki clone (not version controlled) # Local wiki clone (not version controlled)
# ============================================================ # ============================================================
-51
View File
@@ -1,51 +0,0 @@
# {{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)
-51
View File
@@ -1,51 +0,0 @@
# {{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)
-60
View File
@@ -1,60 +0,0 @@
# 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
-114
View File
@@ -1,114 +0,0 @@
# 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 }}
-90
View File
@@ -1,90 +0,0 @@
# 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
@@ -7,11 +7,11 @@ contact_links:
- name: 💬 Ask a Question - name: 💬 Ask a Question
url: https://mokoconsulting.tech/ url: https://mokoconsulting.tech/
about: Get help or ask questions through our website about: Get help or ask questions through our website
- name: 📚 MokoCLI Documentation - name: 📚 MokoStandards Documentation
url: https://git.mokoconsulting.tech/MokoConsulting/mokocli url: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
about: View our coding standards and best practices about: View our coding standards and best practices
- name: 🔒 Report a Security Vulnerability - name: 🔒 Report a Security Vulnerability
url: https://git.mokoconsulting.tech/MokoConsulting/.github-private/security/advisories/new url: https://git.mokoconsulting.tech/mokoconsulting-tech/.github-private/security/advisories/new
about: Report security vulnerabilities privately (for critical issues) about: Report security vulnerabilities privately (for critical issues)
- name: 💡 Community Discussions - name: 💡 Community Discussions
url: https://github.com/orgs/mokoconsulting-tech/discussions url: https://github.com/orgs/mokoconsulting-tech/discussions
@@ -42,7 +42,7 @@ Suggested text here
<!-- Add any other context, screenshots, or references --> <!-- Add any other context, screenshots, or references -->
## Standards Alignment ## Standards Alignment
- [ ] Follows MokoCLI documentation guidelines - [ ] Follows MokoStandards documentation guidelines
- [ ] Uses en_US/en_GB localization - [ ] Uses en_US/en_GB localization
- [ ] Includes proper SPDX headers where applicable - [ ] 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. Add any other context, mockups, or screenshots about the feature request here.
## Relevant Standards ## Relevant Standards
Does this relate to any standards in [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli)? Does this relate to any standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] Accessibility (WCAG 2.1 AA) - [ ] Accessibility (WCAG 2.1 AA)
- [ ] Localization (en_US/en_GB) - [ ] Localization (en_US/en_GB)
- [ ] Security best practices - [ ] 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 documentation is available and accessible
- [ ] API supports the required authentication method - [ ] API supports the required authentication method
- [ ] I have tested the API endpoints manually - [ ] I have tested the API endpoints manually
- [ ] The integration follows the Template-NPM architecture pattern - [ ] The integration follows the Template-MCP architecture pattern
@@ -35,7 +35,7 @@ Use this template only for:
<!-- Describe how this could be addressed --> <!-- Describe how this could be addressed -->
## Standards Reference ## Standards Reference
Does this relate to security standards in [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli)? Does this relate to security standards in [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/MokoStandards)?
- [ ] SPDX license identifiers - [ ] SPDX license identifiers
- [ ] Secret management - [ ] Secret management
- [ ] Dependency security - [ ] Dependency security
@@ -1,10 +1,10 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech> # Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Automation # INGROUP: moko-platform.Automation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/moko-platform
# PATH: /.mokogit/workflows/branch-protection.yml # PATH: /.gitea/workflows/branch-protection.yml
# BRIEF: Apply standardised branch protection rules to all governed repositories # BRIEF: Apply standardised branch protection rules to all governed repositories
# #
# +========================================================================+ # +========================================================================+
@@ -42,8 +42,8 @@ on:
default: '' default: ''
env: env:
GIT_URL: https://git.mokoconsulting.tech GITEA_URL: https://git.mokoconsulting.tech
GIT_ORG: MokoConsulting GITEA_ORG: MokoConsulting
permissions: permissions:
contents: read contents: read
@@ -59,11 +59,11 @@ jobs:
env: env:
GA_TOKEN: ${{ secrets.GA_TOKEN }} GA_TOKEN: ${{ secrets.GA_TOKEN }}
run: | run: |
API="${GIT_URL}/api/v1" API="${GITEA_URL}/api/v1"
# Platform/standards/infra repos to exclude # Platform/standards/infra repos to exclude
EXCLUDE="git-org-config org-profile git-private .mokogit-private mokocli MokoTesting" EXCLUDE="gitea-org-config org-profile gitea-private .mokogitea-private MokoStandards moko-platform MokoTesting"
EXCLUDE="$EXCLUDE Template-Client Template-Dolibarr Template-Generic Template-Joomla MokoDoliProjTemplate" EXCLUDE="$EXCLUDE MokoStandards-Template-Client MokoStandards-Template-Dolibarr MokoStandards-Template-Generic MokoStandards-Template-Joomla MokoDoliProjTemplate"
if [ -n "${{ inputs.repos }}" ]; then if [ -n "${{ inputs.repos }}" ]; then
# User-specified repos # User-specified repos
@@ -75,7 +75,7 @@ jobs:
while true; do while true; do
BATCH=$(curl -sS \ BATCH=$(curl -sS \
-H "Authorization: token ${GA_TOKEN}" \ -H "Authorization: token ${GA_TOKEN}" \
"${API}/orgs/${GIT_ORG}/repos?page=${PAGE}&limit=50" \ "${API}/orgs/${GITEA_ORG}/repos?page=${PAGE}&limit=50" \
| jq -r '.[].name // empty') | jq -r '.[].name // empty')
[ -z "$BATCH" ] && break [ -z "$BATCH" ] && break
REPOS="$REPOS $BATCH" REPOS="$REPOS $BATCH"
@@ -108,7 +108,7 @@ jobs:
GA_TOKEN: ${{ secrets.GA_TOKEN }} GA_TOKEN: ${{ secrets.GA_TOKEN }}
DRY_RUN: ${{ inputs.dry_run || 'false' }} DRY_RUN: ${{ inputs.dry_run || 'false' }}
run: | run: |
API="${GIT_URL}/api/v1" API="${GITEA_URL}/api/v1"
REPOS="${{ steps.repos.outputs.repos }}" REPOS="${{ steps.repos.outputs.repos }}"
SUCCESS=0 SUCCESS=0
@@ -215,7 +215,7 @@ jobs:
curl -sS -o /dev/null -w "" \ curl -sS -o /dev/null -w "" \
-X DELETE \ -X DELETE \
-H "Authorization: token ${GA_TOKEN}" \ -H "Authorization: token ${GA_TOKEN}" \
"${API}/repos/${GIT_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections/${ENCODED_NAME}" 2>/dev/null || true
# Create rule # Create rule
RESPONSE=$(curl -sS -w "\n%{http_code}" \ RESPONSE=$(curl -sS -w "\n%{http_code}" \
@@ -223,7 +223,7 @@ jobs:
-H "Authorization: token ${GA_TOKEN}" \ -H "Authorization: token ${GA_TOKEN}" \
-H "Content-Type: application/json" \ -H "Content-Type: application/json" \
-d "$RULE" \ -d "$RULE" \
"${API}/repos/${GIT_ORG}/${REPO}/branch_protections") "${API}/repos/${GITEA_ORG}/${REPO}/branch_protections")
HTTP=$(echo "$RESPONSE" | tail -1) HTTP=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | sed '$d') BODY=$(echo "$RESPONSE" | sed '$d')
+24
View File
@@ -0,0 +1,24 @@
<?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>
@@ -5,7 +5,7 @@
# DEFGROUP: GitHub.Workflow # DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Workflows.Shared # INGROUP: MokoStandards.Workflows.Shared
# REPO: https://github.com/mokoconsulting-tech/MokoStandards # REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.mokogit/workflows/auto-assign.yml # PATH: /.mokogitea/workflows/auto-assign.yml
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: Auto-assign jmiller to unassigned issues and PRs every 15 minutes # BRIEF: Auto-assign jmiller to unassigned issues and PRs every 15 minutes
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Release # INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/auto-bump.yml # PATH: /.mokogitea/workflows/auto-bump.yml
# VERSION: 09.02.00 # VERSION: 09.02.00
# BRIEF: Auto patch-bump version on every push to dev (skips merge commits) # BRIEF: Auto patch-bump version on every push to dev (skips merge commits)
@@ -22,7 +22,7 @@ on:
env: env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
permissions: permissions:
contents: write contents: write
@@ -40,10 +40,10 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
token: ${{ secrets.MOKOGIT_TOKEN }} token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1 fetch-depth: 1
- name: Setup MokoCLI tools - name: Setup mokocli tools
run: | run: |
if ! command -v composer &> /dev/null; then 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 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
@@ -52,7 +52,7 @@ jobs:
echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV" echo "MOKO_CLI=/opt/mokocli/cli" >> "$GITHUB_ENV"
else else
git clone --depth 1 --branch main --quiet \ git clone --depth 1 --branch main --quiet \
"https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \ "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/MokoConsulting/mokocli.git" \
/tmp/mokocli /tmp/mokocli
cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet cd /tmp/mokocli && composer install --no-dev --no-interaction --quiet
echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV" echo "MOKO_CLI=/tmp/mokocli/cli" >> "$GITHUB_ENV"
@@ -62,5 +62,5 @@ jobs:
run: | run: |
php ${MOKO_CLI}/version_auto_bump.php \ php ${MOKO_CLI}/version_auto_bump.php \
--path . --branch "${GITHUB_REF_NAME}" \ --path . --branch "${GITHUB_REF_NAME}" \
--token "${{ secrets.MOKOGIT_TOKEN }}" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" \
--repo-url "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" --repo-url "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/auto-dev-issue.yml.template # PATH: /templates/workflows/shared/auto-dev-issue.yml.template
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow # BRIEF: Auto-create tracking issue with sub-issues for dev/rc branch workflow
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/auto-dev-issue.yml in all governed repos. # NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/auto-dev-issue.yml in all governed repos.
name: "Universal: Dev/RC Branch Issue" name: "Universal: Dev/RC Branch Issue"
@@ -3,18 +3,18 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Release # INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
# PATH: /templates/workflows/universal/auto-release.yml.template # PATH: /templates/workflows/universal/auto-release.yml.template
# VERSION: 05.00.00 # VERSION: 05.00.00
# BRIEF: Universal build & release detects platform from manifest.xml # BRIEF: Universal build & release detects platform from metadata API
# #
# +=======================================================================+ # +=======================================================================+
# | UNIVERSAL BUILD & RELEASE PIPELINE | # | UNIVERSAL BUILD & RELEASE PIPELINE |
# +=======================================================================+ # +=======================================================================+
# | | # | |
# | Reads manifest.xml (joomla|dolibarr|generic) to branch logic. | # | Reads metadata API (joomla|dolibarr|generic) to branch logic. |
# | | # | |
# | Platform-specific: | # | Platform-specific: |
# | joomla: XML manifest, type-prefixed packages | # | joomla: XML manifest, type-prefixed packages |
@@ -31,7 +31,7 @@ on:
branches: branches:
- main - main
paths-ignore: paths-ignore:
- '.mokogit/workflows/**' - '.mokogitea/workflows/**'
- '*.md' - '*.md'
- 'wiki/**' - 'wiki/**'
- '.editorconfig' - '.editorconfig'
@@ -52,9 +52,9 @@ on:
env: env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GIT_ORG: ${{ vars.GITEA_ORG || github.repository_owner }} GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GIT_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }} GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
permissions: permissions:
contents: write contents: write
@@ -73,12 +73,12 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
token: ${{ secrets.MOKOGIT_TOKEN }} token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 1 fetch-depth: 1
- name: Setup MokoCLI tools - name: Setup mokocli tools
env: env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: | run: |
if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then if [ -f /opt/mokocli/cli/version_bump.php ] && [ -f /opt/mokocli/vendor/autoload.php ]; then
@@ -99,55 +99,30 @@ jobs:
- name: Rename branch to rc - name: Rename branch to rc
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" php ${MOKO_CLI}/branch_rename.php \
AUTH="Authorization: token ${{ secrets.MOKOGIT_TOKEN }}" --from "${{ github.event.pull_request.head.ref || 'dev' }}" --to rc \
FROM="${{ github.event.pull_request.head.ref || 'dev' }}" --token "${{ secrets.MOKOGITEA_TOKEN }}" \
PR="${{ github.event.pull_request.number }}" --api-base "${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}" \
--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 - name: Checkout rc and configure git
run: | run: |
git fetch origin rc git fetch origin rc
git checkout rc git checkout rc
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech" git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]" git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Publish RC release - name: Publish RC release
run: | run: |
php ${MOKO_CLI}/release_publish.php \ php ${MOKO_CLI}/release_publish.php \
--path . --stability rc --bump minor --branch rc \ --path . --stability rc --bump minor --branch rc \
--token "${{ secrets.MOKOGIT_TOKEN }}" --token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: Update RC release notes from CHANGELOG.md - name: Update RC release notes from CHANGELOG.md
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Extract [Unreleased] section from changelog # Extract [Unreleased] section from changelog
NOTES="" NOTES=""
@@ -196,14 +171,14 @@ jobs:
- name: Checkout repository - name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
with: with:
token: ${{ secrets.MOKOGIT_TOKEN }} token: ${{ secrets.MOKOGITEA_TOKEN }}
fetch-depth: 0 fetch-depth: 0
- name: Configure git for bot pushes - name: Configure git for bot pushes
run: | run: |
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech" git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]" git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
- name: Check for merge conflict markers - name: Check for merge conflict markers
run: | run: |
@@ -218,9 +193,9 @@ jobs:
fi fi
echo "No conflict markers found" echo "No conflict markers found"
- name: Setup MokoCLI tools - name: Setup mokocli tools
env: env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}' COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_MIRROR_TOKEN }}"}}'
run: | run: |
@@ -267,7 +242,7 @@ jobs:
fi fi
php ${MOKO_CLI}/release_publish.php \ php ${MOKO_CLI}/release_publish.php \
--path . --stability stable ${BUMP_FLAG} --branch main \ --path . --stability stable ${BUMP_FLAG} --branch main \
--token "${{ secrets.MOKOGIT_TOKEN }}" --token "${{ secrets.MOKOGITEA_TOKEN }}"
- name: "Read published version" - name: "Read published version"
id: version id: version
@@ -294,8 +269,8 @@ jobs:
!startsWith(steps.platform.outputs.platform, 'joomla') !startsWith(steps.platform.outputs.platform, 'joomla')
run: | run: |
VERSION="${{ steps.version.outputs.version }}" VERSION="${{ steps.version.outputs.version }}"
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
SEMVER_TAG="v${VERSION}" SEMVER_TAG="v${VERSION}"
echo "Creating semver tag: ${SEMVER_TAG}" echo "Creating semver tag: ${SEMVER_TAG}"
@@ -319,8 +294,8 @@ jobs:
- name: Update release notes and promote changelog - name: Update release notes and promote changelog
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Get the stable release info (version and ID) # Get the stable release info (version and ID)
RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \ RELEASE_JSON=$(curl -sf -H "Authorization: token ${TOKEN}" \
@@ -388,10 +363,10 @@ jobs:
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
RELEASE_TAG="${{ steps.version.outputs.release_tag }}" RELEASE_TAG="${{ steps.version.outputs.release_tag }}"
GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}" GH_REPO="${{ vars.GH_MIRROR_REPO || github.repository }}"
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_mirror.php \ php ${MOKO_CLI}/release_mirror.php \
--version "$VERSION" --tag "$RELEASE_TAG" \ --version "$VERSION" --tag "$RELEASE_TAG" \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \ --gh-token "${{ secrets.GH_MIRROR_TOKEN }}" --gh-repo "$GH_REPO" \
--branch main 2>&1 || true --branch main 2>&1 || true
echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY echo "GitHub mirror updated" >> $GITHUB_STEP_SUMMARY
@@ -417,8 +392,8 @@ jobs:
if: steps.version.outputs.skip != 'true' if: steps.version.outputs.skip != 'true'
continue-on-error: true continue-on-error: true
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
# Delete rc branch (ephemeral — created by promote-rc) # Delete rc branch (ephemeral — created by promote-rc)
curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \ curl -sf -X DELETE -H "Authorization: token ${TOKEN}" \
@@ -441,8 +416,8 @@ jobs:
if: steps.version.outputs.skip != 'true' if: steps.version.outputs.skip != 'true'
continue-on-error: true continue-on-error: true
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}" VERSION="${{ steps.bump.outputs.version || steps.version.outputs.version }}"
BRANCH_NAME="version/${VERSION}" BRANCH_NAME="version/${VERSION}"
MAIN_SHA=$(git rev-parse HEAD) MAIN_SHA=$(git rev-parse HEAD)
@@ -462,9 +437,9 @@ jobs:
if: steps.version.outputs.skip != 'true' if: steps.version.outputs.skip != 'true'
continue-on-error: true continue-on-error: true
run: | run: |
API_BASE="${MOKOGIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${MOKOGITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/version_reset_dev.php \ php ${MOKO_CLI}/version_reset_dev.php \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "${API_BASE}" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "${API_BASE}" \
--branch dev --path . 2>&1 || true --branch dev --path . 2>&1 || true
# -- Summary -------------------------------------------------------------- # -- Summary --------------------------------------------------------------
@@ -488,5 +463,5 @@ jobs:
echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY echo "| Version | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY echo "| Branch | \`${{ steps.version.outputs.branch }}\` |" >> $GITHUB_STEP_SUMMARY
echo "| Tag | \`${{ steps.version.outputs.tag }}\` |" >> $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 echo "| Release | [View](${MOKOGITEA_URL}/${GITEA_ORG}/${GITEA_REPO}/releases/tag/${{ steps.version.outputs.tag }}) |" >> $GITHUB_STEP_SUMMARY
fi fi
+48
View File
@@ -0,0 +1,48 @@
# 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/mokocli
# 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
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/changelog-validation.yml.template # PATH: /templates/workflows/shared/changelog-validation.yml.template
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: Validates CHANGELOG.md format and version consistency # BRIEF: Validates CHANGELOG.md format and version consistency
# NOTE: Deployed to .mokogit/workflows/changelog-validation.yml in governed repos. # NOTE: Deployed to .mokogitea/workflows/changelog-validation.yml in governed repos.
name: "Universal: Changelog Validation" name: "Universal: Changelog Validation"
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.CI # INGROUP: MokoStandards.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic # REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Generic
# PATH: /.mokogit/workflows/ci-generic.yml # PATH: /.gitea/workflows/ci-generic.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js) # BRIEF: CI pipeline — lint, validate, and test for generic projects (PHP + Node.js)
@@ -3,12 +3,12 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Universal # INGROUP: mokocli.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/ci-issue-reporter.yml # PATH: /.mokogitea/workflows/ci-issue-reporter.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Reusable workflow — creates/updates a MokoGIT issue when a CI gate fails. # BRIEF: Reusable workflow — creates/updates a Gitea issue when a CI gate fails.
# Clones MokoCLI and runs cli/ci_issue_reporter.sh. # Clones MokoCLI and runs cli/ci_issue_reporter.sh.
name: "Universal: CI Issue Reporter" name: "Universal: CI Issue Reporter"
@@ -35,7 +35,7 @@ on:
type: string type: string
default: "" default: ""
secrets: secrets:
MOKOGIT_TOKEN: MOKOGITEA_TOKEN:
required: true required: true
env: env:
@@ -49,16 +49,16 @@ jobs:
steps: steps:
- name: Clone MokoCLI - name: Clone MokoCLI
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
MOKOGIT_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}" MOKOGITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
git clone --depth 1 --filter=blob:none --sparse "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli git clone --depth 1 --filter=blob:none --sparse "${MOKOGITEA_URL}/MokoConsulting/MokoCLI.git" /tmp/mokocli
cd /tmp/mokocli && git sparse-checkout set cli/ci_issue_reporter.sh cd /tmp/mokocli && git sparse-checkout set cli/ci_issue_reporter.sh
- name: Report CI failure - name: Report CI failure
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: | run: |
chmod +x /tmp/mokocli/cli/ci_issue_reporter.sh chmod +x /tmp/mokocli/cli/ci_issue_reporter.sh
/tmp/mokocli/cli/ci_issue_reporter.sh \ /tmp/mokocli/cli/ci_issue_reporter.sh \
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Maintenance # INGROUP: MokoStandards.Maintenance
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.mokogit/workflows/cleanup.yml # PATH: /.gitea/workflows/cleanup.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Scheduled cleanup — delete merged branches and old workflow runs # BRIEF: Scheduled cleanup — delete merged branches and old workflow runs
@@ -21,7 +21,7 @@ permissions:
contents: write contents: write
env: env:
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs: jobs:
cleanup: cleanup:
@@ -33,17 +33,17 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
token: ${{ secrets.MOKOGIT_TOKEN }} token: ${{ secrets.MOKOGITEA_TOKEN }}
- name: Delete merged branches - name: Delete merged branches
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
echo "=== Merged Branch Cleanup ===" echo "=== Merged Branch Cleanup ==="
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}" API="${MOKOGITEA_URL}/api/v1/repos/${{ github.repository }}"
# List branches via API # List branches via API
BRANCHES=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \ BRANCHES=$(curl -sS -H "Authorization: token ${MOKOGITEA_TOKEN}" \
"${API}/branches?limit=50" | jq -r '.[].name') "${API}/branches?limit=50" | jq -r '.[].name')
DELETED=0 DELETED=0
@@ -56,7 +56,7 @@ jobs:
# Check if branch is merged into main # Check if branch is merged into main
if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then if git merge-base --is-ancestor "origin/${BRANCH}" origin/main 2>/dev/null; then
echo " Deleting merged branch: ${BRANCH}" echo " Deleting merged branch: ${BRANCH}"
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \ curl -sS -X DELETE -H "Authorization: token ${MOKOGITEA_TOKEN}" \
"${API}/branches/${BRANCH}" 2>/dev/null || true "${API}/branches/${BRANCH}" 2>/dev/null || true
DELETED=$((DELETED + 1)) DELETED=$((DELETED + 1))
fi fi
@@ -66,20 +66,20 @@ jobs:
- name: Clean old workflow runs - name: Clean old workflow runs
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
echo "=== Workflow Run Cleanup ===" echo "=== Workflow Run Cleanup ==="
API="${MOKOGIT_URL}/api/v1/repos/${{ github.repository }}" API="${MOKOGITEA_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) 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 # Get old completed runs
RUNS=$(curl -sS -H "Authorization: token ${MOKOGIT_TOKEN}" \ RUNS=$(curl -sS -H "Authorization: token ${MOKOGITEA_TOKEN}" \
"${API}/actions/runs?status=completed&limit=50" | \ "${API}/actions/runs?status=completed&limit=50" | \
jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null) jq -r ".workflow_runs[] | select(.created_at < \"${CUTOFF}\") | .id" 2>/dev/null)
DELETED=0 DELETED=0
for RUN_ID in $RUNS; do for RUN_ID in $RUNS; do
curl -sS -X DELETE -H "Authorization: token ${MOKOGIT_TOKEN}" \ curl -sS -X DELETE -H "Authorization: token ${MOKOGITEA_TOKEN}" \
"${API}/actions/runs/${RUN_ID}" 2>/dev/null || true "${API}/actions/runs/${RUN_ID}" 2>/dev/null || true
DELETED=$((DELETED + 1)) DELETED=$((DELETED + 1))
done done
+115
View File
@@ -0,0 +1,115 @@
# 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
@@ -0,0 +1,44 @@
# 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 }}
@@ -0,0 +1,758 @@
# 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
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Security # INGROUP: MokoStandards.Security
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards-API
# PATH: /templates/workflows/gitleaks.yml.template # PATH: /templates/workflows/gitleaks.yml.template
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens # BRIEF: Secret scanning — detect leaked credentials, API keys, and tokens
@@ -34,7 +34,7 @@ permissions:
env: env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }} NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'git-security' }} NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-security' }}
jobs: jobs:
gitleaks: gitleaks:
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Automation # INGROUP: mokocli.Automation
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Auto-create feature branch when an issue is opened # BRIEF: Auto-create feature branch when an issue is opened
@@ -19,7 +19,7 @@ permissions:
issues: write issues: write
env: env:
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
jobs: jobs:
create-branch: create-branch:
@@ -27,22 +27,14 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Create branch and comment - 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: | run: |
TOKEN="${MOKOGIT_TOKEN}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
API="${MOKOGIT_URL}/api/v1/repos/${REPO}" API="${MOKOGITEA_URL}/api/v1/repos/${{ github.repository }}"
ISSUE_NUM="${{ github.event.issue.number }}"
ISSUE_TITLE="${{ github.event.issue.title }}"
# Build slug from title: lowercase, replace non-alnum with dash, trim. # 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=$(echo "${ISSUE_TITLE}" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/-/g' | sed 's/--*/-/g' | sed 's/^-//;s/-$//' | cut -c1-40)
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}" BRANCH="feature/${ISSUE_NUM}-${SLUG}"
# Check dev branch exists # Check dev branch exists
@@ -66,7 +58,7 @@ jobs:
echo "Created branch: ${BRANCH}" echo "Created branch: ${BRANCH}"
# Comment on issue with branch link # Comment on issue with branch link
REPO_URL="${MOKOGIT_URL}/${REPO}" REPO_URL="${MOKOGITEA_URL}/${{ github.repository }}"
BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`" BODY="Branch created: [\`${BRANCH}\`](${REPO_URL}/src/branch/${BRANCH})\n\n\`\`\`bash\ngit fetch origin\ngit checkout ${BRANCH}\n\`\`\`"
curl -sf -X POST \ curl -sf -X POST \
@@ -32,8 +32,7 @@ jobs:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: >- if: >-
!contains(github.event.head_commit.message, '[skip ci]') && !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: steps:
- name: Checkout repository - name: Checkout repository
@@ -88,13 +87,13 @@ jobs:
done done
# ── Version ────────────────────────────────────────────────────── # ── Version ──────────────────────────────────────────────────────
- name: Setup MokoCLI tools - name: Setup moko-platform tools
env: env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: | run: |
git clone --depth 1 --branch version/04 --quiet \ git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/MokoConsulting/mokocli.git" \ "https://x-access-token:${GH_TOKEN}@github.com/MokoConsulting/moko-platform.git" \
/tmp/mokostandards /tmp/mokostandards
cd /tmp/mokostandards cd /tmp/mokostandards
composer install --no-dev --no-interaction --quiet composer install --no-dev --no-interaction --quiet
@@ -22,7 +22,6 @@ permissions:
jobs: jobs:
build: build:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
strategy: strategy:
matrix: matrix:
node-version: [20, 22] node-version: [20, 22]
@@ -19,7 +19,6 @@ permissions:
jobs: jobs:
check-sdk: check-sdk:
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: ${{ !startsWith(github.event.repository.name, 'Template-') }}
steps: steps:
- uses: actions/checkout@v4 - uses: actions/checkout@v4
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Notifications # INGROUP: MokoStandards.Notifications
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards
# PATH: /.mokogit/workflows/notify.yml # PATH: /.gitea/workflows/notify.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Push notifications via ntfy on release success or workflow failure # BRIEF: Push notifications via ntfy on release success or workflow failure
@@ -26,7 +26,7 @@ permissions:
env: env:
NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }} NTFY_URL: ${{ vars.NTFY_URL || 'https://ntfy.mokoconsulting.tech' }}
NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'git-releases' }} NTFY_TOPIC: ${{ vars.NTFY_TOPIC || 'gitea-releases' }}
jobs: jobs:
notify: notify:
@@ -3,9 +3,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.CI # INGROUP: moko-platform.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/moko-platform
# PATH: /templates/workflows/universal/pr-check.yml.template # PATH: /templates/workflows/universal/pr-check.yml.template
# VERSION: 09.23.00 # VERSION: 09.23.00
# BRIEF: PR gate — branch policy + code validation before merge # BRIEF: PR gate — branch policy + code validation before merge
@@ -147,12 +147,11 @@ jobs:
- name: Detect platform - name: Detect platform
id: platform id: platform
run: | run: |
# Platform comes from the MokoGIT metadata API (public GET). # Platform comes from the MokoGitea metadata API (public GET).
API="${GITHUB_SERVER_URL:-https://git.mokoconsulting.tech}/api/v1/repos/${GITHUB_REPOSITORY}/metadata" 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)" 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" [ -z "$PLATFORM" ] && PLATFORM="generic"
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
echo "Detected platform: $PLATFORM"
- name: Setup PHP - name: Setup PHP
if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr' if: steps.platform.outputs.platform == 'joomla' || steps.platform.outputs.platform == 'dolibarr'
@@ -283,10 +282,10 @@ jobs:
for ELEMENT in name version description; do for ELEMENT in name version description; do
grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; } grep -q "<${ELEMENT}>" "$MANIFEST" || { echo "::error::Missing <${ELEMENT}> in manifest"; exit 1; }
done done
# Block legacy raw/branch update server URLs on MokoGIT # Block legacy raw/branch update server URLs on MokoGitea
RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogit\|git\.mokoconsulting\.tech' || true) RAW_URLS=$(grep -n 'raw/branch' "$MANIFEST" | grep -i 'mokoconsulting\|mokogitea\|git\.mokoconsulting\.tech' || true)
if [ -n "$RAW_URLS" ]; then if [ -n "$RAW_URLS" ]; then
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 "::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 "$RAW_URLS" echo "$RAW_URLS"
exit 1 exit 1
fi fi
@@ -497,12 +496,12 @@ jobs:
steps: steps:
- name: Trigger RC pre-release - name: Trigger RC pre-release
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
REPO: ${{ github.repository }} REPO: ${{ github.repository }}
BRANCH: ${{ github.head_ref }} BRANCH: ${{ github.head_ref }}
MOKOGIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} MOKOGITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
run: | run: |
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\"}}" curl -s -X POST "${MOKOGITEA_URL}/api/v1/repos/${REPO}/actions/workflows/pre-release.yml/dispatches" -H "Authorization: token ${MOKOGITEA_TOKEN}" -H "Content-Type: application/json" -d "{\"ref\":\"${BRANCH}\",\"inputs\":{\"stability\":\"release-candidate\"}}"
echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY echo "### Pre-Release" >> $GITHUB_STEP_SUMMARY
echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY echo "Triggered RC build on branch \`${BRANCH}\`" >> $GITHUB_STEP_SUMMARY
@@ -513,7 +512,7 @@ jobs:
if: >- if: >-
always() && always() &&
needs.validate.result == 'failure' needs.validate.result == 'failure'
uses: ./.mokogit/workflows/ci-issue-reporter.yml uses: ./.mokogitea/workflows/ci-issue-reporter.yml
with: with:
gate: "PR Validation" gate: "PR Validation"
workflow: "PR Check" workflow: "PR Check"
@@ -3,8 +3,8 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Release # INGROUP: mokocli.Release
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /templates/workflows/universal/pre-release.yml.template # PATH: /templates/workflows/universal/pre-release.yml.template
# VERSION: 05.02.00 # VERSION: 05.02.00
@@ -40,9 +40,9 @@ permissions:
contents: write contents: write
env: env:
GIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
GIT_ORG: ${{ vars.GITEA_ORG || github.repository_owner }} GITEA_ORG: ${{ vars.GITEA_ORG || github.repository_owner }}
GIT_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }} GITEA_REPO: ${{ vars.GITEA_REPO || github.event.repository.name }}
jobs: jobs:
build: build:
@@ -57,7 +57,7 @@ jobs:
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
fetch-depth: 0 fetch-depth: 0
token: ${{ secrets.MOKOGIT_TOKEN }} token: ${{ secrets.MOKOGITEA_TOKEN }}
ref: ${{ github.ref_name }} ref: ${{ github.ref_name }}
submodules: recursive submodules: recursive
@@ -65,9 +65,9 @@ jobs:
run: | run: |
git submodule foreach --quiet 'git checkout main && git pull --quiet origin main' 2>/dev/null || true git submodule foreach --quiet 'git checkout main && git pull --quiet origin main' 2>/dev/null || true
- name: Setup MokoCLI tools - name: Setup mokocli tools
env: env:
MOKO_CLONE_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKO_CLONE_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting MOKO_CLONE_HOST: git.mokoconsulting.tech/MokoConsulting
run: | run: |
# Use pre-installed /opt/mokocli if available (updated by cron every 6h) # Use pre-installed /opt/mokocli if available (updated by cron every 6h)
@@ -152,9 +152,9 @@ jobs:
fi fi
# Commit version bump # Commit version bump
git config --local user.email "mokogit-actions[bot]@mokoconsulting.tech" git config --local user.email "gitea-actions[bot]@mokoconsulting.tech"
git config --local user.name "mokogit-actions[bot]" git config --local user.name "gitea-actions[bot]"
git remote set-url origin "https://x-access-token:${{ secrets.MOKOGIT_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git" git remote set-url origin "https://x-access-token:${{ secrets.MOKOGITEA_TOKEN }}@git.mokoconsulting.tech/${{ github.repository }}.git"
git add -A git add -A
git diff --cached --quiet || { git diff --cached --quiet || {
git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]" git commit -m "chore(version): pre-release bump to ${VERSION} [skip ci]"
@@ -164,12 +164,12 @@ jobs:
# Auto-detect element via manifest_element.php # Auto-detect element via manifest_element.php
php ${MOKO_CLI}/manifest_element.php \ php ${MOKO_CLI}/manifest_element.php \
--path . --version "$VERSION" --stability "$STABILITY" \ --path . --version "$VERSION" --stability "$STABILITY" \
--repo "${GIT_REPO}" --github-output --repo "${GITEA_REPO}" --github-output
# Read back element outputs # Read back element outputs
EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2) EXT_ELEMENT=$(grep '^ext_element=' "$GITHUB_OUTPUT" | tail -1 | cut -d= -f2)
ZIP_NAME=$(grep '^zip_name=' "$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 "${GIT_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -') [ -z "$EXT_ELEMENT" ] && EXT_ELEMENT=$(echo "${GITEA_REPO}" | tr '[:upper:]' '[:lower:]' | tr -d ' -')
[ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip" [ -z "$ZIP_NAME" ] && ZIP_NAME="${EXT_ELEMENT}-${VERSION}.zip"
echo "version=${VERSION}" >> "$GITHUB_OUTPUT" echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
@@ -187,18 +187,18 @@ jobs:
run: | run: |
TAG="${{ steps.meta.outputs.tag }}" TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}" VERSION="${{ steps.meta.outputs.version }}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_create.php \ php ${MOKO_CLI}/release_create.php \
--path . --version "$VERSION" --tag "$TAG" \ --path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GIT_REPO}" --branch "${{ github.ref_name }}" --prerelease --repo "${GITEA_REPO}" --branch "${{ github.ref_name }}" --prerelease
- name: Update release notes from CHANGELOG.md - name: Update release notes from CHANGELOG.md
if: steps.eligibility.outputs.proceed == 'true' if: steps.eligibility.outputs.proceed == 'true'
run: | run: |
TAG="${{ steps.meta.outputs.tag }}" TAG="${{ steps.meta.outputs.tag }}"
VERSION="${{ steps.meta.outputs.version }}" VERSION="${{ steps.meta.outputs.version }}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
# Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading) # Extract [Unreleased] section from changelog (everything between [Unreleased] and next ## heading)
if [ -f "CHANGELOG.md" ]; then if [ -f "CHANGELOG.md" ]; then
@@ -209,7 +209,7 @@ jobs:
fi fi
# Update release body via API # Update release body via API
RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGIT_TOKEN }}" \ RELEASE_ID=$(curl -sf -H "Authorization: token ${{ secrets.MOKOGITEA_TOKEN }}" \
"${API_BASE}/releases/tags/${TAG}" | python3 -c "import json,sys; print(json.load(sys.stdin).get('id',''))" 2>/dev/null || true) "${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 if [ -n "$RELEASE_ID" ]; then
@@ -221,7 +221,7 @@ jobs:
'${API_BASE}/releases/${RELEASE_ID}', '${API_BASE}/releases/${RELEASE_ID}',
data=payload, method='PATCH', data=payload, method='PATCH',
headers={ headers={
'Authorization': 'token ${{ secrets.MOKOGIT_TOKEN }}', 'Authorization': 'token ${{ secrets.MOKOGITEA_TOKEN }}',
'Content-Type': 'application/json' 'Content-Type': 'application/json'
}) })
urllib.request.urlopen(req) urllib.request.urlopen(req)
@@ -235,21 +235,21 @@ jobs:
run: | run: |
VERSION="${{ steps.meta.outputs.version }}" VERSION="${{ steps.meta.outputs.version }}"
TAG="${{ steps.meta.outputs.tag }}" TAG="${{ steps.meta.outputs.tag }}"
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
php ${MOKO_CLI}/release_package.php \ php ${MOKO_CLI}/release_package.php \
--path . --version "$VERSION" --tag "$TAG" \ --path . --version "$VERSION" --tag "$TAG" \
--token "${{ secrets.MOKOGIT_TOKEN }}" --api-base "$API_BASE" \ --token "${{ secrets.MOKOGITEA_TOKEN }}" --api-base "$API_BASE" \
--repo "${GIT_REPO}" --output /tmp || true --repo "${GITEA_REPO}" --output /tmp || true
# updates.xml is generated dynamically by MokoGIT license server # updates.xml is generated dynamically by MokoGitea license server
# No need to build, commit, or sync updates.xml from workflows # No need to build, commit, or sync updates.xml from workflows
- name: "Delete lesser pre-release channels (cascade)" - name: "Delete lesser pre-release channels (cascade)"
if: steps.eligibility.outputs.proceed == 'true' if: steps.eligibility.outputs.proceed == 'true'
continue-on-error: true continue-on-error: true
run: | run: |
API_BASE="${GIT_URL}/api/v1/repos/${GIT_ORG}/${GIT_REPO}" API_BASE="${GITEA_URL}/api/v1/repos/${GITEA_ORG}/${GITEA_REPO}"
TOKEN="${{ secrets.MOKOGIT_TOKEN }}" TOKEN="${{ secrets.MOKOGITEA_TOKEN }}"
php ${MOKO_CLI}/release_cascade.php \ php ${MOKO_CLI}/release_cascade.php \
--stability "${{ steps.meta.outputs.stability }}" \ --stability "${{ steps.meta.outputs.stability }}" \
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Universal # INGROUP: mokocli.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/rc-revert.yml # PATH: /.mokogitea/workflows/rc-revert.yml
# VERSION: 09.23.00 # VERSION: 09.23.00
# BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge # BRIEF: Rename rc/ branch back to dev/ when PR is closed without merge
@@ -32,8 +32,8 @@ jobs:
env: env:
BRANCH: ${{ github.event.pull_request.head.ref }} BRANCH: ${{ github.event.pull_request.head.ref }}
REPO: ${{ github.repository }} REPO: ${{ github.repository }}
GIT_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }} GITEA_URL: ${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}
TOKEN: ${{ secrets.MOKOGIT_TOKEN }} TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
set -euo pipefail set -euo pipefail
# BRANCH is attacker-controlled (PR head ref). Strict allowlist before ANY use. # BRANCH is attacker-controlled (PR head ref). Strict allowlist before ANY use.
@@ -42,7 +42,7 @@ jobs:
fi fi
SUFFIX="${BRANCH#rc/}" SUFFIX="${BRANCH#rc/}"
DEV_BRANCH="dev/${SUFFIX}" DEV_BRANCH="dev/${SUFFIX}"
API="${GIT_URL}/api/v1/repos/${REPO}/branches" API="${GITEA_URL}/api/v1/repos/${REPO}/branches"
# Create dev/ branch from rc/ branch # Create dev/ branch from rc/ branch
STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \ STATUS=$(curl -sf -o /dev/null -w "%{http_code}" -X POST \
@@ -6,9 +6,9 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Validation # INGROUP: mokocli.Validation
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/mokocli
# PATH: /templates/workflows/joomla/repo_health.yml.template # PATH: /templates/workflows/joomla/repo_health.yml.template
# VERSION: 09.23.00 # VERSION: 09.23.00
# BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts. # BRIEF: Enforces repository guardrails by validating scripts governance, tooling availability, and core repository health artifacts.
@@ -45,7 +45,7 @@ env:
SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate SCRIPTS_ALLOWED_DIRS: scripts,scripts/fix,scripts/lib,scripts/release,scripts/run,scripts/validate
# Repo health policy # Repo health policy
REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogit/workflows/ REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.mokogitea/workflows/
REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/ REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/
REPO_DISALLOWED_DIRS: REPO_DISALLOWED_DIRS:
REPO_DISALLOWED_FILES: TODO.md,todo.md REPO_DISALLOWED_FILES: TODO.md,todo.md
@@ -56,7 +56,7 @@ env:
# File / directory variables # File / directory variables
DOCS_INDEX: docs/docs-index.md DOCS_INDEX: docs/docs-index.md
SCRIPT_DIR: scripts SCRIPT_DIR: scripts
WORKFLOWS_DIR: .mokogit/workflows WORKFLOWS_DIR: .mokogitea/workflows
SHELLCHECK_PATTERN: '*.sh' SHELLCHECK_PATTERN: '*.sh'
SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml' SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml'
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
@@ -77,7 +77,7 @@ jobs:
- name: Check actor permission (admin only) - name: Check actor permission (admin only)
id: perm id: perm
env: env:
TOKEN: ${{ secrets.MOKOGIT_TOKEN || github.token }} TOKEN: ${{ secrets.MOKOGITEA_TOKEN || github.token }}
REPO: ${{ github.repository }} REPO: ${{ github.repository }}
ACTOR: ${{ github.actor }} ACTOR: ${{ github.actor }}
run: | run: |
@@ -88,14 +88,14 @@ jobs:
# Hardcoded authorized users — always allowed # Hardcoded authorized users — always allowed
case "$ACTOR" in case "$ACTOR" in
jmiller|mokogit-actions[bot]) jmiller|gitea-actions[bot])
ALLOWED=true ALLOWED=true
PERMISSION=admin PERMISSION=admin
METHOD="hardcoded allowlist" METHOD="hardcoded allowlist"
;; ;;
*) *)
# Detect platform and check permissions via API # Detect platform and check permissions via API
API_BASE="${GITHUB_API_URL:-${GIT_API_URL:-https://api.github.com}}" API_BASE="${GITHUB_API_URL:-${GITEA_API_URL:-https://api.github.com}}"
RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \ RESP=$(curl -sf -H "Authorization: token ${TOKEN}" \
"${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}') "${API_BASE}/repos/${REPO}/collaborators/${ACTOR}/permission" 2>/dev/null || echo '{}')
PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown") PERMISSION=$(echo "$RESP" | grep -oP '"permission"\s*:\s*"\K[^"]+' || echo "unknown")
@@ -605,7 +605,7 @@ jobs:
printf '%s\n' '| Domain | Status | Notes |' printf '%s\n' '| Domain | Status | Notes |'
printf '%s\n' '|---|---|---|' printf '%s\n' '|---|---|---|'
printf '%s\n' '| Access control | OK | Admin-only execution gate |' printf '%s\n' '| Access control | OK | Admin-only execution gate |'
printf '%s\n' '| Release policy | N/A | Releases handled by MokoGIT |' printf '%s\n' '| Release policy | N/A | Releases handled by MokoGitea |'
printf '%s\n' '| Scripts governance | OK | Directory policy and advisory reporting |' 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 required artifacts | OK | Required, optional, disallowed enforcement |'
printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |' printf '%s\n' '| Repo content heuristics | OK | Brand, license, changelog structure |'
@@ -677,7 +677,7 @@ jobs:
if: >- if: >-
always() && always() &&
needs.scripts_governance.result == 'failure' needs.scripts_governance.result == 'failure'
uses: ./.mokogit/workflows/ci-issue-reporter.yml uses: ./.mokogitea/workflows/ci-issue-reporter.yml
with: with:
gate: "Scripts Governance" gate: "Scripts Governance"
workflow: "Repo Health" workflow: "Repo Health"
@@ -691,7 +691,7 @@ jobs:
if: >- if: >-
always() && always() &&
needs.repo_health.result == 'failure' needs.repo_health.result == 'failure'
uses: ./.mokogit/workflows/ci-issue-reporter.yml uses: ./.mokogitea/workflows/ci-issue-reporter.yml
with: with:
gate: "Repository Health" gate: "Repository Health"
workflow: "Repo Health" workflow: "Repo Health"
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/repository-cleanup.yml.template # PATH: /templates/workflows/shared/repository-cleanup.yml.template
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes # BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/repository-cleanup.yml in all governed repos. # NOTE: Synced via bulk-repo-sync to .mokogitea/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. # Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch.
name: "Universal: Repository Cleanup" name: "Universal: Repository Cleanup"
@@ -2,14 +2,14 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: GitHub.Workflow # DEFGROUP: GitHub.Workflow
# INGROUP: MokoCLI.Compliance # INGROUP: MokoStandards.Compliance
# REPO: https://github.com/mokoconsulting-tech/mokocli # REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.mokogit/workflows/standards-compliance.yml # PATH: /.mokogitea/workflows/standards-compliance.yml
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: MokoCLI compliance validation workflow # BRIEF: MokoStandards compliance validation workflow
# NOTE: Validates repository structure, documentation, and coding standards # NOTE: Validates repository structure, documentation, and coding standards
name: "Generic: Standards Compliance" name: "MCP: Standards Compliance"
# ╔════════════════════════════════════════════════════════════════════════╗ # ╔════════════════════════════════════════════════════════════════════════╗
# ║ MOKOSTANDARDS COMPLIANCE WORKFLOW ║ # ║ MOKOSTANDARDS COMPLIANCE WORKFLOW ║
@@ -42,7 +42,7 @@ env:
WORKFLOW_VERSION: "04.04.01" WORKFLOW_VERSION: "04.04.01"
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true
# MokoCLI Policy Compliance: # MokoStandards Policy Compliance:
# - File formatting: Enforces organizational coding standards # - File formatting: Enforces organizational coding standards
# - Reference: docs/policy/file-formatting.md # - Reference: docs/policy/file-formatting.md
@@ -252,7 +252,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: LICENSE File Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: LICENSE File Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** LICENSE file is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY echo "**Error:** LICENSE file is required for all MokoStandards-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 "**Action Required:** Add LICENSE file with appropriate open-source license (GPL-3.0-or-later recommended)" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "❌ ERROR: LICENSE file not found - This is a critical requirement" echo "❌ ERROR: LICENSE file not found - This is a critical requirement"
@@ -291,7 +291,7 @@ jobs:
MISSING=0 MISSING=0
PRESENT=0 PRESENT=0
TOTAL=1 TOTAL=2
echo "### Required Directories" >> $GITHUB_STEP_SUMMARY echo "### Required Directories" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
@@ -299,7 +299,7 @@ jobs:
echo "|-----------|--------|-------|------|-------|" >> $GITHUB_STEP_SUMMARY echo "|-----------|--------|-------|------|-------|" >> $GITHUB_STEP_SUMMARY
# Check required directories # Check required directories
for dir in .mokogit; do for dir in docs .github; do
if [ -d "$dir" ]; then if [ -d "$dir" ]; then
FILE_COUNT=$(find "$dir" -type f 2>/dev/null | wc -l) FILE_COUNT=$(find "$dir" -type f 2>/dev/null | wc -l)
DIR_SIZE=$(du -sh "$dir" 2>/dev/null | cut -f1) DIR_SIZE=$(du -sh "$dir" 2>/dev/null | cut -f1)
@@ -320,13 +320,14 @@ jobs:
echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Remediation Steps:**" >> $GITHUB_STEP_SUMMARY echo "**Remediation Steps:**" >> $GITHUB_STEP_SUMMARY
[ ! -d ".mokogit" ] && echo "- Create .mokogit directory: \`mkdir -p .mokogit/workflows\`" >> $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
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $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 "📚 Reference: [MokoStandards Repository Structure](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/core-structure.md)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Required Directories Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: Required Directories Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository structure does not meet MokoCLI requirements" >> $GITHUB_STEP_SUMMARY echo "**Status:** Repository structure does not meet MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "**Missing:** $MISSING required director(y|ies)" >> $GITHUB_STEP_SUMMARY echo "**Missing:** $MISSING required director(y|ies)" >> $GITHUB_STEP_SUMMARY
echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL directories present)" >> $GITHUB_STEP_SUMMARY echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL directories present)" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
@@ -383,17 +384,17 @@ jobs:
echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY echo "### 🔴 Critical Issues: $MISSING" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Remediation Steps:**" >> $GITHUB_STEP_SUMMARY echo "**Remediation Steps:**" >> $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 "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 "LICENSE" ] && echo "- Add LICENSE file: Choose from [OSI-approved licenses](https://opensource.org/licenses)" >> $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/mokocli/tree/main/templates/docs/required/CONTRIBUTING.md)" >> $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/mokocli/tree/main/templates/docs/required/SECURITY.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/mokocli/tree/main/templates/.editorconfig)" >> $GITHUB_STEP_SUMMARY [ ! -f ".editorconfig" ] && echo "- Add .editorconfig: Use [template](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/templates/.editorconfig)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $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 "📚 Reference: [MokoStandards File Requirements](https://github.com/mokoconsulting-tech/MokoStandards/tree/main/docs/policy/file-header-standards.md)" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Required Files Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: Required Files Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository files do not meet MokoCLI requirements" >> $GITHUB_STEP_SUMMARY echo "**Status:** Repository files do not meet MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "**Missing:** $MISSING required file(s)" >> $GITHUB_STEP_SUMMARY echo "**Missing:** $MISSING required file(s)" >> $GITHUB_STEP_SUMMARY
echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL files present)" >> $GITHUB_STEP_SUMMARY echo "**Compliance:** $PERCENT% ($PRESENT/$TOTAL files present)" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
@@ -436,7 +437,7 @@ jobs:
echo "$TABS_IN_SPACES_FILES" >> $GITHUB_STEP_SUMMARY echo "$TABS_IN_SPACES_FILES" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $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 "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 MokoCLI policy" >> $GITHUB_STEP_SUMMARY echo "All other files (including .md, .ps1, LICENSE, etc.) may use tabs per MokoStandards policy" >> $GITHUB_STEP_SUMMARY
else else
echo "✅ No tabs found in files requiring spaces" >> $GITHUB_STEP_SUMMARY 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 echo "Note: Tabs are allowed in most files (policy default). Only checked files requiring spaces." >> $GITHUB_STEP_SUMMARY
@@ -453,7 +454,7 @@ jobs:
! -path "./vendor/*" \ ! -path "./vendor/*" \
! -path "./node_modules/*" \ ! -path "./node_modules/*" \
! -path "./.git/*" \ ! -path "./.git/*" \
-exec file {} \; | grep -v "UTF-8" | grep -v "ASCII" | head -5 || true) -exec file {} \; | grep -v "UTF-8" | grep -v "ASCII" | head -5)
if [ -n "$NON_UTF8" ]; then if [ -n "$NON_UTF8" ]; then
echo "⚠️ Non-UTF-8 files detected:" >> $GITHUB_STEP_SUMMARY echo "⚠️ Non-UTF-8 files detected:" >> $GITHUB_STEP_SUMMARY
@@ -475,14 +476,14 @@ jobs:
! -path "./vendor/*" \ ! -path "./vendor/*" \
! -path "./node_modules/*" \ ! -path "./node_modules/*" \
! -path "./.git/*" \ ! -path "./.git/*" \
-exec file {} \; | grep "CRLF" | head -5 || true) -exec file {} \; | grep "CRLF" | head -5)
if [ -n "$CRLF_FILES" ]; then if [ -n "$CRLF_FILES" ]; then
echo "⚠️ Files with CRLF line endings found:" >> $GITHUB_STEP_SUMMARY echo "⚠️ Files with CRLF line endings found:" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "$CRLF_FILES" >> $GITHUB_STEP_SUMMARY echo "$CRLF_FILES" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "MokoCLI requires LF line endings" >> $GITHUB_STEP_SUMMARY echo "MokoStandards requires LF line endings" >> $GITHUB_STEP_SUMMARY
else else
echo "✅ Line endings are consistent (LF)" >> $GITHUB_STEP_SUMMARY echo "✅ Line endings are consistent (LF)" >> $GITHUB_STEP_SUMMARY
fi fi
@@ -503,13 +504,13 @@ jobs:
tools: composer tools: composer
coverage: none coverage: none
- name: Setup MokoCLI tools - name: Setup MokoStandards tools
env: env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: | run: |
git clone --depth 1 --branch version/04 --quiet \ git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
/tmp/mokostandards 2>/dev/null || true /tmp/mokostandards 2>/dev/null || true
if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then if [ -d "/tmp/mokostandards" ] && [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards cd /tmp/mokostandards
@@ -523,7 +524,7 @@ jobs:
echo "## 🔢 Version Consistency Validation" >> $GITHUB_STEP_SUMMARY echo "## 🔢 Version Consistency Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
# Use MokoCLI tools (no Composer needed on the governed repo) # Use MokoStandards tools (no Composer needed on the governed repo)
if [ -f "/tmp/mokostandards/api/validate/check_version_consistency.php" ]; then 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 php /tmp/mokostandards/api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log
EXIT_CODE=${PIPESTATUS[0]} EXIT_CODE=${PIPESTATUS[0]}
@@ -531,7 +532,7 @@ jobs:
php api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log php api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log
EXIT_CODE=${PIPESTATUS[0]} EXIT_CODE=${PIPESTATUS[0]}
else else
echo "⏭️ MokoCLI tools not available — skipping version check" >> $GITHUB_STEP_SUMMARY echo "⏭️ MokoStandards tools not available — skipping version check" >> $GITHUB_STEP_SUMMARY
exit 0 exit 0
fi fi
@@ -563,17 +564,17 @@ jobs:
set -x set -x
echo "### GitHub Actions Workflows" >> $GITHUB_STEP_SUMMARY echo "### GitHub Actions Workflows" >> $GITHUB_STEP_SUMMARY
WORKFLOWS_DIR=".mokogit/workflows" WORKFLOWS_DIR=".github/workflows"
if [ ! -d "$WORKFLOWS_DIR" ]; then if [ ! -d "$WORKFLOWS_DIR" ]; then
echo "❌ No workflows directory found" >> $GITHUB_STEP_SUMMARY echo "❌ No workflows directory found" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: Workflows Directory Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: Workflows Directory Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** .mokogit/workflows directory is required for CI/CD automation" >> $GITHUB_STEP_SUMMARY echo "**Error:** .github/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 "**Action Required:** Create .github/workflows directory and add GitHub Actions workflows" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "❌ ERROR: .mokogit/workflows directory not found" echo "❌ ERROR: .github/workflows directory not found"
exit 1 exit 1
fi fi
@@ -596,12 +597,12 @@ jobs:
echo "⚠️ CodeQL workflow not found" >> $GITHUB_STEP_SUMMARY echo "⚠️ CodeQL workflow not found" >> $GITHUB_STEP_SUMMARY
fi fi
# Check for MokoCLI-synced workflows # Check for MokoStandards-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 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 if [ -f "$WORKFLOWS_DIR/$wf" ]; then
echo "✅ ${wf}" >> $GITHUB_STEP_SUMMARY echo "✅ ${wf}" >> $GITHUB_STEP_SUMMARY
else else
echo "⚠️ ${wf} not found (synced from MokoCLI)" >> $GITHUB_STEP_SUMMARY echo "⚠️ ${wf} not found (synced from MokoStandards)" >> $GITHUB_STEP_SUMMARY
fi fi
done done
@@ -612,7 +613,7 @@ jobs:
echo "### Workflow YAML Syntax" >> $GITHUB_STEP_SUMMARY echo "### Workflow YAML Syntax" >> $GITHUB_STEP_SUMMARY
INVALID=0 INVALID=0
for workflow in $(find .mokogit/workflows -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" \) 2>/dev/null); do for workflow in $(find .github/workflows -maxdepth 1 -type f \( -name "*.yml" -o -name "*.yaml" \) 2>/dev/null); do
if [ -f "$workflow" ]; then if [ -f "$workflow" ]; then
if python3 -c "import yaml, sys; yaml.safe_load(open(sys.argv[1]))" "$workflow" 2>/dev/null; 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 echo "✅ $(basename $workflow)" >> $GITHUB_STEP_SUMMARY
@@ -629,7 +630,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** $INVALID workflow file(s) have invalid YAML syntax" >> $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 "**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('.mokogit/workflows/FILE.yml'))\"\` locally" >> $GITHUB_STEP_SUMMARY echo "**Tool:** Run \`python3 -c \"import yaml; yaml.safe_load(open('.github/workflows/FILE.yml'))\"\` locally" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "❌ ERROR: $INVALID workflow file(s) with invalid YAML syntax" echo "❌ ERROR: $INVALID workflow file(s) with invalid YAML syntax"
exit 1 exit 1
@@ -641,7 +642,7 @@ jobs:
echo "✅ SUCCESS: All workflow files passed YAML validation" echo "✅ SUCCESS: All workflow files passed YAML validation"
- name: Validate CodeQL Configuration - name: Validate CodeQL Configuration
if: hashFiles('.mokogit/workflows/codeql-analysis.yml') != '' if: hashFiles('.github/workflows/codeql-analysis.yml') != ''
run: | run: |
set -e set -e
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
@@ -649,7 +650,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
# Inline validation (rewritten from Python to bash for PHP-only architecture) # Inline validation (rewritten from Python to bash for PHP-only architecture)
CODEQL_FILE=".mokogit/workflows/codeql-analysis.yml" CODEQL_FILE=".github/workflows/codeql-analysis.yml"
if [ ! -f "$CODEQL_FILE" ]; then if [ ! -f "$CODEQL_FILE" ]; then
echo "⚠️ CodeQL workflow file not found" >> $GITHUB_STEP_SUMMARY echo "⚠️ CodeQL workflow file not found" >> $GITHUB_STEP_SUMMARY
@@ -808,7 +809,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: README.md Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: README.md Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** README.md is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY echo "**Error:** README.md is required for all MokoStandards-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create README.md with project description, setup instructions, and usage examples" >> $GITHUB_STEP_SUMMARY echo "**Action Required:** Create README.md with project description, setup instructions, and usage examples" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "❌ ERROR: README.md not found - This is a critical requirement" echo "❌ ERROR: README.md not found - This is a critical requirement"
@@ -914,7 +915,7 @@ jobs:
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "### ❌ Validation Failed: CHANGELOG.md Missing" >> $GITHUB_STEP_SUMMARY echo "### ❌ Validation Failed: CHANGELOG.md Missing" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Error:** CHANGELOG.md is required for all MokoCLI-compliant repositories" >> $GITHUB_STEP_SUMMARY echo "**Error:** CHANGELOG.md is required for all MokoStandards-compliant repositories" >> $GITHUB_STEP_SUMMARY
echo "**Action Required:** Create CHANGELOG.md following [Keep a Changelog](https://keepachangelog.com/) format" >> $GITHUB_STEP_SUMMARY echo "**Action Required:** Create CHANGELOG.md following [Keep a Changelog](https://keepachangelog.com/) format" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "❌ ERROR: CHANGELOG.md not found - This is a critical requirement" echo "❌ ERROR: CHANGELOG.md not found - This is a critical requirement"
@@ -1182,11 +1183,11 @@ jobs:
# Install yamllint if not present # Install yamllint if not present
: :
else else
pip install yamllint >/dev/null 2>&1 || true pip install yamllint >/dev/null 2>&1
fi fi
# Run yamllint and count line-length warnings # Run yamllint and count line-length warnings
YAML_OUTPUT=$(yamllint .mokogit/workflows/*.yml 2>&1 | grep "line too long" || true) YAML_OUTPUT=$(yamllint .github/workflows/*.yml 2>&1 | grep "line too long" || true)
if [ -n "$YAML_OUTPUT" ]; then if [ -n "$YAML_OUTPUT" ]; then
YAML_VIOLATIONS=$(echo "$YAML_OUTPUT" | wc -l) YAML_VIOLATIONS=$(echo "$YAML_OUTPUT" | wc -l)
echo "⚠️ Found $YAML_VIOLATIONS lines exceeding 180 characters in YAML files" >> $GITHUB_STEP_SUMMARY echo "⚠️ Found $YAML_VIOLATIONS lines exceeding 180 characters in YAML files" >> $GITHUB_STEP_SUMMARY
@@ -1213,7 +1214,7 @@ jobs:
! -path "./.git/*" \ ! -path "./.git/*" \
! -path "./build/*" \ ! -path "./build/*" \
! -path "./dist/*" \ ! -path "./dist/*" \
-exec awk 'length > 120 { print FILENAME ":" NR ": " length " chars" }' {} \; 2>/dev/null | head -20 || true) -exec awk 'length > 120 { print FILENAME ":" NR ": " length " chars" }' {} \; 2>/dev/null | head -20)
if [ -n "$LONG_LINES" ]; then if [ -n "$LONG_LINES" ]; then
LINE_COUNT=$(echo "$LONG_LINES" | wc -l) LINE_COUNT=$(echo "$LONG_LINES" | wc -l)
@@ -1975,10 +1976,10 @@ jobs:
if [ -f "composer.json" ]; then if [ -f "composer.json" ]; then
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
else else
echo "No composer.json — pulling MokoCLI tools" echo "No composer.json — pulling MokoStandards tools"
if [ ! -d "/tmp/mokostandards" ]; then if [ ! -d "/tmp/mokostandards" ]; then
git clone --depth 1 --branch version/04 --quiet \ git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
/tmp/mokostandards 2>/dev/null || true /tmp/mokostandards 2>/dev/null || true
if [ -f "/tmp/mokostandards/composer.json" ]; then if [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
@@ -2047,10 +2048,10 @@ jobs:
if [ -f "composer.json" ]; then if [ -f "composer.json" ]; then
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
else else
echo "No composer.json — pulling MokoCLI tools" echo "No composer.json — pulling MokoStandards tools"
if [ ! -d "/tmp/mokostandards" ]; then if [ ! -d "/tmp/mokostandards" ]; then
git clone --depth 1 --branch version/04 --quiet \ git clone --depth 1 --branch version/04 --quiet \
"https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/mokocli.git" \ "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
/tmp/mokostandards 2>/dev/null || true /tmp/mokostandards 2>/dev/null || true
if [ -f "/tmp/mokostandards/composer.json" ]; then if [ -f "/tmp/mokostandards/composer.json" ]; then
cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true cd /tmp/mokostandards && composer install --no-dev --no-interaction --quiet 2>/dev/null || true
@@ -2130,17 +2131,17 @@ jobs:
WARNINGS=0 WARNINGS=0
ERRORS=0 ERRORS=0
# 1. Check .mokogit/config.tf location (not root override files) # 1. Check .github/config.tf location (not root override files)
echo "### Override Configuration Check" >> $GITHUB_STEP_SUMMARY echo "### Override Configuration Check" >> $GITHUB_STEP_SUMMARY
LEGACY_OVERRIDES=$(find . -maxdepth 1 -name "*override*.tf" -o -name "MokoCLI.override.tf" 2>/dev/null | wc -l || echo 0) LEGACY_OVERRIDES=$(find . -maxdepth 1 -name "*override*.tf" -o -name "MokoStandards.override.tf" 2>/dev/null | wc -l || echo 0)
if [ "$LEGACY_OVERRIDES" -gt 0 ]; then if [ "$LEGACY_OVERRIDES" -gt 0 ]; then
echo "⚠️ Found legacy override files in root directory" >> $GITHUB_STEP_SUMMARY echo "⚠️ Found legacy override files in root directory" >> $GITHUB_STEP_SUMMARY
echo "**Expected Location**: .mokogit/config.tf" >> $GITHUB_STEP_SUMMARY echo "**Expected Location**: .github/config.tf" >> $GITHUB_STEP_SUMMARY
echo "**Legacy files found**: $LEGACY_OVERRIDES" >> $GITHUB_STEP_SUMMARY echo "**Legacy files found**: $LEGACY_OVERRIDES" >> $GITHUB_STEP_SUMMARY
WARNINGS=$((WARNINGS + 1)) WARNINGS=$((WARNINGS + 1))
else else
if [ -f ".mokogit/config.tf" ]; then if [ -f ".github/config.tf" ]; then
echo "✅ Override configuration in correct location (.mokogit/config.tf)" >> $GITHUB_STEP_SUMMARY echo "✅ Override configuration in correct location (.github/config.tf)" >> $GITHUB_STEP_SUMMARY
else else
echo "️ No override configuration found" >> $GITHUB_STEP_SUMMARY echo "️ No override configuration found" >> $GITHUB_STEP_SUMMARY
fi fi
@@ -2298,7 +2299,7 @@ jobs:
- name: Generate Compliance Report - name: Generate Compliance Report
run: | run: |
set -x set -x
echo "# 📊 MokoCLI Compliance Report" >> $GITHUB_STEP_SUMMARY echo "# 📊 MokoStandards Compliance Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
# Calculate overall status # Calculate overall status
@@ -2485,7 +2486,7 @@ jobs:
else else
echo "## 🎉 Excellent!" >> $GITHUB_STEP_SUMMARY echo "## 🎉 Excellent!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "Your repository is **fully compliant** with MokoCLI!" >> $GITHUB_STEP_SUMMARY echo "Your repository is **fully compliant** with MokoStandards!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Achievements:**" >> $GITHUB_STEP_SUMMARY echo "**Achievements:**" >> $GITHUB_STEP_SUMMARY
echo "- ✅ All required directories and files present" >> $GITHUB_STEP_SUMMARY echo "- ✅ All required directories and files present" >> $GITHUB_STEP_SUMMARY
@@ -2500,12 +2501,12 @@ jobs:
echo "---" >> $GITHUB_STEP_SUMMARY echo "---" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "📚 **Resources:**" >> $GITHUB_STEP_SUMMARY echo "📚 **Resources:**" >> $GITHUB_STEP_SUMMARY
echo "- [MokoCLI Documentation](https://github.com/mokoconsulting-tech/mokocli)" >> $GITHUB_STEP_SUMMARY echo "- [MokoStandards Documentation](https://github.com/mokoconsulting-tech/MokoStandards)" >> $GITHUB_STEP_SUMMARY
echo "- [Repository Structure Guide](https://github.com/mokoconsulting-tech/mokocli/tree/main/docs/policy/core-structure.md)" >> $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/mokocli/tree/main/docs/policy/document-formatting.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/mokocli/tree/main/docs/policy/coding-style-guide.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 "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "_Generated by MokoCLI Compliance Workflow v${WORKFLOW_VERSION}_" >> $GITHUB_STEP_SUMMARY echo "_Generated by MokoStandards Compliance Workflow v${WORKFLOW_VERSION}_" >> $GITHUB_STEP_SUMMARY
# Create tracking issue for non-compliance if on push # Create tracking issue for non-compliance if on push
if [ "$COMPLIANCE_PERCENT" -lt 100 ] && [ "${{ github.event_name }}" = "push" ]; then if [ "$COMPLIANCE_PERCENT" -lt 100 ] && [ "${{ github.event_name }}" = "push" ]; then
@@ -2529,9 +2530,9 @@ jobs:
echo "### ✅ Full Standards Compliance Achieved" >> $GITHUB_STEP_SUMMARY echo "### ✅ Full Standards Compliance Achieved" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY
echo "**Overall Compliance:** 100%" >> $GITHUB_STEP_SUMMARY echo "**Overall Compliance:** 100%" >> $GITHUB_STEP_SUMMARY
echo "**Status:** Repository meets all MokoCLI requirements" >> $GITHUB_STEP_SUMMARY echo "**Status:** Repository meets all MokoStandards requirements" >> $GITHUB_STEP_SUMMARY
echo "" echo ""
echo "✅ SUCCESS: Repository is fully MokoCLI compliant" echo "✅ SUCCESS: Repository is fully MokoStandards compliant"
- name: Create or reopen tracking issue for standards violations - name: Create or reopen tracking issue for standards violations
if: failure() if: failure()
@@ -11,7 +11,7 @@
# PATH: /templates/workflows/shared/sync-version-on-merge.yml.template # PATH: /templates/workflows/shared/sync-version-on-merge.yml.template
# VERSION: 04.06.00 # VERSION: 04.06.00
# BRIEF: Auto-bump patch version on every push to main and propagate to all file headers # BRIEF: Auto-bump patch version on every push to main and propagate to all file headers
# NOTE: Synced via bulk-repo-sync to .mokogit/workflows/sync-version-on-merge.yml in all governed repos. # NOTE: Synced via bulk-repo-sync to .mokogitea/workflows/sync-version-on-merge.yml in all governed repos.
# README.md is the single source of truth for the repository version. # README.md is the single source of truth for the repository version.
name: "Universal: Sync Version on Merge" name: "Universal: Sync Version on Merge"
@@ -47,19 +47,22 @@ jobs:
token: ${{ secrets.GH_TOKEN || github.token }} token: ${{ secrets.GH_TOKEN || github.token }}
fetch-depth: 0 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 - name: Setup MokoStandards tools
env:
GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }}
COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}'
run: | run: |
# Use pre-installed mokoplatform on runner host (symlink /opt/mokoplatform -> /opt/moko-platform) git clone --depth 1 --branch version/04 --quiet \
if [ -d /opt/mokoplatform/api/cli ] && [ -f /opt/mokoplatform/vendor/autoload.php ]; then "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \
ln -sf /opt/mokoplatform /tmp/mokostandards /tmp/mokostandards
echo "Using pre-installed /opt/mokoplatform" cd /tmp/mokostandards
elif [ -d /opt/moko-platform/api/cli ]; then composer install --no-dev --no-interaction --quiet
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 - name: Auto-bump patch version
if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }} if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }}
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow.Template # DEFGROUP: Gitea.Workflow.Template
# INGROUP: MokoCLI.CI # INGROUP: MokoStandards.CI
# REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla # REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-Joomla
# PATH: /.mokogit/workflows/version-set.yml # PATH: /.mokogitea/workflows/version-set.yml
# VERSION: 01.00.00 # VERSION: 01.00.00
# BRIEF: Set or reset the extension version across all version-bearing files # BRIEF: Set or reset the extension version across all version-bearing files
@@ -48,7 +48,7 @@ jobs:
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
with: with:
token: ${{ secrets.MOKOGIT_TOKEN || github.token }} token: ${{ secrets.MOKOGITEA_TOKEN || github.token }}
ref: ${{ inputs.branch || github.ref }} ref: ${{ inputs.branch || github.ref }}
fetch-depth: 1 fetch-depth: 1
@@ -3,10 +3,10 @@
# SPDX-License-Identifier: GPL-3.0-or-later # SPDX-License-Identifier: GPL-3.0-or-later
# #
# FILE INFORMATION # FILE INFORMATION
# DEFGROUP: MokoGIT.Workflow # DEFGROUP: Gitea.Workflow
# INGROUP: MokoCLI.Universal # INGROUP: mokocli.Universal
# REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli # REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli
# PATH: /.mokogit/workflows/workflow-sync-trigger.yml # PATH: /.mokogitea/workflows/workflow-sync-trigger.yml
# VERSION: 01.01.00 # VERSION: 01.01.00
# BRIEF: Trigger workflow sync to live repos when a PR is merged to main # BRIEF: Trigger workflow sync to live repos when a PR is merged to main
@@ -27,10 +27,9 @@ jobs:
name: Sync workflows to live repos name: Sync workflows to live repos
runs-on: ubuntu-latest runs-on: ubuntu-latest
if: >- if: >-
startsWith(github.event.repository.name, 'Template-') && github.event_name == 'workflow_dispatch' ||
(github.event_name == 'workflow_dispatch' ||
(github.event.pull_request.merged == true && (github.event.pull_request.merged == true &&
!contains(github.event.pull_request.title, '[skip sync]'))) !contains(github.event.pull_request.title, '[skip sync]'))
steps: steps:
- name: Determine platform from repo name - name: Determine platform from repo name
@@ -41,19 +40,19 @@ jobs:
Template-Joomla) PLATFORM="joomla" ;; Template-Joomla) PLATFORM="joomla" ;;
Template-Dolibarr) PLATFORM="dolibarr" ;; Template-Dolibarr) PLATFORM="dolibarr" ;;
Template-Go) PLATFORM="go" ;; Template-Go) PLATFORM="go" ;;
Template-NPM) PLATFORM="npm" ;; Template-MCP) PLATFORM="mcp" ;;
Template-Generic) PLATFORM="" ;; Template-Generic) PLATFORM="" ;;
*) PLATFORM="" ;; *) PLATFORM="" ;;
esac esac
echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT" echo "platform=$PLATFORM" >> "$GITHUB_OUTPUT"
echo "Platform: ${PLATFORM:-all}" echo "Platform: ${PLATFORM:-all}"
- name: Clone MokoCLI - name: Clone mokocli
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
MOKOGIT_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}" MOKOGITEA_URL="${{ vars.GITEA_URL || 'https://git.mokoconsulting.tech' }}"
git clone --depth 1 "${MOKOGIT_URL}/MokoConsulting/mokocli.git" /tmp/mokocli git clone --depth 1 "${MOKOGITEA_URL}/MokoConsulting/mokocli.git" /tmp/mokocli
- name: Install PHP - name: Install PHP
run: | run: |
@@ -68,12 +67,11 @@ jobs:
- name: Run workflow sync - name: Run workflow sync
env: env:
MOKOGIT_TOKEN: ${{ secrets.MOKOGIT_TOKEN }} MOKOGITEA_TOKEN: ${{ secrets.MOKOGITEA_TOKEN }}
run: | run: |
ARGS="--token ${MOKOGIT_TOKEN}" ARGS="--token ${MOKOGITEA_TOKEN}"
ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}" ARGS="${ARGS} --org ${{ vars.GITEA_ORG || github.repository_owner }}"
ARGS="${ARGS} --phase repos" ARGS="${ARGS} --phase repos"
ARGS="${ARGS} --delete-orphans"
PLATFORM="${{ steps.platform.outputs.platform }}" PLATFORM="${{ steps.platform.outputs.platform }}"
if [ -n "$PLATFORM" ]; then if [ -n "$PLATFORM" ]; then
+2 -9
View File
@@ -3,16 +3,9 @@
## [Unreleased] ## [Unreleased]
### Changed ### Changed
- 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. - Migrated all workflow and template paths from `.github/` to `.mokogitea/`
- Template source paths updated: `templates/gitea/` to `templates/mokogitea/`
### 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 - HCL definition files removed -- Template repos are now the canonical source
### Added ### 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 - `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 ## Project Overview
**Template-NPM** -- Template repository for creating MokoCLI-compliant MCP API servers **Template-MCP** -- Template repository for creating MokoStandards-compliant MCP API servers
| Field | Value | | Field | Value |
|---|---| |---|---|
@@ -12,8 +12,8 @@ This file provides guidance to Claude Code when working with this repository.
| **Language** | TypeScript | | **Language** | TypeScript |
| **Default branch** | main | | **Default branch** | main |
| **License** | GPL-3.0-or-later | | **License** | GPL-3.0-or-later |
| **Wiki** | [Template-NPM Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki) | | **Wiki** | [Template-MCP Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki) |
| **Standards** | [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home) | | **Standards** | [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home) |
## Common Commands ## Common Commands
@@ -42,11 +42,11 @@ This is an MCP (Model Context Protocol) server. Key files:
## Rules ## Rules
- **Workflow directory**: `.mokogit/` (not `.gitea/` or `.github/`) - **Workflow directory**: `.mokogitea/` (not `.gitea/` or `.github/`)
- **Never commit** `.claude/`, `.mcp.json`, `TODO.md`, or `*.min.css`/`*.min.js` - **Never commit** `.claude/`, `.mcp.json`, `TODO.md`, or `*.min.css`/`*.min.js`
- **Attribution**: use `Authored-by: Moko Consulting` in commits - **Attribution**: use `Authored-by: Moko Consulting` in commits
- **Branch strategy**: develop on `dev`, merge to `main` for release - **Branch strategy**: develop on `dev`, merge to `main` for release
- **Minification**: handled at build time (CI) and runtime (MokoMinifyHelper for Joomla templates) - **Minification**: handled at build time (CI) and runtime (MokoMinifyHelper for Joomla templates)
- **Wiki**: documentation lives in the MokoGIT wiki, not in `docs/` files - **Wiki**: documentation lives in the Gitea wiki, not in `docs/` files
- **Standards**: this repo follows [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home) - **Standards**: this repo follows [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/wiki/Home)
+1 -1
View File
@@ -13,7 +13,7 @@
# FILE INFORMATION # FILE INFORMATION
DEFGROUP: DEFGROUP:
INGROUP: Project.Documentation INGROUP: Project.Documentation
REPO: MokoConsulting/Template-NPM REPO: mokoconsulting-tech/MokoStandards-Template-Generic
VERSION: 00.00.01 VERSION: 00.00.01
PATH: ./CODE_OF_CONDUCT.md PATH: ./CODE_OF_CONDUCT.md
BRIEF: Contributor Covenant Code of Conduct version 1.3.0 BRIEF: Contributor Covenant Code of Conduct version 1.3.0
+5 -5
View File
@@ -13,13 +13,13 @@
# FILE INFORMATION # FILE INFORMATION
DEFGROUP: DEFGROUP:
INGROUP: Project.Documentation INGROUP: Project.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/Template-NPM REPO: https://git.mokoconsulting.tech/MokoConsulting/MokoStandards-Template-Generic
VERSION: 00.00.01 VERSION: 00.00.01
PATH: ./CONTRIBUTING.md PATH: ./CONTRIBUTING.md
BRIEF: Contribution guidelines for the project BRIEF: Contribution guidelines for the project
--> -->
# Contributing to Template-NPM # Contributing to MokoStandards-Template-Generic
We appreciate your interest in contributing to this project! This document provides guidelines for contributing. 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 ### CI/CD
- MokoGIT Actions runs all CI workflows - Gitea Actions runs all CI workflows
- GitHub Actions are disabled on mirrored repos - GitHub Actions are disabled on mirrored repos
- Workflows live in both `.github/workflows/` and `.mokogit/workflows/` - Workflows live in both `.github/workflows/` and `.gitea/workflows/`
### Update Servers (Joomla) ### Update Servers (Joomla)
In manifest `<updateservers>`, MokoGIT must be priority 1, GitHub priority 2. In manifest `<updateservers>`, Gitea must be priority 1, GitHub priority 2.
### Secrets ### Secrets
+3 -3
View File
@@ -11,9 +11,9 @@
You should have received a copy of the GNU General Public License (./LICENSE). You should have received a copy of the GNU General Public License (./LICENSE).
# FILE INFORMATION # FILE INFORMATION
DEFGROUP: MokoCLI DEFGROUP: MokoStandards
INGROUP: MokoCLI.Documentation INGROUP: MokoStandards.Documentation
REPO: https://git.mokoconsulting.tech/MokoConsulting/mokocli/ REPO: https://git.mokoconsulting.tech/mokoconsulting-tech/MokoStandards/
VERSION: 05.00.00 VERSION: 05.00.00
PATH: ./LICENSE PATH: ./LICENSE
BRIEF: Project license (GPL-3.0-or-later) BRIEF: Project license (GPL-3.0-or-later)
+1 -1
View File
@@ -23,7 +23,7 @@ install-deps: ## Install dependencies
@$(NPM) install @$(NPM) install
@echo "$(COLOR_GREEN)✓ Dependencies installed$(COLOR_RESET)" @echo "$(COLOR_GREEN)✓ Dependencies installed$(COLOR_RESET)"
MOKO_PLATFORM ?= $(or $(wildcard ../mokocli),$(wildcard $(HOME)/mokocli),$(wildcard /opt/mokocli)) MOKO_PLATFORM ?= $(or $(wildcard ../moko-platform),$(wildcard $(HOME)/moko-platform),$(wildcard /opt/moko-platform))
MINIFY_SCRIPT := $(MOKO_PLATFORM)/build/minify.js MINIFY_SCRIPT := $(MOKO_PLATFORM)/build/minify.js
.PHONY: minify .PHONY: minify
+10 -14
View File
@@ -1,8 +1,8 @@
# Template-NPM # Template-MCP
![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) ![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)
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. 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.
## Features ## Features
@@ -11,7 +11,7 @@ Template repository for creating MokoCLI-compliant Model Context Protocol (MCP)
- **REST API bridge architecture** -- standardized pattern for bridging any REST API as MCP tools, with typed request/response handling - **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 - **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 - **Build tooling** -- Makefile with `build`, `dev`, `clean`, and `lint` targets; npm scripts for compilation and development
- **MokoCLI compliant** -- follows all Moko Consulting governance conventions: file headers, commit messages, `.gitattributes`, `.gitmessage`, PR/issue templates - **MokoStandards 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 - **Example configuration** -- `config.example.json` demonstrates the connection configuration schema
- **Documentation templates** -- wiki pages for API reference, architecture overview, and installation pre-generated - **Documentation templates** -- wiki pages for API reference, architecture overview, and installation pre-generated
@@ -19,7 +19,7 @@ Template repository for creating MokoCLI-compliant Model Context Protocol (MCP)
1. Create a new repository from this template (or clone directly): 1. Create a new repository from this template (or clone directly):
```bash ```bash
git clone https://git.mokoconsulting.tech/MokoConsulting/Template-NPM.git my-mcp-server git clone https://git.mokoconsulting.tech/MokoConsulting/Template-MCP.git my-mcp-server
cd my-mcp-server cd my-mcp-server
``` ```
2. Install dependencies: 2. Install dependencies:
@@ -61,11 +61,11 @@ Template repository for creating MokoCLI-compliant Model Context Protocol (MCP)
## Documentation ## Documentation
Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki), including: Full documentation is available on the [Wiki](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki), including:
- [API](https://git.mokoconsulting.tech/MokoConsulting/Template-NPM/wiki/API) -- tool reference and connection parameter documentation - [API](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/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 - [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-NPM/wiki/INSTALLATION) -- setup prerequisites and configuration guide - [INSTALLATION](https://git.mokoconsulting.tech/MokoConsulting/Template-MCP/wiki/INSTALLATION) -- setup prerequisites and configuration guide
## Contributing ## Contributing
@@ -77,8 +77,4 @@ This project is licensed under the GNU General Public License v3.0 or later -- s
--- ---
*[Moko Consulting](https://mokoconsulting.tech) -- [MokoCLI](https://git.mokoconsulting.tech/MokoConsulting/mokocli/wiki/Home)* *[Moko Consulting](https://mokoconsulting.tech) -- [MokoStandards](https://git.mokoconsulting.tech/MokoConsulting/moko-platform/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
@@ -0,0 +1,237 @@
#!/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