diff --git a/.github/CLAUDE.md b/.github/CLAUDE.md index e991394..4e7b705 100644 --- a/.github/CLAUDE.md +++ b/.github/CLAUDE.md @@ -122,13 +122,13 @@ BRIEF: One-line description ### Joomla Version Alignment -The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. +The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `updates.xml`. The `make release` command / release workflow updates all three automatically. ```xml 01.02.04 - @@ -154,7 +154,7 @@ The version in `README.md` **must always match** the `` tag in `manifes ``` MokoCassiopeia/ ├── manifest.xml # Joomla installer manifest (root — required) -├── update.xml # Update server manifest (root — required, see below) +├── updates.xml # Update server manifest (root — required, see below) ├── site/ # Frontend (site) code │ ├── controller.php │ ├── controllers/ @@ -183,22 +183,22 @@ MokoCassiopeia/ --- -## update.xml — Required in Repo Root +## updates.xml — Required in Repo Root -`update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. +`updates.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. The `manifest.xml` must reference it via: ```xml - https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/update.xml + https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/updates.xml ``` **Rules:** -- Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. -- The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. +- Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below. +- The `` in `updates.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. @@ -207,8 +207,8 @@ The `manifest.xml` must reference it via: ## manifest.xml Rules - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). -- `` tag must be kept in sync with `README.md` version and `update.xml`. -- Must include `` block pointing to this repo's `update.xml`. +- `` tag must be kept in sync with `README.md` version and `updates.xml`. +- Must include `` block pointing to this repo's `updates.xml`. - Must include `` and `` sections. - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. @@ -286,8 +286,8 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d | Change type | Documentation to update | |-------------|------------------------| | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | -| New or changed manifest.xml | Update `update.xml` version; bump README.md version | -| New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | +| New or changed manifest.xml | Update `updates.xml` version; bump README.md version | +| New release | Prepend `` block to `updates.xml`; update CHANGELOG.md; bump README.md version | | New or changed workflow | `docs/workflows/.md` | | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | @@ -301,4 +301,4 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files - Never hardcode version numbers in body text — update `README.md` and let automation propagate - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` -- Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync +- Never let `manifest.xml` version, `updates.xml` version, and `README.md` version go out of sync diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 93f049a..c70eb15 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -8,8 +8,26 @@ # Combined with branch protection (require PR reviews), this prevents # unauthorized modifications to workflows, configs, and governance files. -# ── Workflows (synced from MokoStandards — must not be manually edited) ── -/.github/workflows/ @jmiller-moko +# ── Synced workflows (managed by MokoStandards — do not edit manually) ──── +/.github/workflows/deploy-dev.yml @jmiller-moko +/.github/workflows/deploy-demo.yml @jmiller-moko +/.github/workflows/deploy-rs.yml @jmiller-moko +/.github/workflows/auto-release.yml @jmiller-moko +/.github/workflows/auto-dev-issue.yml @jmiller-moko +/.github/workflows/auto-assign.yml @jmiller-moko +/.github/workflows/sync-version-on-merge.yml @jmiller-moko +/.github/workflows/enterprise-firewall-setup.yml @jmiller-moko +/.github/workflows/repository-cleanup.yml @jmiller-moko +/.github/workflows/standards-compliance.yml @jmiller-moko +/.github/workflows/codeql-analysis.yml @jmiller-moko +/.github/workflows/repo_health.yml @jmiller-moko +/.github/workflows/ci-joomla.yml @jmiller-moko +/.github/workflows/update-server.yml @jmiller-moko +/.github/workflows/deploy-manual.yml @jmiller-moko +/.github/workflows/ci-dolibarr.yml @jmiller-moko +/.github/workflows/publish-to-mokodolimods.yml @jmiller-moko +/.github/workflows/changelog-validation.yml @jmiller-moko +# Custom workflows in .github/workflows/ not listed above are repo-owned. # ── GitHub configuration ───────────────────────────────────────────────── /.github/ISSUE_TEMPLATE/ @jmiller-moko @@ -23,7 +41,7 @@ /composer.json @jmiller-moko /phpstan.neon @jmiller-moko /Makefile @jmiller-moko -/.ftp_ignore @jmiller-moko +/.ftpignore @jmiller-moko /.gitignore @jmiller-moko /.gitattributes @jmiller-moko /.editorconfig @jmiller-moko diff --git a/.github/ISSUE_TEMPLATE/firewall-request.md b/.github/ISSUE_TEMPLATE/firewall-request.md index 38be866..4a43395 100644 --- a/.github/ISSUE_TEMPLATE/firewall-request.md +++ b/.github/ISSUE_TEMPLATE/firewall-request.md @@ -3,7 +3,7 @@ name: Firewall Request about: Request firewall rule changes or access to external resources title: '[FIREWALL] [Resource Name] - [Brief Description]' labels: ['firewall-request', 'infrastructure', 'security'] -assignees: ['jmiller-moko'] +assignees: [] --- diff --git a/.github/ISSUE_TEMPLATE/question.md b/.github/ISSUE_TEMPLATE/question.md index 74df7a0..e17850b 100644 --- a/.github/ISSUE_TEMPLATE/question.md +++ b/.github/ISSUE_TEMPLATE/question.md @@ -3,7 +3,7 @@ name: Question about: Ask a question about usage, features, or best practices title: '[QUESTION] ' labels: ['question'] -assignees: ['jmiller-moko'] +assignees: [] --- diff --git a/.github/ISSUE_TEMPLATE/request-license.md b/.github/ISSUE_TEMPLATE/request-license.md index a9c87a7..52c3b74 100644 --- a/.github/ISSUE_TEMPLATE/request-license.md +++ b/.github/ISSUE_TEMPLATE/request-license.md @@ -3,7 +3,7 @@ name: License Request about: Request an organization license for Sublime Text title: '[LICENSE REQUEST] Sublime Text - [Your Name]' labels: ['license-request', 'admin'] -assignees: ['jmiller-moko'] +assignees: [] --- diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index e991394..4e7b705 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -122,13 +122,13 @@ BRIEF: One-line description ### Joomla Version Alignment -The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `update.xml`. The `make release` command / release workflow updates all three automatically. +The version in `README.md` **must always match** the `` tag in `manifest.xml` and the latest entry in `updates.xml`. The `make release` command / release workflow updates all three automatically. ```xml 01.02.04 - @@ -154,7 +154,7 @@ The version in `README.md` **must always match** the `` tag in `manifes ``` MokoCassiopeia/ ├── manifest.xml # Joomla installer manifest (root — required) -├── update.xml # Update server manifest (root — required, see below) +├── updates.xml # Update server manifest (root — required, see below) ├── site/ # Frontend (site) code │ ├── controller.php │ ├── controllers/ @@ -183,22 +183,22 @@ MokoCassiopeia/ --- -## update.xml — Required in Repo Root +## updates.xml — Required in Repo Root -`update.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. +`updates.xml` **must exist at the repository root**. It is the Joomla update server manifest that allows Joomla installations to check for new versions of this extension. The `manifest.xml` must reference it via: ```xml - https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/update.xml + https://github.com/mokoconsulting-tech/MokoCassiopeia/raw/main/updates.xml ``` **Rules:** -- Every release must prepend a new `` block at the top of `update.xml` — old entries must be preserved below. -- The `` in `update.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. +- Every release must prepend a new `` block at the top of `updates.xml` — old entries must be preserved below. +- The `` in `updates.xml` must exactly match `` in `manifest.xml` and the version in `README.md`. - The `` must be a publicly accessible direct download link (GitHub Releases asset URL). - `` — the backslash is a **literal backslash character** in the XML attribute value; Joomla's update-server parser treats the value as a regular expression, so `\.` matches a literal dot and `[0-9]+` matches one or more digits. Do not double-escape it. @@ -207,8 +207,8 @@ The `manifest.xml` must reference it via: ## manifest.xml Rules - Lives at the repo root as `manifest.xml` (not inside `site/` or `admin/`). -- `` tag must be kept in sync with `README.md` version and `update.xml`. -- Must include `` block pointing to this repo's `update.xml`. +- `` tag must be kept in sync with `README.md` version and `updates.xml`. +- Must include `` block pointing to this repo's `updates.xml`. - Must include `` and `` sections. - Joomla 4.x requires `Moko\{{EXTENSION_NAME}}` for namespaced extensions. @@ -286,8 +286,8 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d | Change type | Documentation to update | |-------------|------------------------| | New or renamed PHP class/method | PHPDoc block; `docs/api/` entry | -| New or changed manifest.xml | Update `update.xml` version; bump README.md version | -| New release | Prepend `` block to `update.xml`; update CHANGELOG.md; bump README.md version | +| New or changed manifest.xml | Update `updates.xml` version; bump README.md version | +| New release | Prepend `` block to `updates.xml`; update CHANGELOG.md; bump README.md version | | New or changed workflow | `docs/workflows/.md` | | Any modified file | Update the `VERSION` field in that file's `FILE INFORMATION` block | | **Every PR** | **Bump the patch version** — increment `XX.YY.ZZ` in `README.md`; `sync-version-on-merge` propagates it | @@ -301,4 +301,4 @@ Approved prefixes: `dev/` · `rc/` · `version/` · `patch/` · `copilot/` · `d - Never add `defined('_JEXEC') or die;` to CLI scripts or model tests — only to web-accessible PHP files - Never hardcode version numbers in body text — update `README.md` and let automation propagate - Never use `github.token` or `secrets.GITHUB_TOKEN` in workflows — always use `secrets.GH_TOKEN` -- Never let `manifest.xml` version, `update.xml` version, and `README.md` version go out of sync +- Never let `manifest.xml` version, `updates.xml` version, and `README.md` version go out of sync diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b94720f..667ae72 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -5,7 +5,7 @@ # INGROUP: MokoStandards.Security # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /.github/dependabot.yml -# VERSION: 01.00.00 +# VERSION: 03.09.03 # BRIEF: Dependabot configuration for automated dependency updates and security patches # NOTE: Monitors GitHub Actions for vulnerabilities and keeps ecosystem secure diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 22a7107..e5d4c49 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -477,7 +477,7 @@ jobs: [ ! -d "$SOURCE_DIR" ] && { echo "No src/ or htdocs/ — skipping package"; exit 0; } cd "$SOURCE_DIR" - zip -r "/tmp/${PACKAGE_NAME}" . + zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore' cd .. FILESIZE=$(stat -c%s "/tmp/${PACKAGE_NAME}" 2>/dev/null || stat -f%z "/tmp/${PACKAGE_NAME}" 2>/dev/null || echo "unknown") diff --git a/.github/workflows/update-server.yml b/.github/workflows/update-server.yml index fff9ec6..f0830c2 100644 --- a/.github/workflows/update-server.yml +++ b/.github/workflows/update-server.yml @@ -79,6 +79,20 @@ jobs: REPO="${{ github.repository }}" VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "0.0.0") + # Auto-bump patch on alpha/beta/rc branches (not dev — dev bumps manually) + if [[ "$BRANCH" != dev/* ]]; then + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + BUMPED=$(php /tmp/mokostandards/api/cli/version_bump.php --path . 2>/dev/null || true) + if [ -n "$BUMPED" ]; then + VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null || echo "$VERSION") + git add -A + git commit -m "chore(version): auto-bump patch ${VERSION} [skip ci]" \ + --author="github-actions[bot] " 2>/dev/null || true + git push 2>/dev/null || true + fi + fi + # Determine stability from branch or input if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then STABILITY="${{ inputs.stability }}" @@ -151,7 +165,7 @@ jobs: [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" if [ -d "$SOURCE_DIR" ]; then cd "$SOURCE_DIR" - zip -r "/tmp/${PACKAGE_NAME}" . + zip -r "/tmp/${PACKAGE_NAME}" . -x '.ftpignore' cd .. SHA256=$(sha256sum "/tmp/${PACKAGE_NAME}" | cut -d' ' -f1) @@ -239,6 +253,64 @@ jobs: git push } + - name: SFTP deploy to dev server + if: contains(github.ref, 'dev/') + env: + DEV_HOST: ${{ vars.DEV_FTP_HOST }} + DEV_PATH: ${{ vars.DEV_FTP_PATH }} + DEV_SUFFIX: ${{ vars.DEV_FTP_SUFFIX }} + DEV_USER: ${{ vars.DEV_FTP_USERNAME }} + DEV_PORT: ${{ vars.DEV_FTP_PORT }} + DEV_KEY: ${{ secrets.DEV_FTP_KEY }} + DEV_PASS: ${{ secrets.DEV_FTP_PASSWORD }} + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + # ── Permission check: admin or maintain role required ────── + ACTOR="${{ github.actor }}" + REPO="${{ github.repository }}" + PERMISSION=$(gh api "repos/${REPO}/collaborators/${ACTOR}/permission" \ + --jq '.permission' 2>/dev/null || \ + gh api "repos/${REPO}/collaborators/${ACTOR}" \ + --jq '.role' 2>/dev/null || echo "read") + case "$PERMISSION" in + admin|maintain|write) ;; + *) + echo "Deploy denied: ${ACTOR} has '${PERMISSION}' — requires admin, maintain, or write" + exit 0 + ;; + esac + + [ -z "$DEV_HOST" ] || [ -z "$DEV_PATH" ] && { echo "DEV FTP not configured — skipping SFTP"; exit 0; } + + SOURCE_DIR="src" + [ ! -d "$SOURCE_DIR" ] && SOURCE_DIR="htdocs" + [ ! -d "$SOURCE_DIR" ] && exit 0 + + PORT="${DEV_PORT:-22}" + REMOTE="${DEV_PATH%/}" + [ -n "$DEV_SUFFIX" ] && REMOTE="${REMOTE}/${DEV_SUFFIX#/}" + + printf '{"host":"%s","port":%s,"username":"%s","remotePath":"%s"' \ + "$DEV_HOST" "$PORT" "$DEV_USER" "$REMOTE" > /tmp/sftp-config.json + if [ -n "$DEV_KEY" ]; then + echo "$DEV_KEY" > /tmp/deploy_key && chmod 600 /tmp/deploy_key + printf ',"privateKeyPath":"/tmp/deploy_key"}' >> /tmp/sftp-config.json + else + printf ',"password":"%s"}' "$DEV_PASS" >> /tmp/sftp-config.json + fi + + PLATFORM=$(php /tmp/mokostandards/api/cli/platform_detect.php --path . 2>/dev/null || true) + if [ "$PLATFORM" = "waas-component" ] && [ -f "/tmp/mokostandards/api/deploy/deploy-joomla.php" ]; then + php /tmp/mokostandards/api/deploy/deploy-joomla.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json + elif [ -f "/tmp/mokostandards/api/deploy/deploy-sftp.php" ]; then + php /tmp/mokostandards/api/deploy/deploy-sftp.php --path . --src-dir "$SOURCE_DIR" --config /tmp/sftp-config.json + fi + rm -f /tmp/deploy_key /tmp/sftp-config.json + echo "SFTP deploy to dev complete" >> $GITHUB_STEP_SUMMARY + + - name: Summary + if: always() + run: | echo "## Joomla Update Server" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY