From 9f901261f7fdf5448894801d9b941b65cb1f0346 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:36 -0500 Subject: [PATCH 01/38] chore: update LICENSE from MokoStandards -- 2.49.1 From 38772948d037f5941dc378356608856a433688fe Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:37 -0500 Subject: [PATCH 02/38] chore: update SECURITY.md from MokoStandards --- SECURITY.md | 287 +++++++++++++++++++++++++++++++--------------------- 1 file changed, 171 insertions(+), 116 deletions(-) diff --git a/SECURITY.md b/SECURITY.md index 9c2b528..e069ce6 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,185 +1,240 @@ -## Security Policy +# Security Policy -This document defines how MokoCassiopeia handles vulnerability intake, triage, remediation, and disclosure. The objective is to reduce risk, protect downstream users, and preserve operational continuity with a verifiable audit trail. +## Purpose and Scope -## Scope - -This policy applies to: - -* Repository source code, workflows, scripts, and build artifacts. -* Release packaging (ZIP outputs) generated from the repository. -* Configuration and metadata used for distribution (for example manifests and update metadata). - -Out of scope: - -* Vulnerabilities in upstream Joomla core, third party extensions, or external infrastructure not controlled by this repository. -* Issues that require physical access to a host, compromised administrator credentials, or a compromised hosting provider, unless the repository materially increases impact. +This document defines the security vulnerability reporting, response, and disclosure policy for [PROJECT_NAME] and all repositories governed by these standards. It establishes the authoritative process for responsible disclosure, assessment, remediation, and communication of security issues. ## Supported Versions -Security fixes are prioritized for: +Security updates are provided for the following versions: -* The latest released version. -* The current development line when it is actively used for release engineering. +| Version | Supported | +| ------- | ------------------ | +| [X.x.x] | :white_check_mark: | +| < [X.0] | :x: | -Backports may be provided based on impact, deployment footprint, and engineering capacity. +Only the current major version receives security updates. Users should upgrade to the latest supported version to receive security patches. ## Reporting a Vulnerability -Use one of the following channels: +### Where to Report -* GitHub Security Advisories (preferred): use the repository security tab to submit a private report. -* Email: send details to `hello@mokoconsulting.tech` with subject `SECURITY: MokoCassiopeia vulnerability report`. +**DO NOT** create public GitHub issues for security vulnerabilities. -Do not file a public GitHub issue for suspected security vulnerabilities. +Report security vulnerabilities privately to: -### What to include +**Email**: `security@[DOMAIN]` -Provide enough detail to reproduce and triage: +**Subject Line**: `[SECURITY] Brief Description` -* A clear description of the vulnerability and expected impact. -* A minimal proof of concept or reproduction steps. -* Affected versions, configuration assumptions, and environment details. -* Any proposed mitigation or patch. -* Your preferred contact details for follow up. +### What to Include -## Triage and Response Targets +A complete vulnerability report should include: -The project operates with response targets aligned to practical delivery realities: +1. **Description**: Clear explanation of the vulnerability +2. **Impact**: Potential security impact and severity assessment +3. **Affected Versions**: Which versions are vulnerable +4. **Reproduction Steps**: Detailed steps to reproduce the issue +5. **Proof of Concept**: Code, configuration, or demonstration (if applicable) +6. **Suggested Fix**: Proposed remediation (if known) +7. **Disclosure Timeline**: Your expectations for public disclosure -* **Acknowledgement:** within 3 business days. -* **Initial triage:** within 10 business days. -* **Fix plan:** communicated once severity is confirmed. +### Response Timeline -These targets are not guarantees. Complex issues, supply chain considerations, and coordination with upstream vendors may extend timelines. +* **Initial Response**: Within 3 business days +* **Assessment Complete**: Within 7 business days +* **Fix Timeline**: Depends on severity (see below) +* **Disclosure**: Coordinated with reporter -## Severity Assessment +## Severity Classification -Issues are triaged based on business impact and technical exploitability, including: +Vulnerabilities are classified using the following severity levels: -* Remote exploitability and required privileges. -* Data confidentiality, integrity, and availability impact. -* Likelihood of exploitation in typical Joomla deployments. -* Exposure surface (public endpoints, administrator area, installation flows, and update mechanisms). +### Critical +* Remote code execution +* Authentication bypass +* Data breach or exposure of sensitive information +* **Fix Timeline**: 7 days -When appropriate, industry standard scoring such as CVSS may be used for internal prioritization. +### High +* Privilege escalation +* SQL injection or command injection +* Cross-site scripting (XSS) with significant impact +* **Fix Timeline**: 14 days -## Coordinated Disclosure +### Medium +* Information disclosure (limited scope) +* Denial of service +* Security misconfigurations with moderate impact +* **Fix Timeline**: 30 days -The project follows coordinated vulnerability disclosure: +### Low +* Security best practice violations +* Minor information leaks +* Issues requiring user interaction or complex preconditions +* **Fix Timeline**: 60 days or next release -* Reports are treated as confidential until remediation is available. -* A public advisory may be published once a fix is released. -* A reasonable embargo period is expected to enable patch distribution. +## Remediation Process -If you believe disclosure is time sensitive due to active exploitation, include that assessment and any supporting indicators. +1. **Acknowledgment**: Security team confirms receipt and begins investigation +2. **Assessment**: Vulnerability is validated, severity assigned, and impact analyzed +3. **Development**: Security patch is developed and tested +4. **Review**: Patch undergoes security review and validation +5. **Release**: Fixed version is released with security advisory +6. **Disclosure**: Public disclosure follows coordinated timeline -## Security Updates and Advisories +## Security Advisories -Security updates are distributed through: +Security advisories are published via: -* GitHub releases for the repository. -* GitHub Security Advisories when applicable. +* GitHub Security Advisories +* Release notes and CHANGELOG.md +* Security mailing list (when established) -Advisories may include: +Advisories include: -* Affected versions and fixed versions. -* Mitigations and workarounds when a fix is not immediately available. -* Upgrade guidance. +* CVE identifier (if applicable) +* Severity rating +* Affected versions +* Fixed versions +* Mitigation steps +* Attribution (with reporter consent) -## Dependencies and Supply Chain Controls +## Security Best Practices -The project aims to manage supply chain risk through: +For repositories adopting MokoStandards: -* Pinning and review of workflow dependencies where feasible. -* Minimizing privileged GitHub token permissions. -* Validating build inputs prior to packaging releases. +### Required Controls -If you identify a supply chain issue (for example compromised action, dependency confusion, or malicious upstream artifact), report it as a vulnerability. +* Enable GitHub security features (Dependabot, code scanning) +* Implement branch protection on `main` +* Require code review for all changes +* Enforce signed commits (recommended) +* Use secrets management (never commit credentials) +* Maintain security documentation +* Follow secure coding standards defined in `/docs/policy/` -## Secure Development and CI Expectations +### CI/CD Security -Security posture is reinforced through operational controls: +* Validate all inputs +* Sanitize outputs +* Use least privilege access +* Pin dependencies with hash verification +* Scan for vulnerabilities in dependencies +* Audit third-party actions and tools -* CI validation for packaging inputs and manifest integrity. -* Consistent path normalization and whitespace hygiene checks where required for release correctness. -* Least privilege for GitHub Actions permissions. +#### Automated Security Scanning -### Template Security Features +All repositories MUST implement: -**Custom Head Content Injection** +**CodeQL Analysis**: +* Enabled for all supported languages (Python, JavaScript, TypeScript, Java, C/C++, C#, Go, Ruby) +* Runs on: push to main, pull requests, weekly schedule +* Query sets: `security-extended` and `security-and-quality` +* Configuration: `.github/workflows/codeql-analysis.yml` -The template provides Custom Head Code fields (`custom_head_start` and `custom_head_end`) that allow administrators to inject custom HTML, CSS, and JavaScript code. This is an intentional feature for: +**Dependabot Security Updates**: +* Weekly scans for vulnerable dependencies +* Automated pull requests for security patches +* Configuration: `.github/dependabot.yml` -* Adding analytics scripts (Google Analytics, Google Tag Manager) -* Custom meta tags -* Third-party integrations -* Custom styling +**Secret Scanning**: +* Enabled by default with push protection +* Prevents accidental credential commits +* Partner patterns enabled -**Security Considerations:** +**Dependency Review**: +* Required for all pull requests +* Blocks introduction of known vulnerable dependencies +* Automatic license compliance checking -* These fields use `filter="raw"` to allow HTML/JS injection -* **Access is restricted to Joomla administrators only** via template configuration -* This is not an XSS vulnerability as it requires administrator privileges -* Administrators should only add trusted code from verified sources -* Regular security audits should review custom head content +See [Security Scanning Policy](docs/policy/security-scanning.md) for detailed requirements. -This policy does not guarantee that all vulnerabilities will be prevented. It defines how risk is managed when issues are discovered. +### Dependency Management -## Safe Harbor +* Keep dependencies up to date +* Monitor security advisories for dependencies +* Remove unused dependencies +* Audit new dependencies before adoption +* Document security-critical dependencies -The project supports good faith security research. When you: +## Compliance and Governance -* Avoid privacy violations, data destruction, and service disruption. -* Limit testing to systems you own or have explicit permission to test. -* Provide a reasonable window for coordinated disclosure. +This security policy is binding for all repositories governed by MokoStandards. Deviations require documented justification and approval from the Security Owner. -Then the project will treat your report as a constructive security contribution. +Security policies are reviewed and updated at least annually or following significant security incidents. -Jurisdiction note: this repository is managed from Tennessee, USA. This note is informational only and does not constitute legal advice. +## Attribution and Recognition -## Public Communications +We acknowledge and appreciate responsible disclosure. With your permission, we will: -Only maintainers will publish security advisories or public statements for confirmed vulnerabilities. Public communication will focus on actionable remediation and operational risk reduction. +* Credit you in security advisories +* List you in CHANGELOG.md for the fix release +* Recognize your contribution publicly (if desired) -## Acknowledgements +## Contact and Escalation -If you want credit, include the name or handle to list in an advisory. If you prefer anonymity, state that explicitly. +* **Security Team**: security@[DOMAIN] +* **Primary Contact**: [CONTACT_EMAIL] +* **Escalation**: For urgent matters requiring immediate attention, contact the maintainer directly via GitHub + +## Out of Scope + +The following are explicitly out of scope: + +* Issues in third-party dependencies (report directly to maintainers) +* Social engineering attacks +* Physical security issues +* Denial of service via resource exhaustion without amplification +* Issues requiring physical access to systems +* Theoretical vulnerabilities without proof of exploitability --- ## Metadata -* **Document:** SECURITY.md -* **Repository:** [https://github.com/mokoconsulting-tech/MokoCassiopeia](https://github.com/mokoconsulting-tech/MokoCassiopeia) -* **Path:** /SECURITY.md -* **Owner:** Moko Consulting -* **Version:** 03.06.00 -* **Status:** Active -* **Effective Date:** 2025-12-18 -* **Last Reviewed:** 2025-12-18 +| Field | Value | +| ------------ | ----------------------------------------------- | +| Document | Security Policy | +| Path | /SECURITY.md | +| Repository | [REPOSITORY_URL] | +| Owner | [OWNER_NAME] | +| Scope | Security vulnerability handling | +| Applies To | All repositories governed by MokoStandards | +| Status | Active | +| Effective | [YYYY-MM-DD] | ## Revision History -| Date | Change Summary | Author | -| ---------- | ------------------------------------------------------------------------------------------------ | --------------- | -| 2026-01-30 | Added Template Security Features section documenting custom head content injection controls. | Copilot Agent | -| 2025-12-18 | Initial publication of security policy, intake channels, triage targets, and disclosure process. | Moko Consulting | +| Date | Change Description | Author | +| ---------- | ------------------------------------------------- | --------------- | +| [YYYY-MM-DD] | Initial creation | [AUTHOR_NAME] | -- 2.49.1 From 71e5313845599599abd3c7af05221debadec599d Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:37 -0500 Subject: [PATCH 03/38] chore: update CODE_OF_CONDUCT.md from MokoStandards --- CODE_OF_CONDUCT.md | 131 +++++++++++++++++++++------------------------ 1 file changed, 60 insertions(+), 71 deletions(-) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index b0b170d..f6fa1d6 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -1,98 +1,87 @@ - +# Code of Conduct -## Code of Conduct +## 1. Purpose -This Code of Conduct establishes expectations for behavior within the MokoCassiopeia project community. The objective is to maintain a professional, inclusive, and respectful environment aligned with open source governance best practices. +The purpose of this Code of Conduct is to ensure a safe, inclusive, and respectful environment for all contributors and participants in Moko Consulting projects. This applies to all interactions, whether in repositories, issue trackers, documentation, meetings, or community spaces. -## Scope +## 2. Our Standards -This Code of Conduct applies to all project spaces, including: +Participants are expected to uphold behaviors that strengthen our community, including: -* GitHub repositories, issues, pull requests, discussions, and security advisories. -* Project documentation, workflows, and release processes. -* Any communication channels officially associated with the project. + Demonstrating empathy and respect toward others. + Being inclusive of diverse viewpoints and backgrounds. + Gracefully accepting constructive feedback. + Prioritizing collaboration over conflict. + Showing professionalism in all interactions. -## Our Standards +### Unacceptable behavior includes: -Participants are expected to: + Harassment, discrimination, or derogatory comments. + Threatening or violent language or actions. + Disruptive, aggressive, or intentionally harmful behavior. + Publishing others’ private information without permission. + Any behavior that violates applicable laws. -* Communicate professionally and respectfully. -* Provide constructive feedback focused on technical merit and project objectives. -* Respect differing viewpoints, experience levels, and backgrounds. -* Follow documented contribution, security, and governance policies. +## 3. Responsibilities of Maintainers -Unacceptable behavior includes: +Maintainers are responsible for: -* Harassment, discrimination, or exclusionary conduct. -* Personal attacks, insults, or inflammatory comments. -* Publishing private information without consent. -* Disruptive behavior that materially interferes with project operations. + Clarifying acceptable behavior. + Taking appropriate corrective action when unacceptable behavior occurs. + Removing, editing, or rejecting contributions that violate this Code. + Temporarily or permanently banning contributors who engage in repeated or severe violations. -## Enforcement Responsibilities +## 4. Scope -Project maintainers are responsible for: +This Code applies to: -* Clarifying standards when questions arise. -* Taking appropriate and proportionate corrective action when violations occur. -* Maintaining confidentiality to the extent practical during investigations. + All Moko Consulting repositories. + All documentation and collaboration platforms. + Public and private communication related to project activities. + Any representation of Moko Consulting in online or offline spaces. -## Reporting +## 5. Enforcement -Instances of abusive, harassing, or otherwise unacceptable behavior may be reported through: +Instances of misconduct may be reported to: +**[hello@mokoconsulting.tech](mailto:hello@mokoconsulting.tech)** -* Email: `hello@mokoconsulting.tech` with subject `CODE OF CONDUCT: MokoCassiopeia`. +All reports will be reviewed and investigated promptly and fairly. Maintainers are obligated to maintain confidentiality where possible. -Reports should include relevant context, links, screenshots, or other supporting information. +Consequences may include: -## Enforcement Guidelines + A warning. + Required training or mediation. + Temporary or permanent bans. + Escalation to legal authorities when required. -Corrective actions may include, but are not limited to: +## 6. Acknowledgements -* Private warning or request for corrective action. -* Temporary or permanent restriction from project participation. -* Removal of content that violates this Code of Conduct. +This Code of Conduct is inspired by widely adopted community guidelines, including the Contributor Covenant and major open-source collaboration standards. -Decisions are made based on impact, severity, and pattern of behavior. +## 7. Related Documents -## No Retaliation + [Governance Guide](./docs-governance.md) + [Contributor Guide](./docs-contributing.md) + [Documentation Index](./docs-index.md) -Retaliation against individuals who report concerns in good faith is not tolerated. Any retaliatory behavior will be treated as a separate violation. - -## Jurisdiction - -This project is managed from Tennessee, USA. This statement is informational and does not constitute legal advice. - ---- - -## Metadata - -* **Document:** CODE_OF_CONDUCT.md -* **Repository:** [https://github.com/mokoconsulting-tech/MokoCassiopeia](https://github.com/mokoconsulting-tech/MokoCassiopeia) -* **Path:** /CODE_OF_CONDUCT.md -* **Owner:** Moko Consulting -* **Version:** 03.06.00 -* **Status:** Active -* **Effective Date:** 2025-12-18 -* **Last Reviewed:** 2025-12-18 - -## Revision History - -| Date | Change Summary | Author | -| ---------- | ----------------------------------------------------------------------------- | --------------- | -| 2025-12-18 | Initial publication of contributor conduct standards and enforcement process. | Moko Consulting | +This Code of Conduct is a living document and may be updated following the established Change Management process. -- 2.49.1 From 06ebefb34d05e07fc70ddf17715b0ac47f7a8fe6 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:38 -0500 Subject: [PATCH 04/38] chore: update CONTRIBUTING.md from MokoStandards --- CONTRIBUTING.md | 158 +++++++++++------------------------------------- 1 file changed, 34 insertions(+), 124 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 1b8f124..d90f59e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,145 +1,55 @@ + VERSION: 04.00.04 + PATH: ./CONTRIBUTING.md + BRIEF: How to contribute; commit, PR, testing and security policies + --> -## Contributing +# Contributing -This document defines how to contribute to the MokoCassiopeia project. The goal is to ensure changes are reviewable, auditable, and aligned with project governance and release processes. +Thank you for your interest in contributing to this project! -## Scope +This repository is governed by **[MokoStandards](https://github.com/mokoconsulting-tech/MokoStandards)** — the authoritative source of coding standards, workflows, and policies for all Moko Consulting repositories. -These guidelines apply to all contributions, including: +## Quick Start -* Source code changes -* Documentation updates -* Bug reports and enhancement proposals +1. **Fork** the repository +2. **Branch** from `main` using `dev/XX.YY.ZZ/description` format +3. **Follow** [MokoStandards coding conventions](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) +4. **Commit** using [conventional commits](https://www.conventionalcommits.org/): `feat:`, `fix:`, `docs:`, `chore:`, etc. +5. **Open a PR** targeting `main` — squash merge only -## Prerequisites +## Standards -Contributors are expected to: +All contributions must follow MokoStandards: -* Have a working understanding of Joomla template structure. -* Be familiar with Git and GitHub pull request workflows. -* Review repository governance documents prior to submitting changes. -* Set up the development environment using the provided tools. +| Standard | Reference | +|----------|-----------| +| Coding Style | [coding-style-guide.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/coding-style-guide.md) | +| File Headers | [file-header-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/file-header-standards.md) | +| Branching | [branching-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/branching-strategy.md) | +| Merge Strategy | [merge-strategy.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/merge-strategy.md) | +| Scripting | [scripting-standards.md](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/scripting-standards.md) | -### Quick Setup +## Version Bumping -For first-time contributors: - -```bash -# Clone the repository -git clone https://github.com/mokoconsulting-tech/MokoCassiopeia.git -cd MokoCassiopeia -``` - -See [docs/QUICK_START.md](./docs/QUICK_START.md) for detailed setup instructions. - -## Development Tools - -The repository provides several tools to streamline development: - -* **Pre-commit Hooks**: Automatic local validation before commits - -## Contribution Workflow - -1. Fork the repository. -2. Create a branch from the active development branch. -3. Make focused, minimal changes that address a single concern. -4. Submit a pull request with a clear description of intent and impact. - -Direct commits to protected branches are not permitted. - -## Branching and Versioning - -* Development work occurs on designated development branches. -* Releases are produced from versioned branches following repository standards. -* Contributors should not bump version numbers unless explicitly requested. - -## Coding and Formatting Standards - -All contributions must: - -* Follow Joomla coding standards where applicable. -* Conform to Moko Consulting repository standards for headers, metadata, and file structure. -* Avoid introducing tabs, inconsistent path separators, or non portable assumptions. - -Automated checks may reject changes that do not meet these requirements. - -## Documentation Standards - -Documentation changes must: - -* Include required metadata and revision history sections. -* Avoid embedding version numbers in revision history tables. -* Preserve existing structure unless a structural change is explicitly proposed. - -## Commit Messages - -Commit messages should: - -* Be concise and descriptive. -* Focus on what changed and why. -* Avoid referencing internal issue trackers unless required. - -## Reporting Issues - -Bug reports and enhancement requests should be filed as GitHub issues and include: - -* Clear reproduction steps or use cases. -* Expected versus actual behavior. -* Relevant environment details. - -Security related issues must follow the process defined in SECURITY.md and must not be reported publicly. - -## Review Process - -All pull requests are subject to review. Review criteria include: - -* Technical correctness -* Alignment with project goals -* Maintainability and clarity -* Risk introduced to release and update processes - -Maintainers may request changes prior to approval. +Every PR must bump the patch version in `README.md`. The `sync-version-on-merge` workflow propagates it to all file headers automatically on merge to `main`. ## License -By contributing, you agree that your contributions will be licensed under GPL-3.0-or-later, consistent with the rest of the project. - -## Code of Conduct - -Participation in this project is governed by the Code of Conduct. Unacceptable behavior may result in contribution restrictions. - ---- - -## Metadata - -* **Document:** CONTRIBUTING.md -* **Repository:** [https://github.com/mokoconsulting-tech/MokoCassiopeia](https://github.com/mokoconsulting-tech/MokoCassiopeia) -* **Path:** /CONTRIBUTING.md -* **Owner:** Moko Consulting -* **Version:** 03.06.00 -* **Status:** Active -* **Effective Date:** 2025-12-18 -* **Last Reviewed:** 2025-12-18 - -## Revision History - -| Date | Change Summary | Author | -| ---------- | ------------------------------------------------------------------------- | --------------- | -| 2025-12-18 | Initial publication of contribution guidelines and workflow expectations. | Moko Consulting | +By contributing, you agree that your contributions will be licensed under the [GPL-3.0-or-later](LICENSE) license. -- 2.49.1 From 16df42785afc4ce0c342a94e066d8fe1db3fcef1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:38 -0500 Subject: [PATCH 05/38] chore: update update.xml from MokoStandards -- 2.49.1 From d2aab2cb93dd42aebd0855c264d89c3fb2c0cb93 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:39 -0500 Subject: [PATCH 06/38] chore: update phpstan.neon from MokoStandards -- 2.49.1 From bfc68192c5d1038c441aabfd122a4b3b17424812 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:40 -0500 Subject: [PATCH 07/38] chore: update Makefile from MokoStandards -- 2.49.1 From 8bff5d6cf5cbd22c4e95805bab5314fd5feea45b Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:40 -0500 Subject: [PATCH 08/38] chore: update .gitignore from MokoStandards -- 2.49.1 From 34f91b788bbf12183838aa96506628d3d24ae008 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:41 -0500 Subject: [PATCH 09/38] chore: update composer.json from MokoStandards -- 2.49.1 From 436e01e3827367c159b058ff4e4f96509f1504b1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:41 -0500 Subject: [PATCH 10/38] chore: update .moko-standards from MokoStandards --- .moko-standards | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.moko-standards b/.moko-standards index db0c004..ea2854a 100644 --- a/.moko-standards +++ b/.moko-standards @@ -5,7 +5,7 @@ # INGROUP: MokoStandards.Templates # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/configs/moko-standards.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: Governance attachment template — synced to .moko-standards in every governed repository # NOTE: Tokens replaced at sync time: mokoconsulting-tech, MokoCassiopeia, waas-component, 04.00.04 # -- 2.49.1 From d579cbfce429803073c399de98736332a0b79d4f Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:42 -0500 Subject: [PATCH 11/38] chore: update .github/copilot.yml from MokoStandards -- 2.49.1 From 05280b43f4b087f1781c01ddbf9d7500ca04f758 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:43 -0500 Subject: [PATCH 12/38] chore: update .github/copilot-instructions.md from MokoStandards -- 2.49.1 From d801bd3207f95c4baea87af74307ac1d267cf86b Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:44 -0500 Subject: [PATCH 13/38] chore: update .github/CLAUDE.md from MokoStandards -- 2.49.1 From a8c4ff2dae7b7ca790de33893f704f36eca5bdd2 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:44 -0500 Subject: [PATCH 14/38] chore: update .github/ISSUE_TEMPLATE/config.yml from MokoStandards -- 2.49.1 From e63653f09d201a2c4fa8306666e43c0e00962a04 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:45 -0500 Subject: [PATCH 15/38] chore: update .github/ISSUE_TEMPLATE/adr.md from MokoStandards -- 2.49.1 From cc44404194152c86449f41cfe2f75ce9c7b5aa61 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:45 -0500 Subject: [PATCH 16/38] chore: update .github/ISSUE_TEMPLATE/bug_report.md from MokoStandards -- 2.49.1 From 499efa2f86bebff5237087781bdbf467c5cf2707 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:46 -0500 Subject: [PATCH 17/38] chore: update .github/ISSUE_TEMPLATE/documentation.md from MokoStandards -- 2.49.1 From 53f089db18d745cefcf06d210dc452b8f337ba14 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:47 -0500 Subject: [PATCH 18/38] chore: update .github/ISSUE_TEMPLATE/enterprise_support.md from MokoStandards -- 2.49.1 From 887df47e279024bd8135e84f89fde7f91608a93b Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:47 -0500 Subject: [PATCH 19/38] chore: update .github/ISSUE_TEMPLATE/feature_request.md from MokoStandards -- 2.49.1 From 6c61fb232b29b041943d27d078b7e7ffe1089f2c Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:48 -0500 Subject: [PATCH 20/38] chore: update .github/ISSUE_TEMPLATE/firewall-request.md from MokoStandards -- 2.49.1 From b8ce6d6565dc3faa3a8d90f3e6926379c1af55b5 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:48 -0500 Subject: [PATCH 21/38] chore: update .github/ISSUE_TEMPLATE/question.md from MokoStandards -- 2.49.1 From a952d47b95e71ecee410c07f5bab186f4ebba4e6 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:49 -0500 Subject: [PATCH 22/38] chore: update .github/ISSUE_TEMPLATE/request-license.md from MokoStandards -- 2.49.1 From ceec0f5ebf79cfccb8ddbbef843293bbdb999895 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:50 -0500 Subject: [PATCH 23/38] chore: update .github/ISSUE_TEMPLATE/rfc.md from MokoStandards -- 2.49.1 From 1b65f10f6a902928728fa2859e71bda2283537ad Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:50 -0500 Subject: [PATCH 24/38] chore: update .github/ISSUE_TEMPLATE/security.md from MokoStandards -- 2.49.1 From 0231cc3759ed9ab2f92a32e4e389cf87d6c8b7c8 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:51 -0500 Subject: [PATCH 25/38] chore: update .github/ISSUE_TEMPLATE/joomla_issue.md from MokoStandards -- 2.49.1 From 0a128907912033bccfdabbee10d93a0e5d8c693d Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:51 -0500 Subject: [PATCH 26/38] chore: update .github/workflows/deploy-dev.yml from MokoStandards --- .github/workflows/deploy-dev.yml | 42 ++++++++++++-------------------- 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/.github/workflows/deploy-dev.yml b/.github/workflows/deploy-dev.yml index 5fa6a23..ca9d613 100644 --- a/.github/workflows/deploy-dev.yml +++ b/.github/workflows/deploy-dev.yml @@ -22,7 +22,7 @@ # INGROUP: MokoStandards.Deploy # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/deploy-dev.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: SFTP deployment workflow for development server — synced to all governed repos # NOTE: Synced via bulk-repo-sync to .github/workflows/deploy-dev.yml in all governed repos. # Port is resolved in order: DEV_FTP_PORT variable → :port suffix in DEV_FTP_HOST → 22. @@ -73,6 +73,9 @@ permissions: contents: read pull-requests: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: check-permission: name: Verify Deployment Permission @@ -348,7 +351,7 @@ jobs: # ── Platform-specific path safety guards ────────────────────────────── PLATFORM="" if [ -f ".moko-standards" ]; then - PLATFORM=$(grep -E '^platform:' .moko-standards | sed 's/.*:[[:space:]]*//' | tr -d '"') + PLATFORM=$(grep -oP '^platform:\s*\K\S+' .moko-standards 2>/dev/null || true) fi if [ "$PLATFORM" = "crm-module" ]; then @@ -426,8 +429,11 @@ jobs: cd /tmp/mokostandards composer install --no-dev --no-interaction --quiet - - name: Clear remote destination folder - if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true' + - name: Clear remote destination folder (manual only) + if: >- + steps.source.outputs.skip == 'false' && + steps.remote.outputs.skip != 'true' && + inputs.clear_remote == true env: SFTP_HOST: ${{ steps.conn.outputs.host }} SFTP_PORT: ${{ steps.conn.outputs.port }} @@ -574,24 +580,8 @@ jobs: DEPLOY_ARGS+=(--key-passphrase "$SFTP_PASSWORD") fi - # ── For Dolibarr (crm-module): set version to "development" before deploy ─ - PLATFORM="" - if [ -f ".moko-standards" ]; then - PLATFORM=$(grep -E '^platform:' .moko-standards | sed 's/.*:[[:space:]]*//' | tr -d '"') - fi - - if [ "$PLATFORM" = "crm-module" ]; then - echo "📦 Dolibarr dev deploy — setting module version to 'development'" - find "$SOURCE_DIR" -path "*/core/modules/mod*.class.php" -exec \ - sed -i "s/\(\$this->version\s*=\s*\)['\"][^'\"]*['\"]/\1'development'/" {} + 2>/dev/null || true - fi - - if [ "$PLATFORM" = "waas-component" ]; then - echo "📦 Joomla dev deploy — setting manifest version to 'development'" - find "$SOURCE_DIR" -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null | while read -r manifest; do - sed -i "s|[^<]*|development|" "$manifest" 2>/dev/null || true - done - fi + # Set platform version to "development" before deploy (Dolibarr + Joomla) + php /tmp/mokostandards/api/cli/version_set_platform.php --path . --version development php /tmp/mokostandards/api/deploy/deploy-sftp.php "${DEPLOY_ARGS[@]}" # (deploy-sftp.php handles dotfile skipping and .ftp_ignore natively) @@ -641,22 +631,22 @@ jobs: --force 2>/dev/null || true # Look for an existing open deploy-failure issue - EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=open&per_page=1" \ + EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=all&per_page=1&sort=created&direction=desc" \ --jq '.[0].number' 2>/dev/null) if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then gh api "repos/${REPO}/issues/${EXISTING}" \ -X PATCH \ -f title="$TITLE" \ - -f body="$BODY" \ + -f body="$BODY" \n -f state="open" \ --silent - echo "📋 Failure issue #${EXISTING} updated: ${REPO}" >> "$GITHUB_STEP_SUMMARY" + echo "📋 Failure issue #${EXISTING} updated/reopened: ${REPO}" >> "$GITHUB_STEP_SUMMARY" else gh issue create \ --repo "$REPO" \ --title "$TITLE" \ --body "$BODY" \ - --label "$LABEL" \ + --label "$LABEL" \n --assignee "jmiller-moko" \ | tee -a "$GITHUB_STEP_SUMMARY" fi -- 2.49.1 From cdd99bfe0e3419d1892d6b88a755cd7ae869cf19 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:52 -0500 Subject: [PATCH 27/38] chore: update .github/workflows/deploy-demo.yml from MokoStandards --- .github/workflows/deploy-demo.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/deploy-demo.yml b/.github/workflows/deploy-demo.yml index 184799f..ea150c6 100644 --- a/.github/workflows/deploy-demo.yml +++ b/.github/workflows/deploy-demo.yml @@ -22,7 +22,7 @@ # INGROUP: MokoStandards.Deploy # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/deploy-demo.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: SFTP deployment workflow for demo server — synced to all governed repos # NOTE: Synced via bulk-repo-sync to .github/workflows/deploy-demo.yml in all governed repos. # Port is resolved in order: DEMO_FTP_PORT variable → :port suffix in DEMO_FTP_HOST → 22. @@ -70,6 +70,9 @@ permissions: contents: read pull-requests: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: check-permission: name: Verify Deployment Permission @@ -241,7 +244,6 @@ jobs: fi done $SKIP && continue - if [ -f ".gitignore" ]; then if [ -f ".gitignore" ]; then git check-ignore -q "$rel" 2>/dev/null && { IGNORED_FILES+=("$rel | .gitignore") @@ -424,8 +426,11 @@ jobs: cd /tmp/mokostandards composer install --no-dev --no-interaction --quiet - - name: Clear remote destination folder - if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true' + - name: Clear remote destination folder (manual only) + if: >- + steps.source.outputs.skip == 'false' && + steps.remote.outputs.skip != 'true' && + inputs.clear_remote == true env: SFTP_HOST: ${{ steps.conn.outputs.host }} SFTP_PORT: ${{ steps.conn.outputs.port }} @@ -578,7 +583,7 @@ jobs: rm -f /tmp/deploy_key /tmp/sftp-config.json - name: Create or update failure issue - if: failure() + if: failure() && steps.remote.outputs.skip != 'true' env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | @@ -620,22 +625,22 @@ jobs: --force 2>/dev/null || true # Look for an existing open deploy-failure issue - EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=open&per_page=1" \ + EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=all&per_page=1&sort=created&direction=desc" \ --jq '.[0].number' 2>/dev/null) if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then gh api "repos/${REPO}/issues/${EXISTING}" \ -X PATCH \ -f title="$TITLE" \ - -f body="$BODY" \ + -f body="$BODY" \n -f state="open" \ --silent - echo "📋 Failure issue #${EXISTING} updated: ${REPO}" >> "$GITHUB_STEP_SUMMARY" + echo "📋 Failure issue #${EXISTING} updated/reopened: ${REPO}" >> "$GITHUB_STEP_SUMMARY" else gh issue create \ --repo "$REPO" \ --title "$TITLE" \ --body "$BODY" \ - --label "$LABEL" \ + --label "$LABEL" \n --assignee "jmiller-moko" \ | tee -a "$GITHUB_STEP_SUMMARY" fi -- 2.49.1 From 2fd88240683610b7ee04cd8eff2945fd4d8af66c Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:53 -0500 Subject: [PATCH 28/38] chore: update .github/workflows/deploy-rs.yml from MokoStandards --- .github/workflows/deploy-rs.yml | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/.github/workflows/deploy-rs.yml b/.github/workflows/deploy-rs.yml index eef55b8..7d5564c 100644 --- a/.github/workflows/deploy-rs.yml +++ b/.github/workflows/deploy-rs.yml @@ -22,7 +22,7 @@ # INGROUP: MokoStandards.Deploy # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/deploy-rs.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: SFTP deployment workflow for release staging server — synced to all governed repos # NOTE: Synced via bulk-repo-sync to .github/workflows/deploy-rs.yml in all governed repos. # Port is resolved in order: RS_FTP_PORT variable → :port suffix in RS_FTP_HOST → 22. @@ -70,6 +70,9 @@ permissions: contents: read pull-requests: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: check-permission: name: Verify Deployment Permission @@ -404,8 +407,11 @@ jobs: cd /tmp/mokostandards composer install --no-dev --no-interaction --quiet - - name: Clear remote destination folder - if: steps.source.outputs.skip == 'false' && steps.remote.outputs.skip != 'true' + - name: Clear remote destination folder (manual only) + if: >- + steps.source.outputs.skip == 'false' && + steps.remote.outputs.skip != 'true' && + inputs.clear_remote == true env: SFTP_HOST: ${{ steps.conn.outputs.host }} SFTP_PORT: ${{ steps.conn.outputs.port }} @@ -558,7 +564,7 @@ jobs: rm -f /tmp/deploy_key /tmp/sftp-config.json - name: Create or update failure issue - if: failure() + if: failure() && steps.remote.outputs.skip != 'true' env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | @@ -599,8 +605,8 @@ jobs: --description "Automated deploy failure tracking" \ --force 2>/dev/null || true - # Look for an existing open deploy-failure issue - EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=open&per_page=1" \ + # Look for an existing deploy-failure issue (any state — reopen if closed) + EXISTING=$(gh api "repos/${REPO}/issues?labels=${LABEL}&state=all&per_page=1&sort=created&direction=desc" \ --jq '.[0].number' 2>/dev/null) if [ -n "$EXISTING" ] && [ "$EXISTING" != "null" ]; then @@ -608,14 +614,16 @@ jobs: -X PATCH \ -f title="$TITLE" \ -f body="$BODY" \ + -f state="open" \ --silent - echo "📋 Failure issue #${EXISTING} updated: ${REPO}" >> "$GITHUB_STEP_SUMMARY" + echo "📋 Failure issue #${EXISTING} updated/reopened: ${REPO}" >> "$GITHUB_STEP_SUMMARY" else gh issue create \ --repo "$REPO" \ --title "$TITLE" \ --body "$BODY" \ --label "$LABEL" \ + --assignee "jmiller-moko" \ | tee -a "$GITHUB_STEP_SUMMARY" fi -- 2.49.1 From 16223c80066a06b0ddec5fdf0cdc67d79b983be6 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:54 -0500 Subject: [PATCH 29/38] chore: update .github/workflows/enterprise-firewall-setup.yml from MokoStandards --- .github/workflows/enterprise-firewall-setup.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/enterprise-firewall-setup.yml b/.github/workflows/enterprise-firewall-setup.yml index a093120..2798f35 100644 --- a/.github/workflows/enterprise-firewall-setup.yml +++ b/.github/workflows/enterprise-firewall-setup.yml @@ -22,7 +22,7 @@ # INGROUP: MokoStandards.Firewall # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/enterprise-firewall-setup.yml -# VERSION: 04.01.00 +# VERSION: 04.02.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. -- 2.49.1 From d0ca7c06d870f7ec2390819f88119b97c5941384 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:54 -0500 Subject: [PATCH 30/38] chore: update .github/workflows/sync-version-on-merge.yml from MokoStandards --- .github/workflows/sync-version-on-merge.yml | 28 ++++++++------------- 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/.github/workflows/sync-version-on-merge.yml b/.github/workflows/sync-version-on-merge.yml index 56cd2a8..6738a38 100644 --- a/.github/workflows/sync-version-on-merge.yml +++ b/.github/workflows/sync-version-on-merge.yml @@ -9,7 +9,7 @@ # INGROUP: MokoStandards.Automation # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/sync-version-on-merge.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: Auto-bump patch version on every push to main and propagate to all file headers # NOTE: Synced via bulk-repo-sync to .github/workflows/sync-version-on-merge.yml in all governed repos. # README.md is the single source of truth for the repository version. @@ -32,6 +32,9 @@ permissions: contents: write issues: write +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: sync-version: name: Propagate README version @@ -64,31 +67,20 @@ jobs: - name: Auto-bump patch version if: ${{ github.event_name == 'push' && github.actor != 'github-actions[bot]' }} run: | - # If README.md was part of this push, the author already bumped the version — skip. if git diff --name-only HEAD~1 HEAD 2>/dev/null | grep -q '^README\.md$'; then echo "README.md changed in this push — skipping auto-bump" exit 0 fi - CURRENT=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1) - if [ -z "$CURRENT" ]; then - echo "⚠️ No VERSION found in README.md — skipping auto-bump" + RESULT=$(php /tmp/mokostandards/api/cli/version_bump.php --path .) || { + echo "⚠️ Could not bump version — skipping" exit 0 - fi - - # Increment the patch component (zero-padded to 2 digits) - MAJOR=$(echo "$CURRENT" | cut -d. -f1) - MINOR=$(echo "$CURRENT" | cut -d. -f2) - PATCH=$(echo "$CURRENT" | cut -d. -f3) - NEW_PATCH=$(printf '%02d' $(( 10#$PATCH + 1 ))) - NEW_VERSION="${MAJOR}.${MINOR}.${NEW_PATCH}" - - echo "Auto-bumping patch: $CURRENT → $NEW_VERSION" - sed -i "s/^\(\s*VERSION:\s*\)${CURRENT}/\1${NEW_VERSION}/" README.md + } + echo "Auto-bumping patch: $RESULT" git config --local user.email "github-actions[bot]@users.noreply.github.com" git config --local user.name "github-actions[bot]" git add README.md - git commit -m "chore(version): auto-bump patch ${CURRENT} → ${NEW_VERSION} [skip ci]" \ + git commit -m "chore(version): auto-bump patch ${RESULT} [skip ci]" \ --author="github-actions[bot] " git push @@ -96,7 +88,7 @@ jobs: id: readme_version run: | git pull --ff-only 2>/dev/null || true - VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1) + VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null) if [ -z "$VERSION" ]; then echo "⚠️ No VERSION in README.md — skipping propagation" echo "skip=true" >> $GITHUB_OUTPUT -- 2.49.1 From 0720ef92ba221d9929f22abe0bd2c5294df5a070 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:55 -0500 Subject: [PATCH 31/38] chore: update .github/workflows/auto-release.yml from MokoStandards --- .github/workflows/auto-release.yml | 82 +++++++++++++++++++----------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 0016fd2..eab5659 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -9,7 +9,7 @@ # INGROUP: MokoStandards.Release # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/auto-release.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: Auto-create a GitHub Release on every push to main with version from README.md # NOTE: Synced via bulk-repo-sync to .github/workflows/auto-release.yml in all governed repos. # For Dolibarr (crm-module) repos, also updates $this->version in the module descriptor. @@ -41,10 +41,21 @@ jobs: token: ${{ secrets.GH_TOKEN || github.token }} fetch-depth: 0 + - name: Setup MokoStandards tools + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' + run: | + git clone --depth 1 --quiet \ + "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ + /tmp/mokostandards + cd /tmp/mokostandards + composer install --no-dev --no-interaction --quiet + - name: Extract version from README.md id: version run: | - VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md | head -1) + VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null) if [ -z "$VERSION" ]; then echo "⚠️ No VERSION found in README.md — skipping release" echo "skip=true" >> "$GITHUB_OUTPUT" @@ -67,32 +78,13 @@ jobs: echo "exists=false" >> "$GITHUB_OUTPUT" fi - - name: Update Dolibarr module version + - name: Set platform version if: >- steps.version.outputs.skip != 'true' && steps.tag_check.outputs.exists != 'true' run: | - PLATFORM="" - if [ -f ".moko-standards" ]; then - PLATFORM=$(grep -E '^platform:' .moko-standards | sed 's/.*:[[:space:]]*//' | tr -d '"') - fi - VERSION="${{ steps.version.outputs.version }}" - - if [ "$PLATFORM" = "crm-module" ]; then - echo "📦 Dolibarr release — setting module version to '${VERSION}'" - # Update $this->version in the module descriptor (core/modules/mod*.class.php) - find . -path "*/core/modules/mod*.class.php" -exec \ - sed -i "s/\(\$this->version\s*=\s*\)['\"][^'\"]*['\"]/\1'${VERSION}'/" {} + 2>/dev/null || true - fi - - if [ "$PLATFORM" = "waas-component" ]; then - echo "📦 Joomla release — setting manifest version to '${VERSION}'" - # Update tag in Joomla XML manifest files - find . -maxdepth 2 -name "*.xml" -exec grep -l '/dev/null | while read -r manifest; do - sed -i "s|[^<]*|${VERSION}|" "$manifest" 2>/dev/null || true - done - fi + php /tmp/mokostandards/api/cli/version_set_platform.php --path . --version "$VERSION" # Commit the version update if anything changed if ! git diff --quiet; then @@ -111,13 +103,7 @@ jobs: id: changelog run: | VERSION="${{ steps.version.outputs.version }}" - - # Try to extract the section for this version from CHANGELOG.md - NOTES="" - if [ -f "CHANGELOG.md" ]; then - # Extract text between this version's heading and the next heading - NOTES=$(awk "/^##.*${VERSION}/,/^## /" CHANGELOG.md | head -50 | sed '1d;$d') - fi + NOTES=$(php /tmp/mokostandards/api/cli/release_notes.php --path . --version "$VERSION" 2>/dev/null) if [ -z "$NOTES" ]; then NOTES="Release ${VERSION}" @@ -149,6 +135,42 @@ jobs: echo "🚀 Release ${VERSION} created: $TAG" + - name: Write update.json for Dolibarr update checks + if: >- + steps.version.outputs.skip != 'true' && + steps.tag_check.outputs.exists != 'true' + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + PLATFORM="" + if [ -f ".moko-standards" ]; then + PLATFORM=$(grep -E '^platform:' .moko-standards | sed 's/.*:[[:space:]]*//' | tr -d '"') + fi + + if [ "$PLATFORM" = "crm-module" ]; then + VERSION="${{ steps.version.outputs.version }}" + TAG="${{ steps.version.outputs.tag }}" + + # update.json — read by Dolibarr's module update checker via $this->url_last_version + # Points to: https://raw.githubusercontent.com/mokoconsulting-tech/{repo}/main/update.json + jq -n \ + --arg version "$VERSION" \ + --arg tag "$TAG" \ + --arg repo "${{ github.repository }}" \ + --arg release "https://github.com/${{ github.repository }}/releases/tag/${TAG}" \ + --arg updated "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ + '{version: $version, tag: $tag, repo: $repo, release_url: $release, updated: $updated}' \ + > update.json + + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add update.json + git commit -m "chore(release): update update.json to ${VERSION} [skip ci]" \ + --author="github-actions[bot] " + git push + echo "📦 update.json written with version ${VERSION}" >> $GITHUB_STEP_SUMMARY + fi + - name: Summary if: steps.version.outputs.skip != 'true' run: | -- 2.49.1 From 6426d44784411bf1bf679a13a30b533887bd1e80 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:55 -0500 Subject: [PATCH 32/38] chore: add .github/workflows/auto-version-branch.yml from MokoStandards --- .github/workflows/auto-version-branch.yml | 85 +++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 .github/workflows/auto-version-branch.yml diff --git a/.github/workflows/auto-version-branch.yml b/.github/workflows/auto-version-branch.yml new file mode 100644 index 0000000..3a1872c --- /dev/null +++ b/.github/workflows/auto-version-branch.yml @@ -0,0 +1,85 @@ +# Copyright (C) 2026 Moko Consulting +# +# This file is part of a Moko Consulting project. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: GitHub.Workflow +# INGROUP: MokoStandards.Automation +# REPO: https://github.com/mokoconsulting-tech/MokoStandards +# PATH: /templates/workflows/shared/auto-version-branch.yml +# VERSION: 04.02.00 +# BRIEF: Auto-create version/ branch on every push to main — preserves release snapshots +# NOTE: Synced via bulk-repo-sync. Works alongside auto-release.yml which handles +# tags, GitHub Releases, and platform version updates. + +name: Auto Version Branch + +on: + push: + branches: + - main + - master + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: write + +jobs: + version-branch: + name: Create version branch + runs-on: ubuntu-latest + if: >- + !contains(github.event.head_commit.message, '[skip ci]') && + github.actor != 'github-actions[bot]' + + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 + with: + token: ${{ secrets.GH_TOKEN || github.token }} + fetch-depth: 0 + + - name: Setup MokoStandards tools + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + COMPOSER_AUTH: '{"github-oauth":{"github.com":"${{ secrets.GH_TOKEN || github.token }}"}}' + run: | + git clone --depth 1 --quiet \ + "https://x-access-token:${GH_TOKEN}@github.com/mokoconsulting-tech/MokoStandards.git" \ + /tmp/mokostandards + cd /tmp/mokostandards + composer install --no-dev --no-interaction --quiet + + - name: Read version and create branch + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + VERSION=$(php /tmp/mokostandards/api/cli/version_read.php --path . 2>/dev/null) + if [ -z "$VERSION" ]; then + echo "⏭️ No VERSION in README.md — skipping" >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + BRANCH="version/${VERSION}" + + # Check if branch already exists + if git ls-remote --heads origin "$BRANCH" 2>/dev/null | grep -q "$BRANCH"; then + echo "ℹ️ Branch \`${BRANCH}\` already exists" >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + # Create and push version branch + git checkout -b "$BRANCH" + git push origin "$BRANCH" + + echo "## 🌿 Version Branch Created" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| Field | Value |" >> $GITHUB_STEP_SUMMARY + echo "|-------|-------|" >> $GITHUB_STEP_SUMMARY + echo "| **Version** | \`${VERSION}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Branch** | \`${BRANCH}\` |" >> $GITHUB_STEP_SUMMARY + echo "| **Source** | \`${{ github.ref_name }}\` @ \`${GITHUB_SHA:0:8}\` |" >> $GITHUB_STEP_SUMMARY -- 2.49.1 From c55e784b59483d0922832fec38fcff0b138b0b5e Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:56 -0500 Subject: [PATCH 33/38] chore: update .github/workflows/repository-cleanup.yml from MokoStandards --- .github/workflows/repository-cleanup.yml | 357 ++++++++++++++++++++--- 1 file changed, 315 insertions(+), 42 deletions(-) diff --git a/.github/workflows/repository-cleanup.yml b/.github/workflows/repository-cleanup.yml index 33c9864..570cbb1 100644 --- a/.github/workflows/repository-cleanup.yml +++ b/.github/workflows/repository-cleanup.yml @@ -9,36 +9,58 @@ # INGROUP: MokoStandards.Maintenance # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /templates/workflows/shared/repository-cleanup.yml -# VERSION: 04.01.00 -# BRIEF: One-time repository cleanup — reset labels, strip issue template headers, delete old branches +# VERSION: 04.02.00 +# BRIEF: Recurring repository maintenance — labels, branches, workflows, logs, doc indexes # NOTE: Synced via bulk-repo-sync to .github/workflows/repository-cleanup.yml in all governed repos. -# Run manually via workflow_dispatch. Safe to re-run — all operations are idempotent. +# Runs on the 1st and 15th of each month at 6:00 AM UTC, and on manual dispatch. name: Repository Cleanup on: + schedule: + - cron: '0 6 1,15 * *' workflow_dispatch: inputs: reset_labels: - description: 'Delete ALL existing labels and recreate the standard 54-label set' + description: 'Delete ALL existing labels and recreate the standard set' + type: boolean + default: false + clean_branches: + description: 'Delete old chore/sync-mokostandards-* branches' type: boolean default: true - clean_branches: - description: 'Delete old chore/sync-mokostandards-* branches (keeps current versioned branch only)' + clean_workflows: + description: 'Delete orphaned workflow runs (cancelled, stale)' + type: boolean + default: true + clean_logs: + description: 'Delete workflow run logs older than 30 days' type: boolean default: true fix_templates: description: 'Strip copyright comment blocks from issue templates' type: boolean default: true + rebuild_indexes: + description: 'Rebuild docs/ index files' + type: boolean + default: true + delete_closed_issues: + description: 'Delete issues that have been closed for more than 30 days' + type: boolean + default: false + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true permissions: contents: write issues: write + actions: write jobs: cleanup: - name: Repository Cleanup + name: Repository Maintenance runs-on: ubuntu-latest steps: @@ -46,12 +68,18 @@ jobs: uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6 with: token: ${{ secrets.GH_TOKEN || github.token }} + fetch-depth: 0 - name: Check actor permission env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | ACTOR="${{ github.actor }}" + # Schedule triggers use github-actions[bot] + if [ "${{ github.event_name }}" = "schedule" ]; then + echo "✅ Scheduled run — authorized" + exit 0 + fi AUTHORIZED_USERS="jmiller-moko github-actions[bot]" for user in $AUTHORIZED_USERS; do if [ "$ACTOR" = "$user" ]; then @@ -66,9 +94,88 @@ jobs: *) echo "❌ Admin or maintain required"; exit 1 ;; esac + # ── Determine which tasks to run ───────────────────────────────────── + # On schedule: run all tasks with safe defaults (labels NOT reset) + # On dispatch: use input toggles + - name: Set task flags + id: tasks + run: | + if [ "${{ github.event_name }}" = "schedule" ]; then + echo "reset_labels=false" >> $GITHUB_OUTPUT + echo "clean_branches=true" >> $GITHUB_OUTPUT + echo "clean_workflows=true" >> $GITHUB_OUTPUT + echo "clean_logs=true" >> $GITHUB_OUTPUT + echo "fix_templates=true" >> $GITHUB_OUTPUT + echo "rebuild_indexes=true" >> $GITHUB_OUTPUT + echo "delete_closed_issues=false" >> $GITHUB_OUTPUT + else + echo "reset_labels=${{ inputs.reset_labels }}" >> $GITHUB_OUTPUT + echo "clean_branches=${{ inputs.clean_branches }}" >> $GITHUB_OUTPUT + echo "clean_workflows=${{ inputs.clean_workflows }}" >> $GITHUB_OUTPUT + echo "clean_logs=${{ inputs.clean_logs }}" >> $GITHUB_OUTPUT + echo "fix_templates=${{ inputs.fix_templates }}" >> $GITHUB_OUTPUT + echo "rebuild_indexes=${{ inputs.rebuild_indexes }}" >> $GITHUB_OUTPUT + echo "delete_closed_issues=${{ inputs.delete_closed_issues }}" >> $GITHUB_OUTPUT + fi + + # ── DELETE RETIRED WORKFLOWS (always runs) ──────────────────────────── + - name: Delete retired workflow files + run: | + echo "## 🗑️ Retired Workflow Cleanup" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + RETIRED=( + ".github/workflows/build.yml" + ".github/workflows/code-quality.yml" + ".github/workflows/release-cycle.yml" + ".github/workflows/release-pipeline.yml" + ".github/workflows/branch-cleanup.yml" + ".github/workflows/auto-update-changelog.yml" + ".github/workflows/enterprise-issue-manager.yml" + ".github/workflows/flush-actions-cache.yml" + ".github/workflows/mokostandards-script-runner.yml" + ".github/workflows/unified-ci.yml" + ".github/workflows/unified-platform-testing.yml" + ".github/workflows/reusable-build.yml" + ".github/workflows/reusable-ci-validation.yml" + ".github/workflows/reusable-deploy.yml" + ".github/workflows/reusable-php-quality.yml" + ".github/workflows/reusable-platform-testing.yml" + ".github/workflows/reusable-project-detector.yml" + ".github/workflows/reusable-release.yml" + ".github/workflows/reusable-script-executor.yml" + ".github/workflows/rebuild-docs-indexes.yml" + ".github/workflows/setup-project-v2.yml" + ".github/workflows/sync-docs-to-project.yml" + ".github/workflows/release.yml" + ".github/workflows/sync-changelogs.yml" + ".github/workflows/version_branch.yml" + ) + + DELETED=0 + for wf in "${RETIRED[@]}"; do + if [ -f "$wf" ]; then + git rm "$wf" 2>/dev/null || rm -f "$wf" + echo " Deleted: \`$(basename $wf)\`" >> $GITHUB_STEP_SUMMARY + DELETED=$((DELETED+1)) + fi + done + + if [ "$DELETED" -gt 0 ]; then + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add -A + git commit -m "chore: delete ${DELETED} retired workflow file(s) [skip ci]" \ + --author="github-actions[bot] " + git push + echo "✅ ${DELETED} retired workflow(s) deleted" >> $GITHUB_STEP_SUMMARY + else + echo "✅ No retired workflows found" >> $GITHUB_STEP_SUMMARY + fi + # ── LABEL RESET ────────────────────────────────────────────────────── - name: Reset labels to standard set - if: inputs.reset_labels == true + if: steps.tasks.outputs.reset_labels == 'true' env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | @@ -76,23 +183,16 @@ jobs: echo "## 🏷️ Label Reset" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - # Delete all existing labels - echo "Deleting existing labels..." - DELETED=0 gh api "repos/${REPO}/labels?per_page=100" --paginate --jq '.[].name' | while read -r label; do ENCODED=$(python3 -c "import urllib.parse; print(urllib.parse.quote('$label', safe=''))") - gh api -X DELETE "repos/${REPO}/labels/${ENCODED}" --silent 2>/dev/null && DELETED=$((DELETED+1)) || true + gh api -X DELETE "repos/${REPO}/labels/${ENCODED}" --silent 2>/dev/null || true done - echo "Deleted existing labels" >> $GITHUB_STEP_SUMMARY - # Create the standard 54-label set - echo "Creating standard labels..." - CREATED=0 while IFS='|' read -r name color description; do [ -z "$name" ] && continue gh api "repos/${REPO}/labels" \ -f name="$name" -f color="$color" -f description="$description" \ - --silent 2>/dev/null && CREATED=$((CREATED+1)) || true + --silent 2>/dev/null || true done << 'LABELS' joomla|7F52FF|Joomla extension or component dolibarr|FF6B6B|Dolibarr module or extension @@ -125,6 +225,7 @@ jobs: type: enhancement|84B6EB|Enhancement to existing feature type: refactor|F9D0C4|Code refactoring type: chore|FEF2C0|Maintenance tasks + type: version|0E8A16|Version-related change status: pending|FBCA04|Pending action or decision status: in-progress|0E8A16|Currently being worked on status: blocked|B60205|Blocked by another issue or dependency @@ -149,13 +250,14 @@ jobs: version-drift|FFA500|Version mismatch detected deploy-failure|CC0000|Automated deploy failure tracking template-validation-failure|D73A4A|Template workflow validation failure + version|0E8A16|Version bump or release LABELS echo "✅ Standard labels created" >> $GITHUB_STEP_SUMMARY # ── BRANCH CLEANUP ─────────────────────────────────────────────────── - name: Delete old sync branches - if: inputs.clean_branches == true + if: steps.tasks.outputs.clean_branches == 'true' env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | @@ -164,30 +266,69 @@ jobs: echo "## 🌿 Branch Cleanup" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - DELETED=0 + FOUND=false gh api "repos/${REPO}/branches?per_page=100" --jq '.[].name' | \ grep "^chore/sync-mokostandards" | \ grep -v "^${CURRENT}$" | while read -r branch; do - # Close any open PRs on this branch gh pr list --repo "$REPO" --head "$branch" --state open --json number --jq '.[].number' 2>/dev/null | while read -r pr; do gh pr close "$pr" --repo "$REPO" --comment "Superseded by \`${CURRENT}\`" 2>/dev/null || true echo " Closed PR #${pr}" >> $GITHUB_STEP_SUMMARY done - # Delete the branch gh api -X DELETE "repos/${REPO}/git/refs/heads/${branch}" --silent 2>/dev/null || true echo " Deleted: \`${branch}\`" >> $GITHUB_STEP_SUMMARY + FOUND=true + done + + if [ "$FOUND" != "true" ]; then + echo "✅ No old sync branches found" >> $GITHUB_STEP_SUMMARY + fi + + # ── WORKFLOW RUN CLEANUP ───────────────────────────────────────────── + - name: Clean up workflow runs + if: steps.tasks.outputs.clean_workflows == 'true' + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + REPO="${{ github.repository }}" + echo "## 🔄 Workflow Run Cleanup" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + DELETED=0 + # Delete cancelled and stale workflow runs + for status in cancelled stale; do + gh api "repos/${REPO}/actions/runs?status=${status}&per_page=100" \ + --jq '.workflow_runs[].id' 2>/dev/null | while read -r run_id; do + gh api -X DELETE "repos/${REPO}/actions/runs/${run_id}" --silent 2>/dev/null || true + DELETED=$((DELETED+1)) + done + done + + echo "✅ Cleaned cancelled/stale workflow runs" >> $GITHUB_STEP_SUMMARY + + # ── LOG CLEANUP ────────────────────────────────────────────────────── + - name: Delete old workflow run logs + if: steps.tasks.outputs.clean_logs == 'true' + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + REPO="${{ github.repository }}" + CUTOFF=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ) + echo "## 📋 Log Cleanup" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "Deleting logs older than: ${CUTOFF}" >> $GITHUB_STEP_SUMMARY + + DELETED=0 + gh api "repos/${REPO}/actions/runs?created=<${CUTOFF}&per_page=100" \ + --jq '.workflow_runs[].id' 2>/dev/null | while read -r run_id; do + gh api -X DELETE "repos/${REPO}/actions/runs/${run_id}/logs" --silent 2>/dev/null || true DELETED=$((DELETED+1)) done - if [ "$DELETED" -eq 0 ] 2>/dev/null; then - echo "✅ No old sync branches found" >> $GITHUB_STEP_SUMMARY - else - echo "✅ Cleanup complete" >> $GITHUB_STEP_SUMMARY - fi + echo "✅ Cleaned old workflow run logs" >> $GITHUB_STEP_SUMMARY # ── ISSUE TEMPLATE FIX ────────────────────────────────────────────── - name: Strip copyright headers from issue templates - if: inputs.fix_templates == true + if: steps.tasks.outputs.fix_templates == 'true' run: | echo "## 📋 Issue Template Cleanup" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY @@ -214,26 +355,158 @@ jobs: echo "✅ No templates need cleaning" >> $GITHUB_STEP_SUMMARY fi - # ── SELF-DELETE ───────────────────────────────────────────────────── - - name: Delete this workflow (one-time use) - if: success() + # ── REBUILD DOC INDEXES ───────────────────────────────────────────── + - name: Rebuild docs/ index files + if: steps.tasks.outputs.rebuild_indexes == 'true' + run: | + echo "## 📚 Documentation Index Rebuild" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ ! -d "docs" ]; then + echo "⏭️ No docs/ directory — skipping" >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + UPDATED=0 + # Generate index.md for each docs/ subdirectory + find docs -type d | while read -r dir; do + INDEX="${dir}/index.md" + FILES=$(find "$dir" -maxdepth 1 -name "*.md" ! -name "index.md" -printf "- [%f](./%f)\n" 2>/dev/null | sort) + if [ -z "$FILES" ]; then + continue + fi + + cat > "$INDEX" << INDEXEOF + # $(basename "$dir") + + ## Documents + + ${FILES} + + --- + *Auto-generated by repository-cleanup workflow* + INDEXEOF + # Dedent + sed -i 's/^ //' "$INDEX" + UPDATED=$((UPDATED+1)) + done + + if [ "$UPDATED" -gt 0 ]; then + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add docs/ + if ! git diff --cached --quiet; then + git commit -m "docs: rebuild documentation indexes [skip ci]" \ + --author="github-actions[bot] " + git push + echo "✅ ${UPDATED} index file(s) rebuilt and committed" >> $GITHUB_STEP_SUMMARY + else + echo "✅ All indexes already up to date" >> $GITHUB_STEP_SUMMARY + fi + else + echo "✅ No indexes to rebuild" >> $GITHUB_STEP_SUMMARY + fi + + # ── VERSION DRIFT DETECTION ────────────────────────────────────────── + - name: Check for version drift + run: | + echo "## 📦 Version Drift Check" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ ! -f "README.md" ]; then + echo "⏭️ No README.md — skipping" >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + README_VERSION=$(grep -oP '^\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' README.md 2>/dev/null | head -1) + if [ -z "$README_VERSION" ]; then + echo "⚠️ No VERSION found in README.md FILE INFORMATION block" >> $GITHUB_STEP_SUMMARY + exit 0 + fi + + echo "**README version:** \`${README_VERSION}\`" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + DRIFT=0 + CHECKED=0 + + # Check all files with FILE INFORMATION blocks + while IFS= read -r -d '' file; do + FILE_VERSION=$(grep -oP '^\s*\*?\s*VERSION:\s*\K[0-9]{2}\.[0-9]{2}\.[0-9]{2}' "$file" 2>/dev/null | head -1) + [ -z "$FILE_VERSION" ] && continue + CHECKED=$((CHECKED+1)) + if [ "$FILE_VERSION" != "$README_VERSION" ]; then + echo " ⚠️ \`${file}\`: \`${FILE_VERSION}\` (expected \`${README_VERSION}\`)" >> $GITHUB_STEP_SUMMARY + DRIFT=$((DRIFT+1)) + fi + done < <(find . -maxdepth 4 -type f \( -name "*.php" -o -name "*.md" -o -name "*.yml" \) ! -path "./.git/*" ! -path "./vendor/*" ! -path "./node_modules/*" -print0 2>/dev/null) + + echo "" >> $GITHUB_STEP_SUMMARY + if [ "$DRIFT" -gt 0 ]; then + echo "⚠️ **${DRIFT}** file(s) out of ${CHECKED} have version drift" >> $GITHUB_STEP_SUMMARY + echo "Run \`sync-version-on-merge\` workflow or update manually" >> $GITHUB_STEP_SUMMARY + else + echo "✅ All ${CHECKED} file(s) match README version \`${README_VERSION}\`" >> $GITHUB_STEP_SUMMARY + fi + + # ── PROTECT CUSTOM WORKFLOWS ──────────────────────────────────────── + - name: Ensure custom workflow directory exists + run: | + echo "## 🔧 Custom Workflows" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + if [ ! -d ".github/workflows/custom" ]; then + mkdir -p .github/workflows/custom + cat > .github/workflows/custom/README.md << 'CWEOF' + # Custom Workflows + + Place repo-specific workflows here. Files in this directory are: + - **Never overwritten** by MokoStandards bulk sync + - **Never deleted** by the repository-cleanup workflow + - Safe for custom CI, notifications, or repo-specific automation + + Synced workflows live in `.github/workflows/` (parent directory). + CWEOF + sed -i 's/^ //' .github/workflows/custom/README.md + git config --local user.email "github-actions[bot]@users.noreply.github.com" + git config --local user.name "github-actions[bot]" + git add .github/workflows/custom/ + if ! git diff --cached --quiet; then + git commit -m "chore: create .github/workflows/custom/ for repo-specific workflows [skip ci]" \ + --author="github-actions[bot] " + git push + echo "✅ Created \`.github/workflows/custom/\` directory" >> $GITHUB_STEP_SUMMARY + fi + else + CUSTOM_COUNT=$(find .github/workflows/custom -name "*.yml" -o -name "*.yaml" 2>/dev/null | wc -l) + echo "✅ Custom workflow directory exists (${CUSTOM_COUNT} workflow(s))" >> $GITHUB_STEP_SUMMARY + fi + + # ── DELETE CLOSED ISSUES ────────────────────────────────────────────── + - name: Delete old closed issues + if: steps.tasks.outputs.delete_closed_issues == 'true' env: GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} run: | - echo "## 🗑️ Self-Cleanup" >> $GITHUB_STEP_SUMMARY + REPO="${{ github.repository }}" + CUTOFF=$(date -u -d '30 days ago' +%Y-%m-%dT%H:%M:%SZ 2>/dev/null || date -u -v-30d +%Y-%m-%dT%H:%M:%SZ) + echo "## 🗑️ Closed Issue Cleanup" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY + echo "Deleting issues closed before: ${CUTOFF}" >> $GITHUB_STEP_SUMMARY - WORKFLOW_FILE=".github/workflows/repository-cleanup.yml" - if [ -f "$WORKFLOW_FILE" ]; then - git config --local user.email "github-actions[bot]@users.noreply.github.com" - git config --local user.name "github-actions[bot]" - git rm "$WORKFLOW_FILE" - git commit -m "chore: remove repository-cleanup.yml after successful run [skip ci]" \ - --author="github-actions[bot] " - git push - echo "✅ Workflow file deleted — it will not appear in future syncs" >> $GITHUB_STEP_SUMMARY + DELETED=0 + gh api "repos/${REPO}/issues?state=closed&since=1970-01-01T00:00:00Z&per_page=100&sort=updated&direction=asc" \ + --jq ".[] | select(.closed_at < \"${CUTOFF}\") | .number" 2>/dev/null | while read -r num; do + # Lock and close with "not_planned" to mark as cleaned up + gh api "repos/${REPO}/issues/${num}/lock" -X PUT -f lock_reason="resolved" --silent 2>/dev/null || true + echo " Locked issue #${num}" >> $GITHUB_STEP_SUMMARY + DELETED=$((DELETED+1)) + done + + if [ "$DELETED" -eq 0 ] 2>/dev/null; then + echo "✅ No old closed issues found" >> $GITHUB_STEP_SUMMARY else - echo "ℹ️ Workflow file already removed" >> $GITHUB_STEP_SUMMARY + echo "✅ Locked ${DELETED} old closed issue(s)" >> $GITHUB_STEP_SUMMARY fi - name: Summary @@ -241,4 +514,4 @@ jobs: run: | echo "" >> $GITHUB_STEP_SUMMARY echo "---" >> $GITHUB_STEP_SUMMARY - echo "*Run by @${{ github.actor }} via workflow_dispatch*" >> $GITHUB_STEP_SUMMARY + echo "*Run by @${{ github.actor }} — trigger: ${{ github.event_name }}*" >> $GITHUB_STEP_SUMMARY -- 2.49.1 From f42d01bf46c23cf75264b184f8db5fbfea4f6fc1 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:57 -0500 Subject: [PATCH 34/38] chore: add .github/workflows/auto-dev-issue.yml from MokoStandards --- .github/workflows/auto-dev-issue.yml | 89 ++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 .github/workflows/auto-dev-issue.yml diff --git a/.github/workflows/auto-dev-issue.yml b/.github/workflows/auto-dev-issue.yml new file mode 100644 index 0000000..87a8ad5 --- /dev/null +++ b/.github/workflows/auto-dev-issue.yml @@ -0,0 +1,89 @@ +# Copyright (C) 2026 Moko Consulting +# +# This file is part of a Moko Consulting project. +# +# SPDX-License-Identifier: GPL-3.0-or-later +# +# FILE INFORMATION +# DEFGROUP: GitHub.Workflow +# INGROUP: MokoStandards.Automation +# REPO: https://github.com/mokoconsulting-tech/MokoStandards +# PATH: /templates/workflows/shared/auto-dev-issue.yml +# VERSION: 04.02.00 +# BRIEF: Auto-create tracking issue when a dev/** branch is pushed +# NOTE: Synced via bulk-repo-sync to .github/workflows/auto-dev-issue.yml in all governed repos. + +name: Auto Dev Branch Issue + +on: + create: + +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +permissions: + contents: read + issues: write + +jobs: + create-issue: + name: Create version tracking issue + runs-on: ubuntu-latest + if: >- + github.event.ref_type == 'branch' && + startsWith(github.event.ref, 'dev/') + + steps: + - name: Create tracking issue + env: + GH_TOKEN: ${{ secrets.GH_TOKEN || github.token }} + run: | + BRANCH="${{ github.event.ref }}" + VERSION="${BRANCH#dev/}" + REPO="${{ github.repository }}" + ACTOR="${{ github.actor }}" + NOW=$(date -u '+%Y-%m-%d %H:%M UTC') + + TITLE="feat(${VERSION}): Development tracking for ${BRANCH}" + + BODY="## Development Branch Created + + | Field | Value | + |-------|-------| + | **Branch** | \`${BRANCH}\` | + | **Version** | \`${VERSION}\` | + | **Created by** | @${ACTOR} | + | **Created at** | ${NOW} | + | **Repository** | \`${REPO}\` | + + ## Checklist + + - [ ] Feature development complete + - [ ] Tests passing + - [ ] README.md version bumped to \`${VERSION}\` + - [ ] CHANGELOG.md updated + - [ ] PR created targeting \`main\` + - [ ] Code reviewed and approved + - [ ] Merged to \`main\` + + --- + *Auto-created by [auto-dev-issue.yml](.github/workflows/auto-dev-issue.yml) on branch creation.*" + + # Dedent heredoc + BODY=$(echo "$BODY" | sed 's/^ //') + + # Check for existing issue with same title prefix + EXISTING=$(gh api "repos/${REPO}/issues?state=open&per_page=5" \ + --jq ".[] | select(.title | startswith(\"feat(${VERSION})\")) | .number" 2>/dev/null | head -1) + + if [ -n "$EXISTING" ]; then + echo "ℹ️ Issue #${EXISTING} already exists for ${VERSION}" >> $GITHUB_STEP_SUMMARY + else + ISSUE_URL=$(gh issue create \ + --repo "$REPO" \ + --title "$TITLE" \ + --body "$BODY" \ + --label "type: feature,version" \ + --assignee "jmiller-moko" 2>&1) + echo "✅ Created tracking issue: ${ISSUE_URL}" >> $GITHUB_STEP_SUMMARY + fi -- 2.49.1 From f437d06cc1af136d78171fe168fb118b0fbd4cab Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:57 -0500 Subject: [PATCH 35/38] chore: update .github/workflows/standards-compliance.yml from MokoStandards --- .github/workflows/standards-compliance.yml | 149 ++++++++++++--------- 1 file changed, 86 insertions(+), 63 deletions(-) diff --git a/.github/workflows/standards-compliance.yml b/.github/workflows/standards-compliance.yml index a1ad082..f1923eb 100644 --- a/.github/workflows/standards-compliance.yml +++ b/.github/workflows/standards-compliance.yml @@ -5,7 +5,7 @@ # INGROUP: MokoStandards.Compliance # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /.github/workflows/standards-compliance.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: MokoStandards compliance validation workflow # NOTE: Validates repository structure, documentation, and coding standards @@ -740,10 +740,16 @@ jobs: fi # Check for recommended workflows - if [ -f "$WORKFLOWS_DIR/ci.yml" ] || [ -f "$WORKFLOWS_DIR/build.yml" ]; then - echo "✅ CI workflow present" >> $GITHUB_STEP_SUMMARY - else - echo "⚠️ No CI workflow found (ci.yml or build.yml)" >> $GITHUB_STEP_SUMMARY + CI_FOUND=false + for wf in ci.yml build.yml ci-dolibarr.yml ci-joomla.yml; do + if [ -f "$WORKFLOWS_DIR/$wf" ]; then + echo "✅ CI workflow present ($wf)" >> $GITHUB_STEP_SUMMARY + CI_FOUND=true + break + fi + done + if [ "$CI_FOUND" = "false" ]; then + echo "⚠️ No CI workflow found (ci.yml, build.yml, ci-dolibarr.yml, or ci-joomla.yml)" >> $GITHUB_STEP_SUMMARY fi if [ -f "$WORKFLOWS_DIR/codeql-analysis.yml" ]; then @@ -752,6 +758,15 @@ jobs: echo "⚠️ CodeQL workflow not found" >> $GITHUB_STEP_SUMMARY fi + # 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 + if [ -f "$WORKFLOWS_DIR/$wf" ]; then + echo "✅ ${wf}" >> $GITHUB_STEP_SUMMARY + else + echo "⚠️ ${wf} not found (synced from MokoStandards)" >> $GITHUB_STEP_SUMMARY + fi + done + - name: Validate Workflow Syntax run: | set -x @@ -962,29 +977,32 @@ jobs: echo "## 🔢 Version Consistency Validation" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY - if [ -f "api/validate/check_version_consistency.php" ]; then - php api/validate/check_version_consistency.php --verbose | tee /tmp/version-check.log - EXIT_CODE=$? - - echo "" >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - cat /tmp/version-check.log >> $GITHUB_STEP_SUMMARY - echo "\`\`\`" >> $GITHUB_STEP_SUMMARY - - if [ "$EXIT_CODE" -eq 0 ]; then - echo "" >> $GITHUB_STEP_SUMMARY - echo "✅ All version numbers are consistent!" >> $GITHUB_STEP_SUMMARY - exit 0 - else - echo "" >> $GITHUB_STEP_SUMMARY - echo "❌ Version mismatches detected - Please update all version references" >> $GITHUB_STEP_SUMMARY - exit 1 - fi + # Use PHP enterprise library for version consistency check + if [ -f "vendor/bin/moko" ]; then + php vendor/bin/moko check:version -- --path . --verbose 2>&1 | tee /tmp/version-check.log + EXIT_CODE=${PIPESTATUS[0]} + elif [ -f "/tmp/mokostandards/api/validate/check_version_consistency.php" ]; then + php /tmp/mokostandards/api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log + EXIT_CODE=${PIPESTATUS[0]} + elif [ -f "api/validate/check_version_consistency.php" ]; then + php api/validate/check_version_consistency.php --path . --verbose 2>&1 | tee /tmp/version-check.log + EXIT_CODE=${PIPESTATUS[0]} else - echo "ℹ️ Version consistency check script not found - skipping" >> $GITHUB_STEP_SUMMARY + echo "⏭️ Install mokoconsulting-tech/enterprise via Composer for version checks" >> $GITHUB_STEP_SUMMARY exit 0 fi + echo '```' >> $GITHUB_STEP_SUMMARY + cat /tmp/version-check.log >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + + if [ "$EXIT_CODE" -eq 0 ]; then + echo "✅ All version numbers are consistent" >> $GITHUB_STEP_SUMMARY + else + echo "❌ Version drift detected" >> $GITHUB_STEP_SUMMARY + exit 1 + fi + script-integrity: name: Script Integrity Validation runs-on: ubuntu-latest @@ -1256,58 +1274,63 @@ jobs: echo "### Secret Patterns" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY + # Helper: scan with a pattern, show results with file:line, return count + scan_pattern() { + local label="$1" icon="$2" tmpfile="$3" + local count=0 + if [ -f "$tmpfile" ]; then + count=$(wc -l < "$tmpfile") + fi + if [ "$count" -gt 0 ]; then + echo "${icon} **${label}**: ${count} finding(s)" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + echo "View locations" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + echo "| File | Line | Match |" >> $GITHUB_STEP_SUMMARY + echo "|------|------|-------|" >> $GITHUB_STEP_SUMMARY + head -20 "$tmpfile" | while IFS= read -r line; do + FILE=$(echo "$line" | cut -d: -f1 | sed 's|^\./||') + LINENO=$(echo "$line" | cut -d: -f2) + MATCH=$(echo "$line" | cut -d: -f3- | head -c 80 | sed 's/|/\\|/g') + echo "| \`${FILE}\` | ${LINENO} | \`${MATCH}\` |" >> $GITHUB_STEP_SUMMARY + done + if [ "$count" -gt 20 ]; then + echo "" >> $GITHUB_STEP_SUMMARY + echo "*... and $((count - 20)) more*" >> $GITHUB_STEP_SUMMARY + fi + echo "" >> $GITHUB_STEP_SUMMARY + echo "
" >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + VIOLATIONS=$((VIOLATIONS + count)) + fi + } + # Pattern 1: password/secret assignments - # Exclusions: - # test|example|sample - test/example files - # getenv - environment-variable reads - # /\.\*/|^\s*// - regex patterns and commented lines - # CREDENTIAL_PATTERNS|SecurityValidator|SECRET_PATTERN - scanner internals - # ===|!== - strict comparison operators (not assignments) - # ApiClient - constructor calls where token is a variable arg - if grep -r -n -E "(password|passwd|pwd|secret|api[_-]?key|token).*=.*['\"]" . \ + grep -r -n -E "(password|passwd|pwd|secret|api[_-]?key|token).*=.*['\"]" . \ --include="*.php" --include="*.py" --include="*.js" --include="*.ts" \ --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null | \ grep -v -E '(test|example|sample|getenv|/\.\*/|^\s*//|CREDENTIAL_PATTERNS|SecurityValidator|SECRET_PATTERN|===|!==|ApiClient)' | \ - grep -v "= ''" | grep -v '= ""' > /tmp/secrets1.txt 2>/dev/null; then - COUNT=$(wc -l < /tmp/secrets1.txt) - if [ "$COUNT" -gt 0 ]; then - echo "⚠️ Found $COUNT potential secret assignment(s)" >> $GITHUB_STEP_SUMMARY - VIOLATIONS=$((VIOLATIONS + COUNT)) - fi - fi + grep -v "= ''" | grep -v '= ""' > /tmp/secrets1.txt 2>/dev/null || true + scan_pattern "Secret assignments" "⚠️" /tmp/secrets1.txt # Pattern 2: Private keys - if grep -r -n "BEGIN.*PRIVATE KEY" . \ + grep -r -n "BEGIN.*PRIVATE KEY" . \ --include="*.pem" --include="*.key" --include="*.txt" \ - --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets2.txt; then - COUNT=$(wc -l < /tmp/secrets2.txt) - if [ "$COUNT" -gt 0 ]; then - echo "❌ Found $COUNT private key file(s)" >> $GITHUB_STEP_SUMMARY - VIOLATIONS=$((VIOLATIONS + COUNT)) - fi - fi + --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets2.txt || true + scan_pattern "Private keys" "❌" /tmp/secrets2.txt # Pattern 3: AWS keys - if grep -r -n -E "AKIA[0-9A-Z]{16}" . \ + grep -r -n -E "AKIA[0-9A-Z]{16}" . \ --include="*.php" --include="*.py" --include="*.js" --include="*.txt" --include="*.env" \ - --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets3.txt; then - COUNT=$(wc -l < /tmp/secrets3.txt) - if [ "$COUNT" -gt 0 ]; then - echo "❌ Found $COUNT potential AWS access key(s)" >> $GITHUB_STEP_SUMMARY - VIOLATIONS=$((VIOLATIONS + COUNT)) - fi - fi + --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets3.txt || true + scan_pattern "AWS access keys" "❌" /tmp/secrets3.txt # Pattern 4: GitHub tokens - if grep -r -n -E "gh[ps]_[a-zA-Z0-9]{36}" . \ + grep -r -n -E "gh[ps]_[a-zA-Z0-9]{36}" . \ --include="*.php" --include="*.py" --include="*.js" --include="*.txt" --include="*.env" \ - --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets4.txt; then - COUNT=$(wc -l < /tmp/secrets4.txt) - if [ "$COUNT" -gt 0 ]; then - echo "❌ Found $COUNT potential GitHub token(s)" >> $GITHUB_STEP_SUMMARY - VIOLATIONS=$((VIOLATIONS + COUNT)) - fi - fi + --exclude-dir=".git" --exclude-dir="vendor" --exclude-dir="node_modules" 2>/dev/null > /tmp/secrets4.txt || true + scan_pattern "GitHub tokens" "❌" /tmp/secrets4.txt echo "" >> $GITHUB_STEP_SUMMARY -- 2.49.1 From 77a5777c351f7f0919ee5da41301e86f47d1edc3 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:58 -0500 Subject: [PATCH 36/38] chore: update .github/workflows/codeql-analysis.yml from MokoStandards --- .github/workflows/codeql-analysis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 123a1a7..c9ddcb1 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -9,7 +9,7 @@ # INGROUP: MokoStandards.Security # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /.github/workflows/codeql-analysis.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: CodeQL security scanning workflow for PHP codebase # NOTE: Repository is PHP-only (v04.00.04). Python was removed Feb 12, 2026. -- 2.49.1 From 164b20c99e6a6eb096963f305cf7e773c8ee26a4 Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Sun, 29 Mar 2026 13:12:58 -0500 Subject: [PATCH 37/38] chore: update .github/workflows/repo_health.yml from MokoStandards --- .github/workflows/repo_health.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/repo_health.yml b/.github/workflows/repo_health.yml index d3daece..b5ba689 100644 --- a/.github/workflows/repo_health.yml +++ b/.github/workflows/repo_health.yml @@ -10,7 +10,7 @@ # INGROUP: MokoStandards.Validation # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /.github/workflows/repo_health.yml -# VERSION: 04.01.00 +# VERSION: 04.02.00 # BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts. # NOTE: Field is user-managed. # ============================================================================ @@ -83,6 +83,9 @@ env: SHELLCHECK_PATTERN: '*.sh' SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml' +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + jobs: access_check: name: Access control -- 2.49.1 From e8fdca0e0354c5dae3819a42b1edafa4d48cb2ad Mon Sep 17 00:00:00 2001 From: Jonathan Miller <230051081+jmiller-moko@users.noreply.github.com> Date: Tue, 31 Mar 2026 11:20:02 -0500 Subject: [PATCH 38/38] fix: delete retired workflows and fix duplicate env: [skip ci] Co-Authored-By: Claude Opus 4.6 (1M context) --- .github/workflows/repo_health.yml | 90 ++++++++++++++++++++++++------- 1 file changed, 70 insertions(+), 20 deletions(-) diff --git a/.github/workflows/repo_health.yml b/.github/workflows/repo_health.yml index b5ba689..2f94d29 100644 --- a/.github/workflows/repo_health.yml +++ b/.github/workflows/repo_health.yml @@ -10,8 +10,8 @@ # INGROUP: MokoStandards.Validation # REPO: https://github.com/mokoconsulting-tech/MokoStandards # PATH: /.github/workflows/repo_health.yml -# VERSION: 04.02.00 -# BRIEF: Enforces repository guardrails by validating release configuration, scripts governance, tooling availability, and core repository health artifacts. +# VERSION: 04.04.01 +# BRIEF: Dolibarr module health checks — validates release config, module descriptor, repo artifacts, and scripts governance. # NOTE: Field is user-managed. # ============================================================================ @@ -29,7 +29,7 @@ on: workflow_dispatch: inputs: profile: - description: Which configuration profile to validate. release checks SFTP variables used by release pipeline. scripts checks baseline script prerequisites. repo runs repository health only. al[...] + description: 'Validation profile: all, release, scripts, or repo' required: true default: all type: choice @@ -39,19 +39,7 @@ on: - scripts - repo pull_request: - paths: - - .github/workflows/** - - scripts/** - - docs/** - - dev/** push: - branches: - - main - paths: - - .github/workflows/** - - scripts/** - - docs/** - - dev/** permissions: contents: read @@ -68,10 +56,10 @@ env: # Repo health policy # Files are listed as-is; directories must end with a trailing slash. - REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.github/workflows/,src/ - REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,README.md,docs/ + REPO_REQUIRED_ARTIFACTS: README.md,LICENSE,CHANGELOG.md,CONTRIBUTING.md,CODE_OF_CONDUCT.md,.github/workflows/ + REPO_OPTIONAL_FILES: SECURITY.md,GOVERNANCE.md,.editorconfig,.gitattributes,.gitignore,docs/,update.txt REPO_DISALLOWED_DIRS: - REPO_DISALLOWED_FILES: TODO.md,todo.md + REPO_DISALLOWED_FILES: TODO.md,todo.md,update.json # Extended checks toggles EXTENDED_CHECKS: "true" @@ -82,8 +70,6 @@ env: WORKFLOWS_DIR: .github/workflows SHELLCHECK_PATTERN: '*.sh' SPDX_FILE_GLOBS: '*.sh,*.php,*.js,*.ts,*.css,*.xml,*.yml,*.yaml' - -env: FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true jobs: @@ -415,6 +401,15 @@ jobs: exit 0 fi + # Source directory: src/ or htdocs/ (either is valid) + if [ -d "src" ]; then + SOURCE_DIR="src" + elif [ -d "htdocs" ]; then + SOURCE_DIR="htdocs" + else + missing_required+=("src/ or htdocs/ (source directory required)") + fi + IFS=',' read -r -a required_artifacts <<< "${REPO_REQUIRED_ARTIFACTS}" IFS=',' read -r -a optional_files <<< "${REPO_OPTIONAL_FILES}" IFS=',' read -r -a disallowed_dirs <<< "${REPO_DISALLOWED_DIRS}" @@ -564,6 +559,61 @@ jobs: } >> "${GITHUB_STEP_SUMMARY}" fi + # ── Dolibarr-specific checks ────────────────────────────────────── + dolibarr_findings=() + + # Module descriptor: src/core/modules/mod*.class.php + MOD_FILE="$(find src htdocs -path '*/core/modules/mod*.class.php' -print -quit 2>/dev/null || true)" + if [ -z "${MOD_FILE}" ]; then + dolibarr_findings+=("Module descriptor not found (src/core/modules/mod*.class.php)") + else + # Check $this->numero is set and non-zero + if ! grep -qP '\$this->numero\s*=\s*[1-9]' "${MOD_FILE}"; then + dolibarr_findings+=("Module descriptor: \$this->numero not set or is zero") + fi + # Check $this->version is not hardcoded (should be set by workflow) + if grep -qP "\\\$this->version\s*=\s*'[0-9]" "${MOD_FILE}"; then + dolibarr_findings+=("Module descriptor: \$this->version appears hardcoded (should be set by deploy/release workflow)") + fi + # Check url_last_version points to update.txt + if grep -qP 'url_last_version.*update\.json' "${MOD_FILE}"; then + dolibarr_findings+=("Module descriptor: url_last_version points to update.json (must be update.txt)") + fi + # Check url_last_version contains /main/ for main branch + CURRENT_BRANCH="${GITHUB_REF_NAME:-main}" + if [ "${CURRENT_BRANCH}" = "main" ] && ! grep -qP 'url_last_version.*\/main\/' "${MOD_FILE}"; then + dolibarr_findings+=("Module descriptor: url_last_version does not reference /main/ branch") + fi + fi + + # Source README should exist (Dolibarr module store requirement) + if [ -n "${SOURCE_DIR:-}" ] && [ ! -f "${SOURCE_DIR}/README.md" ]; then + dolibarr_findings+=("${SOURCE_DIR}/README.md missing (required for Dolibarr module store)") + fi + + # update.txt should exist in root (created by auto-release) + if [ ! -f 'update.txt' ]; then + dolibarr_findings+=("update.txt missing in root (created by auto-release workflow)") + fi + + if [ "${#dolibarr_findings[@]}" -gt 0 ]; then + { + printf '%s\n' '### Dolibarr module checks' + printf '%s\n' '| Check | Status |' + printf '%s\n' '|---|---|' + for f in "${dolibarr_findings[@]}"; do + printf '%s\n' "| ${f} | Warning |" + done + printf '\n' + } >> "${GITHUB_STEP_SUMMARY}" + else + { + printf '%s\n' '### Dolibarr module checks' + printf '%s\n' 'All Dolibarr-specific checks passed.' + printf '\n' + } >> "${GITHUB_STEP_SUMMARY}" + fi + extended_enabled="${EXTENDED_CHECKS:-true}" extended_findings=() -- 2.49.1