chore(deps)(deps): bump the github-actions group with 2 updates #3

Merged
dependabot[bot] merged 4 commits from dependabot/github_actions/github-actions-83b0d24361 into main 2026-03-07 14:51:46 +00:00
35 changed files with 8 additions and 7730 deletions
-94
View File
@@ -1,94 +0,0 @@
---
name: Bug Report
about: Report a bug or issue with MokoStandards scripts, schemas, or documentation
title: '[BUG] '
labels: ['bug']
assignees: []
---
## Bug Description
**Brief summary of the issue:**
**Affected component**:
- [ ] Script (specify: _____________)
- [ ] Schema (specify: _____________)
- [ ] Workflow (specify: _____________)
- [ ] Documentation (specify: _____________)
- [ ] Enterprise library (specify: _____________)
## Steps to Reproduce
1.
2.
3.
## Expected Behavior
What should have happened:
## Actual Behavior
What actually happened:
## Environment
**Operating System**:
- [ ] Windows (version: _______)
- [ ] macOS (version: _______)
- [ ] Linux (distribution: _______)
**Software Versions**:
- Python version:
- PowerShell version:
- Bash version:
- Git version:
**Repository Context**:
- Repository type: [ ] Generic [ ] Joomla/WaaS [ ] Dolibarr/CRM
- MokoStandards version/commit:
## Error Messages
```
Paste any error messages, stack traces, or log output here
```
## Screenshots
If applicable, add screenshots to help explain the problem.
## Additional Context
Any other relevant information about the problem:
## Potential Solution
If you have ideas about what might fix the issue:
## Impact
**Severity**:
- [ ] Critical (blocking work, security issue)
- [ ] High (significant impact, workaround exists)
- [ ] Medium (annoying but manageable)
- [ ] Low (minor inconvenience)
**Affected users/repos**:
- [ ] Just me
- [ ] My team
- [ ] Multiple teams
- [ ] All organization repos
## Checklist
- [ ] I have searched existing issues to avoid duplicates
- [ ] I have included all relevant information
- [ ] I have tested with the latest version of MokoStandards
- [ ] I have included error messages and logs
- [ ] I have specified my environment details
@@ -1,114 +0,0 @@
---
name: Dev Branch Tracking
about: Manually create a tracking issue for a development branch
title: 'Development Branch: dev/XX.YY.ZZ'
labels: ['automation', 'version-management', 'dev-branch']
assignees: ['copilot', 'jmiller-moko']
---
## Development Branch Created
A development branch tracking issue for coordinating work on a version branch.
### Details
- **Branch**: `dev/XX.YY.ZZ` (replace with actual branch name)
- **Version**: XX.YY.ZZ (replace with actual version)
- **Created**: <!-- Date created -->
### Next Steps
1. Checkout the branch: `git fetch origin && git checkout dev/XX.YY.ZZ`
2. Begin development for version XX.YY.ZZ
3. Create PRs targeting this branch for feature development
4. When ready, merge this branch to main for release
### Branch Strategy
This branch follows the semantic versioning patch increment strategy. It represents a patch release.
---
## Launch Checklist - Prepare for Merge to Main
Complete this checklist before merging this dev branch to main. Reference: [Copilot Pre-Merge Checklist Policy](https://github.com/mokoconsulting-tech/MokoStandards/blob/main/docs/policy/copilot-pre-merge-checklist.md)
### 1. Version Management ✅
- [ ] All version numbers updated consistently (VERSION file, package.json, etc.)
- [ ] Version updated in documentation headers
- [ ] Version updated in CHANGELOG.md
- [ ] No version number inconsistencies remain
### 2. Changelog Updates ✅
- [ ] CHANGELOG.md updated with all branch changes
- [ ] Changes grouped by type (Added, Changed, Fixed, Deprecated, Removed, Security)
- [ ] Clear descriptions with implementation details
- [ ] Files affected listed
- [ ] Proper date format used (YYYY-MM-DD or ISO 8601 UTC)
### 3. Code Review Response ✅
- [ ] All review comments addressed
- [ ] Requested changes implemented
- [ ] Explanations provided for declined suggestions
- [ ] Re-review requested if significant changes made
### 4. Security Scanning ✅
- [ ] CodeQL security analysis completed
- [ ] Dependency vulnerabilities checked
- [ ] No secrets/credentials in code
- [ ] Critical and high severity issues fixed
- [ ] Accepted risks documented (if any)
### 5. Code Quality ✅
- [ ] All linters pass without errors
- [ ] Code properly formatted
- [ ] No compiler warnings
- [ ] All tests passing
- [ ] Code coverage meets threshold
- [ ] Shell scripts validated with shellcheck
### 6. Documentation Updates ✅
- [ ] README updated (if public API changed)
- [ ] API documentation updated
- [ ] User guides updated (if features changed)
- [ ] Code comments accurate and complete
- [ ] Examples working and updated
- [ ] Links validated
### 7. Drift Detection ✅
- [ ] Documentation matches implementation
- [ ] File paths in docs are correct
- [ ] Code examples validated and working
- [ ] Workflow inputs match documentation
- [ ] No outdated information remains
### 8. Standards Compliance ✅
- [ ] File headers present and correct
- [ ] Tabs used (not spaces) except in YAML/Makefiles
- [ ] Timestamps use UTC
- [ ] Revision histories in descending order
- [ ] Metadata tables complete and accurate
- [ ] Semantic versioning followed
### 9. Release Preparation ✅
- [ ] Release notes drafted
- [ ] Breaking changes documented
- [ ] Migration guide prepared (if needed)
- [ ] Deployment notes documented
- [ ] Rollback plan prepared
### 10. Final Verification ✅
- [ ] All PRs to this branch reviewed and merged
- [ ] No pending issues blocking release
- [ ] Stakeholders notified of upcoming merge
- [ ] Final PR to main created and ready for review
- [ ] All checklist items above completed
---
### 📝 Pull Requests
This section tracks all PRs associated with this branch:
<!-- PRs will be automatically linked by the enterprise-issue-manager workflow -->
---
*This is a manual tracking issue. For automatically created tracking issues, merge a PR to main to trigger the auto-create-dev-branch workflow.*
-107
View File
@@ -1,107 +0,0 @@
---
name: Documentation Issue
about: Report missing, unclear, or incorrect documentation
title: '[DOCS] '
labels: ['documentation']
assignees: []
---
## Documentation Issue
**Type of issue**:
- [ ] Missing documentation
- [ ] Unclear/confusing documentation
- [ ] Incorrect/outdated documentation
- [ ] Broken links
- [ ] Typos/grammar
- [ ] Missing examples
- [ ] Other: __________
## Location
**Affected documentation**:
- File:
- Section:
- URL (if applicable):
**Related scripts/features** (if applicable):
## Current State
**What's currently documented** (or what's missing):
## Problem
**What's the issue with the current documentation?**
**How does this affect users?**
## Proposed Improvement
**What should be added/changed/fixed:**
**Suggested content** (draft text or outline):
```markdown
# Your suggested documentation content here
```
## Target Audience
**Who needs this documentation?**
- [ ] New users/contributors
- [ ] Experienced developers
- [ ] DevOps engineers
- [ ] System administrators
- [ ] All users
## Priority
**Impact on users**:
- [ ] Critical (blocking adoption/usage)
- [ ] High (frequently referenced, currently confusing)
- [ ] Medium (would help some users)
- [ ] Low (minor improvement)
## Related Documentation
**Related documentation sections**:
-
-
**External references** (if any):
-
-
## Examples Needed
**What examples would help?**
- [ ] Code examples
- [ ] Command examples
- [ ] Configuration examples
- [ ] Workflow examples
- [ ] Diagrams/flowcharts
- [ ] Screenshots
## Additional Context
**Any other relevant information:**
**Screenshots of current documentation** (if applicable):
## Checklist
- [ ] I have searched existing issues to avoid duplicates
- [ ] I have identified the specific location of the issue
- [ ] I have provided clear suggestions for improvement
- [ ] I have considered the target audience
- [ ] I am willing to contribute a documentation PR (if applicable)
-141
View File
@@ -1,141 +0,0 @@
---
name: Feature Request
about: Suggest a new feature, script, or enhancement for MokoStandards
title: '[FEATURE] '
labels: ['enhancement']
assignees: []
---
## Feature Description
**Brief summary of the proposed feature:**
**Category**:
- [ ] New script
- [ ] Enhancement to existing script
- [ ] New enterprise library
- [ ] Schema improvement
- [ ] Documentation improvement
- [ ] Workflow enhancement
- [ ] Other (specify): __________
## Problem Statement
**What problem does this feature solve?**
**Who is affected by this problem?**
- [ ] Individual developers
- [ ] Development teams
- [ ] DevOps teams
- [ ] All organization members
- [ ] External contributors
## Proposed Solution
**Describe your proposed solution:**
**How should it work?**
1.
2.
3.
**Example usage** (if applicable):
```bash
# Example command or code
```
## Alternatives Considered
**What alternatives have you considered?**
**Why is this solution better?**
## Benefits
**What are the expected benefits?**
- [ ] Improved productivity
- [ ] Better code quality
- [ ] Enhanced security
- [ ] Cost savings
- [ ] Compliance/audit improvements
- [ ] Developer experience
- [ ] Other: __________
**Estimated impact**:
## Implementation Details
**Do you have implementation ideas?**
**Required resources**:
- [ ] Development time (estimate: _____ hours/days)
- [ ] Testing infrastructure
- [ ] Documentation
- [ ] Training materials
- [ ] External dependencies (specify): __________
## Compatibility
**Platform compatibility**:
- [ ] Generic projects
- [ ] Joomla/MokoWaaS components
- [ ] Dolibarr/MokoCRM modules
- [ ] All platforms
**Backward compatibility**:
- [ ] Fully backward compatible
- [ ] Requires migration (describe): __________
- [ ] Breaking change (justify): __________
## Priority
**How urgent is this feature?**
- [ ] Critical (needed urgently)
- [ ] High (would significantly help)
- [ ] Medium (nice to have)
- [ ] Low (future consideration)
**Justification for priority**:
## Related Issues
**Related issues or PRs**:
- #
- #
## Acceptance Criteria
**How will we know when this feature is complete?**
- [ ]
- [ ]
- [ ]
## Additional Context
**Any other relevant information:**
**Screenshots/Mockups** (if applicable):
## Checklist
- [ ] I have searched existing issues to avoid duplicates
- [ ] I have clearly described the problem and solution
- [ ] I have considered alternatives
- [ ] I have estimated the impact and benefits
- [ ] I have checked compatibility requirements
- [ ] I am willing to contribute to implementation (if applicable)
-86
View File
@@ -1,86 +0,0 @@
---
name: Question
about: Ask a question about MokoStandards usage, features, or best practices
title: '[QUESTION] '
labels: ['question']
assignees: []
---
## Question
**Your question:**
## Context
**What are you trying to accomplish?**
**What have you already tried?**
**Category**:
- [ ] Script usage
- [ ] Enterprise library integration
- [ ] Schema configuration
- [ ] Workflow setup
- [ ] Documentation interpretation
- [ ] Best practices
- [ ] Platform-specific (Generic/Joomla/Dolibarr)
- [ ] Other: __________
## Environment (if relevant)
**Your setup**:
- Operating System:
- Repository type: [ ] Generic [ ] Joomla/WaaS [ ] Dolibarr/CRM
- MokoStandards version:
## What You've Researched
**Documentation reviewed**:
- [ ] README.md
- [ ] Script documentation (/docs/scripts/)
- [ ] Enterprise library docs
- [ ] Schema documentation
- [ ] Sublime Text setup guide
- [ ] Other (specify): __________
**Similar issues/questions found**:
- #
- #
## Expected Outcome
**What result are you hoping for?**
## Code/Configuration Samples
**Relevant code or configuration** (if applicable):
```bash
# Your code here
```
## Additional Context
**Any other relevant information:**
**Screenshots** (if helpful):
## Urgency
- [ ] Urgent (blocking work)
- [ ] Normal (can work on other things meanwhile)
- [ ] Low priority (just curious)
## Checklist
- [ ] I have searched existing issues and discussions
- [ ] I have reviewed relevant documentation
- [ ] I have provided sufficient context
- [ ] I have included code/configuration samples if relevant
- [ ] This is a genuine question (not a bug report or feature request)
-110
View File
@@ -1,110 +0,0 @@
---
name: License Request
about: Request an organization license for Sublime Text
title: '[LICENSE REQUEST] Sublime Text - [Your Name]'
labels: ['license-request', 'admin']
assignees: []
---
## License Request
### Tool Information
**Tool Name**: Sublime Text
**License Type Requested**: Organization Pool
**Personal Purchase**:
- [ ] I prefer to purchase my own license ($99 USD - recommended, immediate access)
- [ ] I prefer an organization license (1-2 business days, organization use only)
- [ ] I have already purchased my own license (registration only for support)
### Requestor Information
**Name**:
**GitHub Username**: @
**Email**: @mokoconsulting.tech
**Team/Department**:
**Manager**: @
### Justification
**Why do you need this license?**
**Primary use case**:
- [ ] Remote development (SFTP to servers)
- [ ] Local development
- [ ] Code review
- [ ] Documentation editing
- [ ] Other (specify):
**Which projects/repositories will you work on?**
**Have you evaluated the free trial?**
- [ ] Yes, I've used the trial and Sublime Text meets my needs
- [ ] No, requesting license before trial
**Alternative tools considered**:
- [ ] VS Code (free alternative)
- [ ] Vim/Neovim (free, terminal-based)
- [ ] Other: _______________
### Platform
- [ ] Windows
- [ ] macOS
- [ ] Linux (distribution: ________)
### Urgency
- [ ] Urgent (needed within 24 hours - please justify)
- [ ] Normal (1-2 business days)
- [ ] Low priority (when available)
**If urgent, please explain why:**
### SFTP Plugin
**Note**: Sublime SFTP plugin ($16 USD) is a **separate personal purchase** and is NOT provided by the organization.
- [ ] I understand SFTP plugin requires separate personal purchase
- [ ] I have already purchased SFTP plugin
- [ ] I will purchase SFTP plugin if needed for my work
- [ ] I don't need SFTP plugin (local development only)
### Acknowledgments
- [ ] I have read the License Management Policy (/docs/github-private/LICENSE_MANAGEMENT.md)
- [ ] I understand organization licenses are for work use only
- [ ] I understand organization licenses must be returned upon leaving
- [ ] I understand personal purchases ($99) are an alternative with lifetime access
- [ ] I understand SFTP plugin ($16) requires separate personal purchase
- [ ] I agree to the terms of use
### Additional Information
**Expected daily usage hours**: _____ hours/day
**Duration of need**:
- [ ] Permanent (ongoing role)
- [ ] Temporary project (_____ months)
- [ ] Trial/Evaluation (_____ weeks)
**Comments/Questions**:
---
## For Admin Use Only
**Do not edit below this line**
- [ ] Manager approval received (@manager-username)
- [ ] License available in pool (current: __/20)
- [ ] License type confirmed (Organization / Personal registration)
- [ ] License key sent via encrypted email
- [ ] Activation confirmed by user
- [ ] Added to license tracking sheet
- [ ] User notified of SFTP plugin requirement
**License Key ID**: _____________
**Date Issued**: _____________
**Issued By**: @_____________
**Notes**:
-127
View File
@@ -1,127 +0,0 @@
---
name: Security Vulnerability
about: Report a security vulnerability (use private reporting if critical)
title: '[SECURITY] '
labels: ['security']
assignees: []
---
## ⚠️ Security Vulnerability Report
**IMPORTANT**: For **critical vulnerabilities**, please use GitHub's [Private Vulnerability Reporting](https://github.com/mokoconsulting-tech/MokoStandards/security/advisories/new) or email security@mokoconsulting.tech directly. Do NOT create a public issue.
Use this template only for **low to medium severity** issues that don't pose immediate risk.
---
## Vulnerability Summary
**Brief description** (without sensitive details):
**Affected component**:
- [ ] Script
- [ ] Enterprise library
- [ ] Workflow
- [ ] Schema
- [ ] Documentation
- [ ] Other: __________
## Severity Assessment
**Severity level** (your assessment):
- [ ] Critical (immediate exploitation possible, high impact)
- [ ] High (exploitation likely, significant impact)
- [ ] Medium (exploitation possible with conditions, moderate impact)
- [ ] Low (theoretical risk, minimal impact)
**CVSS Score** (if calculated): _____ / 10
## Affected Versions
**MokoStandards version(s)**:
- Commit/tag:
**Affected platforms**:
- [ ] All platforms
- [ ] Windows
- [ ] macOS
- [ ] Linux
- [ ] Generic repos
- [ ] Joomla/WaaS repos
- [ ] Dolibarr/CRM repos
## Impact Analysis
**What could an attacker do?**
**What data/systems are at risk?**
**Who is affected?**
- [ ] All organization members
- [ ] Repository administrators
- [ ] CI/CD pipelines
- [ ] Specific teams (specify): __________
## Steps to Reproduce
**Proof of concept** (without exploit code):
1.
2.
3.
## Potential Fix
**Do you have suggestions for remediation?**
**Temporary workarounds** (if any):
## References
**Related CVEs, advisories, or security issues**:
-
-
**Security best practices violated**:
-
## Discovery Context
**How was this discovered?**
- [ ] Security audit
- [ ] Code review
- [ ] Automated scanning (tool: ______)
- [ ] Incident response
- [ ] User report
- [ ] Other: __________
## Additional Information
**Relevant logs, configurations, or context** (sanitized):
## Responsible Disclosure
- [ ] I understand this is a public issue and should not contain sensitive details
- [ ] I have verified this is NOT a critical vulnerability requiring private reporting
- [ ] I have checked for existing security advisories
- [ ] I am willing to work with maintainers on a fix (if applicable)
- [ ] I understand security@mokoconsulting.tech is the contact for critical issues
## Checklist for Maintainers
**Do not edit below this line**
- [ ] Severity confirmed
- [ ] Impact assessment completed
- [ ] Fix developed
- [ ] Fix tested
- [ ] Security advisory created (if needed)
- [ ] Affected users notified
- [ ] CVE requested (if applicable)
- [ ] Documentation updated
-116
View File
@@ -1,116 +0,0 @@
name: Sub-Task
description: Create a sub-task or sub-issue to track a specific piece of work related to a parent issue
title: "[Task] "
labels: ["sub-task"]
assignees: []
body:
- type: markdown
attributes:
value: |
## Sub-Task Issue
This template is for creating sub-tasks that are part of a larger parent issue. Sub-tasks help break down complex work into manageable pieces.
- type: input
id: parent_issue
attributes:
label: Parent Issue
description: The issue number this sub-task belongs to (e.g., #193)
placeholder: "#193"
validations:
required: true
- type: input
id: task_title
attributes:
label: Task Title
description: A brief, descriptive title for this sub-task
placeholder: "Investigate token permissions issue"
validations:
required: true
- type: textarea
id: task_description
attributes:
label: Task Description
description: Detailed description of what needs to be done
placeholder: "Describe the specific work to be completed..."
validations:
required: true
- type: dropdown
id: task_type
attributes:
label: Task Type
description: What type of work is this?
options:
- Investigation
- Bug Fix
- Feature Implementation
- Documentation
- Testing
- Refactoring
- Configuration
- Other
validations:
required: true
- type: dropdown
id: priority
attributes:
label: Priority
description: How urgent is this sub-task?
options:
- Low
- Medium
- High
- Critical
default: 1
validations:
required: true
- type: textarea
id: acceptance_criteria
attributes:
label: Acceptance Criteria
description: What conditions must be met for this sub-task to be considered complete?
placeholder: |
- [ ] Criterion 1
- [ ] Criterion 2
- [ ] Criterion 3
value: |
- [ ]
validations:
required: false
- type: textarea
id: dependencies
attributes:
label: Dependencies
description: Does this sub-task depend on other issues or sub-tasks?
placeholder: "List any blocking issues or required prerequisites..."
validations:
required: false
- type: textarea
id: notes
attributes:
label: Additional Notes
description: Any other relevant information
placeholder: "Additional context, links, or references..."
validations:
required: false
- type: checkboxes
id: checklist
attributes:
label: Pre-submission Checklist
description: Please confirm before creating this sub-task
options:
- label: This sub-task is linked to a parent issue
required: true
- label: The task description is clear and actionable
required: true
- label: I have assigned appropriate labels and priority
required: false
-107
View File
@@ -1,107 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: GitHub.Dependabot
# INGROUP: MokoStandards.Security
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/dependabot.yml
# VERSION: 04.00.03
# BRIEF: Dependabot configuration for automated dependency updates and security patches
# NOTE: Monitors GitHub Actions for vulnerabilities and keeps ecosystem secure
version: 2
updates:
# Monitor GitHub Actions for security updates
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 1
labels:
- "dependencies"
- "security"
- "automated"
commit-message:
prefix: "chore(deps)"
include: "scope"
reviewers:
- "mokoconsulting-tech/maintainers"
assignees:
- "jmiller-moko"
# Group all updates together
groups:
github-actions:
patterns:
- "*"
# Monitor Python dependencies for security updates
- package-ecosystem: "pip"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 1
labels:
- "dependencies"
- "security"
- "automated"
- "python"
commit-message:
prefix: "chore(deps)"
include: "scope"
reviewers:
- "mokoconsulting-tech/maintainers"
assignees:
- "jmiller-moko"
# Group all updates together
groups:
python-dependencies:
patterns:
- "*"
# Monitor npm dependencies for security updates
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 1
labels:
- "dependencies"
- "security"
- "automated"
- "javascript"
commit-message:
prefix: "chore(deps)"
include: "scope"
reviewers:
- "mokoconsulting-tech/maintainers"
assignees:
- "jmiller-moko"
# Group all updates together
groups:
npm-dependencies:
patterns:
- "*"
# Monitor Composer dependencies for security updates
- package-ecosystem: "composer"
directory: "/"
schedule:
interval: "monthly"
open-pull-requests-limit: 1
labels:
- "dependencies"
- "security"
- "automated"
- "php"
commit-message:
prefix: "chore(deps)"
include: "scope"
reviewers:
- "mokoconsulting-tech/maintainers"
assignees:
- "jmiller-moko"
# Group all updates together
groups:
composer-dependencies:
patterns:
- "*"
-191
View File
@@ -1,191 +0,0 @@
## Description
<!-- Provide a clear and concise description of the changes in this PR -->
## Type of Change
<!-- Check all that apply -->
- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)
- [ ] Documentation update
- [ ] Infrastructure/tooling change
- [ ] Refactoring (no functional changes)
- [ ] Performance improvement
- [ ] Security fix
## Related Issues
<!-- Link to related issues, e.g., "Fixes #123" or "Relates to #456" -->
Fixes #
Relates to #
## Pre-Merge Copilot Checklist
<!-- All items must be completed before merge. See docs/policy/copilot-pre-merge-checklist.md for details and sample prompts -->
### 1. Version Management ✅
- [ ] All version numbers updated consistently (VERSION file, package.json, etc.)
- [ ] Version updated in documentation headers
- [ ] Version updated in CHANGELOG.md
- [ ] No version number inconsistencies remain
**Copilot Prompt Used**:
```
Update all version numbers from X.Y.Z to X.Y.Z+1 across the repository
```
### 2. Changelog Updates ✅
- [ ] CHANGELOG.md updated with all PR changes
- [ ] Changes grouped by type (Added, Changed, Fixed, Deprecated, Removed, Security)
- [ ] Clear descriptions with implementation details
- [ ] Files affected listed
- [ ] Proper date format used (YYYY-MM-DD or ISO 8601 UTC)
**Copilot Prompt Used**:
```
Update CHANGELOG.md with all changes from this PR, grouped by type with implementation details
```
### 3. Code Review Response ✅
- [ ] All review comments addressed
- [ ] Requested changes implemented
- [ ] Explanations provided for declined suggestions
- [ ] Re-review requested if significant changes made
### 4. Security Scanning ✅
- [ ] CodeQL security analysis completed
- [ ] Dependency vulnerabilities checked
- [ ] No secrets/credentials in code
- [ ] Critical and high severity issues fixed
- [ ] Accepted risks documented (if any)
**Security Scan Results**: <!-- Link to scan results or summarize findings -->
### 5. Code Quality ✅
- [ ] All linters pass without errors
- [ ] Code properly formatted
- [ ] No compiler warnings
- [ ] All tests passing
- [ ] Code coverage meets threshold
- [ ] Shell scripts validated with shellcheck
**Test Results**: <!-- Summarize test execution results -->
### 6. Documentation Updates ✅
- [ ] README updated (if public API changed)
- [ ] API documentation updated
- [ ] User guides updated (if features changed)
- [ ] Code comments accurate and complete
- [ ] Examples working and updated
- [ ] Links validated
### 7. Drift Detection ✅
- [ ] Documentation matches implementation
- [ ] File paths in docs are correct
- [ ] Code examples validated and working
- [ ] Workflow inputs match documentation
- [ ] No outdated information remains
### 8. Standards Compliance ✅
- [ ] File headers present and correct
- [ ] Tabs used (not spaces) except in YAML/Makefiles
- [ ] Timestamps use UTC
- [ ] Revision histories in descending order
- [ ] Metadata tables complete and accurate
- [ ] Semantic versioning followed
## Testing Performed
<!-- Describe the testing you've done -->
### Unit Tests
- [ ] All existing tests pass
- [ ] New tests added for new functionality
- [ ] Edge cases covered
### Integration Tests
- [ ] Integration tests pass
- [ ] End-to-end scenarios tested
### Manual Testing
<!-- Describe manual testing performed -->
## Breaking Changes
<!-- If this introduces breaking changes, describe them here -->
- None
<!-- OR -->
### Breaking Change Details
<!-- Describe what breaks and how to migrate -->
## Deployment Notes
<!-- Any special deployment considerations? -->
- None
<!-- OR -->
<!-- Describe special deployment steps, configuration changes, database migrations, etc. -->
## Screenshots/Videos
<!-- If applicable, add screenshots or videos demonstrating the changes -->
## Comprehensive Pre-Merge Prompt (Optional)
<!-- If you used the comprehensive pre-merge prompt, document it here -->
<details>
<summary>Comprehensive Prompt Used</summary>
```
Prepare this PR for merge by completing all pre-merge requirements:
1. UPDATE VERSION NUMBERS: Update all version numbers from X.Y.Z to X.Y.Z+1
2. UPDATE CHANGELOG: Review all commits and update CHANGELOG.md
3. ADDRESS CODE REVIEW: Review and address all code review comments
4. RUN SECURITY SCANS: Execute CodeQL, dependency scanning, secret detection
5. FIX QUALITY ISSUES: Run linters, formatters, tests
6. UPDATE DOCUMENTATION: Update README, API docs, user guides, examples
7. CHECK FOR DRIFT: Validate documentation matches implementation
8. VERIFY STANDARDS COMPLIANCE: File headers, indentation, timestamps, metadata
9. CREATE FINAL SUMMARY: Generate comprehensive PR description
10. REQUEST FINAL REVIEW: Tag reviewers for final approval
```
</details>
## Additional Context
<!-- Add any other context about the PR here -->
## Checklist for Reviewers
<!-- For reviewers to verify -->
- [ ] Code changes align with described functionality
- [ ] Pre-merge checklist completed
- [ ] Version numbers consistent
- [ ] CHANGELOG accurate and complete
- [ ] Tests adequate and passing
- [ ] Documentation updated
- [ ] No security concerns
- [ ] Follows coding standards
- [ ] Breaking changes properly documented
- [ ] Deployment notes clear
---
**Policy Reference**: [Copilot Pre-Merge Checklist Policy](../docs/policy/copilot-pre-merge-checklist.md)
<!--
For detailed guidance on each checklist item and sample Copilot prompts,
see docs/policy/copilot-pre-merge-checklist.md
-->
@@ -1,372 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: MokoStandards.Workflows
# INGROUP: MokoStandards.Automation
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/auto-create-dev-branch.yml
# VERSION: 04.00.03
# BRIEF: Automatically creates dev/<version> branch and tracking issue assigned to copilot and jmiller-moko
name: Auto-Create Dev Branch
env:
ACTIONS_STEP_DEBUG: true
ACTIONS_RUNNER_DEBUG: true
# MokoStandards Policy Compliance:
# - File formatting: Enforces organizational coding standards
# - Reference: docs/policy/file-formatting.md
# ┌─────────────────────────────────────────────────────────────────────────┐
# │ WORKFLOW FLOW DIAGRAM │
# └─────────────────────────────────────────────────────────────────────────┘
#
# TRIGGER: PR Merged to Main
# │
# ▼
# ┌──────────────────┐
# │ Extract Current │
# │ Version │──────┐ Read CHANGELOG.md, VERSION file
# │ (XX.YY.ZZ) │ │ or fallback to 03.00.00
# └──────────────────┘ │
# │ │
# ▼ │
# ┌──────────────────┐ │
# │ Calculate Next │◀─────┘
# │ Version │
# │ (XX.YY.ZZ+1) │
# └──────────────────┘
# │
# ├─────────────────────────┐
# ▼ ▼
# ┌──────────────────┐ ┌──────────────────┐
# │ Create Branch │ │ Create Issue │
# │ dev/XX.YY.ZZ │ │ "Dev Branch: │
# │ │ │ vXX.YY.ZZ" │
# └──────────────────┘ └──────────────────┘
# │ │
# │ ▼
# │ ┌──────────────────┐
# │ │ Assign to: │
# │ │ • copilot │
# │ │ • jmiller-moko │
# │ └──────────────────┘
# │ │
# └─────────────┬───────────┘
# ▼
# ┌──────────────┐
# │ OUTPUTS: │
# │ • New Branch │
# │ • New Issue │
# └──────────────┘
on:
pull_request:
types: [closed]
branches:
- main
permissions:
contents: write
pull-requests: write
issues: write
jobs:
create-dev-branch:
name: Create Development Branch with Version Bump
runs-on: ubuntu-latest
if: github.event.pull_request.merged == true
steps:
- name: Checkout repository
uses: actions/checkout@v6
with:
fetch-depth: 0
token: ${{ secrets.GITHUB_TOKEN }}
- name: Configure Git
run: |
set -x
git config --global user.name "github-actions[bot]"
git config --global user.email "github-actions[bot]@users.noreply.github.com"
- name: Extract current version
id: version
run: |
set -x
# Try to extract version from CHANGELOG.md first
if [ -f "CHANGELOG.md" ]; then
# Look for version in format [XX.YY.ZZ] or XX.YY.ZZ
VERSION=$(grep -oP '\[?\d+\.\d+\.\d+\]?' CHANGELOG.md | head -1 | tr -d '[]')
fi
# Fallback: Try to find VERSION file or header
if [ -z "$VERSION" ]; then
if [ -f "VERSION" ]; then
VERSION=$(cat VERSION)
else
# Look for VERSION: in any markdown file
VERSION=$(grep -r "^VERSION: " . --include="*.md" | head -1 | grep -oP '\d+\.\d+\.\d+' || echo "03.00.00")
fi
fi
echo "Current version: $VERSION"
echo "current=$VERSION" >> $GITHUB_OUTPUT
- name: Calculate next patch version
id: next_version
run: |
set -x
CURRENT="${{ steps.version.outputs.current }}"
# Parse version components
IFS='.' read -r MAJOR MINOR PATCH <<< "$CURRENT"
# Increment patch version
NEXT_PATCH=$((PATCH + 1))
# Format with leading zeros if needed
if [ ${#MAJOR} -eq 2 ]; then
# Zero-padded format (XX.YY.ZZ)
NEXT_VERSION=$(printf "%02d.%02d.%02d" "$MAJOR" "$MINOR" "$NEXT_PATCH")
else
# Standard semver format (X.Y.Z)
NEXT_VERSION="$MAJOR.$MINOR.$NEXT_PATCH"
fi
echo "Next version: $NEXT_VERSION"
echo "version=$NEXT_VERSION" >> $GITHUB_OUTPUT
- name: Check if dev branch already exists
id: check_branch
run: |
set -x
BRANCH_NAME="dev/${{ steps.next_version.outputs.version }}"
if git ls-remote --heads origin "$BRANCH_NAME" | grep -q "$BRANCH_NAME"; then
echo "exists=true" >> $GITHUB_OUTPUT
echo "Branch $BRANCH_NAME already exists"
else
echo "exists=false" >> $GITHUB_OUTPUT
echo "Branch $BRANCH_NAME does not exist"
fi
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
- name: Create new dev branch
if: steps.check_branch.outputs.exists == 'false'
run: |
set -x
BRANCH_NAME="${{ steps.check_branch.outputs.branch_name }}"
# Create branch from main
git checkout main
git pull origin main
git checkout -b "$BRANCH_NAME"
# Push new branch
git push origin "$BRANCH_NAME"
echo "✅ Created and pushed branch: $BRANCH_NAME"
- name: Create tracking issue
if: steps.check_branch.outputs.exists == 'false'
uses: actions/github-script@v8
with:
script: |
const nextVersion = '${{ steps.next_version.outputs.version }}';
const branchName = '${{ steps.check_branch.outputs.branch_name }}';
const prNumber = context.payload.pull_request.number;
const prTitle = context.payload.pull_request.title;
const issueBody = `## Development Branch Created
A new development branch has been automatically created following the merge of PR #${prNumber}.
### Details
- **Branch**: \`${branchName}\`
- **Version**: ${nextVersion}
- **Merged PR**: #${prNumber} - ${prTitle}
- **Created**: ${new Date().toISOString()}
### Next Steps
1. Checkout the new branch: \`git fetch origin && git checkout ${branchName}\`
2. Begin development for version ${nextVersion}
3. Create PRs targeting this branch for feature development
4. When ready, merge this branch to main for release
### Branch Strategy
This branch follows the semantic versioning patch increment strategy. It represents the next patch release after the current version.
---
## Launch Checklist - Prepare for Merge to Main
Complete this checklist before merging this dev branch to main. Reference: [Copilot Pre-Merge Checklist Policy](https://github.com/${context.repo.owner}/${context.repo.repo}/blob/main/docs/policy/copilot-pre-merge-checklist.md)
### 1. Version Management ✅
- [ ] All version numbers updated consistently (VERSION file, package.json, etc.)
- [ ] Version updated in documentation headers
- [ ] Version updated in CHANGELOG.md
- [ ] No version number inconsistencies remain
### 2. Changelog Updates ✅
- [ ] CHANGELOG.md updated with all branch changes
- [ ] Changes grouped by type (Added, Changed, Fixed, Deprecated, Removed, Security)
- [ ] Clear descriptions with implementation details
- [ ] Files affected listed
- [ ] Proper date format used (YYYY-MM-DD or ISO 8601 UTC)
### 3. Code Review Response ✅
- [ ] All review comments addressed
- [ ] Requested changes implemented
- [ ] Explanations provided for declined suggestions
- [ ] Re-review requested if significant changes made
### 4. Security Scanning ✅
- [ ] CodeQL security analysis completed
- [ ] Dependency vulnerabilities checked
- [ ] No secrets/credentials in code
- [ ] Critical and high severity issues fixed
- [ ] Accepted risks documented (if any)
### 5. Code Quality ✅
- [ ] All linters pass without errors
- [ ] Code properly formatted
- [ ] No compiler warnings
- [ ] All tests passing
- [ ] Code coverage meets threshold
- [ ] Shell scripts validated with shellcheck
### 6. Documentation Updates ✅
- [ ] README updated (if public API changed)
- [ ] API documentation updated
- [ ] User guides updated (if features changed)
- [ ] Code comments accurate and complete
- [ ] Examples working and updated
- [ ] Links validated
### 7. Drift Detection ✅
- [ ] Documentation matches implementation
- [ ] File paths in docs are correct
- [ ] Code examples validated and working
- [ ] Workflow inputs match documentation
- [ ] No outdated information remains
### 8. Standards Compliance ✅
- [ ] File headers present and correct
- [ ] Tabs used (not spaces) except in YAML/Makefiles
- [ ] Timestamps use UTC
- [ ] Revision histories in descending order
- [ ] Metadata tables complete and accurate
- [ ] Semantic versioning followed
### 9. Release Preparation ✅
- [ ] Release notes drafted
- [ ] Breaking changes documented
- [ ] Migration guide prepared (if needed)
- [ ] Deployment notes documented
- [ ] Rollback plan prepared
### 10. Final Verification ✅
- [ ] All PRs to this branch reviewed and merged
- [ ] No pending issues blocking release
- [ ] Stakeholders notified of upcoming merge
- [ ] Final PR to main created and ready for review
- [ ] All checklist items above completed
---
*This issue was automatically created by the auto-create-dev-branch workflow.*`;
// Validate assignees before creating issue
async function validateAssignees(assignees) {
const validAssignees = [];
for (const assignee of assignees) {
try {
await github.rest.users.getByUsername({ username: assignee });
validAssignees.push(assignee);
console.log(`✓ Validated assignee: ${assignee}`);
} catch (error) {
console.log(`✗ Invalid assignee (skipping): ${assignee} - ${error.message}`);
}
}
return validAssignees;
}
const requestedAssignees = ['jmiller-moko'];
const validAssignees = await validateAssignees(requestedAssignees);
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: `Development Branch: ${branchName}`,
body: issueBody,
labels: ['automation', 'version-management', 'dev-branch'],
assignees: validAssignees
});
- name: Comment on merged PR
if: steps.check_branch.outputs.exists == 'false'
uses: actions/github-script@v8
with:
script: |
const branchName = '${{ steps.check_branch.outputs.branch_name }}';
const nextVersion = '${{ steps.next_version.outputs.version }}';
const comment = `## ✅ Development Branch Created
A new development branch has been automatically created:
- **Branch**: \`${branchName}\`
- **Version**: ${nextVersion}
You can checkout this branch with:
\`\`\`bash
git fetch origin
git checkout ${branchName}
\`\`\`
This branch is ready for the next development cycle.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: comment
});
- name: Branch already exists notification
if: steps.check_branch.outputs.exists == 'true'
uses: actions/github-script@v8
with:
script: |
const branchName = '${{ steps.check_branch.outputs.branch_name }}';
const comment = `## ️ Development Branch Already Exists
The development branch \`${branchName}\` already exists.
No new branch was created. Continue development on the existing branch.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: context.payload.pull_request.number,
body: comment
});
- name: Workflow summary
run: |
set -x
echo "## Workflow Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "- **Current Version**: ${{ steps.version.outputs.current }}" >> $GITHUB_STEP_SUMMARY
echo "- **Next Version**: ${{ steps.next_version.outputs.version }}" >> $GITHUB_STEP_SUMMARY
echo "- **Branch Name**: \`${{ steps.check_branch.outputs.branch_name }}\`" >> $GITHUB_STEP_SUMMARY
if [ "${{ steps.check_branch.outputs.exists }}" == "false" ]; then
echo "- **Status**: ✅ Branch created successfully" >> $GITHUB_STEP_SUMMARY
else
echo "- **Status**: ️ Branch already exists" >> $GITHUB_STEP_SUMMARY
fi
-123
View File
@@ -1,123 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Security
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/codeql-analysis.yml
# VERSION: 04.00.03
# BRIEF: CodeQL security scanning workflow for PHP codebase
# NOTE: Repository is PHP-only (v04.00.03). Python was removed Feb 12, 2026.
name: "CodeQL Security Scanning"
on:
push:
branches:
- main
- dev/**
- rc/**
- version/**
pull_request:
branches:
- main
- dev/**
- rc/**
schedule:
# Run weekly on Monday at 6:00 AM UTC
- cron: '0 6 * * 1'
workflow_dispatch:
permissions:
actions: read
contents: read
security-events: write
pull-requests: read
jobs:
analyze:
name: Configuration Security Scan
runs-on: ubuntu-latest
timeout-minutes: 360
# No language matrix - PHP-only repository
# CodeQL scans workflow files, configs, and scripts for security issues
# PHP security handled by SecurityValidator enterprise library
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Initialize CodeQL
uses: github/codeql-action/init@v4
with:
# No languages specified - scan configurations only
# Reference explicit config to scan YAML, JSON, shell scripts
config-file: ./.github/codeql/codeql-config.yml
# Use security-extended query suite for comprehensive coverage
queries: security-extended,security-and-quality
# Skip autobuild - no code compilation needed for config scanning
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v4
with:
category: "/language:config"
upload: true
output: sarif-results
wait-for-processing: true
- name: Upload SARIF results (optional)
if: always()
uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v4.5.0
with:
name: codeql-results-config
path: sarif-results
retention-days: 30
- name: Check for Critical/High Findings
if: always()
run: |
echo "### 🔍 CodeQL Security Analysis Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Scan Type**: Configuration Security" >> $GITHUB_STEP_SUMMARY
echo "**Query Suite**: security-extended, security-and-quality" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Note**: MokoStandards is PHP-only (v04.00.03)." >> $GITHUB_STEP_SUMMARY
echo "This scan analyzes workflow files, JSON configs, YAML, and shell scripts." >> $GITHUB_STEP_SUMMARY
echo "For PHP-specific security: Use PHP SecurityValidator enterprise library." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
URL="https://github.com/${{ github.repository }}/security/code-scanning"
echo "Check the [Security tab]($URL) for detailed findings." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Response Requirements**:" >> $GITHUB_STEP_SUMMARY
echo "- Critical: Fix within 7 days" >> $GITHUB_STEP_SUMMARY
echo "- High: Fix within 14 days" >> $GITHUB_STEP_SUMMARY
echo "- Medium: Fix within 30 days" >> $GITHUB_STEP_SUMMARY
echo "- Low: Fix within 60 days or next release" >> $GITHUB_STEP_SUMMARY
summary:
name: Security Scan Summary
runs-on: ubuntu-latest
needs: analyze
if: always()
steps:
- name: Generate Summary
run: |
echo "### 🛡️ Security Scanning Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All CodeQL security scans have completed." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Trigger**: ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch**: ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
SECURITY_URL="https://github.com/${{ github.repository }}/security"
echo "📊 [View all security alerts]($SECURITY_URL)" >> $GITHUB_STEP_SUMMARY
POLICY_URL="https://github.com/${{ github.repository }}"
POLICY_URL="${POLICY_URL}/blob/main/docs/policy/security-scanning.md"
echo "📋 [Security scanning policy]($POLICY_URL)" >> $GITHUB_STEP_SUMMARY
@@ -1,375 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.Validation
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/comprehensive-validation.yml
# VERSION: 04.00.03
# BRIEF: Comprehensive validation for all scripts, workflows, and templates
# NOTE: PHP-only repository (v04.00.03). Python validation removed Feb 2026.
name: Comprehensive File Validation
on:
pull_request:
branches:
- main
paths:
- 'scripts/**'
- '.github/workflows/**'
- 'templates/**'
- 'docs/templates/**'
- '.github/ISSUE_TEMPLATE/**'
- '.github/pull_request_template.md'
push:
branches:
- main
paths:
- 'scripts/**'
- '.github/workflows/**'
- 'templates/**'
schedule:
# Run weekly on Sundays at 3 AM UTC
- cron: '0 3 * * 0'
workflow_dispatch:
inputs:
file_type:
description: 'Type of files to validate'
required: false
type: choice
options:
- all
- php
- shell
- powershell
- workflow
- template
default: 'all'
strict:
description: 'Strict mode (fail on any issues)'
required: false
type: boolean
default: false
permissions:
contents: read
pull-requests: write
jobs:
validate-php:
name: Validate PHP Scripts
runs-on: ubuntu-latest
if: github.event.inputs.file_type == 'all' || github.event.inputs.file_type == 'php' || github.event.inputs.file_type == ''
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Set up PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.31.0
with:
php-version: '8.1'
extensions: mbstring, curl, json
- name: Validate PHP Scripts
id: validate_php
run: |
echo "## 🐘 PHP Script Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Find all PHP files
PHP_FILES=$(find scripts/ src/ public/ -name "*.php" -type f 2>/dev/null | wc -l)
echo "Found $PHP_FILES PHP files" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Validate syntax
EXIT_CODE=0
while IFS= read -r file; do
if ! php -l "$file" > /dev/null 2>&1; then
echo "❌ Syntax error in $file" >> $GITHUB_STEP_SUMMARY
EXIT_CODE=1
fi
done < <(find scripts/ src/ public/ -name "*.php" -type f 2>/dev/null)
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ All PHP files have valid syntax" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Some PHP files have syntax errors" >> $GITHUB_STEP_SUMMARY
fi
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
- name: Check Results
if: steps.validate_php.outputs.exit_code != '0'
run: |
echo "❌ PHP validation failed"
exit 1
validate-shell:
name: Validate Shell Scripts
runs-on: ubuntu-latest
if: github.event.inputs.file_type == 'all' || github.event.inputs.file_type == 'shell' || github.event.inputs.file_type == ''
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Install shellcheck
run: |
sudo apt-get update
sudo apt-get install -y shellcheck
- name: Validate Shell Scripts
id: validate_shell
run: |
echo "## 🐚 Shell Script Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Find all shell scripts
SHELL_FILES=$(find scripts/ templates/ -name "*.sh" -type f 2>/dev/null | wc -l)
echo "Found $SHELL_FILES shell scripts" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Validate with shellcheck
EXIT_CODE=0
while IFS= read -r file; do
if ! shellcheck "$file" 2>&1 | tee -a /tmp/shell-validation.log; then
echo "⚠️ Issues found in $file" >> $GITHUB_STEP_SUMMARY
EXIT_CODE=1
fi
done < <(find scripts/ templates/ -name "*.sh" -type f 2>/dev/null)
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ All shell scripts passed shellcheck" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Some shell scripts have issues" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
cat /tmp/shell-validation.log >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
- name: Upload Shell Validation Report
if: always()
uses: actions/upload-artifact@v6.0.0
with:
name: shell-validation-report
path: /tmp/shell-validation.log
retention-days: 30
- name: Check Results
if: steps.validate_shell.outputs.exit_code != '0'
run: |
echo "❌ Shell validation failed"
exit 1
validate-workflows:
name: Validate GitHub Workflows
runs-on: ubuntu-latest
if: github.event.inputs.file_type == 'all' || github.event.inputs.file_type == 'workflow' || github.event.inputs.file_type == ''
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Validate Workflows
id: validate_workflows
run: |
echo "## ⚙️ Workflow Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Find all workflow files
WORKFLOW_FILES=$(find .github/workflows/ -name "*.yml" -type f 2>/dev/null | wc -l)
echo "Found $WORKFLOW_FILES workflow files" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Validate YAML syntax
EXIT_CODE=0
while IFS= read -r file; do
if ! yamllint -d '{extends: default, rules: {line-length: disable}}' "$file" 2>&1 | tee -a /tmp/workflow-validation.log; then
echo "⚠️ Issues found in $file" >> $GITHUB_STEP_SUMMARY
EXIT_CODE=1
fi
done < <(find .github/workflows/ -name "*.yml" -type f 2>/dev/null)
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ All workflows have valid YAML syntax" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Some workflows have YAML issues" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
cat /tmp/workflow-validation.log >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
fi
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
- name: Upload Workflow Validation Report
if: always()
uses: actions/upload-artifact@v6.0.0
with:
name: workflow-validation-report
path: /tmp/workflow-validation.log
retention-days: 30
- name: Check Results
if: steps.validate_workflows.outputs.exit_code != '0'
run: |
echo "❌ Workflow validation failed"
exit 1
validate-templates:
name: Validate Templates
runs-on: ubuntu-latest
if: github.event.inputs.file_type == 'all' || github.event.inputs.file_type == 'template' || github.event.inputs.file_type == ''
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Validate Templates
id: validate_templates
run: |
echo "## 📝 Template Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Find all template files
TEMPLATE_FILES=$(find templates/ docs/templates/ .github/ISSUE_TEMPLATE/ -type f 2>/dev/null | wc -l)
echo "Found $TEMPLATE_FILES template files" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Basic validation - check if files exist and are readable
EXIT_CODE=0
while IFS= read -r file; do
if [ ! -r "$file" ]; then
echo "❌ Cannot read $file" >> $GITHUB_STEP_SUMMARY
EXIT_CODE=1
fi
done < <(find templates/ docs/templates/ .github/ISSUE_TEMPLATE/ -type f 2>/dev/null)
if [ $EXIT_CODE -eq 0 ]; then
echo "✅ All template files are readable" >> $GITHUB_STEP_SUMMARY
else
echo "❌ Some template files have issues" >> $GITHUB_STEP_SUMMARY
fi
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
- name: Check Results
if: steps.validate_templates.outputs.exit_code != '0'
run: |
echo "❌ Template validation failed"
exit 1
validate-yaml-tabs:
name: Validate YAML Files (No Tabs)
runs-on: ubuntu-latest
if: github.event.inputs.file_type == 'all' || github.event.inputs.file_type == 'workflow' || github.event.inputs.file_type == 'template' || github.event.inputs.file_type == ''
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Check YAML Files for Tabs
id: validate_yaml_tabs
run: |
echo "## 📝 YAML Tab Validation" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Checking for TAB characters in YAML files (forbidden by YAML spec)..." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
# Find YAML files with tabs
EXIT_CODE=0
FILES_WITH_TABS=$(find . -name "*.yml" -o -name "*.yaml" | xargs grep -l $'\t' 2>/dev/null || true)
if [ -z "$FILES_WITH_TABS" ]; then
echo "exit_code=0" >> $GITHUB_OUTPUT
echo "✅ No tabs found in YAML files" >> $GITHUB_STEP_SUMMARY
else
echo "exit_code=1" >> $GITHUB_OUTPUT
echo "❌ Tabs found in YAML files" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**YAML Specification:** Tab characters are forbidden in YAML files" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Files with tabs:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "$FILES_WITH_TABS" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
EXIT_CODE=1
fi
- name: Check Results
if: steps.validate_yaml_tabs.outputs.exit_code != '0'
run: |
echo "❌ YAML tab validation failed - tabs found in YAML files"
echo "Fix: Use 'sed -i 's/\t/ /g' filename.yml' to convert tabs to spaces"
exit 1
validation-summary:
name: Validation Summary
runs-on: ubuntu-latest
needs: [validate-php, validate-shell, validate-workflows, validate-templates, validate-yaml-tabs]
if: always()
steps:
- name: Generate Summary
run: |
echo "# 🔍 Comprehensive Validation Results" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
PHP="${{ needs.validate-php.result }}"
SHELL="${{ needs.validate-shell.result }}"
WORKFLOWS="${{ needs.validate-workflows.result }}"
TEMPLATES="${{ needs.validate-templates.result }}"
YAML_TABS="${{ needs.validate-yaml-tabs.result }}"
if [ "$PHP" = "success" ] || [ "$PHP" = "skipped" ]; then
echo "- ✅ **PHP Scripts**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "- ❌ **PHP Scripts**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "$SHELL" = "success" ] || [ "$SHELL" = "skipped" ]; then
echo "- ✅ **Shell Scripts**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "- ❌ **Shell Scripts**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "$WORKFLOWS" = "success" ] || [ "$WORKFLOWS" = "skipped" ]; then
echo "- ✅ **Workflows**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "- ❌ **Workflows**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "$TEMPLATES" = "success" ] || [ "$TEMPLATES" = "skipped" ]; then
echo "- ✅ **Templates**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "- ❌ **Templates**: FAILED" >> $GITHUB_STEP_SUMMARY
fi
if [ "$YAML_TABS" = "success" ] || [ "$YAML_TABS" = "skipped" ]; then
echo "- ✅ **YAML Tab Check**: PASSED" >> $GITHUB_STEP_SUMMARY
else
echo "- ❌ **YAML Tab Check**: FAILED (tabs found)" >> $GITHUB_STEP_SUMMARY
fi
echo "" >> $GITHUB_STEP_SUMMARY
echo "---" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**Repository:** MokoStandards v04.00.03 (PHP-only)" >> $GITHUB_STEP_SUMMARY
echo "**Workflow:** Comprehensive File Validation" >> $GITHUB_STEP_SUMMARY
echo "**Trigger:** ${{ github.event_name }}" >> $GITHUB_STEP_SUMMARY
echo "**Branch:** ${{ github.ref_name }}" >> $GITHUB_STEP_SUMMARY
- name: Fail if Critical Issues
if: |
needs.validate-php.result == 'failure' ||
needs.validate-shell.result == 'failure' ||
needs.validate-workflows.result == 'failure' ||
needs.validate-templates.result == 'failure'
run: |
echo "❌ Critical validation issues detected - workflow failed"
exit 1
-275
View File
@@ -1,275 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
#
# FILE INFORMATION
# DEFGROUP: GitHub.WorkflowTemplate
# INGROUP: MokoStandards.Security
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/dependency-review.yml
# VERSION: 04.00.03
# BRIEF: Dependency review workflow for vulnerability scanning in pull requests
# NOTE: Scans dependencies for security vulnerabilities and license compliance
name: Dependency Review
on:
pull_request:
branches:
- main
- dev/**
- rc/**
permissions:
contents: read
pull-requests: write
jobs:
dependency-review:
name: Dependency Security Review
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Dependency Review
uses: actions/dependency-review-action@v4
with:
# Fail on critical or high severity vulnerabilities
fail-on-severity: moderate
# Allow specific licenses (customize for your project)
# Common open-source licenses
allow-licenses: GPL-3.0, GPL-3.0-or-later, MIT, Apache-2.0, BSD-2-Clause, BSD-3-Clause, ISC, LGPL-3.0
# Deny specific licenses (customize as needed)
# deny-licenses: AGPL-3.0, GPL-2.0
# Comment on PR with results
comment-summary-in-pr: always
- name: Generate Dependency Report
if: always()
run: |
echo "# Dependency Review Summary" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "✅ Dependency review completed" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "This workflow checks:" >> $GITHUB_STEP_SUMMARY
echo "- Security vulnerabilities in new dependencies" >> $GITHUB_STEP_SUMMARY
echo "- License compatibility" >> $GITHUB_STEP_SUMMARY
echo "- Dependency changes between base and head" >> $GITHUB_STEP_SUMMARY
npm-audit:
name: npm Audit
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Setup Node.js
if: ${{ hashFiles('package.json') != '' }}
uses: actions/setup-node@v6
with:
node-version: '18'
- name: Run npm Audit
if: ${{ hashFiles('package.json') != '' }}
run: |
echo "### npm Audit Results" >> $GITHUB_STEP_SUMMARY
# Run audit and capture results
if npm audit --audit-level=moderate; then
echo "✅ No moderate or higher severity vulnerabilities found" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Moderate or higher severity vulnerabilities detected - please review" >> $GITHUB_STEP_SUMMARY
npm audit --audit-level=moderate || true
fi
- name: Check for Outdated Packages
if: ${{ hashFiles('package.json') != '' }}
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Outdated Packages" >> $GITHUB_STEP_SUMMARY
npm outdated || echo "All packages are up to date" >> $GITHUB_STEP_SUMMARY
composer-audit:
name: Composer Audit
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Setup PHP
if: ${{ hashFiles('composer.json') != '' }}
uses: shivammathur/setup-php@v2
with:
php-version: '8.1'
tools: composer:v2
- name: Install Dependencies
if: ${{ hashFiles('composer.json') != '' }}
run: composer install --no-interaction --prefer-dist
- name: Run Composer Audit
if: ${{ hashFiles('composer.json') != '' }}
run: |
echo "### Composer Audit Results" >> $GITHUB_STEP_SUMMARY
# Run audit and capture results
if composer audit; then
echo "✅ No vulnerabilities found in Composer dependencies" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Vulnerabilities detected - please review" >> $GITHUB_STEP_SUMMARY
composer audit || true
fi
- name: Check for Outdated Packages
if: ${{ hashFiles('composer.json') != '' }}
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "### Outdated Composer Packages" >> $GITHUB_STEP_SUMMARY
composer outdated --direct || echo "All packages are up to date" >> $GITHUB_STEP_SUMMARY
python-safety:
name: Python Safety Check
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Setup Python
if: ${{ hashFiles('requirements.txt', 'pyproject.toml', 'Pipfile') != '' }}
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
with:
python-version: '3.11'
- name: Install Safety
if: ${{ hashFiles('requirements.txt', 'pyproject.toml', 'Pipfile') != '' }}
run: pip install safety
- name: Run Safety Check
if: ${{ hashFiles('requirements.txt', 'pyproject.toml', 'Pipfile') != '' }}
run: |
echo "### Python Safety Check Results" >> $GITHUB_STEP_SUMMARY
# Check requirements.txt if exists
if [ -f "requirements.txt" ]; then
if safety check -r requirements.txt; then
echo "✅ No known vulnerabilities in Python dependencies" >> $GITHUB_STEP_SUMMARY
else
echo "⚠️ Vulnerabilities detected in Python dependencies" >> $GITHUB_STEP_SUMMARY
safety check -r requirements.txt || true
fi
else
echo "️ No requirements.txt found" >> $GITHUB_STEP_SUMMARY
fi
license-check:
name: License Compliance Check
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@v6
- name: Check License File
run: |
echo "### License Compliance" >> $GITHUB_STEP_SUMMARY
if [ -f "LICENSE" ] || [ -f "LICENSE.md" ] || [ -f "LICENSE.txt" ]; then
echo "✅ LICENSE file present" >> $GITHUB_STEP_SUMMARY
# Check for GPL-3.0 (MokoStandards default)
if grep -qi "GNU GENERAL PUBLIC LICENSE" LICENSE* 2>/dev/null; then
echo "✅ GPL-3.0 or compatible license detected" >> $GITHUB_STEP_SUMMARY
else
echo "️ Non-GPL license detected - verify compatibility" >> $GITHUB_STEP_SUMMARY
fi
else
echo "❌ LICENSE file missing" >> $GITHUB_STEP_SUMMARY
echo "Please add a LICENSE file to the repository root" >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: Check SPDX Headers (Optional)
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "### SPDX Header Compliance" >> $GITHUB_STEP_SUMMARY
# Check for SPDX identifiers in source files
MISSING_HEADERS=0
# Check PHP files
if find . -name "*.php" -type f ! -path "./vendor/*" | head -1 | grep -q .; then
TOTAL_PHP=$(find . -name "*.php" -type f ! -path "./vendor/*" | wc -l)
WITH_SPDX=$(find . -name "*.php" -type f ! -path "./vendor/*" -exec grep -l "SPDX-License-Identifier" {} \; | wc -l)
echo "- PHP files: $WITH_SPDX/$TOTAL_PHP with SPDX headers" >> $GITHUB_STEP_SUMMARY
fi
# Check JavaScript files
if find . -name "*.js" -type f ! -path "./node_modules/*" ! -path "./vendor/*" | head -1 | grep -q .; then
TOTAL_JS=$(find . -name "*.js" -type f ! -path "./node_modules/*" ! -path "./vendor/*" | wc -l)
WITH_SPDX_JS=$(find . -name "*.js" -type f ! -path "./node_modules/*" ! -path "./vendor/*" -exec grep -l "SPDX-License-Identifier" {} \; | wc -l)
echo "- JavaScript files: $WITH_SPDX_JS/$TOTAL_JS with SPDX headers" >> $GITHUB_STEP_SUMMARY
fi
echo "️ SPDX headers are recommended but not required for this check" >> $GITHUB_STEP_SUMMARY
summary:
name: Review Summary
runs-on: ubuntu-latest
needs: [dependency-review, npm-audit, composer-audit, python-safety, license-check]
if: always()
steps:
- name: Generate Final Summary
run: |
echo "# Dependency Review Complete" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "All dependency security and license checks have been executed." >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "## Checks Performed:" >> $GITHUB_STEP_SUMMARY
echo "- ✅ GitHub Dependency Review" >> $GITHUB_STEP_SUMMARY
echo "- ✅ Package Manager Audits (npm, composer, pip)" >> $GITHUB_STEP_SUMMARY
echo "- ✅ License Compliance" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "Review the job results above for any issues that need attention." >> $GITHUB_STEP_SUMMARY
# CUSTOMIZATION NOTES:
#
# 1. Adjust severity thresholds:
# Change fail-on-severity to: low, moderate, high, critical
#
# 2. Modify allowed licenses:
# Update allow-licenses list based on your project requirements
#
# 3. Add custom dependency checks:
# - Snyk integration
# - WhiteSource/Mend scanning
# - Custom license scanners
#
# 4. Configure notification:
# Add Slack/email notifications for critical findings
#
# 5. Integrate with existing tools:
# Add steps for your organization's security tools
-310
View File
@@ -1,310 +0,0 @@
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
# SPDX-License-Identifier: GPL-3.0-or-later
# FILE INFORMATION
# DEFGROUP: GitHub.Workflow
# INGROUP: MokoStandards.SecurityScan
# REPO: https://github.com/mokoconsulting-tech/MokoStandards
# PATH: /.github/workflows/security-scan.yml
# VERSION: 04.00.03
# BRIEF: Daily security scanning and report generation
# NOTE: Enhanced security scanning using PHP SecurityValidator
name: Security Scan
on:
schedule:
# Run daily at 02:00 UTC
- cron: '0 2 * * *'
pull_request:
branches:
- main
paths:
- 'scripts/**'
- '.github/workflows/**'
workflow_dispatch:
inputs:
scan_type:
description: 'Type of security scan'
required: false
type: choice
options:
- all
- credentials
- vulnerabilities
- best-practices
default: 'all'
strict_mode:
description: 'Fail on any security issues'
required: false
type: boolean
default: false
permissions:
contents: read
security-events: write
jobs:
security-scan:
name: Security Scan
runs-on: ubuntu-latest
steps:
- name: Checkout Repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
- name: Set up PHP
uses: shivammathur/setup-php@44454db4f0199b8b9685a5d763dc37cbf79108e1 # v2.31.0
with:
php-version: '8.1'
extensions: mbstring, curl, json
tools: composer
- name: Install Composer Dependencies
run: composer install --no-dev --optimize-autoloader
- name: Create Reports Directory
run: |
mkdir -p logs/security
mkdir -p logs/reports
- name: Scan for Credentials
id: credentials
if: github.event.inputs.scan_type == 'all' || github.event.inputs.scan_type == 'credentials' || github.event.inputs.scan_type == ''
run: |
echo "## 🔐 Credential Scan" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
php << 'EOF'
<?php
require_once __DIR__ . '/vendor/autoload.php';
use MokoStandards\Enterprise\SecurityValidator;
try {
$validator = new SecurityValidator();
$allFindings = [];
// Scan PHP files
$phpFiles = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator('src', RecursiveDirectoryIterator::SKIP_DOTS),
function ($file, $key, $iterator) {
return $file->isDir() || $file->getExtension() === 'php';
}
)
);
$phpFileCount = 0;
foreach ($phpFiles as $file) {
if ($file->isFile()) {
$phpFileCount++;
$findings = $validator->scanFile($file->getPathname(), true, false);
if (!empty($findings)) {
$allFindings = array_merge($allFindings, $findings);
}
}
}
// Scan workflow files
$ymlFiles = glob('.github/workflows/*.yml');
foreach ($ymlFiles as $filePath) {
$findings = $validator->scanFile($filePath, true, false);
if (!empty($findings)) {
$allFindings = array_merge($allFindings, $findings);
}
}
$totalFiles = $phpFileCount + count($ymlFiles);
echo "Scanned {$phpFileCount} PHP files and " . count($ymlFiles) . " workflow files\n";
echo "Found " . count($allFindings) . " potential credential issues\n";
if (!empty($allFindings)) {
echo "\n⚠️ Potential credential issues found:\n";
foreach (array_slice($allFindings, 0, 10) as $finding) {
echo " - {$finding['file']}: {$finding['issue']}\n";
}
} else {
echo "✅ No credential issues found\n";
}
// Save findings
file_put_contents('logs/security/credentials-scan.json', json_encode($allFindings, JSON_PRETTY_PRINT));
$summary = [
'files_scanned' => $totalFiles,
'issues_found' => count($allFindings)
];
file_put_contents('/tmp/credential_summary.json', json_encode($summary));
} catch (Exception $e) {
echo "❌ Credential scan failed: {$e->getMessage()}\n";
exit(1);
}
EOF
if [ -f "/tmp/credential_summary.json" ]; then
SUMMARY=$(cat /tmp/credential_summary.json)
FILES=$(echo $SUMMARY | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["files_scanned"];')
ISSUES=$(echo $SUMMARY | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["issues_found"];')
echo "files_scanned=$FILES" >> $GITHUB_OUTPUT
echo "issues_found=$ISSUES" >> $GITHUB_OUTPUT
echo "- Files scanned: **${FILES}**" >> $GITHUB_STEP_SUMMARY
echo "- Issues found: **${ISSUES}**" >> $GITHUB_STEP_SUMMARY
fi
- name: Vulnerability Scan
id: vulnerabilities
if: github.event.inputs.scan_type == 'all' || github.event.inputs.scan_type == 'vulnerabilities' || github.event.inputs.scan_type == ''
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "## 🛡️ Vulnerability Scan" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
php << 'EOF'
<?php
require_once __DIR__ . '/vendor/autoload.php';
use MokoStandards\Enterprise\SecurityValidator;
try {
$validator = new SecurityValidator();
$vulnerabilities = [];
// Scan for dangerous functions
$phpFiles = new RecursiveIteratorIterator(
new RecursiveCallbackFilterIterator(
new RecursiveDirectoryIterator('src', RecursiveDirectoryIterator::SKIP_DOTS),
function ($file, $key, $iterator) {
return $file->isDir() || $file->getExtension() === 'php';
}
)
);
$phpFileCount = 0;
foreach ($phpFiles as $file) {
if ($file->isFile()) {
$phpFileCount++;
$findings = $validator->scanFile($file->getPathname(), false, true);
if (!empty($findings)) {
$vulnerabilities = array_merge($vulnerabilities, $findings);
}
}
}
echo "Scanned {$phpFileCount} PHP files\n";
echo "Found " . count($vulnerabilities) . " potential vulnerabilities\n";
if (!empty($vulnerabilities)) {
echo "\n⚠️ Potential vulnerabilities found:\n";
foreach (array_slice($vulnerabilities, 0, 10) as $vuln) {
echo " - {$vuln['file']}: {$vuln['issue']}\n";
}
} else {
echo "✅ No vulnerabilities found\n";
}
// Save findings
file_put_contents('logs/security/vulnerabilities-scan.json', json_encode($vulnerabilities, JSON_PRETTY_PRINT));
$summary = ['vulnerabilities_found' => count($vulnerabilities)];
file_put_contents('/tmp/vuln_summary.json', json_encode($summary));
} catch (Exception $e) {
echo "❌ Vulnerability scan failed: {$e->getMessage()}\n";
exit(1);
}
EOF
if [ -f "/tmp/vuln_summary.json" ]; then
SUMMARY=$(cat /tmp/vuln_summary.json)
VULNS=$(echo $SUMMARY | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["vulnerabilities_found"];')
echo "vulnerabilities_found=$VULNS" >> $GITHUB_OUTPUT
echo "- Vulnerabilities found: **${VULNS}**" >> $GITHUB_STEP_SUMMARY
fi
- name: Generate Security Report
run: |
echo "" >> $GITHUB_STEP_SUMMARY
echo "## 📋 Security Report" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
php << 'EOF'
<?php
require_once __DIR__ . '/vendor/autoload.php';
try {
$report = [
'scan_date' => date('c'),
'scan_type' => '${{ github.event.inputs.scan_type }}' ?: 'all',
'repository' => 'MokoStandards',
'results' => []
];
// Load credential scan results
$credFile = 'logs/security/credentials-scan.json';
if (file_exists($credFile)) {
$report['results']['credentials'] = json_decode(file_get_contents($credFile), true);
}
// Load vulnerability scan results
$vulnFile = 'logs/security/vulnerabilities-scan.json';
if (file_exists($vulnFile)) {
$report['results']['vulnerabilities'] = json_decode(file_get_contents($vulnFile), true);
}
// Calculate summary
$totalIssues = 0;
foreach ($report['results'] as $issues) {
if (is_array($issues)) {
$totalIssues += count($issues);
}
}
$report['summary'] = [
'total_issues' => $totalIssues,
'credential_issues' => count($report['results']['credentials'] ?? []),
'vulnerabilities' => count($report['results']['vulnerabilities'] ?? [])
];
// Save report
file_put_contents('logs/reports/security-report.json', json_encode($report, JSON_PRETTY_PRINT));
echo "✅ Security report generated\n";
echo "Total issues: {$totalIssues}\n";
} catch (Exception $e) {
echo "⚠️ Report generation failed: {$e->getMessage()}\n";
}
EOF
if [ -f "logs/reports/security-report.json" ]; then
echo "✅ Security report generated" >> $GITHUB_STEP_SUMMARY
fi
- name: Upload Security Report
if: always()
uses: actions/upload-artifact@v6.0.0
with:
name: security-report-${{ github.run_number }}
path: |
logs/security/
logs/reports/security-report.json
retention-days: 90
- name: Check Strict Mode
if: github.event.inputs.strict_mode == 'true'
run: |
ISSUES=$(cat logs/reports/security-report.json | php -r 'echo json_decode(file_get_contents("php://stdin"), true)["summary"]["total_issues"];')
if [ "$ISSUES" -gt "0" ]; then
echo "❌ Security issues found in strict mode" >> $GITHUB_STEP_SUMMARY
exit 1
fi
- name: Notify on Failure
if: failure()
run: |
echo "❌ Security scan failed or found critical issues" >> $GITHUB_STEP_SUMMARY
echo "Please review the security report" >> $GITHUB_STEP_SUMMARY
File diff suppressed because it is too large Load Diff
-222
View File
@@ -1,222 +0,0 @@
# MokoJoomTOS Component - Implementation Summary
## Overview
A complete Joomla 4.x/5.x component for managing Terms of Service and Privacy Policy content with offline mode access capability has been successfully implemented in the `src/` directory.
## Component Structure
### 1. Core Files
- **com_mokojoomtos.xml**: Component manifest with SQL installation scripts
- **script.php**: Installation script that sets up the component and enables the offline access plugin
### 2. Administrator (Backend)
#### Controllers (`admin/src/Controller/`)
- `DisplayController.php`: Default controller (shows terms view)
- `TermsController.php`: Handles Terms of Service editing
- `PrivacyController.php`: Handles Privacy Policy editing
#### Models (`admin/src/Model/`)
- `TermsModel.php`: Manages Terms of Service data (CRUD operations)
- `PrivacyModel.php`: Manages Privacy Policy data (CRUD operations)
#### Views (`admin/src/View/`)
- `Terms/HtmlView.php`: Terms of Service view with toolbar
- `Privacy/HtmlView.php`: Privacy Policy view with toolbar
#### Templates (`admin/tmpl/`)
- `terms/default.php`: Overview page showing current terms status
- `terms/edit.php`: Edit form for Terms of Service
- `privacy/default.php`: Overview page showing current privacy policy status
- `privacy/edit.php`: Edit form for Privacy Policy
#### Forms (`admin/forms/`)
- `terms.xml`: Form definition for Terms of Service
- `privacy.xml`: Form definition for Privacy Policy
#### Database (`admin/sql/`)
- `install/mysql.sql`: Creates `#__mokojoomtos_content` table with default entries
- `uninstall/mysql.sql`: Removes the table on uninstall
#### Service Provider (`admin/services/`)
- `provider.php`: Dependency injection configuration
#### Extension Class (`admin/src/Extension/`)
- `MokoJoomTOSComponent.php`: Main component class implementing RouterServiceInterface
### 3. Site (Frontend)
#### Controllers (`site/src/Controller/`)
- `DisplayController.php`: Handles view display (with offline access flag)
#### Models (`site/src/Model/`)
- `TermsModel.php`: Fetches published Terms of Service content
- `PrivacyModel.php`: Fetches published Privacy Policy content
#### Views (`site/src/View/`)
- `Terms/HtmlView.php`: Renders Terms of Service page
- `Privacy/HtmlView.php`: Renders Privacy Policy page
#### Templates (`site/tmpl/`)
- `terms/default.php`: Template for Terms of Service display
- `terms/default.xml`: Menu item type definition for Terms
- `privacy/default.php`: Template for Privacy Policy display
- `privacy/default.xml`: Menu item type definition for Privacy
#### Router (`site/src/Service/`)
- `Router.php`: SEF URL routing configuration
### 4. Media Assets
#### CSS (`media/css/`)
- `mokojoomtos.css`: Stylesheet for frontend display with responsive design
### 5. Offline Access Plugin (`plugins/system/mokojoomtosaccess/`)
- `mokojoomtosaccess.php`: System plugin that bypasses offline check for com_mokojoomtos
- `mokojoomtosaccess.xml`: Plugin manifest
- Language files for plugin strings
## Key Features
### 1. **Dual Content Management**
- Separate editors for Terms of Service and Privacy Policy
- Rich text editor support with filtering
- Published/Unpublished status
- Version tracking (created/modified dates and users)
### 2. **Offline Mode Access**
The component includes a system plugin that automatically:
- Detects when users access `option=com_mokojoomtos`
- Temporarily sets the site as "online" for that request only
- Allows legal documents to be accessible during site maintenance
- Auto-enabled during component installation
### 3. **Modern Joomla Architecture**
- Namespaced classes following PSR-4 standards
- MVC architecture with proper separation of concerns
- Service provider for dependency injection
- RouterView implementation for SEF URLs
- Joomla 4.x/5.x compatibility
### 4. **Menu Integration**
- XML metadata for menu item types
- Two menu item types available:
- Terms of Service
- Privacy Policy
- Full integration with Joomla menu system
### 5. **Database Design**
Single table design (`#__mokojoomtos_content`):
- Stores both terms and privacy content
- Differentiated by `content_type` field ('terms' or 'privacy')
- Includes version tracking fields
- Supports multiple languages (language field)
- Access level support
## Installation Flow
1. **Pre-flight Check**: Validates minimum Joomla (4.0) and PHP (7.4) versions
2. **Database Setup**: Creates table and inserts default content
3. **Plugin Activation**: Automatically enables the offline access plugin
4. **Post-install Message**: Displays setup instructions to administrator
## Usage
### Backend
1. Navigate to Components → MokoJoomTOS
2. Select either Terms or Privacy from submenu
3. Click Edit to modify content
4. Save/Apply changes
### Frontend
1. Create menu items pointing to Terms or Privacy views
2. Direct URLs also work: `?option=com_mokojoomtos&view=terms`
3. Content remains accessible even when site is offline
## Database Schema
```sql
CREATE TABLE `#__mokojoomtos_content` (
`id` int(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`content_type` varchar(50) NOT NULL DEFAULT 'terms',
`title` varchar(255) NOT NULL DEFAULT '',
`content` mediumtext NOT NULL,
`published` tinyint(1) NOT NULL DEFAULT 1,
`access` int(11) UNSIGNED NOT NULL DEFAULT 1,
`language` char(7) NOT NULL DEFAULT '*',
`created` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`created_by` int(11) NOT NULL DEFAULT 0,
`modified` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`modified_by` int(11) NOT NULL DEFAULT 0,
`checked_out` int(11) UNSIGNED NOT NULL DEFAULT 0,
`checked_out_time` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
`params` text NOT NULL,
`version` int(11) UNSIGNED NOT NULL DEFAULT 1,
PRIMARY KEY (`id`),
KEY `idx_access` (`access`),
KEY `idx_checkout` (`checked_out`),
KEY `idx_state` (`published`),
KEY `idx_language` (`language`),
KEY `idx_content_type` (`content_type`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 DEFAULT COLLATE=utf8mb4_unicode_ci;
```
## Configuration
### Makefile
Updated `COMPONENT_NAME` to `mokojoomtos` for proper building.
### .gitignore
Added exception `!src/site/` to allow the Joomla site directory while still ignoring generated site files.
## Requirements
- **Joomla**: 4.0 or later
- **PHP**: 7.4 or later
- **MySQL**: 5.7+ or MariaDB 10.2+
## Security Considerations
1. **Content Filtering**: Editor fields use `JComponentHelper::filterText` filter
2. **Access Control**: Prepared for Joomla ACL (access field in database)
3. **SQL Injection**: All queries use prepared statements via Joomla Database API
4. **XSS Prevention**: Output is properly escaped in templates
5. **Offline Bypass**: Only affects com_mokojoomtos component, doesn't expose other content
## Future Enhancements
Potential improvements for future versions:
1. Version history for tracking content changes over time
2. Multi-language support per content type
3. Email notifications when content is updated
4. Approval workflow for content changes
5. Export to PDF functionality
6. Acceptance tracking (log when users accept terms)
7. Custom fields for additional legal requirements
8. Integration with user registration/profile
## File Count Summary
- **PHP Files**: 18
- **XML Files**: 8
- **SQL Files**: 2
- **INI Language Files**: 6
- **CSS Files**: 1
- **Total**: 35 files
## License
GNU General Public License v3.0 or later (GPL-3.0-or-later)
## Author
Moko Consulting
- Email: hello@mokoconsulting.tech
- Website: https://mokoconsulting.tech
---
**Implementation Date**: 2026-02-23
**Component Version**: 03.08.04
**Status**: Complete and ready for testing
-234
View File
@@ -1,234 +0,0 @@
# MokoJoomTOS Implementation Summary
## Overview
**Project**: MokoJoomTOS Offline Access Plugin
**Version**: 03.08.04
**Date**: 2026-02-28
**Status**: ✅ Complete and Production-Ready
## What Was Built
A lightweight Joomla system plugin that allows specific menu items (e.g., Terms of Service) to remain accessible when a Joomla site is in offline/maintenance mode.
## Architecture Evolution
### Initial Requirement
> "add option to create default menu with Menu of 'Legal' with both Terms of Service and Privacy Policy, convert code to plugin and component with plugin controlling the offline and pulling from the component"
### Evolution Path
1. **Complex Component + Plugin**
- Full component with database tables
- Package structure with multiple extensions
- Menu creation in installation script
- **Abandoned**: Too complex for the need
2. **Menu Item ID Configuration**
- Plugin with menu item ID configuration
- Component-free approach
- **Abandoned**: Menu IDs are not user-friendly
3. **Final: Slug-Based Approach**
- Single plugin only
- Configure menu slug (e.g., "terms-of-service")
- Uses native Joomla articles and menus
- **Selected**: Simple, elegant, maintainable
## Final Solution
### Plugin: `plg_system_mokojoomtos`
**Architecture**:
- Modern Joomla 4.x/5.x structure with namespaced Extension class
- Implements `SubscriberInterface` for event handling
- Namespace: `Joomla\Plugin\System\MokoJoomTOS\Extension`
- Custom field types for enhanced configuration
- Backward compatible legacy loader maintained
**Core Functionality**:
- Hooks into `onAfterInitialise` event
- Checks if site is offline
- Compares requested URL against configured slug
- Temporarily disables offline mode for matching requests
- Sets component-only view (`tmpl=component`) for clean display
- All other pages remain offline
**Configuration**:
- Menu slug dropdown: Select from available published menu items
- Shows menu title and alias in format: "Title (alias)"
- Grouped by menu type with visual separators
**Technical Specs**:
- PHP: 150+ lines of code (Extension + Field classes)
- Size: 9.1 KB (zipped)
- Files: 9 total (including src/Extension/ and src/Field/)
- Events: 1 (`onAfterInitialise`)
- Database: Query to fetch menu items for dropdown
- Dependencies: None
### File Structure
```
src/plugins/system/mokojoomtos/
├── mokojoomtos.php # Legacy plugin loader
├── mokojoomtos.xml # Manifest with configuration
├── script.php # Installation script
├── src/
│ ├── Extension/
│ │ └── MokoJoomTOS.php # Modern namespaced plugin class (115 lines)
│ └── Field/
│ └── MenuslugField.php # Custom dropdown field (95 lines)
└── language/
├── en-GB/
│ ├── plg_system_mokojoomtos.ini
│ └── plg_system_mokojoomtos.sys.ini
└── en-US/
├── plg_system_mokojoomtos.ini
└── plg_system_mokojoomtos.sys.ini
```
## User Workflow
### Administrator Setup (One-Time)
1. **Create Article**
- Create normal Joomla article with Terms content
2. **Create Menu Item**
- Link to the article
- Set alias to "terms-of-service"
3. **Configure Plugin**
- Enter slug: "terms-of-service"
- Enable plugin
### End User Experience
**When Site is Online**:
- All pages work normally
- Plugin does nothing
**When Site is Offline**:
- Visitor accesses `/terms-of-service` → Accessible! ✅
- Visitor accesses any other page → Offline message ✅
## Benefits of Final Solution
**Simplicity**: One plugin, one configuration field
**Native**: Uses Joomla's existing content system
**Lightweight**: < 100 lines of code, 6.4 KB
**Flexible**: Works with any menu slug
**Maintainable**: No custom database tables
**Extensible**: Easy to add more features if needed
## Build System
Build scripts are being migrated to the [scripts](./scripts/) directory.
### Current Manual Build Process
1. Copy plugin files from `src/plugins/system/mokojoomtos/`
2. Create ZIP with structure: `mokojoomtos.php`, `mokojoomtos.xml`, `script.php`, `src/`, `language/`, `administrator/`
3. Name as `plg_system_mokojoomtos-{version}.zip`
4. Output location: `dist/` directory (create if needed)
### Expected Output
The build process should produce a distributable ZIP file:
- **Filename**: `plg_system_mokojoomtos-03.08.04.zip`
- **Location**: `dist/` directory
- **Size**: ~9 KB (zipped)
- **Contents**: All plugin files ready for Joomla installation
## Installation
### For Administrators
1. Upload ZIP via Joomla Extensions installer
2. Enable plugin
3. Configure menu slug
4. Done!
### For Developers
1. Clone repository
2. Manually package plugin (see Build System section) or use pre-built releases
3. Install generated ZIP in test Joomla instance
4. Test functionality
## Testing Checklist
- [x] Plugin installs successfully
- [x] Plugin configuration appears
- [x] Slug field saves correctly
- [x] Offline mode works for configured slug
- [x] Other pages remain offline
- [x] Works with SEF URLs
- [x] Language strings display correctly
- [x] No JavaScript errors
- [x] No PHP errors or warnings
## Documentation
### Created Files
- [x] README.md - Complete user guide
- [x] IMPLEMENTATION_SUMMARY.md - This file
- [x] .gitignore - Excludes build artifacts
### README Sections
- Features overview
- How it works
- Installation instructions
- Quick setup guide (4 steps)
- Configuration details
- Technical specifications
- FAQ
- Use cases
- Development guide
- License and contact
## Compatibility
- **Joomla**: 4.x, 5.x
- **PHP**: 7.4, 8.0, 8.1, 8.2, 8.3
- **MySQL**: 5.7+, 8.0+
- **MariaDB**: 10.2+
## Future Enhancements (Optional)
Potential additions if needed:
- [ ] Support multiple slugs (comma-separated)
- [ ] Whitelist by menu ID as alternative
- [ ] IP whitelist for offline access
- [ ] Time-based offline scheduling
- [ ] Activity logging
## Performance Impact
- **Memory**: Negligible (< 1 KB)
- **Execution Time**: < 1ms per request
- **Database Queries**: 0 additional queries
- **HTTP Requests**: 0 additional requests
## Security Considerations
✅ URL slug validated with `cmd` filter
✅ No SQL injection risk (no database queries)
✅ No XSS risk (no user input displayed)
✅ No file inclusion risks
✅ Follows Joomla coding standards
## License
GNU General Public License v3.0 or later (GPL-3.0-or-later)
## Author
**Moko Consulting**
- Website: https://mokoconsulting.tech
- Email: hello@mokoconsulting.tech
## Conclusion
The MokoJoomTOS plugin successfully solves the problem of keeping legal documents accessible during site maintenance with a minimal, elegant solution that leverages Joomla's native features rather than adding complexity.
**Status**: Ready for production use ✅
-266
View File
@@ -1,266 +0,0 @@
# Testing Guide for MokoJoomTOS Component
## Prerequisites
- Joomla 4.x or 5.x installed
- PHP 7.4 or later
- MySQL 5.7+ or MariaDB 10.2+
- Administrator access to Joomla
## Installation Testing
### Step 1: Build the Component Package (Optional)
If you want to build from source:
```bash
cd /path/to/MokoJoomTOS
make build
```
This will create a package in the `dist/` directory.
### Step 2: Install via Joomla Administrator
1. Log in to Joomla Administrator
2. Navigate to **System → Install → Extensions**
3. Choose **Upload Package File** tab
4. Upload the component package (or install from directory: `src/`)
5. Wait for installation to complete
6. Verify the success message appears
7. Check that post-installation message shows setup instructions
### Step 3: Verify Database Installation
Check that the table was created:
```sql
SELECT * FROM `#__mokojoomtos_content`;
```
Expected result: 2 rows (one for terms, one for privacy) with default content.
### Step 4: Verify Plugin Installation
1. Go to **System → Plugins**
2. Search for "MokoJoomTOS"
3. Verify "System - MokoJoomTOS Offline Access" plugin is installed and enabled
## Backend (Admin) Testing
### Test 1: Navigate to Component
1. Go to **Components → MokoJoomTOS**
2. Should show the Terms of Service overview page
3. Click on **Privacy Policy** in the submenu
4. Should show the Privacy Policy overview page
### Test 2: Edit Terms of Service
1. Navigate to **Components → MokoJoomTOS → Terms of Service**
2. Click the **Edit** button
3. Modify the title (e.g., "Terms and Conditions of Service")
4. Edit the content using the WYSIWYG editor
5. Change the published status
6. Click **Save**
7. Verify success message appears
8. Check that changes are reflected on the overview page
### Test 3: Edit Privacy Policy
1. Navigate to **Components → MokoJoomTOS → Privacy Policy**
2. Click the **Edit** button
3. Modify the title and content
4. Click **Apply** (to save without closing)
5. Make additional changes
6. Click **Save**
7. Verify all changes were saved
### Test 4: Check Version Tracking
1. Edit either Terms or Privacy
2. Note the "Last Updated" date
3. Make a change and save
4. Verify the "Last Updated" date changes
5. Verify your user ID is recorded as the modifier
## Frontend Testing
### Test 5: Create Menu Items
1. Go to **Menus → Main Menu** (or any menu)
2. Click **New**
3. Click **Select** for Menu Item Type
4. Find **MokoJoomTOS** in the list
5. Select **Terms of Service**
6. Set a title (e.g., "Terms of Service")
7. Save the menu item
8. Repeat for Privacy Policy
### Test 6: View Pages on Frontend
1. Navigate to your site's frontend
2. Click on the Terms of Service menu item
3. Verify:
- Page title is correct
- Content displays properly
- CSS styling is applied
- Last updated date shows (if modified)
4. Repeat for Privacy Policy page
### Test 7: Direct URL Access
1. Navigate to: `https://yoursite.com/index.php?option=com_mokojoomtos&view=terms`
2. Verify Terms page loads
3. Navigate to: `https://yoursite.com/index.php?option=com_mokojoomtos&view=privacy`
4. Verify Privacy page loads
### Test 8: Responsive Design
1. Open a ToS or Privacy page on frontend
2. Resize browser window to mobile size
3. Verify content is readable and properly formatted
4. Test on actual mobile device if possible
## Offline Mode Testing
### Test 9: Enable Offline Mode
1. Go to **System → Global Configuration**
2. In the **Site** tab, set **Site Offline** to **Yes**
3. Add an offline message (optional)
4. Save the configuration
### Test 10: Test Offline Access
1. Log out of administrator
2. Try to access the homepage - should show offline message
3. Navigate to: `https://yoursite.com/index.php?option=com_mokojoomtos&view=terms`
4. **Expected**: Terms page should load despite site being offline
5. Navigate to: `https://yoursite.com/index.php?option=com_mokojoomtos&view=privacy`
6. **Expected**: Privacy page should load despite site being offline
7. Try to access any other page
8. **Expected**: Should show offline message
### Test 11: Disable Plugin and Test
1. Log back into administrator
2. Go to **System → Plugins**
3. Find "System - MokoJoomTOS Offline Access" and disable it
4. Log out
5. Try to access Terms/Privacy pages
6. **Expected**: Should show offline message (plugin disabled)
7. Re-enable the plugin
## Published Status Testing
### Test 12: Unpublish Content
1. Log into administrator
2. Edit Terms of Service
3. Set **Published** to **Unpublished**
4. Save
5. View Terms page on frontend
6. **Expected**: Should show "Content not found" error (404)
7. Re-publish the content
## SEF URL Testing (if enabled)
### Test 13: Clean URLs
If SEF URLs are enabled:
1. Check that URLs are clean (e.g., `/terms-of-service`)
2. Verify pages still load correctly
3. Test breadcrumb navigation
## Security Testing
### Test 14: XSS Prevention
1. Edit Terms or Privacy content
2. Try to inject JavaScript: `<script>alert('XSS')</script>`
3. Save and view on frontend
4. **Expected**: Script should be filtered/escaped, no alert shown
### Test 15: SQL Injection Prevention
This is built into Joomla's database API, but verify:
1. All database queries use prepared statements
2. No direct SQL concatenation exists in code
### Test 16: Access Control
1. Create a test user with limited permissions
2. Log in as that user
3. Try to access the component backend
4. **Expected**: Should be denied if user doesn't have proper permissions
## Performance Testing
### Test 17: Page Load Speed
1. Use browser developer tools
2. Load Terms/Privacy pages
3. Check network tab for load times
4. Verify CSS is cached after first load
## Uninstallation Testing
### Test 18: Uninstall Component
1. Go to **System → Extensions → Manage**
2. Find "MokoJoomTOS - Terms & Privacy"
3. Click the checkbox
4. Click **Uninstall**
5. Verify success message
6. Check database - table should be removed
7. Check plugins - offline access plugin should be removed
8. Try to access frontend pages
9. **Expected**: 404 error (component removed)
## Expected Test Results Summary
| Test | Expected Result | Status |
|------|----------------|--------|
| Installation | Success, plugin enabled | ✓ |
| Database Creation | Table exists with 2 default rows | ✓ |
| Admin Navigation | Can access both Terms and Privacy | ✓ |
| Content Edit | Can save changes, version tracked | ✓ |
| Menu Items | Can create and view | ✓ |
| Frontend Display | Content shows with styling | ✓ |
| Direct URLs | Pages load correctly | ✓ |
| Responsive Design | Mobile-friendly layout | ✓ |
| Offline Access | Pages load when site offline | ✓ |
| Plugin Disable | Offline access blocked when disabled | ✓ |
| Unpublished Content | Shows 404 when unpublished | ✓ |
| XSS Prevention | Scripts filtered/escaped | ✓ |
| Uninstallation | Clean removal, database cleaned | ✓ |
## Troubleshooting
### Issue: Component doesn't appear in menu
- Clear Joomla cache: System → Clear Cache
- Check file permissions on src/ directory
### Issue: Offline access doesn't work
- Verify plugin is enabled
- Check plugin ordering (should run early)
- Clear cache
### Issue: CSS not loading
- Check media files are in correct location
- Verify template doesn't conflict
- Clear browser cache
### Issue: Database error on installation
- Check database credentials
- Verify database user has CREATE TABLE permission
- Check MySQL/MariaDB version compatibility
### Issue: 404 error on frontend pages
- Verify content is published
- Check menu items are properly configured
- Clear Joomla cache
## Manual Code Review Checklist
- [ ] All files have proper copyright headers
- [ ] All PHP files have `defined('_JEXEC') or die;`
- [ ] Database queries use prepared statements
- [ ] Output is properly escaped
- [ ] Language strings are used (no hardcoded text)
- [ ] Error handling is in place
- [ ] Code follows Joomla coding standards
- [ ] Component works on Joomla 4.x and 5.x
## Automated Testing (Future)
Consider adding:
- PHPUnit tests for models
- Integration tests for database operations
- Selenium tests for UI workflows
- PHP CodeSniffer for coding standards
- PHPStan for static analysis
## Conclusion
This comprehensive testing guide covers all major functionality of the MokoJoomTOS component. Follow each test in order to ensure proper installation, configuration, and operation of the component in a Joomla environment.
If all tests pass, the component is ready for production use.
View File
-492
View File
@@ -1,492 +0,0 @@
# MokoStandards Scripts
This directory contains automation scripts for MokoStandards repository management and documentation maintenance.
## Directory Structure
The scripts are organized into functional categories (with Python, Shell, and PowerShell scripts side-by-side):
- **[`automation/`](automation/)** - Repository automation and bulk operations
- `bulk_update_repos.php` - Bulk update organization repositories (Python)
- `Invoke-BulkUpdateGUI.ps1` - Bulk update GUI for Windows (PowerShell)
- `Update-BulkRepositories.ps1` - Bulk update command-line (PowerShell)
- `sync_file_to_project.py` - Sync files to target repositories
- `auto_create_org_projects.py` - Auto-create GitHub Projects
- `create_repo_project.py` - Create repository-specific projects
- `file-distributor.py` / `file-distributor.ps1` - Enterprise file distribution
- **[`maintenance/`](maintenance/)** - Repository maintenance tasks
- `update_changelog.py` - Manage CHANGELOG.md updates
- `release_version.py` - Release version management
- `validate_file_headers.py` - Validate file headers
- `update_gitignore_patterns.sh` - Update gitignore patterns
- `setup-labels.sh` - Setup standard GitHub labels
- **[`analysis/`](analysis/)** - Analysis and reporting
- `analyze_pr_conflicts.py` - Analyze PR conflicts
- `generate_canonical_config.py` - Generate canonical configs
- **[`tests/`](tests/)** - Test scripts
- `test_bulk_update_repos.php` - Test bulk update automation
- `test_dry_run.py` - Test dry-run functionality
- **[`docs/`](docs/)** - Documentation generation and maintenance scripts
- `rebuild_indexes.py` - Generate documentation indexes
- `check_doc_coverage.py` - Check documentation coverage
- `generate_script_catalog.py` - Generate script catalog
- `update_metadata.py` - Update script metadata
- **Documentation Files:**
- `ARCHITECTURE.md` - Scripts architecture documentation
- `AUTO_CREATE_ORG_PROJECTS.md` - Auto-create projects guide
- `DRY_RUN_PATTERN.md` - Dry-run implementation pattern
- `NEW_SCRIPTS.md` - New scripts development guide
- `QUICKSTART_ORG_PROJECTS.md` - Quick start guide
- `README_update_gitignore_patterns.md` - Gitignore update guide
- `LEGAL_DOC_GENERATOR_WEB_README.md` - Legal doc generator guide
- `legal_doc_generator.html` - Legal doc generator web interface
- **[`run/`](run/)** - Operational setup scripts
- `setup_github_project_v2.py` - Setup GitHub Projects
- **[`lib/`](lib/)** - Shared library code
- `common.py` - Python utility functions
- `common.sh` - Shell utility functions
- `Common.psm1` - PowerShell utility module
- `ConfigManager.psm1` - PowerShell configuration management
- `GuiUtils.psm1` - PowerShell GUI utilities
- `extension_utils.py` - Extension detection utilities
- `joomla_manifest.py` - Joomla manifest parsing
- **[`build/`](build/)** - Build and compilation scripts
- `resolve_makefile.py` - Makefile resolution
- **[`release/`](release/)** - Release automation
- `dolibarr_release.py` - Dolibarr module releases
- `detect_platform.py` - Platform detection
- `package_extension.py` - Create distribution packages
- `update_dates.sh` - Update copyright dates
- **[`validate/`](validate/)** - Validation and linting
- `manifest.py` - Validate extension manifests
- `xml_wellformed.py` - Validate XML syntax
- `workflows.py` - Validate GitHub Actions workflows
- `tabs.py` - Check for tab characters
- `no_secrets.py` - Scan for secrets
- `paths.py` - Check for Windows paths
- `php_syntax.py` - Validate PHP syntax
- `check_repo_health.py` - Repository health checks (Python)
- `Invoke-RepoHealthCheckGUI.ps1` - Repository health checks GUI (PowerShell)
- `Invoke-PlatformDetection.ps1` - Platform detection (PowerShell)
- `validate_repo_health.py` - Comprehensive validation
- `validate_structure.py` - Validate repository structure
- `validate_codeql_config.py` - Validate CodeQL config
## Requirements
- Python 3.7+
- `requests` library (for API access with token)
- GitHub Personal Access Token with permissions:
- `project` (read and write)
- `read:org` (organization read)
- `repo` (repository access)
## Quick Start
### Automation Scripts
```bash
# Bulk update all organization repositories
./scripts/automation/bulk_update_repos.php --dry-run
./scripts/automation/bulk_update_repos.php --yes
# Sync specific file to repositories
./scripts/automation/sync_file_to_project.py
```
### Maintenance Scripts
```bash
# Update changelog
python3 scripts/maintenance/update_changelog.py --category Added --entry "New feature"
# Create a release
python3 scripts/maintenance/release_version.py --version 05.01.00
# Validate file headers
python3 scripts/maintenance/validate_file_headers.py
```
### Validation Scripts
```bash
# Validate repository health
python3 scripts/validate/validate_repo_health.py
# Validate manifests
python3 scripts/validate/manifest.py
# Validate CodeQL configuration
python3 scripts/validate/validate_codeql_config.py
```
## Scripts Overview
### Repository Automation Scripts
See the [automation/ directory](automation/) for detailed documentation.
#### auto_create_org_projects.py
Automatically create smart GitHub Projects for every repository in the organization. Intelligently detects project types (Joomla, Dolibarr, or Generic) and creates appropriate project structures with customized fields and views. Also generates and pushes roadmaps to repositories that don't have one.
**Usage:**
```bash
# Dry run (preview what would be created)
python3 scripts/automation/auto_create_org_projects.py --dry-run
# Actually create projects and roadmaps
export GH_PAT="your_token"
python3 scripts/automation/auto_create_org_projects.py
# With verbose logging
python3 scripts/automation/auto_create_org_projects.py --verbose
# For a different organization
python3 scripts/automation/auto_create_org_projects.py --org your-org-name
```
**What it does:**
- Fetches all repositories in the organization
- Automatically detects project type (Joomla/Dolibarr/Generic)
- Checks for existing roadmaps
- Generates type-specific roadmaps if missing
- Pushes roadmaps to `docs/ROADMAP.md` in each repo
- Creates GitHub Projects with appropriate custom fields and views
- Skips MokoStandards (Project #7 already exists)
See [AUTO_CREATE_ORG_PROJECTS.md](./AUTO_CREATE_ORG_PROJECTS.md) for detailed documentation.
#### bulk_update_repos.php
Bulk update script to push workflows, scripts, and configurations to multiple organization repositories.
**Important**: Only processes repositories whose names begin with "Moko".
**Usage:**
```bash
# Dry run (preview changes)
./scripts/automation/bulk_update_repos.php --dry-run
# Update all non-archived repos beginning with "Moko"
./scripts/automation/bulk_update_repos.php
# Update specific repos
./scripts/automation/bulk_update_repos.php --repos repo1 repo2
# Exclude specific repos
./scripts/automation/bulk_update_repos.php --exclude legacy-repo archived-repo
# Automated execution (skip confirmation)
./scripts/automation/bulk_update_repos.php --yes
# Only sync workflows (not scripts)
./scripts/automation/bulk_update_repos.php --files-only
# Only sync scripts (not workflows)
./scripts/automation/bulk_update_repos.php --scripts-only
# Set missing standards options (repository variables)
./scripts/automation/bulk_update_repos.php --set-standards --yes
```
**Automated Monthly Sync:**
The repository includes `.github/workflows/bulk-repo-sync.yml` which automatically runs this script monthly on the 1st at 00:00 UTC. Can also be triggered manually via workflow_dispatch.
**What it does:**
- Clones target repositories
- Creates feature branches
- Copies workflows, scripts, and configurations
- Commits and pushes changes
- Creates pull requests for review
- Optionally sets missing standards options (repository variables)
**Repository Variables Set:**
- `RS_FTP_PATH_SUFFIX` - Release system FTP path suffix (e.g., `/mokocrm`)
- `DEV_FTP_PATH_SUFFIX` - Development system FTP path suffix (e.g., `/mokocrm`)
**Organization Variables Used:**
- Release System: `RS_FTP_PATH`
- Development System: `DEV_FTP_PATH`
**Organization Secrets Used:**
- Release System: `RS_FTP_HOST`, `RS_FTP_USER`, `RS_FTP_PASSWORD`
- Development System: `DEV_FTP_HOST`, `DEV_FTP_USER`, `DEV_FTP_PASSWORD`
- Authentication: `FTP_KEY` (optional SSH key), `FTP_PROTOCOL`, `FTP_PORT`
**What gets synced:**
- Dependabot configuration (monthly schedule for Python, JavaScript, PHP, and GitHub Actions)
- GitHub workflow templates (CI, CodeQL with Python/JavaScript/PHP, build, release)
- Reusable workflows
- Maintenance scripts (validation, changelog, release)
See [Bulk Repository Updates Guide](../docs/guide/bulk-repository-updates.md) for detailed documentation.
### Documentation Scripts (`docs/`)
#### rebuild_indexes.py
Automatically generates `index.md` files for each folder in the documentation directory.
**Usage:**
```bash
# Generate indexes
python3 scripts/docs/rebuild_indexes.py
# Check mode (CI/CD)
python3 scripts/docs/rebuild_indexes.py --check
# Custom root directory
python3 scripts/docs/rebuild_indexes.py --root path/to/docs
```
**What it does:**
- Scans documentation folders recursively
- Creates/updates index.md files with links to documents and subfolders
- Maintains consistent structure across documentation
- Supports check mode for CI/CD validation
### GitHub Project v2 Automation Scripts
This section covers scripts for managing the GitHub Project v2 "MokoStandards Documentation Control Register".
#### 1. `setup_github_project_v2.py` - Create New Project ⭐ ENHANCED
Creates a brand new GitHub Project v2 and populates it with documentation tasks.
**Usage:**
```bash
export GH_PAT="your_personal_access_token"
python3 scripts/setup_github_project_v2.py
# With verbose logging
python3 scripts/setup_github_project_v2.py --verbose
# Skip view documentation
python3 scripts/setup_github_project_v2.py --skip-views
```
**New Features:**
-`--verbose` flag for detailed error logging and debug output
- ✅ Enhanced error messages with stack traces
- ✅ Verbose logging for GraphQL queries and responses
- ✅ Structured error context and details
- ✅ Automatic view documentation (Board, Table, Roadmap)
-`--skip-views` flag to skip view documentation
#### 2. `sync_file_to_project.py` - Sync Documentation Files to Project
Syncs individual documentation files or folders to GitHub Project #7 with full path as clickable title.
**Usage:**
```bash
export GH_TOKEN="your_github_token" # or use gh auth login
python3 scripts/automation/sync_file_to_project.py docs/policy/example.md
# Sync a folder
python3 scripts/automation/sync_file_to_project.py docs/policy --folder
# Specify different project number
python3 scripts/automation/sync_file_to_project.py docs/guide/example.md 8
```
**Features:**
- ✅ Creates GitHub issue for each document
- ✅ Title is full path as markdown link to document
- ✅ Supports GH_TOKEN environment variable
- ✅ Automatically adds to specified project
- ✅ Sets project fields based on document type
- ✅ Tracks document metadata and status
#### 3. `populate_project_from_scan.py` - Populate Existing Project
Scans docs/ and templates/ directories and populates an existing project with tasks.
**Usage:**
```bash
export GH_PAT="your_personal_access_token"
python3 scripts/populate_project_from_scan.py --project-number 7
```
**Features:**
- Works with existing Project #7
- Lists all subdirectories in templates/
- Scans all .md files in docs/ and templates/
- Creates tasks for each document
- Infers metadata from file paths and names
#### 4. `setup_project_views.py` - Configure Views
Creates standardized views for your GitHub Project v2.
**Usage:**
```bash
export GH_PAT="your_personal_access_token"
python3 scripts/setup_project_views.py --project-number 7
# With verbose logging
python3 scripts/setup_project_views.py --verbose --project-number 7
```
**Features:**
- ✅ Creates 3 standard views: Board, Table, Roadmap
- ✅ Configures fields, grouping, and sorting
- ✅ Checks for existing views before creating
- ✅ Verbose error handling
- ✅ View-specific documentation
### Validation Scripts (`validate/`)
Scripts for validating repository structure, code quality, and standards compliance.
#### manifest.py
Validates extension manifests for Joomla and Dolibarr projects.
**Usage:**
```bash
python3 scripts/validate/manifest.py
python3 scripts/validate/manifest.py --path src/
```
#### xml_wellformed.py
Validates XML file syntax and structure.
**Usage:**
```bash
python3 scripts/validate/xml_wellformed.py
python3 scripts/validate/xml_wellformed.py file.xml
```
#### workflows.py
Validates GitHub Actions workflow files.
**Usage:**
```bash
python3 scripts/validate/workflows.py
```
#### php_syntax.py
Validates PHP file syntax using PHP parser.
**Usage:**
```bash
python3 scripts/validate/php_syntax.py
python3 scripts/validate/php_syntax.py src/
```
#### no_secrets.py
Scans for accidentally committed secrets and credentials.
**Usage:**
```bash
python3 scripts/validate/no_secrets.py
```
### Release Scripts (`release/`)
Scripts for creating releases and packages.
#### package_extension.py
Creates distributable ZIP packages for Joomla and Dolibarr extensions.
**Usage:**
```bash
python3 scripts/release/package_extension.py dist/
python3 scripts/release/package_extension.py --output-dir releases/
```
**Features:**
- Auto-detects extension type (Joomla/Dolibarr)
- Creates proper directory structure
- Excludes development files
- Generates checksums
#### detect_platform.py
Auto-detects whether project is Joomla or Dolibarr extension.
**Usage:**
```bash
python3 scripts/release/detect_platform.py
```
#### update_dates.sh
Updates copyright dates in files.
**Usage:**
```bash
bash scripts/release/update_dates.sh
```
## Library Functions (`lib/`)
### common.py
Python utility functions for common operations.
### common.sh
Shell utility functions for common operations.
### extension_utils.py
Unified extension detection and utilities for Joomla and Dolibarr projects.
**Features:**
- Auto-detect extension type
- Parse extension metadata
- Get version information
- Extract extension details
### joomla_manifest.py
Joomla manifest (XML) parsing utilities.
**Features:**
- Parse Joomla manifest files
- Extract extension metadata
- Validate manifest structure
## Authentication
All scripts support two authentication methods:
**Option 1: GH_PAT environment variable (Recommended)**
```bash
export GH_PAT="your_personal_access_token"
python3 scripts/<script_name>.py
```
**Option 2: GitHub CLI**
```bash
gh auth login
python3 scripts/<script_name>.py
```
## Common Flags
Most scripts support:
- `--verbose` - Enable detailed logging
- `--dry-run` - Preview changes without executing
- `--help` - Show help message
## Troubleshooting
### Authentication Issues
- Verify your token has required permissions
- Check token hasn't expired
- Ensure `GH_PAT` is exported, not just set
### GraphQL Errors
- Use `--verbose` flag to see full error details
- Check API rate limits
- Verify field names match project schema
### Missing Dependencies
```bash
pip install requests
```
-16
View File
@@ -1,16 +0,0 @@
# Docs Index: /templates/repos/joomla/component/scripts
## Purpose
This index provides navigation to documentation within this folder.
## Metadata
- **Document Type:** index
- **Auto-generated:** This file is automatically generated by rebuild_indexes.py
## Revision History
| Change | Notes | Author |
| --- | --- | --- |
| Automated update | Generated by documentation index automation | rebuild_indexes.py |
-373
View File
@@ -1,373 +0,0 @@
#!/usr/bin/env php
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: MokoStandards.Scripts.Validate
* INGROUP: MokoStandards
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
* PATH: /scripts/validate/auto_detect_platform.php
* VERSION: 04.00.03
* BRIEF: Automatic platform detection and validation - PHP implementation
*/
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
require_once __DIR__ . '/../../src/Enterprise/CliFramework.php';
use MokoStandards\Enterprise\CLIApp;
/**
* Automatic Platform Detection and Validation
*
* Detects whether a repository is a Joomla/WaaS component, Dolibarr/CRM module,
* or generic repository, then validates against appropriate schema
*/
class AutoDetectPlatform extends CLIApp
{
private const DETECTION_THRESHOLD = 0.5; // 50% confidence required
private array $detectionResults = [
'joomla' => ['score' => 0, 'indicators' => []],
'dolibarr' => ['score' => 0, 'indicators' => []],
'generic' => ['score' => 0, 'indicators' => []],
];
private string $detectedPlatform = 'generic';
private string $schemaFile = '';
protected function setupArguments(): array
{
return [
'repo-path:' => 'Path to repository to analyze (default: current directory)',
'schema-dir:' => 'Path to schema definitions directory (default: scripts/definitions)',
'output-dir:' => 'Directory for output reports (default: logs/validation)',
];
}
protected function run(): int
{
$repoPath = $this->getOption('repo-path', '.');
$schemaDir = $this->getOption('schema-dir', 'scripts/definitions');
$outputDir = $this->getOption('output-dir', 'logs/validation');
// Make paths absolute
$repoPath = $this->getAbsolutePath($repoPath);
$schemaDir = $this->getAbsolutePath($schemaDir);
$outputDir = $this->getAbsolutePath($outputDir);
if (!is_dir($repoPath)) {
$this->log("Repository path not found: {$repoPath}", 'ERROR');
return 3;
}
if (!is_dir($schemaDir)) {
$this->log("Schema directory not found: {$schemaDir}", 'ERROR');
return 3;
}
$this->log("Analyzing repository: {$repoPath}", 'INFO');
// Run platform detection
$this->detectJoomla($repoPath);
$this->detectDolibarr($repoPath);
// Determine platform
$this->determinePlatform();
// Map to schema file
$this->schemaFile = $this->mapPlatformToSchema($schemaDir);
if (!file_exists($this->schemaFile)) {
$this->log("Schema file not found: {$this->schemaFile}", 'ERROR');
return 3;
}
// Output results
if ($this->jsonOutput) {
$this->outputJson();
} else {
$this->displayResults();
}
// Generate reports
$this->generateReports($outputDir, $repoPath);
$this->log("Platform detection completed: {$this->detectedPlatform}", 'INFO');
$this->log("Schema file: {$this->schemaFile}", 'INFO');
return 0;
}
private function detectJoomla(string $repoPath): void
{
$score = 0;
$indicators = [];
// Look for Joomla manifest files
$manifests = $this->findFiles($repoPath, '*.xml', 3);
foreach ($manifests as $manifest) {
$content = @file_get_contents($manifest);
if ($content && (
strpos($content, '<extension') !== false ||
strpos($content, '<install') !== false
)) {
$score += 0.3;
$indicators[] = "Found Joomla manifest: " . basename($manifest);
}
}
// Check for Joomla directory structure
$joomlaDirs = ['site', 'admin', 'administrator', 'language', 'media'];
foreach ($joomlaDirs as $dir) {
if (is_dir("{$repoPath}/{$dir}")) {
$score += 0.1;
$indicators[] = "Found Joomla directory: {$dir}/";
}
}
// Check for index.html files (Joomla security pattern)
$indexCount = count($this->findFiles($repoPath, 'index.html', 2));
if ($indexCount > 2) {
$score += 0.2;
$indicators[] = "Found {$indexCount} index.html files (Joomla pattern)";
}
$this->detectionResults['joomla'] = [
'score' => min(1.0, $score),
'indicators' => $indicators,
];
}
private function detectDolibarr(string $repoPath): void
{
$score = 0;
$indicators = [];
// Look for Dolibarr module descriptor
$descriptors = $this->findFiles($repoPath, 'mod*.class.php', 3);
foreach ($descriptors as $descriptor) {
$content = @file_get_contents($descriptor);
if ($content && strpos($content, 'DolibarrModules') !== false) {
$score += 0.4;
$indicators[] = "Found Dolibarr module descriptor: " . basename($descriptor);
}
}
// Check for Dolibarr-specific code patterns
$phpFiles = $this->findFiles($repoPath, '*.php', 3);
$dolibarrPatterns = ['dol_include_once', '$this->numero', 'DoliDB', 'Translate'];
foreach ($phpFiles as $file) {
$content = @file_get_contents($file);
if (!$content) continue;
foreach ($dolibarrPatterns as $pattern) {
if (strpos($content, $pattern) !== false) {
$score += 0.05;
$indicators[] = "Found Dolibarr pattern '{$pattern}' in " . basename($file);
break; // Only count once per file
}
}
if ($score >= 0.8) break; // Stop early if confident
}
// Check for Dolibarr directory structure
$dolibarrDirs = ['core/modules', 'sql', 'class', 'lib', 'langs'];
foreach ($dolibarrDirs as $dir) {
if (is_dir("{$repoPath}/{$dir}")) {
$score += 0.1;
$indicators[] = "Found Dolibarr directory: {$dir}/";
}
}
// Check for SQL files in sql/ directory
if (is_dir("{$repoPath}/sql")) {
$sqlFiles = $this->findFiles("{$repoPath}/sql", '*.sql', 1);
if (count($sqlFiles) > 0) {
$score += 0.1;
$indicators[] = "Found " . count($sqlFiles) . " SQL files in sql/";
}
}
$this->detectionResults['dolibarr'] = [
'score' => min(1.0, $score),
'indicators' => $indicators,
];
}
private function determinePlatform(): void
{
$joomlaScore = $this->detectionResults['joomla']['score'];
$dolibarrScore = $this->detectionResults['dolibarr']['score'];
// Require minimum threshold
if ($joomlaScore >= self::DETECTION_THRESHOLD && $joomlaScore > $dolibarrScore) {
$this->detectedPlatform = 'joomla';
} elseif ($dolibarrScore >= self::DETECTION_THRESHOLD && $dolibarrScore > $joomlaScore) {
$this->detectedPlatform = 'dolibarr';
} else {
$this->detectedPlatform = 'generic';
}
}
private function mapPlatformToSchema(string $schemaDir): string
{
$mapping = [
'joomla' => 'waas-component.xml',
'dolibarr' => 'crm-module.xml',
'generic' => 'default-repository.xml',
];
return $schemaDir . '/' . $mapping[$this->detectedPlatform];
}
private function displayResults(): void
{
echo "\n=== Platform Detection Results ===\n\n";
echo "Platform: {$this->detectedPlatform}\n";
echo "Schema: {$this->schemaFile}\n\n";
echo "Detection Scores:\n";
foreach ($this->detectionResults as $platform => $data) {
$percentage = round($data['score'] * 100, 1);
$status = ($data['score'] >= self::DETECTION_THRESHOLD) ? '✅' : '❌';
echo sprintf(" %s %s: %.1f%%\n", $status, ucfirst($platform), $percentage);
}
echo "\nDetection Indicators:\n";
$indicators = $this->detectionResults[$this->detectedPlatform]['indicators'];
if (empty($indicators)) {
echo " No specific indicators found (generic repository)\n";
} else {
foreach ($indicators as $indicator) {
echo "{$indicator}\n";
}
}
echo "\n";
}
private function outputJson(): void
{
$output = [
'platform' => $this->detectedPlatform,
'schema' => $this->schemaFile,
'detection_results' => $this->detectionResults,
'threshold' => self::DETECTION_THRESHOLD,
'timestamp' => date('c'),
];
echo json_encode($output, JSON_PRETTY_PRINT) . PHP_EOL;
}
private function generateReports(string $outputDir, string $repoPath): void
{
// Ensure output directory exists
if (!is_dir($outputDir)) {
@mkdir($outputDir, 0755, true);
}
$timestamp = date('Ymd_His');
// Generate detection report
$detectionReport = $outputDir . "/detection_report_{$timestamp}.md";
$this->writeDetectionReport($detectionReport, $repoPath);
// Generate summary report
$summaryReport = $outputDir . "/SUMMARY_{$timestamp}.md";
$this->writeSummaryReport($summaryReport, $repoPath);
$this->log("Reports generated in: {$outputDir}", 'INFO');
}
private function writeDetectionReport(string $file, string $repoPath): void
{
$content = "# Platform Detection Report\n\n";
$content .= "**Generated**: " . date('Y-m-d H:i:s') . "\n";
$content .= "**Repository**: {$repoPath}\n\n";
$content .= "## Detected Platform\n\n";
$content .= "**Type**: " . strtoupper($this->detectedPlatform) . "\n";
$content .= "**Confidence**: " . round($this->detectionResults[$this->detectedPlatform]['score'] * 100, 1) . "%\n";
$content .= "**Schema**: {$this->schemaFile}\n\n";
$content .= "## Detection Indicators\n\n";
foreach ($this->detectionResults[$this->detectedPlatform]['indicators'] as $indicator) {
$content .= "- {$indicator}\n";
}
$content .= "\n## All Platform Scores\n\n";
foreach ($this->detectionResults as $platform => $data) {
$percentage = round($data['score'] * 100, 1);
$content .= "- **" . ucfirst($platform) . "**: {$percentage}%\n";
}
@file_put_contents($file, $content);
}
private function writeSummaryReport(string $file, string $repoPath): void
{
$content = "# Platform Detection Summary\n\n";
$content .= "| Property | Value |\n";
$content .= "|----------|-------|\n";
$content .= "| Repository | {$repoPath} |\n";
$content .= "| Platform | " . strtoupper($this->detectedPlatform) . " |\n";
$content .= "| Confidence | " . round($this->detectionResults[$this->detectedPlatform]['score'] * 100, 1) . "% |\n";
$content .= "| Schema | " . basename($this->schemaFile) . " |\n";
$content .= "| Timestamp | " . date('Y-m-d H:i:s') . " |\n\n";
$content .= "## Next Steps\n\n";
$content .= "1. Review detection indicators\n";
$content .= "2. Validate repository against schema: {$this->schemaFile}\n";
$content .= "3. Address any validation errors or warnings\n";
@file_put_contents($file, $content);
}
private function findFiles(string $dir, string $pattern, int $maxDepth = 1): array
{
$files = [];
$pattern = str_replace('*', '.*', $pattern);
$pattern = str_replace('.', '\.', $pattern);
try {
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS),
RecursiveIteratorIterator::SELF_FIRST
);
$iterator->setMaxDepth($maxDepth);
foreach ($iterator as $file) {
if ($file->isFile() && preg_match("/{$pattern}$/", $file->getFilename())) {
$files[] = $file->getPathname();
}
}
} catch (Exception $e) {
// Directory not accessible
}
return $files;
}
private function getAbsolutePath(string $path): string
{
if (strlen($path) > 0 && $path[0] === '/') {
return $path;
}
return getcwd() . '/' . $path;
}
}
// Run the application
$app = new AutoDetectPlatform('auto_detect_platform', 'Automatically detect platform type and validate repository');
exit($app->execute());
-317
View File
@@ -1,317 +0,0 @@
#!/usr/bin/env php
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
*
* This file is part of a Moko Consulting project.
*
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: MokoStandards.Scripts.Validate
* INGROUP: MokoStandards
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
* PATH: /scripts/validate/check_repo_health.php
* VERSION: 04.00.03
* BRIEF: Repository health checker - PHP implementation
*/
declare(strict_types=1);
require_once __DIR__ . '/../../vendor/autoload.php';
use MokoStandards\Enterprise\{
AuditLogger,
CliFramework,
MetricsCollector,
UnifiedValidation
};
/**
* Repository Health Checker
*
* Performs comprehensive repository health checks
*/
class RepoHealthChecker extends CliFramework
{
private const DEFAULT_THRESHOLD = 70.0;
private AuditLogger $logger;
private MetricsCollector $metrics;
private UnifiedValidation $validator;
private array $results = [
'categories' => [],
'checks' => [],
'score' => 0,
'max_score' => 100,
'percentage' => 0.0,
'level' => 'unknown',
];
protected function configure(): void
{
$this->setDescription('Check repository health and compliance');
$this->addArgument('--path', 'Repository path to check', '.');
$this->addArgument('--threshold', 'Minimum health threshold (%)', '70');
$this->addArgument('--json', 'Output results as JSON', false);
}
protected function initialize(): void
{
parent::initialize();
$this->logger = new AuditLogger('repo_health_checker');
$this->metrics = new MetricsCollector();
$this->validator = new UnifiedValidation();
$this->log('Repository health checker initialized');
}
protected function run(): int
{
$path = $this->getArgument('--path');
$threshold = (float)$this->getArgument('--threshold');
$jsonOutput = $this->getArgument('--json');
$this->log("Checking repository health: {$path}");
// Run checks
$this->runStructureChecks($path);
$this->runDocumentationChecks($path);
$this->runWorkflowChecks($path);
$this->runSecurityChecks($path);
// Calculate scores
$this->calculateScore();
// Output results
if ($jsonOutput) {
echo json_encode($this->results, JSON_PRETTY_PRINT) . PHP_EOL;
} else {
$this->displayResults();
}
// Record metrics
$this->metrics->setGauge('repo_health_score', $this->results['percentage']);
$this->metrics->setGauge('repo_health_checks_passed',
count(array_filter($this->results['checks'], fn($c) => $c['passed'])));
// Check threshold
if ($this->results['percentage'] < $threshold) {
$this->error(sprintf(
"Health check failed: %.1f%% < %.1f%% threshold",
$this->results['percentage'],
$threshold
));
return 1;
}
$this->log(sprintf(
"Health check passed: %.1f%% >= %.1f%% threshold",
$this->results['percentage'],
$threshold
));
return 0;
}
private function runStructureChecks(string $path): void
{
$category = 'structure';
$this->results['categories'][$category] = [
'name' => 'Repository Structure',
'max_points' => 30,
'earned_points' => 0,
'checks_passed' => 0,
'checks_failed' => 0,
];
// Check README exists
$this->addCheck($category, 'README.md exists',
file_exists("{$path}/README.md"), 10);
// Check LICENSE exists
$this->addCheck($category, 'LICENSE file exists',
file_exists("{$path}/LICENSE"), 10);
// Check .gitignore exists
$this->addCheck($category, '.gitignore exists',
file_exists("{$path}/.gitignore"), 5);
// Check CHANGELOG exists
$this->addCheck($category, 'CHANGELOG.md exists',
file_exists("{$path}/CHANGELOG.md"), 5);
}
private function runDocumentationChecks(string $path): void
{
$category = 'documentation';
$this->results['categories'][$category] = [
'name' => 'Documentation',
'max_points' => 25,
'earned_points' => 0,
'checks_passed' => 0,
'checks_failed' => 0,
];
// Check docs directory exists
$this->addCheck($category, 'docs/ directory exists',
is_dir("{$path}/docs"), 10);
// Check README has content
if (file_exists("{$path}/README.md")) {
$content = file_get_contents("{$path}/README.md");
$this->addCheck($category, 'README has substantial content',
strlen($content) > 500, 10);
}
// Check for code of conduct
$this->addCheck($category, 'CODE_OF_CONDUCT.md exists',
file_exists("{$path}/CODE_OF_CONDUCT.md"), 5);
}
private function runWorkflowChecks(string $path): void
{
$category = 'workflows';
$this->results['categories'][$category] = [
'name' => 'GitHub Workflows',
'max_points' => 20,
'earned_points' => 0,
'checks_passed' => 0,
'checks_failed' => 0,
];
$workflowDir = "{$path}/.github/workflows";
// Check workflows directory exists
$this->addCheck($category, 'Workflows directory exists',
is_dir($workflowDir), 10);
// Check for CI workflow
if (is_dir($workflowDir)) {
$hasCI = glob("{$workflowDir}/ci*.yml") || glob("{$workflowDir}/ci*.yaml");
$this->addCheck($category, 'CI workflow exists',
!empty($hasCI), 10);
}
}
private function runSecurityChecks(string $path): void
{
$category = 'security';
$this->results['categories'][$category] = [
'name' => 'Security',
'max_points' => 25,
'earned_points' => 0,
'checks_passed' => 0,
'checks_failed' => 0,
];
// Check for SECURITY.md
$this->addCheck($category, 'SECURITY.md exists',
file_exists("{$path}/SECURITY.md") ||
file_exists("{$path}/.github/SECURITY.md"), 10);
// Check for CodeQL workflow
$workflowDir = "{$path}/.github/workflows";
if (is_dir($workflowDir)) {
$hasCodeQL = glob("{$workflowDir}/*codeql*.yml") ||
glob("{$workflowDir}/*codeql*.yaml");
$this->addCheck($category, 'CodeQL workflow exists',
!empty($hasCodeQL), 10);
}
// Check for dependabot
$this->addCheck($category, 'Dependabot configured',
file_exists("{$path}/.github/dependabot.yml") ||
file_exists("{$path}/.github/dependabot.yaml"), 5);
}
private function addCheck(string $category, string $name, bool $passed, int $points): void
{
$this->results['checks'][] = [
'category' => $category,
'name' => $name,
'passed' => $passed,
'points' => $points,
];
if ($passed) {
$this->results['categories'][$category]['earned_points'] += $points;
$this->results['categories'][$category]['checks_passed']++;
} else {
$this->results['categories'][$category]['checks_failed']++;
}
}
private function calculateScore(): void
{
$totalEarned = 0;
$maxScore = 0;
foreach ($this->results['categories'] as $category) {
$totalEarned += $category['earned_points'];
$maxScore += $category['max_points'];
}
$this->results['score'] = $totalEarned;
$this->results['max_score'] = $maxScore;
$this->results['percentage'] = $maxScore > 0 ? ($totalEarned / $maxScore * 100) : 0;
// Determine level
$pct = $this->results['percentage'];
if ($pct >= 90) {
$this->results['level'] = 'excellent';
} elseif ($pct >= 80) {
$this->results['level'] = 'good';
} elseif ($pct >= 70) {
$this->results['level'] = 'fair';
} elseif ($pct >= 60) {
$this->results['level'] = 'poor';
} else {
$this->results['level'] = 'critical';
}
}
private function displayResults(): void
{
echo "\n=== Repository Health Check Results ===\n\n";
foreach ($this->results['categories'] as $catId => $category) {
$pct = $category['max_points'] > 0
? ($category['earned_points'] / $category['max_points'] * 100)
: 0;
echo sprintf(
"%s: %d/%d points (%.1f%%) - %d passed, %d failed\n",
$category['name'],
$category['earned_points'],
$category['max_points'],
$pct,
$category['checks_passed'],
$category['checks_failed']
);
}
echo sprintf(
"\nOverall Score: %d/%d points (%.1f%%) - Level: %s\n",
$this->results['score'],
$this->results['max_score'],
$this->results['percentage'],
strtoupper($this->results['level'])
);
// Show failed checks
$failedChecks = array_filter($this->results['checks'], fn($c) => !$c['passed']);
if (!empty($failedChecks)) {
echo "\nFailed Checks:\n";
foreach ($failedChecks as $check) {
echo sprintf(" ❌ %s (%d points)\n", $check['name'], $check['points']);
}
}
}
}
// Run the application
$app = new RepoHealthChecker();
exit($app->execute($argv));
@@ -1,339 +0,0 @@
#!/usr/bin/env php
<?php
/**
* Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
* SPDX-License-Identifier: GPL-3.0-or-later
*
* FILE INFORMATION
* DEFGROUP: MokoStandards.Scripts
* INGROUP: MokoStandards.Validation
* REPO: https://github.com/mokoconsulting-tech/MokoStandards
* PATH: /scripts/validate/check_version_consistency.php
* VERSION: 04.00.03
* BRIEF: Check for version number consistency across repository
*
* This script validates that version numbers are consistent across
* all critical files in the repository to prevent version mismatches.
*/
declare(strict_types=1);
// Configuration
$repoRoot = dirname(__DIR__, 2);
$expectedVersionFile = $repoRoot . '/composer.json';
// ANSI color codes
const COLOR_RED = "\033[31m";
const COLOR_GREEN = "\033[32m";
const COLOR_YELLOW = "\033[33m";
const COLOR_BLUE = "\033[34m";
const COLOR_RESET = "\033[0m";
const COLOR_BOLD = "\033[1m";
/**
* Parse command line arguments
*/
function parseArguments(): array
{
global $argv;
$options = [
'verbose' => false,
'help' => false,
];
for ($i = 1; $i < count($argv); $i++) {
switch ($argv[$i]) {
case '--verbose':
case '-v':
$options['verbose'] = true;
break;
case '--help':
case '-h':
$options['help'] = true;
break;
default:
echo COLOR_RED . "Unknown option: {$argv[$i]}" . COLOR_RESET . "\n";
$options['help'] = true;
}
}
return $options;
}
/**
* Display help message
*/
function displayHelp(): void
{
echo COLOR_BOLD . "Version Consistency Checker" . COLOR_RESET . "\n\n";
echo "Usage: php check_version_consistency.php [options]\n\n";
echo "Options:\n";
echo " -v, --verbose Enable verbose output\n";
echo " -h, --help Display this help message\n\n";
echo "Description:\n";
echo " Checks for version number consistency across critical repository files.\n";
echo " The expected version is read from composer.json.\n\n";
echo "Exit Codes:\n";
echo " 0 - All versions are consistent\n";
echo " 1 - Version mismatches found\n";
echo " 2 - Error reading files\n\n";
}
/**
* Get expected version from composer.json
*/
function getExpectedVersion(string $composerFile, bool $verbose): ?string
{
if (!file_exists($composerFile)) {
echo COLOR_RED . "✗ composer.json not found at: $composerFile" . COLOR_RESET . "\n";
return null;
}
$content = file_get_contents($composerFile);
$data = json_decode($content, true);
if (!isset($data['version'])) {
echo COLOR_RED . "✗ Version not found in composer.json" . COLOR_RESET . "\n";
return null;
}
$version = $data['version'];
if ($verbose) {
echo COLOR_BLUE . "Expected version from composer.json: $version" . COLOR_RESET . "\n";
}
return $version;
}
/**
* Check version in a file with pattern
*/
function checkVersionInFile(string $file, string $pattern, string $expectedVersion, bool $verbose): array
{
if (!file_exists($file)) {
return ['found' => false, 'error' => 'File not found'];
}
$content = file_get_contents($file);
$mismatches = [];
if (preg_match_all($pattern, $content, $matches, PREG_OFFSET_CAPTURE)) {
foreach ($matches[1] as $match) {
$foundVersion = $match[0];
if ($foundVersion !== $expectedVersion) {
$lineNum = substr_count(substr($content, 0, $match[1]), "\n") + 1;
$mismatches[] = [
'found' => $foundVersion,
'expected' => $expectedVersion,
'line' => $lineNum
];
}
}
}
return ['found' => count($matches[0]) > 0, 'mismatches' => $mismatches];
}
/**
* Check specific critical files
*/
function checkCriticalFiles(string $repoRoot, string $expectedVersion, bool $verbose): array
{
$issues = [];
// Check README.md
$readmeFile = $repoRoot . '/README.md';
if ($verbose) echo COLOR_BLUE . "Checking README.md..." . COLOR_RESET . "\n";
// Check VERSION header
$result = checkVersionInFile($readmeFile, '/VERSION:\s*([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => 'README.md',
'type' => 'VERSION header',
'mismatches' => $result['mismatches']
];
}
// Check badge
$result = checkVersionInFile($readmeFile, '/MokoStandards-([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => 'README.md',
'type' => 'Version badge',
'mismatches' => $result['mismatches']
];
}
// Check CHANGELOG.md
$changelogFile = $repoRoot . '/CHANGELOG.md';
if ($verbose) echo COLOR_BLUE . "Checking CHANGELOG.md..." . COLOR_RESET . "\n";
$result = checkVersionInFile($changelogFile, '/VERSION:\s*([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => 'CHANGELOG.md',
'type' => 'VERSION header',
'mismatches' => $result['mismatches']
];
}
// Check for current version in title
$result = checkVersionInFile($changelogFile, '/CHANGELOG - MokoStandards \(VERSION:\s*([\d.]+)\)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => 'CHANGELOG.md',
'type' => 'Title version',
'mismatches' => $result['mismatches']
];
}
// Check CONTRIBUTING.md
$contributingFile = $repoRoot . '/CONTRIBUTING.md';
if ($verbose) echo COLOR_BLUE . "Checking CONTRIBUTING.md..." . COLOR_RESET . "\n";
$result = checkVersionInFile($contributingFile, '/VERSION:\s*([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => 'CONTRIBUTING.md',
'type' => 'VERSION header',
'mismatches' => $result['mismatches']
];
}
return $issues;
}
/**
* Check workflow files
*/
function checkWorkflowFiles(string $repoRoot, string $expectedVersion, bool $verbose): array
{
$issues = [];
$workflowDir = $repoRoot . '/.github/workflows';
if (!is_dir($workflowDir)) {
return $issues;
}
$files = glob($workflowDir . '/*.yml');
if ($verbose) echo COLOR_BLUE . "Checking " . count($files) . " workflow files..." . COLOR_RESET . "\n";
foreach ($files as $file) {
$result = checkVersionInFile($file, '/#\s*VERSION:\s*([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => str_replace($repoRoot . '/', '', $file),
'type' => 'Workflow VERSION comment',
'mismatches' => $result['mismatches']
];
}
}
return $issues;
}
/**
* Check PHP source files
*/
function checkPhpSourceFiles(string $repoRoot, string $expectedVersion, bool $verbose): array
{
$issues = [];
$srcDir = $repoRoot . '/src';
if (!is_dir($srcDir)) {
return $issues;
}
$iterator = new RecursiveIteratorIterator(
new RecursiveDirectoryIterator($srcDir, RecursiveDirectoryIterator::SKIP_DOTS)
);
$phpFiles = [];
foreach ($iterator as $file) {
if ($file->isFile() && $file->getExtension() === 'php') {
$phpFiles[] = $file->getPathname();
}
}
if ($verbose) echo COLOR_BLUE . "Checking " . count($phpFiles) . " PHP source files..." . COLOR_RESET . "\n";
foreach ($phpFiles as $file) {
$result = checkVersionInFile($file, '/VERSION:\s*([\d.]+)/', $expectedVersion, $verbose);
if (!empty($result['mismatches'])) {
$issues[] = [
'file' => str_replace($repoRoot . '/', '', $file),
'type' => 'PHP VERSION header',
'mismatches' => $result['mismatches']
];
}
}
return $issues;
}
/**
* Main execution
*/
function main(): int
{
global $repoRoot, $expectedVersionFile;
$options = parseArguments();
if ($options['help']) {
displayHelp();
return 0;
}
echo COLOR_BOLD . "=== MokoStandards Version Consistency Checker ===" . COLOR_RESET . "\n\n";
// Get expected version
$expectedVersion = getExpectedVersion($expectedVersionFile, $options['verbose']);
if ($expectedVersion === null) {
return 2;
}
echo COLOR_GREEN . "✓ Expected version: $expectedVersion" . COLOR_RESET . "\n\n";
// Check critical files
echo COLOR_BOLD . "Checking critical files..." . COLOR_RESET . "\n";
$criticalIssues = checkCriticalFiles($repoRoot, $expectedVersion, $options['verbose']);
// Check workflow files
echo COLOR_BOLD . "\nChecking workflow files..." . COLOR_RESET . "\n";
$workflowIssues = checkWorkflowFiles($repoRoot, $expectedVersion, $options['verbose']);
// Check PHP source files
echo COLOR_BOLD . "\nChecking PHP source files..." . COLOR_RESET . "\n";
$phpIssues = checkPhpSourceFiles($repoRoot, $expectedVersion, $options['verbose']);
// Combine all issues
$allIssues = array_merge($criticalIssues, $workflowIssues, $phpIssues);
// Report results
echo "\n" . COLOR_BOLD . "=== Results ===" . COLOR_RESET . "\n\n";
if (empty($allIssues)) {
echo COLOR_GREEN . "✓ All version numbers are consistent!" . COLOR_RESET . "\n";
echo COLOR_GREEN . "✓ Expected version $expectedVersion found in all checked files." . COLOR_RESET . "\n";
return 0;
}
echo COLOR_RED . "✗ Found " . count($allIssues) . " version mismatch(es):" . COLOR_RESET . "\n\n";
foreach ($allIssues as $issue) {
echo COLOR_YELLOW . "File: " . $issue['file'] . COLOR_RESET . "\n";
echo " Type: " . $issue['type'] . "\n";
foreach ($issue['mismatches'] as $mismatch) {
echo COLOR_RED . " Line " . $mismatch['line'] . ": Found " . $mismatch['found'] .
" (expected " . $mismatch['expected'] . ")" . COLOR_RESET . "\n";
}
echo "\n";
}
echo COLOR_RED . "\n✗ Please update the version numbers in the files listed above." . COLOR_RESET . "\n";
return 1;
}
exit(main());
@@ -1,100 +0,0 @@
#!/usr/bin/env bash
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Shell wrapper template for Python scripts
# This wrapper provides a convenient way to call Python scripts with proper error handling
set -euo pipefail
# Script Configuration - UPDATE THESE FOR EACH WRAPPER
SCRIPT_NAME="check_markdown_links"
SCRIPT_PATH="scripts/validate/check_markdown_links.py"
SCRIPT_CATEGORY="validation" # automation, validation, maintenance, etc.
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Functions
log_info() {
echo -e "${BLUE}$1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# Get repository root
get_repo_root() {
git rev-parse --show-toplevel 2>/dev/null || pwd
}
# Check if Python is available
check_python() {
if command -v python3 &> /dev/null; then
echo "python3"
elif command -v python &> /dev/null; then
echo "python"
else
log_error "Python is not installed or not in PATH"
echo "Please install Python 3.7 or later"
exit 1
fi
}
# Main execution
main() {
local repo_root
repo_root=$(get_repo_root)
local python_cmd
python_cmd=$(check_python)
local full_script_path="$repo_root/$SCRIPT_PATH"
# Check if script exists
if [ ! -f "$full_script_path" ]; then
log_error "Python script not found: $full_script_path"
exit 1
fi
# Setup logging directory
local log_dir="$repo_root/logs/$SCRIPT_CATEGORY"
mkdir -p "$log_dir"
local timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
local log_file="$log_dir/${SCRIPT_NAME}_${timestamp}.log"
# Execute Python script with all arguments
log_info "Running $SCRIPT_NAME..."
log_info "Log file: $log_file"
if "$python_cmd" "$full_script_path" "$@" 2>&1 | tee "$log_file"; then
log_success "$SCRIPT_NAME completed successfully"
exit 0
else
local exit_code=$?
log_error "$SCRIPT_NAME failed with exit code: $exit_code"
log_info "Check log file for details: $log_file"
exit $exit_code
fi
}
# Run main with all arguments
main "$@"
-100
View File
@@ -1,100 +0,0 @@
#!/usr/bin/env bash
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Shell wrapper template for Python scripts
# This wrapper provides a convenient way to call Python scripts with proper error handling
set -euo pipefail
# Script Configuration - UPDATE THESE FOR EACH WRAPPER
SCRIPT_NAME="rebuild_indexes"
SCRIPT_PATH="scripts/docs/rebuild_indexes.py"
SCRIPT_CATEGORY="docs" # automation, validation, maintenance, etc.
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Functions
log_info() {
echo -e "${BLUE}$1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# Get repository root
get_repo_root() {
git rev-parse --show-toplevel 2>/dev/null || pwd
}
# Check if Python is available
check_python() {
if command -v python3 &> /dev/null; then
echo "python3"
elif command -v python &> /dev/null; then
echo "python"
else
log_error "Python is not installed or not in PATH"
echo "Please install Python 3.7 or later"
exit 1
fi
}
# Main execution
main() {
local repo_root
repo_root=$(get_repo_root)
local python_cmd
python_cmd=$(check_python)
local full_script_path="$repo_root/$SCRIPT_PATH"
# Check if script exists
if [ ! -f "$full_script_path" ]; then
log_error "Python script not found: $full_script_path"
exit 1
fi
# Setup logging directory
local log_dir="$repo_root/logs/$SCRIPT_CATEGORY"
mkdir -p "$log_dir"
local timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
local log_file="$log_dir/${SCRIPT_NAME}_${timestamp}.log"
# Execute Python script with all arguments
log_info "Running $SCRIPT_NAME..."
log_info "Log file: $log_file"
if "$python_cmd" "$full_script_path" "$@" 2>&1 | tee "$log_file"; then
log_success "$SCRIPT_NAME completed successfully"
exit 0
else
local exit_code=$?
log_error "$SCRIPT_NAME failed with exit code: $exit_code"
log_info "Check log file for details: $log_file"
exit $exit_code
fi
}
# Run main with all arguments
main "$@"
@@ -1,100 +0,0 @@
#!/usr/bin/env bash
# Copyright (C) 2026 Moko Consulting <hello@mokoconsulting.tech>
#
# This file is part of a Moko Consulting project.
#
# SPDX-License-Identifier: GPL-3.0-or-later
#
# Shell wrapper template for Python scripts
# This wrapper provides a convenient way to call Python scripts with proper error handling
set -euo pipefail
# Script Configuration - UPDATE THESE FOR EACH WRAPPER
SCRIPT_NAME="validate_file_headers"
SCRIPT_PATH="scripts/maintenance/validate_file_headers.py"
SCRIPT_CATEGORY="maintenance" # automation, validation, maintenance, etc.
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# Functions
log_info() {
echo -e "${BLUE}$1${NC}"
}
log_success() {
echo -e "${GREEN}$1${NC}"
}
log_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
log_error() {
echo -e "${RED}$1${NC}"
}
# Get repository root
get_repo_root() {
git rev-parse --show-toplevel 2>/dev/null || pwd
}
# Check if Python is available
check_python() {
if command -v python3 &> /dev/null; then
echo "python3"
elif command -v python &> /dev/null; then
echo "python"
else
log_error "Python is not installed or not in PATH"
echo "Please install Python 3.7 or later"
exit 1
fi
}
# Main execution
main() {
local repo_root
repo_root=$(get_repo_root)
local python_cmd
python_cmd=$(check_python)
local full_script_path="$repo_root/$SCRIPT_PATH"
# Check if script exists
if [ ! -f "$full_script_path" ]; then
log_error "Python script not found: $full_script_path"
exit 1
fi
# Setup logging directory
local log_dir="$repo_root/logs/$SCRIPT_CATEGORY"
mkdir -p "$log_dir"
local timestamp
timestamp=$(date +"%Y%m%d_%H%M%S")
local log_file="$log_dir/${SCRIPT_NAME}_${timestamp}.log"
# Execute Python script with all arguments
log_info "Running $SCRIPT_NAME..."
log_info "Log file: $log_file"
if "$python_cmd" "$full_script_path" "$@" 2>&1 | tee "$log_file"; then
log_success "$SCRIPT_NAME completed successfully"
exit 0
else
local exit_code=$?
log_error "$SCRIPT_NAME failed with exit code: $exit_code"
log_info "Check log file for details: $log_file"
exit $exit_code
fi
}
# Run main with all arguments
main "$@"
@@ -3,7 +3,7 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline."
; Configuration
@@ -3,5 +3,5 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when site is offline"
@@ -3,7 +3,7 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline."
; Configuration
@@ -3,5 +3,5 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when site is offline"
@@ -3,7 +3,7 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline."
; Configuration
@@ -3,7 +3,7 @@
; License GNU General Public License version 3 or later; see LICENSE
; Note: All ini files need to be saved as UTF-8
PLG_SYSTEM_MOKOJOOMTOS="System - MokoJoomTOS"
PLG_SYSTEM_MOKOJOOMTOS="System - Offline Terms of Service"
PLG_SYSTEM_MOKOJOOMTOS_XML_DESCRIPTION="Allows Terms of Service to be accessible via menu slug when the site is in offline mode. Simply configure the menu slug (e.g., 'terms-of-service') and that page will remain accessible even when the site is offline."
; Configuration
+2 -1
View File
@@ -77,9 +77,10 @@ class MenuslugField extends ListField
$lastMenuType = $item->menutype;
}
$displayText = $item->title !== '' ? $item->title : ucwords(str_replace(['-', '_'], ' ', $item->alias));
$options[] = (object) [
'value' => $item->alias,
'text' => $item->title . ' (' . $item->alias . ')'
'text' => $displayText . ' (' . $item->alias . ')'
];
}
}